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 <sultan@kerneltoast.com>
Change-Id: Idbb2e825c489e174d5701e0c315b51a3149bfe49
fourteen
Sultan Alsawaf 3 years ago committed by Jenna
parent ba1afaa024
commit f7ff514106
  1. 21
      kernel/time/tick-common.c

@ -472,7 +472,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.
@ -485,10 +485,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);
sched_clock_suspend();
@ -511,9 +518,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();
trace_suspend_resume(TPS("timekeeping_freeze"),
@ -521,8 +530,10 @@ void tick_unfreeze(void)
} else {
tick_resume_local();
}
if (tick_do_timer_cpu == TICK_DO_TIMER_NONE)
tick_do_timer_cpu = cpu;
tick_freeze_depth--;
tick_frozen_mask &= ~BIT(cpu);
raw_spin_unlock(&tick_freeze_lock);
}

Loading…
Cancel
Save