Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Deepthi Dharwar and committed by
Benjamin Herrenschmidt
852d8cb1 8bf8385b

+18 -5
+18 -5
arch/powerpc/platforms/pseries/processor_idle.c
··· 197 197 struct cpuidle_device *dev = 198 198 per_cpu_ptr(pseries_cpuidle_devices, hotcpu); 199 199 200 - switch (action & 0xf) { 201 - case CPU_ONLINE: 202 - if (dev && cpuidle_get_driver()) { 203 - cpuidle_disable_device(dev); 200 + if (dev && cpuidle_get_driver()) { 201 + switch (action) { 202 + case CPU_ONLINE: 203 + case CPU_ONLINE_FROZEN: 204 + cpuidle_pause_and_lock(); 204 205 cpuidle_enable_device(dev); 206 + cpuidle_resume_and_unlock(); 207 + break; 208 + 209 + case CPU_DEAD: 210 + case CPU_DEAD_FROZEN: 211 + cpuidle_pause_and_lock(); 212 + cpuidle_disable_device(dev); 213 + cpuidle_resume_and_unlock(); 214 + break; 215 + 216 + default: 217 + return NOTIFY_DONE; 205 218 } 206 - break; 207 219 } 208 220 return NOTIFY_OK; 209 221 } ··· 357 345 static void __exit pseries_processor_idle_exit(void) 358 346 { 359 347 348 + unregister_cpu_notifier(&setup_hotplug_notifier); 360 349 pseries_idle_devices_uninit(); 361 350 cpuidle_unregister_driver(&pseries_idle_driver); 362 351