[RFC PATCH v3 0/4] Add ntp_error to clock snapshot, enable NTP_PPS on tickless kernel

From: David Woodhouse

Date: Mon Jun 22 2026 - 17:18:54 EST


The real time reported by the kernel's timekeeping sawtooths around the
'ideal' time line that the kernel would like to report. Limited by the
integer arithmetic, the kernel varies the 'mult' factor by ±1 each tick
to achieve the correct rate on average over time. The reported time is
further sanitized to ensure continuity when mult changes, even part way
through a tick. The delta from the ideal to what is currently reported,
is stored in tk->ntp_error. The sawtooth effect is more pronounced on
tickless kernels, as the 'mult' value does not get adjusted each tick
but only less frequently.

Both ktime_get_snapshot_id() and get_device_system_crosststamp() report
the same sanitized time, but *every* user of those functions (PTP, PPS,
KVM enlightenments) would be better served by the true ideal time.

Add snapshot_ntp_error() helper and use it from both of those functions
to adjust the system time they report and return the more accurate
result.

With this change, CONFIG_NTP_PPS works correctly on a tickless kernel;
enable it. And change the non-CONFIG_NTP_PPS code path in pps_get_ts()
to use ktime_get_snapshot_id() too, for the more accurate data.

Tested with a hack to make vmclock simulate a 1PPS signal, although there
are now better options for that. But it's enough to show that even the
tickless kernel converges to ±1ns of the PPS signal and remains there
(tested with a periodic PTP_SYS_OFFSET_EXTENDED to compare with the
vmclock reference).

[ 0.653414] Run /init as init process
PPS: coarse-set CLOCK_REALTIME from vmclock
[ 1.655824] pps pps0: bound kernel consumer: edge=0x1
PPS: enabled, bound to hardpps, STA_PPSTIME|STA_PPSFREQ set
PRECISE: dev-sys(adj)=+5609ns OK
EXT[ 0] diff=+5608ns
EXT[ 1] diff=+5262ns
[ 2.917076] hardpps: PPSJITTER: jitter=5173, limit=0
EXT[ 2] diff=+4914ns
EXT[ 3] diff=+1197ns
EXT[ 4] diff=-297ns
EXT[ 5] diff=-103ns
EXT[ 6] diff=+0ns
EXT[ 7] diff=+0ns
EXT[ 8] diff=-1ns
EXT[ 9] diff=+0ns
EXT[10] diff=+0ns

David Woodhouse (4):
timekeeping: Apply extrapolated ntp_error to clock snapshots
pps: Drop the !NO_HZ_COMMON dependency from NTP_PPS
pps: Always use ktime_get_snapshot_id() for pps_get_ts()
[DO NOT MERGE] ptp: ptp_vmclock: Add simulated 1PPS support

drivers/pps/Kconfig | 3 -
drivers/ptp/ptp_vmclock.c | 196 ++++++++++++++++++++++++++++++++++--
include/linux/pps_kernel.h | 4 +-
include/linux/timekeeper_internal.h | 6 ++
kernel/time/timekeeping.c | 71 ++++++++++++-
5 files changed, 259 insertions(+), 21 deletions(-)