diff options
| author | Rohit Gupta <rohgup@codeaurora.org> | 2016-12-19 10:44:16 -0800 |
|---|---|---|
| committer | Rohit Gupta <rohgup@codeaurora.org> | 2016-12-19 11:03:43 -0800 |
| commit | d36dd7737c6ebdde116241fb68f3bf48321e4aa0 (patch) | |
| tree | ee164f87fa0c7fcec15e37cd751c0fec8384a174 | |
| parent | a80e267a8c0d61790c3d1d5f7181ebd1be39c438 (diff) | |
cpufreq: Register for hotplug notifier before locking hotplug
If a CPU hotplug operation occurs in parallel while a driver is
registering with the cpufreq framework it can lead to the following
deadlock scenario:
Thread A (cpufreq_register_driver()) Thread B (cpu_down())
get_online_cpus()
|
atomic_inc(&cpu_hotplug.refcount)
cpu_down()
|
mutex_lock(&cpu_add_remove_lock)
|
cpu_hotplug_begin() waits on
cpu_hotplug.refcount to reset
register_cpu_notifier()
|
mutex_lock(&cpu_add_remove_lock)
This happens because the registration for hotplug notifiers happens
inside the hotplug locked section.
This change moves hotplug registration call before get_online_cpus()
to avoid the deadlock.
Change-Id: Ia59a3e2710133d3b3608e49938e746e58af5a6d4
Signed-off-by: Rohit Gupta <rohgup@codeaurora.org>
| -rw-r--r-- | drivers/cpufreq/cpufreq.c | 7 |
1 files changed, 6 insertions, 1 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index d45cf584d23b..5ff82dfd56b3 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2269,6 +2269,9 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb, { unsigned int cpu = (unsigned long)hcpu; + if (!cpufreq_driver) + return NOTIFY_OK; + switch (action & ~CPU_TASKS_FROZEN) { case CPU_ONLINE: cpufreq_online(cpu); @@ -2435,6 +2438,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) pr_debug("trying to register driver %s\n", driver_data->name); + /* Register for hotplug notifers before blocking hotplug. */ + register_hotcpu_notifier(&cpufreq_cpu_notifier); + /* Protect against concurrent CPU online/offline. */ get_online_cpus(); @@ -2466,7 +2472,6 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) goto err_if_unreg; } - register_hotcpu_notifier(&cpufreq_cpu_notifier); pr_info("driver %s up and running\n", driver_data->name); out: |
