From eba302268a019275fd6ff452d4ff0b94fef11c76 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 21:59:51 +0200 Subject: [PATCH 01/28] timekeeping: Provide ktime_get_snapshot_id() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ktime_get_snapshot() provides a snapshot of the underlying clocksource counter value and the corresponding CLOCK_MONOTONIC_RAW, CLOCK_REALTIME and CLOCK_BOOTTIME timestamps. There is no usage of CLOCK_REALTIME and CLOCK_BOOTTIME at the same time and CLOCK_BOOTTIME support was just added for the ARM64 KVM tracing mechanism, which needs CLOCK_BOOTTIME and the underlying clocksource counter value. ktime_get_snapshot() is also not suitable for usage with CLOCK_AUX, but that's a prerequisite to support PTP hardware timestamping for CLOCK_AUX steering. As a first step, rename ktime_get_snapshot() to ktime_get_snapshot_id(), which now takes a clockid argument to select the clock which needs to be captured. The result is stored in system_time_snapshot::systime, which will replace the system_time_snapshot::real/boot members once all usage sites have been converted. ktime_get_snapshot() is a simple wrapper which hands in CLOCK_REALTIME as clockid argument for the conversion period. That means CLOCK_REALTIME is now captured twice, but that redunancy is only temporary. As all usage sites of struct system_time_snapshot has to be updated anyway, rename the 'raw' member to 'monoraw' for clarity. No functional change vs. current users of ktime_get_snapshot() Signed-off-by: Thomas Gleixner Tested-by: David Woodhouse Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Thomas Weißschuh Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20260529195556.971591633@kernel.org --- include/linux/timekeeping.h | 34 ++++++++++----- kernel/time/timekeeping.c | 85 ++++++++++++++++++++++++++++--------- 2 files changed, 88 insertions(+), 31 deletions(-) diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index aee2c1a46e47..161157c8d27e 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -276,24 +276,32 @@ static inline bool ktime_get_aux_ts64(clockid_t id, struct timespec64 *kt) { ret #endif /** - * struct system_time_snapshot - simultaneous raw/real time capture with - * counter value - * @cycles: Clocksource counter value to produce the system times - * @real: Realtime system time - * @boot: Boot time - * @raw: Monotonic raw system time - * @cs_id: Clocksource ID + * struct system_time_snapshot - Simultaneous time capture of CLOCK_MONOTONIC_RAW, + * a selected CLOCK_* and the clocksource counter value + * @cycles: Clocksource counter value to produce the system times + * @systime: The system time of the selected CLOCK ID + * @real: Realtime system time + * @boot: Boot time + * @raw: Monotonic raw system time + * @monoraw: Monotonic raw system time + * @cs_id: Clocksource ID * @clock_was_set_seq: The sequence number of clock-was-set events * @cs_was_changed_seq: The sequence number of clocksource change events + * @valid: True if the snapshot is valid */ struct system_time_snapshot { u64 cycles; + ktime_t systime; ktime_t real; ktime_t boot; - ktime_t raw; + union { + ktime_t raw; + ktime_t monoraw; + }; enum clocksource_ids cs_id; unsigned int clock_was_set_seq; u8 cs_was_changed_seq; + u8 valid; }; /** @@ -341,9 +349,15 @@ extern int get_device_system_crosststamp( struct system_device_crosststamp *xtstamp); /* - * Simultaneously snapshot realtime and monotonic raw clocks + * Simultaneously snapshot a given clock with MONOTONIC_RAW and the underlying + * clocksource counter value. */ -extern void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot); +extern void ktime_get_snapshot_id(clockid_t clock_id, struct system_time_snapshot *systime_snapshot); + +static inline void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot) +{ + ktime_get_snapshot_id(CLOCK_REALTIME, systime_snapshot); +} /* * Persistent clock related interfaces diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index c493a4010305..0053dc0010f4 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1183,43 +1183,86 @@ noinstr time64_t __ktime_get_real_seconds(void) } /** - * ktime_get_snapshot - snapshots the realtime/monotonic raw clocks with counter - * @systime_snapshot: pointer to struct receiving the system time snapshot + * ktime_get_snapshot_id - Simultaneously snapshot a given clock ID with + * CLOCK_MONOTONIC_RAW and the underlying + * clocksource counter value. + * @clock_id: The clock ID to snapshot + * @systime_snapshot: Pointer to struct receiving the system time snapshot */ -void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot) +void ktime_get_snapshot_id(clockid_t clock_id, struct system_time_snapshot *systime_snapshot) { - struct timekeeper *tk = &tk_core.timekeeper; + ktime_t base_raw, base_sys, offs_sys, *offs, offs_zero = 0; + u64 nsec_raw, nsec_sys, now; + struct timekeeper *tk; + struct tk_data *tkd; unsigned int seq; - ktime_t base_raw; ktime_t base_real; ktime_t base_boot; - u64 nsec_raw; - u64 nsec_real; - u64 now; - WARN_ON_ONCE(timekeeping_suspended); + /* Invalidate the snapshot for all failure cases */ + systime_snapshot->valid = false; + + if (WARN_ON_ONCE(timekeeping_suspended)) + return; + + switch (clock_id) { + case CLOCK_REALTIME: + tkd = &tk_core; + offs = &tk_core.timekeeper.offs_real; + break; + /* Map RAW to MONOTONIC so the loop below is trivial */ + case CLOCK_MONOTONIC_RAW: + case CLOCK_MONOTONIC: + tkd = &tk_core; + offs = &offs_zero; + break; + case CLOCK_BOOTTIME: + tkd = &tk_core; + offs = &tk_core.timekeeper.offs_boot; + break; + default: + WARN_ON_ONCE(1); + return; + } + + tk = &tkd->timekeeper; do { - seq = read_seqcount_begin(&tk_core.seq); + seq = read_seqcount_begin(&tkd->seq); + now = tk_clock_read(&tk->tkr_mono); systime_snapshot->cs_id = tk->tkr_mono.clock->id; systime_snapshot->cs_was_changed_seq = tk->cs_was_changed_seq; systime_snapshot->clock_was_set_seq = tk->clock_was_set_seq; - base_real = ktime_add(tk->tkr_mono.base, - tk_core.timekeeper.offs_real); - base_boot = ktime_add(tk->tkr_mono.base, - tk_core.timekeeper.offs_boot); + + base_sys = tk->tkr_mono.base; + offs_sys = *offs; base_raw = tk->tkr_raw.base; - nsec_real = timekeeping_cycles_to_ns(&tk->tkr_mono, now); - nsec_raw = timekeeping_cycles_to_ns(&tk->tkr_raw, now); - } while (read_seqcount_retry(&tk_core.seq, seq)); + + /* Kept around until the callers are fixed up */ + base_real = ktime_add(base_sys, tk_core.timekeeper.offs_real); + base_boot = ktime_add(base_sys, tk_core.timekeeper.offs_boot); + + nsec_sys = timekeeping_cycles_to_ns(&tk->tkr_mono, now); + nsec_raw = timekeeping_cycles_to_ns(&tk->tkr_raw, now); + } while (read_seqcount_retry(&tkd->seq, seq)); systime_snapshot->cycles = now; - systime_snapshot->real = ktime_add_ns(base_real, nsec_real); - systime_snapshot->boot = ktime_add_ns(base_boot, nsec_real); - systime_snapshot->raw = ktime_add_ns(base_raw, nsec_raw); + systime_snapshot->systime = ktime_add_ns(base_sys, offs_sys + nsec_sys); + systime_snapshot->real = ktime_add_ns(base_real, nsec_sys); + systime_snapshot->boot = ktime_add_ns(base_boot, nsec_sys); + systime_snapshot->monoraw = ktime_add_ns(base_raw, nsec_raw); + + /* + * Special case for PTP. Just transfer the raw time into sys, + * so the call sites can consistently use snap::systime. + */ + if (clock_id == CLOCK_MONOTONIC_RAW) + systime_snapshot->systime = systime_snapshot->monoraw; + /* Tell the consumer that this snapshot is valid */ + systime_snapshot->valid = true; } -EXPORT_SYMBOL_GPL(ktime_get_snapshot); +EXPORT_SYMBOL_GPL(ktime_get_snapshot_id); /* Scale base by mult/div checking for overflow */ static int scale64_check_overflow(u64 mult, u64 div, u64 *base) From ef22786707e3967b539c3b1e6b5c7ea8b408430f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 21:59:55 +0200 Subject: [PATCH 02/28] timekeeping: Use system_time_snapshot::systime/monoraw instead of ::real/raw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit system_time_snapshot::systime provides the same information as system_time_snapshot::real when the snapshot was taken with ktime_get_snapshot_id(CLOCK_REALTIME). Convert the history interpolation over to use 'systime' and 'monoraw' as 'real/raw' are going away once all users are converted. As a side effect this is the first step to support CLOCK_AUX with get_device_crosstime_stamp() and the history interpolation. Signed-off-by: Thomas Gleixner Tested-by: David Woodhouse Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Thomas Weißschuh Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20260529195557.024415766@kernel.org --- kernel/time/timekeeping.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 0053dc0010f4..ccd04addb021 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1323,7 +1323,7 @@ static int adjust_historical_crosststamp(struct system_time_snapshot *history, * partial_history_cycles / total_history_cycles */ corr_raw = (u64)ktime_to_ns( - ktime_sub(ts->sys_monoraw, history->raw)); + ktime_sub(ts->sys_monoraw, history->monoraw)); ret = scale64_check_overflow(partial_history_cycles, total_history_cycles, &corr_raw); if (ret) @@ -1341,7 +1341,7 @@ static int adjust_historical_crosststamp(struct system_time_snapshot *history, (corr_raw, tk->tkr_mono.mult, tk->tkr_raw.mult); } else { corr_real = (u64)ktime_to_ns( - ktime_sub(ts->sys_realtime, history->real)); + ktime_sub(ts->sys_realtime, history->systime)); ret = scale64_check_overflow(partial_history_cycles, total_history_cycles, &corr_real); if (ret) @@ -1350,8 +1350,8 @@ static int adjust_historical_crosststamp(struct system_time_snapshot *history, /* Fixup monotonic raw and real time time values */ if (interp_forward) { - ts->sys_monoraw = ktime_add_ns(history->raw, corr_raw); - ts->sys_realtime = ktime_add_ns(history->real, corr_real); + ts->sys_monoraw = ktime_add_ns(history->monoraw, corr_raw); + ts->sys_realtime = ktime_add_ns(history->systime, corr_real); } else { ts->sys_monoraw = ktime_sub_ns(ts->sys_monoraw, corr_raw); ts->sys_realtime = ktime_sub_ns(ts->sys_realtime, corr_real); From fe1159fe49b40f73de88d2c29200c813952e061f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 21:59:59 +0200 Subject: [PATCH 03/28] pps: generators: Use ktime_get_real_ts64() instead of ktime_get_snapshot() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no reason to use the more complex ktime_get_snapshot() for retrieving CLOCK_REALTIME. Just use ktime_get_real_ts64(), which avoids the extra timespec64 conversion as a bonus. No functional change intended. Signed-off-by: Thomas Gleixner Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Thomas Weißschuh Reviewed-by: Jacob Keller Acked-by: Rodolfo Giometti Link: https://patch.msgid.link/20260529195557.074439049@kernel.org --- drivers/pps/generators/pps_gen-dummy.c | 6 +----- drivers/pps/generators/pps_gen_tio.c | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/pps/generators/pps_gen-dummy.c b/drivers/pps/generators/pps_gen-dummy.c index 547fa7fe29f4..a4395543c4bb 100644 --- a/drivers/pps/generators/pps_gen-dummy.c +++ b/drivers/pps/generators/pps_gen-dummy.c @@ -39,11 +39,7 @@ static void pps_gen_ktimer_event(struct timer_list *unused) static int pps_gen_dummy_get_time(struct pps_gen_device *pps_gen, struct timespec64 *time) { - struct system_time_snapshot snap; - - ktime_get_snapshot(&snap); - *time = ktime_to_timespec64(snap.real); - + ktime_get_real_ts64(time); return 0; } diff --git a/drivers/pps/generators/pps_gen_tio.c b/drivers/pps/generators/pps_gen_tio.c index de00a85bfafa..9483d126ada0 100644 --- a/drivers/pps/generators/pps_gen_tio.c +++ b/drivers/pps/generators/pps_gen_tio.c @@ -189,11 +189,7 @@ static int pps_tio_gen_enable(struct pps_gen_device *pps_gen, bool enable) static int pps_tio_get_time(struct pps_gen_device *pps_gen, struct timespec64 *time) { - struct system_time_snapshot snap; - - ktime_get_snapshot(&snap); - *time = ktime_to_timespec64(snap.real); - + ktime_get_real_ts64(time); return 0; } From d5becddf8a0f18bcc18129efa086530b5263c6b4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 22:00:04 +0200 Subject: [PATCH 04/28] pps: Convert to ktime_get_snapshot_id() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ktime_get_snapshot() resolves to ktime_get_snapshot_id(CLOCK_REALTIME). Make it obvious in the code and convert the readout to use the snapshot::systime and monoraw fields instead of snapshot::real and raw, which aregoing away. Similar to the PPS generators, avoid the more expensive snapshot when CONFIG_NTP_PPS is disabled. No functional change intended. Signed-off-by: Thomas Gleixner Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Thomas Weißschuh Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20260529195557.123410250@kernel.org --- include/linux/pps_kernel.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/linux/pps_kernel.h b/include/linux/pps_kernel.h index aab0aebb529e..9f088c9023b1 100644 --- a/include/linux/pps_kernel.h +++ b/include/linux/pps_kernel.h @@ -99,12 +99,14 @@ static inline void timespec_to_pps_ktime(struct pps_ktime *kt, static inline void pps_get_ts(struct pps_event_time *ts) { +#ifdef CONFIG_NTP_PPS struct system_time_snapshot snap; - ktime_get_snapshot(&snap); - ts->ts_real = ktime_to_timespec64(snap.real); -#ifdef CONFIG_NTP_PPS - ts->ts_raw = ktime_to_timespec64(snap.raw); + ktime_get_snapshot_id(CLOCK_REALTIME, &snap); + ts->ts_real = ktime_to_timespec64(snap.systime); + ts->ts_raw = ktime_to_timespec64(snap.monoraw); +#else + ktime_get_real_ts64(&ts->ts_real); #endif } From ed645be2ab1bcbc0e27242c7316fc15475962333 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 22:00:08 +0200 Subject: [PATCH 05/28] KVM: arm64: Use ktime_get_snapshot_id() to retrieve CLOCK_BOOTTIME MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ktime_get_snapshot() is replaced by ktime_get_snapshot_id() which allows to request a particular CLOCK ID to be captured along with the clocksource counter. Convert the tracing mechanism over and use the new system_time_snapshot::systime field, which holds the system timestamp selected by the CLOCK ID argument. No functional change intended. Signed-off-by: Thomas Gleixner Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Thomas Weißschuh Reviewed-by: Jacob Keller Acked-by: Marc Zyngier Acked-by: Vincent Donnefort Link: https://patch.msgid.link/20260529195557.174373054@kernel.org --- arch/arm64/kvm/hyp_trace.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c index 8b7f2bf2fba8..822ce32d39ae 100644 --- a/arch/arm64/kvm/hyp_trace.c +++ b/arch/arm64/kvm/hyp_trace.c @@ -51,8 +51,8 @@ static void __hyp_clock_work(struct work_struct *work) hyp_clock = container_of(dwork, struct hyp_trace_clock, work); - ktime_get_snapshot(&snap); - boot = ktime_to_ns(snap.boot); + ktime_get_snapshot_id(CLOCK_BOOTTIME, &snap); + boot = ktime_to_ns(snap.systime); delta_boot = boot - hyp_clock->boot; delta_cycles = snap.cycles - hyp_clock->cycles; @@ -118,9 +118,9 @@ static void hyp_trace_clock_enable(struct hyp_trace_clock *hyp_clock, bool enabl hyp_clock->running = false; } - ktime_get_snapshot(&snap); + ktime_get_snapshot_id(CLOCK_BOOTTIME, &snap); - hyp_clock->boot = ktime_to_ns(snap.boot); + hyp_clock->boot = ktime_to_ns(snap.systime); hyp_clock->cycles = snap.cycles; hyp_clock->mult = 0; From 744f8406a3d197b8e466d1ab09c4c3b8de8d65ea Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 22:00:12 +0200 Subject: [PATCH 06/28] KVM: arm64: Use ktime_get_snapshot_id() to snapshot CLOCK_REALTIME MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ktime_get_snapshot() is replaced by ktime_get_snapshot_id() which allows to request a particular CLOCK ID to be captured along with the clocksource counter. Convert the usage in kvm_get_ptp_time() over and use the new system_time_snapshot::systime field, which holds the system timestamp selected by the CLOCK ID argument. No functional change intended. Signed-off-by: Thomas Gleixner Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Thomas Weißschuh Reviewed-by: Jacob Keller Acked-by: Marc Zyngier Link: https://patch.msgid.link/20260529195557.225399927@kernel.org --- arch/arm64/kvm/hypercalls.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c index 58c5fe7d7572..b11b8821c9fb 100644 --- a/arch/arm64/kvm/hypercalls.c +++ b/arch/arm64/kvm/hypercalls.c @@ -28,7 +28,7 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val) * system time and counter value must captured at the same * time to keep consistency and precision. */ - ktime_get_snapshot(&systime_snapshot); + ktime_get_snapshot_id(CLOCK_REALTIME, &systime_snapshot); /* * This is only valid if the current clocksource is the @@ -61,8 +61,8 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val) * in the future (about 292 years from 1970, and at that stage * nobody will give a damn about it). */ - val[0] = upper_32_bits(systime_snapshot.real); - val[1] = lower_32_bits(systime_snapshot.real); + val[0] = upper_32_bits(systime_snapshot.systime); + val[1] = lower_32_bits(systime_snapshot.systime); val[2] = upper_32_bits(cycles); val[3] = lower_32_bits(cycles); } From 50de63d924deb0357d510818c7443b3446a837be Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 22:00:16 +0200 Subject: [PATCH 07/28] ptp: ptp_vmclock: Convert to ktime_get_snapshot_id() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ktime_get_snapshot() is replaced by ktime_get_snapshot_id() which allows to request a particular CLOCK ID to be captured along with the clocksource counter. Convert vmclock over and use the new system_time_snapshot::systime field, which holds the system timestamp selected by the CLOCK ID argument. No functional change intended. Signed-off-by: Thomas Gleixner Tested-by: David Woodhouse Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Thomas Weißschuh Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20260529195557.281425262@kernel.org --- drivers/ptp/ptp_vmclock.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/ptp/ptp_vmclock.c b/drivers/ptp/ptp_vmclock.c index 8b630eb916b5..0f12b54be740 100644 --- a/drivers/ptp/ptp_vmclock.c +++ b/drivers/ptp/ptp_vmclock.c @@ -132,7 +132,7 @@ static int vmclock_get_crosststamp(struct vmclock_state *st, * will be derived from the *same* counter value. * * If the system isn't using the same counter, then the value - * from ktime_get_snapshot() will still be used as pre_ts, and + * from ktime_get_snapshot_id() will still be used as pre_ts, and * ptp_read_system_postts() is called to populate postts after * calling get_cycles(). * @@ -140,7 +140,7 @@ static int vmclock_get_crosststamp(struct vmclock_state *st, * the seq_count loop. */ if (sts) { - ktime_get_snapshot(&systime_snapshot); + ktime_get_snapshot_id(CLOCK_REALTIME, &systime_snapshot); if (systime_snapshot.cs_id == st->cs_id) { cycle = systime_snapshot.cycles; } else { @@ -181,7 +181,7 @@ static int vmclock_get_crosststamp(struct vmclock_state *st, } if (sts) { - sts->pre_ts = ktime_to_timespec64(systime_snapshot.real); + sts->pre_ts = ktime_to_timespec64(systime_snapshot.systime); if (systime_snapshot.cs_id == st->cs_id) sts->post_ts = sts->pre_ts; } @@ -272,7 +272,7 @@ static int ptp_vmclock_getcrosststamp(struct ptp_clock_info *ptp, if (ret == -ENODEV) { struct system_time_snapshot systime_snapshot; - ktime_get_snapshot(&systime_snapshot); + ktime_get_snapshot_id(CLOCK_REALTIME, &systime_snapshot); if (systime_snapshot.cs_id == CSID_X86_TSC || systime_snapshot.cs_id == CSID_X86_KVM_CLK) { From 705e1068071f82b6c66b9e28124fbb7123b04c1d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 22:00:20 +0200 Subject: [PATCH 08/28] timekeeping: Remove system_time_snapshot::real/boot/raw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All users are converted over to ktime_get_snapshot_id() and system_time_snapshot::systime and ::monoraw. Remove the leftovers. Signed-off-by: Thomas Gleixner Tested-by: David Woodhouse Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Thomas Weißschuh Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20260529195557.330029635@kernel.org --- include/linux/timekeeping.h | 10 +--------- kernel/time/timekeeping.c | 8 -------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index 161157c8d27e..eb64c90c4127 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -280,9 +280,6 @@ static inline bool ktime_get_aux_ts64(clockid_t id, struct timespec64 *kt) { ret * a selected CLOCK_* and the clocksource counter value * @cycles: Clocksource counter value to produce the system times * @systime: The system time of the selected CLOCK ID - * @real: Realtime system time - * @boot: Boot time - * @raw: Monotonic raw system time * @monoraw: Monotonic raw system time * @cs_id: Clocksource ID * @clock_was_set_seq: The sequence number of clock-was-set events @@ -292,12 +289,7 @@ static inline bool ktime_get_aux_ts64(clockid_t id, struct timespec64 *kt) { ret struct system_time_snapshot { u64 cycles; ktime_t systime; - ktime_t real; - ktime_t boot; - union { - ktime_t raw; - ktime_t monoraw; - }; + ktime_t monoraw; enum clocksource_ids cs_id; unsigned int clock_was_set_seq; u8 cs_was_changed_seq; diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index ccd04addb021..a134b1bad923 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1196,8 +1196,6 @@ void ktime_get_snapshot_id(clockid_t clock_id, struct system_time_snapshot *syst struct timekeeper *tk; struct tk_data *tkd; unsigned int seq; - ktime_t base_real; - ktime_t base_boot; /* Invalidate the snapshot for all failure cases */ systime_snapshot->valid = false; @@ -1239,18 +1237,12 @@ void ktime_get_snapshot_id(clockid_t clock_id, struct system_time_snapshot *syst offs_sys = *offs; base_raw = tk->tkr_raw.base; - /* Kept around until the callers are fixed up */ - base_real = ktime_add(base_sys, tk_core.timekeeper.offs_real); - base_boot = ktime_add(base_sys, tk_core.timekeeper.offs_boot); - nsec_sys = timekeeping_cycles_to_ns(&tk->tkr_mono, now); nsec_raw = timekeeping_cycles_to_ns(&tk->tkr_raw, now); } while (read_seqcount_retry(&tkd->seq, seq)); systime_snapshot->cycles = now; systime_snapshot->systime = ktime_add_ns(base_sys, offs_sys + nsec_sys); - systime_snapshot->real = ktime_add_ns(base_real, nsec_sys); - systime_snapshot->boot = ktime_add_ns(base_boot, nsec_sys); systime_snapshot->monoraw = ktime_add_ns(base_raw, nsec_raw); /* From 23c1bfa9f8dbefe0be1fa32aaf235c08cb24bd78 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 22:00:24 +0200 Subject: [PATCH 09/28] timekeeping: Add CLOCK_AUX support for ktime_get_snapshot_id() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that all users are converted it's possible to enable snapshotting of CLOCK_AUX time. The underlying clocksource is the same as for all other CLOCK variants. Signed-off-by: Thomas Gleixner Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Thomas Weißschuh Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20260529195557.380601005@kernel.org --- kernel/time/timekeeping.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index a134b1bad923..e43aa11dbfd6 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -67,6 +67,7 @@ static inline bool tk_is_aux(const struct timekeeper *tk) { return tk->id >= TIMEKEEPER_AUX_FIRST && tk->id <= TIMEKEEPER_AUX_LAST; } +static inline struct tk_data *aux_get_tk_data(clockid_t id); #else static inline bool tk_get_aux_ts64(unsigned int tkid, struct timespec64 *ts) { @@ -77,6 +78,10 @@ static inline bool tk_is_aux(const struct timekeeper *tk) { return false; } +static inline struct tk_data *aux_get_tk_data(clockid_t id) +{ + return NULL; +} #endif static inline void tk_update_aux_offs(struct timekeeper *tk, ktime_t offs) @@ -1218,6 +1223,12 @@ void ktime_get_snapshot_id(clockid_t clock_id, struct system_time_snapshot *syst tkd = &tk_core; offs = &tk_core.timekeeper.offs_boot; break; + case CLOCK_AUX ... CLOCK_AUX_LAST: + tkd = aux_get_tk_data(clock_id); + if (!tkd) + return; + offs = &tkd->timekeeper.offs_aux; + break; default: WARN_ON_ONCE(1); return; @@ -1228,6 +1239,10 @@ void ktime_get_snapshot_id(clockid_t clock_id, struct system_time_snapshot *syst do { seq = read_seqcount_begin(&tkd->seq); + /* Aux clocks can be invalid */ + if (!tk->clock_valid) + return; + now = tk_clock_read(&tk->tkr_mono); systime_snapshot->cs_id = tk->tkr_mono.clock->id; systime_snapshot->cs_was_changed_seq = tk->cs_was_changed_seq; From 6c14771816435a7ecf52d981a341e2de21463268 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 22:00:28 +0200 Subject: [PATCH 10/28] timekeeping: Add system_counterval_t to struct system_device_crosststamp An upcoming extension to the PTP IOCTL requires to return the system counter value and the clocksource ID to user space. get_device_system_crosststamp() has this information already. Extend struct system_device_crosststamp with a system_counterval_t member and fill in the data. Signed-off-by: Thomas Gleixner Tested-by: David Woodhouse Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20260529195557.429406675@kernel.org --- include/linux/timekeeping.h | 28 ++++++++++++---------- kernel/time/timekeeping.c | 48 +++++++++++++++++-------------------- 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index eb64c90c4127..3867db65f391 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -296,19 +296,6 @@ struct system_time_snapshot { u8 valid; }; -/** - * struct system_device_crosststamp - system/device cross-timestamp - * (synchronized capture) - * @device: Device time - * @sys_realtime: Realtime simultaneous with device time - * @sys_monoraw: Monotonic raw simultaneous with device time - */ -struct system_device_crosststamp { - ktime_t device; - ktime_t sys_realtime; - ktime_t sys_monoraw; -}; - /** * struct system_counterval_t - system counter value with the ID of the * corresponding clocksource @@ -325,6 +312,21 @@ struct system_counterval_t { bool use_nsecs; }; +/** + * struct system_device_crosststamp - system/device cross-timestamp + * (synchronized capture) + * @device: Device time + * @sys_counter: Clocksource counter value simultaneous with device time + * @sys_realtime: Realtime simultaneous with device time + * @sys_monoraw: Monotonic raw simultaneous with device time + */ +struct system_device_crosststamp { + ktime_t device; + struct system_counterval_t sys_counter; + ktime_t sys_realtime; + ktime_t sys_monoraw; +}; + extern bool ktime_real_to_base_clock(ktime_t treal, enum clocksource_ids base_id, u64 *cycles); extern bool timekeeping_clocksource_has_base(enum clocksource_ids id); diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index e43aa11dbfd6..372179ff27a3 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1418,6 +1418,8 @@ static bool convert_base_to_cs(struct system_counterval_t *scv) return false; scv->cycles += base->offset; + /* Set the clocksource ID as scv::cycles is now clocksource based */ + scv->cs_id = cs->id; return true; } @@ -1485,11 +1487,11 @@ EXPORT_SYMBOL_GPL(ktime_real_to_base_clock); /** * get_device_system_crosststamp - Synchronously capture system/device timestamp - * @get_time_fn: Callback to get simultaneous device time and - * system counter from the device driver + * @get_time_fn: Callback to get simultaneous device time and system counter + * from the device driver * @ctx: Context passed to get_time_fn() - * @history_begin: Historical reference point used to interpolate system - * time when counter provided by the driver is before the current interval + * @history_begin: Historical reference point used to interpolate system time when + * the counter value provided by the driver is before the current interval * @xtstamp: Receives simultaneously captured system and device time * * Reads a timestamp from a device and correlates it to system time @@ -1502,14 +1504,12 @@ int get_device_system_crosststamp(int (*get_time_fn) struct system_time_snapshot *history_begin, struct system_device_crosststamp *xtstamp) { - struct system_counterval_t system_counterval = {}; + u64 syscnt_cycles, cycles, now, interval_start; struct timekeeper *tk = &tk_core.timekeeper; - u64 cycles, now, interval_start; - unsigned int clock_was_set_seq = 0; + unsigned int seq, clock_was_set_seq = 0; ktime_t base_real, base_raw; u64 nsec_real, nsec_raw; u8 cs_was_changed_seq; - unsigned int seq; bool do_interp; int ret; @@ -1519,19 +1519,20 @@ int get_device_system_crosststamp(int (*get_time_fn) * Try to synchronously capture device time and a system * counter value calling back into the device driver */ - ret = get_time_fn(&xtstamp->device, &system_counterval, ctx); + ret = get_time_fn(&xtstamp->device, &xtstamp->sys_counter, ctx); if (ret) return ret; /* * Verify that the clocksource ID associated with the captured * system counter value is the same as for the currently - * installed timekeeper clocksource + * installed timekeeper clocksource and convert to it. */ - if (system_counterval.cs_id == CSID_GENERIC || - !convert_base_to_cs(&system_counterval)) + if (xtstamp->sys_counter.cs_id == CSID_GENERIC || + !convert_base_to_cs(&xtstamp->sys_counter)) return -ENODEV; - cycles = system_counterval.cycles; + + cycles = syscnt_cycles = xtstamp->sys_counter.cycles; /* * Check whether the system counter value provided by the @@ -1573,24 +1574,19 @@ int get_device_system_crosststamp(int (*get_time_fn) * clocksource change */ if (!history_begin || - !timestamp_in_interval(history_begin->cycles, - cycles, system_counterval.cycles) || + !timestamp_in_interval(history_begin->cycles, cycles, syscnt_cycles) || history_begin->cs_was_changed_seq != cs_was_changed_seq) return -EINVAL; - partial_history_cycles = cycles - system_counterval.cycles; - total_history_cycles = cycles - history_begin->cycles; - discontinuity = - history_begin->clock_was_set_seq != clock_was_set_seq; - ret = adjust_historical_crosststamp(history_begin, - partial_history_cycles, - total_history_cycles, - discontinuity, xtstamp); - if (ret) - return ret; + partial_history_cycles = cycles - syscnt_cycles; + total_history_cycles = cycles - history_begin->cycles; + discontinuity = history_begin->clock_was_set_seq != clock_was_set_seq; + + ret = adjust_historical_crosststamp(history_begin, partial_history_cycles, + total_history_cycles, discontinuity, xtstamp); } - return 0; + return ret; } EXPORT_SYMBOL_GPL(get_device_system_crosststamp); From e3b8d03faa4d266d19ff7a7534e7bf810ff681cf Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 22:00:32 +0200 Subject: [PATCH 11/28] timekeeping: Add CLOCK ID to system_device_crosststamp The normal capture for system/device cross timestamps is CLOCK_REALTIME, but that's meaningless for AUX clocks. Add a clock_id field to struct system_device_crosststamp and initialize it with CLOCK_REALTIME at the two places which prepare for cross timestamps. After the related code has been cleaned up, the core code will honor the clock_id field when calculating the system time from the system counter snapshot. No functional change. Signed-off-by: Thomas Gleixner Tested-by: David Woodhouse Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20260529195557.482153523@kernel.org --- drivers/ptp/ptp_chardev.c | 2 +- include/linux/timekeeping.h | 2 ++ sound/hda/common/controller.c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c index c61cf9edac48..da964c3778fb 100644 --- a/drivers/ptp/ptp_chardev.c +++ b/drivers/ptp/ptp_chardev.c @@ -317,8 +317,8 @@ typedef int (*ptp_crosststamp_fn)(struct ptp_clock_info *, static long ptp_sys_offset_precise(struct ptp_clock *ptp, void __user *arg, ptp_crosststamp_fn crosststamp_fn) { + struct system_device_crosststamp xtstamp = { .clock_id = CLOCK_REALTIME }; struct ptp_sys_offset_precise precise_offset; - struct system_device_crosststamp xtstamp; struct timespec64 ts; int err; diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index 3867db65f391..fff6d9e319c4 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -315,12 +315,14 @@ struct system_counterval_t { /** * struct system_device_crosststamp - system/device cross-timestamp * (synchronized capture) + * @clock_id: System time Clock ID to capture * @device: Device time * @sys_counter: Clocksource counter value simultaneous with device time * @sys_realtime: Realtime simultaneous with device time * @sys_monoraw: Monotonic raw simultaneous with device time */ struct system_device_crosststamp { + clockid_t clock_id; ktime_t device; struct system_counterval_t sys_counter; ktime_t sys_realtime; diff --git a/sound/hda/common/controller.c b/sound/hda/common/controller.c index 5934e5cdfdfd..a880dcd8f2e8 100644 --- a/sound/hda/common/controller.c +++ b/sound/hda/common/controller.c @@ -489,9 +489,9 @@ static int azx_get_time_info(struct snd_pcm_substream *substream, struct snd_pcm_audio_tstamp_config *audio_tstamp_config, struct snd_pcm_audio_tstamp_report *audio_tstamp_report) { + struct system_device_crosststamp xtstamp = { .clock_id = CLOCK_REALTIME }; struct azx_dev *azx_dev = get_azx_dev(substream); struct snd_pcm_runtime *runtime = substream->runtime; - struct system_device_crosststamp xtstamp; int ret; u64 nsec; From 570cf418bfc9d7d0ab662794dd2e2f4eeb79dfe5 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 22:00:36 +0200 Subject: [PATCH 12/28] wifi: iwlwifi: Adopt PTP cross timestamps to core changes iwlwifi only supports CLOCK_REALTIME timestamps and provides an incomplete result without system counter values etc. It also zeros struct system_device_crosststamp, which is already zeroed in the core and initialized with the clock ID. Remove the zeroing and reject any request for a clock ID other than REALTIME. Signed-off-by: Thomas Gleixner Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20260529195557.535447186@kernel.org --- drivers/net/wireless/intel/iwlwifi/mld/ptp.c | 3 ++- drivers/net/wireless/intel/iwlwifi/mvm/ptp.c | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/ptp.c b/drivers/net/wireless/intel/iwlwifi/mld/ptp.c index c65f4b56a327..921b93c9e836 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/ptp.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/ptp.c @@ -250,7 +250,8 @@ iwl_mld_phc_get_crosstimestamp(struct ptp_clock_info *ptp, /* System (wall) time */ ktime_t sys_time; - memset(xtstamp, 0, sizeof(struct system_device_crosststamp)); + if (xtstamp->clock_id != CLOCK_REALTIME) + return -ENOTSUPP; ret = iwl_mld_get_crosstimestamp_fw(mld, &gp2, &sys_time); if (ret) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c index f7b620136c85..4c40a5218436 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c @@ -160,13 +160,14 @@ iwl_mvm_phc_get_crosstimestamp(struct ptp_clock_info *ptp, /* System (wall) time */ ktime_t sys_time; - memset(xtstamp, 0, sizeof(struct system_device_crosststamp)); - if (!mvm->ptp_data.ptp_clock) { IWL_ERR(mvm, "No PHC clock registered\n"); return -ENODEV; } + if (xtstamp->clock_id != CLOCK_REALTIME) + return -ENOTSUPP; + mutex_lock(&mvm->mutex); if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SYNCED_TIME)) { ret = iwl_mvm_get_crosstimestamp_fw(mvm, &gp2, &sys_time); From 23bc637750e4142ef9e86a06872fdf32e74a9050 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 22:00:40 +0200 Subject: [PATCH 13/28] ice/ptp: Use provided clock ID for history snapshot The PTP core indicates in system_device_crosststamp::clock_id the clock ID for which then system time stamp should be taken. That allows to utilize hardware timestamps with e.g. AUX clocks. Save the provided clock ID and use it in ice_capture_crosststamp() for taking the history snapshot. No functional change. Signed-off-by: Thomas Gleixner Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20260529195557.587226681@kernel.org --- drivers/net/ethernet/intel/ice/ice_ptp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index 36df742c326c..f9e4ec6f7ebb 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -2065,11 +2065,13 @@ static const struct ice_crosststamp_cfg ice_crosststamp_cfg_e830 = { /** * struct ice_crosststamp_ctx - Device cross timestamp context * @snapshot: snapshot of system clocks for historic interpolation + * @snapshot_clock_id: System clock ID for @snapshot * @pf: pointer to the PF private structure * @cfg: pointer to hardware configuration for cross timestamp */ struct ice_crosststamp_ctx { struct system_time_snapshot snapshot; + clockid_t snapshot_clock_id; struct ice_pf *pf; const struct ice_crosststamp_cfg *cfg; }; @@ -2115,7 +2117,7 @@ static int ice_capture_crosststamp(ktime_t *device, } /* Snapshot system time for historic interpolation */ - ktime_get_snapshot(&ctx->snapshot); + ktime_get_snapshot_id(ctx->snapshot_clock_id, &ctx->snapshot); /* Program cmd to master timer */ ice_ptp_src_cmd(hw, ICE_PTP_READ_TIME); @@ -2176,6 +2178,7 @@ static int ice_ptp_getcrosststamp(struct ptp_clock_info *info, { struct ice_pf *pf = ptp_info_to_pf(info); struct ice_crosststamp_ctx ctx = { + .snapshot_clock_id = cts->clock_id, .pf = pf, }; From af1816babcd9eff5c40eaf0de149b469debdfdb4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 22:00:44 +0200 Subject: [PATCH 14/28] igc: Use provided clock ID for history snapshot The PTP core indicates in system_device_crosststamp::clock_id the clock ID for which the system time stamp should be taken. That allows to utilize hardware timestamps with e.g. AUX clocks. Save the provided clock ID and use it in igc_phc_get_syncdevicetime() for taking the history snapshot. No functional change. Signed-off-by: Thomas Gleixner Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20260529195557.637381831@kernel.org --- drivers/net/ethernet/intel/igc/igc.h | 1 + drivers/net/ethernet/intel/igc/igc_ptp.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 17236813965d..46d625b15f44 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -326,6 +326,7 @@ struct igc_adapter { struct timespec64 prev_ptp_time; /* Pre-reset PTP clock */ ktime_t ptp_reset_start; /* Reset time in clock mono */ struct system_time_snapshot snapshot; + clockid_t snapshot_clock_id; struct mutex ptm_lock; /* Only allow one PTM transaction at a time */ char fw_version[32]; diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c index 3d6b2264164a..b40aba9ab685 100644 --- a/drivers/net/ethernet/intel/igc/igc_ptp.c +++ b/drivers/net/ethernet/intel/igc/igc_ptp.c @@ -1049,7 +1049,7 @@ static int igc_phc_get_syncdevicetime(ktime_t *device, */ do { /* Get a snapshot of system clocks to use as historic value. */ - ktime_get_snapshot(&adapter->snapshot); + ktime_get_snapshot_id(adapter->snapshot_clock_id, &adapter->snapshot); igc_ptm_trigger(hw); @@ -1103,6 +1103,8 @@ static int igc_ptp_getcrosststamp(struct ptp_clock_info *ptp, /* This blocks until any in progress PTM transactions complete */ mutex_lock(&adapter->ptm_lock); + adapter->snapshot_clock_id = cts->clock_id; + ret = get_device_system_crosststamp(igc_phc_get_syncdevicetime, adapter, &adapter->snapshot, cts); mutex_unlock(&adapter->ptm_lock); From 8216433ebe7e1b904c9e0f3176d7f99cbdb78bcd Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 22:00:48 +0200 Subject: [PATCH 15/28] net/mlx5: Use provided clock ID for history snapshot The PTP core indicates in system_device_crosststamp::clock_id the clock ID for which the system time stamp should be taken. That allows to utilize hardware timestamps with e.g. AUX clocks. Use ktime_get_snapshot_id() and hand the provided clock ID in. No functional change. Signed-off-by: Thomas Gleixner Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20260529195557.689836531@kernel.org --- drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c index d785f1b4f2e1..5df786133e4b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c @@ -340,7 +340,7 @@ static int mlx5_ptp_getcrosststamp(struct ptp_clock_info *ptp, goto unlock; } - ktime_get_snapshot(&history_begin); + ktime_get_snapshot_id(cts->clock_id, &history_begin); err = get_device_system_crosststamp(mlx5_mtctr_syncdevicetime, mdev, &history_begin, cts); @@ -366,7 +366,7 @@ static int mlx5_ptp_getcrosscycles(struct ptp_clock_info *ptp, goto unlock; } - ktime_get_snapshot(&history_begin); + ktime_get_snapshot_id(cts->clock_id, &history_begin); err = get_device_system_crosststamp(mlx5_mtctr_syncdevicecyclestime, mdev, &history_begin, cts); From 786493096848006020d7b8e57a53742a64fe5d4d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 22:00:52 +0200 Subject: [PATCH 16/28] virtio_rtc: Use provided clock ID for history snapshot The PTP core indicates in system_device_crosststamp::clock_id the clock ID for which the system time stamp should be taken. That allows to utilize hardware timestamps with e.g. AUX clocks. Use ktime_get_snapshot_id() and hand the provided clock ID in. No functional change. Signed-off-by: Thomas Gleixner Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Jacob Keller Acked-by: Michael S. Tsirkin Link: https://patch.msgid.link/20260529195557.744271454@kernel.org --- drivers/virtio/virtio_rtc_ptp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/virtio/virtio_rtc_ptp.c b/drivers/virtio/virtio_rtc_ptp.c index f84599950cd4..ff8d834493dc 100644 --- a/drivers/virtio/virtio_rtc_ptp.c +++ b/drivers/virtio/virtio_rtc_ptp.c @@ -139,7 +139,7 @@ static int viortc_ptp_getcrosststamp(struct ptp_clock_info *ptp, if (ret) return ret; - ktime_get_snapshot(&history_begin); + ktime_get_snapshot_id(xtstamp->clock_id, &history_begin); if (history_begin.cs_id != cs_id) return -EOPNOTSUPP; From b21d442c9aebe5ed95303883d3365e430e134cf1 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 22:00:56 +0200 Subject: [PATCH 17/28] timekeeping: Remove ktime_get_snapshot() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All users have been converted to ktime_get_snapshot_id(). Signed-off-by: Thomas Gleixner Tested-by: David Woodhouse Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Thomas Weißschuh Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20260529195557.795510496@kernel.org --- include/linux/timekeeping.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index fff6d9e319c4..2d9860ecb285 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -350,11 +350,6 @@ extern int get_device_system_crosststamp( */ extern void ktime_get_snapshot_id(clockid_t clock_id, struct system_time_snapshot *systime_snapshot); -static inline void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot) -{ - ktime_get_snapshot_id(CLOCK_REALTIME, systime_snapshot); -} - /* * Persistent clock related interfaces */ From 09fb74f77e02489d1d8c555d44bab99d4905127c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 22:01:00 +0200 Subject: [PATCH 18/28] timekeeping: Prepare for cross timestamps on arbitrary clock IDs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PTP device system crosstime stamps support only CLOCK_REALTIME, which is meaningless for AUX clocks. The PTP core hands in the clock ID already, so prepare the core code to honor it. - Add a new sys_systime field to struct system_device_crosststamp which aliases the sys_realtime field. Once all users are converted sys_realtime can be removed. - Prepare get_device_system_crosststamp() and the related code for it by switching to sys_systime and providing the initial changes to utilize different time keepers. No functional change intended. Signed-off-by: Thomas Gleixner Tested-by: David Woodhouse Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Thomas Weißschuh Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20260529195557.846634842@kernel.org --- include/linux/timekeeping.h | 7 ++++- kernel/time/timekeeping.c | 60 +++++++++++++++++++++---------------- 2 files changed, 41 insertions(+), 26 deletions(-) diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index 2d9860ecb285..017599d04eb4 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -319,13 +319,18 @@ struct system_counterval_t { * @device: Device time * @sys_counter: Clocksource counter value simultaneous with device time * @sys_realtime: Realtime simultaneous with device time + * @sys_systime: System time for @clock_id * @sys_monoraw: Monotonic raw simultaneous with device time */ struct system_device_crosststamp { clockid_t clock_id; ktime_t device; struct system_counterval_t sys_counter; - ktime_t sys_realtime; + union { + /* realtime goes away once all users are converted */ + ktime_t sys_realtime; + ktime_t sys_systime; + }; ktime_t sys_monoraw; }; diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 372179ff27a3..dae61c9e31e6 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1312,7 +1312,7 @@ static int adjust_historical_crosststamp(struct system_time_snapshot *history, struct system_device_crosststamp *ts) { struct timekeeper *tk = &tk_core.timekeeper; - u64 corr_raw, corr_real; + u64 corr_raw, corr_sys; bool interp_forward; int ret; @@ -1329,8 +1329,7 @@ static int adjust_historical_crosststamp(struct system_time_snapshot *history, * Scale the monotonic raw time delta by: * partial_history_cycles / total_history_cycles */ - corr_raw = (u64)ktime_to_ns( - ktime_sub(ts->sys_monoraw, history->monoraw)); + corr_raw = (u64)ktime_to_ns(ktime_sub(ts->sys_monoraw, history->monoraw)); ret = scale64_check_overflow(partial_history_cycles, total_history_cycles, &corr_raw); if (ret) @@ -1338,30 +1337,29 @@ static int adjust_historical_crosststamp(struct system_time_snapshot *history, /* * If there is a discontinuity in the history, scale monotonic raw - * correction by: - * mult(real)/mult(raw) yielding the realtime correction - * Otherwise, calculate the realtime correction similar to monotonic - * raw calculation + * correction by: + * mult(sys)/mult(raw) yielding the system time correction + * + * Otherwise, calculate the system time correction similar to monotonic + * raw calculation */ if (discontinuity) { - corr_real = mul_u64_u32_div - (corr_raw, tk->tkr_mono.mult, tk->tkr_raw.mult); + corr_sys = mul_u64_u32_div(corr_raw, tk->tkr_mono.mult, tk->tkr_raw.mult); } else { - corr_real = (u64)ktime_to_ns( - ktime_sub(ts->sys_realtime, history->systime)); - ret = scale64_check_overflow(partial_history_cycles, - total_history_cycles, &corr_real); + corr_sys = (u64)ktime_to_ns(ktime_sub(ts->sys_systime, history->systime)); + ret = scale64_check_overflow(partial_history_cycles, total_history_cycles, + &corr_sys); if (ret) return ret; } - /* Fixup monotonic raw and real time time values */ + /* Fixup monotonic raw and system time time values */ if (interp_forward) { ts->sys_monoraw = ktime_add_ns(history->monoraw, corr_raw); - ts->sys_realtime = ktime_add_ns(history->systime, corr_real); + ts->sys_systime = ktime_add_ns(history->systime, corr_sys); } else { ts->sys_monoraw = ktime_sub_ns(ts->sys_monoraw, corr_raw); - ts->sys_realtime = ktime_sub_ns(ts->sys_realtime, corr_real); + ts->sys_systime = ktime_sub_ns(ts->sys_systime, corr_sys); } return 0; @@ -1505,16 +1503,29 @@ int get_device_system_crosststamp(int (*get_time_fn) struct system_device_crosststamp *xtstamp) { u64 syscnt_cycles, cycles, now, interval_start; - struct timekeeper *tk = &tk_core.timekeeper; unsigned int seq, clock_was_set_seq = 0; - ktime_t base_real, base_raw; - u64 nsec_real, nsec_raw; + ktime_t base_sys, base_raw, *offs; + u64 nsec_sys, nsec_raw; u8 cs_was_changed_seq; bool do_interp; + struct timekeeper *tk; + struct tk_data *tkd; int ret; + switch (xtstamp->clock_id) { + case CLOCK_REALTIME: + tkd = &tk_core; + offs = &tk_core.timekeeper.offs_real; + break; + default: + WARN_ON_ONCE(1); + return -ENODEV; + } + + tk = &tkd->timekeeper; + do { - seq = read_seqcount_begin(&tk_core.seq); + seq = read_seqcount_begin(&tkd->seq); /* * Try to synchronously capture device time and a system * counter value calling back into the device driver @@ -1549,15 +1560,14 @@ int get_device_system_crosststamp(int (*get_time_fn) do_interp = false; } - base_real = ktime_add(tk->tkr_mono.base, - tk_core.timekeeper.offs_real); + base_sys = ktime_add(tk->tkr_mono.base, *offs); base_raw = tk->tkr_raw.base; - nsec_real = timekeeping_cycles_to_ns(&tk->tkr_mono, cycles); + nsec_sys = timekeeping_cycles_to_ns(&tk->tkr_mono, cycles); nsec_raw = timekeeping_cycles_to_ns(&tk->tkr_raw, cycles); - } while (read_seqcount_retry(&tk_core.seq, seq)); + } while (read_seqcount_retry(&tkd->seq, seq)); - xtstamp->sys_realtime = ktime_add_ns(base_real, nsec_real); + xtstamp->sys_systime = ktime_add_ns(base_sys, nsec_sys); xtstamp->sys_monoraw = ktime_add_ns(base_raw, nsec_raw); /* From 12b497db7cbd2f07b7f182452bce6bb0e48e71dc Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 22:01:05 +0200 Subject: [PATCH 19/28] ptp: Use system_device_crosststamp::sys_systime .. to prepare for cross timestamps with variable clock IDs. No functional change. Signed-off-by: Thomas Gleixner Tested-by: David Woodhouse Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20260529195557.897808371@kernel.org --- drivers/ptp/ptp_chardev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c index da964c3778fb..f52bbb39cd8b 100644 --- a/drivers/ptp/ptp_chardev.c +++ b/drivers/ptp/ptp_chardev.c @@ -333,7 +333,7 @@ static long ptp_sys_offset_precise(struct ptp_clock *ptp, void __user *arg, ts = ktime_to_timespec64(xtstamp.device); precise_offset.device.sec = ts.tv_sec; precise_offset.device.nsec = ts.tv_nsec; - ts = ktime_to_timespec64(xtstamp.sys_realtime); + ts = ktime_to_timespec64(xtstamp.sys_systime); precise_offset.sys_realtime.sec = ts.tv_sec; precise_offset.sys_realtime.nsec = ts.tv_nsec; ts = ktime_to_timespec64(xtstamp.sys_monoraw); From 25af33c5c532b4429ffa803320aa626af7888f6c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 22:01:09 +0200 Subject: [PATCH 20/28] wifi: iwlwifi: Use system_device_crosststamp::sys_systime sys_systime is an alias for sys_realtime. The latter will be removed so switch the code over to the new naming scheme. No functional change. Signed-off-by: Thomas Gleixner Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20260529195557.946612509@kernel.org --- drivers/net/wireless/intel/iwlwifi/mld/ptp.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/ptp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/ptp.c b/drivers/net/wireless/intel/iwlwifi/mld/ptp.c index 921b93c9e836..f829156d42b3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/ptp.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/ptp.c @@ -271,7 +271,7 @@ iwl_mld_phc_get_crosstimestamp(struct ptp_clock_info *ptp, /* System monotonic raw time is not used */ xtstamp->device = ns_to_ktime(gp2_ns); - xtstamp->sys_realtime = sys_time; + xtstamp->sys_systime = sys_time; return ret; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c index 4c40a5218436..bcd6f7cead2a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c @@ -185,7 +185,7 @@ iwl_mvm_phc_get_crosstimestamp(struct ptp_clock_info *ptp, /* System monotonic raw time is not used */ xtstamp->device = (ktime_t)gp2_ns; - xtstamp->sys_realtime = sys_time; + xtstamp->sys_systime = sys_time; out: mutex_unlock(&mvm->mutex); From 13029a25eaa92457d8363a94c48592991770cc67 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 22:01:13 +0200 Subject: [PATCH 21/28] ALSA: hda/common: Use system_device_crosststamp::sys_systime sys_systime is an alias for sys_realtime. The latter will be removed so switch the code over to the new naming scheme. No functional change. Signed-off-by: Thomas Gleixner Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20260529195557.995298795@kernel.org --- sound/hda/common/controller.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/hda/common/controller.c b/sound/hda/common/controller.c index a880dcd8f2e8..77a67fb9eaf9 100644 --- a/sound/hda/common/controller.c +++ b/sound/hda/common/controller.c @@ -525,7 +525,7 @@ static int azx_get_time_info(struct snd_pcm_substream *substream, break; default: - *system_ts = ktime_to_timespec64(xtstamp.sys_realtime); + *system_ts = ktime_to_timespec64(xtstamp.sys_systime); break; } From 5ccaf1e569f04d8fd5f0167be728fdb48f448f81 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 22:01:17 +0200 Subject: [PATCH 22/28] timekeeping: Remove system_device_crosststamp::sys_realtime MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All users are converted to sys_systime. Signed-off-by: Thomas Gleixner Tested-by: David Woodhouse Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Thomas Weißschuh Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20260529195558.046694580@kernel.org --- include/linux/timekeeping.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index 017599d04eb4..7f03e1cefcf6 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -318,7 +318,6 @@ struct system_counterval_t { * @clock_id: System time Clock ID to capture * @device: Device time * @sys_counter: Clocksource counter value simultaneous with device time - * @sys_realtime: Realtime simultaneous with device time * @sys_systime: System time for @clock_id * @sys_monoraw: Monotonic raw simultaneous with device time */ @@ -326,11 +325,7 @@ struct system_device_crosststamp { clockid_t clock_id; ktime_t device; struct system_counterval_t sys_counter; - union { - /* realtime goes away once all users are converted */ - ktime_t sys_realtime; - ktime_t sys_systime; - }; + ktime_t sys_systime; ktime_t sys_monoraw; }; From 9aebde8af6fe247d92816c197badf7e236c8f037 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 22:01:21 +0200 Subject: [PATCH 23/28] timekeeping: Add support for AUX clock cross timestamping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that all prerequisites are in place add the final support for AUX clocks in get_device_system_crosststamp(), which enables the PTP layer to support hardware cross timestamps with a new IOTCL. Signed-off-by: Thomas Gleixner Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Thomas Weißschuh Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20260529195558.097464513@kernel.org --- kernel/time/timekeeping.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index dae61c9e31e6..65d870c2d40d 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1517,6 +1517,12 @@ int get_device_system_crosststamp(int (*get_time_fn) tkd = &tk_core; offs = &tk_core.timekeeper.offs_real; break; + case CLOCK_AUX ... CLOCK_AUX_LAST: + tkd = aux_get_tk_data(xtstamp->clock_id); + if (!tkd) + return -ENODEV; + offs = &tkd->timekeeper.offs_aux; + break; default: WARN_ON_ONCE(1); return -ENODEV; From a6d799608e6a61b48908bff955200d03c34c90ca Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 May 2026 22:01:25 +0200 Subject: [PATCH 24/28] ptp: Switch to ktime_get_snapshot_id() for pre/post timestamps To prepare for a new PTP IOCTL, which exposes the raw counter value along with the requested system time snapshot, switch the pre/post time stamp sampling over to use ktime_get_snapshot_id() and fix up all usage sites. No functional change intended. The ptp_vmclock conversion was simplified by David Woodhouse. Signed-off-by: Thomas Gleixner Tested-by: David Woodhouse Tested-by: Arthur Kiyanovski Reviewed-by: David Woodhouse Reviewed-by: Jacob Keller Acked-by: Vadim Fedorenko Link: https://patch.msgid.link/20260529195558.149589566@kernel.org --- drivers/net/dsa/sja1105/sja1105_main.c | 8 ++++---- drivers/ptp/ptp_chardev.c | 14 +++++++++----- drivers/ptp/ptp_ocp.c | 11 ++++------- drivers/ptp/ptp_vmclock.c | 23 +++++++---------------- include/linux/ptp_clock_kernel.h | 15 ++++++++------- 5 files changed, 32 insertions(+), 39 deletions(-) diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index c72c2bfdcffb..2697073dbf90 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -2310,10 +2310,10 @@ int sja1105_static_config_reload(struct sja1105_private *priv, goto out; } - t1 = timespec64_to_ns(&ptp_sts_before.pre_ts); - t2 = timespec64_to_ns(&ptp_sts_before.post_ts); - t3 = timespec64_to_ns(&ptp_sts_after.pre_ts); - t4 = timespec64_to_ns(&ptp_sts_after.post_ts); + t1 = ktime_to_ns(ptp_sts_before.pre_sts.systime); + t2 = ktime_to_ns(ptp_sts_before.post_sts.systime); + t3 = ktime_to_ns(ptp_sts_after.pre_sts.systime); + t4 = ktime_to_ns(ptp_sts_after.post_sts.systime); /* Mid point, corresponds to pre-reset PTPCLKVAL */ t12 = t1 + (t2 - t1) / 2; /* Mid point, corresponds to post-reset PTPCLKVAL, aka 0 */ diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c index f52bbb39cd8b..dc23cd708cfe 100644 --- a/drivers/ptp/ptp_chardev.c +++ b/drivers/ptp/ptp_chardev.c @@ -386,15 +386,19 @@ static long ptp_sys_offset_extended(struct ptp_clock *ptp, void __user *arg, return err; /* Filter out disabled or unavailable clocks */ - if (sts.pre_ts.tv_sec < 0 || sts.post_ts.tv_sec < 0) + if (!sts.pre_sts.valid || !sts.post_sts.valid) return -EINVAL; - extoff->ts[i][0].sec = sts.pre_ts.tv_sec; - extoff->ts[i][0].nsec = sts.pre_ts.tv_nsec; extoff->ts[i][1].sec = ts.tv_sec; extoff->ts[i][1].nsec = ts.tv_nsec; - extoff->ts[i][2].sec = sts.post_ts.tv_sec; - extoff->ts[i][2].nsec = sts.post_ts.tv_nsec; + + ts = ktime_to_timespec64(sts.pre_sts.systime); + extoff->ts[i][0].sec = ts.tv_sec; + extoff->ts[i][0].nsec = ts.tv_nsec; + + ts = ktime_to_timespec64(sts.post_sts.systime); + extoff->ts[i][2].sec = ts.tv_sec; + extoff->ts[i][2].nsec = ts.tv_nsec; } return copy_to_user(arg, extoff, sizeof(*extoff)) ? -EFAULT : 0; diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index beacc2ffb166..28b0302c6250 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -1491,11 +1491,8 @@ __ptp_ocp_gettime_locked(struct ptp_ocp *bp, struct timespec64 *ts, } ptp_read_system_postts(sts); - if (sts && bp->ts_window_adjust) { - s64 ns = timespec64_to_ns(&sts->post_ts); - - sts->post_ts = ns_to_timespec64(ns - bp->ts_window_adjust); - } + if (sts && bp->ts_window_adjust) + sts->post_sts.systime -= bp->ts_window_adjust; time_ns = ioread32(&bp->reg->time_ns); time_sec = ioread32(&bp->reg->time_sec); @@ -4595,8 +4592,8 @@ ptp_ocp_summary_show(struct seq_file *s, void *data) struct timespec64 sys_ts; s64 pre_ns, post_ns, ns; - pre_ns = timespec64_to_ns(&sts.pre_ts); - post_ns = timespec64_to_ns(&sts.post_ts); + pre_ns = ktime_to_ns(sts.pre_sts.systime); + post_ns = ktime_to_ns(sts.post_sts.systime); ns = (pre_ns + post_ns) / 2; ns += (s64)bp->utc_tai_offset * NSEC_PER_SEC; sys_ts = ns_to_timespec64(ns); diff --git a/drivers/ptp/ptp_vmclock.c b/drivers/ptp/ptp_vmclock.c index 0f12b54be740..d6a5a533164a 100644 --- a/drivers/ptp/ptp_vmclock.c +++ b/drivers/ptp/ptp_vmclock.c @@ -101,7 +101,6 @@ static int vmclock_get_crosststamp(struct vmclock_state *st, struct timespec64 *tspec) { ktime_t deadline = ktime_add(ktime_get(), VMCLOCK_MAX_WAIT); - struct system_time_snapshot systime_snapshot; uint64_t cycle, delta, seq, frac_sec; #ifdef CONFIG_X86 @@ -132,17 +131,15 @@ static int vmclock_get_crosststamp(struct vmclock_state *st, * will be derived from the *same* counter value. * * If the system isn't using the same counter, then the value - * from ktime_get_snapshot_id() will still be used as pre_ts, and - * ptp_read_system_postts() is called to populate postts after - * calling get_cycles(). - * - * The conversion to timespec64 happens further down, outside - * the seq_count loop. + * from ptp_read_system_prets() will still be used as pre_ts, + * and ptp_read_system_postts() is called to populate postts + * after calling get_cycles(). */ if (sts) { - ktime_get_snapshot_id(CLOCK_REALTIME, &systime_snapshot); - if (systime_snapshot.cs_id == st->cs_id) { - cycle = systime_snapshot.cycles; + ptp_read_system_prets(sts); + if (sts->pre_sts.cs_id == st->cs_id) { + cycle = sts->pre_sts.cycles; + sts->post_sts = sts->pre_sts; } else { cycle = get_cycles(); ptp_read_system_postts(sts); @@ -180,12 +177,6 @@ static int vmclock_get_crosststamp(struct vmclock_state *st, system_counter->cs_id = st->cs_id; } - if (sts) { - sts->pre_ts = ktime_to_timespec64(systime_snapshot.systime); - if (systime_snapshot.cs_id == st->cs_id) - sts->post_ts = sts->pre_ts; - } - return 0; } diff --git a/include/linux/ptp_clock_kernel.h b/include/linux/ptp_clock_kernel.h index 884364596dd3..36a27a910595 100644 --- a/include/linux/ptp_clock_kernel.h +++ b/include/linux/ptp_clock_kernel.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #define PTP_CLOCK_NAME_LEN 32 @@ -45,13 +46,13 @@ struct system_device_crosststamp; /** * struct ptp_system_timestamp - system time corresponding to a PHC timestamp - * @pre_ts: system timestamp before capturing PHC - * @post_ts: system timestamp after capturing PHC - * @clockid: clock-base used for capturing the system timestamps + * @pre_sts: system time snapshot before capturing PHC + * @post_sts: system time snapshot after capturing PHC + * @clockid: clock-base used for capturing the system timestamps */ struct ptp_system_timestamp { - struct timespec64 pre_ts; - struct timespec64 post_ts; + struct system_time_snapshot pre_sts; + struct system_time_snapshot post_sts; clockid_t clockid; }; @@ -510,13 +511,13 @@ static inline ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, static inline void ptp_read_system_prets(struct ptp_system_timestamp *sts) { if (sts) - ktime_get_clock_ts64(sts->clockid, &sts->pre_ts); + ktime_get_snapshot_id(sts->clockid, &sts->pre_sts); } static inline void ptp_read_system_postts(struct ptp_system_timestamp *sts) { if (sts) - ktime_get_clock_ts64(sts->clockid, &sts->post_ts); + ktime_get_snapshot_id(sts->clockid, &sts->post_sts); } #endif From ca1ec8bfac8c95d0fed9e3611ea21400d1f37262 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 29 May 2026 22:01:29 +0200 Subject: [PATCH 25/28] timekeeping: Add clocksource read_snapshot() method and hw_cycles to snapshot Add a read_snapshot() callback to struct clocksource which returns the derived clocksource value while also providing the underlying hardware counter reading and the related clocksource ID. This allows ktime_get_snapshot_id() to populate new hw_cycles and hw_csid fields in struct system_time_snapshot. For clocksources that are derived from an underlying counter (e.g., Hyper-V TSC page scales TSC to 10MHz, kvmclock scales TSC to 1GHz), this provides atomic access to both the derived value needed for timekeeping calculations, and the raw hardware counter needed by consumers like KVM's master clock and the vmclock PTP driver. [ tglx: Reworked it slightly ] Signed-off-by: David Woodhouse Signed-off-by: Thomas Gleixner Reviewed-by: Jacob Keller Assisted-by: Kiro:claude-opus-4.6-1m Link: https://patch.msgid.link/20260526230635.136914-1-dwmw2@infradead.org Link: https://patch.msgid.link/20260529195558.202568489@kernel.org --- include/linux/clocksource.h | 24 ++++++++++++++++++++++++ include/linux/timekeeping.h | 6 ++++++ kernel/time/timekeeping.c | 21 ++++++++++++++++++++- 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 7c38190b10bf..6d9ddf1587a2 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -31,6 +31,21 @@ struct module; #include +/** + * struct clocksource_hw_snapshot - Snapshot for the underlying hardware counter of derived + * clocksources like kvmclock or Hyper-V scaled TSC + * @hw_cycles: The hardware counter value + * @hw_csid: Clocksource ID of the hardware counter + * + * Such clocksources must implement the read_snapshot() callback and fill in the + * hardware counter value, the clocksource ID of the hardware counter and derive + * the actual clocksource cycles from @hw_cycles to provide an atomic snapshot + */ +struct clocksource_hw_snapshot { + u64 hw_cycles; + enum clocksource_ids hw_csid; +}; + /** * struct clocksource - hardware abstraction for a free running counter * Provides mostly state-free accessors to the underlying hardware. @@ -72,6 +87,14 @@ struct module; * @flags: Flags describing special properties * @base: Hardware abstraction for clock on which a clocksource * is based + * @read_snapshot: Extended @read() function for clocksources such as + * kvmclock or the Hyper-V scaled TSC where the actual + * clocksource value for timekeeping is calculated from an + * underlying hardware counter. Returns the timekeeping + * relevant cycle value and stores the raw value of the + * underlying counter from which it was calculated + * including the clocksource ID of that counter in the + * clocksource hardware snapshot. * @enable: Optional function to enable the clocksource * @disable: Optional function to disable the clocksource * @suspend: Optional suspend function for the clocksource @@ -113,6 +136,7 @@ struct clocksource { unsigned long flags; struct clocksource_base *base; + u64 (*read_snapshot)(struct clocksource *cs, struct clocksource_hw_snapshot *chs); int (*enable)(struct clocksource *cs); void (*disable)(struct clocksource *cs); void (*suspend)(struct clocksource *cs); diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index 7f03e1cefcf6..984a866d293b 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -279,18 +279,24 @@ static inline bool ktime_get_aux_ts64(clockid_t id, struct timespec64 *kt) { ret * struct system_time_snapshot - Simultaneous time capture of CLOCK_MONOTONIC_RAW, * a selected CLOCK_* and the clocksource counter value * @cycles: Clocksource counter value to produce the system times + * @hw_cycles: For derived clocksources, the hardware counter value from + * which @cycles was derived * @systime: The system time of the selected CLOCK ID * @monoraw: Monotonic raw system time * @cs_id: Clocksource ID + * @hw_csid: Clocksource ID of the underlying hardware counter for derived + * clocksources which implement the read_snapshot() callback. * @clock_was_set_seq: The sequence number of clock-was-set events * @cs_was_changed_seq: The sequence number of clocksource change events * @valid: True if the snapshot is valid */ struct system_time_snapshot { u64 cycles; + u64 hw_cycles; ktime_t systime; ktime_t monoraw; enum clocksource_ids cs_id; + enum clocksource_ids hw_csid; unsigned int clock_was_set_seq; u8 cs_was_changed_seq; u8 valid; diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 65d870c2d40d..0d5b67f609bb 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -320,6 +320,7 @@ static __always_inline u64 tk_clock_read(const struct tk_read_base *tkr) return clock->read(clock); } + static inline void clocksource_disable_inline_read(void) { } static inline void clocksource_enable_inline_read(void) { } #endif @@ -1187,6 +1188,18 @@ noinstr time64_t __ktime_get_real_seconds(void) return tk->xtime_sec; } +static inline u64 tk_clock_read_snapshot(const struct tk_read_base *tkr, + struct clocksource_hw_snapshot *chs) +{ + struct clocksource *clock = READ_ONCE(tkr->clock); + + if (unlikely(clock->read_snapshot)) + return clock->read_snapshot(clock, chs); + + return clock->read(clock); +} + + /** * ktime_get_snapshot_id - Simultaneously snapshot a given clock ID with * CLOCK_MONOTONIC_RAW and the underlying @@ -1237,14 +1250,20 @@ void ktime_get_snapshot_id(clockid_t clock_id, struct system_time_snapshot *syst tk = &tkd->timekeeper; do { + struct clocksource_hw_snapshot chs = { }; + seq = read_seqcount_begin(&tkd->seq); /* Aux clocks can be invalid */ if (!tk->clock_valid) return; - now = tk_clock_read(&tk->tkr_mono); + now = tk_clock_read_snapshot(&tk->tkr_mono, &chs); systime_snapshot->cs_id = tk->tkr_mono.clock->id; + + systime_snapshot->hw_cycles = chs.hw_cycles; + systime_snapshot->hw_csid = chs.hw_csid; + systime_snapshot->cs_was_changed_seq = tk->cs_was_changed_seq; systime_snapshot->clock_was_set_seq = tk->clock_was_set_seq; From c51100f9e26857f2b2376d5cd657a15f52b9e05c Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 4 Jun 2026 10:35:16 +0100 Subject: [PATCH 26/28] clocksource/hyperv: Implement read_snapshot() for TSC page clocksource Implement the read_snapshot() callback for the Hyper-V TSC page clock- source. This returns the derived 10MHz reference time (for timekeeping) while also providing the raw TSC value that was used to compute it. When the TSC page is valid, hv_read_tsc_page_tsc() atomically captures both values from a single RDTSC inside the sequence-counter protected read. When the TSC page is invalid (sequence == 0), the hw_csid and hw_cycles are set to zero indicating no value is available. This enables ktime_get_snapshot_id() to provide the raw TSC to consumers like KVM's master clock when running nested guests under Hyper-V. Signed-off-by: David Woodhouse Signed-off-by: Thomas Gleixner Assisted-by: Kiro:claude-opus-4.6-1m Reviewed-by: Michael Kelley Link: https://patch.msgid.link/20260604095755.64849-2-dwmw2@infradead.org --- drivers/clocksource/hyperv_timer.c | 37 ++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c index e9f5034a1bc8..df567795d175 100644 --- a/drivers/clocksource/hyperv_timer.c +++ b/drivers/clocksource/hyperv_timer.c @@ -444,6 +444,22 @@ static u64 notrace read_hv_clock_tsc_cs(struct clocksource *arg) return read_hv_clock_tsc(); } +static u64 notrace read_hv_clock_tsc_cs_snapshot(struct clocksource *arg, + struct clocksource_hw_snapshot *chs) +{ + u64 time; + + if (hv_read_tsc_page_tsc(tsc_page, &chs->hw_cycles, &time)) { + chs->hw_csid = CSID_X86_TSC; + } else { + chs->hw_cycles = 0; + chs->hw_csid = CSID_GENERIC; + time = read_hv_clock_msr(); + } + + return time; +} + static u64 noinstr read_hv_sched_clock_tsc(void) { return (read_hv_clock_tsc() - hv_sched_clock_offset) * @@ -492,18 +508,19 @@ static int hv_cs_enable(struct clocksource *cs) #endif static struct clocksource hyperv_cs_tsc = { - .name = "hyperv_clocksource_tsc_page", - .rating = 500, - .read = read_hv_clock_tsc_cs, - .mask = CLOCKSOURCE_MASK(64), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, - .suspend= suspend_hv_clock_tsc, - .resume = resume_hv_clock_tsc, + .name = "hyperv_clocksource_tsc_page", + .rating = 500, + .read = read_hv_clock_tsc_cs, + .read_snapshot = read_hv_clock_tsc_cs_snapshot, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .suspend = suspend_hv_clock_tsc, + .resume = resume_hv_clock_tsc, #ifdef HAVE_VDSO_CLOCKMODE_HVCLOCK - .enable = hv_cs_enable, - .vdso_clock_mode = VDSO_CLOCKMODE_HVCLOCK, + .enable = hv_cs_enable, + .vdso_clock_mode = VDSO_CLOCKMODE_HVCLOCK, #else - .vdso_clock_mode = VDSO_CLOCKMODE_NONE, + .vdso_clock_mode = VDSO_CLOCKMODE_NONE, #endif }; From 19fa3e50644d2d47fca713b0df640f67dcd26634 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 4 Jun 2026 10:35:17 +0100 Subject: [PATCH 27/28] x86/kvmclock: Implement read_snapshot() for kvmclock clocksource Implement the read_snapshot() callback for the kvmclock clocksource. This returns the kvmclock nanosecond value (for timekeeping) while also providing the raw TSC value that was used to compute it. The TSC is read inside the pvclock seqlock-protected region, ensuring the raw TSC and derived kvmclock value are atomically paired. This enables ktime_get_snapshot_id() to provide the raw TSC to consumers like the vmclock PTP driver, which currently has to do a separate call to get_cycles() to obtain a value at *approximately* the same time, to feed through the vmclock calculation. Signed-off-by: David Woodhouse Signed-off-by: Thomas Gleixner Assisted-by: Kiro:claude-opus-4.6-1m Link: https://patch.msgid.link/20260604095755.64849-3-dwmw2@infradead.org --- arch/x86/kernel/kvmclock.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c index b5991d53fc0e..cb3d0ca1fa22 100644 --- a/arch/x86/kernel/kvmclock.c +++ b/arch/x86/kernel/kvmclock.c @@ -87,6 +87,27 @@ static u64 kvm_clock_get_cycles(struct clocksource *cs) return kvm_clock_read(); } +static u64 kvm_clock_get_cycles_snapshot(struct clocksource *cs, + struct clocksource_hw_snapshot *chs) +{ + struct pvclock_vcpu_time_info *src; + unsigned version; + u64 ret, tsc; + + preempt_disable_notrace(); + src = this_cpu_pvti(); + do { + version = pvclock_read_begin(src); + tsc = rdtsc_ordered(); + ret = __pvclock_read_cycles(src, tsc); + } while (pvclock_read_retry(src, version)); + preempt_enable_notrace(); + + chs->hw_cycles = tsc; + chs->hw_csid = CSID_X86_TSC; + return ret; +} + static noinstr u64 kvm_sched_clock_read(void) { return pvclock_clocksource_read_nowd(this_cpu_pvti()) - kvm_sched_clock_offset; @@ -156,13 +177,14 @@ static int kvm_cs_enable(struct clocksource *cs) } static struct clocksource kvm_clock = { - .name = "kvm-clock", - .read = kvm_clock_get_cycles, - .rating = 400, - .mask = CLOCKSOURCE_MASK(64), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, - .id = CSID_X86_KVM_CLK, - .enable = kvm_cs_enable, + .name = "kvm-clock", + .read = kvm_clock_get_cycles, + .read_snapshot = kvm_clock_get_cycles_snapshot, + .rating = 400, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .id = CSID_X86_KVM_CLK, + .enable = kvm_cs_enable, }; static void kvm_register_clock(char *txt) From bc484a5096732cd858771cccd3164ec985bdc03d Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 4 Jun 2026 10:35:18 +0100 Subject: [PATCH 28/28] ptp: vmclock: Use hw_cycles from snapshot for precise TSC pairing When the system clocksource is kvmclock or Hyper-V (not the TSC directly), vmclock_get_crosststamp() falls through to a separate get_cycles() call, losing the atomic pairing between the system time snapshot and the TSC reading. Now that ktime_get_snapshot_id() populates hw_cycles with the underlying TSC value for derived clocksources, use it when available. This gives a perfect (system_time, tsc) pairing for the device time calculation. The SUPPORT_KVMCLOCK wrapper is still needed to convert the TSC into kvmclock nanoseconds for system_counter->cycles, because otherwise get_device_system_crosststamp() can't interpret the result against the system clock. Signed-off-by: David Woodhouse Signed-off-by: Thomas Gleixner Assisted-by: Kiro:claude-opus-4.6-1m Link: https://patch.msgid.link/20260604095755.64849-4-dwmw2@infradead.org --- drivers/ptp/ptp_vmclock.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/ptp/ptp_vmclock.c b/drivers/ptp/ptp_vmclock.c index d6a5a533164a..eebdcd5ebc08 100644 --- a/drivers/ptp/ptp_vmclock.c +++ b/drivers/ptp/ptp_vmclock.c @@ -140,6 +140,10 @@ static int vmclock_get_crosststamp(struct vmclock_state *st, if (sts->pre_sts.cs_id == st->cs_id) { cycle = sts->pre_sts.cycles; sts->post_sts = sts->pre_sts; + } else if (sts->pre_sts.hw_csid == st->cs_id && + sts->pre_sts.hw_cycles) { + cycle = sts->pre_sts.hw_cycles; + sts->post_sts = sts->pre_sts; } else { cycle = get_cycles(); ptp_read_system_postts(sts);