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 /arch/x86/xen | |
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
Diffstat (limited to 'arch/x86/xen')
-rw-r--r-- | arch/x86/xen/Kconfig | 5 | ||||
-rw-r--r-- | arch/x86/xen/Makefile | 2 | ||||
-rw-r--r-- | arch/x86/xen/enlighten.c | 158 | ||||
-rw-r--r-- | arch/x86/xen/mmu.c | 35 | ||||
-rw-r--r-- | arch/x86/xen/mmu.h | 1 | ||||
-rw-r--r-- | arch/x86/xen/platform-pci-unplug.c | 137 | ||||
-rw-r--r-- | arch/x86/xen/suspend.c | 12 | ||||
-rw-r--r-- | arch/x86/xen/time.c | 57 | ||||
-rw-r--r-- | arch/x86/xen/xen-ops.h | 11 |
9 files changed, 396 insertions, 22 deletions
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 | ||