diff options
Diffstat (limited to 'drivers/xen')
-rw-r--r-- | drivers/xen/Makefile | 5 | ||||
-rw-r--r-- | drivers/xen/balloon.c | 42 | ||||
-rw-r--r-- | drivers/xen/events.c | 147 | ||||
-rw-r--r-- | drivers/xen/evtchn.c | 100 | ||||
-rw-r--r-- | drivers/xen/manage.c | 1 | ||||
-rw-r--r-- | drivers/xen/xenfs/privcmd.c | 14 | ||||
-rw-r--r-- | drivers/xen/xenfs/super.c | 46 |
7 files changed, 221 insertions, 134 deletions
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index eb8a78d77d9d..533a199e7a3f 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile | |||
@@ -8,9 +8,12 @@ obj-$(CONFIG_BLOCK) += biomerge.o | |||
8 | obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o | 8 | obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o |
9 | obj-$(CONFIG_XEN_XENCOMM) += xencomm.o | 9 | obj-$(CONFIG_XEN_XENCOMM) += xencomm.o |
10 | obj-$(CONFIG_XEN_BALLOON) += balloon.o | 10 | obj-$(CONFIG_XEN_BALLOON) += balloon.o |
11 | obj-$(CONFIG_XEN_DEV_EVTCHN) += evtchn.o | 11 | obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o |
12 | obj-$(CONFIG_XENFS) += xenfs/ | 12 | obj-$(CONFIG_XENFS) += xenfs/ |
13 | obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o | 13 | obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o |
14 | obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o | 14 | obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o |
15 | obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o | 15 | obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o |
16 | obj-$(CONFIG_XEN_DOM0) += pci.o | 16 | obj-$(CONFIG_XEN_DOM0) += pci.o |
17 | |||
18 | xen-evtchn-y := evtchn.o | ||
19 | |||
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 500290b150bb..43f9f02c7db0 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <asm/pgtable.h> | 50 | #include <asm/pgtable.h> |
51 | #include <asm/uaccess.h> | 51 | #include <asm/uaccess.h> |
52 | #include <asm/tlb.h> | 52 | #include <asm/tlb.h> |
53 | #include <asm/e820.h> | ||
53 | 54 | ||
54 | #include <asm/xen/hypervisor.h> | 55 | #include <asm/xen/hypervisor.h> |
55 | #include <asm/xen/hypercall.h> | 56 | #include <asm/xen/hypercall.h> |
@@ -119,7 +120,7 @@ static void scrub_page(struct page *page) | |||
119 | } | 120 | } |
120 | 121 | ||
121 | /* balloon_append: add the given page to the balloon. */ | 122 | /* balloon_append: add the given page to the balloon. */ |
122 | static void balloon_append(struct page *page) | 123 | static void __balloon_append(struct page *page) |
123 | { | 124 | { |
124 | /* Lowmem is re-populated first, so highmem pages go at list tail. */ | 125 | /* Lowmem is re-populated first, so highmem pages go at list tail. */ |
125 | if (PageHighMem(page)) { | 126 | if (PageHighMem(page)) { |
@@ -130,7 +131,11 @@ static void balloon_append(struct page *page) | |||
130 | list_add(&page->lru, &ballooned_pages); | 131 | list_add(&page->lru, &ballooned_pages); |
131 | balloon_stats.balloon_low++; | 132 | balloon_stats.balloon_low++; |
132 | } | 133 | } |
134 | } | ||
133 | 135 | ||
136 | static void balloon_append(struct page *page) | ||
137 | { | ||
138 | __balloon_append(page); | ||
134 | totalram_pages--; | 139 | totalram_pages--; |
135 | } | 140 | } |
136 | 141 | ||
@@ -191,7 +196,7 @@ static unsigned long current_target(void) | |||
191 | 196 | ||
192 | static int increase_reservation(unsigned long nr_pages) | 197 | static int increase_reservation(unsigned long nr_pages) |
193 | { | 198 | { |
194 | unsigned long pfn, i, flags; | 199 | unsigned long pfn, i; |
195 | struct page *page; | 200 | struct page *page; |
196 | long rc; | 201 | long rc; |
197 | struct xen_memory_reservation reservation = { | 202 | struct xen_memory_reservation reservation = { |
@@ -203,8 +208,6 @@ static int increase_reservation(unsigned long nr_pages) | |||
203 | if (nr_pages > ARRAY_SIZE(frame_list)) | 208 | if (nr_pages > ARRAY_SIZE(frame_list)) |
204 | nr_pages = ARRAY_SIZE(frame_list); | 209 | nr_pages = ARRAY_SIZE(frame_list); |
205 | 210 | ||
206 | spin_lock_irqsave(&xen_reservation_lock, flags); | ||
207 | |||
208 | page = balloon_first_page(); | 211 | page = balloon_first_page(); |
209 | for (i = 0; i < nr_pages; i++) { | 212 | for (i = 0; i < nr_pages; i++) { |
210 | BUG_ON(page == NULL); | 213 | BUG_ON(page == NULL); |
@@ -247,14 +250,12 @@ static int increase_reservation(unsigned long nr_pages) | |||
247 | balloon_stats.current_pages += rc; | 250 | balloon_stats.current_pages += rc; |
248 | 251 | ||
249 | out: | 252 | out: |
250 | spin_unlock_irqrestore(&xen_reservation_lock, flags); | ||
251 | |||
252 | return rc < 0 ? rc : rc != nr_pages; | 253 | return rc < 0 ? rc : rc != nr_pages; |
253 | } | 254 | } |
254 | 255 | ||
255 | static int decrease_reservation(unsigned long nr_pages) | 256 | static int decrease_reservation(unsigned long nr_pages) |
256 | { | 257 | { |
257 | unsigned long pfn, i, flags; | 258 | unsigned long pfn, i; |
258 | struct page *page; | 259 | struct page *page; |
259 | int need_sleep = 0; | 260 | int need_sleep = 0; |
260 | int ret; | 261 | int ret; |
@@ -292,8 +293,6 @@ static int decrease_reservation(unsigned long nr_pages) | |||
292 | kmap_flush_unused(); | 293 | kmap_flush_unused(); |
293 | flush_tlb_all(); | 294 | flush_tlb_all(); |
294 | 295 | ||
295 | spin_lock_irqsave(&xen_reservation_lock, flags); | ||
296 | |||
297 | /* No more mappings: invalidate P2M and add to balloon. */ | 296 | /* No more mappings: invalidate P2M and add to balloon. */ |
298 | for (i = 0; i < nr_pages; i++) { | 297 | for (i = 0; i < nr_pages; i++) { |
299 | pfn = mfn_to_pfn(frame_list[i]); | 298 | pfn = mfn_to_pfn(frame_list[i]); |
@@ -308,8 +307,6 @@ static int decrease_reservation(unsigned long nr_pages) | |||
308 | 307 | ||
309 | balloon_stats.current_pages -= nr_pages; | 308 | balloon_stats.current_pages -= nr_pages; |
310 | 309 | ||
311 | spin_unlock_irqrestore(&xen_reservation_lock, flags); | ||
312 | |||
313 | return need_sleep; | 310 | return need_sleep; |
314 | } | 311 | } |
315 | 312 | ||
@@ -395,7 +392,7 @@ static struct notifier_block xenstore_notifier; | |||
395 | 392 | ||
396 | static int __init balloon_init(void) | 393 | static int __init balloon_init(void) |
397 | { | 394 | { |
398 | unsigned long pfn; | 395 | unsigned long pfn, extra_pfn_end; |
399 | struct page *page; | 396 | struct page *page; |
400 | 397 | ||
401 | if (!xen_pv_domain()) | 398 | if (!xen_pv_domain()) |
@@ -415,11 +412,24 @@ static int __init balloon_init(void) | |||
415 | 412 | ||
416 | register_balloon(&balloon_sysdev); | 413 | register_balloon(&balloon_sysdev); |
417 | 414 | ||
418 | /* Initialise the balloon with excess memory space. */ | 415 | /* |
419 | for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) { | 416 | * Initialise the balloon with excess memory space. We need |
417 | * to make sure we don't add memory which doesn't exist or | ||
418 | * logically exist. The E820 map can be trimmed to be smaller | ||
419 | * than the amount of physical memory due to the mem= command | ||
420 | * line parameter. And if this is a 32-bit non-HIGHMEM kernel | ||
421 | * on a system with memory which requires highmem to access, | ||
422 | * don't try to use it. | ||
423 | */ | ||
424 | extra_pfn_end = min(min(max_pfn, e820_end_of_ram_pfn()), | ||
425 | (unsigned long)PFN_DOWN(xen_extra_mem_start + xen_extra_mem_size)); | ||
426 | for (pfn = PFN_UP(xen_extra_mem_start); | ||
427 | pfn < extra_pfn_end; | ||
428 | pfn++) { | ||
420 | page = pfn_to_page(pfn); | 429 | page = pfn_to_page(pfn); |
421 | if (!PageReserved(page)) | 430 | /* totalram_pages doesn't include the boot-time |
422 | balloon_append(page); | 431 | balloon extension, so don't subtract from it. */ |
432 | __balloon_append(page); | ||
423 | } | 433 | } |
424 | 434 | ||
425 | target_watch.callback = watch_target; | 435 | target_watch.callback = watch_target; |
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 97612f548a8e..31af0ac31a98 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c | |||
@@ -105,7 +105,6 @@ struct irq_info | |||
105 | 105 | ||
106 | static struct irq_info *irq_info; | 106 | static struct irq_info *irq_info; |
107 | static int *pirq_to_irq; | 107 | static int *pirq_to_irq; |
108 | static int nr_pirqs; | ||
109 | 108 | ||
110 | static int *evtchn_to_irq; | 109 | static int *evtchn_to_irq; |
111 | struct cpu_evtchn_s { | 110 | struct cpu_evtchn_s { |
@@ -278,17 +277,17 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu) | |||
278 | cpumask_copy(irq_to_desc(irq)->affinity, cpumask_of(cpu)); | 277 | cpumask_copy(irq_to_desc(irq)->affinity, cpumask_of(cpu)); |
279 | #endif | 278 | #endif |
280 | 279 | ||
281 | __clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq))); | 280 | clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq))); |
282 | __set_bit(chn, cpu_evtchn_mask(cpu)); | 281 | set_bit(chn, cpu_evtchn_mask(cpu)); |
283 | 282 | ||
284 | irq_info[irq].cpu = cpu; | 283 | irq_info[irq].cpu = cpu; |
285 | } | 284 | } |
286 | 285 | ||
287 | static void init_evtchn_cpu_bindings(void) | 286 | static void init_evtchn_cpu_bindings(void) |
288 | { | 287 | { |
288 | int i; | ||
289 | #ifdef CONFIG_SMP | 289 | #ifdef CONFIG_SMP |
290 | struct irq_desc *desc; | 290 | struct irq_desc *desc; |
291 | int i; | ||
292 | 291 | ||
293 | /* By default all event channels notify CPU#0. */ | 292 | /* By default all event channels notify CPU#0. */ |
294 | for_each_irq_desc(i, desc) { | 293 | for_each_irq_desc(i, desc) { |
@@ -296,7 +295,10 @@ static void init_evtchn_cpu_bindings(void) | |||
296 | } | 295 | } |
297 | #endif | 296 | #endif |
298 | 297 | ||
299 | memset(cpu_evtchn_mask(0), ~0, sizeof(struct cpu_evtchn_s)); | 298 | for_each_possible_cpu(i) |
299 | memset(cpu_evtchn_mask(i), | ||
300 | (i == 0) ? ~0 : 0, sizeof(struct cpu_evtchn_s)); | ||
301 | |||
300 | } | 302 | } |
301 | 303 | ||
302 | static inline void clear_evtchn(int port) | 304 | static inline void clear_evtchn(int port) |
@@ -382,12 +384,17 @@ static int get_nr_hw_irqs(void) | |||
382 | return ret; | 384 | return ret; |
383 | } | 385 | } |
384 | 386 | ||
385 | /* callers of this function should make sure that PHYSDEVOP_get_nr_pirqs | 387 | static int find_unbound_pirq(int type) |
386 | * succeeded otherwise nr_pirqs won't hold the right value */ | ||
387 | static int find_unbound_pirq(void) | ||
388 | { | 388 | { |
389 | int i; | 389 | int rc, i; |
390 | for (i = nr_pirqs-1; i >= 0; i--) { | 390 | struct physdev_get_free_pirq op_get_free_pirq; |
391 | op_get_free_pirq.type = type; | ||
392 | |||
393 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_free_pirq, &op_get_free_pirq); | ||
394 | if (!rc) | ||
395 | return op_get_free_pirq.pirq; | ||
396 | |||
397 | for (i = 0; i < nr_irqs; i++) { | ||
391 | if (pirq_to_irq[i] < 0) | 398 | if (pirq_to_irq[i] < 0) |
392 | return i; | 399 | return i; |
393 | } | 400 | } |
@@ -420,7 +427,7 @@ static int find_unbound_irq(void) | |||
420 | if (irq == start) | 427 | if (irq == start) |
421 | goto no_irqs; | 428 | goto no_irqs; |
422 | 429 | ||
423 | res = irq_alloc_desc_at(irq, 0); | 430 | res = irq_alloc_desc_at(irq, -1); |
424 | 431 | ||
425 | if (WARN_ON(res != irq)) | 432 | if (WARN_ON(res != irq)) |
426 | return -1; | 433 | return -1; |
@@ -608,10 +615,10 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name) | |||
608 | 615 | ||
609 | spin_lock(&irq_mapping_update_lock); | 616 | spin_lock(&irq_mapping_update_lock); |
610 | 617 | ||
611 | if ((pirq > nr_pirqs) || (gsi > nr_irqs)) { | 618 | if ((pirq > nr_irqs) || (gsi > nr_irqs)) { |
612 | printk(KERN_WARNING "xen_map_pirq_gsi: %s %s is incorrect!\n", | 619 | printk(KERN_WARNING "xen_map_pirq_gsi: %s %s is incorrect!\n", |
613 | pirq > nr_pirqs ? "nr_pirqs" :"", | 620 | pirq > nr_irqs ? "pirq" :"", |
614 | gsi > nr_irqs ? "nr_irqs" : ""); | 621 | gsi > nr_irqs ? "gsi" : ""); |
615 | goto out; | 622 | goto out; |
616 | } | 623 | } |
617 | 624 | ||
@@ -627,7 +634,7 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name) | |||
627 | if (identity_mapped_irq(gsi) || (!xen_initial_domain() && | 634 | if (identity_mapped_irq(gsi) || (!xen_initial_domain() && |
628 | xen_pv_domain())) { | 635 | xen_pv_domain())) { |
629 | irq = gsi; | 636 | irq = gsi; |
630 | irq_alloc_desc_at(irq, 0); | 637 | irq_alloc_desc_at(irq, -1); |
631 | } else | 638 | } else |
632 | irq = find_unbound_irq(); | 639 | irq = find_unbound_irq(); |
633 | 640 | ||
@@ -661,17 +668,21 @@ out: | |||
661 | #include <linux/msi.h> | 668 | #include <linux/msi.h> |
662 | #include "../pci/msi.h" | 669 | #include "../pci/msi.h" |
663 | 670 | ||
664 | void xen_allocate_pirq_msi(char *name, int *irq, int *pirq) | 671 | void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc) |
665 | { | 672 | { |
666 | spin_lock(&irq_mapping_update_lock); | 673 | spin_lock(&irq_mapping_update_lock); |
667 | 674 | ||
668 | *irq = find_unbound_irq(); | 675 | if (alloc & XEN_ALLOC_IRQ) { |
669 | if (*irq == -1) | 676 | *irq = find_unbound_irq(); |
670 | goto out; | 677 | if (*irq == -1) |
678 | goto out; | ||
679 | } | ||
671 | 680 | ||
672 | *pirq = find_unbound_pirq(); | 681 | if (alloc & XEN_ALLOC_PIRQ) { |
673 | if (*pirq == -1) | 682 | *pirq = find_unbound_pirq(MAP_PIRQ_TYPE_MSI); |
674 | goto out; | 683 | if (*pirq == -1) |
684 | goto out; | ||
685 | } | ||
675 | 686 | ||
676 | set_irq_chip_and_handler_name(*irq, &xen_pirq_chip, | 687 | set_irq_chip_and_handler_name(*irq, &xen_pirq_chip, |
677 | handle_level_irq, name); | 688 | handle_level_irq, name); |
@@ -752,13 +763,14 @@ int xen_destroy_irq(int irq) | |||
752 | goto out; | 763 | goto out; |
753 | 764 | ||
754 | if (xen_initial_domain()) { | 765 | if (xen_initial_domain()) { |
755 | unmap_irq.pirq = info->u.pirq.gsi; | 766 | unmap_irq.pirq = info->u.pirq.pirq; |
756 | unmap_irq.domid = DOMID_SELF; | 767 | unmap_irq.domid = DOMID_SELF; |
757 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq); | 768 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq); |
758 | if (rc) { | 769 | if (rc) { |
759 | printk(KERN_WARNING "unmap irq failed %d\n", rc); | 770 | printk(KERN_WARNING "unmap irq failed %d\n", rc); |
760 | goto out; | 771 | goto out; |
761 | } | 772 | } |
773 | pirq_to_irq[info->u.pirq.pirq] = -1; | ||
762 | } | 774 | } |
763 | irq_info[irq] = mk_unbound_info(); | 775 | irq_info[irq] = mk_unbound_info(); |
764 | 776 | ||
@@ -779,6 +791,11 @@ int xen_gsi_from_irq(unsigned irq) | |||
779 | return gsi_from_irq(irq); | 791 | return gsi_from_irq(irq); |
780 | } | 792 | } |
781 | 793 | ||
794 | int xen_irq_from_pirq(unsigned pirq) | ||
795 | { | ||
796 | return pirq_to_irq[pirq]; | ||
797 | } | ||
798 | |||
782 | int bind_evtchn_to_irq(unsigned int evtchn) | 799 | int bind_evtchn_to_irq(unsigned int evtchn) |
783 | { | 800 | { |
784 | int irq; | 801 | int irq; |
@@ -1276,6 +1293,42 @@ static int retrigger_dynirq(unsigned int irq) | |||
1276 | return ret; | 1293 | return ret; |
1277 | } | 1294 | } |
1278 | 1295 | ||
1296 | static void restore_cpu_pirqs(void) | ||
1297 | { | ||
1298 | int pirq, rc, irq, gsi; | ||
1299 | struct physdev_map_pirq map_irq; | ||
1300 | |||
1301 | for (pirq = 0; pirq < nr_irqs; pirq++) { | ||
1302 | irq = pirq_to_irq[pirq]; | ||
1303 | if (irq == -1) | ||
1304 | continue; | ||
1305 | |||
1306 | /* save/restore of PT devices doesn't work, so at this point the | ||
1307 | * only devices present are GSI based emulated devices */ | ||
1308 | gsi = gsi_from_irq(irq); | ||
1309 | if (!gsi) | ||
1310 | continue; | ||
1311 | |||
1312 | map_irq.domid = DOMID_SELF; | ||
1313 | map_irq.type = MAP_PIRQ_TYPE_GSI; | ||
1314 | map_irq.index = gsi; | ||
1315 | map_irq.pirq = pirq; | ||
1316 | |||
1317 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq); | ||
1318 | if (rc) { | ||
1319 | printk(KERN_WARNING "xen map irq failed gsi=%d irq=%d pirq=%d rc=%d\n", | ||
1320 | gsi, irq, pirq, rc); | ||
1321 | irq_info[irq] = mk_unbound_info(); | ||
1322 | pirq_to_irq[pirq] = -1; | ||
1323 | continue; | ||
1324 | } | ||
1325 | |||
1326 | printk(KERN_DEBUG "xen: --> irq=%d, pirq=%d\n", irq, map_irq.pirq); | ||
1327 | |||
1328 | startup_pirq(irq); | ||
1329 | } | ||
1330 | } | ||
1331 | |||
1279 | static void restore_cpu_virqs(unsigned int cpu) | 1332 | static void restore_cpu_virqs(unsigned int cpu) |
1280 | { | 1333 | { |
1281 | struct evtchn_bind_virq bind_virq; | 1334 | struct evtchn_bind_virq bind_virq; |
@@ -1299,9 +1352,6 @@ static void restore_cpu_virqs(unsigned int cpu) | |||
1299 | evtchn_to_irq[evtchn] = irq; | 1352 | evtchn_to_irq[evtchn] = irq; |
1300 | irq_info[irq] = mk_virq_info(evtchn, virq); | 1353 | irq_info[irq] = mk_virq_info(evtchn, virq); |
1301 | bind_evtchn_to_cpu(evtchn, cpu); | 1354 | bind_evtchn_to_cpu(evtchn, cpu); |
1302 | |||
1303 | /* Ready for use. */ | ||
1304 | unmask_evtchn(evtchn); | ||
1305 | } | 1355 | } |
1306 | } | 1356 | } |
1307 | 1357 | ||
@@ -1327,10 +1377,6 @@ static void restore_cpu_ipis(unsigned int cpu) | |||
1327 | evtchn_to_irq[evtchn] = irq; | 1377 | evtchn_to_irq[evtchn] = irq; |
1328 | irq_info[irq] = mk_ipi_info(evtchn, ipi); | 1378 | irq_info[irq] = mk_ipi_info(evtchn, ipi); |
1329 | bind_evtchn_to_cpu(evtchn, cpu); | 1379 | bind_evtchn_to_cpu(evtchn, cpu); |
1330 | |||
1331 | /* Ready for use. */ | ||
1332 | unmask_evtchn(evtchn); | ||
1333 | |||
1334 | } | 1380 | } |
1335 | } | 1381 | } |
1336 | 1382 | ||
@@ -1390,6 +1436,7 @@ void xen_poll_irq(int irq) | |||
1390 | void xen_irq_resume(void) | 1436 | void xen_irq_resume(void) |
1391 | { | 1437 | { |
1392 | unsigned int cpu, irq, evtchn; | 1438 | unsigned int cpu, irq, evtchn; |
1439 | struct irq_desc *desc; | ||
1393 | 1440 | ||
1394 | init_evtchn_cpu_bindings(); | 1441 | init_evtchn_cpu_bindings(); |
1395 | 1442 | ||
@@ -1408,6 +1455,25 @@ void xen_irq_resume(void) | |||
1408 | restore_cpu_virqs(cpu); | 1455 | restore_cpu_virqs(cpu); |
1409 | restore_cpu_ipis(cpu); | 1456 | restore_cpu_ipis(cpu); |
1410 | } | 1457 | } |
1458 | |||
1459 | /* | ||
1460 | * Unmask any IRQF_NO_SUSPEND IRQs which are enabled. These | ||
1461 | * are not handled by the IRQ core. | ||
1462 | */ | ||
1463 | for_each_irq_desc(irq, desc) { | ||
1464 | if (!desc->action || !(desc->action->flags & IRQF_NO_SUSPEND)) | ||
1465 | continue; | ||
1466 | if (desc->status & IRQ_DISABLED) | ||
1467 | continue; | ||
1468 | |||
1469 | evtchn = evtchn_from_irq(irq); | ||
1470 | if (evtchn == -1) | ||
1471 | continue; | ||
1472 | |||
1473 | unmask_evtchn(evtchn); | ||
1474 | } | ||
1475 | |||
1476 | restore_cpu_pirqs(); | ||
1411 | } | 1477 | } |
1412 | 1478 | ||
1413 | static struct irq_chip xen_dynamic_chip __read_mostly = { | 1479 | static struct irq_chip xen_dynamic_chip __read_mostly = { |
@@ -1492,26 +1558,17 @@ void xen_callback_vector(void) {} | |||
1492 | 1558 | ||
1493 | void __init xen_init_IRQ(void) | 1559 | void __init xen_init_IRQ(void) |
1494 | { | 1560 | { |
1495 | int i, rc; | 1561 | int i; |
1496 | struct physdev_nr_pirqs op_nr_pirqs; | ||
1497 | 1562 | ||
1498 | cpu_evtchn_mask_p = kcalloc(nr_cpu_ids, sizeof(struct cpu_evtchn_s), | 1563 | cpu_evtchn_mask_p = kcalloc(nr_cpu_ids, sizeof(struct cpu_evtchn_s), |
1499 | GFP_KERNEL); | 1564 | GFP_KERNEL); |
1500 | irq_info = kcalloc(nr_irqs, sizeof(*irq_info), GFP_KERNEL); | 1565 | irq_info = kcalloc(nr_irqs, sizeof(*irq_info), GFP_KERNEL); |
1501 | 1566 | ||
1502 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_nr_pirqs, &op_nr_pirqs); | 1567 | /* We are using nr_irqs as the maximum number of pirq available but |
1503 | if (rc < 0) { | 1568 | * that number is actually chosen by Xen and we don't know exactly |
1504 | nr_pirqs = nr_irqs; | 1569 | * what it is. Be careful choosing high pirq numbers. */ |
1505 | if (rc != -ENOSYS) | 1570 | pirq_to_irq = kcalloc(nr_irqs, sizeof(*pirq_to_irq), GFP_KERNEL); |
1506 | printk(KERN_WARNING "PHYSDEVOP_get_nr_pirqs returned rc=%d\n", rc); | 1571 | for (i = 0; i < nr_irqs; i++) |
1507 | } else { | ||
1508 | if (xen_pv_domain() && !xen_initial_domain()) | ||
1509 | nr_pirqs = max((int)op_nr_pirqs.nr_pirqs, nr_irqs); | ||
1510 | else | ||
1511 | nr_pirqs = op_nr_pirqs.nr_pirqs; | ||
1512 | } | ||
1513 | pirq_to_irq = kcalloc(nr_pirqs, sizeof(*pirq_to_irq), GFP_KERNEL); | ||
1514 | for (i = 0; i < nr_pirqs; i++) | ||
1515 | pirq_to_irq[i] = -1; | 1572 | pirq_to_irq[i] = -1; |
1516 | 1573 | ||
1517 | evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq), | 1574 | evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq), |
diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c index fec6ba3c08a8..ef11daf0cafe 100644 --- a/drivers/xen/evtchn.c +++ b/drivers/xen/evtchn.c | |||
@@ -69,20 +69,51 @@ struct per_user_data { | |||
69 | const char *name; | 69 | const char *name; |
70 | }; | 70 | }; |
71 | 71 | ||
72 | /* Who's bound to each port? */ | 72 | /* |
73 | static struct per_user_data *port_user[NR_EVENT_CHANNELS]; | 73 | * Who's bound to each port? This is logically an array of struct |
74 | * per_user_data *, but we encode the current enabled-state in bit 0. | ||
75 | */ | ||
76 | static unsigned long *port_user; | ||
74 | static DEFINE_SPINLOCK(port_user_lock); /* protects port_user[] and ring_prod */ | 77 | static DEFINE_SPINLOCK(port_user_lock); /* protects port_user[] and ring_prod */ |
75 | 78 | ||
76 | irqreturn_t evtchn_interrupt(int irq, void *data) | 79 | static inline struct per_user_data *get_port_user(unsigned port) |
80 | { | ||
81 | return (struct per_user_data *)(port_user[port] & ~1); | ||
82 | } | ||
83 | |||
84 | static inline void set_port_user(unsigned port, struct per_user_data *u) | ||
85 | { | ||
86 | port_user[port] = (unsigned long)u; | ||
87 | } | ||
88 | |||
89 | static inline bool get_port_enabled(unsigned port) | ||
90 | { | ||
91 | return port_user[port] & 1; | ||
92 | } | ||
93 | |||
94 | static inline void set_port_enabled(unsigned port, bool enabled) | ||
95 | { | ||
96 | if (enabled) | ||
97 | port_user[port] |= 1; | ||
98 | else | ||
99 | port_user[port] &= ~1; | ||
100 | } | ||
101 | |||
102 | static irqreturn_t evtchn_interrupt(int irq, void *data) | ||
77 | { | 103 | { |
78 | unsigned int port = (unsigned long)data; | 104 | unsigned int port = (unsigned long)data; |
79 | struct per_user_data *u; | 105 | struct per_user_data *u; |
80 | 106 | ||
81 | spin_lock(&port_user_lock); | 107 | spin_lock(&port_user_lock); |
82 | 108 | ||
83 | u = port_user[port]; | 109 | u = get_port_user(port); |
110 | |||
111 | WARN(!get_port_enabled(port), | ||
112 | "Interrupt for port %d, but apparently not enabled; per-user %p\n", | ||
113 | port, u); | ||
84 | 114 | ||
85 | disable_irq_nosync(irq); | 115 | disable_irq_nosync(irq); |
116 | set_port_enabled(port, false); | ||
86 | 117 | ||
87 | if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) { | 118 | if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) { |
88 | u->ring[EVTCHN_RING_MASK(u->ring_prod)] = port; | 119 | u->ring[EVTCHN_RING_MASK(u->ring_prod)] = port; |
@@ -92,9 +123,8 @@ irqreturn_t evtchn_interrupt(int irq, void *data) | |||
92 | kill_fasync(&u->evtchn_async_queue, | 123 | kill_fasync(&u->evtchn_async_queue, |
93 | SIGIO, POLL_IN); | 124 | SIGIO, POLL_IN); |
94 | } | 125 | } |
95 | } else { | 126 | } else |
96 | u->ring_overflow = 1; | 127 | u->ring_overflow = 1; |
97 | } | ||
98 | 128 | ||
99 | spin_unlock(&port_user_lock); | 129 | spin_unlock(&port_user_lock); |
100 | 130 | ||
@@ -198,9 +228,18 @@ static ssize_t evtchn_write(struct file *file, const char __user *buf, | |||
198 | goto out; | 228 | goto out; |
199 | 229 | ||
200 | spin_lock_irq(&port_user_lock); | 230 | spin_lock_irq(&port_user_lock); |
201 | for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) | 231 | |
202 | if ((kbuf[i] < NR_EVENT_CHANNELS) && (port_user[kbuf[i]] == u)) | 232 | for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) { |
203 | enable_irq(irq_from_evtchn(kbuf[i])); | 233 | unsigned port = kbuf[i]; |
234 | |||
235 | if (port < NR_EVENT_CHANNELS && | ||
236 | get_port_user(port) == u && | ||
237 | !get_port_enabled(port)) { | ||
238 | set_port_enabled(port, true); | ||
239 | enable_irq(irq_from_evtchn(port)); | ||
240 | } | ||
241 | } | ||
242 | |||
204 | spin_unlock_irq(&port_user_lock); | 243 | spin_unlock_irq(&port_user_lock); |
205 | 244 | ||
206 | rc = count; | 245 | rc = count; |
@@ -222,8 +261,9 @@ static int evtchn_bind_to_user(struct per_user_data *u, int port) | |||
222 | * interrupt handler yet, and our caller has already | 261 | * interrupt handler yet, and our caller has already |
223 | * serialized bind operations.) | 262 | * serialized bind operations.) |
224 | */ | 263 | */ |
225 | BUG_ON(port_user[port] != NULL); | 264 | BUG_ON(get_port_user(port) != NULL); |
226 | port_user[port] = u; | 265 | set_port_user(port, u); |
266 | set_port_enabled(port, true); /* start enabled */ | ||
227 | 267 | ||
228 | rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED, | 268 | rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED, |
229 | u->name, (void *)(unsigned long)port); | 269 | u->name, (void *)(unsigned long)port); |
@@ -239,10 +279,7 @@ static void evtchn_unbind_from_user(struct per_user_data *u, int port) | |||
239 | 279 | ||
240 | unbind_from_irqhandler(irq, (void *)(unsigned long)port); | 280 | unbind_from_irqhandler(irq, (void *)(unsigned long)port); |
241 | 281 | ||
242 | /* make sure we unbind the irq handler before clearing the port */ | 282 | set_port_user(port, NULL); |
243 | barrier(); | ||
244 | |||
245 | port_user[port] = NULL; | ||
246 | } | 283 | } |
247 | 284 | ||
248 | static long evtchn_ioctl(struct file *file, | 285 | static long evtchn_ioctl(struct file *file, |
@@ -333,15 +370,17 @@ static long evtchn_ioctl(struct file *file, | |||
333 | spin_lock_irq(&port_user_lock); | 370 | spin_lock_irq(&port_user_lock); |
334 | 371 | ||
335 | rc = -ENOTCONN; | 372 | rc = -ENOTCONN; |
336 | if (port_user[unbind.port] != u) { | 373 | if (get_port_user(unbind.port) != u) { |
337 | spin_unlock_irq(&port_user_lock); | 374 | spin_unlock_irq(&port_user_lock); |
338 | break; | 375 | break; |
339 | } | 376 | } |
340 | 377 | ||
341 | evtchn_unbind_from_user(u, unbind.port); | 378 | disable_irq(irq_from_evtchn(unbind.port)); |
342 | 379 | ||
343 | spin_unlock_irq(&port_user_lock); | 380 | spin_unlock_irq(&port_user_lock); |
344 | 381 | ||
382 | evtchn_unbind_from_user(u, unbind.port); | ||
383 | |||
345 | rc = 0; | 384 | rc = 0; |
346 | break; | 385 | break; |
347 | } | 386 | } |
@@ -355,7 +394,7 @@ static long evtchn_ioctl(struct file *file, | |||
355 | 394 | ||
356 | if (notify.port >= NR_EVENT_CHANNELS) { | 395 | if (notify.port >= NR_EVENT_CHANNELS) { |
357 | rc = -EINVAL; | 396 | rc = -EINVAL; |
358 | } else if (port_user[notify.port] != u) { | 397 | } else if (get_port_user(notify.port) != u) { |
359 | rc = -ENOTCONN; | 398 | rc = -ENOTCONN; |
360 | } else { | 399 | } else { |
361 | notify_remote_via_evtchn(notify.port); | 400 | notify_remote_via_evtchn(notify.port); |
@@ -431,7 +470,7 @@ static int evtchn_open(struct inode *inode, struct file *filp) | |||
431 | 470 | ||
432 | filp->private_data = u; | 471 | filp->private_data = u; |
433 | 472 | ||
434 | return 0; | 473 | return nonseekable_open(inode, filp);; |
435 | } | 474 | } |
436 | 475 | ||
437 | static int evtchn_release(struct inode *inode, struct file *filp) | 476 | static int evtchn_release(struct inode *inode, struct file *filp) |
@@ -444,14 +483,21 @@ static int evtchn_release(struct inode *inode, struct file *filp) | |||
444 | free_page((unsigned long)u->ring); | 483 | free_page((unsigned long)u->ring); |
445 | 484 | ||
446 | for (i = 0; i < NR_EVENT_CHANNELS; i++) { | 485 | for (i = 0; i < NR_EVENT_CHANNELS; i++) { |
447 | if (port_user[i] != u) | 486 | if (get_port_user(i) != u) |
448 | continue; | 487 | continue; |
449 | 488 | ||
450 | evtchn_unbind_from_user(port_user[i], i); | 489 | disable_irq(irq_from_evtchn(i)); |
451 | } | 490 | } |
452 | 491 | ||
453 | spin_unlock_irq(&port_user_lock); | 492 | spin_unlock_irq(&port_user_lock); |
454 | 493 | ||
494 | for (i = 0; i < NR_EVENT_CHANNELS; i++) { | ||
495 | if (get_port_user(i) != u) | ||
496 | continue; | ||
497 | |||
498 | evtchn_unbind_from_user(get_port_user(i), i); | ||
499 | } | ||
500 | |||
455 | kfree(u->name); | 501 | kfree(u->name); |
456 | kfree(u); | 502 | kfree(u); |
457 | 503 | ||
@@ -467,12 +513,12 @@ static const struct file_operations evtchn_fops = { | |||
467 | .fasync = evtchn_fasync, | 513 | .fasync = evtchn_fasync, |
468 | .open = evtchn_open, | 514 | .open = evtchn_open, |
469 | .release = evtchn_release, | 515 | .release = evtchn_release, |
470 | .llseek = noop_llseek, | 516 | .llseek = no_llseek, |
471 | }; | 517 | }; |
472 | 518 | ||
473 | static struct miscdevice evtchn_miscdev = { | 519 | static struct miscdevice evtchn_miscdev = { |
474 | .minor = MISC_DYNAMIC_MINOR, | 520 | .minor = MISC_DYNAMIC_MINOR, |
475 | .name = "evtchn", | 521 | .name = "xen/evtchn", |
476 | .fops = &evtchn_fops, | 522 | .fops = &evtchn_fops, |
477 | }; | 523 | }; |
478 | static int __init evtchn_init(void) | 524 | static int __init evtchn_init(void) |
@@ -482,8 +528,11 @@ static int __init evtchn_init(void) | |||
482 | if (!xen_domain()) | 528 | if (!xen_domain()) |
483 | return -ENODEV; | 529 | return -ENODEV; |
484 | 530 | ||
531 | port_user = kcalloc(NR_EVENT_CHANNELS, sizeof(*port_user), GFP_KERNEL); | ||
532 | if (port_user == NULL) | ||
533 | return -ENOMEM; | ||
534 | |||
485 | spin_lock_init(&port_user_lock); | 535 | spin_lock_init(&port_user_lock); |
486 | memset(port_user, 0, sizeof(port_user)); | ||
487 | 536 | ||
488 | /* Create '/dev/misc/evtchn'. */ | 537 | /* Create '/dev/misc/evtchn'. */ |
489 | err = misc_register(&evtchn_miscdev); | 538 | err = misc_register(&evtchn_miscdev); |
@@ -499,6 +548,9 @@ static int __init evtchn_init(void) | |||
499 | 548 | ||
500 | static void __exit evtchn_cleanup(void) | 549 | static void __exit evtchn_cleanup(void) |
501 | { | 550 | { |
551 | kfree(port_user); | ||
552 | port_user = NULL; | ||
553 | |||
502 | misc_deregister(&evtchn_miscdev); | 554 | misc_deregister(&evtchn_miscdev); |
503 | } | 555 | } |
504 | 556 | ||
diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index ef9c7db52077..db8c4c4ac880 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c | |||
@@ -49,6 +49,7 @@ static int xen_hvm_suspend(void *data) | |||
49 | 49 | ||
50 | if (!*cancelled) { | 50 | if (!*cancelled) { |
51 | xen_irq_resume(); | 51 | xen_irq_resume(); |
52 | xen_console_resume(); | ||
52 | xen_timer_resume(); | 53 | xen_timer_resume(); |
53 | } | 54 | } |
54 | 55 | ||
diff --git a/drivers/xen/xenfs/privcmd.c b/drivers/xen/xenfs/privcmd.c index f80be7f6eb95..dbd3b16fd131 100644 --- a/drivers/xen/xenfs/privcmd.c +++ b/drivers/xen/xenfs/privcmd.c | |||
@@ -15,7 +15,6 @@ | |||
15 | #include <linux/mman.h> | 15 | #include <linux/mman.h> |
16 | #include <linux/uaccess.h> | 16 | #include <linux/uaccess.h> |
17 | #include <linux/swap.h> | 17 | #include <linux/swap.h> |
18 | #include <linux/smp_lock.h> | ||
19 | #include <linux/highmem.h> | 18 | #include <linux/highmem.h> |
20 | #include <linux/pagemap.h> | 19 | #include <linux/pagemap.h> |
21 | #include <linux/seq_file.h> | 20 | #include <linux/seq_file.h> |
@@ -266,9 +265,7 @@ static int mmap_return_errors(void *data, void *state) | |||
266 | xen_pfn_t *mfnp = data; | 265 | xen_pfn_t *mfnp = data; |
267 | struct mmap_batch_state *st = state; | 266 | struct mmap_batch_state *st = state; |
268 | 267 | ||
269 | put_user(*mfnp, st->user++); | 268 | return put_user(*mfnp, st->user++); |
270 | |||
271 | return 0; | ||
272 | } | 269 | } |
273 | 270 | ||
274 | static struct vm_operations_struct privcmd_vm_ops; | 271 | static struct vm_operations_struct privcmd_vm_ops; |
@@ -323,10 +320,8 @@ static long privcmd_ioctl_mmap_batch(void __user *udata) | |||
323 | up_write(&mm->mmap_sem); | 320 | up_write(&mm->mmap_sem); |
324 | 321 | ||
325 | if (state.err > 0) { | 322 | if (state.err > 0) { |
326 | ret = 0; | ||
327 | |||
328 | state.user = m.arr; | 323 | state.user = m.arr; |
329 | traverse_pages(m.num, sizeof(xen_pfn_t), | 324 | ret = traverse_pages(m.num, sizeof(xen_pfn_t), |
330 | &pagelist, | 325 | &pagelist, |
331 | mmap_return_errors, &state); | 326 | mmap_return_errors, &state); |
332 | } | 327 | } |
@@ -384,8 +379,9 @@ static int privcmd_mmap(struct file *file, struct vm_area_struct *vma) | |||
384 | if (xen_feature(XENFEAT_auto_translated_physmap)) | 379 | if (xen_feature(XENFEAT_auto_translated_physmap)) |
385 | return -ENOSYS; | 380 | return -ENOSYS; |
386 | 381 | ||
387 | /* DONTCOPY is essential for Xen as copy_page_range is broken. */ | 382 | /* DONTCOPY is essential for Xen because copy_page_range doesn't know |
388 | vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY; | 383 | * how to recreate these mappings */ |
384 | vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY | VM_PFNMAP; | ||
389 | vma->vm_ops = &privcmd_vm_ops; | 385 | vma->vm_ops = &privcmd_vm_ops; |
390 | vma->vm_private_data = NULL; | 386 | vma->vm_private_data = NULL; |
391 | 387 | ||
diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c index f6339d11d59c..1aa389719846 100644 --- a/drivers/xen/xenfs/super.c +++ b/drivers/xen/xenfs/super.c | |||
@@ -12,8 +12,6 @@ | |||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
14 | #include <linux/magic.h> | 14 | #include <linux/magic.h> |
15 | #include <linux/mm.h> | ||
16 | #include <linux/backing-dev.h> | ||
17 | 15 | ||
18 | #include <xen/xen.h> | 16 | #include <xen/xen.h> |
19 | 17 | ||
@@ -24,28 +22,12 @@ | |||
24 | MODULE_DESCRIPTION("Xen filesystem"); | 22 | MODULE_DESCRIPTION("Xen filesystem"); |
25 | MODULE_LICENSE("GPL"); | 23 | MODULE_LICENSE("GPL"); |
26 | 24 | ||
27 | static int xenfs_set_page_dirty(struct page *page) | ||
28 | { | ||
29 | return !TestSetPageDirty(page); | ||
30 | } | ||
31 | |||
32 | static const struct address_space_operations xenfs_aops = { | ||
33 | .set_page_dirty = xenfs_set_page_dirty, | ||
34 | }; | ||
35 | |||
36 | static struct backing_dev_info xenfs_backing_dev_info = { | ||
37 | .ra_pages = 0, /* No readahead */ | ||
38 | .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, | ||
39 | }; | ||
40 | |||
41 | static struct inode *xenfs_make_inode(struct super_block *sb, int mode) | 25 | static struct inode *xenfs_make_inode(struct super_block *sb, int mode) |
42 | { | 26 | { |
43 | struct inode *ret = new_inode(sb); | 27 | struct inode *ret = new_inode(sb); |
44 | 28 | ||
45 | if (ret) { | 29 | if (ret) { |
46 | ret->i_mode = mode; | 30 | ret->i_mode = mode; |
47 | ret->i_mapping->a_ops = &xenfs_aops; | ||
48 | ret->i_mapping->backing_dev_info = &xenfs_backing_dev_info; | ||
49 | ret->i_uid = ret->i_gid = 0; | 31 | ret->i_uid = ret->i_gid = 0; |
50 | ret->i_blocks = 0; | 32 | ret->i_blocks = 0; |
51 | ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME; | 33 | ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME; |
@@ -121,9 +103,9 @@ static int xenfs_fill_super(struct super_block *sb, void *data, int silent) | |||
121 | return rc; | 103 | return rc; |
122 | } | 104 | } |
123 | 105 | ||
124 | static int xenfs_mount(struct file_system_type *fs_type, | 106 | static struct dentry *xenfs_mount(struct file_system_type *fs_type, |
125 | int flags, const char *dev_name, | 107 | int flags, const char *dev_name, |
126 | void *data) | 108 | void *data) |
127 | { | 109 | { |
128 | return mount_single(fs_type, flags, data, xenfs_fill_super); | 110 | return mount_single(fs_type, flags, data, xenfs_fill_super); |
129 | } | 111 | } |
@@ -137,25 +119,11 @@ static struct file_system_type xenfs_type = { | |||
137 | 119 | ||
138 | static int __init xenfs_init(void) | 120 | static int __init xenfs_init(void) |
139 | { | 121 | { |
140 | int err; | 122 | if (xen_domain()) |
141 | if (!xen_domain()) { | 123 | return register_filesystem(&xenfs_type); |
142 | printk(KERN_INFO "xenfs: not registering filesystem on non-xen platform\n"); | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | err = register_filesystem(&xenfs_type); | ||
147 | if (err) { | ||
148 | printk(KERN_ERR "xenfs: Unable to register filesystem!\n"); | ||
149 | goto out; | ||
150 | } | ||
151 | |||
152 | err = bdi_init(&xenfs_backing_dev_info); | ||
153 | if (err) | ||
154 | unregister_filesystem(&xenfs_type); | ||
155 | |||
156 | out: | ||
157 | 124 | ||
158 | return err; | 125 | printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n"); |
126 | return 0; | ||
159 | } | 127 | } |
160 | 128 | ||
161 | static void __exit xenfs_exit(void) | 129 | static void __exit xenfs_exit(void) |