@@ -223,6 +223,63 @@ static void hv_machine_crash_shutdown(struct pt_regs *regs)
223223 hyperv_cleanup ();
224224}
225225#endif /* CONFIG_CRASH_DUMP */
226+
227+ static u64 hv_ref_counter_at_suspend ;
228+ static void (* old_save_sched_clock_state )(void );
229+ static void (* old_restore_sched_clock_state )(void );
230+
231+ /*
232+ * Hyper-V clock counter resets during hibernation. Save and restore clock
233+ * offset during suspend/resume, while also considering the time passed
234+ * before suspend. This is to make sure that sched_clock using hv tsc page
235+ * based clocksource, proceeds from where it left off during suspend and
236+ * it shows correct time for the timestamps of kernel messages after resume.
237+ */
238+ static void save_hv_clock_tsc_state (void )
239+ {
240+ hv_ref_counter_at_suspend = hv_read_reference_counter ();
241+ }
242+
243+ static void restore_hv_clock_tsc_state (void )
244+ {
245+ /*
246+ * Adjust the offsets used by hv tsc clocksource to
247+ * account for the time spent before hibernation.
248+ * adjusted value = reference counter (time) at suspend
249+ * - reference counter (time) now.
250+ */
251+ hv_adj_sched_clock_offset (hv_ref_counter_at_suspend - hv_read_reference_counter ());
252+ }
253+
254+ /*
255+ * Functions to override save_sched_clock_state and restore_sched_clock_state
256+ * functions of x86_platform. The Hyper-V clock counter is reset during
257+ * suspend-resume and the offset used to measure time needs to be
258+ * corrected, post resume.
259+ */
260+ static void hv_save_sched_clock_state (void )
261+ {
262+ old_save_sched_clock_state ();
263+ save_hv_clock_tsc_state ();
264+ }
265+
266+ static void hv_restore_sched_clock_state (void )
267+ {
268+ restore_hv_clock_tsc_state ();
269+ old_restore_sched_clock_state ();
270+ }
271+
272+ static void __init x86_setup_ops_for_tsc_pg_clock (void )
273+ {
274+ if (!(ms_hyperv .features & HV_MSR_REFERENCE_TSC_AVAILABLE ))
275+ return ;
276+
277+ old_save_sched_clock_state = x86_platform .save_sched_clock_state ;
278+ x86_platform .save_sched_clock_state = hv_save_sched_clock_state ;
279+
280+ old_restore_sched_clock_state = x86_platform .restore_sched_clock_state ;
281+ x86_platform .restore_sched_clock_state = hv_restore_sched_clock_state ;
282+ }
226283#endif /* CONFIG_HYPERV */
227284
228285static uint32_t __init ms_hyperv_platform (void )
@@ -579,6 +636,7 @@ static void __init ms_hyperv_init_platform(void)
579636
580637 /* Register Hyper-V specific clocksource */
581638 hv_init_clocksource ();
639+ x86_setup_ops_for_tsc_pg_clock ();
582640 hv_vtl_init_platform ();
583641#endif
584642 /*
0 commit comments