Extract retrieval of TSC frequency information from CPUID into a standalone
helper so that TDX guest support can reuse the logic.

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

No functional change intended.

Reviewed-by: David Woodhouse <[email protected]>
Signed-off-by: Sean Christopherson <[email protected]>
---
 arch/x86/kernel/tsc.c | 61 +++++++++++++++++++++++++++----------------
 1 file changed, 38 insertions(+), 23 deletions(-)

diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index f049c126e47c..12043812c8f5 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -645,46 +645,62 @@ static unsigned long quick_pit_calibrate(void)
        return delta;
 }
 
+struct cpuid_tsc_info {
+       unsigned int denominator;
+       unsigned int numerator;
+       unsigned int crystal_khz;
+};
+
+static int cpuid_get_tsc_info(struct cpuid_tsc_info *info)
+{
+       unsigned int ecx_hz, edx;
+
+       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;
+}
+
 /**
  * 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);
 
        /*
@@ -692,15 +708,14 @@ 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;
 
        /*
@@ -716,9 +731,9 @@ unsigned long native_calibrate_tsc(void)
         * lapic_timer_period here to avoid having to calibrate the APIC
         * timer later.
         */
-       apic_set_timer_period_khz(crystal_khz, "CPUID 0x15/0x16");
+       apic_set_timer_period_khz(info.crystal_khz, "CPUID 0x15/0x16");
 
-       return crystal_khz * ebx_numerator / eax_denominator;
+       return info.crystal_khz * info.numerator / info.denominator;
 }
 
 static unsigned long cpu_khz_from_cpuid(void)
-- 
2.55.0.rc0.799.gd6f94ed593-goog


Reply via email to