From bc5a0faeadf8614e2b73b919e6f726bcaba67b25 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Fri, 2 Dec 2011 14:12:08 +1100 Subject: [PATCH] intel_idle: disable auto_demotion for hotplugged CPUs auto_demotion_disable is called only for online CPUs. For hotplugged CPUs, we should disable it too. Signed-off-by: Shaohua Li Cc: Len Brown Signed-off-by: Andrew Morton --- drivers/idle/intel_idle.c | 53 ++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index af0b4a5d52f2..38da9f8dadc8 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -297,33 +297,42 @@ static void __setup_broadcast_timer(void *arg) clockevents_notify(reason, &cpu); } -static int setup_broadcast_cpuhp_notify(struct notifier_block *n, +static void auto_demotion_disable(void *dummy) +{ + unsigned long long msr_bits; + + rdmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits); + msr_bits &= ~auto_demotion_disable_flags; + wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits); +} + +static void __intel_idle_notify_handler(void *arg) +{ + if (auto_demotion_disable_flags) + auto_demotion_disable(NULL); + + if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) + __setup_broadcast_timer((void *)true); +} + +static int setup_intelidle_cpuhp_notify(struct notifier_block *n, unsigned long action, void *hcpu) { int hotcpu = (unsigned long)hcpu; switch (action & 0xf) { case CPU_ONLINE: - smp_call_function_single(hotcpu, __setup_broadcast_timer, - (void *)true, 1); + smp_call_function_single(hotcpu, __intel_idle_notify_handler, + NULL, 1); break; } return NOTIFY_OK; } -static struct notifier_block setup_broadcast_notifier = { - .notifier_call = setup_broadcast_cpuhp_notify, +static struct notifier_block setup_intelidle_notifier = { + .notifier_call = setup_intelidle_cpuhp_notify, }; -static void auto_demotion_disable(void *dummy) -{ - unsigned long long msr_bits; - - rdmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits); - msr_bits &= ~auto_demotion_disable_flags; - wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits); -} - /* * intel_idle_probe() */ @@ -393,10 +402,8 @@ static int intel_idle_probe(void) if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */ lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE; - else { + else on_each_cpu(__setup_broadcast_timer, (void *)true, 1); - register_cpu_notifier(&setup_broadcast_notifier); - } pr_debug(PREFIX "v" INTEL_IDLE_VERSION " model 0x%X\n", boot_cpu_data.x86_model); @@ -559,6 +566,10 @@ static int __init intel_idle_init(void) return retval; } + if (auto_demotion_disable_flags || lapic_timer_reliable_states != + LAPIC_TIMER_ALWAYS_RELIABLE) + register_cpu_notifier(&setup_intelidle_notifier); + return 0; } @@ -567,10 +578,12 @@ static void __exit intel_idle_exit(void) intel_idle_cpuidle_devices_uninit(); cpuidle_unregister_driver(&intel_idle_driver); - if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) { + if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) on_each_cpu(__setup_broadcast_timer, (void *)false, 1); - unregister_cpu_notifier(&setup_broadcast_notifier); - } + + if (auto_demotion_disable_flags || lapic_timer_reliable_states != + LAPIC_TIMER_ALWAYS_RELIABLE) + unregister_cpu_notifier(&setup_intelidle_notifier); return; } -- 2.39.5