Commit b2fb87d3 authored by Juri Lelli's avatar Juri Lelli Committed by Dietmar Eggemann
Browse files

FIXUP: sched/cpufreq_sched: fix hotplug by implementing init/exit



There is a race condition between cpu hotplug and gov_sched stop path
that can result in a OOPS. Also, gov_sched is still lacking proper
implementation for POLICY_{INIT,EXIT} events.

Fix the bug by implementing such methods and by ensuring gov_sched has
always a valid reference to gd->task (via {get,put}_task_struct()).

Signed-off-by: default avatarJuri Lelli <juri.lelli@arm.com>
parent 3ff6ba04
......@@ -229,7 +229,7 @@ static inline void clear_sched_energy_freq(void)
static_key_slow_dec(&__sched_energy_freq);
}
static int cpufreq_sched_start(struct cpufreq_policy *policy)
static int cpufreq_sched_policy_init(struct cpufreq_policy *policy)
{
struct gov_data *gd;
int cpu;
......@@ -264,6 +264,7 @@ static int cpufreq_sched_start(struct cpufreq_policy *policy)
pr_err("%s: failed to create kcpufreq_sched_task thread\n", __func__);
goto err;
}
get_task_struct(gd->task);
init_irq_work(&gd->irq_work, cpufreq_sched_irq_work);
}
......@@ -271,9 +272,6 @@ static int cpufreq_sched_start(struct cpufreq_policy *policy)
gd->policy = policy;
set_sched_energy_freq();
for_each_cpu(cpu, policy->cpus)
per_cpu(governor_started, cpu) = 1;
return 0;
err:
......@@ -281,17 +279,34 @@ err:
return -ENOMEM;
}
static int cpufreq_sched_start(struct cpufreq_policy *policy)
{
int cpu;
for_each_cpu(cpu, policy->cpus)
per_cpu(governor_started, cpu) = 1;
return 0;
}
static int cpufreq_sched_stop(struct cpufreq_policy *policy)
{
struct gov_data *gd = policy->governor_data;
int cpu;
for_each_cpu(cpu, policy->cpus)
per_cpu(governor_started, cpu) = 0;
return 0;
}
static int cpufreq_sched_policy_exit(struct cpufreq_policy *policy)
{
struct gov_data *gd = policy->governor_data;
clear_sched_energy_freq();
if (cpufreq_driver_might_sleep()) {
kthread_stop(gd->task);
put_task_struct(gd->task);
}
policy->governor_data = NULL;
......@@ -304,6 +319,12 @@ static int cpufreq_sched_stop(struct cpufreq_policy *policy)
static int cpufreq_sched_setup(struct cpufreq_policy *policy, unsigned int event)
{
switch (event) {
case CPUFREQ_GOV_POLICY_INIT:
return cpufreq_sched_policy_init(policy);
case CPUFREQ_GOV_POLICY_EXIT:
return cpufreq_sched_policy_exit(policy);
case CPUFREQ_GOV_START:
/* Start managing the frequency */
return cpufreq_sched_start(policy);
......@@ -312,8 +333,6 @@ static int cpufreq_sched_setup(struct cpufreq_policy *policy, unsigned int event
return cpufreq_sched_stop(policy);
case CPUFREQ_GOV_LIMITS: /* unused */
case CPUFREQ_GOV_POLICY_INIT: /* unused */
case CPUFREQ_GOV_POLICY_EXIT: /* unused */
break;
}
return 0;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment