Skip to content

Commit

Permalink
cpufreq: Avoid cpufreq_suspend() deadlock on system shutdown
Browse files Browse the repository at this point in the history
commit 65650b3 upstream.

It is incorrect to set the cpufreq syscore shutdown callback pointer
to cpufreq_suspend(), because that function cannot be run in the
syscore stage of system shutdown for two reasons: (a) it may attempt
to carry out actions depending on devices that have already been shut
down at that point and (b) the RCU synchronization carried out by it
may not be able to make progress then.

The latter issue has been present since commit 45975c7 ("rcu:
Define RCU-sched API in terms of RCU for Tree RCU PREEMPT builds"),
but the former one has been there since commit 90de2a4 ("cpufreq:
suspend cpufreq governors on shutdown") regardless.

Fix that by dropping cpufreq_syscore_ops altogether and making
device_shutdown() call cpufreq_suspend() directly before shutting
down devices, which is along the lines of what system-wide power
management does.

Fixes: 45975c7 ("rcu: Define RCU-sched API in terms of RCU for Tree RCU PREEMPT builds")
Fixes: 90de2a4 ("cpufreq: suspend cpufreq governors on shutdown")
Reported-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Tested-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Cc: 4.0+ <stable@vger.kernel.org> # 4.0+
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
rafaeljw authored and gregkh committed Oct 29, 2019
1 parent 5f19cbb commit 89ab39d
Show file tree
Hide file tree
Showing 2 changed files with 3 additions and 10 deletions.
3 changes: 3 additions & 0 deletions drivers/base/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* Copyright (c) 2006 Novell, Inc.
*/

#include <linux/cpufreq.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/fwnode.h>
Expand Down Expand Up @@ -2943,6 +2944,8 @@ void device_shutdown(void)
wait_for_device_probe();
device_block_probing();

cpufreq_suspend();

spin_lock(&devices_kset->list_lock);
/*
* Walk the devices list backward, shutting down each in turn.
Expand Down
10 changes: 0 additions & 10 deletions drivers/cpufreq/cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -2578,14 +2578,6 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
}
EXPORT_SYMBOL_GPL(cpufreq_unregister_driver);

/*
* Stop cpufreq at shutdown to make sure it isn't holding any locks
* or mutexes when secondary CPUs are halted.
*/
static struct syscore_ops cpufreq_syscore_ops = {
.shutdown = cpufreq_suspend,
};

struct kobject *cpufreq_global_kobject;
EXPORT_SYMBOL(cpufreq_global_kobject);

Expand All @@ -2597,8 +2589,6 @@ static int __init cpufreq_core_init(void)
cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_subsys.dev_root->kobj);
BUG_ON(!cpufreq_global_kobject);

register_syscore_ops(&cpufreq_syscore_ops);

return 0;
}
module_param(off, int, 0444);
Expand Down

0 comments on commit 89ab39d

Please sign in to comment.