aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq
diff options
context:
space:
mode:
authorTodd Poynor <toddpoynor@google.com>2011-06-22 14:34:23 -0700
committerTodd Poynor <toddpoynor@google.com>2011-09-15 11:04:06 -0700
commita50b0530418bc4c6446478aa80ecfaa661df7099 (patch)
treec149271e6220e097549226031895456be226c59b /drivers/cpufreq
parenta682462f220720a1e46fae07deab04690aa0d40c (diff)
downloadkernel_samsung_espresso10-a50b0530418bc4c6446478aa80ecfaa661df7099.zip
kernel_samsung_espresso10-a50b0530418bc4c6446478aa80ecfaa661df7099.tar.gz
kernel_samsung_espresso10-a50b0530418bc4c6446478aa80ecfaa661df7099.tar.bz2
cpufreq: interactive: Fix handling of SMP where CPUs must scale in tandem
The interactive governor relies on quirks of the Tegra 2 cpufreq implementation for handling SMP systems where the CPUs do not have separate rate controls. It needs to determine the maximum rate for all CPUs covered by the policy and set that speed. Change-Id: I1ed9fa171e5a9c45a1fa5944e3fa823eb157e81f Signed-off-by: Todd Poynor <toddpoynor@google.com>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/cpufreq_interactive.c49
1 files changed, 40 insertions, 9 deletions
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index f90d3a5..d8f62f4 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -25,6 +25,7 @@
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/kthread.h>
+#include <linux/mutex.h>
#include <asm/cputime.h>
@@ -55,6 +56,7 @@ static cpumask_t up_cpumask;
static spinlock_t up_cpumask_lock;
static cpumask_t down_cpumask;
static spinlock_t down_cpumask_lock;
+static struct mutex set_speed_lock;
/* Go to max speed when CPU load at or above this value. */
#define DEFAULT_GO_MAXSPEED_LOAD 85
@@ -339,22 +341,36 @@ static int cpufreq_interactive_up_task(void *data)
}
set_current_state(TASK_RUNNING);
-
tmp_mask = up_cpumask;
cpumask_clear(&up_cpumask);
spin_unlock_irqrestore(&up_cpumask_lock, flags);
for_each_cpu(cpu, &tmp_mask) {
- pcpu = &per_cpu(cpuinfo, cpu);
+ unsigned int j;
+ unsigned int max_freq = 0;
+ pcpu = &per_cpu(cpuinfo, cpu);
smp_rmb();
if (!pcpu->governor_enabled)
continue;
- __cpufreq_driver_target(pcpu->policy,
- pcpu->target_freq,
- CPUFREQ_RELATION_H);
+ mutex_lock(&set_speed_lock);
+
+ for_each_cpu(j, pcpu->policy->cpus) {
+ struct cpufreq_interactive_cpuinfo *pjcpu =
+ &per_cpu(cpuinfo, j);
+
+ if (pjcpu->target_freq > max_freq)
+ max_freq = pjcpu->target_freq;
+ }
+
+ if (max_freq != pcpu->policy->cur)
+ __cpufreq_driver_target(pcpu->policy,
+ max_freq,
+ CPUFREQ_RELATION_H);
+ mutex_unlock(&set_speed_lock);
+
pcpu->freq_change_time_in_idle =
get_cpu_idle_time_us(cpu,
&pcpu->freq_change_time);
@@ -377,16 +393,30 @@ static void cpufreq_interactive_freq_down(struct work_struct *work)
spin_unlock_irqrestore(&down_cpumask_lock, flags);
for_each_cpu(cpu, &tmp_mask) {
- pcpu = &per_cpu(cpuinfo, cpu);
+ unsigned int j;
+ unsigned int max_freq = 0;
+ pcpu = &per_cpu(cpuinfo, cpu);
smp_rmb();
if (!pcpu->governor_enabled)
continue;
- __cpufreq_driver_target(pcpu->policy,
- pcpu->target_freq,
- CPUFREQ_RELATION_H);
+ mutex_lock(&set_speed_lock);
+
+ for_each_cpu(j, pcpu->policy->cpus) {
+ struct cpufreq_interactive_cpuinfo *pjcpu =
+ &per_cpu(cpuinfo, j);
+
+ if (pjcpu->target_freq > max_freq)
+ max_freq = pjcpu->target_freq;
+ }
+
+ if (max_freq != pcpu->policy->cur)
+ __cpufreq_driver_target(pcpu->policy, max_freq,
+ CPUFREQ_RELATION_H);
+
+ mutex_unlock(&set_speed_lock);
pcpu->freq_change_time_in_idle =
get_cpu_idle_time_us(cpu,
&pcpu->freq_change_time);
@@ -608,6 +638,7 @@ static int __init cpufreq_interactive_init(void)
spin_lock_init(&up_cpumask_lock);
spin_lock_init(&down_cpumask_lock);
+ mutex_init(&set_speed_lock);
idle_notifier_register(&cpufreq_interactive_idle_nb);