From 5ce32209e76f933062cd667b4cff51ac0c400c32 Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Tue, 8 Apr 2014 12:25:12 -0700 Subject: [PATCH 1/6] video: adf: document adf_format_validate_yuv's origin Change-Id: I929045a96a56bdb2c915be92b8ef11b560f3ab79 Signed-off-by: Greg Hackmann --- drivers/video/adf/adf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/video/adf/adf.c b/drivers/video/adf/adf.c index 2d20024fd251..589baaa5fbcd 100644 --- a/drivers/video/adf/adf.c +++ b/drivers/video/adf/adf.c @@ -2,6 +2,8 @@ * Copyright (C) 2013 Google, Inc. * adf_modeinfo_{set_name,set_vrefresh} modified from * drivers/gpu/drm/drm_modes.c + * adf_format_validate_yuv modified from framebuffer_check in + * drivers/gpu/drm/drm_crtc.c * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and From adbe864576c5e5ac848d7e6009f760efdd00b44d Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Tue, 8 Apr 2014 12:36:41 -0700 Subject: [PATCH 2/6] video: adf: add buffer padding quirk Quirks specify common behaviors that vary slightly among devices, and which ADF must account for. The buffer padding quirk captures the way different devices fetch the last scanline in a buffer: some devices fetch an entire line (including padding to the pitch) while others only fetch up to the visible width. ADF's buffer size validation now takes this quirk into account. Change-Id: I828b13316e27621d8a9efd9d5fffa6ce12a525ff Signed-off-by: Greg Hackmann --- drivers/video/adf/adf.c | 18 ++++++++++++++++-- include/video/adf.h | 18 ++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/drivers/video/adf/adf.c b/drivers/video/adf/adf.c index 589baaa5fbcd..e6ef144136c2 100644 --- a/drivers/video/adf/adf.c +++ b/drivers/video/adf/adf.c @@ -1073,6 +1073,7 @@ int adf_format_validate_yuv(struct adf_device *dev, struct adf_buffer *buf, u32 width = buf->w / (i != 0 ? hsub : 1); u32 height = buf->h / (i != 0 ? vsub : 1); u8 cpp = adf_format_plane_cpp(buf->format, i); + u32 last_line_size; if (buf->pitch[i] < (u64) width * cpp) { dev_err(&dev->base.dev, "plane %u pitch is shorter than buffer width (pitch = %u, width = %u, bpp = %u)\n", @@ -1080,8 +1081,21 @@ int adf_format_validate_yuv(struct adf_device *dev, struct adf_buffer *buf, return -EINVAL; } - if ((u64) height * buf->pitch[i] + buf->offset[i] > - buf->dma_bufs[i]->size) { + switch (dev->ops->quirks.buffer_padding) { + case ADF_BUFFER_PADDED_TO_PITCH: + last_line_size = buf->pitch[i]; + break; + + case ADF_BUFFER_UNPADDED: + last_line_size = width * cpp; + break; + + default: + BUG(); + } + + if ((u64) (height - 1) * buf->pitch[i] + last_line_size + + buf->offset[i] > buf->dma_bufs[i]->size) { dev_err(&dev->base.dev, "plane %u buffer too small (height = %u, pitch = %u, offset = %u, size = %zu)\n", i, height, buf->pitch[i], buf->offset[i], buf->dma_bufs[i]->size); diff --git a/include/video/adf.h b/include/video/adf.h index 2b742ab463dd..34f10e538f9e 100644 --- a/include/video/adf.h +++ b/include/video/adf.h @@ -192,11 +192,27 @@ struct adf_obj { int minor; }; +/** + * struct adf_device_quirks - common display device quirks + * + * @buffer_padding: whether the last scanline of a buffer extends to the + * buffer's pitch (@ADF_BUFFER_PADDED_TO_PITCH) or just to the visible + * width (@ADF_BUFFER_UNPADDED) + */ +struct adf_device_quirks { + /* optional, defaults to ADF_BUFFER_PADDED_TO_PITCH */ + enum { + ADF_BUFFER_PADDED_TO_PITCH = 0, + ADF_BUFFER_UNPADDED = 1, + } buffer_padding; +}; + /** * struct adf_device_ops - display device implementation ops * * @owner: device's module * @base: common operations (see &struct adf_obj_ops) + * @quirks: device's quirks (see &struct adf_device_quirks) * * @attach: attach overlay engine @eng to interface @intf. Return 0 on success * or error code (<0) on failure. @@ -228,6 +244,8 @@ struct adf_device_ops { /* required */ struct module *owner; const struct adf_obj_ops base; + /* optional */ + const struct adf_device_quirks quirks; /* optional */ int (*attach)(struct adf_device *dev, struct adf_overlay_engine *eng, From 5f08c8d82d008650468c96506fcdf7208f384795 Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Tue, 8 Apr 2014 13:07:29 -0700 Subject: [PATCH 3/6] video: adf: adf_memblock_export symbol should be exported Change-Id: I228db28da885b47b6fa9fc7e4001663797d24f49 Signed-off-by: Greg Hackmann --- drivers/video/adf/adf_memblock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/adf/adf_memblock.c b/drivers/video/adf/adf_memblock.c index 3c99f27388db..aa03809e59b7 100644 --- a/drivers/video/adf/adf_memblock.c +++ b/drivers/video/adf/adf_memblock.c @@ -147,3 +147,4 @@ struct dma_buf *adf_memblock_export(phys_addr_t base, size_t size, int flags) return buf; } +EXPORT_SYMBOL(adf_memblock_export); From 9b97d655a558607c5d46ef1f21365d695f8d1ee2 Mon Sep 17 00:00:00 2001 From: Badhri Jagan Sridharan Date: Mon, 7 Apr 2014 18:26:30 -0700 Subject: [PATCH 4/6] cpufreq: interactive: restructure CPUFREQ_GOV_LIMITS The cpufreq_interactive_timer gets cancelled and rescheduled whenever the cpufreq_policy is changed. When the cpufreq policy is changed at a rate faster than the sampling_rate of the interactive governor, then the governor misses to change the target frequency for long duration. The patch removes the need of cancelling the timers when policy->min is changed. Signed-off-by: Badhri Jagan Sridharan Change-Id: Ibd98d151e1c73b8bd969484583ff98ee9f1135ef --- drivers/cpufreq/cpufreq_interactive.c | 48 +++++++++++++++++++-------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c index 8297ac69863b..9bf1a661e147 100644 --- a/drivers/cpufreq/cpufreq_interactive.c +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -46,8 +46,10 @@ struct cpufreq_interactive_cpuinfo { u64 cputime_speedadj_timestamp; struct cpufreq_policy *policy; struct cpufreq_frequency_table *freq_table; + spinlock_t target_freq_lock; /*protects target freq */ unsigned int target_freq; unsigned int floor_freq; + unsigned int max_freq; u64 floor_validate_time; u64 hispeed_validate_time; struct rw_semaphore enable_sem; @@ -398,6 +400,7 @@ static void cpufreq_interactive_timer(unsigned long data) if (WARN_ON_ONCE(!delta_time)) goto rearm; + spin_lock_irqsave(&pcpu->target_freq_lock, flags); do_div(cputime_speedadj, delta_time); loadadjfreq = (unsigned int)cputime_speedadj * 100; cpu_load = loadadjfreq / pcpu->target_freq; @@ -423,6 +426,7 @@ static void cpufreq_interactive_timer(unsigned long data) trace_cpufreq_interactive_notyet( data, cpu_load, pcpu->target_freq, pcpu->policy->cur, new_freq); + spin_unlock_irqrestore(&pcpu->target_freq_lock, flags); goto rearm; } @@ -430,8 +434,10 @@ static void cpufreq_interactive_timer(unsigned long data) if (cpufreq_frequency_table_target(pcpu->policy, pcpu->freq_table, new_freq, CPUFREQ_RELATION_L, - &index)) + &index)) { + spin_unlock_irqrestore(&pcpu->target_freq_lock, flags); goto rearm; + } new_freq = pcpu->freq_table[index].frequency; @@ -445,6 +451,7 @@ static void cpufreq_interactive_timer(unsigned long data) trace_cpufreq_interactive_notyet( data, cpu_load, pcpu->target_freq, pcpu->policy->cur, new_freq); + spin_unlock_irqrestore(&pcpu->target_freq_lock, flags); goto rearm; } } @@ -466,6 +473,7 @@ static void cpufreq_interactive_timer(unsigned long data) trace_cpufreq_interactive_already( data, cpu_load, pcpu->target_freq, pcpu->policy->cur, new_freq); + spin_unlock_irqrestore(&pcpu->target_freq_lock, flags); goto rearm_if_notmax; } @@ -473,6 +481,7 @@ static void cpufreq_interactive_timer(unsigned long data) pcpu->policy->cur, new_freq); pcpu->target_freq = new_freq; + spin_unlock_irqrestore(&pcpu->target_freq_lock, flags); spin_lock_irqsave(&speedchange_cpumask_lock, flags); cpumask_set_cpu(data, &speedchange_cpumask); spin_unlock_irqrestore(&speedchange_cpumask_lock, flags); @@ -616,16 +625,17 @@ static void cpufreq_interactive_boost(void) { int i; int anyboost = 0; - unsigned long flags; + unsigned long flags[2]; struct cpufreq_interactive_cpuinfo *pcpu; struct cpufreq_interactive_tunables *tunables; - spin_lock_irqsave(&speedchange_cpumask_lock, flags); + spin_lock_irqsave(&speedchange_cpumask_lock, flags[0]); for_each_online_cpu(i) { pcpu = &per_cpu(cpuinfo, i); tunables = pcpu->policy->governor_data; + spin_lock_irqsave(&pcpu->target_freq_lock, flags[1]); if (pcpu->target_freq < tunables->hispeed_freq) { pcpu->target_freq = tunables->hispeed_freq; cpumask_set_cpu(i, &speedchange_cpumask); @@ -641,9 +651,10 @@ static void cpufreq_interactive_boost(void) pcpu->floor_freq = tunables->hispeed_freq; pcpu->floor_validate_time = ktime_to_us(ktime_get()); + spin_unlock_irqrestore(&pcpu->target_freq_lock, flags[1]); } - spin_unlock_irqrestore(&speedchange_cpumask_lock, flags); + spin_unlock_irqrestore(&speedchange_cpumask_lock, flags[0]); if (anyboost) wake_up_process(speedchange_task); @@ -1154,6 +1165,7 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, struct cpufreq_interactive_cpuinfo *pcpu; struct cpufreq_frequency_table *freq_table; struct cpufreq_interactive_tunables *tunables; + unsigned long flags; if (have_governor_per_policy()) tunables = policy->governor_data; @@ -1249,6 +1261,7 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, ktime_to_us(ktime_get()); pcpu->hispeed_validate_time = pcpu->floor_validate_time; + pcpu->max_freq = policy->max; down_write(&pcpu->enable_sem); del_timer_sync(&pcpu->cpu_timer); del_timer_sync(&pcpu->cpu_slack_timer); @@ -1284,29 +1297,37 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, for_each_cpu(j, policy->cpus) { pcpu = &per_cpu(cpuinfo, j); - /* hold write semaphore to avoid race */ - down_write(&pcpu->enable_sem); + down_read(&pcpu->enable_sem); if (pcpu->governor_enabled == 0) { - up_write(&pcpu->enable_sem); + up_read(&pcpu->enable_sem); continue; } - /* update target_freq firstly */ + spin_lock_irqsave(&pcpu->target_freq_lock, flags); if (policy->max < pcpu->target_freq) pcpu->target_freq = policy->max; else if (policy->min > pcpu->target_freq) pcpu->target_freq = policy->min; - /* Reschedule timer. + spin_unlock_irqrestore(&pcpu->target_freq_lock, flags); + up_read(&pcpu->enable_sem); + + /* Reschedule timer only if policy->max is raised. * Delete the timers, else the timer callback may * return without re-arm the timer when failed * acquire the semaphore. This race may cause timer * stopped unexpectedly. */ - del_timer_sync(&pcpu->cpu_timer); - del_timer_sync(&pcpu->cpu_slack_timer); - cpufreq_interactive_timer_start(tunables, j); - up_write(&pcpu->enable_sem); + + if (policy->max > pcpu->max_freq) { + down_write(&pcpu->enable_sem); + del_timer_sync(&pcpu->cpu_timer); + del_timer_sync(&pcpu->cpu_slack_timer); + cpufreq_interactive_timer_start(tunables, j); + up_write(&pcpu->enable_sem); + } + + pcpu->max_freq = policy->max; } break; } @@ -1342,6 +1363,7 @@ static int __init cpufreq_interactive_init(void) init_timer(&pcpu->cpu_slack_timer); pcpu->cpu_slack_timer.function = cpufreq_interactive_nop_timer; spin_lock_init(&pcpu->load_lock); + spin_lock_init(&pcpu->target_freq_lock); init_rwsem(&pcpu->enable_sem); } From 49cc72365fb7ee87762a7ccc6a32ef68627216c5 Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Thu, 3 Apr 2014 15:39:23 -0700 Subject: [PATCH 5/6] cpufreq: interactive: turn boost_pulse off on boost off Change-Id: I36fe217fa047d68ea90e78b12c7db4537ea8010b Signed-off-by: Ruchi Kandoi --- drivers/cpufreq/cpufreq_interactive.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c index 9bf1a661e147..6a0137d90768 100644 --- a/drivers/cpufreq/cpufreq_interactive.c +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -948,6 +948,7 @@ static ssize_t store_boost(struct cpufreq_interactive_tunables *tunables, trace_cpufreq_interactive_boost("on"); cpufreq_interactive_boost(); } else { + boostpulse_endtime = ktime_to_us(ktime_get()); trace_cpufreq_interactive_unboost("off"); } From d4f9b043ae029cf3462775d488232c8de4808f22 Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Wed, 9 Apr 2014 16:47:59 -0700 Subject: [PATCH 6/6] cpufreq: interactive: remove compilation error from commit 49cc72365fb7ee87762a7ccc6a32ef68627216c5 Change-Id: I068b18281d03ac879ef64d8ff36ed43367293767 Signed-off-by: Ruchi Kandoi --- drivers/cpufreq/cpufreq_interactive.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c index 6a0137d90768..a376dfa8f412 100644 --- a/drivers/cpufreq/cpufreq_interactive.c +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -948,7 +948,7 @@ static ssize_t store_boost(struct cpufreq_interactive_tunables *tunables, trace_cpufreq_interactive_boost("on"); cpufreq_interactive_boost(); } else { - boostpulse_endtime = ktime_to_us(ktime_get()); + tunables->boostpulse_endtime = ktime_to_us(ktime_get()); trace_cpufreq_interactive_unboost("off"); }