diff options
author | Stefano Stabellini <stefano.stabellini@eu.citrix.com> | 2010-07-01 12:10:39 -0400 |
---|---|---|
committer | Stefano Stabellini <stefano.stabellini@eu.citrix.com> | 2010-10-22 16:25:43 -0400 |
commit | 809f9267bbaba7765cdb86a47f2e6e4bf4951b69 (patch) | |
tree | 5ed0ad8e7f5f535d94927498feefba15c9770e91 | |
parent | 3942b740e5183caad47a4a3fcb37a4509ce7af83 (diff) |
xen: map MSIs into pirqs
Map MSIs into pirqs, writing 0 in the MSI vector data field and the pirq
number in the MSI destination id field.
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 | 57 | ||||
-rw-r--r-- | drivers/xen/events.c | 22 | ||||
-rw-r--r-- | include/xen/events.h | 2 |
3 files changed, 81 insertions, 0 deletions
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index d5284c491aef..b5bd6420851e 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c | |||
@@ -64,10 +64,62 @@ static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi, | |||
64 | 64 | ||
65 | #if defined(CONFIG_PCI_MSI) | 65 | #if defined(CONFIG_PCI_MSI) |
66 | #include <linux/msi.h> | 66 | #include <linux/msi.h> |
67 | #include <asm/msidef.h> | ||
67 | 68 | ||
68 | struct xen_pci_frontend_ops *xen_pci_frontend; | 69 | struct xen_pci_frontend_ops *xen_pci_frontend; |
69 | EXPORT_SYMBOL_GPL(xen_pci_frontend); | 70 | EXPORT_SYMBOL_GPL(xen_pci_frontend); |
70 | 71 | ||
72 | static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int pirq, | ||
73 | struct msi_msg *msg) | ||
74 | { | ||
75 | /* We set vector == 0 to tell the hypervisor we don't care about it, | ||
76 | * but we want a pirq setup instead. | ||
77 | * We use the dest_id field to pass the pirq that we want. */ | ||
78 | msg->address_hi = MSI_ADDR_BASE_HI | MSI_ADDR_EXT_DEST_ID(pirq); | ||
79 | msg->address_lo = | ||
80 | MSI_ADDR_BASE_LO | | ||
81 | MSI_ADDR_DEST_MODE_PHYSICAL | | ||
82 | MSI_ADDR_REDIRECTION_CPU | | ||
83 | MSI_ADDR_DEST_ID(pirq); | ||
84 | |||
85 | msg->data = | ||
86 | MSI_DATA_TRIGGER_EDGE | | ||
87 | MSI_DATA_LEVEL_ASSERT | | ||
88 | /* delivery mode reserved */ | ||
89 | (3 << 8) | | ||
90 | MSI_DATA_VECTOR(0); | ||
91 | } | ||
92 | |||
93 | static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | ||
94 | { | ||
95 | int irq, pirq, ret = 0; | ||
96 | struct msi_desc *msidesc; | ||
97 | struct msi_msg msg; | ||
98 | |||
99 | list_for_each_entry(msidesc, &dev->msi_list, list) { | ||
100 | xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ? | ||
101 | "msi-x" : "msi", &irq, &pirq); | ||
102 | if (irq < 0 || pirq < 0) | ||
103 | goto error; | ||
104 | printk(KERN_DEBUG "xen: msi --> irq=%d, pirq=%d\n", irq, pirq); | ||
105 | xen_msi_compose_msg(dev, pirq, &msg); | ||
106 | ret = set_irq_msi(irq, msidesc); | ||
107 | if (ret < 0) | ||
108 | goto error_while; | ||
109 | write_msi_msg(irq, &msg); | ||
110 | } | ||
111 | return 0; | ||
112 | |||
113 | error_while: | ||
114 | unbind_from_irqhandler(irq, NULL); | ||
115 | error: | ||
116 | if (ret == -ENODEV) | ||
117 | dev_err(&dev->dev, "Xen PCI frontend has not registered" \ | ||
118 | " MSI/MSI-X support!\n"); | ||
119 | |||
120 | return ret; | ||
121 | } | ||
122 | |||
71 | /* | 123 | /* |
72 | * For MSI interrupts we have to use drivers/xen/event.s functions to | 124 | * For MSI interrupts we have to use drivers/xen/event.s functions to |
73 | * allocate an irq_desc and setup the right */ | 125 | * allocate an irq_desc and setup the right */ |
@@ -198,5 +250,10 @@ int __init pci_xen_hvm_init(void) | |||
198 | */ | 250 | */ |
199 | __acpi_register_gsi = acpi_register_gsi_xen_hvm; | 251 | __acpi_register_gsi = acpi_register_gsi_xen_hvm; |
200 | #endif | 252 | #endif |
253 | |||
254 | #ifdef CONFIG_PCI_MSI | ||
255 | x86_msi.setup_msi_irqs = xen_hvm_setup_msi_irqs; | ||
256 | x86_msi.teardown_msi_irq = xen_teardown_msi_irq; | ||
257 | #endif | ||
201 | return 0; | 258 | return 0; |
202 | } | 259 | } |
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 32269bcbd88c..efa683ee8840 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c | |||
@@ -656,6 +656,28 @@ out: | |||
656 | return irq; | 656 | return irq; |
657 | } | 657 | } |
658 | 658 | ||
659 | void xen_allocate_pirq_msi(char *name, int *irq, int *pirq) | ||
660 | { | ||
661 | spin_lock(&irq_mapping_update_lock); | ||
662 | |||
663 | *irq = find_unbound_irq(); | ||
664 | if (*irq == -1) | ||
665 | goto out; | ||
666 | |||
667 | *pirq = find_unbound_pirq(); | ||
668 | if (*pirq == -1) | ||
669 | goto out; | ||
670 | |||
671 | set_irq_chip_and_handler_name(*irq, &xen_pirq_chip, | ||
672 | handle_level_irq, name); | ||
673 | |||
674 | irq_info[*irq] = mk_pirq_info(0, *pirq, 0, 0); | ||
675 | pirq_to_irq[*pirq] = *irq; | ||
676 | |||
677 | out: | ||
678 | spin_unlock(&irq_mapping_update_lock); | ||
679 | } | ||
680 | |||
659 | int xen_destroy_irq(int irq) | 681 | int xen_destroy_irq(int irq) |
660 | { | 682 | { |
661 | struct irq_desc *desc; | 683 | struct irq_desc *desc; |
diff --git a/include/xen/events.h b/include/xen/events.h index deec8faace22..0c58db6ea3f4 100644 --- a/include/xen/events.h +++ b/include/xen/events.h | |||
@@ -72,6 +72,8 @@ 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 | /* Allocate an irq and a pirq to be used with MSIs. */ | ||
76 | void xen_allocate_pirq_msi(char *name, int *irq, int *pirq); | ||
75 | 77 | ||
76 | /* De-allocates the above mentioned physical interrupt. */ | 78 | /* De-allocates the above mentioned physical interrupt. */ |
77 | int xen_destroy_irq(int irq); | 79 | int xen_destroy_irq(int irq); |