blob: 08e3cdccdfa840fa959756564e2595316865ac5e [file] [log] [blame]
Alex Nixonb5401a92010-03-18 16:31:34 -04001/*
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/pci_x86.h>
14
15#include <asm/xen/hypervisor.h>
16
17#include <xen/events.h>
18#include <asm/xen/pci.h>
19
Stefano Stabellini42a1de52010-06-24 16:42:04 +010020#ifdef CONFIG_ACPI
21static int xen_hvm_register_pirq(u32 gsi, int triggering)
22{
23 int rc, irq;
24 struct physdev_map_pirq map_irq;
25 int shareable = 0;
26 char *name;
27
28 if (!xen_hvm_domain())
29 return -1;
30
31 map_irq.domid = DOMID_SELF;
32 map_irq.type = MAP_PIRQ_TYPE_GSI;
33 map_irq.index = gsi;
34 map_irq.pirq = -1;
35
36 rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
37 if (rc) {
38 printk(KERN_WARNING "xen map irq failed %d\n", rc);
39 return -1;
40 }
41
42 if (triggering == ACPI_EDGE_SENSITIVE) {
43 shareable = 0;
44 name = "ioapic-edge";
45 } else {
46 shareable = 1;
47 name = "ioapic-level";
48 }
49
50 irq = xen_map_pirq_gsi(map_irq.pirq, gsi, shareable, name);
51
52 printk(KERN_DEBUG "xen: --> irq=%d, pirq=%d\n", irq, map_irq.pirq);
53
54 return irq;
55}
56#endif
57
Alex Nixonb5401a92010-03-18 16:31:34 -040058#if defined(CONFIG_PCI_MSI)
59#include <linux/msi.h>
60
61struct xen_pci_frontend_ops *xen_pci_frontend;
62EXPORT_SYMBOL_GPL(xen_pci_frontend);
63
64/*
65 * For MSI interrupts we have to use drivers/xen/event.s functions to
66 * allocate an irq_desc and setup the right */
67
68
69static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
70{
71 int irq, ret, i;
72 struct msi_desc *msidesc;
73 int *v;
74
75 v = kzalloc(sizeof(int) * max(1, nvec), GFP_KERNEL);
76 if (!v)
77 return -ENOMEM;
78
79 if (!xen_initial_domain()) {
80 if (type == PCI_CAP_ID_MSIX)
81 ret = xen_pci_frontend_enable_msix(dev, &v, nvec);
82 else
83 ret = xen_pci_frontend_enable_msi(dev, &v);
84 if (ret)
85 goto error;
86 }
87 i = 0;
88 list_for_each_entry(msidesc, &dev->msi_list, list) {
89 irq = xen_allocate_pirq(v[i], 0, /* not sharable */
90 (type == PCI_CAP_ID_MSIX) ?
91 "pcifront-msi-x" : "pcifront-msi");
92 if (irq < 0)
93 return -1;
94
95 ret = set_irq_msi(irq, msidesc);
96 if (ret)
97 goto error_while;
98 i++;
99 }
100 kfree(v);
101 return 0;
102
103error_while:
104 unbind_from_irqhandler(irq, NULL);
105error:
106 if (ret == -ENODEV)
107 dev_err(&dev->dev, "Xen PCI frontend has not registered" \
108 " MSI/MSI-X support!\n");
109
110 kfree(v);
111 return ret;
112}
113
114static void xen_teardown_msi_irqs(struct pci_dev *dev)
115{
116 /* Only do this when were are in non-privileged mode.*/
117 if (!xen_initial_domain()) {
118 struct msi_desc *msidesc;
119
120 msidesc = list_entry(dev->msi_list.next, struct msi_desc, list);
121 if (msidesc->msi_attrib.is_msix)
122 xen_pci_frontend_disable_msix(dev);
123 else
124 xen_pci_frontend_disable_msi(dev);
125 }
126
127}
128
129static void xen_teardown_msi_irq(unsigned int irq)
130{
131 xen_destroy_irq(irq);
132}
133#endif
134
135static int xen_pcifront_enable_irq(struct pci_dev *dev)
136{
137 int rc;
138 int share = 1;
139
140 dev_info(&dev->dev, "Xen PCI enabling IRQ: %d\n", dev->irq);
141
142 if (dev->irq < 0)
143 return -EINVAL;
144
145 if (dev->irq < NR_IRQS_LEGACY)
146 share = 0;
147
148 rc = xen_allocate_pirq(dev->irq, share, "pcifront");
149 if (rc < 0) {
150 dev_warn(&dev->dev, "Xen PCI IRQ: %d, failed to register:%d\n",
151 dev->irq, rc);
152 return rc;
153 }
154 return 0;
155}
156
157int __init pci_xen_init(void)
158{
159 if (!xen_pv_domain() || xen_initial_domain())
160 return -ENODEV;
161
162 printk(KERN_INFO "PCI: setting up Xen PCI frontend stub\n");
163
164 pcibios_set_cache_line_size();
165
166 pcibios_enable_irq = xen_pcifront_enable_irq;
167 pcibios_disable_irq = NULL;
168
169#ifdef CONFIG_ACPI
170 /* Keep ACPI out of the picture */
171 acpi_noirq = 1;
172#endif
173
Alex Nixonb5401a92010-03-18 16:31:34 -0400174#ifdef CONFIG_PCI_MSI
175 x86_msi.setup_msi_irqs = xen_setup_msi_irqs;
176 x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
177 x86_msi.teardown_msi_irqs = xen_teardown_msi_irqs;
178#endif
179 return 0;
180}