Commit 4baa0afc authored by Thomas Gleixner's avatar Thomas Gleixner

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: default avatarThomas 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.deSigned-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent cff7d378
...@@ -6,6 +6,10 @@ enum cpuhp_state { ...@@ -6,6 +6,10 @@ enum cpuhp_state {
CPUHP_CREATE_THREADS, CPUHP_CREATE_THREADS,
CPUHP_NOTIFY_PREPARE, CPUHP_NOTIFY_PREPARE,
CPUHP_BRINGUP_CPU, CPUHP_BRINGUP_CPU,
CPUHP_AP_OFFLINE,
CPUHP_AP_NOTIFY_STARTING,
CPUHP_AP_ONLINE,
CPUHP_TEARDOWN_CPU,
CPUHP_NOTIFY_ONLINE, CPUHP_NOTIFY_ONLINE,
CPUHP_ONLINE, CPUHP_ONLINE,
}; };
......
...@@ -57,6 +57,7 @@ struct cpuhp_step { ...@@ -57,6 +57,7 @@ struct cpuhp_step {
}; };
static struct cpuhp_step cpuhp_bp_states[]; static struct cpuhp_step cpuhp_bp_states[];
static struct cpuhp_step cpuhp_ap_states[];
/** /**
* cpuhp_invoke_callback _ Invoke the callbacks for a given state * cpuhp_invoke_callback _ Invoke the callbacks for a given state
...@@ -304,6 +305,12 @@ static int notify_online(unsigned int cpu) ...@@ -304,6 +305,12 @@ static int notify_online(unsigned int cpu)
return 0; return 0;
} }
static int notify_starting(unsigned int cpu)
{
cpu_notify(CPU_STARTING, cpu);
return 0;
}
static int bringup_cpu(unsigned int cpu) static int bringup_cpu(unsigned int cpu)
{ {
struct task_struct *idle = idle_thread_get(cpu); struct task_struct *idle = idle_thread_get(cpu);
...@@ -421,9 +428,17 @@ static int notify_down_prepare(unsigned int cpu) ...@@ -421,9 +428,17 @@ static int notify_down_prepare(unsigned int cpu)
return err; return err;
} }
static int notify_dying(unsigned int cpu)
{
cpu_notify(CPU_DYING, cpu);
return 0;
}
/* Take this CPU down. */ /* Take this CPU down. */
static int take_cpu_down(void *_param) 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(); int err, cpu = smp_processor_id();
/* Ensure this CPU doesn't handle any more interrupts. */ /* Ensure this CPU doesn't handle any more interrupts. */
...@@ -431,7 +446,12 @@ static int take_cpu_down(void *_param) ...@@ -431,7 +446,12 @@ static int take_cpu_down(void *_param)
if (err < 0) if (err < 0)
return err; 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 */ /* Give up timekeeping duties */
tick_handover_do_timer(); tick_handover_do_timer();
/* Park the stopper thread */ /* Park the stopper thread */
...@@ -512,6 +532,7 @@ static int notify_dead(unsigned int cpu) ...@@ -512,6 +532,7 @@ static int notify_dead(unsigned int cpu)
#define notify_down_prepare NULL #define notify_down_prepare NULL
#define takedown_cpu NULL #define takedown_cpu NULL
#define notify_dead NULL #define notify_dead NULL
#define notify_dying NULL
#endif #endif
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
...@@ -615,6 +636,28 @@ void smpboot_thread_init(void) ...@@ -615,6 +636,28 @@ void smpboot_thread_init(void)
register_cpu_notifier(&smpboot_thread_notifier); 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) static void undo_cpu_up(unsigned int cpu, struct cpuhp_cpu_state *st)
{ {
for (st->state--; st->state > st->target; st->state--) { for (st->state--; st->state > st->target; st->state--) {
...@@ -842,19 +885,6 @@ core_initcall(cpu_hotplug_pm_sync_init); ...@@ -842,19 +885,6 @@ core_initcall(cpu_hotplug_pm_sync_init);
#endif /* CONFIG_PM_SLEEP_SMP */ #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 */ #endif /* CONFIG_SMP */
/* Boot processor state steps */ /* Boot processor state steps */
...@@ -879,8 +909,12 @@ static struct cpuhp_step cpuhp_bp_states[] = { ...@@ -879,8 +909,12 @@ static struct cpuhp_step cpuhp_bp_states[] = {
[CPUHP_BRINGUP_CPU] = { [CPUHP_BRINGUP_CPU] = {
.name = "cpu:bringup", .name = "cpu:bringup",
.startup = bringup_cpu, .startup = bringup_cpu,
.teardown = NULL,
},
[CPUHP_TEARDOWN_CPU] = {
.name = "cpu:teardown",
.startup = NULL,
.teardown = takedown_cpu, .teardown = takedown_cpu,
.skip_onerr = true,
}, },
[CPUHP_NOTIFY_ONLINE] = { [CPUHP_NOTIFY_ONLINE] = {
.name = "notify:online", .name = "notify:online",
...@@ -895,6 +929,23 @@ static struct cpuhp_step cpuhp_bp_states[] = { ...@@ -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 * cpu_bit_bitmap[] is a special, "compressed" data structure that
* represents all NR_CPUS bits binary values of 1<<nr. * represents all NR_CPUS bits binary values of 1<<nr.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment