include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / arch / powerpc / platforms / cell / axon_msi.c
index 8b055bc..8efe481 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/msi.h>
 #include <linux/of_platform.h>
 #include <linux/debugfs.h>
+#include <linux/slab.h>
 
 #include <asm/dcr.h>
 #include <asm/machdep.h>
@@ -85,7 +86,7 @@ static inline void axon_msi_debug_setup(struct device_node *dn,
 
 static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val)
 {
-       pr_debug("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n);
+       pr_devel("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n);
 
        dcr_write(msic->dcr_host, dcr_n, val);
 }
@@ -95,28 +96,53 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
        struct axon_msic *msic = get_irq_data(irq);
        u32 write_offset, msi;
        int idx;
+       int retry = 0;
 
        write_offset = dcr_read(msic->dcr_host, MSIC_WRITE_OFFSET_REG);
-       pr_debug("axon_msi: original write_offset 0x%x\n", write_offset);
+       pr_devel("axon_msi: original write_offset 0x%x\n", write_offset);
 
        /* write_offset doesn't wrap properly, so we have to mask it */
        write_offset &= MSIC_FIFO_SIZE_MASK;
 
-       while (msic->read_offset != write_offset) {
+       while (msic->read_offset != write_offset && retry < 100) {
                idx  = msic->read_offset / sizeof(__le32);
                msi  = le32_to_cpu(msic->fifo_virt[idx]);
                msi &= 0xFFFF;
 
-               pr_debug("axon_msi: woff %x roff %x msi %x\n",
+               pr_devel("axon_msi: woff %x roff %x msi %x\n",
                          write_offset, msic->read_offset, msi);
 
+               if (msi < NR_IRQS && irq_map[msi].host == msic->irq_host) {
+                       generic_handle_irq(msi);
+                       msic->fifo_virt[idx] = cpu_to_le32(0xffffffff);
+               } else {
+                       /*
+                        * Reading the MSIC_WRITE_OFFSET_REG does not
+                        * reliably flush the outstanding DMA to the
+                        * FIFO buffer. Here we were reading stale
+                        * data, so we need to retry.
+                        */
+                       udelay(1);
+                       retry++;
+                       pr_devel("axon_msi: invalid irq 0x%x!\n", msi);
+                       continue;
+               }
+
+               if (retry) {
+                       pr_devel("axon_msi: late irq 0x%x, retry %d\n",
+                                msi, retry);
+                       retry = 0;
+               }
+
                msic->read_offset += MSIC_FIFO_ENTRY_SIZE;
                msic->read_offset &= MSIC_FIFO_SIZE_MASK;
+       }
 
-               if (msi < NR_IRQS && irq_map[msi].host == msic->irq_host)
-                       generic_handle_irq(msi);
-               else
-                       pr_debug("axon_msi: invalid irq 0x%x!\n", msi);
+       if (retry) {
+               printk(KERN_WARNING "axon_msi: irq timed out\n");
+
+               msic->read_offset += MSIC_FIFO_ENTRY_SIZE;
+               msic->read_offset &= MSIC_FIFO_SIZE_MASK;
        }
 
        desc->chip->eoi(irq);
@@ -287,7 +313,7 @@ static struct irq_chip msic_irq_chip = {
        .mask           = mask_msi_irq,
        .unmask         = unmask_msi_irq,
        .shutdown       = unmask_msi_irq,
-       .typename       = "AXON-MSI",
+       .name           = "AXON-MSI",
 };
 
 static int msic_host_map(struct irq_host *h, unsigned int virq,
@@ -304,10 +330,10 @@ static struct irq_host_ops msic_host_ops = {
 
 static int axon_msi_shutdown(struct of_device *device)
 {
-       struct axon_msic *msic = device->dev.platform_data;
+       struct axon_msic *msic = dev_get_drvdata(&device->dev);
        u32 tmp;
 
-       pr_debug("axon_msi: disabling %s\n",
+       pr_devel("axon_msi: disabling %s\n",
                  msic->irq_host->of_node->full_name);
        tmp  = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
        tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
@@ -324,7 +350,7 @@ static int axon_msi_probe(struct of_device *device,
        unsigned int virq;
        int dcr_base, dcr_len;
 
-       pr_debug("axon_msi: setting up dn %s\n", dn->full_name);
+       pr_devel("axon_msi: setting up dn %s\n", dn->full_name);
 
        msic = kzalloc(sizeof(struct axon_msic), GFP_KERNEL);
        if (!msic) {
@@ -340,7 +366,7 @@ static int axon_msi_probe(struct of_device *device,
                printk(KERN_ERR
                       "axon_msi: couldn't parse dcr properties on %s\n",
                        dn->full_name);
-               goto out;
+               goto out_free_msic;
        }
 
        msic->dcr_host = dcr_map(dn, dcr_base, dcr_len);
@@ -358,7 +384,15 @@ static int axon_msi_probe(struct of_device *device,
                goto out_free_msic;
        }
 
-       msic->irq_host = irq_alloc_host(of_node_get(dn), IRQ_HOST_MAP_NOMAP,
+       virq = irq_of_parse_and_map(dn, 0);
+       if (virq == NO_IRQ) {
+               printk(KERN_ERR "axon_msi: irq parse and map failed for %s\n",
+                      dn->full_name);
+               goto out_free_fifo;
+       }
+       memset(msic->fifo_virt, 0xff, MSIC_FIFO_SIZE_BYTES);
+
+       msic->irq_host = irq_alloc_host(dn, IRQ_HOST_MAP_NOMAP,
                                        NR_IRQS, &msic_host_ops, 0);
        if (!msic->irq_host) {
                printk(KERN_ERR "axon_msi: couldn't allocate irq_host for %s\n",
@@ -368,16 +402,9 @@ static int axon_msi_probe(struct of_device *device,
 
        msic->irq_host->host_data = msic;
 
-       virq = irq_of_parse_and_map(dn, 0);
-       if (virq == NO_IRQ) {
-               printk(KERN_ERR "axon_msi: irq parse and map failed for %s\n",
-                      dn->full_name);
-               goto out_free_host;
-       }
-
        set_irq_data(virq, msic);
        set_irq_chained_handler(virq, axon_msi_cascade);
-       pr_debug("axon_msi: irq 0x%x setup for axon_msi\n", virq);
+       pr_devel("axon_msi: irq 0x%x setup for axon_msi\n", virq);
 
        /* Enable the MSIC hardware */
        msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, msic->fifo_phys >> 32);
@@ -387,7 +414,10 @@ static int axon_msi_probe(struct of_device *device,
                        MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE |
                        MSIC_CTRL_FIFO_SIZE);
 
-       device->dev.platform_data = msic;
+       msic->read_offset = dcr_read(msic->dcr_host, MSIC_WRITE_OFFSET_REG)
+                               & MSIC_FIFO_SIZE_MASK;
+
+       dev_set_drvdata(&device->dev, msic);
 
        ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
        ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
@@ -399,8 +429,6 @@ static int axon_msi_probe(struct of_device *device,
 
        return 0;
 
-out_free_host:
-       kfree(msic->irq_host);
 out_free_fifo:
        dma_free_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES, msic->fifo_virt,
                          msic->fifo_phys);
@@ -457,13 +485,13 @@ void axon_msi_debug_setup(struct device_node *dn, struct axon_msic *msic)
 
        addr = of_translate_address(dn, of_get_property(dn, "reg", NULL));
        if (addr == OF_BAD_ADDR) {
-               pr_debug("axon_msi: couldn't translate reg property\n");
+               pr_devel("axon_msi: couldn't translate reg property\n");
                return;
        }
 
        msic->trigger = ioremap(addr, 0x4);
        if (!msic->trigger) {
-               pr_debug("axon_msi: ioremap failed\n");
+               pr_devel("axon_msi: ioremap failed\n");
                return;
        }
 
@@ -471,7 +499,7 @@ void axon_msi_debug_setup(struct device_node *dn, struct axon_msic *msic)
 
        if (!debugfs_create_file(name, 0600, powerpc_debugfs_root,
                                 msic, &fops_msic)) {
-               pr_debug("axon_msi: debugfs_create_file failed!\n");
+               pr_devel("axon_msi: debugfs_create_file failed!\n");
                return;
        }
 }