From 3af8699aee5f59e9ef60c10686dbf4207b2c3e25 Mon Sep 17 00:00:00 2001 From: Sultan Alsawaf Date: Sat, 28 Jan 2023 13:34:41 +0530 Subject: [PATCH] timekeeping: Keep the tick alive when CPUs cycle out of s2idle When some CPUs cycle out of s2idle due to non-wakeup IRQs, it's possible for them to run while the CPU responsible for jiffies updates remains idle. This can delay the execution of timers indefinitely until the CPU managing the jiffies updates finally wakes up, by which point everything could be dead if enough time passes. Fix it by handing off timekeeping duties when the timekeeping CPU enters s2idle and freezes its tick. When all CPUs are in s2idle, the first one to wake up for any reason (either from a wakeup IRQ or non-wakeup IRQ) will assume responsibility for the timekeeping tick. Signed-off-by: Sultan Alsawaf Signed-off-by: Panchajanya1999 (cherry picked from commit 717100653a78c63fe56b95721fffee5fad96ee91) (cherry picked from commit 83196f829f9e2d4aef6a4d30ac449a7bfc985208) (cherry picked from commit ab251b18b95c2fe80f457dabdf2e7132a6b0ea27) (cherry picked from commit e58369f386e19f02bc5db1a155040e54dd201a60) --- kernel/time/tick-common.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index 2423fcf29..5d3a5dabd 100755 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c @@ -497,7 +497,7 @@ void tick_resume(void) #ifdef CONFIG_SUSPEND static DEFINE_RAW_SPINLOCK(tick_freeze_lock); -static unsigned int tick_freeze_depth; +static unsigned long tick_frozen_mask; /** * tick_freeze - Suspend the local tick and (possibly) timekeeping. @@ -510,10 +510,17 @@ static unsigned int tick_freeze_depth; */ void tick_freeze(void) { + int cpu = smp_processor_id(); + raw_spin_lock(&tick_freeze_lock); - tick_freeze_depth++; - if (tick_freeze_depth == num_online_cpus()) { + tick_frozen_mask |= BIT(cpu); + if (tick_do_timer_cpu == cpu) { + cpu = ffz(tick_frozen_mask); + tick_do_timer_cpu = (cpu < nr_cpu_ids) ? cpu : + TICK_DO_TIMER_NONE; + } + if (tick_frozen_mask == *cpumask_bits(cpu_online_mask)) { trace_suspend_resume(TPS("timekeeping_freeze"), smp_processor_id(), true); system_state = SYSTEM_SUSPEND; @@ -537,9 +544,11 @@ void tick_freeze(void) */ void tick_unfreeze(void) { + int cpu = smp_processor_id(); + raw_spin_lock(&tick_freeze_lock); - if (tick_freeze_depth == num_online_cpus()) { + if (tick_frozen_mask == *cpumask_bits(cpu_online_mask)) { timekeeping_resume(); sched_clock_resume(); system_state = SYSTEM_RUNNING; @@ -550,7 +559,7 @@ void tick_unfreeze(void) tick_resume_local(); } - tick_freeze_depth--; + tick_frozen_mask &= ~BIT(cpu); raw_spin_unlock(&tick_freeze_lock); }