Extract retrieval of TSC frequency information from CPUID into standalone helpers so that TDX guest support and kvmlock can reuse the logic. Provide a version that includes the multiplier math as TDX in particular does NOT want to use native_calibrate_tsc()'s fallback logic that derives the TSC frequency based on CPUID.0x16 when the core crystal frequency isn't known. No functional change intended. Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx> --- arch/x86/include/asm/tsc.h | 41 ++++++++++++++++++++++++++++++++++++++ arch/x86/kernel/tsc.c | 14 ++----------- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h index 94408a784c8e..14a81a66b37c 100644 --- a/arch/x86/include/asm/tsc.h +++ b/arch/x86/include/asm/tsc.h @@ -28,6 +28,47 @@ static inline cycles_t get_cycles(void) } #define get_cycles get_cycles +static inline int cpuid_get_tsc_info(unsigned int *crystal_khz, + unsigned int *denominator, + unsigned int *numerator) +{ + unsigned int ecx_hz, edx; + + if (boot_cpu_data.cpuid_level < CPUID_LEAF_TSC) + return -ENOENT; + + *crystal_khz = *denominator = *numerator = ecx_hz = edx = 0; + + /* CPUID 15H TSC/Crystal ratio, plus optionally Crystal Hz */ + cpuid(CPUID_LEAF_TSC, denominator, numerator, &ecx_hz, &edx); + + if (!*denominator || !*numerator) + return -ENOENT; + + /* + * Note, some CPUs provide the multiplier information, but not the core + * crystal frequency. The multiplier information is still useful for + * such CPUs, as the crystal frequency can be gleaned from CPUID.0x16. + */ + *crystal_khz = ecx_hz / 1000; + return 0; +} + +static inline int cpuid_get_tsc_freq(unsigned int *tsc_khz, + unsigned int *crystal_khz) +{ + unsigned int denominator, numerator; + + if (cpuid_get_tsc_info(tsc_khz, &denominator, &numerator)) + return -ENOENT; + + if (!*crystal_khz) + return -ENOENT; + + *tsc_khz = *crystal_khz * numerator / denominator; + return 0; +} + extern void tsc_early_init(void); extern void tsc_init(void); extern void mark_tsc_unstable(char *reason); diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 34dec0b72ea8..e3faa2b36910 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -661,25 +661,15 @@ static unsigned long quick_pit_calibrate(void) */ unsigned long native_calibrate_tsc(void) { - unsigned int eax_denominator, ebx_numerator, ecx_hz, edx; + unsigned int eax_denominator, ebx_numerator; unsigned int crystal_khz; if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) return 0; - if (boot_cpu_data.cpuid_level < CPUID_LEAF_TSC) + if (cpuid_get_tsc_info(&crystal_khz, &eax_denominator, &ebx_numerator)) return 0; - eax_denominator = ebx_numerator = ecx_hz = edx = 0; - - /* CPUID 15H TSC/Crystal ratio, plus optionally Crystal Hz */ - cpuid(CPUID_LEAF_TSC, &eax_denominator, &ebx_numerator, &ecx_hz, &edx); - - if (ebx_numerator == 0 || eax_denominator == 0) - return 0; - - crystal_khz = ecx_hz / 1000; - /* * Denverton SoCs don't report crystal clock, and also don't support * CPUID_LEAF_FREQ for the calculation below, so hardcode the 25MHz -- 2.48.1.362.g079036d154-goog