From: Ruslan Ruslichenko <[email protected]> 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 <[email protected]> --- hw/core/fdt_generic_util.c | 103 +++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/hw/core/fdt_generic_util.c b/hw/core/fdt_generic_util.c index d57d9387a1..af20ffd9db 100644 --- a/hw/core/fdt_generic_util.c +++ b/hw/core/fdt_generic_util.c @@ -622,6 +622,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. * @@ -892,6 +908,8 @@ static int fdt_init_qdev(char *node_path, FDTMachineInfo *fdti, char *compat) { Object *dev, *parent; char *dev_type = NULL; + Error *errp = NULL; + int i; QEMUDevtreeProp *prop, *props; char parent_node_path[DT_PATH_LENGTH]; @@ -1022,6 +1040,91 @@ static int fdt_init_qdev(char *node_path, FDTMachineInfo *fdti, char *compat) } } + if (object_dynamic_cast(dev, TYPE_SYS_BUS_DEVICE) || + object_dynamic_cast(dev, TYPE_FDT_GENERIC_MMAP)) { + FDTGenericRegPropInfo reg = {0}; + char parent_path[DT_PATH_LENGTH]; + int cell_idx = 0; + bool extended = true; + + qemu_fdt_getprop_cell(fdti->fdt, node_path, "reg-extended", 0, false, + &errp); + if (errp) { + error_free(errp); + errp = NULL; + extended = false; + qemu_devtree_getparent(fdti->fdt, parent_path, node_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++, + false, &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)) { + fdt_init_yield(fdti); + } + 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(fdti->fdt, pnp, size_prop_name, + 0, true, &errp); + + 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); + reg.x[i][reg.n] = nc ? + qemu_fdt_getprop_sized_cell(fdti->fdt, node_path, + extended ? "reg-extended" + : "reg", + cell_idx, nc, &errp) + : 0; + 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)) { + fdt_init_yield(fdti); + } + } + } + } + g_free(dev_type); return 0; -- 2.43.0
