mirror of https://github.com/torvalds/linux.git
tick: Do not set device to detached state in tick_shutdown()
tick_shutdown() sets the state of the clockevent device to detached first and the invokes clockevents_exchange_device(), which in turn invokes clockevents_switch_state(). But clockevents_switch_state() returns without invoking the device shutdown callback as the device is already in detached state. As a consequence the timer device is not shutdown when a CPU goes offline. tick_shutdown() does this because it was originally invoked on a online CPU and not on the outgoing CPU. It therefore could not access the clockevent device of the already offlined CPU and just set the state. Since commit3b1596a21ftick_shutdown() is called on the outgoing CPU, so the hardware device can be accessed. Remove the state set before calling clockevents_exchange_device(), so that the subsequent clockevents_switch_state() handles the state transition and invokes the shutdown callback of the clockevent device. [ tglx: Massaged change log ] Fixes:3b1596a21f("clockevents: Shutdown and unregister current clockevents at CPUHP_AP_TICK_DYING") Signed-off-by: Bibo Mao <maobibo@loongson.cn> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Frederic Weisbecker <frederic@kernel.org> Link: https://lore.kernel.org/all/20250906064952.3749122-2-maobibo@loongson.cn
This commit is contained in:
parent
3c3af563b3
commit
fe2a449a45
|
|
@ -633,7 +633,7 @@ void tick_offline_cpu(unsigned int cpu)
|
||||||
raw_spin_lock(&clockevents_lock);
|
raw_spin_lock(&clockevents_lock);
|
||||||
|
|
||||||
tick_broadcast_offline(cpu);
|
tick_broadcast_offline(cpu);
|
||||||
tick_shutdown(cpu);
|
tick_shutdown();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unregister the clock event devices which were
|
* Unregister the clock event devices which were
|
||||||
|
|
|
||||||
|
|
@ -411,24 +411,18 @@ int tick_cpu_dying(unsigned int dying_cpu)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shutdown an event device on a given cpu:
|
* Shutdown an event device on the outgoing CPU:
|
||||||
*
|
*
|
||||||
* This is called on a life CPU, when a CPU is dead. So we cannot
|
* Called by the dying CPU during teardown, with clockevents_lock held
|
||||||
* access the hardware device itself.
|
* and interrupts disabled.
|
||||||
* We just set the mode and remove it from the lists.
|
|
||||||
*/
|
*/
|
||||||
void tick_shutdown(unsigned int cpu)
|
void tick_shutdown(void)
|
||||||
{
|
{
|
||||||
struct tick_device *td = &per_cpu(tick_cpu_device, cpu);
|
struct tick_device *td = this_cpu_ptr(&tick_cpu_device);
|
||||||
struct clock_event_device *dev = td->evtdev;
|
struct clock_event_device *dev = td->evtdev;
|
||||||
|
|
||||||
td->mode = TICKDEV_MODE_PERIODIC;
|
td->mode = TICKDEV_MODE_PERIODIC;
|
||||||
if (dev) {
|
if (dev) {
|
||||||
/*
|
|
||||||
* Prevent that the clock events layer tries to call
|
|
||||||
* the set mode function!
|
|
||||||
*/
|
|
||||||
clockevent_set_state(dev, CLOCK_EVT_STATE_DETACHED);
|
|
||||||
clockevents_exchange_device(dev, NULL);
|
clockevents_exchange_device(dev, NULL);
|
||||||
dev->event_handler = clockevents_handle_noop;
|
dev->event_handler = clockevents_handle_noop;
|
||||||
td->evtdev = NULL;
|
td->evtdev = NULL;
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ extern void tick_setup_periodic(struct clock_event_device *dev, int broadcast);
|
||||||
extern void tick_handle_periodic(struct clock_event_device *dev);
|
extern void tick_handle_periodic(struct clock_event_device *dev);
|
||||||
extern void tick_check_new_device(struct clock_event_device *dev);
|
extern void tick_check_new_device(struct clock_event_device *dev);
|
||||||
extern void tick_offline_cpu(unsigned int cpu);
|
extern void tick_offline_cpu(unsigned int cpu);
|
||||||
extern void tick_shutdown(unsigned int cpu);
|
extern void tick_shutdown(void);
|
||||||
extern void tick_suspend(void);
|
extern void tick_suspend(void);
|
||||||
extern void tick_resume(void);
|
extern void tick_resume(void);
|
||||||
extern bool tick_check_replacement(struct clock_event_device *curdev,
|
extern bool tick_check_replacement(struct clock_event_device *curdev,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue