aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kernel/time/clockevents.c4
-rw-r--r--kernel/time/hrtimer.c5
-rw-r--r--kernel/time/tick-sched.c14
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;