diff options
-rw-r--r-- | arch/x86/include/asm/hypervisor.h | 13 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/hypervisor.c | 7 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/vmware.c | 13 | ||||
-rw-r--r-- | arch/x86/kernel/kvm.c | 1 | ||||
-rw-r--r-- | arch/x86/xen/enlighten.c | 1 |
5 files changed, 26 insertions, 9 deletions
diff --git a/arch/x86/include/asm/hypervisor.h b/arch/x86/include/asm/hypervisor.h index b518c7509933..86095ed14135 100644 --- a/arch/x86/include/asm/hypervisor.h +++ b/arch/x86/include/asm/hypervisor.h | |||
@@ -25,6 +25,7 @@ | |||
25 | 25 | ||
26 | extern void init_hypervisor(struct cpuinfo_x86 *c); | 26 | extern void init_hypervisor(struct cpuinfo_x86 *c); |
27 | extern void init_hypervisor_platform(void); | 27 | extern void init_hypervisor_platform(void); |
28 | extern bool hypervisor_x2apic_available(void); | ||
28 | 29 | ||
29 | /* | 30 | /* |
30 | * x86 hypervisor information | 31 | * x86 hypervisor information |
@@ -41,6 +42,9 @@ struct hypervisor_x86 { | |||
41 | 42 | ||
42 | /* Platform setup (run once per boot) */ | 43 | /* Platform setup (run once per boot) */ |
43 | void (*init_platform)(void); | 44 | void (*init_platform)(void); |
45 | |||
46 | /* X2APIC detection (run once per boot) */ | ||
47 | bool (*x2apic_available)(void); | ||
44 | }; | 48 | }; |
45 | 49 | ||
46 | extern const struct hypervisor_x86 *x86_hyper; | 50 | extern const struct hypervisor_x86 *x86_hyper; |
@@ -51,13 +55,4 @@ extern const struct hypervisor_x86 x86_hyper_ms_hyperv; | |||
51 | extern const struct hypervisor_x86 x86_hyper_xen_hvm; | 55 | extern const struct hypervisor_x86 x86_hyper_xen_hvm; |
52 | extern const struct hypervisor_x86 x86_hyper_kvm; | 56 | extern const struct hypervisor_x86 x86_hyper_kvm; |
53 | 57 | ||
54 | static inline bool hypervisor_x2apic_available(void) | ||
55 | { | ||
56 | if (kvm_para_available()) | ||
57 | return true; | ||
58 | if (xen_x2apic_para_available()) | ||
59 | return true; | ||
60 | return false; | ||
61 | } | ||
62 | |||
63 | #endif | 58 | #endif |
diff --git a/arch/x86/kernel/cpu/hypervisor.c b/arch/x86/kernel/cpu/hypervisor.c index a8f8fa9769d6..1e7e84a02eba 100644 --- a/arch/x86/kernel/cpu/hypervisor.c +++ b/arch/x86/kernel/cpu/hypervisor.c | |||
@@ -79,3 +79,10 @@ void __init init_hypervisor_platform(void) | |||
79 | if (x86_hyper->init_platform) | 79 | if (x86_hyper->init_platform) |
80 | x86_hyper->init_platform(); | 80 | x86_hyper->init_platform(); |
81 | } | 81 | } |
82 | |||
83 | bool __init hypervisor_x2apic_available(void) | ||
84 | { | ||
85 | return x86_hyper && | ||
86 | x86_hyper->x2apic_available && | ||
87 | x86_hyper->x2apic_available(); | ||
88 | } | ||
diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c index d22d0c4edcfd..03a36321ec54 100644 --- a/arch/x86/kernel/cpu/vmware.c +++ b/arch/x86/kernel/cpu/vmware.c | |||
@@ -33,6 +33,9 @@ | |||
33 | 33 | ||
34 | #define VMWARE_PORT_CMD_GETVERSION 10 | 34 | #define VMWARE_PORT_CMD_GETVERSION 10 |
35 | #define VMWARE_PORT_CMD_GETHZ 45 | 35 | #define VMWARE_PORT_CMD_GETHZ 45 |
36 | #define VMWARE_PORT_CMD_GETVCPU_INFO 68 | ||
37 | #define VMWARE_PORT_CMD_LEGACY_X2APIC 3 | ||
38 | #define VMWARE_PORT_CMD_VCPU_RESERVED 31 | ||
36 | 39 | ||
37 | #define VMWARE_PORT(cmd, eax, ebx, ecx, edx) \ | 40 | #define VMWARE_PORT(cmd, eax, ebx, ecx, edx) \ |
38 | __asm__("inl (%%dx)" : \ | 41 | __asm__("inl (%%dx)" : \ |
@@ -125,10 +128,20 @@ static void __cpuinit vmware_set_cpu_features(struct cpuinfo_x86 *c) | |||
125 | set_cpu_cap(c, X86_FEATURE_TSC_RELIABLE); | 128 | set_cpu_cap(c, X86_FEATURE_TSC_RELIABLE); |
126 | } | 129 | } |
127 | 130 | ||
131 | /* Checks if hypervisor supports x2apic without VT-D interrupt remapping. */ | ||
132 | static bool __init vmware_legacy_x2apic_available(void) | ||
133 | { | ||
134 | uint32_t eax, ebx, ecx, edx; | ||
135 | VMWARE_PORT(GETVCPU_INFO, eax, ebx, ecx, edx); | ||
136 | return (eax & (1 << VMWARE_PORT_CMD_VCPU_RESERVED)) == 0 && | ||
137 | (eax & (1 << VMWARE_PORT_CMD_LEGACY_X2APIC)) != 0; | ||
138 | } | ||
139 | |||
128 | const __refconst struct hypervisor_x86 x86_hyper_vmware = { | 140 | const __refconst struct hypervisor_x86 x86_hyper_vmware = { |
129 | .name = "VMware", | 141 | .name = "VMware", |
130 | .detect = vmware_platform, | 142 | .detect = vmware_platform, |
131 | .set_cpu_features = vmware_set_cpu_features, | 143 | .set_cpu_features = vmware_set_cpu_features, |
132 | .init_platform = vmware_platform_setup, | 144 | .init_platform = vmware_platform_setup, |
145 | .x2apic_available = vmware_legacy_x2apic_available, | ||
133 | }; | 146 | }; |
134 | EXPORT_SYMBOL(x86_hyper_vmware); | 147 | EXPORT_SYMBOL(x86_hyper_vmware); |
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 9c2bd8bd4b4c..2b44ea5f269d 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c | |||
@@ -505,6 +505,7 @@ static bool __init kvm_detect(void) | |||
505 | const struct hypervisor_x86 x86_hyper_kvm __refconst = { | 505 | const struct hypervisor_x86 x86_hyper_kvm __refconst = { |
506 | .name = "KVM", | 506 | .name = "KVM", |
507 | .detect = kvm_detect, | 507 | .detect = kvm_detect, |
508 | .x2apic_available = kvm_para_available, | ||
508 | }; | 509 | }; |
509 | EXPORT_SYMBOL_GPL(x86_hyper_kvm); | 510 | EXPORT_SYMBOL_GPL(x86_hyper_kvm); |
510 | 511 | ||
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 138e5667409a..8b4c56d85ca0 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -1668,6 +1668,7 @@ const struct hypervisor_x86 x86_hyper_xen_hvm __refconst = { | |||
1668 | .name = "Xen HVM", | 1668 | .name = "Xen HVM", |
1669 | .detect = xen_hvm_platform, | 1669 | .detect = xen_hvm_platform, |
1670 | .init_platform = xen_hvm_guest_init, | 1670 | .init_platform = xen_hvm_guest_init, |
1671 | .x2apic_available = xen_x2apic_para_available, | ||
1671 | }; | 1672 | }; |
1672 | EXPORT_SYMBOL(x86_hyper_xen_hvm); | 1673 | EXPORT_SYMBOL(x86_hyper_xen_hvm); |
1673 | #endif | 1674 | #endif |