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 */ 6bf2c59fcSPeter Zijlstra #include <linux/sched/mm.h> 71da177e4SLinus Torvalds #include <linux/proc_fs.h> 81da177e4SLinus Torvalds #include <linux/smp.h> 91da177e4SLinus Torvalds #include <linux/init.h> 101da177e4SLinus Torvalds #include <linux/notifier.h> 113f07c014SIngo Molnar #include <linux/sched/signal.h> 12ef8bd77fSIngo Molnar #include <linux/sched/hotplug.h> 139ca12ac0SNicholas Piggin #include <linux/sched/isolation.h> 1429930025SIngo Molnar #include <linux/sched/task.h> 15a74cfffbSThomas Gleixner #include <linux/sched/smt.h> 161da177e4SLinus Torvalds #include <linux/unistd.h> 171da177e4SLinus Torvalds #include <linux/cpu.h> 18cb79295eSAnton Vorontsov #include <linux/oom.h> 19cb79295eSAnton Vorontsov #include <linux/rcupdate.h> 209984de1aSPaul Gortmaker #include <linux/export.h> 21e4cc2f87SAnton Vorontsov #include <linux/bug.h> 221da177e4SLinus Torvalds #include <linux/kthread.h> 231da177e4SLinus Torvalds #include <linux/stop_machine.h> 2481615b62SIngo Molnar #include <linux/mutex.h> 255a0e3ad6STejun Heo #include <linux/gfp.h> 2679cfbdfaSSrivatsa S. Bhat #include <linux/suspend.h> 27a19423b9SGautham R. Shenoy #include <linux/lockdep.h> 28345527b1SPreeti U Murthy #include <linux/tick.h> 29a8994181SThomas Gleixner #include <linux/irq.h> 30941154bdSThomas Gleixner #include <linux/nmi.h> 314cb28cedSThomas Gleixner #include <linux/smpboot.h> 32e6d4989aSRichard Weinberger #include <linux/relay.h> 336731d4f1SSebastian Andrzej Siewior #include <linux/slab.h> 34fc8dffd3SThomas Gleixner #include <linux/percpu-rwsem.h> 35cff7d378SThomas Gleixner 36bb3632c6STodd E Brandt #include <trace/events/power.h> 37cff7d378SThomas Gleixner #define CREATE_TRACE_POINTS 38cff7d378SThomas Gleixner #include <trace/events/cpuhp.h> 391da177e4SLinus Torvalds 4038498a67SThomas Gleixner #include "smpboot.h" 4138498a67SThomas Gleixner 42cff7d378SThomas Gleixner /** 43cff7d378SThomas Gleixner * cpuhp_cpu_state - Per cpu hotplug state storage 44cff7d378SThomas Gleixner * @state: The current cpu state 45cff7d378SThomas Gleixner * @target: The target state 464cb28cedSThomas Gleixner * @thread: Pointer to the hotplug thread 474cb28cedSThomas Gleixner * @should_run: Thread should execute 483b9d6da6SSebastian Andrzej Siewior * @rollback: Perform a rollback 49a724632cSThomas Gleixner * @single: Single callback invocation 50a724632cSThomas Gleixner * @bringup: Single callback bringup or teardown selector 51a724632cSThomas Gleixner * @cb_state: The state for a single callback (install/uninstall) 524cb28cedSThomas Gleixner * @result: Result of the operation 535ebe7742SPeter Zijlstra * @done_up: Signal completion to the issuer of the task for cpu-up 545ebe7742SPeter Zijlstra * @done_down: Signal completion to the issuer of the task for cpu-down 55cff7d378SThomas Gleixner */ 56cff7d378SThomas Gleixner struct cpuhp_cpu_state { 57cff7d378SThomas Gleixner enum cpuhp_state state; 58cff7d378SThomas Gleixner enum cpuhp_state target; 591db49484SPeter Zijlstra enum cpuhp_state fail; 604cb28cedSThomas Gleixner #ifdef CONFIG_SMP 614cb28cedSThomas Gleixner struct task_struct *thread; 624cb28cedSThomas Gleixner bool should_run; 633b9d6da6SSebastian Andrzej Siewior bool rollback; 64a724632cSThomas Gleixner bool single; 65a724632cSThomas Gleixner bool bringup; 66*2ea46c6fSPeter Zijlstra int cpu; 67cf392d10SThomas Gleixner struct hlist_node *node; 684dddfb5fSPeter Zijlstra struct hlist_node *last; 694cb28cedSThomas Gleixner enum cpuhp_state cb_state; 704cb28cedSThomas Gleixner int result; 715ebe7742SPeter Zijlstra struct completion done_up; 725ebe7742SPeter Zijlstra struct completion done_down; 734cb28cedSThomas Gleixner #endif 74cff7d378SThomas Gleixner }; 75cff7d378SThomas Gleixner 761db49484SPeter Zijlstra static DEFINE_PER_CPU(struct cpuhp_cpu_state, cpuhp_state) = { 771db49484SPeter Zijlstra .fail = CPUHP_INVALID, 781db49484SPeter Zijlstra }; 79cff7d378SThomas Gleixner 80e797bda3SThomas Gleixner #ifdef CONFIG_SMP 81e797bda3SThomas Gleixner cpumask_t cpus_booted_once_mask; 82e797bda3SThomas Gleixner #endif 83e797bda3SThomas Gleixner 8449dfe2a6SThomas Gleixner #if defined(CONFIG_LOCKDEP) && defined(CONFIG_SMP) 855f4b55e1SPeter Zijlstra static struct lockdep_map cpuhp_state_up_map = 865f4b55e1SPeter Zijlstra STATIC_LOCKDEP_MAP_INIT("cpuhp_state-up", &cpuhp_state_up_map); 875f4b55e1SPeter Zijlstra static struct lockdep_map cpuhp_state_down_map = 885f4b55e1SPeter Zijlstra STATIC_LOCKDEP_MAP_INIT("cpuhp_state-down", &cpuhp_state_down_map); 895f4b55e1SPeter Zijlstra 905f4b55e1SPeter Zijlstra 9176dc6c09SMathieu Malaterre static inline void cpuhp_lock_acquire(bool bringup) 925f4b55e1SPeter Zijlstra { 935f4b55e1SPeter Zijlstra lock_map_acquire(bringup ? &cpuhp_state_up_map : &cpuhp_state_down_map); 945f4b55e1SPeter Zijlstra } 955f4b55e1SPeter Zijlstra 9676dc6c09SMathieu Malaterre static inline void cpuhp_lock_release(bool bringup) 975f4b55e1SPeter Zijlstra { 985f4b55e1SPeter Zijlstra lock_map_release(bringup ? &cpuhp_state_up_map : &cpuhp_state_down_map); 995f4b55e1SPeter Zijlstra } 1005f4b55e1SPeter Zijlstra #else 1015f4b55e1SPeter Zijlstra 10276dc6c09SMathieu Malaterre static inline void cpuhp_lock_acquire(bool bringup) { } 10376dc6c09SMathieu Malaterre static inline void cpuhp_lock_release(bool bringup) { } 1045f4b55e1SPeter Zijlstra 10549dfe2a6SThomas Gleixner #endif 10649dfe2a6SThomas Gleixner 107cff7d378SThomas Gleixner /** 108cff7d378SThomas Gleixner * cpuhp_step - Hotplug state machine step 109cff7d378SThomas Gleixner * @name: Name of the step 110cff7d378SThomas Gleixner * @startup: Startup function of the step 111cff7d378SThomas Gleixner * @teardown: Teardown function of the step 112757c989bSThomas Gleixner * @cant_stop: Bringup/teardown can't be stopped at this step 113cff7d378SThomas Gleixner */ 114cff7d378SThomas Gleixner struct cpuhp_step { 115cff7d378SThomas Gleixner const char *name; 116cf392d10SThomas Gleixner union { 1173c1627e9SThomas Gleixner int (*single)(unsigned int cpu); 1183c1627e9SThomas Gleixner int (*multi)(unsigned int cpu, 119cf392d10SThomas Gleixner struct hlist_node *node); 1203c1627e9SThomas Gleixner } startup; 121cf392d10SThomas Gleixner union { 1223c1627e9SThomas Gleixner int (*single)(unsigned int cpu); 1233c1627e9SThomas Gleixner int (*multi)(unsigned int cpu, 124cf392d10SThomas Gleixner struct hlist_node *node); 1253c1627e9SThomas Gleixner } teardown; 126cf392d10SThomas Gleixner struct hlist_head list; 127757c989bSThomas Gleixner bool cant_stop; 128cf392d10SThomas Gleixner bool multi_instance; 129cff7d378SThomas Gleixner }; 130cff7d378SThomas Gleixner 13198f8cdceSThomas Gleixner static DEFINE_MUTEX(cpuhp_state_mutex); 13217a2f1ceSLai Jiangshan static struct cpuhp_step cpuhp_hp_states[]; 133cff7d378SThomas Gleixner 134a724632cSThomas Gleixner static struct cpuhp_step *cpuhp_get_step(enum cpuhp_state state) 135a724632cSThomas Gleixner { 13617a2f1ceSLai Jiangshan return cpuhp_hp_states + state; 137a724632cSThomas Gleixner } 138a724632cSThomas Gleixner 139453e4108SVincent Donnefort static bool cpuhp_step_empty(bool bringup, struct cpuhp_step *step) 140453e4108SVincent Donnefort { 141453e4108SVincent Donnefort return bringup ? !step->startup.single : !step->teardown.single; 142453e4108SVincent Donnefort } 143453e4108SVincent Donnefort 144cff7d378SThomas Gleixner /** 145cff7d378SThomas Gleixner * cpuhp_invoke_callback _ Invoke the callbacks for a given state 146cff7d378SThomas Gleixner * @cpu: The cpu for which the callback should be invoked 14796abb968SPeter Zijlstra * @state: The state to do callbacks for 148a724632cSThomas Gleixner * @bringup: True if the bringup callback should be invoked 14996abb968SPeter Zijlstra * @node: For multi-instance, do a single entry callback for install/remove 15096abb968SPeter Zijlstra * @lastp: For multi-instance rollback, remember how far we got 151cff7d378SThomas Gleixner * 152cf392d10SThomas Gleixner * Called from cpu hotplug and from the state register machinery. 153cff7d378SThomas Gleixner */ 154a724632cSThomas Gleixner static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state, 15596abb968SPeter Zijlstra bool bringup, struct hlist_node *node, 15696abb968SPeter Zijlstra struct hlist_node **lastp) 157cff7d378SThomas Gleixner { 158cff7d378SThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 159a724632cSThomas Gleixner struct cpuhp_step *step = cpuhp_get_step(state); 160cf392d10SThomas Gleixner int (*cbm)(unsigned int cpu, struct hlist_node *node); 161cf392d10SThomas Gleixner int (*cb)(unsigned int cpu); 162cf392d10SThomas Gleixner int ret, cnt; 163cff7d378SThomas Gleixner 1641db49484SPeter Zijlstra if (st->fail == state) { 1651db49484SPeter Zijlstra st->fail = CPUHP_INVALID; 1661db49484SPeter Zijlstra return -EAGAIN; 1671db49484SPeter Zijlstra } 1681db49484SPeter Zijlstra 169453e4108SVincent Donnefort if (cpuhp_step_empty(bringup, step)) { 170453e4108SVincent Donnefort WARN_ON_ONCE(1); 171453e4108SVincent Donnefort return 0; 172453e4108SVincent Donnefort } 173453e4108SVincent Donnefort 174cf392d10SThomas Gleixner if (!step->multi_instance) { 17596abb968SPeter Zijlstra WARN_ON_ONCE(lastp && *lastp); 1763c1627e9SThomas Gleixner cb = bringup ? step->startup.single : step->teardown.single; 177453e4108SVincent Donnefort 178a724632cSThomas Gleixner trace_cpuhp_enter(cpu, st->target, state, cb); 179cff7d378SThomas Gleixner ret = cb(cpu); 180a724632cSThomas Gleixner trace_cpuhp_exit(cpu, st->state, state, ret); 181cf392d10SThomas Gleixner return ret; 182cf392d10SThomas Gleixner } 1833c1627e9SThomas Gleixner cbm = bringup ? step->startup.multi : step->teardown.multi; 184cf392d10SThomas Gleixner 185cf392d10SThomas Gleixner /* Single invocation for instance add/remove */ 186cf392d10SThomas Gleixner if (node) { 18796abb968SPeter Zijlstra WARN_ON_ONCE(lastp && *lastp); 188cf392d10SThomas Gleixner trace_cpuhp_multi_enter(cpu, st->target, state, cbm, node); 189cf392d10SThomas Gleixner ret = cbm(cpu, node); 190cf392d10SThomas Gleixner trace_cpuhp_exit(cpu, st->state, state, ret); 191cf392d10SThomas Gleixner return ret; 192cf392d10SThomas Gleixner } 193cf392d10SThomas Gleixner 194cf392d10SThomas Gleixner /* State transition. Invoke on all instances */ 195cf392d10SThomas Gleixner cnt = 0; 196cf392d10SThomas Gleixner hlist_for_each(node, &step->list) { 19796abb968SPeter Zijlstra if (lastp && node == *lastp) 19896abb968SPeter Zijlstra break; 19996abb968SPeter Zijlstra 200cf392d10SThomas Gleixner trace_cpuhp_multi_enter(cpu, st->target, state, cbm, node); 201cf392d10SThomas Gleixner ret = cbm(cpu, node); 202cf392d10SThomas Gleixner trace_cpuhp_exit(cpu, st->state, state, ret); 20396abb968SPeter Zijlstra if (ret) { 20496abb968SPeter Zijlstra if (!lastp) 205cf392d10SThomas Gleixner goto err; 20696abb968SPeter Zijlstra 20796abb968SPeter Zijlstra *lastp = node; 20896abb968SPeter Zijlstra return ret; 20996abb968SPeter Zijlstra } 210cf392d10SThomas Gleixner cnt++; 211cf392d10SThomas Gleixner } 21296abb968SPeter Zijlstra if (lastp) 21396abb968SPeter Zijlstra *lastp = NULL; 214cf392d10SThomas Gleixner return 0; 215cf392d10SThomas Gleixner err: 216cf392d10SThomas Gleixner /* Rollback the instances if one failed */ 2173c1627e9SThomas Gleixner cbm = !bringup ? step->startup.multi : step->teardown.multi; 218cf392d10SThomas Gleixner if (!cbm) 219cf392d10SThomas Gleixner return ret; 220cf392d10SThomas Gleixner 221cf392d10SThomas Gleixner hlist_for_each(node, &step->list) { 222cf392d10SThomas Gleixner if (!cnt--) 223cf392d10SThomas Gleixner break; 224724a8688SPeter Zijlstra 225724a8688SPeter Zijlstra trace_cpuhp_multi_enter(cpu, st->target, state, cbm, node); 226724a8688SPeter Zijlstra ret = cbm(cpu, node); 227724a8688SPeter Zijlstra trace_cpuhp_exit(cpu, st->state, state, ret); 228724a8688SPeter Zijlstra /* 229724a8688SPeter Zijlstra * Rollback must not fail, 230724a8688SPeter Zijlstra */ 231724a8688SPeter Zijlstra WARN_ON_ONCE(ret); 232cff7d378SThomas Gleixner } 233cff7d378SThomas Gleixner return ret; 234cff7d378SThomas Gleixner } 235cff7d378SThomas Gleixner 23698a79d6aSRusty Russell #ifdef CONFIG_SMP 237fcb3029aSArnd Bergmann static bool cpuhp_is_ap_state(enum cpuhp_state state) 238fcb3029aSArnd Bergmann { 239fcb3029aSArnd Bergmann /* 240fcb3029aSArnd Bergmann * The extra check for CPUHP_TEARDOWN_CPU is only for documentation 241fcb3029aSArnd Bergmann * purposes as that state is handled explicitly in cpu_down. 242fcb3029aSArnd Bergmann */ 243fcb3029aSArnd Bergmann return state > CPUHP_BRINGUP_CPU && state != CPUHP_TEARDOWN_CPU; 244fcb3029aSArnd Bergmann } 245fcb3029aSArnd Bergmann 2465ebe7742SPeter Zijlstra static inline void wait_for_ap_thread(struct cpuhp_cpu_state *st, bool bringup) 2475ebe7742SPeter Zijlstra { 2485ebe7742SPeter Zijlstra struct completion *done = bringup ? &st->done_up : &st->done_down; 2495ebe7742SPeter Zijlstra wait_for_completion(done); 2505ebe7742SPeter Zijlstra } 2515ebe7742SPeter Zijlstra 2525ebe7742SPeter Zijlstra static inline void complete_ap_thread(struct cpuhp_cpu_state *st, bool bringup) 2535ebe7742SPeter Zijlstra { 2545ebe7742SPeter Zijlstra struct completion *done = bringup ? &st->done_up : &st->done_down; 2555ebe7742SPeter Zijlstra complete(done); 2565ebe7742SPeter Zijlstra } 2575ebe7742SPeter Zijlstra 2585ebe7742SPeter Zijlstra /* 2595ebe7742SPeter Zijlstra * The former STARTING/DYING states, ran with IRQs disabled and must not fail. 2605ebe7742SPeter Zijlstra */ 2615ebe7742SPeter Zijlstra static bool cpuhp_is_atomic_state(enum cpuhp_state state) 2625ebe7742SPeter Zijlstra { 2635ebe7742SPeter Zijlstra return CPUHP_AP_IDLE_DEAD <= state && state < CPUHP_AP_ONLINE; 2645ebe7742SPeter Zijlstra } 2655ebe7742SPeter Zijlstra 266b3199c02SRusty Russell /* Serializes the updates to cpu_online_mask, cpu_present_mask */ 267aa953877SLinus Torvalds static DEFINE_MUTEX(cpu_add_remove_lock); 268090e77c3SThomas Gleixner bool cpuhp_tasks_frozen; 269090e77c3SThomas Gleixner EXPORT_SYMBOL_GPL(cpuhp_tasks_frozen); 2701da177e4SLinus Torvalds 27179a6cdebSLai Jiangshan /* 27293ae4f97SSrivatsa S. Bhat * The following two APIs (cpu_maps_update_begin/done) must be used when 27393ae4f97SSrivatsa S. Bhat * attempting to serialize the updates to cpu_online_mask & cpu_present_mask. 27479a6cdebSLai Jiangshan */ 27579a6cdebSLai Jiangshan void cpu_maps_update_begin(void) 27679a6cdebSLai Jiangshan { 27779a6cdebSLai Jiangshan mutex_lock(&cpu_add_remove_lock); 27879a6cdebSLai Jiangshan } 27979a6cdebSLai Jiangshan 28079a6cdebSLai Jiangshan void cpu_maps_update_done(void) 28179a6cdebSLai Jiangshan { 28279a6cdebSLai Jiangshan mutex_unlock(&cpu_add_remove_lock); 28379a6cdebSLai Jiangshan } 2841da177e4SLinus Torvalds 285fc8dffd3SThomas Gleixner /* 286fc8dffd3SThomas Gleixner * If set, cpu_up and cpu_down will return -EBUSY and do nothing. 287e3920fb4SRafael J. Wysocki * Should always be manipulated under cpu_add_remove_lock 288e3920fb4SRafael J. Wysocki */ 289e3920fb4SRafael J. Wysocki static int cpu_hotplug_disabled; 290e3920fb4SRafael J. Wysocki 29179a6cdebSLai Jiangshan #ifdef CONFIG_HOTPLUG_CPU 29279a6cdebSLai Jiangshan 293fc8dffd3SThomas Gleixner DEFINE_STATIC_PERCPU_RWSEM(cpu_hotplug_lock); 294a19423b9SGautham R. Shenoy 2958f553c49SThomas Gleixner void cpus_read_lock(void) 296a9d9baa1SAshok Raj { 297fc8dffd3SThomas Gleixner percpu_down_read(&cpu_hotplug_lock); 298a9d9baa1SAshok Raj } 2998f553c49SThomas Gleixner EXPORT_SYMBOL_GPL(cpus_read_lock); 300a9d9baa1SAshok Raj 3016f4ceee9SWaiman Long int cpus_read_trylock(void) 3026f4ceee9SWaiman Long { 3036f4ceee9SWaiman Long return percpu_down_read_trylock(&cpu_hotplug_lock); 3046f4ceee9SWaiman Long } 3056f4ceee9SWaiman Long EXPORT_SYMBOL_GPL(cpus_read_trylock); 3066f4ceee9SWaiman Long 3078f553c49SThomas Gleixner void cpus_read_unlock(void) 308a9d9baa1SAshok Raj { 309fc8dffd3SThomas Gleixner percpu_up_read(&cpu_hotplug_lock); 310a9d9baa1SAshok Raj } 3118f553c49SThomas Gleixner EXPORT_SYMBOL_GPL(cpus_read_unlock); 312a9d9baa1SAshok Raj 3138f553c49SThomas Gleixner void cpus_write_lock(void) 314d221938cSGautham R Shenoy { 315fc8dffd3SThomas Gleixner percpu_down_write(&cpu_hotplug_lock); 316d221938cSGautham R Shenoy } 317d221938cSGautham R Shenoy 3188f553c49SThomas Gleixner void cpus_write_unlock(void) 319d221938cSGautham R Shenoy { 320fc8dffd3SThomas Gleixner percpu_up_write(&cpu_hotplug_lock); 321fc8dffd3SThomas Gleixner } 322fc8dffd3SThomas Gleixner 323fc8dffd3SThomas Gleixner void lockdep_assert_cpus_held(void) 324fc8dffd3SThomas Gleixner { 325ce48c457SValentin Schneider /* 326ce48c457SValentin Schneider * We can't have hotplug operations before userspace starts running, 327ce48c457SValentin Schneider * and some init codepaths will knowingly not take the hotplug lock. 328ce48c457SValentin Schneider * This is all valid, so mute lockdep until it makes sense to report 329ce48c457SValentin Schneider * unheld locks. 330ce48c457SValentin Schneider */ 331ce48c457SValentin Schneider if (system_state < SYSTEM_RUNNING) 332ce48c457SValentin Schneider return; 333ce48c457SValentin Schneider 334fc8dffd3SThomas Gleixner percpu_rwsem_assert_held(&cpu_hotplug_lock); 335d221938cSGautham R Shenoy } 33679a6cdebSLai Jiangshan 33743759fe5SFrederic Weisbecker #ifdef CONFIG_LOCKDEP 33843759fe5SFrederic Weisbecker int lockdep_is_cpus_held(void) 33943759fe5SFrederic Weisbecker { 34043759fe5SFrederic Weisbecker return percpu_rwsem_is_held(&cpu_hotplug_lock); 34143759fe5SFrederic Weisbecker } 34243759fe5SFrederic Weisbecker #endif 34343759fe5SFrederic Weisbecker 344cb92173dSPeter Zijlstra static void lockdep_acquire_cpus_lock(void) 345cb92173dSPeter Zijlstra { 3461751060eSPeter Zijlstra rwsem_acquire(&cpu_hotplug_lock.dep_map, 0, 0, _THIS_IP_); 347cb92173dSPeter Zijlstra } 348cb92173dSPeter Zijlstra 349cb92173dSPeter Zijlstra static void lockdep_release_cpus_lock(void) 350cb92173dSPeter Zijlstra { 3511751060eSPeter Zijlstra rwsem_release(&cpu_hotplug_lock.dep_map, _THIS_IP_); 352cb92173dSPeter Zijlstra } 353cb92173dSPeter Zijlstra 35416e53dbfSSrivatsa S. Bhat /* 35516e53dbfSSrivatsa S. Bhat * Wait for currently running CPU hotplug operations to complete (if any) and 35616e53dbfSSrivatsa S. Bhat * disable future CPU hotplug (from sysfs). The 'cpu_add_remove_lock' protects 35716e53dbfSSrivatsa S. Bhat * the 'cpu_hotplug_disabled' flag. The same lock is also acquired by the 35816e53dbfSSrivatsa S. Bhat * hotplug path before performing hotplug operations. So acquiring that lock 35916e53dbfSSrivatsa S. Bhat * guarantees mutual exclusion from any currently running hotplug operations. 36016e53dbfSSrivatsa S. Bhat */ 36116e53dbfSSrivatsa S. Bhat void cpu_hotplug_disable(void) 36216e53dbfSSrivatsa S. Bhat { 36316e53dbfSSrivatsa S. Bhat cpu_maps_update_begin(); 36489af7ba5SVitaly Kuznetsov cpu_hotplug_disabled++; 36516e53dbfSSrivatsa S. Bhat cpu_maps_update_done(); 36616e53dbfSSrivatsa S. Bhat } 36732145c46SVitaly Kuznetsov EXPORT_SYMBOL_GPL(cpu_hotplug_disable); 36816e53dbfSSrivatsa S. Bhat 36901b41159SLianwei Wang static void __cpu_hotplug_enable(void) 37001b41159SLianwei Wang { 37101b41159SLianwei Wang if (WARN_ONCE(!cpu_hotplug_disabled, "Unbalanced cpu hotplug enable\n")) 37201b41159SLianwei Wang return; 37301b41159SLianwei Wang cpu_hotplug_disabled--; 37401b41159SLianwei Wang } 37501b41159SLianwei Wang 37616e53dbfSSrivatsa S. Bhat void cpu_hotplug_enable(void) 37716e53dbfSSrivatsa S. Bhat { 37816e53dbfSSrivatsa S. Bhat cpu_maps_update_begin(); 37901b41159SLianwei Wang __cpu_hotplug_enable(); 38016e53dbfSSrivatsa S. Bhat cpu_maps_update_done(); 38116e53dbfSSrivatsa S. Bhat } 38232145c46SVitaly Kuznetsov EXPORT_SYMBOL_GPL(cpu_hotplug_enable); 383cb92173dSPeter Zijlstra 384cb92173dSPeter Zijlstra #else 385cb92173dSPeter Zijlstra 386cb92173dSPeter Zijlstra static void lockdep_acquire_cpus_lock(void) 387cb92173dSPeter Zijlstra { 388cb92173dSPeter Zijlstra } 389cb92173dSPeter Zijlstra 390cb92173dSPeter Zijlstra static void lockdep_release_cpus_lock(void) 391cb92173dSPeter Zijlstra { 392cb92173dSPeter Zijlstra } 393cb92173dSPeter Zijlstra 394b9d10be7SToshi Kani #endif /* CONFIG_HOTPLUG_CPU */ 39579a6cdebSLai Jiangshan 396a74cfffbSThomas Gleixner /* 397a74cfffbSThomas Gleixner * Architectures that need SMT-specific errata handling during SMT hotplug 398a74cfffbSThomas Gleixner * should override this. 399a74cfffbSThomas Gleixner */ 400a74cfffbSThomas Gleixner void __weak arch_smt_update(void) { } 401a74cfffbSThomas Gleixner 4020cc3cd21SThomas Gleixner #ifdef CONFIG_HOTPLUG_SMT 4030cc3cd21SThomas Gleixner enum cpuhp_smt_control cpu_smt_control __read_mostly = CPU_SMT_ENABLED; 404bc2d8d26SThomas Gleixner 4058e1b706bSJiri Kosina void __init cpu_smt_disable(bool force) 4060cc3cd21SThomas Gleixner { 407e1572f1dSVitaly Kuznetsov if (!cpu_smt_possible()) 4088e1b706bSJiri Kosina return; 4098e1b706bSJiri Kosina 4108e1b706bSJiri Kosina if (force) { 4110cc3cd21SThomas Gleixner pr_info("SMT: Force disabled\n"); 4120cc3cd21SThomas Gleixner cpu_smt_control = CPU_SMT_FORCE_DISABLED; 4138e1b706bSJiri Kosina } else { 414d0e7d144SBorislav Petkov pr_info("SMT: disabled\n"); 4158e1b706bSJiri Kosina cpu_smt_control = CPU_SMT_DISABLED; 4160cc3cd21SThomas Gleixner } 4178e1b706bSJiri Kosina } 4188e1b706bSJiri Kosina 419fee0aedeSThomas Gleixner /* 420fee0aedeSThomas Gleixner * The decision whether SMT is supported can only be done after the full 421b284909aSJosh Poimboeuf * CPU identification. Called from architecture code. 422fee0aedeSThomas Gleixner */ 423fee0aedeSThomas Gleixner void __init cpu_smt_check_topology(void) 424fee0aedeSThomas Gleixner { 425b284909aSJosh Poimboeuf if (!topology_smt_supported()) 426fee0aedeSThomas Gleixner cpu_smt_control = CPU_SMT_NOT_SUPPORTED; 427fee0aedeSThomas Gleixner } 428fee0aedeSThomas Gleixner 4298e1b706bSJiri Kosina static int __init smt_cmdline_disable(char *str) 4308e1b706bSJiri Kosina { 4318e1b706bSJiri Kosina cpu_smt_disable(str && !strcmp(str, "force")); 4320cc3cd21SThomas Gleixner return 0; 4330cc3cd21SThomas Gleixner } 4340cc3cd21SThomas Gleixner early_param("nosmt", smt_cmdline_disable); 4350cc3cd21SThomas Gleixner 4360cc3cd21SThomas Gleixner static inline bool cpu_smt_allowed(unsigned int cpu) 4370cc3cd21SThomas Gleixner { 438b284909aSJosh Poimboeuf if (cpu_smt_control == CPU_SMT_ENABLED) 4390cc3cd21SThomas Gleixner return true; 4400cc3cd21SThomas Gleixner 441b284909aSJosh Poimboeuf if (topology_is_primary_thread(cpu)) 4420cc3cd21SThomas Gleixner return true; 4430cc3cd21SThomas Gleixner 4440cc3cd21SThomas Gleixner /* 4450cc3cd21SThomas Gleixner * On x86 it's required to boot all logical CPUs at least once so 4460cc3cd21SThomas Gleixner * that the init code can get a chance to set CR4.MCE on each 447182e073fSEthon Paul * CPU. Otherwise, a broadcasted MCE observing CR4.MCE=0b on any 4480cc3cd21SThomas Gleixner * core will shutdown the machine. 4490cc3cd21SThomas Gleixner */ 450e797bda3SThomas Gleixner return !cpumask_test_cpu(cpu, &cpus_booted_once_mask); 4510cc3cd21SThomas Gleixner } 452e1572f1dSVitaly Kuznetsov 453e1572f1dSVitaly Kuznetsov /* Returns true if SMT is not supported of forcefully (irreversibly) disabled */ 454e1572f1dSVitaly Kuznetsov bool cpu_smt_possible(void) 455e1572f1dSVitaly Kuznetsov { 456e1572f1dSVitaly Kuznetsov return cpu_smt_control != CPU_SMT_FORCE_DISABLED && 457e1572f1dSVitaly Kuznetsov cpu_smt_control != CPU_SMT_NOT_SUPPORTED; 458e1572f1dSVitaly Kuznetsov } 459e1572f1dSVitaly Kuznetsov EXPORT_SYMBOL_GPL(cpu_smt_possible); 4600cc3cd21SThomas Gleixner #else 4610cc3cd21SThomas Gleixner static inline bool cpu_smt_allowed(unsigned int cpu) { return true; } 4620cc3cd21SThomas Gleixner #endif 4630cc3cd21SThomas Gleixner 4644dddfb5fSPeter Zijlstra static inline enum cpuhp_state 4654dddfb5fSPeter Zijlstra cpuhp_set_state(struct cpuhp_cpu_state *st, enum cpuhp_state target) 4664dddfb5fSPeter Zijlstra { 4674dddfb5fSPeter Zijlstra enum cpuhp_state prev_state = st->state; 468*2ea46c6fSPeter Zijlstra bool bringup = st->state < target; 4694dddfb5fSPeter Zijlstra 4704dddfb5fSPeter Zijlstra st->rollback = false; 4714dddfb5fSPeter Zijlstra st->last = NULL; 4724dddfb5fSPeter Zijlstra 4734dddfb5fSPeter Zijlstra st->target = target; 4744dddfb5fSPeter Zijlstra st->single = false; 475*2ea46c6fSPeter Zijlstra st->bringup = bringup; 476*2ea46c6fSPeter Zijlstra if (cpu_dying(st->cpu) != !bringup) 477*2ea46c6fSPeter Zijlstra set_cpu_dying(st->cpu, !bringup); 4784dddfb5fSPeter Zijlstra 4794dddfb5fSPeter Zijlstra return prev_state; 4804dddfb5fSPeter Zijlstra } 4814dddfb5fSPeter Zijlstra 4824dddfb5fSPeter Zijlstra static inline void 4834dddfb5fSPeter Zijlstra cpuhp_reset_state(struct cpuhp_cpu_state *st, enum cpuhp_state prev_state) 4844dddfb5fSPeter Zijlstra { 485*2ea46c6fSPeter Zijlstra bool bringup = !st->bringup; 486*2ea46c6fSPeter Zijlstra 487453e4108SVincent Donnefort st->target = prev_state; 488453e4108SVincent Donnefort 489453e4108SVincent Donnefort /* 490453e4108SVincent Donnefort * Already rolling back. No need invert the bringup value or to change 491453e4108SVincent Donnefort * the current state. 492453e4108SVincent Donnefort */ 493453e4108SVincent Donnefort if (st->rollback) 494453e4108SVincent Donnefort return; 495453e4108SVincent Donnefort 4964dddfb5fSPeter Zijlstra st->rollback = true; 4974dddfb5fSPeter Zijlstra 4984dddfb5fSPeter Zijlstra /* 4994dddfb5fSPeter Zijlstra * If we have st->last we need to undo partial multi_instance of this 5004dddfb5fSPeter Zijlstra * state first. Otherwise start undo at the previous state. 5014dddfb5fSPeter Zijlstra */ 5024dddfb5fSPeter Zijlstra if (!st->last) { 5034dddfb5fSPeter Zijlstra if (st->bringup) 5044dddfb5fSPeter Zijlstra st->state--; 5054dddfb5fSPeter Zijlstra else 5064dddfb5fSPeter Zijlstra st->state++; 5074dddfb5fSPeter Zijlstra } 5084dddfb5fSPeter Zijlstra 509*2ea46c6fSPeter Zijlstra st->bringup = bringup; 510*2ea46c6fSPeter Zijlstra if (cpu_dying(st->cpu) != !bringup) 511*2ea46c6fSPeter Zijlstra set_cpu_dying(st->cpu, !bringup); 5124dddfb5fSPeter Zijlstra } 5134dddfb5fSPeter Zijlstra 5144dddfb5fSPeter Zijlstra /* Regular hotplug invocation of the AP hotplug thread */ 5154dddfb5fSPeter Zijlstra static void __cpuhp_kick_ap(struct cpuhp_cpu_state *st) 5164dddfb5fSPeter Zijlstra { 5174dddfb5fSPeter Zijlstra if (!st->single && st->state == st->target) 5184dddfb5fSPeter Zijlstra return; 5194dddfb5fSPeter Zijlstra 5204dddfb5fSPeter Zijlstra st->result = 0; 5214dddfb5fSPeter Zijlstra /* 5224dddfb5fSPeter Zijlstra * Make sure the above stores are visible before should_run becomes 5234dddfb5fSPeter Zijlstra * true. Paired with the mb() above in cpuhp_thread_fun() 5244dddfb5fSPeter Zijlstra */ 5254dddfb5fSPeter Zijlstra smp_mb(); 5264dddfb5fSPeter Zijlstra st->should_run = true; 5274dddfb5fSPeter Zijlstra wake_up_process(st->thread); 5285ebe7742SPeter Zijlstra wait_for_ap_thread(st, st->bringup); 5294dddfb5fSPeter Zijlstra } 5304dddfb5fSPeter Zijlstra 5314dddfb5fSPeter Zijlstra static int cpuhp_kick_ap(struct cpuhp_cpu_state *st, enum cpuhp_state target) 5324dddfb5fSPeter Zijlstra { 5334dddfb5fSPeter Zijlstra enum cpuhp_state prev_state; 5344dddfb5fSPeter Zijlstra int ret; 5354dddfb5fSPeter Zijlstra 5364dddfb5fSPeter Zijlstra prev_state = cpuhp_set_state(st, target); 5374dddfb5fSPeter Zijlstra __cpuhp_kick_ap(st); 5384dddfb5fSPeter Zijlstra if ((ret = st->result)) { 5394dddfb5fSPeter Zijlstra cpuhp_reset_state(st, prev_state); 5404dddfb5fSPeter Zijlstra __cpuhp_kick_ap(st); 5414dddfb5fSPeter Zijlstra } 5424dddfb5fSPeter Zijlstra 5434dddfb5fSPeter Zijlstra return ret; 5444dddfb5fSPeter Zijlstra } 5459cd4f1a4SThomas Gleixner 5468df3e07eSThomas Gleixner static int bringup_wait_for_ap(unsigned int cpu) 5478df3e07eSThomas Gleixner { 5488df3e07eSThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 5498df3e07eSThomas Gleixner 5509cd4f1a4SThomas Gleixner /* Wait for the CPU to reach CPUHP_AP_ONLINE_IDLE */ 5515ebe7742SPeter Zijlstra wait_for_ap_thread(st, true); 552dea1d0f5SThomas Gleixner if (WARN_ON_ONCE((!cpu_online(cpu)))) 553dea1d0f5SThomas Gleixner return -ECANCELED; 5549cd4f1a4SThomas Gleixner 55545178ac0SPeter Zijlstra /* Unpark the hotplug thread of the target cpu */ 5569cd4f1a4SThomas Gleixner kthread_unpark(st->thread); 5579cd4f1a4SThomas Gleixner 5580cc3cd21SThomas Gleixner /* 5590cc3cd21SThomas Gleixner * SMT soft disabling on X86 requires to bring the CPU out of the 5600cc3cd21SThomas Gleixner * BIOS 'wait for SIPI' state in order to set the CR4.MCE bit. The 561f5602011SJiri Kosina * CPU marked itself as booted_once in notify_cpu_starting() so the 5620cc3cd21SThomas Gleixner * cpu_smt_allowed() check will now return false if this is not the 5630cc3cd21SThomas Gleixner * primary sibling. 5640cc3cd21SThomas Gleixner */ 5650cc3cd21SThomas Gleixner if (!cpu_smt_allowed(cpu)) 5660cc3cd21SThomas Gleixner return -ECANCELED; 5670cc3cd21SThomas Gleixner 5684dddfb5fSPeter Zijlstra if (st->target <= CPUHP_AP_ONLINE_IDLE) 5694dddfb5fSPeter Zijlstra return 0; 5704dddfb5fSPeter Zijlstra 5714dddfb5fSPeter Zijlstra return cpuhp_kick_ap(st, st->target); 5728df3e07eSThomas Gleixner } 5738df3e07eSThomas Gleixner 574ba997462SThomas Gleixner static int bringup_cpu(unsigned int cpu) 575ba997462SThomas Gleixner { 576ba997462SThomas Gleixner struct task_struct *idle = idle_thread_get(cpu); 577ba997462SThomas Gleixner int ret; 578ba997462SThomas Gleixner 579aa877175SBoris Ostrovsky /* 580aa877175SBoris Ostrovsky * Some architectures have to walk the irq descriptors to 581aa877175SBoris Ostrovsky * setup the vector space for the cpu which comes online. 582aa877175SBoris Ostrovsky * Prevent irq alloc/free across the bringup. 583aa877175SBoris Ostrovsky */ 584aa877175SBoris Ostrovsky irq_lock_sparse(); 585aa877175SBoris Ostrovsky 586ba997462SThomas Gleixner /* Arch-specific enabling code. */ 587ba997462SThomas Gleixner ret = __cpu_up(cpu, idle); 588aa877175SBoris Ostrovsky irq_unlock_sparse(); 589530e9b76SThomas Gleixner if (ret) 590ba997462SThomas Gleixner return ret; 5919cd4f1a4SThomas Gleixner return bringup_wait_for_ap(cpu); 592ba997462SThomas Gleixner } 593ba997462SThomas Gleixner 594bf2c59fcSPeter Zijlstra static int finish_cpu(unsigned int cpu) 595bf2c59fcSPeter Zijlstra { 596bf2c59fcSPeter Zijlstra struct task_struct *idle = idle_thread_get(cpu); 597bf2c59fcSPeter Zijlstra struct mm_struct *mm = idle->active_mm; 598bf2c59fcSPeter Zijlstra 599bf2c59fcSPeter Zijlstra /* 600bf2c59fcSPeter Zijlstra * idle_task_exit() will have switched to &init_mm, now 601bf2c59fcSPeter Zijlstra * clean up any remaining active_mm state. 602bf2c59fcSPeter Zijlstra */ 603bf2c59fcSPeter Zijlstra if (mm != &init_mm) 604bf2c59fcSPeter Zijlstra idle->active_mm = &init_mm; 605bf2c59fcSPeter Zijlstra mmdrop(mm); 606bf2c59fcSPeter Zijlstra return 0; 607bf2c59fcSPeter Zijlstra } 608bf2c59fcSPeter Zijlstra 6092e1a3483SThomas Gleixner /* 6102e1a3483SThomas Gleixner * Hotplug state machine related functions 6112e1a3483SThomas Gleixner */ 6122e1a3483SThomas Gleixner 613453e4108SVincent Donnefort /* 614453e4108SVincent Donnefort * Get the next state to run. Empty ones will be skipped. Returns true if a 615453e4108SVincent Donnefort * state must be run. 616453e4108SVincent Donnefort * 617453e4108SVincent Donnefort * st->state will be modified ahead of time, to match state_to_run, as if it 618453e4108SVincent Donnefort * has already ran. 619453e4108SVincent Donnefort */ 620453e4108SVincent Donnefort static bool cpuhp_next_state(bool bringup, 621453e4108SVincent Donnefort enum cpuhp_state *state_to_run, 622453e4108SVincent Donnefort struct cpuhp_cpu_state *st, 623453e4108SVincent Donnefort enum cpuhp_state target) 6242e1a3483SThomas Gleixner { 625453e4108SVincent Donnefort do { 626453e4108SVincent Donnefort if (bringup) { 627453e4108SVincent Donnefort if (st->state >= target) 628453e4108SVincent Donnefort return false; 629453e4108SVincent Donnefort 630453e4108SVincent Donnefort *state_to_run = ++st->state; 631453e4108SVincent Donnefort } else { 632453e4108SVincent Donnefort if (st->state <= target) 633453e4108SVincent Donnefort return false; 634453e4108SVincent Donnefort 635453e4108SVincent Donnefort *state_to_run = st->state--; 636453e4108SVincent Donnefort } 637453e4108SVincent Donnefort 638453e4108SVincent Donnefort if (!cpuhp_step_empty(bringup, cpuhp_get_step(*state_to_run))) 639453e4108SVincent Donnefort break; 640453e4108SVincent Donnefort } while (true); 641453e4108SVincent Donnefort 642453e4108SVincent Donnefort return true; 643453e4108SVincent Donnefort } 644453e4108SVincent Donnefort 645453e4108SVincent Donnefort static int cpuhp_invoke_callback_range(bool bringup, 646453e4108SVincent Donnefort unsigned int cpu, 647453e4108SVincent Donnefort struct cpuhp_cpu_state *st, 648453e4108SVincent Donnefort enum cpuhp_state target) 649453e4108SVincent Donnefort { 650453e4108SVincent Donnefort enum cpuhp_state state; 651453e4108SVincent Donnefort int err = 0; 652453e4108SVincent Donnefort 653453e4108SVincent Donnefort while (cpuhp_next_state(bringup, &state, st, target)) { 654453e4108SVincent Donnefort err = cpuhp_invoke_callback(cpu, state, bringup, NULL, NULL); 655453e4108SVincent Donnefort if (err) 656453e4108SVincent Donnefort break; 657453e4108SVincent Donnefort } 658453e4108SVincent Donnefort 659453e4108SVincent Donnefort return err; 6602e1a3483SThomas Gleixner } 6612e1a3483SThomas Gleixner 662206b9235SThomas Gleixner static inline bool can_rollback_cpu(struct cpuhp_cpu_state *st) 663206b9235SThomas Gleixner { 664206b9235SThomas Gleixner if (IS_ENABLED(CONFIG_HOTPLUG_CPU)) 665206b9235SThomas Gleixner return true; 666206b9235SThomas Gleixner /* 667206b9235SThomas Gleixner * When CPU hotplug is disabled, then taking the CPU down is not 668206b9235SThomas Gleixner * possible because takedown_cpu() and the architecture and 669206b9235SThomas Gleixner * subsystem specific mechanisms are not available. So the CPU 670206b9235SThomas Gleixner * which would be completely unplugged again needs to stay around 671206b9235SThomas Gleixner * in the current state. 672206b9235SThomas Gleixner */ 673206b9235SThomas Gleixner return st->state <= CPUHP_BRINGUP_CPU; 674206b9235SThomas Gleixner } 675206b9235SThomas Gleixner 6762e1a3483SThomas Gleixner static int cpuhp_up_callbacks(unsigned int cpu, struct cpuhp_cpu_state *st, 677a724632cSThomas Gleixner enum cpuhp_state target) 6782e1a3483SThomas Gleixner { 6792e1a3483SThomas Gleixner enum cpuhp_state prev_state = st->state; 6802e1a3483SThomas Gleixner int ret = 0; 6812e1a3483SThomas Gleixner 682453e4108SVincent Donnefort ret = cpuhp_invoke_callback_range(true, cpu, st, target); 6832e1a3483SThomas Gleixner if (ret) { 684453e4108SVincent Donnefort cpuhp_reset_state(st, prev_state); 685453e4108SVincent Donnefort if (can_rollback_cpu(st)) 686453e4108SVincent Donnefort WARN_ON(cpuhp_invoke_callback_range(false, cpu, st, 687453e4108SVincent Donnefort prev_state)); 6882e1a3483SThomas Gleixner } 6892e1a3483SThomas Gleixner return ret; 6902e1a3483SThomas Gleixner } 6912e1a3483SThomas Gleixner 6924cb28cedSThomas Gleixner /* 6934cb28cedSThomas Gleixner * The cpu hotplug threads manage the bringup and teardown of the cpus 6944cb28cedSThomas Gleixner */ 6954cb28cedSThomas Gleixner static void cpuhp_create(unsigned int cpu) 6964cb28cedSThomas Gleixner { 6974cb28cedSThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 6984cb28cedSThomas Gleixner 6995ebe7742SPeter Zijlstra init_completion(&st->done_up); 7005ebe7742SPeter Zijlstra init_completion(&st->done_down); 701*2ea46c6fSPeter Zijlstra st->cpu = cpu; 7024cb28cedSThomas Gleixner } 7034cb28cedSThomas Gleixner 7044cb28cedSThomas Gleixner static int cpuhp_should_run(unsigned int cpu) 7054cb28cedSThomas Gleixner { 7064cb28cedSThomas Gleixner struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); 7074cb28cedSThomas Gleixner 7084cb28cedSThomas Gleixner return st->should_run; 7094cb28cedSThomas Gleixner } 7104cb28cedSThomas Gleixner 7114cb28cedSThomas Gleixner /* 7124cb28cedSThomas Gleixner * Execute teardown/startup callbacks on the plugged cpu. Also used to invoke 7134cb28cedSThomas Gleixner * callbacks when a state gets [un]installed at runtime. 7144dddfb5fSPeter Zijlstra * 7154dddfb5fSPeter Zijlstra * Each invocation of this function by the smpboot thread does a single AP 7164dddfb5fSPeter Zijlstra * state callback. 7174dddfb5fSPeter Zijlstra * 7184dddfb5fSPeter Zijlstra * It has 3 modes of operation: 7194dddfb5fSPeter Zijlstra * - single: runs st->cb_state 7204dddfb5fSPeter Zijlstra * - up: runs ++st->state, while st->state < st->target 7214dddfb5fSPeter Zijlstra * - down: runs st->state--, while st->state > st->target 7224dddfb5fSPeter Zijlstra * 7234dddfb5fSPeter Zijlstra * When complete or on error, should_run is cleared and the completion is fired. 7244cb28cedSThomas Gleixner */ 7254cb28cedSThomas Gleixner static void cpuhp_thread_fun(unsigned int cpu) 7264cb28cedSThomas Gleixner { 7274cb28cedSThomas Gleixner struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); 7284dddfb5fSPeter Zijlstra bool bringup = st->bringup; 7294dddfb5fSPeter Zijlstra enum cpuhp_state state; 7304cb28cedSThomas Gleixner 731f8b7530aSNeeraj Upadhyay if (WARN_ON_ONCE(!st->should_run)) 732f8b7530aSNeeraj Upadhyay return; 733f8b7530aSNeeraj Upadhyay 7344cb28cedSThomas Gleixner /* 7354dddfb5fSPeter Zijlstra * ACQUIRE for the cpuhp_should_run() load of ->should_run. Ensures 7364dddfb5fSPeter Zijlstra * that if we see ->should_run we also see the rest of the state. 7374cb28cedSThomas Gleixner */ 7384cb28cedSThomas Gleixner smp_mb(); 7394dddfb5fSPeter Zijlstra 740cb92173dSPeter Zijlstra /* 741cb92173dSPeter Zijlstra * The BP holds the hotplug lock, but we're now running on the AP, 742cb92173dSPeter Zijlstra * ensure that anybody asserting the lock is held, will actually find 743cb92173dSPeter Zijlstra * it so. 744cb92173dSPeter Zijlstra */ 745cb92173dSPeter Zijlstra lockdep_acquire_cpus_lock(); 7465f4b55e1SPeter Zijlstra cpuhp_lock_acquire(bringup); 7474dddfb5fSPeter Zijlstra 748a724632cSThomas Gleixner if (st->single) { 7494dddfb5fSPeter Zijlstra state = st->cb_state; 7504dddfb5fSPeter Zijlstra st->should_run = false; 7514dddfb5fSPeter Zijlstra } else { 752453e4108SVincent Donnefort st->should_run = cpuhp_next_state(bringup, &state, st, st->target); 753453e4108SVincent Donnefort if (!st->should_run) 754453e4108SVincent Donnefort goto end; 7554dddfb5fSPeter Zijlstra } 7564dddfb5fSPeter Zijlstra 7574dddfb5fSPeter Zijlstra WARN_ON_ONCE(!cpuhp_is_ap_state(state)); 7584dddfb5fSPeter Zijlstra 7594dddfb5fSPeter Zijlstra if (cpuhp_is_atomic_state(state)) { 7604cb28cedSThomas Gleixner local_irq_disable(); 7614dddfb5fSPeter Zijlstra st->result = cpuhp_invoke_callback(cpu, state, bringup, st->node, &st->last); 7624cb28cedSThomas Gleixner local_irq_enable(); 7633b9d6da6SSebastian Andrzej Siewior 7644dddfb5fSPeter Zijlstra /* 7654dddfb5fSPeter Zijlstra * STARTING/DYING must not fail! 7664dddfb5fSPeter Zijlstra */ 7674dddfb5fSPeter Zijlstra WARN_ON_ONCE(st->result); 7684cb28cedSThomas Gleixner } else { 7694dddfb5fSPeter Zijlstra st->result = cpuhp_invoke_callback(cpu, state, bringup, st->node, &st->last); 7704cb28cedSThomas Gleixner } 7714dddfb5fSPeter Zijlstra 7724dddfb5fSPeter Zijlstra if (st->result) { 7734dddfb5fSPeter Zijlstra /* 7744dddfb5fSPeter Zijlstra * If we fail on a rollback, we're up a creek without no 7754dddfb5fSPeter Zijlstra * paddle, no way forward, no way back. We loose, thanks for 7764dddfb5fSPeter Zijlstra * playing. 7774dddfb5fSPeter Zijlstra */ 7784dddfb5fSPeter Zijlstra WARN_ON_ONCE(st->rollback); 7794dddfb5fSPeter Zijlstra st->should_run = false; 7804dddfb5fSPeter Zijlstra } 7814dddfb5fSPeter Zijlstra 782453e4108SVincent Donnefort end: 7835f4b55e1SPeter Zijlstra cpuhp_lock_release(bringup); 784cb92173dSPeter Zijlstra lockdep_release_cpus_lock(); 7854dddfb5fSPeter Zijlstra 7864dddfb5fSPeter Zijlstra if (!st->should_run) 7875ebe7742SPeter Zijlstra complete_ap_thread(st, bringup); 7884cb28cedSThomas Gleixner } 7894cb28cedSThomas Gleixner 7904cb28cedSThomas Gleixner /* Invoke a single callback on a remote cpu */ 791a724632cSThomas Gleixner static int 792cf392d10SThomas Gleixner cpuhp_invoke_ap_callback(int cpu, enum cpuhp_state state, bool bringup, 793cf392d10SThomas Gleixner struct hlist_node *node) 7944cb28cedSThomas Gleixner { 7954cb28cedSThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 7964dddfb5fSPeter Zijlstra int ret; 7974cb28cedSThomas Gleixner 7984cb28cedSThomas Gleixner if (!cpu_online(cpu)) 7994cb28cedSThomas Gleixner return 0; 8004cb28cedSThomas Gleixner 8015f4b55e1SPeter Zijlstra cpuhp_lock_acquire(false); 8025f4b55e1SPeter Zijlstra cpuhp_lock_release(false); 8035f4b55e1SPeter Zijlstra 8045f4b55e1SPeter Zijlstra cpuhp_lock_acquire(true); 8055f4b55e1SPeter Zijlstra cpuhp_lock_release(true); 80649dfe2a6SThomas Gleixner 8076a4e2451SThomas Gleixner /* 8086a4e2451SThomas Gleixner * If we are up and running, use the hotplug thread. For early calls 8096a4e2451SThomas Gleixner * we invoke the thread function directly. 8106a4e2451SThomas Gleixner */ 8116a4e2451SThomas Gleixner if (!st->thread) 81296abb968SPeter Zijlstra return cpuhp_invoke_callback(cpu, state, bringup, node, NULL); 8136a4e2451SThomas Gleixner 8144dddfb5fSPeter Zijlstra st->rollback = false; 8154dddfb5fSPeter Zijlstra st->last = NULL; 8164dddfb5fSPeter Zijlstra 8174dddfb5fSPeter Zijlstra st->node = node; 8184dddfb5fSPeter Zijlstra st->bringup = bringup; 8194cb28cedSThomas Gleixner st->cb_state = state; 820a724632cSThomas Gleixner st->single = true; 8214dddfb5fSPeter Zijlstra 8224dddfb5fSPeter Zijlstra __cpuhp_kick_ap(st); 823a724632cSThomas Gleixner 8244cb28cedSThomas Gleixner /* 8254dddfb5fSPeter Zijlstra * If we failed and did a partial, do a rollback. 8264cb28cedSThomas Gleixner */ 8274dddfb5fSPeter Zijlstra if ((ret = st->result) && st->last) { 8284dddfb5fSPeter Zijlstra st->rollback = true; 8294dddfb5fSPeter Zijlstra st->bringup = !bringup; 8304dddfb5fSPeter Zijlstra 8314dddfb5fSPeter Zijlstra __cpuhp_kick_ap(st); 8324cb28cedSThomas Gleixner } 8334cb28cedSThomas Gleixner 8341f7c70d6SThomas Gleixner /* 8351f7c70d6SThomas Gleixner * Clean up the leftovers so the next hotplug operation wont use stale 8361f7c70d6SThomas Gleixner * data. 8371f7c70d6SThomas Gleixner */ 8381f7c70d6SThomas Gleixner st->node = st->last = NULL; 8394dddfb5fSPeter Zijlstra return ret; 8401cf4f629SThomas Gleixner } 8411cf4f629SThomas Gleixner 8421cf4f629SThomas Gleixner static int cpuhp_kick_ap_work(unsigned int cpu) 8431cf4f629SThomas Gleixner { 8441cf4f629SThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 8454dddfb5fSPeter Zijlstra enum cpuhp_state prev_state = st->state; 8464dddfb5fSPeter Zijlstra int ret; 8471cf4f629SThomas Gleixner 8485f4b55e1SPeter Zijlstra cpuhp_lock_acquire(false); 8495f4b55e1SPeter Zijlstra cpuhp_lock_release(false); 8505f4b55e1SPeter Zijlstra 8515f4b55e1SPeter Zijlstra cpuhp_lock_acquire(true); 8525f4b55e1SPeter Zijlstra cpuhp_lock_release(true); 8534dddfb5fSPeter Zijlstra 8544dddfb5fSPeter Zijlstra trace_cpuhp_enter(cpu, st->target, prev_state, cpuhp_kick_ap_work); 8554dddfb5fSPeter Zijlstra ret = cpuhp_kick_ap(st, st->target); 8564dddfb5fSPeter Zijlstra trace_cpuhp_exit(cpu, st->state, prev_state, ret); 8574dddfb5fSPeter Zijlstra 8584dddfb5fSPeter Zijlstra return ret; 8594cb28cedSThomas Gleixner } 8604cb28cedSThomas Gleixner 8614cb28cedSThomas Gleixner static struct smp_hotplug_thread cpuhp_threads = { 8624cb28cedSThomas Gleixner .store = &cpuhp_state.thread, 8634cb28cedSThomas Gleixner .create = &cpuhp_create, 8644cb28cedSThomas Gleixner .thread_should_run = cpuhp_should_run, 8654cb28cedSThomas Gleixner .thread_fn = cpuhp_thread_fun, 8664cb28cedSThomas Gleixner .thread_comm = "cpuhp/%u", 8674cb28cedSThomas Gleixner .selfparking = true, 8684cb28cedSThomas Gleixner }; 8694cb28cedSThomas Gleixner 8704cb28cedSThomas Gleixner void __init cpuhp_threads_init(void) 8714cb28cedSThomas Gleixner { 8724cb28cedSThomas Gleixner BUG_ON(smpboot_register_percpu_thread(&cpuhp_threads)); 8734cb28cedSThomas Gleixner kthread_unpark(this_cpu_read(cpuhp_state.thread)); 8744cb28cedSThomas Gleixner } 8754cb28cedSThomas Gleixner 876777c6e0dSMichal Hocko #ifdef CONFIG_HOTPLUG_CPU 8778ff00399SNicholas Piggin #ifndef arch_clear_mm_cpumask_cpu 8788ff00399SNicholas Piggin #define arch_clear_mm_cpumask_cpu(cpu, mm) cpumask_clear_cpu(cpu, mm_cpumask(mm)) 8798ff00399SNicholas Piggin #endif 8808ff00399SNicholas Piggin 881e4cc2f87SAnton Vorontsov /** 882e4cc2f87SAnton Vorontsov * clear_tasks_mm_cpumask - Safely clear tasks' mm_cpumask for a CPU 883e4cc2f87SAnton Vorontsov * @cpu: a CPU id 884e4cc2f87SAnton Vorontsov * 885e4cc2f87SAnton Vorontsov * This function walks all processes, finds a valid mm struct for each one and 886e4cc2f87SAnton Vorontsov * then clears a corresponding bit in mm's cpumask. While this all sounds 887e4cc2f87SAnton Vorontsov * trivial, there are various non-obvious corner cases, which this function 888e4cc2f87SAnton Vorontsov * tries to solve in a safe manner. 889e4cc2f87SAnton Vorontsov * 890e4cc2f87SAnton Vorontsov * Also note that the function uses a somewhat relaxed locking scheme, so it may 891e4cc2f87SAnton Vorontsov * be called only for an already offlined CPU. 892e4cc2f87SAnton Vorontsov */ 893cb79295eSAnton Vorontsov void clear_tasks_mm_cpumask(int cpu) 894cb79295eSAnton Vorontsov { 895cb79295eSAnton Vorontsov struct task_struct *p; 896cb79295eSAnton Vorontsov 897cb79295eSAnton Vorontsov /* 898cb79295eSAnton Vorontsov * This function is called after the cpu is taken down and marked 899cb79295eSAnton Vorontsov * offline, so its not like new tasks will ever get this cpu set in 900cb79295eSAnton Vorontsov * their mm mask. -- Peter Zijlstra 901cb79295eSAnton Vorontsov * Thus, we may use rcu_read_lock() here, instead of grabbing 902cb79295eSAnton Vorontsov * full-fledged tasklist_lock. 903cb79295eSAnton Vorontsov */ 904e4cc2f87SAnton Vorontsov WARN_ON(cpu_online(cpu)); 905cb79295eSAnton Vorontsov rcu_read_lock(); 906cb79295eSAnton Vorontsov for_each_process(p) { 907cb79295eSAnton Vorontsov struct task_struct *t; 908cb79295eSAnton Vorontsov 909e4cc2f87SAnton Vorontsov /* 910e4cc2f87SAnton Vorontsov * Main thread might exit, but other threads may still have 911e4cc2f87SAnton Vorontsov * a valid mm. Find one. 912e4cc2f87SAnton Vorontsov */ 913cb79295eSAnton Vorontsov t = find_lock_task_mm(p); 914cb79295eSAnton Vorontsov if (!t) 915cb79295eSAnton Vorontsov continue; 9168ff00399SNicholas Piggin arch_clear_mm_cpumask_cpu(cpu, t->mm); 917cb79295eSAnton Vorontsov task_unlock(t); 918cb79295eSAnton Vorontsov } 919cb79295eSAnton Vorontsov rcu_read_unlock(); 920cb79295eSAnton Vorontsov } 921cb79295eSAnton Vorontsov 9221da177e4SLinus Torvalds /* Take this CPU down. */ 92371cf5aeeSMathias Krause static int take_cpu_down(void *_param) 9241da177e4SLinus Torvalds { 9254baa0afcSThomas Gleixner struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); 9264baa0afcSThomas Gleixner enum cpuhp_state target = max((int)st->target, CPUHP_AP_OFFLINE); 927090e77c3SThomas Gleixner int err, cpu = smp_processor_id(); 928724a8688SPeter Zijlstra int ret; 9291da177e4SLinus Torvalds 9301da177e4SLinus Torvalds /* Ensure this CPU doesn't handle any more interrupts. */ 9311da177e4SLinus Torvalds err = __cpu_disable(); 9321da177e4SLinus Torvalds if (err < 0) 933f3705136SZwane Mwaikambo return err; 934f3705136SZwane Mwaikambo 935a724632cSThomas Gleixner /* 936453e4108SVincent Donnefort * Must be called from CPUHP_TEARDOWN_CPU, which means, as we are going 937453e4108SVincent Donnefort * down, that the current state is CPUHP_TEARDOWN_CPU - 1. 938a724632cSThomas Gleixner */ 939453e4108SVincent Donnefort WARN_ON(st->state != (CPUHP_TEARDOWN_CPU - 1)); 940453e4108SVincent Donnefort 9414baa0afcSThomas Gleixner /* Invoke the former CPU_DYING callbacks */ 942453e4108SVincent Donnefort ret = cpuhp_invoke_callback_range(false, cpu, st, target); 943453e4108SVincent Donnefort 944724a8688SPeter Zijlstra /* 945724a8688SPeter Zijlstra * DYING must not fail! 946724a8688SPeter Zijlstra */ 947724a8688SPeter Zijlstra WARN_ON_ONCE(ret); 9484baa0afcSThomas Gleixner 94952c063d1SThomas Gleixner /* Give up timekeeping duties */ 95052c063d1SThomas Gleixner tick_handover_do_timer(); 9511b72d432SThomas Gleixner /* Remove CPU from timer broadcasting */ 9521b72d432SThomas Gleixner tick_offline_cpu(cpu); 95314e568e7SThomas Gleixner /* Park the stopper thread */ 954090e77c3SThomas Gleixner stop_machine_park(cpu); 955f3705136SZwane Mwaikambo return 0; 9561da177e4SLinus Torvalds } 9571da177e4SLinus Torvalds 95898458172SThomas Gleixner static int takedown_cpu(unsigned int cpu) 9591da177e4SLinus Torvalds { 960e69aab13SThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 96198458172SThomas Gleixner int err; 9621da177e4SLinus Torvalds 9632a58c527SThomas Gleixner /* Park the smpboot threads */ 9641cf4f629SThomas Gleixner kthread_park(per_cpu_ptr(&cpuhp_state, cpu)->thread); 9651cf4f629SThomas Gleixner 9666acce3efSPeter Zijlstra /* 967a8994181SThomas Gleixner * Prevent irq alloc/free while the dying cpu reorganizes the 968a8994181SThomas Gleixner * interrupt affinities. 969a8994181SThomas Gleixner */ 970a8994181SThomas Gleixner irq_lock_sparse(); 971a8994181SThomas Gleixner 972a8994181SThomas Gleixner /* 9736acce3efSPeter Zijlstra * So now all preempt/rcu users must observe !cpu_active(). 9746acce3efSPeter Zijlstra */ 975210e2133SSebastian Andrzej Siewior err = stop_machine_cpuslocked(take_cpu_down, NULL, cpumask_of(cpu)); 97604321587SRusty Russell if (err) { 9773b9d6da6SSebastian Andrzej Siewior /* CPU refused to die */ 978a8994181SThomas Gleixner irq_unlock_sparse(); 9793b9d6da6SSebastian Andrzej Siewior /* Unpark the hotplug thread so we can rollback there */ 9803b9d6da6SSebastian Andrzej Siewior kthread_unpark(per_cpu_ptr(&cpuhp_state, cpu)->thread); 98198458172SThomas Gleixner return err; 9821da177e4SLinus Torvalds } 98304321587SRusty Russell BUG_ON(cpu_online(cpu)); 9841da177e4SLinus Torvalds 98548c5ccaeSPeter Zijlstra /* 9865b1ead68SBrendan Jackman * The teardown callback for CPUHP_AP_SCHED_STARTING will have removed 9875b1ead68SBrendan Jackman * all runnable tasks from the CPU, there's only the idle task left now 98848c5ccaeSPeter Zijlstra * that the migration thread is done doing the stop_machine thing. 98951a96c77SPeter Zijlstra * 99051a96c77SPeter Zijlstra * Wait for the stop thread to go away. 99148c5ccaeSPeter Zijlstra */ 9925ebe7742SPeter Zijlstra wait_for_ap_thread(st, false); 993e69aab13SThomas Gleixner BUG_ON(st->state != CPUHP_AP_IDLE_DEAD); 9941da177e4SLinus Torvalds 995a8994181SThomas Gleixner /* Interrupts are moved away from the dying cpu, reenable alloc/free */ 996a8994181SThomas Gleixner irq_unlock_sparse(); 997a8994181SThomas Gleixner 998345527b1SPreeti U Murthy hotplug_cpu__broadcast_tick_pull(cpu); 9991da177e4SLinus Torvalds /* This actually kills the CPU. */ 10001da177e4SLinus Torvalds __cpu_die(cpu); 10011da177e4SLinus Torvalds 1002a49b116dSThomas Gleixner tick_cleanup_dead_cpu(cpu); 1003a58163d8SPaul E. McKenney rcutree_migrate_callbacks(cpu); 100498458172SThomas Gleixner return 0; 100598458172SThomas Gleixner } 10061da177e4SLinus Torvalds 100771f87b2fSThomas Gleixner static void cpuhp_complete_idle_dead(void *arg) 100871f87b2fSThomas Gleixner { 100971f87b2fSThomas Gleixner struct cpuhp_cpu_state *st = arg; 101071f87b2fSThomas Gleixner 10115ebe7742SPeter Zijlstra complete_ap_thread(st, false); 101271f87b2fSThomas Gleixner } 101371f87b2fSThomas Gleixner 1014e69aab13SThomas Gleixner void cpuhp_report_idle_dead(void) 1015e69aab13SThomas Gleixner { 1016e69aab13SThomas Gleixner struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); 1017e69aab13SThomas Gleixner 1018e69aab13SThomas Gleixner BUG_ON(st->state != CPUHP_AP_OFFLINE); 101927d50c7eSThomas Gleixner rcu_report_dead(smp_processor_id()); 102071f87b2fSThomas Gleixner st->state = CPUHP_AP_IDLE_DEAD; 102171f87b2fSThomas Gleixner /* 102271f87b2fSThomas Gleixner * We cannot call complete after rcu_report_dead() so we delegate it 102371f87b2fSThomas Gleixner * to an online cpu. 102471f87b2fSThomas Gleixner */ 102571f87b2fSThomas Gleixner smp_call_function_single(cpumask_first(cpu_online_mask), 102671f87b2fSThomas Gleixner cpuhp_complete_idle_dead, st, 0); 1027e69aab13SThomas Gleixner } 1028e69aab13SThomas Gleixner 10294dddfb5fSPeter Zijlstra static int cpuhp_down_callbacks(unsigned int cpu, struct cpuhp_cpu_state *st, 10304dddfb5fSPeter Zijlstra enum cpuhp_state target) 10314dddfb5fSPeter Zijlstra { 10324dddfb5fSPeter Zijlstra enum cpuhp_state prev_state = st->state; 10334dddfb5fSPeter Zijlstra int ret = 0; 10344dddfb5fSPeter Zijlstra 1035453e4108SVincent Donnefort ret = cpuhp_invoke_callback_range(false, cpu, st, target); 10364dddfb5fSPeter Zijlstra if (ret) { 1037453e4108SVincent Donnefort 1038453e4108SVincent Donnefort cpuhp_reset_state(st, prev_state); 1039453e4108SVincent Donnefort 104069fa6eb7SThomas Gleixner if (st->state < prev_state) 1041453e4108SVincent Donnefort WARN_ON(cpuhp_invoke_callback_range(true, cpu, st, 1042453e4108SVincent Donnefort prev_state)); 10434dddfb5fSPeter Zijlstra } 1044453e4108SVincent Donnefort 10454dddfb5fSPeter Zijlstra return ret; 10464dddfb5fSPeter Zijlstra } 1047cff7d378SThomas Gleixner 104898458172SThomas Gleixner /* Requires cpu_add_remove_lock to be held */ 1049af1f4045SThomas Gleixner static int __ref _cpu_down(unsigned int cpu, int tasks_frozen, 1050af1f4045SThomas Gleixner enum cpuhp_state target) 105198458172SThomas Gleixner { 1052cff7d378SThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 1053cff7d378SThomas Gleixner int prev_state, ret = 0; 105498458172SThomas Gleixner 105598458172SThomas Gleixner if (num_online_cpus() == 1) 105698458172SThomas Gleixner return -EBUSY; 105798458172SThomas Gleixner 1058757c989bSThomas Gleixner if (!cpu_present(cpu)) 105998458172SThomas Gleixner return -EINVAL; 106098458172SThomas Gleixner 10618f553c49SThomas Gleixner cpus_write_lock(); 106298458172SThomas Gleixner 106398458172SThomas Gleixner cpuhp_tasks_frozen = tasks_frozen; 106498458172SThomas Gleixner 10654dddfb5fSPeter Zijlstra prev_state = cpuhp_set_state(st, target); 10661cf4f629SThomas Gleixner /* 10671cf4f629SThomas Gleixner * If the current CPU state is in the range of the AP hotplug thread, 10681cf4f629SThomas Gleixner * then we need to kick the thread. 10691cf4f629SThomas Gleixner */ 10708df3e07eSThomas Gleixner if (st->state > CPUHP_TEARDOWN_CPU) { 10714dddfb5fSPeter Zijlstra st->target = max((int)target, CPUHP_TEARDOWN_CPU); 10721cf4f629SThomas Gleixner ret = cpuhp_kick_ap_work(cpu); 10731cf4f629SThomas Gleixner /* 10741cf4f629SThomas Gleixner * The AP side has done the error rollback already. Just 10751cf4f629SThomas Gleixner * return the error code.. 10761cf4f629SThomas Gleixner */ 10771cf4f629SThomas Gleixner if (ret) 10781cf4f629SThomas Gleixner goto out; 10791cf4f629SThomas Gleixner 10801cf4f629SThomas Gleixner /* 10811cf4f629SThomas Gleixner * We might have stopped still in the range of the AP hotplug 10821cf4f629SThomas Gleixner * thread. Nothing to do anymore. 10831cf4f629SThomas Gleixner */ 10848df3e07eSThomas Gleixner if (st->state > CPUHP_TEARDOWN_CPU) 10851cf4f629SThomas Gleixner goto out; 10864dddfb5fSPeter Zijlstra 10874dddfb5fSPeter Zijlstra st->target = target; 10881cf4f629SThomas Gleixner } 10891cf4f629SThomas Gleixner /* 10908df3e07eSThomas Gleixner * The AP brought itself down to CPUHP_TEARDOWN_CPU. So we need 10911cf4f629SThomas Gleixner * to do the further cleanups. 10921cf4f629SThomas Gleixner */ 1093a724632cSThomas Gleixner ret = cpuhp_down_callbacks(cpu, st, target); 109462f25069SVincent Donnefort if (ret && st->state < prev_state) { 109562f25069SVincent Donnefort if (st->state == CPUHP_TEARDOWN_CPU) { 10964dddfb5fSPeter Zijlstra cpuhp_reset_state(st, prev_state); 10974dddfb5fSPeter Zijlstra __cpuhp_kick_ap(st); 109862f25069SVincent Donnefort } else { 109962f25069SVincent Donnefort WARN(1, "DEAD callback error for CPU%d", cpu); 110062f25069SVincent Donnefort } 11013b9d6da6SSebastian Andrzej Siewior } 110298458172SThomas Gleixner 11031cf4f629SThomas Gleixner out: 11048f553c49SThomas Gleixner cpus_write_unlock(); 1105941154bdSThomas Gleixner /* 1106941154bdSThomas Gleixner * Do post unplug cleanup. This is still protected against 1107941154bdSThomas Gleixner * concurrent CPU hotplug via cpu_add_remove_lock. 1108941154bdSThomas Gleixner */ 1109941154bdSThomas Gleixner lockup_detector_cleanup(); 1110a74cfffbSThomas Gleixner arch_smt_update(); 1111cff7d378SThomas Gleixner return ret; 1112e3920fb4SRafael J. Wysocki } 1113e3920fb4SRafael J. Wysocki 1114cc1fe215SThomas Gleixner static int cpu_down_maps_locked(unsigned int cpu, enum cpuhp_state target) 1115cc1fe215SThomas Gleixner { 1116cc1fe215SThomas Gleixner if (cpu_hotplug_disabled) 1117cc1fe215SThomas Gleixner return -EBUSY; 1118cc1fe215SThomas Gleixner return _cpu_down(cpu, 0, target); 1119cc1fe215SThomas Gleixner } 1120cc1fe215SThomas Gleixner 112133c3736eSQais Yousef static int cpu_down(unsigned int cpu, enum cpuhp_state target) 1122e3920fb4SRafael J. Wysocki { 11239ea09af3SHeiko Carstens int err; 1124e3920fb4SRafael J. Wysocki 1125d221938cSGautham R Shenoy cpu_maps_update_begin(); 1126cc1fe215SThomas Gleixner err = cpu_down_maps_locked(cpu, target); 1127d221938cSGautham R Shenoy cpu_maps_update_done(); 11281da177e4SLinus Torvalds return err; 11291da177e4SLinus Torvalds } 11304dddfb5fSPeter Zijlstra 113133c3736eSQais Yousef /** 113233c3736eSQais Yousef * cpu_device_down - Bring down a cpu device 113333c3736eSQais Yousef * @dev: Pointer to the cpu device to offline 113433c3736eSQais Yousef * 113533c3736eSQais Yousef * This function is meant to be used by device core cpu subsystem only. 113633c3736eSQais Yousef * 113733c3736eSQais Yousef * Other subsystems should use remove_cpu() instead. 113833c3736eSQais Yousef */ 113933c3736eSQais Yousef int cpu_device_down(struct device *dev) 1140af1f4045SThomas Gleixner { 114133c3736eSQais Yousef return cpu_down(dev->id, CPUHP_OFFLINE); 1142af1f4045SThomas Gleixner } 11434dddfb5fSPeter Zijlstra 114493ef1429SQais Yousef int remove_cpu(unsigned int cpu) 114593ef1429SQais Yousef { 114693ef1429SQais Yousef int ret; 114793ef1429SQais Yousef 114893ef1429SQais Yousef lock_device_hotplug(); 114993ef1429SQais Yousef ret = device_offline(get_cpu_device(cpu)); 115093ef1429SQais Yousef unlock_device_hotplug(); 115193ef1429SQais Yousef 115293ef1429SQais Yousef return ret; 115393ef1429SQais Yousef } 115493ef1429SQais Yousef EXPORT_SYMBOL_GPL(remove_cpu); 115593ef1429SQais Yousef 11560441a559SQais Yousef void smp_shutdown_nonboot_cpus(unsigned int primary_cpu) 11570441a559SQais Yousef { 11580441a559SQais Yousef unsigned int cpu; 11590441a559SQais Yousef int error; 11600441a559SQais Yousef 11610441a559SQais Yousef cpu_maps_update_begin(); 11620441a559SQais Yousef 11630441a559SQais Yousef /* 11640441a559SQais Yousef * Make certain the cpu I'm about to reboot on is online. 11650441a559SQais Yousef * 11660441a559SQais Yousef * This is inline to what migrate_to_reboot_cpu() already do. 11670441a559SQais Yousef */ 11680441a559SQais Yousef if (!cpu_online(primary_cpu)) 11690441a559SQais Yousef primary_cpu = cpumask_first(cpu_online_mask); 11700441a559SQais Yousef 11710441a559SQais Yousef for_each_online_cpu(cpu) { 11720441a559SQais Yousef if (cpu == primary_cpu) 11730441a559SQais Yousef continue; 11740441a559SQais Yousef 11750441a559SQais Yousef error = cpu_down_maps_locked(cpu, CPUHP_OFFLINE); 11760441a559SQais Yousef if (error) { 11770441a559SQais Yousef pr_err("Failed to offline CPU%d - error=%d", 11780441a559SQais Yousef cpu, error); 11790441a559SQais Yousef break; 11800441a559SQais Yousef } 11810441a559SQais Yousef } 11820441a559SQais Yousef 11830441a559SQais Yousef /* 11840441a559SQais Yousef * Ensure all but the reboot CPU are offline. 11850441a559SQais Yousef */ 11860441a559SQais Yousef BUG_ON(num_online_cpus() > 1); 11870441a559SQais Yousef 11880441a559SQais Yousef /* 11890441a559SQais Yousef * Make sure the CPUs won't be enabled by someone else after this 11900441a559SQais Yousef * point. Kexec will reboot to a new kernel shortly resetting 11910441a559SQais Yousef * everything along the way. 11920441a559SQais Yousef */ 11930441a559SQais Yousef cpu_hotplug_disabled++; 11940441a559SQais Yousef 11950441a559SQais Yousef cpu_maps_update_done(); 11960441a559SQais Yousef } 11974dddfb5fSPeter Zijlstra 11984dddfb5fSPeter Zijlstra #else 11994dddfb5fSPeter Zijlstra #define takedown_cpu NULL 12001da177e4SLinus Torvalds #endif /*CONFIG_HOTPLUG_CPU*/ 12011da177e4SLinus Torvalds 12024baa0afcSThomas Gleixner /** 1203ee1e714bSThomas Gleixner * notify_cpu_starting(cpu) - Invoke the callbacks on the starting CPU 12044baa0afcSThomas Gleixner * @cpu: cpu that just started 12054baa0afcSThomas Gleixner * 12064baa0afcSThomas Gleixner * It must be called by the arch code on the new cpu, before the new cpu 12074baa0afcSThomas Gleixner * enables interrupts and before the "boot" cpu returns from __cpu_up(). 12084baa0afcSThomas Gleixner */ 12094baa0afcSThomas Gleixner void notify_cpu_starting(unsigned int cpu) 12104baa0afcSThomas Gleixner { 12114baa0afcSThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 12124baa0afcSThomas Gleixner enum cpuhp_state target = min((int)st->target, CPUHP_AP_ONLINE); 1213724a8688SPeter Zijlstra int ret; 12144baa0afcSThomas Gleixner 12150c6d4576SSebastian Andrzej Siewior rcu_cpu_starting(cpu); /* Enables RCU usage on this CPU. */ 1216e797bda3SThomas Gleixner cpumask_set_cpu(cpu, &cpus_booted_once_mask); 1217453e4108SVincent Donnefort ret = cpuhp_invoke_callback_range(true, cpu, st, target); 1218453e4108SVincent Donnefort 1219724a8688SPeter Zijlstra /* 1220724a8688SPeter Zijlstra * STARTING must not fail! 1221724a8688SPeter Zijlstra */ 1222724a8688SPeter Zijlstra WARN_ON_ONCE(ret); 12234baa0afcSThomas Gleixner } 12244baa0afcSThomas Gleixner 1225949338e3SThomas Gleixner /* 12269cd4f1a4SThomas Gleixner * Called from the idle task. Wake up the controlling task which brings the 122745178ac0SPeter Zijlstra * hotplug thread of the upcoming CPU up and then delegates the rest of the 122845178ac0SPeter Zijlstra * online bringup to the hotplug thread. 1229949338e3SThomas Gleixner */ 12308df3e07eSThomas Gleixner void cpuhp_online_idle(enum cpuhp_state state) 1231949338e3SThomas Gleixner { 12328df3e07eSThomas Gleixner struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); 12338df3e07eSThomas Gleixner 12348df3e07eSThomas Gleixner /* Happens for the boot cpu */ 12358df3e07eSThomas Gleixner if (state != CPUHP_AP_ONLINE_IDLE) 12368df3e07eSThomas Gleixner return; 12378df3e07eSThomas Gleixner 123845178ac0SPeter Zijlstra /* 123945178ac0SPeter Zijlstra * Unpart the stopper thread before we start the idle loop (and start 124045178ac0SPeter Zijlstra * scheduling); this ensures the stopper task is always available. 124145178ac0SPeter Zijlstra */ 124245178ac0SPeter Zijlstra stop_machine_unpark(smp_processor_id()); 124345178ac0SPeter Zijlstra 12448df3e07eSThomas Gleixner st->state = CPUHP_AP_ONLINE_IDLE; 12455ebe7742SPeter Zijlstra complete_ap_thread(st, true); 1246949338e3SThomas Gleixner } 1247949338e3SThomas Gleixner 1248e3920fb4SRafael J. Wysocki /* Requires cpu_add_remove_lock to be held */ 1249af1f4045SThomas Gleixner static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target) 12501da177e4SLinus Torvalds { 1251cff7d378SThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 12523bb5d2eeSSuresh Siddha struct task_struct *idle; 12532e1a3483SThomas Gleixner int ret = 0; 12541da177e4SLinus Torvalds 12558f553c49SThomas Gleixner cpus_write_lock(); 125638498a67SThomas Gleixner 1257757c989bSThomas Gleixner if (!cpu_present(cpu)) { 12585e5041f3SYasuaki Ishimatsu ret = -EINVAL; 12595e5041f3SYasuaki Ishimatsu goto out; 12605e5041f3SYasuaki Ishimatsu } 12615e5041f3SYasuaki Ishimatsu 1262757c989bSThomas Gleixner /* 126333c3736eSQais Yousef * The caller of cpu_up() might have raced with another 126433c3736eSQais Yousef * caller. Nothing to do. 1265757c989bSThomas Gleixner */ 1266757c989bSThomas Gleixner if (st->state >= target) 1267757c989bSThomas Gleixner goto out; 1268757c989bSThomas Gleixner 1269757c989bSThomas Gleixner if (st->state == CPUHP_OFFLINE) { 1270cff7d378SThomas Gleixner /* Let it fail before we try to bring the cpu up */ 12713bb5d2eeSSuresh Siddha idle = idle_thread_get(cpu); 12723bb5d2eeSSuresh Siddha if (IS_ERR(idle)) { 12733bb5d2eeSSuresh Siddha ret = PTR_ERR(idle); 127438498a67SThomas Gleixner goto out; 12753bb5d2eeSSuresh Siddha } 1276757c989bSThomas Gleixner } 127738498a67SThomas Gleixner 1278ba997462SThomas Gleixner cpuhp_tasks_frozen = tasks_frozen; 1279ba997462SThomas Gleixner 12804dddfb5fSPeter Zijlstra cpuhp_set_state(st, target); 12811cf4f629SThomas Gleixner /* 12821cf4f629SThomas Gleixner * If the current CPU state is in the range of the AP hotplug thread, 12831cf4f629SThomas Gleixner * then we need to kick the thread once more. 12841cf4f629SThomas Gleixner */ 12858df3e07eSThomas Gleixner if (st->state > CPUHP_BRINGUP_CPU) { 12861cf4f629SThomas Gleixner ret = cpuhp_kick_ap_work(cpu); 12871cf4f629SThomas Gleixner /* 12881cf4f629SThomas Gleixner * The AP side has done the error rollback already. Just 12891cf4f629SThomas Gleixner * return the error code.. 12901cf4f629SThomas Gleixner */ 12911cf4f629SThomas Gleixner if (ret) 12921cf4f629SThomas Gleixner goto out; 12931cf4f629SThomas Gleixner } 12941cf4f629SThomas Gleixner 12951cf4f629SThomas Gleixner /* 12961cf4f629SThomas Gleixner * Try to reach the target state. We max out on the BP at 12978df3e07eSThomas Gleixner * CPUHP_BRINGUP_CPU. After that the AP hotplug thread is 12981cf4f629SThomas Gleixner * responsible for bringing it up to the target state. 12991cf4f629SThomas Gleixner */ 13008df3e07eSThomas Gleixner target = min((int)target, CPUHP_BRINGUP_CPU); 1301a724632cSThomas Gleixner ret = cpuhp_up_callbacks(cpu, st, target); 130238498a67SThomas Gleixner out: 13038f553c49SThomas Gleixner cpus_write_unlock(); 1304a74cfffbSThomas Gleixner arch_smt_update(); 13051da177e4SLinus Torvalds return ret; 13061da177e4SLinus Torvalds } 1307e3920fb4SRafael J. Wysocki 130833c3736eSQais Yousef static int cpu_up(unsigned int cpu, enum cpuhp_state target) 1309e3920fb4SRafael J. Wysocki { 1310e3920fb4SRafael J. Wysocki int err = 0; 1311cf23422bSminskey guo 1312e0b582ecSRusty Russell if (!cpu_possible(cpu)) { 131384117da5SFabian Frederick pr_err("can't online cpu %d because it is not configured as may-hotadd at boot time\n", 131484117da5SFabian Frederick cpu); 131587d5e023SChen Gong #if defined(CONFIG_IA64) 131684117da5SFabian Frederick pr_err("please check additional_cpus= boot parameter\n"); 131773e753a5SKAMEZAWA Hiroyuki #endif 131873e753a5SKAMEZAWA Hiroyuki return -EINVAL; 131973e753a5SKAMEZAWA Hiroyuki } 1320e3920fb4SRafael J. Wysocki 132101b0f197SToshi Kani err = try_online_node(cpu_to_node(cpu)); 1322cf23422bSminskey guo if (err) 1323cf23422bSminskey guo return err; 1324cf23422bSminskey guo 1325d221938cSGautham R Shenoy cpu_maps_update_begin(); 1326e761b772SMax Krasnyansky 1327e761b772SMax Krasnyansky if (cpu_hotplug_disabled) { 1328e3920fb4SRafael J. Wysocki err = -EBUSY; 1329e761b772SMax Krasnyansky goto out; 1330e761b772SMax Krasnyansky } 133105736e4aSThomas Gleixner if (!cpu_smt_allowed(cpu)) { 133205736e4aSThomas Gleixner err = -EPERM; 133305736e4aSThomas Gleixner goto out; 133405736e4aSThomas Gleixner } 1335e761b772SMax Krasnyansky 1336af1f4045SThomas Gleixner err = _cpu_up(cpu, 0, target); 1337e761b772SMax Krasnyansky out: 1338d221938cSGautham R Shenoy cpu_maps_update_done(); 1339e3920fb4SRafael J. Wysocki return err; 1340e3920fb4SRafael J. Wysocki } 1341af1f4045SThomas Gleixner 134233c3736eSQais Yousef /** 134333c3736eSQais Yousef * cpu_device_up - Bring up a cpu device 134433c3736eSQais Yousef * @dev: Pointer to the cpu device to online 134533c3736eSQais Yousef * 134633c3736eSQais Yousef * This function is meant to be used by device core cpu subsystem only. 134733c3736eSQais Yousef * 134833c3736eSQais Yousef * Other subsystems should use add_cpu() instead. 134933c3736eSQais Yousef */ 135033c3736eSQais Yousef int cpu_device_up(struct device *dev) 1351af1f4045SThomas Gleixner { 135233c3736eSQais Yousef return cpu_up(dev->id, CPUHP_ONLINE); 1353af1f4045SThomas Gleixner } 1354e3920fb4SRafael J. Wysocki 135593ef1429SQais Yousef int add_cpu(unsigned int cpu) 135693ef1429SQais Yousef { 135793ef1429SQais Yousef int ret; 135893ef1429SQais Yousef 135993ef1429SQais Yousef lock_device_hotplug(); 136093ef1429SQais Yousef ret = device_online(get_cpu_device(cpu)); 136193ef1429SQais Yousef unlock_device_hotplug(); 136293ef1429SQais Yousef 136393ef1429SQais Yousef return ret; 136493ef1429SQais Yousef } 136593ef1429SQais Yousef EXPORT_SYMBOL_GPL(add_cpu); 136693ef1429SQais Yousef 1367d720f986SQais Yousef /** 1368d720f986SQais Yousef * bringup_hibernate_cpu - Bring up the CPU that we hibernated on 1369d720f986SQais Yousef * @sleep_cpu: The cpu we hibernated on and should be brought up. 1370d720f986SQais Yousef * 1371d720f986SQais Yousef * On some architectures like arm64, we can hibernate on any CPU, but on 1372d720f986SQais Yousef * wake up the CPU we hibernated on might be offline as a side effect of 1373d720f986SQais Yousef * using maxcpus= for example. 1374d720f986SQais Yousef */ 1375d720f986SQais Yousef int bringup_hibernate_cpu(unsigned int sleep_cpu) 1376d720f986SQais Yousef { 1377d720f986SQais Yousef int ret; 1378d720f986SQais Yousef 1379d720f986SQais Yousef if (!cpu_online(sleep_cpu)) { 1380d720f986SQais Yousef pr_info("Hibernated on a CPU that is offline! Bringing CPU up.\n"); 138133c3736eSQais Yousef ret = cpu_up(sleep_cpu, CPUHP_ONLINE); 1382d720f986SQais Yousef if (ret) { 1383d720f986SQais Yousef pr_err("Failed to bring hibernate-CPU up!\n"); 1384d720f986SQais Yousef return ret; 1385d720f986SQais Yousef } 1386d720f986SQais Yousef } 1387d720f986SQais Yousef return 0; 1388d720f986SQais Yousef } 1389d720f986SQais Yousef 1390b99a2659SQais Yousef void bringup_nonboot_cpus(unsigned int setup_max_cpus) 1391b99a2659SQais Yousef { 1392b99a2659SQais Yousef unsigned int cpu; 1393b99a2659SQais Yousef 1394b99a2659SQais Yousef for_each_present_cpu(cpu) { 1395b99a2659SQais Yousef if (num_online_cpus() >= setup_max_cpus) 1396b99a2659SQais Yousef break; 1397b99a2659SQais Yousef if (!cpu_online(cpu)) 139833c3736eSQais Yousef cpu_up(cpu, CPUHP_ONLINE); 1399b99a2659SQais Yousef } 1400b99a2659SQais Yousef } 1401e3920fb4SRafael J. Wysocki 1402f3de4be9SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_SMP 1403e0b582ecSRusty Russell static cpumask_var_t frozen_cpus; 1404e3920fb4SRafael J. Wysocki 1405fb7fb84aSQais Yousef int freeze_secondary_cpus(int primary) 1406e3920fb4SRafael J. Wysocki { 1407d391e552SJames Morse int cpu, error = 0; 1408e3920fb4SRafael J. Wysocki 1409d221938cSGautham R Shenoy cpu_maps_update_begin(); 14109ca12ac0SNicholas Piggin if (primary == -1) { 14119ca12ac0SNicholas Piggin primary = cpumask_first(cpu_online_mask); 14129ca12ac0SNicholas Piggin if (!housekeeping_cpu(primary, HK_FLAG_TIMER)) 14139ca12ac0SNicholas Piggin primary = housekeeping_any_cpu(HK_FLAG_TIMER); 14149ca12ac0SNicholas Piggin } else { 1415d391e552SJames Morse if (!cpu_online(primary)) 1416d391e552SJames Morse primary = cpumask_first(cpu_online_mask); 14179ca12ac0SNicholas Piggin } 14189ca12ac0SNicholas Piggin 14199ee349adSXiaotian Feng /* 14209ee349adSXiaotian Feng * We take down all of the non-boot CPUs in one shot to avoid races 1421e3920fb4SRafael J. Wysocki * with the userspace trying to use the CPU hotplug at the same time 1422e3920fb4SRafael J. Wysocki */ 1423e0b582ecSRusty Russell cpumask_clear(frozen_cpus); 14246ad4c188SPeter Zijlstra 142584117da5SFabian Frederick pr_info("Disabling non-boot CPUs ...\n"); 1426e3920fb4SRafael J. Wysocki for_each_online_cpu(cpu) { 1427d391e552SJames Morse if (cpu == primary) 1428e3920fb4SRafael J. Wysocki continue; 1429a66d955eSPavankumar Kondeti 1430fb7fb84aSQais Yousef if (pm_wakeup_pending()) { 1431a66d955eSPavankumar Kondeti pr_info("Wakeup pending. Abort CPU freeze\n"); 1432a66d955eSPavankumar Kondeti error = -EBUSY; 1433a66d955eSPavankumar Kondeti break; 1434a66d955eSPavankumar Kondeti } 1435a66d955eSPavankumar Kondeti 1436bb3632c6STodd E Brandt trace_suspend_resume(TPS("CPU_OFF"), cpu, true); 1437af1f4045SThomas Gleixner error = _cpu_down(cpu, 1, CPUHP_OFFLINE); 1438bb3632c6STodd E Brandt trace_suspend_resume(TPS("CPU_OFF"), cpu, false); 1439feae3203SMike Travis if (!error) 1440e0b582ecSRusty Russell cpumask_set_cpu(cpu, frozen_cpus); 1441feae3203SMike Travis else { 144284117da5SFabian Frederick pr_err("Error taking CPU%d down: %d\n", cpu, error); 1443e3920fb4SRafael J. Wysocki break; 1444e3920fb4SRafael J. Wysocki } 1445e3920fb4SRafael J. Wysocki } 144686886e55SJoseph Cihula 144789af7ba5SVitaly Kuznetsov if (!error) 1448e3920fb4SRafael J. Wysocki BUG_ON(num_online_cpus() > 1); 144989af7ba5SVitaly Kuznetsov else 145084117da5SFabian Frederick pr_err("Non-boot CPUs are not disabled\n"); 145189af7ba5SVitaly Kuznetsov 145289af7ba5SVitaly Kuznetsov /* 145389af7ba5SVitaly Kuznetsov * Make sure the CPUs won't be enabled by someone else. We need to do 145456555855SQais Yousef * this even in case of failure as all freeze_secondary_cpus() users are 145556555855SQais Yousef * supposed to do thaw_secondary_cpus() on the failure path. 145689af7ba5SVitaly Kuznetsov */ 145789af7ba5SVitaly Kuznetsov cpu_hotplug_disabled++; 145889af7ba5SVitaly Kuznetsov 1459d221938cSGautham R Shenoy cpu_maps_update_done(); 1460e3920fb4SRafael J. Wysocki return error; 1461e3920fb4SRafael J. Wysocki } 1462e3920fb4SRafael J. Wysocki 146356555855SQais Yousef void __weak arch_thaw_secondary_cpus_begin(void) 1464d0af9eedSSuresh Siddha { 1465d0af9eedSSuresh Siddha } 1466d0af9eedSSuresh Siddha 146756555855SQais Yousef void __weak arch_thaw_secondary_cpus_end(void) 1468d0af9eedSSuresh Siddha { 1469d0af9eedSSuresh Siddha } 1470d0af9eedSSuresh Siddha 147156555855SQais Yousef void thaw_secondary_cpus(void) 1472e3920fb4SRafael J. Wysocki { 1473e3920fb4SRafael J. Wysocki int cpu, error; 1474e3920fb4SRafael J. Wysocki 1475e3920fb4SRafael J. Wysocki /* Allow everyone to use the CPU hotplug again */ 1476d221938cSGautham R Shenoy cpu_maps_update_begin(); 147701b41159SLianwei Wang __cpu_hotplug_enable(); 1478e0b582ecSRusty Russell if (cpumask_empty(frozen_cpus)) 14791d64b9cbSRafael J. Wysocki goto out; 1480e3920fb4SRafael J. Wysocki 148184117da5SFabian Frederick pr_info("Enabling non-boot CPUs ...\n"); 1482d0af9eedSSuresh Siddha 148356555855SQais Yousef arch_thaw_secondary_cpus_begin(); 1484d0af9eedSSuresh Siddha 1485e0b582ecSRusty Russell for_each_cpu(cpu, frozen_cpus) { 1486bb3632c6STodd E Brandt trace_suspend_resume(TPS("CPU_ON"), cpu, true); 1487af1f4045SThomas Gleixner error = _cpu_up(cpu, 1, CPUHP_ONLINE); 1488bb3632c6STodd E Brandt trace_suspend_resume(TPS("CPU_ON"), cpu, false); 1489e3920fb4SRafael J. Wysocki if (!error) { 149084117da5SFabian Frederick pr_info("CPU%d is up\n", cpu); 1491e3920fb4SRafael J. Wysocki continue; 1492e3920fb4SRafael J. Wysocki } 149384117da5SFabian Frederick pr_warn("Error taking CPU%d up: %d\n", cpu, error); 1494e3920fb4SRafael J. Wysocki } 1495d0af9eedSSuresh Siddha 149656555855SQais Yousef arch_thaw_secondary_cpus_end(); 1497d0af9eedSSuresh Siddha 1498e0b582ecSRusty Russell cpumask_clear(frozen_cpus); 14991d64b9cbSRafael J. Wysocki out: 1500d221938cSGautham R Shenoy cpu_maps_update_done(); 1501e3920fb4SRafael J. Wysocki } 1502e0b582ecSRusty Russell 1503d7268a31SFenghua Yu static int __init alloc_frozen_cpus(void) 1504e0b582ecSRusty Russell { 1505e0b582ecSRusty Russell if (!alloc_cpumask_var(&frozen_cpus, GFP_KERNEL|__GFP_ZERO)) 1506e0b582ecSRusty Russell return -ENOMEM; 1507e0b582ecSRusty Russell return 0; 1508e0b582ecSRusty Russell } 1509e0b582ecSRusty Russell core_initcall(alloc_frozen_cpus); 151079cfbdfaSSrivatsa S. Bhat 151179cfbdfaSSrivatsa S. Bhat /* 151279cfbdfaSSrivatsa S. Bhat * When callbacks for CPU hotplug notifications are being executed, we must 151379cfbdfaSSrivatsa S. Bhat * ensure that the state of the system with respect to the tasks being frozen 151479cfbdfaSSrivatsa S. Bhat * or not, as reported by the notification, remains unchanged *throughout the 151579cfbdfaSSrivatsa S. Bhat * duration* of the execution of the callbacks. 151679cfbdfaSSrivatsa S. Bhat * Hence we need to prevent the freezer from racing with regular CPU hotplug. 151779cfbdfaSSrivatsa S. Bhat * 151879cfbdfaSSrivatsa S. Bhat * This synchronization is implemented by mutually excluding regular CPU 151979cfbdfaSSrivatsa S. Bhat * hotplug and Suspend/Hibernate call paths by hooking onto the Suspend/ 152079cfbdfaSSrivatsa S. Bhat * Hibernate notifications. 152179cfbdfaSSrivatsa S. Bhat */ 152279cfbdfaSSrivatsa S. Bhat static int 152379cfbdfaSSrivatsa S. Bhat cpu_hotplug_pm_callback(struct notifier_block *nb, 152479cfbdfaSSrivatsa S. Bhat unsigned long action, void *ptr) 152579cfbdfaSSrivatsa S. Bhat { 152679cfbdfaSSrivatsa S. Bhat switch (action) { 152779cfbdfaSSrivatsa S. Bhat 152879cfbdfaSSrivatsa S. Bhat case PM_SUSPEND_PREPARE: 152979cfbdfaSSrivatsa S. Bhat case PM_HIBERNATION_PREPARE: 153016e53dbfSSrivatsa S. Bhat cpu_hotplug_disable(); 153179cfbdfaSSrivatsa S. Bhat break; 153279cfbdfaSSrivatsa S. Bhat 153379cfbdfaSSrivatsa S. Bhat case PM_POST_SUSPEND: 153479cfbdfaSSrivatsa S. Bhat case PM_POST_HIBERNATION: 153516e53dbfSSrivatsa S. Bhat cpu_hotplug_enable(); 153679cfbdfaSSrivatsa S. Bhat break; 153779cfbdfaSSrivatsa S. Bhat 153879cfbdfaSSrivatsa S. Bhat default: 153979cfbdfaSSrivatsa S. Bhat return NOTIFY_DONE; 154079cfbdfaSSrivatsa S. Bhat } 154179cfbdfaSSrivatsa S. Bhat 154279cfbdfaSSrivatsa S. Bhat return NOTIFY_OK; 154379cfbdfaSSrivatsa S. Bhat } 154479cfbdfaSSrivatsa S. Bhat 154579cfbdfaSSrivatsa S. Bhat 1546d7268a31SFenghua Yu static int __init cpu_hotplug_pm_sync_init(void) 154779cfbdfaSSrivatsa S. Bhat { 15486e32d479SFenghua Yu /* 15496e32d479SFenghua Yu * cpu_hotplug_pm_callback has higher priority than x86 15506e32d479SFenghua Yu * bsp_pm_callback which depends on cpu_hotplug_pm_callback 15516e32d479SFenghua Yu * to disable cpu hotplug to avoid cpu hotplug race. 15526e32d479SFenghua Yu */ 155379cfbdfaSSrivatsa S. Bhat pm_notifier(cpu_hotplug_pm_callback, 0); 155479cfbdfaSSrivatsa S. Bhat return 0; 155579cfbdfaSSrivatsa S. Bhat } 155679cfbdfaSSrivatsa S. Bhat core_initcall(cpu_hotplug_pm_sync_init); 155779cfbdfaSSrivatsa S. Bhat 1558f3de4be9SRafael J. Wysocki #endif /* CONFIG_PM_SLEEP_SMP */ 155968f4f1ecSMax Krasnyansky 15608ce371f9SPeter Zijlstra int __boot_cpu_id; 15618ce371f9SPeter Zijlstra 156268f4f1ecSMax Krasnyansky #endif /* CONFIG_SMP */ 1563b8d317d1SMike Travis 1564cff7d378SThomas Gleixner /* Boot processor state steps */ 156517a2f1ceSLai Jiangshan static struct cpuhp_step cpuhp_hp_states[] = { 1566cff7d378SThomas Gleixner [CPUHP_OFFLINE] = { 1567cff7d378SThomas Gleixner .name = "offline", 15683c1627e9SThomas Gleixner .startup.single = NULL, 15693c1627e9SThomas Gleixner .teardown.single = NULL, 1570cff7d378SThomas Gleixner }, 1571cff7d378SThomas Gleixner #ifdef CONFIG_SMP 1572cff7d378SThomas Gleixner [CPUHP_CREATE_THREADS]= { 1573677f6646SThomas Gleixner .name = "threads:prepare", 15743c1627e9SThomas Gleixner .startup.single = smpboot_create_threads, 15753c1627e9SThomas Gleixner .teardown.single = NULL, 1576757c989bSThomas Gleixner .cant_stop = true, 1577cff7d378SThomas Gleixner }, 157800e16c3dSThomas Gleixner [CPUHP_PERF_PREPARE] = { 15793c1627e9SThomas Gleixner .name = "perf:prepare", 15803c1627e9SThomas Gleixner .startup.single = perf_event_init_cpu, 15813c1627e9SThomas Gleixner .teardown.single = perf_event_exit_cpu, 158200e16c3dSThomas Gleixner }, 15837ee681b2SThomas Gleixner [CPUHP_WORKQUEUE_PREP] = { 15843c1627e9SThomas Gleixner .name = "workqueue:prepare", 15853c1627e9SThomas Gleixner .startup.single = workqueue_prepare_cpu, 15863c1627e9SThomas Gleixner .teardown.single = NULL, 15877ee681b2SThomas Gleixner }, 158827590dc1SThomas Gleixner [CPUHP_HRTIMERS_PREPARE] = { 15893c1627e9SThomas Gleixner .name = "hrtimers:prepare", 15903c1627e9SThomas Gleixner .startup.single = hrtimers_prepare_cpu, 15913c1627e9SThomas Gleixner .teardown.single = hrtimers_dead_cpu, 159227590dc1SThomas Gleixner }, 159331487f83SRichard Weinberger [CPUHP_SMPCFD_PREPARE] = { 1594677f6646SThomas Gleixner .name = "smpcfd:prepare", 15953c1627e9SThomas Gleixner .startup.single = smpcfd_prepare_cpu, 15963c1627e9SThomas Gleixner .teardown.single = smpcfd_dead_cpu, 159731487f83SRichard Weinberger }, 1598e6d4989aSRichard Weinberger [CPUHP_RELAY_PREPARE] = { 1599e6d4989aSRichard Weinberger .name = "relay:prepare", 1600e6d4989aSRichard Weinberger .startup.single = relay_prepare_cpu, 1601e6d4989aSRichard Weinberger .teardown.single = NULL, 1602e6d4989aSRichard Weinberger }, 16036731d4f1SSebastian Andrzej Siewior [CPUHP_SLAB_PREPARE] = { 16046731d4f1SSebastian Andrzej Siewior .name = "slab:prepare", 16056731d4f1SSebastian Andrzej Siewior .startup.single = slab_prepare_cpu, 16066731d4f1SSebastian Andrzej Siewior .teardown.single = slab_dead_cpu, 1607cff7d378SThomas Gleixner }, 16084df83742SThomas Gleixner [CPUHP_RCUTREE_PREP] = { 1609677f6646SThomas Gleixner .name = "RCU/tree:prepare", 16103c1627e9SThomas Gleixner .startup.single = rcutree_prepare_cpu, 16113c1627e9SThomas Gleixner .teardown.single = rcutree_dead_cpu, 16124df83742SThomas Gleixner }, 1613cff7d378SThomas Gleixner /* 16144fae16dfSRichard Cochran * On the tear-down path, timers_dead_cpu() must be invoked 16154fae16dfSRichard Cochran * before blk_mq_queue_reinit_notify() from notify_dead(), 16164fae16dfSRichard Cochran * otherwise a RCU stall occurs. 16174fae16dfSRichard Cochran */ 161826456f87SThomas Gleixner [CPUHP_TIMERS_PREPARE] = { 1619d018031fSMukesh Ojha .name = "timers:prepare", 162026456f87SThomas Gleixner .startup.single = timers_prepare_cpu, 16213c1627e9SThomas Gleixner .teardown.single = timers_dead_cpu, 16224fae16dfSRichard Cochran }, 1623d10ef6f9SThomas Gleixner /* Kicks the plugged cpu into life */ 1624cff7d378SThomas Gleixner [CPUHP_BRINGUP_CPU] = { 1625cff7d378SThomas Gleixner .name = "cpu:bringup", 16263c1627e9SThomas Gleixner .startup.single = bringup_cpu, 1627bf2c59fcSPeter Zijlstra .teardown.single = finish_cpu, 1628757c989bSThomas Gleixner .cant_stop = true, 16294baa0afcSThomas Gleixner }, 1630d10ef6f9SThomas Gleixner /* Final state before CPU kills itself */ 1631d10ef6f9SThomas Gleixner [CPUHP_AP_IDLE_DEAD] = { 1632d10ef6f9SThomas Gleixner .name = "idle:dead", 1633d10ef6f9SThomas Gleixner }, 1634d10ef6f9SThomas Gleixner /* 1635d10ef6f9SThomas Gleixner * Last state before CPU enters the idle loop to die. Transient state 1636d10ef6f9SThomas Gleixner * for synchronization. 1637d10ef6f9SThomas Gleixner */ 1638d10ef6f9SThomas Gleixner [CPUHP_AP_OFFLINE] = { 1639d10ef6f9SThomas Gleixner .name = "ap:offline", 1640d10ef6f9SThomas Gleixner .cant_stop = true, 1641d10ef6f9SThomas Gleixner }, 16429cf7243dSThomas Gleixner /* First state is scheduler control. Interrupts are disabled */ 16439cf7243dSThomas Gleixner [CPUHP_AP_SCHED_STARTING] = { 16449cf7243dSThomas Gleixner .name = "sched:starting", 16453c1627e9SThomas Gleixner .startup.single = sched_cpu_starting, 16463c1627e9SThomas Gleixner .teardown.single = sched_cpu_dying, 16479cf7243dSThomas Gleixner }, 16484df83742SThomas Gleixner [CPUHP_AP_RCUTREE_DYING] = { 1649677f6646SThomas Gleixner .name = "RCU/tree:dying", 16503c1627e9SThomas Gleixner .startup.single = NULL, 16513c1627e9SThomas Gleixner .teardown.single = rcutree_dying_cpu, 16524baa0afcSThomas Gleixner }, 165346febd37SLai Jiangshan [CPUHP_AP_SMPCFD_DYING] = { 165446febd37SLai Jiangshan .name = "smpcfd:dying", 165546febd37SLai Jiangshan .startup.single = NULL, 165646febd37SLai Jiangshan .teardown.single = smpcfd_dying_cpu, 165746febd37SLai Jiangshan }, 1658d10ef6f9SThomas Gleixner /* Entry state on starting. Interrupts enabled from here on. Transient 1659d10ef6f9SThomas Gleixner * state for synchronsization */ 1660d10ef6f9SThomas Gleixner [CPUHP_AP_ONLINE] = { 1661d10ef6f9SThomas Gleixner .name = "ap:online", 1662d10ef6f9SThomas Gleixner }, 166317a2f1ceSLai Jiangshan /* 16641cf12e08SThomas Gleixner * Handled on control processor until the plugged processor manages 166517a2f1ceSLai Jiangshan * this itself. 166617a2f1ceSLai Jiangshan */ 166717a2f1ceSLai Jiangshan [CPUHP_TEARDOWN_CPU] = { 166817a2f1ceSLai Jiangshan .name = "cpu:teardown", 166917a2f1ceSLai Jiangshan .startup.single = NULL, 167017a2f1ceSLai Jiangshan .teardown.single = takedown_cpu, 167117a2f1ceSLai Jiangshan .cant_stop = true, 167217a2f1ceSLai Jiangshan }, 16731cf12e08SThomas Gleixner 16741cf12e08SThomas Gleixner [CPUHP_AP_SCHED_WAIT_EMPTY] = { 16751cf12e08SThomas Gleixner .name = "sched:waitempty", 16761cf12e08SThomas Gleixner .startup.single = NULL, 16771cf12e08SThomas Gleixner .teardown.single = sched_cpu_wait_empty, 16781cf12e08SThomas Gleixner }, 16791cf12e08SThomas Gleixner 1680d10ef6f9SThomas Gleixner /* Handle smpboot threads park/unpark */ 16811cf4f629SThomas Gleixner [CPUHP_AP_SMPBOOT_THREADS] = { 1682677f6646SThomas Gleixner .name = "smpboot/threads:online", 16833c1627e9SThomas Gleixner .startup.single = smpboot_unpark_threads, 1684c4de6569SThomas Gleixner .teardown.single = smpboot_park_threads, 16851cf4f629SThomas Gleixner }, 1686c5cb83bbSThomas Gleixner [CPUHP_AP_IRQ_AFFINITY_ONLINE] = { 1687c5cb83bbSThomas Gleixner .name = "irq/affinity:online", 1688c5cb83bbSThomas Gleixner .startup.single = irq_affinity_online_cpu, 1689c5cb83bbSThomas Gleixner .teardown.single = NULL, 1690c5cb83bbSThomas Gleixner }, 169100e16c3dSThomas Gleixner [CPUHP_AP_PERF_ONLINE] = { 16923c1627e9SThomas Gleixner .name = "perf:online", 16933c1627e9SThomas Gleixner .startup.single = perf_event_init_cpu, 16943c1627e9SThomas Gleixner .teardown.single = perf_event_exit_cpu, 169500e16c3dSThomas Gleixner }, 16969cf57731SPeter Zijlstra [CPUHP_AP_WATCHDOG_ONLINE] = { 16979cf57731SPeter Zijlstra .name = "lockup_detector:online", 16989cf57731SPeter Zijlstra .startup.single = lockup_detector_online_cpu, 16999cf57731SPeter Zijlstra .teardown.single = lockup_detector_offline_cpu, 17009cf57731SPeter Zijlstra }, 17017ee681b2SThomas Gleixner [CPUHP_AP_WORKQUEUE_ONLINE] = { 17023c1627e9SThomas Gleixner .name = "workqueue:online", 17033c1627e9SThomas Gleixner .startup.single = workqueue_online_cpu, 17043c1627e9SThomas Gleixner .teardown.single = workqueue_offline_cpu, 17057ee681b2SThomas Gleixner }, 17064df83742SThomas Gleixner [CPUHP_AP_RCUTREE_ONLINE] = { 1707677f6646SThomas Gleixner .name = "RCU/tree:online", 17083c1627e9SThomas Gleixner .startup.single = rcutree_online_cpu, 17093c1627e9SThomas Gleixner .teardown.single = rcutree_offline_cpu, 17104df83742SThomas Gleixner }, 17114baa0afcSThomas Gleixner #endif 1712d10ef6f9SThomas Gleixner /* 1713d10ef6f9SThomas Gleixner * The dynamically registered state space is here 1714d10ef6f9SThomas Gleixner */ 1715d10ef6f9SThomas Gleixner 1716aaddd7d1SThomas Gleixner #ifdef CONFIG_SMP 1717aaddd7d1SThomas Gleixner /* Last state is scheduler control setting the cpu active */ 1718aaddd7d1SThomas Gleixner [CPUHP_AP_ACTIVE] = { 1719aaddd7d1SThomas Gleixner .name = "sched:active", 17203c1627e9SThomas Gleixner .startup.single = sched_cpu_activate, 17213c1627e9SThomas Gleixner .teardown.single = sched_cpu_deactivate, 1722aaddd7d1SThomas Gleixner }, 1723aaddd7d1SThomas Gleixner #endif 1724aaddd7d1SThomas Gleixner 1725d10ef6f9SThomas Gleixner /* CPU is fully up and running. */ 17264baa0afcSThomas Gleixner [CPUHP_ONLINE] = { 17274baa0afcSThomas Gleixner .name = "online", 17283c1627e9SThomas Gleixner .startup.single = NULL, 17293c1627e9SThomas Gleixner .teardown.single = NULL, 17304baa0afcSThomas Gleixner }, 17314baa0afcSThomas Gleixner }; 17324baa0afcSThomas Gleixner 17335b7aa87eSThomas Gleixner /* Sanity check for callbacks */ 17345b7aa87eSThomas Gleixner static int cpuhp_cb_check(enum cpuhp_state state) 17355b7aa87eSThomas Gleixner { 17365b7aa87eSThomas Gleixner if (state <= CPUHP_OFFLINE || state >= CPUHP_ONLINE) 17375b7aa87eSThomas Gleixner return -EINVAL; 17385b7aa87eSThomas Gleixner return 0; 17395b7aa87eSThomas Gleixner } 17405b7aa87eSThomas Gleixner 1741dc280d93SThomas Gleixner /* 1742dc280d93SThomas Gleixner * Returns a free for dynamic slot assignment of the Online state. The states 1743dc280d93SThomas Gleixner * are protected by the cpuhp_slot_states mutex and an empty slot is identified 1744dc280d93SThomas Gleixner * by having no name assigned. 1745dc280d93SThomas Gleixner */ 1746dc280d93SThomas Gleixner static int cpuhp_reserve_state(enum cpuhp_state state) 1747dc280d93SThomas Gleixner { 17484205e478SThomas Gleixner enum cpuhp_state i, end; 17494205e478SThomas Gleixner struct cpuhp_step *step; 1750dc280d93SThomas Gleixner 17514205e478SThomas Gleixner switch (state) { 17524205e478SThomas Gleixner case CPUHP_AP_ONLINE_DYN: 175317a2f1ceSLai Jiangshan step = cpuhp_hp_states + CPUHP_AP_ONLINE_DYN; 17544205e478SThomas Gleixner end = CPUHP_AP_ONLINE_DYN_END; 17554205e478SThomas Gleixner break; 17564205e478SThomas Gleixner case CPUHP_BP_PREPARE_DYN: 175717a2f1ceSLai Jiangshan step = cpuhp_hp_states + CPUHP_BP_PREPARE_DYN; 17584205e478SThomas Gleixner end = CPUHP_BP_PREPARE_DYN_END; 17594205e478SThomas Gleixner break; 17604205e478SThomas Gleixner default: 17614205e478SThomas Gleixner return -EINVAL; 17624205e478SThomas Gleixner } 17634205e478SThomas Gleixner 17644205e478SThomas Gleixner for (i = state; i <= end; i++, step++) { 17654205e478SThomas Gleixner if (!step->name) 1766dc280d93SThomas Gleixner return i; 1767dc280d93SThomas Gleixner } 1768dc280d93SThomas Gleixner WARN(1, "No more dynamic states available for CPU hotplug\n"); 1769dc280d93SThomas Gleixner return -ENOSPC; 1770dc280d93SThomas Gleixner } 1771dc280d93SThomas Gleixner 1772dc280d93SThomas Gleixner static int cpuhp_store_callbacks(enum cpuhp_state state, const char *name, 17735b7aa87eSThomas Gleixner int (*startup)(unsigned int cpu), 1774cf392d10SThomas Gleixner int (*teardown)(unsigned int cpu), 1775cf392d10SThomas Gleixner bool multi_instance) 17765b7aa87eSThomas Gleixner { 17775b7aa87eSThomas Gleixner /* (Un)Install the callbacks for further cpu hotplug operations */ 17785b7aa87eSThomas Gleixner struct cpuhp_step *sp; 1779dc280d93SThomas Gleixner int ret = 0; 17805b7aa87eSThomas Gleixner 17810c96b273SEthan Barnes /* 17820c96b273SEthan Barnes * If name is NULL, then the state gets removed. 17830c96b273SEthan Barnes * 17840c96b273SEthan Barnes * CPUHP_AP_ONLINE_DYN and CPUHP_BP_PREPARE_DYN are handed out on 17850c96b273SEthan Barnes * the first allocation from these dynamic ranges, so the removal 17860c96b273SEthan Barnes * would trigger a new allocation and clear the wrong (already 17870c96b273SEthan Barnes * empty) state, leaving the callbacks of the to be cleared state 17880c96b273SEthan Barnes * dangling, which causes wreckage on the next hotplug operation. 17890c96b273SEthan Barnes */ 17900c96b273SEthan Barnes if (name && (state == CPUHP_AP_ONLINE_DYN || 17910c96b273SEthan Barnes state == CPUHP_BP_PREPARE_DYN)) { 1792dc280d93SThomas Gleixner ret = cpuhp_reserve_state(state); 1793dc280d93SThomas Gleixner if (ret < 0) 1794dc434e05SSebastian Andrzej Siewior return ret; 1795dc280d93SThomas Gleixner state = ret; 1796dc280d93SThomas Gleixner } 17975b7aa87eSThomas Gleixner sp = cpuhp_get_step(state); 1798dc434e05SSebastian Andrzej Siewior if (name && sp->name) 1799dc434e05SSebastian Andrzej Siewior return -EBUSY; 1800dc434e05SSebastian Andrzej Siewior 18013c1627e9SThomas Gleixner sp->startup.single = startup; 18023c1627e9SThomas Gleixner sp->teardown.single = teardown; 18035b7aa87eSThomas Gleixner sp->name = name; 1804cf392d10SThomas Gleixner sp->multi_instance = multi_instance; 1805cf392d10SThomas Gleixner INIT_HLIST_HEAD(&sp->list); 1806dc280d93SThomas Gleixner return ret; 18075b7aa87eSThomas Gleixner } 18085b7aa87eSThomas Gleixner 18095b7aa87eSThomas Gleixner static void *cpuhp_get_teardown_cb(enum cpuhp_state state) 18105b7aa87eSThomas Gleixner { 18113c1627e9SThomas Gleixner return cpuhp_get_step(state)->teardown.single; 18125b7aa87eSThomas Gleixner } 18135b7aa87eSThomas Gleixner 18145b7aa87eSThomas Gleixner /* 18155b7aa87eSThomas Gleixner * Call the startup/teardown function for a step either on the AP or 18165b7aa87eSThomas Gleixner * on the current CPU. 18175b7aa87eSThomas Gleixner */ 1818cf392d10SThomas Gleixner static int cpuhp_issue_call(int cpu, enum cpuhp_state state, bool bringup, 1819cf392d10SThomas Gleixner struct hlist_node *node) 18205b7aa87eSThomas Gleixner { 1821a724632cSThomas Gleixner struct cpuhp_step *sp = cpuhp_get_step(state); 18225b7aa87eSThomas Gleixner int ret; 18235b7aa87eSThomas Gleixner 18244dddfb5fSPeter Zijlstra /* 18254dddfb5fSPeter Zijlstra * If there's nothing to do, we done. 18264dddfb5fSPeter Zijlstra * Relies on the union for multi_instance. 18274dddfb5fSPeter Zijlstra */ 1828453e4108SVincent Donnefort if (cpuhp_step_empty(bringup, sp)) 18295b7aa87eSThomas Gleixner return 0; 18305b7aa87eSThomas Gleixner /* 18315b7aa87eSThomas Gleixner * The non AP bound callbacks can fail on bringup. On teardown 18325b7aa87eSThomas Gleixner * e.g. module removal we crash for now. 18335b7aa87eSThomas Gleixner */ 18341cf4f629SThomas Gleixner #ifdef CONFIG_SMP 18351cf4f629SThomas Gleixner if (cpuhp_is_ap_state(state)) 1836cf392d10SThomas Gleixner ret = cpuhp_invoke_ap_callback(cpu, state, bringup, node); 18371cf4f629SThomas Gleixner else 183896abb968SPeter Zijlstra ret = cpuhp_invoke_callback(cpu, state, bringup, node, NULL); 18391cf4f629SThomas Gleixner #else 184096abb968SPeter Zijlstra ret = cpuhp_invoke_callback(cpu, state, bringup, node, NULL); 18411cf4f629SThomas Gleixner #endif 18425b7aa87eSThomas Gleixner BUG_ON(ret && !bringup); 18435b7aa87eSThomas Gleixner return ret; 18445b7aa87eSThomas Gleixner } 18455b7aa87eSThomas Gleixner 18465b7aa87eSThomas Gleixner /* 18475b7aa87eSThomas Gleixner * Called from __cpuhp_setup_state on a recoverable failure. 18485b7aa87eSThomas Gleixner * 18495b7aa87eSThomas Gleixner * Note: The teardown callbacks for rollback are not allowed to fail! 18505b7aa87eSThomas Gleixner */ 18515b7aa87eSThomas Gleixner static void cpuhp_rollback_install(int failedcpu, enum cpuhp_state state, 1852cf392d10SThomas Gleixner struct hlist_node *node) 18535b7aa87eSThomas Gleixner { 18545b7aa87eSThomas Gleixner int cpu; 18555b7aa87eSThomas Gleixner 18565b7aa87eSThomas Gleixner /* Roll back the already executed steps on the other cpus */ 18575b7aa87eSThomas Gleixner for_each_present_cpu(cpu) { 18585b7aa87eSThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 18595b7aa87eSThomas Gleixner int cpustate = st->state; 18605b7aa87eSThomas Gleixner 18615b7aa87eSThomas Gleixner if (cpu >= failedcpu) 18625b7aa87eSThomas Gleixner break; 18635b7aa87eSThomas Gleixner 18645b7aa87eSThomas Gleixner /* Did we invoke the startup call on that cpu ? */ 18655b7aa87eSThomas Gleixner if (cpustate >= state) 1866cf392d10SThomas Gleixner cpuhp_issue_call(cpu, state, false, node); 18675b7aa87eSThomas Gleixner } 18685b7aa87eSThomas Gleixner } 18695b7aa87eSThomas Gleixner 18709805c673SThomas Gleixner int __cpuhp_state_add_instance_cpuslocked(enum cpuhp_state state, 18719805c673SThomas Gleixner struct hlist_node *node, 1872cf392d10SThomas Gleixner bool invoke) 1873cf392d10SThomas Gleixner { 1874cf392d10SThomas Gleixner struct cpuhp_step *sp; 1875cf392d10SThomas Gleixner int cpu; 1876cf392d10SThomas Gleixner int ret; 1877cf392d10SThomas Gleixner 18789805c673SThomas Gleixner lockdep_assert_cpus_held(); 18799805c673SThomas Gleixner 1880cf392d10SThomas Gleixner sp = cpuhp_get_step(state); 1881cf392d10SThomas Gleixner if (sp->multi_instance == false) 1882cf392d10SThomas Gleixner return -EINVAL; 1883cf392d10SThomas Gleixner 1884dc434e05SSebastian Andrzej Siewior mutex_lock(&cpuhp_state_mutex); 1885cf392d10SThomas Gleixner 18863c1627e9SThomas Gleixner if (!invoke || !sp->startup.multi) 1887cf392d10SThomas Gleixner goto add_node; 1888cf392d10SThomas Gleixner 1889cf392d10SThomas Gleixner /* 1890cf392d10SThomas Gleixner * Try to call the startup callback for each present cpu 1891cf392d10SThomas Gleixner * depending on the hotplug state of the cpu. 1892cf392d10SThomas Gleixner */ 1893cf392d10SThomas Gleixner for_each_present_cpu(cpu) { 1894cf392d10SThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 1895cf392d10SThomas Gleixner int cpustate = st->state; 1896cf392d10SThomas Gleixner 1897cf392d10SThomas Gleixner if (cpustate < state) 1898cf392d10SThomas Gleixner continue; 1899cf392d10SThomas Gleixner 1900cf392d10SThomas Gleixner ret = cpuhp_issue_call(cpu, state, true, node); 1901cf392d10SThomas Gleixner if (ret) { 19023c1627e9SThomas Gleixner if (sp->teardown.multi) 1903cf392d10SThomas Gleixner cpuhp_rollback_install(cpu, state, node); 1904dc434e05SSebastian Andrzej Siewior goto unlock; 1905cf392d10SThomas Gleixner } 1906cf392d10SThomas Gleixner } 1907cf392d10SThomas Gleixner add_node: 1908cf392d10SThomas Gleixner ret = 0; 1909cf392d10SThomas Gleixner hlist_add_head(node, &sp->list); 1910dc434e05SSebastian Andrzej Siewior unlock: 1911cf392d10SThomas Gleixner mutex_unlock(&cpuhp_state_mutex); 19129805c673SThomas Gleixner return ret; 19139805c673SThomas Gleixner } 19149805c673SThomas Gleixner 19159805c673SThomas Gleixner int __cpuhp_state_add_instance(enum cpuhp_state state, struct hlist_node *node, 19169805c673SThomas Gleixner bool invoke) 19179805c673SThomas Gleixner { 19189805c673SThomas Gleixner int ret; 19199805c673SThomas Gleixner 19209805c673SThomas Gleixner cpus_read_lock(); 19219805c673SThomas Gleixner ret = __cpuhp_state_add_instance_cpuslocked(state, node, invoke); 19228f553c49SThomas Gleixner cpus_read_unlock(); 1923cf392d10SThomas Gleixner return ret; 1924cf392d10SThomas Gleixner } 1925cf392d10SThomas Gleixner EXPORT_SYMBOL_GPL(__cpuhp_state_add_instance); 1926cf392d10SThomas Gleixner 19275b7aa87eSThomas Gleixner /** 192871def423SSebastian Andrzej Siewior * __cpuhp_setup_state_cpuslocked - Setup the callbacks for an hotplug machine state 19295b7aa87eSThomas Gleixner * @state: The state to setup 19305b7aa87eSThomas Gleixner * @invoke: If true, the startup function is invoked for cpus where 19315b7aa87eSThomas Gleixner * cpu state >= @state 19325b7aa87eSThomas Gleixner * @startup: startup callback function 19335b7aa87eSThomas Gleixner * @teardown: teardown callback function 1934dc280d93SThomas Gleixner * @multi_instance: State is set up for multiple instances which get 1935dc280d93SThomas Gleixner * added afterwards. 19365b7aa87eSThomas Gleixner * 193771def423SSebastian Andrzej Siewior * The caller needs to hold cpus read locked while calling this function. 1938512f0980SBoris Ostrovsky * Returns: 1939512f0980SBoris Ostrovsky * On success: 1940512f0980SBoris Ostrovsky * Positive state number if @state is CPUHP_AP_ONLINE_DYN 1941512f0980SBoris Ostrovsky * 0 for all other states 1942512f0980SBoris Ostrovsky * On failure: proper (negative) error code 19435b7aa87eSThomas Gleixner */ 194471def423SSebastian Andrzej Siewior int __cpuhp_setup_state_cpuslocked(enum cpuhp_state state, 19455b7aa87eSThomas Gleixner const char *name, bool invoke, 19465b7aa87eSThomas Gleixner int (*startup)(unsigned int cpu), 1947cf392d10SThomas Gleixner int (*teardown)(unsigned int cpu), 1948cf392d10SThomas Gleixner bool multi_instance) 19495b7aa87eSThomas Gleixner { 19505b7aa87eSThomas Gleixner int cpu, ret = 0; 1951b9d9d691SThomas Gleixner bool dynstate; 19525b7aa87eSThomas Gleixner 195371def423SSebastian Andrzej Siewior lockdep_assert_cpus_held(); 195471def423SSebastian Andrzej Siewior 19555b7aa87eSThomas Gleixner if (cpuhp_cb_check(state) || !name) 19565b7aa87eSThomas Gleixner return -EINVAL; 19575b7aa87eSThomas Gleixner 1958dc434e05SSebastian Andrzej Siewior mutex_lock(&cpuhp_state_mutex); 19595b7aa87eSThomas Gleixner 1960dc280d93SThomas Gleixner ret = cpuhp_store_callbacks(state, name, startup, teardown, 1961dc280d93SThomas Gleixner multi_instance); 19625b7aa87eSThomas Gleixner 1963b9d9d691SThomas Gleixner dynstate = state == CPUHP_AP_ONLINE_DYN; 1964b9d9d691SThomas Gleixner if (ret > 0 && dynstate) { 1965b9d9d691SThomas Gleixner state = ret; 1966b9d9d691SThomas Gleixner ret = 0; 1967b9d9d691SThomas Gleixner } 1968b9d9d691SThomas Gleixner 1969dc280d93SThomas Gleixner if (ret || !invoke || !startup) 19705b7aa87eSThomas Gleixner goto out; 19715b7aa87eSThomas Gleixner 19725b7aa87eSThomas Gleixner /* 19735b7aa87eSThomas Gleixner * Try to call the startup callback for each present cpu 19745b7aa87eSThomas Gleixner * depending on the hotplug state of the cpu. 19755b7aa87eSThomas Gleixner */ 19765b7aa87eSThomas Gleixner for_each_present_cpu(cpu) { 19775b7aa87eSThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 19785b7aa87eSThomas Gleixner int cpustate = st->state; 19795b7aa87eSThomas Gleixner 19805b7aa87eSThomas Gleixner if (cpustate < state) 19815b7aa87eSThomas Gleixner continue; 19825b7aa87eSThomas Gleixner 1983cf392d10SThomas Gleixner ret = cpuhp_issue_call(cpu, state, true, NULL); 19845b7aa87eSThomas Gleixner if (ret) { 1985a724632cSThomas Gleixner if (teardown) 1986cf392d10SThomas Gleixner cpuhp_rollback_install(cpu, state, NULL); 1987cf392d10SThomas Gleixner cpuhp_store_callbacks(state, NULL, NULL, NULL, false); 19885b7aa87eSThomas Gleixner goto out; 19895b7aa87eSThomas Gleixner } 19905b7aa87eSThomas Gleixner } 19915b7aa87eSThomas Gleixner out: 1992dc434e05SSebastian Andrzej Siewior mutex_unlock(&cpuhp_state_mutex); 1993dc280d93SThomas Gleixner /* 1994dc280d93SThomas Gleixner * If the requested state is CPUHP_AP_ONLINE_DYN, return the 1995dc280d93SThomas Gleixner * dynamically allocated state in case of success. 1996dc280d93SThomas Gleixner */ 1997b9d9d691SThomas Gleixner if (!ret && dynstate) 19985b7aa87eSThomas Gleixner return state; 19995b7aa87eSThomas Gleixner return ret; 20005b7aa87eSThomas Gleixner } 200171def423SSebastian Andrzej Siewior EXPORT_SYMBOL(__cpuhp_setup_state_cpuslocked); 200271def423SSebastian Andrzej Siewior 200371def423SSebastian Andrzej Siewior int __cpuhp_setup_state(enum cpuhp_state state, 200471def423SSebastian Andrzej Siewior const char *name, bool invoke, 200571def423SSebastian Andrzej Siewior int (*startup)(unsigned int cpu), 200671def423SSebastian Andrzej Siewior int (*teardown)(unsigned int cpu), 200771def423SSebastian Andrzej Siewior bool multi_instance) 200871def423SSebastian Andrzej Siewior { 200971def423SSebastian Andrzej Siewior int ret; 201071def423SSebastian Andrzej Siewior 201171def423SSebastian Andrzej Siewior cpus_read_lock(); 201271def423SSebastian Andrzej Siewior ret = __cpuhp_setup_state_cpuslocked(state, name, invoke, startup, 201371def423SSebastian Andrzej Siewior teardown, multi_instance); 201471def423SSebastian Andrzej Siewior cpus_read_unlock(); 201571def423SSebastian Andrzej Siewior return ret; 201671def423SSebastian Andrzej Siewior } 20175b7aa87eSThomas Gleixner EXPORT_SYMBOL(__cpuhp_setup_state); 20185b7aa87eSThomas Gleixner 2019cf392d10SThomas Gleixner int __cpuhp_state_remove_instance(enum cpuhp_state state, 2020cf392d10SThomas Gleixner struct hlist_node *node, bool invoke) 2021cf392d10SThomas Gleixner { 2022cf392d10SThomas Gleixner struct cpuhp_step *sp = cpuhp_get_step(state); 2023cf392d10SThomas Gleixner int cpu; 2024cf392d10SThomas Gleixner 2025cf392d10SThomas Gleixner BUG_ON(cpuhp_cb_check(state)); 2026cf392d10SThomas Gleixner 2027cf392d10SThomas Gleixner if (!sp->multi_instance) 2028cf392d10SThomas Gleixner return -EINVAL; 2029cf392d10SThomas Gleixner 20308f553c49SThomas Gleixner cpus_read_lock(); 2031dc434e05SSebastian Andrzej Siewior mutex_lock(&cpuhp_state_mutex); 2032dc434e05SSebastian Andrzej Siewior 2033cf392d10SThomas Gleixner if (!invoke || !cpuhp_get_teardown_cb(state)) 2034cf392d10SThomas Gleixner goto remove; 2035cf392d10SThomas Gleixner /* 2036cf392d10SThomas Gleixner * Call the teardown callback for each present cpu depending 2037cf392d10SThomas Gleixner * on the hotplug state of the cpu. This function is not 2038cf392d10SThomas Gleixner * allowed to fail currently! 2039cf392d10SThomas Gleixner */ 2040cf392d10SThomas Gleixner for_each_present_cpu(cpu) { 2041cf392d10SThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 2042cf392d10SThomas Gleixner int cpustate = st->state; 2043cf392d10SThomas Gleixner 2044cf392d10SThomas Gleixner if (cpustate >= state) 2045cf392d10SThomas Gleixner cpuhp_issue_call(cpu, state, false, node); 2046cf392d10SThomas Gleixner } 2047cf392d10SThomas Gleixner 2048cf392d10SThomas Gleixner remove: 2049cf392d10SThomas Gleixner hlist_del(node); 2050cf392d10SThomas Gleixner mutex_unlock(&cpuhp_state_mutex); 20518f553c49SThomas Gleixner cpus_read_unlock(); 2052cf392d10SThomas Gleixner 2053cf392d10SThomas Gleixner return 0; 2054cf392d10SThomas Gleixner } 2055cf392d10SThomas Gleixner EXPORT_SYMBOL_GPL(__cpuhp_state_remove_instance); 2056dc434e05SSebastian Andrzej Siewior 20575b7aa87eSThomas Gleixner /** 205871def423SSebastian Andrzej Siewior * __cpuhp_remove_state_cpuslocked - Remove the callbacks for an hotplug machine state 20595b7aa87eSThomas Gleixner * @state: The state to remove 20605b7aa87eSThomas Gleixner * @invoke: If true, the teardown function is invoked for cpus where 20615b7aa87eSThomas Gleixner * cpu state >= @state 20625b7aa87eSThomas Gleixner * 206371def423SSebastian Andrzej Siewior * The caller needs to hold cpus read locked while calling this function. 20645b7aa87eSThomas Gleixner * The teardown callback is currently not allowed to fail. Think 20655b7aa87eSThomas Gleixner * about module removal! 20665b7aa87eSThomas Gleixner */ 206771def423SSebastian Andrzej Siewior void __cpuhp_remove_state_cpuslocked(enum cpuhp_state state, bool invoke) 20685b7aa87eSThomas Gleixner { 2069cf392d10SThomas Gleixner struct cpuhp_step *sp = cpuhp_get_step(state); 20705b7aa87eSThomas Gleixner int cpu; 20715b7aa87eSThomas Gleixner 20725b7aa87eSThomas Gleixner BUG_ON(cpuhp_cb_check(state)); 20735b7aa87eSThomas Gleixner 207471def423SSebastian Andrzej Siewior lockdep_assert_cpus_held(); 20755b7aa87eSThomas Gleixner 2076dc434e05SSebastian Andrzej Siewior mutex_lock(&cpuhp_state_mutex); 2077cf392d10SThomas Gleixner if (sp->multi_instance) { 2078cf392d10SThomas Gleixner WARN(!hlist_empty(&sp->list), 2079cf392d10SThomas Gleixner "Error: Removing state %d which has instances left.\n", 2080cf392d10SThomas Gleixner state); 2081cf392d10SThomas Gleixner goto remove; 2082cf392d10SThomas Gleixner } 2083cf392d10SThomas Gleixner 2084a724632cSThomas Gleixner if (!invoke || !cpuhp_get_teardown_cb(state)) 20855b7aa87eSThomas Gleixner goto remove; 20865b7aa87eSThomas Gleixner 20875b7aa87eSThomas Gleixner /* 20885b7aa87eSThomas Gleixner * Call the teardown callback for each present cpu depending 20895b7aa87eSThomas Gleixner * on the hotplug state of the cpu. This function is not 20905b7aa87eSThomas Gleixner * allowed to fail currently! 20915b7aa87eSThomas Gleixner */ 20925b7aa87eSThomas Gleixner for_each_present_cpu(cpu) { 20935b7aa87eSThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 20945b7aa87eSThomas Gleixner int cpustate = st->state; 20955b7aa87eSThomas Gleixner 20965b7aa87eSThomas Gleixner if (cpustate >= state) 2097cf392d10SThomas Gleixner cpuhp_issue_call(cpu, state, false, NULL); 20985b7aa87eSThomas Gleixner } 20995b7aa87eSThomas Gleixner remove: 2100cf392d10SThomas Gleixner cpuhp_store_callbacks(state, NULL, NULL, NULL, false); 2101dc434e05SSebastian Andrzej Siewior mutex_unlock(&cpuhp_state_mutex); 210271def423SSebastian Andrzej Siewior } 210371def423SSebastian Andrzej Siewior EXPORT_SYMBOL(__cpuhp_remove_state_cpuslocked); 210471def423SSebastian Andrzej Siewior 210571def423SSebastian Andrzej Siewior void __cpuhp_remove_state(enum cpuhp_state state, bool invoke) 210671def423SSebastian Andrzej Siewior { 210771def423SSebastian Andrzej Siewior cpus_read_lock(); 210871def423SSebastian Andrzej Siewior __cpuhp_remove_state_cpuslocked(state, invoke); 21098f553c49SThomas Gleixner cpus_read_unlock(); 21105b7aa87eSThomas Gleixner } 21115b7aa87eSThomas Gleixner EXPORT_SYMBOL(__cpuhp_remove_state); 21125b7aa87eSThomas Gleixner 2113dc8d37edSArnd Bergmann #ifdef CONFIG_HOTPLUG_SMT 2114dc8d37edSArnd Bergmann static void cpuhp_offline_cpu_device(unsigned int cpu) 2115dc8d37edSArnd Bergmann { 2116dc8d37edSArnd Bergmann struct device *dev = get_cpu_device(cpu); 2117dc8d37edSArnd Bergmann 2118dc8d37edSArnd Bergmann dev->offline = true; 2119dc8d37edSArnd Bergmann /* Tell user space about the state change */ 2120dc8d37edSArnd Bergmann kobject_uevent(&dev->kobj, KOBJ_OFFLINE); 2121dc8d37edSArnd Bergmann } 2122dc8d37edSArnd Bergmann 2123dc8d37edSArnd Bergmann static void cpuhp_online_cpu_device(unsigned int cpu) 2124dc8d37edSArnd Bergmann { 2125dc8d37edSArnd Bergmann struct device *dev = get_cpu_device(cpu); 2126dc8d37edSArnd Bergmann 2127dc8d37edSArnd Bergmann dev->offline = false; 2128dc8d37edSArnd Bergmann /* Tell user space about the state change */ 2129dc8d37edSArnd Bergmann kobject_uevent(&dev->kobj, KOBJ_ONLINE); 2130dc8d37edSArnd Bergmann } 2131dc8d37edSArnd Bergmann 2132dc8d37edSArnd Bergmann int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval) 2133dc8d37edSArnd Bergmann { 2134dc8d37edSArnd Bergmann int cpu, ret = 0; 2135dc8d37edSArnd Bergmann 2136dc8d37edSArnd Bergmann cpu_maps_update_begin(); 2137dc8d37edSArnd Bergmann for_each_online_cpu(cpu) { 2138dc8d37edSArnd Bergmann if (topology_is_primary_thread(cpu)) 2139dc8d37edSArnd Bergmann continue; 2140dc8d37edSArnd Bergmann ret = cpu_down_maps_locked(cpu, CPUHP_OFFLINE); 2141dc8d37edSArnd Bergmann if (ret) 2142dc8d37edSArnd Bergmann break; 2143dc8d37edSArnd Bergmann /* 2144dc8d37edSArnd Bergmann * As this needs to hold the cpu maps lock it's impossible 2145dc8d37edSArnd Bergmann * to call device_offline() because that ends up calling 2146dc8d37edSArnd Bergmann * cpu_down() which takes cpu maps lock. cpu maps lock 2147dc8d37edSArnd Bergmann * needs to be held as this might race against in kernel 2148dc8d37edSArnd Bergmann * abusers of the hotplug machinery (thermal management). 2149dc8d37edSArnd Bergmann * 2150dc8d37edSArnd Bergmann * So nothing would update device:offline state. That would 2151dc8d37edSArnd Bergmann * leave the sysfs entry stale and prevent onlining after 2152dc8d37edSArnd Bergmann * smt control has been changed to 'off' again. This is 2153dc8d37edSArnd Bergmann * called under the sysfs hotplug lock, so it is properly 2154dc8d37edSArnd Bergmann * serialized against the regular offline usage. 2155dc8d37edSArnd Bergmann */ 2156dc8d37edSArnd Bergmann cpuhp_offline_cpu_device(cpu); 2157dc8d37edSArnd Bergmann } 2158dc8d37edSArnd Bergmann if (!ret) 2159dc8d37edSArnd Bergmann cpu_smt_control = ctrlval; 2160dc8d37edSArnd Bergmann cpu_maps_update_done(); 2161dc8d37edSArnd Bergmann return ret; 2162dc8d37edSArnd Bergmann } 2163dc8d37edSArnd Bergmann 2164dc8d37edSArnd Bergmann int cpuhp_smt_enable(void) 2165dc8d37edSArnd Bergmann { 2166dc8d37edSArnd Bergmann int cpu, ret = 0; 2167dc8d37edSArnd Bergmann 2168dc8d37edSArnd Bergmann cpu_maps_update_begin(); 2169dc8d37edSArnd Bergmann cpu_smt_control = CPU_SMT_ENABLED; 2170dc8d37edSArnd Bergmann for_each_present_cpu(cpu) { 2171dc8d37edSArnd Bergmann /* Skip online CPUs and CPUs on offline nodes */ 2172dc8d37edSArnd Bergmann if (cpu_online(cpu) || !node_online(cpu_to_node(cpu))) 2173dc8d37edSArnd Bergmann continue; 2174dc8d37edSArnd Bergmann ret = _cpu_up(cpu, 0, CPUHP_ONLINE); 2175dc8d37edSArnd Bergmann if (ret) 2176dc8d37edSArnd Bergmann break; 2177dc8d37edSArnd Bergmann /* See comment in cpuhp_smt_disable() */ 2178dc8d37edSArnd Bergmann cpuhp_online_cpu_device(cpu); 2179dc8d37edSArnd Bergmann } 2180dc8d37edSArnd Bergmann cpu_maps_update_done(); 2181dc8d37edSArnd Bergmann return ret; 2182dc8d37edSArnd Bergmann } 2183dc8d37edSArnd Bergmann #endif 2184dc8d37edSArnd Bergmann 218598f8cdceSThomas Gleixner #if defined(CONFIG_SYSFS) && defined(CONFIG_HOTPLUG_CPU) 218698f8cdceSThomas Gleixner static ssize_t show_cpuhp_state(struct device *dev, 218798f8cdceSThomas Gleixner struct device_attribute *attr, char *buf) 218898f8cdceSThomas Gleixner { 218998f8cdceSThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id); 219098f8cdceSThomas Gleixner 219198f8cdceSThomas Gleixner return sprintf(buf, "%d\n", st->state); 219298f8cdceSThomas Gleixner } 219398f8cdceSThomas Gleixner static DEVICE_ATTR(state, 0444, show_cpuhp_state, NULL); 219498f8cdceSThomas Gleixner 2195757c989bSThomas Gleixner static ssize_t write_cpuhp_target(struct device *dev, 2196757c989bSThomas Gleixner struct device_attribute *attr, 2197757c989bSThomas Gleixner const char *buf, size_t count) 2198757c989bSThomas Gleixner { 2199757c989bSThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id); 2200757c989bSThomas Gleixner struct cpuhp_step *sp; 2201757c989bSThomas Gleixner int target, ret; 2202757c989bSThomas Gleixner 2203757c989bSThomas Gleixner ret = kstrtoint(buf, 10, &target); 2204757c989bSThomas Gleixner if (ret) 2205757c989bSThomas Gleixner return ret; 2206757c989bSThomas Gleixner 2207757c989bSThomas Gleixner #ifdef CONFIG_CPU_HOTPLUG_STATE_CONTROL 2208757c989bSThomas Gleixner if (target < CPUHP_OFFLINE || target > CPUHP_ONLINE) 2209757c989bSThomas Gleixner return -EINVAL; 2210757c989bSThomas Gleixner #else 2211757c989bSThomas Gleixner if (target != CPUHP_OFFLINE && target != CPUHP_ONLINE) 2212757c989bSThomas Gleixner return -EINVAL; 2213757c989bSThomas Gleixner #endif 2214757c989bSThomas Gleixner 2215757c989bSThomas Gleixner ret = lock_device_hotplug_sysfs(); 2216757c989bSThomas Gleixner if (ret) 2217757c989bSThomas Gleixner return ret; 2218757c989bSThomas Gleixner 2219757c989bSThomas Gleixner mutex_lock(&cpuhp_state_mutex); 2220757c989bSThomas Gleixner sp = cpuhp_get_step(target); 2221757c989bSThomas Gleixner ret = !sp->name || sp->cant_stop ? -EINVAL : 0; 2222757c989bSThomas Gleixner mutex_unlock(&cpuhp_state_mutex); 2223757c989bSThomas Gleixner if (ret) 222440da1b11SSebastian Andrzej Siewior goto out; 2225757c989bSThomas Gleixner 2226757c989bSThomas Gleixner if (st->state < target) 222733c3736eSQais Yousef ret = cpu_up(dev->id, target); 2228757c989bSThomas Gleixner else 222933c3736eSQais Yousef ret = cpu_down(dev->id, target); 223040da1b11SSebastian Andrzej Siewior out: 2231757c989bSThomas Gleixner unlock_device_hotplug(); 2232757c989bSThomas Gleixner return ret ? ret : count; 2233757c989bSThomas Gleixner } 2234757c989bSThomas Gleixner 223598f8cdceSThomas Gleixner static ssize_t show_cpuhp_target(struct device *dev, 223698f8cdceSThomas Gleixner struct device_attribute *attr, char *buf) 223798f8cdceSThomas Gleixner { 223898f8cdceSThomas Gleixner struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id); 223998f8cdceSThomas Gleixner 224098f8cdceSThomas Gleixner return sprintf(buf, "%d\n", st->target); 224198f8cdceSThomas Gleixner } 2242757c989bSThomas Gleixner static DEVICE_ATTR(target, 0644, show_cpuhp_target, write_cpuhp_target); 224398f8cdceSThomas Gleixner 22441db49484SPeter Zijlstra 22451db49484SPeter Zijlstra static ssize_t write_cpuhp_fail(struct device *dev, 22461db49484SPeter Zijlstra struct device_attribute *attr, 22471db49484SPeter Zijlstra const char *buf, size_t count) 22481db49484SPeter Zijlstra { 22491db49484SPeter Zijlstra struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id); 22501db49484SPeter Zijlstra struct cpuhp_step *sp; 22511db49484SPeter Zijlstra int fail, ret; 22521db49484SPeter Zijlstra 22531db49484SPeter Zijlstra ret = kstrtoint(buf, 10, &fail); 22541db49484SPeter Zijlstra if (ret) 22551db49484SPeter Zijlstra return ret; 22561db49484SPeter Zijlstra 22573ae70c25SVincent Donnefort if (fail == CPUHP_INVALID) { 22583ae70c25SVincent Donnefort st->fail = fail; 22593ae70c25SVincent Donnefort return count; 22603ae70c25SVincent Donnefort } 22613ae70c25SVincent Donnefort 226233d4a5a7SEiichi Tsukata if (fail < CPUHP_OFFLINE || fail > CPUHP_ONLINE) 226333d4a5a7SEiichi Tsukata return -EINVAL; 226433d4a5a7SEiichi Tsukata 22651db49484SPeter Zijlstra /* 22661db49484SPeter Zijlstra * Cannot fail STARTING/DYING callbacks. 22671db49484SPeter Zijlstra */ 22681db49484SPeter Zijlstra if (cpuhp_is_atomic_state(fail)) 22691db49484SPeter Zijlstra return -EINVAL; 22701db49484SPeter Zijlstra 22711db49484SPeter Zijlstra /* 227262f25069SVincent Donnefort * DEAD callbacks cannot fail... 227362f25069SVincent Donnefort * ... neither can CPUHP_BRINGUP_CPU during hotunplug. The latter 227462f25069SVincent Donnefort * triggering STARTING callbacks, a failure in this state would 227562f25069SVincent Donnefort * hinder rollback. 227662f25069SVincent Donnefort */ 227762f25069SVincent Donnefort if (fail <= CPUHP_BRINGUP_CPU && st->state > CPUHP_BRINGUP_CPU) 227862f25069SVincent Donnefort return -EINVAL; 227962f25069SVincent Donnefort 228062f25069SVincent Donnefort /* 22811db49484SPeter Zijlstra * Cannot fail anything that doesn't have callbacks. 22821db49484SPeter Zijlstra */ 22831db49484SPeter Zijlstra mutex_lock(&cpuhp_state_mutex); 22841db49484SPeter Zijlstra sp = cpuhp_get_step(fail); 22851db49484SPeter Zijlstra if (!sp->startup.single && !sp->teardown.single) 22861db49484SPeter Zijlstra ret = -EINVAL; 22871db49484SPeter Zijlstra mutex_unlock(&cpuhp_state_mutex); 22881db49484SPeter Zijlstra if (ret) 22891db49484SPeter Zijlstra return ret; 22901db49484SPeter Zijlstra 22911db49484SPeter Zijlstra st->fail = fail; 22921db49484SPeter Zijlstra 22931db49484SPeter Zijlstra return count; 22941db49484SPeter Zijlstra } 22951db49484SPeter Zijlstra 22961db49484SPeter Zijlstra static ssize_t show_cpuhp_fail(struct device *dev, 22971db49484SPeter Zijlstra struct device_attribute *attr, char *buf) 22981db49484SPeter Zijlstra { 22991db49484SPeter Zijlstra struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id); 23001db49484SPeter Zijlstra 23011db49484SPeter Zijlstra return sprintf(buf, "%d\n", st->fail); 23021db49484SPeter Zijlstra } 23031db49484SPeter Zijlstra 23041db49484SPeter Zijlstra static DEVICE_ATTR(fail, 0644, show_cpuhp_fail, write_cpuhp_fail); 23051db49484SPeter Zijlstra 230698f8cdceSThomas Gleixner static struct attribute *cpuhp_cpu_attrs[] = { 230798f8cdceSThomas Gleixner &dev_attr_state.attr, 230898f8cdceSThomas Gleixner &dev_attr_target.attr, 23091db49484SPeter Zijlstra &dev_attr_fail.attr, 231098f8cdceSThomas Gleixner NULL 231198f8cdceSThomas Gleixner }; 231298f8cdceSThomas Gleixner 2313993647a2SArvind Yadav static const struct attribute_group cpuhp_cpu_attr_group = { 231498f8cdceSThomas Gleixner .attrs = cpuhp_cpu_attrs, 231598f8cdceSThomas Gleixner .name = "hotplug", 231698f8cdceSThomas Gleixner NULL 231798f8cdceSThomas Gleixner }; 231898f8cdceSThomas Gleixner 231998f8cdceSThomas Gleixner static ssize_t show_cpuhp_states(struct device *dev, 232098f8cdceSThomas Gleixner struct device_attribute *attr, char *buf) 232198f8cdceSThomas Gleixner { 232298f8cdceSThomas Gleixner ssize_t cur, res = 0; 232398f8cdceSThomas Gleixner int i; 232498f8cdceSThomas Gleixner 232598f8cdceSThomas Gleixner mutex_lock(&cpuhp_state_mutex); 2326757c989bSThomas Gleixner for (i = CPUHP_OFFLINE; i <= CPUHP_ONLINE; i++) { 232798f8cdceSThomas Gleixner struct cpuhp_step *sp = cpuhp_get_step(i); 232898f8cdceSThomas Gleixner 232998f8cdceSThomas Gleixner if (sp->name) { 233098f8cdceSThomas Gleixner cur = sprintf(buf, "%3d: %s\n", i, sp->name); 233198f8cdceSThomas Gleixner buf += cur; 233298f8cdceSThomas Gleixner res += cur; 233398f8cdceSThomas Gleixner } 233498f8cdceSThomas Gleixner } 233598f8cdceSThomas Gleixner mutex_unlock(&cpuhp_state_mutex); 233698f8cdceSThomas Gleixner return res; 233798f8cdceSThomas Gleixner } 233898f8cdceSThomas Gleixner static DEVICE_ATTR(states, 0444, show_cpuhp_states, NULL); 233998f8cdceSThomas Gleixner 234098f8cdceSThomas Gleixner static struct attribute *cpuhp_cpu_root_attrs[] = { 234198f8cdceSThomas Gleixner &dev_attr_states.attr, 234298f8cdceSThomas Gleixner NULL 234398f8cdceSThomas Gleixner }; 234498f8cdceSThomas Gleixner 2345993647a2SArvind Yadav static const struct attribute_group cpuhp_cpu_root_attr_group = { 234698f8cdceSThomas Gleixner .attrs = cpuhp_cpu_root_attrs, 234798f8cdceSThomas Gleixner .name = "hotplug", 234898f8cdceSThomas Gleixner NULL 234998f8cdceSThomas Gleixner }; 235098f8cdceSThomas Gleixner 235105736e4aSThomas Gleixner #ifdef CONFIG_HOTPLUG_SMT 235205736e4aSThomas Gleixner 235305736e4aSThomas Gleixner static ssize_t 2354de7b77e5SJosh Poimboeuf __store_smt_control(struct device *dev, struct device_attribute *attr, 235505736e4aSThomas Gleixner const char *buf, size_t count) 235605736e4aSThomas Gleixner { 235705736e4aSThomas Gleixner int ctrlval, ret; 235805736e4aSThomas Gleixner 235905736e4aSThomas Gleixner if (sysfs_streq(buf, "on")) 236005736e4aSThomas Gleixner ctrlval = CPU_SMT_ENABLED; 236105736e4aSThomas Gleixner else if (sysfs_streq(buf, "off")) 236205736e4aSThomas Gleixner ctrlval = CPU_SMT_DISABLED; 236305736e4aSThomas Gleixner else if (sysfs_streq(buf, "forceoff")) 236405736e4aSThomas Gleixner ctrlval = CPU_SMT_FORCE_DISABLED; 236505736e4aSThomas Gleixner else 236605736e4aSThomas Gleixner return -EINVAL; 236705736e4aSThomas Gleixner 236805736e4aSThomas Gleixner if (cpu_smt_control == CPU_SMT_FORCE_DISABLED) 236905736e4aSThomas Gleixner return -EPERM; 237005736e4aSThomas Gleixner 237105736e4aSThomas Gleixner if (cpu_smt_control == CPU_SMT_NOT_SUPPORTED) 237205736e4aSThomas Gleixner return -ENODEV; 237305736e4aSThomas Gleixner 237405736e4aSThomas Gleixner ret = lock_device_hotplug_sysfs(); 237505736e4aSThomas Gleixner if (ret) 237605736e4aSThomas Gleixner return ret; 237705736e4aSThomas Gleixner 237805736e4aSThomas Gleixner if (ctrlval != cpu_smt_control) { 237905736e4aSThomas Gleixner switch (ctrlval) { 238005736e4aSThomas Gleixner case CPU_SMT_ENABLED: 2381215af549SThomas Gleixner ret = cpuhp_smt_enable(); 238205736e4aSThomas Gleixner break; 238305736e4aSThomas Gleixner case CPU_SMT_DISABLED: 238405736e4aSThomas Gleixner case CPU_SMT_FORCE_DISABLED: 238505736e4aSThomas Gleixner ret = cpuhp_smt_disable(ctrlval); 238605736e4aSThomas Gleixner break; 238705736e4aSThomas Gleixner } 238805736e4aSThomas Gleixner } 238905736e4aSThomas Gleixner 239005736e4aSThomas Gleixner unlock_device_hotplug(); 239105736e4aSThomas Gleixner return ret ? ret : count; 239205736e4aSThomas Gleixner } 2393de7b77e5SJosh Poimboeuf 2394de7b77e5SJosh Poimboeuf #else /* !CONFIG_HOTPLUG_SMT */ 2395de7b77e5SJosh Poimboeuf static ssize_t 2396de7b77e5SJosh Poimboeuf __store_smt_control(struct device *dev, struct device_attribute *attr, 2397de7b77e5SJosh Poimboeuf const char *buf, size_t count) 2398de7b77e5SJosh Poimboeuf { 2399de7b77e5SJosh Poimboeuf return -ENODEV; 2400de7b77e5SJosh Poimboeuf } 2401de7b77e5SJosh Poimboeuf #endif /* CONFIG_HOTPLUG_SMT */ 2402de7b77e5SJosh Poimboeuf 2403de7b77e5SJosh Poimboeuf static const char *smt_states[] = { 2404de7b77e5SJosh Poimboeuf [CPU_SMT_ENABLED] = "on", 2405de7b77e5SJosh Poimboeuf [CPU_SMT_DISABLED] = "off", 2406de7b77e5SJosh Poimboeuf [CPU_SMT_FORCE_DISABLED] = "forceoff", 2407de7b77e5SJosh Poimboeuf [CPU_SMT_NOT_SUPPORTED] = "notsupported", 2408de7b77e5SJosh Poimboeuf [CPU_SMT_NOT_IMPLEMENTED] = "notimplemented", 2409de7b77e5SJosh Poimboeuf }; 2410de7b77e5SJosh Poimboeuf 2411de7b77e5SJosh Poimboeuf static ssize_t 2412de7b77e5SJosh Poimboeuf show_smt_control(struct device *dev, struct device_attribute *attr, char *buf) 2413de7b77e5SJosh Poimboeuf { 2414de7b77e5SJosh Poimboeuf const char *state = smt_states[cpu_smt_control]; 2415de7b77e5SJosh Poimboeuf 2416de7b77e5SJosh Poimboeuf return snprintf(buf, PAGE_SIZE - 2, "%s\n", state); 2417de7b77e5SJosh Poimboeuf } 2418de7b77e5SJosh Poimboeuf 2419de7b77e5SJosh Poimboeuf static ssize_t 2420de7b77e5SJosh Poimboeuf store_smt_control(struct device *dev, struct device_attribute *attr, 2421de7b77e5SJosh Poimboeuf const char *buf, size_t count) 2422de7b77e5SJosh Poimboeuf { 2423de7b77e5SJosh Poimboeuf return __store_smt_control(dev, attr, buf, count); 2424de7b77e5SJosh Poimboeuf } 242505736e4aSThomas Gleixner static DEVICE_ATTR(control, 0644, show_smt_control, store_smt_control); 242605736e4aSThomas Gleixner 242705736e4aSThomas Gleixner static ssize_t 242805736e4aSThomas Gleixner show_smt_active(struct device *dev, struct device_attribute *attr, char *buf) 242905736e4aSThomas Gleixner { 2430de7b77e5SJosh Poimboeuf return snprintf(buf, PAGE_SIZE - 2, "%d\n", sched_smt_active()); 243105736e4aSThomas Gleixner } 243205736e4aSThomas Gleixner static DEVICE_ATTR(active, 0444, show_smt_active, NULL); 243305736e4aSThomas Gleixner 243405736e4aSThomas Gleixner static struct attribute *cpuhp_smt_attrs[] = { 243505736e4aSThomas Gleixner &dev_attr_control.attr, 243605736e4aSThomas Gleixner &dev_attr_active.attr, 243705736e4aSThomas Gleixner NULL 243805736e4aSThomas Gleixner }; 243905736e4aSThomas Gleixner 244005736e4aSThomas Gleixner static const struct attribute_group cpuhp_smt_attr_group = { 244105736e4aSThomas Gleixner .attrs = cpuhp_smt_attrs, 244205736e4aSThomas Gleixner .name = "smt", 244305736e4aSThomas Gleixner NULL 244405736e4aSThomas Gleixner }; 244505736e4aSThomas Gleixner 2446de7b77e5SJosh Poimboeuf static int __init cpu_smt_sysfs_init(void) 244705736e4aSThomas Gleixner { 244805736e4aSThomas Gleixner return sysfs_create_group(&cpu_subsys.dev_root->kobj, 244905736e4aSThomas Gleixner &cpuhp_smt_attr_group); 245005736e4aSThomas Gleixner } 245105736e4aSThomas Gleixner 245298f8cdceSThomas Gleixner static int __init cpuhp_sysfs_init(void) 245398f8cdceSThomas Gleixner { 245498f8cdceSThomas Gleixner int cpu, ret; 245598f8cdceSThomas Gleixner 2456de7b77e5SJosh Poimboeuf ret = cpu_smt_sysfs_init(); 245705736e4aSThomas Gleixner if (ret) 245805736e4aSThomas Gleixner return ret; 245905736e4aSThomas Gleixner 246098f8cdceSThomas Gleixner ret = sysfs_create_group(&cpu_subsys.dev_root->kobj, 246198f8cdceSThomas Gleixner &cpuhp_cpu_root_attr_group); 246298f8cdceSThomas Gleixner if (ret) 246398f8cdceSThomas Gleixner return ret; 246498f8cdceSThomas Gleixner 246598f8cdceSThomas Gleixner for_each_possible_cpu(cpu) { 246698f8cdceSThomas Gleixner struct device *dev = get_cpu_device(cpu); 246798f8cdceSThomas Gleixner 246898f8cdceSThomas Gleixner if (!dev) 246998f8cdceSThomas Gleixner continue; 247098f8cdceSThomas Gleixner ret = sysfs_create_group(&dev->kobj, &cpuhp_cpu_attr_group); 247198f8cdceSThomas Gleixner if (ret) 247298f8cdceSThomas Gleixner return ret; 247398f8cdceSThomas Gleixner } 247498f8cdceSThomas Gleixner return 0; 247598f8cdceSThomas Gleixner } 247698f8cdceSThomas Gleixner device_initcall(cpuhp_sysfs_init); 2477de7b77e5SJosh Poimboeuf #endif /* CONFIG_SYSFS && CONFIG_HOTPLUG_CPU */ 247898f8cdceSThomas Gleixner 2479e56b3bc7SLinus Torvalds /* 2480e56b3bc7SLinus Torvalds * cpu_bit_bitmap[] is a special, "compressed" data structure that 2481e56b3bc7SLinus Torvalds * represents all NR_CPUS bits binary values of 1<<nr. 2482e56b3bc7SLinus Torvalds * 2483e0b582ecSRusty Russell * It is used by cpumask_of() to get a constant address to a CPU 2484e56b3bc7SLinus Torvalds * mask value that has a single bit set only. 2485e56b3bc7SLinus Torvalds */ 2486b8d317d1SMike Travis 2487e56b3bc7SLinus Torvalds /* cpu_bit_bitmap[0] is empty - so we can back into it */ 24884d51985eSMichael Rodriguez #define MASK_DECLARE_1(x) [x+1][0] = (1UL << (x)) 2489e56b3bc7SLinus Torvalds #define MASK_DECLARE_2(x) MASK_DECLARE_1(x), MASK_DECLARE_1(x+1) 2490e56b3bc7SLinus Torvalds #define MASK_DECLARE_4(x) MASK_DECLARE_2(x), MASK_DECLARE_2(x+2) 2491e56b3bc7SLinus Torvalds #define MASK_DECLARE_8(x) MASK_DECLARE_4(x), MASK_DECLARE_4(x+4) 2492b8d317d1SMike Travis 2493e56b3bc7SLinus Torvalds const unsigned long cpu_bit_bitmap[BITS_PER_LONG+1][BITS_TO_LONGS(NR_CPUS)] = { 2494b8d317d1SMike Travis 2495e56b3bc7SLinus Torvalds MASK_DECLARE_8(0), MASK_DECLARE_8(8), 2496e56b3bc7SLinus Torvalds MASK_DECLARE_8(16), MASK_DECLARE_8(24), 2497e56b3bc7SLinus Torvalds #if BITS_PER_LONG > 32 2498e56b3bc7SLinus Torvalds MASK_DECLARE_8(32), MASK_DECLARE_8(40), 2499e56b3bc7SLinus Torvalds MASK_DECLARE_8(48), MASK_DECLARE_8(56), 2500b8d317d1SMike Travis #endif 2501b8d317d1SMike Travis }; 2502e56b3bc7SLinus Torvalds EXPORT_SYMBOL_GPL(cpu_bit_bitmap); 25032d3854a3SRusty Russell 25042d3854a3SRusty Russell const DECLARE_BITMAP(cpu_all_bits, NR_CPUS) = CPU_BITS_ALL; 25052d3854a3SRusty Russell EXPORT_SYMBOL(cpu_all_bits); 2506b3199c02SRusty Russell 2507b3199c02SRusty Russell #ifdef CONFIG_INIT_ALL_POSSIBLE 25084b804c85SRasmus Villemoes struct cpumask __cpu_possible_mask __read_mostly 2509c4c54dd1SRasmus Villemoes = {CPU_BITS_ALL}; 2510b3199c02SRusty Russell #else 25114b804c85SRasmus Villemoes struct cpumask __cpu_possible_mask __read_mostly; 2512b3199c02SRusty Russell #endif 25134b804c85SRasmus Villemoes EXPORT_SYMBOL(__cpu_possible_mask); 2514b3199c02SRusty Russell 25154b804c85SRasmus Villemoes struct cpumask __cpu_online_mask __read_mostly; 25164b804c85SRasmus Villemoes EXPORT_SYMBOL(__cpu_online_mask); 2517b3199c02SRusty Russell 25184b804c85SRasmus Villemoes struct cpumask __cpu_present_mask __read_mostly; 25194b804c85SRasmus Villemoes EXPORT_SYMBOL(__cpu_present_mask); 2520b3199c02SRusty Russell 25214b804c85SRasmus Villemoes struct cpumask __cpu_active_mask __read_mostly; 25224b804c85SRasmus Villemoes EXPORT_SYMBOL(__cpu_active_mask); 25233fa41520SRusty Russell 2524e40f74c5SPeter Zijlstra struct cpumask __cpu_dying_mask __read_mostly; 2525e40f74c5SPeter Zijlstra EXPORT_SYMBOL(__cpu_dying_mask); 2526e40f74c5SPeter Zijlstra 25270c09ab96SThomas Gleixner atomic_t __num_online_cpus __read_mostly; 25280c09ab96SThomas Gleixner EXPORT_SYMBOL(__num_online_cpus); 25290c09ab96SThomas Gleixner 25303fa41520SRusty Russell void init_cpu_present(const struct cpumask *src) 25313fa41520SRusty Russell { 2532c4c54dd1SRasmus Villemoes cpumask_copy(&__cpu_present_mask, src); 25333fa41520SRusty Russell } 25343fa41520SRusty Russell 25353fa41520SRusty Russell void init_cpu_possible(const struct cpumask *src) 25363fa41520SRusty Russell { 2537c4c54dd1SRasmus Villemoes cpumask_copy(&__cpu_possible_mask, src); 25383fa41520SRusty Russell } 25393fa41520SRusty Russell 25403fa41520SRusty Russell void init_cpu_online(const struct cpumask *src) 25413fa41520SRusty Russell { 2542c4c54dd1SRasmus Villemoes cpumask_copy(&__cpu_online_mask, src); 25433fa41520SRusty Russell } 2544cff7d378SThomas Gleixner 25450c09ab96SThomas Gleixner void set_cpu_online(unsigned int cpu, bool online) 25460c09ab96SThomas Gleixner { 25470c09ab96SThomas Gleixner /* 25480c09ab96SThomas Gleixner * atomic_inc/dec() is required to handle the horrid abuse of this 25490c09ab96SThomas Gleixner * function by the reboot and kexec code which invoke it from 25500c09ab96SThomas Gleixner * IPI/NMI broadcasts when shutting down CPUs. Invocation from 25510c09ab96SThomas Gleixner * regular CPU hotplug is properly serialized. 25520c09ab96SThomas Gleixner * 25530c09ab96SThomas Gleixner * Note, that the fact that __num_online_cpus is of type atomic_t 25540c09ab96SThomas Gleixner * does not protect readers which are not serialized against 25550c09ab96SThomas Gleixner * concurrent hotplug operations. 25560c09ab96SThomas Gleixner */ 25570c09ab96SThomas Gleixner if (online) { 25580c09ab96SThomas Gleixner if (!cpumask_test_and_set_cpu(cpu, &__cpu_online_mask)) 25590c09ab96SThomas Gleixner atomic_inc(&__num_online_cpus); 25600c09ab96SThomas Gleixner } else { 25610c09ab96SThomas Gleixner if (cpumask_test_and_clear_cpu(cpu, &__cpu_online_mask)) 25620c09ab96SThomas Gleixner atomic_dec(&__num_online_cpus); 25630c09ab96SThomas Gleixner } 25640c09ab96SThomas Gleixner } 25650c09ab96SThomas Gleixner 2566cff7d378SThomas Gleixner /* 2567cff7d378SThomas Gleixner * Activate the first processor. 2568cff7d378SThomas Gleixner */ 2569cff7d378SThomas Gleixner void __init boot_cpu_init(void) 2570cff7d378SThomas Gleixner { 2571cff7d378SThomas Gleixner int cpu = smp_processor_id(); 2572cff7d378SThomas Gleixner 2573cff7d378SThomas Gleixner /* Mark the boot cpu "present", "online" etc for SMP and UP case */ 2574cff7d378SThomas Gleixner set_cpu_online(cpu, true); 2575cff7d378SThomas Gleixner set_cpu_active(cpu, true); 2576cff7d378SThomas Gleixner set_cpu_present(cpu, true); 2577cff7d378SThomas Gleixner set_cpu_possible(cpu, true); 25788ce371f9SPeter Zijlstra 25798ce371f9SPeter Zijlstra #ifdef CONFIG_SMP 25808ce371f9SPeter Zijlstra __boot_cpu_id = cpu; 25818ce371f9SPeter Zijlstra #endif 2582cff7d378SThomas Gleixner } 2583cff7d378SThomas Gleixner 2584cff7d378SThomas Gleixner /* 2585cff7d378SThomas Gleixner * Must be called _AFTER_ setting up the per_cpu areas 2586cff7d378SThomas Gleixner */ 2587b5b1404dSLinus Torvalds void __init boot_cpu_hotplug_init(void) 2588cff7d378SThomas Gleixner { 2589269777aaSAbel Vesa #ifdef CONFIG_SMP 2590e797bda3SThomas Gleixner cpumask_set_cpu(smp_processor_id(), &cpus_booted_once_mask); 2591269777aaSAbel Vesa #endif 25920cc3cd21SThomas Gleixner this_cpu_write(cpuhp_state.state, CPUHP_ONLINE); 2593cff7d378SThomas Gleixner } 259498af8452SJosh Poimboeuf 2595731dc9dfSTyler Hicks /* 2596731dc9dfSTyler Hicks * These are used for a global "mitigations=" cmdline option for toggling 2597731dc9dfSTyler Hicks * optional CPU mitigations. 2598731dc9dfSTyler Hicks */ 2599731dc9dfSTyler Hicks enum cpu_mitigations { 2600731dc9dfSTyler Hicks CPU_MITIGATIONS_OFF, 2601731dc9dfSTyler Hicks CPU_MITIGATIONS_AUTO, 2602731dc9dfSTyler Hicks CPU_MITIGATIONS_AUTO_NOSMT, 2603731dc9dfSTyler Hicks }; 2604731dc9dfSTyler Hicks 2605731dc9dfSTyler Hicks static enum cpu_mitigations cpu_mitigations __ro_after_init = 2606731dc9dfSTyler Hicks CPU_MITIGATIONS_AUTO; 260798af8452SJosh Poimboeuf 260898af8452SJosh Poimboeuf static int __init mitigations_parse_cmdline(char *arg) 260998af8452SJosh Poimboeuf { 261098af8452SJosh Poimboeuf if (!strcmp(arg, "off")) 261198af8452SJosh Poimboeuf cpu_mitigations = CPU_MITIGATIONS_OFF; 261298af8452SJosh Poimboeuf else if (!strcmp(arg, "auto")) 261398af8452SJosh Poimboeuf cpu_mitigations = CPU_MITIGATIONS_AUTO; 261498af8452SJosh Poimboeuf else if (!strcmp(arg, "auto,nosmt")) 261598af8452SJosh Poimboeuf cpu_mitigations = CPU_MITIGATIONS_AUTO_NOSMT; 26161bf72720SGeert Uytterhoeven else 26171bf72720SGeert Uytterhoeven pr_crit("Unsupported mitigations=%s, system may still be vulnerable\n", 26181bf72720SGeert Uytterhoeven arg); 261998af8452SJosh Poimboeuf 262098af8452SJosh Poimboeuf return 0; 262198af8452SJosh Poimboeuf } 262298af8452SJosh Poimboeuf early_param("mitigations", mitigations_parse_cmdline); 2623731dc9dfSTyler Hicks 2624731dc9dfSTyler Hicks /* mitigations=off */ 2625731dc9dfSTyler Hicks bool cpu_mitigations_off(void) 2626731dc9dfSTyler Hicks { 2627731dc9dfSTyler Hicks return cpu_mitigations == CPU_MITIGATIONS_OFF; 2628731dc9dfSTyler Hicks } 2629731dc9dfSTyler Hicks EXPORT_SYMBOL_GPL(cpu_mitigations_off); 2630731dc9dfSTyler Hicks 2631731dc9dfSTyler Hicks /* mitigations=auto,nosmt */ 2632731dc9dfSTyler Hicks bool cpu_mitigations_auto_nosmt(void) 2633731dc9dfSTyler Hicks { 2634731dc9dfSTyler Hicks return cpu_mitigations == CPU_MITIGATIONS_AUTO_NOSMT; 2635731dc9dfSTyler Hicks } 2636731dc9dfSTyler Hicks EXPORT_SYMBOL_GPL(cpu_mitigations_auto_nosmt); 2637