diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-15 13:47:56 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-15 13:47:56 -0400 |
| commit | 010b8f4e264b0b6f596186574956dde2fa02df1c (patch) | |
| tree | 277d599cc0147be3a3d5bfdf676510c0add154c0 | |
| parent | 397fae081869784d07cd4edde0ddf436ca2011e0 (diff) | |
| parent | 71eef7d1e3d9df760897fdd2cad6949a8bcf1620 (diff) | |
Merge branch 'stable/irq.cleanup' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen
* 'stable/irq.cleanup' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen:
xen: events: remove dom0 specific xen_create_msi_irq
xen: events: use xen_bind_pirq_msi_to_irq from xen_create_msi_irq
xen: events: push set_irq_msi down into xen_create_msi_irq
xen: events: update pirq_to_irq in xen_create_msi_irq
xen: events: refactor xen_create_msi_irq slightly
xen: events: separate MSI PIRQ allocation from PIRQ binding to IRQ
xen: events: assume PHYSDEVOP_get_free_pirq exists
xen: pci: collapse apic_register_gsi_xen_hvm and xen_hvm_register_pirq
xen: events: return irq from xen_allocate_pirq_msi
xen: events: drop XEN_ALLOC_IRQ flag to xen_allocate_pirq_msi
xen: events: do not leak IRQ from xen_allocate_pirq_msi when no pirq available.
xen: pci: only define xen_initdom_setup_msi_irqs if CONFIG_XEN_DOM0
| -rw-r--r-- | arch/x86/pci/xen.c | 130 | ||||
| -rw-r--r-- | drivers/xen/events.c | 96 | ||||
| -rw-r--r-- | include/xen/events.h | 8 |
3 files changed, 91 insertions, 143 deletions
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index 8634e1b49c0..8c4085a95ef 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c | |||
| @@ -20,7 +20,8 @@ | |||
| 20 | #include <asm/xen/pci.h> | 20 | #include <asm/xen/pci.h> |
| 21 | 21 | ||
| 22 | #ifdef CONFIG_ACPI | 22 | #ifdef CONFIG_ACPI |
| 23 | static int xen_hvm_register_pirq(u32 gsi, int triggering) | 23 | static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi, |
| 24 | int trigger, int polarity) | ||
| 24 | { | 25 | { |
| 25 | int rc, irq; | 26 | int rc, irq; |
| 26 | struct physdev_map_pirq map_irq; | 27 | struct physdev_map_pirq map_irq; |
| @@ -41,7 +42,7 @@ static int xen_hvm_register_pirq(u32 gsi, int triggering) | |||
| 41 | return -1; | 42 | return -1; |
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | if (triggering == ACPI_EDGE_SENSITIVE) { | 45 | if (trigger == ACPI_EDGE_SENSITIVE) { |
| 45 | shareable = 0; | 46 | shareable = 0; |
| 46 | name = "ioapic-edge"; | 47 | name = "ioapic-edge"; |
| 47 | } else { | 48 | } else { |
| @@ -55,12 +56,6 @@ static int xen_hvm_register_pirq(u32 gsi, int triggering) | |||
| 55 | 56 | ||
| 56 | return irq; | 57 | return irq; |
| 57 | } | 58 | } |
| 58 | |||
| 59 | static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi, | ||
| 60 | int trigger, int polarity) | ||
| 61 | { | ||
| 62 | return xen_hvm_register_pirq(gsi, trigger); | ||
| 63 | } | ||
| 64 | #endif | 59 | #endif |
| 65 | 60 | ||
| 66 | #if defined(CONFIG_PCI_MSI) | 61 | #if defined(CONFIG_PCI_MSI) |
| @@ -91,7 +86,7 @@ static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int pirq, | |||
| 91 | 86 | ||
| 92 | static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | 87 | static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) |
| 93 | { | 88 | { |
| 94 | int irq, pirq, ret = 0; | 89 | int irq, pirq; |
| 95 | struct msi_desc *msidesc; | 90 | struct msi_desc *msidesc; |
| 96 | struct msi_msg msg; | 91 | struct msi_msg msg; |
| 97 | 92 | ||
| @@ -99,39 +94,32 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | |||
| 99 | __read_msi_msg(msidesc, &msg); | 94 | __read_msi_msg(msidesc, &msg); |
| 100 | pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) | | 95 | pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) | |
| 101 | ((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff); | 96 | ((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff); |
| 102 | if (xen_irq_from_pirq(pirq) >= 0 && msg.data == XEN_PIRQ_MSI_DATA) { | 97 | if (msg.data != XEN_PIRQ_MSI_DATA || |
| 103 | xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ? | 98 | xen_irq_from_pirq(pirq) < 0) { |
| 104 | "msi-x" : "msi", &irq, &pirq, XEN_ALLOC_IRQ); | 99 | pirq = xen_allocate_pirq_msi(dev, msidesc); |
| 105 | if (irq < 0) | 100 | if (pirq < 0) |
| 106 | goto error; | 101 | goto error; |
| 107 | ret = set_irq_msi(irq, msidesc); | 102 | xen_msi_compose_msg(dev, pirq, &msg); |
| 108 | if (ret < 0) | 103 | __write_msi_msg(msidesc, &msg); |
| 109 | goto error_while; | 104 | dev_dbg(&dev->dev, "xen: msi bound to pirq=%d\n", pirq); |
| 110 | printk(KERN_DEBUG "xen: msi already setup: msi --> irq=%d" | 105 | } else { |
| 111 | " pirq=%d\n", irq, pirq); | 106 | dev_dbg(&dev->dev, |
| 112 | return 0; | 107 | "xen: msi already bound to pirq=%d\n", pirq); |
| 113 | } | 108 | } |
| 114 | xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ? | 109 | irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq, 0, |
| 115 | "msi-x" : "msi", &irq, &pirq, (XEN_ALLOC_IRQ | XEN_ALLOC_PIRQ)); | 110 | (type == PCI_CAP_ID_MSIX) ? |
| 116 | if (irq < 0 || pirq < 0) | 111 | "msi-x" : "msi"); |
| 112 | if (irq < 0) | ||
| 117 | goto error; | 113 | goto error; |
| 118 | printk(KERN_DEBUG "xen: msi --> irq=%d, pirq=%d\n", irq, pirq); | 114 | dev_dbg(&dev->dev, |
| 119 | xen_msi_compose_msg(dev, pirq, &msg); | 115 | "xen: msi --> pirq=%d --> irq=%d\n", pirq, irq); |
| 120 | ret = set_irq_msi(irq, msidesc); | ||
| 121 | if (ret < 0) | ||
| 122 | goto error_while; | ||
| 123 | write_msi_msg(irq, &msg); | ||
| 124 | } | 116 | } |
| 125 | return 0; | 117 | return 0; |
| 126 | 118 | ||
| 127 | error_while: | ||
| 128 | unbind_from_irqhandler(irq, NULL); | ||
| 129 | error: | 119 | error: |
| 130 | if (ret == -ENODEV) | 120 | dev_err(&dev->dev, |
| 131 | dev_err(&dev->dev, "Xen PCI frontend has not registered" \ | 121 | "Xen PCI frontend has not registered MSI/MSI-X support!\n"); |
| 132 | " MSI/MSI-X support!\n"); | 122 | return -ENODEV; |
| 133 | |||
| 134 | return ret; | ||
| 135 | } | 123 | } |
| 136 | 124 | ||
| 137 | /* | 125 | /* |
| @@ -157,28 +145,19 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | |||
| 157 | goto error; | 145 | goto error; |
| 158 | i = 0; | 146 | i = 0; |
| 159 | list_for_each_entry(msidesc, &dev->msi_list, list) { | 147 | list_for_each_entry(msidesc, &dev->msi_list, list) { |
| 160 | xen_allocate_pirq_msi( | 148 | irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i], 0, |
| 161 | (type == PCI_CAP_ID_MSIX) ? | 149 | (type == PCI_CAP_ID_MSIX) ? |
| 162 | "pcifront-msi-x" : "pcifront-msi", | 150 | "pcifront-msi-x" : |
| 163 | &irq, &v[i], XEN_ALLOC_IRQ); | 151 | "pcifront-msi"); |
| 164 | if (irq < 0) { | 152 | if (irq < 0) |
| 165 | ret = -1; | ||
| 166 | goto free; | 153 | goto free; |
| 167 | } | ||
| 168 | ret = set_irq_msi(irq, msidesc); | ||
| 169 | if (ret) | ||
| 170 | goto error_while; | ||
| 171 | i++; | 154 | i++; |
| 172 | } | 155 | } |
| 173 | kfree(v); | 156 | kfree(v); |
| 174 | return 0; | 157 | return 0; |
| 175 | 158 | ||
| 176 | error_while: | ||
| 177 | unbind_from_irqhandler(irq, NULL); | ||
| 178 | error: | 159 | error: |
| 179 | if (ret == -ENODEV) | 160 | dev_err(&dev->dev, "Xen PCI frontend has not registered MSI/MSI-X support!\n"); |
| 180 | dev_err(&dev->dev, "Xen PCI frontend has not registered" \ | ||
| 181 | " MSI/MSI-X support!\n"); | ||
| 182 | free: | 161 | free: |
| 183 | kfree(v); | 162 | kfree(v); |
| 184 | return ret; | 163 | return ret; |
| @@ -203,27 +182,56 @@ static void xen_teardown_msi_irq(unsigned int irq) | |||
| 203 | xen_destroy_irq(irq); | 182 | xen_destroy_irq(irq); |
| 204 | } | 183 | } |
| 205 | 184 | ||
| 185 | #ifdef CONFIG_XEN_DOM0 | ||
| 206 | static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | 186 | static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) |
| 207 | { | 187 | { |
| 208 | int irq, ret; | 188 | int ret = 0; |
| 209 | struct msi_desc *msidesc; | 189 | struct msi_desc *msidesc; |
| 210 | 190 | ||
| 211 | list_for_each_entry(msidesc, &dev->msi_list, list) { | 191 | list_for_each_entry(msidesc, &dev->msi_list, list) { |
| 212 | irq = xen_create_msi_irq(dev, msidesc, type); | 192 | struct physdev_map_pirq map_irq; |
| 213 | if (irq < 0) | ||
| 214 | return -1; | ||
| 215 | 193 | ||
| 216 | ret = set_irq_msi(irq, msidesc); | 194 | memset(&map_irq, 0, sizeof(map_irq)); |
| 217 | if (ret) | 195 | map_irq.domid = DOMID_SELF; |
| 218 | goto error; | 196 | map_irq.type = MAP_PIRQ_TYPE_MSI; |
| 219 | } | 197 | map_irq.index = -1; |
| 220 | return 0; | 198 | map_irq.pirq = -1; |
| 199 | map_irq.bus = dev->bus->number; | ||
| 200 | map_irq.devfn = dev->devfn; | ||
| 221 | 201 | ||
| 222 | error: | 202 | if (type == PCI_CAP_ID_MSIX) { |
| 223 | xen_destroy_irq(irq); | 203 | int pos; |
| 204 | u32 table_offset, bir; | ||
| 205 | |||
| 206 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | ||
| 207 | |||
| 208 | pci_read_config_dword(dev, pos + PCI_MSIX_TABLE, | ||
| 209 | &table_offset); | ||
| 210 | bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK); | ||
| 211 | |||
| 212 | map_irq.table_base = pci_resource_start(dev, bir); | ||
| 213 | map_irq.entry_nr = msidesc->msi_attrib.entry_nr; | ||
| 214 | } | ||
| 215 | |||
| 216 | ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq); | ||
| 217 | if (ret) { | ||
| 218 | dev_warn(&dev->dev, "xen map irq failed %d\n", ret); | ||
| 219 | goto out; | ||
| 220 | } | ||
| 221 | |||
| 222 | ret = xen_bind_pirq_msi_to_irq(dev, msidesc, | ||
| 223 | map_irq.pirq, map_irq.index, | ||
| 224 | (type == PCI_CAP_ID_MSIX) ? | ||
| 225 | "msi-x" : "msi"); | ||
| 226 | if (ret < 0) | ||
| 227 | goto out; | ||
| 228 | } | ||
| 229 | ret = 0; | ||
| 230 | out: | ||
| 224 | return ret; | 231 | return ret; |
| 225 | } | 232 | } |
| 226 | #endif | 233 | #endif |
| 234 | #endif | ||
| 227 | 235 | ||
| 228 | static int xen_pcifront_enable_irq(struct pci_dev *dev) | 236 | static int xen_pcifront_enable_irq(struct pci_dev *dev) |
| 229 | { | 237 | { |
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 89987a7bf26..6befe622715 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c | |||
| @@ -644,104 +644,46 @@ out: | |||
| 644 | } | 644 | } |
| 645 | 645 | ||
| 646 | #ifdef CONFIG_PCI_MSI | 646 | #ifdef CONFIG_PCI_MSI |
| 647 | #include <linux/msi.h> | 647 | int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc) |
| 648 | #include "../pci/msi.h" | ||
| 649 | |||
| 650 | static int find_unbound_pirq(int type) | ||
| 651 | { | 648 | { |
| 652 | int rc, i; | 649 | int rc; |
| 653 | struct physdev_get_free_pirq op_get_free_pirq; | 650 | struct physdev_get_free_pirq op_get_free_pirq; |
| 654 | op_get_free_pirq.type = type; | ||
| 655 | 651 | ||
| 652 | op_get_free_pirq.type = MAP_PIRQ_TYPE_MSI; | ||
| 656 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_free_pirq, &op_get_free_pirq); | 653 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_free_pirq, &op_get_free_pirq); |
| 657 | if (!rc) | ||
| 658 | return op_get_free_pirq.pirq; | ||
| 659 | |||
| 660 | for (i = 0; i < nr_irqs; i++) { | ||
| 661 | if (pirq_to_irq[i] < 0) | ||
| 662 | return i; | ||
| 663 | } | ||
| 664 | return -1; | ||
| 665 | } | ||
| 666 | |||
| 667 | void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc) | ||
| 668 | { | ||
| 669 | spin_lock(&irq_mapping_update_lock); | ||
| 670 | |||
| 671 | if (alloc & XEN_ALLOC_IRQ) { | ||
| 672 | *irq = xen_allocate_irq_dynamic(); | ||
| 673 | if (*irq == -1) | ||
| 674 | goto out; | ||
| 675 | } | ||
| 676 | |||
| 677 | if (alloc & XEN_ALLOC_PIRQ) { | ||
| 678 | *pirq = find_unbound_pirq(MAP_PIRQ_TYPE_MSI); | ||
| 679 | if (*pirq == -1) | ||
| 680 | goto out; | ||
| 681 | } | ||
| 682 | |||
| 683 | set_irq_chip_and_handler_name(*irq, &xen_pirq_chip, | ||
| 684 | handle_level_irq, name); | ||
| 685 | 654 | ||
| 686 | irq_info[*irq] = mk_pirq_info(0, *pirq, 0, 0); | 655 | WARN_ONCE(rc == -ENOSYS, |
| 687 | pirq_to_irq[*pirq] = *irq; | 656 | "hypervisor does not support the PHYSDEVOP_get_free_pirq interface\n"); |
| 688 | 657 | ||
| 689 | out: | 658 | return rc ? -1 : op_get_free_pirq.pirq; |
| 690 | spin_unlock(&irq_mapping_update_lock); | ||
| 691 | } | 659 | } |
| 692 | 660 | ||
| 693 | int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type) | 661 | int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, |
| 662 | int pirq, int vector, const char *name) | ||
| 694 | { | 663 | { |
| 695 | int irq = -1; | 664 | int irq, ret; |
| 696 | struct physdev_map_pirq map_irq; | ||
| 697 | int rc; | ||
| 698 | int pos; | ||
| 699 | u32 table_offset, bir; | ||
| 700 | |||
| 701 | memset(&map_irq, 0, sizeof(map_irq)); | ||
| 702 | map_irq.domid = DOMID_SELF; | ||
| 703 | map_irq.type = MAP_PIRQ_TYPE_MSI; | ||
| 704 | map_irq.index = -1; | ||
| 705 | map_irq.pirq = -1; | ||
| 706 | map_irq.bus = dev->bus->number; | ||
| 707 | map_irq.devfn = dev->devfn; | ||
| 708 | |||
| 709 | if (type == PCI_CAP_ID_MSIX) { | ||
| 710 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | ||
| 711 | |||
| 712 | pci_read_config_dword(dev, msix_table_offset_reg(pos), | ||
| 713 | &table_offset); | ||
| 714 | bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK); | ||
| 715 | |||
| 716 | map_irq.table_base = pci_resource_start(dev, bir); | ||
| 717 | map_irq.entry_nr = msidesc->msi_attrib.entry_nr; | ||
| 718 | } | ||
| 719 | 665 | ||
| 720 | spin_lock(&irq_mapping_update_lock); | 666 | spin_lock(&irq_mapping_update_lock); |
| 721 | 667 | ||
| 722 | irq = xen_allocate_irq_dynamic(); | 668 | irq = xen_allocate_irq_dynamic(); |
| 723 | |||
| 724 | if (irq == -1) | 669 | if (irq == -1) |
| 725 | goto out; | 670 | goto out; |
| 726 | 671 | ||
| 727 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq); | ||
| 728 | if (rc) { | ||
| 729 | printk(KERN_WARNING "xen map irq failed %d\n", rc); | ||
| 730 | |||
| 731 | xen_free_irq(irq); | ||
| 732 | |||
| 733 | irq = -1; | ||
| 734 | goto out; | ||
| 735 | } | ||
| 736 | irq_info[irq] = mk_pirq_info(0, map_irq.pirq, 0, map_irq.index); | ||
| 737 | |||
| 738 | set_irq_chip_and_handler_name(irq, &xen_pirq_chip, | 672 | set_irq_chip_and_handler_name(irq, &xen_pirq_chip, |
| 739 | handle_level_irq, | 673 | handle_level_irq, name); |
| 740 | (type == PCI_CAP_ID_MSIX) ? "msi-x":"msi"); | ||
| 741 | 674 | ||
| 675 | irq_info[irq] = mk_pirq_info(0, pirq, 0, vector); | ||
| 676 | pirq_to_irq[pirq] = irq; | ||
| 677 | ret = set_irq_msi(irq, msidesc); | ||
| 678 | if (ret < 0) | ||
| 679 | goto error_irq; | ||
| 742 | out: | 680 | out: |
| 743 | spin_unlock(&irq_mapping_update_lock); | 681 | spin_unlock(&irq_mapping_update_lock); |
| 744 | return irq; | 682 | return irq; |
| 683 | error_irq: | ||
| 684 | spin_unlock(&irq_mapping_update_lock); | ||
| 685 | xen_free_irq(irq); | ||
| 686 | return -1; | ||
| 745 | } | 687 | } |
| 746 | #endif | 688 | #endif |
| 747 | 689 | ||
diff --git a/include/xen/events.h b/include/xen/events.h index 00f53ddcc06..962da2ced5b 100644 --- a/include/xen/events.h +++ b/include/xen/events.h | |||
| @@ -75,11 +75,9 @@ int xen_allocate_pirq(unsigned gsi, int shareable, char *name); | |||
| 75 | int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name); | 75 | 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 | int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc); |
| 79 | #define XEN_ALLOC_PIRQ (1 << 0) | 79 | int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, |
| 80 | #define XEN_ALLOC_IRQ (1 << 1) | 80 | int pirq, int vector, const char *name); |
| 81 | void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc_mask); | ||
| 82 | int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type); | ||
| 83 | #endif | 81 | #endif |
| 84 | 82 | ||
| 85 | /* De-allocates the above mentioned physical interrupt. */ | 83 | /* De-allocates the above mentioned physical interrupt. */ |
