aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2016-02-26 13:43:29 -0500
committerThomas Gleixner <tglx@linutronix.de>2016-03-01 14:36:54 -0500
commit4baa0afc6719cbf36a1e08551484a641926b3fd1 (patch)
treecfdfc5dca7ad32022340ac95c31092fc32984000
parentcff7d378d3fdbb53db9b6e2578b14855f401cd41 (diff)
cpu/hotplug: Convert the hotplugged cpu work to a state machine
Move the functions which need to run on the hotplugged processor into a state machine array and let the code iterate through these functions. In a later state, this will grow synchronization points between the control processor and the hotplugged processor, so we can move the various architecture implementations of the synchronizations to the core. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: linux-arch@vger.kernel.org Cc: Rik van Riel <riel@redhat.com> Cc: Rafael Wysocki <rafael.j.wysocki@intel.com> Cc: "Srivatsa S. Bhat" <srivatsa@mit.edu> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Arjan van de Ven <arjan@linux.intel.com> Cc: Sebastian Siewior <bigeasy@linutronix.de> Cc: Rusty Russell <rusty@rustcorp.com.au> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Tejun Heo <tj@kernel.org> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Paul McKenney <paulmck@linux.vnet.ibm.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Paul Turner <pjt@google.com> Link: http://lkml.kernel.org/r/20160226182340.770651526@linutronix.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--include/linux/cpuhotplug.h4
-rw-r--r--kernel/cpu.c81
2 files changed, 70 insertions, 15 deletions
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index d55c9e64acd7..d9303cca83d3 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -6,6 +6,10 @@ enum cpuhp_state {
6 CPUHP_CREATE_THREADS, 6 CPUHP_CREATE_THREADS,
7 CPUHP_NOTIFY_PREPARE, 7 CPUHP_NOTIFY_PREPARE,
8 CPUHP_BRINGUP_CPU, 8 CPUHP_BRINGUP_CPU,
9 CPUHP_AP_OFFLINE,
10 CPUHP_AP_NOTIFY_STARTING,
11 CPUHP_AP_ONLINE,
12 CPUHP_TEARDOWN_CPU,
9 CPUHP_NOTIFY_ONLINE, 13 CPUHP_NOTIFY_ONLINE,
10 CPUHP_ONLINE, 14 CPUHP_ONLINE,
11}; 15};
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 301851974b8d..797723e81756 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -57,6 +57,7 @@ struct cpuhp_step {
57}; 57};
58 58
59static struct cpuhp_step cpuhp_bp_states[]; 59static struct cpuhp_step cpuhp_bp_states[];
60static struct cpuhp_step cpuhp_ap_states[];
60 61
61/** 62/**
62 * cpuhp_invoke_callback _ Invoke the callbacks for a given state 63 * cpuhp_invoke_callback _ Invoke the callbacks for a given state
@@ -304,6 +305,12 @@ static int notify_online(unsigned int cpu)
304 return 0; 305 return 0;
305} 306}
306 307
308static int notify_starting(unsigned int cpu)
309{
310 cpu_notify(CPU_STARTING, cpu);
311 return 0;
312}
313
307static int bringup_cpu(unsigned int cpu) 314static int bringup_cpu(unsigned int cpu)
308{ 315{
309 struct task_struct *idle = idle_thread_get(cpu); 316 struct task_struct *idle = idle_thread_get(cpu);
@@ -421,9 +428,17 @@ static int notify_down_prepare(unsigned int cpu)
421 return err; 428 return err;
422} 429}
423 430
431static int notify_dying(unsigned int cpu)
432{
433 cpu_notify(CPU_DYING, cpu);
434 return 0;
435}
436
424/* Take this CPU down. */ 437/* Take this CPU down. */
425static int take_cpu_down(void *_param) 438static int take_cpu_down(void *_param)
426{ 439{
440 struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state);
441 enum cpuhp_state target = max((int)st->target, CPUHP_AP_OFFLINE);
427 int err, cpu = smp_processor_id(); 442 int err, cpu = smp_processor_id();
428 443
429 /* Ensure this CPU doesn't handle any more interrupts. */ 444 /* Ensure this CPU doesn't handle any more interrupts. */
@@ -431,7 +446,12 @@ static int take_cpu_down(void *_param)
431 if (err < 0) 446 if (err < 0)
432 return err; 447 return err;
433 448
434 cpu_notify(CPU_DYING, cpu); 449 /* Invoke the former CPU_DYING callbacks */
450 for (; st->state > target; st->state--) {
451 struct cpuhp_step *step = cpuhp_ap_states + st->state;
452
453 cpuhp_invoke_callback(cpu, st->state, step->teardown);
454 }
435 /* Give up timekeeping duties */ 455 /* Give up timekeeping duties */
436 tick_handover_do_timer(); 456 tick_handover_do_timer();
437 /* Park the stopper thread */ 457 /* Park the stopper thread */
@@ -512,6 +532,7 @@ static int notify_dead(unsigned int cpu)
512#define notify_down_prepare NULL 532#define notify_down_prepare NULL
513#define takedown_cpu NULL 533#define takedown_cpu NULL
514#define notify_dead NULL 534#define notify_dead NULL
535#define notify_dying NULL
515#endif 536#endif
516 537
517#ifdef CONFIG_HOTPLUG_CPU 538#ifdef CONFIG_HOTPLUG_CPU
@@ -615,6 +636,28 @@ void smpboot_thread_init(void)
615 register_cpu_notifier(&smpboot_thread_notifier); 636 register_cpu_notifier(&smpboot_thread_notifier);
616} 637}
617 638
639/**
640 * notify_cpu_starting(cpu) - call the CPU_STARTING notifiers
641 * @cpu: cpu that just started
642 *
643 * This function calls the cpu_chain notifiers with CPU_STARTING.
644 * It must be called by the arch code on the new cpu, before the new cpu
645 * enables interrupts and before the "boot" cpu returns from __cpu_up().
646 */
647void notify_cpu_starting(unsigned int cpu)
648{
649 struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
650 enum cpuhp_state target = min((int)st->target, CPUHP_AP_ONLINE);
651
652 while (st->state < target) {
653 struct cpuhp_step *step;
654
655 st->state++;
656 step = cpuhp_ap_states + st->state;
657 cpuhp_invoke_callback(cpu, st->state, step->startup);
658 }
659}
660
618static void undo_cpu_up(unsigned int cpu, struct cpuhp_cpu_state *st) 661static void undo_cpu_up(unsigned int cpu, struct cpuhp_cpu_state *st)
619{ 662{
620 for (st->state--; st->state > st->target; st->state--) { 663 for (st->state--; st->state > st->target; st->state--) {
@@ -842,19 +885,6 @@ core_initcall(cpu_hotplug_pm_sync_init);
842 885
843#endif /* CONFIG_PM_SLEEP_SMP */ 886#endif /* CONFIG_PM_SLEEP_SMP */
844 887
845/**
846 * notify_cpu_starting(cpu) - call the CPU_STARTING notifiers
847 * @cpu: cpu that just started
848 *
849 * This function calls the cpu_chain notifiers with CPU_STARTING.
850 * It must be called by the arch code on the new cpu, before the new cpu
851 * enables interrupts and before the "boot" cpu returns from __cpu_up().
852 */
853void notify_cpu_starting(unsigned int cpu)
854{
855 cpu_notify(CPU_STARTING, cpu);
856}
857
858#endif /* CONFIG_SMP */ 888#endif /* CONFIG_SMP */
859 889
860/* Boot processor state steps */ 890/* Boot processor state steps */
@@ -879,8 +909,12 @@ static struct cpuhp_step cpuhp_bp_states[] = {
879 [CPUHP_BRINGUP_CPU] = { 909 [CPUHP_BRINGUP_CPU] = {
880 .name = "cpu:bringup", 910 .name = "cpu:bringup",
881 .startup = bringup_cpu, 911 .startup = bringup_cpu,
912 .teardown = NULL,
913 },
914 [CPUHP_TEARDOWN_CPU] = {
915 .name = "cpu:teardown",
916 .startup = NULL,
882 .teardown = takedown_cpu, 917 .teardown = takedown_cpu,
883 .skip_onerr = true,
884 }, 918 },
885 [CPUHP_NOTIFY_ONLINE] = { 919 [CPUHP_NOTIFY_ONLINE] = {
886 .name = "notify:online", 920 .name = "notify:online",
@@ -895,6 +929,23 @@ static struct cpuhp_step cpuhp_bp_states[] = {
895 }, 929 },
896}; 930};
897 931
932/* Application processor state steps */
933static struct cpuhp_step cpuhp_ap_states[] = {
934#ifdef CONFIG_SMP
935 [CPUHP_AP_NOTIFY_STARTING] = {
936 .name = "notify:starting",
937 .startup = notify_starting,
938 .teardown = notify_dying,
939 .skip_onerr = true,
940 },
941#endif
942 [CPUHP_ONLINE] = {
943 .name = "online",
944 .startup = NULL,
945 .teardown = NULL,
946 },
947};
948
898/* 949/*
899 * cpu_bit_bitmap[] is a special, "compressed" data structure that 950 * cpu_bit_bitmap[] is a special, "compressed" data structure that
900 * represents all NR_CPUS bits binary values of 1<<nr. 951 * represents all NR_CPUS bits binary values of 1<<nr.