aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2008-09-03 17:37:08 -0400
committerThomas Gleixner <tglx@linutronix.de>2008-09-05 05:11:52 -0400
commit9c17bcda991000351cb2373f78be7e4b1c44caa3 (patch)
tree769385b50e512a3aafa8735be23c199bf83c56e7
parent7205656ab48da29a95d7f55e43a81db755d3cb3a (diff)
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 <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--kernel/time/tick-broadcast.c20
1 files changed, 13 insertions, 7 deletions
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index 3044a88357fa..5744f40b2697 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -210,7 +210,7 @@ static void tick_do_broadcast_on_off(void *why)
210 struct clock_event_device *bc, *dev; 210 struct clock_event_device *bc, *dev;
211 struct tick_device *td; 211 struct tick_device *td;
212 unsigned long flags, *reason = why; 212 unsigned long flags, *reason = why;
213 int cpu; 213 int cpu, bc_stopped;
214 214
215 spin_lock_irqsave(&tick_broadcast_lock, flags); 215 spin_lock_irqsave(&tick_broadcast_lock, flags);
216 216
@@ -228,6 +228,8 @@ static void tick_do_broadcast_on_off(void *why)
228 if (!tick_device_is_functional(dev)) 228 if (!tick_device_is_functional(dev))
229 goto out; 229 goto out;
230 230
231 bc_stopped = cpus_empty(tick_broadcast_mask);
232
231 switch (*reason) { 233 switch (*reason) {
232 case CLOCK_EVT_NOTIFY_BROADCAST_ON: 234 case CLOCK_EVT_NOTIFY_BROADCAST_ON:
233 case CLOCK_EVT_NOTIFY_BROADCAST_FORCE: 235 case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
@@ -250,9 +252,10 @@ static void tick_do_broadcast_on_off(void *why)
250 break; 252 break;
251 } 253 }
252 254
253 if (cpus_empty(tick_broadcast_mask)) 255 if (cpus_empty(tick_broadcast_mask)) {
254 clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN); 256 if (!bc_stopped)
255 else { 257 clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
258 } else if (bc_stopped) {
256 if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) 259 if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
257 tick_broadcast_start_periodic(bc); 260 tick_broadcast_start_periodic(bc);
258 else 261 else
@@ -501,9 +504,12 @@ static void tick_broadcast_clear_oneshot(int cpu)
501 */ 504 */
502void tick_broadcast_setup_oneshot(struct clock_event_device *bc) 505void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
503{ 506{
504 bc->event_handler = tick_handle_oneshot_broadcast; 507 /* Set it up only once ! */
505 clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT); 508 if (bc->event_handler != tick_handle_oneshot_broadcast) {
506 bc->next_event.tv64 = KTIME_MAX; 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 }
507} 513}
508 514
509/* 515/*