]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
clockevents: Add missing resets of the next_event_forced flag
authorThomas Gleixner <tglx@kernel.org>
Tue, 14 Apr 2026 20:55:01 +0000 (22:55 +0200)
committerThomas Gleixner <tglx@kernel.org>
Thu, 16 Apr 2026 19:22:04 +0000 (21:22 +0200)
The prevention mechanism against timer interrupt starvation missed to reset
the next_event_forced flag in a couple of places:

    - When the clock event state changes. That can cause the flag to be
      stale over a shutdown/startup sequence

    - When a non-forced event is armed, which then prevents rearming before
      that event. If that event is far out in the future this will cause
      missed timer interrupts.

    - In the suspend wakeup handler.

That led to stalls which have been reported by several people.

Add the missing resets, which fixes the problems for the reporters.

Fixes: d6e152d905bd ("clockevents: Prevent timer interrupt starvation")
Reported-by: Hanabishi <i.r.e.c.c.a.k.u.n+kernel.org@gmail.com>
Reported-by: Eric Naim <dnaim@cachyos.org>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Tested-by: Hanabishi <i.r.e.c.c.a.k.u.n+kernel.org@gmail.com>
Tested-by: Eric Naim <dnaim@cachyos.org>
Cc: stable@vger.kernel.org
Closes: https://lore.kernel.org/68d1e9ac-2780-4be3-8ee3-0788062dd3a4@gmail.com
Link: https://patch.msgid.link/87340xfeje.ffs@tglx
kernel/time/clockevents.c
kernel/time/tick-broadcast.c

index b4d73060497249f388985673c62905d8ee7da573..5e22697b098d8b1b45a9bbdf086155c96ea3643b 100644 (file)
@@ -94,6 +94,9 @@ static int __clockevents_switch_state(struct clock_event_device *dev,
        if (dev->features & CLOCK_EVT_FEAT_DUMMY)
                return 0;
 
+       /* On state transitions clear the forced flag unconditionally */
+       dev->next_event_forced = 0;
+
        /* Transition with new state-specific callbacks */
        switch (state) {
        case CLOCK_EVT_STATE_DETACHED:
@@ -366,8 +369,10 @@ int clockevents_program_event(struct clock_event_device *dev, ktime_t expires, b
        if (delta > (int64_t)dev->min_delta_ns) {
                delta = min(delta, (int64_t) dev->max_delta_ns);
                cycles = ((u64)delta * dev->mult) >> dev->shift;
-               if (!dev->set_next_event((unsigned long) cycles, dev))
+               if (!dev->set_next_event((unsigned long) cycles, dev)) {
+                       dev->next_event_forced = 0;
                        return 0;
+               }
        }
 
        if (dev->next_event_forced)
index 7e57fa31ee26f14fa60cc971f68c8c0e4fd0deb6..115e0bf012764eb2a539bbdd1231ebeac8252da2 100644 (file)
@@ -108,6 +108,7 @@ static struct clock_event_device *tick_get_oneshot_wakeup_device(int cpu)
 
 static void tick_oneshot_wakeup_handler(struct clock_event_device *wd)
 {
+       wd->next_event_forced = 0;
        /*
         * If we woke up early and the tick was reprogrammed in the
         * meantime then this may be spurious but harmless.