xref: /linux-6.15/kernel/cpu.c (revision 2ea46c6f)
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