aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2016-08-12 13:49:39 -0400
committerThomas Gleixner <tglx@linutronix.de>2016-09-02 14:05:05 -0400
commitcf392d10b69e6e6c57ceea48b347a2ab1a4b75b2 (patch)
tree45d917264300caaab4eede4ab32b10f75bd8e4c2
parenta724632ca0c84b494875e9367e07e29472c139ba (diff)
cpu/hotplug: Add multi instance support
This patch adds the ability for a given state to have multiple instances. Until now all states have a single instance and the startup / teardown callback use global variables. A few drivers need to perform a the same callbacks on multiple "instances". Currently we have three drivers in tree which all have a global list which they iterate over. With multi instance they support don't need their private list and the functionality has been moved into core code. Plus we hold the hotplug lock in core so no cpus comes/goes while instances are registered and we do rollback in error case :) Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Will Deacon <will.deacon@arm.com> Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/1471024183-12666-3-git-send-email-bigeasy@linutronix.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--include/linux/cpuhotplug.h110
-rw-r--r--include/trace/events/cpuhp.h28
-rw-r--r--kernel/cpu.c218
3 files changed, 318 insertions, 38 deletions
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 242bf530edfc..dcfe619171b4 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -99,7 +99,7 @@ enum cpuhp_state {
99 99
100int __cpuhp_setup_state(enum cpuhp_state state, const char *name, bool invoke, 100int __cpuhp_setup_state(enum cpuhp_state state, const char *name, bool invoke,
101 int (*startup)(unsigned int cpu), 101 int (*startup)(unsigned int cpu),
102 int (*teardown)(unsigned int cpu)); 102 int (*teardown)(unsigned int cpu), bool multi_instance);
103 103
104/** 104/**
105 * cpuhp_setup_state - Setup hotplug state callbacks with calling the callbacks 105 * cpuhp_setup_state - Setup hotplug state callbacks with calling the callbacks
@@ -116,7 +116,7 @@ static inline int cpuhp_setup_state(enum cpuhp_state state,
116 int (*startup)(unsigned int cpu), 116 int (*startup)(unsigned int cpu),
117 int (*teardown)(unsigned int cpu)) 117 int (*teardown)(unsigned int cpu))
118{ 118{
119 return __cpuhp_setup_state(state, name, true, startup, teardown); 119 return __cpuhp_setup_state(state, name, true, startup, teardown, false);
120} 120}
121 121
122/** 122/**
@@ -135,7 +135,66 @@ static inline int cpuhp_setup_state_nocalls(enum cpuhp_state state,
135 int (*startup)(unsigned int cpu), 135 int (*startup)(unsigned int cpu),
136 int (*teardown)(unsigned int cpu)) 136 int (*teardown)(unsigned int cpu))
137{ 137{
138 return __cpuhp_setup_state(state, name, false, startup, teardown); 138 return __cpuhp_setup_state(state, name, false, startup, teardown,
139 false);
140}
141
142/**
143 * cpuhp_setup_state_multi - Add callbacks for multi state
144 * @state: The state for which the calls are installed
145 * @name: Name of the callback.
146 * @startup: startup callback function
147 * @teardown: teardown callback function
148 *
149 * Sets the internal multi_instance flag and prepares a state to work as a multi
150 * instance callback. No callbacks are invoked at this point. The callbacks are
151 * invoked once an instance for this state are registered via
152 * @cpuhp_state_add_instance or @cpuhp_state_add_instance_nocalls.
153 */
154static inline int cpuhp_setup_state_multi(enum cpuhp_state state,
155 const char *name,
156 int (*startup)(unsigned int cpu,
157 struct hlist_node *node),
158 int (*teardown)(unsigned int cpu,
159 struct hlist_node *node))
160{
161 return __cpuhp_setup_state(state, name, false,
162 (void *) startup,
163 (void *) teardown, true);
164}
165
166int __cpuhp_state_add_instance(enum cpuhp_state state, struct hlist_node *node,
167 bool invoke);
168
169/**
170 * cpuhp_state_add_instance - Add an instance for a state and invoke startup
171 * callback.
172 * @state: The state for which the instance is installed
173 * @node: The node for this individual state.
174 *
175 * Installs the instance for the @state and invokes the startup callback on
176 * the present cpus which have already reached the @state. The @state must have
177 * been earlier marked as multi-instance by @cpuhp_setup_state_multi.
178 */
179static inline int cpuhp_state_add_instance(enum cpuhp_state state,
180 struct hlist_node *node)
181{
182 return __cpuhp_state_add_instance(state, node, true);
183}
184
185/**
186 * cpuhp_state_add_instance_nocalls - Add an instance for a state without
187 * invoking the startup callback.
188 * @state: The state for which the instance is installed
189 * @node: The node for this individual state.
190 *
191 * Installs the instance for the @state The @state must have been earlier
192 * marked as multi-instance by @cpuhp_setup_state_multi.
193 */
194static inline int cpuhp_state_add_instance_nocalls(enum cpuhp_state state,
195 struct hlist_node *node)
196{
197 return __cpuhp_state_add_instance(state, node, false);
139} 198}
140 199
141void __cpuhp_remove_state(enum cpuhp_state state, bool invoke); 200void __cpuhp_remove_state(enum cpuhp_state state, bool invoke);
@@ -162,6 +221,51 @@ static inline void cpuhp_remove_state_nocalls(enum cpuhp_state state)
162 __cpuhp_remove_state(state, false); 221 __cpuhp_remove_state(state, false);
163} 222}
164 223
224/**
225 * cpuhp_remove_multi_state - Remove hotplug multi state callback
226 * @state: The state for which the calls are removed
227 *
228 * Removes the callback functions from a multi state. This is the reverse of
229 * cpuhp_setup_state_multi(). All instances should have been removed before
230 * invoking this function.
231 */
232static inline void cpuhp_remove_multi_state(enum cpuhp_state state)
233{
234 __cpuhp_remove_state(state, false);
235}
236
237int __cpuhp_state_remove_instance(enum cpuhp_state state,
238 struct hlist_node *node, bool invoke);
239
240/**
241 * cpuhp_state_remove_instance - Remove hotplug instance from state and invoke
242 * the teardown callback
243 * @state: The state from which the instance is removed
244 * @node: The node for this individual state.
245 *
246 * Removes the instance and invokes the teardown callback on the present cpus
247 * which have already reached the @state.
248 */
249static inline int cpuhp_state_remove_instance(enum cpuhp_state state,
250 struct hlist_node *node)
251{
252 return __cpuhp_state_remove_instance(state, node, true);
253}
254
255/**
256 * cpuhp_state_remove_instance_nocalls - Remove hotplug instance from state
257 * without invoking the reatdown callback
258 * @state: The state from which the instance is removed
259 * @node: The node for this individual state.
260 *
261 * Removes the instance without invoking the teardown callback.
262 */
263static inline int cpuhp_state_remove_instance_nocalls(enum cpuhp_state state,
264 struct hlist_node *node)
265{
266 return __cpuhp_state_remove_instance(state, node, false);
267}
268
165#ifdef CONFIG_SMP 269#ifdef CONFIG_SMP
166void cpuhp_online_idle(enum cpuhp_state state); 270void cpuhp_online_idle(enum cpuhp_state state);
167#else 271#else
diff --git a/include/trace/events/cpuhp.h b/include/trace/events/cpuhp.h
index a72bd93ec7e5..996953db91d7 100644
--- a/include/trace/events/cpuhp.h
+++ b/include/trace/events/cpuhp.h
@@ -33,6 +33,34 @@ TRACE_EVENT(cpuhp_enter,
33 __entry->cpu, __entry->target, __entry->idx, __entry->fun) 33 __entry->cpu, __entry->target, __entry->idx, __entry->fun)
34); 34);
35 35
36TRACE_EVENT(cpuhp_multi_enter,
37
38 TP_PROTO(unsigned int cpu,
39 int target,
40 int idx,
41 int (*fun)(unsigned int, struct hlist_node *),
42 struct hlist_node *node),
43
44 TP_ARGS(cpu, target, idx, fun, node),
45
46 TP_STRUCT__entry(
47 __field( unsigned int, cpu )
48 __field( int, target )
49 __field( int, idx )
50 __field( void *, fun )
51 ),
52
53 TP_fast_assign(
54 __entry->cpu = cpu;
55 __entry->target = target;
56 __entry->idx = idx;
57 __entry->fun = fun;
58 ),
59
60 TP_printk("cpu: %04u target: %3d step: %3d (%pf)",
61 __entry->cpu, __entry->target, __entry->idx, __entry->fun)
62);
63
36TRACE_EVENT(cpuhp_exit, 64TRACE_EVENT(cpuhp_exit,
37 65
38 TP_PROTO(unsigned int cpu, 66 TP_PROTO(unsigned int cpu,
diff --git a/kernel/cpu.c b/kernel/cpu.c
index d36d8e0abfb8..c506485eaa75 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -52,6 +52,7 @@ struct cpuhp_cpu_state {
52 bool rollback; 52 bool rollback;
53 bool single; 53 bool single;
54 bool bringup; 54 bool bringup;
55 struct hlist_node *node;
55 enum cpuhp_state cb_state; 56 enum cpuhp_state cb_state;
56 int result; 57 int result;
57 struct completion done; 58 struct completion done;
@@ -70,11 +71,21 @@ static DEFINE_PER_CPU(struct cpuhp_cpu_state, cpuhp_state);
70 * @cant_stop: Bringup/teardown can't be stopped at this step 71 * @cant_stop: Bringup/teardown can't be stopped at this step
71 */ 72 */
72struct cpuhp_step { 73struct cpuhp_step {
73 const char *name; 74 const char *name;
74 int (*startup)(unsigned int cpu); 75 union {
75 int (*teardown)(unsigned int cpu); 76 int (*startup)(unsigned int cpu);
76 bool skip_onerr; 77 int (*startup_multi)(unsigned int cpu,
77 bool cant_stop; 78 struct hlist_node *node);
79 };
80 union {
81 int (*teardown)(unsigned int cpu);
82 int (*teardown_multi)(unsigned int cpu,
83 struct hlist_node *node);
84 };
85 struct hlist_head list;
86 bool skip_onerr;
87 bool cant_stop;
88 bool multi_instance;
78}; 89};
79 90
80static DEFINE_MUTEX(cpuhp_state_mutex); 91static DEFINE_MUTEX(cpuhp_state_mutex);
@@ -104,20 +115,59 @@ static struct cpuhp_step *cpuhp_get_step(enum cpuhp_state state)
104 * @step: The step in the state machine 115 * @step: The step in the state machine
105 * @bringup: True if the bringup callback should be invoked 116 * @bringup: True if the bringup callback should be invoked
106 * 117 *
107 * Called from cpu hotplug and from the state register machinery 118 * Called from cpu hotplug and from the state register machinery.
108 */ 119 */
109static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state, 120static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state,
110 bool bringup) 121 bool bringup, struct hlist_node *node)
111{ 122{
112 struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 123 struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
113 struct cpuhp_step *step = cpuhp_get_step(state); 124 struct cpuhp_step *step = cpuhp_get_step(state);
114 int (*cb)(unsigned int cpu) = bringup ? step->startup : step->teardown; 125 int (*cbm)(unsigned int cpu, struct hlist_node *node);
115 int ret = 0; 126 int (*cb)(unsigned int cpu);
116 127 int ret, cnt;
117 if (cb) { 128
129 if (!step->multi_instance) {
130 cb = bringup ? step->startup : step->teardown;
131 if (!cb)
132 return 0;
118 trace_cpuhp_enter(cpu, st->target, state, cb); 133 trace_cpuhp_enter(cpu, st->target, state, cb);
119 ret = cb(cpu); 134 ret = cb(cpu);
120 trace_cpuhp_exit(cpu, st->state, state, ret); 135 trace_cpuhp_exit(cpu, st->state, state, ret);
136 return ret;
137 }
138 cbm = bringup ? step->startup_multi : step->teardown_multi;
139 if (!cbm)
140 return 0;
141
142 /* Single invocation for instance add/remove */
143 if (node) {
144 trace_cpuhp_multi_enter(cpu, st->target, state, cbm, node);
145 ret = cbm(cpu, node);
146 trace_cpuhp_exit(cpu, st->state, state, ret);
147 return ret;
148 }
149
150 /* State transition. Invoke on all instances */
151 cnt = 0;
152 hlist_for_each(node, &step->list) {
153 trace_cpuhp_multi_enter(cpu, st->target, state, cbm, node);
154 ret = cbm(cpu, node);
155 trace_cpuhp_exit(cpu, st->state, state, ret);
156 if (ret)
157 goto err;
158 cnt++;
159 }
160 return 0;
161err:
162 /* Rollback the instances if one failed */
163 cbm = !bringup ? step->startup_multi : step->teardown_multi;
164 if (!cbm)
165 return ret;
166
167 hlist_for_each(node, &step->list) {
168 if (!cnt--)
169 break;
170 cbm(cpu, node);
121 } 171 }
122 return ret; 172 return ret;
123} 173}
@@ -398,7 +448,7 @@ static void undo_cpu_down(unsigned int cpu, struct cpuhp_cpu_state *st)
398 struct cpuhp_step *step = cpuhp_get_step(st->state); 448 struct cpuhp_step *step = cpuhp_get_step(st->state);
399 449
400 if (!step->skip_onerr) 450 if (!step->skip_onerr)
401 cpuhp_invoke_callback(cpu, st->state, true); 451 cpuhp_invoke_callback(cpu, st->state, true, NULL);
402 } 452 }
403} 453}
404 454
@@ -409,7 +459,7 @@ static int cpuhp_down_callbacks(unsigned int cpu, struct cpuhp_cpu_state *st,
409 int ret = 0; 459 int ret = 0;
410 460
411 for (; st->state > target; st->state--) { 461 for (; st->state > target; st->state--) {
412 ret = cpuhp_invoke_callback(cpu, st->state, false); 462 ret = cpuhp_invoke_callback(cpu, st->state, false, NULL);
413 if (ret) { 463 if (ret) {
414 st->target = prev_state; 464 st->target = prev_state;
415 undo_cpu_down(cpu, st); 465 undo_cpu_down(cpu, st);
@@ -425,7 +475,7 @@ static void undo_cpu_up(unsigned int cpu, struct cpuhp_cpu_state *st)
425 struct cpuhp_step *step = cpuhp_get_step(st->state); 475 struct cpuhp_step *step = cpuhp_get_step(st->state);
426 476
427 if (!step->skip_onerr) 477 if (!step->skip_onerr)
428 cpuhp_invoke_callback(cpu, st->state, false); 478 cpuhp_invoke_callback(cpu, st->state, false, NULL);
429 } 479 }
430} 480}
431 481
@@ -437,7 +487,7 @@ static int cpuhp_up_callbacks(unsigned int cpu, struct cpuhp_cpu_state *st,
437 487
438 while (st->state < target) { 488 while (st->state < target) {
439 st->state++; 489 st->state++;
440 ret = cpuhp_invoke_callback(cpu, st->state, true); 490 ret = cpuhp_invoke_callback(cpu, st->state, true, NULL);
441 if (ret) { 491 if (ret) {
442 st->target = prev_state; 492 st->target = prev_state;
443 undo_cpu_up(cpu, st); 493 undo_cpu_up(cpu, st);
@@ -502,11 +552,11 @@ static void cpuhp_thread_fun(unsigned int cpu)
502 if (st->cb_state < CPUHP_AP_ONLINE) { 552 if (st->cb_state < CPUHP_AP_ONLINE) {
503 local_irq_disable(); 553 local_irq_disable();
504 ret = cpuhp_invoke_callback(cpu, st->cb_state, 554 ret = cpuhp_invoke_callback(cpu, st->cb_state,
505 st->bringup); 555 st->bringup, st->node);
506 local_irq_enable(); 556 local_irq_enable();
507 } else { 557 } else {
508 ret = cpuhp_invoke_callback(cpu, st->cb_state, 558 ret = cpuhp_invoke_callback(cpu, st->cb_state,
509 st->bringup); 559 st->bringup, st->node);
510 } 560 }
511 } else if (st->rollback) { 561 } else if (st->rollback) {
512 BUG_ON(st->state < CPUHP_AP_ONLINE_IDLE); 562 BUG_ON(st->state < CPUHP_AP_ONLINE_IDLE);
@@ -534,7 +584,8 @@ static void cpuhp_thread_fun(unsigned int cpu)
534 584
535/* Invoke a single callback on a remote cpu */ 585/* Invoke a single callback on a remote cpu */
536static int 586static int
537cpuhp_invoke_ap_callback(int cpu, enum cpuhp_state state, bool bringup) 587cpuhp_invoke_ap_callback(int cpu, enum cpuhp_state state, bool bringup,
588 struct hlist_node *node)
538{ 589{
539 struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 590 struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
540 591
@@ -546,11 +597,12 @@ cpuhp_invoke_ap_callback(int cpu, enum cpuhp_state state, bool bringup)
546 * we invoke the thread function directly. 597 * we invoke the thread function directly.
547 */ 598 */
548 if (!st->thread) 599 if (!st->thread)
549 return cpuhp_invoke_callback(cpu, state, bringup); 600 return cpuhp_invoke_callback(cpu, state, bringup, node);
550 601
551 st->cb_state = state; 602 st->cb_state = state;
552 st->single = true; 603 st->single = true;
553 st->bringup = bringup; 604 st->bringup = bringup;
605 st->node = node;
554 606
555 /* 607 /*
556 * Make sure the above stores are visible before should_run becomes 608 * Make sure the above stores are visible before should_run becomes
@@ -726,7 +778,7 @@ static int take_cpu_down(void *_param)
726 st->state--; 778 st->state--;
727 /* Invoke the former CPU_DYING callbacks */ 779 /* Invoke the former CPU_DYING callbacks */
728 for (; st->state > target; st->state--) 780 for (; st->state > target; st->state--)
729 cpuhp_invoke_callback(cpu, st->state, false); 781 cpuhp_invoke_callback(cpu, st->state, false, NULL);
730 782
731 /* Give up timekeeping duties */ 783 /* Give up timekeeping duties */
732 tick_handover_do_timer(); 784 tick_handover_do_timer();
@@ -921,7 +973,7 @@ void notify_cpu_starting(unsigned int cpu)
921 973
922 while (st->state < target) { 974 while (st->state < target) {
923 st->state++; 975 st->state++;
924 cpuhp_invoke_callback(cpu, st->state, true); 976 cpuhp_invoke_callback(cpu, st->state, true, NULL);
925 } 977 }
926} 978}
927 979
@@ -1386,7 +1438,8 @@ static int cpuhp_cb_check(enum cpuhp_state state)
1386static void cpuhp_store_callbacks(enum cpuhp_state state, 1438static void cpuhp_store_callbacks(enum cpuhp_state state,
1387 const char *name, 1439 const char *name,
1388 int (*startup)(unsigned int cpu), 1440 int (*startup)(unsigned int cpu),
1389 int (*teardown)(unsigned int cpu)) 1441 int (*teardown)(unsigned int cpu),
1442 bool multi_instance)
1390{ 1443{
1391 /* (Un)Install the callbacks for further cpu hotplug operations */ 1444 /* (Un)Install the callbacks for further cpu hotplug operations */
1392 struct cpuhp_step *sp; 1445 struct cpuhp_step *sp;
@@ -1396,6 +1449,8 @@ static void cpuhp_store_callbacks(enum cpuhp_state state,
1396 sp->startup = startup; 1449 sp->startup = startup;
1397 sp->teardown = teardown; 1450 sp->teardown = teardown;
1398 sp->name = name; 1451 sp->name = name;
1452 sp->multi_instance = multi_instance;
1453 INIT_HLIST_HEAD(&sp->list);
1399 mutex_unlock(&cpuhp_state_mutex); 1454 mutex_unlock(&cpuhp_state_mutex);
1400} 1455}
1401 1456
@@ -1408,7 +1463,8 @@ static void *cpuhp_get_teardown_cb(enum cpuhp_state state)
1408 * Call the startup/teardown function for a step either on the AP or 1463 * Call the startup/teardown function for a step either on the AP or
1409 * on the current CPU. 1464 * on the current CPU.
1410 */ 1465 */
1411static int cpuhp_issue_call(int cpu, enum cpuhp_state state, bool bringup) 1466static int cpuhp_issue_call(int cpu, enum cpuhp_state state, bool bringup,
1467 struct hlist_node *node)
1412{ 1468{
1413 struct cpuhp_step *sp = cpuhp_get_step(state); 1469 struct cpuhp_step *sp = cpuhp_get_step(state);
1414 int ret; 1470 int ret;
@@ -1421,11 +1477,11 @@ static int cpuhp_issue_call(int cpu, enum cpuhp_state state, bool bringup)
1421 */ 1477 */
1422#ifdef CONFIG_SMP 1478#ifdef CONFIG_SMP
1423 if (cpuhp_is_ap_state(state)) 1479 if (cpuhp_is_ap_state(state))
1424 ret = cpuhp_invoke_ap_callback(cpu, state, bringup); 1480 ret = cpuhp_invoke_ap_callback(cpu, state, bringup, node);
1425 else 1481 else
1426 ret = cpuhp_invoke_callback(cpu, state, bringup); 1482 ret = cpuhp_invoke_callback(cpu, state, bringup, node);
1427#else 1483#else
1428 ret = cpuhp_invoke_callback(cpu, state, bringup); 1484 ret = cpuhp_invoke_callback(cpu, state, bringup, node);
1429#endif 1485#endif
1430 BUG_ON(ret && !bringup); 1486 BUG_ON(ret && !bringup);
1431 return ret; 1487 return ret;
@@ -1436,7 +1492,8 @@ static int cpuhp_issue_call(int cpu, enum cpuhp_state state, bool bringup)
1436 * 1492 *
1437 * Note: The teardown callbacks for rollback are not allowed to fail! 1493 * Note: The teardown callbacks for rollback are not allowed to fail!
1438 */ 1494 */
1439static void cpuhp_rollback_install(int failedcpu, enum cpuhp_state state) 1495static void cpuhp_rollback_install(int failedcpu, enum cpuhp_state state,
1496 struct hlist_node *node)
1440{ 1497{
1441 int cpu; 1498 int cpu;
1442 1499
@@ -1450,7 +1507,7 @@ static void cpuhp_rollback_install(int failedcpu, enum cpuhp_state state)
1450 1507
1451 /* Did we invoke the startup call on that cpu ? */ 1508 /* Did we invoke the startup call on that cpu ? */
1452 if (cpustate >= state) 1509 if (cpustate >= state)
1453 cpuhp_issue_call(cpu, state, false); 1510 cpuhp_issue_call(cpu, state, false, node);
1454 } 1511 }
1455} 1512}
1456 1513
@@ -1477,6 +1534,52 @@ static int cpuhp_reserve_state(enum cpuhp_state state)
1477 return -ENOSPC; 1534 return -ENOSPC;
1478} 1535}
1479 1536
1537int __cpuhp_state_add_instance(enum cpuhp_state state, struct hlist_node *node,
1538 bool invoke)
1539{
1540 struct cpuhp_step *sp;
1541 int cpu;
1542 int ret;
1543
1544 sp = cpuhp_get_step(state);
1545 if (sp->multi_instance == false)
1546 return -EINVAL;
1547
1548 get_online_cpus();
1549
1550 if (!invoke || !sp->startup_multi)
1551 goto add_node;
1552
1553 /*
1554 * Try to call the startup callback for each present cpu
1555 * depending on the hotplug state of the cpu.
1556 */
1557 for_each_present_cpu(cpu) {
1558 struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
1559 int cpustate = st->state;
1560
1561 if (cpustate < state)
1562 continue;
1563
1564 ret = cpuhp_issue_call(cpu, state, true, node);
1565 if (ret) {
1566 if (sp->teardown_multi)
1567 cpuhp_rollback_install(cpu, state, node);
1568 goto err;
1569 }
1570 }
1571add_node:
1572 ret = 0;
1573 mutex_lock(&cpuhp_state_mutex);
1574 hlist_add_head(node, &sp->list);
1575 mutex_unlock(&cpuhp_state_mutex);
1576
1577err:
1578 put_online_cpus();
1579 return ret;
1580}
1581EXPORT_SYMBOL_GPL(__cpuhp_state_add_instance);
1582
1480/** 1583/**
1481 * __cpuhp_setup_state - Setup the callbacks for an hotplug machine state 1584 * __cpuhp_setup_state - Setup the callbacks for an hotplug machine state
1482 * @state: The state to setup 1585 * @state: The state to setup
@@ -1490,7 +1593,8 @@ static int cpuhp_reserve_state(enum cpuhp_state state)
1490int __cpuhp_setup_state(enum cpuhp_state state, 1593int __cpuhp_setup_state(enum cpuhp_state state,
1491 const char *name, bool invoke, 1594 const char *name, bool invoke,
1492 int (*startup)(unsigned int cpu), 1595 int (*startup)(unsigned int cpu),
1493 int (*teardown)(unsigned int cpu)) 1596 int (*teardown)(unsigned int cpu),
1597 bool multi_instance)
1494{ 1598{
1495 int cpu, ret = 0; 1599 int cpu, ret = 0;
1496 int dyn_state = 0; 1600 int dyn_state = 0;
@@ -1509,7 +1613,7 @@ int __cpuhp_setup_state(enum cpuhp_state state,
1509 state = ret; 1613 state = ret;
1510 } 1614 }
1511 1615
1512 cpuhp_store_callbacks(state, name, startup, teardown); 1616 cpuhp_store_callbacks(state, name, startup, teardown, multi_instance);
1513 1617
1514 if (!invoke || !startup) 1618 if (!invoke || !startup)
1515 goto out; 1619 goto out;
@@ -1525,11 +1629,11 @@ int __cpuhp_setup_state(enum cpuhp_state state,
1525 if (cpustate < state) 1629 if (cpustate < state)
1526 continue; 1630 continue;
1527 1631
1528 ret = cpuhp_issue_call(cpu, state, true); 1632 ret = cpuhp_issue_call(cpu, state, true, NULL);
1529 if (ret) { 1633 if (ret) {
1530 if (teardown) 1634 if (teardown)
1531 cpuhp_rollback_install(cpu, state); 1635 cpuhp_rollback_install(cpu, state, NULL);
1532 cpuhp_store_callbacks(state, NULL, NULL, NULL); 1636 cpuhp_store_callbacks(state, NULL, NULL, NULL, false);
1533 goto out; 1637 goto out;
1534 } 1638 }
1535 } 1639 }
@@ -1541,6 +1645,42 @@ out:
1541} 1645}
1542EXPORT_SYMBOL(__cpuhp_setup_state); 1646EXPORT_SYMBOL(__cpuhp_setup_state);
1543 1647
1648int __cpuhp_state_remove_instance(enum cpuhp_state state,
1649 struct hlist_node *node, bool invoke)
1650{
1651 struct cpuhp_step *sp = cpuhp_get_step(state);
1652 int cpu;
1653
1654 BUG_ON(cpuhp_cb_check(state));
1655
1656 if (!sp->multi_instance)
1657 return -EINVAL;
1658
1659 get_online_cpus();
1660 if (!invoke || !cpuhp_get_teardown_cb(state))
1661 goto remove;
1662 /*
1663 * Call the teardown callback for each present cpu depending
1664 * on the hotplug state of the cpu. This function is not
1665 * allowed to fail currently!
1666 */
1667 for_each_present_cpu(cpu) {
1668 struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
1669 int cpustate = st->state;
1670
1671 if (cpustate >= state)
1672 cpuhp_issue_call(cpu, state, false, node);
1673 }
1674
1675remove:
1676 mutex_lock(&cpuhp_state_mutex);
1677 hlist_del(node);
1678 mutex_unlock(&cpuhp_state_mutex);
1679 put_online_cpus();
1680
1681 return 0;
1682}
1683EXPORT_SYMBOL_GPL(__cpuhp_state_remove_instance);
1544/** 1684/**
1545 * __cpuhp_remove_state - Remove the callbacks for an hotplug machine state 1685 * __cpuhp_remove_state - Remove the callbacks for an hotplug machine state
1546 * @state: The state to remove 1686 * @state: The state to remove
@@ -1552,12 +1692,20 @@ EXPORT_SYMBOL(__cpuhp_setup_state);
1552 */ 1692 */
1553void __cpuhp_remove_state(enum cpuhp_state state, bool invoke) 1693void __cpuhp_remove_state(enum cpuhp_state state, bool invoke)
1554{ 1694{
1695 struct cpuhp_step *sp = cpuhp_get_step(state);
1555 int cpu; 1696 int cpu;
1556 1697
1557 BUG_ON(cpuhp_cb_check(state)); 1698 BUG_ON(cpuhp_cb_check(state));
1558 1699
1559 get_online_cpus(); 1700 get_online_cpus();
1560 1701
1702 if (sp->multi_instance) {
1703 WARN(!hlist_empty(&sp->list),
1704 "Error: Removing state %d which has instances left.\n",
1705 state);
1706 goto remove;
1707 }
1708
1561 if (!invoke || !cpuhp_get_teardown_cb(state)) 1709 if (!invoke || !cpuhp_get_teardown_cb(state))
1562 goto remove; 1710 goto remove;
1563 1711
@@ -1571,10 +1719,10 @@ void __cpuhp_remove_state(enum cpuhp_state state, bool invoke)
1571 int cpustate = st->state; 1719 int cpustate = st->state;
1572 1720
1573 if (cpustate >= state) 1721 if (cpustate >= state)
1574 cpuhp_issue_call(cpu, state, false); 1722 cpuhp_issue_call(cpu, state, false, NULL);
1575 } 1723 }
1576remove: 1724remove:
1577 cpuhp_store_callbacks(state, NULL, NULL, NULL); 1725 cpuhp_store_callbacks(state, NULL, NULL, NULL, false);
1578 put_online_cpus(); 1726 put_online_cpus();
1579} 1727}
1580EXPORT_SYMBOL(__cpuhp_remove_state); 1728EXPORT_SYMBOL(__cpuhp_remove_state);