aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
authorAnton Blanchard <anton@samba.org>2011-11-23 15:07:17 -0500
committerBrad Figg <brad.figg@canonical.com>2012-01-23 18:36:28 -0500
commitdbd581ca78685d825feed568ef5062fdd4806c1a (patch)
treef06e3ec8fc438b606842d119233533cc7a4a89f9 /arch/powerpc/kernel
parent9d2815f4cc68c3744665eae8678ec78b4f17bf2e (diff)
powerpc/time: Handle wrapping of decrementer
BugLink: http://bugs.launchpad.net/bugs/915926 commit 37fb9a0231ee43d42d069863bdfd567fca2b61af upstream. 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> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> Signed-off-by: Herton Ronaldo Krzesinski <herton.krzesinski@canonical.com> Signed-off-by: Brad Figg <brad.figg@canonical.com>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/irq.c15
-rw-r--r--arch/powerpc/kernel/time.c9
2 files changed, 15 insertions, 9 deletions
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 5b428e30866..ca2987d939f 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -170,16 +170,13 @@ notrace void arch_local_irq_restore(unsigned long en)
170 */ 170 */
171 local_paca->hard_enabled = en; 171 local_paca->hard_enabled = en;
172 172
173#ifndef CONFIG_BOOKE 173 /*
174 /* On server, re-trigger the decrementer if it went negative since 174 * Trigger the decrementer if we have a pending event. Some processors
175 * some processors only trigger on edge transitions of the sign bit. 175 * only trigger on edge transitions of the sign bit. We might also
176 * 176 * have disabled interrupts long enough that the decrementer wrapped
177 * BookE has a level sensitive decrementer (latches in TSR) so we 177 * to positive.
178 * don't need that
179 */ 178 */
180 if ((int)mfspr(SPRN_DEC) < 0) 179 decrementer_check_overflow();
181 mtspr(SPRN_DEC, 1);
182#endif /* CONFIG_BOOKE */
183 180
184 /* 181 /*
185 * Force the delivery of pending soft-disabled interrupts on PS3. 182 * Force the delivery of pending soft-disabled interrupts on PS3.
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 03b29a6759a..2de304af07a 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -889,6 +889,15 @@ static void __init clocksource_init(void)
889 clock->name, clock->mult, clock->shift); 889 clock->name, clock->mult, clock->shift);
890} 890}
891 891
892void decrementer_check_overflow(void)
893{
894 u64 now = get_tb_or_rtc();
895 struct decrementer_clock *decrementer = &__get_cpu_var(decrementers);
896
897 if (now >= decrementer->next_tb)
898 set_dec(1);
899}
900
892static int decrementer_set_next_event(unsigned long evt, 901static int decrementer_set_next_event(unsigned long evt,
893 struct clock_event_device *dev) 902 struct clock_event_device *dev)
894{ 903{