diff options
| -rw-r--r-- | arch/x86/pci/xen.c | 27 | ||||
| -rw-r--r-- | arch/x86/xen/platform-pci-unplug.c | 2 | ||||
| -rw-r--r-- | arch/x86/xen/suspend.c | 1 | ||||
| -rw-r--r-- | arch/x86/xen/xen-ops.h | 2 | ||||
| -rw-r--r-- | drivers/xen/events.c | 105 | ||||
| -rw-r--r-- | drivers/xen/manage.c | 1 | ||||
| -rw-r--r-- | include/xen/events.h | 7 | ||||
| -rw-r--r-- | include/xen/interface/physdev.h | 10 |
8 files changed, 114 insertions, 41 deletions
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index d7b5109f7a9..25cd4a07d09 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c | |||
| @@ -70,6 +70,9 @@ static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi, | |||
| 70 | struct xen_pci_frontend_ops *xen_pci_frontend; | 70 | struct xen_pci_frontend_ops *xen_pci_frontend; |
| 71 | EXPORT_SYMBOL_GPL(xen_pci_frontend); | 71 | EXPORT_SYMBOL_GPL(xen_pci_frontend); |
| 72 | 72 | ||
| 73 | #define XEN_PIRQ_MSI_DATA (MSI_DATA_TRIGGER_EDGE | \ | ||
| 74 | MSI_DATA_LEVEL_ASSERT | (3 << 8) | MSI_DATA_VECTOR(0)) | ||
| 75 | |||
| 73 | static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int pirq, | 76 | static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int pirq, |
| 74 | struct msi_msg *msg) | 77 | struct msi_msg *msg) |
| 75 | { | 78 | { |
| @@ -83,12 +86,7 @@ static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int pirq, | |||
| 83 | MSI_ADDR_REDIRECTION_CPU | | 86 | MSI_ADDR_REDIRECTION_CPU | |
| 84 | MSI_ADDR_DEST_ID(pirq); | 87 | MSI_ADDR_DEST_ID(pirq); |
| 85 | 88 | ||
| 86 | msg->data = | 89 | msg->data = XEN_PIRQ_MSI_DATA; |
| 87 | MSI_DATA_TRIGGER_EDGE | | ||
| 88 | MSI_DATA_LEVEL_ASSERT | | ||
| 89 | /* delivery mode reserved */ | ||
| 90 | (3 << 8) | | ||
| 91 | MSI_DATA_VECTOR(0); | ||
| 92 | } | 90 | } |
| 93 | 91 | ||
| 94 | static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | 92 | static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) |
| @@ -98,8 +96,23 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | |||
| 98 | struct msi_msg msg; | 96 | struct msi_msg msg; |
| 99 | 97 | ||
| 100 | list_for_each_entry(msidesc, &dev->msi_list, list) { | 98 | list_for_each_entry(msidesc, &dev->msi_list, list) { |
| 99 | __read_msi_msg(msidesc, &msg); | ||
| 100 | pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) | | ||
| 101 | ((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff); | ||
| 102 | if (xen_irq_from_pirq(pirq) >= 0 && msg.data == XEN_PIRQ_MSI_DATA) { | ||
| 103 | xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ? | ||
| 104 | "msi-x" : "msi", &irq, &pirq, XEN_ALLOC_IRQ); | ||
| 105 | if (irq < 0) | ||
| 106 | goto error; | ||
| 107 | ret = set_irq_msi(irq, msidesc); | ||
| 108 | if (ret < 0) | ||
| 109 | goto error_while; | ||
| 110 | printk(KERN_DEBUG "xen: msi already setup: msi --> irq=%d" | ||
| 111 | " pirq=%d\n", irq, pirq); | ||
| 112 | return 0; | ||
| 113 | } | ||
| 101 | xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ? | 114 | xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ? |
| 102 | "msi-x" : "msi", &irq, &pirq); | 115 | "msi-x" : "msi", &irq, &pirq, (XEN_ALLOC_IRQ | XEN_ALLOC_PIRQ)); |
| 103 | if (irq < 0 || pirq < 0) | 116 | if (irq < 0 || pirq < 0) |
| 104 | goto error; | 117 | goto error; |
| 105 | printk(KERN_DEBUG "xen: msi --> irq=%d, pirq=%d\n", irq, pirq); | 118 | printk(KERN_DEBUG "xen: msi --> irq=%d, pirq=%d\n", irq, pirq); |
diff --git a/arch/x86/xen/platform-pci-unplug.c b/arch/x86/xen/platform-pci-unplug.c index 0f456386cce..25c52f94a27 100644 --- a/arch/x86/xen/platform-pci-unplug.c +++ b/arch/x86/xen/platform-pci-unplug.c | |||
| @@ -68,7 +68,7 @@ static int __init check_platform_magic(void) | |||
| 68 | return 0; | 68 | return 0; |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | void __init xen_unplug_emulated_devices(void) | 71 | void xen_unplug_emulated_devices(void) |
| 72 | { | 72 | { |
| 73 | int r; | 73 | int r; |
| 74 | 74 | ||
diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c index 1d789d56877..9bbd63a129b 100644 --- a/arch/x86/xen/suspend.c +++ b/arch/x86/xen/suspend.c | |||
| @@ -31,6 +31,7 @@ void xen_hvm_post_suspend(int suspend_cancelled) | |||
| 31 | int cpu; | 31 | int cpu; |
| 32 | xen_hvm_init_shared_info(); | 32 | xen_hvm_init_shared_info(); |
| 33 | xen_callback_vector(); | 33 | xen_callback_vector(); |
| 34 | xen_unplug_emulated_devices(); | ||
| 34 | if (xen_feature(XENFEAT_hvm_safe_pvclock)) { | 35 | if (xen_feature(XENFEAT_hvm_safe_pvclock)) { |
| 35 | for_each_online_cpu(cpu) { | 36 | for_each_online_cpu(cpu) { |
| 36 | xen_setup_runstate_info(cpu); | 37 | xen_setup_runstate_info(cpu); |
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index 64044747348..9d41bf98575 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h | |||
| @@ -43,7 +43,7 @@ void xen_vcpu_restore(void); | |||
| 43 | 43 | ||
| 44 | void xen_callback_vector(void); | 44 | void xen_callback_vector(void); |
| 45 | void xen_hvm_init_shared_info(void); | 45 | void xen_hvm_init_shared_info(void); |
| 46 | void __init xen_unplug_emulated_devices(void); | 46 | void xen_unplug_emulated_devices(void); |
| 47 | 47 | ||
| 48 | void __init xen_build_dynamic_phys_to_machine(void); | 48 | void __init xen_build_dynamic_phys_to_machine(void); |
| 49 | 49 | ||
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 0009e489272..31af0ac31a9 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 { |
| @@ -385,12 +384,17 @@ static int get_nr_hw_irqs(void) | |||
| 385 | return ret; | 384 | return ret; |
| 386 | } | 385 | } |
| 387 | 386 | ||
| 388 | /* callers of this function should make sure that PHYSDEVOP_get_nr_pirqs | 387 | static int find_unbound_pirq(int type) |
| 389 | * succeeded otherwise nr_pirqs won't hold the right value */ | ||
| 390 | static int find_unbound_pirq(void) | ||
| 391 | { | 388 | { |
| 392 | int i; | 389 | int rc, i; |
| 393 | 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++) { | ||
| 394 | if (pirq_to_irq[i] < 0) | 398 | if (pirq_to_irq[i] < 0) |
| 395 | return i; | 399 | return i; |
| 396 | } | 400 | } |
| @@ -611,10 +615,10 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name) | |||
| 611 | 615 | ||
| 612 | spin_lock(&irq_mapping_update_lock); | 616 | spin_lock(&irq_mapping_update_lock); |
| 613 | 617 | ||
| 614 | if ((pirq > nr_pirqs) || (gsi > nr_irqs)) { | 618 | if ((pirq > nr_irqs) || (gsi > nr_irqs)) { |
| 615 | 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", |
| 616 | pirq > nr_pirqs ? "nr_pirqs" :"", | 620 | pirq > nr_irqs ? "pirq" :"", |
| 617 | gsi > nr_irqs ? "nr_irqs" : ""); | 621 | gsi > nr_irqs ? "gsi" : ""); |
| 618 | goto out; | 622 | goto out; |
| 619 | } | 623 | } |
| 620 | 624 | ||
| @@ -664,17 +668,21 @@ out: | |||
| 664 | #include <linux/msi.h> | 668 | #include <linux/msi.h> |
| 665 | #include "../pci/msi.h" | 669 | #include "../pci/msi.h" |
| 666 | 670 | ||
| 667 | 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) |
| 668 | { | 672 | { |
| 669 | spin_lock(&irq_mapping_update_lock); | 673 | spin_lock(&irq_mapping_update_lock); |
| 670 | 674 | ||
| 671 | *irq = find_unbound_irq(); | 675 | if (alloc & XEN_ALLOC_IRQ) { |
| 672 | if (*irq == -1) | 676 | *irq = find_unbound_irq(); |
| 673 | goto out; | 677 | if (*irq == -1) |
| 678 | goto out; | ||
| 679 | } | ||
| 674 | 680 | ||
| 675 | *pirq = find_unbound_pirq(); | 681 | if (alloc & XEN_ALLOC_PIRQ) { |
| 676 | if (*pirq == -1) | 682 | *pirq = find_unbound_pirq(MAP_PIRQ_TYPE_MSI); |
| 677 | goto out; | 683 | if (*pirq == -1) |
| 684 | goto out; | ||
| 685 | } | ||
| 678 | 686 | ||
| 679 | set_irq_chip_and_handler_name(*irq, &xen_pirq_chip, | 687 | set_irq_chip_and_handler_name(*irq, &xen_pirq_chip, |
| 680 | handle_level_irq, name); | 688 | handle_level_irq, name); |
| @@ -762,6 +770,7 @@ int xen_destroy_irq(int irq) | |||
| 762 | printk(KERN_WARNING "unmap irq failed %d\n", rc); | 770 | printk(KERN_WARNING "unmap irq failed %d\n", rc); |
| 763 | goto out; | 771 | goto out; |
| 764 | } | 772 | } |
| 773 | pirq_to_irq[info->u.pirq.pirq] = -1; | ||
| 765 | } | 774 | } |
| 766 | irq_info[irq] = mk_unbound_info(); | 775 | irq_info[irq] = mk_unbound_info(); |
| 767 | 776 | ||
| @@ -782,6 +791,11 @@ int xen_gsi_from_irq(unsigned irq) | |||
| 782 | return gsi_from_irq(irq); | 791 | return gsi_from_irq(irq); |
| 783 | } | 792 | } |
| 784 | 793 | ||
| 794 | int xen_irq_from_pirq(unsigned pirq) | ||
| 795 | { | ||
| 796 | return pirq_to_irq[pirq]; | ||
| 797 | } | ||
| 798 | |||
| 785 | int bind_evtchn_to_irq(unsigned int evtchn) | 799 | int bind_evtchn_to_irq(unsigned int evtchn) |
| 786 | { | 800 | { |
| 787 | int irq; | 801 | int irq; |
| @@ -1279,6 +1293,42 @@ static int retrigger_dynirq(unsigned int irq) | |||
| 1279 | return ret; | 1293 | return ret; |
| 1280 | } | 1294 | } |
| 1281 | 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 | |||
| 1282 | static void restore_cpu_virqs(unsigned int cpu) | 1332 | static void restore_cpu_virqs(unsigned int cpu) |
| 1283 | { | 1333 | { |
| 1284 | struct evtchn_bind_virq bind_virq; | 1334 | struct evtchn_bind_virq bind_virq; |
| @@ -1422,6 +1472,8 @@ void xen_irq_resume(void) | |||
| 1422 | 1472 | ||
| 1423 | unmask_evtchn(evtchn); | 1473 | unmask_evtchn(evtchn); |
| 1424 | } | 1474 | } |
| 1475 | |||
| 1476 | restore_cpu_pirqs(); | ||
| 1425 | } | 1477 | } |
| 1426 | 1478 | ||
| 1427 | static struct irq_chip xen_dynamic_chip __read_mostly = { | 1479 | static struct irq_chip xen_dynamic_chip __read_mostly = { |
| @@ -1506,26 +1558,17 @@ void xen_callback_vector(void) {} | |||
| 1506 | 1558 | ||
| 1507 | void __init xen_init_IRQ(void) | 1559 | void __init xen_init_IRQ(void) |
| 1508 | { | 1560 | { |
| 1509 | int i, rc; | 1561 | int i; |
| 1510 | struct physdev_nr_pirqs op_nr_pirqs; | ||
| 1511 | 1562 | ||
| 1512 | 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), |
| 1513 | GFP_KERNEL); | 1564 | GFP_KERNEL); |
| 1514 | irq_info = kcalloc(nr_irqs, sizeof(*irq_info), GFP_KERNEL); | 1565 | irq_info = kcalloc(nr_irqs, sizeof(*irq_info), GFP_KERNEL); |
| 1515 | 1566 | ||
| 1516 | 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 |
| 1517 | if (rc < 0) { | 1568 | * that number is actually chosen by Xen and we don't know exactly |
| 1518 | nr_pirqs = nr_irqs; | 1569 | * what it is. Be careful choosing high pirq numbers. */ |
| 1519 | if (rc != -ENOSYS) | 1570 | pirq_to_irq = kcalloc(nr_irqs, sizeof(*pirq_to_irq), GFP_KERNEL); |
| 1520 | printk(KERN_WARNING "PHYSDEVOP_get_nr_pirqs returned rc=%d\n", rc); | 1571 | for (i = 0; i < nr_irqs; i++) |
| 1521 | } else { | ||
| 1522 | if (xen_pv_domain() && !xen_initial_domain()) | ||
| 1523 | nr_pirqs = max((int)op_nr_pirqs.nr_pirqs, nr_irqs); | ||
| 1524 | else | ||
| 1525 | nr_pirqs = op_nr_pirqs.nr_pirqs; | ||
| 1526 | } | ||
| 1527 | pirq_to_irq = kcalloc(nr_pirqs, sizeof(*pirq_to_irq), GFP_KERNEL); | ||
| 1528 | for (i = 0; i < nr_pirqs; i++) | ||
| 1529 | pirq_to_irq[i] = -1; | 1572 | pirq_to_irq[i] = -1; |
| 1530 | 1573 | ||
| 1531 | 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/manage.c b/drivers/xen/manage.c index ef9c7db5207..db8c4c4ac88 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/include/xen/events.h b/include/xen/events.h index 646dd17d3aa..00f53ddcc06 100644 --- a/include/xen/events.h +++ b/include/xen/events.h | |||
| @@ -76,7 +76,9 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name); | |||
| 76 | 76 | ||
| 77 | #ifdef CONFIG_PCI_MSI | 77 | #ifdef CONFIG_PCI_MSI |
| 78 | /* Allocate an irq and a pirq to be used with MSIs. */ | 78 | /* Allocate an irq and a pirq to be used with MSIs. */ |
| 79 | void xen_allocate_pirq_msi(char *name, int *irq, int *pirq); | 79 | #define XEN_ALLOC_PIRQ (1 << 0) |
| 80 | #define XEN_ALLOC_IRQ (1 << 1) | ||
| 81 | void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc_mask); | ||
| 80 | int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type); | 82 | int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type); |
| 81 | #endif | 83 | #endif |
| 82 | 84 | ||
| @@ -89,4 +91,7 @@ int xen_vector_from_irq(unsigned pirq); | |||
| 89 | /* Return gsi allocated to pirq */ | 91 | /* Return gsi allocated to pirq */ |
| 90 | int xen_gsi_from_irq(unsigned pirq); | 92 | int xen_gsi_from_irq(unsigned pirq); |
| 91 | 93 | ||
| 94 | /* Return irq from pirq */ | ||
| 95 | int xen_irq_from_pirq(unsigned pirq); | ||
| 96 | |||
| 92 | #endif /* _XEN_EVENTS_H */ | 97 | #endif /* _XEN_EVENTS_H */ |
diff --git a/include/xen/interface/physdev.h b/include/xen/interface/physdev.h index 2b2c66c3df0..534cac89a77 100644 --- a/include/xen/interface/physdev.h +++ b/include/xen/interface/physdev.h | |||
| @@ -188,6 +188,16 @@ struct physdev_nr_pirqs { | |||
| 188 | uint32_t nr_pirqs; | 188 | uint32_t nr_pirqs; |
| 189 | }; | 189 | }; |
| 190 | 190 | ||
| 191 | /* type is MAP_PIRQ_TYPE_GSI or MAP_PIRQ_TYPE_MSI | ||
| 192 | * the hypercall returns a free pirq */ | ||
| 193 | #define PHYSDEVOP_get_free_pirq 23 | ||
| 194 | struct physdev_get_free_pirq { | ||
| 195 | /* IN */ | ||
| 196 | int type; | ||
| 197 | /* OUT */ | ||
| 198 | uint32_t pirq; | ||
| 199 | }; | ||
| 200 | |||
| 191 | /* | 201 | /* |
| 192 | * Notify that some PIRQ-bound event channels have been unmasked. | 202 | * Notify that some PIRQ-bound event channels have been unmasked. |
| 193 | * ** This command is obsolete since interface version 0x00030202 and is ** | 203 | * ** This command is obsolete since interface version 0x00030202 and is ** |
