From 1762568ec52b8b29b5bc3b870adb00f46178b51e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 30 May 2025 16:37:28 +0100 Subject: [PATCH] [fdt] Provide ability to locate the parent device node Signed-off-by: Michael Brown --- src/core/fdt.c | 96 +++++++++++++++++++++++++++++++++++++++++- src/include/ipxe/fdt.h | 2 + src/tests/fdt_test.c | 12 ++++++ 3 files changed, 109 insertions(+), 1 deletion(-) diff --git a/src/core/fdt.c b/src/core/fdt.c index c8ae4d949..b2ee0133b 100644 --- a/src/core/fdt.c +++ b/src/core/fdt.c @@ -181,7 +181,7 @@ static int fdt_next ( struct fdt *fdt, struct fdt_descriptor *desc ) { * @ret rc Return status code */ static int fdt_enter ( struct fdt *fdt, unsigned int offset, - struct fdt_descriptor *desc ) { + struct fdt_descriptor *desc ) { int rc; /* Find begin node token */ @@ -212,6 +212,100 @@ static int fdt_enter ( struct fdt *fdt, unsigned int offset, } } +/** + * Find node relative depth + * + * @v fdt Device tree + * @v offset Starting node offset + * @v target Target node offset + * @ret depth Depth, or negative error + */ +static int fdt_depth ( struct fdt *fdt, unsigned int offset, + unsigned int target ) { + struct fdt_descriptor desc; + int depth; + int rc; + + /* Enter node */ + if ( ( rc = fdt_enter ( fdt, offset, &desc ) ) != 0 ) + return rc; + + /* Find target node */ + for ( depth = 0 ; depth >= 0 ; depth += desc.depth ) { + + /* Describe token */ + if ( ( rc = fdt_next ( fdt, &desc ) ) != 0 ) { + DBGC ( fdt, "FDT +%#04x has malformed node: %s\n", + offset, strerror ( rc ) ); + return rc; + } + + /* Check for target node */ + if ( desc.offset == target ) { + DBGC2 ( fdt, "FDT +%#04x has descendant node +%#04x " + "at depth +%d\n", offset, target, depth ); + return depth; + } + } + + DBGC ( fdt, "FDT +#%04x has no descendant node +%#04x\n", + offset, target ); + return -ENOENT; +} + +/** + * Find parent node + * + * @v fdt Device tree + * @v offset Starting node offset + * @v parent Parent node offset to fill in + * @ret rc Return status code + */ +int fdt_parent ( struct fdt *fdt, unsigned int offset, unsigned int *parent ) { + struct fdt_descriptor desc; + int pdepth; + int depth; + int rc; + + /* Find depth from root of tree */ + depth = fdt_depth ( fdt, 0, offset ); + if ( depth < 0 ) { + rc = depth; + return rc; + } + pdepth = ( depth - 1 ); + + /* Enter root node */ + if ( ( rc = fdt_enter ( fdt, 0, &desc ) ) != 0 ) + return rc; + *parent = desc.offset; + + /* Find parent node */ + for ( depth = 0 ; depth >= 0 ; depth += desc.depth ) { + + /* Describe token */ + if ( ( rc = fdt_next ( fdt, &desc ) ) != 0 ) { + DBGC ( fdt, "FDT +%#04x has malformed node: %s\n", + offset, strerror ( rc ) ); + return rc; + } + + /* Record possible parent node */ + if ( ( depth == pdepth ) && desc.name && ( ! desc.data ) ) + *parent = desc.offset; + + /* Check for target node */ + if ( desc.offset == offset ) { + DBGC2 ( fdt, "FDT +%#04x has parent node at +%#04x\n", + offset, *parent ); + return 0; + } + } + + DBGC ( fdt, "FDT +#%04x has no parent node\n", offset ); + return -ENOENT; +} + /** * Find child node * diff --git a/src/include/ipxe/fdt.h b/src/include/ipxe/fdt.h index 461b09632..d5a0d2179 100644 --- a/src/include/ipxe/fdt.h +++ b/src/include/ipxe/fdt.h @@ -170,6 +170,8 @@ fdt_reservations ( struct fdt *fdt ) { extern int fdt_describe ( struct fdt *fdt, unsigned int offset, struct fdt_descriptor *desc ); +extern int fdt_parent ( struct fdt *fdt, unsigned int offset, + unsigned int *parent ); extern int fdt_path ( struct fdt *fdt, const char *path, unsigned int *offset ); extern int fdt_alias ( struct fdt *fdt, const char *name, diff --git a/src/tests/fdt_test.c b/src/tests/fdt_test.c index 1dead2126..408f77c6d 100644 --- a/src/tests/fdt_test.c +++ b/src/tests/fdt_test.c @@ -263,6 +263,18 @@ static void fdt_test_exec ( void ) { ok ( strcmp ( desc.data, "memory" ) == 0 ); ok ( desc.depth == 0 ); + /* Verify parent lookup */ + ok ( fdt_path ( &fdt, "/soc/ethernet@10090000/ethernet-phy@0", + &offset ) == 0 ); + ok ( fdt_parent ( &fdt, offset, &offset ) == 0 ); + ok ( fdt_describe ( &fdt, offset, &desc ) == 0 ); + ok ( strcmp ( desc.name, "ethernet@10090000" ) == 0 ); + ok ( fdt_parent ( &fdt, offset, &offset ) == 0 ); + ok ( fdt_describe ( &fdt, offset, &desc ) == 0 ); + ok ( strcmp ( desc.name, "soc" ) == 0 ); + ok ( fdt_parent ( &fdt, offset, &offset ) == 0 ); + ok ( offset == 0 ); + /* Verify device tree creation */ image = image_memory ( "test.dtb", sifive_u, sizeof ( sifive_u ) ); ok ( image != NULL ); -- 2.47.2