From: David Woodhouse <[email protected]>

Implement the read_snapshot() callback for the Hyper-V TSC page
clocksource. 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 <[email protected]>
Assisted-by: Kiro:claude-opus-4.6-1m
Reviewed-by: Michael Kelley <[email protected]>
---
 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
 };
 
-- 
2.54.0


Reply via email to