Skip to content

Commit

Permalink
clockevents: prevent multiple init/shutdown
Browse files Browse the repository at this point in the history
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 <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
  • Loading branch information
Thomas Gleixner committed Sep 5, 2008
1 parent 7205656 commit 9c17bcd
Showing 1 changed file with 13 additions and 7 deletions.
20 changes: 13 additions & 7 deletions kernel/time/tick-broadcast.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ static void tick_do_broadcast_on_off(void *why)
struct clock_event_device *bc, *dev;
struct tick_device *td;
unsigned long flags, *reason = why;
int cpu;
int cpu, bc_stopped;

spin_lock_irqsave(&tick_broadcast_lock, flags);

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

bc_stopped = cpus_empty(tick_broadcast_mask);

switch (*reason) {
case CLOCK_EVT_NOTIFY_BROADCAST_ON:
case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
Expand All @@ -250,9 +252,10 @@ static void tick_do_broadcast_on_off(void *why)
break;
}

if (cpus_empty(tick_broadcast_mask))
clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
else {
if (cpus_empty(tick_broadcast_mask)) {
if (!bc_stopped)
clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
} else if (bc_stopped) {
if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
tick_broadcast_start_periodic(bc);
else
Expand Down Expand Up @@ -501,9 +504,12 @@ static void tick_broadcast_clear_oneshot(int cpu)
*/
void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
{
bc->event_handler = tick_handle_oneshot_broadcast;
clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
bc->next_event.tv64 = KTIME_MAX;
/* Set it up only once ! */
if (bc->event_handler != tick_handle_oneshot_broadcast) {
bc->event_handler = tick_handle_oneshot_broadcast;
clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
bc->next_event.tv64 = KTIME_MAX;
}
}

/*
Expand Down

0 comments on commit 9c17bcd

Please sign in to comment.