Commit 69239749e1ac4f3496906aa4267cb9f61ce52c9c

Authored by Tony Lindgren
Committed by Linus Torvalds
1 parent f7c09bd972

[PATCH] fix next_timer_interrupt() for hrtimer

Also from Thomas Gleixner <tglx@linutronix.de>

Function next_timer_interrupt() got broken with a recent patch
6ba1b91213e81aa92b5cf7539f7d2a94ff54947c 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: Thomas 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: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

Showing 4 changed files with 61 additions and 4 deletions Side-by-side Diff

arch/arm/kernel/time.c
... ... @@ -422,12 +422,14 @@
422 422 void timer_dyn_reprogram(void)
423 423 {
424 424 struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
  425 + unsigned long next, seq;
425 426  
426   - if (dyn_tick) {
427   - write_seqlock(&xtime_lock);
428   - if (dyn_tick->state & DYN_TICK_ENABLED)
  427 + if (dyn_tick && (dyn_tick->state & DYN_TICK_ENABLED)) {
  428 + next = next_timer_interrupt();
  429 + do {
  430 + seq = read_seqbegin(&xtime_lock);
429 431 dyn_tick->reprogram(next_timer_interrupt() - jiffies);
430   - write_sequnlock(&xtime_lock);
  432 + } while (read_seqretry(&xtime_lock, seq));
431 433 }
432 434 }
433 435  
include/linux/hrtimer.h
... ... @@ -116,6 +116,10 @@
116 116 extern ktime_t hrtimer_get_remaining(const struct hrtimer *timer);
117 117 extern int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp);
118 118  
  119 +#ifdef CONFIG_NO_IDLE_HZ
  120 +extern ktime_t hrtimer_get_next_event(void);
  121 +#endif
  122 +
119 123 static inline int hrtimer_active(const struct hrtimer *timer)
120 124 {
121 125 return timer->state == HRTIMER_PENDING;
... ... @@ -505,6 +505,41 @@
505 505 return rem;
506 506 }
507 507  
  508 +#ifdef CONFIG_NO_IDLE_HZ
  509 +/**
  510 + * hrtimer_get_next_event - get the time until next expiry event
  511 + *
  512 + * Returns the delta to the next expiry event or KTIME_MAX if no timer
  513 + * is pending.
  514 + */
  515 +ktime_t hrtimer_get_next_event(void)
  516 +{
  517 + struct hrtimer_base *base = __get_cpu_var(hrtimer_bases);
  518 + ktime_t delta, mindelta = { .tv64 = KTIME_MAX };
  519 + unsigned long flags;
  520 + int i;
  521 +
  522 + for (i = 0; i < MAX_HRTIMER_BASES; i++, base++) {
  523 + struct hrtimer *timer;
  524 +
  525 + spin_lock_irqsave(&base->lock, flags);
  526 + if (!base->first) {
  527 + spin_unlock_irqrestore(&base->lock, flags);
  528 + continue;
  529 + }
  530 + timer = rb_entry(base->first, struct hrtimer, node);
  531 + delta.tv64 = timer->expires.tv64;
  532 + spin_unlock_irqrestore(&base->lock, flags);
  533 + delta = ktime_sub(delta, base->get_time());
  534 + if (delta.tv64 < mindelta.tv64)
  535 + mindelta.tv64 = delta.tv64;
  536 + }
  537 + if (mindelta.tv64 < 0)
  538 + mindelta.tv64 = 0;
  539 + return mindelta;
  540 +}
  541 +#endif
  542 +
508 543 /**
509 544 * hrtimer_init - initialize a timer to the given clock
510 545 *
... ... @@ -489,9 +489,21 @@
489 489 struct list_head *list;
490 490 struct timer_list *nte;
491 491 unsigned long expires;
  492 + unsigned long hr_expires = MAX_JIFFY_OFFSET;
  493 + ktime_t hr_delta;
492 494 tvec_t *varray[4];
493 495 int i, j;
494 496  
  497 + hr_delta = hrtimer_get_next_event();
  498 + if (hr_delta.tv64 != KTIME_MAX) {
  499 + struct timespec tsdelta;
  500 + tsdelta = ktime_to_timespec(hr_delta);
  501 + hr_expires = timespec_to_jiffies(&tsdelta);
  502 + if (hr_expires < 3)
  503 + return hr_expires + jiffies;
  504 + }
  505 + hr_expires += jiffies;
  506 +
495 507 base = &__get_cpu_var(tvec_bases);
496 508 spin_lock(&base->t_base.lock);
497 509 expires = base->timer_jiffies + (LONG_MAX >> 1);
... ... @@ -542,6 +554,10 @@
542 554 }
543 555 }
544 556 spin_unlock(&base->t_base.lock);
  557 +
  558 + if (time_before(hr_expires, expires))
  559 + return hr_expires;
  560 +
545 561 return expires;
546 562 }
547 563 #endif