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 /arch | |
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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/pci/xen.c | 57 |
1 files changed, 57 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 | } |