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 d95e71d..8efe481 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/pci.h>
 #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>
@@ -69,11 +71,22 @@ struct axon_msic {
        dma_addr_t fifo_phys;
        dcr_host_t dcr_host;
        u32 read_offset;
+#ifdef DEBUG
+       u32 __iomem *trigger;
+#endif
 };
 
+#ifdef DEBUG
+void axon_msi_debug_setup(struct device_node *dn, struct axon_msic *msic);
+#else
+static inline void axon_msi_debug_setup(struct device_node *dn,
+                                       struct axon_msic *msic) { }
+#endif
+
+
 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);
 }
@@ -83,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);
@@ -123,7 +161,7 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev)
                return NULL;
        }
 
-       for (; dn; tmp = of_get_parent(dn), of_node_put(dn), dn = tmp) {
+       for (; dn; dn = of_get_next_parent(dn)) {
                ph = of_get_property(dn, "msi-translator", NULL);
                if (ph)
                        break;
@@ -169,7 +207,7 @@ static int axon_msi_check_device(struct pci_dev *dev, int nvec, int type)
 
 static int setup_msi_msg_address(struct pci_dev *dev, struct msi_msg *msg)
 {
-       struct device_node *dn, *tmp;
+       struct device_node *dn;
        struct msi_desc *entry;
        int len;
        const u32 *prop;
@@ -182,7 +220,7 @@ static int setup_msi_msg_address(struct pci_dev *dev, struct msi_msg *msg)
 
        entry = list_first_entry(&dev->msi_list, struct msi_desc, list);
 
-       for (; dn; tmp = of_get_parent(dn), of_node_put(dn), dn = tmp) {
+       for (; dn; dn = of_get_next_parent(dn)) {
                if (entry->msi_attrib.is_64) {
                        prop = of_get_property(dn, "msi-address-64", &len);
                        if (prop)
@@ -275,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,
@@ -292,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;
@@ -312,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) {
@@ -328,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);
@@ -346,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",
@@ -356,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);
@@ -375,18 +414,21 @@ 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;
        ppc_md.msi_check_device = axon_msi_check_device;
 
+       axon_msi_debug_setup(dn, msic);
+
        printk(KERN_DEBUG "axon_msi: setup MSIC on %s\n", dn->full_name);
 
        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);
@@ -418,3 +460,47 @@ static int __init axon_msi_init(void)
        return of_register_platform_driver(&axon_msi_driver);
 }
 subsys_initcall(axon_msi_init);
+
+
+#ifdef DEBUG
+static int msic_set(void *data, u64 val)
+{
+       struct axon_msic *msic = data;
+       out_le32(msic->trigger, val);
+       return 0;
+}
+
+static int msic_get(void *data, u64 *val)
+{
+       *val = 0;
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_msic, msic_get, msic_set, "%llu\n");
+
+void axon_msi_debug_setup(struct device_node *dn, struct axon_msic *msic)
+{
+       char name[8];
+       u64 addr;
+
+       addr = of_translate_address(dn, of_get_property(dn, "reg", NULL));
+       if (addr == OF_BAD_ADDR) {
+               pr_devel("axon_msi: couldn't translate reg property\n");
+               return;
+       }
+
+       msic->trigger = ioremap(addr, 0x4);
+       if (!msic->trigger) {
+               pr_devel("axon_msi: ioremap failed\n");
+               return;
+       }
+
+       snprintf(name, sizeof(name), "msic_%d", of_node_to_nid(dn));
+
+       if (!debugfs_create_file(name, 0600, powerpc_debugfs_root,
+                                msic, &fops_msic)) {
+               pr_devel("axon_msi: debugfs_create_file failed!\n");
+               return;
+       }
+}
+#endif /* DEBUG */