From: Dmitry Torokhov Date: Wed, 4 Feb 2015 21:54:48 +0000 (-0800) Subject: cpufreq: interactive: fix policy locking X-Git-Tag: firefly_0821_release~176^2~411 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=02018626853b6dd6dee77d1e1befeaf2d6a8098e;p=firefly-linux-kernel-4.4.55.git cpufreq: interactive: fix policy locking cpufreq_interactive_speedchange_task() is running as a separate kernel thread and is calling __cpufreq_driver_target(), which requires callers to hold policy->rwsem for writing to prevent racing with other parts of the kernel trying to adjust the frequency, for example kernel thermal throttling. Let's change the code to take policy->rwsem and while at it refactor the code a bit. This was originally 2 changes reviewed at: https://chromium-review.googlesource.com/246273 https://chromium-review.googlesource.com/256120 Change-Id: Icc2d97c6c1b929acd2ee32e8c81d81fd2af778ab Signed-off-by: Dmitry Torokhov Reviewed-by: Dylan Reid Reviewed-by: Douglas Anderson Signed-off-by: Dmitry Torokhov --- diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c index 0be66df4a6e6..5224e897d460 100644 --- a/drivers/cpufreq/cpufreq_interactive.c +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -511,6 +511,58 @@ static void cpufreq_interactive_idle_end(void) up_read(&pcpu->enable_sem); } +static void cpufreq_interactive_get_policy_info(struct cpufreq_policy *policy, + unsigned int *pmax_freq, + u64 *phvt, u64 *pfvt) +{ + struct cpufreq_interactive_cpuinfo *pcpu; + unsigned int max_freq = 0; + u64 hvt = ~0ULL, fvt = 0; + unsigned int i; + + for_each_cpu(i, policy->cpus) { + pcpu = &per_cpu(cpuinfo, i); + + fvt = max(fvt, pcpu->loc_floor_val_time); + if (pcpu->target_freq > max_freq) { + max_freq = pcpu->target_freq; + hvt = pcpu->loc_hispeed_val_time; + } else if (pcpu->target_freq == max_freq) { + hvt = min(hvt, pcpu->loc_hispeed_val_time); + } + } + + *pmax_freq = max_freq; + *phvt = hvt; + *pfvt = fvt; +} + +static void cpufreq_interactive_adjust_cpu(unsigned int cpu, + struct cpufreq_policy *policy) +{ + struct cpufreq_interactive_cpuinfo *pcpu; + u64 hvt, fvt; + unsigned int max_freq; + int i; + + cpufreq_interactive_get_policy_info(policy, &max_freq, &hvt, &fvt); + + for_each_cpu(i, policy->cpus) { + pcpu = &per_cpu(cpuinfo, i); + pcpu->pol_floor_val_time = fvt; + } + + if (max_freq != policy->cur) { + __cpufreq_driver_target(policy, max_freq, CPUFREQ_RELATION_H); + for_each_cpu(i, policy->cpus) { + pcpu = &per_cpu(cpuinfo, i); + pcpu->pol_hispeed_val_time = hvt; + } + } + + trace_cpufreq_interactive_setspeed(cpu, max_freq, policy->cur); +} + static int cpufreq_interactive_speedchange_task(void *data) { unsigned int cpu; @@ -539,49 +591,18 @@ static int cpufreq_interactive_speedchange_task(void *data) spin_unlock_irqrestore(&speedchange_cpumask_lock, flags); for_each_cpu(cpu, &tmp_mask) { - unsigned int j; - unsigned int max_freq = 0; - struct cpufreq_interactive_cpuinfo *pjcpu; - u64 hvt = ~0ULL, fvt = 0; - pcpu = &per_cpu(cpuinfo, cpu); - if (!down_read_trylock(&pcpu->enable_sem)) - continue; - if (!pcpu->governor_enabled) { - up_read(&pcpu->enable_sem); - continue; - } - for_each_cpu(j, pcpu->policy->cpus) { - pjcpu = &per_cpu(cpuinfo, j); + down_write(&pcpu->policy->rwsem); - fvt = max(fvt, pjcpu->loc_floor_val_time); - if (pjcpu->target_freq > max_freq) { - max_freq = pjcpu->target_freq; - hvt = pjcpu->loc_hispeed_val_time; - } else if (pjcpu->target_freq == max_freq) { - hvt = min(hvt, pjcpu->loc_hispeed_val_time); - } - } - for_each_cpu(j, pcpu->policy->cpus) { - pjcpu = &per_cpu(cpuinfo, j); - pjcpu->pol_floor_val_time = fvt; - } - - if (max_freq != pcpu->policy->cur) { - __cpufreq_driver_target(pcpu->policy, - max_freq, - CPUFREQ_RELATION_H); - for_each_cpu(j, pcpu->policy->cpus) { - pjcpu = &per_cpu(cpuinfo, j); - pjcpu->pol_hispeed_val_time = hvt; - } + if (likely(down_read_trylock(&pcpu->enable_sem))) { + if (likely(pcpu->governor_enabled)) + cpufreq_interactive_adjust_cpu(cpu, + pcpu->policy); + up_read(&pcpu->enable_sem); } - trace_cpufreq_interactive_setspeed(cpu, - pcpu->target_freq, - pcpu->policy->cur); - up_read(&pcpu->enable_sem); + up_write(&pcpu->policy->rwsem); } }