]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/powerpc/platforms/cell/axon_msi.c
[POWERPC] Avoid possible extra of_node_put in axon_msi.c
[linux-2.6-omap-h63xx.git] / arch / powerpc / platforms / cell / axon_msi.c
index 4c9ab5b70bae0e8c590021fa55d88710bc6bfa61..d95e71dee91f85f000a1662c200f2075b6bec95f 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/msi.h>
-#include <linux/reboot.h>
+#include <linux/of_platform.h>
 
 #include <asm/dcr.h>
 #include <asm/machdep.h>
 
 
 struct axon_msic {
-       struct device_node *dn;
        struct irq_host *irq_host;
-       __le32 *fifo;
+       __le32 *fifo_virt;
+       dma_addr_t fifo_phys;
        dcr_host_t dcr_host;
-       struct list_head list;
        u32 read_offset;
-       u32 dcr_base;
 };
 
-static LIST_HEAD(axon_msic_list);
-
 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);
 
-       dcr_write(msic->dcr_host, msic->dcr_base + dcr_n, val);
-}
-
-static u32 msic_dcr_read(struct axon_msic *msic, unsigned int dcr_n)
-{
-       return dcr_read(msic->dcr_host, msic->dcr_base + dcr_n);
+       dcr_write(msic->dcr_host, dcr_n, val);
 }
 
 static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
@@ -93,7 +84,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
        u32 write_offset, msi;
        int idx;
 
-       write_offset = msic_dcr_read(msic, MSIC_WRITE_OFFSET_REG);
+       write_offset = dcr_read(msic->dcr_host, MSIC_WRITE_OFFSET_REG);
        pr_debug("axon_msi: original write_offset 0x%x\n", write_offset);
 
        /* write_offset doesn't wrap properly, so we have to mask it */
@@ -101,7 +92,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
 
        while (msic->read_offset != write_offset) {
                idx  = msic->read_offset / sizeof(__le32);
-               msi  = le32_to_cpu(msic->fifo[idx]);
+               msi  = le32_to_cpu(msic->fifo_virt[idx]);
                msi &= 0xFFFF;
 
                pr_debug("axon_msi: woff %x roff %x msi %x\n",
@@ -126,7 +117,7 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev)
        const phandle *ph;
        struct axon_msic *msic = NULL;
 
-       dn = pci_device_to_OF_node(dev);
+       dn = of_node_get(pci_device_to_OF_node(dev));
        if (!dn) {
                dev_dbg(&dev->dev, "axon_msi: no pci_dn found\n");
                return NULL;
@@ -146,6 +137,7 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev)
 
        tmp = dn;
        dn = of_find_node_by_phandle(*ph);
+       of_node_put(tmp);
        if (!dn) {
                dev_dbg(&dev->dev,
                        "axon_msi: msi-translator doesn't point to a node\n");
@@ -163,7 +155,6 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev)
 
 out_error:
        of_node_put(dn);
-       of_node_put(tmp);
 
        return msic;
 }
@@ -183,7 +174,7 @@ static int setup_msi_msg_address(struct pci_dev *dev, struct msi_msg *msg)
        int len;
        const u32 *prop;
 
-       dn = pci_device_to_OF_node(dev);
+       dn = of_node_get(pci_device_to_OF_node(dev));
        if (!dn) {
                dev_dbg(&dev->dev, "axon_msi: no pci_dn found\n");
                return -ENODEV;
@@ -295,44 +286,31 @@ static int msic_host_map(struct irq_host *h, unsigned int virq,
        return 0;
 }
 
-static int msic_host_match(struct irq_host *host, struct device_node *dn)
-{
-       struct axon_msic *msic = host->host_data;
-
-       return msic->dn == dn;
-}
-
 static struct irq_host_ops msic_host_ops = {
-       .match  = msic_host_match,
        .map    = msic_host_map,
 };
 
-static int axon_msi_notify_reboot(struct notifier_block *nb,
-                                 unsigned long code, void *data)
+static int axon_msi_shutdown(struct of_device *device)
 {
-       struct axon_msic *msic;
+       struct axon_msic *msic = device->dev.platform_data;
        u32 tmp;
 
-       list_for_each_entry(msic, &axon_msic_list, list) {
-               pr_debug("axon_msi: disabling %s\n", msic->dn->full_name);
-               tmp  = msic_dcr_read(msic, MSIC_CTRL_REG);
-               tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
-               msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
-       }
+       pr_debug("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;
+       msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
 
        return 0;
 }
 
-static struct notifier_block axon_msi_reboot_notifier = {
-       .notifier_call = axon_msi_notify_reboot
-};
-
-static int axon_msi_setup_one(struct device_node *dn)
+static int axon_msi_probe(struct of_device *device,
+                         const struct of_device_id *device_id)
 {
-       struct page *page;
+       struct device_node *dn = device->node;
        struct axon_msic *msic;
        unsigned int virq;
-       int dcr_len;
+       int dcr_base, dcr_len;
 
        pr_debug("axon_msi: setting up dn %s\n", dn->full_name);
 
@@ -343,35 +321,33 @@ static int axon_msi_setup_one(struct device_node *dn)
                goto out;
        }
 
-       msic->dcr_base = dcr_resource_start(dn, 0);
+       dcr_base = dcr_resource_start(dn, 0);
        dcr_len = dcr_resource_len(dn, 0);
 
-       if (msic->dcr_base == 0 || dcr_len == 0) {
+       if (dcr_base == 0 || dcr_len == 0) {
                printk(KERN_ERR
                       "axon_msi: couldn't parse dcr properties on %s\n",
                        dn->full_name);
                goto out;
        }
 
-       msic->dcr_host = dcr_map(dn, msic->dcr_base, dcr_len);
+       msic->dcr_host = dcr_map(dn, dcr_base, dcr_len);
        if (!DCR_MAP_OK(msic->dcr_host)) {
                printk(KERN_ERR "axon_msi: dcr_map failed for %s\n",
                       dn->full_name);
                goto out_free_msic;
        }
 
-       page = alloc_pages_node(of_node_to_nid(dn), GFP_KERNEL,
-                               get_order(MSIC_FIFO_SIZE_BYTES));
-       if (!page) {
+       msic->fifo_virt = dma_alloc_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES,
+                                            &msic->fifo_phys, GFP_KERNEL);
+       if (!msic->fifo_virt) {
                printk(KERN_ERR "axon_msi: couldn't allocate fifo for %s\n",
                       dn->full_name);
                goto out_free_msic;
        }
 
-       msic->fifo = page_address(page);
-
-       msic->irq_host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, NR_IRQS,
-                                       &msic_host_ops, 0);
+       msic->irq_host = irq_alloc_host(of_node_get(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",
                       dn->full_name);
@@ -387,21 +363,23 @@ static int axon_msi_setup_one(struct device_node *dn)
                goto out_free_host;
        }
 
-       msic->dn = of_node_get(dn);
-
        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);
 
        /* Enable the MSIC hardware */
-       msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, (u64)msic->fifo >> 32);
+       msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, msic->fifo_phys >> 32);
        msic_dcr_write(msic, MSIC_BASE_ADDR_LO_REG,
-                                 (u64)msic->fifo & 0xFFFFFFFF);
+                                 msic->fifo_phys & 0xFFFFFFFF);
        msic_dcr_write(msic, MSIC_CTRL_REG,
                        MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE |
                        MSIC_CTRL_FIFO_SIZE);
 
-       list_add(&msic->list, &axon_msic_list);
+       device->dev.platform_data = 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;
 
        printk(KERN_DEBUG "axon_msi: setup MSIC on %s\n", dn->full_name);
 
@@ -410,7 +388,8 @@ static int axon_msi_setup_one(struct device_node *dn)
 out_free_host:
        kfree(msic->irq_host);
 out_free_fifo:
-       __free_pages(virt_to_page(msic->fifo), get_order(MSIC_FIFO_SIZE_BYTES));
+       dma_free_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES, msic->fifo_virt,
+                         msic->fifo_phys);
 out_free_msic:
        kfree(msic);
 out:
@@ -418,28 +397,24 @@ out:
        return -1;
 }
 
-static int axon_msi_init(void)
-{
-       struct device_node *dn;
-       int found = 0;
-
-       pr_debug("axon_msi: initialising ...\n");
-
-       for_each_compatible_node(dn, NULL, "ibm,axon-msic") {
-               if (axon_msi_setup_one(dn) == 0)
-                       found++;
-       }
-
-       if (found) {
-               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;
-
-               register_reboot_notifier(&axon_msi_reboot_notifier);
+static const struct of_device_id axon_msi_device_id[] = {
+       {
+               .compatible     = "ibm,axon-msic"
+       },
+       {}
+};
 
-               pr_debug("axon_msi: registered callbacks!\n");
-       }
+static struct of_platform_driver axon_msi_driver = {
+       .match_table    = axon_msi_device_id,
+       .probe          = axon_msi_probe,
+       .shutdown       = axon_msi_shutdown,
+       .driver         = {
+               .name   = "axon-msi"
+       },
+};
 
-       return 0;
+static int __init axon_msi_init(void)
+{
+       return of_register_platform_driver(&axon_msi_driver);
 }
-arch_initcall(axon_msi_init);
+subsys_initcall(axon_msi_init);