[Skiboot] [PATCH v6 04/16] core/fdt: Refactor FDT

Gavin Shan gwshan at linux.vnet.ibm.com
Fri May 1 15:02:17 AEST 2015


The patch refactors FDT in order support PCI hotplug, which requires
the module to support the capability of creating FDT blob for the
subordinate device nodes of the specified one.

 * Current implementation assumes that the FDT blob is pointed by
   global variable "fdt", which won't be true when create FDT blob
   for PCI sub-device-tree during hotplug. Adding one additional
   parameter "void *fdt" to individual functions for the operated
   FDT blob.
 * Refactoring dt_flatten_node() so that it can be used to build
   FDT blob from root device node at bootup time, or the indicated
   one during PCI hotplug time.
 * Export create_dbt(), which can be used to create FDT blob during
   bootup or PCI hotplug time.

Signed-off-by: Gavin Shan <gwshan at linux.vnet.ibm.com>
---
 core/fdt.c            | 131 ++++++++++++++++++++++++++++++++------------------
 core/init.c           |   2 +-
 include/device_tree.h |   5 --
 include/skiboot.h     |   2 +-
 4 files changed, 86 insertions(+), 54 deletions(-)

diff --git a/core/fdt.c b/core/fdt.c
index 7abebba..c92dac8 100644
--- a/core/fdt.c
+++ b/core/fdt.c
@@ -27,7 +27,6 @@
 #include <ccan/str/str.h>
 
 static int fdt_error;
-static void *fdt;
 
 #undef DEBUG_FDT
 
@@ -44,12 +43,12 @@ static void __save_err(int err, const char *str)
 
 #define save_err(...) __save_err(__VA_ARGS__, #__VA_ARGS__)
 
-static void dt_property_cell(const char *name, u32 cell)
+static void dt_property_cell(void *fdt, const char *name, u32 cell)
 {
 	save_err(fdt_property_cell(fdt, name, cell));
 }
 
-static void dt_begin_node(const char *name, uint32_t phandle)
+static void dt_begin_node(void *fdt, const char *name, uint32_t phandle)
 {
 	save_err(fdt_begin_node(fdt, name));
 
@@ -57,23 +56,23 @@ static void dt_begin_node(const char *name, uint32_t phandle)
 	 * We add both the new style "phandle" and the legacy
 	 * "linux,phandle" properties
 	 */
-	dt_property_cell("linux,phandle", phandle);
-	dt_property_cell("phandle", phandle);
+	dt_property_cell(fdt, "linux,phandle", phandle);
+	dt_property_cell(fdt, "phandle", phandle);
 }
 
-static void dt_property(const char *name, const void *val, size_t size)
+static void dt_property(void *fdt, const char *name, const void *val, size_t size)
 {
 	save_err(fdt_property(fdt, name, val, size));
 }
 
-static void dt_end_node(void)
+static void dt_end_node(void *fdt)
 {
 	save_err(fdt_end_node(fdt));
 }
 
-static void dump_fdt(void)
-{
 #ifdef DEBUG_FDT
+static void dump_fdt(void *fdt)
+{
 	int i, off, depth, err;
 
 	printf("Device tree %u@%p\n", fdt_totalsize(fdt), fdt);
@@ -110,35 +109,47 @@ static void dump_fdt(void)
 		}
 		printf("name: %s [%u]\n", name, off);
 	}
-#endif
 }
+#else
+#define dump_fdt(x...)
+#endif
 
-static void flatten_dt_node(const struct dt_node *root)
+static void dt_flatten_properties(void *fdt, const struct dt_node *dn)
 {
-	const struct dt_node *i;
-	const struct dt_property *p;
+	struct dt_property *p;
 
-#ifdef DEBUG_FDT
-	printf("FDT: node: %s\n", root->name);
-#endif
-
-	list_for_each(&root->properties, p, list) {
+	list_for_each(&dn->properties, p, list) {
 		if (strstarts(p->name, DT_PRIVATE))
 			continue;
 #ifdef DEBUG_FDT
 		printf("FDT:   prop: %s size: %ld\n", p->name, p->len);
 #endif
-		dt_property(p->name, p->prop, p->len);
+		dt_property(fdt, p->name, p->prop, p->len);
 	}
+}
 
-	list_for_each(&root->children, i, list) {
-		dt_begin_node(i->name, i->phandle);
-		flatten_dt_node(i);
-		dt_end_node();
+static void dt_flatten_node(void *fdt, const struct dt_node *dn, bool inclusive)
+{
+	const struct dt_node *child;
+
+#ifdef DEBUG_FDT
+	printf("FDT: node: %s\n", dn->name);
+#endif
+
+	if (inclusive) {
+		dt_begin_node(fdt, dn->name, dn->phandle);
+		dt_flatten_properties(fdt, dn);
 	}
+
+	list_for_each(&dn->children, child, list)
+		dt_flatten_node(fdt, child, true);
+
+	/* Note that we have open ending pattern */
+	if (inclusive)
+		dt_end_node(fdt);
 }
 
-static void create_dtb_reservemap(const struct dt_node *root)
+static void create_dtb_reservemap(void *fdt, const struct dt_node *root)
 {
 	uint64_t base, size;
 	const uint64_t *ranges;
@@ -160,38 +171,61 @@ static void create_dtb_reservemap(const struct dt_node *root)
 	save_err(fdt_finish_reservemap(fdt));
 }
 
-void *create_dtb(const struct dt_node *root)
+static int __create_dtb(const struct dt_node *root, size_t len,
+			bool inclusive, void **pblob)
 {
-	size_t len = DEVICE_TREE_MAX_SIZE;
-	uint32_t old_last_phandle = last_phandle;
+	void *fdt;
 
-	do {
-		if (fdt)
-			free(fdt);
-		last_phandle = old_last_phandle;
-		fdt_error = 0;
-		fdt = malloc(len);
-		if (!fdt) {
-			prerror("dtb: could not malloc %lu\n", (long)len);
-			return NULL;
-		}
+	/* Clear cached error */
+	fdt_error = 0;
 
-		fdt_create(fdt, len);
+	/* Allocate memory chunk */
+	fdt = malloc(len);
+	if (!fdt) {
+		*pblob = NULL;
+		prerror("dtb: cannot alloc %lu\n", (long)len);
+		return 0;
+	}
 
-		create_dtb_reservemap(root);
+	/* FDT header */
+	fdt_create(fdt, len);
 
-		/* Open root node */
-		dt_begin_node(root->name, root->phandle);
+	/* Reserved memory chunks */
+	if (root == dt_root && inclusive)
+		create_dtb_reservemap(fdt, root);
 
-		/* Unflatten our live tree */
-		flatten_dt_node(root);
+	/* Unflatten our live tree */
+	dt_flatten_node(fdt, root, inclusive);
 
-		/* Close root node */
-		dt_end_node();
+	save_err(fdt_finish(fdt));
+	if (fdt_error) {
+		free(fdt);
+		return fdt_error;
+	}
 
-		save_err(fdt_finish(fdt));
+	*pblob = fdt;
+	return 0;
+}
 
-		if (!fdt_error)
+void *create_dtb(const struct dt_node *root, size_t *size, bool inclusive)
+{
+	size_t len;
+	uint32_t old_last_phandle = last_phandle;
+	void *fdt = NULL;
+	int ret;
+
+	/* Get the initial length */
+	if (size) {
+		len = *size;
+		*size = 0;
+	} else {
+		len = DEVICE_TREE_MAX_SIZE;
+	}
+
+	do {
+		last_phandle = old_last_phandle;
+		ret = __create_dtb(root, len, inclusive, &fdt);
+		if (!ret)
 			break;
 
 		len *= 2;
@@ -203,5 +237,8 @@ void *create_dtb(const struct dt_node *root)
 		prerror("dtb: error %s\n", fdt_strerror(fdt_error));
 		return NULL;
 	}
+
+	if (size)
+		*size = len;
 	return fdt;
 }
diff --git a/core/init.c b/core/init.c
index 445272a..2836ae3 100644
--- a/core/init.c
+++ b/core/init.c
@@ -414,7 +414,7 @@ void __noreturn load_and_boot_kernel(bool is_reboot)
 	op_display(OP_LOG, OP_MOD_INIT, 0x000B);
 
 	/* Create the device tree blob to boot OS. */
-	fdt = create_dtb(dt_root);
+	fdt = create_dtb(dt_root, NULL, true);
 	if (!fdt) {
 		op_display(OP_FATAL, OP_MOD_INIT, 2);
 		abort();
diff --git a/include/device_tree.h b/include/device_tree.h
index d04f20a..a32821c 100644
--- a/include/device_tree.h
+++ b/include/device_tree.h
@@ -18,11 +18,6 @@
 #define __DEVICE_TREE_H
 #include <stdint.h>
 
-/* Note: Device tree creation has no locks. It's assumed to be done
- * by a single processor in a non racy way
- */
-void *create_dtb(const struct dt_node *root);
-
 /* Helpers to cache errors in fdt; use this instead of fdt_* */
 uint32_t dt_begin_node(const char *name); /* returns phandle */
 void dt_property_string(const char *name, const char *value);
diff --git a/include/skiboot.h b/include/skiboot.h
index fc5bc1d..19b77b3 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -235,7 +235,7 @@ extern void prd_occ_reset(uint32_t proc);
 extern void prd_init(void);
 
 /* Flatten device-tree */
-extern void *create_dtb(const struct dt_node *root);
+void *create_dtb(const struct dt_node *root, size_t *size, bool inclusive);
 
 /* SLW reinit function for switching core settings */
 extern int64_t slw_reinit(uint64_t flags);
-- 
2.1.0



More information about the Skiboot mailing list