[Skiboot] [PATCH v9 08/22] core/fdt: OPAL API opal_get_device_tree()
Gavin Shan
gwshan at linux.vnet.ibm.com
Thu Nov 12 13:33:15 AEDT 2015
This implements OPAL API opal_get_device_tree(), which will be used
to retrieve the device sub-tree introduced by newly hot plugged PCI
devices.
Signed-off-by: Gavin Shan <gwshan at linux.vnet.ibm.com>
---
core/fdt.c | 109 ++++++++++++++++++++++++++++++++++-------------------
include/opal-api.h | 3 +-
2 files changed, 73 insertions(+), 39 deletions(-)
diff --git a/core/fdt.c b/core/fdt.c
index a9392b1..3a85618 100644
--- a/core/fdt.c
+++ b/core/fdt.c
@@ -126,19 +126,23 @@ static void flatten_dt_properties(void *fdt, const struct dt_node *dn)
}
}
-static void flatten_dt_node(void *fdt, const struct dt_node *root)
+static void flatten_dt_node(void *fdt, const struct dt_node *root, bool inc)
{
const struct dt_node *i;
+ if (inc) {
#ifdef DEBUG_FDT
- printf("FDT: node: %s\n", root->name);
+ printf("FDT: node: %s\n", root->name);
#endif
- flatten_dt_properties(fdt, root);
- list_for_each(&root->children, i, list) {
- dt_begin_node(fdt, i);
- flatten_dt_node(fdt, i);
- dt_end_node(fdt);
+ dt_begin_node(fdt, root);
+ flatten_dt_properties(fdt, root);
}
+
+ list_for_each(&root->children, i, list)
+ flatten_dt_node(fdt, i, true);
+
+ if (inc)
+ dt_end_node(fdt);
}
static void create_dtb_reservemap(void *fdt, const struct dt_node *root)
@@ -163,51 +167,80 @@ static void create_dtb_reservemap(void *fdt, const struct dt_node *root)
save_err(fdt_finish_reservemap(fdt));
}
-void *create_dtb(const struct dt_node *root)
+static int __create_dtb(void *fdt, size_t len,
+ const struct dt_node *root,
+ bool inc)
{
- void *fdt = NULL;
- size_t len = DEVICE_TREE_MAX_SIZE;
uint32_t old_last_phandle = last_phandle;
- do {
- if (fdt)
- free(fdt);
+ fdt_create(fdt, len);
+
+ if (root == dt_root && inc)
+ create_dtb_reservemap(fdt, root);
+
+ /* Unflatten our live tree */
+ flatten_dt_node(fdt, root, inc);
+
+ save_err(fdt_finish(fdt));
+ if (fdt_error) {
last_phandle = old_last_phandle;
- fdt_error = 0;
- fdt = malloc(len);
- if (!fdt) {
- prerror("dtb: could not malloc %lu\n", (long)len);
- return NULL;
- }
+ prerror("dtb: error %s\n", fdt_strerror(fdt_error));
+ return fdt_error;
+ }
+
+#ifdef DEBUG_FDT
+ dump_fdt(fdt);
+#endif
+ return 0;
+}
- fdt_create(fdt, len);
+static int64_t opal_get_device_tree(uint32_t phandle,
+ uint64_t buf,
+ uint64_t len)
+{
+ struct dt_node *root;
+ void *fdt = (void *)buf;
+ int ret;
- create_dtb_reservemap(fdt, root);
+ if (!fdt || !len)
+ return OPAL_PARAMETER;
- /* Open root node */
- dt_begin_node(fdt, root);
+ root = dt_find_by_phandle(dt_root, phandle);
+ if (!root)
+ return OPAL_CLOSED;
- /* Unflatten our live tree */
- flatten_dt_node(fdt, root);
+ ret = __create_dtb(fdt, len, root, false);
+ if (ret == -FDT_ERR_NOSPACE)
+ return OPAL_NO_MEM;
+ else if (ret)
+ return OPAL_EMPTY;
- /* Close root node */
- dt_end_node(fdt);
+ return OPAL_SUCCESS;
+}
+opal_call(OPAL_GET_DEVICE_TREE, opal_get_device_tree, 3);
- save_err(fdt_finish(fdt));
+void *create_dtb(const struct dt_node *root)
+{
+ void *fdt = NULL;
+ size_t len = DEVICE_TREE_MAX_SIZE;
+ int ret;
- if (!fdt_error)
+ do {
+ fdt = malloc(len);
+ if (!fdt) {
+ prerror("dtb: cannot allocate FDT blob (%lu bytes)\n",
+ (long)len);
break;
+ }
- len *= 2;
- } while (fdt_error == -FDT_ERR_NOSPACE);
+ ret = __create_dtb(fdt, len, root, true);
+ if (ret) {
+ free(fdt);
+ fdt = NULL;
+ }
-#ifdef DEBUG_FDT
- dump_fdt(fdt);
-#endif
+ len *= 2;
+ } while (ret == -FDT_ERR_NOSPACE);
- if (fdt_error) {
- prerror("dtb: error %s\n", fdt_strerror(fdt_error));
- return NULL;
- }
return fdt;
}
diff --git a/include/opal-api.h b/include/opal-api.h
index 7a11fe8..fff9148 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -162,7 +162,8 @@
#define OPAL_LEDS_GET_INDICATOR 114
#define OPAL_LEDS_SET_INDICATOR 115
#define OPAL_CEC_REBOOT2 116
-#define OPAL_LAST 116
+#define OPAL_GET_DEVICE_TREE 117
+#define OPAL_LAST 117
/* Device tree flags */
--
2.1.0
More information about the Skiboot
mailing list