aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/pci_msi.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-10-11 06:16:13 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-14 00:53:13 -0400
commit759f89e03c9e5656ff18c02e21b439506f7c0cdc (patch)
tree6e7703c0672210f2c0a1168de161d15c7470081d /arch/sparc64/kernel/pci_msi.c
parenta2cd15586e630b0870bf34783568d83901890743 (diff)
[SPARC64]: Consolidate MSI support code.
This also makes us use the MSI queues correctly. Each MSI queue is serviced by a normal sun4u/sun4v INO interrupt handler. This handler runs the MSI queue and dispatches the virtual interrupts indicated by arriving MSIs in that MSI queue. All of the common logic is placed in pci_msi.c, with callbacks to handle the PCI controller specific aspects of the operations. This common infrastructure will make it much easier to add MSG support. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/pci_msi.c')
-rw-r--r--arch/sparc64/kernel/pci_msi.c433
1 files changed, 433 insertions, 0 deletions
diff --git a/arch/sparc64/kernel/pci_msi.c b/arch/sparc64/kernel/pci_msi.c
new file mode 100644
index 00000000000..0fa33b1f427
--- /dev/null
+++ b/arch/sparc64/kernel/pci_msi.c
@@ -0,0 +1,433 @@
1/* pci_msi.c: Sparc64 MSI support common layer.
2 *
3 * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
4 */
5#include <linux/kernel.h>
6#include <linux/interrupt.h>
7#include <linux/irq.h>
8
9#include "pci_impl.h"
10
11static irqreturn_t sparc64_msiq_interrupt(int irq, void *cookie)
12{
13 struct sparc64_msiq_cookie *msiq_cookie = cookie;
14 struct pci_pbm_info *pbm = msiq_cookie->pbm;
15 unsigned long msiqid = msiq_cookie->msiqid;
16 const struct sparc64_msiq_ops *ops;
17 unsigned long orig_head, head;
18 int err;
19
20 ops = pbm->msi_ops;
21
22 err = ops->get_head(pbm, msiqid, &head);
23 if (unlikely(err < 0))
24 goto err_get_head;
25
26 orig_head = head;
27 for (;;) {
28 unsigned long msi;
29
30 err = ops->dequeue_msi(pbm, msiqid, &head, &msi);
31 if (likely(err > 0))
32 __do_IRQ(pbm->msi_irq_table[msi - pbm->msi_first]);
33
34 if (unlikely(err < 0))
35 goto err_dequeue;
36
37 if (err == 0)
38 break;
39 }
40 if (likely(head != orig_head)) {
41 err = ops->set_head(pbm, msiqid, head);
42 if (unlikely(err < 0))
43 goto err_set_head;
44 }
45 return IRQ_HANDLED;
46
47err_get_head:
48 printk(KERN_EMERG "MSI: Get head on msiqid[%lu] gives error %d\n",
49 msiqid, err);
50 goto err_out;
51
52err_dequeue:
53 printk(KERN_EMERG "MSI: Dequeue head[%lu] from msiqid[%lu] "
54 "gives error %d\n",
55 head, msiqid, err);
56 goto err_out;
57
58err_set_head:
59 printk(KERN_EMERG "MSI: Set head[%lu] on msiqid[%lu] "
60 "gives error %d\n",
61 head, msiqid, err);
62 goto err_out;
63
64err_out:
65 return IRQ_NONE;
66}
67
68static u32 pick_msiq(struct pci_pbm_info *pbm)
69{
70 static DEFINE_SPINLOCK(rotor_lock);
71 unsigned long flags;
72 u32 ret, rotor;
73
74 spin_lock_irqsave(&rotor_lock, flags);
75
76 rotor = pbm->msiq_rotor;
77 ret = pbm->msiq_first + rotor;
78
79 if (++rotor >= pbm->msiq_num)
80 rotor = 0;
81 pbm->msiq_rotor = rotor;
82
83 spin_unlock_irqrestore(&rotor_lock, flags);
84
85 return ret;
86}
87
88
89static int alloc_msi(struct pci_pbm_info *pbm)
90{
91 int i;
92
93 for (i = 0; i < pbm->msi_num; i++) {
94 if (!test_and_set_bit(i, pbm->msi_bitmap))
95 return i + pbm->msi_first;
96 }
97
98 return -ENOENT;
99}
100
101static void free_msi(struct pci_pbm_info *pbm, int msi_num)
102{
103 msi_num -= pbm->msi_first;
104 clear_bit(msi_num, pbm->msi_bitmap);
105}
106
107static struct irq_chip msi_irq = {
108 .typename = "PCI-MSI",
109 .mask = mask_msi_irq,
110 .unmask = unmask_msi_irq,
111 .enable = unmask_msi_irq,
112 .disable = mask_msi_irq,
113 /* XXX affinity XXX */
114};
115
116int sparc64_setup_msi_irq(unsigned int *virt_irq_p,
117 struct pci_dev *pdev,
118 struct msi_desc *entry)
119{
120 struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
121 const struct sparc64_msiq_ops *ops = pbm->msi_ops;
122 struct msi_msg msg;
123 int msi, err;
124 u32 msiqid;
125
126 *virt_irq_p = virt_irq_alloc(~0);
127 err = -ENOMEM;
128 if (!*virt_irq_p)
129 goto out_err;
130
131 set_irq_chip(*virt_irq_p, &msi_irq);
132
133 err = alloc_msi(pbm);
134 if (unlikely(err < 0))
135 goto out_virt_irq_free;
136
137 msi = err;
138
139 msiqid = pick_msiq(pbm);
140
141 err = ops->msi_setup(pbm, msiqid, msi,
142 (entry->msi_attrib.is_64 ? 1 : 0));
143 if (err)
144 goto out_msi_free;
145
146 pbm->msi_irq_table[msi - pbm->msi_first] = *virt_irq_p;
147
148 if (entry->msi_attrib.is_64) {
149 msg.address_hi = pbm->msi64_start >> 32;
150 msg.address_lo = pbm->msi64_start & 0xffffffff;
151 } else {
152 msg.address_hi = 0;
153 msg.address_lo = pbm->msi32_start;
154 }
155 msg.data = msi;
156
157 set_irq_msi(*virt_irq_p, entry);
158 write_msi_msg(*virt_irq_p, &msg);
159
160 return 0;
161
162out_msi_free:
163 free_msi(pbm, msi);
164
165out_virt_irq_free:
166 set_irq_chip(*virt_irq_p, NULL);
167 virt_irq_free(*virt_irq_p);
168 *virt_irq_p = 0;
169
170out_err:
171 return err;
172}
173
174void sparc64_teardown_msi_irq(unsigned int virt_irq,
175 struct pci_dev *pdev)
176{
177 struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
178 const struct sparc64_msiq_ops *ops = pbm->msi_ops;
179 unsigned int msi_num;
180 int i, err;
181
182 for (i = 0; i < pbm->msi_num; i++) {
183 if (pbm->msi_irq_table[i] == virt_irq)
184 break;
185 }
186 if (i >= pbm->msi_num) {
187 printk(KERN_ERR "%s: teardown: No MSI for irq %u\n",
188 pbm->name, virt_irq);
189 return;
190 }
191
192 msi_num = pbm->msi_first + i;
193 pbm->msi_irq_table[i] = ~0U;
194
195 err = ops->msi_teardown(pbm, msi_num);
196 if (err) {
197 printk(KERN_ERR "%s: teardown: ops->teardown() on MSI %u, "
198 "irq %u, gives error %d\n",
199 pbm->name, msi_num, virt_irq, err);
200 return;
201 }
202
203 free_msi(pbm, msi_num);
204
205 set_irq_chip(virt_irq, NULL);
206 virt_irq_free(virt_irq);
207}
208
209static int msi_bitmap_alloc(struct pci_pbm_info *pbm)
210{
211 unsigned long size, bits_per_ulong;
212
213 bits_per_ulong = sizeof(unsigned long) * 8;
214 size = (pbm->msi_num + (bits_per_ulong - 1)) & ~(bits_per_ulong - 1);
215 size /= 8;
216 BUG_ON(size % sizeof(unsigned long));
217
218 pbm->msi_bitmap = kzalloc(size, GFP_KERNEL);
219 if (!pbm->msi_bitmap)
220 return -ENOMEM;
221
222 return 0;
223}
224
225static void msi_bitmap_free(struct pci_pbm_info *pbm)
226{
227 kfree(pbm->msi_bitmap);
228 pbm->msi_bitmap = NULL;
229}
230
231static int msi_table_alloc(struct pci_pbm_info *pbm)
232{
233 int size, i;
234
235 size = pbm->msiq_num * sizeof(struct sparc64_msiq_cookie);
236 pbm->msiq_irq_cookies = kzalloc(size, GFP_KERNEL);
237 if (!pbm->msiq_irq_cookies)
238 return -ENOMEM;
239
240 for (i = 0; i < pbm->msiq_num; i++) {
241 struct sparc64_msiq_cookie *p;
242
243 p = &pbm->msiq_irq_cookies[i];
244 p->pbm = pbm;
245 p->msiqid = pbm->msiq_first + i;
246 }
247
248 size = pbm->msi_num * sizeof(unsigned int);
249 pbm->msi_irq_table = kzalloc(size, GFP_KERNEL);
250 if (!pbm->msi_irq_table) {
251 kfree(pbm->msiq_irq_cookies);
252 pbm->msiq_irq_cookies = NULL;
253 return -ENOMEM;
254 }
255
256 return 0;
257}
258
259static void msi_table_free(struct pci_pbm_info *pbm)
260{
261 kfree(pbm->msiq_irq_cookies);
262 pbm->msiq_irq_cookies = NULL;
263
264 kfree(pbm->msi_irq_table);
265 pbm->msi_irq_table = NULL;
266}
267
268static int bringup_one_msi_queue(struct pci_pbm_info *pbm,
269 const struct sparc64_msiq_ops *ops,
270 unsigned long msiqid,
271 unsigned long devino)
272{
273 int irq = ops->msiq_build_irq(pbm, msiqid, devino);
274 int err;
275
276 if (irq < 0)
277 return irq;
278
279 err = request_irq(irq, sparc64_msiq_interrupt, 0,
280 "MSIQ",
281 &pbm->msiq_irq_cookies[msiqid - pbm->msiq_first]);
282 if (err)
283 return err;
284
285 return 0;
286}
287
288static int sparc64_bringup_msi_queues(struct pci_pbm_info *pbm,
289 const struct sparc64_msiq_ops *ops)
290{
291 int i;
292
293 for (i = 0; i < pbm->msiq_num; i++) {
294 unsigned long msiqid = i + pbm->msiq_first;
295 unsigned long devino = i + pbm->msiq_first_devino;
296 int err;
297
298 err = bringup_one_msi_queue(pbm, ops, msiqid, devino);
299 if (err)
300 return err;
301 }
302
303 return 0;
304}
305
306void sparc64_pbm_msi_init(struct pci_pbm_info *pbm,
307 const struct sparc64_msiq_ops *ops)
308{
309 const u32 *val;
310 int len;
311
312 val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
313 if (!val || len != 4)
314 goto no_msi;
315 pbm->msiq_num = *val;
316 if (pbm->msiq_num) {
317 const struct msiq_prop {
318 u32 first_msiq;
319 u32 num_msiq;
320 u32 first_devino;
321 } *mqp;
322 const struct msi_range_prop {
323 u32 first_msi;
324 u32 num_msi;
325 } *mrng;
326 const struct addr_range_prop {
327 u32 msi32_high;
328 u32 msi32_low;
329 u32 msi32_len;
330 u32 msi64_high;
331 u32 msi64_low;
332 u32 msi64_len;
333 } *arng;
334
335 val = of_get_property(pbm->prom_node, "msi-eq-size", &len);
336 if (!val || len != 4)
337 goto no_msi;
338
339 pbm->msiq_ent_count = *val;
340
341 mqp = of_get_property(pbm->prom_node,
342 "msi-eq-to-devino", &len);
343 if (!mqp)
344 mqp = of_get_property(pbm->prom_node,
345 "msi-eq-devino", &len);
346 if (!mqp || len != sizeof(struct msiq_prop))
347 goto no_msi;
348
349 pbm->msiq_first = mqp->first_msiq;
350 pbm->msiq_first_devino = mqp->first_devino;
351
352 val = of_get_property(pbm->prom_node, "#msi", &len);
353 if (!val || len != 4)
354 goto no_msi;
355 pbm->msi_num = *val;
356
357 mrng = of_get_property(pbm->prom_node, "msi-ranges", &len);
358 if (!mrng || len != sizeof(struct msi_range_prop))
359 goto no_msi;
360 pbm->msi_first = mrng->first_msi;
361
362 val = of_get_property(pbm->prom_node, "msi-data-mask", &len);
363 if (!val || len != 4)
364 goto no_msi;
365 pbm->msi_data_mask = *val;
366
367 val = of_get_property(pbm->prom_node, "msix-data-width", &len);
368 if (!val || len != 4)
369 goto no_msi;
370 pbm->msix_data_width = *val;
371
372 arng = of_get_property(pbm->prom_node, "msi-address-ranges",
373 &len);
374 if (!arng || len != sizeof(struct addr_range_prop))
375 goto no_msi;
376 pbm->msi32_start = ((u64)arng->msi32_high << 32) |
377 (u64) arng->msi32_low;
378 pbm->msi64_start = ((u64)arng->msi64_high << 32) |
379 (u64) arng->msi64_low;
380 pbm->msi32_len = arng->msi32_len;
381 pbm->msi64_len = arng->msi64_len;
382
383 if (msi_bitmap_alloc(pbm))
384 goto no_msi;
385
386 if (msi_table_alloc(pbm)) {
387 msi_bitmap_free(pbm);
388 goto no_msi;
389 }
390
391 if (ops->msiq_alloc(pbm)) {
392 msi_table_free(pbm);
393 msi_bitmap_free(pbm);
394 goto no_msi;
395 }
396
397 if (sparc64_bringup_msi_queues(pbm, ops)) {
398 ops->msiq_free(pbm);
399 msi_table_free(pbm);
400 msi_bitmap_free(pbm);
401 goto no_msi;
402 }
403
404 printk(KERN_INFO "%s: MSI Queue first[%u] num[%u] count[%u] "
405 "devino[0x%x]\n",
406 pbm->name,
407 pbm->msiq_first, pbm->msiq_num,
408 pbm->msiq_ent_count,
409 pbm->msiq_first_devino);
410 printk(KERN_INFO "%s: MSI first[%u] num[%u] mask[0x%x] "
411 "width[%u]\n",
412 pbm->name,
413 pbm->msi_first, pbm->msi_num, pbm->msi_data_mask,
414 pbm->msix_data_width);
415 printk(KERN_INFO "%s: MSI addr32[0x%lx:0x%x] "
416 "addr64[0x%lx:0x%x]\n",
417 pbm->name,
418 pbm->msi32_start, pbm->msi32_len,
419 pbm->msi64_start, pbm->msi64_len);
420 printk(KERN_INFO "%s: MSI queues at RA [%016lx]\n",
421 pbm->name,
422 __pa(pbm->msi_queues));
423
424 pbm->msi_ops = ops;
425 pbm->setup_msi_irq = sparc64_setup_msi_irq;
426 pbm->teardown_msi_irq = sparc64_teardown_msi_irq;
427 }
428 return;
429
430no_msi:
431 pbm->msiq_num = 0;
432 printk(KERN_INFO "%s: No MSI support.\n", pbm->name);
433}