diff options
author | Anton Blanchard <anton@samba.org> | 2011-11-23 20:07:17 +0000 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2011-11-25 14:09:58 +1100 |
commit | 37fb9a0231ee43d42d069863bdfd567fca2b61af (patch) | |
tree | 37b53a4a591c3e20676809a6f4f6c59ff693f15a /arch/powerpc/kernel/time.c | |
parent | caca6a03d365883564885f2c1da3e88dcf65d139 (diff) | |
download | op-kernel-dev-37fb9a0231ee43d42d069863bdfd567fca2b61af.zip op-kernel-dev-37fb9a0231ee43d42d069863bdfd567fca2b61af.tar.gz |
powerpc/time: Handle wrapping of decrementer
When re-enabling interrupts we have code to handle edge sensitive
decrementers by resetting the decrementer to 1 whenever it is negative.
If interrupts were disabled long enough that the decrementer wrapped to
positive we do nothing. This means interrupts can be delayed for a long
time until it finally goes negative again.
While we hope interrupts are never be disabled long enough for the
decrementer to go positive, we have a very good test team that can
drive any kernel into the ground. The softlockup data we get back
from these fails could be seconds in the future, completely missing
the cause of the lockup.
We already keep track of the timebase of the next event so use that
to work out if we should trigger a decrementer exception.
Signed-off-by: Anton Blanchard <anton@samba.org>
Cc: stable@kernel.org
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/time.c')
-rw-r--r-- | arch/powerpc/kernel/time.c | 9 |
1 files changed, 9 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 522bb1d..5db163c 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -889,6 +889,15 @@ static void __init clocksource_init(void) clock->name, clock->mult, clock->shift); } +void decrementer_check_overflow(void) +{ + u64 now = get_tb_or_rtc(); + struct decrementer_clock *decrementer = &__get_cpu_var(decrementers); + + if (now >= decrementer->next_tb) + set_dec(1); +} + static int decrementer_set_next_event(unsigned long evt, struct clock_event_device *dev) { |