]> git.ipfire.org Git - thirdparty/u-boot.git/blobdiff - lib/of_live.c
net: hifemac_mdio: use log_msg_ret() correctly, report error by dev_err()
[thirdparty/u-boot.git] / lib / of_live.c
index c49e95e38c7c79922a4f6e72aface9e0a7e500ba..90b9459ede313e492e28c8556c730f3bd8aaa9df 100644 (file)
@@ -8,12 +8,20 @@
  * Copyright (c) 2017 Google, Inc
  */
 
-#include <common.h>
+#define LOG_CATEGORY   LOGC_DT
+
+#include <abuf.h>
+#include <log.h>
 #include <linux/libfdt.h>
 #include <of_live.h>
 #include <malloc.h>
 #include <dm/of_access.h>
 #include <linux/err.h>
+#include <linux/sizes.h>
+
+enum {
+       BUF_STEP        = SZ_64K,
+};
 
 static void *unflatten_dt_alloc(void **mem, unsigned long size,
                                unsigned long align)
@@ -96,6 +104,10 @@ static void *unflatten_dt_node(const void *blob, void *mem, int *poffset,
                char *fn;
 
                fn = (char *)np + sizeof(*np);
+               if (new_format) {
+                       np->name = pathp;
+                       has_name = 1;
+               }
                np->full_name = fn;
                if (new_format) {
                        /* rebuild full path for new format */
@@ -201,7 +213,8 @@ static void *unflatten_dt_node(const void *blob, void *mem, int *poffset,
        }
        if (!dryrun) {
                *prev_pp = NULL;
-               np->name = of_get_property(np, "name", NULL);
+               if (!has_name)
+                       np->name = of_get_property(np, "name", NULL);
                np->type = of_get_property(np, "device_type", NULL);
 
                if (!np->name)
@@ -247,19 +260,7 @@ static void *unflatten_dt_node(const void *blob, void *mem, int *poffset,
        return mem;
 }
 
-/**
- * unflatten_device_tree() - create tree of device_nodes from flat blob
- *
- * unflattens a device-tree, 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.
- * @blob: The blob to expand
- * @mynodes: The device_node tree created by the call
- * @return 0 if OK, -ve on error
- */
-static int unflatten_device_tree(const void *blob,
-                                struct device_node **mynodes)
+int unflatten_device_tree(const void *blob, struct device_node **mynodes)
 {
        unsigned long size;
        int start;
@@ -293,9 +294,12 @@ static int unflatten_device_tree(const void *blob,
        debug("  size is %lx, allocating...\n", size);
 
        /* Allocate memory for the expanded device tree */
-       mem = malloc(size + 4);
+       mem = memalign(__alignof__(struct device_node), size + 4);
        memset(mem, '\0', size);
 
+       /* Set up value for dm_test_livetree_align() */
+       *(u32 *)mem = BAD_OF_ROOT;
+
        *(__be32 *)(mem + size) = cpu_to_be32(0xdeadbeef);
 
        debug("  unflattening %p...\n", mem);
@@ -333,3 +337,142 @@ int of_live_build(const void *fdt_blob, struct device_node **rootp)
 
        return ret;
 }
+
+void of_live_free(struct device_node *root)
+{
+       /* the tree is stored as a contiguous block of memory */
+       free(root);
+}
+
+int of_live_create_empty(struct device_node **rootp)
+{
+       struct device_node *root;
+
+       root = calloc(1, sizeof(struct device_node));
+       if (!root)
+               return -ENOMEM;
+       root->name = strdup("");
+       if (!root->name) {
+               free(root);
+               return -ENOMEM;
+       }
+       root->type = "<NULL>";
+       root->full_name = "";
+       *rootp = root;
+
+       return 0;
+}
+
+static int check_space(int ret, struct abuf *buf)
+{
+       if (ret == -FDT_ERR_NOSPACE) {
+               if (!abuf_realloc_inc(buf, BUF_STEP))
+                       return log_msg_ret("spc", -ENOMEM);
+               ret = fdt_resize(abuf_data(buf), abuf_data(buf),
+                                abuf_size(buf));
+               if (ret)
+                       return log_msg_ret("res", -EFAULT);
+
+               return -EAGAIN;
+       }
+
+       return 0;
+}
+
+/**
+ * flatten_node() - Write out the node and its properties into a flat tree
+ */
+static int flatten_node(struct abuf *buf, const struct device_node *node)
+{
+       const struct device_node *np;
+       const struct property *pp;
+       int ret;
+
+       ret = fdt_begin_node(abuf_data(buf), node->name);
+       ret = check_space(ret, buf);
+       if (ret == -EAGAIN) {
+               ret = fdt_begin_node(abuf_data(buf), node->name);
+               if (ret) {
+                       log_debug("Internal error a %d\n", ret);
+                       return -EFAULT;
+               }
+       }
+       if (ret)
+               return log_msg_ret("beg", ret);
+
+       /* First write out the properties */
+       for (pp = node->properties; !ret && pp; pp = pp->next) {
+               ret = fdt_property(abuf_data(buf), pp->name, pp->value,
+                                  pp->length);
+               ret = check_space(ret, buf);
+               if (ret == -EAGAIN) {
+                       ret = fdt_property(abuf_data(buf), pp->name, pp->value,
+                                          pp->length);
+               }
+       }
+
+       /* Next write out the subnodes */
+       for (np = node->child; np; np = np->sibling) {
+               ret = flatten_node(buf, np);
+               if (ret)
+                       return log_msg_ret("sub", ret);
+       }
+
+       ret = fdt_end_node(abuf_data(buf));
+       ret = check_space(ret, buf);
+       if (ret == -EAGAIN) {
+               ret = fdt_end_node(abuf_data(buf));
+               if (ret) {
+                       log_debug("Internal error b %d\n", ret);
+                       return -EFAULT;
+               }
+       }
+       if (ret)
+               return log_msg_ret("end", ret);
+
+       return 0;
+}
+
+int of_live_flatten(const struct device_node *root, struct abuf *buf)
+{
+       int ret;
+
+       abuf_init(buf);
+       if (!abuf_realloc(buf, BUF_STEP))
+               return log_msg_ret("ini", -ENOMEM);
+
+       ret = fdt_create(abuf_data(buf), abuf_size(buf));
+       if (!ret)
+               ret = fdt_finish_reservemap(abuf_data(buf));
+       if (ret) {
+               log_debug("Failed to start FDT (err=%d)\n", ret);
+               return log_msg_ret("sta", -EINVAL);
+       }
+
+       ret = flatten_node(buf, root);
+       if (ret)
+               return log_msg_ret("flt", ret);
+
+       ret = fdt_finish(abuf_data(buf));
+       ret = check_space(ret, buf);
+       if (ret == -EAGAIN) {
+               ret = fdt_finish(abuf_data(buf));
+               if (ret) {
+                       log_debug("Internal error c %d\n", ret);
+                       return -EFAULT;
+               }
+       }
+       if (ret)
+               return log_msg_ret("fin", ret);
+
+       ret = fdt_pack(abuf_data(buf));
+       if (ret) {
+               log_debug("Failed to pack (err=%d)\n", ret);
+               return log_msg_ret("pac", -EFAULT);
+       }
+
+       if (!abuf_realloc(buf, fdt_totalsize(abuf_data(buf))))
+               return log_msg_ret("abu", -EFAULT);
+
+       return 0;
+}