OpenWrt – Blame information for rev 4
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | From b46f8c74afdd30cd52bfdcc2231470a0bab04416 Mon Sep 17 00:00:00 2001 |
2 | From: James Hogan <james.hogan@imgtec.com> |
||
3 | Date: Fri, 22 Apr 2016 18:22:45 +0100 |
||
4 | Subject: clockevents: Retry programming min delta up to 10 times |
||
5 | |||
6 | Under virtualisation it is possible to get unexpected latency during a |
||
7 | clockevent device's set_next_event() callback which can make it return |
||
8 | -ETIME even for a delta based on min_delta_ns. |
||
9 | |||
10 | The clockevents_program_min_delta() implementation for |
||
11 | CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=n doesn't handle retries when this |
||
12 | happens, nor does clockevents_program_event() or its callers when force |
||
13 | is true (for example hrtimer_reprogram()). This can result in hangs |
||
14 | until the clock event device does a full period. |
||
15 | |||
16 | It isn't appropriate to use MIN_ADJUST in this case as occasional |
||
17 | hypervisor induced high latency will cause min_delta_ns to quickly |
||
18 | increase to the maximum. |
||
19 | Instead, borrow the retry pattern from the MIN_ADJUST case, but without |
||
20 | making adjustments. We retry up to 10 times before giving up. |
||
21 | |||
22 | (picked https://patchwork.kernel.org/patch/8909491/) |
||
23 | |||
24 | Signed-off-by: James Hogan <james.hogan@imgtec.com> |
||
25 | --- |
||
26 | kernel/time/clockevents.c | 26 +++++++++++++++++++------- |
||
27 | 1 file changed, 19 insertions(+), 7 deletions(-) |
||
28 | |||
29 | --- a/kernel/time/clockevents.c |
||
30 | +++ b/kernel/time/clockevents.c |
||
31 | @@ -281,16 +281,28 @@ static int clockevents_program_min_delta |
||
32 | { |
||
33 | unsigned long long clc; |
||
34 | int64_t delta; |
||
35 | + int i; |
||
36 | |||
37 | - delta = dev->min_delta_ns; |
||
38 | - dev->next_event = ktime_add_ns(ktime_get(), delta); |
||
39 | + for (i = 0;;) { |
||
40 | + delta = dev->min_delta_ns; |
||
41 | + dev->next_event = ktime_add_ns(ktime_get(), delta); |
||
42 | |||
43 | - if (clockevent_state_shutdown(dev)) |
||
44 | - return 0; |
||
45 | + if (clockevent_state_shutdown(dev)) |
||
46 | + return 0; |
||
47 | |||
48 | - dev->retries++; |
||
49 | - clc = ((unsigned long long) delta * dev->mult) >> dev->shift; |
||
50 | - return dev->set_next_event((unsigned long) clc, dev); |
||
51 | + dev->retries++; |
||
52 | + clc = ((unsigned long long) delta * dev->mult) >> dev->shift; |
||
53 | + if (dev->set_next_event((unsigned long) clc, dev) == 0) |
||
54 | + return 0; |
||
55 | + |
||
56 | + if (++i > 9) { |
||
57 | + /* |
||
58 | + * We tried 10 times to program the device with the |
||
59 | + * given min_delta_ns. Get out of here. |
||
60 | + */ |
||
61 | + return -ETIME; |
||
62 | + } |
||
63 | + } |
||
64 | } |
||
65 | |||
66 | #endif /* CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST */ |