aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time/hrtimer.c
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2014-06-23 04:09:37 -0400
committerThomas Gleixner <tglx@linutronix.de>2014-06-23 05:23:47 -0400
commit49a2a07514a3a2ea4a02482fa60575e106d960f9 (patch)
tree59402f8335bc11eb3b78db4074e1b861dfb796eb /kernel/time/hrtimer.c
parentcddd02489f52ccf635ed65931214729a23b93cd6 (diff)
hrtimer: Kick lowres dynticks targets on timer enqueue
In lowres mode, hrtimers are serviced by the tick instead of a clock event. It works well as long as the tick stays periodic but we must also make sure that the hrtimers are serviced in dynticks mode targets, pretty much like timer list timers do. Note that all dynticks modes are concerned: get_nohz_timer_target() tries not to return remote idle CPUs but there is nothing to prevent the elected target from entering dynticks idle mode until we lock its base. It's also prefectly legal to enqueue hrtimers on full dynticks CPU. So there are two requirements to correctly handle dynticks: 1) On target's tick stop time, we must not delay the next tick further the next hrtimer. 2) On hrtimer queue time. If the tick of the target is stopped, we must wake up that CPU such that it sees the new hrtimer and recalculate the next tick accordingly. The point 1 is well handled currently through get_nohz_timer_interrupt() and cmp_next_hrtimer_event(). But the point 2 isn't handled at all. Fixing this is easy though as we have the necessary API ready for that. All we need is to call wake_up_nohz_cpu() on a target when a newly enqueued hrtimer requires tick rescheduling, like timer list timer do. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Link: http://lkml.kernel.org/r/3d7ea08ce008698e26bd39fe10f55949391073ab.1403507178.git.viresh.kumar@linaro.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/time/hrtimer.c')
-rw-r--r--kernel/time/hrtimer.c27
1 files changed, 19 insertions, 8 deletions
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index 0e32d4e7583f..f9007478fcce 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -1013,14 +1013,25 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
1013 1013
1014 leftmost = enqueue_hrtimer(timer, new_base); 1014 leftmost = enqueue_hrtimer(timer, new_base);
1015 1015
1016 /* 1016 if (!leftmost) {
1017 * Only allow reprogramming if the new base is on this CPU. 1017 unlock_hrtimer_base(timer, &flags);
1018 * (it might still be on another CPU if the timer was pending) 1018 return ret;
1019 * 1019 }
1020 * XXX send_remote_softirq() ? 1020
1021 */ 1021 if (!hrtimer_is_hres_active(timer)) {
1022 if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases) 1022 /*
1023 && hrtimer_enqueue_reprogram(timer, new_base)) { 1023 * Kick to reschedule the next tick to handle the new timer
1024 * on dynticks target.
1025 */
1026 wake_up_nohz_cpu(new_base->cpu_base->cpu);
1027 } else if (new_base->cpu_base == &__get_cpu_var(hrtimer_bases) &&
1028 hrtimer_enqueue_reprogram(timer, new_base)) {
1029 /*
1030 * Only allow reprogramming if the new base is on this CPU.
1031 * (it might still be on another CPU if the timer was pending)
1032 *
1033 * XXX send_remote_softirq() ?
1034 */
1024 if (wakeup) { 1035 if (wakeup) {
1025 /* 1036 /*
1026 * We need to drop cpu_base->lock to avoid a 1037 * We need to drop cpu_base->lock to avoid a