]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - src/patches/suse-2.6.27.39/patches.arch/x86-vmware-tsc-03-detect-from-hypervisor
Imported linux-2.6.27.39 suse/xen patches.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.arch / x86-vmware-tsc-03-detect-from-hypervisor
CommitLineData
2cb7cef9
BS
1From: Alok Kataria <akataria@vmware.com>
2Subject: x86: Hypervisor detection and get tsc_freq from hypervisor
3Patch-mainline:
4References: bnc#441338
5
6Impact: Changes timebase calibration on Vmware.
7
8v3->v2 : Abstract the hypervisor detection and feature (tsc_freq) request
9 behind a hypervisor.c file
10v2->v1 : Add a x86_hyper_vendor field to the cpuinfo_x86 structure.
11 This avoids multiple calls to the hypervisor detection function.
12
13This patch adds function to detect if we are running under VMware.
14The current way to check if we are on VMware is following,
15# check if "hypervisor present bit" is set, if so read the 0x40000000
16 cpuid leaf and check for "VMwareVMware" signature.
17# if the above fails, check the DMI vendors name for "VMware" string
18 if we find one we query the VMware hypervisor port to check if we are
19 under VMware.
20
21The DMI + "VMware hypervisor port check" is needed for older VMware products,
22which don't implement the hypervisor signature cpuid leaf.
23Also note that since we are checking for the DMI signature the hypervisor
24port should never be accessed on native hardware.
25
26This patch also adds a hypervisor_get_tsc_freq function, instead of
27calibrating the frequency which can be error prone in virtualized
28environment, we ask the hypervisor for it. We get the frequency from
29the hypervisor by accessing the hypervisor port if we are running on VMware.
30Other hypervisors too can add code to the generic routine to get frequency on
31their platform.
32
33Signed-off-by: Alok N Kataria <akataria@vmware.com>
34Signed-off-by: Dan Hecht <dhecht@vmware.com>
35Signed-off-by: H. Peter Anvin <hpa@zytor.com>
36Signed-off-by: Takashi Iwai <tiwai@suse.de>
37
38---
39
40 arch/x86/kernel/cpu/Makefile | 1
41 arch/x86/kernel/cpu/common.c | 2
42 arch/x86/kernel/cpu/common_64.c | 2
43 arch/x86/kernel/cpu/hypervisor.c | 48 +++++++++++++++++++++
44 arch/x86/kernel/cpu/vmware.c | 88 +++++++++++++++++++++++++++++++++++++++
45 arch/x86/kernel/setup.c | 7 +++
46 arch/x86/kernel/tsc.c | 9 +++
47 include/asm-x86/hypervisor.h | 26 +++++++++++
48 include/asm-x86/processor.h | 4 +
49 include/asm-x86/vmware.h | 26 +++++++++++
50 10 files changed, 212 insertions(+), 1 deletion(-)
51 create mode 100644 arch/x86/kernel/cpu/hypervisor.c
52 create mode 100644 arch/x86/kernel/cpu/vmware.c
53 create mode 100644 include/asm-x86/hypervisor.h
54 create mode 100644 include/asm-x86/vmware.h
55
56
57--- a/arch/x86/kernel/cpu/Makefile
58+++ b/arch/x86/kernel/cpu/Makefile
59@@ -4,6 +4,7 @@
60
61 obj-y := intel_cacheinfo.o addon_cpuid_features.o
62 obj-y += proc.o feature_names.o
63+obj-y += vmware.o hypervisor.o
64
65 obj-$(CONFIG_X86_32) += common.o bugs.o
66 obj-$(CONFIG_X86_64) += common_64.o bugs_64.o
67--- a/arch/x86/kernel/cpu/common.c
68+++ b/arch/x86/kernel/cpu/common.c
69@@ -14,6 +14,7 @@
70 #include <asm/mce.h>
71 #include <asm/pat.h>
72 #include <asm/asm.h>
73+#include <asm/hypervisor.h>
74 #ifdef CONFIG_X86_LOCAL_APIC
75 #include <asm/mpspec.h>
76 #include <asm/apic.h>
77@@ -505,6 +506,7 @@ static void __cpuinit identify_cpu(struc
78 c->x86, c->x86_model);
79 }
80
81+ init_hypervisor(c);
82 /*
83 * On SMP, boot_cpu_data holds the common feature set between
84 * all CPUs; so make sure that we indicate which features are
85--- a/arch/x86/kernel/cpu/common_64.c
86+++ b/arch/x86/kernel/cpu/common_64.c
87@@ -34,6 +34,7 @@
88 #include <asm/sections.h>
89 #include <asm/setup.h>
90 #include <asm/genapic.h>
91+#include <asm/hypervisor.h>
92
93 #include "cpu.h"
94
95@@ -387,6 +388,7 @@ static void __cpuinit identify_cpu(struc
96
97 detect_ht(c);
98
99+ init_hypervisor(c);
100 /*
101 * On SMP, boot_cpu_data holds the common feature set between
102 * all CPUs; so make sure that we indicate which features are
103--- /dev/null
104+++ b/arch/x86/kernel/cpu/hypervisor.c
105@@ -0,0 +1,48 @@
106+/*
107+ * Common hypervisor code
108+ *
109+ * Copyright (C) 2008, VMware, Inc.
110+ * Author : Alok N Kataria <akataria@vmware.com>
111+ *
112+ * This program is free software; you can redistribute it and/or modify
113+ * it under the terms of the GNU General Public License as published by
114+ * the Free Software Foundation; either version 2 of the License, or
115+ * (at your option) any later version.
116+ *
117+ * This program is distributed in the hope that it will be useful, but
118+ * WITHOUT ANY WARRANTY; without even the implied warranty of
119+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
120+ * NON INFRINGEMENT. See the GNU General Public License for more
121+ * details.
122+ *
123+ * You should have received a copy of the GNU General Public License
124+ * along with this program; if not, write to the Free Software
125+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
126+ *
127+ */
128+
129+#include <asm/processor.h>
130+#include <asm/vmware.h>
131+
132+static inline void __cpuinit
133+detect_hypervisor_vendor(struct cpuinfo_x86 *c)
134+{
135+ if (vmware_platform()) {
136+ c->x86_hyper_vendor = X86_HYPER_VENDOR_VMWARE;
137+ } else {
138+ c->x86_hyper_vendor = X86_HYPER_VENDOR_NONE;
139+ }
140+}
141+
142+unsigned long get_hypervisor_tsc_freq(void)
143+{
144+ if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE)
145+ return vmware_get_tsc_khz();
146+ return 0;
147+}
148+
149+void __cpuinit init_hypervisor(struct cpuinfo_x86 *c)
150+{
151+ detect_hypervisor_vendor(c);
152+}
153+
154--- /dev/null
155+++ b/arch/x86/kernel/cpu/vmware.c
156@@ -0,0 +1,88 @@
157+/*
158+ * VMware Detection code.
159+ *
160+ * Copyright (C) 2008, VMware, Inc.
161+ * Author : Alok N Kataria <akataria@vmware.com>
162+ *
163+ * This program is free software; you can redistribute it and/or modify
164+ * it under the terms of the GNU General Public License as published by
165+ * the Free Software Foundation; either version 2 of the License, or
166+ * (at your option) any later version.
167+ *
168+ * This program is distributed in the hope that it will be useful, but
169+ * WITHOUT ANY WARRANTY; without even the implied warranty of
170+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
171+ * NON INFRINGEMENT. See the GNU General Public License for more
172+ * details.
173+ *
174+ * You should have received a copy of the GNU General Public License
175+ * along with this program; if not, write to the Free Software
176+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
177+ *
178+ */
179+
180+#include <linux/dmi.h>
181+#include <asm/div64.h>
182+
183+#define CPUID_VMWARE_INFO_LEAF 0x40000000
184+#define VMWARE_HYPERVISOR_MAGIC 0x564D5868
185+#define VMWARE_HYPERVISOR_PORT 0x5658
186+
187+#define VMWARE_PORT_CMD_GETVERSION 10
188+#define VMWARE_PORT_CMD_GETHZ 45
189+
190+#define VMWARE_PORT(cmd, eax, ebx, ecx, edx) \
191+ __asm__("inl (%%dx)" : \
192+ "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \
193+ "0"(VMWARE_HYPERVISOR_MAGIC), \
194+ "1"(VMWARE_PORT_CMD_##cmd), \
195+ "2"(VMWARE_HYPERVISOR_PORT), "3"(0) : \
196+ "memory");
197+
198+static inline int __vmware_platform(void)
199+{
200+ uint32_t eax, ebx, ecx, edx;
201+ VMWARE_PORT(GETVERSION, eax, ebx, ecx, edx);
202+ return eax != (uint32_t)-1 && ebx == VMWARE_HYPERVISOR_MAGIC;
203+}
204+
205+static unsigned long __vmware_get_tsc_khz(void)
206+{
207+ uint64_t tsc_hz;
208+ uint32_t eax, ebx, ecx, edx;
209+
210+ VMWARE_PORT(GETHZ, eax, ebx, ecx, edx);
211+
212+ if (eax == (uint32_t)-1)
213+ return 0;
214+ tsc_hz = eax | (((uint64_t)ebx) << 32);
215+ do_div(tsc_hz, 1000);
216+ BUG_ON(tsc_hz >> 32);
217+ return tsc_hz;
218+}
219+
220+int vmware_platform(void)
221+{
222+ if (cpu_has_hypervisor) {
223+ unsigned int eax, ebx, ecx, edx;
224+ char hyper_vendor_id[13];
225+
226+ cpuid(CPUID_VMWARE_INFO_LEAF, &eax, &ebx, &ecx, &edx);
227+ memcpy(hyper_vendor_id + 0, &ebx, 4);
228+ memcpy(hyper_vendor_id + 4, &ecx, 4);
229+ memcpy(hyper_vendor_id + 8, &edx, 4);
230+ hyper_vendor_id[12] = '\0';
231+ if (!strcmp(hyper_vendor_id, "VMwareVMware"))
232+ return 1;
233+ } else if (dmi_available && dmi_name_in_vendors("VMware") &&
234+ __vmware_platform())
235+ return 1;
236+
237+ return 0;
238+}
239+
240+unsigned long vmware_get_tsc_khz(void)
241+{
242+ BUG_ON(!vmware_platform());
243+ return __vmware_get_tsc_khz();
244+}
245--- a/arch/x86/kernel/setup.c
246+++ b/arch/x86/kernel/setup.c
247@@ -98,6 +98,7 @@
248
249 #include <mach_apic.h>
250 #include <asm/paravirt.h>
251+#include <asm/hypervisor.h>
252
253 #include <asm/percpu.h>
254 #include <asm/topology.h>
255@@ -896,6 +897,12 @@ void __init setup_arch(char **cmdline_p)
256 e820_reserve_resources();
257 e820_mark_nosave_regions(max_low_pfn);
258
259+ /*
260+ * VMware detection requires dmi to be available, so this
261+ * needs to be done after dmi_scan_machine, for the BP.
262+ */
263+ init_hypervisor(&boot_cpu_data);
264+
265 #ifdef CONFIG_X86_32
266 request_resource(&iomem_resource, &video_ram_resource);
267 #endif
268--- a/arch/x86/kernel/tsc.c
269+++ b/arch/x86/kernel/tsc.c
270@@ -15,6 +15,7 @@
271 #include <asm/vgtod.h>
272 #include <asm/time.h>
273 #include <asm/delay.h>
274+#include <asm/hypervisor.h>
275
276 unsigned int cpu_khz; /* TSC clocks / usec, not used here */
277 EXPORT_SYMBOL(cpu_khz);
278@@ -189,9 +190,15 @@ unsigned long native_calibrate_tsc(void)
279 {
280 u64 tsc1, tsc2, delta, pm1, pm2, hpet1, hpet2;
281 unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX;
282- unsigned long flags;
283+ unsigned long flags, tsc_khz;
284 int hpet = is_hpet_enabled(), i;
285
286+ tsc_khz = get_hypervisor_tsc_freq();
287+ if (tsc_khz) {
288+ printk(KERN_INFO "TSC: Frequency read from the hypervisor\n");
289+ return tsc_khz;
290+ }
291+
292 /*
293 * Run 5 calibration loops to get the lowest frequency value
294 * (the best estimate). We use two different calibration modes
295--- /dev/null
296+++ b/include/asm-x86/hypervisor.h
297@@ -0,0 +1,26 @@
298+/*
299+ * Copyright (C) 2008, VMware, Inc.
300+ *
301+ * This program is free software; you can redistribute it and/or modify
302+ * it under the terms of the GNU General Public License as published by
303+ * the Free Software Foundation; either version 2 of the License, or
304+ * (at your option) any later version.
305+ *
306+ * This program is distributed in the hope that it will be useful, but
307+ * WITHOUT ANY WARRANTY; without even the implied warranty of
308+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
309+ * NON INFRINGEMENT. See the GNU General Public License for more
310+ * details.
311+ *
312+ * You should have received a copy of the GNU General Public License
313+ * along with this program; if not, write to the Free Software
314+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
315+ *
316+ */
317+#ifndef ASM_X86__HYPERVISOR_H
318+#define ASM_X86__HYPERVISOR_H
319+
320+extern unsigned long get_hypervisor_tsc_freq(void);
321+extern void init_hypervisor(struct cpuinfo_x86 *c);
322+
323+#endif
324--- a/include/asm-x86/processor.h
325+++ b/include/asm-x86/processor.h
326@@ -109,6 +109,7 @@ struct cpuinfo_x86 {
327 /* Index into per_cpu list: */
328 u16 cpu_index;
329 #endif
330+ unsigned int x86_hyper_vendor;
331 } __attribute__((__aligned__(SMP_CACHE_BYTES)));
332
333 #define X86_VENDOR_INTEL 0
334@@ -122,6 +123,9 @@ struct cpuinfo_x86 {
335
336 #define X86_VENDOR_UNKNOWN 0xff
337
338+#define X86_HYPER_VENDOR_NONE 0
339+#define X86_HYPER_VENDOR_VMWARE 1
340+
341 /*
342 * capabilities of CPUs
343 */
344--- /dev/null
345+++ b/include/asm-x86/vmware.h
346@@ -0,0 +1,26 @@
347+/*
348+ * Copyright (C) 2008, VMware, Inc.
349+ *
350+ * This program is free software; you can redistribute it and/or modify
351+ * it under the terms of the GNU General Public License as published by
352+ * the Free Software Foundation; either version 2 of the License, or
353+ * (at your option) any later version.
354+ *
355+ * This program is distributed in the hope that it will be useful, but
356+ * WITHOUT ANY WARRANTY; without even the implied warranty of
357+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
358+ * NON INFRINGEMENT. See the GNU General Public License for more
359+ * details.
360+ *
361+ * You should have received a copy of the GNU General Public License
362+ * along with this program; if not, write to the Free Software
363+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
364+ *
365+ */
366+#ifndef ASM_X86__VMWARE_H
367+#define ASM_X86__VMWARE_H
368+
369+extern unsigned long vmware_get_tsc_khz(void);
370+extern int vmware_platform(void);
371+
372+#endif