From: David Woodhouse <[email protected]>

Implement the read_raw() 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), raw is
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 on Hyper-V.

Signed-off-by: David Woodhouse <[email protected]>
Assisted-by: Kiro:claude-opus-4.6-1m
---
 drivers/clocksource/hyperv_timer.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/clocksource/hyperv_timer.c 
b/drivers/clocksource/hyperv_timer.c
index e9f5034a1bc8..c5ae01fdbd8e 100644
--- a/drivers/clocksource/hyperv_timer.c
+++ b/drivers/clocksource/hyperv_timer.c
@@ -444,6 +444,18 @@ static u64 notrace read_hv_clock_tsc_cs(struct clocksource 
*arg)
        return read_hv_clock_tsc();
 }
 
+static u64 notrace read_hv_clock_tsc_cs_raw(struct clocksource *arg, u64 *raw)
+{
+       u64 time;
+
+       if (!hv_read_tsc_page_tsc(tsc_page, raw, &time)) {
+               time = read_hv_clock_msr();
+               *raw = 0;
+       }
+
+       return time;
+}
+
 static u64 noinstr read_hv_sched_clock_tsc(void)
 {
        return (read_hv_clock_tsc() - hv_sched_clock_offset) *
@@ -495,6 +507,8 @@ static struct clocksource hyperv_cs_tsc = {
        .name   = "hyperv_clocksource_tsc_page",
        .rating = 500,
        .read   = read_hv_clock_tsc_cs,
+       .read_raw = read_hv_clock_tsc_cs_raw,
+       .raw_csid = CSID_X86_TSC,
        .mask   = CLOCKSOURCE_MASK(64),
        .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
        .suspend= suspend_hv_clock_tsc,
-- 
2.54.0


Reply via email to