diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2016-02-26 18:43:29 +0000 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2016-03-01 20:36:54 +0100 |
commit | 4baa0afc6719cbf36a1e08551484a641926b3fd1 (patch) | |
tree | cfdfc5dca7ad32022340ac95c31092fc32984000 /kernel/cpu.c | |
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>
Diffstat (limited to 'kernel/cpu.c')
-rw-r--r-- | kernel/cpu.c | 81 |
1 files changed, 66 insertions, 15 deletions
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 { }; static struct cpuhp_step cpuhp_bp_states[]; +static struct cpuhp_step cpuhp_ap_states[]; /** * cpuhp_invoke_callback _ Invoke the callbacks for a given state @@ -304,6 +305,12 @@ static int notify_online(unsigned int cpu) return 0; } +static int notify_starting(unsigned int cpu) +{ + cpu_notify(CPU_STARTING, cpu); + return 0; +} + static int bringup_cpu(unsigned int cpu) { struct task_struct *idle = idle_thread_get(cpu); @@ -421,9 +428,17 @@ static int notify_down_prepare(unsigned int cpu) return err; } +static int notify_dying(unsigned int cpu) +{ + cpu_notify(CPU_DYING, cpu); + return 0; +} + /* Take this CPU down. */ static int take_cpu_down(void *_param) { + struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); + enum cpuhp_state target = max((int)st->target, CPUHP_AP_OFFLINE); int err, cpu = smp_processor_id(); /* Ensure this CPU doesn't handle any more interrupts. */ @@ -431,7 +446,12 @@ static int take_cpu_down(void *_param) if (err < 0) return err; - cpu_notify(CPU_DYING, cpu); + /* Invoke the former CPU_DYING callbacks */ + for (; st->state > target; st->state--) { + struct cpuhp_step *step = cpuhp_ap_states + st->state; + + cpuhp_invoke_callback(cpu, st->state, step->teardown); + } /* Give up timekeeping duties */ tick_handover_do_timer(); /* Park the stopper thread */ @@ -512,6 +532,7 @@ static int notify_dead(unsigned int cpu) #define notify_down_prepare NULL #define takedown_cpu NULL #define notify_dead NULL +#define notify_dying NULL #endif #ifdef CONFIG_HOTPLUG_CPU @@ -615,6 +636,28 @@ void smpboot_thread_init(void) register_cpu_notifier(&smpboot_thread_notifier); } +/** + * notify_cpu_starting(cpu) - call the CPU_STARTING notifiers + * @cpu: cpu that just started + * + * This function calls the cpu_chain notifiers with CPU_STARTING. + * It must be called by the arch code on the new cpu, before the new cpu + * enables interrupts and before the "boot" cpu returns from __cpu_up(). + */ +void notify_cpu_starting(unsigned int cpu) +{ + struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); + enum cpuhp_state target = min((int)st->target, CPUHP_AP_ONLINE); + + while (st->state < target) { + struct cpuhp_step *step; + + st->state++; + step = cpuhp_ap_states + st->state; + cpuhp_invoke_callback(cpu, st->state, step->startup); + } +} + static void undo_cpu_up(unsigned int cpu, struct cpuhp_cpu_state *st) { for (st->state--; st->state > st->target; st->state--) { @@ -842,19 +885,6 @@ core_initcall(cpu_hotplug_pm_sync_init); #endif /* CONFIG_PM_SLEEP_SMP */ -/** - * notify_cpu_starting(cpu) - call the CPU_STARTING notifiers - * @cpu: cpu that just started - * - * This function calls the cpu_chain notifiers with CPU_STARTING. - * It must be called by the arch code on the new cpu, before the new cpu - * enables interrupts and before the "boot" cpu returns from __cpu_up(). - */ -void notify_cpu_starting(unsigned int cpu) -{ - cpu_notify(CPU_STARTING, cpu); -} - #endif /* CONFIG_SMP */ /* Boot processor state steps */ @@ -879,8 +909,12 @@ static struct cpuhp_step cpuhp_bp_states[] = { [CPUHP_BRINGUP_CPU] = { .name = "cpu:bringup", .startup = bringup_cpu, + .teardown = NULL, + }, + [CPUHP_TEARDOWN_CPU] = { + .name = "cpu:teardown", + .startup = NULL, .teardown = takedown_cpu, - .skip_onerr = true, }, [CPUHP_NOTIFY_ONLINE] = { .name = "notify:online", @@ -895,6 +929,23 @@ static struct cpuhp_step cpuhp_bp_states[] = { }, }; +/* Application processor state steps */ +static struct cpuhp_step cpuhp_ap_states[] = { +#ifdef CONFIG_SMP + [CPUHP_AP_NOTIFY_STARTING] = { + .name = "notify:starting", + .startup = notify_starting, + .teardown = notify_dying, + .skip_onerr = true, + }, +#endif + [CPUHP_ONLINE] = { + .name = "online", + .startup = NULL, + .teardown = NULL, + }, +}; + /* * cpu_bit_bitmap[] is a special, "compressed" data structure that * represents all NR_CPUS bits binary values of 1<<nr. |