x86, msi: Use IRQ remapping specific setup_msi_irqs routine
[cascardo/linux.git] / drivers / iommu / irq_remapping.c
1 #include <linux/cpumask.h>
2 #include <linux/kernel.h>
3 #include <linux/string.h>
4 #include <linux/cpumask.h>
5 #include <linux/errno.h>
6 #include <linux/msi.h>
7 #include <linux/irq.h>
8 #include <linux/pci.h>
9
10 #include <asm/hw_irq.h>
11 #include <asm/irq_remapping.h>
12 #include <asm/processor.h>
13 #include <asm/x86_init.h>
14 #include <asm/apic.h>
15
16 #include "irq_remapping.h"
17
18 int irq_remapping_enabled;
19
20 int disable_irq_remap;
21 int disable_sourceid_checking;
22 int no_x2apic_optout;
23
24 static struct irq_remap_ops *remap_ops;
25
26 static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec);
27 static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
28                                   int index, int sub_handle);
29
30 static void irq_remapping_disable_io_apic(void)
31 {
32         /*
33          * With interrupt-remapping, for now we will use virtual wire A
34          * mode, as virtual wire B is little complex (need to configure
35          * both IOAPIC RTE as well as interrupt-remapping table entry).
36          * As this gets called during crash dump, keep this simple for
37          * now.
38          */
39         if (cpu_has_apic || apic_from_smp_config())
40                 disconnect_bsp_APIC(0);
41 }
42
43 static int do_setup_msi_irqs(struct pci_dev *dev, int nvec)
44 {
45         int node, ret, sub_handle, index = 0;
46         unsigned int irq;
47         struct msi_desc *msidesc;
48
49         nvec = __roundup_pow_of_two(nvec);
50
51         WARN_ON(!list_is_singular(&dev->msi_list));
52         msidesc = list_entry(dev->msi_list.next, struct msi_desc, list);
53         WARN_ON(msidesc->irq);
54         WARN_ON(msidesc->msi_attrib.multiple);
55
56         node = dev_to_node(&dev->dev);
57         irq = __create_irqs(get_nr_irqs_gsi(), nvec, node);
58         if (irq == 0)
59                 return -ENOSPC;
60
61         msidesc->msi_attrib.multiple = ilog2(nvec);
62         for (sub_handle = 0; sub_handle < nvec; sub_handle++) {
63                 if (!sub_handle) {
64                         index = msi_alloc_remapped_irq(dev, irq, nvec);
65                         if (index < 0) {
66                                 ret = index;
67                                 goto error;
68                         }
69                 } else {
70                         ret = msi_setup_remapped_irq(dev, irq + sub_handle,
71                                                      index, sub_handle);
72                         if (ret < 0)
73                                 goto error;
74                 }
75                 ret = setup_msi_irq(dev, msidesc, irq, sub_handle);
76                 if (ret < 0)
77                         goto error;
78         }
79         return 0;
80
81 error:
82         destroy_irqs(irq, nvec);
83
84         /*
85          * Restore altered MSI descriptor fields and prevent just destroyed
86          * IRQs from tearing down again in default_teardown_msi_irqs()
87          */
88         msidesc->irq = 0;
89         msidesc->msi_attrib.multiple = 0;
90
91         return ret;
92 }
93
94 static int do_setup_msix_irqs(struct pci_dev *dev, int nvec)
95 {
96         int node, ret, sub_handle, index = 0;
97         struct msi_desc *msidesc;
98         unsigned int irq;
99
100         node            = dev_to_node(&dev->dev);
101         irq             = get_nr_irqs_gsi();
102         sub_handle      = 0;
103
104         list_for_each_entry(msidesc, &dev->msi_list, list) {
105
106                 irq = create_irq_nr(irq, node);
107                 if (irq == 0)
108                         return -1;
109
110                 if (sub_handle == 0)
111                         ret = index = msi_alloc_remapped_irq(dev, irq, nvec);
112                 else
113                         ret = msi_setup_remapped_irq(dev, irq, index, sub_handle);
114
115                 if (ret < 0)
116                         goto error;
117
118                 ret = setup_msi_irq(dev, msidesc, irq, 0);
119                 if (ret < 0)
120                         goto error;
121
122                 sub_handle += 1;
123                 irq        += 1;
124         }
125
126         return 0;
127
128 error:
129         destroy_irq(irq);
130         return ret;
131 }
132
133 static int irq_remapping_setup_msi_irqs(struct pci_dev *dev,
134                                         int nvec, int type)
135 {
136         if (type == PCI_CAP_ID_MSI)
137                 return do_setup_msi_irqs(dev, nvec);
138         else
139                 return do_setup_msix_irqs(dev, nvec);
140 }
141
142 static void __init irq_remapping_modify_x86_ops(void)
143 {
144         x86_io_apic_ops.disable         = irq_remapping_disable_io_apic;
145         x86_msi.setup_msi_irqs          = irq_remapping_setup_msi_irqs;
146         x86_msi.setup_hpet_msi          = setup_hpet_msi_remapped;
147 }
148
149 static __init int setup_nointremap(char *str)
150 {
151         disable_irq_remap = 1;
152         return 0;
153 }
154 early_param("nointremap", setup_nointremap);
155
156 static __init int setup_irqremap(char *str)
157 {
158         if (!str)
159                 return -EINVAL;
160
161         while (*str) {
162                 if (!strncmp(str, "on", 2))
163                         disable_irq_remap = 0;
164                 else if (!strncmp(str, "off", 3))
165                         disable_irq_remap = 1;
166                 else if (!strncmp(str, "nosid", 5))
167                         disable_sourceid_checking = 1;
168                 else if (!strncmp(str, "no_x2apic_optout", 16))
169                         no_x2apic_optout = 1;
170
171                 str += strcspn(str, ",");
172                 while (*str == ',')
173                         str++;
174         }
175
176         return 0;
177 }
178 early_param("intremap", setup_irqremap);
179
180 void __init setup_irq_remapping_ops(void)
181 {
182         remap_ops = &intel_irq_remap_ops;
183
184 #ifdef CONFIG_AMD_IOMMU
185         if (amd_iommu_irq_ops.prepare() == 0)
186                 remap_ops = &amd_iommu_irq_ops;
187 #endif
188 }
189
190 int irq_remapping_supported(void)
191 {
192         if (disable_irq_remap)
193                 return 0;
194
195         if (!remap_ops || !remap_ops->supported)
196                 return 0;
197
198         return remap_ops->supported();
199 }
200
201 int __init irq_remapping_prepare(void)
202 {
203         if (!remap_ops || !remap_ops->prepare)
204                 return -ENODEV;
205
206         return remap_ops->prepare();
207 }
208
209 int __init irq_remapping_enable(void)
210 {
211         int ret;
212
213         if (!remap_ops || !remap_ops->enable)
214                 return -ENODEV;
215
216         ret = remap_ops->enable();
217
218         if (irq_remapping_enabled)
219                 irq_remapping_modify_x86_ops();
220
221         return ret;
222 }
223
224 void irq_remapping_disable(void)
225 {
226         if (!irq_remapping_enabled ||
227             !remap_ops ||
228             !remap_ops->disable)
229                 return;
230
231         remap_ops->disable();
232 }
233
234 int irq_remapping_reenable(int mode)
235 {
236         if (!irq_remapping_enabled ||
237             !remap_ops ||
238             !remap_ops->reenable)
239                 return 0;
240
241         return remap_ops->reenable(mode);
242 }
243
244 int __init irq_remap_enable_fault_handling(void)
245 {
246         if (!irq_remapping_enabled)
247                 return 0;
248
249         if (!remap_ops || !remap_ops->enable_faulting)
250                 return -ENODEV;
251
252         return remap_ops->enable_faulting();
253 }
254
255 int setup_ioapic_remapped_entry(int irq,
256                                 struct IO_APIC_route_entry *entry,
257                                 unsigned int destination, int vector,
258                                 struct io_apic_irq_attr *attr)
259 {
260         if (!remap_ops || !remap_ops->setup_ioapic_entry)
261                 return -ENODEV;
262
263         return remap_ops->setup_ioapic_entry(irq, entry, destination,
264                                              vector, attr);
265 }
266
267 int set_remapped_irq_affinity(struct irq_data *data, const struct cpumask *mask,
268                               bool force)
269 {
270         if (!config_enabled(CONFIG_SMP) || !remap_ops ||
271             !remap_ops->set_affinity)
272                 return 0;
273
274         return remap_ops->set_affinity(data, mask, force);
275 }
276
277 void free_remapped_irq(int irq)
278 {
279         if (!remap_ops || !remap_ops->free_irq)
280                 return;
281
282         remap_ops->free_irq(irq);
283 }
284
285 void compose_remapped_msi_msg(struct pci_dev *pdev,
286                               unsigned int irq, unsigned int dest,
287                               struct msi_msg *msg, u8 hpet_id)
288 {
289         if (!remap_ops || !remap_ops->compose_msi_msg)
290                 return;
291
292         remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id);
293 }
294
295 static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
296 {
297         if (!remap_ops || !remap_ops->msi_alloc_irq)
298                 return -ENODEV;
299
300         return remap_ops->msi_alloc_irq(pdev, irq, nvec);
301 }
302
303 static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
304                                   int index, int sub_handle)
305 {
306         if (!remap_ops || !remap_ops->msi_setup_irq)
307                 return -ENODEV;
308
309         return remap_ops->msi_setup_irq(pdev, irq, index, sub_handle);
310 }
311
312 int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
313 {
314         if (!remap_ops || !remap_ops->setup_hpet_msi)
315                 return -ENODEV;
316
317         return remap_ops->setup_hpet_msi(irq, id);
318 }