[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1490368899-877997-7-git-send-email-pasha.tatashin@oracle.com>
Date: Fri, 24 Mar 2017 11:21:36 -0400
From: Pavel Tatashin <pasha.tatashin@...cle.com>
To: x86@...nel.org, linux-kernel@...r.kernel.org, mingo@...hat.com,
peterz@...radead.org, tglx@...utronix.de, hpa@...or.com
Subject: [v2 6/9] x86/tsc: use cpuid to determine TSC frequency
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.tatashin@...cle.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
Powered by blists - more mailing lists