]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[fdt] Provide ability to locate the parent device node
authorMichael Brown <mcb30@ipxe.org>
Fri, 30 May 2025 15:37:28 +0000 (16:37 +0100)
committerMichael Brown <mcb30@ipxe.org>
Fri, 30 May 2025 15:38:39 +0000 (16:38 +0100)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/core/fdt.c
src/include/ipxe/fdt.h
src/tests/fdt_test.c

index c8ae4d94915491af77cf66b6208ec74f6664ea11..b2ee0133b9a247f77135fe016b2a2bd694170fd5 100644 (file)
@@ -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
  *
index 461b09632624efbc2b5d637637d257dd16300055..d5a0d21795611e7024f787c90859070bdb5bdb26 100644 (file)
@@ -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,
index 1dead2126071b40d33753e90ac9ff72af2b29521..408f77c6d65353a4b67e28fb1ff01a0d4dadac9f 100644 (file)
@@ -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 );