aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/idle
diff options
context:
space:
mode:
authorSrivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>2014-03-10 16:40:30 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-03-20 08:43:46 -0400
commit07494d547e92bde6857522d2a92ff70896aecadb (patch)
tree6b1d929b0a3902c9112217a8cad489521a249ce1 /drivers/idle
parent8daa127f4e857427c66f365f650dda90f459aa54 (diff)
intel-idle: Fix CPU hotplug callback registration
Subsystems that want to register CPU hotplug callbacks, as well as perform initialization for the CPUs that are already online, often do it as shown below: get_online_cpus(); for_each_online_cpu(cpu) init_cpu(cpu); register_cpu_notifier(&foobar_cpu_notifier); put_online_cpus(); This is wrong, since it is prone to ABBA deadlocks involving the cpu_add_remove_lock and the cpu_hotplug.lock (when running concurrently with CPU hotplug operations). Instead, the correct and race-free way of performing the callback registration is: cpu_notifier_register_begin(); for_each_online_cpu(cpu) init_cpu(cpu); /* Note the use of the double underscored version of the API */ __register_cpu_notifier(&foobar_cpu_notifier); cpu_notifier_register_done(); Fix the intel-idle code by using this latter form of callback registration. Cc: Len Brown <lenb@kernel.org> Cc: Ingo Molnar <mingo@kernel.org> Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/idle')
-rw-r--r--drivers/idle/intel_idle.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 8e1939f564f4..51493ed4643b 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -681,14 +681,19 @@ static int __init intel_idle_init(void)
681 if (intel_idle_cpuidle_devices == NULL) 681 if (intel_idle_cpuidle_devices == NULL)
682 return -ENOMEM; 682 return -ENOMEM;
683 683
684 cpu_notifier_register_begin();
685
684 for_each_online_cpu(i) { 686 for_each_online_cpu(i) {
685 retval = intel_idle_cpu_init(i); 687 retval = intel_idle_cpu_init(i);
686 if (retval) { 688 if (retval) {
689 cpu_notifier_register_done();
687 cpuidle_unregister_driver(&intel_idle_driver); 690 cpuidle_unregister_driver(&intel_idle_driver);
688 return retval; 691 return retval;
689 } 692 }
690 } 693 }
691 register_cpu_notifier(&cpu_hotplug_notifier); 694 __register_cpu_notifier(&cpu_hotplug_notifier);
695
696 cpu_notifier_register_done();
692 697
693 return 0; 698 return 0;
694} 699}
@@ -698,10 +703,13 @@ static void __exit intel_idle_exit(void)
698 intel_idle_cpuidle_devices_uninit(); 703 intel_idle_cpuidle_devices_uninit();
699 cpuidle_unregister_driver(&intel_idle_driver); 704 cpuidle_unregister_driver(&intel_idle_driver);
700 705
706 cpu_notifier_register_begin();
701 707
702 if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) 708 if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE)
703 on_each_cpu(__setup_broadcast_timer, (void *)false, 1); 709 on_each_cpu(__setup_broadcast_timer, (void *)false, 1);
704 unregister_cpu_notifier(&cpu_hotplug_notifier); 710 __unregister_cpu_notifier(&cpu_hotplug_notifier);
711
712 cpu_notifier_register_done();
705 713
706 return; 714 return;
707} 715}