@@ -102,6 +102,20 @@ static inline void kvm_sched_clock_init(bool stable)
sizeof(((struct pvclock_vcpu_time_info *)NULL)->system_time));
}
+static unsigned long kvm_get_cpu_khz(void)
+{
+ unsigned int cpu_khz;
+
+ /*
+ * Prefer CPUID over kvmclock when possible, as the base CPU frequency
+ * isn't necessary the same as the kvmlock "TSC" frequency.
+ */
+ if (!cpuid_get_cpu_freq(&cpu_khz))
+ return cpu_khz;
+
+ return pvclock_tsc_khz(this_cpu_pvti());
+}
+
/*
* If we don't do that, there is the possibility that the guest
* will calibrate under heavy load - thus, getting a lower lpj -
@@ -332,7 +346,7 @@ void __init kvmclock_init(void)
flags = pvclock_read_flags(&hv_clock_boot[0].pvti);
kvm_sched_clock_init(flags & PVCLOCK_TSC_STABLE_BIT);
- tsc_register_calibration_routines(kvm_get_tsc_khz, kvm_get_tsc_khz,
+ tsc_register_calibration_routines(kvm_get_tsc_khz, kvm_get_cpu_khz,
tsc_properties);
x86_platform.get_wallclock = kvm_get_wallclock;
If CPUID.0x16 is present and valid, use the CPU frequency provided by CPUID instead of assuming that the virtual CPU runs at the same frequency as TSC and/or kvmclock. Back before constant TSCs were a thing, treating the TSC and CPU frequencies as one and the same was somewhat reasonable, but now it's nonsensical, especially if the hypervisor explicitly enumerates the CPU frequency. Signed-off-by: Sean Christopherson <seanjc@google.com> --- arch/x86/kernel/kvmclock.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)