diff options
author | Deepthi Dharwar <deepthi@linux.vnet.ibm.com> | 2012-07-03 20:07:22 +0000 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-07-11 14:18:35 +1000 |
commit | 852d8cb1ff7cc26e59a4bbb68e230d133b257098 (patch) | |
tree | 54f54d29c7665a83beca7c327588ef0ebb49f5a6 /arch/powerpc | |
parent | 8bf8385b9c3b7f6aaf892eb3141a5af0bbb2027e (diff) |
powerpc/cpuidle: Fixes for pseries_idle hotplug notifier
Currently the call to pseries_notify_cpuidle_add_cpu(), that takes
action on the cpuidle front when a cpu is added/removed
is being made from smp_xics_setup_cpu().
This caused lockdep issues as
reported https://lkml.org/lkml/2012/5/17/2
On addition of each cpu,
resources were cleared and re-allocated each time, all in critical
section as part of start_secondary() call were interrupts are disabled.
To resolve this issue, the pseries_notify_cpuidle_add_cpu() call is
is being replaced by a hotplug notifier which
would prevent cpuidle resources from being
released and allocated each time cpu is onlined in the critical code path.
It was fixed in https://lkml.org/lkml/2012/5/18/174.
Also it is essential to call cpuidle_enable/disable_device
between cpuidle_pause_and_lock() and
cpuidle_resume_and_unlock() when used externally
to avoid race conditions. Add support for CPU_ONLINE_FROZEN
and CPU_DEAD_FROZEN as part of hotplug notify event for
pseries_idle and unregister hotplug notifier
while exiting out. The above mentioned issues
are fixed as part of this patch.
Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/platforms/pseries/processor_idle.c | 23 |
1 files changed, 18 insertions, 5 deletions
diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c index 7f5668b94165..455760b1fe6e 100644 --- a/arch/powerpc/platforms/pseries/processor_idle.c +++ b/arch/powerpc/platforms/pseries/processor_idle.c @@ -197,13 +197,25 @@ static int pseries_cpuidle_add_cpu_notifier(struct notifier_block *n, struct cpuidle_device *dev = per_cpu_ptr(pseries_cpuidle_devices, hotcpu); - switch (action & 0xf) { - case CPU_ONLINE: - if (dev && cpuidle_get_driver()) { - cpuidle_disable_device(dev); + if (dev && cpuidle_get_driver()) { + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + cpuidle_pause_and_lock(); cpuidle_enable_device(dev); + cpuidle_resume_and_unlock(); + break; + + case CPU_DEAD: + case CPU_DEAD_FROZEN: + cpuidle_pause_and_lock(); + cpuidle_disable_device(dev); + cpuidle_resume_and_unlock(); + break; + + default: + return NOTIFY_DONE; } - break; } return NOTIFY_OK; } @@ -345,6 +357,7 @@ static int __init pseries_processor_idle_init(void) static void __exit pseries_processor_idle_exit(void) { + unregister_cpu_notifier(&setup_hotplug_notifier); pseries_idle_devices_uninit(); cpuidle_unregister_driver(&pseries_idle_driver); |