diff options
author | Viresh Kumar <viresh.kumar@linaro.org> | 2015-03-25 17:08:11 +0530 |
---|---|---|
committer | Gary S. Robertson <gary.robertson@linaro.org> | 2015-07-22 16:17:11 -0500 |
commit | fd61abf9170bce9f94a0d1c5c7cafb2505caf11a (patch) | |
tree | d9bb156028e1f8006e88a67e65ab97fdf105328c | |
parent | a83a8fb64304b7697c9c92bddcb86ff24a7f5b9b (diff) |
clockevents: Stop unused clockevent device
Clockevent device can now be stopped by switching to ONESHOT_STOPPED mode, to
avoid getting spurious interrupts on a tickless CPU.
This patch switches mode to ONESHOT_STOPPED at three different places and
following is the reasoning behind them.
1.) NOHZ_MODE_LOWRES
Timers & hrtimers are dependent on tick for their working in this mode and the
only place from where clockevent device is programmed is the tick-code.
So, we only need to switch clockevent device to ONESHOT_STOPPED mode once ticks
aren't required anymore. And the only call site is: tick_nohz_stop_sched_tick().
In LOWRES mode we skip reprogramming the clockevent device here if expires ==
KTIME_MAX. In addition to that we must also switch the clockevent device to
ONESHOT_STOPPED mode to avoid all spurious interrupts that may follow.
2.) NOHZ_MODE_HIGHRES
Tick & timers are dependent on hrtimers for their working in this mode and the
only place from where clockevent device is programmed is the hrtimer-code.
There are two places here from which we reprogram the clockevent device or skip
reprogramming it on expires == KTIME_MAX.
Instead of skipping reprogramming the clockevent device, also switch its mode to
ONESHOT_STOPPED so that it doesn't generate any spurious interrupts.
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
[forward port to 3.18
- manually applied few patch.
]
Signed-off-by: Santosh Shukla <santosh.shukla@linaro.org>
-rw-r--r-- | kernel/time/hrtimer.c | 47 | ||||
-rw-r--r-- | kernel/time/tick-sched.c | 4 |
2 files changed, 47 insertions, 4 deletions
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index db4ea5d7cb41..f269baf68d90 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -539,7 +539,19 @@ hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal) if (cpu_base->hang_detected) return; - tick_program_event(cpu_base->expires_next, 1); + if (cpu_base->expires_next.tv64 != KTIME_MAX) { + tick_program_event(cpu_base->expires_next, 1); + } else { + struct clock_event_device *dev = + __this_cpu_read(tick_cpu_device.evtdev); + /* + * Don't need clockevent device anymore, stop it. + * + * We reach here only for NOHZ_MODE_HIGHRES mode and we are + * guaranteed that no timers/hrtimers are enqueued on this cpu. + */ + clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT_STOPPED); + } } /* @@ -1575,9 +1587,36 @@ retry: cpu_base->expires_next = expires_next; raw_spin_unlock(&cpu_base->lock); - /* Reprogramming necessary ? */ - if (expires_next.tv64 == KTIME_MAX || - !tick_program_event(expires_next, 0)) { + if (expires_next.tv64 == KTIME_MAX) { + struct clock_event_device *dev = + __this_cpu_read(tick_cpu_device.evtdev); + + cpu_base->hang_detected = 0; + + /* + * Don't need clockevent device anymore, stop it. + * + * We reach here only for NOHZ_MODE_HIGHRES mode and we are + * guaranteed that no timers/hrtimers are enqueued on this cpu. + * + * Most of the scenarios will be covered by similar code + * present in hrtimer_force_reprogram(), as we always try to + * evaluate tick requirement on idle/irq exit and cancel + * tick-sched hrtimer when tick isn't required anymore. + * + * It is required here as well as a special case. + * + * Last hrtimer fires on a tickless CPU and doesn't rearm + * itself. tick_nohz_irq_exit() reevaluates next event and it + * gets expires == KTIME_MAX. Because tick was already stopped, + * and last expires == new_expires, we return early. And the + * clockevent device is never stopped. + */ + clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT_STOPPED); + return; + } + + if (!tick_program_event(expires_next, 0)) { cpu_base->hang_detected = 0; goto out; } diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 5f5f3c7486a1..3077f963f350 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -708,6 +708,10 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, if (unlikely(expires.tv64 == KTIME_MAX)) { if (ts->nohz_mode == NOHZ_MODE_HIGHRES) hrtimer_cancel(&ts->sched_timer); + else + /* stop clock event device */ + clockevents_set_mode(dev, + CLOCK_EVT_MODE_ONESHOT_STOPPED); goto out; } |