[{"id":3672937,"web_url":"http://patchwork.ozlabs.org/comment/3672937/","msgid":"<ac8PO_EpAiWxczDy@zatzit>","list_archive_url":null,"date":"2026-04-03T00:52:11","subject":"Re: [PATCH v3 02/33] system/device_tree: add few parsing and\n traversal helpers","submitter":{"id":47,"url":"http://patchwork.ozlabs.org/api/people/47/","name":"David Gibson","email":"david@gibson.dropbear.id.au"},"content":"On Thu, Apr 02, 2026 at 11:55:47PM +0200, Ruslan Ruslichenko wrote:\n> From: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>\n> \n> The patch adds few utility functions for parsing FDT nodes.\n> The helpers are required for upcoming Hardware device tree\n> feature.\n\nIf you're building an entire fdt based machine type, it really seems\nlike you might want a \"live\" dt representation - the flattened format\nis great for communicating between things, but it's not a good data\nstructure if you're actively consulting it.\n\n> \n> Signed-off-by: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>\n> ---\n>  include/system/device_tree.h |  22 ++++\n>  system/device_tree.c         | 194 +++++++++++++++++++++++++++++++++++\n>  2 files changed, 216 insertions(+)\n> \n> diff --git a/include/system/device_tree.h b/include/system/device_tree.h\n> index 5667ff9538..bc378d38d0 100644\n> --- a/include/system/device_tree.h\n> +++ b/include/system/device_tree.h\n> @@ -116,6 +116,11 @@ const void *qemu_fdt_getprop(void *fdt, const char *node_path,\n>  uint32_t qemu_fdt_getprop_cell(void *fdt, const char *node_path,\n>                                 const char *property, int cell_id,\n>                                 Error **errp);\n> +\n> +const void *qemu_fdt_getprop_inherited(void *fdt, const char *node_path,\n> +                             const char *property, int *lenp, Error **errp);\n> +uint32_t qemu_fdt_getprop_cell_inherited(void *fdt, const char *node_path,\n> +                               const char *property, int cell_id, Error **errp);\n>  uint32_t qemu_fdt_get_phandle(void *fdt, const char *path);\n>  uint32_t qemu_fdt_alloc_phandle(void *fdt);\n>  int qemu_fdt_nop_node(void *fdt, const char *node_path);\n> @@ -191,6 +196,23 @@ int qemu_fdt_setprop_sized_cells_from_array(void *fdt,\n>                                                  qdt_tmp);                 \\\n>      })\n>  \n> +/* node queries */\n> +\n> +int qemu_devtree_get_num_children(void *fdt, const char *node_path);\n> +int qemu_devtree_get_children(void *fdt, const char *node_path,\n> +                                     int max_paths, char **returned_paths);\n> +int qemu_devtree_num_props(void *fdt, const char *node_path);\n> +\n> +/* node getters */\n> +\n> +int qemu_devtree_get_node_by_phandle(void *fdt, char *node_path, int phandle);\n> +char *qemu_devtree_getparent(void *fdt, const char *current);\n> +\n> +/* misc */\n> +\n> +int devtree_get_num_nodes(void *fdt);\n> +\n> +#define DT_PATH_LENGTH 1024\n>  \n>  /**\n>   * qemu_fdt_randomize_seeds:\n> diff --git a/system/device_tree.c b/system/device_tree.c\n> index d2db7bd355..1a70223712 100644\n> --- a/system/device_tree.c\n> +++ b/system/device_tree.c\n> @@ -464,6 +464,96 @@ uint32_t qemu_fdt_getprop_cell(void *fdt, const char *node_path,\n>      return be32_to_cpu(p[cell_id]);\n>  }\n>  \n> +const void *qemu_fdt_getprop_inherited(void *fdt, const char *node_path,\n> +                             const char *property, int *lenp, Error **errp)\n> +{\n> +    const void *found_val = NULL;\n> +    int found_len = 0;\n> +    int curr_offset = 0;\n> +    int temp_len;\n> +    char **tokens;\n> +    char **iter;\n> +\n> +    found_val = fdt_getprop(fdt, 0, property, &found_len);\n> +\n> +    tokens = g_strsplit(node_path + 1, \"/\", -1);\n> +\n> +    for (iter = tokens; *iter != NULL; iter++) {\n> +        if (**iter == '\\0') {\n> +            continue;\n> +        }\n> +\n> +        curr_offset = fdt_subnode_offset(fdt, curr_offset, *iter);\n> +        if (curr_offset < 0) {\n> +            error_setg(errp, \"%s: Path '%s' not found\",\n> +                       __func__, *iter);\n> +            g_strfreev(tokens);\n> +            return NULL;\n> +        }\n> +\n> +        const void *val = fdt_getprop(fdt, curr_offset, property, &temp_len);\n> +        if (val) {\n> +            found_val = val;\n> +            found_len = temp_len;\n> +        }\n> +    }\n> +    g_strfreev(tokens);\n> +\n> +    if (!found_val) {\n> +        error_setg(errp, \"%s: Property '%s' not found\",\n> +                   __func__, property);\n> +        return NULL;\n> +    }\n> +\n> +    if (lenp) {\n> +        *lenp = found_len;\n> +    }\n> +\n> +    return found_val;\n> +}\n> +\n> +uint32_t qemu_fdt_getprop_cell_inherited(void *fdt, const char *node_path,\n> +                               const char *property, int cell_id, Error **errp)\n> +{\n> +    int len;\n> +    const uint32_t *p;\n> +\n> +    p = qemu_fdt_getprop_inherited(fdt, node_path, property, &len, errp);\n> +    if (!p) {\n> +        return 0;\n> +    }\n> +    if (len < (cell_id + 1) * 4) {\n> +        error_setg(errp,\n> +                   \"%s: %s/%s is too short, need %d bytes for cell ind %d\",\n> +                   __func__, node_path, property, (cell_id + 1) * 4, cell_id);\n> +        return 0;\n> +    }\n> +    return be32_to_cpu(p[cell_id]);\n> +}\n> +\n> +char *qemu_devtree_getparent(void *fdt, const char *current)\n> +{\n> +    const char *sep;\n> +    int len;\n> +\n> +    if (!current || !strcmp(current, \"/\")) {\n> +        return NULL;\n> +    }\n> +\n> +    sep = strrchr(current, '/');\n> +    if (!sep) {\n> +        return NULL;\n> +    }\n> +\n> +    if (sep == current) {\n> +        len = 1;\n> +    } else {\n> +        len = sep - current;\n> +    }\n> +\n> +    return g_strndup(current, len);\n> +}\n> +\n>  uint32_t qemu_fdt_get_phandle(void *fdt, const char *path)\n>  {\n>      uint32_t r;\n> @@ -631,6 +721,110 @@ out:\n>      return ret;\n>  }\n>  \n> +int qemu_devtree_num_props(void *fdt, const char *node_path)\n> +{\n> +    int offset = fdt_path_offset(fdt, node_path);\n> +    int ret = 0;\n> +\n> +    for (offset = fdt_first_property_offset(fdt, offset);\n> +            offset != -FDT_ERR_NOTFOUND;\n> +            offset = fdt_next_property_offset(fdt, offset)) {\n> +        ret++;\n> +    }\n> +    return ret;\n> +}\n> +\n> +int qemu_devtree_get_children(void *fdt, const char *node_path,\n> +                                     int max_paths, char **returned_paths)\n> +{\n> +    int count = 0;\n> +    int subnode;\n> +    const char *name;\n> +    int offset = fdt_path_offset(fdt, node_path);\n> +\n> +    if (offset < 0) {\n> +        return offset;\n> +    }\n> +\n> +    bool is_root = (strcmp(node_path, \"/\") == 0);\n> +\n> +    fdt_for_each_subnode(subnode, fdt, offset) {\n> +        if (count >= max_paths) {\n> +            break;\n> +        }\n> +        name = fdt_get_name(fdt, subnode, NULL);\n> +        if (returned_paths) {\n> +            returned_paths[count] = g_strdup_printf(\"%s/%s\",\n> +                                                is_root ? \"\" : node_path, name);\n> +        }\n> +\n> +        ++count;\n> +    }\n> +\n> +    return count;\n> +}\n> +\n> +int qemu_devtree_get_num_children(void *fdt, const char *node_path)\n> +{\n> +    int count = 0;\n> +    int subnode;\n> +    int offset = fdt_path_offset(fdt, node_path);\n> +\n> +    if (offset < 0) {\n> +        return offset;\n> +    }\n> +\n> +    fdt_for_each_subnode(subnode, fdt, offset) {\n> +        ++count;\n> +    }\n> +\n> +    return count;\n> +}\n> +\n> +int qemu_devtree_get_node_by_phandle(void *fdt, char *node_path, int phandle)\n> +{\n> +    int offset = 0, cur_depth = 0;\n> +    int path_lens[64] = { 0 };\n> +\n> +    for (offset = 0; offset >= 0; offset = fdt_next_node(fdt, offset,\n> +                                                         &cur_depth)) {\n> +        if (cur_depth >= 64) {\n> +            break;\n> +        }\n> +        const char *name = fdt_get_name(fdt, offset, NULL);\n> +\n> +        int parent_len = (cur_depth > 0) ? path_lens[cur_depth - 1] : 0;\n> +        int len = snprintf(node_path + parent_len,\n> +                             DT_PATH_LENGTH - parent_len,\n> +                             \"%s%s\",\n> +                             (parent_len > 1) ? \"/\" : \"\",\n> +                             (cur_depth == 0) ? \"/\" : name);\n> +\n> +        path_lens[cur_depth] = parent_len + len;\n> +\n> +        if (fdt_get_phandle(fdt, offset) == phandle) {\n> +            return 0;\n> +        }\n> +    }\n> +\n> +    return -FDT_ERR_NOTFOUND;\n> +}\n> +\n> +int devtree_get_num_nodes(void *fdt)\n> +{\n> +    int num_nodes = 0;\n> +    int depth = 0, offset = 0;\n> +\n> +    for (;;) {\n> +        offset = fdt_next_node(fdt, offset, &depth);\n> +        num_nodes++;\n> +        if (offset <= 0 || depth <= 0) {\n> +            break;\n> +        }\n> +    }\n> +    return num_nodes;\n> +}\n> +\n>  void qmp_dumpdtb(const char *filename, Error **errp)\n>  {\n>      ERRP_GUARD();\n> -- \n> 2.43.0\n>","headers":{"Return-Path":"<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n secure) header.d=gibson.dropbear.id.au header.i=@gibson.dropbear.id.au\n header.a=rsa-sha256 header.s=202602 header.b=BKnZ20KD;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)"],"Received":["from lists.gnu.org (lists.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fn0Zk300mz1yD3\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 03 Apr 2026 11:53:16 +1100 (AEDT)","from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1w8Sm2-00051Z-Bo; Thu, 02 Apr 2026 20:52:34 -0400","from eggs.gnu.org ([2001:470:142:3::10])\n by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <dgibson@gandalf.ozlabs.org>)\n id 1w8Sm0-00051I-HN; Thu, 02 Apr 2026 20:52:32 -0400","from gandalf.ozlabs.org ([150.107.74.76] helo=mail.ozlabs.org)\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <dgibson@gandalf.ozlabs.org>)\n id 1w8Slv-0003cH-QR; Thu, 02 Apr 2026 20:52:32 -0400","by gandalf.ozlabs.org (Postfix, from userid 1007)\n id 4fn0YX4MNfz4wT1; Fri, 03 Apr 2026 11:52:16 +1100 (AEDT)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gibson.dropbear.id.au; s=202602; t=1775177536;\n bh=69SJj6SyLHhTzx7sxXWcNj0oPGwYP+ziwDPYCDPLbuE=;\n h=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n b=BKnZ20KDU8qv1K8MpDm5ZppUQfI7joAn0tYkKb5iaRcdRDPWHy5dHGLRIH/dVhUDL\n z3+H8inx8C3frOdjmQOODr9quAWW1UFYfaj+Ef0Enn10/aT9MKmuT8g/Mfz20rOycT\n UPIjTf5oOyprN4/U1eReV5k81TsrAMQH1dBL4jnGSlEUf1w35H/79ku5JoCz0kQ3H4\n lg/MwpDE4HyW+ResZv6UsEvIP6RJ83xxHqB9/4TWSzjrydJi1Fn1tqOXV0lqc5M9dm\n W8FHb3A+wkFXVbI6BbUW6wFCDVI6EW01Ii7thKKpWw1RcdyMnoRC/jt/Qf2CvIxLDu\n LQ121dmisEkng==","Date":"Fri, 3 Apr 2026 11:52:11 +1100","From":"David Gibson <david@gibson.dropbear.id.au>","To":"Ruslan Ruslichenko <ruslichenko.r@gmail.com>","Cc":"qemu-devel@nongnu.org, qemu-arm@nongnu.org, alex.bennee@linaro.org,\n peter.maydell@linaro.org, artem_mygaiev@epam.com,\n volodymyr_babchuk@epam.com, takahiro.nakata.wr@renesas.com,\n \"Edgar E . Iglesias\" <edgar.iglesias@gmail.com>,\n Ruslan_Ruslichenko@epam.com, balaton@eik.bme.hu,\n Alistair Francis <alistair.francis@wdc.com>","Subject":"Re: [PATCH v3 02/33] system/device_tree: add few parsing and\n traversal helpers","Message-ID":"<ac8PO_EpAiWxczDy@zatzit>","References":"<20260402215629.745866-1-ruslichenko.r@gmail.com>\n <20260402215629.745866-3-ruslichenko.r@gmail.com>","MIME-Version":"1.0","Content-Type":"multipart/signed; micalg=pgp-sha512;\n protocol=\"application/pgp-signature\"; boundary=\"bbeq6yawVZfWWRwW\"","Content-Disposition":"inline","In-Reply-To":"<20260402215629.745866-3-ruslichenko.r@gmail.com>","Received-SPF":"pass client-ip=150.107.74.76;\n envelope-from=dgibson@gandalf.ozlabs.org; helo=mail.ozlabs.org","X-Spam_score_int":"-40","X-Spam_score":"-4.1","X-Spam_bar":"----","X-Spam_report":"(-4.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,\n DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, HEADER_FROM_DIFFERENT_DOMAINS=0.249,\n RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001,\n RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_PASS=-0.001,\n SPF_PASS=-0.001 autolearn=ham autolearn_force=no","X-Spam_action":"no action","X-BeenThere":"qemu-devel@nongnu.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"qemu development <qemu-devel.nongnu.org>","List-Unsubscribe":"<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>","List-Archive":"<https://lists.nongnu.org/archive/html/qemu-devel>","List-Post":"<mailto:qemu-devel@nongnu.org>","List-Help":"<mailto:qemu-devel-request@nongnu.org?subject=help>","List-Subscribe":"<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>","Errors-To":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org","Sender":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org"}},{"id":3673242,"web_url":"http://patchwork.ozlabs.org/comment/3673242/","msgid":"<CAN-aV1H92A6OS8C12b2rij+kC84=EdxAoxH3ARW+rq9GvRsz_A@mail.gmail.com>","list_archive_url":null,"date":"2026-04-03T17:25:45","subject":"Re: [PATCH v3 02/33] system/device_tree: add few parsing and\n traversal helpers","submitter":{"id":92275,"url":"http://patchwork.ozlabs.org/api/people/92275/","name":"Ruslan Ruslichenko","email":"ruslichenko.r@gmail.com"},"content":"On Fri, Apr 3, 2026 at 2:52 AM David Gibson <david@gibson.dropbear.id.au> wrote:\n>\n> On Thu, Apr 02, 2026 at 11:55:47PM +0200, Ruslan Ruslichenko wrote:\n> > From: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>\n> >\n> > The patch adds few utility functions for parsing FDT nodes.\n> > The helpers are required for upcoming Hardware device tree\n> > feature.\n>\n> If you're building an entire fdt based machine type, it really seems\n> like you might want a \"live\" dt representation - the flattened format\n> is great for communicating between things, but it's not a good data\n> structure if you're actively consulting it.\n>\n\nHi David,\n\nThank you for the feedback.\nI will look into switching to a live DT representation for the next\nversion of the series.\n\nBR,\nRuslan\n\n> >\n> > Signed-off-by: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>\n> > ---\n> >  include/system/device_tree.h |  22 ++++\n> >  system/device_tree.c         | 194 +++++++++++++++++++++++++++++++++++\n> >  2 files changed, 216 insertions(+)\n> >\n> > diff --git a/include/system/device_tree.h b/include/system/device_tree.h\n> > index 5667ff9538..bc378d38d0 100644\n> > --- a/include/system/device_tree.h\n> > +++ b/include/system/device_tree.h\n> > @@ -116,6 +116,11 @@ const void *qemu_fdt_getprop(void *fdt, const char *node_path,\n> >  uint32_t qemu_fdt_getprop_cell(void *fdt, const char *node_path,\n> >                                 const char *property, int cell_id,\n> >                                 Error **errp);\n> > +\n> > +const void *qemu_fdt_getprop_inherited(void *fdt, const char *node_path,\n> > +                             const char *property, int *lenp, Error **errp);\n> > +uint32_t qemu_fdt_getprop_cell_inherited(void *fdt, const char *node_path,\n> > +                               const char *property, int cell_id, Error **errp);\n> >  uint32_t qemu_fdt_get_phandle(void *fdt, const char *path);\n> >  uint32_t qemu_fdt_alloc_phandle(void *fdt);\n> >  int qemu_fdt_nop_node(void *fdt, const char *node_path);\n> > @@ -191,6 +196,23 @@ int qemu_fdt_setprop_sized_cells_from_array(void *fdt,\n> >                                                  qdt_tmp);                 \\\n> >      })\n> >\n> > +/* node queries */\n> > +\n> > +int qemu_devtree_get_num_children(void *fdt, const char *node_path);\n> > +int qemu_devtree_get_children(void *fdt, const char *node_path,\n> > +                                     int max_paths, char **returned_paths);\n> > +int qemu_devtree_num_props(void *fdt, const char *node_path);\n> > +\n> > +/* node getters */\n> > +\n> > +int qemu_devtree_get_node_by_phandle(void *fdt, char *node_path, int phandle);\n> > +char *qemu_devtree_getparent(void *fdt, const char *current);\n> > +\n> > +/* misc */\n> > +\n> > +int devtree_get_num_nodes(void *fdt);\n> > +\n> > +#define DT_PATH_LENGTH 1024\n> >\n> >  /**\n> >   * qemu_fdt_randomize_seeds:\n> > diff --git a/system/device_tree.c b/system/device_tree.c\n> > index d2db7bd355..1a70223712 100644\n> > --- a/system/device_tree.c\n> > +++ b/system/device_tree.c\n> > @@ -464,6 +464,96 @@ uint32_t qemu_fdt_getprop_cell(void *fdt, const char *node_path,\n> >      return be32_to_cpu(p[cell_id]);\n> >  }\n> >\n> > +const void *qemu_fdt_getprop_inherited(void *fdt, const char *node_path,\n> > +                             const char *property, int *lenp, Error **errp)\n> > +{\n> > +    const void *found_val = NULL;\n> > +    int found_len = 0;\n> > +    int curr_offset = 0;\n> > +    int temp_len;\n> > +    char **tokens;\n> > +    char **iter;\n> > +\n> > +    found_val = fdt_getprop(fdt, 0, property, &found_len);\n> > +\n> > +    tokens = g_strsplit(node_path + 1, \"/\", -1);\n> > +\n> > +    for (iter = tokens; *iter != NULL; iter++) {\n> > +        if (**iter == '\\0') {\n> > +            continue;\n> > +        }\n> > +\n> > +        curr_offset = fdt_subnode_offset(fdt, curr_offset, *iter);\n> > +        if (curr_offset < 0) {\n> > +            error_setg(errp, \"%s: Path '%s' not found\",\n> > +                       __func__, *iter);\n> > +            g_strfreev(tokens);\n> > +            return NULL;\n> > +        }\n> > +\n> > +        const void *val = fdt_getprop(fdt, curr_offset, property, &temp_len);\n> > +        if (val) {\n> > +            found_val = val;\n> > +            found_len = temp_len;\n> > +        }\n> > +    }\n> > +    g_strfreev(tokens);\n> > +\n> > +    if (!found_val) {\n> > +        error_setg(errp, \"%s: Property '%s' not found\",\n> > +                   __func__, property);\n> > +        return NULL;\n> > +    }\n> > +\n> > +    if (lenp) {\n> > +        *lenp = found_len;\n> > +    }\n> > +\n> > +    return found_val;\n> > +}\n> > +\n> > +uint32_t qemu_fdt_getprop_cell_inherited(void *fdt, const char *node_path,\n> > +                               const char *property, int cell_id, Error **errp)\n> > +{\n> > +    int len;\n> > +    const uint32_t *p;\n> > +\n> > +    p = qemu_fdt_getprop_inherited(fdt, node_path, property, &len, errp);\n> > +    if (!p) {\n> > +        return 0;\n> > +    }\n> > +    if (len < (cell_id + 1) * 4) {\n> > +        error_setg(errp,\n> > +                   \"%s: %s/%s is too short, need %d bytes for cell ind %d\",\n> > +                   __func__, node_path, property, (cell_id + 1) * 4, cell_id);\n> > +        return 0;\n> > +    }\n> > +    return be32_to_cpu(p[cell_id]);\n> > +}\n> > +\n> > +char *qemu_devtree_getparent(void *fdt, const char *current)\n> > +{\n> > +    const char *sep;\n> > +    int len;\n> > +\n> > +    if (!current || !strcmp(current, \"/\")) {\n> > +        return NULL;\n> > +    }\n> > +\n> > +    sep = strrchr(current, '/');\n> > +    if (!sep) {\n> > +        return NULL;\n> > +    }\n> > +\n> > +    if (sep == current) {\n> > +        len = 1;\n> > +    } else {\n> > +        len = sep - current;\n> > +    }\n> > +\n> > +    return g_strndup(current, len);\n> > +}\n> > +\n> >  uint32_t qemu_fdt_get_phandle(void *fdt, const char *path)\n> >  {\n> >      uint32_t r;\n> > @@ -631,6 +721,110 @@ out:\n> >      return ret;\n> >  }\n> >\n> > +int qemu_devtree_num_props(void *fdt, const char *node_path)\n> > +{\n> > +    int offset = fdt_path_offset(fdt, node_path);\n> > +    int ret = 0;\n> > +\n> > +    for (offset = fdt_first_property_offset(fdt, offset);\n> > +            offset != -FDT_ERR_NOTFOUND;\n> > +            offset = fdt_next_property_offset(fdt, offset)) {\n> > +        ret++;\n> > +    }\n> > +    return ret;\n> > +}\n> > +\n> > +int qemu_devtree_get_children(void *fdt, const char *node_path,\n> > +                                     int max_paths, char **returned_paths)\n> > +{\n> > +    int count = 0;\n> > +    int subnode;\n> > +    const char *name;\n> > +    int offset = fdt_path_offset(fdt, node_path);\n> > +\n> > +    if (offset < 0) {\n> > +        return offset;\n> > +    }\n> > +\n> > +    bool is_root = (strcmp(node_path, \"/\") == 0);\n> > +\n> > +    fdt_for_each_subnode(subnode, fdt, offset) {\n> > +        if (count >= max_paths) {\n> > +            break;\n> > +        }\n> > +        name = fdt_get_name(fdt, subnode, NULL);\n> > +        if (returned_paths) {\n> > +            returned_paths[count] = g_strdup_printf(\"%s/%s\",\n> > +                                                is_root ? \"\" : node_path, name);\n> > +        }\n> > +\n> > +        ++count;\n> > +    }\n> > +\n> > +    return count;\n> > +}\n> > +\n> > +int qemu_devtree_get_num_children(void *fdt, const char *node_path)\n> > +{\n> > +    int count = 0;\n> > +    int subnode;\n> > +    int offset = fdt_path_offset(fdt, node_path);\n> > +\n> > +    if (offset < 0) {\n> > +        return offset;\n> > +    }\n> > +\n> > +    fdt_for_each_subnode(subnode, fdt, offset) {\n> > +        ++count;\n> > +    }\n> > +\n> > +    return count;\n> > +}\n> > +\n> > +int qemu_devtree_get_node_by_phandle(void *fdt, char *node_path, int phandle)\n> > +{\n> > +    int offset = 0, cur_depth = 0;\n> > +    int path_lens[64] = { 0 };\n> > +\n> > +    for (offset = 0; offset >= 0; offset = fdt_next_node(fdt, offset,\n> > +                                                         &cur_depth)) {\n> > +        if (cur_depth >= 64) {\n> > +            break;\n> > +        }\n> > +        const char *name = fdt_get_name(fdt, offset, NULL);\n> > +\n> > +        int parent_len = (cur_depth > 0) ? path_lens[cur_depth - 1] : 0;\n> > +        int len = snprintf(node_path + parent_len,\n> > +                             DT_PATH_LENGTH - parent_len,\n> > +                             \"%s%s\",\n> > +                             (parent_len > 1) ? \"/\" : \"\",\n> > +                             (cur_depth == 0) ? \"/\" : name);\n> > +\n> > +        path_lens[cur_depth] = parent_len + len;\n> > +\n> > +        if (fdt_get_phandle(fdt, offset) == phandle) {\n> > +            return 0;\n> > +        }\n> > +    }\n> > +\n> > +    return -FDT_ERR_NOTFOUND;\n> > +}\n> > +\n> > +int devtree_get_num_nodes(void *fdt)\n> > +{\n> > +    int num_nodes = 0;\n> > +    int depth = 0, offset = 0;\n> > +\n> > +    for (;;) {\n> > +        offset = fdt_next_node(fdt, offset, &depth);\n> > +        num_nodes++;\n> > +        if (offset <= 0 || depth <= 0) {\n> > +            break;\n> > +        }\n> > +    }\n> > +    return num_nodes;\n> > +}\n> > +\n> >  void qmp_dumpdtb(const char *filename, Error **errp)\n> >  {\n> >      ERRP_GUARD();\n> > --\n> > 2.43.0\n> >\n>\n> --\n> David Gibson (he or they)       | I'll have my music baroque, and my code\n> david AT gibson.dropbear.id.au  | minimalist, thank you, not the other way\n>                                 | around.\n> http://www.ozlabs.org/~dgibson","headers":{"Return-Path":"<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=V1LJ2eHS;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)"],"Received":["from lists.gnu.org (lists.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fnQdM2y4Hz1xtJ\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 04 Apr 2026 04:27:01 +1100 (AEDT)","from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1w8iHU-0004rV-Kd; Fri, 03 Apr 2026 13:26:04 -0400","from eggs.gnu.org ([2001:470:142:3::10])\n by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <ruslichenko.r@gmail.com>)\n id 1w8iHQ-0004qA-Nu\n for qemu-devel@nongnu.org; Fri, 03 Apr 2026 13:26:01 -0400","from mail-ot1-x335.google.com ([2607:f8b0:4864:20::335])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)\n (Exim 4.90_1) (envelope-from <ruslichenko.r@gmail.com>)\n id 1w8iHO-0003hV-Rw\n for qemu-devel@nongnu.org; Fri, 03 Apr 2026 13:26:00 -0400","by mail-ot1-x335.google.com with SMTP id\n 46e09a7af769-7d4c383f2fcso1825797a34.0\n for <qemu-devel@nongnu.org>; Fri, 03 Apr 2026 10:25:58 -0700 (PDT)"],"ARC-Seal":"i=1; a=rsa-sha256; t=1775237157; cv=none;\n d=google.com; s=arc-20240605;\n b=iTQvDYhpU54AZMUfxoR2XkGhjVDceYcD+W8WMIGfD7oa8UfgWJnAjvwHcwJZ06UjFP\n co77n8P7TsoO0r4eANcC24zYoU+Fw5PANc/fgoErxwz3uTF9ye3wYVHnHTavHtE0KL4i\n QOs9GIgdS28NaqMmkF3thXICxLB0BhKuXcs3NOtIlqylU1WmrloSmGHEqom5zYidH6X7\n aj9zsj5rkF4RVM//lZlzrQ5HWklH0yrSys4ETOwCX6A+u39WHAKZ4bMCVyQVhTRJGStE\n 7V+mCrIl6kdFktRR8rbFNl521SBSU2M8hXXGK0pSHCnuRP9h9Oyb07tSKLE9/DRZmKml\n Uqyg==","ARC-Message-Signature":"i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;\n s=arc-20240605;\n h=content-transfer-encoding:cc:to:subject:message-id:date:from\n :in-reply-to:references:mime-version:dkim-signature;\n bh=pDmghM8ARRiPsj8Q17aW1dNVR7bL8LTO6qYzIbK58Og=;\n fh=U39PmFavrHPjECQQd1GB3et4CkI7X+0j50odXDdWbyc=;\n b=ObDEQA01TyOi40rsDFj/G9G9VZZmLIhQgggCw8GgZyLOfwnsyHe0RiRgHHbrqLEE56\n yM37npK/+gGY1iM2x1VInjgeRZ2/8NtQN3ECMxd7r+NbivQTVLFFfQqfRD4MEGdNNw/u\n Qu7K0NYV7AMpjE0rLFYbpo4wYHpffRRIwlWyJVTlzx6kuVYjd2BSRo5u9L0DlyKyG8BN\n ji+5Mmw7BZf4GxpUwXw0pn8K3qbwdcz0MLRHKXxFhS0kzRHO5fc1jwhwpC3z5NE+Xz6C\n ZH2okIu5Tlwm9lwR+4I8wtRIyd8JaDYTfOMLDLdeMYdLbyD1+LuJqa3k6gmrNJOFVCgf\n KETg==; darn=nongnu.org","ARC-Authentication-Results":"i=1; mx.google.com; arc=none","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20251104; t=1775237157; x=1775841957; darn=nongnu.org;\n h=content-transfer-encoding:cc:to:subject:message-id:date:from\n :in-reply-to:references:mime-version:from:to:cc:subject:date\n :message-id:reply-to;\n bh=pDmghM8ARRiPsj8Q17aW1dNVR7bL8LTO6qYzIbK58Og=;\n b=V1LJ2eHSCnFhOTjY54D8FwSrf3EJ0ZNiqrWSRmIlwxyX9G93vqkCRI+BbIbTQEgizP\n U4QlUnQ+soBpxyNxNv+FwyGxyG8soZjLEXgSvDUeBxCT6gEytUahNa5ta+Z6l0tyBVlh\n hs20P8R2YnKEu+CXLhaI+4u+KWZfE9YHcejgFzldWexCI/hxCOwxn4hWMJIwESNbrBb7\n DubUVfP9RtGjl9ylgNEOxMcs6LAfgNgkEhtK/Tu1rxBtq+mQf0LhuiPMlVgmCv1vLqIE\n hMViKV6Xi1cCdfQuYzjBBd9c8nGzl6ejVmTgeO5VFaeCc16UVtFApBYf1w7YZBoQCDkn\n FDug==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1775237157; x=1775841957;\n h=content-transfer-encoding:cc:to:subject:message-id:date:from\n :in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=pDmghM8ARRiPsj8Q17aW1dNVR7bL8LTO6qYzIbK58Og=;\n b=LpLhmNNviXSJJjzsQDTLnH4rTs087iTR+eymT0pf9OtxdCGkLWSydDC8dVLbeE3D1m\n VbIoBD1VwI/5tFffExgfPQtrbGSPq56iMoDlBF0dFmdyyZGTzsnRCovZRTyZ3vojOUQG\n 7l06KY4UkVr3YjZ/HfQzpPKLgk6ZTbOTkcVqGN3VYYcyHVMFxTbPbfVKX2fiYMOtw8cT\n /6xsIGJ/YUgyFzm3W8BC14O9bWxVxK8MzT6QfsmkhGY9qqHrcXYnNrgpNSvSm6zy8o0V\n zEgNQLuW9J+SKE2w9PkQahCczope4SKIsPap0y1aVCX+M3AxOGi/M+dUrsPnKlYJkKwR\n lueg==","X-Gm-Message-State":"AOJu0YwLwnOc9C/iTL2M6lzB8Fcb5QKp3Iz+v3qiGfeMv/t2rbmrRkg+\n uvX/2FIObQEbkmnvTk04vWHvcLCj5aqNDQoLa8i04qzw1T3c6Apn0O+SczgD+ZSs2vkaeZs7U9v\n Rd4Mq8Ttsho+0vjCbPjPTzjk98nfRels=","X-Gm-Gg":"ATEYQzxdzOezXI2QpxqgHX1UU42RhAUGMcSt16lRT7l13qYVzFR5/mYqInnAZJ0QDaN\n 2dBICRLI1xGbgC/LkV/I9iiAZAHyZUMHDXexlS4YH6bAQH/+HhT8VTfy17L7j+PrYCgFGHBcMbj\n +Y/mQBbcI9yLBB/cGbeS4VSGTmYy+haP5UfhjqLzgLvxTS0xYQ4Zt4jibSe1lhyK/h5+23QYLOr\n R78idY9rTm28clWyptQpEaOf437dnVpmuGCNKr1DGAOlsR4VI+1SPQRWP4ME2D2NdYZf28lLaPz\n Tg8RnNc=","X-Received":"by 2002:a05:6830:6c10:b0:7d7:bf70:af2 with SMTP id\n 46e09a7af769-7dbb732ffc9mr2221895a34.1.1775237156928; Fri, 03 Apr 2026\n 10:25:56 -0700 (PDT)","MIME-Version":"1.0","References":"<20260402215629.745866-1-ruslichenko.r@gmail.com>\n <20260402215629.745866-3-ruslichenko.r@gmail.com> <ac8PO_EpAiWxczDy@zatzit>","In-Reply-To":"<ac8PO_EpAiWxczDy@zatzit>","From":"Ruslan Ruslichenko <ruslichenko.r@gmail.com>","Date":"Fri, 3 Apr 2026 19:25:45 +0200","X-Gm-Features":"AQROBzCLkjDP733gcPutaBWRl8O4OViTBh3PcJ-axO0TuztlCvj5kfUZY9WTwoQ","Message-ID":"\n <CAN-aV1H92A6OS8C12b2rij+kC84=EdxAoxH3ARW+rq9GvRsz_A@mail.gmail.com>","Subject":"Re: [PATCH v3 02/33] system/device_tree: add few parsing and\n traversal helpers","To":"David Gibson <david@gibson.dropbear.id.au>","Cc":"qemu-devel@nongnu.org, qemu-arm@nongnu.org, alex.bennee@linaro.org,\n peter.maydell@linaro.org, artem_mygaiev@epam.com, volodymyr_babchuk@epam.com,\n takahiro.nakata.wr@renesas.com,\n \"Edgar E . Iglesias\" <edgar.iglesias@gmail.com>, Ruslan_Ruslichenko@epam.com,\n balaton@eik.bme.hu, Alistair Francis <alistair.francis@wdc.com>","Content-Type":"text/plain; charset=\"UTF-8\"","Content-Transfer-Encoding":"quoted-printable","Received-SPF":"pass client-ip=2607:f8b0:4864:20::335;\n envelope-from=ruslichenko.r@gmail.com; helo=mail-ot1-x335.google.com","X-Spam_score_int":"-20","X-Spam_score":"-2.1","X-Spam_bar":"--","X-Spam_report":"(-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,\n DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001,\n RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,\n SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no","X-Spam_action":"no action","X-BeenThere":"qemu-devel@nongnu.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"qemu development <qemu-devel.nongnu.org>","List-Unsubscribe":"<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>","List-Archive":"<https://lists.nongnu.org/archive/html/qemu-devel>","List-Post":"<mailto:qemu-devel@nongnu.org>","List-Help":"<mailto:qemu-devel-request@nongnu.org?subject=help>","List-Subscribe":"<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>","Errors-To":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org","Sender":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org"}}]