]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
clocksource/hyperv: Implement read_snapshot() for TSC page clocksource
authorDavid Woodhouse <dwmw@amazon.co.uk>
Thu, 4 Jun 2026 09:35:16 +0000 (10:35 +0100)
committerThomas Gleixner <tglx@kernel.org>
Fri, 5 Jun 2026 12:25:03 +0000 (14:25 +0200)
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 <dwmw@amazon.co.uk>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Assisted-by: Kiro:claude-opus-4.6-1m
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Link: https://patch.msgid.link/20260604095755.64849-2-dwmw2@infradead.org
drivers/clocksource/hyperv_timer.c

index e9f5034a1bc899d86d50b53509b2f2d06872a37e..df567795d1751a1bd5c402f19cc7cda1ec91e23b 100644 (file)
@@ -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
 };