@@ -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;
}
@@ -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();
@@ -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);
@@ -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);
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@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(-)