From: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>
Parse device mmio regions provided within 'reg' and
'reg-extened' device tree properties.
Call corresponding device interface class handlers to
create memory regions.
Signed-off-by: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>
---
hw/core/fdt_generic_util.c | 129 +++++++++++++++++++++++++++++++++++++
1 file changed, 129 insertions(+)
diff --git a/hw/core/fdt_generic_util.c b/hw/core/fdt_generic_util.c
index dcacc5033b..838ed9a85c 100644
--- a/hw/core/fdt_generic_util.c
+++ b/hw/core/fdt_generic_util.c
@@ -630,6 +630,22 @@ static inline uint64_t get_int_be(const void *p, int len)
}
}
+/* FIXME: use structs instead of parallel arrays */
+
+static const char *fdt_generic_reg_size_prop_names[] = {
+ "#address-cells",
+ "#size-cells",
+ "#bus-cells",
+ "#priority-cells",
+};
+
+static const int fdt_generic_reg_cells_defaults[] = {
+ 1,
+ 1,
+ 0,
+ 0,
+};
+
/*
* Error handler for device creation failure.
*
@@ -831,6 +847,117 @@ static void fdt_init_qdev_array_prop(Object *obj,
DB_PRINT_NP(0, "set property %s propname to <list>\n", propname);
}
+static void fdt_parse_node_reg_prop(FDTMachineInfo *fdti, char *node_path,
+ Object *dev)
+{
+ FDTGenericRegPropInfo reg = {0};
+ Object *parent;
+ char parent_path[DT_PATH_LENGTH];
+ int cell_idx = 0;
+ bool extended = true;
+ Error *errp = NULL;
+ int i;
+
+ if (!object_dynamic_cast(dev, TYPE_SYS_BUS_DEVICE) &&
+ !object_dynamic_cast(dev, TYPE_FDT_GENERIC_MMAP))
+ return;
+
+ qemu_fdt_getprop_cell(fdti->fdt, node_path, "reg-extended", 0,
+ &errp);
+ if (errp) {
+ error_free(errp);
+ errp = NULL;
+ extended = false;
+ qemu_devtree_getparent(fdti->fdt, parent_path, node_path);
+ }
+
+ parent = fdt_init_get_opaque(fdti, parent_path);
+
+ for (reg.n = 0;; reg.n++) {
+ char ph_parent[DT_PATH_LENGTH];
+ const char *pnp = parent_path;
+
+ reg.parents = g_renew(Object *, reg.parents, reg.n + 1);
+ reg.parents[reg.n] = parent;
+
+ if (extended) {
+ int p_ph = qemu_fdt_getprop_cell(fdti->fdt, node_path,
+ "reg-extended", cell_idx++,
+ &errp);
+ if (errp) {
+ error_free(errp);
+ errp = NULL;
+ goto exit_reg_parse;
+ }
+ if (qemu_devtree_get_node_by_phandle(fdti->fdt, ph_parent,
+ p_ph)) {
+ goto exit_reg_parse;
+ }
+
+ while (!fdt_init_has_opaque(fdti, ph_parent) &&
+ qemu_in_coroutine()) {
+ fdt_init_yield(fdti);
+ }
+
+ if (!fdt_init_has_opaque(fdti, ph_parent)) {
+ goto exit_reg_parse;
+ }
+
+ reg.parents[reg.n] = fdt_init_get_opaque(fdti, ph_parent);
+ pnp = ph_parent;
+ }
+
+ for (i = 0; i < FDT_GENERIC_REG_TUPLE_LENGTH; ++i) {
+ const char *size_prop_name = fdt_generic_reg_size_prop_names[i];
+ int nc = qemu_fdt_getprop_cell_inherited(fdti->fdt, node_path,
+ size_prop_name, 0, &errp);
+ uint64_t val = 0;
+
+ if (errp) {
+ int size_default = fdt_generic_reg_cells_defaults[i];
+
+ DB_PRINT_NP(0, "WARNING: no %s for %s container, assuming "
+ "default of %d\n", size_prop_name, pnp,
+ size_default);
+ nc = size_default;
+ error_free(errp);
+ errp = NULL;
+ }
+
+ reg.x[i] = g_renew(uint64_t, reg.x[i], reg.n + 1);
+ for (int j = 0; j < nc; ++j) {
+ val <<= 32;
+ val |= qemu_fdt_getprop_cell(fdti->fdt, node_path,
+ extended ? "reg-extended"
+ : "reg",
+ cell_idx + j, &errp);
+ if (errp) {
+ val = 0;
+ break;
+ }
+ }
+ reg.x[i][reg.n] = val;
+ cell_idx += nc;
+ if (errp) {
+ goto exit_reg_parse;
+ }
+ }
+ }
+
+exit_reg_parse:
+ if (object_dynamic_cast(dev, TYPE_FDT_GENERIC_MMAP)) {
+ FDTGenericMMapClass *fmc = FDT_GENERIC_MMAP_GET_CLASS(dev);
+ if (fmc->parse_reg) {
+ while (fmc->parse_reg(FDT_GENERIC_MMAP(dev), reg,
+ &error_abort) && qemu_in_coroutine()) {
+ fdt_init_yield(fdti);
+ }
+ }
+ }
+
+ return;
+}
+
static int fdt_init_qdev(char *node_path, FDTMachineInfo *fdti, char *compat)
{
Object *dev, *parent;
@@ -972,6 +1099,8 @@ static int fdt_init_qdev(char *node_path, FDTMachineInfo *fdti, char *compat)
}
}
+ fdt_parse_node_reg_prop(fdti, node_path, dev);
+
g_free(dev_type);
g_free(props);
--
2.43.0