Commit 9c17bcda authored by Thomas Gleixner's avatar Thomas Gleixner

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: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 7205656a
...@@ -210,7 +210,7 @@ static void tick_do_broadcast_on_off(void *why) ...@@ -210,7 +210,7 @@ static void tick_do_broadcast_on_off(void *why)
struct clock_event_device *bc, *dev; struct clock_event_device *bc, *dev;
struct tick_device *td; struct tick_device *td;
unsigned long flags, *reason = why; unsigned long flags, *reason = why;
int cpu; int cpu, bc_stopped;
spin_lock_irqsave(&tick_broadcast_lock, flags); spin_lock_irqsave(&tick_broadcast_lock, flags);
...@@ -228,6 +228,8 @@ static void tick_do_broadcast_on_off(void *why) ...@@ -228,6 +228,8 @@ static void tick_do_broadcast_on_off(void *why)
if (!tick_device_is_functional(dev)) if (!tick_device_is_functional(dev))
goto out; goto out;
bc_stopped = cpus_empty(tick_broadcast_mask);
switch (*reason) { switch (*reason) {
case CLOCK_EVT_NOTIFY_BROADCAST_ON: case CLOCK_EVT_NOTIFY_BROADCAST_ON:
case CLOCK_EVT_NOTIFY_BROADCAST_FORCE: case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
...@@ -250,9 +252,10 @@ static void tick_do_broadcast_on_off(void *why) ...@@ -250,9 +252,10 @@ static void tick_do_broadcast_on_off(void *why)
break; break;
} }
if (cpus_empty(tick_broadcast_mask)) if (cpus_empty(tick_broadcast_mask)) {
if (!bc_stopped)
clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN); clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
else { } else if (bc_stopped) {
if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
tick_broadcast_start_periodic(bc); tick_broadcast_start_periodic(bc);
else else
...@@ -501,9 +504,12 @@ static void tick_broadcast_clear_oneshot(int cpu) ...@@ -501,9 +504,12 @@ static void tick_broadcast_clear_oneshot(int cpu)
*/ */
void tick_broadcast_setup_oneshot(struct clock_event_device *bc) void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
{ {
/* Set it up only once ! */
if (bc->event_handler != tick_handle_oneshot_broadcast) {
bc->event_handler = tick_handle_oneshot_broadcast; bc->event_handler = tick_handle_oneshot_broadcast;
clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT); clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
bc->next_event.tv64 = KTIME_MAX; bc->next_event.tv64 = KTIME_MAX;
}
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment