linux/kernel/time
David Woodhouse 869a55e662 timekeeping: Account for clocksource tick quantisation via NTP
cycle_interval is an integer number of counter cycles per NTP interval,
so the real time it represents differs from the nominal
NTP_INTERVAL_LENGTH by up to half a counter period. For coarse
clocksources this is significant: the 3.579545 MHz ACPI PM timer at
HZ=1000 rounds 3579.545 cycles up to 3580, making each tick 1.000127 ms
(+127 PPM).

Commit a386b5af8e ("time: Compensate for rounding on odd-frequency
clocksources") introduced xtime_remainder to compensate for exactly
this, citing the same 127 PPM ACPI PM example. The compensation is
correct and necessary, but it was applied inside the timekeeping
accumulation in timekeeping.c: subtracted in the mult computation in
timekeeping_adjust() and folded into the ntp_error update in
logarithmic_accumulation(). That keeps the base rate correct and leaves
NTP its full symmetric +/-MAXFREQ range rather than +373/-627 PPM, but
the NTP code in ntp.c never sees it: tick_length is computed without the
correction, so ntp.c's notion of how long a tick is disagrees with the
rate timekeeping actually produces.

Make the offset an explicit part of the NTP tick_length instead. Add
ntp_data::cs_tick_adj, a fixed per-second addend that
ntp_update_frequency() includes alongside ntp_tick_adj and time_freq.
tk_setup_internals() computes it from the difference between the real
cycle_interval duration and the nominal interval, stores it in the
timekeeper, and hands it to NTP through a new argument to ntp_clear() --
which already recomputes the frequency and is invoked after every
clocksource (re)configuration. timekeeping_init() now uses TK_UPDATE_ALL
for this; clearing NTP there is otherwise redundant since ntp_init() has
just initialised it.

ntp.c now computes the true tick rate, giving a single source of truth.
Like ntp_tick_adj, cs_tick_adj stays internal to the kernel: userspace
still sees the nominal 1.000000 ms tick via adjtimex and is unaware of
the addends. timekeeping_adjust() and logarithmic_accumulation() use
ntp_tick / xtime_interval directly, and xtime_remainder is removed.

The base-rate arithmetic is unchanged: ntp_tick becomes
xtime_interval << ntp_error_shift, so the mult division yields the same
base mult and the ntp_error accumulation still nets to zero per tick.

Beyond the cleanup of treating all the tick_length contributions
(nominal interval, ntp_tick_adj, cs_tick_adj, time_freq) consistently
as addends in one place, it also prepares for feed-forward discipline:
a future timekeeping_set_reference() will set tick_length to track an
absolute external reference such as a vmclock, and that path needs
ntp.c to own a tick_length that already reflects the clocksource
quantisation, with no hidden correction applied elsewhere.

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Assisted-by: Kiro:claude-opus-4.8
Acked-by: John Stultz <jstultz@google.com>
Link: https://patch.msgid.link/20260621220051.1030462-4-dwmw2@infradead.org
2026-07-10 09:20:54 +02:00
..
.kunitconfig time/kunit: Add .kunitconfig 2026-02-24 08:41:51 +01:00
alarmtimer.c alarmtimer: Remove stale return description from alarm_handle_timer() 2026-05-06 08:33:08 +02:00
clockevents.c clockevents: Fix duplicate type specifier in stub function parameter 2026-06-02 21:07:55 +02:00
clocksource-wdtest.c clocksource: Rewrite watchdog code completely 2026-03-20 13:36:32 +01:00
clocksource.c clocksource: Unregister subsystem on device registration failure 2026-07-07 23:26:58 +02:00
hrtimer.c hrtimer: Explicitly include linux/hrtimer_bases.h 2026-07-07 23:43:44 +02:00
itimer.c timers/itimer: Avoid direct access to hrtimer clockbase 2025-09-09 12:27:17 +02:00
jiffies.c time/jiffies: Register jiffies clocksource before usage 2026-06-13 15:22:40 +02:00
Kconfig vdso/treewide: Drop GENERIC_TIME_VSYSCALL 2026-06-02 21:41:23 +02:00
Makefile timens: Remove dependency on the vDSO 2026-03-26 15:44:23 +01:00
namespace_internal.h timens: Remove dependency on the vDSO 2026-03-26 15:44:23 +01:00
namespace_vdso.c mm.git review status for linus..mm-stable 2026-04-15 12:59:16 -07:00
namespace.c time/namespace: Validate nanosecond field in proc_timens_set_offset() 2026-07-07 23:26:58 +02:00
ntp_internal.h timekeeping: Account for clocksource tick quantisation via NTP 2026-07-10 09:20:54 +02:00
ntp.c timekeeping: Account for clocksource tick quantisation via NTP 2026-07-10 09:20:54 +02:00
posix-clock.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
posix-cpu-timers.c posix-cpu-timers: Don't abuse lock_task_sighand() in handle_posix_cpu_timers() 2026-07-05 12:15:22 +02:00
posix-stubs.c posix-timers: Get rid of [COMPAT_]SYS_NI() uses 2023-12-20 21:30:27 -08:00
posix-timers.c posix-timers: Switch to hrtimer_start_expires_user() 2026-05-01 21:36:12 +02:00
posix-timers.h posix-timers: Expand timer_[re]arm() callbacks with a boolean return value 2026-05-01 21:36:11 +02:00
sched_clock.c time/sched_clock: Use ACCESS_PRIVATE() to evaluate hrtimer::function 2026-01-13 18:08:57 +01:00
sleep_timeout.c treewide, timers: Rename from_timer() to timer_container_of() 2025-06-08 09:07:37 +02:00
test_udelay.c time: Add MODULE_DESCRIPTION() to time test modules 2024-06-03 11:18:50 +02:00
tick-broadcast-hrtimer.c clockevents: Remove redundant CLOCK_EVT_FEAT_KTIME 2026-02-27 16:40:06 +01:00
tick-broadcast.c clockevents: Add missing resets of the next_event_forced flag 2026-04-16 21:22:04 +02:00
tick-common.c clockevents: Prevent timer interrupt starvation 2026-04-10 22:45:38 +02:00
tick-internal.h tick: Explicitly include linux/hrtimer_bases.h 2026-07-07 23:43:44 +02:00
tick-legacy.c timekeeping: remove xtime_update 2020-10-30 21:57:07 +01:00
tick-oneshot.c treewide: Update email address 2026-01-11 06:09:11 -10:00
tick-sched.c Updates for the NOHZ subsystem: 2026-06-15 13:48:52 +05:30
tick-sched.h tick/sched: Remove unused fields 2026-06-02 21:27:25 +02:00
time_test.c time/kunit: Document handling of negative years of is_leap() 2026-02-02 12:37:54 +01:00
time.c timekeeping: Move the vDSO update declarations into a private header 2026-07-07 23:48:08 +02:00
timeconst.bc time: Add SPDX license identifiers 2018-11-23 11:51:20 +01:00
timeconv.c time: Improve performance of time64_to_tm() 2021-06-24 11:51:59 +02:00
timecounter.c time/timecounter: Inline timecounter_cyc2time() 2025-12-15 20:16:49 +01:00
timekeeping_debug.c timekeeping: Add percpu counter for tracking floor swap events 2024-10-10 10:20:46 +02:00
timekeeping_internal.h timekeeping: Move the vDSO update declarations into a private header 2026-07-07 23:48:08 +02:00
timekeeping.c timekeeping: Account for clocksource tick quantisation via NTP 2026-07-10 09:20:54 +02:00
timekeeping.h timekeeping: Provide infrastructure for coupled clockevents 2026-02-27 16:40:08 +01:00
timer_list.c timer_list: Annotate print_cpu() diagnostic reads 2026-07-07 23:26:58 +02:00
timer_migration.c timers/migration: Fix memory leak in tmigr_setup_groups() error path 2026-07-07 23:26:58 +02:00
timer_migration.h timers/migration: Turn tmigr_hierarchy level_list into a flexible array 2026-06-02 21:34:03 +02:00
timer.c hrtimer: Return ktime_t from hrtimer_get_next_event()/hrtimer_next_event_without() 2026-05-06 08:33:09 +02:00
vsyscall.c vdso/vsyscall: Avoid slow division loop in auxiliary clock update 2025-09-03 11:55:11 +02:00