diff options
| -rw-r--r-- | arch/x86/pci/xen.c | 55 | ||||
| -rw-r--r-- | drivers/xen/events.c | 60 | ||||
| -rw-r--r-- | include/xen/events.h | 4 |
3 files changed, 101 insertions, 18 deletions
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index dd0b5fdb27b9..b3f4b30222fa 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c | |||
| @@ -135,14 +135,12 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | |||
| 135 | if (!v) | 135 | if (!v) |
| 136 | return -ENOMEM; | 136 | return -ENOMEM; |
| 137 | 137 | ||
| 138 | if (!xen_initial_domain()) { | 138 | if (type == PCI_CAP_ID_MSIX) |
| 139 | if (type == PCI_CAP_ID_MSIX) | 139 | ret = xen_pci_frontend_enable_msix(dev, &v, nvec); |
| 140 | ret = xen_pci_frontend_enable_msix(dev, &v, nvec); | 140 | else |
| 141 | else | 141 | ret = xen_pci_frontend_enable_msi(dev, &v); |
| 142 | ret = xen_pci_frontend_enable_msi(dev, &v); | 142 | if (ret) |
| 143 | if (ret) | 143 | goto error; |
| 144 | goto error; | ||
| 145 | } | ||
| 146 | i = 0; | 144 | i = 0; |
| 147 | list_for_each_entry(msidesc, &dev->msi_list, list) { | 145 | list_for_each_entry(msidesc, &dev->msi_list, list) { |
| 148 | irq = xen_allocate_pirq(v[i], 0, /* not sharable */ | 146 | irq = xen_allocate_pirq(v[i], 0, /* not sharable */ |
| @@ -172,23 +170,40 @@ error: | |||
| 172 | 170 | ||
| 173 | static void xen_teardown_msi_irqs(struct pci_dev *dev) | 171 | static void xen_teardown_msi_irqs(struct pci_dev *dev) |
| 174 | { | 172 | { |
| 175 | /* Only do this when were are in non-privileged mode.*/ | 173 | struct msi_desc *msidesc; |
| 176 | if (!xen_initial_domain()) { | ||
| 177 | struct msi_desc *msidesc; | ||
| 178 | |||
| 179 | msidesc = list_entry(dev->msi_list.next, struct msi_desc, list); | ||
| 180 | if (msidesc->msi_attrib.is_msix) | ||
| 181 | xen_pci_frontend_disable_msix(dev); | ||
| 182 | else | ||
| 183 | xen_pci_frontend_disable_msi(dev); | ||
| 184 | } | ||
| 185 | 174 | ||
| 175 | msidesc = list_entry(dev->msi_list.next, struct msi_desc, list); | ||
| 176 | if (msidesc->msi_attrib.is_msix) | ||
| 177 | xen_pci_frontend_disable_msix(dev); | ||
| 178 | else | ||
| 179 | xen_pci_frontend_disable_msi(dev); | ||
| 186 | } | 180 | } |
| 187 | 181 | ||
| 188 | static void xen_teardown_msi_irq(unsigned int irq) | 182 | static void xen_teardown_msi_irq(unsigned int irq) |
| 189 | { | 183 | { |
| 190 | xen_destroy_irq(irq); | 184 | xen_destroy_irq(irq); |
| 191 | } | 185 | } |
| 186 | |||
| 187 | static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | ||
| 188 | { | ||
| 189 | int irq, ret; | ||
| 190 | struct msi_desc *msidesc; | ||
| 191 | |||
| 192 | list_for_each_entry(msidesc, &dev->msi_list, list) { | ||
| 193 | irq = xen_create_msi_irq(dev, msidesc, type); | ||
| 194 | if (irq < 0) | ||
| 195 | return -1; | ||
| 196 | |||
| 197 | ret = set_irq_msi(irq, msidesc); | ||
| 198 | if (ret) | ||
| 199 | goto error; | ||
| 200 | } | ||
| 201 | return 0; | ||
| 202 | |||
| 203 | error: | ||
| 204 | xen_destroy_irq(irq); | ||
| 205 | return ret; | ||
| 206 | } | ||
| 192 | #endif | 207 | #endif |
| 193 | 208 | ||
| 194 | static int xen_pcifront_enable_irq(struct pci_dev *dev) | 209 | static int xen_pcifront_enable_irq(struct pci_dev *dev) |
| @@ -362,6 +377,10 @@ static int acpi_register_gsi_xen(struct device *dev, u32 gsi, | |||
| 362 | 377 | ||
| 363 | static int __init pci_xen_initial_domain(void) | 378 | static int __init pci_xen_initial_domain(void) |
| 364 | { | 379 | { |
| 380 | #ifdef CONFIG_PCI_MSI | ||
| 381 | x86_msi.setup_msi_irqs = xen_initdom_setup_msi_irqs; | ||
| 382 | x86_msi.teardown_msi_irq = xen_teardown_msi_irq; | ||
| 383 | #endif | ||
| 365 | xen_setup_acpi_sci(); | 384 | xen_setup_acpi_sci(); |
| 366 | __acpi_register_gsi = acpi_register_gsi_xen; | 385 | __acpi_register_gsi = acpi_register_gsi_xen; |
| 367 | 386 | ||
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index c649ac0aaeef..a7d9555e664d 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/bootmem.h> | 29 | #include <linux/bootmem.h> |
| 30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
| 31 | #include <linux/irqnr.h> | 31 | #include <linux/irqnr.h> |
| 32 | #include <linux/pci.h> | ||
| 32 | 33 | ||
| 33 | #include <asm/desc.h> | 34 | #include <asm/desc.h> |
| 34 | #include <asm/ptrace.h> | 35 | #include <asm/ptrace.h> |
| @@ -656,6 +657,10 @@ out: | |||
| 656 | return irq; | 657 | return irq; |
| 657 | } | 658 | } |
| 658 | 659 | ||
| 660 | #ifdef CONFIG_PCI_MSI | ||
| 661 | #include <linux/msi.h> | ||
| 662 | #include "../pci/msi.h" | ||
| 663 | |||
| 659 | void xen_allocate_pirq_msi(char *name, int *irq, int *pirq) | 664 | void xen_allocate_pirq_msi(char *name, int *irq, int *pirq) |
| 660 | { | 665 | { |
| 661 | spin_lock(&irq_mapping_update_lock); | 666 | spin_lock(&irq_mapping_update_lock); |
| @@ -678,6 +683,61 @@ out: | |||
| 678 | spin_unlock(&irq_mapping_update_lock); | 683 | spin_unlock(&irq_mapping_update_lock); |
| 679 | } | 684 | } |
| 680 | 685 | ||
| 686 | int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type) | ||
| 687 | { | ||
| 688 | int irq = -1; | ||
| 689 | struct physdev_map_pirq map_irq; | ||
| 690 | int rc; | ||
| 691 | int pos; | ||
| 692 | u32 table_offset, bir; | ||
| 693 | |||
| 694 | memset(&map_irq, 0, sizeof(map_irq)); | ||
| 695 | map_irq.domid = DOMID_SELF; | ||
| 696 | map_irq.type = MAP_PIRQ_TYPE_MSI; | ||
| 697 | map_irq.index = -1; | ||
| 698 | map_irq.pirq = -1; | ||
| 699 | map_irq.bus = dev->bus->number; | ||
| 700 | map_irq.devfn = dev->devfn; | ||
| 701 | |||
| 702 | if (type == PCI_CAP_ID_MSIX) { | ||
| 703 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | ||
| 704 | |||
| 705 | pci_read_config_dword(dev, msix_table_offset_reg(pos), | ||
| 706 | &table_offset); | ||
| 707 | bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK); | ||
| 708 | |||
| 709 | map_irq.table_base = pci_resource_start(dev, bir); | ||
| 710 | map_irq.entry_nr = msidesc->msi_attrib.entry_nr; | ||
| 711 | } | ||
| 712 | |||
| 713 | spin_lock(&irq_mapping_update_lock); | ||
| 714 | |||
| 715 | irq = find_unbound_irq(); | ||
| 716 | |||
| 717 | if (irq == -1) | ||
| 718 | goto out; | ||
| 719 | |||
| 720 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq); | ||
| 721 | if (rc) { | ||
| 722 | printk(KERN_WARNING "xen map irq failed %d\n", rc); | ||
| 723 | |||
| 724 | irq_free_desc(irq); | ||
| 725 | |||
| 726 | irq = -1; | ||
| 727 | goto out; | ||
| 728 | } | ||
| 729 | irq_info[irq] = mk_pirq_info(0, map_irq.pirq, 0, map_irq.index); | ||
| 730 | |||
| 731 | set_irq_chip_and_handler_name(irq, &xen_pirq_chip, | ||
| 732 | handle_level_irq, | ||
| 733 | (type == PCI_CAP_ID_MSIX) ? "msi-x":"msi"); | ||
| 734 | |||
| 735 | out: | ||
| 736 | spin_unlock(&irq_mapping_update_lock); | ||
| 737 | return irq; | ||
| 738 | } | ||
| 739 | #endif | ||
| 740 | |||
| 681 | int xen_destroy_irq(int irq) | 741 | int xen_destroy_irq(int irq) |
| 682 | { | 742 | { |
| 683 | struct irq_desc *desc; | 743 | struct irq_desc *desc; |
diff --git a/include/xen/events.h b/include/xen/events.h index 0c58db6ea3f4..8fa27dc7358b 100644 --- a/include/xen/events.h +++ b/include/xen/events.h | |||
| @@ -72,8 +72,12 @@ void xen_hvm_evtchn_do_upcall(void); | |||
| 72 | * usual. */ | 72 | * usual. */ |
| 73 | int xen_allocate_pirq(unsigned gsi, int shareable, char *name); | 73 | int xen_allocate_pirq(unsigned gsi, int shareable, char *name); |
| 74 | int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name); | 74 | int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name); |
| 75 | |||
| 76 | #ifdef CONFIG_PCI_MSI | ||
| 75 | /* Allocate an irq and a pirq to be used with MSIs. */ | 77 | /* Allocate an irq and a pirq to be used with MSIs. */ |
| 76 | void xen_allocate_pirq_msi(char *name, int *irq, int *pirq); | 78 | void xen_allocate_pirq_msi(char *name, int *irq, int *pirq); |
| 79 | int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type); | ||
| 80 | #endif | ||
| 77 | 81 | ||
| 78 | /* De-allocates the above mentioned physical interrupt. */ | 82 | /* De-allocates the above mentioned physical interrupt. */ |
| 79 | int xen_destroy_irq(int irq); | 83 | int xen_destroy_irq(int irq); |
