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.

Opportunsitically drop native_calibrate_tsc()'s "== 0" and "!= 0" check
in favor of the kernel's preferred style.

No functional change intended.

Signed-off-by: Sean Christopherson <sea...@google.com>
---
 arch/x86/include/asm/tsc.h |  9 +++++
 arch/x86/kernel/tsc.c      | 67 +++++++++++++++++++++++++-------------
 2 files changed, 53 insertions(+), 23 deletions(-)

diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h
index 94408a784c8e..a4d84f721775 100644
--- a/arch/x86/include/asm/tsc.h
+++ b/arch/x86/include/asm/tsc.h
@@ -28,6 +28,15 @@ static inline cycles_t get_cycles(void)
 }
 #define get_cycles get_cycles
 
+struct cpuid_tsc_info {
+       unsigned int denominator;
+       unsigned int numerator;
+       unsigned int crystal_khz;
+       unsigned int tsc_khz;
+};
+extern int cpuid_get_tsc_info(struct cpuid_tsc_info *info);
+extern int cpuid_get_tsc_freq(struct cpuid_tsc_info *info);
+
 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..93713eb81f52 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -655,46 +655,67 @@ static unsigned long quick_pit_calibrate(void)
        return delta;
 }
 
+int cpuid_get_tsc_info(struct cpuid_tsc_info *info)
+{
+       unsigned int ecx_hz, edx;
+
+       memset(info, 0, sizeof(*info));
+
+       if (boot_cpu_data.cpuid_level < CPUID_LEAF_TSC)
+               return -ENOENT;
+
+       /* CPUID 15H TSC/Crystal ratio, plus optionally Crystal Hz */
+       cpuid(CPUID_LEAF_TSC, &info->denominator, &info->numerator, &ecx_hz, 
&edx);
+
+       if (!info->denominator || !info->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.
+        */
+       info->crystal_khz = ecx_hz / 1000;
+       return 0;
+}
+
+int cpuid_get_tsc_freq(struct cpuid_tsc_info *info)
+{
+       if (cpuid_get_tsc_info(info) || !info->crystal_khz)
+               return -ENOENT;
+
+       info->tsc_khz = info->crystal_khz * info->numerator / info->denominator;
+       return 0;
+}
+
 /**
  * native_calibrate_tsc - determine TSC frequency
  * Determine TSC frequency via CPUID, else return 0.
  */
 unsigned long native_calibrate_tsc(void)
 {
-       unsigned int eax_denominator, ebx_numerator, ecx_hz, edx;
-       unsigned int crystal_khz;
+       struct cpuid_tsc_info info;
 
        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(&info))
                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
         * crystal clock.
         */
-       if (crystal_khz == 0 &&
-                       boot_cpu_data.x86_vfm == INTEL_ATOM_GOLDMONT_D)
-               crystal_khz = 25000;
+       if (!info.crystal_khz && boot_cpu_data.x86_vfm == INTEL_ATOM_GOLDMONT_D)
+               info.crystal_khz = 25000;
 
        /*
         * TSC frequency reported directly by CPUID is a "hardware reported"
         * frequency and is the most accurate one so far we have. This
         * is considered a known frequency.
         */
-       if (crystal_khz != 0)
+       if (info.crystal_khz)
                setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
 
        /*
@@ -702,15 +723,15 @@ unsigned long native_calibrate_tsc(void)
         * clock, but we can easily calculate it to a high degree of accuracy
         * by considering the crystal ratio and the CPU speed.
         */
-       if (crystal_khz == 0 && boot_cpu_data.cpuid_level >= CPUID_LEAF_FREQ) {
+       if (!info.crystal_khz && boot_cpu_data.cpuid_level >= CPUID_LEAF_FREQ) {
                unsigned int eax_base_mhz, ebx, ecx, edx;
 
                cpuid(CPUID_LEAF_FREQ, &eax_base_mhz, &ebx, &ecx, &edx);
-               crystal_khz = eax_base_mhz * 1000 *
-                       eax_denominator / ebx_numerator;
+               info.crystal_khz = eax_base_mhz * 1000 *
+                       info.denominator / info.numerator;
        }
 
-       if (crystal_khz == 0)
+       if (!info.crystal_khz)
                return 0;
 
        /*
@@ -727,10 +748,10 @@ unsigned long native_calibrate_tsc(void)
         * lapic_timer_period here to avoid having to calibrate the APIC
         * timer later.
         */
-       lapic_timer_period = crystal_khz * 1000 / HZ;
+       lapic_timer_period = info.crystal_khz * 1000 / HZ;
 #endif
 
-       return crystal_khz * ebx_numerator / eax_denominator;
+       return info.crystal_khz * info.numerator / info.denominator;
 }
 
 static unsigned long cpu_khz_from_cpuid(void)
-- 
2.48.1.711.g2feabab25a-goog


Reply via email to