aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/pci/xen.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/pci/xen.c')
-rw-r--r--arch/x86/pci/xen.c414
1 files changed, 414 insertions, 0 deletions
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
new file mode 100644
index 000000000000..117f5b8daf75
--- /dev/null
+++ b/arch/x86/pci/xen.c
@@ -0,0 +1,414 @@
1/*
2 * Xen PCI Frontend Stub - puts some "dummy" functions in to the Linux
3 * x86 PCI core to support the Xen PCI Frontend
4 *
5 * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
6 */
7#include <linux/module.h>
8#include <linux/init.h>
9#include <linux/pci.h>
10#include <linux/acpi.h>
11
12#include <linux/io.h>
13#include <asm/io_apic.h>
14#include <asm/pci_x86.h>
15
16#include <asm/xen/hypervisor.h>
17
18#include <xen/features.h>
19#include <xen/events.h>
20#include <asm/xen/pci.h>
21
22#ifdef CONFIG_ACPI
23static int xen_hvm_register_pirq(u32 gsi, int triggering)
24{
25 int rc, irq;
26 struct physdev_map_pirq map_irq;
27 int shareable = 0;
28 char *name;
29
30 if (!xen_hvm_domain())
31 return -1;
32
33 map_irq.domid = DOMID_SELF;
34 map_irq.type = MAP_PIRQ_TYPE_GSI;
35 map_irq.index = gsi;
36 map_irq.pirq = -1;
37
38 rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
39 if (rc) {
40 printk(KERN_WARNING "xen map irq failed %d\n", rc);
41 return -1;
42 }
43
44 if (triggering == ACPI_EDGE_SENSITIVE) {
45 shareable = 0;
46 name = "ioapic-edge";
47 } else {
48 shareable = 1;
49 name = "ioapic-level";
50 }
51
52 irq = xen_map_pirq_gsi(map_irq.pirq, gsi, shareable, name);
53
54 printk(KERN_DEBUG "xen: --> irq=%d, pirq=%d\n", irq, map_irq.pirq);
55
56 return irq;
57}
58
59static 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
65
66#if defined(CONFIG_PCI_MSI)
67#include <linux/msi.h>
68#include <asm/msidef.h>
69
70struct xen_pci_frontend_ops *xen_pci_frontend;
71EXPORT_SYMBOL_GPL(xen_pci_frontend);
72
73static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int pirq,
74 struct msi_msg *msg)
75{
76 /* We set vector == 0 to tell the hypervisor we don't care about it,
77 * but we want a pirq setup instead.
78 * We use the dest_id field to pass the pirq that we want. */
79 msg->address_hi = MSI_ADDR_BASE_HI | MSI_ADDR_EXT_DEST_ID(pirq);
80 msg->address_lo =
81 MSI_ADDR_BASE_LO |
82 MSI_ADDR_DEST_MODE_PHYSICAL |
83 MSI_ADDR_REDIRECTION_CPU |
84 MSI_ADDR_DEST_ID(pirq);
85
86 msg->data =
87 MSI_DATA_TRIGGER_EDGE |
88 MSI_DATA_LEVEL_ASSERT |
89 /* delivery mode reserved */
90 (3 << 8) |
91 MSI_DATA_VECTOR(0);
92}
93
94static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
95{
96 int irq, pirq, ret = 0;
97 struct msi_desc *msidesc;
98 struct msi_msg msg;
99
100 list_for_each_entry(msidesc, &dev->msi_list, list) {
101 xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ?
102 "msi-x" : "msi", &irq, &pirq);
103 if (irq < 0 || pirq < 0)
104 goto error;
105 printk(KERN_DEBUG "xen: msi --> irq=%d, pirq=%d\n", irq, pirq);
106 xen_msi_compose_msg(dev, pirq, &msg);
107 ret = set_irq_msi(irq, msidesc);
108 if (ret < 0)
109 goto error_while;
110 write_msi_msg(irq, &msg);
111 }
112 return 0;
113
114error_while:
115 unbind_from_irqhandler(irq, NULL);
116error:
117 if (ret == -ENODEV)
118 dev_err(&dev->dev, "Xen PCI frontend has not registered" \
119 " MSI/MSI-X support!\n");
120
121 return ret;
122}
123
124/*
125 * For MSI interrupts we have to use drivers/xen/event.s functions to
126 * allocate an irq_desc and setup the right */
127
128
129static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
130{
131 int irq, ret, i;
132 struct msi_desc *msidesc;
133 int *v;
134
135 v = kzalloc(sizeof(int) * max(1, nvec), GFP_KERNEL);
136 if (!v)
137 return -ENOMEM;
138
139 if (type == PCI_CAP_ID_MSIX)
140 ret = xen_pci_frontend_enable_msix(dev, &v, nvec);
141 else
142 ret = xen_pci_frontend_enable_msi(dev, &v);
143 if (ret)
144 goto error;
145 i = 0;
146 list_for_each_entry(msidesc, &dev->msi_list, list) {
147 irq = xen_allocate_pirq(v[i], 0, /* not sharable */
148 (type == PCI_CAP_ID_MSIX) ?
149 "pcifront-msi-x" : "pcifront-msi");
150 if (irq < 0)
151 return -1;
152
153 ret = set_irq_msi(irq, msidesc);
154 if (ret)
155 goto error_while;
156 i++;
157 }
158 kfree(v);
159 return 0;
160
161error_while:
162 unbind_from_irqhandler(irq, NULL);
163error:
164 if (ret == -ENODEV)
165 dev_err(&dev->dev, "Xen PCI frontend has not registered" \
166 " MSI/MSI-X support!\n");
167
168 kfree(v);
169 return ret;
170}
171
172static void xen_teardown_msi_irqs(struct pci_dev *dev)
173{
174 struct msi_desc *msidesc;
175
176 msidesc = list_entry(dev->msi_list.next, struct msi_desc, list);
177 if (msidesc->msi_attrib.is_msix)
178 xen_pci_frontend_disable_msix(dev);
179 else
180 xen_pci_frontend_disable_msi(dev);
181}
182
183static void xen_teardown_msi_irq(unsigned int irq)
184{
185 xen_destroy_irq(irq);
186}
187
188static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
189{
190 int irq, ret;
191 struct msi_desc *msidesc;
192
193 list_for_each_entry(msidesc, &dev->msi_list, list) {
194 irq = xen_create_msi_irq(dev, msidesc, type);
195 if (irq < 0)
196 return -1;
197
198 ret = set_irq_msi(irq, msidesc);
199 if (ret)
200 goto error;
201 }
202 return 0;
203
204error:
205 xen_destroy_irq(irq);
206 return ret;
207}
208#endif
209
210static int xen_pcifront_enable_irq(struct pci_dev *dev)
211{
212 int rc;
213 int share = 1;
214
215 dev_info(&dev->dev, "Xen PCI enabling IRQ: %d\n", dev->irq);
216
217 if (dev->irq < 0)
218 return -EINVAL;
219
220 if (dev->irq < NR_IRQS_LEGACY)
221 share = 0;
222
223 rc = xen_allocate_pirq(dev->irq, share, "pcifront");
224 if (rc < 0) {
225 dev_warn(&dev->dev, "Xen PCI IRQ: %d, failed to register:%d\n",
226 dev->irq, rc);
227 return rc;
228 }
229 return 0;
230}
231
232int __init pci_xen_init(void)
233{
234 if (!xen_pv_domain() || xen_initial_domain())
235 return -ENODEV;
236
237 printk(KERN_INFO "PCI: setting up Xen PCI frontend stub\n");
238
239 pcibios_set_cache_line_size();
240
241 pcibios_enable_irq = xen_pcifront_enable_irq;
242 pcibios_disable_irq = NULL;
243
244#ifdef CONFIG_ACPI
245 /* Keep ACPI out of the picture */
246 acpi_noirq = 1;
247#endif
248
249#ifdef CONFIG_PCI_MSI
250 x86_msi.setup_msi_irqs = xen_setup_msi_irqs;
251 x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
252 x86_msi.teardown_msi_irqs = xen_teardown_msi_irqs;
253#endif
254 return 0;
255}
256
257int __init pci_xen_hvm_init(void)
258{
259 if (!xen_feature(XENFEAT_hvm_pirqs))
260 return 0;
261
262#ifdef CONFIG_ACPI
263 /*
264 * We don't want to change the actual ACPI delivery model,
265 * just how GSIs get registered.
266 */
267 __acpi_register_gsi = acpi_register_gsi_xen_hvm;
268#endif
269
270#ifdef CONFIG_PCI_MSI
271 x86_msi.setup_msi_irqs = xen_hvm_setup_msi_irqs;
272 x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
273#endif
274 return 0;
275}
276
277#ifdef CONFIG_XEN_DOM0
278static int xen_register_pirq(u32 gsi, int triggering)
279{
280 int rc, irq;
281 struct physdev_map_pirq map_irq;
282 int shareable = 0;
283 char *name;
284
285 if (!xen_pv_domain())
286 return -1;
287
288 if (triggering == ACPI_EDGE_SENSITIVE) {
289 shareable = 0;
290 name = "ioapic-edge";
291 } else {
292 shareable = 1;
293 name = "ioapic-level";
294 }
295
296 irq = xen_allocate_pirq(gsi, shareable, name);
297
298 printk(KERN_DEBUG "xen: --> irq=%d\n", irq);
299
300 if (irq < 0)
301 goto out;
302
303 map_irq.domid = DOMID_SELF;
304 map_irq.type = MAP_PIRQ_TYPE_GSI;
305 map_irq.index = gsi;
306 map_irq.pirq = irq;
307
308 rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
309 if (rc) {
310 printk(KERN_WARNING "xen map irq failed %d\n", rc);
311 return -1;
312 }
313
314out:
315 return irq;
316}
317
318static int xen_register_gsi(u32 gsi, int triggering, int polarity)
319{
320 int rc, irq;
321 struct physdev_setup_gsi setup_gsi;
322
323 if (!xen_pv_domain())
324 return -1;
325
326 printk(KERN_DEBUG "xen: registering gsi %u triggering %d polarity %d\n",
327 gsi, triggering, polarity);
328
329 irq = xen_register_pirq(gsi, triggering);
330
331 setup_gsi.gsi = gsi;
332 setup_gsi.triggering = (triggering == ACPI_EDGE_SENSITIVE ? 0 : 1);
333 setup_gsi.polarity = (polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
334
335 rc = HYPERVISOR_physdev_op(PHYSDEVOP_setup_gsi, &setup_gsi);
336 if (rc == -EEXIST)
337 printk(KERN_INFO "Already setup the GSI :%d\n", gsi);
338 else if (rc) {
339 printk(KERN_ERR "Failed to setup GSI :%d, err_code:%d\n",
340 gsi, rc);
341 }
342
343 return irq;
344}
345
346static __init void xen_setup_acpi_sci(void)
347{
348 int rc;
349 int trigger, polarity;
350 int gsi = acpi_sci_override_gsi;
351
352 if (!gsi)
353 return;
354
355 rc = acpi_get_override_irq(gsi, &trigger, &polarity);
356 if (rc) {
357 printk(KERN_WARNING "xen: acpi_get_override_irq failed for acpi"
358 " sci, rc=%d\n", rc);
359 return;
360 }
361 trigger = trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
362 polarity = polarity ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
363
364 printk(KERN_INFO "xen: sci override: global_irq=%d trigger=%d "
365 "polarity=%d\n", gsi, trigger, polarity);
366
367 gsi = xen_register_gsi(gsi, trigger, polarity);
368 printk(KERN_INFO "xen: acpi sci %d\n", gsi);
369
370 return;
371}
372
373static int acpi_register_gsi_xen(struct device *dev, u32 gsi,
374 int trigger, int polarity)
375{
376 return xen_register_gsi(gsi, trigger, polarity);
377}
378
379static int __init pci_xen_initial_domain(void)
380{
381#ifdef CONFIG_PCI_MSI
382 x86_msi.setup_msi_irqs = xen_initdom_setup_msi_irqs;
383 x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
384#endif
385 xen_setup_acpi_sci();
386 __acpi_register_gsi = acpi_register_gsi_xen;
387
388 return 0;
389}
390
391void __init xen_setup_pirqs(void)
392{
393 int irq;
394
395 pci_xen_initial_domain();
396
397 if (0 == nr_ioapics) {
398 for (irq = 0; irq < NR_IRQS_LEGACY; irq++)
399 xen_allocate_pirq(irq, 0, "xt-pic");
400 return;
401 }
402
403 /* Pre-allocate legacy irqs */
404 for (irq = 0; irq < NR_IRQS_LEGACY; irq++) {
405 int trigger, polarity;
406
407 if (acpi_get_override_irq(irq, &trigger, &polarity) == -1)
408 continue;
409
410 xen_register_pirq(irq,
411 trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE);
412 }
413}
414#endif