]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
timekeeping: Initialize the coupled clocksource conversion completely
authorThomas Gleixner <tglx@kernel.org>
Tue, 3 Mar 2026 21:56:27 +0000 (22:56 +0100)
committerThomas Gleixner <tglx@kernel.org>
Thu, 5 Mar 2026 16:40:46 +0000 (17:40 +0100)
Nathan reported a boot failure after the coupled clocksource/event support
was enabled for the TSC deadline timer. It turns out that on the affected
test systems the TSC frequency is not refined against HPET, so it is
registered with the same frequency as the TSC-early clocksource.

As a consequence the update function which checks for a change of the
shift/mult pair of the clocksource fails to compute the conversion
limit, which is zero initialized. This check is there to avoid pointless
computations on every timekeeping update cycle (tick).

So the actual clockevent conversion function limits the delta expiry to
zero, which means the timer is always programmed to expire in the
past. This obviously results in a spectacular timer interrupt storm,
which goes unnoticed because the per CPU interrupts on x86 are not
exposed to the runaway detection mechanism and the NMI watchdog is not
yet functional. So the machine simply stops booting.

That did not show up in testing. All test machines refine the TSC frequency
so TSC has a differrent shift/mult pair than TSC-early and the conversion
limit is properly initialized.

Cure that by setting the conversion limit right at the point where the new
clocksource is installed.

Fixes: cd38bdb8e696 ("timekeeping: Provide infrastructure for coupled clockevents")
Reported-by: Nathan Chancellor <nathan@kernel.org>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Tested-by: Nathan Chancellor <nathan@kernel.org>
Acked-by: John Stultz <jstultz@google.com>
Link: https://patch.msgid.link/87bjh4zies.ffs@tglx
Closes: https://lore.kernel.org/20260303012905.GA978396@ax162
kernel/time/timekeeping.c

index b7a0f93011e0b36ecb4f3e72bedcab987696b002..5153218df29f54fdd294c217a908d485f5df60d2 100644 (file)
@@ -404,6 +404,13 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock)
                 */
                clocks_calc_mult_shift(&tk->cs_ns_to_cyc_mult, &tk->cs_ns_to_cyc_shift,
                                       NSEC_PER_MSEC, clock->freq_khz, 3600 * 1000);
+               /*
+                * Initialize the conversion limit as the previous clocksource
+                * might have the same shift/mult pair so the quick check in
+                * tk_update_ns_to_cyc() fails to update it after a clocksource
+                * change leaving it effectivly zero.
+                */
+               tk->cs_ns_to_cyc_maxns = div_u64(clock->mask, tk->cs_ns_to_cyc_mult);
        }
 }