11da177e4SLinus Torvalds /* CPU control. 21da177e4SLinus Torvalds * (C) 2001, 2002, 2003, 2004 Rusty Russell 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * This code is licenced under the GPL. 51da177e4SLinus Torvalds */ 61da177e4SLinus Torvalds #include <linux/proc_fs.h> 71da177e4SLinus Torvalds #include <linux/smp.h> 81da177e4SLinus Torvalds #include <linux/init.h> 91da177e4SLinus Torvalds #include <linux/notifier.h> 103f07c014SIngo Molnar #include <linux/sched/signal.h> 11ef8bd77fSIngo Molnar #include <linux/sched/hotplug.h> 1229930025SIngo Molnar #include <linux/sched/task.h> 131da177e4SLinus Torvalds #include <linux/unistd.h> 141da177e4SLinus Torvalds #include <linux/cpu.h> 15cb79295eSAnton Vorontsov #include <linux/oom.h> 16cb79295eSAnton Vorontsov #include <linux/rcupdate.h> 179984de1aSPaul Gortmaker #include <linux/export.h> 18e4cc2f87SAnton Vorontsov #include <linux/bug.h> 191da177e4SLinus Torvalds #include <linux/kthread.h> 201da177e4SLinus Torvalds #include <linux/stop_machine.h> 2181615b62SIngo Molnar #include <linux/mutex.h> 225a0e3ad6STejun Heo #include <linux/gfp.h> 2379cfbdfaSSrivatsa S. Bhat #include <linux/suspend.h> 24a19423b9SGautham R. Shenoy #include <linux/lockdep.h> 25345527b1SPreeti U Murthy #include <linux/tick.h> 26a8994181SThomas Gleixner #include <linux/irq.h> 274cb28cedSThomas Gleixner #include <linux/smpboot.h> 28e6d4989aSRichard Weinberger #include <linux/relay.h> 296731d4f1SSebastian Andrzej Siewior #include <linux/slab.h> 30*fc8dffd3SThomas Gleixner #include <linux/percpu-rwsem.h> 31cff7d378SThomas Gleixner 32bb3632c6STodd E Brandt #include <trace/events/power.h> 33cff7d378SThomas Gleixner #define CREATE_TRACE_POINTS 34cff7d378SThomas Gleixner #include <trace/events/cpuhp.h> 351da177e4SLinus Torvalds 3638498a67SThomas Gleixner #include "smpboot.h" 3738498a67SThomas Gleixner 38cff7d378SThomas Gleixner /** 39cff7d378SThomas Gleixner * cpuhp_cpu_state - Per cpu hotplug state storage 40cff7d378SThomas Gleixner * @state: The current cpu state 41cff7d378SThomas Gleixner * @target: The target state 424cb28cedSThomas Gleixner * @thread: Pointer to the hotplug thread 434cb28cedSThomas Gleixner * @should_run: Thread should execute 443b9d6da6SSebastian Andrzej Siewior * @rollback: Perform a rollback 45a724632cSThomas Gleixner * @single: Single callback invocation 46a724632cSThomas Gleixner * @bringup: Single callback bringup or teardown selector 47a724632cSThomas Gleixner * @cb_state: The state for a single callback (install/uninstall) 484cb28cedSThomas Gleixner * @result: Result of the operation 494cb28cedSThomas Gleixner * @done: Signal completion to the issuer of the task 50cff7d378SThomas Gleixner */ 51cff7d378SThomas Gleixner struct cpuhp_cpu_state { 52cff7d378SThomas Gleixner enum cpuhp_state state; 53cff7d378SThomas Gleixner enum cpuhp_state target; 544cb28cedSThomas Gleixner #ifdef CONFIG_SMP 554cb28cedSThomas Gleixner struct task_struct *thread; 564cb28cedSThomas Gleixner bool should_run; 573b9d6da6SSebastian Andrzej Siewior bool rollback; 58a724632cSThomas Gleixner bool single; 59a724632cSThomas Gleixner bool bringup; 60cf392d10SThomas Gleixner struct hlist_node *node; 614cb28cedSThomas Gleixner enum cpuhp_state cb_state; 624cb28cedSThomas Gleixner int result; 634cb28cedSThomas Gleixner struct completion done; 644cb28cedSThomas Gleixner #endif 65cff7d378SThomas Gleixner }; 66cff7d378SThomas Gleixner 67cff7d378SThomas Gleixner static DEFINE_PER_CPU(struct cpuhp_cpu_state, cpuhp_state); 68cff7d378SThomas Gleixner 69cff7d378SThomas Gleixner /** 70cff7d378SThomas Gleixner * cpuhp_step - Hotplug state machine step 71cff7d378SThomas Gleixner * @name: Name of the step 72cff7d378SThomas Gleixner * @startup: Startup function of the step 73cff7d378SThomas Gleixner * @teardown: Teardown function of the step 74cff7d378SThomas Gleixner * @skip_onerr: Do not invoke the functions on error rollback 75cff7d378SThomas Gleixner * Will go away once the notifiers are gone 76757c989bSThomas Gleixner * @cant_stop: Bringup/teardown can't be stopped at this step 77cff7d378SThomas Gleixner */ 78cff7d378SThomas Gleixner struct cpuhp_step { 79cff7d378SThomas Gleixner const char *name; 80cf392d10SThomas Gleixner union { 813c1627e9SThomas Gleixner int (*single)(unsigned int cpu); 823c1627e9SThomas Gleixner int (*multi)(unsigned int cpu, 83cf392d10SThomas Gleixner struct hlist_node *node); 843c1627e9SThomas Gleixner } startup; 85cf392d10SThomas Gleixner union { 863c1627e9SThomas Gleixner int (*single)(unsigned int cpu); 873c1627e9SThomas Gleixner int (*multi)(unsigned int cpu, 88cf392d10SThomas Gleixner struct hlist_node *node); 893c1627e9SThomas Gleixner } teardown; 90cf392d10SThomas Gleixner struct hlist_head list; 91cff7d378SThomas Gleixner bool skip_onerr; 92757c989bSThomas Gleixner bool cant_stop; 93cf392d10SThomas Gleixner bool multi_instance; 94cff7d378SThomas Gleixner }; 95cff7d378SThomas Gleixner 9698f8cdceSThomas Gleixner static DEFINE_MUTEX(cpuhp_state_mutex); 97cff7d378SThomas Gleixner static struct cpuhp_step cpuhp_bp_states[]; 984baa0afcSThomas Gleixner static struct cpuhp_step cpuhp_ap_states[]; 99cff7d378SThomas Gleixner 100a724632cSThomas Gleixner static bool cpuhp_is_ap_state(enum cpuhp_state state) 101a724632cSThomas Gleixner { 102a724632cSThomas Gleixner /* 103a724632cSThomas Gleixner * The extra check for CPUHP_TEARDOWN_CPU is only for documentation 104a724632cSThomas Gleixner * purposes as that state is handled explicitly in cpu_down. 105a724632cSThomas Gleixner */ 106a724632cSThomas Gleixner return state > CPUHP_BRINGUP_CPU && state != CPUHP_TEARDOWN_CPU; 107a724632cSThomas Gleixner } 108a724632cSThomas Gleixner 109a724632cSThomas Gleixner static struct cpuhp_step *cpuhp_get_step(enum cpuhp_state state) 110a724632cSThomas Gleixner { 111a724632cSThomas Gleixner struct cpuhp_step *sp; 112a724632cSThomas Gleixner 113a724632cSThomas Gleixner sp = cpuhp_is_ap_state(state) ? cpuhp_ap_states : cpuhp_bp_states; 114a724632cSThomas Gleixner return sp + state; 115a724632cSThomas Gleixner } 116a724632cSThomas Gleixner 117cff7d378SThomas Gleixner /** 118cff7d378SThomas Gleixner * cpuhp_invoke_callback _ Invoke the callbacks for a given state 119cff7d378SThomas Gleixner * @cpu: The cpu for which the callback should be invoked 120cff7d378SThomas Gleixner * @step: The step in the state machine 121a724632cSThomas Gleixner * @bringup: True if the bringup callback should be invoked 122cff7d378SThomas Gleixner * 123cf392d10SThomas Gleixner * Called from cpu hotplug and from the state register machinery. 124cff7d378SThomas Gleixner */ 125a724632cSThomas Gleixner static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state, 126cf392d10SThomas Gleixner bool bringup, struct hlist_node *node) 127cff7d378SThomas Gleixner { 128cff7d378SThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 129a724632cSThomas Gleixner struct cpuhp_step *step = cpuhp_get_step(state); 130cf392d10SThomas Gleixner int (*cbm)(unsigned int cpu, struct hlist_node *node); 131cf392d10SThomas Gleixner int (*cb)(unsigned int cpu); 132cf392d10SThomas Gleixner int ret, cnt; 133cff7d378SThomas Gleixner 134cf392d10SThomas Gleixner if (!step->multi_instance) { 1353c1627e9SThomas Gleixner cb = bringup ? step->startup.single : step->teardown.single; 136cf392d10SThomas Gleixner if (!cb) 137cf392d10SThomas Gleixner return 0; 138a724632cSThomas Gleixner trace_cpuhp_enter(cpu, st->target, state, cb); 139cff7d378SThomas Gleixner ret = cb(cpu); 140a724632cSThomas Gleixner trace_cpuhp_exit(cpu, st->state, state, ret); 141cf392d10SThomas Gleixner return ret; 142cf392d10SThomas Gleixner } 1433c1627e9SThomas Gleixner cbm = bringup ? step->startup.multi : step->teardown.multi; 144cf392d10SThomas Gleixner if (!cbm) 145cf392d10SThomas Gleixner return 0; 146cf392d10SThomas Gleixner 147cf392d10SThomas Gleixner /* Single invocation for instance add/remove */ 148cf392d10SThomas Gleixner if (node) { 149cf392d10SThomas Gleixner trace_cpuhp_multi_enter(cpu, st->target, state, cbm, node); 150cf392d10SThomas Gleixner ret = cbm(cpu, node); 151cf392d10SThomas Gleixner trace_cpuhp_exit(cpu, st->state, state, ret); 152cf392d10SThomas Gleixner return ret; 153cf392d10SThomas Gleixner } 154cf392d10SThomas Gleixner 155cf392d10SThomas Gleixner /* State transition. Invoke on all instances */ 156cf392d10SThomas Gleixner cnt = 0; 157cf392d10SThomas Gleixner hlist_for_each(node, &step->list) { 158cf392d10SThomas Gleixner trace_cpuhp_multi_enter(cpu, st->target, state, cbm, node); 159cf392d10SThomas Gleixner ret = cbm(cpu, node); 160cf392d10SThomas Gleixner trace_cpuhp_exit(cpu, st->state, state, ret); 161cf392d10SThomas Gleixner if (ret) 162cf392d10SThomas Gleixner goto err; 163cf392d10SThomas Gleixner cnt++; 164cf392d10SThomas Gleixner } 165cf392d10SThomas Gleixner return 0; 166cf392d10SThomas Gleixner err: 167cf392d10SThomas Gleixner /* Rollback the instances if one failed */ 1683c1627e9SThomas Gleixner cbm = !bringup ? step->startup.multi : step->teardown.multi; 169cf392d10SThomas Gleixner if (!cbm) 170cf392d10SThomas Gleixner return ret; 171cf392d10SThomas Gleixner 172cf392d10SThomas Gleixner hlist_for_each(node, &step->list) { 173cf392d10SThomas Gleixner if (!cnt--) 174cf392d10SThomas Gleixner break; 175cf392d10SThomas Gleixner cbm(cpu, node); 176cff7d378SThomas Gleixner } 177cff7d378SThomas Gleixner return ret; 178cff7d378SThomas Gleixner } 179cff7d378SThomas Gleixner 18098a79d6aSRusty Russell #ifdef CONFIG_SMP 181b3199c02SRusty Russell /* Serializes the updates to cpu_online_mask, cpu_present_mask */ 182aa953877SLinus Torvalds static DEFINE_MUTEX(cpu_add_remove_lock); 183090e77c3SThomas Gleixner bool cpuhp_tasks_frozen; 184090e77c3SThomas Gleixner EXPORT_SYMBOL_GPL(cpuhp_tasks_frozen); 1851da177e4SLinus Torvalds 18679a6cdebSLai Jiangshan /* 18793ae4f97SSrivatsa S. Bhat * The following two APIs (cpu_maps_update_begin/done) must be used when 18893ae4f97SSrivatsa S. Bhat * attempting to serialize the updates to cpu_online_mask & cpu_present_mask. 18979a6cdebSLai Jiangshan */ 19079a6cdebSLai Jiangshan void cpu_maps_update_begin(void) 19179a6cdebSLai Jiangshan { 19279a6cdebSLai Jiangshan mutex_lock(&cpu_add_remove_lock); 19379a6cdebSLai Jiangshan } 19479a6cdebSLai Jiangshan 19579a6cdebSLai Jiangshan void cpu_maps_update_done(void) 19679a6cdebSLai Jiangshan { 19779a6cdebSLai Jiangshan mutex_unlock(&cpu_add_remove_lock); 19879a6cdebSLai Jiangshan } 1991da177e4SLinus Torvalds 200*fc8dffd3SThomas Gleixner /* 201*fc8dffd3SThomas Gleixner * If set, cpu_up and cpu_down will return -EBUSY and do nothing. 202e3920fb4SRafael J. Wysocki * Should always be manipulated under cpu_add_remove_lock 203e3920fb4SRafael J. Wysocki */ 204e3920fb4SRafael J. Wysocki static int cpu_hotplug_disabled; 205e3920fb4SRafael J. Wysocki 20679a6cdebSLai Jiangshan #ifdef CONFIG_HOTPLUG_CPU 20779a6cdebSLai Jiangshan 208*fc8dffd3SThomas Gleixner DEFINE_STATIC_PERCPU_RWSEM(cpu_hotplug_lock); 20962db99f4SPaul E. McKenney 2108f553c49SThomas Gleixner void cpus_read_lock(void) 211a9d9baa1SAshok Raj { 212*fc8dffd3SThomas Gleixner percpu_down_read(&cpu_hotplug_lock); 213a9d9baa1SAshok Raj } 2148f553c49SThomas Gleixner EXPORT_SYMBOL_GPL(cpus_read_lock); 215a9d9baa1SAshok Raj 2168f553c49SThomas Gleixner void cpus_read_unlock(void) 217a9d9baa1SAshok Raj { 218*fc8dffd3SThomas Gleixner percpu_up_read(&cpu_hotplug_lock); 219a9d9baa1SAshok Raj } 2208f553c49SThomas Gleixner EXPORT_SYMBOL_GPL(cpus_read_unlock); 221a9d9baa1SAshok Raj 2228f553c49SThomas Gleixner void cpus_write_lock(void) 223d221938cSGautham R Shenoy { 224*fc8dffd3SThomas Gleixner percpu_down_write(&cpu_hotplug_lock); 225d221938cSGautham R Shenoy } 226d221938cSGautham R Shenoy 2278f553c49SThomas Gleixner void cpus_write_unlock(void) 228d221938cSGautham R Shenoy { 229*fc8dffd3SThomas Gleixner percpu_up_write(&cpu_hotplug_lock); 230*fc8dffd3SThomas Gleixner } 231*fc8dffd3SThomas Gleixner 232*fc8dffd3SThomas Gleixner void lockdep_assert_cpus_held(void) 233*fc8dffd3SThomas Gleixner { 234*fc8dffd3SThomas Gleixner percpu_rwsem_assert_held(&cpu_hotplug_lock); 235d221938cSGautham R Shenoy } 23679a6cdebSLai Jiangshan 23716e53dbfSSrivatsa S. Bhat /* 23816e53dbfSSrivatsa S. Bhat * Wait for currently running CPU hotplug operations to complete (if any) and 23916e53dbfSSrivatsa S. Bhat * disable future CPU hotplug (from sysfs). The 'cpu_add_remove_lock' protects 24016e53dbfSSrivatsa S. Bhat * the 'cpu_hotplug_disabled' flag. The same lock is also acquired by the 24116e53dbfSSrivatsa S. Bhat * hotplug path before performing hotplug operations. So acquiring that lock 24216e53dbfSSrivatsa S. Bhat * guarantees mutual exclusion from any currently running hotplug operations. 24316e53dbfSSrivatsa S. Bhat */ 24416e53dbfSSrivatsa S. Bhat void cpu_hotplug_disable(void) 24516e53dbfSSrivatsa S. Bhat { 24616e53dbfSSrivatsa S. Bhat cpu_maps_update_begin(); 24789af7ba5SVitaly Kuznetsov cpu_hotplug_disabled++; 24816e53dbfSSrivatsa S. Bhat cpu_maps_update_done(); 24916e53dbfSSrivatsa S. Bhat } 25032145c46SVitaly Kuznetsov EXPORT_SYMBOL_GPL(cpu_hotplug_disable); 25116e53dbfSSrivatsa S. Bhat 25201b41159SLianwei Wang static void __cpu_hotplug_enable(void) 25301b41159SLianwei Wang { 25401b41159SLianwei Wang if (WARN_ONCE(!cpu_hotplug_disabled, "Unbalanced cpu hotplug enable\n")) 25501b41159SLianwei Wang return; 25601b41159SLianwei Wang cpu_hotplug_disabled--; 25701b41159SLianwei Wang } 25801b41159SLianwei Wang 25916e53dbfSSrivatsa S. Bhat void cpu_hotplug_enable(void) 26016e53dbfSSrivatsa S. Bhat { 26116e53dbfSSrivatsa S. Bhat cpu_maps_update_begin(); 26201b41159SLianwei Wang __cpu_hotplug_enable(); 26316e53dbfSSrivatsa S. Bhat cpu_maps_update_done(); 26416e53dbfSSrivatsa S. Bhat } 26532145c46SVitaly Kuznetsov EXPORT_SYMBOL_GPL(cpu_hotplug_enable); 266b9d10be7SToshi Kani #endif /* CONFIG_HOTPLUG_CPU */ 26779a6cdebSLai Jiangshan 2688df3e07eSThomas Gleixner static int bringup_wait_for_ap(unsigned int cpu) 2698df3e07eSThomas Gleixner { 2708df3e07eSThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 2718df3e07eSThomas Gleixner 2728df3e07eSThomas Gleixner wait_for_completion(&st->done); 2738df3e07eSThomas Gleixner return st->result; 2748df3e07eSThomas Gleixner } 2758df3e07eSThomas Gleixner 276ba997462SThomas Gleixner static int bringup_cpu(unsigned int cpu) 277ba997462SThomas Gleixner { 278ba997462SThomas Gleixner struct task_struct *idle = idle_thread_get(cpu); 279ba997462SThomas Gleixner int ret; 280ba997462SThomas Gleixner 281aa877175SBoris Ostrovsky /* 282aa877175SBoris Ostrovsky * Some architectures have to walk the irq descriptors to 283aa877175SBoris Ostrovsky * setup the vector space for the cpu which comes online. 284aa877175SBoris Ostrovsky * Prevent irq alloc/free across the bringup. 285aa877175SBoris Ostrovsky */ 286aa877175SBoris Ostrovsky irq_lock_sparse(); 287aa877175SBoris Ostrovsky 288ba997462SThomas Gleixner /* Arch-specific enabling code. */ 289ba997462SThomas Gleixner ret = __cpu_up(cpu, idle); 290aa877175SBoris Ostrovsky irq_unlock_sparse(); 291530e9b76SThomas Gleixner if (ret) 292ba997462SThomas Gleixner return ret; 2938df3e07eSThomas Gleixner ret = bringup_wait_for_ap(cpu); 294ba997462SThomas Gleixner BUG_ON(!cpu_online(cpu)); 2958df3e07eSThomas Gleixner return ret; 296ba997462SThomas Gleixner } 297ba997462SThomas Gleixner 2982e1a3483SThomas Gleixner /* 2992e1a3483SThomas Gleixner * Hotplug state machine related functions 3002e1a3483SThomas Gleixner */ 301a724632cSThomas Gleixner static void undo_cpu_down(unsigned int cpu, struct cpuhp_cpu_state *st) 3022e1a3483SThomas Gleixner { 3032e1a3483SThomas Gleixner for (st->state++; st->state < st->target; st->state++) { 304a724632cSThomas Gleixner struct cpuhp_step *step = cpuhp_get_step(st->state); 3052e1a3483SThomas Gleixner 3062e1a3483SThomas Gleixner if (!step->skip_onerr) 307cf392d10SThomas Gleixner cpuhp_invoke_callback(cpu, st->state, true, NULL); 3082e1a3483SThomas Gleixner } 3092e1a3483SThomas Gleixner } 3102e1a3483SThomas Gleixner 3112e1a3483SThomas Gleixner static int cpuhp_down_callbacks(unsigned int cpu, struct cpuhp_cpu_state *st, 312a724632cSThomas Gleixner enum cpuhp_state target) 3132e1a3483SThomas Gleixner { 3142e1a3483SThomas Gleixner enum cpuhp_state prev_state = st->state; 3152e1a3483SThomas Gleixner int ret = 0; 3162e1a3483SThomas Gleixner 3172e1a3483SThomas Gleixner for (; st->state > target; st->state--) { 318cf392d10SThomas Gleixner ret = cpuhp_invoke_callback(cpu, st->state, false, NULL); 3192e1a3483SThomas Gleixner if (ret) { 3202e1a3483SThomas Gleixner st->target = prev_state; 321a724632cSThomas Gleixner undo_cpu_down(cpu, st); 3222e1a3483SThomas Gleixner break; 3232e1a3483SThomas Gleixner } 3242e1a3483SThomas Gleixner } 3252e1a3483SThomas Gleixner return ret; 3262e1a3483SThomas Gleixner } 3272e1a3483SThomas Gleixner 328a724632cSThomas Gleixner static void undo_cpu_up(unsigned int cpu, struct cpuhp_cpu_state *st) 3292e1a3483SThomas Gleixner { 3302e1a3483SThomas Gleixner for (st->state--; st->state > st->target; st->state--) { 331a724632cSThomas Gleixner struct cpuhp_step *step = cpuhp_get_step(st->state); 3322e1a3483SThomas Gleixner 3332e1a3483SThomas Gleixner if (!step->skip_onerr) 334cf392d10SThomas Gleixner cpuhp_invoke_callback(cpu, st->state, false, NULL); 3352e1a3483SThomas Gleixner } 3362e1a3483SThomas Gleixner } 3372e1a3483SThomas Gleixner 3382e1a3483SThomas Gleixner static int cpuhp_up_callbacks(unsigned int cpu, struct cpuhp_cpu_state *st, 339a724632cSThomas Gleixner enum cpuhp_state target) 3402e1a3483SThomas Gleixner { 3412e1a3483SThomas Gleixner enum cpuhp_state prev_state = st->state; 3422e1a3483SThomas Gleixner int ret = 0; 3432e1a3483SThomas Gleixner 3442e1a3483SThomas Gleixner while (st->state < target) { 3452e1a3483SThomas Gleixner st->state++; 346cf392d10SThomas Gleixner ret = cpuhp_invoke_callback(cpu, st->state, true, NULL); 3472e1a3483SThomas Gleixner if (ret) { 3482e1a3483SThomas Gleixner st->target = prev_state; 349a724632cSThomas Gleixner undo_cpu_up(cpu, st); 3502e1a3483SThomas Gleixner break; 3512e1a3483SThomas Gleixner } 3522e1a3483SThomas Gleixner } 3532e1a3483SThomas Gleixner return ret; 3542e1a3483SThomas Gleixner } 3552e1a3483SThomas Gleixner 3564cb28cedSThomas Gleixner /* 3574cb28cedSThomas Gleixner * The cpu hotplug threads manage the bringup and teardown of the cpus 3584cb28cedSThomas Gleixner */ 3594cb28cedSThomas Gleixner static void cpuhp_create(unsigned int cpu) 3604cb28cedSThomas Gleixner { 3614cb28cedSThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 3624cb28cedSThomas Gleixner 3634cb28cedSThomas Gleixner init_completion(&st->done); 3644cb28cedSThomas Gleixner } 3654cb28cedSThomas Gleixner 3664cb28cedSThomas Gleixner static int cpuhp_should_run(unsigned int cpu) 3674cb28cedSThomas Gleixner { 3684cb28cedSThomas Gleixner struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); 3694cb28cedSThomas Gleixner 3704cb28cedSThomas Gleixner return st->should_run; 3714cb28cedSThomas Gleixner } 3724cb28cedSThomas Gleixner 3734cb28cedSThomas Gleixner /* Execute the teardown callbacks. Used to be CPU_DOWN_PREPARE */ 3744cb28cedSThomas Gleixner static int cpuhp_ap_offline(unsigned int cpu, struct cpuhp_cpu_state *st) 3754cb28cedSThomas Gleixner { 3761cf4f629SThomas Gleixner enum cpuhp_state target = max((int)st->target, CPUHP_TEARDOWN_CPU); 3774cb28cedSThomas Gleixner 378a724632cSThomas Gleixner return cpuhp_down_callbacks(cpu, st, target); 3794cb28cedSThomas Gleixner } 3804cb28cedSThomas Gleixner 3814cb28cedSThomas Gleixner /* Execute the online startup callbacks. Used to be CPU_ONLINE */ 3824cb28cedSThomas Gleixner static int cpuhp_ap_online(unsigned int cpu, struct cpuhp_cpu_state *st) 3834cb28cedSThomas Gleixner { 384a724632cSThomas Gleixner return cpuhp_up_callbacks(cpu, st, st->target); 3854cb28cedSThomas Gleixner } 3864cb28cedSThomas Gleixner 3874cb28cedSThomas Gleixner /* 3884cb28cedSThomas Gleixner * Execute teardown/startup callbacks on the plugged cpu. Also used to invoke 3894cb28cedSThomas Gleixner * callbacks when a state gets [un]installed at runtime. 3904cb28cedSThomas Gleixner */ 3914cb28cedSThomas Gleixner static void cpuhp_thread_fun(unsigned int cpu) 3924cb28cedSThomas Gleixner { 3934cb28cedSThomas Gleixner struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); 3944cb28cedSThomas Gleixner int ret = 0; 3954cb28cedSThomas Gleixner 3964cb28cedSThomas Gleixner /* 3974cb28cedSThomas Gleixner * Paired with the mb() in cpuhp_kick_ap_work and 3984cb28cedSThomas Gleixner * cpuhp_invoke_ap_callback, so the work set is consistent visible. 3994cb28cedSThomas Gleixner */ 4004cb28cedSThomas Gleixner smp_mb(); 4014cb28cedSThomas Gleixner if (!st->should_run) 4024cb28cedSThomas Gleixner return; 4034cb28cedSThomas Gleixner 4044cb28cedSThomas Gleixner st->should_run = false; 4054cb28cedSThomas Gleixner 4064cb28cedSThomas Gleixner /* Single callback invocation for [un]install ? */ 407a724632cSThomas Gleixner if (st->single) { 4084cb28cedSThomas Gleixner if (st->cb_state < CPUHP_AP_ONLINE) { 4094cb28cedSThomas Gleixner local_irq_disable(); 410a724632cSThomas Gleixner ret = cpuhp_invoke_callback(cpu, st->cb_state, 411cf392d10SThomas Gleixner st->bringup, st->node); 4124cb28cedSThomas Gleixner local_irq_enable(); 4134cb28cedSThomas Gleixner } else { 414a724632cSThomas Gleixner ret = cpuhp_invoke_callback(cpu, st->cb_state, 415cf392d10SThomas Gleixner st->bringup, st->node); 4164cb28cedSThomas Gleixner } 4173b9d6da6SSebastian Andrzej Siewior } else if (st->rollback) { 4183b9d6da6SSebastian Andrzej Siewior BUG_ON(st->state < CPUHP_AP_ONLINE_IDLE); 4193b9d6da6SSebastian Andrzej Siewior 420a724632cSThomas Gleixner undo_cpu_down(cpu, st); 4213b9d6da6SSebastian Andrzej Siewior st->rollback = false; 4224cb28cedSThomas Gleixner } else { 4231cf4f629SThomas Gleixner /* Cannot happen .... */ 4248df3e07eSThomas Gleixner BUG_ON(st->state < CPUHP_AP_ONLINE_IDLE); 4251cf4f629SThomas Gleixner 4264cb28cedSThomas Gleixner /* Regular hotplug work */ 4274cb28cedSThomas Gleixner if (st->state < st->target) 4284cb28cedSThomas Gleixner ret = cpuhp_ap_online(cpu, st); 4294cb28cedSThomas Gleixner else if (st->state > st->target) 4304cb28cedSThomas Gleixner ret = cpuhp_ap_offline(cpu, st); 4314cb28cedSThomas Gleixner } 4324cb28cedSThomas Gleixner st->result = ret; 4334cb28cedSThomas Gleixner complete(&st->done); 4344cb28cedSThomas Gleixner } 4354cb28cedSThomas Gleixner 4364cb28cedSThomas Gleixner /* Invoke a single callback on a remote cpu */ 437a724632cSThomas Gleixner static int 438cf392d10SThomas Gleixner cpuhp_invoke_ap_callback(int cpu, enum cpuhp_state state, bool bringup, 439cf392d10SThomas Gleixner struct hlist_node *node) 4404cb28cedSThomas Gleixner { 4414cb28cedSThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 4424cb28cedSThomas Gleixner 4434cb28cedSThomas Gleixner if (!cpu_online(cpu)) 4444cb28cedSThomas Gleixner return 0; 4454cb28cedSThomas Gleixner 4466a4e2451SThomas Gleixner /* 4476a4e2451SThomas Gleixner * If we are up and running, use the hotplug thread. For early calls 4486a4e2451SThomas Gleixner * we invoke the thread function directly. 4496a4e2451SThomas Gleixner */ 4506a4e2451SThomas Gleixner if (!st->thread) 451cf392d10SThomas Gleixner return cpuhp_invoke_callback(cpu, state, bringup, node); 4526a4e2451SThomas Gleixner 4534cb28cedSThomas Gleixner st->cb_state = state; 454a724632cSThomas Gleixner st->single = true; 455a724632cSThomas Gleixner st->bringup = bringup; 456cf392d10SThomas Gleixner st->node = node; 457a724632cSThomas Gleixner 4584cb28cedSThomas Gleixner /* 4594cb28cedSThomas Gleixner * Make sure the above stores are visible before should_run becomes 4604cb28cedSThomas Gleixner * true. Paired with the mb() above in cpuhp_thread_fun() 4614cb28cedSThomas Gleixner */ 4624cb28cedSThomas Gleixner smp_mb(); 4634cb28cedSThomas Gleixner st->should_run = true; 4644cb28cedSThomas Gleixner wake_up_process(st->thread); 4654cb28cedSThomas Gleixner wait_for_completion(&st->done); 4664cb28cedSThomas Gleixner return st->result; 4674cb28cedSThomas Gleixner } 4684cb28cedSThomas Gleixner 4694cb28cedSThomas Gleixner /* Regular hotplug invocation of the AP hotplug thread */ 4701cf4f629SThomas Gleixner static void __cpuhp_kick_ap_work(struct cpuhp_cpu_state *st) 4714cb28cedSThomas Gleixner { 4724cb28cedSThomas Gleixner st->result = 0; 473a724632cSThomas Gleixner st->single = false; 4744cb28cedSThomas Gleixner /* 4754cb28cedSThomas Gleixner * Make sure the above stores are visible before should_run becomes 4764cb28cedSThomas Gleixner * true. Paired with the mb() above in cpuhp_thread_fun() 4774cb28cedSThomas Gleixner */ 4784cb28cedSThomas Gleixner smp_mb(); 4794cb28cedSThomas Gleixner st->should_run = true; 4804cb28cedSThomas Gleixner wake_up_process(st->thread); 4811cf4f629SThomas Gleixner } 4821cf4f629SThomas Gleixner 4831cf4f629SThomas Gleixner static int cpuhp_kick_ap_work(unsigned int cpu) 4841cf4f629SThomas Gleixner { 4851cf4f629SThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 4861cf4f629SThomas Gleixner enum cpuhp_state state = st->state; 4871cf4f629SThomas Gleixner 4881cf4f629SThomas Gleixner trace_cpuhp_enter(cpu, st->target, state, cpuhp_kick_ap_work); 4891cf4f629SThomas Gleixner __cpuhp_kick_ap_work(st); 4904cb28cedSThomas Gleixner wait_for_completion(&st->done); 4914cb28cedSThomas Gleixner trace_cpuhp_exit(cpu, st->state, state, st->result); 4924cb28cedSThomas Gleixner return st->result; 4934cb28cedSThomas Gleixner } 4944cb28cedSThomas Gleixner 4954cb28cedSThomas Gleixner static struct smp_hotplug_thread cpuhp_threads = { 4964cb28cedSThomas Gleixner .store = &cpuhp_state.thread, 4974cb28cedSThomas Gleixner .create = &cpuhp_create, 4984cb28cedSThomas Gleixner .thread_should_run = cpuhp_should_run, 4994cb28cedSThomas Gleixner .thread_fn = cpuhp_thread_fun, 5004cb28cedSThomas Gleixner .thread_comm = "cpuhp/%u", 5014cb28cedSThomas Gleixner .selfparking = true, 5024cb28cedSThomas Gleixner }; 5034cb28cedSThomas Gleixner 5044cb28cedSThomas Gleixner void __init cpuhp_threads_init(void) 5054cb28cedSThomas Gleixner { 5064cb28cedSThomas Gleixner BUG_ON(smpboot_register_percpu_thread(&cpuhp_threads)); 5074cb28cedSThomas Gleixner kthread_unpark(this_cpu_read(cpuhp_state.thread)); 5084cb28cedSThomas Gleixner } 5094cb28cedSThomas Gleixner 510777c6e0dSMichal Hocko #ifdef CONFIG_HOTPLUG_CPU 511e4cc2f87SAnton Vorontsov /** 512e4cc2f87SAnton Vorontsov * clear_tasks_mm_cpumask - Safely clear tasks' mm_cpumask for a CPU 513e4cc2f87SAnton Vorontsov * @cpu: a CPU id 514e4cc2f87SAnton Vorontsov * 515e4cc2f87SAnton Vorontsov * This function walks all processes, finds a valid mm struct for each one and 516e4cc2f87SAnton Vorontsov * then clears a corresponding bit in mm's cpumask. While this all sounds 517e4cc2f87SAnton Vorontsov * trivial, there are various non-obvious corner cases, which this function 518e4cc2f87SAnton Vorontsov * tries to solve in a safe manner. 519e4cc2f87SAnton Vorontsov * 520e4cc2f87SAnton Vorontsov * Also note that the function uses a somewhat relaxed locking scheme, so it may 521e4cc2f87SAnton Vorontsov * be called only for an already offlined CPU. 522e4cc2f87SAnton Vorontsov */ 523cb79295eSAnton Vorontsov void clear_tasks_mm_cpumask(int cpu) 524cb79295eSAnton Vorontsov { 525cb79295eSAnton Vorontsov struct task_struct *p; 526cb79295eSAnton Vorontsov 527cb79295eSAnton Vorontsov /* 528cb79295eSAnton Vorontsov * This function is called after the cpu is taken down and marked 529cb79295eSAnton Vorontsov * offline, so its not like new tasks will ever get this cpu set in 530cb79295eSAnton Vorontsov * their mm mask. -- Peter Zijlstra 531cb79295eSAnton Vorontsov * Thus, we may use rcu_read_lock() here, instead of grabbing 532cb79295eSAnton Vorontsov * full-fledged tasklist_lock. 533cb79295eSAnton Vorontsov */ 534e4cc2f87SAnton Vorontsov WARN_ON(cpu_online(cpu)); 535cb79295eSAnton Vorontsov rcu_read_lock(); 536cb79295eSAnton Vorontsov for_each_process(p) { 537cb79295eSAnton Vorontsov struct task_struct *t; 538cb79295eSAnton Vorontsov 539e4cc2f87SAnton Vorontsov /* 540e4cc2f87SAnton Vorontsov * Main thread might exit, but other threads may still have 541e4cc2f87SAnton Vorontsov * a valid mm. Find one. 542e4cc2f87SAnton Vorontsov */ 543cb79295eSAnton Vorontsov t = find_lock_task_mm(p); 544cb79295eSAnton Vorontsov if (!t) 545cb79295eSAnton Vorontsov continue; 546cb79295eSAnton Vorontsov cpumask_clear_cpu(cpu, mm_cpumask(t->mm)); 547cb79295eSAnton Vorontsov task_unlock(t); 548cb79295eSAnton Vorontsov } 549cb79295eSAnton Vorontsov rcu_read_unlock(); 550cb79295eSAnton Vorontsov } 551cb79295eSAnton Vorontsov 552b728ca06SKirill Tkhai static inline void check_for_tasks(int dead_cpu) 5531da177e4SLinus Torvalds { 554b728ca06SKirill Tkhai struct task_struct *g, *p; 5551da177e4SLinus Torvalds 556a75a6068SOleg Nesterov read_lock(&tasklist_lock); 557a75a6068SOleg Nesterov for_each_process_thread(g, p) { 558b728ca06SKirill Tkhai if (!p->on_rq) 559b728ca06SKirill Tkhai continue; 560b728ca06SKirill Tkhai /* 561b728ca06SKirill Tkhai * We do the check with unlocked task_rq(p)->lock. 562b728ca06SKirill Tkhai * Order the reading to do not warn about a task, 563b728ca06SKirill Tkhai * which was running on this cpu in the past, and 564b728ca06SKirill Tkhai * it's just been woken on another cpu. 565b728ca06SKirill Tkhai */ 566b728ca06SKirill Tkhai rmb(); 567b728ca06SKirill Tkhai if (task_cpu(p) != dead_cpu) 568b728ca06SKirill Tkhai continue; 569b728ca06SKirill Tkhai 57084117da5SFabian Frederick pr_warn("Task %s (pid=%d) is on cpu %d (state=%ld, flags=%x)\n", 571b728ca06SKirill Tkhai p->comm, task_pid_nr(p), dead_cpu, p->state, p->flags); 572a75a6068SOleg Nesterov } 573a75a6068SOleg Nesterov read_unlock(&tasklist_lock); 5741da177e4SLinus Torvalds } 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds /* Take this CPU down. */ 57771cf5aeeSMathias Krause static int take_cpu_down(void *_param) 5781da177e4SLinus Torvalds { 5794baa0afcSThomas Gleixner struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); 5804baa0afcSThomas Gleixner enum cpuhp_state target = max((int)st->target, CPUHP_AP_OFFLINE); 581090e77c3SThomas Gleixner int err, cpu = smp_processor_id(); 5821da177e4SLinus Torvalds 5831da177e4SLinus Torvalds /* Ensure this CPU doesn't handle any more interrupts. */ 5841da177e4SLinus Torvalds err = __cpu_disable(); 5851da177e4SLinus Torvalds if (err < 0) 586f3705136SZwane Mwaikambo return err; 587f3705136SZwane Mwaikambo 588a724632cSThomas Gleixner /* 589a724632cSThomas Gleixner * We get here while we are in CPUHP_TEARDOWN_CPU state and we must not 590a724632cSThomas Gleixner * do this step again. 591a724632cSThomas Gleixner */ 592a724632cSThomas Gleixner WARN_ON(st->state != CPUHP_TEARDOWN_CPU); 593a724632cSThomas Gleixner st->state--; 5944baa0afcSThomas Gleixner /* Invoke the former CPU_DYING callbacks */ 595a724632cSThomas Gleixner for (; st->state > target; st->state--) 596cf392d10SThomas Gleixner cpuhp_invoke_callback(cpu, st->state, false, NULL); 5974baa0afcSThomas Gleixner 59852c063d1SThomas Gleixner /* Give up timekeeping duties */ 59952c063d1SThomas Gleixner tick_handover_do_timer(); 60014e568e7SThomas Gleixner /* Park the stopper thread */ 601090e77c3SThomas Gleixner stop_machine_park(cpu); 602f3705136SZwane Mwaikambo return 0; 6031da177e4SLinus Torvalds } 6041da177e4SLinus Torvalds 60598458172SThomas Gleixner static int takedown_cpu(unsigned int cpu) 6061da177e4SLinus Torvalds { 607e69aab13SThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 60898458172SThomas Gleixner int err; 6091da177e4SLinus Torvalds 6102a58c527SThomas Gleixner /* Park the smpboot threads */ 6111cf4f629SThomas Gleixner kthread_park(per_cpu_ptr(&cpuhp_state, cpu)->thread); 6122a58c527SThomas Gleixner smpboot_park_threads(cpu); 6131cf4f629SThomas Gleixner 6146acce3efSPeter Zijlstra /* 615a8994181SThomas Gleixner * Prevent irq alloc/free while the dying cpu reorganizes the 616a8994181SThomas Gleixner * interrupt affinities. 617a8994181SThomas Gleixner */ 618a8994181SThomas Gleixner irq_lock_sparse(); 619a8994181SThomas Gleixner 620a8994181SThomas Gleixner /* 6216acce3efSPeter Zijlstra * So now all preempt/rcu users must observe !cpu_active(). 6226acce3efSPeter Zijlstra */ 623210e2133SSebastian Andrzej Siewior err = stop_machine_cpuslocked(take_cpu_down, NULL, cpumask_of(cpu)); 62404321587SRusty Russell if (err) { 6253b9d6da6SSebastian Andrzej Siewior /* CPU refused to die */ 626a8994181SThomas Gleixner irq_unlock_sparse(); 6273b9d6da6SSebastian Andrzej Siewior /* Unpark the hotplug thread so we can rollback there */ 6283b9d6da6SSebastian Andrzej Siewior kthread_unpark(per_cpu_ptr(&cpuhp_state, cpu)->thread); 62998458172SThomas Gleixner return err; 6301da177e4SLinus Torvalds } 63104321587SRusty Russell BUG_ON(cpu_online(cpu)); 6321da177e4SLinus Torvalds 63348c5ccaeSPeter Zijlstra /* 634ee1e714bSThomas Gleixner * The CPUHP_AP_SCHED_MIGRATE_DYING callback will have removed all 63548c5ccaeSPeter Zijlstra * runnable tasks from the cpu, there's only the idle task left now 63648c5ccaeSPeter Zijlstra * that the migration thread is done doing the stop_machine thing. 63751a96c77SPeter Zijlstra * 63851a96c77SPeter Zijlstra * Wait for the stop thread to go away. 63948c5ccaeSPeter Zijlstra */ 640e69aab13SThomas Gleixner wait_for_completion(&st->done); 641e69aab13SThomas Gleixner BUG_ON(st->state != CPUHP_AP_IDLE_DEAD); 6421da177e4SLinus Torvalds 643a8994181SThomas Gleixner /* Interrupts are moved away from the dying cpu, reenable alloc/free */ 644a8994181SThomas Gleixner irq_unlock_sparse(); 645a8994181SThomas Gleixner 646345527b1SPreeti U Murthy hotplug_cpu__broadcast_tick_pull(cpu); 6471da177e4SLinus Torvalds /* This actually kills the CPU. */ 6481da177e4SLinus Torvalds __cpu_die(cpu); 6491da177e4SLinus Torvalds 650a49b116dSThomas Gleixner tick_cleanup_dead_cpu(cpu); 65198458172SThomas Gleixner return 0; 65298458172SThomas Gleixner } 6531da177e4SLinus Torvalds 65471f87b2fSThomas Gleixner static void cpuhp_complete_idle_dead(void *arg) 65571f87b2fSThomas Gleixner { 65671f87b2fSThomas Gleixner struct cpuhp_cpu_state *st = arg; 65771f87b2fSThomas Gleixner 65871f87b2fSThomas Gleixner complete(&st->done); 65971f87b2fSThomas Gleixner } 66071f87b2fSThomas Gleixner 661e69aab13SThomas Gleixner void cpuhp_report_idle_dead(void) 662e69aab13SThomas Gleixner { 663e69aab13SThomas Gleixner struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); 664e69aab13SThomas Gleixner 665e69aab13SThomas Gleixner BUG_ON(st->state != CPUHP_AP_OFFLINE); 66627d50c7eSThomas Gleixner rcu_report_dead(smp_processor_id()); 66771f87b2fSThomas Gleixner st->state = CPUHP_AP_IDLE_DEAD; 66871f87b2fSThomas Gleixner /* 66971f87b2fSThomas Gleixner * We cannot call complete after rcu_report_dead() so we delegate it 67071f87b2fSThomas Gleixner * to an online cpu. 67171f87b2fSThomas Gleixner */ 67271f87b2fSThomas Gleixner smp_call_function_single(cpumask_first(cpu_online_mask), 67371f87b2fSThomas Gleixner cpuhp_complete_idle_dead, st, 0); 674e69aab13SThomas Gleixner } 675e69aab13SThomas Gleixner 676cff7d378SThomas Gleixner #else 677cff7d378SThomas Gleixner #define takedown_cpu NULL 678cff7d378SThomas Gleixner #endif 679cff7d378SThomas Gleixner 680cff7d378SThomas Gleixner #ifdef CONFIG_HOTPLUG_CPU 681cff7d378SThomas Gleixner 68298458172SThomas Gleixner /* Requires cpu_add_remove_lock to be held */ 683af1f4045SThomas Gleixner static int __ref _cpu_down(unsigned int cpu, int tasks_frozen, 684af1f4045SThomas Gleixner enum cpuhp_state target) 68598458172SThomas Gleixner { 686cff7d378SThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 687cff7d378SThomas Gleixner int prev_state, ret = 0; 68898458172SThomas Gleixner 68998458172SThomas Gleixner if (num_online_cpus() == 1) 69098458172SThomas Gleixner return -EBUSY; 69198458172SThomas Gleixner 692757c989bSThomas Gleixner if (!cpu_present(cpu)) 69398458172SThomas Gleixner return -EINVAL; 69498458172SThomas Gleixner 6958f553c49SThomas Gleixner cpus_write_lock(); 69698458172SThomas Gleixner 69798458172SThomas Gleixner cpuhp_tasks_frozen = tasks_frozen; 69898458172SThomas Gleixner 699cff7d378SThomas Gleixner prev_state = st->state; 700af1f4045SThomas Gleixner st->target = target; 7011cf4f629SThomas Gleixner /* 7021cf4f629SThomas Gleixner * If the current CPU state is in the range of the AP hotplug thread, 7031cf4f629SThomas Gleixner * then we need to kick the thread. 7041cf4f629SThomas Gleixner */ 7058df3e07eSThomas Gleixner if (st->state > CPUHP_TEARDOWN_CPU) { 7061cf4f629SThomas Gleixner ret = cpuhp_kick_ap_work(cpu); 7071cf4f629SThomas Gleixner /* 7081cf4f629SThomas Gleixner * The AP side has done the error rollback already. Just 7091cf4f629SThomas Gleixner * return the error code.. 7101cf4f629SThomas Gleixner */ 7111cf4f629SThomas Gleixner if (ret) 7121cf4f629SThomas Gleixner goto out; 7131cf4f629SThomas Gleixner 7141cf4f629SThomas Gleixner /* 7151cf4f629SThomas Gleixner * We might have stopped still in the range of the AP hotplug 7161cf4f629SThomas Gleixner * thread. Nothing to do anymore. 7171cf4f629SThomas Gleixner */ 7188df3e07eSThomas Gleixner if (st->state > CPUHP_TEARDOWN_CPU) 7191cf4f629SThomas Gleixner goto out; 7201cf4f629SThomas Gleixner } 7211cf4f629SThomas Gleixner /* 7228df3e07eSThomas Gleixner * The AP brought itself down to CPUHP_TEARDOWN_CPU. So we need 7231cf4f629SThomas Gleixner * to do the further cleanups. 7241cf4f629SThomas Gleixner */ 725a724632cSThomas Gleixner ret = cpuhp_down_callbacks(cpu, st, target); 7263b9d6da6SSebastian Andrzej Siewior if (ret && st->state > CPUHP_TEARDOWN_CPU && st->state < prev_state) { 7273b9d6da6SSebastian Andrzej Siewior st->target = prev_state; 7283b9d6da6SSebastian Andrzej Siewior st->rollback = true; 7293b9d6da6SSebastian Andrzej Siewior cpuhp_kick_ap_work(cpu); 7303b9d6da6SSebastian Andrzej Siewior } 73198458172SThomas Gleixner 7321cf4f629SThomas Gleixner out: 7338f553c49SThomas Gleixner cpus_write_unlock(); 734cff7d378SThomas Gleixner return ret; 735e3920fb4SRafael J. Wysocki } 736e3920fb4SRafael J. Wysocki 737af1f4045SThomas Gleixner static int do_cpu_down(unsigned int cpu, enum cpuhp_state target) 738e3920fb4SRafael J. Wysocki { 7399ea09af3SHeiko Carstens int err; 740e3920fb4SRafael J. Wysocki 741d221938cSGautham R Shenoy cpu_maps_update_begin(); 742e761b772SMax Krasnyansky 743e761b772SMax Krasnyansky if (cpu_hotplug_disabled) { 744e3920fb4SRafael J. Wysocki err = -EBUSY; 745e761b772SMax Krasnyansky goto out; 746e761b772SMax Krasnyansky } 747e761b772SMax Krasnyansky 748af1f4045SThomas Gleixner err = _cpu_down(cpu, 0, target); 749e3920fb4SRafael J. Wysocki 750e761b772SMax Krasnyansky out: 751d221938cSGautham R Shenoy cpu_maps_update_done(); 7521da177e4SLinus Torvalds return err; 7531da177e4SLinus Torvalds } 754af1f4045SThomas Gleixner int cpu_down(unsigned int cpu) 755af1f4045SThomas Gleixner { 756af1f4045SThomas Gleixner return do_cpu_down(cpu, CPUHP_OFFLINE); 757af1f4045SThomas Gleixner } 758b62b8ef9SZhang Rui EXPORT_SYMBOL(cpu_down); 7591da177e4SLinus Torvalds #endif /*CONFIG_HOTPLUG_CPU*/ 7601da177e4SLinus Torvalds 7614baa0afcSThomas Gleixner /** 762ee1e714bSThomas Gleixner * notify_cpu_starting(cpu) - Invoke the callbacks on the starting CPU 7634baa0afcSThomas Gleixner * @cpu: cpu that just started 7644baa0afcSThomas Gleixner * 7654baa0afcSThomas Gleixner * It must be called by the arch code on the new cpu, before the new cpu 7664baa0afcSThomas Gleixner * enables interrupts and before the "boot" cpu returns from __cpu_up(). 7674baa0afcSThomas Gleixner */ 7684baa0afcSThomas Gleixner void notify_cpu_starting(unsigned int cpu) 7694baa0afcSThomas Gleixner { 7704baa0afcSThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 7714baa0afcSThomas Gleixner enum cpuhp_state target = min((int)st->target, CPUHP_AP_ONLINE); 7724baa0afcSThomas Gleixner 7730c6d4576SSebastian Andrzej Siewior rcu_cpu_starting(cpu); /* Enables RCU usage on this CPU. */ 7744baa0afcSThomas Gleixner while (st->state < target) { 7754baa0afcSThomas Gleixner st->state++; 776cf392d10SThomas Gleixner cpuhp_invoke_callback(cpu, st->state, true, NULL); 7774baa0afcSThomas Gleixner } 7784baa0afcSThomas Gleixner } 7794baa0afcSThomas Gleixner 780949338e3SThomas Gleixner /* 781949338e3SThomas Gleixner * Called from the idle task. We need to set active here, so we can kick off 7828df3e07eSThomas Gleixner * the stopper thread and unpark the smpboot threads. If the target state is 7838df3e07eSThomas Gleixner * beyond CPUHP_AP_ONLINE_IDLE we kick cpuhp thread and let it bring up the 7848df3e07eSThomas Gleixner * cpu further. 785949338e3SThomas Gleixner */ 7868df3e07eSThomas Gleixner void cpuhp_online_idle(enum cpuhp_state state) 787949338e3SThomas Gleixner { 7888df3e07eSThomas Gleixner struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); 7898df3e07eSThomas Gleixner unsigned int cpu = smp_processor_id(); 7908df3e07eSThomas Gleixner 7918df3e07eSThomas Gleixner /* Happens for the boot cpu */ 7928df3e07eSThomas Gleixner if (state != CPUHP_AP_ONLINE_IDLE) 7938df3e07eSThomas Gleixner return; 7948df3e07eSThomas Gleixner 7958df3e07eSThomas Gleixner st->state = CPUHP_AP_ONLINE_IDLE; 7961cf4f629SThomas Gleixner 7978df3e07eSThomas Gleixner /* Unpark the stopper thread and the hotplug thread of this cpu */ 798949338e3SThomas Gleixner stop_machine_unpark(cpu); 7991cf4f629SThomas Gleixner kthread_unpark(st->thread); 8008df3e07eSThomas Gleixner 8018df3e07eSThomas Gleixner /* Should we go further up ? */ 8028df3e07eSThomas Gleixner if (st->target > CPUHP_AP_ONLINE_IDLE) 8038df3e07eSThomas Gleixner __cpuhp_kick_ap_work(st); 8048df3e07eSThomas Gleixner else 8058df3e07eSThomas Gleixner complete(&st->done); 806949338e3SThomas Gleixner } 807949338e3SThomas Gleixner 808e3920fb4SRafael J. Wysocki /* Requires cpu_add_remove_lock to be held */ 809af1f4045SThomas Gleixner static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target) 8101da177e4SLinus Torvalds { 811cff7d378SThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 8123bb5d2eeSSuresh Siddha struct task_struct *idle; 8132e1a3483SThomas Gleixner int ret = 0; 8141da177e4SLinus Torvalds 8158f553c49SThomas Gleixner cpus_write_lock(); 81638498a67SThomas Gleixner 817757c989bSThomas Gleixner if (!cpu_present(cpu)) { 8185e5041f3SYasuaki Ishimatsu ret = -EINVAL; 8195e5041f3SYasuaki Ishimatsu goto out; 8205e5041f3SYasuaki Ishimatsu } 8215e5041f3SYasuaki Ishimatsu 822757c989bSThomas Gleixner /* 823757c989bSThomas Gleixner * The caller of do_cpu_up might have raced with another 824757c989bSThomas Gleixner * caller. Ignore it for now. 825757c989bSThomas Gleixner */ 826757c989bSThomas Gleixner if (st->state >= target) 827757c989bSThomas Gleixner goto out; 828757c989bSThomas Gleixner 829757c989bSThomas Gleixner if (st->state == CPUHP_OFFLINE) { 830cff7d378SThomas Gleixner /* Let it fail before we try to bring the cpu up */ 8313bb5d2eeSSuresh Siddha idle = idle_thread_get(cpu); 8323bb5d2eeSSuresh Siddha if (IS_ERR(idle)) { 8333bb5d2eeSSuresh Siddha ret = PTR_ERR(idle); 83438498a67SThomas Gleixner goto out; 8353bb5d2eeSSuresh Siddha } 836757c989bSThomas Gleixner } 83738498a67SThomas Gleixner 838ba997462SThomas Gleixner cpuhp_tasks_frozen = tasks_frozen; 839ba997462SThomas Gleixner 840af1f4045SThomas Gleixner st->target = target; 8411cf4f629SThomas Gleixner /* 8421cf4f629SThomas Gleixner * If the current CPU state is in the range of the AP hotplug thread, 8431cf4f629SThomas Gleixner * then we need to kick the thread once more. 8441cf4f629SThomas Gleixner */ 8458df3e07eSThomas Gleixner if (st->state > CPUHP_BRINGUP_CPU) { 8461cf4f629SThomas Gleixner ret = cpuhp_kick_ap_work(cpu); 8471cf4f629SThomas Gleixner /* 8481cf4f629SThomas Gleixner * The AP side has done the error rollback already. Just 8491cf4f629SThomas Gleixner * return the error code.. 8501cf4f629SThomas Gleixner */ 8511cf4f629SThomas Gleixner if (ret) 8521cf4f629SThomas Gleixner goto out; 8531cf4f629SThomas Gleixner } 8541cf4f629SThomas Gleixner 8551cf4f629SThomas Gleixner /* 8561cf4f629SThomas Gleixner * Try to reach the target state. We max out on the BP at 8578df3e07eSThomas Gleixner * CPUHP_BRINGUP_CPU. After that the AP hotplug thread is 8581cf4f629SThomas Gleixner * responsible for bringing it up to the target state. 8591cf4f629SThomas Gleixner */ 8608df3e07eSThomas Gleixner target = min((int)target, CPUHP_BRINGUP_CPU); 861a724632cSThomas Gleixner ret = cpuhp_up_callbacks(cpu, st, target); 86238498a67SThomas Gleixner out: 8638f553c49SThomas Gleixner cpus_write_unlock(); 8641da177e4SLinus Torvalds return ret; 8651da177e4SLinus Torvalds } 866e3920fb4SRafael J. Wysocki 867af1f4045SThomas Gleixner static int do_cpu_up(unsigned int cpu, enum cpuhp_state target) 868e3920fb4SRafael J. Wysocki { 869e3920fb4SRafael J. Wysocki int err = 0; 870cf23422bSminskey guo 871e0b582ecSRusty Russell if (!cpu_possible(cpu)) { 87284117da5SFabian Frederick pr_err("can't online cpu %d because it is not configured as may-hotadd at boot time\n", 87384117da5SFabian Frederick cpu); 87487d5e023SChen Gong #if defined(CONFIG_IA64) 87584117da5SFabian Frederick pr_err("please check additional_cpus= boot parameter\n"); 87673e753a5SKAMEZAWA Hiroyuki #endif 87773e753a5SKAMEZAWA Hiroyuki return -EINVAL; 87873e753a5SKAMEZAWA Hiroyuki } 879e3920fb4SRafael J. Wysocki 88001b0f197SToshi Kani err = try_online_node(cpu_to_node(cpu)); 881cf23422bSminskey guo if (err) 882cf23422bSminskey guo return err; 883cf23422bSminskey guo 884d221938cSGautham R Shenoy cpu_maps_update_begin(); 885e761b772SMax Krasnyansky 886e761b772SMax Krasnyansky if (cpu_hotplug_disabled) { 887e3920fb4SRafael J. Wysocki err = -EBUSY; 888e761b772SMax Krasnyansky goto out; 889e761b772SMax Krasnyansky } 890e761b772SMax Krasnyansky 891af1f4045SThomas Gleixner err = _cpu_up(cpu, 0, target); 892e761b772SMax Krasnyansky out: 893d221938cSGautham R Shenoy cpu_maps_update_done(); 894e3920fb4SRafael J. Wysocki return err; 895e3920fb4SRafael J. Wysocki } 896af1f4045SThomas Gleixner 897af1f4045SThomas Gleixner int cpu_up(unsigned int cpu) 898af1f4045SThomas Gleixner { 899af1f4045SThomas Gleixner return do_cpu_up(cpu, CPUHP_ONLINE); 900af1f4045SThomas Gleixner } 901a513f6baSPaul E. McKenney EXPORT_SYMBOL_GPL(cpu_up); 902e3920fb4SRafael J. Wysocki 903f3de4be9SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_SMP 904e0b582ecSRusty Russell static cpumask_var_t frozen_cpus; 905e3920fb4SRafael J. Wysocki 906d391e552SJames Morse int freeze_secondary_cpus(int primary) 907e3920fb4SRafael J. Wysocki { 908d391e552SJames Morse int cpu, error = 0; 909e3920fb4SRafael J. Wysocki 910d221938cSGautham R Shenoy cpu_maps_update_begin(); 911d391e552SJames Morse if (!cpu_online(primary)) 912d391e552SJames Morse primary = cpumask_first(cpu_online_mask); 9139ee349adSXiaotian Feng /* 9149ee349adSXiaotian Feng * We take down all of the non-boot CPUs in one shot to avoid races 915e3920fb4SRafael J. Wysocki * with the userspace trying to use the CPU hotplug at the same time 916e3920fb4SRafael J. Wysocki */ 917e0b582ecSRusty Russell cpumask_clear(frozen_cpus); 9186ad4c188SPeter Zijlstra 91984117da5SFabian Frederick pr_info("Disabling non-boot CPUs ...\n"); 920e3920fb4SRafael J. Wysocki for_each_online_cpu(cpu) { 921d391e552SJames Morse if (cpu == primary) 922e3920fb4SRafael J. Wysocki continue; 923bb3632c6STodd E Brandt trace_suspend_resume(TPS("CPU_OFF"), cpu, true); 924af1f4045SThomas Gleixner error = _cpu_down(cpu, 1, CPUHP_OFFLINE); 925bb3632c6STodd E Brandt trace_suspend_resume(TPS("CPU_OFF"), cpu, false); 926feae3203SMike Travis if (!error) 927e0b582ecSRusty Russell cpumask_set_cpu(cpu, frozen_cpus); 928feae3203SMike Travis else { 92984117da5SFabian Frederick pr_err("Error taking CPU%d down: %d\n", cpu, error); 930e3920fb4SRafael J. Wysocki break; 931e3920fb4SRafael J. Wysocki } 932e3920fb4SRafael J. Wysocki } 93386886e55SJoseph Cihula 93489af7ba5SVitaly Kuznetsov if (!error) 935e3920fb4SRafael J. Wysocki BUG_ON(num_online_cpus() > 1); 93689af7ba5SVitaly Kuznetsov else 93784117da5SFabian Frederick pr_err("Non-boot CPUs are not disabled\n"); 93889af7ba5SVitaly Kuznetsov 93989af7ba5SVitaly Kuznetsov /* 94089af7ba5SVitaly Kuznetsov * Make sure the CPUs won't be enabled by someone else. We need to do 94189af7ba5SVitaly Kuznetsov * this even in case of failure as all disable_nonboot_cpus() users are 94289af7ba5SVitaly Kuznetsov * supposed to do enable_nonboot_cpus() on the failure path. 94389af7ba5SVitaly Kuznetsov */ 94489af7ba5SVitaly Kuznetsov cpu_hotplug_disabled++; 94589af7ba5SVitaly Kuznetsov 946d221938cSGautham R Shenoy cpu_maps_update_done(); 947e3920fb4SRafael J. Wysocki return error; 948e3920fb4SRafael J. Wysocki } 949e3920fb4SRafael J. Wysocki 950d0af9eedSSuresh Siddha void __weak arch_enable_nonboot_cpus_begin(void) 951d0af9eedSSuresh Siddha { 952d0af9eedSSuresh Siddha } 953d0af9eedSSuresh Siddha 954d0af9eedSSuresh Siddha void __weak arch_enable_nonboot_cpus_end(void) 955d0af9eedSSuresh Siddha { 956d0af9eedSSuresh Siddha } 957d0af9eedSSuresh Siddha 95871cf5aeeSMathias Krause void enable_nonboot_cpus(void) 959e3920fb4SRafael J. Wysocki { 960e3920fb4SRafael J. Wysocki int cpu, error; 961e3920fb4SRafael J. Wysocki 962e3920fb4SRafael J. Wysocki /* Allow everyone to use the CPU hotplug again */ 963d221938cSGautham R Shenoy cpu_maps_update_begin(); 96401b41159SLianwei Wang __cpu_hotplug_enable(); 965e0b582ecSRusty Russell if (cpumask_empty(frozen_cpus)) 9661d64b9cbSRafael J. Wysocki goto out; 967e3920fb4SRafael J. Wysocki 96884117da5SFabian Frederick pr_info("Enabling non-boot CPUs ...\n"); 969d0af9eedSSuresh Siddha 970d0af9eedSSuresh Siddha arch_enable_nonboot_cpus_begin(); 971d0af9eedSSuresh Siddha 972e0b582ecSRusty Russell for_each_cpu(cpu, frozen_cpus) { 973bb3632c6STodd E Brandt trace_suspend_resume(TPS("CPU_ON"), cpu, true); 974af1f4045SThomas Gleixner error = _cpu_up(cpu, 1, CPUHP_ONLINE); 975bb3632c6STodd E Brandt trace_suspend_resume(TPS("CPU_ON"), cpu, false); 976e3920fb4SRafael J. Wysocki if (!error) { 97784117da5SFabian Frederick pr_info("CPU%d is up\n", cpu); 978e3920fb4SRafael J. Wysocki continue; 979e3920fb4SRafael J. Wysocki } 98084117da5SFabian Frederick pr_warn("Error taking CPU%d up: %d\n", cpu, error); 981e3920fb4SRafael J. Wysocki } 982d0af9eedSSuresh Siddha 983d0af9eedSSuresh Siddha arch_enable_nonboot_cpus_end(); 984d0af9eedSSuresh Siddha 985e0b582ecSRusty Russell cpumask_clear(frozen_cpus); 9861d64b9cbSRafael J. Wysocki out: 987d221938cSGautham R Shenoy cpu_maps_update_done(); 988e3920fb4SRafael J. Wysocki } 989e0b582ecSRusty Russell 990d7268a31SFenghua Yu static int __init alloc_frozen_cpus(void) 991e0b582ecSRusty Russell { 992e0b582ecSRusty Russell if (!alloc_cpumask_var(&frozen_cpus, GFP_KERNEL|__GFP_ZERO)) 993e0b582ecSRusty Russell return -ENOMEM; 994e0b582ecSRusty Russell return 0; 995e0b582ecSRusty Russell } 996e0b582ecSRusty Russell core_initcall(alloc_frozen_cpus); 99779cfbdfaSSrivatsa S. Bhat 99879cfbdfaSSrivatsa S. Bhat /* 99979cfbdfaSSrivatsa S. Bhat * When callbacks for CPU hotplug notifications are being executed, we must 100079cfbdfaSSrivatsa S. Bhat * ensure that the state of the system with respect to the tasks being frozen 100179cfbdfaSSrivatsa S. Bhat * or not, as reported by the notification, remains unchanged *throughout the 100279cfbdfaSSrivatsa S. Bhat * duration* of the execution of the callbacks. 100379cfbdfaSSrivatsa S. Bhat * Hence we need to prevent the freezer from racing with regular CPU hotplug. 100479cfbdfaSSrivatsa S. Bhat * 100579cfbdfaSSrivatsa S. Bhat * This synchronization is implemented by mutually excluding regular CPU 100679cfbdfaSSrivatsa S. Bhat * hotplug and Suspend/Hibernate call paths by hooking onto the Suspend/ 100779cfbdfaSSrivatsa S. Bhat * Hibernate notifications. 100879cfbdfaSSrivatsa S. Bhat */ 100979cfbdfaSSrivatsa S. Bhat static int 101079cfbdfaSSrivatsa S. Bhat cpu_hotplug_pm_callback(struct notifier_block *nb, 101179cfbdfaSSrivatsa S. Bhat unsigned long action, void *ptr) 101279cfbdfaSSrivatsa S. Bhat { 101379cfbdfaSSrivatsa S. Bhat switch (action) { 101479cfbdfaSSrivatsa S. Bhat 101579cfbdfaSSrivatsa S. Bhat case PM_SUSPEND_PREPARE: 101679cfbdfaSSrivatsa S. Bhat case PM_HIBERNATION_PREPARE: 101716e53dbfSSrivatsa S. Bhat cpu_hotplug_disable(); 101879cfbdfaSSrivatsa S. Bhat break; 101979cfbdfaSSrivatsa S. Bhat 102079cfbdfaSSrivatsa S. Bhat case PM_POST_SUSPEND: 102179cfbdfaSSrivatsa S. Bhat case PM_POST_HIBERNATION: 102216e53dbfSSrivatsa S. Bhat cpu_hotplug_enable(); 102379cfbdfaSSrivatsa S. Bhat break; 102479cfbdfaSSrivatsa S. Bhat 102579cfbdfaSSrivatsa S. Bhat default: 102679cfbdfaSSrivatsa S. Bhat return NOTIFY_DONE; 102779cfbdfaSSrivatsa S. Bhat } 102879cfbdfaSSrivatsa S. Bhat 102979cfbdfaSSrivatsa S. Bhat return NOTIFY_OK; 103079cfbdfaSSrivatsa S. Bhat } 103179cfbdfaSSrivatsa S. Bhat 103279cfbdfaSSrivatsa S. Bhat 1033d7268a31SFenghua Yu static int __init cpu_hotplug_pm_sync_init(void) 103479cfbdfaSSrivatsa S. Bhat { 10356e32d479SFenghua Yu /* 10366e32d479SFenghua Yu * cpu_hotplug_pm_callback has higher priority than x86 10376e32d479SFenghua Yu * bsp_pm_callback which depends on cpu_hotplug_pm_callback 10386e32d479SFenghua Yu * to disable cpu hotplug to avoid cpu hotplug race. 10396e32d479SFenghua Yu */ 104079cfbdfaSSrivatsa S. Bhat pm_notifier(cpu_hotplug_pm_callback, 0); 104179cfbdfaSSrivatsa S. Bhat return 0; 104279cfbdfaSSrivatsa S. Bhat } 104379cfbdfaSSrivatsa S. Bhat core_initcall(cpu_hotplug_pm_sync_init); 104479cfbdfaSSrivatsa S. Bhat 1045f3de4be9SRafael J. Wysocki #endif /* CONFIG_PM_SLEEP_SMP */ 104668f4f1ecSMax Krasnyansky 10478ce371f9SPeter Zijlstra int __boot_cpu_id; 10488ce371f9SPeter Zijlstra 104968f4f1ecSMax Krasnyansky #endif /* CONFIG_SMP */ 1050b8d317d1SMike Travis 1051cff7d378SThomas Gleixner /* Boot processor state steps */ 1052cff7d378SThomas Gleixner static struct cpuhp_step cpuhp_bp_states[] = { 1053cff7d378SThomas Gleixner [CPUHP_OFFLINE] = { 1054cff7d378SThomas Gleixner .name = "offline", 10553c1627e9SThomas Gleixner .startup.single = NULL, 10563c1627e9SThomas Gleixner .teardown.single = NULL, 1057cff7d378SThomas Gleixner }, 1058cff7d378SThomas Gleixner #ifdef CONFIG_SMP 1059cff7d378SThomas Gleixner [CPUHP_CREATE_THREADS]= { 1060677f6646SThomas Gleixner .name = "threads:prepare", 10613c1627e9SThomas Gleixner .startup.single = smpboot_create_threads, 10623c1627e9SThomas Gleixner .teardown.single = NULL, 1063757c989bSThomas Gleixner .cant_stop = true, 1064cff7d378SThomas Gleixner }, 106500e16c3dSThomas Gleixner [CPUHP_PERF_PREPARE] = { 10663c1627e9SThomas Gleixner .name = "perf:prepare", 10673c1627e9SThomas Gleixner .startup.single = perf_event_init_cpu, 10683c1627e9SThomas Gleixner .teardown.single = perf_event_exit_cpu, 106900e16c3dSThomas Gleixner }, 10707ee681b2SThomas Gleixner [CPUHP_WORKQUEUE_PREP] = { 10713c1627e9SThomas Gleixner .name = "workqueue:prepare", 10723c1627e9SThomas Gleixner .startup.single = workqueue_prepare_cpu, 10733c1627e9SThomas Gleixner .teardown.single = NULL, 10747ee681b2SThomas Gleixner }, 107527590dc1SThomas Gleixner [CPUHP_HRTIMERS_PREPARE] = { 10763c1627e9SThomas Gleixner .name = "hrtimers:prepare", 10773c1627e9SThomas Gleixner .startup.single = hrtimers_prepare_cpu, 10783c1627e9SThomas Gleixner .teardown.single = hrtimers_dead_cpu, 107927590dc1SThomas Gleixner }, 108031487f83SRichard Weinberger [CPUHP_SMPCFD_PREPARE] = { 1081677f6646SThomas Gleixner .name = "smpcfd:prepare", 10823c1627e9SThomas Gleixner .startup.single = smpcfd_prepare_cpu, 10833c1627e9SThomas Gleixner .teardown.single = smpcfd_dead_cpu, 108431487f83SRichard Weinberger }, 1085e6d4989aSRichard Weinberger [CPUHP_RELAY_PREPARE] = { 1086e6d4989aSRichard Weinberger .name = "relay:prepare", 1087e6d4989aSRichard Weinberger .startup.single = relay_prepare_cpu, 1088e6d4989aSRichard Weinberger .teardown.single = NULL, 1089e6d4989aSRichard Weinberger }, 10906731d4f1SSebastian Andrzej Siewior [CPUHP_SLAB_PREPARE] = { 10916731d4f1SSebastian Andrzej Siewior .name = "slab:prepare", 10926731d4f1SSebastian Andrzej Siewior .startup.single = slab_prepare_cpu, 10936731d4f1SSebastian Andrzej Siewior .teardown.single = slab_dead_cpu, 1094cff7d378SThomas Gleixner }, 10954df83742SThomas Gleixner [CPUHP_RCUTREE_PREP] = { 1096677f6646SThomas Gleixner .name = "RCU/tree:prepare", 10973c1627e9SThomas Gleixner .startup.single = rcutree_prepare_cpu, 10983c1627e9SThomas Gleixner .teardown.single = rcutree_dead_cpu, 10994df83742SThomas Gleixner }, 1100cff7d378SThomas Gleixner /* 11014fae16dfSRichard Cochran * On the tear-down path, timers_dead_cpu() must be invoked 11024fae16dfSRichard Cochran * before blk_mq_queue_reinit_notify() from notify_dead(), 11034fae16dfSRichard Cochran * otherwise a RCU stall occurs. 11044fae16dfSRichard Cochran */ 11054fae16dfSRichard Cochran [CPUHP_TIMERS_DEAD] = { 11063c1627e9SThomas Gleixner .name = "timers:dead", 11073c1627e9SThomas Gleixner .startup.single = NULL, 11083c1627e9SThomas Gleixner .teardown.single = timers_dead_cpu, 11094fae16dfSRichard Cochran }, 1110d10ef6f9SThomas Gleixner /* Kicks the plugged cpu into life */ 1111cff7d378SThomas Gleixner [CPUHP_BRINGUP_CPU] = { 1112cff7d378SThomas Gleixner .name = "cpu:bringup", 11133c1627e9SThomas Gleixner .startup.single = bringup_cpu, 11143c1627e9SThomas Gleixner .teardown.single = NULL, 1115757c989bSThomas Gleixner .cant_stop = true, 11164baa0afcSThomas Gleixner }, 111731487f83SRichard Weinberger [CPUHP_AP_SMPCFD_DYING] = { 1118677f6646SThomas Gleixner .name = "smpcfd:dying", 11193c1627e9SThomas Gleixner .startup.single = NULL, 11203c1627e9SThomas Gleixner .teardown.single = smpcfd_dying_cpu, 112131487f83SRichard Weinberger }, 1122d10ef6f9SThomas Gleixner /* 1123d10ef6f9SThomas Gleixner * Handled on controll processor until the plugged processor manages 1124d10ef6f9SThomas Gleixner * this itself. 1125d10ef6f9SThomas Gleixner */ 11264baa0afcSThomas Gleixner [CPUHP_TEARDOWN_CPU] = { 11274baa0afcSThomas Gleixner .name = "cpu:teardown", 11283c1627e9SThomas Gleixner .startup.single = NULL, 11293c1627e9SThomas Gleixner .teardown.single = takedown_cpu, 1130757c989bSThomas Gleixner .cant_stop = true, 1131cff7d378SThomas Gleixner }, 1132a7c73414SThomas Gleixner #else 1133a7c73414SThomas Gleixner [CPUHP_BRINGUP_CPU] = { }, 1134cff7d378SThomas Gleixner #endif 1135cff7d378SThomas Gleixner }; 1136cff7d378SThomas Gleixner 11374baa0afcSThomas Gleixner /* Application processor state steps */ 11384baa0afcSThomas Gleixner static struct cpuhp_step cpuhp_ap_states[] = { 11394baa0afcSThomas Gleixner #ifdef CONFIG_SMP 1140d10ef6f9SThomas Gleixner /* Final state before CPU kills itself */ 1141d10ef6f9SThomas Gleixner [CPUHP_AP_IDLE_DEAD] = { 1142d10ef6f9SThomas Gleixner .name = "idle:dead", 1143d10ef6f9SThomas Gleixner }, 1144d10ef6f9SThomas Gleixner /* 1145d10ef6f9SThomas Gleixner * Last state before CPU enters the idle loop to die. Transient state 1146d10ef6f9SThomas Gleixner * for synchronization. 1147d10ef6f9SThomas Gleixner */ 1148d10ef6f9SThomas Gleixner [CPUHP_AP_OFFLINE] = { 1149d10ef6f9SThomas Gleixner .name = "ap:offline", 1150d10ef6f9SThomas Gleixner .cant_stop = true, 1151d10ef6f9SThomas Gleixner }, 11529cf7243dSThomas Gleixner /* First state is scheduler control. Interrupts are disabled */ 11539cf7243dSThomas Gleixner [CPUHP_AP_SCHED_STARTING] = { 11549cf7243dSThomas Gleixner .name = "sched:starting", 11553c1627e9SThomas Gleixner .startup.single = sched_cpu_starting, 11563c1627e9SThomas Gleixner .teardown.single = sched_cpu_dying, 11579cf7243dSThomas Gleixner }, 11584df83742SThomas Gleixner [CPUHP_AP_RCUTREE_DYING] = { 1159677f6646SThomas Gleixner .name = "RCU/tree:dying", 11603c1627e9SThomas Gleixner .startup.single = NULL, 11613c1627e9SThomas Gleixner .teardown.single = rcutree_dying_cpu, 11624baa0afcSThomas Gleixner }, 1163d10ef6f9SThomas Gleixner /* Entry state on starting. Interrupts enabled from here on. Transient 1164d10ef6f9SThomas Gleixner * state for synchronsization */ 1165d10ef6f9SThomas Gleixner [CPUHP_AP_ONLINE] = { 1166d10ef6f9SThomas Gleixner .name = "ap:online", 1167d10ef6f9SThomas Gleixner }, 1168d10ef6f9SThomas Gleixner /* Handle smpboot threads park/unpark */ 11691cf4f629SThomas Gleixner [CPUHP_AP_SMPBOOT_THREADS] = { 1170677f6646SThomas Gleixner .name = "smpboot/threads:online", 11713c1627e9SThomas Gleixner .startup.single = smpboot_unpark_threads, 11723c1627e9SThomas Gleixner .teardown.single = NULL, 11731cf4f629SThomas Gleixner }, 117400e16c3dSThomas Gleixner [CPUHP_AP_PERF_ONLINE] = { 11753c1627e9SThomas Gleixner .name = "perf:online", 11763c1627e9SThomas Gleixner .startup.single = perf_event_init_cpu, 11773c1627e9SThomas Gleixner .teardown.single = perf_event_exit_cpu, 117800e16c3dSThomas Gleixner }, 11797ee681b2SThomas Gleixner [CPUHP_AP_WORKQUEUE_ONLINE] = { 11803c1627e9SThomas Gleixner .name = "workqueue:online", 11813c1627e9SThomas Gleixner .startup.single = workqueue_online_cpu, 11823c1627e9SThomas Gleixner .teardown.single = workqueue_offline_cpu, 11837ee681b2SThomas Gleixner }, 11844df83742SThomas Gleixner [CPUHP_AP_RCUTREE_ONLINE] = { 1185677f6646SThomas Gleixner .name = "RCU/tree:online", 11863c1627e9SThomas Gleixner .startup.single = rcutree_online_cpu, 11873c1627e9SThomas Gleixner .teardown.single = rcutree_offline_cpu, 11884df83742SThomas Gleixner }, 11894baa0afcSThomas Gleixner #endif 1190d10ef6f9SThomas Gleixner /* 1191d10ef6f9SThomas Gleixner * The dynamically registered state space is here 1192d10ef6f9SThomas Gleixner */ 1193d10ef6f9SThomas Gleixner 1194aaddd7d1SThomas Gleixner #ifdef CONFIG_SMP 1195aaddd7d1SThomas Gleixner /* Last state is scheduler control setting the cpu active */ 1196aaddd7d1SThomas Gleixner [CPUHP_AP_ACTIVE] = { 1197aaddd7d1SThomas Gleixner .name = "sched:active", 11983c1627e9SThomas Gleixner .startup.single = sched_cpu_activate, 11993c1627e9SThomas Gleixner .teardown.single = sched_cpu_deactivate, 1200aaddd7d1SThomas Gleixner }, 1201aaddd7d1SThomas Gleixner #endif 1202aaddd7d1SThomas Gleixner 1203d10ef6f9SThomas Gleixner /* CPU is fully up and running. */ 12044baa0afcSThomas Gleixner [CPUHP_ONLINE] = { 12054baa0afcSThomas Gleixner .name = "online", 12063c1627e9SThomas Gleixner .startup.single = NULL, 12073c1627e9SThomas Gleixner .teardown.single = NULL, 12084baa0afcSThomas Gleixner }, 12094baa0afcSThomas Gleixner }; 12104baa0afcSThomas Gleixner 12115b7aa87eSThomas Gleixner /* Sanity check for callbacks */ 12125b7aa87eSThomas Gleixner static int cpuhp_cb_check(enum cpuhp_state state) 12135b7aa87eSThomas Gleixner { 12145b7aa87eSThomas Gleixner if (state <= CPUHP_OFFLINE || state >= CPUHP_ONLINE) 12155b7aa87eSThomas Gleixner return -EINVAL; 12165b7aa87eSThomas Gleixner return 0; 12175b7aa87eSThomas Gleixner } 12185b7aa87eSThomas Gleixner 1219dc280d93SThomas Gleixner /* 1220dc280d93SThomas Gleixner * Returns a free for dynamic slot assignment of the Online state. The states 1221dc280d93SThomas Gleixner * are protected by the cpuhp_slot_states mutex and an empty slot is identified 1222dc280d93SThomas Gleixner * by having no name assigned. 1223dc280d93SThomas Gleixner */ 1224dc280d93SThomas Gleixner static int cpuhp_reserve_state(enum cpuhp_state state) 1225dc280d93SThomas Gleixner { 12264205e478SThomas Gleixner enum cpuhp_state i, end; 12274205e478SThomas Gleixner struct cpuhp_step *step; 1228dc280d93SThomas Gleixner 12294205e478SThomas Gleixner switch (state) { 12304205e478SThomas Gleixner case CPUHP_AP_ONLINE_DYN: 12314205e478SThomas Gleixner step = cpuhp_ap_states + CPUHP_AP_ONLINE_DYN; 12324205e478SThomas Gleixner end = CPUHP_AP_ONLINE_DYN_END; 12334205e478SThomas Gleixner break; 12344205e478SThomas Gleixner case CPUHP_BP_PREPARE_DYN: 12354205e478SThomas Gleixner step = cpuhp_bp_states + CPUHP_BP_PREPARE_DYN; 12364205e478SThomas Gleixner end = CPUHP_BP_PREPARE_DYN_END; 12374205e478SThomas Gleixner break; 12384205e478SThomas Gleixner default: 12394205e478SThomas Gleixner return -EINVAL; 12404205e478SThomas Gleixner } 12414205e478SThomas Gleixner 12424205e478SThomas Gleixner for (i = state; i <= end; i++, step++) { 12434205e478SThomas Gleixner if (!step->name) 1244dc280d93SThomas Gleixner return i; 1245dc280d93SThomas Gleixner } 1246dc280d93SThomas Gleixner WARN(1, "No more dynamic states available for CPU hotplug\n"); 1247dc280d93SThomas Gleixner return -ENOSPC; 1248dc280d93SThomas Gleixner } 1249dc280d93SThomas Gleixner 1250dc280d93SThomas Gleixner static int cpuhp_store_callbacks(enum cpuhp_state state, const char *name, 12515b7aa87eSThomas Gleixner int (*startup)(unsigned int cpu), 1252cf392d10SThomas Gleixner int (*teardown)(unsigned int cpu), 1253cf392d10SThomas Gleixner bool multi_instance) 12545b7aa87eSThomas Gleixner { 12555b7aa87eSThomas Gleixner /* (Un)Install the callbacks for further cpu hotplug operations */ 12565b7aa87eSThomas Gleixner struct cpuhp_step *sp; 1257dc280d93SThomas Gleixner int ret = 0; 12585b7aa87eSThomas Gleixner 12594205e478SThomas Gleixner if (state == CPUHP_AP_ONLINE_DYN || state == CPUHP_BP_PREPARE_DYN) { 1260dc280d93SThomas Gleixner ret = cpuhp_reserve_state(state); 1261dc280d93SThomas Gleixner if (ret < 0) 1262dc434e05SSebastian Andrzej Siewior return ret; 1263dc280d93SThomas Gleixner state = ret; 1264dc280d93SThomas Gleixner } 12655b7aa87eSThomas Gleixner sp = cpuhp_get_step(state); 1266dc434e05SSebastian Andrzej Siewior if (name && sp->name) 1267dc434e05SSebastian Andrzej Siewior return -EBUSY; 1268dc434e05SSebastian Andrzej Siewior 12693c1627e9SThomas Gleixner sp->startup.single = startup; 12703c1627e9SThomas Gleixner sp->teardown.single = teardown; 12715b7aa87eSThomas Gleixner sp->name = name; 1272cf392d10SThomas Gleixner sp->multi_instance = multi_instance; 1273cf392d10SThomas Gleixner INIT_HLIST_HEAD(&sp->list); 1274dc280d93SThomas Gleixner return ret; 12755b7aa87eSThomas Gleixner } 12765b7aa87eSThomas Gleixner 12775b7aa87eSThomas Gleixner static void *cpuhp_get_teardown_cb(enum cpuhp_state state) 12785b7aa87eSThomas Gleixner { 12793c1627e9SThomas Gleixner return cpuhp_get_step(state)->teardown.single; 12805b7aa87eSThomas Gleixner } 12815b7aa87eSThomas Gleixner 12825b7aa87eSThomas Gleixner /* 12835b7aa87eSThomas Gleixner * Call the startup/teardown function for a step either on the AP or 12845b7aa87eSThomas Gleixner * on the current CPU. 12855b7aa87eSThomas Gleixner */ 1286cf392d10SThomas Gleixner static int cpuhp_issue_call(int cpu, enum cpuhp_state state, bool bringup, 1287cf392d10SThomas Gleixner struct hlist_node *node) 12885b7aa87eSThomas Gleixner { 1289a724632cSThomas Gleixner struct cpuhp_step *sp = cpuhp_get_step(state); 12905b7aa87eSThomas Gleixner int ret; 12915b7aa87eSThomas Gleixner 12923c1627e9SThomas Gleixner if ((bringup && !sp->startup.single) || 12933c1627e9SThomas Gleixner (!bringup && !sp->teardown.single)) 12945b7aa87eSThomas Gleixner return 0; 12955b7aa87eSThomas Gleixner /* 12965b7aa87eSThomas Gleixner * The non AP bound callbacks can fail on bringup. On teardown 12975b7aa87eSThomas Gleixner * e.g. module removal we crash for now. 12985b7aa87eSThomas Gleixner */ 12991cf4f629SThomas Gleixner #ifdef CONFIG_SMP 13001cf4f629SThomas Gleixner if (cpuhp_is_ap_state(state)) 1301cf392d10SThomas Gleixner ret = cpuhp_invoke_ap_callback(cpu, state, bringup, node); 13021cf4f629SThomas Gleixner else 1303cf392d10SThomas Gleixner ret = cpuhp_invoke_callback(cpu, state, bringup, node); 13041cf4f629SThomas Gleixner #else 1305cf392d10SThomas Gleixner ret = cpuhp_invoke_callback(cpu, state, bringup, node); 13061cf4f629SThomas Gleixner #endif 13075b7aa87eSThomas Gleixner BUG_ON(ret && !bringup); 13085b7aa87eSThomas Gleixner return ret; 13095b7aa87eSThomas Gleixner } 13105b7aa87eSThomas Gleixner 13115b7aa87eSThomas Gleixner /* 13125b7aa87eSThomas Gleixner * Called from __cpuhp_setup_state on a recoverable failure. 13135b7aa87eSThomas Gleixner * 13145b7aa87eSThomas Gleixner * Note: The teardown callbacks for rollback are not allowed to fail! 13155b7aa87eSThomas Gleixner */ 13165b7aa87eSThomas Gleixner static void cpuhp_rollback_install(int failedcpu, enum cpuhp_state state, 1317cf392d10SThomas Gleixner struct hlist_node *node) 13185b7aa87eSThomas Gleixner { 13195b7aa87eSThomas Gleixner int cpu; 13205b7aa87eSThomas Gleixner 13215b7aa87eSThomas Gleixner /* Roll back the already executed steps on the other cpus */ 13225b7aa87eSThomas Gleixner for_each_present_cpu(cpu) { 13235b7aa87eSThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 13245b7aa87eSThomas Gleixner int cpustate = st->state; 13255b7aa87eSThomas Gleixner 13265b7aa87eSThomas Gleixner if (cpu >= failedcpu) 13275b7aa87eSThomas Gleixner break; 13285b7aa87eSThomas Gleixner 13295b7aa87eSThomas Gleixner /* Did we invoke the startup call on that cpu ? */ 13305b7aa87eSThomas Gleixner if (cpustate >= state) 1331cf392d10SThomas Gleixner cpuhp_issue_call(cpu, state, false, node); 13325b7aa87eSThomas Gleixner } 13335b7aa87eSThomas Gleixner } 13345b7aa87eSThomas Gleixner 13359805c673SThomas Gleixner int __cpuhp_state_add_instance_cpuslocked(enum cpuhp_state state, 13369805c673SThomas Gleixner struct hlist_node *node, 1337cf392d10SThomas Gleixner bool invoke) 1338cf392d10SThomas Gleixner { 1339cf392d10SThomas Gleixner struct cpuhp_step *sp; 1340cf392d10SThomas Gleixner int cpu; 1341cf392d10SThomas Gleixner int ret; 1342cf392d10SThomas Gleixner 13439805c673SThomas Gleixner lockdep_assert_cpus_held(); 13449805c673SThomas Gleixner 1345cf392d10SThomas Gleixner sp = cpuhp_get_step(state); 1346cf392d10SThomas Gleixner if (sp->multi_instance == false) 1347cf392d10SThomas Gleixner return -EINVAL; 1348cf392d10SThomas Gleixner 1349dc434e05SSebastian Andrzej Siewior mutex_lock(&cpuhp_state_mutex); 1350cf392d10SThomas Gleixner 13513c1627e9SThomas Gleixner if (!invoke || !sp->startup.multi) 1352cf392d10SThomas Gleixner goto add_node; 1353cf392d10SThomas Gleixner 1354cf392d10SThomas Gleixner /* 1355cf392d10SThomas Gleixner * Try to call the startup callback for each present cpu 1356cf392d10SThomas Gleixner * depending on the hotplug state of the cpu. 1357cf392d10SThomas Gleixner */ 1358cf392d10SThomas Gleixner for_each_present_cpu(cpu) { 1359cf392d10SThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 1360cf392d10SThomas Gleixner int cpustate = st->state; 1361cf392d10SThomas Gleixner 1362cf392d10SThomas Gleixner if (cpustate < state) 1363cf392d10SThomas Gleixner continue; 1364cf392d10SThomas Gleixner 1365cf392d10SThomas Gleixner ret = cpuhp_issue_call(cpu, state, true, node); 1366cf392d10SThomas Gleixner if (ret) { 13673c1627e9SThomas Gleixner if (sp->teardown.multi) 1368cf392d10SThomas Gleixner cpuhp_rollback_install(cpu, state, node); 1369dc434e05SSebastian Andrzej Siewior goto unlock; 1370cf392d10SThomas Gleixner } 1371cf392d10SThomas Gleixner } 1372cf392d10SThomas Gleixner add_node: 1373cf392d10SThomas Gleixner ret = 0; 1374cf392d10SThomas Gleixner hlist_add_head(node, &sp->list); 1375dc434e05SSebastian Andrzej Siewior unlock: 1376cf392d10SThomas Gleixner mutex_unlock(&cpuhp_state_mutex); 13779805c673SThomas Gleixner return ret; 13789805c673SThomas Gleixner } 13799805c673SThomas Gleixner 13809805c673SThomas Gleixner int __cpuhp_state_add_instance(enum cpuhp_state state, struct hlist_node *node, 13819805c673SThomas Gleixner bool invoke) 13829805c673SThomas Gleixner { 13839805c673SThomas Gleixner int ret; 13849805c673SThomas Gleixner 13859805c673SThomas Gleixner cpus_read_lock(); 13869805c673SThomas Gleixner ret = __cpuhp_state_add_instance_cpuslocked(state, node, invoke); 13878f553c49SThomas Gleixner cpus_read_unlock(); 1388cf392d10SThomas Gleixner return ret; 1389cf392d10SThomas Gleixner } 1390cf392d10SThomas Gleixner EXPORT_SYMBOL_GPL(__cpuhp_state_add_instance); 1391cf392d10SThomas Gleixner 13925b7aa87eSThomas Gleixner /** 139371def423SSebastian Andrzej Siewior * __cpuhp_setup_state_cpuslocked - Setup the callbacks for an hotplug machine state 13945b7aa87eSThomas Gleixner * @state: The state to setup 13955b7aa87eSThomas Gleixner * @invoke: If true, the startup function is invoked for cpus where 13965b7aa87eSThomas Gleixner * cpu state >= @state 13975b7aa87eSThomas Gleixner * @startup: startup callback function 13985b7aa87eSThomas Gleixner * @teardown: teardown callback function 1399dc280d93SThomas Gleixner * @multi_instance: State is set up for multiple instances which get 1400dc280d93SThomas Gleixner * added afterwards. 14015b7aa87eSThomas Gleixner * 140271def423SSebastian Andrzej Siewior * The caller needs to hold cpus read locked while calling this function. 1403512f0980SBoris Ostrovsky * Returns: 1404512f0980SBoris Ostrovsky * On success: 1405512f0980SBoris Ostrovsky * Positive state number if @state is CPUHP_AP_ONLINE_DYN 1406512f0980SBoris Ostrovsky * 0 for all other states 1407512f0980SBoris Ostrovsky * On failure: proper (negative) error code 14085b7aa87eSThomas Gleixner */ 140971def423SSebastian Andrzej Siewior int __cpuhp_setup_state_cpuslocked(enum cpuhp_state state, 14105b7aa87eSThomas Gleixner const char *name, bool invoke, 14115b7aa87eSThomas Gleixner int (*startup)(unsigned int cpu), 1412cf392d10SThomas Gleixner int (*teardown)(unsigned int cpu), 1413cf392d10SThomas Gleixner bool multi_instance) 14145b7aa87eSThomas Gleixner { 14155b7aa87eSThomas Gleixner int cpu, ret = 0; 1416b9d9d691SThomas Gleixner bool dynstate; 14175b7aa87eSThomas Gleixner 141871def423SSebastian Andrzej Siewior lockdep_assert_cpus_held(); 141971def423SSebastian Andrzej Siewior 14205b7aa87eSThomas Gleixner if (cpuhp_cb_check(state) || !name) 14215b7aa87eSThomas Gleixner return -EINVAL; 14225b7aa87eSThomas Gleixner 1423dc434e05SSebastian Andrzej Siewior mutex_lock(&cpuhp_state_mutex); 14245b7aa87eSThomas Gleixner 1425dc280d93SThomas Gleixner ret = cpuhp_store_callbacks(state, name, startup, teardown, 1426dc280d93SThomas Gleixner multi_instance); 14275b7aa87eSThomas Gleixner 1428b9d9d691SThomas Gleixner dynstate = state == CPUHP_AP_ONLINE_DYN; 1429b9d9d691SThomas Gleixner if (ret > 0 && dynstate) { 1430b9d9d691SThomas Gleixner state = ret; 1431b9d9d691SThomas Gleixner ret = 0; 1432b9d9d691SThomas Gleixner } 1433b9d9d691SThomas Gleixner 1434dc280d93SThomas Gleixner if (ret || !invoke || !startup) 14355b7aa87eSThomas Gleixner goto out; 14365b7aa87eSThomas Gleixner 14375b7aa87eSThomas Gleixner /* 14385b7aa87eSThomas Gleixner * Try to call the startup callback for each present cpu 14395b7aa87eSThomas Gleixner * depending on the hotplug state of the cpu. 14405b7aa87eSThomas Gleixner */ 14415b7aa87eSThomas Gleixner for_each_present_cpu(cpu) { 14425b7aa87eSThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 14435b7aa87eSThomas Gleixner int cpustate = st->state; 14445b7aa87eSThomas Gleixner 14455b7aa87eSThomas Gleixner if (cpustate < state) 14465b7aa87eSThomas Gleixner continue; 14475b7aa87eSThomas Gleixner 1448cf392d10SThomas Gleixner ret = cpuhp_issue_call(cpu, state, true, NULL); 14495b7aa87eSThomas Gleixner if (ret) { 1450a724632cSThomas Gleixner if (teardown) 1451cf392d10SThomas Gleixner cpuhp_rollback_install(cpu, state, NULL); 1452cf392d10SThomas Gleixner cpuhp_store_callbacks(state, NULL, NULL, NULL, false); 14535b7aa87eSThomas Gleixner goto out; 14545b7aa87eSThomas Gleixner } 14555b7aa87eSThomas Gleixner } 14565b7aa87eSThomas Gleixner out: 1457dc434e05SSebastian Andrzej Siewior mutex_unlock(&cpuhp_state_mutex); 1458dc280d93SThomas Gleixner /* 1459dc280d93SThomas Gleixner * If the requested state is CPUHP_AP_ONLINE_DYN, return the 1460dc280d93SThomas Gleixner * dynamically allocated state in case of success. 1461dc280d93SThomas Gleixner */ 1462b9d9d691SThomas Gleixner if (!ret && dynstate) 14635b7aa87eSThomas Gleixner return state; 14645b7aa87eSThomas Gleixner return ret; 14655b7aa87eSThomas Gleixner } 146671def423SSebastian Andrzej Siewior EXPORT_SYMBOL(__cpuhp_setup_state_cpuslocked); 146771def423SSebastian Andrzej Siewior 146871def423SSebastian Andrzej Siewior int __cpuhp_setup_state(enum cpuhp_state state, 146971def423SSebastian Andrzej Siewior const char *name, bool invoke, 147071def423SSebastian Andrzej Siewior int (*startup)(unsigned int cpu), 147171def423SSebastian Andrzej Siewior int (*teardown)(unsigned int cpu), 147271def423SSebastian Andrzej Siewior bool multi_instance) 147371def423SSebastian Andrzej Siewior { 147471def423SSebastian Andrzej Siewior int ret; 147571def423SSebastian Andrzej Siewior 147671def423SSebastian Andrzej Siewior cpus_read_lock(); 147771def423SSebastian Andrzej Siewior ret = __cpuhp_setup_state_cpuslocked(state, name, invoke, startup, 147871def423SSebastian Andrzej Siewior teardown, multi_instance); 147971def423SSebastian Andrzej Siewior cpus_read_unlock(); 148071def423SSebastian Andrzej Siewior return ret; 148171def423SSebastian Andrzej Siewior } 14825b7aa87eSThomas Gleixner EXPORT_SYMBOL(__cpuhp_setup_state); 14835b7aa87eSThomas Gleixner 1484cf392d10SThomas Gleixner int __cpuhp_state_remove_instance(enum cpuhp_state state, 1485cf392d10SThomas Gleixner struct hlist_node *node, bool invoke) 1486cf392d10SThomas Gleixner { 1487cf392d10SThomas Gleixner struct cpuhp_step *sp = cpuhp_get_step(state); 1488cf392d10SThomas Gleixner int cpu; 1489cf392d10SThomas Gleixner 1490cf392d10SThomas Gleixner BUG_ON(cpuhp_cb_check(state)); 1491cf392d10SThomas Gleixner 1492cf392d10SThomas Gleixner if (!sp->multi_instance) 1493cf392d10SThomas Gleixner return -EINVAL; 1494cf392d10SThomas Gleixner 14958f553c49SThomas Gleixner cpus_read_lock(); 1496dc434e05SSebastian Andrzej Siewior mutex_lock(&cpuhp_state_mutex); 1497dc434e05SSebastian Andrzej Siewior 1498cf392d10SThomas Gleixner if (!invoke || !cpuhp_get_teardown_cb(state)) 1499cf392d10SThomas Gleixner goto remove; 1500cf392d10SThomas Gleixner /* 1501cf392d10SThomas Gleixner * Call the teardown callback for each present cpu depending 1502cf392d10SThomas Gleixner * on the hotplug state of the cpu. This function is not 1503cf392d10SThomas Gleixner * allowed to fail currently! 1504cf392d10SThomas Gleixner */ 1505cf392d10SThomas Gleixner for_each_present_cpu(cpu) { 1506cf392d10SThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 1507cf392d10SThomas Gleixner int cpustate = st->state; 1508cf392d10SThomas Gleixner 1509cf392d10SThomas Gleixner if (cpustate >= state) 1510cf392d10SThomas Gleixner cpuhp_issue_call(cpu, state, false, node); 1511cf392d10SThomas Gleixner } 1512cf392d10SThomas Gleixner 1513cf392d10SThomas Gleixner remove: 1514cf392d10SThomas Gleixner hlist_del(node); 1515cf392d10SThomas Gleixner mutex_unlock(&cpuhp_state_mutex); 15168f553c49SThomas Gleixner cpus_read_unlock(); 1517cf392d10SThomas Gleixner 1518cf392d10SThomas Gleixner return 0; 1519cf392d10SThomas Gleixner } 1520cf392d10SThomas Gleixner EXPORT_SYMBOL_GPL(__cpuhp_state_remove_instance); 1521dc434e05SSebastian Andrzej Siewior 15225b7aa87eSThomas Gleixner /** 152371def423SSebastian Andrzej Siewior * __cpuhp_remove_state_cpuslocked - Remove the callbacks for an hotplug machine state 15245b7aa87eSThomas Gleixner * @state: The state to remove 15255b7aa87eSThomas Gleixner * @invoke: If true, the teardown function is invoked for cpus where 15265b7aa87eSThomas Gleixner * cpu state >= @state 15275b7aa87eSThomas Gleixner * 152871def423SSebastian Andrzej Siewior * The caller needs to hold cpus read locked while calling this function. 15295b7aa87eSThomas Gleixner * The teardown callback is currently not allowed to fail. Think 15305b7aa87eSThomas Gleixner * about module removal! 15315b7aa87eSThomas Gleixner */ 153271def423SSebastian Andrzej Siewior void __cpuhp_remove_state_cpuslocked(enum cpuhp_state state, bool invoke) 15335b7aa87eSThomas Gleixner { 1534cf392d10SThomas Gleixner struct cpuhp_step *sp = cpuhp_get_step(state); 15355b7aa87eSThomas Gleixner int cpu; 15365b7aa87eSThomas Gleixner 15375b7aa87eSThomas Gleixner BUG_ON(cpuhp_cb_check(state)); 15385b7aa87eSThomas Gleixner 153971def423SSebastian Andrzej Siewior lockdep_assert_cpus_held(); 15405b7aa87eSThomas Gleixner 1541dc434e05SSebastian Andrzej Siewior mutex_lock(&cpuhp_state_mutex); 1542cf392d10SThomas Gleixner if (sp->multi_instance) { 1543cf392d10SThomas Gleixner WARN(!hlist_empty(&sp->list), 1544cf392d10SThomas Gleixner "Error: Removing state %d which has instances left.\n", 1545cf392d10SThomas Gleixner state); 1546cf392d10SThomas Gleixner goto remove; 1547cf392d10SThomas Gleixner } 1548cf392d10SThomas Gleixner 1549a724632cSThomas Gleixner if (!invoke || !cpuhp_get_teardown_cb(state)) 15505b7aa87eSThomas Gleixner goto remove; 15515b7aa87eSThomas Gleixner 15525b7aa87eSThomas Gleixner /* 15535b7aa87eSThomas Gleixner * Call the teardown callback for each present cpu depending 15545b7aa87eSThomas Gleixner * on the hotplug state of the cpu. This function is not 15555b7aa87eSThomas Gleixner * allowed to fail currently! 15565b7aa87eSThomas Gleixner */ 15575b7aa87eSThomas Gleixner for_each_present_cpu(cpu) { 15585b7aa87eSThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 15595b7aa87eSThomas Gleixner int cpustate = st->state; 15605b7aa87eSThomas Gleixner 15615b7aa87eSThomas Gleixner if (cpustate >= state) 1562cf392d10SThomas Gleixner cpuhp_issue_call(cpu, state, false, NULL); 15635b7aa87eSThomas Gleixner } 15645b7aa87eSThomas Gleixner remove: 1565cf392d10SThomas Gleixner cpuhp_store_callbacks(state, NULL, NULL, NULL, false); 1566dc434e05SSebastian Andrzej Siewior mutex_unlock(&cpuhp_state_mutex); 156771def423SSebastian Andrzej Siewior } 156871def423SSebastian Andrzej Siewior EXPORT_SYMBOL(__cpuhp_remove_state_cpuslocked); 156971def423SSebastian Andrzej Siewior 157071def423SSebastian Andrzej Siewior void __cpuhp_remove_state(enum cpuhp_state state, bool invoke) 157171def423SSebastian Andrzej Siewior { 157271def423SSebastian Andrzej Siewior cpus_read_lock(); 157371def423SSebastian Andrzej Siewior __cpuhp_remove_state_cpuslocked(state, invoke); 15748f553c49SThomas Gleixner cpus_read_unlock(); 15755b7aa87eSThomas Gleixner } 15765b7aa87eSThomas Gleixner EXPORT_SYMBOL(__cpuhp_remove_state); 15775b7aa87eSThomas Gleixner 157898f8cdceSThomas Gleixner #if defined(CONFIG_SYSFS) && defined(CONFIG_HOTPLUG_CPU) 157998f8cdceSThomas Gleixner static ssize_t show_cpuhp_state(struct device *dev, 158098f8cdceSThomas Gleixner struct device_attribute *attr, char *buf) 158198f8cdceSThomas Gleixner { 158298f8cdceSThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id); 158398f8cdceSThomas Gleixner 158498f8cdceSThomas Gleixner return sprintf(buf, "%d\n", st->state); 158598f8cdceSThomas Gleixner } 158698f8cdceSThomas Gleixner static DEVICE_ATTR(state, 0444, show_cpuhp_state, NULL); 158798f8cdceSThomas Gleixner 1588757c989bSThomas Gleixner static ssize_t write_cpuhp_target(struct device *dev, 1589757c989bSThomas Gleixner struct device_attribute *attr, 1590757c989bSThomas Gleixner const char *buf, size_t count) 1591757c989bSThomas Gleixner { 1592757c989bSThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id); 1593757c989bSThomas Gleixner struct cpuhp_step *sp; 1594757c989bSThomas Gleixner int target, ret; 1595757c989bSThomas Gleixner 1596757c989bSThomas Gleixner ret = kstrtoint(buf, 10, &target); 1597757c989bSThomas Gleixner if (ret) 1598757c989bSThomas Gleixner return ret; 1599757c989bSThomas Gleixner 1600757c989bSThomas Gleixner #ifdef CONFIG_CPU_HOTPLUG_STATE_CONTROL 1601757c989bSThomas Gleixner if (target < CPUHP_OFFLINE || target > CPUHP_ONLINE) 1602757c989bSThomas Gleixner return -EINVAL; 1603757c989bSThomas Gleixner #else 1604757c989bSThomas Gleixner if (target != CPUHP_OFFLINE && target != CPUHP_ONLINE) 1605757c989bSThomas Gleixner return -EINVAL; 1606757c989bSThomas Gleixner #endif 1607757c989bSThomas Gleixner 1608757c989bSThomas Gleixner ret = lock_device_hotplug_sysfs(); 1609757c989bSThomas Gleixner if (ret) 1610757c989bSThomas Gleixner return ret; 1611757c989bSThomas Gleixner 1612757c989bSThomas Gleixner mutex_lock(&cpuhp_state_mutex); 1613757c989bSThomas Gleixner sp = cpuhp_get_step(target); 1614757c989bSThomas Gleixner ret = !sp->name || sp->cant_stop ? -EINVAL : 0; 1615757c989bSThomas Gleixner mutex_unlock(&cpuhp_state_mutex); 1616757c989bSThomas Gleixner if (ret) 1617757c989bSThomas Gleixner return ret; 1618757c989bSThomas Gleixner 1619757c989bSThomas Gleixner if (st->state < target) 1620757c989bSThomas Gleixner ret = do_cpu_up(dev->id, target); 1621757c989bSThomas Gleixner else 1622757c989bSThomas Gleixner ret = do_cpu_down(dev->id, target); 1623757c989bSThomas Gleixner 1624757c989bSThomas Gleixner unlock_device_hotplug(); 1625757c989bSThomas Gleixner return ret ? ret : count; 1626757c989bSThomas Gleixner } 1627757c989bSThomas Gleixner 162898f8cdceSThomas Gleixner static ssize_t show_cpuhp_target(struct device *dev, 162998f8cdceSThomas Gleixner struct device_attribute *attr, char *buf) 163098f8cdceSThomas Gleixner { 163198f8cdceSThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id); 163298f8cdceSThomas Gleixner 163398f8cdceSThomas Gleixner return sprintf(buf, "%d\n", st->target); 163498f8cdceSThomas Gleixner } 1635757c989bSThomas Gleixner static DEVICE_ATTR(target, 0644, show_cpuhp_target, write_cpuhp_target); 163698f8cdceSThomas Gleixner 163798f8cdceSThomas Gleixner static struct attribute *cpuhp_cpu_attrs[] = { 163898f8cdceSThomas Gleixner &dev_attr_state.attr, 163998f8cdceSThomas Gleixner &dev_attr_target.attr, 164098f8cdceSThomas Gleixner NULL 164198f8cdceSThomas Gleixner }; 164298f8cdceSThomas Gleixner 164398f8cdceSThomas Gleixner static struct attribute_group cpuhp_cpu_attr_group = { 164498f8cdceSThomas Gleixner .attrs = cpuhp_cpu_attrs, 164598f8cdceSThomas Gleixner .name = "hotplug", 164698f8cdceSThomas Gleixner NULL 164798f8cdceSThomas Gleixner }; 164898f8cdceSThomas Gleixner 164998f8cdceSThomas Gleixner static ssize_t show_cpuhp_states(struct device *dev, 165098f8cdceSThomas Gleixner struct device_attribute *attr, char *buf) 165198f8cdceSThomas Gleixner { 165298f8cdceSThomas Gleixner ssize_t cur, res = 0; 165398f8cdceSThomas Gleixner int i; 165498f8cdceSThomas Gleixner 165598f8cdceSThomas Gleixner mutex_lock(&cpuhp_state_mutex); 1656757c989bSThomas Gleixner for (i = CPUHP_OFFLINE; i <= CPUHP_ONLINE; i++) { 165798f8cdceSThomas Gleixner struct cpuhp_step *sp = cpuhp_get_step(i); 165898f8cdceSThomas Gleixner 165998f8cdceSThomas Gleixner if (sp->name) { 166098f8cdceSThomas Gleixner cur = sprintf(buf, "%3d: %s\n", i, sp->name); 166198f8cdceSThomas Gleixner buf += cur; 166298f8cdceSThomas Gleixner res += cur; 166398f8cdceSThomas Gleixner } 166498f8cdceSThomas Gleixner } 166598f8cdceSThomas Gleixner mutex_unlock(&cpuhp_state_mutex); 166698f8cdceSThomas Gleixner return res; 166798f8cdceSThomas Gleixner } 166898f8cdceSThomas Gleixner static DEVICE_ATTR(states, 0444, show_cpuhp_states, NULL); 166998f8cdceSThomas Gleixner 167098f8cdceSThomas Gleixner static struct attribute *cpuhp_cpu_root_attrs[] = { 167198f8cdceSThomas Gleixner &dev_attr_states.attr, 167298f8cdceSThomas Gleixner NULL 167398f8cdceSThomas Gleixner }; 167498f8cdceSThomas Gleixner 167598f8cdceSThomas Gleixner static struct attribute_group cpuhp_cpu_root_attr_group = { 167698f8cdceSThomas Gleixner .attrs = cpuhp_cpu_root_attrs, 167798f8cdceSThomas Gleixner .name = "hotplug", 167898f8cdceSThomas Gleixner NULL 167998f8cdceSThomas Gleixner }; 168098f8cdceSThomas Gleixner 168198f8cdceSThomas Gleixner static int __init cpuhp_sysfs_init(void) 168298f8cdceSThomas Gleixner { 168398f8cdceSThomas Gleixner int cpu, ret; 168498f8cdceSThomas Gleixner 168598f8cdceSThomas Gleixner ret = sysfs_create_group(&cpu_subsys.dev_root->kobj, 168698f8cdceSThomas Gleixner &cpuhp_cpu_root_attr_group); 168798f8cdceSThomas Gleixner if (ret) 168898f8cdceSThomas Gleixner return ret; 168998f8cdceSThomas Gleixner 169098f8cdceSThomas Gleixner for_each_possible_cpu(cpu) { 169198f8cdceSThomas Gleixner struct device *dev = get_cpu_device(cpu); 169298f8cdceSThomas Gleixner 169398f8cdceSThomas Gleixner if (!dev) 169498f8cdceSThomas Gleixner continue; 169598f8cdceSThomas Gleixner ret = sysfs_create_group(&dev->kobj, &cpuhp_cpu_attr_group); 169698f8cdceSThomas Gleixner if (ret) 169798f8cdceSThomas Gleixner return ret; 169898f8cdceSThomas Gleixner } 169998f8cdceSThomas Gleixner return 0; 170098f8cdceSThomas Gleixner } 170198f8cdceSThomas Gleixner device_initcall(cpuhp_sysfs_init); 170298f8cdceSThomas Gleixner #endif 170398f8cdceSThomas Gleixner 1704e56b3bc7SLinus Torvalds /* 1705e56b3bc7SLinus Torvalds * cpu_bit_bitmap[] is a special, "compressed" data structure that 1706e56b3bc7SLinus Torvalds * represents all NR_CPUS bits binary values of 1<<nr. 1707e56b3bc7SLinus Torvalds * 1708e0b582ecSRusty Russell * It is used by cpumask_of() to get a constant address to a CPU 1709e56b3bc7SLinus Torvalds * mask value that has a single bit set only. 1710e56b3bc7SLinus Torvalds */ 1711b8d317d1SMike Travis 1712e56b3bc7SLinus Torvalds /* cpu_bit_bitmap[0] is empty - so we can back into it */ 17134d51985eSMichael Rodriguez #define MASK_DECLARE_1(x) [x+1][0] = (1UL << (x)) 1714e56b3bc7SLinus Torvalds #define MASK_DECLARE_2(x) MASK_DECLARE_1(x), MASK_DECLARE_1(x+1) 1715e56b3bc7SLinus Torvalds #define MASK_DECLARE_4(x) MASK_DECLARE_2(x), MASK_DECLARE_2(x+2) 1716e56b3bc7SLinus Torvalds #define MASK_DECLARE_8(x) MASK_DECLARE_4(x), MASK_DECLARE_4(x+4) 1717b8d317d1SMike Travis 1718e56b3bc7SLinus Torvalds const unsigned long cpu_bit_bitmap[BITS_PER_LONG+1][BITS_TO_LONGS(NR_CPUS)] = { 1719b8d317d1SMike Travis 1720e56b3bc7SLinus Torvalds MASK_DECLARE_8(0), MASK_DECLARE_8(8), 1721e56b3bc7SLinus Torvalds MASK_DECLARE_8(16), MASK_DECLARE_8(24), 1722e56b3bc7SLinus Torvalds #if BITS_PER_LONG > 32 1723e56b3bc7SLinus Torvalds MASK_DECLARE_8(32), MASK_DECLARE_8(40), 1724e56b3bc7SLinus Torvalds MASK_DECLARE_8(48), MASK_DECLARE_8(56), 1725b8d317d1SMike Travis #endif 1726b8d317d1SMike Travis }; 1727e56b3bc7SLinus Torvalds EXPORT_SYMBOL_GPL(cpu_bit_bitmap); 17282d3854a3SRusty Russell 17292d3854a3SRusty Russell const DECLARE_BITMAP(cpu_all_bits, NR_CPUS) = CPU_BITS_ALL; 17302d3854a3SRusty Russell EXPORT_SYMBOL(cpu_all_bits); 1731b3199c02SRusty Russell 1732b3199c02SRusty Russell #ifdef CONFIG_INIT_ALL_POSSIBLE 17334b804c85SRasmus Villemoes struct cpumask __cpu_possible_mask __read_mostly 1734c4c54dd1SRasmus Villemoes = {CPU_BITS_ALL}; 1735b3199c02SRusty Russell #else 17364b804c85SRasmus Villemoes struct cpumask __cpu_possible_mask __read_mostly; 1737b3199c02SRusty Russell #endif 17384b804c85SRasmus Villemoes EXPORT_SYMBOL(__cpu_possible_mask); 1739b3199c02SRusty Russell 17404b804c85SRasmus Villemoes struct cpumask __cpu_online_mask __read_mostly; 17414b804c85SRasmus Villemoes EXPORT_SYMBOL(__cpu_online_mask); 1742b3199c02SRusty Russell 17434b804c85SRasmus Villemoes struct cpumask __cpu_present_mask __read_mostly; 17444b804c85SRasmus Villemoes EXPORT_SYMBOL(__cpu_present_mask); 1745b3199c02SRusty Russell 17464b804c85SRasmus Villemoes struct cpumask __cpu_active_mask __read_mostly; 17474b804c85SRasmus Villemoes EXPORT_SYMBOL(__cpu_active_mask); 17483fa41520SRusty Russell 17493fa41520SRusty Russell void init_cpu_present(const struct cpumask *src) 17503fa41520SRusty Russell { 1751c4c54dd1SRasmus Villemoes cpumask_copy(&__cpu_present_mask, src); 17523fa41520SRusty Russell } 17533fa41520SRusty Russell 17543fa41520SRusty Russell void init_cpu_possible(const struct cpumask *src) 17553fa41520SRusty Russell { 1756c4c54dd1SRasmus Villemoes cpumask_copy(&__cpu_possible_mask, src); 17573fa41520SRusty Russell } 17583fa41520SRusty Russell 17593fa41520SRusty Russell void init_cpu_online(const struct cpumask *src) 17603fa41520SRusty Russell { 1761c4c54dd1SRasmus Villemoes cpumask_copy(&__cpu_online_mask, src); 17623fa41520SRusty Russell } 1763cff7d378SThomas Gleixner 1764cff7d378SThomas Gleixner /* 1765cff7d378SThomas Gleixner * Activate the first processor. 1766cff7d378SThomas Gleixner */ 1767cff7d378SThomas Gleixner void __init boot_cpu_init(void) 1768cff7d378SThomas Gleixner { 1769cff7d378SThomas Gleixner int cpu = smp_processor_id(); 1770cff7d378SThomas Gleixner 1771cff7d378SThomas Gleixner /* Mark the boot cpu "present", "online" etc for SMP and UP case */ 1772cff7d378SThomas Gleixner set_cpu_online(cpu, true); 1773cff7d378SThomas Gleixner set_cpu_active(cpu, true); 1774cff7d378SThomas Gleixner set_cpu_present(cpu, true); 1775cff7d378SThomas Gleixner set_cpu_possible(cpu, true); 17768ce371f9SPeter Zijlstra 17778ce371f9SPeter Zijlstra #ifdef CONFIG_SMP 17788ce371f9SPeter Zijlstra __boot_cpu_id = cpu; 17798ce371f9SPeter Zijlstra #endif 1780cff7d378SThomas Gleixner } 1781cff7d378SThomas Gleixner 1782cff7d378SThomas Gleixner /* 1783cff7d378SThomas Gleixner * Must be called _AFTER_ setting up the per_cpu areas 1784cff7d378SThomas Gleixner */ 1785cff7d378SThomas Gleixner void __init boot_cpu_state_init(void) 1786cff7d378SThomas Gleixner { 1787cff7d378SThomas Gleixner per_cpu_ptr(&cpuhp_state, smp_processor_id())->state = CPUHP_ONLINE; 1788cff7d378SThomas Gleixner } 1789