We already have ONESHOT_STOPPED mode available now and can use that to disable spurious interrupts hurting our tickless-ness.
In order to not break 'git bisect', lets modify code to restart of clockevent device first, otherwise between the commits we might never come back from tickless state.
Before reprogramming clockevent device it should be switched back to ONESHOT. It might be switched to ONESHOT_STOPPED mode earlier to avoid getting spurious interrupts on a tickless CPU.
So here are the scenarios I could figure out (relevant for both NO_HZ_IDLE and NO_HZ_FULL cases):
1: Mode: NOHZ_MODE_LOWRES
Ticks are restarted from tick_nohz_restart() when we exit from tickless state. In LOWRES mode ticks are handled directly by programming clockevent device and not with hrtimers.
Restart clockevent device by switching to ONESHOT mode first when we re-enable ticks.
If timers are added to a tickless CPU, we restart ticks first by calling wake_up_nohz_cpu() and so we don't need to restart clockevent device in that case.
We aren't doing anything when hrtimers are added on a tickless CPU and that must be handled separately.
2. Mode: NOHZ_MODE_HIGHRES
In HIGHRES mode, ticks are handled with help of a special hrtimer: tick-sched. hrtimer_start() finally calls hrtimer_reprogram() if we need to reprogram clockevent device. This would happen in two cases:
- hrtimers queue was empty and we are adding the first hrtimer. - New hrtimer's expiry is before all enqueued timers.
We want to reconfigure mode only for the first case. There doesn't exist any infrastructure to identify second case. It wouldn't hurt if we call tick_restart_event() (eventually clockevents_set_mode()) unconditionally. Because we will return without doing anything when current mode is same as new mode.
This will also handle the case where a hrtimer is added on a tickless cpu, as we will restart clockevent device for the first hrtimer.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org --- kernel/hrtimer.c | 6 ++++++ kernel/time/tick-sched.c | 2 ++ 2 files changed, 8 insertions(+)
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 3ab2899..3c0bff2 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -645,6 +645,12 @@ static int hrtimer_reprogram(struct hrtimer *timer, return 0;
/* + * clockevent device might be in ONESHOT_STOPPED mode, switchback to + * ONESHOT mode. + */ + tick_restart_event(); + + /* * Clockevents returns -ETIME, when the event was in the past. */ res = tick_program_event(expires, 0); diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 6558b7a..2c9a145 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -855,6 +855,8 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now) if (hrtimer_active(&ts->sched_timer)) break; } else { + /* Switchback clockevent dev to ONESHOT mode */ + tick_restart_event(); if (!tick_program_event( hrtimer_get_expires(&ts->sched_timer), 0)) break;