Commit 860aed25 authored by Paul Mackerras's avatar Paul Mackerras

powerpc/time: Sanity check of decrementer expiration is necessary

This reverts 68568add ("powerpc/time: Remove unnecessary sanity check
of decrementer expiration").  We do need to check whether we have reached
the expiration time of the next event, because we sometimes get an early
decrementer interrupt, most notably when we set the decrementer to 1 in
arch_irq_work_raise().  The effect of not having the sanity check is that
if timer_interrupt() gets called early, we leave the decrementer set to
its maximum value, which means we then don't get any more decrementer
interrupts for about 4 seconds (or longer, depending on timebase
frequency).  I saw these pauses as a consequence of getting a stray
hypervisor decrementer interrupt left over from exiting a KVM guest.

This isn't quite a straight revert because of changes to the surrounding
code, but it restores the same algorithm as was previously used.

Cc: stable@vger.kernel.org
Acked-by: default avatarAnton Blanchard <anton@samba.org>
Acked-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent f8f5701b
...@@ -475,6 +475,7 @@ void timer_interrupt(struct pt_regs * regs) ...@@ -475,6 +475,7 @@ void timer_interrupt(struct pt_regs * regs)
struct pt_regs *old_regs; struct pt_regs *old_regs;
u64 *next_tb = &__get_cpu_var(decrementers_next_tb); u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
struct clock_event_device *evt = &__get_cpu_var(decrementers); struct clock_event_device *evt = &__get_cpu_var(decrementers);
u64 now;
/* Ensure a positive value is written to the decrementer, or else /* Ensure a positive value is written to the decrementer, or else
* some CPUs will continue to take decrementer exceptions. * some CPUs will continue to take decrementer exceptions.
...@@ -509,9 +510,16 @@ void timer_interrupt(struct pt_regs * regs) ...@@ -509,9 +510,16 @@ void timer_interrupt(struct pt_regs * regs)
irq_work_run(); irq_work_run();
} }
*next_tb = ~(u64)0; now = get_tb_or_rtc();
if (evt->event_handler) if (now >= *next_tb) {
evt->event_handler(evt); *next_tb = ~(u64)0;
if (evt->event_handler)
evt->event_handler(evt);
} else {
now = *next_tb - now;
if (now <= DECREMENTER_MAX)
set_dec((int)now);
}
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
/* collect purr register values often, for accurate calculations */ /* collect purr register values often, for accurate calculations */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment