mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-07-07 15:01:44 +00:00
[PATCH] fix next_timer_interrupt() for hrtimer
Also from Thomas Gleixner <tglx@linutronix.de>
Function next_timer_interrupt() got broken with a recent patch
6ba1b91213
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>
This commit is contained in:
parent
f7c09bd972
commit
69239749e1
4 changed files with 61 additions and 4 deletions
|
@ -422,12 +422,14 @@ static int timer_dyn_tick_disable(void)
|
||||||
void timer_dyn_reprogram(void)
|
void timer_dyn_reprogram(void)
|
||||||
{
|
{
|
||||||
struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
|
struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
|
||||||
|
unsigned long next, seq;
|
||||||
|
|
||||||
if (dyn_tick) {
|
if (dyn_tick && (dyn_tick->state & DYN_TICK_ENABLED)) {
|
||||||
write_seqlock(&xtime_lock);
|
next = next_timer_interrupt();
|
||||||
if (dyn_tick->state & DYN_TICK_ENABLED)
|
do {
|
||||||
|
seq = read_seqbegin(&xtime_lock);
|
||||||
dyn_tick->reprogram(next_timer_interrupt() - jiffies);
|
dyn_tick->reprogram(next_timer_interrupt() - jiffies);
|
||||||
write_sequnlock(&xtime_lock);
|
} while (read_seqretry(&xtime_lock, seq));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,10 @@ extern int hrtimer_try_to_cancel(struct hrtimer *timer);
|
||||||
extern ktime_t hrtimer_get_remaining(const 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);
|
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)
|
static inline int hrtimer_active(const struct hrtimer *timer)
|
||||||
{
|
{
|
||||||
return timer->state == HRTIMER_PENDING;
|
return timer->state == HRTIMER_PENDING;
|
||||||
|
|
|
@ -505,6 +505,41 @@ ktime_t hrtimer_get_remaining(const struct hrtimer *timer)
|
||||||
return rem;
|
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
|
* hrtimer_init - initialize a timer to the given clock
|
||||||
*
|
*
|
||||||
|
|
|
@ -489,9 +489,21 @@ unsigned long next_timer_interrupt(void)
|
||||||
struct list_head *list;
|
struct list_head *list;
|
||||||
struct timer_list *nte;
|
struct timer_list *nte;
|
||||||
unsigned long expires;
|
unsigned long expires;
|
||||||
|
unsigned long hr_expires = MAX_JIFFY_OFFSET;
|
||||||
|
ktime_t hr_delta;
|
||||||
tvec_t *varray[4];
|
tvec_t *varray[4];
|
||||||
int i, j;
|
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);
|
base = &__get_cpu_var(tvec_bases);
|
||||||
spin_lock(&base->t_base.lock);
|
spin_lock(&base->t_base.lock);
|
||||||
expires = base->timer_jiffies + (LONG_MAX >> 1);
|
expires = base->timer_jiffies + (LONG_MAX >> 1);
|
||||||
|
@ -542,6 +554,10 @@ found:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spin_unlock(&base->t_base.lock);
|
spin_unlock(&base->t_base.lock);
|
||||||
|
|
||||||
|
if (time_before(hr_expires, expires))
|
||||||
|
return hr_expires;
|
||||||
|
|
||||||
return expires;
|
return expires;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue