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 <sea...@google.com>
---
 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


Reply via email to