Merge branch 'core/softlockup-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / arch / powerpc / sysdev / fsl_msi.c
1 /*
2  * Copyright (C) 2007-2008 Freescale Semiconductor, Inc. All rights reserved.
3  *
4  * Author: Tony Li <tony.li@freescale.com>
5  *         Jason Jin <Jason.jin@freescale.com>
6  *
7  * The hwirq alloc and free code reuse from sysdev/mpic_msi.c
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; version 2 of the
12  * License.
13  *
14  */
15 #include <linux/irq.h>
16 #include <linux/bootmem.h>
17 #include <linux/bitmap.h>
18 #include <linux/msi.h>
19 #include <linux/pci.h>
20 #include <linux/of_platform.h>
21 #include <sysdev/fsl_soc.h>
22 #include <asm/prom.h>
23 #include <asm/hw_irq.h>
24 #include <asm/ppc-pci.h>
25 #include "fsl_msi.h"
26
27 struct fsl_msi_feature {
28         u32 fsl_pic_ip;
29         u32 msiir_offset;
30 };
31
32 static struct fsl_msi *fsl_msi;
33
34 static inline u32 fsl_msi_read(u32 __iomem *base, unsigned int reg)
35 {
36         return in_be32(base + (reg >> 2));
37 }
38
39 /*
40  * We do not need this actually. The MSIR register has been read once
41  * in the cascade interrupt. So, this MSI interrupt has been acked
42 */
43 static void fsl_msi_end_irq(unsigned int virq)
44 {
45 }
46
47 static struct irq_chip fsl_msi_chip = {
48         .mask           = mask_msi_irq,
49         .unmask         = unmask_msi_irq,
50         .ack            = fsl_msi_end_irq,
51         .typename       = " FSL-MSI  ",
52 };
53
54 static int fsl_msi_host_map(struct irq_host *h, unsigned int virq,
55                                 irq_hw_number_t hw)
56 {
57         struct irq_chip *chip = &fsl_msi_chip;
58
59         get_irq_desc(virq)->status |= IRQ_TYPE_EDGE_FALLING;
60
61         set_irq_chip_and_handler(virq, chip, handle_edge_irq);
62
63         return 0;
64 }
65
66 static struct irq_host_ops fsl_msi_host_ops = {
67         .map = fsl_msi_host_map,
68 };
69
70 static irq_hw_number_t fsl_msi_alloc_hwirqs(struct fsl_msi *msi, int num)
71 {
72         unsigned long flags;
73         int order = get_count_order(num);
74         int offset;
75
76         spin_lock_irqsave(&msi->bitmap_lock, flags);
77
78         offset = bitmap_find_free_region(msi->fsl_msi_bitmap,
79                                         NR_MSI_IRQS, order);
80
81         spin_unlock_irqrestore(&msi->bitmap_lock, flags);
82
83         pr_debug("%s: allocated 0x%x (2^%d) at offset 0x%x\n",
84                 __func__, num, order, offset);
85
86         return offset;
87 }
88
89 static void fsl_msi_free_hwirqs(struct fsl_msi *msi, int offset, int num)
90 {
91         unsigned long flags;
92         int order = get_count_order(num);
93
94         pr_debug("%s: freeing 0x%x (2^%d) at offset 0x%x\n",
95                 __func__, num, order, offset);
96
97         spin_lock_irqsave(&msi->bitmap_lock, flags);
98         bitmap_release_region(msi->fsl_msi_bitmap, offset, order);
99         spin_unlock_irqrestore(&msi->bitmap_lock, flags);
100 }
101
102 static int fsl_msi_free_dt_hwirqs(struct fsl_msi *msi)
103 {
104         int i;
105         int len;
106         const u32 *p;
107
108         bitmap_allocate_region(msi->fsl_msi_bitmap, 0,
109                        get_count_order(NR_MSI_IRQS));
110
111         p = of_get_property(msi->of_node, "msi-available-ranges", &len);
112
113         if (!p) {
114                 /* No msi-available-ranges property,
115                  * All the 256 MSI interrupts can be used
116                  */
117                 fsl_msi_free_hwirqs(msi, 0, 0x100);
118                 return 0;
119         }
120
121         if ((len % (2 * sizeof(u32))) != 0) {
122                 printk(KERN_WARNING "fsl_msi: Malformed msi-available-ranges "
123                        "property on %s\n", msi->of_node->full_name);
124                 return -EINVAL;
125         }
126
127         /* Format is: (<u32 start> <u32 count>)+ */
128         len /= 2 * sizeof(u32);
129         for (i = 0; i < len; i++, p += 2)
130                 fsl_msi_free_hwirqs(msi, *p, *(p + 1));
131
132         return 0;
133 }
134
135 static int fsl_msi_init_allocator(struct fsl_msi *msi_data)
136 {
137         int rc;
138         int size = BITS_TO_LONGS(NR_MSI_IRQS) * sizeof(u32);
139
140         msi_data->fsl_msi_bitmap = kzalloc(size, GFP_KERNEL);
141
142         if (msi_data->fsl_msi_bitmap == NULL) {
143                 pr_debug("%s: ENOMEM allocating allocator bitmap!\n",
144                                 __func__);
145                 return -ENOMEM;
146         }
147
148         rc = fsl_msi_free_dt_hwirqs(msi_data);
149         if (rc)
150                 goto out_free;
151
152         return 0;
153 out_free:
154         kfree(msi_data->fsl_msi_bitmap);
155
156         msi_data->fsl_msi_bitmap = NULL;
157         return rc;
158
159 }
160
161 static int fsl_msi_check_device(struct pci_dev *pdev, int nvec, int type)
162 {
163         if (type == PCI_CAP_ID_MSIX)
164                 pr_debug("fslmsi: MSI-X untested, trying anyway.\n");
165
166         return 0;
167 }
168
169 static void fsl_teardown_msi_irqs(struct pci_dev *pdev)
170 {
171         struct msi_desc *entry;
172         struct fsl_msi *msi_data = fsl_msi;
173
174         list_for_each_entry(entry, &pdev->msi_list, list) {
175                 if (entry->irq == NO_IRQ)
176                         continue;
177                 set_irq_msi(entry->irq, NULL);
178                 fsl_msi_free_hwirqs(msi_data, virq_to_hw(entry->irq), 1);
179                 irq_dispose_mapping(entry->irq);
180         }
181
182         return;
183 }
184
185 static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq,
186                                   struct msi_msg *msg)
187 {
188         struct fsl_msi *msi_data = fsl_msi;
189
190         msg->address_lo = msi_data->msi_addr_lo;
191         msg->address_hi = msi_data->msi_addr_hi;
192         msg->data = hwirq;
193
194         pr_debug("%s: allocated srs: %d, ibs: %d\n",
195                 __func__, hwirq / IRQS_PER_MSI_REG, hwirq % IRQS_PER_MSI_REG);
196 }
197
198 static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
199 {
200         irq_hw_number_t hwirq;
201         int rc;
202         unsigned int virq;
203         struct msi_desc *entry;
204         struct msi_msg msg;
205         struct fsl_msi *msi_data = fsl_msi;
206
207         list_for_each_entry(entry, &pdev->msi_list, list) {
208                 hwirq = fsl_msi_alloc_hwirqs(msi_data, 1);
209                 if (hwirq < 0) {
210                         rc = hwirq;
211                         pr_debug("%s: fail allocating msi interrupt\n",
212                                         __func__);
213                         goto out_free;
214                 }
215
216                 virq = irq_create_mapping(msi_data->irqhost, hwirq);
217
218                 if (virq == NO_IRQ) {
219                         pr_debug("%s: fail mapping hwirq 0x%lx\n",
220                                         __func__, hwirq);
221                         fsl_msi_free_hwirqs(msi_data, hwirq, 1);
222                         rc = -ENOSPC;
223                         goto out_free;
224                 }
225                 set_irq_msi(virq, entry);
226
227                 fsl_compose_msi_msg(pdev, hwirq, &msg);
228                 write_msi_msg(virq, &msg);
229         }
230         return 0;
231
232 out_free:
233         return rc;
234 }
235
236 static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
237 {
238         unsigned int cascade_irq;
239         struct fsl_msi *msi_data = fsl_msi;
240         int msir_index = -1;
241         u32 msir_value = 0;
242         u32 intr_index;
243         u32 have_shift = 0;
244
245         spin_lock(&desc->lock);
246         if ((msi_data->feature &  FSL_PIC_IP_MASK) == FSL_PIC_IP_IPIC) {
247                 if (desc->chip->mask_ack)
248                         desc->chip->mask_ack(irq);
249                 else {
250                         desc->chip->mask(irq);
251                         desc->chip->ack(irq);
252                 }
253         }
254
255         if (unlikely(desc->status & IRQ_INPROGRESS))
256                 goto unlock;
257
258         msir_index = (int)desc->handler_data;
259
260         if (msir_index >= NR_MSI_REG)
261                 cascade_irq = NO_IRQ;
262
263         desc->status |= IRQ_INPROGRESS;
264         switch (fsl_msi->feature & FSL_PIC_IP_MASK) {
265         case FSL_PIC_IP_MPIC:
266                 msir_value = fsl_msi_read(msi_data->msi_regs,
267                         msir_index * 0x10);
268                 break;
269         case FSL_PIC_IP_IPIC:
270                 msir_value = fsl_msi_read(msi_data->msi_regs, msir_index * 0x4);
271                 break;
272         }
273
274         while (msir_value) {
275                 intr_index = ffs(msir_value) - 1;
276
277                 cascade_irq = irq_linear_revmap(msi_data->irqhost,
278                                 msir_index * IRQS_PER_MSI_REG +
279                                         intr_index + have_shift);
280                 if (cascade_irq != NO_IRQ)
281                         generic_handle_irq(cascade_irq);
282                 have_shift += intr_index + 1;
283                 msir_value = msir_value >> (intr_index + 1);
284         }
285         desc->status &= ~IRQ_INPROGRESS;
286
287         switch (msi_data->feature & FSL_PIC_IP_MASK) {
288         case FSL_PIC_IP_MPIC:
289                 desc->chip->eoi(irq);
290                 break;
291         case FSL_PIC_IP_IPIC:
292                 if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
293                         desc->chip->unmask(irq);
294                 break;
295         }
296 unlock:
297         spin_unlock(&desc->lock);
298 }
299
300 static int __devinit fsl_of_msi_probe(struct of_device *dev,
301                                 const struct of_device_id *match)
302 {
303         struct fsl_msi *msi;
304         struct resource res;
305         int err, i, count;
306         int rc;
307         int virt_msir;
308         const u32 *p;
309         struct fsl_msi_feature *features = match->data;
310
311         printk(KERN_DEBUG "Setting up Freescale MSI support\n");
312
313         msi = kzalloc(sizeof(struct fsl_msi), GFP_KERNEL);
314         if (!msi) {
315                 dev_err(&dev->dev, "No memory for MSI structure\n");
316                 err = -ENOMEM;
317                 goto error_out;
318         }
319
320         msi->of_node = of_node_get(dev->node);
321
322         msi->irqhost = irq_alloc_host(of_node_get(dev->node),
323                                 IRQ_HOST_MAP_LINEAR,
324                                 NR_MSI_IRQS, &fsl_msi_host_ops, 0);
325         if (msi->irqhost == NULL) {
326                 dev_err(&dev->dev, "No memory for MSI irqhost\n");
327                 of_node_put(dev->node);
328                 err = -ENOMEM;
329                 goto error_out;
330         }
331
332         /* Get the MSI reg base */
333         err = of_address_to_resource(dev->node, 0, &res);
334         if (err) {
335                 dev_err(&dev->dev, "%s resource error!\n",
336                                 dev->node->full_name);
337                 goto error_out;
338         }
339
340         msi->msi_regs = ioremap(res.start, res.end - res.start + 1);
341         if (!msi->msi_regs) {
342                 dev_err(&dev->dev, "ioremap problem failed\n");
343                 goto error_out;
344         }
345
346         msi->feature = features->fsl_pic_ip;
347
348         msi->irqhost->host_data = msi;
349
350         msi->msi_addr_hi = 0x0;
351         msi->msi_addr_lo = res.start + features->msiir_offset;
352
353         rc = fsl_msi_init_allocator(msi);
354         if (rc) {
355                 dev_err(&dev->dev, "Error allocating MSI bitmap\n");
356                 goto error_out;
357         }
358
359         p = of_get_property(dev->node, "interrupts", &count);
360         if (!p) {
361                 dev_err(&dev->dev, "no interrupts property found on %s\n",
362                                 dev->node->full_name);
363                 err = -ENODEV;
364                 goto error_out;
365         }
366         if (count % 8 != 0) {
367                 dev_err(&dev->dev, "Malformed interrupts property on %s\n",
368                                 dev->node->full_name);
369                 err = -EINVAL;
370                 goto error_out;
371         }
372
373         count /= sizeof(u32);
374         for (i = 0; i < count / 2; i++) {
375                 if (i > NR_MSI_REG)
376                         break;
377                 virt_msir = irq_of_parse_and_map(dev->node, i);
378                 if (virt_msir != NO_IRQ) {
379                         set_irq_data(virt_msir, (void *)i);
380                         set_irq_chained_handler(virt_msir, fsl_msi_cascade);
381                 }
382         }
383
384         fsl_msi = msi;
385
386         WARN_ON(ppc_md.setup_msi_irqs);
387         ppc_md.setup_msi_irqs = fsl_setup_msi_irqs;
388         ppc_md.teardown_msi_irqs = fsl_teardown_msi_irqs;
389         ppc_md.msi_check_device = fsl_msi_check_device;
390         return 0;
391 error_out:
392         kfree(msi);
393         return err;
394 }
395
396 static const struct fsl_msi_feature mpic_msi_feature = {
397         .fsl_pic_ip = FSL_PIC_IP_MPIC,
398         .msiir_offset = 0x140,
399 };
400
401 static const struct fsl_msi_feature ipic_msi_feature = {
402         .fsl_pic_ip = FSL_PIC_IP_IPIC,
403         .msiir_offset = 0x38,
404 };
405
406 static const struct of_device_id fsl_of_msi_ids[] = {
407         {
408                 .compatible = "fsl,mpic-msi",
409                 .data = (void *)&mpic_msi_feature,
410         },
411         {
412                 .compatible = "fsl,ipic-msi",
413                 .data = (void *)&ipic_msi_feature,
414         },
415         {}
416 };
417
418 static struct of_platform_driver fsl_of_msi_driver = {
419         .name = "fsl-msi",
420         .match_table = fsl_of_msi_ids,
421         .probe = fsl_of_msi_probe,
422 };
423
424 static __init int fsl_of_msi_init(void)
425 {
426         return of_register_platform_driver(&fsl_of_msi_driver);
427 }
428
429 subsys_initcall(fsl_of_msi_init);