perf/core: Document some hotplug bits
[deliverable/linux.git] / kernel / cpu.c
index e220e565ea9838fc4a9943e56e0270b6b405728c..6ea42e8da861b05077d01a23e15bb140afffa605 100644 (file)
@@ -329,6 +329,14 @@ static int notify_starting(unsigned int cpu)
        return 0;
 }
 
+static int bringup_wait_for_ap(unsigned int cpu)
+{
+       struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
+
+       wait_for_completion(&st->done);
+       return st->result;
+}
+
 static int bringup_cpu(unsigned int cpu)
 {
        struct task_struct *idle = idle_thread_get(cpu);
@@ -340,8 +348,9 @@ static int bringup_cpu(unsigned int cpu)
                cpu_notify(CPU_UP_CANCELED, cpu);
                return ret;
        }
+       ret = bringup_wait_for_ap(cpu);
        BUG_ON(!cpu_online(cpu));
-       return 0;
+       return ret;
 }
 
 /*
@@ -470,7 +479,7 @@ static void cpuhp_thread_fun(unsigned int cpu)
                }
        } else {
                /* Cannot happen .... */
-               BUG_ON(st->state < CPUHP_KICK_AP_THREAD);
+               BUG_ON(st->state < CPUHP_AP_ONLINE_IDLE);
 
                /* Regular hotplug work */
                if (st->state < st->target)
@@ -679,6 +688,7 @@ static int take_cpu_down(void *_param)
 
 static int takedown_cpu(unsigned int cpu)
 {
+       struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
        int err;
 
        /*
@@ -696,8 +706,9 @@ static int takedown_cpu(unsigned int cpu)
        else
                synchronize_rcu();
 
-       /* Park the hotplug thread */
+       /* Park the smpboot threads */
        kthread_park(per_cpu_ptr(&cpuhp_state, cpu)->thread);
+       smpboot_park_threads(cpu);
 
        /*
         * Prevent irq alloc/free while the dying cpu reorganizes the
@@ -724,10 +735,8 @@ static int takedown_cpu(unsigned int cpu)
         *
         * Wait for the stop thread to go away.
         */
-       while (!per_cpu(cpu_dead_idle, cpu))
-               cpu_relax();
-       smp_mb(); /* Read from cpu_dead_idle before __cpu_die(). */
-       per_cpu(cpu_dead_idle, cpu) = false;
+       wait_for_completion(&st->done);
+       BUG_ON(st->state != CPUHP_AP_IDLE_DEAD);
 
        /* Interrupts are moved away from the dying cpu, reenable alloc/free */
        irq_unlock_sparse();
@@ -747,6 +756,28 @@ static int notify_dead(unsigned int cpu)
        return 0;
 }
 
+static void cpuhp_complete_idle_dead(void *arg)
+{
+       struct cpuhp_cpu_state *st = arg;
+
+       complete(&st->done);
+}
+
+void cpuhp_report_idle_dead(void)
+{
+       struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state);
+
+       BUG_ON(st->state != CPUHP_AP_OFFLINE);
+       rcu_report_dead(smp_processor_id());
+       st->state = CPUHP_AP_IDLE_DEAD;
+       /*
+        * We cannot call complete after rcu_report_dead() so we delegate it
+        * to an online cpu.
+        */
+       smp_call_function_single(cpumask_first(cpu_online_mask),
+                                cpuhp_complete_idle_dead, st, 0);
+}
+
 #else
 #define notify_down_prepare    NULL
 #define takedown_cpu           NULL
@@ -780,7 +811,7 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen,
         * If the current CPU state is in the range of the AP hotplug thread,
         * then we need to kick the thread.
         */
-       if (st->state >= CPUHP_KICK_AP_THREAD) {
+       if (st->state > CPUHP_TEARDOWN_CPU) {
                ret = cpuhp_kick_ap_work(cpu);
                /*
                 * The AP side has done the error rollback already. Just
@@ -793,11 +824,11 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen,
                 * We might have stopped still in the range of the AP hotplug
                 * thread. Nothing to do anymore.
                 */
-               if (st->state >= CPUHP_KICK_AP_THREAD)
+               if (st->state > CPUHP_TEARDOWN_CPU)
                        goto out;
        }
        /*
-        * The AP brought itself down below CPUHP_KICK_AP_THREAD. So we need
+        * The AP brought itself down to CPUHP_TEARDOWN_CPU. So we need
         * to do the further cleanups.
         */
        ret = cpuhp_down_callbacks(cpu, st, cpuhp_bp_states, target);
@@ -859,18 +890,32 @@ void notify_cpu_starting(unsigned int cpu)
 
 /*
  * Called from the idle task. We need to set active here, so we can kick off
- * the stopper thread.
+ * the stopper thread and unpark the smpboot threads. If the target state is
+ * beyond CPUHP_AP_ONLINE_IDLE we kick cpuhp thread and let it bring up the
+ * cpu further.
  */
-static int cpuhp_set_cpu_active(unsigned int cpu)
+void cpuhp_online_idle(enum cpuhp_state state)
 {
-       struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
+       struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state);
+       unsigned int cpu = smp_processor_id();
+
+       /* Happens for the boot cpu */
+       if (state != CPUHP_AP_ONLINE_IDLE)
+               return;
+
+       st->state = CPUHP_AP_ONLINE_IDLE;
 
        /* The cpu is marked online, set it active now */
        set_cpu_active(cpu, true);
-       /* Unpark the stopper thread and the hotplug thread */
+       /* Unpark the stopper thread and the hotplug thread of this cpu */
        stop_machine_unpark(cpu);
        kthread_unpark(st->thread);
-       return 0;
+
+       /* Should we go further up ? */
+       if (st->target > CPUHP_AP_ONLINE_IDLE)
+               __cpuhp_kick_ap_work(st);
+       else
+               complete(&st->done);
 }
 
 /* Requires cpu_add_remove_lock to be held */
@@ -910,7 +955,7 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target)
         * If the current CPU state is in the range of the AP hotplug thread,
         * then we need to kick the thread once more.
         */
-       if (st->state >= CPUHP_KICK_AP_THREAD) {
+       if (st->state > CPUHP_BRINGUP_CPU) {
                ret = cpuhp_kick_ap_work(cpu);
                /*
                 * The AP side has done the error rollback already. Just
@@ -922,10 +967,10 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target)
 
        /*
         * Try to reach the target state. We max out on the BP at
-        * CPUHP_KICK_AP_THREAD. After that the AP hotplug thread is
+        * CPUHP_BRINGUP_CPU. After that the AP hotplug thread is
         * responsible for bringing it up to the target state.
         */
-       target = min((int)target, CPUHP_KICK_AP_THREAD);
+       target = min((int)target, CPUHP_BRINGUP_CPU);
        ret = cpuhp_up_callbacks(cpu, st, cpuhp_bp_states, target);
 out:
        cpu_hotplug_done();
@@ -1127,6 +1172,10 @@ static struct cpuhp_step cpuhp_bp_states[] = {
                .teardown               = NULL,
                .cant_stop              = true,
        },
+       /*
+        * Preparatory and dead notifiers. Will be replaced once the notifiers
+        * are converted to states.
+        */
        [CPUHP_NOTIFY_PREPARE] = {
                .name                   = "notify:prepare",
                .startup                = notify_prepare,
@@ -1134,39 +1183,46 @@ static struct cpuhp_step cpuhp_bp_states[] = {
                .skip_onerr             = true,
                .cant_stop              = true,
        },
+       /* Kicks the plugged cpu into life */
        [CPUHP_BRINGUP_CPU] = {
                .name                   = "cpu:bringup",
                .startup                = bringup_cpu,
                .teardown               = NULL,
                .cant_stop              = true,
        },
+       /*
+        * Handled on controll processor until the plugged processor manages
+        * this itself.
+        */
        [CPUHP_TEARDOWN_CPU] = {
                .name                   = "cpu:teardown",
                .startup                = NULL,
                .teardown               = takedown_cpu,
                .cant_stop              = true,
        },
-       [CPUHP_CPU_SET_ACTIVE] = {
-               .name                   = "cpu:active",
-               .startup                = cpuhp_set_cpu_active,
-               .teardown               = NULL,
-       },
-       [CPUHP_KICK_AP_THREAD] = {
-               .name                   = "cpuhp:kickthread",
-               .startup                = cpuhp_kick_ap_work,
-               .teardown               = cpuhp_kick_ap_work,
-       },
 #endif
-       [CPUHP_BP_ONLINE] = {
-               .name                   = "online",
-               .startup                = NULL,
-               .teardown               = NULL,
-       },
 };
 
 /* Application processor state steps */
 static struct cpuhp_step cpuhp_ap_states[] = {
 #ifdef CONFIG_SMP
+       /* Final state before CPU kills itself */
+       [CPUHP_AP_IDLE_DEAD] = {
+               .name                   = "idle:dead",
+       },
+       /*
+        * Last state before CPU enters the idle loop to die. Transient state
+        * for synchronization.
+        */
+       [CPUHP_AP_OFFLINE] = {
+               .name                   = "ap:offline",
+               .cant_stop              = true,
+       },
+       /*
+        * Low level startup/teardown notifiers. Run with interrupts
+        * disabled. Will be removed once the notifiers are converted to
+        * states.
+        */
        [CPUHP_AP_NOTIFY_STARTING] = {
                .name                   = "notify:starting",
                .startup                = notify_starting,
@@ -1174,17 +1230,32 @@ static struct cpuhp_step cpuhp_ap_states[] = {
                .skip_onerr             = true,
                .cant_stop              = true,
        },
+       /* Entry state on starting. Interrupts enabled from here on. Transient
+        * state for synchronsization */
+       [CPUHP_AP_ONLINE] = {
+               .name                   = "ap:online",
+       },
+       /* Handle smpboot threads park/unpark */
        [CPUHP_AP_SMPBOOT_THREADS] = {
                .name                   = "smpboot:threads",
                .startup                = smpboot_unpark_threads,
-               .teardown               = smpboot_park_threads,
+               .teardown               = NULL,
        },
+       /*
+        * Online/down_prepare notifiers. Will be removed once the notifiers
+        * are converted to states.
+        */
        [CPUHP_AP_NOTIFY_ONLINE] = {
                .name                   = "notify:online",
                .startup                = notify_online,
                .teardown               = notify_down_prepare,
        },
 #endif
+       /*
+        * The dynamically registered state space is here
+        */
+
+       /* CPU is fully up and running. */
        [CPUHP_ONLINE] = {
                .name                   = "online",
                .startup                = NULL,
@@ -1202,9 +1273,11 @@ static int cpuhp_cb_check(enum cpuhp_state state)
 
 static bool cpuhp_is_ap_state(enum cpuhp_state state)
 {
-       if (state >= CPUHP_AP_OFFLINE && state <= CPUHP_AP_ONLINE)
-               return true;
-       return state > CPUHP_BP_ONLINE;
+       /*
+        * The extra check for CPUHP_TEARDOWN_CPU is only for documentation
+        * purposes as that state is handled explicitely in cpu_down.
+        */
+       return state > CPUHP_BRINGUP_CPU && state != CPUHP_TEARDOWN_CPU;
 }
 
 static struct cpuhp_step *cpuhp_get_step(enum cpuhp_state state)
This page took 0.048996 seconds and 5 git commands to generate.