cpuidle: (POWER) Replace pseries_notify_cpuidle_add call with a notifier to fix lockdep problem in start_secondary
PATCH v2 1/1 cpuidle: (POWER) Replace pseries_notify_cpuidle_add call with a notifier to fix lockdep problem in start_secondary
cpuidle: (POWER) Replace pseries_notify_cpuidle_add call with a notifier to fix lockdep problem in start_secondary
From: Deepthi Dharwar <[email protected]>
Currently the call to pseries_notify_cpuidle_add(), that takes action on the cpuidle front when a cpu is added/removed is being made from smp_xics_setup_cpu().
This works fine when the cpus were hot added/removed once the system is up but causes lockdep issues as
reported https://lkml.org/lkml/2012/5/17/2
during the time of boot.
During boot, on addition of each cpu,
resources were cleared and re-allocated each time, all in critical section as part of start_secondary() which had interrupts disabled. To resolve this issue, replacing the pseries_notify_cpuidle_add_cpu() call with a hotplug notifier. This would prevent cpuidle resources from being released and allocated each time cpu is onlined during pseries bootup.
---
This patch has in-corporated review comments
received on the earlier version posted.
v1 -> https://lkml.org/lkml/2012/5/18/174 This applies on 3.5-rc5 --- arch/powerpc/include/asm/processor.h | 2 - arch/powerpc/platforms/pseries/processor_idle.c | 35 ++++++++++++++++++++--- arch/powerpc/platforms/pseries/smp.c | 1 - 3 files changed, 30 insertions(+), 8 deletions(-)
arch/powerpc/include/asm/processor.h +0 -2
@@ -389,10 +389,8 @@ extern int powersave_nap; /* set if nap mode can be used in idle loop */#ifdef CONFIG_PSERIES_IDLE extern void update_smt_snooze_delay (int snooze); -extern int pseries_notify_cpuidle_add_cpu (int cpu);#else static inline void update_smt_snooze_delay (int snooze) {} -static inline int pseries_notify_cpuidle_add_cpu (int cpu) {return 0 ; }#endif extern void flush_instruction_cache (void );
arch/powerpc/platforms/pseries/processor_idle.c +30 -5
@@ -186,17 +186,40 @@ static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = { .enter = &shared_cede_loop }, }; -int pseries_notify_cpuidle_add_cpu (int cpu) +static int pseries_cpuidle_add_cpu_notifier (struct notifier_block *n, +unsigned long action,void *hcpu) { +int hotcpu = (unsigned long )hcpu;struct cpuidle_device *dev = -per_cpu_ptr (pseries_cpuidle_devices, cpu); +per_cpu_ptr (pseries_cpuidle_devices, hotcpu); +if (dev &&cpuidle_get_driver ()) { -cpuidle_disable_device (dev); -cpuidle_enable_device (dev); +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 ; + } } -return 0 ; +return NOTIFY_OK ; } +static struct notifier_block setup_hotplug_notifier = { + .notifier_call = pseries_cpuidle_add_cpu_notifier, +}; +/* * pseries_cpuidle_driver_init() */
@@ -321,6 +344,7 @@ static int __init pseries_processor_idle_init(void)return retval; } +register_cpu_notifier (&setup_hotplug_notifier);printk (KERN_DEBUG "pseries_idle_driver registered\n" );return 0 ;
@@ -329,6 +353,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);
arch/powerpc/platforms/pseries/smp.c +0 -1
@@ -147,7 +147,6 @@ static void __devinit smp_xics_setup_cpu(int cpu)set_cpu_current_state (cpu,CPU_STATE_ONLINE );set_default_offline_state (cpu);#endif -pseries_notify_cpuidle_add_cpu (cpu); }static int __devinit smp_pSeries_kick_cpu (int nr)
PATCH v3 1/1 cpuidle: (POWER) Replace pseries_notify_cpuidle_add _cpu call with a notifier to fix lockdep problem in start_secondary
cpuidle: (POWER) Replace pseries_notify_cpuidle_add_cpu call with a notifier to fix lockdep problem in start_secondary
From: Deepthi Dharwar <[email protected]>
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 are cleared and re-allocated each time, all in critical section as part of start_secondary() call which has interrupts disabled.
To resolve this issue, the pseries_notify_cpuidle_add_cpu() call is is now 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.
---
This patch has in-corporated review comments
received on the earlier version posted.
v1 -> https://lkml.org/lkml/2012/5/18/174 v2 -> https://lkml.org/lkml/2012/7/3/61
This applies on 3.5-rc5
arch/powerpc/include/asm/processor.h | 2 - arch/powerpc/platforms/pseries/processor_idle.c | 35 ++++++++++++++++++++--- arch/powerpc/platforms/pseries/smp.c | 1 - 3 files changed, 30 insertions(+), 8 deletions(-)
arch/powerpc/include/asm/processor.h +0 -2
@@ -389,10 +389,8 @@ extern int powersave_nap; /* set if nap mode can be used in idle loop */#ifdef CONFIG_PSERIES_IDLE extern void update_smt_snooze_delay (int snooze); -extern int pseries_notify_cpuidle_add_cpu (int cpu);#else static inline void update_smt_snooze_delay (int snooze) {} -static inline int pseries_notify_cpuidle_add_cpu (int cpu) {return 0 ; }#endif extern void flush_instruction_cache (void );
arch/powerpc/platforms/pseries/processor_idle.c +30 -5
@@ -186,17 +186,40 @@ static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = { .enter = &shared_cede_loop }, }; -int pseries_notify_cpuidle_add_cpu (int cpu) +static int pseries_cpuidle_add_cpu_notifier (struct notifier_block *n, +unsigned long action,void *hcpu) { +int hotcpu = (unsigned long )hcpu;struct cpuidle_device *dev = -per_cpu_ptr (pseries_cpuidle_devices, cpu); +per_cpu_ptr (pseries_cpuidle_devices, hotcpu); +if (dev &&cpuidle_get_driver ()) { -cpuidle_disable_device (dev); -cpuidle_enable_device (dev); +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 ; + } } -return 0 ; +return NOTIFY_OK ; } +static struct notifier_block setup_hotplug_notifier = { + .notifier_call = pseries_cpuidle_add_cpu_notifier, +}; +/* * pseries_cpuidle_driver_init() */
@@ -321,6 +344,7 @@ static int __init pseries_processor_idle_init(void)return retval; } +register_cpu_notifier (&setup_hotplug_notifier);printk (KERN_DEBUG "pseries_idle_driver registered\n" );return 0 ;
@@ -329,6 +353,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);
arch/powerpc/platforms/pseries/smp.c +0 -1
@@ -147,7 +147,6 @@ static void __devinit smp_xics_setup_cpu(int cpu)set_cpu_current_state (cpu,CPU_STATE_ONLINE );set_default_offline_state (cpu);#endif -pseries_notify_cpuidle_add_cpu (cpu); }static int __devinit smp_pSeries_kick_cpu (int nr)
Cheers,
Deepthi
A message that is not in the archive (sent off-list or not yet received): 1341351841.2346.11.camel@pasglop
PATCH 1/1 cpuidle:(POWER) Fixes for pseries_idle hotplug notifier
cpuidle:(POWER) Fixes for pseries_idle hotplug notifier
From: Deepthi Dharwar <[email protected]>
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.
---
This applies on 3.5-rc5.
arch/powerpc/platforms/pseries/processor_idle.c | 23 ++++++++++++++++++----- 1 files changed, 18 insertions(+), 5 deletions(-)
arch/powerpc/platforms/pseries/processor_idle.c +18 -5
@@ -194,13 +194,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 ; }
@@ -342,6 +354,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);
Cheers,
Deepthi