aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAnton Blanchard <anton@samba.org>2011-11-23 15:07:17 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-11-24 22:09:58 -0500
commit37fb9a0231ee43d42d069863bdfd567fca2b61af (patch)
tree37b53a4a591c3e20676809a6f4f6c59ff693f15a /arch
parentcaca6a03d365883564885f2c1da3e88dcf65d139 (diff)
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')
-rw-r--r--arch/powerpc/include/asm/time.h2
-rw-r--r--arch/powerpc/kernel/irq.c15
-rw-r--r--arch/powerpc/kernel/time.c9
3 files changed, 17 insertions, 9 deletions
diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h
index fe6f7c2c9c68..bc3c745cb906 100644
--- a/arch/powerpc/include/asm/time.h
+++ b/arch/powerpc/include/asm/time.h
@@ -219,5 +219,7 @@ DECLARE_PER_CPU(struct cpu_usage, cpu_usage_array);
219extern void secondary_cpu_time_init(void); 219extern void secondary_cpu_time_init(void);
220extern void iSeries_time_init_early(void); 220extern void iSeries_time_init_early(void);
221 221
222extern void decrementer_check_overflow(void);
223
222#endif /* __KERNEL__ */ 224#endif /* __KERNEL__ */
223#endif /* __POWERPC_TIME_H */ 225#endif /* __POWERPC_TIME_H */
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 5c3c46948d94..745c1e7c10fd 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -164,16 +164,13 @@ notrace void arch_local_irq_restore(unsigned long en)
164 */ 164 */
165 local_paca->hard_enabled = en; 165 local_paca->hard_enabled = en;
166 166
167#ifndef CONFIG_BOOKE 167 /*
168 /* On server, re-trigger the decrementer if it went negative since 168 * Trigger the decrementer if we have a pending event. Some processors
169 * some processors only trigger on edge transitions of the sign bit. 169 * only trigger on edge transitions of the sign bit. We might also
170 * 170 * have disabled interrupts long enough that the decrementer wrapped
171 * BookE has a level sensitive decrementer (latches in TSR) so we 171 * to positive.
172 * don't need that
173 */ 172 */
174 if ((int)mfspr(SPRN_DEC) < 0) 173 decrementer_check_overflow();
175 mtspr(SPRN_DEC, 1);
176#endif /* CONFIG_BOOKE */
177 174
178 /* 175 /*
179 * Force the delivery of pending soft-disabled interrupts on PS3. 176 * 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 522bb1dfc353..5db163c96751 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{