Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 69239749 authored by Tony Lindgren's avatar Tony Lindgren Committed by Linus Torvalds
Browse files

[PATCH] fix next_timer_interrupt() for hrtimer



Also from Thomas Gleixner <tglx@linutronix.de>

Function next_timer_interrupt() got broken with a recent patch
6ba1b912 as sys_nanosleep() was moved to
hrtimer.  This broke things as next_timer_interrupt() did not check hrtimer
tree for next event.

Function next_timer_interrupt() is needed with dyntick (CONFIG_NO_IDLE_HZ,
VST) implementations, as the system can be in idle when next hrtimer event
was supposed to happen.  At least ARM and S390 currently use
next_timer_interrupt().

Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Russell King <rmk@arm.linux.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent f7c09bd9
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -422,12 +422,14 @@ static int timer_dyn_tick_disable(void)
void timer_dyn_reprogram(void)
{
	struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
	unsigned long next, seq;

	if (dyn_tick) {
		write_seqlock(&xtime_lock);
		if (dyn_tick->state & DYN_TICK_ENABLED)
	if (dyn_tick && (dyn_tick->state & DYN_TICK_ENABLED)) {
		next = next_timer_interrupt();
		do {
			seq = read_seqbegin(&xtime_lock);
			dyn_tick->reprogram(next_timer_interrupt() - jiffies);
		write_sequnlock(&xtime_lock);
		} while (read_seqretry(&xtime_lock, seq));
	}
}

+4 −0
Original line number Diff line number Diff line
@@ -116,6 +116,10 @@ extern int hrtimer_try_to_cancel(struct hrtimer *timer);
extern ktime_t hrtimer_get_remaining(const struct hrtimer *timer);
extern int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp);

#ifdef CONFIG_NO_IDLE_HZ
extern ktime_t hrtimer_get_next_event(void);
#endif

static inline int hrtimer_active(const struct hrtimer *timer)
{
	return timer->state == HRTIMER_PENDING;
+35 −0
Original line number Diff line number Diff line
@@ -505,6 +505,41 @@ ktime_t hrtimer_get_remaining(const struct hrtimer *timer)
	return rem;
}

#ifdef CONFIG_NO_IDLE_HZ
/**
 * hrtimer_get_next_event - get the time until next expiry event
 *
 * Returns the delta to the next expiry event or KTIME_MAX if no timer
 * is pending.
 */
ktime_t hrtimer_get_next_event(void)
{
	struct hrtimer_base *base = __get_cpu_var(hrtimer_bases);
	ktime_t delta, mindelta = { .tv64 = KTIME_MAX };
	unsigned long flags;
	int i;

	for (i = 0; i < MAX_HRTIMER_BASES; i++, base++) {
		struct hrtimer *timer;

		spin_lock_irqsave(&base->lock, flags);
		if (!base->first) {
			spin_unlock_irqrestore(&base->lock, flags);
			continue;
		}
		timer = rb_entry(base->first, struct hrtimer, node);
		delta.tv64 = timer->expires.tv64;
		spin_unlock_irqrestore(&base->lock, flags);
		delta = ktime_sub(delta, base->get_time());
		if (delta.tv64 < mindelta.tv64)
			mindelta.tv64 = delta.tv64;
	}
	if (mindelta.tv64 < 0)
		mindelta.tv64 = 0;
	return mindelta;
}
#endif

/**
 * hrtimer_init - initialize a timer to the given clock
 *
+16 −0
Original line number Diff line number Diff line
@@ -489,9 +489,21 @@ unsigned long next_timer_interrupt(void)
	struct list_head *list;
	struct timer_list *nte;
	unsigned long expires;
	unsigned long hr_expires = MAX_JIFFY_OFFSET;
	ktime_t hr_delta;
	tvec_t *varray[4];
	int i, j;

	hr_delta = hrtimer_get_next_event();
	if (hr_delta.tv64 != KTIME_MAX) {
		struct timespec tsdelta;
		tsdelta = ktime_to_timespec(hr_delta);
		hr_expires = timespec_to_jiffies(&tsdelta);
		if (hr_expires < 3)
			return hr_expires + jiffies;
	}
	hr_expires += jiffies;

	base = &__get_cpu_var(tvec_bases);
	spin_lock(&base->t_base.lock);
	expires = base->timer_jiffies + (LONG_MAX >> 1);
@@ -542,6 +554,10 @@ unsigned long next_timer_interrupt(void)
		}
	}
	spin_unlock(&base->t_base.lock);

	if (time_before(hr_expires, expires))
		return hr_expires;

	return expires;
}
#endif