summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw@amazon.co.uk>2026-06-21 22:53:57 +0100
committerThomas Gleixner <tglx@kernel.org>2026-07-10 09:20:54 +0200
commitd375af58990902e73dd62bd7c049e759bcff92a5 (patch)
treeb1204e3ab27209bc590202715b478a78616b5d95 /include/linux
parent869a55e662a080a5c6618b68ae320231c720eeee (diff)
timekeeping: Drive time_offset skew via per-tick ntp_error transfer
Currently, the phase offset of time_offset and time_adjust is delivered by adjusting tick_length in second_overflow(), and immediately draining time_offset/time_adjust by the amount that the tick_length adjustment is *estimated* to cause. This is fairly approximate, in part because it is not always correct to assume that precisely NTP_INTERVAL_FREQ ticks will occur between one call to second_overflow() and the next. It could also over and under-run in the final second of delivery. Instead of inflating tick_length, transfer the intended skew directly into ntp_error each tick to achieve the desired rate. In second_overflow(), calculate skew_delta which is the per-tick slew rate, in the same units as time_offset: (ns << NTP_SCALE_SHIFT) / HZ. In logarithmic_accumulation(), drain up to 'skew_delta' time units from time_offset into ntp_error to drive the overall effective rate. The new ntp_drain_skew() function returns the amount which is actually 'claimed' by time_offset (and in a future patch, time_adjust). Any overrun which is delivered by the changed 'mult' (as described below) but not claimed by ntp_drain_skew() will remain in ntp_error to be corrected away in subsequent ticks. Simply transferring the precise amount from time_offset to ntp_error would be sufficent to make the time *eventually* converge, however the skew delivered is limited by the choice of { mult, mult+1 } each tick and thus the convergence would be extremely slow. In theory we could inflate ntp_err_mult with the magnitude of ntp_error in the general case — but that would cause overcorrection in a tickless kernel. Instead, in timekeeping_adjust(), take skew_delta into account when calculating 'mult', such that the available {mult, mult+1} choices bracket the overall effective rate *including* the skew, to avoid the delta just building up in ntp_error. The effect is that the inflated 'mult' causes ntp_error to grow because xtime_interval is (e.g.) longer than the true tick_length. But then the same delta is removed again as it's drained from time_offset. This gives behaviour equivalent to the old tick_length += delta approach but with exact per-tick accounting of the time_offset actually imparted to the clock, and no overrun. Signed-off-by: David Woodhouse <dwmw@amazon.co.uk> Signed-off-by: Thomas Gleixner <tglx@kernel.org> Assisted-by: Kiro:claude-opus-4.8 Link: https://patch.msgid.link/20260621220051.1030462-5-dwmw2@infradead.org
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/timekeeper_internal.h1
1 files changed, 1 insertions, 0 deletions
diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h
index 9c53f44537f0..9c198f65621b 100644
--- a/include/linux/timekeeper_internal.h
+++ b/include/linux/timekeeper_internal.h
@@ -189,6 +189,7 @@ struct timekeeper {
u32 ntp_err_mult;
s64 cs_tick_adj;
u32 skip_second_overflow;
+ s64 skew_delta;
s32 tai_offset;
};