mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-25 19:42:19 +00:00
Merge tag 'smp-core-2022-12-10' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull CPU hotplug updates from Thomas Gleixner:
"A small set of updates for CPU hotplug:
- Prevent stale CPU hotplug state in the cpu_down() path which was
detected by stress testing the sysfs interface
- Ensure that the target CPU hotplug state for the boot CPU is
CPUHP_ONLINE instead of the compile time init value CPUHP_OFFLINE.
- Switch back to the original behaviour of warning when a CPU hotplug
callback in the DYING/STARTING section returns an error code.
Otherwise a buggy callback can leave the CPUs in an non recoverable
state"
* tag 'smp-core-2022-12-10' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
cpu/hotplug: Do not bail-out in DYING/STARTING sections
cpu/hotplug: Set cpuhp target for boot cpu
cpu/hotplug: Make target_store() a nop when target == state
This commit is contained in:
61
kernel/cpu.c
61
kernel/cpu.c
@@ -663,21 +663,51 @@ static bool cpuhp_next_state(bool bringup,
|
||||
return true;
|
||||
}
|
||||
|
||||
static int cpuhp_invoke_callback_range(bool bringup,
|
||||
unsigned int cpu,
|
||||
struct cpuhp_cpu_state *st,
|
||||
enum cpuhp_state target)
|
||||
static int __cpuhp_invoke_callback_range(bool bringup,
|
||||
unsigned int cpu,
|
||||
struct cpuhp_cpu_state *st,
|
||||
enum cpuhp_state target,
|
||||
bool nofail)
|
||||
{
|
||||
enum cpuhp_state state;
|
||||
int err = 0;
|
||||
int ret = 0;
|
||||
|
||||
while (cpuhp_next_state(bringup, &state, st, target)) {
|
||||
int err;
|
||||
|
||||
err = cpuhp_invoke_callback(cpu, state, bringup, NULL, NULL);
|
||||
if (err)
|
||||
if (!err)
|
||||
continue;
|
||||
|
||||
if (nofail) {
|
||||
pr_warn("CPU %u %s state %s (%d) failed (%d)\n",
|
||||
cpu, bringup ? "UP" : "DOWN",
|
||||
cpuhp_get_step(st->state)->name,
|
||||
st->state, err);
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = err;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int cpuhp_invoke_callback_range(bool bringup,
|
||||
unsigned int cpu,
|
||||
struct cpuhp_cpu_state *st,
|
||||
enum cpuhp_state target)
|
||||
{
|
||||
return __cpuhp_invoke_callback_range(bringup, cpu, st, target, false);
|
||||
}
|
||||
|
||||
static inline void cpuhp_invoke_callback_range_nofail(bool bringup,
|
||||
unsigned int cpu,
|
||||
struct cpuhp_cpu_state *st,
|
||||
enum cpuhp_state target)
|
||||
{
|
||||
__cpuhp_invoke_callback_range(bringup, cpu, st, target, true);
|
||||
}
|
||||
|
||||
static inline bool can_rollback_cpu(struct cpuhp_cpu_state *st)
|
||||
@@ -999,7 +1029,6 @@ static int take_cpu_down(void *_param)
|
||||
struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state);
|
||||
enum cpuhp_state target = max((int)st->target, CPUHP_AP_OFFLINE);
|
||||
int err, cpu = smp_processor_id();
|
||||
int ret;
|
||||
|
||||
/* Ensure this CPU doesn't handle any more interrupts. */
|
||||
err = __cpu_disable();
|
||||
@@ -1012,13 +1041,10 @@ static int take_cpu_down(void *_param)
|
||||
*/
|
||||
WARN_ON(st->state != (CPUHP_TEARDOWN_CPU - 1));
|
||||
|
||||
/* Invoke the former CPU_DYING callbacks */
|
||||
ret = cpuhp_invoke_callback_range(false, cpu, st, target);
|
||||
|
||||
/*
|
||||
* DYING must not fail!
|
||||
* Invoke the former CPU_DYING callbacks. DYING must not fail!
|
||||
*/
|
||||
WARN_ON_ONCE(ret);
|
||||
cpuhp_invoke_callback_range_nofail(false, cpu, st, target);
|
||||
|
||||
/* Give up timekeeping duties */
|
||||
tick_handover_do_timer();
|
||||
@@ -1296,16 +1322,14 @@ void notify_cpu_starting(unsigned int cpu)
|
||||
{
|
||||
struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
|
||||
enum cpuhp_state target = min((int)st->target, CPUHP_AP_ONLINE);
|
||||
int ret;
|
||||
|
||||
rcu_cpu_starting(cpu); /* Enables RCU usage on this CPU. */
|
||||
cpumask_set_cpu(cpu, &cpus_booted_once_mask);
|
||||
ret = cpuhp_invoke_callback_range(true, cpu, st, target);
|
||||
|
||||
/*
|
||||
* STARTING must not fail!
|
||||
*/
|
||||
WARN_ON_ONCE(ret);
|
||||
cpuhp_invoke_callback_range_nofail(true, cpu, st, target);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2326,8 +2350,10 @@ static ssize_t target_store(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
if (st->state < target)
|
||||
ret = cpu_up(dev->id, target);
|
||||
else
|
||||
else if (st->state > target)
|
||||
ret = cpu_down(dev->id, target);
|
||||
else if (WARN_ON(st->target != target))
|
||||
st->target = target;
|
||||
out:
|
||||
unlock_device_hotplug();
|
||||
return ret ? ret : count;
|
||||
@@ -2688,6 +2714,7 @@ void __init boot_cpu_hotplug_init(void)
|
||||
cpumask_set_cpu(smp_processor_id(), &cpus_booted_once_mask);
|
||||
#endif
|
||||
this_cpu_write(cpuhp_state.state, CPUHP_ONLINE);
|
||||
this_cpu_write(cpuhp_state.target, CPUHP_ONLINE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user