[PATCH 14/27] hw/core/fdt_generic_util: map device memory

Ruslan Ruslichenko posted 27 patches 1 week, 4 days ago
Maintainers: Peter Maydell <peter.maydell@linaro.org>, Alistair Francis <alistair@alistair23.me>, "Edgar E. Iglesias" <edgar.iglesias@gmail.com>, Eduardo Habkost <eduardo@habkost.net>, Marcel Apfelbaum <marcel.apfelbaum@gmail.com>, "Philippe Mathieu-Daudé" <philmd@linaro.org>, Yanan Wang <wangyanan55@huawei.com>, Zhao Liu <zhao1.liu@intel.com>, Paolo Bonzini <pbonzini@redhat.com>, "Daniel P. Berrangé" <berrange@redhat.com>, David Gibson <david@gibson.dropbear.id.au>, Peter Xu <peterx@redhat.com>
[PATCH 14/27] hw/core/fdt_generic_util: map device memory
Posted by Ruslan Ruslichenko 1 week, 4 days ago
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 | 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