diff options
Diffstat (limited to 'target/linux/pistachio/patches-5.4/107-clockevents-Retry-programming-min-delta-up-to-10-tim.patch')
-rw-r--r-- | target/linux/pistachio/patches-5.4/107-clockevents-Retry-programming-min-delta-up-to-10-tim.patch | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/target/linux/pistachio/patches-5.4/107-clockevents-Retry-programming-min-delta-up-to-10-tim.patch b/target/linux/pistachio/patches-5.4/107-clockevents-Retry-programming-min-delta-up-to-10-tim.patch new file mode 100644 index 0000000000..857823b783 --- /dev/null +++ b/target/linux/pistachio/patches-5.4/107-clockevents-Retry-programming-min-delta-up-to-10-tim.patch @@ -0,0 +1,66 @@ +From b46f8c74afdd30cd52bfdcc2231470a0bab04416 Mon Sep 17 00:00:00 2001 +From: James Hogan <james.hogan@imgtec.com> +Date: Fri, 22 Apr 2016 18:22:45 +0100 +Subject: clockevents: Retry programming min delta up to 10 times + +Under virtualisation it is possible to get unexpected latency during a +clockevent device's set_next_event() callback which can make it return +-ETIME even for a delta based on min_delta_ns. + +The clockevents_program_min_delta() implementation for +CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=n doesn't handle retries when this +happens, nor does clockevents_program_event() or its callers when force +is true (for example hrtimer_reprogram()). This can result in hangs +until the clock event device does a full period. + +It isn't appropriate to use MIN_ADJUST in this case as occasional +hypervisor induced high latency will cause min_delta_ns to quickly +increase to the maximum. +Instead, borrow the retry pattern from the MIN_ADJUST case, but without +making adjustments. We retry up to 10 times before giving up. + +(picked https://patchwork.kernel.org/patch/8909491/) + +Signed-off-by: James Hogan <james.hogan@imgtec.com> +--- + kernel/time/clockevents.c | 26 +++++++++++++++++++------- + 1 file changed, 19 insertions(+), 7 deletions(-) + +--- a/kernel/time/clockevents.c ++++ b/kernel/time/clockevents.c +@@ -281,16 +281,28 @@ static int clockevents_program_min_delta + { + unsigned long long clc; + int64_t delta; ++ int i; + +- delta = dev->min_delta_ns; +- dev->next_event = ktime_add_ns(ktime_get(), delta); ++ for (i = 0;;) { ++ delta = dev->min_delta_ns; ++ dev->next_event = ktime_add_ns(ktime_get(), delta); + +- if (clockevent_state_shutdown(dev)) +- return 0; ++ if (clockevent_state_shutdown(dev)) ++ return 0; + +- dev->retries++; +- clc = ((unsigned long long) delta * dev->mult) >> dev->shift; +- return dev->set_next_event((unsigned long) clc, dev); ++ dev->retries++; ++ clc = ((unsigned long long) delta * dev->mult) >> dev->shift; ++ if (dev->set_next_event((unsigned long) clc, dev) == 0) ++ return 0; ++ ++ if (++i > 9) { ++ /* ++ * We tried 10 times to program the device with the ++ * given min_delta_ns. Get out of here. ++ */ ++ return -ETIME; ++ } ++ } + } + + #endif /* CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST */ |