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 */ |
