Commit 194770bb authored by Roman Volkov's avatar Roman Volkov Committed by Greg Kroah-Hartman

clocksource/drivers/vt8500: Increase the minimum delta

commit f9eccf24 upstream.

The vt8500 clocksource driver declares itself as capable to handle the
minimum delay of 4 cycles by passing the value into
clockevents_config_and_register(). The vt8500_timer_set_next_event()
requires the passed cycles value to be at least 16. The impact is that
userspace hangs in nanosleep() calls with small delay intervals.

This problem is reproducible in Linux 4.2 starting from:
c6eb3f70 ('hrtimer: Get rid of hrtimer softirq')

From Russell King, more detailed explanation:

"It's a speciality of the StrongARM/PXA hardware. It takes a certain
number of OSCR cycles for the value written to hit the compare registers.
So, if a very small delta is written (eg, the compare register is written
with a value of OSCR + 1), the OSCR will have incremented past this value
before it hits the underlying hardware. The result is, that you end up
waiting a very long time for the OSCR to wrap before the event fires.

So, we introduce a check in set_next_event() to detect this and return
-ETIME if the calculated delta is too small, which causes the generic
clockevents code to retry after adding the min_delta specified in
clockevents_config_and_register() to the current time value.

min_delta must be sufficient that we don't re-trip the -ETIME check - if
we do, we will return -ETIME, forward the next event time, try to set it,
return -ETIME again, and basically lock the system up. So, min_delta
must be larger than the check inside set_next_event(). A factor of two
was chosen to ensure that this situation would never occur.

The PXA code worked on PXA systems for years, and I'd suggest no one
changes this mechanism without access to a wide range of PXA systems,
otherwise they're risking breakage."

Cc: Russell King <linux@arm.linux.org.uk>
Acked-by: default avatarAlexey Charkov <alchark@gmail.com>
Signed-off-by: default avatarRoman Volkov <rvolkov@v1ros.org>
Signed-off-by: default avatarDaniel Lezcano <daniel.lezcano@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 9ba2f080
...@@ -50,6 +50,8 @@ ...@@ -50,6 +50,8 @@
#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
#define MIN_OSCR_DELTA 16
static void __iomem *regbase; static void __iomem *regbase;
static cycle_t vt8500_timer_read(struct clocksource *cs) static cycle_t vt8500_timer_read(struct clocksource *cs)
...@@ -80,7 +82,7 @@ static int vt8500_timer_set_next_event(unsigned long cycles, ...@@ -80,7 +82,7 @@ static int vt8500_timer_set_next_event(unsigned long cycles,
cpu_relax(); cpu_relax();
writel((unsigned long)alarm, regbase + TIMER_MATCH_VAL); writel((unsigned long)alarm, regbase + TIMER_MATCH_VAL);
if ((signed)(alarm - clocksource.read(&clocksource)) <= 16) if ((signed)(alarm - clocksource.read(&clocksource)) <= MIN_OSCR_DELTA)
return -ETIME; return -ETIME;
writel(1, regbase + TIMER_IER_VAL); writel(1, regbase + TIMER_IER_VAL);
...@@ -160,7 +162,7 @@ static void __init vt8500_timer_init(struct device_node *np) ...@@ -160,7 +162,7 @@ static void __init vt8500_timer_init(struct device_node *np)
pr_err("%s: setup_irq failed for %s\n", __func__, pr_err("%s: setup_irq failed for %s\n", __func__,
clockevent.name); clockevent.name);
clockevents_config_and_register(&clockevent, VT8500_TIMER_HZ, clockevents_config_and_register(&clockevent, VT8500_TIMER_HZ,
4, 0xf0000000); MIN_OSCR_DELTA * 2, 0xf0000000);
} }
CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init); CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init);
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