]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/of/address.c
Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux.git] / drivers / of / address.c
index 978427a9d5e68faca2c4a0f835e3b8c474113815..99c1b8058559e67b937550d47cbcab3f7dc80ebb 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 
+#include "of_private.h"
+
 /* Max address size we deal with */
 #define OF_MAX_ADDR_CELLS      4
 #define OF_CHECK_ADDR_COUNT(na)        ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS)
@@ -241,6 +243,7 @@ static int parser_init(struct of_pci_range_parser *parser,
        parser->node = node;
        parser->pna = of_n_addr_cells(node);
        parser->np = parser->pna + na + ns;
+       parser->dma = !strcmp(name, "dma-ranges");
 
        parser->range = of_get_property(node, name, &rlen);
        if (parser->range == NULL)
@@ -279,7 +282,11 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
        range->pci_space = be32_to_cpup(parser->range);
        range->flags = of_bus_pci_get_flags(parser->range);
        range->pci_addr = of_read_number(parser->range + 1, ns);
-       range->cpu_addr = of_translate_address(parser->node,
+       if (parser->dma)
+               range->cpu_addr = of_translate_dma_address(parser->node,
+                               parser->range + na);
+       else
+               range->cpu_addr = of_translate_address(parser->node,
                                parser->range + na);
        range->size = of_read_number(parser->range + parser->pna + na, ns);
 
@@ -292,8 +299,12 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
 
                flags = of_bus_pci_get_flags(parser->range);
                pci_addr = of_read_number(parser->range + 1, ns);
-               cpu_addr = of_translate_address(parser->node,
-                               parser->range + na);
+               if (parser->dma)
+                       cpu_addr = of_translate_dma_address(parser->node,
+                                       parser->range + na);
+               else
+                       cpu_addr = of_translate_address(parser->node,
+                                       parser->range + na);
                size = of_read_number(parser->range + parser->pna + na, ns);
 
                if (flags != range->flags)
@@ -517,9 +528,13 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
         *
         * As far as we know, this damage only exists on Apple machines, so
         * This code is only enabled on powerpc. --gcl
+        *
+        * This quirk also applies for 'dma-ranges' which frequently exist in
+        * child nodes without 'dma-ranges' in the parent nodes. --RobH
         */
        ranges = of_get_property(parent, rprop, &rlen);
-       if (ranges == NULL && !of_empty_ranges_quirk(parent)) {
+       if (ranges == NULL && !of_empty_ranges_quirk(parent) &&
+           strcmp(rprop, "dma-ranges")) {
                pr_debug("no ranges; cannot translate\n");
                return 1;
        }
@@ -695,6 +710,16 @@ static struct device_node *__of_get_dma_parent(const struct device_node *np)
        return of_node_get(args.np);
 }
 
+static struct device_node *of_get_next_dma_parent(struct device_node *np)
+{
+       struct device_node *parent;
+
+       parent = __of_get_dma_parent(np);
+       of_node_put(np);
+
+       return parent;
+}
+
 u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr)
 {
        struct device_node *host;
@@ -826,25 +851,6 @@ int of_address_to_resource(struct device_node *dev, int index,
 }
 EXPORT_SYMBOL_GPL(of_address_to_resource);
 
-struct device_node *of_find_matching_node_by_address(struct device_node *from,
-                                       const struct of_device_id *matches,
-                                       u64 base_address)
-{
-       struct device_node *dn = of_find_matching_node(from, matches);
-       struct resource res;
-
-       while (dn) {
-               if (!of_address_to_resource(dn, 0, &res) &&
-                   res.start == base_address)
-                       return dn;
-
-               dn = of_find_matching_node(dn, matches);
-       }
-
-       return NULL;
-}
-
-
 /**
  * of_iomap - Maps the memory mapped IO for a given device_node
  * @device:    the device whose io range will be mapped
@@ -924,47 +930,39 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz
        const __be32 *ranges = NULL;
        int len, naddr, nsize, pna;
        int ret = 0;
+       bool found_dma_ranges = false;
        u64 dmaaddr;
 
-       if (!node)
-               return -EINVAL;
-
-       while (1) {
-               struct device_node *parent;
-
-               naddr = of_n_addr_cells(node);
-               nsize = of_n_size_cells(node);
-
-               parent = __of_get_dma_parent(node);
-               of_node_put(node);
-
-               node = parent;
-               if (!node)
-                       break;
-
+       while (node) {
                ranges = of_get_property(node, "dma-ranges", &len);
 
                /* Ignore empty ranges, they imply no translation required */
                if (ranges && len > 0)
                        break;
 
-               /*
-                * At least empty ranges has to be defined for parent node if
-                * DMA is supported
-                */
-               if (!ranges)
-                       break;
+               /* Once we find 'dma-ranges', then a missing one is an error */
+               if (found_dma_ranges && !ranges) {
+                       ret = -ENODEV;
+                       goto out;
+               }
+               found_dma_ranges = true;
+
+               node = of_get_next_dma_parent(node);
        }
 
-       if (!ranges) {
+       if (!node || !ranges) {
                pr_debug("no dma-ranges found for node(%pOF)\n", np);
                ret = -ENODEV;
                goto out;
        }
 
-       len /= sizeof(u32);
-
+       naddr = of_bus_n_addr_cells(node);
+       nsize = of_bus_n_size_cells(node);
        pna = of_n_addr_cells(node);
+       if ((len / sizeof(__be32)) % (pna + naddr + nsize)) {
+               ret = -EINVAL;
+               goto out;
+       }
 
        /* dma-ranges format:
         * DMA addr     : naddr cells
@@ -972,10 +970,10 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz
         * size         : nsize cells
         */
        dmaaddr = of_read_number(ranges, naddr);
-       *paddr = of_translate_dma_address(np, ranges);
+       *paddr = of_translate_dma_address(node, ranges + naddr);
        if (*paddr == OF_BAD_ADDR) {
-               pr_err("translation of DMA address(%pad) to CPU address failed node(%pOF)\n",
-                      dma_addr, np);
+               pr_err("translation of DMA address(%llx) to CPU address failed node(%pOF)\n",
+                      dmaaddr, np);
                ret = -EINVAL;
                goto out;
        }
@@ -991,7 +989,6 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(of_dma_get_range);
 
 /**
  * of_dma_is_coherent - Check if device is coherent
@@ -1009,7 +1006,7 @@ bool of_dma_is_coherent(struct device_node *np)
                        of_node_put(node);
                        return true;
                }
-               node = of_get_next_parent(node);
+               node = of_get_next_dma_parent(node);
        }
        of_node_put(node);
        return false;