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 <dtor@chromium.org> Reviewed-by: Dylan Reid <dgreid@chromium.org> Reviewed-by: Douglas Anderson <dianders@chromium.org> Signed-off-by: Dmitry Torokhov <dtor@google.com>
This commit is contained in:
committed by
Dmitry Shmidt
parent
e7d40d2bf8
commit
2ebb4d97e0
@@ -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) {
|
||||
|
||||
down_write(&pcpu->policy->rwsem);
|
||||
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
|
||||
for_each_cpu(j, pcpu->policy->cpus) {
|
||||
pjcpu = &per_cpu(cpuinfo, j);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
trace_cpufreq_interactive_setspeed(cpu,
|
||||
pcpu->target_freq,
|
||||
pcpu->policy->cur);
|
||||
|
||||
up_read(&pcpu->enable_sem);
|
||||
up_write(&pcpu->policy->rwsem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user