From: Thomas Gleixner Date: Wed, 22 Oct 2008 07:48:06 +0000 (+0200) Subject: Merge branch 'timers/range-hrtimers' into v28-range-hrtimers-for-linus-v2 X-Git-Tag: v2.6.28-rc1~18^2 X-Git-Url: http://pilppa.com/gitweb/?a=commitdiff_plain;h=268a3dcfea2077fca60d3715caa5c96f9b5e6ea7;p=linux-2.6-omap-h63xx.git Merge branch 'timers/range-hrtimers' into v28-range-hrtimers-for-linus-v2 Conflicts: kernel/time/tick-sched.c Signed-off-by: Thomas Gleixner --- 268a3dcfea2077fca60d3715caa5c96f9b5e6ea7 diff --cc kernel/time/tick-sched.c index 727c1ae0517,a547be11cf9..5bbb1044f84 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@@ -377,32 -377,6 +377,32 @@@ ktime_t tick_nohz_get_sleep_length(void return ts->sleep_length; } +static void tick_nohz_restart(struct tick_sched *ts, ktime_t now) +{ + hrtimer_cancel(&ts->sched_timer); - ts->sched_timer.expires = ts->idle_tick; ++ hrtimer_set_expires(&ts->sched_timer, ts->idle_tick); + + while (1) { + /* Forward the time to expire in the future */ + hrtimer_forward(&ts->sched_timer, now, tick_period); + + if (ts->nohz_mode == NOHZ_MODE_HIGHRES) { - hrtimer_start(&ts->sched_timer, - ts->sched_timer.expires, ++ hrtimer_start_expires(&ts->sched_timer, + HRTIMER_MODE_ABS); + /* Check, if the timer was already in the past */ + if (hrtimer_active(&ts->sched_timer)) + break; + } else { - if (!tick_program_event(ts->sched_timer.expires, 0)) ++ if (!tick_program_event( ++ hrtimer_get_expires(&ts->sched_timer), 0)) + break; + } + /* Update jiffies and reread time */ + tick_do_update_jiffies64(now); + now = ktime_get(); + } +} + /** * tick_nohz_restart_sched_tick - restart the idle tick from the idle task * @@@ -456,7 -430,28 +456,9 @@@ void tick_nohz_restart_sched_tick(void */ ts->tick_stopped = 0; ts->idle_exittime = now; - hrtimer_cancel(&ts->sched_timer); - hrtimer_set_expires(&ts->sched_timer, ts->idle_tick); + - while (1) { - /* Forward the time to expire in the future */ - hrtimer_forward(&ts->sched_timer, now, tick_period); + tick_nohz_restart(ts, now); + - if (ts->nohz_mode == NOHZ_MODE_HIGHRES) { - hrtimer_start_expires(&ts->sched_timer, - HRTIMER_MODE_ABS); - /* Check, if the timer was already in the past */ - if (hrtimer_active(&ts->sched_timer)) - break; - } else { - if (!tick_program_event( - hrtimer_get_expires(&ts->sched_timer), 0)) - break; - } - /* Update jiffies and reread time */ - tick_do_update_jiffies64(now); - now = ktime_get(); - } local_irq_enable(); } @@@ -553,37 -552,6 +555,37 @@@ static void tick_nohz_switch_to_nohz(vo smp_processor_id()); } +/* + * When NOHZ is enabled and the tick is stopped, we need to kick the + * tick timer from irq_enter() so that the jiffies update is kept + * alive during long running softirqs. That's ugly as hell, but + * correctness is key even if we need to fix the offending softirq in + * the first place. + * + * Note, this is different to tick_nohz_restart. We just kick the + * timer and do not touch the other magic bits which need to be done + * when idle is left. + */ +static void tick_nohz_kick_tick(int cpu) +{ + struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); + ktime_t delta, now; + + if (!ts->tick_stopped) + return; + + /* + * Do not touch the tick device, when the next expiry is either + * already reached or less/equal than the tick period. + */ + now = ktime_get(); - delta = ktime_sub(ts->sched_timer.expires, now); ++ delta = ktime_sub(hrtimer_get_expires(&ts->sched_timer), now); + if (delta.tv64 <= tick_period.tv64) + return; + + tick_nohz_restart(ts, now); +} + #else static inline void tick_nohz_switch_to_nohz(void) { }