return fpsize;
 }
 
+static void reverse_nodes(struct device_node *parent)
+{
+       struct device_node *child, *next;
+
+       /* In-depth first */
+       child = parent->child;
+       while (child) {
+               reverse_nodes(child);
+
+               child = child->sibling;
+       }
+
+       /* Reverse the nodes in the child list */
+       child = parent->child;
+       parent->child = NULL;
+       while (child) {
+               next = child->sibling;
+
+               child->sibling = parent->child;
+               parent->child = child;
+               child = next;
+       }
+}
+
 /**
  * unflatten_dt_node - 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
- * @poffset: pointer to node in flat tree
  * @dad: Parent struct device_node
  * @nodepp: The device_node tree created by the call
- * @fpsize: Size of the node path up at the current depth.
- * @dryrun: If true, do not allocate device nodes but still calculate needed
- * memory size
+ *
+ * It returns the size of unflattened device tree or error code
  */
-static void *unflatten_dt_node(const void *blob,
-                              void *mem,
-                              int *poffset,
-                              struct device_node *dad,
-                              struct device_node **nodepp,
-                              unsigned long fpsize,
-                              bool dryrun)
+static int unflatten_dt_node(const void *blob,
+                            void *mem,
+                            struct device_node *dad,
+                            struct device_node **nodepp)
 {
-       struct device_node *np;
-       static int depth;
-       int old_depth;
+       struct device_node *root;
+       int offset = 0, depth = 0;
+#define FDT_MAX_DEPTH  64
+       unsigned long fpsizes[FDT_MAX_DEPTH];
+       struct device_node *nps[FDT_MAX_DEPTH];
+       void *base = mem;
+       bool dryrun = !base;
 
-       fpsize = populate_node(blob, *poffset, &mem, dad, fpsize, &np, dryrun);
-       if (!fpsize)
-               return mem;
+       if (nodepp)
+               *nodepp = NULL;
+
+       root = dad;
+       fpsizes[depth] = dad ? strlen(of_node_full_name(dad)) : 0;
+       nps[depth++] = dad;
+       for (offset = 0;
+            offset >= 0;
+            offset = fdt_next_node(blob, offset, &depth)) {
+               if (WARN_ON_ONCE(depth >= FDT_MAX_DEPTH))
+                       continue;
 
-       old_depth = depth;
-       *poffset = fdt_next_node(blob, *poffset, &depth);
-       if (depth < 0)
-               depth = 0;
-       while (*poffset > 0 && depth > old_depth)
-               mem = unflatten_dt_node(blob, mem, poffset, np, NULL,
-                                       fpsize, dryrun);
+               fpsizes[depth] = populate_node(blob, offset, &mem,
+                                              nps[depth - 1],
+                                              fpsizes[depth - 1],
+                                              &nps[depth], dryrun);
+               if (!fpsizes[depth])
+                       return mem - base;
+
+               if (!dryrun && nodepp && !*nodepp)
+                       *nodepp = nps[depth];
+               if (!dryrun && !root)
+                       root = nps[depth];
+       }
 
-       if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND)
-               pr_err("unflatten: error %d processing FDT\n", *poffset);
+       if (offset < 0 && offset != -FDT_ERR_NOTFOUND) {
+               pr_err("%s: Error %d processing FDT\n", __func__, offset);
+               return -EINVAL;
+       }
 
        /*
         * Reverse the child list. Some drivers assumes node order matches .dts
         * node order
         */
-       if (!dryrun && np->child) {
-               struct device_node *child = np->child;
-               np->child = NULL;
-               while (child) {
-                       struct device_node *next = child->sibling;
-                       child->sibling = np->child;
-                       np->child = child;
-                       child = next;
-               }
-       }
-
-       if (nodepp)
-               *nodepp = np;
+       if (!dryrun)
+               reverse_nodes(root);
 
-       return mem;
+       return mem - base;
 }
 
 /**
                             struct device_node **mynodes,
                             void * (*dt_alloc)(u64 size, u64 align))
 {
-       unsigned long size;
-       int start;
+       int size;
        void *mem;
 
        pr_debug(" -> unflatten_device_tree()\n");
        }
 
        /* First pass, scan for size */
-       start = 0;
-       size = (unsigned long)unflatten_dt_node(blob, NULL, &start, NULL, NULL, 0, true);
-       size = ALIGN(size, 4);
+       size = unflatten_dt_node(blob, NULL, NULL, NULL);
+       if (size < 0)
+               return;
 
-       pr_debug("  size is %lx, allocating...\n", size);
+       size = ALIGN(size, 4);
+       pr_debug("  size is %d, allocating...\n", size);
 
        /* Allocate memory for the expanded device tree */
        mem = dt_alloc(size + 4, __alignof__(struct device_node));
        pr_debug("  unflattening %p...\n", mem);
 
        /* Second pass, do actual unflattening */
-       start = 0;
-       unflatten_dt_node(blob, mem, &start, NULL, mynodes, 0, false);
+       unflatten_dt_node(blob, mem, NULL, mynodes);
        if (be32_to_cpup(mem + size) != 0xdeadbeef)
                pr_warning("End of tree marker overwritten: %08x\n",
                           be32_to_cpup(mem + size));