diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 083e99d..832bbdc 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -83,6 +83,7 @@ DEFINE_PER_CPU(int, cpu_state) = { 0 }; * for idle threads. */ #ifdef CONFIG_HOTPLUG_CPU +static struct notifier_block pm_idle_cpu_notifier; /* * Needed only for CONFIG_HOTPLUG_CPU because __cpuinitdata is * removed after init for !CONFIG_HOTPLUG_CPU. @@ -1162,6 +1163,7 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus) uv_system_init(); set_mtrr_aps_delayed_init(); + register_hotcpu_notifier(&pm_idle_cpu_notifier); out: preempt_enable(); } @@ -1469,6 +1471,42 @@ void native_play_dead(void) hlt_play_dead(); } +static void (*pm_idle_saved)(void); + +static inline void save_pm_idle(void) +{ + pm_idle_saved = pm_idle; + pm_idle = default_idle; + cpu_idle_wait(); +} + +static inline void restore_pm_idle(void) +{ + pm_idle = pm_idle_saved; + cpu_idle_wait(); +} + +static int pm_idle_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + switch (action) { + case CPU_UP_PREPARE: + case CPU_DOWN_PREPARE: + save_pm_idle(); + break; + case CPU_ONLINE: + case CPU_UP_CANCELED: + case CPU_DOWN_FAILED: + case CPU_DEAD: + restore_pm_idle(); + break; + } + return NOTIFY_OK; +} +static struct notifier_block __refdata pm_idle_cpu_notifier = { + .notifier_call = pm_idle_callback, +}; + #else /* ... !CONFIG_HOTPLUG_CPU */ int native_cpu_disable(void) {