diff options
-rw-r--r-- | kernel/time/clockevents.c | 4 | ||||
-rw-r--r-- | kernel/time/hrtimer.c | 5 | ||||
-rw-r--r-- | kernel/time/tick-sched.c | 14 |
3 files changed, 22 insertions, 1 deletions
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index 808ae0902379..95dcdbc269b9 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c @@ -318,6 +318,10 @@ int clockevents_program_event(struct clock_event_device *dev, ktime_t expires, if (dev->mode == CLOCK_EVT_MODE_SHUTDOWN) return 0; + /* We must be in ONESHOT mode here */ + WARN_ONCE(dev->mode != CLOCK_EVT_MODE_ONESHOT, "Current mode: %d\n", + dev->mode); + /* Shortcut for clockevent devices that can deal with ktime. */ if (dev->features & CLOCK_EVT_FEAT_KTIME) return dev->set_next_ktime(expires, dev); diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index c0572ef3b404..db4ea5d7cb41 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -561,6 +561,7 @@ static int hrtimer_reprogram(struct hrtimer *timer, { struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); ktime_t expires = ktime_sub(hrtimer_get_expires(timer), base->offset); + struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); int res; WARN_ON_ONCE(hrtimer_get_expires_tv64(timer) < 0); @@ -595,6 +596,10 @@ static int hrtimer_reprogram(struct hrtimer *timer, if (cpu_base->hang_detected) return 0; + /* Switchback to ONESHOT mode */ + if (unlikely(dev->mode == CLOCK_EVT_MODE_ONESHOT_STOPPED)) + clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT); + /* * Clockevents returns -ETIME, when the event was in the past. */ diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index d7cef36a443c..5f5f3c7486a1 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -717,8 +717,14 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, /* Check, if the timer was already in the past */ if (hrtimer_active(&ts->sched_timer)) goto out; - } else if (!tick_program_event(expires, 0)) + } else { + /* Switchback to ONESHOT mode */ + if (unlikely(dev->mode == CLOCK_EVT_MODE_ONESHOT_STOPPED)) + clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT); + + if (!tick_program_event(expires, 0)) goto out; + } /* * We are past the event already. So we crossed a * jiffie boundary. Update jiffies and raise the @@ -889,6 +895,8 @@ ktime_t tick_nohz_get_sleep_length(void) static void tick_nohz_restart(struct tick_sched *ts, ktime_t now) { + struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); + hrtimer_cancel(&ts->sched_timer); hrtimer_set_expires(&ts->sched_timer, ts->last_tick); @@ -903,6 +911,10 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now) if (hrtimer_active(&ts->sched_timer)) break; } else { + /* Switchback to ONESHOT mode */ + if (likely(dev->mode == CLOCK_EVT_MODE_ONESHOT_STOPPED)) + clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT); + if (!tick_program_event( hrtimer_get_expires(&ts->sched_timer), 0)) break; |