Commit fe2a449a authored by Bibo Mao's avatar Bibo Mao Committed by Thomas Gleixner
Browse files

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 commit 3b1596a2 tick_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: 3b1596a2 ("clockevents: Shutdown and unregister current clockevents at CPUHP_AP_TICK_DYING")
Signed-off-by: default avatarBibo Mao <maobibo@loongson.cn>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Reviewed-by: default avatarFrederic Weisbecker <frederic@kernel.org>
Link: https://lore.kernel.org/all/20250906064952.3749122-2-maobibo@loongson.cn
parent 3c3af563
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -633,7 +633,7 @@ void tick_offline_cpu(unsigned int cpu)
	raw_spin_lock(&clockevents_lock);

	tick_broadcast_offline(cpu);
	tick_shutdown(cpu);
	tick_shutdown();

	/*
	 * Unregister the clock event devices which were
+5 −11
Original line number Diff line number Diff line
@@ -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
 * access the hardware device itself.
 * We just set the mode and remove it from the lists.
 * Called by the dying CPU during teardown, with clockevents_lock held
 * and interrupts disabled.
 */
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;

	td->mode = TICKDEV_MODE_PERIODIC;
	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);
		dev->event_handler = clockevents_handle_noop;
		td->evtdev = NULL;
+1 −1
Original line number Diff line number Diff line
@@ -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_check_new_device(struct clock_event_device *dev);
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_resume(void);
extern bool tick_check_replacement(struct clock_event_device *curdev,