Merge branch 'for-linus' of git://neil.brown.name/md
[pandora-kernel.git] / arch / powerpc / platforms / cell / iommu.c
index 20ea0e1..eeacb3a 100644 (file)
 #include <linux/notifier.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
+#include <linux/lmb.h>
 
 #include <asm/prom.h>
 #include <asm/iommu.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
 #include <asm/udbg.h>
-#include <asm/lmb.h>
 #include <asm/firmware.h>
 #include <asm/cell-regs.h>
 
@@ -316,7 +316,7 @@ static void cell_iommu_setup_stab(struct cbe_iommu *iommu,
        segments = max(dbase + dsize, fbase + fsize) >> IO_SEGMENT_SHIFT;
 
        pr_debug("%s: iommu[%d]: segments: %lu\n",
-                       __FUNCTION__, iommu->nid, segments);
+                       __func__, iommu->nid, segments);
 
        /* set up the segment table */
        stab_size = segments * sizeof(unsigned long);
@@ -343,7 +343,7 @@ static unsigned long *cell_iommu_alloc_ptab(struct cbe_iommu *iommu,
                                (1 << 12) / sizeof(unsigned long));
 
        ptab_size = segments * pages_per_segment * sizeof(unsigned long);
-       pr_debug("%s: iommu[%d]: ptab_size: %lu, order: %d\n", __FUNCTION__,
+       pr_debug("%s: iommu[%d]: ptab_size: %lu, order: %d\n", __func__,
                        iommu->nid, ptab_size, get_order(ptab_size));
        page = alloc_pages_node(iommu->nid, GFP_KERNEL, get_order(ptab_size));
        BUG_ON(!page);
@@ -355,7 +355,7 @@ static unsigned long *cell_iommu_alloc_ptab(struct cbe_iommu *iommu,
        n_pte_pages = (pages_per_segment * sizeof(unsigned long)) >> 12;
 
        pr_debug("%s: iommu[%d]: stab at %p, ptab at %p, n_pte_pages: %lu\n",
-                       __FUNCTION__, iommu->nid, iommu->stab, ptab,
+                       __func__, iommu->nid, iommu->stab, ptab,
                        n_pte_pages);
 
        /* initialise the STEs */
@@ -394,7 +394,7 @@ static void cell_iommu_enable_hardware(struct cbe_iommu *iommu)
 
        if (cell_iommu_find_ioc(iommu->nid, &xlate_base))
                panic("%s: missing IOC register mappings for node %d\n",
-                     __FUNCTION__, iommu->nid);
+                     __func__, iommu->nid);
 
        iommu->xlate_regs = ioremap(xlate_base, IOC_Reg_Size);
        iommu->cmd_regs = iommu->xlate_regs + IOC_IOCmd_Offset;
@@ -540,7 +540,7 @@ static unsigned long cell_dma_direct_offset;
 static unsigned long dma_iommu_fixed_base;
 struct dma_mapping_ops dma_iommu_fixed_ops;
 
-static void cell_dma_dev_setup_iommu(struct device *dev)
+static struct iommu_table *cell_get_iommu_table(struct device *dev)
 {
        struct iommu_window *window;
        struct cbe_iommu *iommu;
@@ -555,11 +555,11 @@ static void cell_dma_dev_setup_iommu(struct device *dev)
                printk(KERN_ERR "iommu: missing iommu for %s (node %d)\n",
                       archdata->of_node ? archdata->of_node->full_name : "?",
                       archdata->numa_node);
-               return;
+               return NULL;
        }
        window = list_entry(iommu->windows.next, struct iommu_window, list);
 
-       archdata->dma_data = &window->table;
+       return &window->table;
 }
 
 static void cell_dma_dev_setup_fixed(struct device *dev);
@@ -572,7 +572,7 @@ static void cell_dma_dev_setup(struct device *dev)
        if (get_dma_ops(dev) == &dma_iommu_fixed_ops)
                cell_dma_dev_setup_fixed(dev);
        else if (get_pci_dma_ops() == &dma_iommu_ops)
-               cell_dma_dev_setup_iommu(dev);
+               archdata->dma_data = cell_get_iommu_table(dev);
        else if (get_pci_dma_ops() == &dma_direct_ops)
                archdata->dma_data = (void *)cell_dma_direct_offset;
        else
@@ -802,17 +802,24 @@ static int __init cell_iommu_init_disabled(void)
 
 static u64 cell_iommu_get_fixed_address(struct device *dev)
 {
-       u64 cpu_addr, size, best_size, pci_addr = OF_BAD_ADDR;
+       u64 cpu_addr, size, best_size, dev_addr = OF_BAD_ADDR;
        struct device_node *np;
        const u32 *ranges = NULL;
-       int i, len, best;
+       int i, len, best, naddr, nsize, pna, range_size;
 
        np = of_node_get(dev->archdata.of_node);
-       while (np) {
+       while (1) {
+               naddr = of_n_addr_cells(np);
+               nsize = of_n_size_cells(np);
+               np = of_get_next_parent(np);
+               if (!np)
+                       break;
+
                ranges = of_get_property(np, "dma-ranges", &len);
-               if (ranges)
+
+               /* Ignore empty ranges, they imply no translation required */
+               if (ranges && len > 0)
                        break;
-               np = of_get_next_parent(np);
        }
 
        if (!ranges) {
@@ -822,15 +829,17 @@ static u64 cell_iommu_get_fixed_address(struct device *dev)
 
        len /= sizeof(u32);
 
+       pna = of_n_addr_cells(np);
+       range_size = naddr + nsize + pna;
+
        /* dma-ranges format:
-        * 1 cell:  pci space
-        * 2 cells: pci address
-        * 2 cells: parent address
-        * 2 cells: size
+        * child addr   : naddr cells
+        * parent addr  : pna cells
+        * size         : nsize cells
         */
-       for (i = 0, best = -1, best_size = 0; i < len; i += 7) {
-               cpu_addr = of_translate_dma_address(np, ranges +i + 3);
-               size = of_read_number(ranges + i + 5, 2);
+       for (i = 0, best = -1, best_size = 0; i < len; i += range_size) {
+               cpu_addr = of_translate_dma_address(np, ranges + i + naddr);
+               size = of_read_number(ranges + i + naddr + pna, nsize);
 
                if (cpu_addr == 0 && size > best_size) {
                        best = i;
@@ -838,15 +847,15 @@ static u64 cell_iommu_get_fixed_address(struct device *dev)
                }
        }
 
-       if (best >= 0)
-               pci_addr = of_read_number(ranges + best + 1, 2);
-       else
+       if (best >= 0) {
+               dev_addr = of_read_number(ranges + best, naddr);
+       else
                dev_dbg(dev, "iommu: no suitable range found!\n");
 
 out:
        of_node_put(np);
 
-       return pci_addr;
+       return dev_addr;
 }
 
 static int dma_set_mask_and_switch(struct device *dev, u64 dma_mask)