Skip to content

Commit aff22d3

Browse files
committed
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer fix from Ingo Molnar: "This tree contains a clockevents regression fix for certain ARM subarchitectures" * 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: clockevents: Sanitize ticks to nsec conversion
2 parents e2756f5 + 97b9410 commit aff22d3

File tree

1 file changed

+50
-15
lines changed

1 file changed

+50
-15
lines changed

kernel/time/clockevents.c

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,29 +33,64 @@ struct ce_unbind {
3333
int res;
3434
};
3535

36-
/**
37-
* clockevents_delta2ns - Convert a latch value (device ticks) to nanoseconds
38-
* @latch: value to convert
39-
* @evt: pointer to clock event device descriptor
40-
*
41-
* Math helper, returns latch value converted to nanoseconds (bound checked)
42-
*/
43-
u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt)
36+
static u64 cev_delta2ns(unsigned long latch, struct clock_event_device *evt,
37+
bool ismax)
4438
{
4539
u64 clc = (u64) latch << evt->shift;
40+
u64 rnd;
4641

4742
if (unlikely(!evt->mult)) {
4843
evt->mult = 1;
4944
WARN_ON(1);
5045
}
46+
rnd = (u64) evt->mult - 1;
47+
48+
/*
49+
* Upper bound sanity check. If the backwards conversion is
50+
* not equal latch, we know that the above shift overflowed.
51+
*/
52+
if ((clc >> evt->shift) != (u64)latch)
53+
clc = ~0ULL;
54+
55+
/*
56+
* Scaled math oddities:
57+
*
58+
* For mult <= (1 << shift) we can safely add mult - 1 to
59+
* prevent integer rounding loss. So the backwards conversion
60+
* from nsec to device ticks will be correct.
61+
*
62+
* For mult > (1 << shift), i.e. device frequency is > 1GHz we
63+
* need to be careful. Adding mult - 1 will result in a value
64+
* which when converted back to device ticks can be larger
65+
* than latch by up to (mult - 1) >> shift. For the min_delta
66+
* calculation we still want to apply this in order to stay
67+
* above the minimum device ticks limit. For the upper limit
68+
* we would end up with a latch value larger than the upper
69+
* limit of the device, so we omit the add to stay below the
70+
* device upper boundary.
71+
*
72+
* Also omit the add if it would overflow the u64 boundary.
73+
*/
74+
if ((~0ULL - clc > rnd) &&
75+
(!ismax || evt->mult <= (1U << evt->shift)))
76+
clc += rnd;
5177

5278
do_div(clc, evt->mult);
53-
if (clc < 1000)
54-
clc = 1000;
55-
if (clc > KTIME_MAX)
56-
clc = KTIME_MAX;
5779

58-
return clc;
80+
/* Deltas less than 1usec are pointless noise */
81+
return clc > 1000 ? clc : 1000;
82+
}
83+
84+
/**
85+
* clockevents_delta2ns - Convert a latch value (device ticks) to nanoseconds
86+
* @latch: value to convert
87+
* @evt: pointer to clock event device descriptor
88+
*
89+
* Math helper, returns latch value converted to nanoseconds (bound checked)
90+
*/
91+
u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt)
92+
{
93+
return cev_delta2ns(latch, evt, false);
5994
}
6095
EXPORT_SYMBOL_GPL(clockevent_delta2ns);
6196

@@ -380,8 +415,8 @@ void clockevents_config(struct clock_event_device *dev, u32 freq)
380415
sec = 600;
381416

382417
clockevents_calc_mult_shift(dev, freq, sec);
383-
dev->min_delta_ns = clockevent_delta2ns(dev->min_delta_ticks, dev);
384-
dev->max_delta_ns = clockevent_delta2ns(dev->max_delta_ticks, dev);
418+
dev->min_delta_ns = cev_delta2ns(dev->min_delta_ticks, dev, false);
419+
dev->max_delta_ns = cev_delta2ns(dev->max_delta_ticks, dev, true);
385420
}
386421

387422
/**

0 commit comments

Comments
 (0)