diff options
author | Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> | 2010-08-04 17:49:16 -0400 |
---|---|---|
committer | Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> | 2010-08-04 17:49:16 -0400 |
commit | ca50a5f39041497253c6362f2ba4da1b56d3e6cb (patch) | |
tree | 482f1607d12b60f6ef482bb4af2c9c58d7814d5f | |
parent | a70ce4b6064b64477ed12ef1878980f842819094 (diff) | |
parent | ca65f9fc0c447da5b270b05c41c21b19c88617c3 (diff) |
Merge branch 'upstream/pvhvm' into upstream/xen
* upstream/pvhvm:
Introduce CONFIG_XEN_PVHVM compile option
blkfront: do not create a PV cdrom device if xen_hvm_guest
support multiple .discard.* sections to avoid section type conflicts
xen/pvhvm: fix build problem when !CONFIG_XEN
xenfs: enable for HVM domains too
x86: Call HVMOP_pagetable_dying on exit_mmap.
x86: Unplug emulated disks and nics.
x86: Use xen_vcpuop_clockevent, xen_clocksource and xen wallclock.
xen: Fix find_unbound_irq in presence of ioapic irqs.
xen: Add suspend/resume support for PV on HVM guests.
xen: Xen PCI platform device driver.
x86/xen: event channels delivery on HVM.
x86: early PV on HVM features initialization.
xen: Add support for HVM hypercalls.
Conflicts:
arch/x86/xen/enlighten.c
arch/x86/xen/time.c
39 files changed, 1156 insertions, 61 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 2b2407d9a6d0..2f32da74f5b1 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -115,6 +115,7 @@ parameter is applicable: | |||
115 | More X86-64 boot options can be found in | 115 | More X86-64 boot options can be found in |
116 | Documentation/x86/x86_64/boot-options.txt . | 116 | Documentation/x86/x86_64/boot-options.txt . |
117 | X86 Either 32bit or 64bit x86 (same as X86-32+X86-64) | 117 | X86 Either 32bit or 64bit x86 (same as X86-32+X86-64) |
118 | XEN Xen support is enabled | ||
118 | 119 | ||
119 | In addition, the following text indicates that the option: | 120 | In addition, the following text indicates that the option: |
120 | 121 | ||
@@ -2879,6 +2880,16 @@ and is between 256 and 4096 characters. It is defined in the file | |||
2879 | xd= [HW,XT] Original XT pre-IDE (RLL encoded) disks. | 2880 | xd= [HW,XT] Original XT pre-IDE (RLL encoded) disks. |
2880 | xd_geo= See header of drivers/block/xd.c. | 2881 | xd_geo= See header of drivers/block/xd.c. |
2881 | 2882 | ||
2883 | xen_emul_unplug= [HW,X86,XEN] | ||
2884 | Unplug Xen emulated devices | ||
2885 | Format: [unplug0,][unplug1] | ||
2886 | ide-disks -- unplug primary master IDE devices | ||
2887 | aux-ide-disks -- unplug non-primary-master IDE devices | ||
2888 | nics -- unplug network devices | ||
2889 | all -- unplug all emulated devices (NICs and IDE disks) | ||
2890 | ignore -- continue loading the Xen platform PCI driver even | ||
2891 | if the version check failed | ||
2892 | |||
2882 | xirc2ps_cs= [NET,PCMCIA] | 2893 | xirc2ps_cs= [NET,PCMCIA] |
2883 | Format: | 2894 | Format: |
2884 | <irq>,<irq_mask>,<io>,<full_duplex>,<do_sound>,<lockup_hack>[,<irq2>[,<irq3>[,<irq4>]]] | 2895 | <irq>,<irq_mask>,<io>,<full_duplex>,<do_sound>,<lockup_hack>[,<irq2>[,<irq3>[,<irq4>]]] |
diff --git a/arch/x86/include/asm/hypervisor.h b/arch/x86/include/asm/hypervisor.h index 70abda7058c8..ff2546ce7178 100644 --- a/arch/x86/include/asm/hypervisor.h +++ b/arch/x86/include/asm/hypervisor.h | |||
@@ -45,5 +45,6 @@ extern const struct hypervisor_x86 *x86_hyper; | |||
45 | /* Recognized hypervisors */ | 45 | /* Recognized hypervisors */ |
46 | extern const struct hypervisor_x86 x86_hyper_vmware; | 46 | extern const struct hypervisor_x86 x86_hyper_vmware; |
47 | extern const struct hypervisor_x86 x86_hyper_ms_hyperv; | 47 | extern const struct hypervisor_x86 x86_hyper_ms_hyperv; |
48 | extern const struct hypervisor_x86 x86_hyper_xen_hvm; | ||
48 | 49 | ||
49 | #endif | 50 | #endif |
diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h index 8767d99c4f64..e2ca30092557 100644 --- a/arch/x86/include/asm/irq_vectors.h +++ b/arch/x86/include/asm/irq_vectors.h | |||
@@ -125,6 +125,9 @@ | |||
125 | */ | 125 | */ |
126 | #define MCE_SELF_VECTOR 0xeb | 126 | #define MCE_SELF_VECTOR 0xeb |
127 | 127 | ||
128 | /* Xen vector callback to receive events in a HVM domain */ | ||
129 | #define XEN_HVM_EVTCHN_CALLBACK 0xe9 | ||
130 | |||
128 | #define NR_VECTORS 256 | 131 | #define NR_VECTORS 256 |
129 | 132 | ||
130 | #define FPU_IRQ 13 | 133 | #define FPU_IRQ 13 |
diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h index 86b1506f4179..ef292c792d74 100644 --- a/arch/x86/include/asm/setup.h +++ b/arch/x86/include/asm/setup.h | |||
@@ -82,7 +82,7 @@ void *extend_brk(size_t size, size_t align); | |||
82 | * executable.) | 82 | * executable.) |
83 | */ | 83 | */ |
84 | #define RESERVE_BRK(name,sz) \ | 84 | #define RESERVE_BRK(name,sz) \ |
85 | static void __section(.discard) __used \ | 85 | static void __section(.discard.text) __used \ |
86 | __brk_reservation_fn_##name##__(void) { \ | 86 | __brk_reservation_fn_##name##__(void) { \ |
87 | asm volatile ( \ | 87 | asm volatile ( \ |
88 | ".pushsection .brk_reservation,\"aw\",@nobits;" \ | 88 | ".pushsection .brk_reservation,\"aw\",@nobits;" \ |
diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h index 9c371e4a9fa6..7fda040a76cd 100644 --- a/arch/x86/include/asm/xen/hypercall.h +++ b/arch/x86/include/asm/xen/hypercall.h | |||
@@ -417,6 +417,12 @@ HYPERVISOR_nmi_op(unsigned long op, unsigned long arg) | |||
417 | return _hypercall2(int, nmi_op, op, arg); | 417 | return _hypercall2(int, nmi_op, op, arg); |
418 | } | 418 | } |
419 | 419 | ||
420 | static inline unsigned long __must_check | ||
421 | HYPERVISOR_hvm_op(int op, void *arg) | ||
422 | { | ||
423 | return _hypercall2(unsigned long, hvm_op, op, arg); | ||
424 | } | ||
425 | |||
420 | static inline void | 426 | static inline void |
421 | MULTI_fpu_taskswitch(struct multicall_entry *mcl, int set) | 427 | MULTI_fpu_taskswitch(struct multicall_entry *mcl, int set) |
422 | { | 428 | { |
diff --git a/arch/x86/kernel/cpu/hypervisor.c b/arch/x86/kernel/cpu/hypervisor.c index dd531cc56a8f..8095f8611f8a 100644 --- a/arch/x86/kernel/cpu/hypervisor.c +++ b/arch/x86/kernel/cpu/hypervisor.c | |||
@@ -34,6 +34,9 @@ static const __initconst struct hypervisor_x86 * const hypervisors[] = | |||
34 | { | 34 | { |
35 | &x86_hyper_vmware, | 35 | &x86_hyper_vmware, |
36 | &x86_hyper_ms_hyperv, | 36 | &x86_hyper_ms_hyperv, |
37 | #ifdef CONFIG_XEN_PVHVM | ||
38 | &x86_hyper_xen_hvm, | ||
39 | #endif | ||
37 | }; | 40 | }; |
38 | 41 | ||
39 | const struct hypervisor_x86 *x86_hyper; | 42 | const struct hypervisor_x86 *x86_hyper; |
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index cd49141cf153..6b196834a0dd 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S | |||
@@ -1166,6 +1166,9 @@ ENTRY(xen_failsafe_callback) | |||
1166 | .previous | 1166 | .previous |
1167 | ENDPROC(xen_failsafe_callback) | 1167 | ENDPROC(xen_failsafe_callback) |
1168 | 1168 | ||
1169 | BUILD_INTERRUPT3(xen_hvm_callback_vector, XEN_HVM_EVTCHN_CALLBACK, | ||
1170 | xen_evtchn_do_upcall) | ||
1171 | |||
1169 | #endif /* CONFIG_XEN */ | 1172 | #endif /* CONFIG_XEN */ |
1170 | 1173 | ||
1171 | #ifdef CONFIG_FUNCTION_TRACER | 1174 | #ifdef CONFIG_FUNCTION_TRACER |
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index 4db7c4d12ffa..649ed17f7009 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
@@ -1329,6 +1329,9 @@ ENTRY(xen_failsafe_callback) | |||
1329 | CFI_ENDPROC | 1329 | CFI_ENDPROC |
1330 | END(xen_failsafe_callback) | 1330 | END(xen_failsafe_callback) |
1331 | 1331 | ||
1332 | apicinterrupt XEN_HVM_EVTCHN_CALLBACK \ | ||
1333 | xen_hvm_callback_vector xen_evtchn_do_upcall | ||
1334 | |||
1332 | #endif /* CONFIG_XEN */ | 1335 | #endif /* CONFIG_XEN */ |
1333 | 1336 | ||
1334 | /* | 1337 | /* |
diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig index b83e119fbeb0..68128a1b401a 100644 --- a/arch/x86/xen/Kconfig +++ b/arch/x86/xen/Kconfig | |||
@@ -13,6 +13,11 @@ config XEN | |||
13 | kernel to boot in a paravirtualized environment under the | 13 | kernel to boot in a paravirtualized environment under the |
14 | Xen hypervisor. | 14 | Xen hypervisor. |
15 | 15 | ||
16 | config XEN_PVHVM | ||
17 | def_bool y | ||
18 | depends on XEN | ||
19 | depends on X86_LOCAL_APIC | ||
20 | |||
16 | config XEN_MAX_DOMAIN_MEMORY | 21 | config XEN_MAX_DOMAIN_MEMORY |
17 | int "Maximum allowed size of a domain in gigabytes" | 22 | int "Maximum allowed size of a domain in gigabytes" |
18 | default 8 if X86_32 | 23 | default 8 if X86_32 |
diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile index 3bb4fc21f4f2..930954685980 100644 --- a/arch/x86/xen/Makefile +++ b/arch/x86/xen/Makefile | |||
@@ -12,7 +12,7 @@ CFLAGS_mmu.o := $(nostackp) | |||
12 | 12 | ||
13 | obj-y := enlighten.o setup.o multicalls.o mmu.o irq.o \ | 13 | obj-y := enlighten.o setup.o multicalls.o mmu.o irq.o \ |
14 | time.o xen-asm.o xen-asm_$(BITS).o \ | 14 | time.o xen-asm.o xen-asm_$(BITS).o \ |
15 | grant-table.o suspend.o | 15 | grant-table.o suspend.o platform-pci-unplug.o |
16 | 16 | ||
17 | obj-$(CONFIG_SMP) += smp.o | 17 | obj-$(CONFIG_SMP) += smp.o |
18 | obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o | 18 | obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o |
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 3c4da8bee06f..d4ff5e83621d 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -11,6 +11,7 @@ | |||
11 | * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007 | 11 | * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007 |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/cpu.h> | ||
14 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
15 | #include <linux/init.h> | 16 | #include <linux/init.h> |
16 | #include <linux/smp.h> | 17 | #include <linux/smp.h> |
@@ -35,8 +36,10 @@ | |||
35 | #include <xen/interface/version.h> | 36 | #include <xen/interface/version.h> |
36 | #include <xen/interface/physdev.h> | 37 | #include <xen/interface/physdev.h> |
37 | #include <xen/interface/vcpu.h> | 38 | #include <xen/interface/vcpu.h> |
39 | #include <xen/interface/memory.h> | ||
38 | #include <xen/features.h> | 40 | #include <xen/features.h> |
39 | #include <xen/page.h> | 41 | #include <xen/page.h> |
42 | #include <xen/hvm.h> | ||
40 | #include <xen/hvc-console.h> | 43 | #include <xen/hvc-console.h> |
41 | 44 | ||
42 | #include <asm/paravirt.h> | 45 | #include <asm/paravirt.h> |
@@ -55,7 +58,9 @@ | |||
55 | #include <asm/pgtable.h> | 58 | #include <asm/pgtable.h> |
56 | #include <asm/tlbflush.h> | 59 | #include <asm/tlbflush.h> |
57 | #include <asm/reboot.h> | 60 | #include <asm/reboot.h> |
61 | #include <asm/setup.h> | ||
58 | #include <asm/stackprotector.h> | 62 | #include <asm/stackprotector.h> |
63 | #include <asm/hypervisor.h> | ||
59 | 64 | ||
60 | #include "xen-ops.h" | 65 | #include "xen-ops.h" |
61 | #include "mmu.h" | 66 | #include "mmu.h" |
@@ -76,6 +81,10 @@ struct shared_info xen_dummy_shared_info; | |||
76 | 81 | ||
77 | void *xen_initial_gdt; | 82 | void *xen_initial_gdt; |
78 | 83 | ||
84 | RESERVE_BRK(shared_info_page_brk, PAGE_SIZE); | ||
85 | __read_mostly int xen_have_vector_callback; | ||
86 | EXPORT_SYMBOL_GPL(xen_have_vector_callback); | ||
87 | |||
79 | /* | 88 | /* |
80 | * Point at some empty memory to start with. We map the real shared_info | 89 | * Point at some empty memory to start with. We map the real shared_info |
81 | * page as soon as fixmap is up and running. | 90 | * page as soon as fixmap is up and running. |
@@ -938,10 +947,6 @@ static const struct pv_init_ops xen_init_ops __initdata = { | |||
938 | .patch = xen_patch, | 947 | .patch = xen_patch, |
939 | }; | 948 | }; |
940 | 949 | ||
941 | static const struct pv_time_ops xen_time_ops __initdata = { | ||
942 | .sched_clock = xen_clocksource_read, | ||
943 | }; | ||
944 | |||
945 | static const struct pv_cpu_ops xen_cpu_ops __initdata = { | 950 | static const struct pv_cpu_ops xen_cpu_ops __initdata = { |
946 | .cpuid = xen_cpuid, | 951 | .cpuid = xen_cpuid, |
947 | 952 | ||
@@ -1096,7 +1101,6 @@ asmlinkage void __init xen_start_kernel(void) | |||
1096 | /* Install Xen paravirt ops */ | 1101 | /* Install Xen paravirt ops */ |
1097 | pv_info = xen_info; | 1102 | pv_info = xen_info; |
1098 | pv_init_ops = xen_init_ops; | 1103 | pv_init_ops = xen_init_ops; |
1099 | pv_time_ops = xen_time_ops; | ||
1100 | pv_cpu_ops = xen_cpu_ops; | 1104 | pv_cpu_ops = xen_cpu_ops; |
1101 | pv_apic_ops = xen_apic_ops; | 1105 | pv_apic_ops = xen_apic_ops; |
1102 | 1106 | ||
@@ -1104,13 +1108,7 @@ asmlinkage void __init xen_start_kernel(void) | |||
1104 | x86_init.oem.arch_setup = xen_arch_setup; | 1108 | x86_init.oem.arch_setup = xen_arch_setup; |
1105 | x86_init.oem.banner = xen_banner; | 1109 | x86_init.oem.banner = xen_banner; |
1106 | 1110 | ||
1107 | x86_init.timers.timer_init = xen_time_init; | 1111 | xen_init_time_ops(); |
1108 | x86_init.timers.setup_percpu_clockev = x86_init_noop; | ||
1109 | x86_cpuinit.setup_percpu_clockev = x86_init_noop; | ||
1110 | |||
1111 | x86_platform.calibrate_tsc = xen_tsc_khz; | ||
1112 | x86_platform.get_wallclock = xen_get_wallclock; | ||
1113 | x86_platform.set_wallclock = xen_set_wallclock; | ||
1114 | 1112 | ||
1115 | /* | 1113 | /* |
1116 | * Set up some pagetable state before starting to set any ptes. | 1114 | * Set up some pagetable state before starting to set any ptes. |
@@ -1235,3 +1233,139 @@ asmlinkage void __init xen_start_kernel(void) | |||
1235 | x86_64_start_reservations((char *)__pa_symbol(&boot_params)); | 1233 | x86_64_start_reservations((char *)__pa_symbol(&boot_params)); |
1236 | #endif | 1234 | #endif |
1237 | } | 1235 | } |
1236 | |||
1237 | static uint32_t xen_cpuid_base(void) | ||
1238 | { | ||
1239 | uint32_t base, eax, ebx, ecx, edx; | ||
1240 | char signature[13]; | ||
1241 | |||
1242 | for (base = 0x40000000; base < 0x40010000; base += 0x100) { | ||
1243 | cpuid(base, &eax, &ebx, &ecx, &edx); | ||
1244 | *(uint32_t *)(signature + 0) = ebx; | ||
1245 | *(uint32_t *)(signature + 4) = ecx; | ||
1246 | *(uint32_t *)(signature + 8) = edx; | ||
1247 | signature[12] = 0; | ||
1248 | |||
1249 | if (!strcmp("XenVMMXenVMM", signature) && ((eax - base) >= 2)) | ||
1250 | return base; | ||
1251 | } | ||
1252 | |||
1253 | return 0; | ||
1254 | } | ||
1255 | |||
1256 | static int init_hvm_pv_info(int *major, int *minor) | ||
1257 | { | ||
1258 | uint32_t eax, ebx, ecx, edx, pages, msr, base; | ||
1259 | u64 pfn; | ||
1260 | |||
1261 | base = xen_cpuid_base(); | ||
1262 | cpuid(base + 1, &eax, &ebx, &ecx, &edx); | ||
1263 | |||
1264 | *major = eax >> 16; | ||
1265 | *minor = eax & 0xffff; | ||
1266 | printk(KERN_INFO "Xen version %d.%d.\n", *major, *minor); | ||
1267 | |||
1268 | cpuid(base + 2, &pages, &msr, &ecx, &edx); | ||
1269 | |||
1270 | pfn = __pa(hypercall_page); | ||
1271 | wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32)); | ||
1272 | |||
1273 | xen_setup_features(); | ||
1274 | |||
1275 | pv_info = xen_info; | ||
1276 | pv_info.kernel_rpl = 0; | ||
1277 | |||
1278 | xen_domain_type = XEN_HVM_DOMAIN; | ||
1279 | |||
1280 | return 0; | ||
1281 | } | ||
1282 | |||
1283 | void xen_hvm_init_shared_info(void) | ||
1284 | { | ||
1285 | int cpu; | ||
1286 | struct xen_add_to_physmap xatp; | ||
1287 | static struct shared_info *shared_info_page = 0; | ||
1288 | |||
1289 | if (!shared_info_page) | ||
1290 | shared_info_page = (struct shared_info *) | ||
1291 | extend_brk(PAGE_SIZE, PAGE_SIZE); | ||
1292 | xatp.domid = DOMID_SELF; | ||
1293 | xatp.idx = 0; | ||
1294 | xatp.space = XENMAPSPACE_shared_info; | ||
1295 | xatp.gpfn = __pa(shared_info_page) >> PAGE_SHIFT; | ||
1296 | if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) | ||
1297 | BUG(); | ||
1298 | |||
1299 | HYPERVISOR_shared_info = (struct shared_info *)shared_info_page; | ||
1300 | |||
1301 | /* xen_vcpu is a pointer to the vcpu_info struct in the shared_info | ||
1302 | * page, we use it in the event channel upcall and in some pvclock | ||
1303 | * related functions. We don't need the vcpu_info placement | ||
1304 | * optimizations because we don't use any pv_mmu or pv_irq op on | ||
1305 | * HVM. | ||
1306 | * When xen_hvm_init_shared_info is run at boot time only vcpu 0 is | ||
1307 | * online but xen_hvm_init_shared_info is run at resume time too and | ||
1308 | * in that case multiple vcpus might be online. */ | ||
1309 | for_each_online_cpu(cpu) { | ||
1310 | per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; | ||
1311 | } | ||
1312 | } | ||
1313 | |||
1314 | #ifdef CONFIG_XEN_PVHVM | ||
1315 | static int __cpuinit xen_hvm_cpu_notify(struct notifier_block *self, | ||
1316 | unsigned long action, void *hcpu) | ||
1317 | { | ||
1318 | int cpu = (long)hcpu; | ||
1319 | switch (action) { | ||
1320 | case CPU_UP_PREPARE: | ||
1321 | per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; | ||
1322 | break; | ||
1323 | default: | ||
1324 | break; | ||
1325 | } | ||
1326 | return NOTIFY_OK; | ||
1327 | } | ||
1328 | |||
1329 | static struct notifier_block __cpuinitdata xen_hvm_cpu_notifier = { | ||
1330 | .notifier_call = xen_hvm_cpu_notify, | ||
1331 | }; | ||
1332 | |||
1333 | static void __init xen_hvm_guest_init(void) | ||
1334 | { | ||
1335 | int r; | ||
1336 | int major, minor; | ||
1337 | |||
1338 | r = init_hvm_pv_info(&major, &minor); | ||
1339 | if (r < 0) | ||
1340 | return; | ||
1341 | |||
1342 | xen_hvm_init_shared_info(); | ||
1343 | |||
1344 | if (xen_feature(XENFEAT_hvm_callback_vector)) | ||
1345 | xen_have_vector_callback = 1; | ||
1346 | register_cpu_notifier(&xen_hvm_cpu_notifier); | ||
1347 | xen_unplug_emulated_devices(); | ||
1348 | have_vcpu_info_placement = 0; | ||
1349 | x86_init.irqs.intr_init = xen_init_IRQ; | ||
1350 | xen_hvm_init_time_ops(); | ||
1351 | xen_hvm_init_mmu_ops(); | ||
1352 | } | ||
1353 | |||
1354 | static bool __init xen_hvm_platform(void) | ||
1355 | { | ||
1356 | if (xen_pv_domain()) | ||
1357 | return false; | ||
1358 | |||
1359 | if (!xen_cpuid_base()) | ||
1360 | return false; | ||
1361 | |||
1362 | return true; | ||
1363 | } | ||
1364 | |||
1365 | const __refconst struct hypervisor_x86 x86_hyper_xen_hvm = { | ||
1366 | .name = "Xen HVM", | ||
1367 | .detect = xen_hvm_platform, | ||
1368 | .init_platform = xen_hvm_guest_init, | ||
1369 | }; | ||
1370 | EXPORT_SYMBOL(x86_hyper_xen_hvm); | ||
1371 | #endif | ||
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 914f04695ce5..413b19b3d0fe 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c | |||
@@ -58,6 +58,7 @@ | |||
58 | 58 | ||
59 | #include <xen/page.h> | 59 | #include <xen/page.h> |
60 | #include <xen/interface/xen.h> | 60 | #include <xen/interface/xen.h> |
61 | #include <xen/interface/hvm/hvm_op.h> | ||
61 | #include <xen/interface/version.h> | 62 | #include <xen/interface/version.h> |
62 | #include <xen/hvc-console.h> | 63 | #include <xen/hvc-console.h> |
63 | 64 | ||
@@ -1941,6 +1942,40 @@ void __init xen_init_mmu_ops(void) | |||
1941 | pv_mmu_ops = xen_mmu_ops; | 1942 | pv_mmu_ops = xen_mmu_ops; |
1942 | } | 1943 | } |
1943 | 1944 | ||
1945 | #ifdef CONFIG_XEN_PVHVM | ||
1946 | static void xen_hvm_exit_mmap(struct mm_struct *mm) | ||
1947 | { | ||
1948 | struct xen_hvm_pagetable_dying a; | ||
1949 | int rc; | ||
1950 | |||
1951 | a.domid = DOMID_SELF; | ||
1952 | a.gpa = __pa(mm->pgd); | ||
1953 | rc = HYPERVISOR_hvm_op(HVMOP_pagetable_dying, &a); | ||
1954 | WARN_ON_ONCE(rc < 0); | ||
1955 | } | ||
1956 | |||
1957 | static int is_pagetable_dying_supported(void) | ||
1958 | { | ||
1959 | struct xen_hvm_pagetable_dying a; | ||
1960 | int rc = 0; | ||
1961 | |||
1962 | a.domid = DOMID_SELF; | ||
1963 | a.gpa = 0x00; | ||
1964 | rc = HYPERVISOR_hvm_op(HVMOP_pagetable_dying, &a); | ||
1965 | if (rc < 0) { | ||
1966 | printk(KERN_DEBUG "HVMOP_pagetable_dying not supported\n"); | ||
1967 | return 0; | ||
1968 | } | ||
1969 | return 1; | ||
1970 | } | ||
1971 | |||
1972 | void __init xen_hvm_init_mmu_ops(void) | ||
1973 | { | ||
1974 | if (is_pagetable_dying_supported()) | ||
1975 | pv_mmu_ops.exit_mmap = xen_hvm_exit_mmap; | ||
1976 | } | ||
1977 | #endif | ||
1978 | |||
1944 | #ifdef CONFIG_XEN_DEBUG_FS | 1979 | #ifdef CONFIG_XEN_DEBUG_FS |
1945 | 1980 | ||
1946 | static struct dentry *d_mmu_debug; | 1981 | static struct dentry *d_mmu_debug; |
diff --git a/arch/x86/xen/mmu.h b/arch/x86/xen/mmu.h index 5fe6bc7f5ecf..fa938c4aa2f7 100644 --- a/arch/x86/xen/mmu.h +++ b/arch/x86/xen/mmu.h | |||
@@ -60,4 +60,5 @@ void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr, | |||
60 | unsigned long xen_read_cr2_direct(void); | 60 | unsigned long xen_read_cr2_direct(void); |
61 | 61 | ||
62 | extern void xen_init_mmu_ops(void); | 62 | extern void xen_init_mmu_ops(void); |
63 | extern void xen_hvm_init_mmu_ops(void); | ||
63 | #endif /* _XEN_MMU_H */ | 64 | #endif /* _XEN_MMU_H */ |
diff --git a/arch/x86/xen/platform-pci-unplug.c b/arch/x86/xen/platform-pci-unplug.c new file mode 100644 index 000000000000..554c002a1e1a --- /dev/null +++ b/arch/x86/xen/platform-pci-unplug.c | |||
@@ -0,0 +1,137 @@ | |||
1 | /****************************************************************************** | ||
2 | * platform-pci-unplug.c | ||
3 | * | ||
4 | * Xen platform PCI device driver | ||
5 | * Copyright (c) 2010, Citrix | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms and conditions of the GNU General Public License, | ||
9 | * version 2, as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
18 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/init.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <linux/module.h> | ||
25 | |||
26 | #include <xen/platform_pci.h> | ||
27 | |||
28 | #define XEN_PLATFORM_ERR_MAGIC -1 | ||
29 | #define XEN_PLATFORM_ERR_PROTOCOL -2 | ||
30 | #define XEN_PLATFORM_ERR_BLACKLIST -3 | ||
31 | |||
32 | /* store the value of xen_emul_unplug after the unplug is done */ | ||
33 | int xen_platform_pci_unplug; | ||
34 | EXPORT_SYMBOL_GPL(xen_platform_pci_unplug); | ||
35 | #ifdef CONFIG_XEN_PVHVM | ||
36 | static int xen_emul_unplug; | ||
37 | |||
38 | static int __init check_platform_magic(void) | ||
39 | { | ||
40 | short magic; | ||
41 | char protocol; | ||
42 | |||
43 | magic = inw(XEN_IOPORT_MAGIC); | ||
44 | if (magic != XEN_IOPORT_MAGIC_VAL) { | ||
45 | printk(KERN_ERR "Xen Platform PCI: unrecognised magic value\n"); | ||
46 | return XEN_PLATFORM_ERR_MAGIC; | ||
47 | } | ||
48 | |||
49 | protocol = inb(XEN_IOPORT_PROTOVER); | ||
50 | |||
51 | printk(KERN_DEBUG "Xen Platform PCI: I/O protocol version %d\n", | ||
52 | protocol); | ||
53 | |||
54 | switch (protocol) { | ||
55 | case 1: | ||
56 | outw(XEN_IOPORT_LINUX_PRODNUM, XEN_IOPORT_PRODNUM); | ||
57 | outl(XEN_IOPORT_LINUX_DRVVER, XEN_IOPORT_DRVVER); | ||
58 | if (inw(XEN_IOPORT_MAGIC) != XEN_IOPORT_MAGIC_VAL) { | ||
59 | printk(KERN_ERR "Xen Platform: blacklisted by host\n"); | ||
60 | return XEN_PLATFORM_ERR_BLACKLIST; | ||
61 | } | ||
62 | break; | ||
63 | default: | ||
64 | printk(KERN_WARNING "Xen Platform PCI: unknown I/O protocol version"); | ||
65 | return XEN_PLATFORM_ERR_PROTOCOL; | ||
66 | } | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | void __init xen_unplug_emulated_devices(void) | ||
72 | { | ||
73 | int r; | ||
74 | |||
75 | /* check the version of the xen platform PCI device */ | ||
76 | r = check_platform_magic(); | ||
77 | /* If the version matches enable the Xen platform PCI driver. | ||
78 | * Also enable the Xen platform PCI driver if the version is really old | ||
79 | * and the user told us to ignore it. */ | ||
80 | if (r && !(r == XEN_PLATFORM_ERR_MAGIC && | ||
81 | (xen_emul_unplug & XEN_UNPLUG_IGNORE))) | ||
82 | return; | ||
83 | /* Set the default value of xen_emul_unplug depending on whether or | ||
84 | * not the Xen PV frontends and the Xen platform PCI driver have | ||
85 | * been compiled for this kernel (modules or built-in are both OK). */ | ||
86 | if (!xen_emul_unplug) { | ||
87 | if (xen_must_unplug_nics()) { | ||
88 | printk(KERN_INFO "Netfront and the Xen platform PCI driver have " | ||
89 | "been compiled for this kernel: unplug emulated NICs.\n"); | ||
90 | xen_emul_unplug |= XEN_UNPLUG_ALL_NICS; | ||
91 | } | ||
92 | if (xen_must_unplug_disks()) { | ||
93 | printk(KERN_INFO "Blkfront and the Xen platform PCI driver have " | ||
94 | "been compiled for this kernel: unplug emulated disks.\n" | ||
95 | "You might have to change the root device\n" | ||
96 | "from /dev/hd[a-d] to /dev/xvd[a-d]\n" | ||
97 | "in your root= kernel command line option\n"); | ||
98 | xen_emul_unplug |= XEN_UNPLUG_ALL_IDE_DISKS; | ||
99 | } | ||
100 | } | ||
101 | /* Now unplug the emulated devices */ | ||
102 | if (!(xen_emul_unplug & XEN_UNPLUG_IGNORE)) | ||
103 | outw(xen_emul_unplug, XEN_IOPORT_UNPLUG); | ||
104 | xen_platform_pci_unplug = xen_emul_unplug; | ||
105 | } | ||
106 | |||
107 | static int __init parse_xen_emul_unplug(char *arg) | ||
108 | { | ||
109 | char *p, *q; | ||
110 | int l; | ||
111 | |||
112 | for (p = arg; p; p = q) { | ||
113 | q = strchr(p, ','); | ||
114 | if (q) { | ||
115 | l = q - p; | ||
116 | q++; | ||
117 | } else { | ||
118 | l = strlen(p); | ||
119 | } | ||
120 | if (!strncmp(p, "all", l)) | ||
121 | xen_emul_unplug |= XEN_UNPLUG_ALL; | ||
122 | else if (!strncmp(p, "ide-disks", l)) | ||
123 | xen_emul_unplug |= XEN_UNPLUG_ALL_IDE_DISKS; | ||
124 | else if (!strncmp(p, "aux-ide-disks", l)) | ||
125 | xen_emul_unplug |= XEN_UNPLUG_AUX_IDE_DISKS; | ||
126 | else if (!strncmp(p, "nics", l)) | ||
127 | xen_emul_unplug |= XEN_UNPLUG_ALL_NICS; | ||
128 | else if (!strncmp(p, "ignore", l)) | ||
129 | xen_emul_unplug |= XEN_UNPLUG_IGNORE; | ||
130 | else | ||
131 | printk(KERN_WARNING "unrecognised option '%s' " | ||
132 | "in parameter 'xen_emul_unplug'\n", p); | ||
133 | } | ||
134 | return 0; | ||
135 | } | ||
136 | early_param("xen_emul_unplug", parse_xen_emul_unplug); | ||
137 | #endif | ||
diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c index a9c661108034..1d789d56877c 100644 --- a/arch/x86/xen/suspend.c +++ b/arch/x86/xen/suspend.c | |||
@@ -26,6 +26,18 @@ void xen_pre_suspend(void) | |||
26 | BUG(); | 26 | BUG(); |
27 | } | 27 | } |
28 | 28 | ||
29 | void xen_hvm_post_suspend(int suspend_cancelled) | ||
30 | { | ||
31 | int cpu; | ||
32 | xen_hvm_init_shared_info(); | ||
33 | xen_callback_vector(); | ||
34 | if (xen_feature(XENFEAT_hvm_safe_pvclock)) { | ||
35 | for_each_online_cpu(cpu) { | ||
36 | xen_setup_runstate_info(cpu); | ||
37 | } | ||
38 | } | ||
39 | } | ||
40 | |||
29 | void xen_post_suspend(int suspend_cancelled) | 41 | void xen_post_suspend(int suspend_cancelled) |
30 | { | 42 | { |
31 | xen_build_mfn_list_list(); | 43 | xen_build_mfn_list_list(); |
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index a86df42e46ad..1a5353a753fc 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <asm/xen/hypercall.h> | 20 | #include <asm/xen/hypercall.h> |
21 | 21 | ||
22 | #include <xen/events.h> | 22 | #include <xen/events.h> |
23 | #include <xen/features.h> | ||
23 | #include <xen/interface/xen.h> | 24 | #include <xen/interface/xen.h> |
24 | #include <xen/interface/vcpu.h> | 25 | #include <xen/interface/vcpu.h> |
25 | 26 | ||
@@ -156,7 +157,7 @@ static void do_stolen_accounting(void) | |||
156 | } | 157 | } |
157 | 158 | ||
158 | /* Get the TSC speed from Xen */ | 159 | /* Get the TSC speed from Xen */ |
159 | unsigned long xen_tsc_khz(void) | 160 | static unsigned long xen_tsc_khz(void) |
160 | { | 161 | { |
161 | struct pvclock_vcpu_time_info *info = | 162 | struct pvclock_vcpu_time_info *info = |
162 | &HYPERVISOR_shared_info->vcpu_info[0].time; | 163 | &HYPERVISOR_shared_info->vcpu_info[0].time; |
@@ -191,7 +192,7 @@ static void xen_read_wallclock(struct timespec *ts) | |||
191 | put_cpu_var(xen_vcpu); | 192 | put_cpu_var(xen_vcpu); |
192 | } | 193 | } |
193 | 194 | ||
194 | unsigned long xen_get_wallclock(void) | 195 | static unsigned long xen_get_wallclock(void) |
195 | { | 196 | { |
196 | struct timespec ts; | 197 | struct timespec ts; |
197 | 198 | ||
@@ -199,7 +200,7 @@ unsigned long xen_get_wallclock(void) | |||
199 | return ts.tv_sec; | 200 | return ts.tv_sec; |
200 | } | 201 | } |
201 | 202 | ||
202 | int xen_set_wallclock(unsigned long now) | 203 | static int xen_set_wallclock(unsigned long now) |
203 | { | 204 | { |
204 | /* do nothing for domU */ | 205 | /* do nothing for domU */ |
205 | return -1; | 206 | return -1; |
@@ -434,7 +435,11 @@ void xen_timer_resume(void) | |||
434 | } | 435 | } |
435 | } | 436 | } |
436 | 437 | ||
437 | __init void xen_time_init(void) | 438 | static const struct pv_time_ops xen_time_ops __initdata = { |
439 | .sched_clock = xen_clocksource_read, | ||
440 | }; | ||
441 | |||
442 | static __init void xen_time_init(void) | ||
438 | { | 443 | { |
439 | int cpu = smp_processor_id(); | 444 | int cpu = smp_processor_id(); |
440 | struct timespec tp; | 445 | struct timespec tp; |
@@ -458,3 +463,47 @@ __init void xen_time_init(void) | |||
458 | xen_setup_timer(cpu); | 463 | xen_setup_timer(cpu); |
459 | xen_setup_cpu_clockevents(); | 464 | xen_setup_cpu_clockevents(); |
460 | } | 465 | } |
466 | |||
467 | __init void xen_init_time_ops(void) | ||
468 | { | ||
469 | pv_time_ops = xen_time_ops; | ||
470 | |||
471 | x86_init.timers.timer_init = xen_time_init; | ||
472 | x86_init.timers.setup_percpu_clockev = x86_init_noop; | ||
473 | x86_cpuinit.setup_percpu_clockev = x86_init_noop; | ||
474 | |||
475 | x86_platform.calibrate_tsc = xen_tsc_khz; | ||
476 | x86_platform.get_wallclock = xen_get_wallclock; | ||
477 | x86_platform.set_wallclock = xen_set_wallclock; | ||
478 | } | ||
479 | |||
480 | #ifdef CONFIG_XEN_PVHVM | ||
481 | static void xen_hvm_setup_cpu_clockevents(void) | ||
482 | { | ||
483 | int cpu = smp_processor_id(); | ||
484 | xen_setup_runstate_info(cpu); | ||
485 | xen_setup_timer(cpu); | ||
486 | xen_setup_cpu_clockevents(); | ||
487 | } | ||
488 | |||
489 | __init void xen_hvm_init_time_ops(void) | ||
490 | { | ||
491 | /* vector callback is needed otherwise we cannot receive interrupts | ||
492 | * on cpu > 0 */ | ||
493 | if (!xen_have_vector_callback && num_present_cpus() > 1) | ||
494 | return; | ||
495 | if (!xen_feature(XENFEAT_hvm_safe_pvclock)) { | ||
496 | printk(KERN_INFO "Xen doesn't support pvclock on HVM," | ||
497 | "disable pv timer\n"); | ||
498 | return; | ||
499 | } | ||
500 | |||
501 | pv_time_ops = xen_time_ops; | ||
502 | x86_init.timers.setup_percpu_clockev = xen_time_init; | ||
503 | x86_cpuinit.setup_percpu_clockev = xen_hvm_setup_cpu_clockevents; | ||
504 | |||
505 | x86_platform.calibrate_tsc = xen_tsc_khz; | ||
506 | x86_platform.get_wallclock = xen_get_wallclock; | ||
507 | x86_platform.set_wallclock = xen_set_wallclock; | ||
508 | } | ||
509 | #endif | ||
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index 00d59d608edf..7c8ab86163e9 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h | |||
@@ -38,6 +38,10 @@ void xen_enable_sysenter(void); | |||
38 | void xen_enable_syscall(void); | 38 | void xen_enable_syscall(void); |
39 | void xen_vcpu_restore(void); | 39 | void xen_vcpu_restore(void); |
40 | 40 | ||
41 | void xen_callback_vector(void); | ||
42 | void xen_hvm_init_shared_info(void); | ||
43 | void __init xen_unplug_emulated_devices(void); | ||
44 | |||
41 | void __init xen_build_dynamic_phys_to_machine(void); | 45 | void __init xen_build_dynamic_phys_to_machine(void); |
42 | 46 | ||
43 | void xen_init_irq_ops(void); | 47 | void xen_init_irq_ops(void); |
@@ -46,11 +50,8 @@ void xen_setup_runstate_info(int cpu); | |||
46 | void xen_teardown_timer(int cpu); | 50 | void xen_teardown_timer(int cpu); |
47 | cycle_t xen_clocksource_read(void); | 51 | cycle_t xen_clocksource_read(void); |
48 | void xen_setup_cpu_clockevents(void); | 52 | void xen_setup_cpu_clockevents(void); |
49 | unsigned long xen_tsc_khz(void); | 53 | void __init xen_init_time_ops(void); |
50 | void __init xen_time_init(void); | 54 | void __init xen_hvm_init_time_ops(void); |
51 | unsigned long xen_get_wallclock(void); | ||
52 | int xen_set_wallclock(unsigned long time); | ||
53 | unsigned long long xen_sched_clock(void); | ||
54 | 55 | ||
55 | irqreturn_t xen_debug_interrupt(int irq, void *dev_id); | 56 | irqreturn_t xen_debug_interrupt(int irq, void *dev_id); |
56 | 57 | ||
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 82ed403147c0..f63ac3d1f8a4 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <xen/grant_table.h> | 48 | #include <xen/grant_table.h> |
49 | #include <xen/events.h> | 49 | #include <xen/events.h> |
50 | #include <xen/page.h> | 50 | #include <xen/page.h> |
51 | #include <xen/platform_pci.h> | ||
51 | 52 | ||
52 | #include <xen/interface/grant_table.h> | 53 | #include <xen/interface/grant_table.h> |
53 | #include <xen/interface/io/blkif.h> | 54 | #include <xen/interface/io/blkif.h> |
@@ -737,6 +738,35 @@ static int blkfront_probe(struct xenbus_device *dev, | |||
737 | } | 738 | } |
738 | } | 739 | } |
739 | 740 | ||
741 | if (xen_hvm_domain()) { | ||
742 | char *type; | ||
743 | int len; | ||
744 | /* no unplug has been done: do not hook devices != xen vbds */ | ||
745 | if (xen_platform_pci_unplug & XEN_UNPLUG_IGNORE) { | ||
746 | int major; | ||
747 | |||
748 | if (!VDEV_IS_EXTENDED(vdevice)) | ||
749 | major = BLKIF_MAJOR(vdevice); | ||
750 | else | ||
751 | major = XENVBD_MAJOR; | ||
752 | |||
753 | if (major != XENVBD_MAJOR) { | ||
754 | printk(KERN_INFO | ||
755 | "%s: HVM does not support vbd %d as xen block device\n", | ||
756 | __FUNCTION__, vdevice); | ||
757 | return -ENODEV; | ||
758 | } | ||
759 | } | ||
760 | /* do not create a PV cdrom device if we are an HVM guest */ | ||
761 | type = xenbus_read(XBT_NIL, dev->nodename, "device-type", &len); | ||
762 | if (IS_ERR(type)) | ||
763 | return -ENODEV; | ||
764 | if (strncmp(type, "cdrom", 5) == 0) { | ||
765 | kfree(type); | ||
766 | return -ENODEV; | ||
767 | } | ||
768 | kfree(type); | ||
769 | } | ||
740 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 770 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
741 | if (!info) { | 771 | if (!info) { |
742 | xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); | 772 | xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); |
diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c index e14081675bb2..ebb11907d402 100644 --- a/drivers/input/xen-kbdfront.c +++ b/drivers/input/xen-kbdfront.c | |||
@@ -339,7 +339,7 @@ static struct xenbus_driver xenkbd_driver = { | |||
339 | 339 | ||
340 | static int __init xenkbd_init(void) | 340 | static int __init xenkbd_init(void) |
341 | { | 341 | { |
342 | if (!xen_domain()) | 342 | if (!xen_pv_domain()) |
343 | return -ENODEV; | 343 | return -ENODEV; |
344 | 344 | ||
345 | /* Nothing to do if running in dom0. */ | 345 | /* Nothing to do if running in dom0. */ |
diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c index fa97d3e7c21a..7c7f42a12796 100644 --- a/drivers/video/xen-fbfront.c +++ b/drivers/video/xen-fbfront.c | |||
@@ -684,7 +684,7 @@ static struct xenbus_driver xenfb_driver = { | |||
684 | 684 | ||
685 | static int __init xenfb_init(void) | 685 | static int __init xenfb_init(void) |
686 | { | 686 | { |
687 | if (!xen_domain()) | 687 | if (!xen_pv_domain()) |
688 | return -ENODEV; | 688 | return -ENODEV; |
689 | 689 | ||
690 | /* Nothing to do if running in dom0. */ | 690 | /* Nothing to do if running in dom0. */ |
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index fad3df2c1276..0a8826936639 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig | |||
@@ -62,4 +62,13 @@ config XEN_SYS_HYPERVISOR | |||
62 | virtual environment, /sys/hypervisor will still be present, | 62 | virtual environment, /sys/hypervisor will still be present, |
63 | but will have no xen contents. | 63 | but will have no xen contents. |
64 | 64 | ||
65 | config XEN_PLATFORM_PCI | ||
66 | tristate "xen platform pci device driver" | ||
67 | depends on XEN_PVHVM | ||
68 | default m | ||
69 | help | ||
70 | Driver for the Xen PCI Platform device: it is responsible for | ||
71 | initializing xenbus and grant_table when running in a Xen HVM | ||
72 | domain. As a consequence this driver is required to run any Xen PV | ||
73 | frontend on Xen HVM. | ||
65 | endmenu | 74 | endmenu |
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index 7c284342f30f..e392fb776af3 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile | |||
@@ -9,4 +9,5 @@ obj-$(CONFIG_XEN_XENCOMM) += xencomm.o | |||
9 | obj-$(CONFIG_XEN_BALLOON) += balloon.o | 9 | obj-$(CONFIG_XEN_BALLOON) += balloon.o |
10 | obj-$(CONFIG_XEN_DEV_EVTCHN) += evtchn.o | 10 | obj-$(CONFIG_XEN_DEV_EVTCHN) += evtchn.o |
11 | obj-$(CONFIG_XENFS) += xenfs/ | 11 | obj-$(CONFIG_XENFS) += xenfs/ |
12 | obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o \ No newline at end of file | 12 | obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o |
13 | obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o | ||
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index db8f506817f0..5e1f34892dcc 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/bootmem.h> | 29 | #include <linux/bootmem.h> |
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | 31 | ||
32 | #include <asm/desc.h> | ||
32 | #include <asm/ptrace.h> | 33 | #include <asm/ptrace.h> |
33 | #include <asm/irq.h> | 34 | #include <asm/irq.h> |
34 | #include <asm/idle.h> | 35 | #include <asm/idle.h> |
@@ -36,10 +37,14 @@ | |||
36 | #include <asm/xen/hypercall.h> | 37 | #include <asm/xen/hypercall.h> |
37 | #include <asm/xen/hypervisor.h> | 38 | #include <asm/xen/hypervisor.h> |
38 | 39 | ||
40 | #include <xen/xen.h> | ||
41 | #include <xen/hvm.h> | ||
39 | #include <xen/xen-ops.h> | 42 | #include <xen/xen-ops.h> |
40 | #include <xen/events.h> | 43 | #include <xen/events.h> |
41 | #include <xen/interface/xen.h> | 44 | #include <xen/interface/xen.h> |
42 | #include <xen/interface/event_channel.h> | 45 | #include <xen/interface/event_channel.h> |
46 | #include <xen/interface/hvm/hvm_op.h> | ||
47 | #include <xen/interface/hvm/params.h> | ||
43 | 48 | ||
44 | /* | 49 | /* |
45 | * This lock protects updates to the following mapping and reference-count | 50 | * This lock protects updates to the following mapping and reference-count |
@@ -335,9 +340,18 @@ static int find_unbound_irq(void) | |||
335 | int irq; | 340 | int irq; |
336 | struct irq_desc *desc; | 341 | struct irq_desc *desc; |
337 | 342 | ||
338 | for (irq = 0; irq < nr_irqs; irq++) | 343 | for (irq = 0; irq < nr_irqs; irq++) { |
344 | desc = irq_to_desc(irq); | ||
345 | /* only 0->15 have init'd desc; handle irq > 16 */ | ||
346 | if (desc == NULL) | ||
347 | break; | ||
348 | if (desc->chip == &no_irq_chip) | ||
349 | break; | ||
350 | if (desc->chip != &xen_dynamic_chip) | ||
351 | continue; | ||
339 | if (irq_info[irq].type == IRQT_UNBOUND) | 352 | if (irq_info[irq].type == IRQT_UNBOUND) |
340 | break; | 353 | break; |
354 | } | ||
341 | 355 | ||
342 | if (irq == nr_irqs) | 356 | if (irq == nr_irqs) |
343 | panic("No available IRQ to bind to: increase nr_irqs!\n"); | 357 | panic("No available IRQ to bind to: increase nr_irqs!\n"); |
@@ -346,7 +360,7 @@ static int find_unbound_irq(void) | |||
346 | if (WARN_ON(desc == NULL)) | 360 | if (WARN_ON(desc == NULL)) |
347 | return -1; | 361 | return -1; |
348 | 362 | ||
349 | dynamic_irq_init(irq); | 363 | dynamic_irq_init_keep_chip_data(irq); |
350 | 364 | ||
351 | return irq; | 365 | return irq; |
352 | } | 366 | } |
@@ -617,17 +631,13 @@ static DEFINE_PER_CPU(unsigned, xed_nesting_count); | |||
617 | * a bitset of words which contain pending event bits. The second | 631 | * a bitset of words which contain pending event bits. The second |
618 | * level is a bitset of pending events themselves. | 632 | * level is a bitset of pending events themselves. |
619 | */ | 633 | */ |
620 | void xen_evtchn_do_upcall(struct pt_regs *regs) | 634 | static void __xen_evtchn_do_upcall(void) |
621 | { | 635 | { |
622 | int cpu = get_cpu(); | 636 | int cpu = get_cpu(); |
623 | struct pt_regs *old_regs = set_irq_regs(regs); | ||
624 | struct shared_info *s = HYPERVISOR_shared_info; | 637 | struct shared_info *s = HYPERVISOR_shared_info; |
625 | struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu); | 638 | struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu); |
626 | unsigned count; | 639 | unsigned count; |
627 | 640 | ||
628 | exit_idle(); | ||
629 | irq_enter(); | ||
630 | |||
631 | do { | 641 | do { |
632 | unsigned long pending_words; | 642 | unsigned long pending_words; |
633 | 643 | ||
@@ -664,14 +674,31 @@ void xen_evtchn_do_upcall(struct pt_regs *regs) | |||
664 | 674 | ||
665 | count = __get_cpu_var(xed_nesting_count); | 675 | count = __get_cpu_var(xed_nesting_count); |
666 | __get_cpu_var(xed_nesting_count) = 0; | 676 | __get_cpu_var(xed_nesting_count) = 0; |
667 | } while(count != 1); | 677 | } while (count != 1 || vcpu_info->evtchn_upcall_pending); |
668 | 678 | ||
669 | out: | 679 | out: |
680 | |||
681 | put_cpu(); | ||
682 | } | ||
683 | |||
684 | void xen_evtchn_do_upcall(struct pt_regs *regs) | ||
685 | { | ||
686 | struct pt_regs *old_regs = set_irq_regs(regs); | ||
687 | |||
688 | exit_idle(); | ||
689 | irq_enter(); | ||
690 | |||
691 | __xen_evtchn_do_upcall(); | ||
692 | |||
670 | irq_exit(); | 693 | irq_exit(); |
671 | set_irq_regs(old_regs); | 694 | set_irq_regs(old_regs); |
695 | } | ||
672 | 696 | ||
673 | put_cpu(); | 697 | void xen_hvm_evtchn_do_upcall(void) |
698 | { | ||
699 | __xen_evtchn_do_upcall(); | ||
674 | } | 700 | } |
701 | EXPORT_SYMBOL_GPL(xen_hvm_evtchn_do_upcall); | ||
675 | 702 | ||
676 | /* Rebind a new event channel to an existing irq. */ | 703 | /* Rebind a new event channel to an existing irq. */ |
677 | void rebind_evtchn_irq(int evtchn, int irq) | 704 | void rebind_evtchn_irq(int evtchn, int irq) |
@@ -708,7 +735,10 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu) | |||
708 | struct evtchn_bind_vcpu bind_vcpu; | 735 | struct evtchn_bind_vcpu bind_vcpu; |
709 | int evtchn = evtchn_from_irq(irq); | 736 | int evtchn = evtchn_from_irq(irq); |
710 | 737 | ||
711 | if (!VALID_EVTCHN(evtchn)) | 738 | /* events delivered via platform PCI interrupts are always |
739 | * routed to vcpu 0 */ | ||
740 | if (!VALID_EVTCHN(evtchn) || | ||
741 | (xen_hvm_domain() && !xen_have_vector_callback)) | ||
712 | return -1; | 742 | return -1; |
713 | 743 | ||
714 | /* Send future instances of this interrupt to other vcpu. */ | 744 | /* Send future instances of this interrupt to other vcpu. */ |
@@ -933,6 +963,44 @@ static struct irq_chip xen_dynamic_chip __read_mostly = { | |||
933 | .retrigger = retrigger_dynirq, | 963 | .retrigger = retrigger_dynirq, |
934 | }; | 964 | }; |
935 | 965 | ||
966 | int xen_set_callback_via(uint64_t via) | ||
967 | { | ||
968 | struct xen_hvm_param a; | ||
969 | a.domid = DOMID_SELF; | ||
970 | a.index = HVM_PARAM_CALLBACK_IRQ; | ||
971 | a.value = via; | ||
972 | return HYPERVISOR_hvm_op(HVMOP_set_param, &a); | ||
973 | } | ||
974 | EXPORT_SYMBOL_GPL(xen_set_callback_via); | ||
975 | |||
976 | #ifdef CONFIG_XEN_PVHVM | ||
977 | /* Vector callbacks are better than PCI interrupts to receive event | ||
978 | * channel notifications because we can receive vector callbacks on any | ||
979 | * vcpu and we don't need PCI support or APIC interactions. */ | ||
980 | void xen_callback_vector(void) | ||
981 | { | ||
982 | int rc; | ||
983 | uint64_t callback_via; | ||
984 | if (xen_have_vector_callback) { | ||
985 | callback_via = HVM_CALLBACK_VECTOR(XEN_HVM_EVTCHN_CALLBACK); | ||
986 | rc = xen_set_callback_via(callback_via); | ||
987 | if (rc) { | ||
988 | printk(KERN_ERR "Request for Xen HVM callback vector" | ||
989 | " failed.\n"); | ||
990 | xen_have_vector_callback = 0; | ||
991 | return; | ||
992 | } | ||
993 | printk(KERN_INFO "Xen HVM callback vector for event delivery is " | ||
994 | "enabled\n"); | ||
995 | /* in the restore case the vector has already been allocated */ | ||
996 | if (!test_bit(XEN_HVM_EVTCHN_CALLBACK, used_vectors)) | ||
997 | alloc_intr_gate(XEN_HVM_EVTCHN_CALLBACK, xen_hvm_callback_vector); | ||
998 | } | ||
999 | } | ||
1000 | #else | ||
1001 | void xen_callback_vector(void) {} | ||
1002 | #endif | ||
1003 | |||
936 | void __init xen_init_IRQ(void) | 1004 | void __init xen_init_IRQ(void) |
937 | { | 1005 | { |
938 | int i; | 1006 | int i; |
@@ -947,5 +1015,10 @@ void __init xen_init_IRQ(void) | |||
947 | for (i = 0; i < NR_EVENT_CHANNELS; i++) | 1015 | for (i = 0; i < NR_EVENT_CHANNELS; i++) |
948 | mask_evtchn(i); | 1016 | mask_evtchn(i); |
949 | 1017 | ||
950 | irq_ctx_init(smp_processor_id()); | 1018 | if (xen_hvm_domain()) { |
1019 | xen_callback_vector(); | ||
1020 | native_init_IRQ(); | ||
1021 | } else { | ||
1022 | irq_ctx_init(smp_processor_id()); | ||
1023 | } | ||
951 | } | 1024 | } |
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index f66db3b91d61..6c4531816496 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c | |||
@@ -37,11 +37,13 @@ | |||
37 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
38 | #include <linux/vmalloc.h> | 38 | #include <linux/vmalloc.h> |
39 | #include <linux/uaccess.h> | 39 | #include <linux/uaccess.h> |
40 | #include <linux/io.h> | ||
40 | 41 | ||
41 | #include <xen/xen.h> | 42 | #include <xen/xen.h> |
42 | #include <xen/interface/xen.h> | 43 | #include <xen/interface/xen.h> |
43 | #include <xen/page.h> | 44 | #include <xen/page.h> |
44 | #include <xen/grant_table.h> | 45 | #include <xen/grant_table.h> |
46 | #include <xen/interface/memory.h> | ||
45 | #include <asm/xen/hypercall.h> | 47 | #include <asm/xen/hypercall.h> |
46 | 48 | ||
47 | #include <asm/pgtable.h> | 49 | #include <asm/pgtable.h> |
@@ -59,6 +61,8 @@ static unsigned int boot_max_nr_grant_frames; | |||
59 | static int gnttab_free_count; | 61 | static int gnttab_free_count; |
60 | static grant_ref_t gnttab_free_head; | 62 | static grant_ref_t gnttab_free_head; |
61 | static DEFINE_SPINLOCK(gnttab_list_lock); | 63 | static DEFINE_SPINLOCK(gnttab_list_lock); |
64 | unsigned long xen_hvm_resume_frames; | ||
65 | EXPORT_SYMBOL_GPL(xen_hvm_resume_frames); | ||
62 | 66 | ||
63 | static struct grant_entry *shared; | 67 | static struct grant_entry *shared; |
64 | 68 | ||
@@ -433,7 +437,7 @@ static unsigned int __max_nr_grant_frames(void) | |||
433 | return query.max_nr_frames; | 437 | return query.max_nr_frames; |
434 | } | 438 | } |
435 | 439 | ||
436 | static inline unsigned int max_nr_grant_frames(void) | 440 | unsigned int gnttab_max_grant_frames(void) |
437 | { | 441 | { |
438 | unsigned int xen_max = __max_nr_grant_frames(); | 442 | unsigned int xen_max = __max_nr_grant_frames(); |
439 | 443 | ||
@@ -441,6 +445,7 @@ static inline unsigned int max_nr_grant_frames(void) | |||
441 | return boot_max_nr_grant_frames; | 445 | return boot_max_nr_grant_frames; |
442 | return xen_max; | 446 | return xen_max; |
443 | } | 447 | } |
448 | EXPORT_SYMBOL_GPL(gnttab_max_grant_frames); | ||
444 | 449 | ||
445 | static int gnttab_map(unsigned int start_idx, unsigned int end_idx) | 450 | static int gnttab_map(unsigned int start_idx, unsigned int end_idx) |
446 | { | 451 | { |
@@ -449,6 +454,30 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx) | |||
449 | unsigned int nr_gframes = end_idx + 1; | 454 | unsigned int nr_gframes = end_idx + 1; |
450 | int rc; | 455 | int rc; |
451 | 456 | ||
457 | if (xen_hvm_domain()) { | ||
458 | struct xen_add_to_physmap xatp; | ||
459 | unsigned int i = end_idx; | ||
460 | rc = 0; | ||
461 | /* | ||
462 | * Loop backwards, so that the first hypercall has the largest | ||
463 | * index, ensuring that the table will grow only once. | ||
464 | */ | ||
465 | do { | ||
466 | xatp.domid = DOMID_SELF; | ||
467 | xatp.idx = i; | ||
468 | xatp.space = XENMAPSPACE_grant_table; | ||
469 | xatp.gpfn = (xen_hvm_resume_frames >> PAGE_SHIFT) + i; | ||
470 | rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp); | ||
471 | if (rc != 0) { | ||
472 | printk(KERN_WARNING | ||
473 | "grant table add_to_physmap failed, err=%d\n", rc); | ||
474 | break; | ||
475 | } | ||
476 | } while (i-- > start_idx); | ||
477 | |||
478 | return rc; | ||
479 | } | ||
480 | |||
452 | frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC); | 481 | frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC); |
453 | if (!frames) | 482 | if (!frames) |
454 | return -ENOMEM; | 483 | return -ENOMEM; |
@@ -465,7 +494,7 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx) | |||
465 | 494 | ||
466 | BUG_ON(rc || setup.status); | 495 | BUG_ON(rc || setup.status); |
467 | 496 | ||
468 | rc = arch_gnttab_map_shared(frames, nr_gframes, max_nr_grant_frames(), | 497 | rc = arch_gnttab_map_shared(frames, nr_gframes, gnttab_max_grant_frames(), |
469 | &shared); | 498 | &shared); |
470 | BUG_ON(rc); | 499 | BUG_ON(rc); |
471 | 500 | ||
@@ -476,9 +505,27 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx) | |||
476 | 505 | ||
477 | int gnttab_resume(void) | 506 | int gnttab_resume(void) |
478 | { | 507 | { |
479 | if (max_nr_grant_frames() < nr_grant_frames) | 508 | unsigned int max_nr_gframes; |
509 | |||
510 | max_nr_gframes = gnttab_max_grant_frames(); | ||
511 | if (max_nr_gframes < nr_grant_frames) | ||
480 | return -ENOSYS; | 512 | return -ENOSYS; |
481 | return gnttab_map(0, nr_grant_frames - 1); | 513 | |
514 | if (xen_pv_domain()) | ||
515 | return gnttab_map(0, nr_grant_frames - 1); | ||
516 | |||
517 | if (!shared) { | ||
518 | shared = ioremap(xen_hvm_resume_frames, PAGE_SIZE * max_nr_gframes); | ||
519 | if (shared == NULL) { | ||
520 | printk(KERN_WARNING | ||
521 | "Failed to ioremap gnttab share frames!"); | ||
522 | return -ENOMEM; | ||
523 | } | ||
524 | } | ||
525 | |||
526 | gnttab_map(0, nr_grant_frames - 1); | ||
527 | |||
528 | return 0; | ||
482 | } | 529 | } |
483 | 530 | ||
484 | int gnttab_suspend(void) | 531 | int gnttab_suspend(void) |
@@ -495,7 +542,7 @@ static int gnttab_expand(unsigned int req_entries) | |||
495 | cur = nr_grant_frames; | 542 | cur = nr_grant_frames; |
496 | extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) / | 543 | extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) / |
497 | GREFS_PER_GRANT_FRAME); | 544 | GREFS_PER_GRANT_FRAME); |
498 | if (cur + extra > max_nr_grant_frames()) | 545 | if (cur + extra > gnttab_max_grant_frames()) |
499 | return -ENOSPC; | 546 | return -ENOSPC; |
500 | 547 | ||
501 | rc = gnttab_map(cur, cur + extra - 1); | 548 | rc = gnttab_map(cur, cur + extra - 1); |
@@ -505,15 +552,12 @@ static int gnttab_expand(unsigned int req_entries) | |||
505 | return rc; | 552 | return rc; |
506 | } | 553 | } |
507 | 554 | ||
508 | static int __devinit gnttab_init(void) | 555 | int gnttab_init(void) |
509 | { | 556 | { |
510 | int i; | 557 | int i; |
511 | unsigned int max_nr_glist_frames, nr_glist_frames; | 558 | unsigned int max_nr_glist_frames, nr_glist_frames; |
512 | unsigned int nr_init_grefs; | 559 | unsigned int nr_init_grefs; |
513 | 560 | ||
514 | if (!xen_domain()) | ||
515 | return -ENODEV; | ||
516 | |||
517 | nr_grant_frames = 1; | 561 | nr_grant_frames = 1; |
518 | boot_max_nr_grant_frames = __max_nr_grant_frames(); | 562 | boot_max_nr_grant_frames = __max_nr_grant_frames(); |
519 | 563 | ||
@@ -556,5 +600,18 @@ static int __devinit gnttab_init(void) | |||
556 | kfree(gnttab_list); | 600 | kfree(gnttab_list); |
557 | return -ENOMEM; | 601 | return -ENOMEM; |
558 | } | 602 | } |
603 | EXPORT_SYMBOL_GPL(gnttab_init); | ||
604 | |||
605 | static int __devinit __gnttab_init(void) | ||
606 | { | ||
607 | /* Delay grant-table initialization in the PV on HVM case */ | ||
608 | if (xen_hvm_domain()) | ||
609 | return 0; | ||
610 | |||
611 | if (!xen_pv_domain()) | ||
612 | return -ENODEV; | ||
613 | |||
614 | return gnttab_init(); | ||
615 | } | ||
559 | 616 | ||
560 | core_initcall(gnttab_init); | 617 | core_initcall(__gnttab_init); |
diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index 07e857b0de13..1799bd890315 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/stop_machine.h> | 9 | #include <linux/stop_machine.h> |
10 | #include <linux/freezer.h> | 10 | #include <linux/freezer.h> |
11 | 11 | ||
12 | #include <xen/xen.h> | ||
12 | #include <xen/xenbus.h> | 13 | #include <xen/xenbus.h> |
13 | #include <xen/grant_table.h> | 14 | #include <xen/grant_table.h> |
14 | #include <xen/events.h> | 15 | #include <xen/events.h> |
@@ -17,6 +18,7 @@ | |||
17 | 18 | ||
18 | #include <asm/xen/hypercall.h> | 19 | #include <asm/xen/hypercall.h> |
19 | #include <asm/xen/page.h> | 20 | #include <asm/xen/page.h> |
21 | #include <asm/xen/hypervisor.h> | ||
20 | 22 | ||
21 | enum shutdown_state { | 23 | enum shutdown_state { |
22 | SHUTDOWN_INVALID = -1, | 24 | SHUTDOWN_INVALID = -1, |
@@ -33,10 +35,30 @@ enum shutdown_state { | |||
33 | static enum shutdown_state shutting_down = SHUTDOWN_INVALID; | 35 | static enum shutdown_state shutting_down = SHUTDOWN_INVALID; |
34 | 36 | ||
35 | #ifdef CONFIG_PM_SLEEP | 37 | #ifdef CONFIG_PM_SLEEP |
36 | static int xen_suspend(void *data) | 38 | static int xen_hvm_suspend(void *data) |
37 | { | 39 | { |
40 | struct sched_shutdown r = { .reason = SHUTDOWN_suspend }; | ||
38 | int *cancelled = data; | 41 | int *cancelled = data; |
42 | |||
43 | BUG_ON(!irqs_disabled()); | ||
44 | |||
45 | *cancelled = HYPERVISOR_sched_op(SCHEDOP_shutdown, &r); | ||
46 | |||
47 | xen_hvm_post_suspend(*cancelled); | ||
48 | gnttab_resume(); | ||
49 | |||
50 | if (!*cancelled) { | ||
51 | xen_irq_resume(); | ||
52 | xen_timer_resume(); | ||
53 | } | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static int xen_suspend(void *data) | ||
59 | { | ||
39 | int err; | 60 | int err; |
61 | int *cancelled = data; | ||
40 | 62 | ||
41 | BUG_ON(!irqs_disabled()); | 63 | BUG_ON(!irqs_disabled()); |
42 | 64 | ||
@@ -106,7 +128,10 @@ static void do_suspend(void) | |||
106 | goto out_resume; | 128 | goto out_resume; |
107 | } | 129 | } |
108 | 130 | ||
109 | err = stop_machine(xen_suspend, &cancelled, cpumask_of(0)); | 131 | if (xen_hvm_domain()) |
132 | err = stop_machine(xen_hvm_suspend, &cancelled, cpumask_of(0)); | ||
133 | else | ||
134 | err = stop_machine(xen_suspend, &cancelled, cpumask_of(0)); | ||
110 | 135 | ||
111 | dpm_resume_noirq(PMSG_RESUME); | 136 | dpm_resume_noirq(PMSG_RESUME); |
112 | 137 | ||
@@ -255,7 +280,19 @@ static int shutdown_event(struct notifier_block *notifier, | |||
255 | return NOTIFY_DONE; | 280 | return NOTIFY_DONE; |
256 | } | 281 | } |
257 | 282 | ||
258 | static int __init setup_shutdown_event(void) | 283 | static int __init __setup_shutdown_event(void) |
284 | { | ||
285 | /* Delay initialization in the PV on HVM case */ | ||
286 | if (xen_hvm_domain()) | ||
287 | return 0; | ||
288 | |||
289 | if (!xen_pv_domain()) | ||
290 | return -ENODEV; | ||
291 | |||
292 | return xen_setup_shutdown_event(); | ||
293 | } | ||
294 | |||
295 | int xen_setup_shutdown_event(void) | ||
259 | { | 296 | { |
260 | static struct notifier_block xenstore_notifier = { | 297 | static struct notifier_block xenstore_notifier = { |
261 | .notifier_call = shutdown_event | 298 | .notifier_call = shutdown_event |
@@ -264,5 +301,6 @@ static int __init setup_shutdown_event(void) | |||
264 | 301 | ||
265 | return 0; | 302 | return 0; |
266 | } | 303 | } |
304 | EXPORT_SYMBOL_GPL(xen_setup_shutdown_event); | ||
267 | 305 | ||
268 | subsys_initcall(setup_shutdown_event); | 306 | subsys_initcall(__setup_shutdown_event); |
diff --git a/drivers/xen/platform-pci.c b/drivers/xen/platform-pci.c new file mode 100644 index 000000000000..c01b5ddce529 --- /dev/null +++ b/drivers/xen/platform-pci.c | |||
@@ -0,0 +1,207 @@ | |||
1 | /****************************************************************************** | ||
2 | * platform-pci.c | ||
3 | * | ||
4 | * Xen platform PCI device driver | ||
5 | * Copyright (c) 2005, Intel Corporation. | ||
6 | * Copyright (c) 2007, XenSource Inc. | ||
7 | * Copyright (c) 2010, Citrix | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms and conditions of the GNU General Public License, | ||
11 | * version 2, as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along with | ||
19 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
20 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/pci.h> | ||
29 | |||
30 | #include <xen/platform_pci.h> | ||
31 | #include <xen/grant_table.h> | ||
32 | #include <xen/xenbus.h> | ||
33 | #include <xen/events.h> | ||
34 | #include <xen/hvm.h> | ||
35 | #include <xen/xen-ops.h> | ||
36 | |||
37 | #define DRV_NAME "xen-platform-pci" | ||
38 | |||
39 | MODULE_AUTHOR("ssmith@xensource.com and stefano.stabellini@eu.citrix.com"); | ||
40 | MODULE_DESCRIPTION("Xen platform PCI device"); | ||
41 | MODULE_LICENSE("GPL"); | ||
42 | |||
43 | static unsigned long platform_mmio; | ||
44 | static unsigned long platform_mmio_alloc; | ||
45 | static unsigned long platform_mmiolen; | ||
46 | static uint64_t callback_via; | ||
47 | |||
48 | unsigned long alloc_xen_mmio(unsigned long len) | ||
49 | { | ||
50 | unsigned long addr; | ||
51 | |||
52 | addr = platform_mmio + platform_mmio_alloc; | ||
53 | platform_mmio_alloc += len; | ||
54 | BUG_ON(platform_mmio_alloc > platform_mmiolen); | ||
55 | |||
56 | return addr; | ||
57 | } | ||
58 | |||
59 | static uint64_t get_callback_via(struct pci_dev *pdev) | ||
60 | { | ||
61 | u8 pin; | ||
62 | int irq; | ||
63 | |||
64 | irq = pdev->irq; | ||
65 | if (irq < 16) | ||
66 | return irq; /* ISA IRQ */ | ||
67 | |||
68 | pin = pdev->pin; | ||
69 | |||
70 | /* We don't know the GSI. Specify the PCI INTx line instead. */ | ||
71 | return ((uint64_t)0x01 << 56) | /* PCI INTx identifier */ | ||
72 | ((uint64_t)pci_domain_nr(pdev->bus) << 32) | | ||
73 | ((uint64_t)pdev->bus->number << 16) | | ||
74 | ((uint64_t)(pdev->devfn & 0xff) << 8) | | ||
75 | ((uint64_t)(pin - 1) & 3); | ||
76 | } | ||
77 | |||
78 | static irqreturn_t do_hvm_evtchn_intr(int irq, void *dev_id) | ||
79 | { | ||
80 | xen_hvm_evtchn_do_upcall(); | ||
81 | return IRQ_HANDLED; | ||
82 | } | ||
83 | |||
84 | static int xen_allocate_irq(struct pci_dev *pdev) | ||
85 | { | ||
86 | return request_irq(pdev->irq, do_hvm_evtchn_intr, | ||
87 | IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TRIGGER_RISING, | ||
88 | "xen-platform-pci", pdev); | ||
89 | } | ||
90 | |||
91 | static int platform_pci_resume(struct pci_dev *pdev) | ||
92 | { | ||
93 | int err; | ||
94 | if (xen_have_vector_callback) | ||
95 | return 0; | ||
96 | err = xen_set_callback_via(callback_via); | ||
97 | if (err) { | ||
98 | dev_err(&pdev->dev, "platform_pci_resume failure!\n"); | ||
99 | return err; | ||
100 | } | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static int __devinit platform_pci_init(struct pci_dev *pdev, | ||
105 | const struct pci_device_id *ent) | ||
106 | { | ||
107 | int i, ret; | ||
108 | long ioaddr, iolen; | ||
109 | long mmio_addr, mmio_len; | ||
110 | unsigned int max_nr_gframes; | ||
111 | |||
112 | i = pci_enable_device(pdev); | ||
113 | if (i) | ||
114 | return i; | ||
115 | |||
116 | ioaddr = pci_resource_start(pdev, 0); | ||
117 | iolen = pci_resource_len(pdev, 0); | ||
118 | |||
119 | mmio_addr = pci_resource_start(pdev, 1); | ||
120 | mmio_len = pci_resource_len(pdev, 1); | ||
121 | |||
122 | if (mmio_addr == 0 || ioaddr == 0) { | ||
123 | dev_err(&pdev->dev, "no resources found\n"); | ||
124 | ret = -ENOENT; | ||
125 | goto pci_out; | ||
126 | } | ||
127 | |||
128 | if (request_mem_region(mmio_addr, mmio_len, DRV_NAME) == NULL) { | ||
129 | dev_err(&pdev->dev, "MEM I/O resource 0x%lx @ 0x%lx busy\n", | ||
130 | mmio_addr, mmio_len); | ||
131 | ret = -EBUSY; | ||
132 | goto pci_out; | ||
133 | } | ||
134 | |||
135 | if (request_region(ioaddr, iolen, DRV_NAME) == NULL) { | ||
136 | dev_err(&pdev->dev, "I/O resource 0x%lx @ 0x%lx busy\n", | ||
137 | iolen, ioaddr); | ||
138 | ret = -EBUSY; | ||
139 | goto mem_out; | ||
140 | } | ||
141 | |||
142 | platform_mmio = mmio_addr; | ||
143 | platform_mmiolen = mmio_len; | ||
144 | |||
145 | if (!xen_have_vector_callback) { | ||
146 | ret = xen_allocate_irq(pdev); | ||
147 | if (ret) { | ||
148 | dev_warn(&pdev->dev, "request_irq failed err=%d\n", ret); | ||
149 | goto out; | ||
150 | } | ||
151 | callback_via = get_callback_via(pdev); | ||
152 | ret = xen_set_callback_via(callback_via); | ||
153 | if (ret) { | ||
154 | dev_warn(&pdev->dev, "Unable to set the evtchn callback " | ||
155 | "err=%d\n", ret); | ||
156 | goto out; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | max_nr_gframes = gnttab_max_grant_frames(); | ||
161 | xen_hvm_resume_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes); | ||
162 | ret = gnttab_init(); | ||
163 | if (ret) | ||
164 | goto out; | ||
165 | xenbus_probe(NULL); | ||
166 | ret = xen_setup_shutdown_event(); | ||
167 | if (ret) | ||
168 | goto out; | ||
169 | return 0; | ||
170 | |||
171 | out: | ||
172 | release_region(ioaddr, iolen); | ||
173 | mem_out: | ||
174 | release_mem_region(mmio_addr, mmio_len); | ||
175 | pci_out: | ||
176 | pci_disable_device(pdev); | ||
177 | return ret; | ||
178 | } | ||
179 | |||
180 | static struct pci_device_id platform_pci_tbl[] __devinitdata = { | ||
181 | {PCI_VENDOR_ID_XEN, PCI_DEVICE_ID_XEN_PLATFORM, | ||
182 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
183 | {0,} | ||
184 | }; | ||
185 | |||
186 | MODULE_DEVICE_TABLE(pci, platform_pci_tbl); | ||
187 | |||
188 | static struct pci_driver platform_driver = { | ||
189 | .name = DRV_NAME, | ||
190 | .probe = platform_pci_init, | ||
191 | .id_table = platform_pci_tbl, | ||
192 | #ifdef CONFIG_PM | ||
193 | .resume_early = platform_pci_resume, | ||
194 | #endif | ||
195 | }; | ||
196 | |||
197 | static int __init platform_pci_module_init(void) | ||
198 | { | ||
199 | /* no unplug has been done, IGNORE hasn't been specified: just | ||
200 | * return now */ | ||
201 | if (!xen_platform_pci_unplug) | ||
202 | return -ENODEV; | ||
203 | |||
204 | return pci_register_driver(&platform_driver); | ||
205 | } | ||
206 | |||
207 | module_init(platform_pci_module_init); | ||
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index abc12426ef0a..29bac5118877 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c | |||
@@ -56,6 +56,9 @@ | |||
56 | #include <xen/events.h> | 56 | #include <xen/events.h> |
57 | #include <xen/page.h> | 57 | #include <xen/page.h> |
58 | 58 | ||
59 | #include <xen/platform_pci.h> | ||
60 | #include <xen/hvm.h> | ||
61 | |||
59 | #include "xenbus_comms.h" | 62 | #include "xenbus_comms.h" |
60 | #include "xenbus_probe.h" | 63 | #include "xenbus_probe.h" |
61 | 64 | ||
@@ -776,8 +779,23 @@ void xenbus_probe(struct work_struct *unused) | |||
776 | /* Notify others that xenstore is up */ | 779 | /* Notify others that xenstore is up */ |
777 | blocking_notifier_call_chain(&xenstore_chain, 0, NULL); | 780 | blocking_notifier_call_chain(&xenstore_chain, 0, NULL); |
778 | } | 781 | } |
782 | EXPORT_SYMBOL_GPL(xenbus_probe); | ||
779 | 783 | ||
780 | static int __init xenbus_probe_init(void) | 784 | static int __init xenbus_probe_initcall(void) |
785 | { | ||
786 | if (!xen_domain()) | ||
787 | return -ENODEV; | ||
788 | |||
789 | if (xen_initial_domain() || xen_hvm_domain()) | ||
790 | return 0; | ||
791 | |||
792 | xenbus_probe(NULL); | ||
793 | return 0; | ||
794 | } | ||
795 | |||
796 | device_initcall(xenbus_probe_initcall); | ||
797 | |||
798 | static int __init xenbus_init(void) | ||
781 | { | 799 | { |
782 | int err = 0; | 800 | int err = 0; |
783 | 801 | ||
@@ -802,11 +820,24 @@ static int __init xenbus_probe_init(void) | |||
802 | if (xen_initial_domain()) { | 820 | if (xen_initial_domain()) { |
803 | /* dom0 not yet supported */ | 821 | /* dom0 not yet supported */ |
804 | } else { | 822 | } else { |
823 | if (xen_hvm_domain()) { | ||
824 | uint64_t v = 0; | ||
825 | err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v); | ||
826 | if (err) | ||
827 | goto out_error; | ||
828 | xen_store_evtchn = (int)v; | ||
829 | err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v); | ||
830 | if (err) | ||
831 | goto out_error; | ||
832 | xen_store_mfn = (unsigned long)v; | ||
833 | xen_store_interface = ioremap(xen_store_mfn << PAGE_SHIFT, PAGE_SIZE); | ||
834 | } else { | ||
835 | xen_store_evtchn = xen_start_info->store_evtchn; | ||
836 | xen_store_mfn = xen_start_info->store_mfn; | ||
837 | xen_store_interface = mfn_to_virt(xen_store_mfn); | ||
838 | } | ||
805 | xenstored_ready = 1; | 839 | xenstored_ready = 1; |
806 | xen_store_evtchn = xen_start_info->store_evtchn; | ||
807 | xen_store_mfn = xen_start_info->store_mfn; | ||
808 | } | 840 | } |
809 | xen_store_interface = mfn_to_virt(xen_store_mfn); | ||
810 | 841 | ||
811 | /* Initialize the interface to xenstore. */ | 842 | /* Initialize the interface to xenstore. */ |
812 | err = xs_init(); | 843 | err = xs_init(); |
@@ -816,9 +847,6 @@ static int __init xenbus_probe_init(void) | |||
816 | goto out_unreg_back; | 847 | goto out_unreg_back; |
817 | } | 848 | } |
818 | 849 | ||
819 | if (!xen_initial_domain()) | ||
820 | xenbus_probe(NULL); | ||
821 | |||
822 | #ifdef CONFIG_XEN_COMPAT_XENFS | 850 | #ifdef CONFIG_XEN_COMPAT_XENFS |
823 | /* | 851 | /* |
824 | * Create xenfs mountpoint in /proc for compatibility with | 852 | * Create xenfs mountpoint in /proc for compatibility with |
@@ -839,7 +867,7 @@ static int __init xenbus_probe_init(void) | |||
839 | return err; | 867 | return err; |
840 | } | 868 | } |
841 | 869 | ||
842 | postcore_initcall(xenbus_probe_init); | 870 | postcore_initcall(xenbus_init); |
843 | 871 | ||
844 | MODULE_LICENSE("GPL"); | 872 | MODULE_LICENSE("GPL"); |
845 | 873 | ||
@@ -947,6 +975,9 @@ static void wait_for_devices(struct xenbus_driver *xendrv) | |||
947 | #ifndef MODULE | 975 | #ifndef MODULE |
948 | static int __init boot_wait_for_devices(void) | 976 | static int __init boot_wait_for_devices(void) |
949 | { | 977 | { |
978 | if (xen_hvm_domain() && !xen_platform_pci_unplug) | ||
979 | return -ENODEV; | ||
980 | |||
950 | ready_to_wait_for_devices = 1; | 981 | ready_to_wait_for_devices = 1; |
951 | wait_for_devices(NULL); | 982 | wait_for_devices(NULL); |
952 | return 0; | 983 | return 0; |
diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c index 8924d93136f1..78bfab0700ba 100644 --- a/drivers/xen/xenfs/super.c +++ b/drivers/xen/xenfs/super.c | |||
@@ -65,7 +65,7 @@ static struct file_system_type xenfs_type = { | |||
65 | 65 | ||
66 | static int __init xenfs_init(void) | 66 | static int __init xenfs_init(void) |
67 | { | 67 | { |
68 | if (xen_pv_domain()) | 68 | if (xen_domain()) |
69 | return register_filesystem(&xenfs_type); | 69 | return register_filesystem(&xenfs_type); |
70 | 70 | ||
71 | printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n"); | 71 | printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n"); |
@@ -74,7 +74,7 @@ static int __init xenfs_init(void) | |||
74 | 74 | ||
75 | static void __exit xenfs_exit(void) | 75 | static void __exit xenfs_exit(void) |
76 | { | 76 | { |
77 | if (xen_pv_domain()) | 77 | if (xen_domain()) |
78 | unregister_filesystem(&xenfs_type); | 78 | unregister_filesystem(&xenfs_type); |
79 | } | 79 | } |
80 | 80 | ||
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 030a954ed292..4e7ae6002056 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h | |||
@@ -653,6 +653,7 @@ | |||
653 | EXIT_DATA \ | 653 | EXIT_DATA \ |
654 | EXIT_CALL \ | 654 | EXIT_CALL \ |
655 | *(.discard) \ | 655 | *(.discard) \ |
656 | *(.discard.*) \ | ||
656 | } | 657 | } |
657 | 658 | ||
658 | /** | 659 | /** |
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 3bedcc149c84..cca2526f28d7 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h | |||
@@ -2772,3 +2772,6 @@ | |||
2772 | #define PCI_DEVICE_ID_RME_DIGI32 0x9896 | 2772 | #define PCI_DEVICE_ID_RME_DIGI32 0x9896 |
2773 | #define PCI_DEVICE_ID_RME_DIGI32_PRO 0x9897 | 2773 | #define PCI_DEVICE_ID_RME_DIGI32_PRO 0x9897 |
2774 | #define PCI_DEVICE_ID_RME_DIGI32_8 0x9898 | 2774 | #define PCI_DEVICE_ID_RME_DIGI32_8 0x9898 |
2775 | |||
2776 | #define PCI_VENDOR_ID_XEN 0x5853 | ||
2777 | #define PCI_DEVICE_ID_XEN_PLATFORM 0x0001 | ||
diff --git a/include/xen/events.h b/include/xen/events.h index e68d59a90ca8..a15d93262e30 100644 --- a/include/xen/events.h +++ b/include/xen/events.h | |||
@@ -56,4 +56,11 @@ void xen_poll_irq(int irq); | |||
56 | /* Determine the IRQ which is bound to an event channel */ | 56 | /* Determine the IRQ which is bound to an event channel */ |
57 | unsigned irq_from_evtchn(unsigned int evtchn); | 57 | unsigned irq_from_evtchn(unsigned int evtchn); |
58 | 58 | ||
59 | /* Xen HVM evtchn vector callback */ | ||
60 | extern void xen_hvm_callback_vector(void); | ||
61 | extern int xen_have_vector_callback; | ||
62 | int xen_set_callback_via(uint64_t via); | ||
63 | void xen_evtchn_do_upcall(struct pt_regs *regs); | ||
64 | void xen_hvm_evtchn_do_upcall(void); | ||
65 | |||
59 | #endif /* _XEN_EVENTS_H */ | 66 | #endif /* _XEN_EVENTS_H */ |
diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h index a40f1cd91be1..9a731706a016 100644 --- a/include/xen/grant_table.h +++ b/include/xen/grant_table.h | |||
@@ -51,6 +51,7 @@ struct gnttab_free_callback { | |||
51 | u16 count; | 51 | u16 count; |
52 | }; | 52 | }; |
53 | 53 | ||
54 | int gnttab_init(void); | ||
54 | int gnttab_suspend(void); | 55 | int gnttab_suspend(void); |
55 | int gnttab_resume(void); | 56 | int gnttab_resume(void); |
56 | 57 | ||
@@ -112,6 +113,9 @@ int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes, | |||
112 | void arch_gnttab_unmap_shared(struct grant_entry *shared, | 113 | void arch_gnttab_unmap_shared(struct grant_entry *shared, |
113 | unsigned long nr_gframes); | 114 | unsigned long nr_gframes); |
114 | 115 | ||
116 | extern unsigned long xen_hvm_resume_frames; | ||
117 | unsigned int gnttab_max_grant_frames(void); | ||
118 | |||
115 | #define gnttab_map_vaddr(map) ((void *)(map.host_virt_addr)) | 119 | #define gnttab_map_vaddr(map) ((void *)(map.host_virt_addr)) |
116 | 120 | ||
117 | #endif /* __ASM_GNTTAB_H__ */ | 121 | #endif /* __ASM_GNTTAB_H__ */ |
diff --git a/include/xen/hvm.h b/include/xen/hvm.h new file mode 100644 index 000000000000..b193fa2f9fdd --- /dev/null +++ b/include/xen/hvm.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* Simple wrappers around HVM functions */ | ||
2 | #ifndef XEN_HVM_H__ | ||
3 | #define XEN_HVM_H__ | ||
4 | |||
5 | #include <xen/interface/hvm/params.h> | ||
6 | #include <asm/xen/hypercall.h> | ||
7 | |||
8 | static inline int hvm_get_parameter(int idx, uint64_t *value) | ||
9 | { | ||
10 | struct xen_hvm_param xhv; | ||
11 | int r; | ||
12 | |||
13 | xhv.domid = DOMID_SELF; | ||
14 | xhv.index = idx; | ||
15 | r = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv); | ||
16 | if (r < 0) { | ||
17 | printk(KERN_ERR "Cannot get hvm parameter %d: %d!\n", | ||
18 | idx, r); | ||
19 | return r; | ||
20 | } | ||
21 | *value = xhv.value; | ||
22 | return r; | ||
23 | } | ||
24 | |||
25 | #define HVM_CALLBACK_VIA_TYPE_VECTOR 0x2 | ||
26 | #define HVM_CALLBACK_VIA_TYPE_SHIFT 56 | ||
27 | #define HVM_CALLBACK_VECTOR(x) (((uint64_t)HVM_CALLBACK_VIA_TYPE_VECTOR)<<\ | ||
28 | HVM_CALLBACK_VIA_TYPE_SHIFT | (x)) | ||
29 | |||
30 | #endif /* XEN_HVM_H__ */ | ||
diff --git a/include/xen/interface/features.h b/include/xen/interface/features.h index f51b6413b054..70d2563ab166 100644 --- a/include/xen/interface/features.h +++ b/include/xen/interface/features.h | |||
@@ -41,6 +41,12 @@ | |||
41 | /* x86: Does this Xen host support the MMU_PT_UPDATE_PRESERVE_AD hypercall? */ | 41 | /* x86: Does this Xen host support the MMU_PT_UPDATE_PRESERVE_AD hypercall? */ |
42 | #define XENFEAT_mmu_pt_update_preserve_ad 5 | 42 | #define XENFEAT_mmu_pt_update_preserve_ad 5 |
43 | 43 | ||
44 | /* x86: Does this Xen host support the HVM callback vector type? */ | ||
45 | #define XENFEAT_hvm_callback_vector 8 | ||
46 | |||
47 | /* x86: pvclock algorithm is safe to use on HVM */ | ||
48 | #define XENFEAT_hvm_safe_pvclock 9 | ||
49 | |||
44 | #define XENFEAT_NR_SUBMAPS 1 | 50 | #define XENFEAT_NR_SUBMAPS 1 |
45 | 51 | ||
46 | #endif /* __XEN_PUBLIC_FEATURES_H__ */ | 52 | #endif /* __XEN_PUBLIC_FEATURES_H__ */ |
diff --git a/include/xen/interface/grant_table.h b/include/xen/interface/grant_table.h index 39da93c21de0..39e571796e32 100644 --- a/include/xen/interface/grant_table.h +++ b/include/xen/interface/grant_table.h | |||
@@ -28,6 +28,7 @@ | |||
28 | #ifndef __XEN_PUBLIC_GRANT_TABLE_H__ | 28 | #ifndef __XEN_PUBLIC_GRANT_TABLE_H__ |
29 | #define __XEN_PUBLIC_GRANT_TABLE_H__ | 29 | #define __XEN_PUBLIC_GRANT_TABLE_H__ |
30 | 30 | ||
31 | #include <xen/interface/xen.h> | ||
31 | 32 | ||
32 | /*********************************** | 33 | /*********************************** |
33 | * GRANT TABLE REPRESENTATION | 34 | * GRANT TABLE REPRESENTATION |
diff --git a/include/xen/interface/hvm/hvm_op.h b/include/xen/interface/hvm/hvm_op.h new file mode 100644 index 000000000000..a4827f46ee97 --- /dev/null +++ b/include/xen/interface/hvm/hvm_op.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
3 | * of this software and associated documentation files (the "Software"), to | ||
4 | * deal in the Software without restriction, including without limitation the | ||
5 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||
6 | * sell copies of the Software, and to permit persons to whom the Software is | ||
7 | * furnished to do so, subject to the following conditions: | ||
8 | * | ||
9 | * The above copyright notice and this permission notice shall be included in | ||
10 | * all copies or substantial portions of the Software. | ||
11 | * | ||
12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
13 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
15 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
16 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
17 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
18 | * DEALINGS IN THE SOFTWARE. | ||
19 | */ | ||
20 | |||
21 | #ifndef __XEN_PUBLIC_HVM_HVM_OP_H__ | ||
22 | #define __XEN_PUBLIC_HVM_HVM_OP_H__ | ||
23 | |||
24 | /* Get/set subcommands: the second argument of the hypercall is a | ||
25 | * pointer to a xen_hvm_param struct. */ | ||
26 | #define HVMOP_set_param 0 | ||
27 | #define HVMOP_get_param 1 | ||
28 | struct xen_hvm_param { | ||
29 | domid_t domid; /* IN */ | ||
30 | uint32_t index; /* IN */ | ||
31 | uint64_t value; /* IN/OUT */ | ||
32 | }; | ||
33 | DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_param); | ||
34 | |||
35 | /* Hint from PV drivers for pagetable destruction. */ | ||
36 | #define HVMOP_pagetable_dying 9 | ||
37 | struct xen_hvm_pagetable_dying { | ||
38 | /* Domain with a pagetable about to be destroyed. */ | ||
39 | domid_t domid; | ||
40 | /* guest physical address of the toplevel pagetable dying */ | ||
41 | aligned_u64 gpa; | ||
42 | }; | ||
43 | typedef struct xen_hvm_pagetable_dying xen_hvm_pagetable_dying_t; | ||
44 | DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_pagetable_dying_t); | ||
45 | |||
46 | #endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */ | ||
diff --git a/include/xen/interface/hvm/params.h b/include/xen/interface/hvm/params.h new file mode 100644 index 000000000000..1888d8c157e6 --- /dev/null +++ b/include/xen/interface/hvm/params.h | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
3 | * of this software and associated documentation files (the "Software"), to | ||
4 | * deal in the Software without restriction, including without limitation the | ||
5 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||
6 | * sell copies of the Software, and to permit persons to whom the Software is | ||
7 | * furnished to do so, subject to the following conditions: | ||
8 | * | ||
9 | * The above copyright notice and this permission notice shall be included in | ||
10 | * all copies or substantial portions of the Software. | ||
11 | * | ||
12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
13 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
15 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
16 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
17 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
18 | * DEALINGS IN THE SOFTWARE. | ||
19 | */ | ||
20 | |||
21 | #ifndef __XEN_PUBLIC_HVM_PARAMS_H__ | ||
22 | #define __XEN_PUBLIC_HVM_PARAMS_H__ | ||
23 | |||
24 | #include "hvm_op.h" | ||
25 | |||
26 | /* | ||
27 | * Parameter space for HVMOP_{set,get}_param. | ||
28 | */ | ||
29 | |||
30 | /* | ||
31 | * How should CPU0 event-channel notifications be delivered? | ||
32 | * val[63:56] == 0: val[55:0] is a delivery GSI (Global System Interrupt). | ||
33 | * val[63:56] == 1: val[55:0] is a delivery PCI INTx line, as follows: | ||
34 | * Domain = val[47:32], Bus = val[31:16], | ||
35 | * DevFn = val[15: 8], IntX = val[ 1: 0] | ||
36 | * val[63:56] == 2: val[7:0] is a vector number. | ||
37 | * If val == 0 then CPU0 event-channel notifications are not delivered. | ||
38 | */ | ||
39 | #define HVM_PARAM_CALLBACK_IRQ 0 | ||
40 | |||
41 | #define HVM_PARAM_STORE_PFN 1 | ||
42 | #define HVM_PARAM_STORE_EVTCHN 2 | ||
43 | |||
44 | #define HVM_PARAM_PAE_ENABLED 4 | ||
45 | |||
46 | #define HVM_PARAM_IOREQ_PFN 5 | ||
47 | |||
48 | #define HVM_PARAM_BUFIOREQ_PFN 6 | ||
49 | |||
50 | /* | ||
51 | * Set mode for virtual timers (currently x86 only): | ||
52 | * delay_for_missed_ticks (default): | ||
53 | * Do not advance a vcpu's time beyond the correct delivery time for | ||
54 | * interrupts that have been missed due to preemption. Deliver missed | ||
55 | * interrupts when the vcpu is rescheduled and advance the vcpu's virtual | ||
56 | * time stepwise for each one. | ||
57 | * no_delay_for_missed_ticks: | ||
58 | * As above, missed interrupts are delivered, but guest time always tracks | ||
59 | * wallclock (i.e., real) time while doing so. | ||
60 | * no_missed_ticks_pending: | ||
61 | * No missed interrupts are held pending. Instead, to ensure ticks are | ||
62 | * delivered at some non-zero rate, if we detect missed ticks then the | ||
63 | * internal tick alarm is not disabled if the VCPU is preempted during the | ||
64 | * next tick period. | ||
65 | * one_missed_tick_pending: | ||
66 | * Missed interrupts are collapsed together and delivered as one 'late tick'. | ||
67 | * Guest time always tracks wallclock (i.e., real) time. | ||
68 | */ | ||
69 | #define HVM_PARAM_TIMER_MODE 10 | ||
70 | #define HVMPTM_delay_for_missed_ticks 0 | ||
71 | #define HVMPTM_no_delay_for_missed_ticks 1 | ||
72 | #define HVMPTM_no_missed_ticks_pending 2 | ||
73 | #define HVMPTM_one_missed_tick_pending 3 | ||
74 | |||
75 | /* Boolean: Enable virtual HPET (high-precision event timer)? (x86-only) */ | ||
76 | #define HVM_PARAM_HPET_ENABLED 11 | ||
77 | |||
78 | /* Identity-map page directory used by Intel EPT when CR0.PG=0. */ | ||
79 | #define HVM_PARAM_IDENT_PT 12 | ||
80 | |||
81 | /* Device Model domain, defaults to 0. */ | ||
82 | #define HVM_PARAM_DM_DOMAIN 13 | ||
83 | |||
84 | /* ACPI S state: currently support S0 and S3 on x86. */ | ||
85 | #define HVM_PARAM_ACPI_S_STATE 14 | ||
86 | |||
87 | /* TSS used on Intel when CR0.PE=0. */ | ||
88 | #define HVM_PARAM_VM86_TSS 15 | ||
89 | |||
90 | /* Boolean: Enable aligning all periodic vpts to reduce interrupts */ | ||
91 | #define HVM_PARAM_VPT_ALIGN 16 | ||
92 | |||
93 | #define HVM_NR_PARAMS 17 | ||
94 | |||
95 | #endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */ | ||
diff --git a/include/xen/platform_pci.h b/include/xen/platform_pci.h new file mode 100644 index 000000000000..ce9d671c636c --- /dev/null +++ b/include/xen/platform_pci.h | |||
@@ -0,0 +1,49 @@ | |||
1 | #ifndef _XEN_PLATFORM_PCI_H | ||
2 | #define _XEN_PLATFORM_PCI_H | ||
3 | |||
4 | #define XEN_IOPORT_MAGIC_VAL 0x49d2 | ||
5 | #define XEN_IOPORT_LINUX_PRODNUM 0x0003 | ||
6 | #define XEN_IOPORT_LINUX_DRVVER 0x0001 | ||
7 | |||
8 | #define XEN_IOPORT_BASE 0x10 | ||
9 | |||
10 | #define XEN_IOPORT_PLATFLAGS (XEN_IOPORT_BASE + 0) /* 1 byte access (R/W) */ | ||
11 | #define XEN_IOPORT_MAGIC (XEN_IOPORT_BASE + 0) /* 2 byte access (R) */ | ||
12 | #define XEN_IOPORT_UNPLUG (XEN_IOPORT_BASE + 0) /* 2 byte access (W) */ | ||
13 | #define XEN_IOPORT_DRVVER (XEN_IOPORT_BASE + 0) /* 4 byte access (W) */ | ||
14 | |||
15 | #define XEN_IOPORT_SYSLOG (XEN_IOPORT_BASE + 2) /* 1 byte access (W) */ | ||
16 | #define XEN_IOPORT_PROTOVER (XEN_IOPORT_BASE + 2) /* 1 byte access (R) */ | ||
17 | #define XEN_IOPORT_PRODNUM (XEN_IOPORT_BASE + 2) /* 2 byte access (W) */ | ||
18 | |||
19 | #define XEN_UNPLUG_ALL_IDE_DISKS 1 | ||
20 | #define XEN_UNPLUG_ALL_NICS 2 | ||
21 | #define XEN_UNPLUG_AUX_IDE_DISKS 4 | ||
22 | #define XEN_UNPLUG_ALL 7 | ||
23 | #define XEN_UNPLUG_IGNORE 8 | ||
24 | |||
25 | static inline int xen_must_unplug_nics(void) { | ||
26 | #if (defined(CONFIG_XEN_NETDEV_FRONTEND) || \ | ||
27 | defined(CONFIG_XEN_NETDEV_FRONTEND_MODULE)) && \ | ||
28 | (defined(CONFIG_XEN_PLATFORM_PCI) || \ | ||
29 | defined(CONFIG_XEN_PLATFORM_PCI_MODULE)) | ||
30 | return 1; | ||
31 | #else | ||
32 | return 0; | ||
33 | #endif | ||
34 | } | ||
35 | |||
36 | static inline int xen_must_unplug_disks(void) { | ||
37 | #if (defined(CONFIG_XEN_BLKDEV_FRONTEND) || \ | ||
38 | defined(CONFIG_XEN_BLKDEV_FRONTEND_MODULE)) && \ | ||
39 | (defined(CONFIG_XEN_PLATFORM_PCI) || \ | ||
40 | defined(CONFIG_XEN_PLATFORM_PCI_MODULE)) | ||
41 | return 1; | ||
42 | #else | ||
43 | return 0; | ||
44 | #endif | ||
45 | } | ||
46 | |||
47 | extern int xen_platform_pci_unplug; | ||
48 | |||
49 | #endif /* _XEN_PLATFORM_PCI_H */ | ||
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index 883a21bba24b..46bc81ef74c6 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h | |||
@@ -7,6 +7,7 @@ DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu); | |||
7 | 7 | ||
8 | void xen_pre_suspend(void); | 8 | void xen_pre_suspend(void); |
9 | void xen_post_suspend(int suspend_cancelled); | 9 | void xen_post_suspend(int suspend_cancelled); |
10 | void xen_hvm_post_suspend(int suspend_cancelled); | ||
10 | 11 | ||
11 | void xen_mm_pin_all(void); | 12 | void xen_mm_pin_all(void); |
12 | void xen_mm_unpin_all(void); | 13 | void xen_mm_unpin_all(void); |
@@ -14,4 +15,6 @@ void xen_mm_unpin_all(void); | |||
14 | void xen_timer_resume(void); | 15 | void xen_timer_resume(void); |
15 | void xen_arch_resume(void); | 16 | void xen_arch_resume(void); |
16 | 17 | ||
18 | int xen_setup_shutdown_event(void); | ||
19 | |||
17 | #endif /* INCLUDE_XEN_OPS_H */ | 20 | #endif /* INCLUDE_XEN_OPS_H */ |