|
@@ -52,6 +52,7 @@ struct cpuhp_cpu_state {
|
|
bool rollback;
|
|
bool rollback;
|
|
bool single;
|
|
bool single;
|
|
bool bringup;
|
|
bool bringup;
|
|
|
|
+ struct hlist_node *node;
|
|
enum cpuhp_state cb_state;
|
|
enum cpuhp_state cb_state;
|
|
int result;
|
|
int result;
|
|
struct completion done;
|
|
struct completion done;
|
|
@@ -70,11 +71,21 @@ static DEFINE_PER_CPU(struct cpuhp_cpu_state, cpuhp_state);
|
|
* @cant_stop: Bringup/teardown can't be stopped at this step
|
|
* @cant_stop: Bringup/teardown can't be stopped at this step
|
|
*/
|
|
*/
|
|
struct cpuhp_step {
|
|
struct cpuhp_step {
|
|
- const char *name;
|
|
|
|
- int (*startup)(unsigned int cpu);
|
|
|
|
- int (*teardown)(unsigned int cpu);
|
|
|
|
- bool skip_onerr;
|
|
|
|
- bool cant_stop;
|
|
|
|
|
|
+ const char *name;
|
|
|
|
+ union {
|
|
|
|
+ int (*startup)(unsigned int cpu);
|
|
|
|
+ int (*startup_multi)(unsigned int cpu,
|
|
|
|
+ struct hlist_node *node);
|
|
|
|
+ };
|
|
|
|
+ union {
|
|
|
|
+ int (*teardown)(unsigned int cpu);
|
|
|
|
+ int (*teardown_multi)(unsigned int cpu,
|
|
|
|
+ struct hlist_node *node);
|
|
|
|
+ };
|
|
|
|
+ struct hlist_head list;
|
|
|
|
+ bool skip_onerr;
|
|
|
|
+ bool cant_stop;
|
|
|
|
+ bool multi_instance;
|
|
};
|
|
};
|
|
|
|
|
|
static DEFINE_MUTEX(cpuhp_state_mutex);
|
|
static DEFINE_MUTEX(cpuhp_state_mutex);
|
|
@@ -104,20 +115,59 @@ static struct cpuhp_step *cpuhp_get_step(enum cpuhp_state state)
|
|
* @step: The step in the state machine
|
|
* @step: The step in the state machine
|
|
* @bringup: True if the bringup callback should be invoked
|
|
* @bringup: True if the bringup callback should be invoked
|
|
*
|
|
*
|
|
- * Called from cpu hotplug and from the state register machinery
|
|
|
|
|
|
+ * Called from cpu hotplug and from the state register machinery.
|
|
*/
|
|
*/
|
|
static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state,
|
|
static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state,
|
|
- bool bringup)
|
|
|
|
|
|
+ bool bringup, struct hlist_node *node)
|
|
{
|
|
{
|
|
struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
|
|
struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
|
|
struct cpuhp_step *step = cpuhp_get_step(state);
|
|
struct cpuhp_step *step = cpuhp_get_step(state);
|
|
- int (*cb)(unsigned int cpu) = bringup ? step->startup : step->teardown;
|
|
|
|
- int ret = 0;
|
|
|
|
-
|
|
|
|
- if (cb) {
|
|
|
|
|
|
+ int (*cbm)(unsigned int cpu, struct hlist_node *node);
|
|
|
|
+ int (*cb)(unsigned int cpu);
|
|
|
|
+ int ret, cnt;
|
|
|
|
+
|
|
|
|
+ if (!step->multi_instance) {
|
|
|
|
+ cb = bringup ? step->startup : step->teardown;
|
|
|
|
+ if (!cb)
|
|
|
|
+ return 0;
|
|
trace_cpuhp_enter(cpu, st->target, state, cb);
|
|
trace_cpuhp_enter(cpu, st->target, state, cb);
|
|
ret = cb(cpu);
|
|
ret = cb(cpu);
|
|
trace_cpuhp_exit(cpu, st->state, state, ret);
|
|
trace_cpuhp_exit(cpu, st->state, state, ret);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+ cbm = bringup ? step->startup_multi : step->teardown_multi;
|
|
|
|
+ if (!cbm)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ /* Single invocation for instance add/remove */
|
|
|
|
+ if (node) {
|
|
|
|
+ trace_cpuhp_multi_enter(cpu, st->target, state, cbm, node);
|
|
|
|
+ ret = cbm(cpu, node);
|
|
|
|
+ trace_cpuhp_exit(cpu, st->state, state, ret);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* State transition. Invoke on all instances */
|
|
|
|
+ cnt = 0;
|
|
|
|
+ hlist_for_each(node, &step->list) {
|
|
|
|
+ trace_cpuhp_multi_enter(cpu, st->target, state, cbm, node);
|
|
|
|
+ ret = cbm(cpu, node);
|
|
|
|
+ trace_cpuhp_exit(cpu, st->state, state, ret);
|
|
|
|
+ if (ret)
|
|
|
|
+ goto err;
|
|
|
|
+ cnt++;
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+err:
|
|
|
|
+ /* Rollback the instances if one failed */
|
|
|
|
+ cbm = !bringup ? step->startup_multi : step->teardown_multi;
|
|
|
|
+ if (!cbm)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ hlist_for_each(node, &step->list) {
|
|
|
|
+ if (!cnt--)
|
|
|
|
+ break;
|
|
|
|
+ cbm(cpu, node);
|
|
}
|
|
}
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
@@ -398,7 +448,7 @@ static void undo_cpu_down(unsigned int cpu, struct cpuhp_cpu_state *st)
|
|
struct cpuhp_step *step = cpuhp_get_step(st->state);
|
|
struct cpuhp_step *step = cpuhp_get_step(st->state);
|
|
|
|
|
|
if (!step->skip_onerr)
|
|
if (!step->skip_onerr)
|
|
- cpuhp_invoke_callback(cpu, st->state, true);
|
|
|
|
|
|
+ cpuhp_invoke_callback(cpu, st->state, true, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -409,7 +459,7 @@ static int cpuhp_down_callbacks(unsigned int cpu, struct cpuhp_cpu_state *st,
|
|
int ret = 0;
|
|
int ret = 0;
|
|
|
|
|
|
for (; st->state > target; st->state--) {
|
|
for (; st->state > target; st->state--) {
|
|
- ret = cpuhp_invoke_callback(cpu, st->state, false);
|
|
|
|
|
|
+ ret = cpuhp_invoke_callback(cpu, st->state, false, NULL);
|
|
if (ret) {
|
|
if (ret) {
|
|
st->target = prev_state;
|
|
st->target = prev_state;
|
|
undo_cpu_down(cpu, st);
|
|
undo_cpu_down(cpu, st);
|
|
@@ -425,7 +475,7 @@ static void undo_cpu_up(unsigned int cpu, struct cpuhp_cpu_state *st)
|
|
struct cpuhp_step *step = cpuhp_get_step(st->state);
|
|
struct cpuhp_step *step = cpuhp_get_step(st->state);
|
|
|
|
|
|
if (!step->skip_onerr)
|
|
if (!step->skip_onerr)
|
|
- cpuhp_invoke_callback(cpu, st->state, false);
|
|
|
|
|
|
+ cpuhp_invoke_callback(cpu, st->state, false, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -437,7 +487,7 @@ static int cpuhp_up_callbacks(unsigned int cpu, struct cpuhp_cpu_state *st,
|
|
|
|
|
|
while (st->state < target) {
|
|
while (st->state < target) {
|
|
st->state++;
|
|
st->state++;
|
|
- ret = cpuhp_invoke_callback(cpu, st->state, true);
|
|
|
|
|
|
+ ret = cpuhp_invoke_callback(cpu, st->state, true, NULL);
|
|
if (ret) {
|
|
if (ret) {
|
|
st->target = prev_state;
|
|
st->target = prev_state;
|
|
undo_cpu_up(cpu, st);
|
|
undo_cpu_up(cpu, st);
|
|
@@ -502,11 +552,11 @@ static void cpuhp_thread_fun(unsigned int cpu)
|
|
if (st->cb_state < CPUHP_AP_ONLINE) {
|
|
if (st->cb_state < CPUHP_AP_ONLINE) {
|
|
local_irq_disable();
|
|
local_irq_disable();
|
|
ret = cpuhp_invoke_callback(cpu, st->cb_state,
|
|
ret = cpuhp_invoke_callback(cpu, st->cb_state,
|
|
- st->bringup);
|
|
|
|
|
|
+ st->bringup, st->node);
|
|
local_irq_enable();
|
|
local_irq_enable();
|
|
} else {
|
|
} else {
|
|
ret = cpuhp_invoke_callback(cpu, st->cb_state,
|
|
ret = cpuhp_invoke_callback(cpu, st->cb_state,
|
|
- st->bringup);
|
|
|
|
|
|
+ st->bringup, st->node);
|
|
}
|
|
}
|
|
} else if (st->rollback) {
|
|
} else if (st->rollback) {
|
|
BUG_ON(st->state < CPUHP_AP_ONLINE_IDLE);
|
|
BUG_ON(st->state < CPUHP_AP_ONLINE_IDLE);
|
|
@@ -534,7 +584,8 @@ static void cpuhp_thread_fun(unsigned int cpu)
|
|
|
|
|
|
/* Invoke a single callback on a remote cpu */
|
|
/* Invoke a single callback on a remote cpu */
|
|
static int
|
|
static int
|
|
-cpuhp_invoke_ap_callback(int cpu, enum cpuhp_state state, bool bringup)
|
|
|
|
|
|
+cpuhp_invoke_ap_callback(int cpu, enum cpuhp_state state, bool bringup,
|
|
|
|
+ struct hlist_node *node)
|
|
{
|
|
{
|
|
struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
|
|
struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
|
|
|
|
|
|
@@ -546,11 +597,12 @@ cpuhp_invoke_ap_callback(int cpu, enum cpuhp_state state, bool bringup)
|
|
* we invoke the thread function directly.
|
|
* we invoke the thread function directly.
|
|
*/
|
|
*/
|
|
if (!st->thread)
|
|
if (!st->thread)
|
|
- return cpuhp_invoke_callback(cpu, state, bringup);
|
|
|
|
|
|
+ return cpuhp_invoke_callback(cpu, state, bringup, node);
|
|
|
|
|
|
st->cb_state = state;
|
|
st->cb_state = state;
|
|
st->single = true;
|
|
st->single = true;
|
|
st->bringup = bringup;
|
|
st->bringup = bringup;
|
|
|
|
+ st->node = node;
|
|
|
|
|
|
/*
|
|
/*
|
|
* Make sure the above stores are visible before should_run becomes
|
|
* Make sure the above stores are visible before should_run becomes
|
|
@@ -726,7 +778,7 @@ static int take_cpu_down(void *_param)
|
|
st->state--;
|
|
st->state--;
|
|
/* Invoke the former CPU_DYING callbacks */
|
|
/* Invoke the former CPU_DYING callbacks */
|
|
for (; st->state > target; st->state--)
|
|
for (; st->state > target; st->state--)
|
|
- cpuhp_invoke_callback(cpu, st->state, false);
|
|
|
|
|
|
+ cpuhp_invoke_callback(cpu, st->state, false, NULL);
|
|
|
|
|
|
/* Give up timekeeping duties */
|
|
/* Give up timekeeping duties */
|
|
tick_handover_do_timer();
|
|
tick_handover_do_timer();
|
|
@@ -921,7 +973,7 @@ void notify_cpu_starting(unsigned int cpu)
|
|
|
|
|
|
while (st->state < target) {
|
|
while (st->state < target) {
|
|
st->state++;
|
|
st->state++;
|
|
- cpuhp_invoke_callback(cpu, st->state, true);
|
|
|
|
|
|
+ cpuhp_invoke_callback(cpu, st->state, true, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1386,7 +1438,8 @@ static int cpuhp_cb_check(enum cpuhp_state state)
|
|
static void cpuhp_store_callbacks(enum cpuhp_state state,
|
|
static void cpuhp_store_callbacks(enum cpuhp_state state,
|
|
const char *name,
|
|
const char *name,
|
|
int (*startup)(unsigned int cpu),
|
|
int (*startup)(unsigned int cpu),
|
|
- int (*teardown)(unsigned int cpu))
|
|
|
|
|
|
+ int (*teardown)(unsigned int cpu),
|
|
|
|
+ bool multi_instance)
|
|
{
|
|
{
|
|
/* (Un)Install the callbacks for further cpu hotplug operations */
|
|
/* (Un)Install the callbacks for further cpu hotplug operations */
|
|
struct cpuhp_step *sp;
|
|
struct cpuhp_step *sp;
|
|
@@ -1396,6 +1449,8 @@ static void cpuhp_store_callbacks(enum cpuhp_state state,
|
|
sp->startup = startup;
|
|
sp->startup = startup;
|
|
sp->teardown = teardown;
|
|
sp->teardown = teardown;
|
|
sp->name = name;
|
|
sp->name = name;
|
|
|
|
+ sp->multi_instance = multi_instance;
|
|
|
|
+ INIT_HLIST_HEAD(&sp->list);
|
|
mutex_unlock(&cpuhp_state_mutex);
|
|
mutex_unlock(&cpuhp_state_mutex);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1408,7 +1463,8 @@ static void *cpuhp_get_teardown_cb(enum cpuhp_state state)
|
|
* Call the startup/teardown function for a step either on the AP or
|
|
* Call the startup/teardown function for a step either on the AP or
|
|
* on the current CPU.
|
|
* on the current CPU.
|
|
*/
|
|
*/
|
|
-static int cpuhp_issue_call(int cpu, enum cpuhp_state state, bool bringup)
|
|
|
|
|
|
+static int cpuhp_issue_call(int cpu, enum cpuhp_state state, bool bringup,
|
|
|
|
+ struct hlist_node *node)
|
|
{
|
|
{
|
|
struct cpuhp_step *sp = cpuhp_get_step(state);
|
|
struct cpuhp_step *sp = cpuhp_get_step(state);
|
|
int ret;
|
|
int ret;
|
|
@@ -1421,11 +1477,11 @@ static int cpuhp_issue_call(int cpu, enum cpuhp_state state, bool bringup)
|
|
*/
|
|
*/
|
|
#ifdef CONFIG_SMP
|
|
#ifdef CONFIG_SMP
|
|
if (cpuhp_is_ap_state(state))
|
|
if (cpuhp_is_ap_state(state))
|
|
- ret = cpuhp_invoke_ap_callback(cpu, state, bringup);
|
|
|
|
|
|
+ ret = cpuhp_invoke_ap_callback(cpu, state, bringup, node);
|
|
else
|
|
else
|
|
- ret = cpuhp_invoke_callback(cpu, state, bringup);
|
|
|
|
|
|
+ ret = cpuhp_invoke_callback(cpu, state, bringup, node);
|
|
#else
|
|
#else
|
|
- ret = cpuhp_invoke_callback(cpu, state, bringup);
|
|
|
|
|
|
+ ret = cpuhp_invoke_callback(cpu, state, bringup, node);
|
|
#endif
|
|
#endif
|
|
BUG_ON(ret && !bringup);
|
|
BUG_ON(ret && !bringup);
|
|
return ret;
|
|
return ret;
|
|
@@ -1436,7 +1492,8 @@ static int cpuhp_issue_call(int cpu, enum cpuhp_state state, bool bringup)
|
|
*
|
|
*
|
|
* Note: The teardown callbacks for rollback are not allowed to fail!
|
|
* Note: The teardown callbacks for rollback are not allowed to fail!
|
|
*/
|
|
*/
|
|
-static void cpuhp_rollback_install(int failedcpu, enum cpuhp_state state)
|
|
|
|
|
|
+static void cpuhp_rollback_install(int failedcpu, enum cpuhp_state state,
|
|
|
|
+ struct hlist_node *node)
|
|
{
|
|
{
|
|
int cpu;
|
|
int cpu;
|
|
|
|
|
|
@@ -1450,7 +1507,7 @@ static void cpuhp_rollback_install(int failedcpu, enum cpuhp_state state)
|
|
|
|
|
|
/* Did we invoke the startup call on that cpu ? */
|
|
/* Did we invoke the startup call on that cpu ? */
|
|
if (cpustate >= state)
|
|
if (cpustate >= state)
|
|
- cpuhp_issue_call(cpu, state, false);
|
|
|
|
|
|
+ cpuhp_issue_call(cpu, state, false, node);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1477,6 +1534,52 @@ static int cpuhp_reserve_state(enum cpuhp_state state)
|
|
return -ENOSPC;
|
|
return -ENOSPC;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+int __cpuhp_state_add_instance(enum cpuhp_state state, struct hlist_node *node,
|
|
|
|
+ bool invoke)
|
|
|
|
+{
|
|
|
|
+ struct cpuhp_step *sp;
|
|
|
|
+ int cpu;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ sp = cpuhp_get_step(state);
|
|
|
|
+ if (sp->multi_instance == false)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ get_online_cpus();
|
|
|
|
+
|
|
|
|
+ if (!invoke || !sp->startup_multi)
|
|
|
|
+ goto add_node;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Try to call the startup callback for each present cpu
|
|
|
|
+ * depending on the hotplug state of the cpu.
|
|
|
|
+ */
|
|
|
|
+ for_each_present_cpu(cpu) {
|
|
|
|
+ struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
|
|
|
|
+ int cpustate = st->state;
|
|
|
|
+
|
|
|
|
+ if (cpustate < state)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ ret = cpuhp_issue_call(cpu, state, true, node);
|
|
|
|
+ if (ret) {
|
|
|
|
+ if (sp->teardown_multi)
|
|
|
|
+ cpuhp_rollback_install(cpu, state, node);
|
|
|
|
+ goto err;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+add_node:
|
|
|
|
+ ret = 0;
|
|
|
|
+ mutex_lock(&cpuhp_state_mutex);
|
|
|
|
+ hlist_add_head(node, &sp->list);
|
|
|
|
+ mutex_unlock(&cpuhp_state_mutex);
|
|
|
|
+
|
|
|
|
+err:
|
|
|
|
+ put_online_cpus();
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL_GPL(__cpuhp_state_add_instance);
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* __cpuhp_setup_state - Setup the callbacks for an hotplug machine state
|
|
* __cpuhp_setup_state - Setup the callbacks for an hotplug machine state
|
|
* @state: The state to setup
|
|
* @state: The state to setup
|
|
@@ -1490,7 +1593,8 @@ static int cpuhp_reserve_state(enum cpuhp_state state)
|
|
int __cpuhp_setup_state(enum cpuhp_state state,
|
|
int __cpuhp_setup_state(enum cpuhp_state state,
|
|
const char *name, bool invoke,
|
|
const char *name, bool invoke,
|
|
int (*startup)(unsigned int cpu),
|
|
int (*startup)(unsigned int cpu),
|
|
- int (*teardown)(unsigned int cpu))
|
|
|
|
|
|
+ int (*teardown)(unsigned int cpu),
|
|
|
|
+ bool multi_instance)
|
|
{
|
|
{
|
|
int cpu, ret = 0;
|
|
int cpu, ret = 0;
|
|
int dyn_state = 0;
|
|
int dyn_state = 0;
|
|
@@ -1509,7 +1613,7 @@ int __cpuhp_setup_state(enum cpuhp_state state,
|
|
state = ret;
|
|
state = ret;
|
|
}
|
|
}
|
|
|
|
|
|
- cpuhp_store_callbacks(state, name, startup, teardown);
|
|
|
|
|
|
+ cpuhp_store_callbacks(state, name, startup, teardown, multi_instance);
|
|
|
|
|
|
if (!invoke || !startup)
|
|
if (!invoke || !startup)
|
|
goto out;
|
|
goto out;
|
|
@@ -1525,11 +1629,11 @@ int __cpuhp_setup_state(enum cpuhp_state state,
|
|
if (cpustate < state)
|
|
if (cpustate < state)
|
|
continue;
|
|
continue;
|
|
|
|
|
|
- ret = cpuhp_issue_call(cpu, state, true);
|
|
|
|
|
|
+ ret = cpuhp_issue_call(cpu, state, true, NULL);
|
|
if (ret) {
|
|
if (ret) {
|
|
if (teardown)
|
|
if (teardown)
|
|
- cpuhp_rollback_install(cpu, state);
|
|
|
|
- cpuhp_store_callbacks(state, NULL, NULL, NULL);
|
|
|
|
|
|
+ cpuhp_rollback_install(cpu, state, NULL);
|
|
|
|
+ cpuhp_store_callbacks(state, NULL, NULL, NULL, false);
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1541,6 +1645,42 @@ out:
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(__cpuhp_setup_state);
|
|
EXPORT_SYMBOL(__cpuhp_setup_state);
|
|
|
|
|
|
|
|
+int __cpuhp_state_remove_instance(enum cpuhp_state state,
|
|
|
|
+ struct hlist_node *node, bool invoke)
|
|
|
|
+{
|
|
|
|
+ struct cpuhp_step *sp = cpuhp_get_step(state);
|
|
|
|
+ int cpu;
|
|
|
|
+
|
|
|
|
+ BUG_ON(cpuhp_cb_check(state));
|
|
|
|
+
|
|
|
|
+ if (!sp->multi_instance)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ get_online_cpus();
|
|
|
|
+ if (!invoke || !cpuhp_get_teardown_cb(state))
|
|
|
|
+ goto remove;
|
|
|
|
+ /*
|
|
|
|
+ * Call the teardown callback for each present cpu depending
|
|
|
|
+ * on the hotplug state of the cpu. This function is not
|
|
|
|
+ * allowed to fail currently!
|
|
|
|
+ */
|
|
|
|
+ for_each_present_cpu(cpu) {
|
|
|
|
+ struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
|
|
|
|
+ int cpustate = st->state;
|
|
|
|
+
|
|
|
|
+ if (cpustate >= state)
|
|
|
|
+ cpuhp_issue_call(cpu, state, false, node);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+remove:
|
|
|
|
+ mutex_lock(&cpuhp_state_mutex);
|
|
|
|
+ hlist_del(node);
|
|
|
|
+ mutex_unlock(&cpuhp_state_mutex);
|
|
|
|
+ put_online_cpus();
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL_GPL(__cpuhp_state_remove_instance);
|
|
/**
|
|
/**
|
|
* __cpuhp_remove_state - Remove the callbacks for an hotplug machine state
|
|
* __cpuhp_remove_state - Remove the callbacks for an hotplug machine state
|
|
* @state: The state to remove
|
|
* @state: The state to remove
|
|
@@ -1552,12 +1692,20 @@ EXPORT_SYMBOL(__cpuhp_setup_state);
|
|
*/
|
|
*/
|
|
void __cpuhp_remove_state(enum cpuhp_state state, bool invoke)
|
|
void __cpuhp_remove_state(enum cpuhp_state state, bool invoke)
|
|
{
|
|
{
|
|
|
|
+ struct cpuhp_step *sp = cpuhp_get_step(state);
|
|
int cpu;
|
|
int cpu;
|
|
|
|
|
|
BUG_ON(cpuhp_cb_check(state));
|
|
BUG_ON(cpuhp_cb_check(state));
|
|
|
|
|
|
get_online_cpus();
|
|
get_online_cpus();
|
|
|
|
|
|
|
|
+ if (sp->multi_instance) {
|
|
|
|
+ WARN(!hlist_empty(&sp->list),
|
|
|
|
+ "Error: Removing state %d which has instances left.\n",
|
|
|
|
+ state);
|
|
|
|
+ goto remove;
|
|
|
|
+ }
|
|
|
|
+
|
|
if (!invoke || !cpuhp_get_teardown_cb(state))
|
|
if (!invoke || !cpuhp_get_teardown_cb(state))
|
|
goto remove;
|
|
goto remove;
|
|
|
|
|
|
@@ -1571,10 +1719,10 @@ void __cpuhp_remove_state(enum cpuhp_state state, bool invoke)
|
|
int cpustate = st->state;
|
|
int cpustate = st->state;
|
|
|
|
|
|
if (cpustate >= state)
|
|
if (cpustate >= state)
|
|
- cpuhp_issue_call(cpu, state, false);
|
|
|
|
|
|
+ cpuhp_issue_call(cpu, state, false, NULL);
|
|
}
|
|
}
|
|
remove:
|
|
remove:
|
|
- cpuhp_store_callbacks(state, NULL, NULL, NULL);
|
|
|
|
|
|
+ cpuhp_store_callbacks(state, NULL, NULL, NULL, false);
|
|
put_online_cpus();
|
|
put_online_cpus();
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(__cpuhp_remove_state);
|
|
EXPORT_SYMBOL(__cpuhp_remove_state);
|