lkml.org 
[lkml]   [2017]   [Mar]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[v1 6/9] x86/tsc: use cpuid to determine TSC frequency
Date
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@oracle.com>
---
arch/x86/kernel/tsc.c | 39 ++++++++++++++++++++++++++-------------
1 files 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.7.1
\
 
 \ /
  Last update: 2017-03-22 21:20    [W:0.096 / U:0.092 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site