The use of a clockevent device's ->min_delta_ns in the event programming path hinders upcoming changes to the clockevent core making it NTP correction aware: both, ->mult and ->min_delta_ns would need to get updated as well as consumed atomically and we'd rather like to avoid any locking here.
We already have got ->min_delta_ticks_adjusted which - resembles the value of ->min_delta_ns - and is guaranteed to be always >= the hardware's hard limit ->min_delta_ticks and thus, can be used w/o locking as we don't care for small deviations. In clockevents_increase_min_delta(), don't use ->min_delta_ns but calculate it dynamically from ->min_delta_ticks_adjusted. As clockevents_increase_min_delta() gets invoked only rarely, the additional division should not be an issue from a performance standpoint. Signed-off-by: Nicolai Stange <nicsta...@gmail.com> --- kernel/time/clockevents.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index aa7b325..86d9f97 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c @@ -210,23 +210,26 @@ int clockevents_tick_resume(struct clock_event_device *dev) */ static int clockevents_increase_min_delta(struct clock_event_device *dev) { + u64 min_delta_ns = cev_delta2ns(dev->min_delta_ticks_adjusted, dev, + false); + /* Nothing to do if we already reached the limit */ - if (dev->min_delta_ns >= MIN_DELTA_LIMIT) { + if (min_delta_ns >= MIN_DELTA_LIMIT) { printk_deferred(KERN_WARNING "CE: Reprogramming failure. Giving up\n"); dev->next_event.tv64 = KTIME_MAX; return -ETIME; } - if (dev->min_delta_ns < 5000) - dev->min_delta_ns = 5000; + if (min_delta_ns < 5000) + min_delta_ns = 5000; else - dev->min_delta_ns += dev->min_delta_ns >> 1; + min_delta_ns += min_delta_ns >> 1; - if (dev->min_delta_ns > MIN_DELTA_LIMIT) - dev->min_delta_ns = MIN_DELTA_LIMIT; + if (min_delta_ns > MIN_DELTA_LIMIT) + min_delta_ns = MIN_DELTA_LIMIT; - dev->min_delta_ticks_adjusted = (unsigned long)((dev->min_delta_ns * + dev->min_delta_ticks_adjusted = (unsigned long)((min_delta_ns * dev->mult) >> dev->shift); dev->min_delta_ticks_adjusted = max(dev->min_delta_ticks_adjusted, dev->min_delta_ticks); @@ -234,7 +237,7 @@ static int clockevents_increase_min_delta(struct clock_event_device *dev) printk_deferred(KERN_WARNING "CE: %s increased min_delta_ns to %llu nsec\n", dev->name ? dev->name : "?", - (unsigned long long) dev->min_delta_ns); + (unsigned long long) min_delta_ns); return 0; } -- 2.9.3