Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
[cascardo/linux.git] / drivers / of / fdt.c
index c2c4afc..14f2f8c 100644 (file)
@@ -264,13 +264,13 @@ static void populate_properties(const void *blob,
                *pprev = NULL;
 }
 
-static unsigned long populate_node(const void *blob,
-                                  int offset,
-                                  void **mem,
-                                  struct device_node *dad,
-                                  unsigned long fpsize,
-                                  struct device_node **pnp,
-                                  bool dryrun)
+static unsigned int populate_node(const void *blob,
+                                 int offset,
+                                 void **mem,
+                                 struct device_node *dad,
+                                 unsigned int fpsize,
+                                 struct device_node **pnp,
+                                 bool dryrun)
 {
        struct device_node *np;
        const char *pathp;
@@ -381,7 +381,7 @@ static void reverse_nodes(struct device_node *parent)
 }
 
 /**
- * unflatten_dt_node - Alloc and populate a device_node from the flat tree
+ * unflatten_dt_nodes - Alloc and populate a device_node from the flat tree
  * @blob: The parent device tree blob
  * @mem: Memory chunk to use for allocating device nodes and properties
  * @dad: Parent struct device_node
@@ -389,15 +389,15 @@ static void reverse_nodes(struct device_node *parent)
  *
  * It returns the size of unflattened device tree or error code
  */
-static int unflatten_dt_node(const void *blob,
-                            void *mem,
-                            struct device_node *dad,
-                            struct device_node **nodepp)
+static int unflatten_dt_nodes(const void *blob,
+                             void *mem,
+                             struct device_node *dad,
+                             struct device_node **nodepp)
 {
        struct device_node *root;
        int offset = 0, depth = 0;
 #define FDT_MAX_DEPTH  64
-       unsigned long fpsizes[FDT_MAX_DEPTH];
+       unsigned int fpsizes[FDT_MAX_DEPTH];
        struct device_node *nps[FDT_MAX_DEPTH];
        void *base = mem;
        bool dryrun = !base;
@@ -407,24 +407,24 @@ static int unflatten_dt_node(const void *blob,
 
        root = dad;
        fpsizes[depth] = dad ? strlen(of_node_full_name(dad)) : 0;
-       nps[depth++] = dad;
+       nps[depth] = dad;
        for (offset = 0;
-            offset >= 0;
+            offset >= 0 && depth >= 0;
             offset = fdt_next_node(blob, offset, &depth)) {
                if (WARN_ON_ONCE(depth >= FDT_MAX_DEPTH))
                        continue;
 
-               fpsizes[depth] = populate_node(blob, offset, &mem,
-                                              nps[depth - 1],
-                                              fpsizes[depth - 1],
-                                              &nps[depth], dryrun);
-               if (!fpsizes[depth])
+               fpsizes[depth+1] = populate_node(blob, offset, &mem,
+                                                nps[depth],
+                                                fpsizes[depth],
+                                                &nps[depth+1], dryrun);
+               if (!fpsizes[depth+1])
                        return mem - base;
 
                if (!dryrun && nodepp && !*nodepp)
-                       *nodepp = nps[depth];
+                       *nodepp = nps[depth+1];
                if (!dryrun && !root)
-                       root = nps[depth];
+                       root = nps[depth+1];
        }
 
        if (offset < 0 && offset != -FDT_ERR_NOTFOUND) {
@@ -450,13 +450,18 @@ static int unflatten_dt_node(const void *blob,
  * pointers of the nodes so the normal device-tree walking functions
  * can be used.
  * @blob: The blob to expand
+ * @dad: Parent device node
  * @mynodes: The device_node tree created by the call
  * @dt_alloc: An allocator that provides a virtual address to memory
  * for the resulting tree
+ *
+ * Returns NULL on failure or the memory chunk containing the unflattened
+ * device tree on success.
  */
-static void __unflatten_device_tree(const void *blob,
-                            struct device_node **mynodes,
-                            void * (*dt_alloc)(u64 size, u64 align))
+static void *__unflatten_device_tree(const void *blob,
+                                    struct device_node *dad,
+                                    struct device_node **mynodes,
+                                    void *(*dt_alloc)(u64 size, u64 align))
 {
        int size;
        void *mem;
@@ -465,7 +470,7 @@ static void __unflatten_device_tree(const void *blob,
 
        if (!blob) {
                pr_debug("No device tree pointer\n");
-               return;
+               return NULL;
        }
 
        pr_debug("Unflattening device tree:\n");
@@ -475,13 +480,13 @@ static void __unflatten_device_tree(const void *blob,
 
        if (fdt_check_header(blob)) {
                pr_err("Invalid device tree blob header\n");
-               return;
+               return NULL;
        }
 
        /* First pass, scan for size */
-       size = unflatten_dt_node(blob, NULL, NULL, NULL);
+       size = unflatten_dt_nodes(blob, NULL, dad, NULL);
        if (size < 0)
-               return;
+               return NULL;
 
        size = ALIGN(size, 4);
        pr_debug("  size is %d, allocating...\n", size);
@@ -495,12 +500,13 @@ static void __unflatten_device_tree(const void *blob,
        pr_debug("  unflattening %p...\n", mem);
 
        /* Second pass, do actual unflattening */
-       unflatten_dt_node(blob, mem, NULL, mynodes);
+       unflatten_dt_nodes(blob, mem, dad, mynodes);
        if (be32_to_cpup(mem + size) != 0xdeadbeef)
                pr_warning("End of tree marker overwritten: %08x\n",
                           be32_to_cpup(mem + size));
 
        pr_debug(" <- unflatten_device_tree()\n");
+       return mem;
 }
 
 static void *kernel_tree_alloc(u64 size, u64 align)
@@ -512,18 +518,29 @@ static DEFINE_MUTEX(of_fdt_unflatten_mutex);
 
 /**
  * of_fdt_unflatten_tree - create tree of device_nodes from flat blob
+ * @blob: Flat device tree blob
+ * @dad: Parent device node
+ * @mynodes: The device tree created by the call
  *
  * unflattens the device-tree passed by the firmware, creating the
  * tree of struct device_node. It also fills the "name" and "type"
  * pointers of the nodes so the normal device-tree walking functions
  * can be used.
+ *
+ * Returns NULL on failure or the memory chunk containing the unflattened
+ * device tree on success.
  */
-void of_fdt_unflatten_tree(const unsigned long *blob,
-                       struct device_node **mynodes)
+void *of_fdt_unflatten_tree(const unsigned long *blob,
+                           struct device_node *dad,
+                           struct device_node **mynodes)
 {
+       void *mem;
+
        mutex_lock(&of_fdt_unflatten_mutex);
-       __unflatten_device_tree(blob, mynodes, &kernel_tree_alloc);
+       mem = __unflatten_device_tree(blob, dad, mynodes, &kernel_tree_alloc);
        mutex_unlock(&of_fdt_unflatten_mutex);
+
+       return mem;
 }
 EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree);
 
@@ -1195,7 +1212,7 @@ bool __init early_init_dt_scan(void *params)
  */
 void __init unflatten_device_tree(void)
 {
-       __unflatten_device_tree(initial_boot_params, &of_root,
+       __unflatten_device_tree(initial_boot_params, NULL, &of_root,
                                early_init_dt_alloc_memory_arch);
 
        /* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */