[v2 4/9] x86/tsc: early MSR-based CPU/TSC frequency discovery

From: Pavel Tatashin
Date: Fri Mar 24 2017 - 11:25:16 EST


Allow discovering MSR-based CPU/TSC frequency early in boot. This method
works only for some Intel CPUs.

Signed-off-by: Pavel Tatashin <pasha.tatashin@xxxxxxxxxx>
---
arch/x86/include/asm/tsc.h | 1 +
arch/x86/kernel/tsc_msr.c | 38 +++++++++++++++++++++++++-------------
2 files changed, 26 insertions(+), 13 deletions(-)

diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h
index f5e6f1c..893de0c 100644
--- a/arch/x86/include/asm/tsc.h
+++ b/arch/x86/include/asm/tsc.h
@@ -61,6 +61,7 @@ static inline void check_tsc_sync_target(void) { }
extern void tsc_save_sched_clock_state(void);
extern void tsc_restore_sched_clock_state(void);

+unsigned long cpu_khz_from_msr_early(int vendor, int family, int model);
unsigned long cpu_khz_from_msr(void);

#endif /* _ASM_X86_TSC_H */
diff --git a/arch/x86/kernel/tsc_msr.c b/arch/x86/kernel/tsc_msr.c
index 19afdbd..6f5f617 100644
--- a/arch/x86/kernel/tsc_msr.c
+++ b/arch/x86/kernel/tsc_msr.c
@@ -62,22 +62,20 @@ static int match_cpu(u8 family, u8 model)
#define id_to_freq(cpu_index, freq_id) \
(freq_desc_tables[cpu_index].freqs[freq_id])

-/*
- * MSR-based CPU/TSC frequency discovery for certain CPUs.
- *
- * Set global "lapic_timer_frequency" to bus_clock_cycles/jiffy
- * Return processor base frequency in KHz, or 0 on failure.
- */
-unsigned long cpu_khz_from_msr(void)
+ /*
+ * Get CPU/TSC frequency early in boot.
+ * Set global "lapic_timer_frequency" to bus_clock_cycles/jiffy
+ * Return processor base frequency in KHz, or 0 on failure.
+ */
+unsigned long cpu_khz_from_msr_early(int vendor, int family, int model)
{
u32 lo, hi, ratio, freq_id, freq;
- unsigned long res;
int cpu_index;

- if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
+ if (vendor != X86_VENDOR_INTEL)
return 0;

- cpu_index = match_cpu(boot_cpu_data.x86, boot_cpu_data.x86_model);
+ cpu_index = match_cpu(family, model);
if (cpu_index < 0)
return 0;

@@ -94,13 +92,27 @@ unsigned long cpu_khz_from_msr(void)
freq_id = lo & 0x7;
freq = id_to_freq(cpu_index, freq_id);

- /* TSC frequency = maximum resolved freq * maximum resolved bus ratio */
- res = freq * ratio;
-
#ifdef CONFIG_X86_LOCAL_APIC
lapic_timer_frequency = (freq * 1000) / HZ;
#endif

+ /* TSC frequency = maximum resolved freq * maximum resolved bus ratio */
+ return freq * ratio;
+}
+
+/*
+ * MSR-based CPU/TSC frequency discovery for certain CPUs.
+ */
+unsigned long cpu_khz_from_msr(void)
+{
+ unsigned long res;
+
+ res = cpu_khz_from_msr_early(boot_cpu_data.x86_vendor,
+ boot_cpu_data.x86,
+ boot_cpu_data.x86_model);
+ if (res == 0)
+ return 0;
+
/*
* TSC frequency determined by MSR is always considered "known"
* because it is reported by HW.
--
1.8.3.1