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
This commit is contained in:
commit
aff22d3f1a
1 changed files with 51 additions and 16 deletions
|
@ -33,6 +33,54 @@ struct ce_unbind {
|
||||||
int res;
|
int res;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static u64 cev_delta2ns(unsigned long latch, struct clock_event_device *evt,
|
||||||
|
bool ismax)
|
||||||
|
{
|
||||||
|
u64 clc = (u64) latch << evt->shift;
|
||||||
|
u64 rnd;
|
||||||
|
|
||||||
|
if (unlikely(!evt->mult)) {
|
||||||
|
evt->mult = 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);
|
||||||
|
|
||||||
|
/* Deltas less than 1usec are pointless noise */
|
||||||
|
return clc > 1000 ? clc : 1000;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clockevents_delta2ns - Convert a latch value (device ticks) to nanoseconds
|
* clockevents_delta2ns - Convert a latch value (device ticks) to nanoseconds
|
||||||
* @latch: value to convert
|
* @latch: value to convert
|
||||||
|
@ -42,20 +90,7 @@ struct ce_unbind {
|
||||||
*/
|
*/
|
||||||
u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt)
|
u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt)
|
||||||
{
|
{
|
||||||
u64 clc = (u64) latch << evt->shift;
|
return cev_delta2ns(latch, evt, false);
|
||||||
|
|
||||||
if (unlikely(!evt->mult)) {
|
|
||||||
evt->mult = 1;
|
|
||||||
WARN_ON(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
do_div(clc, evt->mult);
|
|
||||||
if (clc < 1000)
|
|
||||||
clc = 1000;
|
|
||||||
if (clc > KTIME_MAX)
|
|
||||||
clc = KTIME_MAX;
|
|
||||||
|
|
||||||
return clc;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(clockevent_delta2ns);
|
EXPORT_SYMBOL_GPL(clockevent_delta2ns);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Reference in a new issue