diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2008-09-05 21:01:45 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2008-09-06 01:21:17 -0400 |
commit | 7300711e8c6824fcfbd42a126980ff50439d8dd0 (patch) | |
tree | 20183d1ce4fa8237042644b2a79fbf01471da18d /kernel/time | |
parent | 7cfb0435330364f90f274a26ecdc5f47f738498c (diff) |
clockevents: broadcast fixup possible waiters
Until the C1E patches arrived there where no users of periodic broadcast
before switching to oneshot mode. Now we need to trigger a possible
waiter for a periodic broadcast when switching to oneshot mode.
Otherwise we can starve them for ever.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/time')
-rw-r--r-- | kernel/time/tick-broadcast.c | 37 |
1 files changed, 36 insertions, 1 deletions
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 2bc1f046151c..2f5a38294bf9 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c | |||
@@ -491,6 +491,18 @@ static void tick_broadcast_clear_oneshot(int cpu) | |||
491 | cpu_clear(cpu, tick_broadcast_oneshot_mask); | 491 | cpu_clear(cpu, tick_broadcast_oneshot_mask); |
492 | } | 492 | } |
493 | 493 | ||
494 | static void tick_broadcast_init_next_event(cpumask_t *mask, ktime_t expires) | ||
495 | { | ||
496 | struct tick_device *td; | ||
497 | int cpu; | ||
498 | |||
499 | for_each_cpu_mask_nr(cpu, *mask) { | ||
500 | td = &per_cpu(tick_cpu_device, cpu); | ||
501 | if (td->evtdev) | ||
502 | td->evtdev->next_event = expires; | ||
503 | } | ||
504 | } | ||
505 | |||
494 | /** | 506 | /** |
495 | * tick_broadcast_setup_oneshot - setup the broadcast device | 507 | * tick_broadcast_setup_oneshot - setup the broadcast device |
496 | */ | 508 | */ |
@@ -498,9 +510,32 @@ void tick_broadcast_setup_oneshot(struct clock_event_device *bc) | |||
498 | { | 510 | { |
499 | /* Set it up only once ! */ | 511 | /* Set it up only once ! */ |
500 | if (bc->event_handler != tick_handle_oneshot_broadcast) { | 512 | if (bc->event_handler != tick_handle_oneshot_broadcast) { |
513 | int was_periodic = bc->mode == CLOCK_EVT_MODE_PERIODIC; | ||
514 | int cpu = smp_processor_id(); | ||
515 | cpumask_t mask; | ||
516 | |||
501 | bc->event_handler = tick_handle_oneshot_broadcast; | 517 | bc->event_handler = tick_handle_oneshot_broadcast; |
502 | clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT); | 518 | clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT); |
503 | bc->next_event.tv64 = KTIME_MAX; | 519 | |
520 | /* Take the do_timer update */ | ||
521 | tick_do_timer_cpu = cpu; | ||
522 | |||
523 | /* | ||
524 | * We must be careful here. There might be other CPUs | ||
525 | * waiting for periodic broadcast. We need to set the | ||
526 | * oneshot_mask bits for those and program the | ||
527 | * broadcast device to fire. | ||
528 | */ | ||
529 | mask = tick_broadcast_mask; | ||
530 | cpu_clear(cpu, mask); | ||
531 | cpus_or(tick_broadcast_oneshot_mask, | ||
532 | tick_broadcast_oneshot_mask, mask); | ||
533 | |||
534 | if (was_periodic && !cpus_empty(mask)) { | ||
535 | tick_broadcast_init_next_event(&mask, tick_next_period); | ||
536 | tick_broadcast_set_event(tick_next_period, 1); | ||
537 | } else | ||
538 | bc->next_event.tv64 = KTIME_MAX; | ||
504 | } | 539 | } |
505 | } | 540 | } |
506 | 541 | ||