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