]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
powerpc/time: Handle wrapping of decrementer
authorAnton Blanchard <anton@samba.org>
Wed, 23 Nov 2011 20:07:17 +0000 (20:07 +0000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Fri, 25 Nov 2011 03:09:58 +0000 (14:09 +1100)
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>
arch/powerpc/include/asm/time.h
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/time.c

index fe6f7c2c9c6889600bd0ec00fab55ed6b7daf1f6..bc3c745cb906a4d88fceffcdbac506bb1631eb5d 100644 (file)
@@ -219,5 +219,7 @@ DECLARE_PER_CPU(struct cpu_usage, cpu_usage_array);
 extern void secondary_cpu_time_init(void);
 extern void iSeries_time_init_early(void);
 
+extern void decrementer_check_overflow(void);
+
 #endif /* __KERNEL__ */
 #endif /* __POWERPC_TIME_H */
index 5c3c46948d9400c3abe923265049e5b90994330c..745c1e7c10fd7fdd8f2c26c1f33031d3b75305cc 100644 (file)
@@ -164,16 +164,13 @@ notrace void arch_local_irq_restore(unsigned long en)
         */
        local_paca->hard_enabled = en;
 
-#ifndef CONFIG_BOOKE
-       /* On server, re-trigger the decrementer if it went negative since
-        * some processors only trigger on edge transitions of the sign bit.
-        *
-        * BookE has a level sensitive decrementer (latches in TSR) so we
-        * don't need that
+       /*
+        * Trigger the decrementer if we have a pending event. Some processors
+        * only trigger on edge transitions of the sign bit. We might also
+        * have disabled interrupts long enough that the decrementer wrapped
+        * to positive.
         */
-       if ((int)mfspr(SPRN_DEC) < 0)
-               mtspr(SPRN_DEC, 1);
-#endif /* CONFIG_BOOKE */
+       decrementer_check_overflow();
 
        /*
         * Force the delivery of pending soft-disabled interrupts on PS3.
index 522bb1dfc3538ddc7b08ec3986393577edc5e9e8..5db163c96751f8d3979a8757f25958cf91264c39 100644 (file)
@@ -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)
 {