This is needed for hibernation, e.g. when we resume the old kernel, we need to disable the "current" kernel's TSC page and then resume the old kernel's. Signed-off-by: Dexuan Cui <decui@xxxxxxxxxxxxx> Reviewed-by: Michael Kelley <mikelley@xxxxxxxxxxxxx> --- drivers/clocksource/hyperv_timer.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c index 726a65e..07f4747 100644 --- a/drivers/clocksource/hyperv_timer.c +++ b/drivers/clocksource/hyperv_timer.c @@ -237,12 +237,37 @@ static u64 read_hv_sched_clock_tsc(void) return read_hv_clock_tsc(NULL) - hv_sched_clock_offset; } +static void suspend_hv_clock_tsc(struct clocksource *arg) +{ + u64 tsc_msr; + + /* Disable the TSC page */ + hv_get_reference_tsc(tsc_msr); + tsc_msr &= ~BIT_ULL(0); + hv_set_reference_tsc(tsc_msr); +} + + +static void resume_hv_clock_tsc(struct clocksource *arg) +{ + phys_addr_t phys_addr = virt_to_phys(&tsc_pg); + u64 tsc_msr; + + /* Re-enable the TSC page */ + hv_get_reference_tsc(tsc_msr); + tsc_msr &= GENMASK_ULL(11, 0); + tsc_msr |= BIT_ULL(0) | (u64)phys_addr; + hv_set_reference_tsc(tsc_msr); +} + static struct clocksource hyperv_cs_tsc = { .name = "hyperv_clocksource_tsc_page", .rating = 400, .read = read_hv_clock_tsc, .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .suspend= suspend_hv_clock_tsc, + .resume = resume_hv_clock_tsc, }; static u64 notrace read_hv_clock_msr(struct clocksource *arg) -- 1.8.3.1