Viresh Kumar viresh.kumar@linaro.org writes:
When no timers/hrtimers are pending, the expiry time is set to a special value: 'KTIME_MAX'. This normally happens with NO_HZ_{IDLE|FULL} in both LOWRES/HIGHRES modes.
When 'expiry == KTIME_MAX', we either cancel the 'tick-sched' hrtimer (NOHZ_MODE_HIGHRES) or skip reprogramming clockevent device (NOHZ_MODE_LOWRES). But, the clockevent device is already reprogrammed from the tick-handler for next tick.
As the clock event device is programmed in ONESHOT mode it will at least fire one more time (unnecessarily). Timers on few implementations (like arm_arch_timer, etc.) only support PERIODIC mode and their drivers emulate ONESHOT over that. Which means that on these platforms we will get spurious interrupts periodically (at last programmed interval rate, normally tick rate).
In order to avoid spurious interrupts, the clockevent device should be stopped or its interrupts should be masked.
A simple (yet hacky) solution to get this fixed could be: update hrtimer_force_reprogram() to always reprogram clockevent device and update clockevent drivers to STOP generating events (or delay it to max time) when 'expires' is set to KTIME_MAX. But the drawback here is that every clockevent driver has to be hacked for this particular case and its very easy for new ones to miss this.
However, Thomas suggested to add an optional state ONESHOT_STOPPED to solve this problem: lkml.org/lkml/2014/5/9/508.
This patch adds support for ONESHOT_STOPPED state in clockevents core. It will only be available to drivers that implement the state-specific callbacks instead of the legacy ->set_mode() callback.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org
Reviewed-by: Kevin Hilman khilman@linaro.org
with a minor nit...
[...]
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index 73689df1e4b8..04f6c3433f8e 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c @@ -138,6 +138,17 @@ static int __clockevents_set_state(struct clock_event_device *dev, return -ENOSYS; return dev->set_state_oneshot(dev);
- case CLOCK_EVT_STATE_ONESHOT_STOPPED:
/* Core internal bug */
This comment is not useful at all (nor are all the other ones already in this file.) IMO, the comment should say something like: "ONESHOT_STOPPED is only valid when currently in the ONESHOT state." or something similar.
if (WARN_ONCE(dev->state != CLOCK_EVT_STATE_ONESHOT,
"Current state: %d\n", dev->state))
Similarily this output will not be useful, and should say something like: "Can only enter ONESHOT_STOPPED from ONESHOT. Current state: %d\n".
return -EINVAL;
if (dev->set_state_oneshot_stopped)
return dev->set_state_oneshot_stopped(dev);
else
return -ENOSYS;
- default: return -ENOSYS; }
Kevin