Skip to content

Commit 9c17bcd

Browse files
committed
clockevents: prevent multiple init/shutdown
While chasing the C1E/HPET bugreports I went through the clock events code inch by inch and found that the broadcast device can be initialized and shutdown multiple times. Multiple shutdowns are not critical, but useless waste of time. Multiple initializations are simply broken. Another CPU might have the device in use already after the first initialization and the second init could just render it unusable again. Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Ingo Molnar <[email protected]>
1 parent 7205656 commit 9c17bcd

File tree

1 file changed

+13
-7
lines changed

1 file changed

+13
-7
lines changed

kernel/time/tick-broadcast.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ static void tick_do_broadcast_on_off(void *why)
210210
struct clock_event_device *bc, *dev;
211211
struct tick_device *td;
212212
unsigned long flags, *reason = why;
213-
int cpu;
213+
int cpu, bc_stopped;
214214

215215
spin_lock_irqsave(&tick_broadcast_lock, flags);
216216

@@ -228,6 +228,8 @@ static void tick_do_broadcast_on_off(void *why)
228228
if (!tick_device_is_functional(dev))
229229
goto out;
230230

231+
bc_stopped = cpus_empty(tick_broadcast_mask);
232+
231233
switch (*reason) {
232234
case CLOCK_EVT_NOTIFY_BROADCAST_ON:
233235
case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
@@ -250,9 +252,10 @@ static void tick_do_broadcast_on_off(void *why)
250252
break;
251253
}
252254

253-
if (cpus_empty(tick_broadcast_mask))
254-
clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
255-
else {
255+
if (cpus_empty(tick_broadcast_mask)) {
256+
if (!bc_stopped)
257+
clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
258+
} else if (bc_stopped) {
256259
if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
257260
tick_broadcast_start_periodic(bc);
258261
else
@@ -501,9 +504,12 @@ static void tick_broadcast_clear_oneshot(int cpu)
501504
*/
502505
void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
503506
{
504-
bc->event_handler = tick_handle_oneshot_broadcast;
505-
clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
506-
bc->next_event.tv64 = KTIME_MAX;
507+
/* Set it up only once ! */
508+
if (bc->event_handler != tick_handle_oneshot_broadcast) {
509+
bc->event_handler = tick_handle_oneshot_broadcast;
510+
clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
511+
bc->next_event.tv64 = KTIME_MAX;
512+
}
507513
}
508514

509515
/*

0 commit comments

Comments
 (0)