Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

timekeeping: Distangle resume and clock-was-set events

Resuming timekeeping is a clock-was-set event and uses the clock-was-set
notification mechanism. This is in the way of making the clock-was-set
update for hrtimers selective so unnecessary IPIs are avoided when a CPU
base does not have timers queued which are affected by the clock setting.

Distangle it by invoking hrtimer_resume() on each unfreezing CPU and invoke
the new timerfd_resume() function from timekeeping_resume() which is the
only place where this is needed.

Rename hrtimer_resume() to hrtimer_resume_local() to reflect the change.

With this the clock_was_set*() functions are not longer required to IPI all
CPUs unconditionally and can get some smarts to avoid them.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/r/20210713135158.488853478@linutronix.de

+18 -11
-1
include/linux/hrtimer.h
··· 354 354 static inline void timerfd_clock_was_set(void) { } 355 355 static inline void timerfd_resume(void) { } 356 356 #endif 357 - extern void hrtimers_resume(void); 358 357 359 358 DECLARE_PER_CPU(struct tick_device, tick_cpu_device); 360 359
+6 -9
kernel/time/hrtimer.c
··· 900 900 static DECLARE_WORK(hrtimer_work, clock_was_set_work); 901 901 902 902 /* 903 - * Called from timekeeping and resume code to reprogram the hrtimer 904 - * interrupt device on all cpus and to notify timerfd. 903 + * Called from timekeeping code to reprogram the hrtimer interrupt device 904 + * on all cpus and to notify timerfd. 905 905 */ 906 906 void clock_was_set_delayed(void) 907 907 { ··· 909 909 } 910 910 911 911 /* 912 - * During resume we might have to reprogram the high resolution timer 913 - * interrupt on all online CPUs. However, all other CPUs will be 914 - * stopped with IRQs interrupts disabled so the clock_was_set() call 915 - * must be deferred. 912 + * Called during resume either directly from via timekeeping_resume() 913 + * or in the case of s2idle from tick_unfreeze() to ensure that the 914 + * hrtimers are up to date. 916 915 */ 917 - void hrtimers_resume(void) 916 + void hrtimers_resume_local(void) 918 917 { 919 918 lockdep_assert_irqs_disabled(); 920 919 /* Retrigger on the local CPU */ 921 920 retrigger_next_event(NULL); 922 - /* And schedule a retrigger for all others */ 923 - clock_was_set_delayed(); 924 921 } 925 922 926 923 /*
+7
kernel/time/tick-common.c
··· 470 470 else 471 471 tick_resume_oneshot(); 472 472 } 473 + 474 + /* 475 + * Ensure that hrtimers are up to date and the clockevents device 476 + * is reprogrammed correctly when high resolution timers are 477 + * enabled. 478 + */ 479 + hrtimers_resume_local(); 473 480 } 474 481 475 482 /**
+2
kernel/time/tick-internal.h
··· 168 168 169 169 void clock_was_set(void); 170 170 void clock_was_set_delayed(void); 171 + 172 + void hrtimers_resume_local(void);
+3 -1
kernel/time/timekeeping.c
··· 1810 1810 1811 1811 touch_softlockup_watchdog(); 1812 1812 1813 + /* Resume the clockevent device(s) and hrtimers */ 1813 1814 tick_resume(); 1814 - hrtimers_resume(); 1815 + /* Notify timerfd as resume is equivalent to clock_was_set() */ 1816 + timerfd_resume(); 1815 1817 } 1816 1818 1817 1819 int timekeeping_suspend(void)