diff options
author | Qing He <qing.he@intel.com> | 2010-10-11 10:30:09 -0400 |
---|---|---|
committer | Stefano Stabellini <stefano.stabellini@eu.citrix.com> | 2010-10-22 16:25:44 -0400 |
commit | f731e3ef02b4744f4d7ca2f63539b900e47db31f (patch) | |
tree | 865ef6f817c372b99f0b36dc6f2638df087d51e7 | |
parent | 38aa66fcb79e0a46c24bba96b6f2b851a6ec2037 (diff) |
xen: remap MSIs into pirqs when running as initial domain
Implement xen_create_msi_irq to create an msi and remap it as pirq.
Use xen_create_msi_irq to implement an initial domain specific version
of setup_msi_irqs.
Signed-off-by: Qing He <qing.he@intel.com>
Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
-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); |