As for next_expiry, we want to expand base->clk catch up logic beyond nohz in order to avoid triggering useless softirqs.
If we want to fire softirqs only to expire pending timers, periodic base->clk increments must be skippable for random amounts of time. Therefore we must prepare to catch-up with missing updates whenever we need an up-to-date base clock. Signed-off-by: Frederic Weisbecker <frede...@kernel.org> Cc: Peter Zijlstra <pet...@infradead.org> Cc: Anna-Maria Gleixner <anna-ma...@linutronix.de> Cc: Juri Lelli <juri.le...@redhat.com> --- kernel/time/timer.c | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 501d36ef0b75..ffa2c956d968 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -885,19 +885,12 @@ get_target_base(struct timer_base *base, unsigned tflags) static inline void forward_timer_base(struct timer_base *base) { -#ifdef CONFIG_NO_HZ_COMMON unsigned long jnow; - /* - * We only forward the base when we are idle or have just come out of - * idle (must_forward_clk logic), and have a delta between base clock - * and jiffies. In the common case, run_timers will take care of it. - */ - if (likely(!base->must_forward_clk)) + if (!base->must_forward_clk) return; jnow = READ_ONCE(jiffies); - base->must_forward_clk = base->is_idle; if ((long)(jnow - base->clk) < 2) return; @@ -912,7 +905,6 @@ static inline void forward_timer_base(struct timer_base *base) return; base->clk = base->next_expiry; } -#endif } @@ -1666,10 +1658,8 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) * logic is only maintained for the BASE_STD base, deferrable * timers may still see large granularity skew (by design). */ - if ((expires - basem) > TICK_NSEC) { - base->must_forward_clk = true; + if ((expires - basem) > TICK_NSEC) base->is_idle = true; - } } raw_spin_unlock(&base->lock); @@ -1768,16 +1758,7 @@ static inline void __run_timers(struct timer_base *base) /* * timer_base::must_forward_clk must be cleared before running * timers so that any timer functions that call mod_timer() will - * not try to forward the base. Idle tracking / clock forwarding - * logic is only used with BASE_STD timers. - * - * The must_forward_clk flag is cleared unconditionally also for - * the deferrable base. The deferrable base is not affected by idle - * tracking and never forwarded, so clearing the flag is a NOOP. - * - * The fact that the deferrable base is never forwarded can cause - * large variations in granularity for deferrable timers, but they - * can be deferred for long periods due to idle anyway. + * not try to forward the base. */ base->must_forward_clk = false; @@ -1790,6 +1771,7 @@ static inline void __run_timers(struct timer_base *base) while (levels--) expire_timers(base, heads + levels); } + base->must_forward_clk = true; raw_spin_unlock_irq(&base->lock); timer_base_unlock_expiry(base); } -- 2.26.2