@@ -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);
@@ -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
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@google.com> --- arch/x86/include/asm/tsc.h | 41 ++++++++++++++++++++++++++++++++++++++ arch/x86/kernel/tsc.c | 14 ++----------- 2 files changed, 43 insertions(+), 12 deletions(-)