Message ID | 10202295.pfq90QWH5T@kreacher (mailing list archive) |
---|---|
State | Mainlined, archived |
Headers | show |
Series | cpufreq: Avoid cpufreq_suspend() deadlock on system shutdown | expand |
On 09-10-19, 01:29, Rafael J. Wysocki wrote: > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > 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 45975c7d21a1 ("rcu: > Define RCU-sched API in terms of RCU for Tree RCU PREEMPT builds"), > but the former one has always been there 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: 45975c7d21a1 ("rcu: Define RCU-sched API in terms of RCU for Tree RCU PREEMPT builds") > 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> > --- > drivers/base/core.c | 3 +++ > drivers/cpufreq/cpufreq.c | 10 ---------- > 2 files changed, 3 insertions(+), 10 deletions(-) Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Index: linux-pm/drivers/cpufreq/cpufreq.c =================================================================== --- linux-pm.orig/drivers/cpufreq/cpufreq.c +++ linux-pm/drivers/cpufreq/cpufreq.c @@ -2737,14 +2737,6 @@ int cpufreq_unregister_driver(struct cpu } 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); @@ -2756,8 +2748,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); Index: linux-pm/drivers/base/core.c =================================================================== --- linux-pm.orig/drivers/base/core.c +++ linux-pm/drivers/base/core.c @@ -9,6 +9,7 @@ */ #include <linux/acpi.h> +#include <linux/cpufreq.h> #include <linux/device.h> #include <linux/err.h> #include <linux/fwnode.h> @@ -3179,6 +3180,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.