]>
Commit | Line | Data |
---|---|---|
1 | From: Alok Kataria <akataria@vmware.com> | |
2 | Subject: x86: USE the synthetic TSC_RELIABLE feature bit. | |
3 | Patch-mainline: | |
4 | References: bnc#441338 | |
5 | ||
6 | Impact: Changes timebase calibration on Vmware. | |
7 | ||
8 | Use the synthetic TSC_RELIABLE bit to workaround virtualization anomalies. | |
9 | ||
10 | Virtual TSCs can be kept nearly in sync, but because the virtual TSC | |
11 | offset is set by software, it's not perfect. So, the TSC | |
12 | synchronization test can fail. Even then the TSC can be used as a | |
13 | clocksource since the VMware platform exports a reliable TSC to the | |
14 | guest for timekeeping purposes. Use this bit to check if we need to | |
15 | skip the TSC sync checks. | |
16 | ||
17 | Along with this also set the CONSTANT_TSC bit when on VMware, since we | |
18 | still want to use TSC as clocksource on VM running over hardware which | |
19 | has unsynchronized TSC's (opteron's), since the hypervisor will take | |
20 | care of providing consistent TSC to the guest. | |
21 | ||
22 | Signed-off-by: Alok N Kataria <akataria@vmware.com> | |
23 | Signed-off-by: Dan Hecht <dhecht@vmware.com> | |
24 | Signed-off-by: H. Peter Anvin <hpa@zytor.com> | |
25 | Signed-off-by: Takashi Iwai <tiwai@suse.de> | |
26 | ||
27 | --- | |
28 | ||
29 | arch/x86/kernel/cpu/hypervisor.c | 11 ++++++++++- | |
30 | arch/x86/kernel/cpu/vmware.c | 18 ++++++++++++++++++ | |
31 | arch/x86/kernel/tsc_sync.c | 8 +++++++- | |
32 | include/asm-x86/vmware.h | 1 + | |
33 | 4 files changed, 36 insertions(+), 2 deletions(-) | |
34 | ||
35 | ||
36 | diff --git a/arch/x86/kernel/cpu/hypervisor.c b/arch/x86/kernel/cpu/hypervisor.c | |
37 | index 7bd5506..35ae2b7 100644 | |
38 | --- a/arch/x86/kernel/cpu/hypervisor.c | |
39 | +++ b/arch/x86/kernel/cpu/hypervisor.c | |
40 | @@ -41,8 +41,17 @@ unsigned long get_hypervisor_tsc_freq(void) | |
41 | return 0; | |
42 | } | |
43 | ||
44 | +static inline void __cpuinit | |
45 | +hypervisor_set_feature_bits(struct cpuinfo_x86 *c) | |
46 | +{ | |
47 | + if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE) { | |
48 | + vmware_set_feature_bits(c); | |
49 | + return; | |
50 | + } | |
51 | +} | |
52 | + | |
53 | void __cpuinit init_hypervisor(struct cpuinfo_x86 *c) | |
54 | { | |
55 | detect_hypervisor_vendor(c); | |
56 | + hypervisor_set_feature_bits(c); | |
57 | } | |
58 | - | |
59 | diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c | |
60 | index d5d1b75..2ac4394 100644 | |
61 | --- a/arch/x86/kernel/cpu/vmware.c | |
62 | +++ b/arch/x86/kernel/cpu/vmware.c | |
63 | @@ -86,3 +86,21 @@ unsigned long vmware_get_tsc_khz(void) | |
64 | BUG_ON(!vmware_platform()); | |
65 | return __vmware_get_tsc_khz(); | |
66 | } | |
67 | + | |
68 | +/* | |
69 | + * VMware hypervisor takes care of exporting a reliable TSC to the guest. | |
70 | + * Still, due to timing difference when running on virtual cpus, the TSC can | |
71 | + * be marked as unstable in some cases. For example, the TSC sync check at | |
72 | + * bootup can fail due to a marginal offset between vcpus' TSCs (though the | |
73 | + * TSCs do not drift from each other). Also, the ACPI PM timer clocksource | |
74 | + * is not suitable as a watchdog when running on a hypervisor because the | |
75 | + * kernel may miss a wrap of the counter if the vcpu is descheduled for a | |
76 | + * long time. To skip these checks at runtime we set these capability bits, | |
77 | + * so that the kernel could just trust the hypervisor with providing a | |
78 | + * reliable virtual TSC that is suitable for timekeeping. | |
79 | + */ | |
80 | +void __cpuinit vmware_set_feature_bits(struct cpuinfo_x86 *c) | |
81 | +{ | |
82 | + set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); | |
83 | + set_cpu_cap(c, X86_FEATURE_TSC_RELIABLE); | |
84 | +} | |
85 | diff --git a/arch/x86/kernel/tsc_sync.c b/arch/x86/kernel/tsc_sync.c | |
86 | index 9ffb01c..5977c40 100644 | |
87 | --- a/arch/x86/kernel/tsc_sync.c | |
88 | +++ b/arch/x86/kernel/tsc_sync.c | |
89 | @@ -108,6 +108,12 @@ void __cpuinit check_tsc_sync_source(int cpu) | |
90 | if (unsynchronized_tsc()) | |
91 | return; | |
92 | ||
93 | + if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) { | |
94 | + printk(KERN_INFO | |
95 | + "Skipping synchronization checks as TSC is reliable.\n"); | |
96 | + return; | |
97 | + } | |
98 | + | |
99 | printk(KERN_INFO "checking TSC synchronization [CPU#%d -> CPU#%d]:", | |
100 | smp_processor_id(), cpu); | |
101 | ||
102 | @@ -161,7 +167,7 @@ void __cpuinit check_tsc_sync_target(void) | |
103 | { | |
104 | int cpus = 2; | |
105 | ||
106 | - if (unsynchronized_tsc()) | |
107 | + if (unsynchronized_tsc() || boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) | |
108 | return; | |
109 | ||
110 | /* | |
111 | diff --git a/include/asm-x86/vmware.h b/include/asm-x86/vmware.h | |
112 | index 02dfea5..c11b7e1 100644 | |
113 | --- a/include/asm-x86/vmware.h | |
114 | +++ b/include/asm-x86/vmware.h | |
115 | @@ -22,5 +22,6 @@ | |
116 | ||
117 | extern unsigned long vmware_get_tsc_khz(void); | |
118 | extern int vmware_platform(void); | |
119 | +extern void vmware_set_feature_bits(struct cpuinfo_x86 *c); | |
120 | ||
121 | #endif |