diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2016-02-26 13:43:29 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2016-03-01 14:36:54 -0500 |
commit | 4baa0afc6719cbf36a1e08551484a641926b3fd1 (patch) | |
tree | cfdfc5dca7ad32022340ac95c31092fc32984000 | |
parent | cff7d378d3fdbb53db9b6e2578b14855f401cd41 (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.h | 4 | ||||
-rw-r--r-- | kernel/cpu.c | 81 |
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 | ||
59 | static struct cpuhp_step cpuhp_bp_states[]; | 59 | static struct cpuhp_step cpuhp_bp_states[]; |
60 | static 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 | ||
308 | static int notify_starting(unsigned int cpu) | ||
309 | { | ||
310 | cpu_notify(CPU_STARTING, cpu); | ||
311 | return 0; | ||
312 | } | ||
313 | |||
307 | static int bringup_cpu(unsigned int cpu) | 314 | static 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 | ||
431 | static 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. */ |
425 | static int take_cpu_down(void *_param) | 438 | static 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 | */ | ||
647 | void 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 | |||
618 | static void undo_cpu_up(unsigned int cpu, struct cpuhp_cpu_state *st) | 661 | static 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 | */ | ||
853 | void 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 */ | ||
933 | static 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. |