aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/hypervisor.h25
-rw-r--r--arch/x86/include/asm/x86_init.h24
-rw-r--r--arch/x86/kernel/apic/apic.c2
-rw-r--r--arch/x86/kernel/cpu/hypervisor.c54
-rw-r--r--arch/x86/kernel/cpu/mshyperv.c2
-rw-r--r--arch/x86/kernel/cpu/vmware.c4
-rw-r--r--arch/x86/kernel/kvm.c2
-rw-r--r--arch/x86/kernel/x86_init.c9
-rw-r--r--arch/x86/mm/init.c2
-rw-r--r--arch/x86/xen/enlighten_hvm.c8
-rw-r--r--arch/x86/xen/enlighten_pv.c2
-rw-r--r--include/linux/hypervisor.h8
12 files changed, 81 insertions, 61 deletions
diff --git a/arch/x86/include/asm/hypervisor.h b/arch/x86/include/asm/hypervisor.h
index 0ead9dbb9130..0eca7239a7aa 100644
--- a/arch/x86/include/asm/hypervisor.h
+++ b/arch/x86/include/asm/hypervisor.h
@@ -23,6 +23,7 @@
23#ifdef CONFIG_HYPERVISOR_GUEST 23#ifdef CONFIG_HYPERVISOR_GUEST
24 24
25#include <asm/kvm_para.h> 25#include <asm/kvm_para.h>
26#include <asm/x86_init.h>
26#include <asm/xen/hypervisor.h> 27#include <asm/xen/hypervisor.h>
27 28
28/* 29/*
@@ -35,17 +36,11 @@ struct hypervisor_x86 {
35 /* Detection routine */ 36 /* Detection routine */
36 uint32_t (*detect)(void); 37 uint32_t (*detect)(void);
37 38
38 /* Platform setup (run once per boot) */ 39 /* init time callbacks */
39 void (*init_platform)(void); 40 struct x86_hyper_init init;
40 41
41 /* X2APIC detection (run once per boot) */ 42 /* runtime callbacks */
42 bool (*x2apic_available)(void); 43 struct x86_hyper_runtime runtime;
43
44 /* pin current vcpu to specified physical cpu (run rarely) */
45 void (*pin_vcpu)(int);
46
47 /* called during init_mem_mapping() to setup early mappings. */
48 void (*init_mem_mapping)(void);
49}; 44};
50 45
51extern const struct hypervisor_x86 *x86_hyper; 46extern const struct hypervisor_x86 *x86_hyper;
@@ -58,17 +53,7 @@ extern const struct hypervisor_x86 x86_hyper_xen_hvm;
58extern const struct hypervisor_x86 x86_hyper_kvm; 53extern const struct hypervisor_x86 x86_hyper_kvm;
59 54
60extern void init_hypervisor_platform(void); 55extern void init_hypervisor_platform(void);
61extern bool hypervisor_x2apic_available(void);
62extern void hypervisor_pin_vcpu(int cpu);
63
64static inline void hypervisor_init_mem_mapping(void)
65{
66 if (x86_hyper && x86_hyper->init_mem_mapping)
67 x86_hyper->init_mem_mapping();
68}
69#else 56#else
70static inline void init_hypervisor_platform(void) { } 57static inline void init_hypervisor_platform(void) { }
71static inline bool hypervisor_x2apic_available(void) { return false; }
72static inline void hypervisor_init_mem_mapping(void) { }
73#endif /* CONFIG_HYPERVISOR_GUEST */ 58#endif /* CONFIG_HYPERVISOR_GUEST */
74#endif /* _ASM_X86_HYPERVISOR_H */ 59#endif /* _ASM_X86_HYPERVISOR_H */
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index 8a1ebf9540dd..ad15a0fda917 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -115,6 +115,18 @@ struct x86_init_pci {
115}; 115};
116 116
117/** 117/**
118 * struct x86_hyper_init - x86 hypervisor init functions
119 * @init_platform: platform setup
120 * @x2apic_available: X2APIC detection
121 * @init_mem_mapping: setup early mappings during init_mem_mapping()
122 */
123struct x86_hyper_init {
124 void (*init_platform)(void);
125 bool (*x2apic_available)(void);
126 void (*init_mem_mapping)(void);
127};
128
129/**
118 * struct x86_init_ops - functions for platform specific setup 130 * struct x86_init_ops - functions for platform specific setup
119 * 131 *
120 */ 132 */
@@ -127,6 +139,7 @@ struct x86_init_ops {
127 struct x86_init_timers timers; 139 struct x86_init_timers timers;
128 struct x86_init_iommu iommu; 140 struct x86_init_iommu iommu;
129 struct x86_init_pci pci; 141 struct x86_init_pci pci;
142 struct x86_hyper_init hyper;
130}; 143};
131 144
132/** 145/**
@@ -200,6 +213,15 @@ struct x86_legacy_features {
200}; 213};
201 214
202/** 215/**
216 * struct x86_hyper_runtime - x86 hypervisor specific runtime callbacks
217 *
218 * @pin_vcpu: pin current vcpu to specified physical cpu (run rarely)
219 */
220struct x86_hyper_runtime {
221 void (*pin_vcpu)(int cpu);
222};
223
224/**
203 * struct x86_platform_ops - platform specific runtime functions 225 * struct x86_platform_ops - platform specific runtime functions
204 * @calibrate_cpu: calibrate CPU 226 * @calibrate_cpu: calibrate CPU
205 * @calibrate_tsc: calibrate TSC, if different from CPU 227 * @calibrate_tsc: calibrate TSC, if different from CPU
@@ -218,6 +240,7 @@ struct x86_legacy_features {
218 * possible in x86_early_init_platform_quirks() by 240 * possible in x86_early_init_platform_quirks() by
219 * only using the current x86_hardware_subarch 241 * only using the current x86_hardware_subarch
220 * semantics. 242 * semantics.
243 * @hyper: x86 hypervisor specific runtime callbacks
221 */ 244 */
222struct x86_platform_ops { 245struct x86_platform_ops {
223 unsigned long (*calibrate_cpu)(void); 246 unsigned long (*calibrate_cpu)(void);
@@ -233,6 +256,7 @@ struct x86_platform_ops {
233 void (*apic_post_init)(void); 256 void (*apic_post_init)(void);
234 struct x86_legacy_features legacy; 257 struct x86_legacy_features legacy;
235 void (*set_legacy_features)(void); 258 void (*set_legacy_features)(void);
259 struct x86_hyper_runtime hyper;
236}; 260};
237 261
238struct pci_dev; 262struct pci_dev;
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index ff891772c9f8..89c7c8569e5e 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1645,7 +1645,7 @@ static __init void try_to_enable_x2apic(int remap_mode)
1645 * under KVM 1645 * under KVM
1646 */ 1646 */
1647 if (max_physical_apicid > 255 || 1647 if (max_physical_apicid > 255 ||
1648 !hypervisor_x2apic_available()) { 1648 !x86_init.hyper.x2apic_available()) {
1649 pr_info("x2apic: IRQ remapping doesn't support X2APIC mode\n"); 1649 pr_info("x2apic: IRQ remapping doesn't support X2APIC mode\n");
1650 x2apic_disable(); 1650 x2apic_disable();
1651 return; 1651 return;
diff --git a/arch/x86/kernel/cpu/hypervisor.c b/arch/x86/kernel/cpu/hypervisor.c
index 4fa90006ac68..22226c1bf092 100644
--- a/arch/x86/kernel/cpu/hypervisor.c
+++ b/arch/x86/kernel/cpu/hypervisor.c
@@ -44,51 +44,49 @@ static const __initconst struct hypervisor_x86 * const hypervisors[] =
44const struct hypervisor_x86 *x86_hyper; 44const struct hypervisor_x86 *x86_hyper;
45EXPORT_SYMBOL(x86_hyper); 45EXPORT_SYMBOL(x86_hyper);
46 46
47static inline void __init 47static inline const struct hypervisor_x86 * __init
48detect_hypervisor_vendor(void) 48detect_hypervisor_vendor(void)
49{ 49{
50 const struct hypervisor_x86 *h, * const *p; 50 const struct hypervisor_x86 *h = NULL, * const *p;
51 uint32_t pri, max_pri = 0; 51 uint32_t pri, max_pri = 0;
52 52
53 for (p = hypervisors; p < hypervisors + ARRAY_SIZE(hypervisors); p++) { 53 for (p = hypervisors; p < hypervisors + ARRAY_SIZE(hypervisors); p++) {
54 h = *p; 54 pri = (*p)->detect();
55 pri = h->detect(); 55 if (pri > max_pri) {
56 if (pri != 0 && pri > max_pri) {
57 max_pri = pri; 56 max_pri = pri;
58 x86_hyper = h; 57 h = *p;
59 } 58 }
60 } 59 }
61 60
62 if (max_pri) 61 if (h)
63 pr_info("Hypervisor detected: %s\n", x86_hyper->name); 62 pr_info("Hypervisor detected: %s\n", h->name);
63
64 return h;
64} 65}
65 66
66void __init init_hypervisor_platform(void) 67static void __init copy_array(const void *src, void *target, unsigned int size)
67{ 68{
69 unsigned int i, n = size / sizeof(void *);
70 const void * const *from = (const void * const *)src;
71 const void **to = (const void **)target;
68 72
69 detect_hypervisor_vendor(); 73 for (i = 0; i < n; i++)
70 74 if (from[i])
71 if (!x86_hyper) 75 to[i] = from[i];
72 return;
73
74 if (x86_hyper->init_platform)
75 x86_hyper->init_platform();
76} 76}
77 77
78bool __init hypervisor_x2apic_available(void) 78void __init init_hypervisor_platform(void)
79{ 79{
80 return x86_hyper && 80 const struct hypervisor_x86 *h;
81 x86_hyper->x2apic_available &&
82 x86_hyper->x2apic_available();
83}
84 81
85void hypervisor_pin_vcpu(int cpu) 82 h = detect_hypervisor_vendor();
86{ 83
87 if (!x86_hyper) 84 if (!h)
88 return; 85 return;
89 86
90 if (x86_hyper->pin_vcpu) 87 copy_array(&h->init, &x86_init.hyper, sizeof(h->init));
91 x86_hyper->pin_vcpu(cpu); 88 copy_array(&h->runtime, &x86_platform.hyper, sizeof(h->runtime));
92 else 89
93 WARN_ONCE(1, "vcpu pinning requested but not supported!\n"); 90 x86_hyper = h;
91 x86_init.hyper.init_platform();
94} 92}
diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
index 236324e83a3a..6bb84d655e4b 100644
--- a/arch/x86/kernel/cpu/mshyperv.c
+++ b/arch/x86/kernel/cpu/mshyperv.c
@@ -257,6 +257,6 @@ static void __init ms_hyperv_init_platform(void)
257const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = { 257const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
258 .name = "Microsoft Hyper-V", 258 .name = "Microsoft Hyper-V",
259 .detect = ms_hyperv_platform, 259 .detect = ms_hyperv_platform,
260 .init_platform = ms_hyperv_init_platform, 260 .init.init_platform = ms_hyperv_init_platform,
261}; 261};
262EXPORT_SYMBOL(x86_hyper_ms_hyperv); 262EXPORT_SYMBOL(x86_hyper_ms_hyperv);
diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c
index 40ed26852ebd..4804c1d063c8 100644
--- a/arch/x86/kernel/cpu/vmware.c
+++ b/arch/x86/kernel/cpu/vmware.c
@@ -208,7 +208,7 @@ static bool __init vmware_legacy_x2apic_available(void)
208const __refconst struct hypervisor_x86 x86_hyper_vmware = { 208const __refconst struct hypervisor_x86 x86_hyper_vmware = {
209 .name = "VMware", 209 .name = "VMware",
210 .detect = vmware_platform, 210 .detect = vmware_platform,
211 .init_platform = vmware_platform_setup, 211 .init.init_platform = vmware_platform_setup,
212 .x2apic_available = vmware_legacy_x2apic_available, 212 .init.x2apic_available = vmware_legacy_x2apic_available,
213}; 213};
214EXPORT_SYMBOL(x86_hyper_vmware); 214EXPORT_SYMBOL(x86_hyper_vmware);
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index 8bb9594d0761..9dca8437c795 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -547,7 +547,7 @@ static uint32_t __init kvm_detect(void)
547const struct hypervisor_x86 x86_hyper_kvm __refconst = { 547const struct hypervisor_x86 x86_hyper_kvm __refconst = {
548 .name = "KVM", 548 .name = "KVM",
549 .detect = kvm_detect, 549 .detect = kvm_detect,
550 .x2apic_available = kvm_para_available, 550 .init.x2apic_available = kvm_para_available,
551}; 551};
552EXPORT_SYMBOL_GPL(x86_hyper_kvm); 552EXPORT_SYMBOL_GPL(x86_hyper_kvm);
553 553
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index a088b2c47f73..5b2d10c1973a 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -28,6 +28,8 @@ void x86_init_noop(void) { }
28void __init x86_init_uint_noop(unsigned int unused) { } 28void __init x86_init_uint_noop(unsigned int unused) { }
29int __init iommu_init_noop(void) { return 0; } 29int __init iommu_init_noop(void) { return 0; }
30void iommu_shutdown_noop(void) { } 30void iommu_shutdown_noop(void) { }
31bool __init bool_x86_init_noop(void) { return false; }
32void x86_op_int_noop(int cpu) { }
31 33
32/* 34/*
33 * The platform setup functions are preset with the default functions 35 * The platform setup functions are preset with the default functions
@@ -81,6 +83,12 @@ struct x86_init_ops x86_init __initdata = {
81 .init_irq = x86_default_pci_init_irq, 83 .init_irq = x86_default_pci_init_irq,
82 .fixup_irqs = x86_default_pci_fixup_irqs, 84 .fixup_irqs = x86_default_pci_fixup_irqs,
83 }, 85 },
86
87 .hyper = {
88 .init_platform = x86_init_noop,
89 .x2apic_available = bool_x86_init_noop,
90 .init_mem_mapping = x86_init_noop,
91 },
84}; 92};
85 93
86struct x86_cpuinit_ops x86_cpuinit = { 94struct x86_cpuinit_ops x86_cpuinit = {
@@ -101,6 +109,7 @@ struct x86_platform_ops x86_platform __ro_after_init = {
101 .get_nmi_reason = default_get_nmi_reason, 109 .get_nmi_reason = default_get_nmi_reason,
102 .save_sched_clock_state = tsc_save_sched_clock_state, 110 .save_sched_clock_state = tsc_save_sched_clock_state,
103 .restore_sched_clock_state = tsc_restore_sched_clock_state, 111 .restore_sched_clock_state = tsc_restore_sched_clock_state,
112 .hyper.pin_vcpu = x86_op_int_noop,
104}; 113};
105 114
106EXPORT_SYMBOL_GPL(x86_platform); 115EXPORT_SYMBOL_GPL(x86_platform);
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index af5c1ed21d43..a22c2b95e513 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -671,7 +671,7 @@ void __init init_mem_mapping(void)
671 load_cr3(swapper_pg_dir); 671 load_cr3(swapper_pg_dir);
672 __flush_tlb_all(); 672 __flush_tlb_all();
673 673
674 hypervisor_init_mem_mapping(); 674 x86_init.hyper.init_mem_mapping();
675 675
676 early_memtest(0, max_pfn_mapped << PAGE_SHIFT); 676 early_memtest(0, max_pfn_mapped << PAGE_SHIFT);
677} 677}
diff --git a/arch/x86/xen/enlighten_hvm.c b/arch/x86/xen/enlighten_hvm.c
index de503c225ae1..7b1622089f96 100644
--- a/arch/x86/xen/enlighten_hvm.c
+++ b/arch/x86/xen/enlighten_hvm.c
@@ -229,9 +229,9 @@ static uint32_t __init xen_platform_hvm(void)
229const struct hypervisor_x86 x86_hyper_xen_hvm = { 229const struct hypervisor_x86 x86_hyper_xen_hvm = {
230 .name = "Xen HVM", 230 .name = "Xen HVM",
231 .detect = xen_platform_hvm, 231 .detect = xen_platform_hvm,
232 .init_platform = xen_hvm_guest_init, 232 .init.init_platform = xen_hvm_guest_init,
233 .pin_vcpu = xen_pin_vcpu, 233 .init.x2apic_available = xen_x2apic_para_available,
234 .x2apic_available = xen_x2apic_para_available, 234 .init.init_mem_mapping = xen_hvm_init_mem_mapping,
235 .init_mem_mapping = xen_hvm_init_mem_mapping, 235 .runtime.pin_vcpu = xen_pin_vcpu,
236}; 236};
237EXPORT_SYMBOL(x86_hyper_xen_hvm); 237EXPORT_SYMBOL(x86_hyper_xen_hvm);
diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c
index d4396e27b1fb..69d1a7054ddb 100644
--- a/arch/x86/xen/enlighten_pv.c
+++ b/arch/x86/xen/enlighten_pv.c
@@ -1463,6 +1463,6 @@ static uint32_t __init xen_platform_pv(void)
1463const struct hypervisor_x86 x86_hyper_xen_pv = { 1463const struct hypervisor_x86 x86_hyper_xen_pv = {
1464 .name = "Xen PV", 1464 .name = "Xen PV",
1465 .detect = xen_platform_pv, 1465 .detect = xen_platform_pv,
1466 .pin_vcpu = xen_pin_vcpu, 1466 .runtime.pin_vcpu = xen_pin_vcpu,
1467}; 1467};
1468EXPORT_SYMBOL(x86_hyper_xen_pv); 1468EXPORT_SYMBOL(x86_hyper_xen_pv);
diff --git a/include/linux/hypervisor.h b/include/linux/hypervisor.h
index b4054fd5b6f6..b19563f9a8eb 100644
--- a/include/linux/hypervisor.h
+++ b/include/linux/hypervisor.h
@@ -7,8 +7,12 @@
7 * Juergen Gross <jgross@suse.com> 7 * Juergen Gross <jgross@suse.com>
8 */ 8 */
9 9
10#ifdef CONFIG_HYPERVISOR_GUEST 10#ifdef CONFIG_X86
11#include <asm/hypervisor.h> 11#include <asm/x86_init.h>
12static inline void hypervisor_pin_vcpu(int cpu)
13{
14 x86_platform.hyper.pin_vcpu(cpu);
15}
12#else 16#else
13static inline void hypervisor_pin_vcpu(int cpu) 17static inline void hypervisor_pin_vcpu(int cpu)
14{ 18{