Commit aff22d3f authored by Linus Torvalds's avatar Linus Torvalds

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
parents e2756f5e 97b94106
...@@ -33,29 +33,64 @@ struct ce_unbind { ...@@ -33,29 +33,64 @@ struct ce_unbind {
int res; int res;
}; };
/** static u64 cev_delta2ns(unsigned long latch, struct clock_event_device *evt,
* clockevents_delta2ns - Convert a latch value (device ticks) to nanoseconds bool ismax)
* @latch: value to convert
* @evt: pointer to clock event device descriptor
*
* Math helper, returns latch value converted to nanoseconds (bound checked)
*/
u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt)
{ {
u64 clc = (u64) latch << evt->shift; u64 clc = (u64) latch << evt->shift;
u64 rnd;
if (unlikely(!evt->mult)) { if (unlikely(!evt->mult)) {
evt->mult = 1; evt->mult = 1;
WARN_ON(1); WARN_ON(1);
} }
rnd = (u64) evt->mult - 1;
/*
* Upper bound sanity check. If the backwards conversion is
* not equal latch, we know that the above shift overflowed.
*/
if ((clc >> evt->shift) != (u64)latch)
clc = ~0ULL;
/*
* Scaled math oddities:
*
* For mult <= (1 << shift) we can safely add mult - 1 to
* prevent integer rounding loss. So the backwards conversion
* from nsec to device ticks will be correct.
*
* For mult > (1 << shift), i.e. device frequency is > 1GHz we
* need to be careful. Adding mult - 1 will result in a value
* which when converted back to device ticks can be larger
* than latch by up to (mult - 1) >> shift. For the min_delta
* calculation we still want to apply this in order to stay
* above the minimum device ticks limit. For the upper limit
* we would end up with a latch value larger than the upper
* limit of the device, so we omit the add to stay below the
* device upper boundary.
*
* Also omit the add if it would overflow the u64 boundary.
*/
if ((~0ULL - clc > rnd) &&
(!ismax || evt->mult <= (1U << evt->shift)))
clc += rnd;
do_div(clc, evt->mult); do_div(clc, evt->mult);
if (clc < 1000)
clc = 1000;
if (clc > KTIME_MAX)
clc = KTIME_MAX;
return clc; /* Deltas less than 1usec are pointless noise */
return clc > 1000 ? clc : 1000;
}
/**
* clockevents_delta2ns - Convert a latch value (device ticks) to nanoseconds
* @latch: value to convert
* @evt: pointer to clock event device descriptor
*
* Math helper, returns latch value converted to nanoseconds (bound checked)
*/
u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt)
{
return cev_delta2ns(latch, evt, false);
} }
EXPORT_SYMBOL_GPL(clockevent_delta2ns); EXPORT_SYMBOL_GPL(clockevent_delta2ns);
...@@ -380,8 +415,8 @@ void clockevents_config(struct clock_event_device *dev, u32 freq) ...@@ -380,8 +415,8 @@ void clockevents_config(struct clock_event_device *dev, u32 freq)
sec = 600; sec = 600;
clockevents_calc_mult_shift(dev, freq, sec); clockevents_calc_mult_shift(dev, freq, sec);
dev->min_delta_ns = clockevent_delta2ns(dev->min_delta_ticks, dev); dev->min_delta_ns = cev_delta2ns(dev->min_delta_ticks, dev, false);
dev->max_delta_ns = clockevent_delta2ns(dev->max_delta_ticks, dev); dev->max_delta_ns = cev_delta2ns(dev->max_delta_ticks, dev, true);
} }
/** /**
......
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