One of the newer methods to determine TSC frequency, is to use one of cpuid extensions to get TSC/Crystal ratio. This method is preferred on CPUs that implements it. This patch adds a new function calibrate_tsc_early() that can be called early in boot to determine the TSC by using this method.
Signed-off-by: Pavel Tatashin <pasha.tatas...@oracle.com> --- arch/x86/kernel/tsc.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 5add503..1c9fc23 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -26,6 +26,9 @@ #include <asm/apic.h> #include <asm/intel-family.h> +/* CPUID 15H TSC/Crystal ratio, plus optionally Crystal Hz */ +#define CPUID_TSC_LEAF 0x15 + unsigned int __read_mostly cpu_khz; /* TSC clocks / usec, not used here */ EXPORT_SYMBOL(cpu_khz); @@ -671,24 +674,16 @@ static unsigned long quick_pit_calibrate(bool early_boot) } /** - * native_calibrate_tsc - * Determine TSC frequency via CPUID, else return 0. + * The caller already checked that TSC leaf capability can be read from cpuid */ -unsigned long native_calibrate_tsc(void) +static unsigned long calibrate_tsc_early(int model) { unsigned int eax_denominator, ebx_numerator, ecx_hz, edx; unsigned int crystal_khz; - if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) - return 0; - - if (boot_cpu_data.cpuid_level < 0x15) - return 0; - eax_denominator = ebx_numerator = ecx_hz = edx = 0; - /* CPUID 15H TSC/Crystal ratio, plus optionally Crystal Hz */ - cpuid(0x15, &eax_denominator, &ebx_numerator, &ecx_hz, &edx); + cpuid(CPUID_TSC_LEAF, &eax_denominator, &ebx_numerator, &ecx_hz, &edx); if (ebx_numerator == 0 || eax_denominator == 0) return 0; @@ -696,7 +691,7 @@ unsigned long native_calibrate_tsc(void) crystal_khz = ecx_hz / 1000; if (crystal_khz == 0) { - switch (boot_cpu_data.x86_model) { + switch (model) { case INTEL_FAM6_SKYLAKE_MOBILE: case INTEL_FAM6_SKYLAKE_DESKTOP: case INTEL_FAM6_KABYLAKE_MOBILE: @@ -713,6 +708,24 @@ unsigned long native_calibrate_tsc(void) } } + return crystal_khz * ebx_numerator / eax_denominator; +} + +/** + * native_calibrate_tsc + * Determine TSC frequency via CPUID, else return 0. + */ +unsigned long native_calibrate_tsc(void) +{ + unsigned int tsc_khz; + + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) + return 0; + + if (boot_cpu_data.cpuid_level < CPUID_TSC_LEAF) + return 0; + + tsc_khz = calibrate_tsc_early(boot_cpu_data.x86_model); /* * TSC frequency determined by CPUID is a "hardware reported" * frequency and is the most accurate one so far we have. This @@ -727,7 +740,7 @@ unsigned long native_calibrate_tsc(void) if (boot_cpu_data.x86_model == INTEL_FAM6_ATOM_GOLDMONT) setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE); - return crystal_khz * ebx_numerator / eax_denominator; + return tsc_khz; } static unsigned long cpu_khz_from_cpuid(void) -- 1.8.3.1