aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-07-25 22:41:35 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-07-25 22:41:35 -0400
commit5f22004ba9b4cf740773777ea7b74586743f6051 (patch)
tree4d26c7f8c2ac3f30a252eaf746825792deda92fd
parent8e466955d6f78896cc6519b6f07e89173d3ba58b (diff)
parentc48ec42d6eae08f55685ab660f0743ed33b9f22a (diff)
Merge branch 'x86-timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 timer updates from Ingo Molnar: "The main change in this tree is the reworking, fixing and extension of the TSC frequency enumeration code (by Len Brown)" * 'x86-timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/tsc: Remove the unused check_tsc_disabled() x86/tsc: Enumerate BXT tsc_khz via CPUID x86/tsc: Enumerate SKL cpu_khz and tsc_khz via CPUID x86/tsc_msr: Remove irqoff around MSR-based TSC enumeration x86/tsc_msr: Add Airmont reference clock values x86/tsc_msr: Correct Silvermont reference clock values x86/tsc_msr: Update comments, expand definitions x86/tsc_msr: Remove debugging messages x86/tsc_msr: Identify Intel-specific code Revert "x86/tsc: Add missing Cherrytrail frequency to the table"
-rw-r--r--arch/x86/include/asm/tsc.h5
-rw-r--r--arch/x86/include/asm/x86_init.h4
-rw-r--r--arch/x86/kernel/tsc.c100
-rw-r--r--arch/x86/kernel/tsc_msr.c68
-rw-r--r--arch/x86/kernel/x86_init.c1
5 files changed, 110 insertions, 68 deletions
diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h
index 7428697c5b8d..33b6365c22fe 100644
--- a/arch/x86/include/asm/tsc.h
+++ b/arch/x86/include/asm/tsc.h
@@ -35,7 +35,7 @@ extern void tsc_init(void);
35extern void mark_tsc_unstable(char *reason); 35extern void mark_tsc_unstable(char *reason);
36extern int unsynchronized_tsc(void); 36extern int unsynchronized_tsc(void);
37extern int check_tsc_unstable(void); 37extern int check_tsc_unstable(void);
38extern int check_tsc_disabled(void); 38extern unsigned long native_calibrate_cpu(void);
39extern unsigned long native_calibrate_tsc(void); 39extern unsigned long native_calibrate_tsc(void);
40extern unsigned long long native_sched_clock_from_tsc(u64 tsc); 40extern unsigned long long native_sched_clock_from_tsc(u64 tsc);
41 41
@@ -52,7 +52,6 @@ extern int notsc_setup(char *);
52extern void tsc_save_sched_clock_state(void); 52extern void tsc_save_sched_clock_state(void);
53extern void tsc_restore_sched_clock_state(void); 53extern void tsc_restore_sched_clock_state(void);
54 54
55/* MSR based TSC calibration for Intel Atom SoC platforms */ 55unsigned long cpu_khz_from_msr(void);
56unsigned long try_msr_calibrate_tsc(void);
57 56
58#endif /* _ASM_X86_TSC_H */ 57#endif /* _ASM_X86_TSC_H */
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index 66c15a01667f..6ba793178441 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -182,7 +182,8 @@ struct x86_legacy_features {
182 182
183/** 183/**
184 * struct x86_platform_ops - platform specific runtime functions 184 * struct x86_platform_ops - platform specific runtime functions
185 * @calibrate_tsc: calibrate TSC 185 * @calibrate_cpu: calibrate CPU
186 * @calibrate_tsc: calibrate TSC, if different from CPU
186 * @get_wallclock: get time from HW clock like RTC etc. 187 * @get_wallclock: get time from HW clock like RTC etc.
187 * @set_wallclock: set time back to HW clock 188 * @set_wallclock: set time back to HW clock
188 * @is_untracked_pat_range exclude from PAT logic 189 * @is_untracked_pat_range exclude from PAT logic
@@ -201,6 +202,7 @@ struct x86_legacy_features {
201 * semantics. 202 * semantics.
202 */ 203 */
203struct x86_platform_ops { 204struct x86_platform_ops {
205 unsigned long (*calibrate_cpu)(void);
204 unsigned long (*calibrate_tsc)(void); 206 unsigned long (*calibrate_tsc)(void);
205 void (*get_wallclock)(struct timespec *ts); 207 void (*get_wallclock)(struct timespec *ts);
206 int (*set_wallclock)(const struct timespec *ts); 208 int (*set_wallclock)(const struct timespec *ts);
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 38ba6de56ede..a804b5ab32d0 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -239,7 +239,7 @@ static inline unsigned long long cycles_2_ns(unsigned long long cyc)
239 return ns; 239 return ns;
240} 240}
241 241
242static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu) 242static void set_cyc2ns_scale(unsigned long khz, int cpu)
243{ 243{
244 unsigned long long tsc_now, ns_now; 244 unsigned long long tsc_now, ns_now;
245 struct cyc2ns_data *data; 245 struct cyc2ns_data *data;
@@ -248,7 +248,7 @@ static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu)
248 local_irq_save(flags); 248 local_irq_save(flags);
249 sched_clock_idle_sleep_event(); 249 sched_clock_idle_sleep_event();
250 250
251 if (!cpu_khz) 251 if (!khz)
252 goto done; 252 goto done;
253 253
254 data = cyc2ns_write_begin(cpu); 254 data = cyc2ns_write_begin(cpu);
@@ -261,7 +261,7 @@ static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu)
261 * time function is continuous; see the comment near struct 261 * time function is continuous; see the comment near struct
262 * cyc2ns_data. 262 * cyc2ns_data.
263 */ 263 */
264 clocks_calc_mult_shift(&data->cyc2ns_mul, &data->cyc2ns_shift, cpu_khz, 264 clocks_calc_mult_shift(&data->cyc2ns_mul, &data->cyc2ns_shift, khz,
265 NSEC_PER_MSEC, 0); 265 NSEC_PER_MSEC, 0);
266 266
267 /* 267 /*
@@ -335,12 +335,6 @@ int check_tsc_unstable(void)
335} 335}
336EXPORT_SYMBOL_GPL(check_tsc_unstable); 336EXPORT_SYMBOL_GPL(check_tsc_unstable);
337 337
338int check_tsc_disabled(void)
339{
340 return tsc_disabled;
341}
342EXPORT_SYMBOL_GPL(check_tsc_disabled);
343
344#ifdef CONFIG_X86_TSC 338#ifdef CONFIG_X86_TSC
345int __init notsc_setup(char *str) 339int __init notsc_setup(char *str)
346{ 340{
@@ -665,19 +659,77 @@ success:
665} 659}
666 660
667/** 661/**
668 * native_calibrate_tsc - calibrate the tsc on boot 662 * native_calibrate_tsc
663 * Determine TSC frequency via CPUID, else return 0.
669 */ 664 */
670unsigned long native_calibrate_tsc(void) 665unsigned long native_calibrate_tsc(void)
671{ 666{
667 unsigned int eax_denominator, ebx_numerator, ecx_hz, edx;
668 unsigned int crystal_khz;
669
670 if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
671 return 0;
672
673 if (boot_cpu_data.cpuid_level < 0x15)
674 return 0;
675
676 eax_denominator = ebx_numerator = ecx_hz = edx = 0;
677
678 /* CPUID 15H TSC/Crystal ratio, plus optionally Crystal Hz */
679 cpuid(0x15, &eax_denominator, &ebx_numerator, &ecx_hz, &edx);
680
681 if (ebx_numerator == 0 || eax_denominator == 0)
682 return 0;
683
684 crystal_khz = ecx_hz / 1000;
685
686 if (crystal_khz == 0) {
687 switch (boot_cpu_data.x86_model) {
688 case 0x4E: /* SKL */
689 case 0x5E: /* SKL */
690 crystal_khz = 24000; /* 24.0 MHz */
691 break;
692 case 0x5C: /* BXT */
693 crystal_khz = 19200; /* 19.2 MHz */
694 break;
695 }
696 }
697
698 return crystal_khz * ebx_numerator / eax_denominator;
699}
700
701static unsigned long cpu_khz_from_cpuid(void)
702{
703 unsigned int eax_base_mhz, ebx_max_mhz, ecx_bus_mhz, edx;
704
705 if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
706 return 0;
707
708 if (boot_cpu_data.cpuid_level < 0x16)
709 return 0;
710
711 eax_base_mhz = ebx_max_mhz = ecx_bus_mhz = edx = 0;
712
713 cpuid(0x16, &eax_base_mhz, &ebx_max_mhz, &ecx_bus_mhz, &edx);
714
715 return eax_base_mhz * 1000;
716}
717
718/**
719 * native_calibrate_cpu - calibrate the cpu on boot
720 */
721unsigned long native_calibrate_cpu(void)
722{
672 u64 tsc1, tsc2, delta, ref1, ref2; 723 u64 tsc1, tsc2, delta, ref1, ref2;
673 unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX; 724 unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX;
674 unsigned long flags, latch, ms, fast_calibrate; 725 unsigned long flags, latch, ms, fast_calibrate;
675 int hpet = is_hpet_enabled(), i, loopmin; 726 int hpet = is_hpet_enabled(), i, loopmin;
676 727
677 /* Calibrate TSC using MSR for Intel Atom SoCs */ 728 fast_calibrate = cpu_khz_from_cpuid();
678 local_irq_save(flags); 729 if (fast_calibrate)
679 fast_calibrate = try_msr_calibrate_tsc(); 730 return fast_calibrate;
680 local_irq_restore(flags); 731
732 fast_calibrate = cpu_khz_from_msr();
681 if (fast_calibrate) 733 if (fast_calibrate)
682 return fast_calibrate; 734 return fast_calibrate;
683 735
@@ -837,8 +889,12 @@ int recalibrate_cpu_khz(void)
837 if (!boot_cpu_has(X86_FEATURE_TSC)) 889 if (!boot_cpu_has(X86_FEATURE_TSC))
838 return -ENODEV; 890 return -ENODEV;
839 891
892 cpu_khz = x86_platform.calibrate_cpu();
840 tsc_khz = x86_platform.calibrate_tsc(); 893 tsc_khz = x86_platform.calibrate_tsc();
841 cpu_khz = tsc_khz; 894 if (tsc_khz == 0)
895 tsc_khz = cpu_khz;
896 else if (abs(cpu_khz - tsc_khz) * 10 > tsc_khz)
897 cpu_khz = tsc_khz;
842 cpu_data(0).loops_per_jiffy = cpufreq_scale(cpu_data(0).loops_per_jiffy, 898 cpu_data(0).loops_per_jiffy = cpufreq_scale(cpu_data(0).loops_per_jiffy,
843 cpu_khz_old, cpu_khz); 899 cpu_khz_old, cpu_khz);
844 900
@@ -1244,8 +1300,18 @@ void __init tsc_init(void)
1244 return; 1300 return;
1245 } 1301 }
1246 1302
1303 cpu_khz = x86_platform.calibrate_cpu();
1247 tsc_khz = x86_platform.calibrate_tsc(); 1304 tsc_khz = x86_platform.calibrate_tsc();
1248 cpu_khz = tsc_khz; 1305
1306 /*
1307 * Trust non-zero tsc_khz as authorative,
1308 * and use it to sanity check cpu_khz,
1309 * which will be off if system timer is off.
1310 */
1311 if (tsc_khz == 0)
1312 tsc_khz = cpu_khz;
1313 else if (abs(cpu_khz - tsc_khz) * 10 > tsc_khz)
1314 cpu_khz = tsc_khz;
1249 1315
1250 if (!tsc_khz) { 1316 if (!tsc_khz) {
1251 mark_tsc_unstable("could not calculate TSC khz"); 1317 mark_tsc_unstable("could not calculate TSC khz");
@@ -1265,7 +1331,7 @@ void __init tsc_init(void)
1265 */ 1331 */
1266 for_each_possible_cpu(cpu) { 1332 for_each_possible_cpu(cpu) {
1267 cyc2ns_init(cpu); 1333 cyc2ns_init(cpu);
1268 set_cyc2ns_scale(cpu_khz, cpu); 1334 set_cyc2ns_scale(tsc_khz, cpu);
1269 } 1335 }
1270 1336
1271 if (tsc_disabled > 0) 1337 if (tsc_disabled > 0)
diff --git a/arch/x86/kernel/tsc_msr.c b/arch/x86/kernel/tsc_msr.c
index 9911a0620f9a..0fe720d64fef 100644
--- a/arch/x86/kernel/tsc_msr.c
+++ b/arch/x86/kernel/tsc_msr.c
@@ -1,14 +1,5 @@
1/* 1/*
2 * tsc_msr.c - MSR based TSC calibration on Intel Atom SoC platforms. 2 * tsc_msr.c - TSC frequency enumeration via MSR
3 *
4 * TSC in Intel Atom SoC runs at a constant rate which can be figured
5 * by this formula:
6 * <maximum core-clock to bus-clock ratio> * <maximum resolved frequency>
7 * See Intel 64 and IA-32 System Programming Guid section 16.12 and 30.11.5
8 * for details.
9 * Especially some Intel Atom SoCs don't have PIT(i8254) or HPET, so MSR
10 * based calibration is the only option.
11 *
12 * 3 *
13 * Copyright (C) 2013 Intel Corporation 4 * Copyright (C) 2013 Intel Corporation
14 * Author: Bin Gao <bin.gao@intel.com> 5 * Author: Bin Gao <bin.gao@intel.com>
@@ -22,18 +13,10 @@
22#include <asm/apic.h> 13#include <asm/apic.h>
23#include <asm/param.h> 14#include <asm/param.h>
24 15
25/* CPU reference clock frequency: in KHz */ 16#define MAX_NUM_FREQS 9
26#define FREQ_80 80000
27#define FREQ_83 83200
28#define FREQ_100 99840
29#define FREQ_133 133200
30#define FREQ_166 166400
31
32#define MAX_NUM_FREQS 8
33 17
34/* 18/*
35 * According to Intel 64 and IA-32 System Programming Guide, 19 * If MSR_PERF_STAT[31] is set, the maximum resolved bus ratio can be
36 * if MSR_PERF_STAT[31] is set, the maximum resolved bus ratio can be
37 * read in MSR_PLATFORM_ID[12:8], otherwise in MSR_PERF_STAT[44:40]. 20 * read in MSR_PLATFORM_ID[12:8], otherwise in MSR_PERF_STAT[44:40].
38 * Unfortunately some Intel Atom SoCs aren't quite compliant to this, 21 * Unfortunately some Intel Atom SoCs aren't quite compliant to this,
39 * so we need manually differentiate SoC families. This is what the 22 * so we need manually differentiate SoC families. This is what the
@@ -48,17 +31,18 @@ struct freq_desc {
48 31
49static struct freq_desc freq_desc_tables[] = { 32static struct freq_desc freq_desc_tables[] = {
50 /* PNW */ 33 /* PNW */
51 { 6, 0x27, 0, { 0, 0, 0, 0, 0, FREQ_100, 0, FREQ_83 } }, 34 { 6, 0x27, 0, { 0, 0, 0, 0, 0, 99840, 0, 83200 } },
52 /* CLV+ */ 35 /* CLV+ */
53 { 6, 0x35, 0, { 0, FREQ_133, 0, 0, 0, FREQ_100, 0, FREQ_83 } }, 36 { 6, 0x35, 0, { 0, 133200, 0, 0, 0, 99840, 0, 83200 } },
54 /* TNG */ 37 /* TNG - Intel Atom processor Z3400 series */
55 { 6, 0x4a, 1, { 0, FREQ_100, FREQ_133, 0, 0, 0, 0, 0 } }, 38 { 6, 0x4a, 1, { 0, 100000, 133300, 0, 0, 0, 0, 0 } },
56 /* VLV2 */ 39 /* VLV2 - Intel Atom processor E3000, Z3600, Z3700 series */
57 { 6, 0x37, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_166, 0, 0, 0, 0 } }, 40 { 6, 0x37, 1, { 83300, 100000, 133300, 116700, 80000, 0, 0, 0 } },
58 /* ANN */ 41 /* ANN - Intel Atom processor Z3500 series */
59 { 6, 0x5a, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_100, 0, 0, 0, 0 } }, 42 { 6, 0x5a, 1, { 83300, 100000, 133300, 100000, 0, 0, 0, 0 } },
60 /* AIRMONT */ 43 /* AMT - Intel Atom processor X7-Z8000 and X5-Z8000 series */
61 { 6, 0x4c, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_166, FREQ_80, 0, 0, 0 } }, 44 { 6, 0x4c, 1, { 83300, 100000, 133300, 116700,
45 80000, 93300, 90000, 88900, 87500 } },
62}; 46};
63 47
64static int match_cpu(u8 family, u8 model) 48static int match_cpu(u8 family, u8 model)
@@ -79,16 +63,20 @@ static int match_cpu(u8 family, u8 model)
79 (freq_desc_tables[cpu_index].freqs[freq_id]) 63 (freq_desc_tables[cpu_index].freqs[freq_id])
80 64
81/* 65/*
82 * Do MSR calibration only for known/supported CPUs. 66 * MSR-based CPU/TSC frequency discovery for certain CPUs.
83 * 67 *
84 * Returns the calibration value or 0 if MSR calibration failed. 68 * Set global "lapic_timer_frequency" to bus_clock_cycles/jiffy
69 * Return processor base frequency in KHz, or 0 on failure.
85 */ 70 */
86unsigned long try_msr_calibrate_tsc(void) 71unsigned long cpu_khz_from_msr(void)
87{ 72{
88 u32 lo, hi, ratio, freq_id, freq; 73 u32 lo, hi, ratio, freq_id, freq;
89 unsigned long res; 74 unsigned long res;
90 int cpu_index; 75 int cpu_index;
91 76
77 if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
78 return 0;
79
92 cpu_index = match_cpu(boot_cpu_data.x86, boot_cpu_data.x86_model); 80 cpu_index = match_cpu(boot_cpu_data.x86, boot_cpu_data.x86_model);
93 if (cpu_index < 0) 81 if (cpu_index < 0)
94 return 0; 82 return 0;
@@ -100,31 +88,17 @@ unsigned long try_msr_calibrate_tsc(void)
100 rdmsr(MSR_IA32_PERF_STATUS, lo, hi); 88 rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
101 ratio = (hi >> 8) & 0x1f; 89 ratio = (hi >> 8) & 0x1f;
102 } 90 }
103 pr_info("Maximum core-clock to bus-clock ratio: 0x%x\n", ratio);
104
105 if (!ratio)
106 goto fail;
107 91
108 /* Get FSB FREQ ID */ 92 /* Get FSB FREQ ID */
109 rdmsr(MSR_FSB_FREQ, lo, hi); 93 rdmsr(MSR_FSB_FREQ, lo, hi);
110 freq_id = lo & 0x7; 94 freq_id = lo & 0x7;
111 freq = id_to_freq(cpu_index, freq_id); 95 freq = id_to_freq(cpu_index, freq_id);
112 pr_info("Resolved frequency ID: %u, frequency: %u KHz\n",
113 freq_id, freq);
114 if (!freq)
115 goto fail;
116 96
117 /* TSC frequency = maximum resolved freq * maximum resolved bus ratio */ 97 /* TSC frequency = maximum resolved freq * maximum resolved bus ratio */
118 res = freq * ratio; 98 res = freq * ratio;
119 pr_info("TSC runs at %lu KHz\n", res);
120 99
121#ifdef CONFIG_X86_LOCAL_APIC 100#ifdef CONFIG_X86_LOCAL_APIC
122 lapic_timer_frequency = (freq * 1000) / HZ; 101 lapic_timer_frequency = (freq * 1000) / HZ;
123 pr_info("lapic_timer_frequency = %d\n", lapic_timer_frequency);
124#endif 102#endif
125 return res; 103 return res;
126
127fail:
128 pr_warn("Fast TSC calibration using MSR failed\n");
129 return 0;
130} 104}
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index dad5fe9633a3..58b459296e13 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -92,6 +92,7 @@ static void default_nmi_init(void) { };
92static int default_i8042_detect(void) { return 1; }; 92static int default_i8042_detect(void) { return 1; };
93 93
94struct x86_platform_ops x86_platform = { 94struct x86_platform_ops x86_platform = {
95 .calibrate_cpu = native_calibrate_cpu,
95 .calibrate_tsc = native_calibrate_tsc, 96 .calibrate_tsc = native_calibrate_tsc,
96 .get_wallclock = mach_get_cmos_time, 97 .get_wallclock = mach_get_cmos_time,
97 .set_wallclock = mach_set_rtc_mmss, 98 .set_wallclock = mach_set_rtc_mmss,