* [RFC PATCH 01/77] checks: Use consistent type for strspn() returned value
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
@ 2026-01-12 14:18 ` Herve Codina
2026-01-12 14:55 ` Ayush Singh
2026-01-13 3:08 ` David Gibson
2026-01-12 14:18 ` [RFC PATCH 02/77] Introduce v18 dtb version Herve Codina
` (78 subsequent siblings)
79 siblings, 2 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:18 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
strspn() returns a size_t value.
The function is called in several places and in all places this value is
stored in a size_t variable except in check_node_name_chars_strict().
Fix the variable type used in check_node_name_chars_strict().
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
checks.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/checks.c b/checks.c
index 5d09216..041e565 100644
--- a/checks.c
+++ b/checks.c
@@ -324,7 +324,7 @@ ERROR(node_name_chars, check_node_name_chars, NODECHARS);
static void check_node_name_chars_strict(struct check *c, struct dt_info *dti,
struct node *node)
{
- int n = strspn(node->name, c->data);
+ size_t n = strspn(node->name, c->data);
if (n < node->basenamelen)
FAIL(c, dti, node, "Character '%c' not recommended in node name",
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 01/77] checks: Use consistent type for strspn() returned value
2026-01-12 14:18 ` [RFC PATCH 01/77] checks: Use consistent type for strspn() returned value Herve Codina
@ 2026-01-12 14:55 ` Ayush Singh
2026-01-13 3:08 ` David Gibson
1 sibling, 0 replies; 160+ messages in thread
From: Ayush Singh @ 2026-01-12 14:55 UTC (permalink / raw)
To: Herve Codina, David Gibson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
On 1/12/26 7:48 PM, Herve Codina wrote:
> strspn() returns a size_t value.
>
> The function is called in several places and in all places this value is
> stored in a size_t variable except in check_node_name_chars_strict().
>
> Fix the variable type used in check_node_name_chars_strict().
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> checks.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/checks.c b/checks.c
> index 5d09216..041e565 100644
> --- a/checks.c
> +++ b/checks.c
> @@ -324,7 +324,7 @@ ERROR(node_name_chars, check_node_name_chars, NODECHARS);
> static void check_node_name_chars_strict(struct check *c, struct dt_info *dti,
> struct node *node)
> {
> - int n = strspn(node->name, c->data);
> + size_t n = strspn(node->name, c->data);
>
> if (n < node->basenamelen)
> FAIL(c, dti, node, "Character '%c' not recommended in node name",
Reviewed-by: Ayush Singh <ayush@beagleboard.org>
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 01/77] checks: Use consistent type for strspn() returned value
2026-01-12 14:18 ` [RFC PATCH 01/77] checks: Use consistent type for strspn() returned value Herve Codina
2026-01-12 14:55 ` Ayush Singh
@ 2026-01-13 3:08 ` David Gibson
2026-01-13 4:42 ` David Gibson
1 sibling, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-13 3:08 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 1249 bytes --]
On Mon, Jan 12, 2026 at 03:18:51PM +0100, Herve Codina wrote:
> strspn() returns a size_t value.
>
> The function is called in several places and in all places this value is
> stored in a size_t variable except in check_node_name_chars_strict().
>
> Fix the variable type used in check_node_name_chars_strict().
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
This one makes sense regardless of the rest, so, merged.
> ---
> checks.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/checks.c b/checks.c
> index 5d09216..041e565 100644
> --- a/checks.c
> +++ b/checks.c
> @@ -324,7 +324,7 @@ ERROR(node_name_chars, check_node_name_chars, NODECHARS);
> static void check_node_name_chars_strict(struct check *c, struct dt_info *dti,
> struct node *node)
> {
> - int n = strspn(node->name, c->data);
> + size_t n = strspn(node->name, c->data);
>
> if (n < node->basenamelen)
> FAIL(c, dti, node, "Character '%c' not recommended in node name",
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 01/77] checks: Use consistent type for strspn() returned value
2026-01-13 3:08 ` David Gibson
@ 2026-01-13 4:42 ` David Gibson
2026-01-13 8:02 ` Herve Codina
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-13 4:42 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 1864 bytes --]
On Tue, Jan 13, 2026 at 02:08:54PM +1100, David Gibson wrote:
> On Mon, Jan 12, 2026 at 03:18:51PM +0100, Herve Codina wrote:
> > strspn() returns a size_t value.
> >
> > The function is called in several places and in all places this value is
> > stored in a size_t variable except in check_node_name_chars_strict().
> >
> > Fix the variable type used in check_node_name_chars_strict().
> >
> > Signed-off-by: Herve Codina <herve.codina@bootlin.com>
>
> This one makes sense regardless of the rest, so, merged.
I spoke too soon. This causes a compile error:
https://github.com/dgibson/dtc/actions/runs/20944813954/job/60185662154#step:5:130
For some reason it's only showing on the make build, not meson. I
guess there must be a mismatch in which warnings are enabled.
>
> > ---
> > checks.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/checks.c b/checks.c
> > index 5d09216..041e565 100644
> > --- a/checks.c
> > +++ b/checks.c
> > @@ -324,7 +324,7 @@ ERROR(node_name_chars, check_node_name_chars, NODECHARS);
> > static void check_node_name_chars_strict(struct check *c, struct dt_info *dti,
> > struct node *node)
> > {
> > - int n = strspn(node->name, c->data);
> > + size_t n = strspn(node->name, c->data);
> >
> > if (n < node->basenamelen)
> > FAIL(c, dti, node, "Character '%c' not recommended in node name",
> > --
> > 2.52.0
> >
> >
>
> --
> David Gibson (he or they) | I'll have my music baroque, and my code
> david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
> | around.
> http://www.ozlabs.org/~dgibson
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 01/77] checks: Use consistent type for strspn() returned value
2026-01-13 4:42 ` David Gibson
@ 2026-01-13 8:02 ` Herve Codina
0 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-13 8:02 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
Hi David,
On Tue, 13 Jan 2026 15:42:31 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Tue, Jan 13, 2026 at 02:08:54PM +1100, David Gibson wrote:
> > On Mon, Jan 12, 2026 at 03:18:51PM +0100, Herve Codina wrote:
> > > strspn() returns a size_t value.
> > >
> > > The function is called in several places and in all places this value is
> > > stored in a size_t variable except in check_node_name_chars_strict().
> > >
> > > Fix the variable type used in check_node_name_chars_strict().
> > >
> > > Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> >
> > This one makes sense regardless of the rest, so, merged.
>
> I spoke too soon. This causes a compile error:
>
> https://github.com/dgibson/dtc/actions/runs/20944813954/job/60185662154#step:5:130
>
> For some reason it's only showing on the make build, not meson. I
> guess there must be a mismatch in which warnings are enabled.
I used only meson and so I missed the signed/unsigned comparison warning.
I will remove this signed/unsigned warning in the next iteration.
Best regards,
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 02/77] Introduce v18 dtb version
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
2026-01-12 14:18 ` [RFC PATCH 01/77] checks: Use consistent type for strspn() returned value Herve Codina
@ 2026-01-12 14:18 ` Herve Codina
2026-01-15 0:12 ` David Gibson
2026-01-12 14:18 ` [RFC PATCH 03/77] libfdt: Introduce fdt_next_tag_full() and use it in fdt_next_tag() Herve Codina
` (77 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:18 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
This v18 version will add support for
- metadata in device-tree blobs in order to have a better handling of
phandles and unresolved references.
- Addon device-tree blob (successor of device-tree overlay)
- Import and export symbols feature
- multiple trees in a addon device-tree blob (i.e. root device tree and
orphan node tree)
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
dtc.h | 2 +-
fdtdump.c | 2 +-
flattree.c | 2 ++
libfdt/fdt.h | 1 +
libfdt/fdt_rw.c | 13 +++++++------
libfdt/libfdt.h | 2 +-
tests/pylibfdt_tests.py | 2 +-
tests/trees.S | 2 +-
8 files changed, 15 insertions(+), 11 deletions(-)
diff --git a/dtc.h b/dtc.h
index 3a220b9..186caad 100644
--- a/dtc.h
+++ b/dtc.h
@@ -29,7 +29,7 @@
#define debug(...)
#endif
-#define DEFAULT_FDT_VERSION 17
+#define DEFAULT_FDT_VERSION 18
/*
* Command line options
diff --git a/fdtdump.c b/fdtdump.c
index d424869..ec25edf 100644
--- a/fdtdump.c
+++ b/fdtdump.c
@@ -18,7 +18,7 @@
#include "util.h"
#define FDT_MAGIC_SIZE 4
-#define MAX_VERSION 17U
+#define MAX_VERSION 18U
#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
#define PALIGN(p, a) ((void *)(ALIGN((uintptr_t)(p), (a))))
diff --git a/flattree.c b/flattree.c
index 30e6de2..c3887da 100644
--- a/flattree.c
+++ b/flattree.c
@@ -30,6 +30,8 @@ static struct version_info {
FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_NOPS},
{17, 16, FDT_V17_SIZE,
FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS},
+ {18, 18, FDT_V18_SIZE,
+ FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS},
};
struct emitter {
diff --git a/libfdt/fdt.h b/libfdt/fdt.h
index a07abfc..9372353 100644
--- a/libfdt/fdt.h
+++ b/libfdt/fdt.h
@@ -62,5 +62,6 @@ struct fdt_property {
#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t))
#define FDT_V16_SIZE FDT_V3_SIZE
#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t))
+#define FDT_V18_SIZE FDT_V17_SIZE
#endif /* FDT_H */
diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c
index 7475caf..00e32bb 100644
--- a/libfdt/fdt_rw.c
+++ b/libfdt/fdt_rw.c
@@ -28,13 +28,13 @@ static int fdt_rw_probe_(void *fdt)
return 0;
FDT_RO_PROBE(fdt);
- if (!can_assume(LATEST) && fdt_version(fdt) < 17)
+ if (!can_assume(LATEST) && fdt_version(fdt) < 18)
return -FDT_ERR_BADVERSION;
if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
fdt_size_dt_struct(fdt)))
return -FDT_ERR_BADLAYOUT;
- if (!can_assume(LATEST) && fdt_version(fdt) > 17)
- fdt_set_version(fdt, 17);
+ if (!can_assume(LATEST) && fdt_version(fdt) > 18)
+ fdt_set_version(fdt, 18);
return 0;
}
@@ -455,7 +455,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
err = fdt_move(fdt, buf, bufsize);
if (err)
return err;
- fdt_set_version(buf, 17);
+ fdt_set_version(buf, 18);
+ fdt_set_last_comp_version(buf, 18);
fdt_set_size_dt_struct(buf, struct_size);
fdt_set_totalsize(buf, bufsize);
return 0;
@@ -484,8 +485,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
fdt_set_magic(buf, FDT_MAGIC);
fdt_set_totalsize(buf, bufsize);
- fdt_set_version(buf, 17);
- fdt_set_last_comp_version(buf, 16);
+ fdt_set_version(buf, 18);
+ fdt_set_last_comp_version(buf, 18);
fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
return 0;
diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h
index 7a10f66..c5cd35d 100644
--- a/libfdt/libfdt.h
+++ b/libfdt/libfdt.h
@@ -15,7 +15,7 @@ extern "C" {
#define FDT_FIRST_SUPPORTED_VERSION 0x02
#define FDT_LAST_COMPATIBLE_VERSION 0x10
-#define FDT_LAST_SUPPORTED_VERSION 0x11
+#define FDT_LAST_SUPPORTED_VERSION 0x12
/* Error codes: informative error codes */
#define FDT_ERR_NOTFOUND 1
diff --git a/tests/pylibfdt_tests.py b/tests/pylibfdt_tests.py
index a4f73ed..373e11a 100644
--- a/tests/pylibfdt_tests.py
+++ b/tests/pylibfdt_tests.py
@@ -288,7 +288,7 @@ class PyLibfdtBasicTests(unittest.TestCase):
self.assertEqual(self.fdt.off_dt_struct(), 88)
self.assertEqual(self.fdt.off_dt_strings(), 652)
self.assertEqual(self.fdt.off_mem_rsvmap(), 40)
- self.assertEqual(self.fdt.version(), 17)
+ self.assertEqual(self.fdt.version(), 18)
self.assertEqual(self.fdt.last_comp_version(), 16)
self.assertEqual(self.fdt.boot_cpuid_phys(), 0)
self.assertEqual(self.fdt.size_dt_strings(), 105)
diff --git a/tests/trees.S b/tests/trees.S
index d69f7f1..ecd43bc 100644
--- a/tests/trees.S
+++ b/tests/trees.S
@@ -17,7 +17,7 @@
fdtlong (\tree\()_struct - \tree)
fdtlong (\tree\()_strings - \tree)
fdtlong (\tree\()_rsvmap - \tree)
- fdtlong 0x11
+ fdtlong 0x12
fdtlong 0x10
fdtlong 0
fdtlong (\tree\()_strings_end - \tree\()_strings)
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 02/77] Introduce v18 dtb version
2026-01-12 14:18 ` [RFC PATCH 02/77] Introduce v18 dtb version Herve Codina
@ 2026-01-15 0:12 ` David Gibson
2026-01-16 9:09 ` Herve Codina
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-15 0:12 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 6238 bytes --]
On Mon, Jan 12, 2026 at 03:18:52PM +0100, Herve Codina wrote:
> This v18 version will add support for
> - metadata in device-tree blobs in order to have a better handling of
> phandles and unresolved references.
> - Addon device-tree blob (successor of device-tree overlay)
> - Import and export symbols feature
> - multiple trees in a addon device-tree blob (i.e. root device tree and
> orphan node tree)
So, once this patch is applied, the rest of the series pretty much has
to be applied "atomically" - otherwise a version built in the interim
will be lying in saying that it supports v18.
I therefore suggest moving any changes that *can* be moved before this
patch, should be moved before this patch. That will assist in
reviewing and merging the series piecemeal, rather than as a single
giant blob.
Regarding the content itself. It seems like this is a pretty major
change to the dtb format - maybe that would suggest bumping the
version by more than one (e.g. like we went from v3 to v16 in the
past).
It would also be nice to have some docs for the new dtb extensions
before or at the same time as this.
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> dtc.h | 2 +-
> fdtdump.c | 2 +-
> flattree.c | 2 ++
> libfdt/fdt.h | 1 +
> libfdt/fdt_rw.c | 13 +++++++------
> libfdt/libfdt.h | 2 +-
> tests/pylibfdt_tests.py | 2 +-
> tests/trees.S | 2 +-
> 8 files changed, 15 insertions(+), 11 deletions(-)
>
> diff --git a/dtc.h b/dtc.h
> index 3a220b9..186caad 100644
> --- a/dtc.h
> +++ b/dtc.h
> @@ -29,7 +29,7 @@
> #define debug(...)
> #endif
>
> -#define DEFAULT_FDT_VERSION 17
> +#define DEFAULT_FDT_VERSION 18
>
> /*
> * Command line options
> diff --git a/fdtdump.c b/fdtdump.c
> index d424869..ec25edf 100644
> --- a/fdtdump.c
> +++ b/fdtdump.c
> @@ -18,7 +18,7 @@
> #include "util.h"
>
> #define FDT_MAGIC_SIZE 4
> -#define MAX_VERSION 17U
> +#define MAX_VERSION 18U
>
> #define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
> #define PALIGN(p, a) ((void *)(ALIGN((uintptr_t)(p), (a))))
> diff --git a/flattree.c b/flattree.c
> index 30e6de2..c3887da 100644
> --- a/flattree.c
> +++ b/flattree.c
> @@ -30,6 +30,8 @@ static struct version_info {
> FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_NOPS},
> {17, 16, FDT_V17_SIZE,
> FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS},
> + {18, 18, FDT_V18_SIZE,
> + FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS},
> };
>
> struct emitter {
> diff --git a/libfdt/fdt.h b/libfdt/fdt.h
> index a07abfc..9372353 100644
> --- a/libfdt/fdt.h
> +++ b/libfdt/fdt.h
> @@ -62,5 +62,6 @@ struct fdt_property {
> #define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t))
> #define FDT_V16_SIZE FDT_V3_SIZE
> #define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t))
> +#define FDT_V18_SIZE FDT_V17_SIZE
>
> #endif /* FDT_H */
> diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c
> index 7475caf..00e32bb 100644
> --- a/libfdt/fdt_rw.c
> +++ b/libfdt/fdt_rw.c
> @@ -28,13 +28,13 @@ static int fdt_rw_probe_(void *fdt)
> return 0;
> FDT_RO_PROBE(fdt);
>
> - if (!can_assume(LATEST) && fdt_version(fdt) < 17)
> + if (!can_assume(LATEST) && fdt_version(fdt) < 18)
> return -FDT_ERR_BADVERSION;
> if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
> fdt_size_dt_struct(fdt)))
> return -FDT_ERR_BADLAYOUT;
> - if (!can_assume(LATEST) && fdt_version(fdt) > 17)
> - fdt_set_version(fdt, 17);
> + if (!can_assume(LATEST) && fdt_version(fdt) > 18)
> + fdt_set_version(fdt, 18);
>
> return 0;
> }
> @@ -455,7 +455,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
> err = fdt_move(fdt, buf, bufsize);
> if (err)
> return err;
> - fdt_set_version(buf, 17);
> + fdt_set_version(buf, 18);
> + fdt_set_last_comp_version(buf, 18);
> fdt_set_size_dt_struct(buf, struct_size);
> fdt_set_totalsize(buf, bufsize);
> return 0;
> @@ -484,8 +485,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
>
> fdt_set_magic(buf, FDT_MAGIC);
> fdt_set_totalsize(buf, bufsize);
> - fdt_set_version(buf, 17);
> - fdt_set_last_comp_version(buf, 16);
> + fdt_set_version(buf, 18);
> + fdt_set_last_comp_version(buf, 18);
> fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
>
> return 0;
> diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h
> index 7a10f66..c5cd35d 100644
> --- a/libfdt/libfdt.h
> +++ b/libfdt/libfdt.h
> @@ -15,7 +15,7 @@ extern "C" {
>
> #define FDT_FIRST_SUPPORTED_VERSION 0x02
> #define FDT_LAST_COMPATIBLE_VERSION 0x10
> -#define FDT_LAST_SUPPORTED_VERSION 0x11
> +#define FDT_LAST_SUPPORTED_VERSION 0x12
>
> /* Error codes: informative error codes */
> #define FDT_ERR_NOTFOUND 1
> diff --git a/tests/pylibfdt_tests.py b/tests/pylibfdt_tests.py
> index a4f73ed..373e11a 100644
> --- a/tests/pylibfdt_tests.py
> +++ b/tests/pylibfdt_tests.py
> @@ -288,7 +288,7 @@ class PyLibfdtBasicTests(unittest.TestCase):
> self.assertEqual(self.fdt.off_dt_struct(), 88)
> self.assertEqual(self.fdt.off_dt_strings(), 652)
> self.assertEqual(self.fdt.off_mem_rsvmap(), 40)
> - self.assertEqual(self.fdt.version(), 17)
> + self.assertEqual(self.fdt.version(), 18)
> self.assertEqual(self.fdt.last_comp_version(), 16)
> self.assertEqual(self.fdt.boot_cpuid_phys(), 0)
> self.assertEqual(self.fdt.size_dt_strings(), 105)
> diff --git a/tests/trees.S b/tests/trees.S
> index d69f7f1..ecd43bc 100644
> --- a/tests/trees.S
> +++ b/tests/trees.S
> @@ -17,7 +17,7 @@
> fdtlong (\tree\()_struct - \tree)
> fdtlong (\tree\()_strings - \tree)
> fdtlong (\tree\()_rsvmap - \tree)
> - fdtlong 0x11
> + fdtlong 0x12
> fdtlong 0x10
> fdtlong 0
> fdtlong (\tree\()_strings_end - \tree\()_strings)
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 02/77] Introduce v18 dtb version
2026-01-15 0:12 ` David Gibson
@ 2026-01-16 9:09 ` Herve Codina
2026-01-19 5:13 ` David Gibson
0 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-16 9:09 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
Hi David,
On Thu, 15 Jan 2026 11:12:49 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Mon, Jan 12, 2026 at 03:18:52PM +0100, Herve Codina wrote:
> > This v18 version will add support for
> > - metadata in device-tree blobs in order to have a better handling of
> > phandles and unresolved references.
> > - Addon device-tree blob (successor of device-tree overlay)
> > - Import and export symbols feature
> > - multiple trees in a addon device-tree blob (i.e. root device tree and
> > orphan node tree)
>
> So, once this patch is applied, the rest of the series pretty much has
> to be applied "atomically" - otherwise a version built in the interim
> will be lying in saying that it supports v18.
>
> I therefore suggest moving any changes that *can* be moved before this
> patch, should be moved before this patch. That will assist in
> reviewing and merging the series piecemeal, rather than as a single
> giant blob.
>
>
> Regarding the content itself. It seems like this is a pretty major
> change to the dtb format - maybe that would suggest bumping the
> version by more than one (e.g. like we went from v3 to v16 in the
> past).
I see your point.
Maybe the Rob's idea related to 'unknown tag' and the suggestion I did [1]
related to the generic tag value definition to support those 'unknown tag'
could help here.
As a reminder here, this generic tag value definition consist in:
--- 8< ---
A tag value is on 32bits. We can define the structure of this value.
- bit 31 (msb):
- 0: This is not a new kind to tag and so it doesn't follow this definition.
All existing tags are in this category
- 1: New kind of tag adopting this definition
- bits 30..28:
tag data length encoding
0b000: No data related to the tag
0b001: 1 data cell (u32) directly follows the tag
0b010: 2 data cells (2 u32) directly follow the tag
...
0b110: 6 data cells (6 u32) directly follow the tag
0b111: Tag is followed by a cell (u32) indicating the size (in bytes)
of data available just after this cell (including any padding
if needed).
Because this size include some possible padding, its value is a
multiple of 4 bytes.
The offset of the tag + 4 + size points to the next tag.
- bit 27..0
tag specific identifier
--- 8< ---
I mean dtb version v20 could be:
- New header size with dt_flags added in the header (if this new field is
kept).
- Support for the generic tag values and so the notion of 'unknown tag'
With that done, everything else added afterward will have no impact on the
dtb format itself.
Only libfdt and dtc will have versions defined at some point with support for
some new flags or new keyword.
What do you think about this v20 dtb version?
>
> It would also be nice to have some docs for the new dtb extensions
> before or at the same time as this.
Yes, the generic tag value definition.
[1] https://lore.kernel.org/all/20260114171822.2a44d2a5@bootlin.com/
Best regards
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 02/77] Introduce v18 dtb version
2026-01-16 9:09 ` Herve Codina
@ 2026-01-19 5:13 ` David Gibson
2026-01-19 9:48 ` Herve Codina
2026-01-20 20:38 ` Rob Herring
0 siblings, 2 replies; 160+ messages in thread
From: David Gibson @ 2026-01-19 5:13 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 4494 bytes --]
On Fri, Jan 16, 2026 at 10:09:34AM +0100, Herve Codina wrote:
> Hi David,
>
> On Thu, 15 Jan 2026 11:12:49 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > On Mon, Jan 12, 2026 at 03:18:52PM +0100, Herve Codina wrote:
> > > This v18 version will add support for
> > > - metadata in device-tree blobs in order to have a better handling of
> > > phandles and unresolved references.
> > > - Addon device-tree blob (successor of device-tree overlay)
> > > - Import and export symbols feature
> > > - multiple trees in a addon device-tree blob (i.e. root device tree and
> > > orphan node tree)
> >
> > So, once this patch is applied, the rest of the series pretty much has
> > to be applied "atomically" - otherwise a version built in the interim
> > will be lying in saying that it supports v18.
> >
> > I therefore suggest moving any changes that *can* be moved before this
> > patch, should be moved before this patch. That will assist in
> > reviewing and merging the series piecemeal, rather than as a single
> > giant blob.
> >
> >
> > Regarding the content itself. It seems like this is a pretty major
> > change to the dtb format - maybe that would suggest bumping the
> > version by more than one (e.g. like we went from v3 to v16 in the
> > past).
>
> I see your point.
>
> Maybe the Rob's idea related to 'unknown tag' and the suggestion I did [1]
> related to the generic tag value definition to support those 'unknown tag'
> could help here.
Having a standard encoding of tag length so unknown tags can be
skipped is a reasonable idea. I think you do need provision to mark a
tag as "safe to ignore" or not - e.g. something like FDT_BEGIN_NODE
could never be safely ignored.
> As a reminder here, this generic tag value definition consist in:
> --- 8< ---
> A tag value is on 32bits. We can define the structure of this value.
> - bit 31 (msb):
> - 0: This is not a new kind to tag and so it doesn't follow this definition.
> All existing tags are in this category
> - 1: New kind of tag adopting this definition
>
> - bits 30..28:
> tag data length encoding
> 0b000: No data related to the tag
> 0b001: 1 data cell (u32) directly follows the tag
> 0b010: 2 data cells (2 u32) directly follow the tag
> ...
> 0b110: 6 data cells (6 u32) directly follow the tag
> 0b111: Tag is followed by a cell (u32) indicating the size (in bytes)
> of data available just after this cell (including any padding
> if needed).
I'd suggesting giving a byte length not including alignment padding.
That way if you wanted to encode a bytestring in there, you wouldn't
need a way of encoding the unpadded length in adddition to the
standard way encoding the padded length.
> Because this size include some possible padding, its value is a
> multiple of 4 bytes.
> The offset of the tag + 4 + size points to the next tag.
>
>
> - bit 27..0
> tag specific identifier
> --- 8< ---
>
> I mean dtb version v20 could be:
>
> - New header size with dt_flags added in the header (if this new field is
> kept).
>
> - Support for the generic tag values and so the notion of 'unknown tag'
>
> With that done, everything else added afterward will have no impact on the
> dtb format itself.
Well... maybe. It's not entirely clear to me whether all the new tags
can be safely ignored by something that doesn't understand them.
e.g. a consumer can't safely ignore the tags which give unresolved
phandle references if it then expects the phandle values in the actual
property values to be correct.
>
> Only libfdt and dtc will have versions defined at some point with support for
> some new flags or new keyword.
>
> What do you think about this v20 dtb version?
>
> >
> > It would also be nice to have some docs for the new dtb extensions
> > before or at the same time as this.
>
> Yes, the generic tag value definition.
We'd want that, but it's not enough. The specific tag types should be
documented as well.
>
>
> [1] https://lore.kernel.org/all/20260114171822.2a44d2a5@bootlin.com/
>
> Best regards
> Hervé
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 02/77] Introduce v18 dtb version
2026-01-19 5:13 ` David Gibson
@ 2026-01-19 9:48 ` Herve Codina
2026-01-28 1:49 ` David Gibson
2026-01-20 20:38 ` Rob Herring
1 sibling, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-19 9:48 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
On Mon, 19 Jan 2026 16:13:35 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Fri, Jan 16, 2026 at 10:09:34AM +0100, Herve Codina wrote:
> > Hi David,
> >
> > On Thu, 15 Jan 2026 11:12:49 +1100
> > David Gibson <david@gibson.dropbear.id.au> wrote:
> >
> > > On Mon, Jan 12, 2026 at 03:18:52PM +0100, Herve Codina wrote:
> > > > This v18 version will add support for
> > > > - metadata in device-tree blobs in order to have a better handling of
> > > > phandles and unresolved references.
> > > > - Addon device-tree blob (successor of device-tree overlay)
> > > > - Import and export symbols feature
> > > > - multiple trees in a addon device-tree blob (i.e. root device tree and
> > > > orphan node tree)
> > >
> > > So, once this patch is applied, the rest of the series pretty much has
> > > to be applied "atomically" - otherwise a version built in the interim
> > > will be lying in saying that it supports v18.
> > >
> > > I therefore suggest moving any changes that *can* be moved before this
> > > patch, should be moved before this patch. That will assist in
> > > reviewing and merging the series piecemeal, rather than as a single
> > > giant blob.
> > >
> > >
> > > Regarding the content itself. It seems like this is a pretty major
> > > change to the dtb format - maybe that would suggest bumping the
> > > version by more than one (e.g. like we went from v3 to v16 in the
> > > past).
> >
> > I see your point.
> >
> > Maybe the Rob's idea related to 'unknown tag' and the suggestion I did [1]
> > related to the generic tag value definition to support those 'unknown tag'
> > could help here.
>
> Having a standard encoding of tag length so unknown tags can be
> skipped is a reasonable idea. I think you do need provision to mark a
> tag as "safe to ignore" or not - e.g. something like FDT_BEGIN_NODE
> could never be safely ignored.
A bit can be used for marking a tag as "safe to ignore if unknown".
I can reduce the bits 30..28 field.
bit 30:
- 0b0: Do not ignore this tag if the tag id is unknown.
If this tag id is unknown an error in the parsing should be reported.
- 0b1: This tag can be safely ignore if its id is unknown. I that case the
tag and its related data are simply skipped.
bits 29..28:
- 0b00: No data
- 0b01: tag followed by 1 cell (u32) data
- 0b10: tag followed by 2 cells (2 x u32) data
- 0b11: Tag is followed by a cell (u32) indicating the size of following
data
Also, it is worth noting that the 0x0....... tag value family can still be
used.
Even if related to "old" tags, if a tag in this family is an unknwown tag,
the parser will report an error (at least because it doesn't know how to
skip the data part).
>
> > As a reminder here, this generic tag value definition consist in:
> > --- 8< ---
> > A tag value is on 32bits. We can define the structure of this value.
> > - bit 31 (msb):
> > - 0: This is not a new kind to tag and so it doesn't follow this definition.
> > All existing tags are in this category
> > - 1: New kind of tag adopting this definition
> >
> > - bits 30..28:
> > tag data length encoding
> > 0b000: No data related to the tag
> > 0b001: 1 data cell (u32) directly follows the tag
> > 0b010: 2 data cells (2 u32) directly follow the tag
> > ...
> > 0b110: 6 data cells (6 u32) directly follow the tag
> > 0b111: Tag is followed by a cell (u32) indicating the size (in bytes)
> > of data available just after this cell (including any padding
> > if needed).
>
> I'd suggesting giving a byte length not including alignment padding.
> That way if you wanted to encode a bytestring in there, you wouldn't
> need a way of encoding the unpadded length in adddition to the
> standard way encoding the padded length.
And so, next tag is always length + sizeof(padding). Next tag is aligned
on 32bits.
>
> > Because this size include some possible padding, its value is a
> > multiple of 4 bytes.
> > The offset of the tag + 4 + size points to the next tag.
> >
> >
> > - bit 27..0
> > tag specific identifier
> > --- 8< ---
> >
> > I mean dtb version v20 could be:
> >
> > - New header size with dt_flags added in the header (if this new field is
> > kept).
> >
> > - Support for the generic tag values and so the notion of 'unknown tag'
> >
> > With that done, everything else added afterward will have no impact on the
> > dtb format itself.
>
> Well... maybe. It's not entirely clear to me whether all the new tags
> can be safely ignored by something that doesn't understand them.
> e.g. a consumer can't safely ignore the tags which give unresolved
> phandle references if it then expects the phandle values in the actual
> property values to be correct.
I would say that it depends on new (future) tags.
For instance, FDT_EXPORT_SYM, the tag used for exported symbols can be ignore
by the bootloader if it doesn't know about this tag.
Indeed, it doesn't need to understand and manipulate this tag. It just needs to
keep it in the dtb passed to the kernel.
> >
> > Only libfdt and dtc will have versions defined at some point with support for
> > some new flags or new keyword.
> >
> > What do you think about this v20 dtb version?
> >
> > >
> > > It would also be nice to have some docs for the new dtb extensions
> > > before or at the same time as this.
> >
> > Yes, the generic tag value definition.
>
> We'd want that, but it's not enough. The specific tag types should be
> documented as well.
Yes they will be documented as soon as they are introduced.
The generic tag value definition is the first step to have in docs to allow
the "skip if unknown" feature.
Best regards,
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 02/77] Introduce v18 dtb version
2026-01-19 9:48 ` Herve Codina
@ 2026-01-28 1:49 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-28 1:49 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 7379 bytes --]
On Mon, Jan 19, 2026 at 10:48:52AM +0100, Herve Codina wrote:
> On Mon, 19 Jan 2026 16:13:35 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > On Fri, Jan 16, 2026 at 10:09:34AM +0100, Herve Codina wrote:
> > > Hi David,
> > >
> > > On Thu, 15 Jan 2026 11:12:49 +1100
> > > David Gibson <david@gibson.dropbear.id.au> wrote:
> > >
> > > > On Mon, Jan 12, 2026 at 03:18:52PM +0100, Herve Codina wrote:
> > > > > This v18 version will add support for
> > > > > - metadata in device-tree blobs in order to have a better handling of
> > > > > phandles and unresolved references.
> > > > > - Addon device-tree blob (successor of device-tree overlay)
> > > > > - Import and export symbols feature
> > > > > - multiple trees in a addon device-tree blob (i.e. root device tree and
> > > > > orphan node tree)
> > > >
> > > > So, once this patch is applied, the rest of the series pretty much has
> > > > to be applied "atomically" - otherwise a version built in the interim
> > > > will be lying in saying that it supports v18.
> > > >
> > > > I therefore suggest moving any changes that *can* be moved before this
> > > > patch, should be moved before this patch. That will assist in
> > > > reviewing and merging the series piecemeal, rather than as a single
> > > > giant blob.
> > > >
> > > >
> > > > Regarding the content itself. It seems like this is a pretty major
> > > > change to the dtb format - maybe that would suggest bumping the
> > > > version by more than one (e.g. like we went from v3 to v16 in the
> > > > past).
> > >
> > > I see your point.
> > >
> > > Maybe the Rob's idea related to 'unknown tag' and the suggestion I did [1]
> > > related to the generic tag value definition to support those 'unknown tag'
> > > could help here.
> >
> > Having a standard encoding of tag length so unknown tags can be
> > skipped is a reasonable idea. I think you do need provision to mark a
> > tag as "safe to ignore" or not - e.g. something like FDT_BEGIN_NODE
> > could never be safely ignored.
>
> A bit can be used for marking a tag as "safe to ignore if unknown".
> I can reduce the bits 30..28 field.
>
> bit 30:
> - 0b0: Do not ignore this tag if the tag id is unknown.
> If this tag id is unknown an error in the parsing should be reported.
> - 0b1: This tag can be safely ignore if its id is unknown. I that case the
> tag and its related data are simply skipped.
>
> bits 29..28:
> - 0b00: No data
> - 0b01: tag followed by 1 cell (u32) data
> - 0b10: tag followed by 2 cells (2 x u32) data
> - 0b11: Tag is followed by a cell (u32) indicating the size of following
> data
>
> Also, it is worth noting that the 0x0....... tag value family can still be
> used.
Actually, that's a good point. We can do this more simply: the new
ranges with defined lengths are only used for ignorable tags. If we
need to add new tags which aren't safe to ignore, they go in the 0x0
range, like the existing tags.
> Even if related to "old" tags, if a tag in this family is an unknwown tag,
> the parser will report an error (at least because it doesn't know how to
> skip the data part).
>
> >
> > > As a reminder here, this generic tag value definition consist in:
> > > --- 8< ---
> > > A tag value is on 32bits. We can define the structure of this value.
> > > - bit 31 (msb):
> > > - 0: This is not a new kind to tag and so it doesn't follow this definition.
> > > All existing tags are in this category
> > > - 1: New kind of tag adopting this definition
> > >
> > > - bits 30..28:
> > > tag data length encoding
> > > 0b000: No data related to the tag
> > > 0b001: 1 data cell (u32) directly follows the tag
> > > 0b010: 2 data cells (2 u32) directly follow the tag
> > > ...
> > > 0b110: 6 data cells (6 u32) directly follow the tag
> > > 0b111: Tag is followed by a cell (u32) indicating the size (in bytes)
> > > of data available just after this cell (including any padding
> > > if needed).
> >
> > I'd suggesting giving a byte length not including alignment padding.
> > That way if you wanted to encode a bytestring in there, you wouldn't
> > need a way of encoding the unpadded length in adddition to the
> > standard way encoding the padded length.
>
> And so, next tag is always length + sizeof(padding). Next tag is aligned
> on 32bits.
Exactly. Or to make it clearer that we don't need any additional
information, next tag is at ALIGN_UP(length, FDT_TAG_SIZE). We
already do something like this with with FDT_BEGIN_NODE tags - we
ignore bytes to realign after the node name string.
> > > Because this size include some possible padding, its value is a
> > > multiple of 4 bytes.
> > > The offset of the tag + 4 + size points to the next tag.
> > >
> > >
> > > - bit 27..0
> > > tag specific identifier
> > > --- 8< ---
> > >
> > > I mean dtb version v20 could be:
> > >
> > > - New header size with dt_flags added in the header (if this new field is
> > > kept).
> > >
> > > - Support for the generic tag values and so the notion of 'unknown tag'
> > >
> > > With that done, everything else added afterward will have no impact on the
> > > dtb format itself.
> >
> > Well... maybe. It's not entirely clear to me whether all the new tags
> > can be safely ignored by something that doesn't understand them.
> > e.g. a consumer can't safely ignore the tags which give unresolved
> > phandle references if it then expects the phandle values in the actual
> > property values to be correct.
>
> I would say that it depends on new (future) tags.
Certainly.
> For instance, FDT_EXPORT_SYM, the tag used for exported symbols can be ignore
> by the bootloader if it doesn't know about this tag.
> Indeed, it doesn't need to understand and manipulate this tag. It just needs to
> keep it in the dtb passed to the kernel.
Ow, that's when it gets complicated. Whether a tag is safely
ignorable depends on what the consumer is doing with it. Fixups and
exports can be safely ignored by something just passing it through.
However reference fixups *can't* be safely ignored by something that
will consult phandles, because they might not be correct until the
fixups are applied.
> > > Only libfdt and dtc will have versions defined at some point with support for
> > > some new flags or new keyword.
> > >
> > > What do you think about this v20 dtb version?
> > >
> > > >
> > > > It would also be nice to have some docs for the new dtb extensions
> > > > before or at the same time as this.
> > >
> > > Yes, the generic tag value definition.
> >
> > We'd want that, but it's not enough. The specific tag types should be
> > documented as well.
>
> Yes they will be documented as soon as they are introduced.
>
> The generic tag value definition is the first step to have in docs to allow
> the "skip if unknown" feature.
>
> Best regards,
> Hervé
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 02/77] Introduce v18 dtb version
2026-01-19 5:13 ` David Gibson
2026-01-19 9:48 ` Herve Codina
@ 2026-01-20 20:38 ` Rob Herring
2026-01-29 1:40 ` David Gibson
1 sibling, 1 reply; 160+ messages in thread
From: Rob Herring @ 2026-01-20 20:38 UTC (permalink / raw)
To: David Gibson
Cc: Herve Codina, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
On Sun, Jan 18, 2026 at 11:18 PM David Gibson
<david@gibson.dropbear.id.au> wrote:
>
> On Fri, Jan 16, 2026 at 10:09:34AM +0100, Herve Codina wrote:
> > Hi David,
> >
> > On Thu, 15 Jan 2026 11:12:49 +1100
> > David Gibson <david@gibson.dropbear.id.au> wrote:
> >
> > > On Mon, Jan 12, 2026 at 03:18:52PM +0100, Herve Codina wrote:
> > > > This v18 version will add support for
> > > > - metadata in device-tree blobs in order to have a better handling of
> > > > phandles and unresolved references.
> > > > - Addon device-tree blob (successor of device-tree overlay)
> > > > - Import and export symbols feature
> > > > - multiple trees in a addon device-tree blob (i.e. root device tree and
> > > > orphan node tree)
> > >
> > > So, once this patch is applied, the rest of the series pretty much has
> > > to be applied "atomically" - otherwise a version built in the interim
> > > will be lying in saying that it supports v18.
> > >
> > > I therefore suggest moving any changes that *can* be moved before this
> > > patch, should be moved before this patch. That will assist in
> > > reviewing and merging the series piecemeal, rather than as a single
> > > giant blob.
> > >
> > >
> > > Regarding the content itself. It seems like this is a pretty major
> > > change to the dtb format - maybe that would suggest bumping the
> > > version by more than one (e.g. like we went from v3 to v16 in the
> > > past).
> >
> > I see your point.
> >
> > Maybe the Rob's idea related to 'unknown tag' and the suggestion I did [1]
> > related to the generic tag value definition to support those 'unknown tag'
> > could help here.
>
> Having a standard encoding of tag length so unknown tags can be
> skipped is a reasonable idea. I think you do need provision to mark a
> tag as "safe to ignore" or not - e.g. something like FDT_BEGIN_NODE
> could never be safely ignored.
>
> > As a reminder here, this generic tag value definition consist in:
> > --- 8< ---
> > A tag value is on 32bits. We can define the structure of this value.
> > - bit 31 (msb):
> > - 0: This is not a new kind to tag and so it doesn't follow this definition.
> > All existing tags are in this category
> > - 1: New kind of tag adopting this definition
> >
> > - bits 30..28:
> > tag data length encoding
> > 0b000: No data related to the tag
> > 0b001: 1 data cell (u32) directly follows the tag
> > 0b010: 2 data cells (2 u32) directly follow the tag
> > ...
> > 0b110: 6 data cells (6 u32) directly follow the tag
> > 0b111: Tag is followed by a cell (u32) indicating the size (in bytes)
> > of data available just after this cell (including any padding
> > if needed).
>
> I'd suggesting giving a byte length not including alignment padding.
> That way if you wanted to encode a bytestring in there, you wouldn't
> need a way of encoding the unpadded length in adddition to the
> standard way encoding the padded length.
>
> > Because this size include some possible padding, its value is a
> > multiple of 4 bytes.
> > The offset of the tag + 4 + size points to the next tag.
> >
> >
> > - bit 27..0
> > tag specific identifier
> > --- 8< ---
> >
> > I mean dtb version v20 could be:
> >
> > - New header size with dt_flags added in the header (if this new field is
> > kept).
> >
> > - Support for the generic tag values and so the notion of 'unknown tag'
> >
> > With that done, everything else added afterward will have no impact on the
> > dtb format itself.
>
> Well... maybe. It's not entirely clear to me whether all the new tags
> can be safely ignored by something that doesn't understand them.
> e.g. a consumer can't safely ignore the tags which give unresolved
> phandle references if it then expects the phandle values in the actual
> property values to be correct.
I think we'd want some higher level "this is an addon or base DT" than
presence of tags. Maybe that's just the version. Perhaps a new header
field to say this is a base or addon DT. Or both?
Everything in this series intended for the base DT should be safe to
ignore just as __symbols__ (and __local_fixups__ if you add /plugin/)
is safe to ignore. It's only software that understands and wants to
use the new "addons" that needs to understand.
Rob
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 02/77] Introduce v18 dtb version
2026-01-20 20:38 ` Rob Herring
@ 2026-01-29 1:40 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-29 1:40 UTC (permalink / raw)
To: Rob Herring
Cc: Herve Codina, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 5287 bytes --]
On Tue, Jan 20, 2026 at 02:38:45PM -0600, Rob Herring wrote:
> On Sun, Jan 18, 2026 at 11:18 PM David Gibson
> <david@gibson.dropbear.id.au> wrote:
> >
> > On Fri, Jan 16, 2026 at 10:09:34AM +0100, Herve Codina wrote:
> > > Hi David,
> > >
> > > On Thu, 15 Jan 2026 11:12:49 +1100
> > > David Gibson <david@gibson.dropbear.id.au> wrote:
> > >
> > > > On Mon, Jan 12, 2026 at 03:18:52PM +0100, Herve Codina wrote:
> > > > > This v18 version will add support for
> > > > > - metadata in device-tree blobs in order to have a better handling of
> > > > > phandles and unresolved references.
> > > > > - Addon device-tree blob (successor of device-tree overlay)
> > > > > - Import and export symbols feature
> > > > > - multiple trees in a addon device-tree blob (i.e. root device tree and
> > > > > orphan node tree)
> > > >
> > > > So, once this patch is applied, the rest of the series pretty much has
> > > > to be applied "atomically" - otherwise a version built in the interim
> > > > will be lying in saying that it supports v18.
> > > >
> > > > I therefore suggest moving any changes that *can* be moved before this
> > > > patch, should be moved before this patch. That will assist in
> > > > reviewing and merging the series piecemeal, rather than as a single
> > > > giant blob.
> > > >
> > > >
> > > > Regarding the content itself. It seems like this is a pretty major
> > > > change to the dtb format - maybe that would suggest bumping the
> > > > version by more than one (e.g. like we went from v3 to v16 in the
> > > > past).
> > >
> > > I see your point.
> > >
> > > Maybe the Rob's idea related to 'unknown tag' and the suggestion I did [1]
> > > related to the generic tag value definition to support those 'unknown tag'
> > > could help here.
> >
> > Having a standard encoding of tag length so unknown tags can be
> > skipped is a reasonable idea. I think you do need provision to mark a
> > tag as "safe to ignore" or not - e.g. something like FDT_BEGIN_NODE
> > could never be safely ignored.
> >
> > > As a reminder here, this generic tag value definition consist in:
> > > --- 8< ---
> > > A tag value is on 32bits. We can define the structure of this value.
> > > - bit 31 (msb):
> > > - 0: This is not a new kind to tag and so it doesn't follow this definition.
> > > All existing tags are in this category
> > > - 1: New kind of tag adopting this definition
> > >
> > > - bits 30..28:
> > > tag data length encoding
> > > 0b000: No data related to the tag
> > > 0b001: 1 data cell (u32) directly follows the tag
> > > 0b010: 2 data cells (2 u32) directly follow the tag
> > > ...
> > > 0b110: 6 data cells (6 u32) directly follow the tag
> > > 0b111: Tag is followed by a cell (u32) indicating the size (in bytes)
> > > of data available just after this cell (including any padding
> > > if needed).
> >
> > I'd suggesting giving a byte length not including alignment padding.
> > That way if you wanted to encode a bytestring in there, you wouldn't
> > need a way of encoding the unpadded length in adddition to the
> > standard way encoding the padded length.
> >
> > > Because this size include some possible padding, its value is a
> > > multiple of 4 bytes.
> > > The offset of the tag + 4 + size points to the next tag.
> > >
> > >
> > > - bit 27..0
> > > tag specific identifier
> > > --- 8< ---
> > >
> > > I mean dtb version v20 could be:
> > >
> > > - New header size with dt_flags added in the header (if this new field is
> > > kept).
> > >
> > > - Support for the generic tag values and so the notion of 'unknown tag'
> > >
> > > With that done, everything else added afterward will have no impact on the
> > > dtb format itself.
> >
> > Well... maybe. It's not entirely clear to me whether all the new tags
> > can be safely ignored by something that doesn't understand them.
> > e.g. a consumer can't safely ignore the tags which give unresolved
> > phandle references if it then expects the phandle values in the actual
> > property values to be correct.
>
> I think we'd want some higher level "this is an addon or base DT" than
> presence of tags. Maybe that's just the version. Perhaps a new header
> field to say this is a base or addon DT. Or both?
I think Herve's flags proposed flags field does that. I tend to
prefer the idea of using new and different magic numbers for the
variant forms though - makes it really clear that they're a different
thing from a "normal" fdt.
>
> Everything in this series intended for the base DT should be safe to
> ignore just as __symbols__ (and __local_fixups__ if you add /plugin/)
> is safe to ignore.
That kind of depends what you're doing with the DT. If you need to do
phandle lookups, you can't safely ignore the fixups.
> It's only software that understands and wants to
> use the new "addons" that needs to understand.
>
> Rob
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 03/77] libfdt: Introduce fdt_next_tag_full() and use it in fdt_next_tag()
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
2026-01-12 14:18 ` [RFC PATCH 01/77] checks: Use consistent type for strspn() returned value Herve Codina
2026-01-12 14:18 ` [RFC PATCH 02/77] Introduce v18 dtb version Herve Codina
@ 2026-01-12 14:18 ` Herve Codina
2026-01-15 0:17 ` David Gibson
2026-01-12 14:18 ` [RFC PATCH 04/77] dtc: Allow to use data_append_markers() out of data.c Herve Codina
` (76 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:18 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
In v18 dtb new tags are added. Prepare libfdt to handle those new tags.
Keep fdt_next_tag() handling only existing tags and introduce
fdt_next_tag_full() to handle new tags.
fdt_next_tag() uses fdt_next_tag_full() but it will filter out new tags
when they are introduced to have those new tags transparent for existing
fdt_next_tag() callers.
Code that will need to handle those new tags will use explicitly
fdt_next_tag_full() to have access to them when they need to.
No new tags have been introduced yet and modifications done here prepare
their introduction.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
libfdt/fdt.c | 35 ++++++++++++++++++++++++++++++++++-
libfdt/libfdt.h | 18 ++++++++++++++++++
libfdt/version.lds | 1 +
3 files changed, 53 insertions(+), 1 deletion(-)
diff --git a/libfdt/fdt.c b/libfdt/fdt.c
index 95f644c..ce051a0 100644
--- a/libfdt/fdt.c
+++ b/libfdt/fdt.c
@@ -159,7 +159,7 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
return fdt_offset_ptr_(fdt, offset);
}
-uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
+uint32_t fdt_next_tag_full(const void *fdt, int startoffset, int *nextoffset)
{
const fdt32_t *tagp, *lenp;
uint32_t tag, len, sum;
@@ -220,6 +220,39 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
return tag;
}
+uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
+{
+ uint32_t tag, tmp_tag;
+ int tmp_offset, tmp_next;
+
+ /* Retrieve next tag */
+ tag = fdt_next_tag_full(fdt, startoffset, nextoffset);
+
+ /* Look at next one to see what we need to do */
+ tmp_next = *nextoffset;
+ do {
+ tmp_offset = tmp_next;
+ tmp_tag = fdt_next_tag_full(fdt, tmp_offset, &tmp_next);
+ switch (tmp_tag) {
+ case FDT_BEGIN_NODE:
+ case FDT_END_NODE:
+ case FDT_PROP:
+ case FDT_NOP:
+ case FDT_END:
+ /* Next tag is not new tag introduced in v18 -> Ok */
+ *nextoffset = tmp_offset;
+ return tag;
+
+ default:
+ break;
+ }
+ } while (1);
+
+ /* We shouldn't reach this code */
+ *nextoffset = -FDT_ERR_BADSTRUCTURE;
+ return FDT_END;
+}
+
int fdt_check_node_offset_(const void *fdt, int offset)
{
if (!can_assume(VALID_INPUT)
diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h
index c5cd35d..d1a9cd5 100644
--- a/libfdt/libfdt.h
+++ b/libfdt/libfdt.h
@@ -154,6 +154,24 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
*/
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
+/**
+ * fdt_next_tag_full - get next tag in the device tree without any filtering
+ * @fdt: Pointer to the device tree blob
+ * @offset: Offset within the blob to start searching
+ * @nextoffset: Pointer to variable to store the offset of the next tag
+ *
+ * fdt_next_tag_full() returns the tag type of the next tag in the device tree
+ * blob starting from the given @offset. If @nextoffset is non-NULL, it will
+ * be set to the offset immediately following the tag.
+ * fdt_next_tag() can return only a subset of all possible tags performing some
+ * internal filtering. fdt_next_tag_full() doesn't perform this filtering.
+ *
+ * returns:
+ * the tag type (FDT_BEGIN_NODE, FDT_END_NODE, FDT_PROP, FDT_NOP, FDT_END),
+ * FDT_END, if offset is out of bounds
+ */
+uint32_t fdt_next_tag_full(const void *fdt, int offset, int *nextoffset);
+
/*
* External helpers to access words from a device tree blob. They're built
* to work even with unaligned pointers on platforms (such as ARMv5) that don't
diff --git a/libfdt/version.lds b/libfdt/version.lds
index cbfef54..7e2dde2 100644
--- a/libfdt/version.lds
+++ b/libfdt/version.lds
@@ -52,6 +52,7 @@ LIBFDT_1.2 {
fdt_strerror;
fdt_offset_ptr;
fdt_next_tag;
+ fdt_next_tag_full;
fdt_appendprop;
fdt_create_empty_tree;
fdt_first_property_offset;
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 03/77] libfdt: Introduce fdt_next_tag_full() and use it in fdt_next_tag()
2026-01-12 14:18 ` [RFC PATCH 03/77] libfdt: Introduce fdt_next_tag_full() and use it in fdt_next_tag() Herve Codina
@ 2026-01-15 0:17 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-15 0:17 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 5165 bytes --]
On Mon, Jan 12, 2026 at 03:18:53PM +0100, Herve Codina wrote:
> In v18 dtb new tags are added. Prepare libfdt to handle those new tags.
>
> Keep fdt_next_tag() handling only existing tags and introduce
> fdt_next_tag_full() to handle new tags.
Ugh, that's super ugly.
My first inclination is to say that if you're using the low-level
fdt_next_tag() interface, it's your responsibility to check the
version first - fdt_next_tag() should return... the next tag... and
it's the caller's problem if it doesn't know about it.
Maybe that breaks some real user too badly, though. The other
approach would be to use the symbol versioning we already have: we
bump the libfdt version, and have different versions of fdt_next_tag()
depending on the version you're using.
Btw, once you generate a dtb with new tags, its last_compat_version
must become v18 as well as it's version - tools need to be aware of
the new tags.
>
> fdt_next_tag() uses fdt_next_tag_full() but it will filter out new tags
> when they are introduced to have those new tags transparent for existing
> fdt_next_tag() callers.
>
> Code that will need to handle those new tags will use explicitly
> fdt_next_tag_full() to have access to them when they need to.
>
> No new tags have been introduced yet and modifications done here prepare
> their introduction.
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> libfdt/fdt.c | 35 ++++++++++++++++++++++++++++++++++-
> libfdt/libfdt.h | 18 ++++++++++++++++++
> libfdt/version.lds | 1 +
> 3 files changed, 53 insertions(+), 1 deletion(-)
>
> diff --git a/libfdt/fdt.c b/libfdt/fdt.c
> index 95f644c..ce051a0 100644
> --- a/libfdt/fdt.c
> +++ b/libfdt/fdt.c
> @@ -159,7 +159,7 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
> return fdt_offset_ptr_(fdt, offset);
> }
>
> -uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
> +uint32_t fdt_next_tag_full(const void *fdt, int startoffset, int *nextoffset)
> {
> const fdt32_t *tagp, *lenp;
> uint32_t tag, len, sum;
> @@ -220,6 +220,39 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
> return tag;
> }
>
> +uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
> +{
> + uint32_t tag, tmp_tag;
> + int tmp_offset, tmp_next;
> +
> + /* Retrieve next tag */
> + tag = fdt_next_tag_full(fdt, startoffset, nextoffset);
> +
> + /* Look at next one to see what we need to do */
> + tmp_next = *nextoffset;
> + do {
> + tmp_offset = tmp_next;
> + tmp_tag = fdt_next_tag_full(fdt, tmp_offset, &tmp_next);
> + switch (tmp_tag) {
> + case FDT_BEGIN_NODE:
> + case FDT_END_NODE:
> + case FDT_PROP:
> + case FDT_NOP:
> + case FDT_END:
> + /* Next tag is not new tag introduced in v18 -> Ok */
> + *nextoffset = tmp_offset;
> + return tag;
> +
> + default:
> + break;
> + }
> + } while (1);
> +
> + /* We shouldn't reach this code */
> + *nextoffset = -FDT_ERR_BADSTRUCTURE;
> + return FDT_END;
> +}
> +
> int fdt_check_node_offset_(const void *fdt, int offset)
> {
> if (!can_assume(VALID_INPUT)
> diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h
> index c5cd35d..d1a9cd5 100644
> --- a/libfdt/libfdt.h
> +++ b/libfdt/libfdt.h
> @@ -154,6 +154,24 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
> */
> uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
>
> +/**
> + * fdt_next_tag_full - get next tag in the device tree without any filtering
> + * @fdt: Pointer to the device tree blob
> + * @offset: Offset within the blob to start searching
> + * @nextoffset: Pointer to variable to store the offset of the next tag
> + *
> + * fdt_next_tag_full() returns the tag type of the next tag in the device tree
> + * blob starting from the given @offset. If @nextoffset is non-NULL, it will
> + * be set to the offset immediately following the tag.
> + * fdt_next_tag() can return only a subset of all possible tags performing some
> + * internal filtering. fdt_next_tag_full() doesn't perform this filtering.
> + *
> + * returns:
> + * the tag type (FDT_BEGIN_NODE, FDT_END_NODE, FDT_PROP, FDT_NOP, FDT_END),
> + * FDT_END, if offset is out of bounds
> + */
> +uint32_t fdt_next_tag_full(const void *fdt, int offset, int *nextoffset);
> +
> /*
> * External helpers to access words from a device tree blob. They're built
> * to work even with unaligned pointers on platforms (such as ARMv5) that don't
> diff --git a/libfdt/version.lds b/libfdt/version.lds
> index cbfef54..7e2dde2 100644
> --- a/libfdt/version.lds
> +++ b/libfdt/version.lds
> @@ -52,6 +52,7 @@ LIBFDT_1.2 {
> fdt_strerror;
> fdt_offset_ptr;
> fdt_next_tag;
> + fdt_next_tag_full;
> fdt_appendprop;
> fdt_create_empty_tree;
> fdt_first_property_offset;
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 04/77] dtc: Allow to use data_append_markers() out of data.c
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (2 preceding siblings ...)
2026-01-12 14:18 ` [RFC PATCH 03/77] libfdt: Introduce fdt_next_tag_full() and use it in fdt_next_tag() Herve Codina
@ 2026-01-12 14:18 ` Herve Codina
2026-01-15 0:18 ` David Gibson
2026-01-12 14:18 ` [RFC PATCH 05/77] fdtdump: Change FDT_PROP prob handling to ease future addition Herve Codina
` (75 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:18 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
With meta-data available in dtb, markers can be set as soon as a dtb is
parsed. This will be done in flattree.c using data_append_markers().
Prepare this usage allowing this function to be used out of data.c
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
data.c | 2 +-
dtc.h | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/data.c b/data.c
index 5b25aa0..11b2169 100644
--- a/data.c
+++ b/data.c
@@ -127,7 +127,7 @@ struct data data_insert_at_marker(struct data d, struct marker *m,
return d;
}
-static struct data data_append_markers(struct data d, struct marker *m)
+struct data data_append_markers(struct data d, struct marker *m)
{
struct marker **mp = &d.markers;
diff --git a/dtc.h b/dtc.h
index 186caad..3bbd97e 100644
--- a/dtc.h
+++ b/dtc.h
@@ -187,6 +187,7 @@ struct data data_insert_data(struct data d, struct marker *m, struct data old);
struct marker *alloc_marker(unsigned int offset, enum markertype type,
char *ref);
struct data data_add_marker(struct data d, enum markertype type, char *ref);
+struct data data_append_markers(struct data d, struct marker *m);
bool data_is_one_string(struct data d);
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 04/77] dtc: Allow to use data_append_markers() out of data.c
2026-01-12 14:18 ` [RFC PATCH 04/77] dtc: Allow to use data_append_markers() out of data.c Herve Codina
@ 2026-01-15 0:18 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-15 0:18 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 1683 bytes --]
On Mon, Jan 12, 2026 at 03:18:54PM +0100, Herve Codina wrote:
> With meta-data available in dtb, markers can be set as soon as a dtb is
> parsed. This will be done in flattree.c using data_append_markers().
>
> Prepare this usage allowing this function to be used out of data.c
Trivial enough I'd suggest folding it into the patch that needs to use
data_append_markers() elsewhere.
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> data.c | 2 +-
> dtc.h | 1 +
> 2 files changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/data.c b/data.c
> index 5b25aa0..11b2169 100644
> --- a/data.c
> +++ b/data.c
> @@ -127,7 +127,7 @@ struct data data_insert_at_marker(struct data d, struct marker *m,
> return d;
> }
>
> -static struct data data_append_markers(struct data d, struct marker *m)
> +struct data data_append_markers(struct data d, struct marker *m)
> {
> struct marker **mp = &d.markers;
>
> diff --git a/dtc.h b/dtc.h
> index 186caad..3bbd97e 100644
> --- a/dtc.h
> +++ b/dtc.h
> @@ -187,6 +187,7 @@ struct data data_insert_data(struct data d, struct marker *m, struct data old);
> struct marker *alloc_marker(unsigned int offset, enum markertype type,
> char *ref);
> struct data data_add_marker(struct data d, enum markertype type, char *ref);
> +struct data data_append_markers(struct data d, struct marker *m);
>
> bool data_is_one_string(struct data d);
>
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 05/77] fdtdump: Change FDT_PROP prob handling to ease future addition
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (3 preceding siblings ...)
2026-01-12 14:18 ` [RFC PATCH 04/77] dtc: Allow to use data_append_markers() out of data.c Herve Codina
@ 2026-01-12 14:18 ` Herve Codina
2026-01-12 15:41 ` Ayush Singh
2026-01-12 14:18 ` [RFC PATCH 06/77] Add support for FDT_REF_LOCAL dtb tag Herve Codina
` (74 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:18 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
In order to ease future tags addition, perform operation related to
FDT_PROP when the tag is explicitly FDT_PROP instead of relying to a
kind of default value case.
Handle the FDT_PROP tag exactly in the same way as it is done for
other tags.
No functional modification.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
fdtdump.c | 34 ++++++++++++++++++----------------
1 file changed, 18 insertions(+), 16 deletions(-)
diff --git a/fdtdump.c b/fdtdump.c
index ec25edf..95a2274 100644
--- a/fdtdump.c
+++ b/fdtdump.c
@@ -129,23 +129,25 @@ static void dump_blob(void *blob, bool debug)
continue;
}
- if (tag != FDT_PROP) {
- fprintf(stderr, "%*s ** Unknown tag 0x%08"PRIx32"\n", depth * shift, "", tag);
- break;
+ if (tag == FDT_PROP) {
+ sz = fdt32_to_cpu(GET_CELL(p));
+ s = p_strings + fdt32_to_cpu(GET_CELL(p));
+ if (version < 16 && sz >= 8)
+ p = PALIGN(p, 8);
+ t = p;
+
+ p = PALIGN(p + sz, 4);
+
+ dumpf("%04"PRIxPTR": string: %s\n", (uintptr_t)s - blob_off, s);
+ dumpf("%04"PRIxPTR": value\n", (uintptr_t)t - blob_off);
+ printf("%*s%s", depth * shift, "", s);
+ utilfdt_print_data(t, sz);
+ printf(";\n");
+ continue;
}
- sz = fdt32_to_cpu(GET_CELL(p));
- s = p_strings + fdt32_to_cpu(GET_CELL(p));
- if (version < 16 && sz >= 8)
- p = PALIGN(p, 8);
- t = p;
-
- p = PALIGN(p + sz, 4);
-
- dumpf("%04"PRIxPTR": string: %s\n", (uintptr_t)s - blob_off, s);
- dumpf("%04"PRIxPTR": value\n", (uintptr_t)t - blob_off);
- printf("%*s%s", depth * shift, "", s);
- utilfdt_print_data(t, sz);
- printf(";\n");
+
+ fprintf(stderr, "%*s ** Unknown tag 0x%08"PRIx32"\n", depth * shift, "", tag);
+ break;
}
}
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 05/77] fdtdump: Change FDT_PROP prob handling to ease future addition
2026-01-12 14:18 ` [RFC PATCH 05/77] fdtdump: Change FDT_PROP prob handling to ease future addition Herve Codina
@ 2026-01-12 15:41 ` Ayush Singh
2026-01-15 0:28 ` David Gibson
0 siblings, 1 reply; 160+ messages in thread
From: Ayush Singh @ 2026-01-12 15:41 UTC (permalink / raw)
To: Herve Codina, David Gibson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
On 1/12/26 7:48 PM, Herve Codina wrote:
> In order to ease future tags addition, perform operation related to
> FDT_PROP when the tag is explicitly FDT_PROP instead of relying to a
> kind of default value case.
>
> Handle the FDT_PROP tag exactly in the same way as it is done for
> other tags.
>
> No functional modification.
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> fdtdump.c | 34 ++++++++++++++++++----------------
> 1 file changed, 18 insertions(+), 16 deletions(-)
>
> diff --git a/fdtdump.c b/fdtdump.c
> index ec25edf..95a2274 100644
> --- a/fdtdump.c
> +++ b/fdtdump.c
> @@ -129,23 +129,25 @@ static void dump_blob(void *blob, bool debug)
> continue;
> }
>
> - if (tag != FDT_PROP) {
> - fprintf(stderr, "%*s ** Unknown tag 0x%08"PRIx32"\n", depth * shift, "", tag);
> - break;
> + if (tag == FDT_PROP) {
> + sz = fdt32_to_cpu(GET_CELL(p));
> + s = p_strings + fdt32_to_cpu(GET_CELL(p));
> + if (version < 16 && sz >= 8)
> + p = PALIGN(p, 8);
> + t = p;
> +
> + p = PALIGN(p + sz, 4);
> +
> + dumpf("%04"PRIxPTR": string: %s\n", (uintptr_t)s - blob_off, s);
> + dumpf("%04"PRIxPTR": value\n", (uintptr_t)t - blob_off);
> + printf("%*s%s", depth * shift, "", s);
> + utilfdt_print_data(t, sz);
> + printf(";\n");
> + continue;
> }
> - sz = fdt32_to_cpu(GET_CELL(p));
> - s = p_strings + fdt32_to_cpu(GET_CELL(p));
> - if (version < 16 && sz >= 8)
> - p = PALIGN(p, 8);
> - t = p;
> -
> - p = PALIGN(p + sz, 4);
> -
> - dumpf("%04"PRIxPTR": string: %s\n", (uintptr_t)s - blob_off, s);
> - dumpf("%04"PRIxPTR": value\n", (uintptr_t)t - blob_off);
> - printf("%*s%s", depth * shift, "", s);
> - utilfdt_print_data(t, sz);
> - printf(";\n");
> +
> + fprintf(stderr, "%*s ** Unknown tag 0x%08"PRIx32"\n", depth * shift, "", tag);
> + break;
> }
> }
>
This seems reasonable refactor independently from the rest of the patch
series.
Reviewed-by: Ayush Singh <ayush@beagleboard.org>
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 05/77] fdtdump: Change FDT_PROP prob handling to ease future addition
2026-01-12 15:41 ` Ayush Singh
@ 2026-01-15 0:28 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-15 0:28 UTC (permalink / raw)
To: Ayush Singh
Cc: Herve Codina, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 2455 bytes --]
On Mon, Jan 12, 2026 at 09:11:52PM +0530, Ayush Singh wrote:
> On 1/12/26 7:48 PM, Herve Codina wrote:
>
> > In order to ease future tags addition, perform operation related to
> > FDT_PROP when the tag is explicitly FDT_PROP instead of relying to a
> > kind of default value case.
> >
> > Handle the FDT_PROP tag exactly in the same way as it is done for
> > other tags.
> >
> > No functional modification.
> >
> > Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> > ---
> > fdtdump.c | 34 ++++++++++++++++++----------------
> > 1 file changed, 18 insertions(+), 16 deletions(-)
> >
> > diff --git a/fdtdump.c b/fdtdump.c
> > index ec25edf..95a2274 100644
> > --- a/fdtdump.c
> > +++ b/fdtdump.c
> > @@ -129,23 +129,25 @@ static void dump_blob(void *blob, bool debug)
> > continue;
> > }
> > - if (tag != FDT_PROP) {
> > - fprintf(stderr, "%*s ** Unknown tag 0x%08"PRIx32"\n", depth * shift, "", tag);
> > - break;
> > + if (tag == FDT_PROP) {
> > + sz = fdt32_to_cpu(GET_CELL(p));
> > + s = p_strings + fdt32_to_cpu(GET_CELL(p));
> > + if (version < 16 && sz >= 8)
> > + p = PALIGN(p, 8);
> > + t = p;
> > +
> > + p = PALIGN(p + sz, 4);
> > +
> > + dumpf("%04"PRIxPTR": string: %s\n", (uintptr_t)s - blob_off, s);
> > + dumpf("%04"PRIxPTR": value\n", (uintptr_t)t - blob_off);
> > + printf("%*s%s", depth * shift, "", s);
> > + utilfdt_print_data(t, sz);
> > + printf(";\n");
> > + continue;
> > }
> > - sz = fdt32_to_cpu(GET_CELL(p));
> > - s = p_strings + fdt32_to_cpu(GET_CELL(p));
> > - if (version < 16 && sz >= 8)
> > - p = PALIGN(p, 8);
> > - t = p;
> > -
> > - p = PALIGN(p + sz, 4);
> > -
> > - dumpf("%04"PRIxPTR": string: %s\n", (uintptr_t)s - blob_off, s);
> > - dumpf("%04"PRIxPTR": value\n", (uintptr_t)t - blob_off);
> > - printf("%*s%s", depth * shift, "", s);
> > - utilfdt_print_data(t, sz);
> > - printf(";\n");
> > +
> > + fprintf(stderr, "%*s ** Unknown tag 0x%08"PRIx32"\n", depth * shift, "", tag);
> > + break;
> > }
> > }
>
>
> This seems reasonable refactor independently from the rest of the patch
> series.
Agreed. Merged.
> Reviewed-by: Ayush Singh <ayush@beagleboard.org>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 06/77] Add support for FDT_REF_LOCAL dtb tag
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (4 preceding siblings ...)
2026-01-12 14:18 ` [RFC PATCH 05/77] fdtdump: Change FDT_PROP prob handling to ease future addition Herve Codina
@ 2026-01-12 14:18 ` Herve Codina
2026-01-13 19:22 ` Rob Herring
2026-01-12 14:18 ` [RFC PATCH 07/77] livetree: Improve get_node_by_phandle() Herve Codina
` (73 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:18 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
FDT_REF_LOCAL dtb tag is a meta-data tag attached to a property.
It indicates that the property defined before this tag (FDT_PROP) uses a
phandle value and the node related to this phandle value is local (i.e.
the node is present in the device-tree blob).
It is followed by one value:
- offset (32bit):
Offset in the property data where the phandle is available.
Example:
FDT_PROP 0x00000008 xxxxxxxx 0xca 0xfe 0xde 0xca 0x01 0x02 0x03 0x04
FDT_REF_LOCAL 0x00000004
This means that at the offset 4 of the property data, the value
(0x01020304) is a phandle and the related node is available in the
dtb.
This is what is encoded in the dtb when the related dts has a property
with the value set to <0xcafedeca &foo> with 'foo' a reference to an
existing node where the phandle value is 0x01020304.
If several local phandles are used in the property data, several
FDT_REF_LOCAL are present after the FDT_PROP tag. Each of them points
with its offset value to the position of one phandle.
For instance, if a first property with 8 bytes of data has a phandle
value at offset 4 and a second property with 16 bytes of data has
phandle values at offset 0 and 8, the following tags sequence is
present:
FDT_PROP 0x00000008 xxxxxxxx <data bytes>
FDT_REF_LOCAL 0x00000004
FDT_PROP 0x00000010 xxxxxxxx <data bytes>
FDT_REF_LOCAL 0x00000000
FDT_REF_LOCAL 0x00000008
Add support for this new dtb tag.
Suggested-by: David Gibson <david@gibson.dropbear.id.au>
Link: https://lore.kernel.org/all/aL-2fmYsbexEtpNp@zatzit/
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
data.c | 1 +
dtc.h | 1 +
fdtdump.c | 14 +++++++++++++-
flattree.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
libfdt/fdt.c | 24 ++++++++++++++++++++++--
libfdt/fdt.h | 1 +
6 files changed, 84 insertions(+), 4 deletions(-)
diff --git a/data.c b/data.c
index 11b2169..9bae704 100644
--- a/data.c
+++ b/data.c
@@ -288,6 +288,7 @@ struct marker *alloc_marker(unsigned int offset, enum markertype type,
m->type = type;
m->ref = ref;
m->next = NULL;
+ m->is_local = 0;
return m;
}
diff --git a/dtc.h b/dtc.h
index 3bbd97e..965321c 100644
--- a/dtc.h
+++ b/dtc.h
@@ -128,6 +128,7 @@ struct marker {
enum markertype type;
unsigned int offset;
char *ref;
+ bool is_local;
struct marker *next;
};
diff --git a/fdtdump.c b/fdtdump.c
index 95a2274..dffa9a6 100644
--- a/fdtdump.c
+++ b/fdtdump.c
@@ -57,8 +57,9 @@ static void dump_blob(void *blob, bool debug)
const char *p_strings = (const char *)blob + off_str;
uint32_t version = fdt32_to_cpu(bph->version);
uint32_t totalsize = fdt32_to_cpu(bph->totalsize);
- uint32_t tag;
+ uint32_t tag, offset;
const char *p, *s, *t;
+ const char *last_prop_name = NULL;
int depth, sz, shift;
int i;
uint64_t addr, size;
@@ -105,6 +106,7 @@ static void dump_blob(void *blob, bool debug)
(uintptr_t)p - blob_off - 4, tag, tagname(tag));
if (tag == FDT_BEGIN_NODE) {
+ last_prop_name = NULL;
s = p;
p = PALIGN(p + strlen(s) + 1, 4);
@@ -118,6 +120,7 @@ static void dump_blob(void *blob, bool debug)
}
if (tag == FDT_END_NODE) {
+ last_prop_name = NULL;
depth--;
printf("%*s};\n", depth * shift, "");
@@ -143,6 +146,15 @@ static void dump_blob(void *blob, bool debug)
printf("%*s%s", depth * shift, "", s);
utilfdt_print_data(t, sz);
printf(";\n");
+ last_prop_name = s;
+ continue;
+ }
+
+ if (tag == FDT_REF_LOCAL) {
+ offset = fdt32_to_cpu(GET_CELL(p));
+
+ printf("%*s// [FDT_REF_LOCAL] %s[%"PRIu32"]\n", depth * shift, "",
+ last_prop_name, offset);
continue;
}
diff --git a/flattree.c b/flattree.c
index c3887da..5c597ad 100644
--- a/flattree.c
+++ b/flattree.c
@@ -13,6 +13,7 @@
#define FTF_STRTABSIZE 0x10
#define FTF_STRUCTSIZE 0x20
#define FTF_NOPS 0x40
+#define FTF_REF_XXX 0x80
static struct version_info {
int version;
@@ -31,7 +32,7 @@ static struct version_info {
{17, 16, FDT_V17_SIZE,
FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS},
{18, 18, FDT_V18_SIZE,
- FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS},
+ FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS|FTF_REF_XXX},
};
struct emitter {
@@ -42,6 +43,7 @@ struct emitter {
void (*beginnode)(void *, struct label *labels);
void (*endnode)(void *, struct label *labels);
void (*property)(void *, struct label *labels);
+ void (*ref_local)(void *);
};
static void bin_emit_cell(void *e, cell_t val)
@@ -91,6 +93,11 @@ static void bin_emit_property(void *e, struct label *labels)
bin_emit_cell(e, FDT_PROP);
}
+static void bin_emit_ref_local(void *e)
+{
+ bin_emit_cell(e, FDT_REF_LOCAL);
+}
+
static struct emitter bin_emitter = {
.cell = bin_emit_cell,
.string = bin_emit_string,
@@ -99,6 +106,7 @@ static struct emitter bin_emitter = {
.beginnode = bin_emit_beginnode,
.endnode = bin_emit_endnode,
.property = bin_emit_property,
+ .ref_local = bin_emit_ref_local,
};
static void emit_label(FILE *f, const char *prefix, const char *label)
@@ -210,6 +218,14 @@ static void asm_emit_property(void *e, struct label *labels)
asm_emit_cell(e, FDT_PROP);
}
+static void asm_emit_ref_local(void *e)
+{
+ FILE *f = e;
+
+ fprintf(f, "\t/* FDT_REF_LOCAL */\n");
+ asm_emit_cell(e, FDT_REF_LOCAL);
+}
+
static struct emitter asm_emitter = {
.cell = asm_emit_cell,
.string = asm_emit_string,
@@ -218,6 +234,7 @@ static struct emitter asm_emitter = {
.beginnode = asm_emit_beginnode,
.endnode = asm_emit_endnode,
.property = asm_emit_property,
+ .ref_local = asm_emit_ref_local,
};
static int stringtable_insert(struct data *d, const char *str)
@@ -242,6 +259,7 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
struct property *prop;
struct node *child;
bool seen_name_prop = false;
+ struct marker *m;
if (tree->deleted)
return;
@@ -272,6 +290,17 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
emit->data(etarget, prop->val);
emit->align(etarget, sizeof(cell_t));
+
+ if (vi->flags & FTF_REF_XXX) {
+ m = prop->val.markers;
+ for_each_marker_of_type(m, REF_PHANDLE) {
+ if (m->is_local) {
+ emit->ref_local(etarget);
+ emit->cell(etarget, m->offset);
+ continue;
+ }
+ }
+ }
}
if ((vi->flags & FTF_NAMEPROPS) && !seen_name_prop) {
@@ -737,6 +766,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
struct node *node;
const char *flatname;
uint32_t val;
+ uint32_t offset;
node = build_node(NULL, NULL, NULL);
@@ -751,6 +781,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
do {
struct property *prop;
struct node *child;
+ struct marker *m;
val = flat_read_word(dtbuf);
switch (val) {
@@ -782,6 +813,17 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
/* Ignore */
break;
+ case FDT_REF_LOCAL:
+ if (!(flags & FTF_REF_XXX))
+ die("REF_LOCAL tag found in flat tree"
+ " version <18\n");
+
+ offset = flat_read_word(dtbuf);
+ m = alloc_marker(offset, REF_PHANDLE, NULL);
+ m->is_local = true;
+ prop->val = data_append_markers(prop->val, m);
+ break;
+
default:
die("Invalid opcode word %08x in device tree blob\n",
val);
@@ -900,6 +942,9 @@ struct dt_info *dt_from_blob(const char *fname)
flags |= FTF_NOPS;
}
+ if (version >= 18)
+ flags |= FTF_REF_XXX;
+
inbuf_init(&memresvbuf,
blob + off_mem_rsvmap, blob + totalsize);
inbuf_init(&dtbuf, blob + off_dt, blob + totalsize);
diff --git a/libfdt/fdt.c b/libfdt/fdt.c
index ce051a0..7268fb6 100644
--- a/libfdt/fdt.c
+++ b/libfdt/fdt.c
@@ -161,7 +161,7 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
uint32_t fdt_next_tag_full(const void *fdt, int startoffset, int *nextoffset)
{
- const fdt32_t *tagp, *lenp;
+ const fdt32_t *tagp, *lenp, *tmp32p;
uint32_t tag, len, sum;
int offset = startoffset;
const char *p;
@@ -209,6 +209,14 @@ uint32_t fdt_next_tag_full(const void *fdt, int startoffset, int *nextoffset)
case FDT_NOP:
break;
+ case FDT_REF_LOCAL:
+ /* Skip offset value */
+ tmp32p = fdt_offset_ptr(fdt, offset, sizeof(*tmp32p));
+ if (!can_assume(VALID_DTB) && !tmp32p)
+ return FDT_END; /* premature end */
+ offset += sizeof(fdt32_t);
+ break;
+
default:
return FDT_END;
}
@@ -239,10 +247,22 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
case FDT_PROP:
case FDT_NOP:
case FDT_END:
- /* Next tag is not new tag introduced in v18 -> Ok */
+ /*
+ * Next tag is not a meta-data tag -> Ok this next tag
+ * has to be handle by fd_next_tag().
+ * Filter out any potential meta-data tag returning
+ * nextoffset pointing to this current next tag.
+ */
*nextoffset = tmp_offset;
return tag;
+ case FDT_REF_LOCAL:
+ /*
+ * Next tag is a meta-data tag present in the middle
+ * of the structure -> Skip it and look at next one
+ */
+ break;
+
default:
break;
}
diff --git a/libfdt/fdt.h b/libfdt/fdt.h
index 9372353..f8efdf1 100644
--- a/libfdt/fdt.h
+++ b/libfdt/fdt.h
@@ -55,6 +55,7 @@ struct fdt_property {
#define FDT_PROP 0x3 /* Property: name off,
size, content */
#define FDT_NOP 0x4 /* nop */
+#define FDT_REF_LOCAL 0x5 /* local phandle reference: offset */
#define FDT_END 0x9
#define FDT_V1_SIZE (7*sizeof(fdt32_t))
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 06/77] Add support for FDT_REF_LOCAL dtb tag
2026-01-12 14:18 ` [RFC PATCH 06/77] Add support for FDT_REF_LOCAL dtb tag Herve Codina
@ 2026-01-13 19:22 ` Rob Herring
2026-01-15 0:34 ` David Gibson
0 siblings, 1 reply; 160+ messages in thread
From: Rob Herring @ 2026-01-13 19:22 UTC (permalink / raw)
To: Herve Codina
Cc: David Gibson, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
On Mon, Jan 12, 2026 at 8:20 AM Herve Codina <herve.codina@bootlin.com> wrote:
>
> FDT_REF_LOCAL dtb tag is a meta-data tag attached to a property.
>
> It indicates that the property defined before this tag (FDT_PROP) uses a
> phandle value and the node related to this phandle value is local (i.e.
> the node is present in the device-tree blob).
>
> It is followed by one value:
> - offset (32bit):
> Offset in the property data where the phandle is available.
>
> Example:
> FDT_PROP 0x00000008 xxxxxxxx 0xca 0xfe 0xde 0xca 0x01 0x02 0x03 0x04
> FDT_REF_LOCAL 0x00000004
>
> This means that at the offset 4 of the property data, the value
> (0x01020304) is a phandle and the related node is available in the
> dtb.
>
> This is what is encoded in the dtb when the related dts has a property
> with the value set to <0xcafedeca &foo> with 'foo' a reference to an
> existing node where the phandle value is 0x01020304.
>
> If several local phandles are used in the property data, several
> FDT_REF_LOCAL are present after the FDT_PROP tag. Each of them points
> with its offset value to the position of one phandle.
>
> For instance, if a first property with 8 bytes of data has a phandle
> value at offset 4 and a second property with 16 bytes of data has
> phandle values at offset 0 and 8, the following tags sequence is
> present:
> FDT_PROP 0x00000008 xxxxxxxx <data bytes>
> FDT_REF_LOCAL 0x00000004
> FDT_PROP 0x00000010 xxxxxxxx <data bytes>
> FDT_REF_LOCAL 0x00000000
> FDT_REF_LOCAL 0x00000008
To follow up on my desire to both be easily extended and have more
type info, I have something like this in mind:
FDT_TYPE_INFO 0x10 FDT_REF_LOCAL 0x0 FDT_TYPE_U32 0x4 FDT_REF_LOCAL
0x8 FDT_TYPE_U32 0xc
Length is 16 because I would do u16 for the types and lengths. I'm not
sure what the max property length is. In theory 2^32, but I suspect
we'd run into other issues (e.g. libfdt offsets are 32-bit on 32-bit
systems). We could also do 8 bits for type and 24 bits for offset.
Offset could also be relative to the prior offset.
Rob
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 06/77] Add support for FDT_REF_LOCAL dtb tag
2026-01-13 19:22 ` Rob Herring
@ 2026-01-15 0:34 ` David Gibson
2026-01-15 15:54 ` Rob Herring
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-15 0:34 UTC (permalink / raw)
To: Rob Herring
Cc: Herve Codina, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 3239 bytes --]
On Tue, Jan 13, 2026 at 01:22:08PM -0600, Rob Herring wrote:
> On Mon, Jan 12, 2026 at 8:20 AM Herve Codina <herve.codina@bootlin.com> wrote:
> >
> > FDT_REF_LOCAL dtb tag is a meta-data tag attached to a property.
> >
> > It indicates that the property defined before this tag (FDT_PROP) uses a
> > phandle value and the node related to this phandle value is local (i.e.
> > the node is present in the device-tree blob).
> >
> > It is followed by one value:
> > - offset (32bit):
> > Offset in the property data where the phandle is available.
> >
> > Example:
> > FDT_PROP 0x00000008 xxxxxxxx 0xca 0xfe 0xde 0xca 0x01 0x02 0x03 0x04
> > FDT_REF_LOCAL 0x00000004
> >
> > This means that at the offset 4 of the property data, the value
> > (0x01020304) is a phandle and the related node is available in the
> > dtb.
> >
> > This is what is encoded in the dtb when the related dts has a property
> > with the value set to <0xcafedeca &foo> with 'foo' a reference to an
> > existing node where the phandle value is 0x01020304.
> >
> > If several local phandles are used in the property data, several
> > FDT_REF_LOCAL are present after the FDT_PROP tag. Each of them points
> > with its offset value to the position of one phandle.
> >
> > For instance, if a first property with 8 bytes of data has a phandle
> > value at offset 4 and a second property with 16 bytes of data has
> > phandle values at offset 0 and 8, the following tags sequence is
> > present:
> > FDT_PROP 0x00000008 xxxxxxxx <data bytes>
> > FDT_REF_LOCAL 0x00000004
> > FDT_PROP 0x00000010 xxxxxxxx <data bytes>
> > FDT_REF_LOCAL 0x00000000
> > FDT_REF_LOCAL 0x00000008
>
> To follow up on my desire to both be easily extended and have more
> type info, I have something like this in mind:
>
> FDT_TYPE_INFO 0x10 FDT_REF_LOCAL 0x0 FDT_TYPE_U32 0x4 FDT_REF_LOCAL
> 0x8 FDT_TYPE_U32 0xc
I think general type info should be out of scope for this:
* This series is already enormous and complicated without that
* phandles aren't just another type, they have structural relevance
which makes them a special case
Plus, I'm actually pretty dubious about adding type information to
dtbs in the first place. It gives the impression that dt property
values are self-describing, but they're not. If you want a
self-describing format, I think you'd be better off dropping the
OF-related past entirely, and using json or one of the various other
modern self-describing structure data formats.
> Length is 16 because I would do u16 for the types and lengths. I'm not
> sure what the max property length is. In theory 2^32, but I suspect
> we'd run into other issues (e.g. libfdt offsets are 32-bit on 32-bit
> systems). We could also do 8 bits for type and 24 bits for offset.
> Offset could also be relative to the prior offset.
Structurally dtbs are limited to 2^32 bytes, by policy they're limited
to 2^31 bytes (so we can safely store an offset in a signed 32-bit
int).
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 06/77] Add support for FDT_REF_LOCAL dtb tag
2026-01-15 0:34 ` David Gibson
@ 2026-01-15 15:54 ` Rob Herring
2026-01-16 10:16 ` Herve Codina
2026-01-19 6:16 ` David Gibson
0 siblings, 2 replies; 160+ messages in thread
From: Rob Herring @ 2026-01-15 15:54 UTC (permalink / raw)
To: David Gibson
Cc: Herve Codina, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
On Wed, Jan 14, 2026 at 6:51 PM David Gibson
<david@gibson.dropbear.id.au> wrote:
>
> On Tue, Jan 13, 2026 at 01:22:08PM -0600, Rob Herring wrote:
> > On Mon, Jan 12, 2026 at 8:20 AM Herve Codina <herve.codina@bootlin.com> wrote:
> > >
> > > FDT_REF_LOCAL dtb tag is a meta-data tag attached to a property.
> > >
> > > It indicates that the property defined before this tag (FDT_PROP) uses a
> > > phandle value and the node related to this phandle value is local (i.e.
> > > the node is present in the device-tree blob).
> > >
> > > It is followed by one value:
> > > - offset (32bit):
> > > Offset in the property data where the phandle is available.
> > >
> > > Example:
> > > FDT_PROP 0x00000008 xxxxxxxx 0xca 0xfe 0xde 0xca 0x01 0x02 0x03 0x04
> > > FDT_REF_LOCAL 0x00000004
> > >
> > > This means that at the offset 4 of the property data, the value
> > > (0x01020304) is a phandle and the related node is available in the
> > > dtb.
> > >
> > > This is what is encoded in the dtb when the related dts has a property
> > > with the value set to <0xcafedeca &foo> with 'foo' a reference to an
> > > existing node where the phandle value is 0x01020304.
> > >
> > > If several local phandles are used in the property data, several
> > > FDT_REF_LOCAL are present after the FDT_PROP tag. Each of them points
> > > with its offset value to the position of one phandle.
> > >
> > > For instance, if a first property with 8 bytes of data has a phandle
> > > value at offset 4 and a second property with 16 bytes of data has
> > > phandle values at offset 0 and 8, the following tags sequence is
> > > present:
> > > FDT_PROP 0x00000008 xxxxxxxx <data bytes>
> > > FDT_REF_LOCAL 0x00000004
> > > FDT_PROP 0x00000010 xxxxxxxx <data bytes>
> > > FDT_REF_LOCAL 0x00000000
> > > FDT_REF_LOCAL 0x00000008
> >
> > To follow up on my desire to both be easily extended and have more
> > type info, I have something like this in mind:
> >
> > FDT_TYPE_INFO 0x10 FDT_REF_LOCAL 0x0 FDT_TYPE_U32 0x4 FDT_REF_LOCAL
> > 0x8 FDT_TYPE_U32 0xc
>
> I think general type info should be out of scope for this:
> * This series is already enormous and complicated without that
It is enormous, but I don't think the intention was to finalize and
merge it all at once. I certainly don't intend to review it all now.
The final result looks sane to me and with that we have a good idea
what information needs to go in the DTB. I think the first step is to
define the new metadata tags and what DTB format changes are needed.
> * phandles aren't just another type, they have structural relevance
> which makes them a special case
Fair enough.
What's similar is we need to define FOO is at offset X just like the
markers within dtc. We can add other types later, I'm just asking that
the design here for new tags and phandles accounts for that.
> Plus, I'm actually pretty dubious about adding type information to
> dtbs in the first place. It gives the impression that dt property
> values are self-describing, but they're not. If you want a
> self-describing format, I think you'd be better off dropping the
> OF-related past entirely, and using json or one of the various other
> modern self-describing structure data formats.
json has no concept of integer sizes (and numbers are floats). The
typical work-around for that is encode everything as a string and then
we're pretty much back to everything's a byte array. Pretty sure we've
been thru this already. So I don't know what format we'd use. I've not
come across one. Perhaps just DTS as that does have the type
information. :) In any case, I'm not interested in a revolution, just
evolution. I want a format that transparently works with only an
updated libfdt. Anything else is simply going to go nowhere (as
evident by the last 15 years of new DTB format discussions).
I know you aren't a fan of relying on .dts information for type
information, but that's not the only source anymore. We now have an
entire database of every last property and its type. That could be
what's used to populate type information. Again, we don't have to
define how we do it now, just allow for it (and any other metadata we
have yet to think about) in the DTB format changes.
Rob
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 06/77] Add support for FDT_REF_LOCAL dtb tag
2026-01-15 15:54 ` Rob Herring
@ 2026-01-16 10:16 ` Herve Codina
2026-01-16 10:17 ` Herve Codina
2026-01-19 6:16 ` David Gibson
1 sibling, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-16 10:16 UTC (permalink / raw)
To: Rob Herring
Cc: David Gibson, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
Hi Rob, David,
On Thu, 15 Jan 2026 09:54:22 -0600
Rob Herring <robh@kernel.org> wrote:
> On Wed, Jan 14, 2026 at 6:51 PM David Gibson
> <david@gibson.dropbear.id.au> wrote:
> >
> > On Tue, Jan 13, 2026 at 01:22:08PM -0600, Rob Herring wrote:
> > > On Mon, Jan 12, 2026 at 8:20 AM Herve Codina <herve.codina@bootlin.com> wrote:
> > > >
> > > > FDT_REF_LOCAL dtb tag is a meta-data tag attached to a property.
> > > >
> > > > It indicates that the property defined before this tag (FDT_PROP) uses a
> > > > phandle value and the node related to this phandle value is local (i.e.
> > > > the node is present in the device-tree blob).
> > > >
> > > > It is followed by one value:
> > > > - offset (32bit):
> > > > Offset in the property data where the phandle is available.
> > > >
> > > > Example:
> > > > FDT_PROP 0x00000008 xxxxxxxx 0xca 0xfe 0xde 0xca 0x01 0x02 0x03 0x04
> > > > FDT_REF_LOCAL 0x00000004
> > > >
> > > > This means that at the offset 4 of the property data, the value
> > > > (0x01020304) is a phandle and the related node is available in the
> > > > dtb.
> > > >
> > > > This is what is encoded in the dtb when the related dts has a property
> > > > with the value set to <0xcafedeca &foo> with 'foo' a reference to an
> > > > existing node where the phandle value is 0x01020304.
> > > >
> > > > If several local phandles are used in the property data, several
> > > > FDT_REF_LOCAL are present after the FDT_PROP tag. Each of them points
> > > > with its offset value to the position of one phandle.
> > > >
> > > > For instance, if a first property with 8 bytes of data has a phandle
> > > > value at offset 4 and a second property with 16 bytes of data has
> > > > phandle values at offset 0 and 8, the following tags sequence is
> > > > present:
> > > > FDT_PROP 0x00000008 xxxxxxxx <data bytes>
> > > > FDT_REF_LOCAL 0x00000004
> > > > FDT_PROP 0x00000010 xxxxxxxx <data bytes>
> > > > FDT_REF_LOCAL 0x00000000
> > > > FDT_REF_LOCAL 0x00000008
> > >
> > > To follow up on my desire to both be easily extended and have more
> > > type info, I have something like this in mind:
> > >
> > > FDT_TYPE_INFO 0x10 FDT_REF_LOCAL 0x0 FDT_TYPE_U32 0x4 FDT_REF_LOCAL
> > > 0x8 FDT_TYPE_U32 0xc
> >
> > I think general type info should be out of scope for this:
> > * This series is already enormous and complicated without that
>
> It is enormous, but I don't think the intention was to finalize and
> merge it all at once. I certainly don't intend to review it all now.
> The final result looks sane to me and with that we have a good idea
> what information needs to go in the DTB. I think the first step is to
> define the new metadata tags and what DTB format changes are needed.
Indeed, the goal of this RFC is to give the big picture and open
discussions.
FDT_TYPE_INFO tag is a container. It just groups other tags together.
I don't use the term TYPE in the proposal related to generic tag values [1].
I use FDT_INFO_PROPERTY which is more generic.
Best regards,
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 06/77] Add support for FDT_REF_LOCAL dtb tag
2026-01-16 10:16 ` Herve Codina
@ 2026-01-16 10:17 ` Herve Codina
0 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-16 10:17 UTC (permalink / raw)
To: Rob Herring
Cc: David Gibson, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
On Fri, 16 Jan 2026 11:16:16 +0100
Herve Codina <herve.codina@bootlin.com> wrote:
> Hi Rob, David,
>
> On Thu, 15 Jan 2026 09:54:22 -0600
> Rob Herring <robh@kernel.org> wrote:
>
> > On Wed, Jan 14, 2026 at 6:51 PM David Gibson
> > <david@gibson.dropbear.id.au> wrote:
> > >
> > > On Tue, Jan 13, 2026 at 01:22:08PM -0600, Rob Herring wrote:
> > > > On Mon, Jan 12, 2026 at 8:20 AM Herve Codina <herve.codina@bootlin.com> wrote:
> > > > >
> > > > > FDT_REF_LOCAL dtb tag is a meta-data tag attached to a property.
> > > > >
> > > > > It indicates that the property defined before this tag (FDT_PROP) uses a
> > > > > phandle value and the node related to this phandle value is local (i.e.
> > > > > the node is present in the device-tree blob).
> > > > >
> > > > > It is followed by one value:
> > > > > - offset (32bit):
> > > > > Offset in the property data where the phandle is available.
> > > > >
> > > > > Example:
> > > > > FDT_PROP 0x00000008 xxxxxxxx 0xca 0xfe 0xde 0xca 0x01 0x02 0x03 0x04
> > > > > FDT_REF_LOCAL 0x00000004
> > > > >
> > > > > This means that at the offset 4 of the property data, the value
> > > > > (0x01020304) is a phandle and the related node is available in the
> > > > > dtb.
> > > > >
> > > > > This is what is encoded in the dtb when the related dts has a property
> > > > > with the value set to <0xcafedeca &foo> with 'foo' a reference to an
> > > > > existing node where the phandle value is 0x01020304.
> > > > >
> > > > > If several local phandles are used in the property data, several
> > > > > FDT_REF_LOCAL are present after the FDT_PROP tag. Each of them points
> > > > > with its offset value to the position of one phandle.
> > > > >
> > > > > For instance, if a first property with 8 bytes of data has a phandle
> > > > > value at offset 4 and a second property with 16 bytes of data has
> > > > > phandle values at offset 0 and 8, the following tags sequence is
> > > > > present:
> > > > > FDT_PROP 0x00000008 xxxxxxxx <data bytes>
> > > > > FDT_REF_LOCAL 0x00000004
> > > > > FDT_PROP 0x00000010 xxxxxxxx <data bytes>
> > > > > FDT_REF_LOCAL 0x00000000
> > > > > FDT_REF_LOCAL 0x00000008
> > > >
> > > > To follow up on my desire to both be easily extended and have more
> > > > type info, I have something like this in mind:
> > > >
> > > > FDT_TYPE_INFO 0x10 FDT_REF_LOCAL 0x0 FDT_TYPE_U32 0x4 FDT_REF_LOCAL
> > > > 0x8 FDT_TYPE_U32 0xc
> > >
> > > I think general type info should be out of scope for this:
> > > * This series is already enormous and complicated without that
> >
> > It is enormous, but I don't think the intention was to finalize and
> > merge it all at once. I certainly don't intend to review it all now.
> > The final result looks sane to me and with that we have a good idea
> > what information needs to go in the DTB. I think the first step is to
> > define the new metadata tags and what DTB format changes are needed.
>
> Indeed, the goal of this RFC is to give the big picture and open
> discussions.
>
> FDT_TYPE_INFO tag is a container. It just groups other tags together.
>
> I don't use the term TYPE in the proposal related to generic tag values [1].
> I use FDT_INFO_PROPERTY which is more generic.
>
> Best regards,
> Hervé
[1] https://lore.kernel.org/all/20260114171822.2a44d2a5@bootlin.com/
--
Hervé Codina, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 06/77] Add support for FDT_REF_LOCAL dtb tag
2026-01-15 15:54 ` Rob Herring
2026-01-16 10:16 ` Herve Codina
@ 2026-01-19 6:16 ` David Gibson
1 sibling, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-19 6:16 UTC (permalink / raw)
To: Rob Herring
Cc: Herve Codina, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 6135 bytes --]
On Thu, Jan 15, 2026 at 09:54:22AM -0600, Rob Herring wrote:
> On Wed, Jan 14, 2026 at 6:51 PM David Gibson
> <david@gibson.dropbear.id.au> wrote:
> >
> > On Tue, Jan 13, 2026 at 01:22:08PM -0600, Rob Herring wrote:
> > > On Mon, Jan 12, 2026 at 8:20 AM Herve Codina <herve.codina@bootlin.com> wrote:
> > > >
> > > > FDT_REF_LOCAL dtb tag is a meta-data tag attached to a property.
> > > >
> > > > It indicates that the property defined before this tag (FDT_PROP) uses a
> > > > phandle value and the node related to this phandle value is local (i.e.
> > > > the node is present in the device-tree blob).
> > > >
> > > > It is followed by one value:
> > > > - offset (32bit):
> > > > Offset in the property data where the phandle is available.
> > > >
> > > > Example:
> > > > FDT_PROP 0x00000008 xxxxxxxx 0xca 0xfe 0xde 0xca 0x01 0x02 0x03 0x04
> > > > FDT_REF_LOCAL 0x00000004
> > > >
> > > > This means that at the offset 4 of the property data, the value
> > > > (0x01020304) is a phandle and the related node is available in the
> > > > dtb.
> > > >
> > > > This is what is encoded in the dtb when the related dts has a property
> > > > with the value set to <0xcafedeca &foo> with 'foo' a reference to an
> > > > existing node where the phandle value is 0x01020304.
> > > >
> > > > If several local phandles are used in the property data, several
> > > > FDT_REF_LOCAL are present after the FDT_PROP tag. Each of them points
> > > > with its offset value to the position of one phandle.
> > > >
> > > > For instance, if a first property with 8 bytes of data has a phandle
> > > > value at offset 4 and a second property with 16 bytes of data has
> > > > phandle values at offset 0 and 8, the following tags sequence is
> > > > present:
> > > > FDT_PROP 0x00000008 xxxxxxxx <data bytes>
> > > > FDT_REF_LOCAL 0x00000004
> > > > FDT_PROP 0x00000010 xxxxxxxx <data bytes>
> > > > FDT_REF_LOCAL 0x00000000
> > > > FDT_REF_LOCAL 0x00000008
> > >
> > > To follow up on my desire to both be easily extended and have more
> > > type info, I have something like this in mind:
> > >
> > > FDT_TYPE_INFO 0x10 FDT_REF_LOCAL 0x0 FDT_TYPE_U32 0x4 FDT_REF_LOCAL
> > > 0x8 FDT_TYPE_U32 0xc
> >
> > I think general type info should be out of scope for this:
> > * This series is already enormous and complicated without that
>
> It is enormous, but I don't think the intention was to finalize and
> merge it all at once. I certainly don't intend to review it all now.
> The final result looks sane to me and with that we have a good idea
> what information needs to go in the DTB. I think the first step is to
> define the new metadata tags and what DTB format changes are needed.
I mostly agree. But as noted, we can't advertise v18 (or whatever)
support until we actually *do* support it - which would imply having
some docs / specs on what exactly is in v18. So the series will need
some re-ordering to allow pieces to be merged earlier.
> > * phandles aren't just another type, they have structural relevance
> > which makes them a special case
>
> Fair enough.
>
> What's similar is we need to define FOO is at offset X just like the
> markers within dtc. We can add other types later, I'm just asking that
> the design here for new tags and phandles accounts for that.
>
> > Plus, I'm actually pretty dubious about adding type information to
> > dtbs in the first place. It gives the impression that dt property
> > values are self-describing, but they're not. If you want a
> > self-describing format, I think you'd be better off dropping the
> > OF-related past entirely, and using json or one of the various other
> > modern self-describing structure data formats.
>
> json has no concept of integer sizes (and numbers are floats).
Good point, and dtb has heavier than many need of true 64-bit ints.
It's a real half-ton of flies in a mostly pretty decent data model :(.
> The
> typical work-around for that is encode everything as a string and then
> we're pretty much back to everything's a byte array. Pretty sure we've
> been thru this already. So I don't know what format we'd use. I've not
> come across one.
ASN.1? CBOR? Messagepack? Protobuf? I don't love any of those, but
I'm not sure they'd be *more* clunky than something we cobble together
on top of dtb.
> Perhaps just DTS as that does have the type
> information. :) In any case, I'm not interested in a revolution, just
> evolution. I want a format that transparently works with only an
> updated libfdt. Anything else is simply going to go nowhere (as
> evident by the last 15 years of new DTB format discussions).
As a rule, I also prefer evolution to revolution. But there can come
a point where you're straining the thing you're building on further
than makes sense any more.
> I know you aren't a fan of relying on .dts information for type
> information, but that's not the only source anymore. We now have an
> entire database of every last property and its type. That could be
> what's used to populate type information. Again, we don't have to
> define how we do it now, just allow for it (and any other metadata we
> have yet to think about) in the DTB format changes.
I guess it depends a bit how you're thinking of this type information.
Are you thinking of it as an intrinsic part of the dtb information
that a consumer (like the kernel) would use? Something akin to the
symbols or relocation information in an ELF object.
Or are you thinking of it as something for the benefit of intermediate
tools, that could be stripped out before going to the final consumer?
Something like debug symbols in an ELF object.
I'm open to the second approach, although I'm still a bit concerned
that once it's there as "debug" information things might start relying
on it which shouldn't.
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 07/77] livetree: Improve get_node_by_phandle()
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (5 preceding siblings ...)
2026-01-12 14:18 ` [RFC PATCH 06/77] Add support for FDT_REF_LOCAL dtb tag Herve Codina
@ 2026-01-12 14:18 ` Herve Codina
2026-01-15 0:41 ` David Gibson
2026-01-12 14:18 ` [RFC PATCH 08/77] dtc: Introduce update_phandles_ref() Herve Codina
` (72 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:18 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
get_node_by_phandle() allows to get a node based on its phandle value.
It checks the phandle value against value available in internal node
structure.
This internal phandle value is updated during process_check() and so,
get_node_by_phandle() cannot give correct results before the
process_check() call.
Improve get_node_by_phandle() to look at node phandle properties when
the internal phandle value is not valid.
This allows to return a correct matching node even if process_check()
was not called yet.
With the recently introduced FDT_REF_LOCAL dtb tag, this will be needed
to update internal phandle references before the call to process_check().
Indeed, this tag allows to identify phandles and internal references
need to be updated based on the phandle value before the
process_check() call.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
livetree.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/livetree.c b/livetree.c
index f328824..9b67934 100644
--- a/livetree.c
+++ b/livetree.c
@@ -609,16 +609,35 @@ struct node *get_node_by_label(struct node *tree, const char *label)
return NULL;
}
+static cell_t get_node_phandle_existing(struct node *node)
+{
+ struct property *prop;
+
+ if (phandle_is_valid(node->phandle))
+ return node->phandle;
+
+ prop = get_property(node, "phandle");
+ if (!prop) {
+ prop = get_property(node, "linux,phandle");
+ if (!prop)
+ return 0;
+ }
+
+ return propval_cell(prop);
+}
+
struct node *get_node_by_phandle(struct node *tree, cell_t phandle)
{
struct node *child, *node;
+ cell_t tree_phandle;
if (!phandle_is_valid(phandle)) {
assert(generate_fixups);
return NULL;
}
- if (tree->phandle == phandle) {
+ tree_phandle = get_node_phandle_existing(tree);
+ if (phandle_is_valid(tree_phandle) && tree_phandle == phandle) {
if (tree->deleted)
return NULL;
return tree;
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 07/77] livetree: Improve get_node_by_phandle()
2026-01-12 14:18 ` [RFC PATCH 07/77] livetree: Improve get_node_by_phandle() Herve Codina
@ 2026-01-15 0:41 ` David Gibson
2026-01-16 10:52 ` Herve Codina
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-15 0:41 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 2765 bytes --]
On Mon, Jan 12, 2026 at 03:18:57PM +0100, Herve Codina wrote:
> get_node_by_phandle() allows to get a node based on its phandle value.
> It checks the phandle value against value available in internal node
> structure.
>
> This internal phandle value is updated during process_check() and so,
> get_node_by_phandle() cannot give correct results before the
> process_check() call.
>
> Improve get_node_by_phandle() to look at node phandle properties when
> the internal phandle value is not valid.
>
> This allows to return a correct matching node even if process_check()
> was not called yet.
>
> With the recently introduced FDT_REF_LOCAL dtb tag, this will be needed
> to update internal phandle references before the call to process_check().
> Indeed, this tag allows to identify phandles and internal references
> need to be updated based on the phandle value before the
> process_check() call.
Having two entirely different paths for get_node_by_phandle() is
really ugly.
I suspect a better approach would be to special case updates to the
internal phandle field as we parse the phandle properties, rather than
doing it as a batch during the checks.
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> livetree.c | 21 ++++++++++++++++++++-
> 1 file changed, 20 insertions(+), 1 deletion(-)
>
> diff --git a/livetree.c b/livetree.c
> index f328824..9b67934 100644
> --- a/livetree.c
> +++ b/livetree.c
> @@ -609,16 +609,35 @@ struct node *get_node_by_label(struct node *tree, const char *label)
> return NULL;
> }
>
> +static cell_t get_node_phandle_existing(struct node *node)
> +{
> + struct property *prop;
> +
> + if (phandle_is_valid(node->phandle))
g> + return node->phandle;
> +
> + prop = get_property(node, "phandle");
> + if (!prop) {
> + prop = get_property(node, "linux,phandle");
> + if (!prop)
> + return 0;
> + }
> +
> + return propval_cell(prop);
> +}
> +
> struct node *get_node_by_phandle(struct node *tree, cell_t phandle)
> {
> struct node *child, *node;
> + cell_t tree_phandle;
>
> if (!phandle_is_valid(phandle)) {
> assert(generate_fixups);
> return NULL;
> }
>
> - if (tree->phandle == phandle) {
> + tree_phandle = get_node_phandle_existing(tree);
It's especially nasty that we call the expensive version first, then
fall back to the cheap version...
> + if (phandle_is_valid(tree_phandle) && tree_phandle == phandle) {
> if (tree->deleted)
> return NULL;
> return tree;
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 07/77] livetree: Improve get_node_by_phandle()
2026-01-15 0:41 ` David Gibson
@ 2026-01-16 10:52 ` Herve Codina
2026-01-19 5:18 ` David Gibson
0 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-16 10:52 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
Hi David,
On Thu, 15 Jan 2026 11:41:32 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Mon, Jan 12, 2026 at 03:18:57PM +0100, Herve Codina wrote:
> > get_node_by_phandle() allows to get a node based on its phandle value.
> > It checks the phandle value against value available in internal node
> > structure.
> >
> > This internal phandle value is updated during process_check() and so,
> > get_node_by_phandle() cannot give correct results before the
> > process_check() call.
> >
> > Improve get_node_by_phandle() to look at node phandle properties when
> > the internal phandle value is not valid.
> >
> > This allows to return a correct matching node even if process_check()
> > was not called yet.
> >
> > With the recently introduced FDT_REF_LOCAL dtb tag, this will be needed
> > to update internal phandle references before the call to process_check().
> > Indeed, this tag allows to identify phandles and internal references
> > need to be updated based on the phandle value before the
> > process_check() call.
>
> Having two entirely different paths for get_node_by_phandle() is
> really ugly.
>
> I suspect a better approach would be to special case updates to the
> internal phandle field as we parse the phandle properties, rather than
> doing it as a batch during the checks.
Doing that when we parse the property will be quite complex. Indeed,
when we parse a dts, the node internal object is not yet created when
the property is parsed.
What I think could be done is to set the phandle field just after the
parsing of input (dts or dtb). In current implementation this is done by
process_check() when fixup_phandle_references() is called.
This fixup_phandle_references() call should be removed from process_check()
and called right after the input parsing.
I you are ok with that, I can propose something in the next iteration.
Best regards,
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 07/77] livetree: Improve get_node_by_phandle()
2026-01-16 10:52 ` Herve Codina
@ 2026-01-19 5:18 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-19 5:18 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 3379 bytes --]
On Fri, Jan 16, 2026 at 11:52:54AM +0100, Herve Codina wrote:
> Hi David,
>
> On Thu, 15 Jan 2026 11:41:32 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > On Mon, Jan 12, 2026 at 03:18:57PM +0100, Herve Codina wrote:
> > > get_node_by_phandle() allows to get a node based on its phandle value.
> > > It checks the phandle value against value available in internal node
> > > structure.
> > >
> > > This internal phandle value is updated during process_check() and so,
> > > get_node_by_phandle() cannot give correct results before the
> > > process_check() call.
> > >
> > > Improve get_node_by_phandle() to look at node phandle properties when
> > > the internal phandle value is not valid.
> > >
> > > This allows to return a correct matching node even if process_check()
> > > was not called yet.
> > >
> > > With the recently introduced FDT_REF_LOCAL dtb tag, this will be needed
> > > to update internal phandle references before the call to process_check().
> > > Indeed, this tag allows to identify phandles and internal references
> > > need to be updated based on the phandle value before the
> > > process_check() call.
> >
> > Having two entirely different paths for get_node_by_phandle() is
> > really ugly.
> >
> > I suspect a better approach would be to special case updates to the
> > internal phandle field as we parse the phandle properties, rather than
> > doing it as a batch during the checks.
>
> Doing that when we parse the property will be quite complex. Indeed,
> when we parse a dts, the node internal object is not yet created when
> the property is parsed.
Ah, good point.
> What I think could be done is to set the phandle field just after the
> parsing of input (dts or dtb). In current implementation this is done by
> process_check() when fixup_phandle_references() is called.
Oof. So, on the one hand, doing this indexing in the "checks" is kind
of weird - I implemented it that way because it just seemed a
convenient place that already scanned the full tree and had mechanisms
for dependencies between different steps.
However... these dependencies are a bit subtle. Part of the trick
here is that the indexing has dependencies on the really basic checks
that we don't have invalid or duplicate node/property names. If we
moved the phandle indexing before that, we'd have to explicitly deal
with the possibility of multiple "phandle" properties and other
weirdness.
Maybe we want to split the "checks" into two different phases. One
for "structural" checks, which check the basic required properties:
characters in names, no duplicate names, no duplicate phandles. That
phase could also handle fixups and indexing that aren't really checks.
A later phase could do the semantic checks (does the interrupts tree
make sense etc.). We could do processing between those two phases if
it makes sense to do so.
> This fixup_phandle_references() call should be removed from process_check()
> and called right after the input parsing.
>
> I you are ok with that, I can propose something in the next iteration.
>
> Best regards,
> Hervé
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 08/77] dtc: Introduce update_phandles_ref()
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (6 preceding siblings ...)
2026-01-12 14:18 ` [RFC PATCH 07/77] livetree: Improve get_node_by_phandle() Herve Codina
@ 2026-01-12 14:18 ` Herve Codina
2026-01-15 0:46 ` David Gibson
2026-01-12 14:18 ` [RFC PATCH 09/77] dtc: Introduce mark_local_phandles() Herve Codina
` (71 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:18 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
With the introduction of FDT_REF_LOCAL dtb tag, a local phandle used
by a property is identify when a dtb is parsed.
In order to have consistent internal data, the reference related to this
phandle usage needs to be updated based on the phandle value.
This is done by update_phandles_ref().
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
dtc.c | 2 ++
dtc.h | 2 ++
livetree.c | 38 ++++++++++++++++++++++++++++++++++++++
3 files changed, 42 insertions(+)
diff --git a/dtc.c b/dtc.c
index b3445b7..88f03ff 100644
--- a/dtc.c
+++ b/dtc.c
@@ -333,6 +333,8 @@ int main(int argc, char *argv[])
generate_fixups = 1;
}
+ update_phandles_ref(dti);
+
process_checks(force, dti);
if (auto_label_aliases)
diff --git a/dtc.h b/dtc.h
index 965321c..351fe41 100644
--- a/dtc.h
+++ b/dtc.h
@@ -345,6 +345,8 @@ void generate_label_tree(struct dt_info *dti, const char *name, bool allocph);
void generate_fixups_tree(struct dt_info *dti, const char *name);
void generate_local_fixups_tree(struct dt_info *dti, const char *name);
+void update_phandles_ref(struct dt_info *dti);
+
/* Checks */
void parse_checks_option(bool warn, bool error, const char *arg);
diff --git a/livetree.c b/livetree.c
index 9b67934..9e30a63 100644
--- a/livetree.c
+++ b/livetree.c
@@ -1158,3 +1158,41 @@ void generate_local_fixups_tree(struct dt_info *dti, const char *name)
"Warning: Preexisting data in %s malformed, some content could not be added.\n",
name);
}
+
+static void update_phandles_ref_internal(struct dt_info *dti, struct node *node)
+{
+ struct node *c;
+ struct property *prop;
+ struct marker *m;
+ struct node *refnode;
+ cell_t phandle;
+
+ for_each_property(node, prop) {
+ m = prop->val.markers;
+ for_each_marker_of_type(m, REF_PHANDLE) {
+ if (m->ref)
+ continue;
+
+ if (m->is_local) {
+ phandle = propval_cell_n(prop,
+ m->offset / sizeof(cell_t));
+ refnode = get_node_by_phandle(dti->dt, phandle);
+ if (!refnode)
+ die("Node not found for phandle 0x%"PRIx32"\n", phandle);
+
+ m->ref = refnode->fullpath;
+ continue;
+ } else {
+ die("Found a non local phandle without a reference\n");
+ }
+ }
+ }
+
+ for_each_child(node, c)
+ update_phandles_ref_internal(dti, c);
+}
+
+void update_phandles_ref(struct dt_info *dti)
+{
+ update_phandles_ref_internal(dti, dti->dt);
+}
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 08/77] dtc: Introduce update_phandles_ref()
2026-01-12 14:18 ` [RFC PATCH 08/77] dtc: Introduce update_phandles_ref() Herve Codina
@ 2026-01-15 0:46 ` David Gibson
2026-01-16 11:26 ` Herve Codina
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-15 0:46 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 3511 bytes --]
On Mon, Jan 12, 2026 at 03:18:58PM +0100, Herve Codina wrote:
> With the introduction of FDT_REF_LOCAL dtb tag, a local phandle used
> by a property is identify when a dtb is parsed.
>
> In order to have consistent internal data, the reference related to this
> phandle usage needs to be updated based on the phandle value.
>
> This is done by update_phandles_ref().
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> dtc.c | 2 ++
> dtc.h | 2 ++
> livetree.c | 38 ++++++++++++++++++++++++++++++++++++++
> 3 files changed, 42 insertions(+)
>
> diff --git a/dtc.c b/dtc.c
> index b3445b7..88f03ff 100644
> --- a/dtc.c
> +++ b/dtc.c
> @@ -333,6 +333,8 @@ int main(int argc, char *argv[])
> generate_fixups = 1;
> }
>
> + update_phandles_ref(dti);
> +
> process_checks(force, dti);
>
> if (auto_label_aliases)
> diff --git a/dtc.h b/dtc.h
> index 965321c..351fe41 100644
> --- a/dtc.h
> +++ b/dtc.h
> @@ -345,6 +345,8 @@ void generate_label_tree(struct dt_info *dti, const char *name, bool allocph);
> void generate_fixups_tree(struct dt_info *dti, const char *name);
> void generate_local_fixups_tree(struct dt_info *dti, const char *name);
>
> +void update_phandles_ref(struct dt_info *dti);
> +
> /* Checks */
>
> void parse_checks_option(bool warn, bool error, const char *arg);
> diff --git a/livetree.c b/livetree.c
> index 9b67934..9e30a63 100644
> --- a/livetree.c
> +++ b/livetree.c
> @@ -1158,3 +1158,41 @@ void generate_local_fixups_tree(struct dt_info *dti, const char *name)
> "Warning: Preexisting data in %s malformed, some content could not be added.\n",
> name);
> }
> +
> +static void update_phandles_ref_internal(struct dt_info *dti, struct node *node)
> +{
> + struct node *c;
> + struct property *prop;
> + struct marker *m;
> + struct node *refnode;
> + cell_t phandle;
> +
> + for_each_property(node, prop) {
> + m = prop->val.markers;
> + for_each_marker_of_type(m, REF_PHANDLE) {
> + if (m->ref)
> + continue;
IIUC this means that REF_PHANDLE markers can be missing their ref.
Allowing the markers to be in an incomplete state is a footgun. If
possible it would be better to fully generate the markers when we
create them. If not, we should use a different marker type when it's
introduced, and convert it later.
I think what's going on here is one type is saying "you have a
reference, fill in the phandle", the other is saying "you have a
phandle, fill in the reference". Those seem like they should be
different types to me, even if they can be converted once all the
fixups are applied.
> +
> + if (m->is_local) {
> + phandle = propval_cell_n(prop,
> + m->offset / sizeof(cell_t));
> + refnode = get_node_by_phandle(dti->dt, phandle);
> + if (!refnode)
> + die("Node not found for phandle 0x%"PRIx32"\n", phandle);
> +
> + m->ref = refnode->fullpath;
> + continue;
> + } else {
> + die("Found a non local phandle without a reference\n");
> + }
> + }
> + }
> +
> + for_each_child(node, c)
> + update_phandles_ref_internal(dti, c);
> +}
> +
> +void update_phandles_ref(struct dt_info *dti)
> +{
> + update_phandles_ref_internal(dti, dti->dt);
> +}
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 08/77] dtc: Introduce update_phandles_ref()
2026-01-15 0:46 ` David Gibson
@ 2026-01-16 11:26 ` Herve Codina
2026-01-19 5:21 ` David Gibson
0 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-16 11:26 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
On Thu, 15 Jan 2026 11:46:52 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Mon, Jan 12, 2026 at 03:18:58PM +0100, Herve Codina wrote:
> > With the introduction of FDT_REF_LOCAL dtb tag, a local phandle used
> > by a property is identify when a dtb is parsed.
> >
> > In order to have consistent internal data, the reference related to this
> > phandle usage needs to be updated based on the phandle value.
> >
> > This is done by update_phandles_ref().
> >
> > Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> > ---
> > dtc.c | 2 ++
> > dtc.h | 2 ++
> > livetree.c | 38 ++++++++++++++++++++++++++++++++++++++
> > 3 files changed, 42 insertions(+)
> >
> > diff --git a/dtc.c b/dtc.c
> > index b3445b7..88f03ff 100644
> > --- a/dtc.c
> > +++ b/dtc.c
> > @@ -333,6 +333,8 @@ int main(int argc, char *argv[])
> > generate_fixups = 1;
> > }
> >
> > + update_phandles_ref(dti);
> > +
> > process_checks(force, dti);
> >
> > if (auto_label_aliases)
> > diff --git a/dtc.h b/dtc.h
> > index 965321c..351fe41 100644
> > --- a/dtc.h
> > +++ b/dtc.h
> > @@ -345,6 +345,8 @@ void generate_label_tree(struct dt_info *dti, const char *name, bool allocph);
> > void generate_fixups_tree(struct dt_info *dti, const char *name);
> > void generate_local_fixups_tree(struct dt_info *dti, const char *name);
> >
> > +void update_phandles_ref(struct dt_info *dti);
> > +
> > /* Checks */
> >
> > void parse_checks_option(bool warn, bool error, const char *arg);
> > diff --git a/livetree.c b/livetree.c
> > index 9b67934..9e30a63 100644
> > --- a/livetree.c
> > +++ b/livetree.c
> > @@ -1158,3 +1158,41 @@ void generate_local_fixups_tree(struct dt_info *dti, const char *name)
> > "Warning: Preexisting data in %s malformed, some content could not be added.\n",
> > name);
> > }
> > +
> > +static void update_phandles_ref_internal(struct dt_info *dti, struct node *node)
> > +{
> > + struct node *c;
> > + struct property *prop;
> > + struct marker *m;
> > + struct node *refnode;
> > + cell_t phandle;
> > +
> > + for_each_property(node, prop) {
> > + m = prop->val.markers;
> > + for_each_marker_of_type(m, REF_PHANDLE) {
> > + if (m->ref)
> > + continue;
>
> IIUC this means that REF_PHANDLE markers can be missing their ref.
Yes, no ref are present in dtb for phandle pointing to local node, only
the phandle value is present. We need at some point to set the ref from
this phandle value.
> Allowing the markers to be in an incomplete state is a footgun. If
> possible it would be better to fully generate the markers when we
> create them. If not, we should use a different marker type when it's
> introduced, and convert it later.
>
> I think what's going on here is one type is saying "you have a
> reference, fill in the phandle", the other is saying "you have a
> phandle, fill in the reference". Those seem like they should be
> different types to me, even if they can be converted once all the
> fixups are applied.
Right, I can introduce
- REF_PHANDLE_FILL_PHANDLE: "you have a phandle, fill in the reference"
- REF_PHANDLE_FILL_REF: "you have a reference, fill the phandle"
Well, fill the phandle or not... Indeed, this reference can be external and
so this can be an unresolved symbol.
But anyway those new marker types will exist only between the parsing step and
the step where we convert them to REF_PHANDLE markers.
Will see what I can propose in the next series iteration.
Best regards,
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 08/77] dtc: Introduce update_phandles_ref()
2026-01-16 11:26 ` Herve Codina
@ 2026-01-19 5:21 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-19 5:21 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 4329 bytes --]
On Fri, Jan 16, 2026 at 12:26:30PM +0100, Herve Codina wrote:
> On Thu, 15 Jan 2026 11:46:52 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > On Mon, Jan 12, 2026 at 03:18:58PM +0100, Herve Codina wrote:
> > > With the introduction of FDT_REF_LOCAL dtb tag, a local phandle used
> > > by a property is identify when a dtb is parsed.
> > >
> > > In order to have consistent internal data, the reference related to this
> > > phandle usage needs to be updated based on the phandle value.
> > >
> > > This is done by update_phandles_ref().
> > >
> > > Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> > > ---
> > > dtc.c | 2 ++
> > > dtc.h | 2 ++
> > > livetree.c | 38 ++++++++++++++++++++++++++++++++++++++
> > > 3 files changed, 42 insertions(+)
> > >
> > > diff --git a/dtc.c b/dtc.c
> > > index b3445b7..88f03ff 100644
> > > --- a/dtc.c
> > > +++ b/dtc.c
> > > @@ -333,6 +333,8 @@ int main(int argc, char *argv[])
> > > generate_fixups = 1;
> > > }
> > >
> > > + update_phandles_ref(dti);
> > > +
> > > process_checks(force, dti);
> > >
> > > if (auto_label_aliases)
> > > diff --git a/dtc.h b/dtc.h
> > > index 965321c..351fe41 100644
> > > --- a/dtc.h
> > > +++ b/dtc.h
> > > @@ -345,6 +345,8 @@ void generate_label_tree(struct dt_info *dti, const char *name, bool allocph);
> > > void generate_fixups_tree(struct dt_info *dti, const char *name);
> > > void generate_local_fixups_tree(struct dt_info *dti, const char *name);
> > >
> > > +void update_phandles_ref(struct dt_info *dti);
> > > +
> > > /* Checks */
> > >
> > > void parse_checks_option(bool warn, bool error, const char *arg);
> > > diff --git a/livetree.c b/livetree.c
> > > index 9b67934..9e30a63 100644
> > > --- a/livetree.c
> > > +++ b/livetree.c
> > > @@ -1158,3 +1158,41 @@ void generate_local_fixups_tree(struct dt_info *dti, const char *name)
> > > "Warning: Preexisting data in %s malformed, some content could not be added.\n",
> > > name);
> > > }
> > > +
> > > +static void update_phandles_ref_internal(struct dt_info *dti, struct node *node)
> > > +{
> > > + struct node *c;
> > > + struct property *prop;
> > > + struct marker *m;
> > > + struct node *refnode;
> > > + cell_t phandle;
> > > +
> > > + for_each_property(node, prop) {
> > > + m = prop->val.markers;
> > > + for_each_marker_of_type(m, REF_PHANDLE) {
> > > + if (m->ref)
> > > + continue;
> >
> > IIUC this means that REF_PHANDLE markers can be missing their ref.
>
> Yes, no ref are present in dtb for phandle pointing to local node, only
> the phandle value is present. We need at some point to set the ref from
> this phandle value.
>
> > Allowing the markers to be in an incomplete state is a footgun. If
> > possible it would be better to fully generate the markers when we
> > create them. If not, we should use a different marker type when it's
> > introduced, and convert it later.
> >
> > I think what's going on here is one type is saying "you have a
> > reference, fill in the phandle", the other is saying "you have a
> > phandle, fill in the reference". Those seem like they should be
> > different types to me, even if they can be converted once all the
> > fixups are applied.
>
> Right, I can introduce
> - REF_PHANDLE_FILL_PHANDLE: "you have a phandle, fill in the reference"
>
> - REF_PHANDLE_FILL_REF: "you have a reference, fill the phandle"
> Well, fill the phandle or not... Indeed, this reference can be external and
> so this can be an unresolved symbol.
>
> But anyway those new marker types will exist only between the parsing step and
> the step where we convert them to REF_PHANDLE markers.
So REF_PHANDLE always has a complete reference, and a
complete-as-possible phandle value (-1 if it's an external reference)?
I think that makes sense - I don't love the proposed names for the
earlier markers, but better ones aren't immediately occurring to me.
>
> Will see what I can propose in the next series iteration.
>
> Best regards,
> Hervé
>
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 09/77] dtc: Introduce mark_local_phandles()
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (7 preceding siblings ...)
2026-01-12 14:18 ` [RFC PATCH 08/77] dtc: Introduce update_phandles_ref() Herve Codina
@ 2026-01-12 14:18 ` Herve Codina
2026-01-15 0:48 ` David Gibson
2026-01-12 14:19 ` [RFC PATCH 10/77] tests: Add basic metadata tests Herve Codina
` (70 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:18 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
In order to have the new FDT_REF_LOCAL tag present in a dtb, the phandle
reference needs to be identify as a local reference.
This is the purpose of mark_local_phandles().
It identifies a phandle reference as a local reference when this
reference points to a local node.
With that node, the related FDT_REF_LOCAL tag is set in the dtb.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
dtc.c | 1 +
dtc.h | 1 +
livetree.c | 26 ++++++++++++++++++++++++++
3 files changed, 28 insertions(+)
diff --git a/dtc.c b/dtc.c
index 88f03ff..d0b4de3 100644
--- a/dtc.c
+++ b/dtc.c
@@ -334,6 +334,7 @@ int main(int argc, char *argv[])
}
update_phandles_ref(dti);
+ mark_local_phandles(dti);
process_checks(force, dti);
diff --git a/dtc.h b/dtc.h
index 351fe41..08c9f07 100644
--- a/dtc.h
+++ b/dtc.h
@@ -346,6 +346,7 @@ void generate_fixups_tree(struct dt_info *dti, const char *name);
void generate_local_fixups_tree(struct dt_info *dti, const char *name);
void update_phandles_ref(struct dt_info *dti);
+void mark_local_phandles(struct dt_info *dti);
/* Checks */
diff --git a/livetree.c b/livetree.c
index 9e30a63..2a0a7ed 100644
--- a/livetree.c
+++ b/livetree.c
@@ -1196,3 +1196,29 @@ void update_phandles_ref(struct dt_info *dti)
{
update_phandles_ref_internal(dti, dti->dt);
}
+
+static void mark_local_phandles_internal(struct dt_info *dti,
+ struct node *node)
+{
+ struct node *c;
+ struct property *prop;
+ struct marker *m;
+ struct node *refnode;
+
+ for_each_property(node, prop) {
+ m = prop->val.markers;
+ for_each_marker_of_type(m, REF_PHANDLE) {
+ refnode = get_node_by_ref(dti->dt, m->ref);
+ if (refnode)
+ m->is_local = true;
+ }
+ }
+
+ for_each_child(node, c)
+ mark_local_phandles_internal(dti, c);
+}
+
+void mark_local_phandles(struct dt_info *dti)
+{
+ mark_local_phandles_internal(dti, dti->dt);
+}
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 09/77] dtc: Introduce mark_local_phandles()
2026-01-12 14:18 ` [RFC PATCH 09/77] dtc: Introduce mark_local_phandles() Herve Codina
@ 2026-01-15 0:48 ` David Gibson
2026-01-16 13:09 ` Herve Codina
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-15 0:48 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 2647 bytes --]
On Mon, Jan 12, 2026 at 03:18:59PM +0100, Herve Codina wrote:
> In order to have the new FDT_REF_LOCAL tag present in a dtb, the phandle
> reference needs to be identify as a local reference.
>
> This is the purpose of mark_local_phandles().
>
> It identifies a phandle reference as a local reference when this
> reference points to a local node.
>
> With that node, the related FDT_REF_LOCAL tag is set in the dtb.
I dislike caching redundant information (whether the ref is local) -
it's an opportunity for them to get out of sync and cause bugs. Is
there a strong case that you can't just determine whether it's local
only when you actually go to use it?
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> dtc.c | 1 +
> dtc.h | 1 +
> livetree.c | 26 ++++++++++++++++++++++++++
> 3 files changed, 28 insertions(+)
>
> diff --git a/dtc.c b/dtc.c
> index 88f03ff..d0b4de3 100644
> --- a/dtc.c
> +++ b/dtc.c
> @@ -334,6 +334,7 @@ int main(int argc, char *argv[])
> }
>
> update_phandles_ref(dti);
> + mark_local_phandles(dti);
>
> process_checks(force, dti);
>
> diff --git a/dtc.h b/dtc.h
> index 351fe41..08c9f07 100644
> --- a/dtc.h
> +++ b/dtc.h
> @@ -346,6 +346,7 @@ void generate_fixups_tree(struct dt_info *dti, const char *name);
> void generate_local_fixups_tree(struct dt_info *dti, const char *name);
>
> void update_phandles_ref(struct dt_info *dti);
> +void mark_local_phandles(struct dt_info *dti);
>
> /* Checks */
>
> diff --git a/livetree.c b/livetree.c
> index 9e30a63..2a0a7ed 100644
> --- a/livetree.c
> +++ b/livetree.c
> @@ -1196,3 +1196,29 @@ void update_phandles_ref(struct dt_info *dti)
> {
> update_phandles_ref_internal(dti, dti->dt);
> }
> +
> +static void mark_local_phandles_internal(struct dt_info *dti,
> + struct node *node)
> +{
> + struct node *c;
> + struct property *prop;
> + struct marker *m;
> + struct node *refnode;
> +
> + for_each_property(node, prop) {
> + m = prop->val.markers;
> + for_each_marker_of_type(m, REF_PHANDLE) {
> + refnode = get_node_by_ref(dti->dt, m->ref);
> + if (refnode)
> + m->is_local = true;
> + }
> + }
> +
> + for_each_child(node, c)
> + mark_local_phandles_internal(dti, c);
> +}
> +
> +void mark_local_phandles(struct dt_info *dti)
> +{
> + mark_local_phandles_internal(dti, dti->dt);
> +}
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 09/77] dtc: Introduce mark_local_phandles()
2026-01-15 0:48 ` David Gibson
@ 2026-01-16 13:09 ` Herve Codina
2026-01-19 5:46 ` David Gibson
0 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-16 13:09 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
Hi David,
On Thu, 15 Jan 2026 11:48:44 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Mon, Jan 12, 2026 at 03:18:59PM +0100, Herve Codina wrote:
> > In order to have the new FDT_REF_LOCAL tag present in a dtb, the phandle
> > reference needs to be identify as a local reference.
> >
> > This is the purpose of mark_local_phandles().
> >
> > It identifies a phandle reference as a local reference when this
> > reference points to a local node.
> >
> > With that node, the related FDT_REF_LOCAL tag is set in the dtb.
>
> I dislike caching redundant information (whether the ref is local) -
> it's an opportunity for them to get out of sync and cause bugs. Is
> there a strong case that you can't just determine whether it's local
> only when you actually go to use it?
Well, I can't find any strong case.
I would like to avoid passing the full dti (struct dt_info) to flatten_tree()
in order to determine if the ref is local or not to set a FDT_REF_LOCAL or
a FDT_REF_PHANDLE tag.
Also, this flag, set when a FDT_REF_LOCAL tag is parsed from a dtb, is
useful later when the ref has to be found based on the phandle value.
Indeed, because the is_local flag is set, the phandle value available in the
property *must* reference an existing node in the dtb.
In other word, in update_phandles_ref_internal(),
--- 8< ---
if (m->is_local) {
phandle = propval_cell_n(prop,
m->offset / sizeof(cell_t));
refnode = dti_get_node_by_phandle(dti, phandle);
if (!refnode)
die("Node not found for phandle 0x%"PRIx32"\n", phandle);
m->ref = refnode->fullpath;
continue;
} else {
...
--- 8< ---
Best regards,
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 09/77] dtc: Introduce mark_local_phandles()
2026-01-16 13:09 ` Herve Codina
@ 2026-01-19 5:46 ` David Gibson
2026-01-19 12:14 ` Herve Codina
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-19 5:46 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 2412 bytes --]
On Fri, Jan 16, 2026 at 02:09:12PM +0100, Herve Codina wrote:
> Hi David,
>
> On Thu, 15 Jan 2026 11:48:44 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > On Mon, Jan 12, 2026 at 03:18:59PM +0100, Herve Codina wrote:
> > > In order to have the new FDT_REF_LOCAL tag present in a dtb, the phandle
> > > reference needs to be identify as a local reference.
> > >
> > > This is the purpose of mark_local_phandles().
> > >
> > > It identifies a phandle reference as a local reference when this
> > > reference points to a local node.
> > >
> > > With that node, the related FDT_REF_LOCAL tag is set in the dtb.
> >
> > I dislike caching redundant information (whether the ref is local) -
> > it's an opportunity for them to get out of sync and cause bugs. Is
> > there a strong case that you can't just determine whether it's local
> > only when you actually go to use it?
>
> Well, I can't find any strong case.
>
> I would like to avoid passing the full dti (struct dt_info) to flatten_tree()
> in order to determine if the ref is local or not to set a FDT_REF_LOCAL or
> a FDT_REF_PHANDLE tag.
>
> Also, this flag, set when a FDT_REF_LOCAL tag is parsed from a dtb, is
> useful later when the ref has to be found based on the phandle value.
>
> Indeed, because the is_local flag is set, the phandle value available in the
> property *must* reference an existing node in the dtb.
>
> In other word, in update_phandles_ref_internal(),
Hmm, I see. As with the "known phandle, unknown ref" vs. "known ref,
unknown phandle" cases, I think this might be clearer with different
marker types. During parse we make everything "known ref, unknown
phandle", then later change to either "known ref, resolved to local
phandle" or "known ref, needs external resolution" markers.
> --- 8< ---
> if (m->is_local) {
> phandle = propval_cell_n(prop,
> m->offset / sizeof(cell_t));
> refnode = dti_get_node_by_phandle(dti, phandle);
> if (!refnode)
> die("Node not found for phandle 0x%"PRIx32"\n", phandle);
>
> m->ref = refnode->fullpath;
> continue;
> } else {
> ...
> --- 8< ---
>
> Best regards,
> Hervé
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 09/77] dtc: Introduce mark_local_phandles()
2026-01-19 5:46 ` David Gibson
@ 2026-01-19 12:14 ` Herve Codina
0 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-19 12:14 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
On Mon, 19 Jan 2026 16:46:37 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Fri, Jan 16, 2026 at 02:09:12PM +0100, Herve Codina wrote:
> > Hi David,
> >
> > On Thu, 15 Jan 2026 11:48:44 +1100
> > David Gibson <david@gibson.dropbear.id.au> wrote:
> >
> > > On Mon, Jan 12, 2026 at 03:18:59PM +0100, Herve Codina wrote:
> > > > In order to have the new FDT_REF_LOCAL tag present in a dtb, the phandle
> > > > reference needs to be identify as a local reference.
> > > >
> > > > This is the purpose of mark_local_phandles().
> > > >
> > > > It identifies a phandle reference as a local reference when this
> > > > reference points to a local node.
> > > >
> > > > With that node, the related FDT_REF_LOCAL tag is set in the dtb.
> > >
> > > I dislike caching redundant information (whether the ref is local) -
> > > it's an opportunity for them to get out of sync and cause bugs. Is
> > > there a strong case that you can't just determine whether it's local
> > > only when you actually go to use it?
> >
> > Well, I can't find any strong case.
> >
> > I would like to avoid passing the full dti (struct dt_info) to flatten_tree()
> > in order to determine if the ref is local or not to set a FDT_REF_LOCAL or
> > a FDT_REF_PHANDLE tag.
> >
> > Also, this flag, set when a FDT_REF_LOCAL tag is parsed from a dtb, is
> > useful later when the ref has to be found based on the phandle value.
> >
> > Indeed, because the is_local flag is set, the phandle value available in the
> > property *must* reference an existing node in the dtb.
> >
> > In other word, in update_phandles_ref_internal(),
>
> Hmm, I see. As with the "known phandle, unknown ref" vs. "known ref,
> unknown phandle" cases, I think this might be clearer with different
> marker types. During parse we make everything "known ref, unknown
> phandle", then later change to either "known ref, resolved to local
> phandle" or "known ref, needs external resolution" markers.
When we parse a dtb, we have "Unknown ref, known phandle". FDT_REF_LOCAL
identify a local phandle value without any 'ref' involved.
The ref is set after parsing and it is set to the full path of the node
matching the phandle value.
Will see what I can do with new markers to identify those different cases.
>
>
>
> > --- 8< ---
> > if (m->is_local) {
> > phandle = propval_cell_n(prop,
> > m->offset / sizeof(cell_t));
> > refnode = dti_get_node_by_phandle(dti, phandle);
> > if (!refnode)
> > die("Node not found for phandle 0x%"PRIx32"\n", phandle);
> >
> > m->ref = refnode->fullpath;
> > continue;
> > } else {
> > ...
> > --- 8< ---
> >
> > Best regards,
> > Hervé
> >
>
Best regards,
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 10/77] tests: Add basic metadata tests
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (8 preceding siblings ...)
2026-01-12 14:18 ` [RFC PATCH 09/77] dtc: Introduce mark_local_phandles() Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-15 0:50 ` David Gibson
2026-01-12 14:19 ` [RFC PATCH 11/77] Add support for FDT_REF_PHANDLE dtb tag Herve Codina
` (69 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
This first test is related to local phandle references (FDT_REF_LOCAL
dtb tag).
The test pattern used is
- Generate a dts (xxx.dts.dts) from an input dts
- Check this generated dts against expected contents
- Generate a dtb (xxx.dtb) from the same input dts
- Check this generated dtb against expected contents
- Generate a dts (xxx.dtb.dts) from the generated dtb
- Check this generated dts against expected contents
- Generate a dtb (xxx.dtb.dts.dtb) from the generated dts
- Check this generated dtb, expect the same contents as for xxx.dtb
Even if only one meta-data feature is currently tested in this tests
introduction, use a loop in order to ease future addition consisting in
adding new input dts as soon as new meta-data feature are supported.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
tests/meson.build | 3 +-
tests/metadata_reflocal.dtb.dts.expect | 23 ++++++++++
tests/metadata_reflocal.dtb.expect | 20 +++++++++
tests/metadata_reflocal.dts | 27 ++++++++++++
tests/metadata_reflocal.dts.dts.expect | 23 ++++++++++
tests/run_tests.sh | 58 +++++++++++++++++++++++++-
6 files changed, 152 insertions(+), 2 deletions(-)
create mode 100644 tests/metadata_reflocal.dtb.dts.expect
create mode 100644 tests/metadata_reflocal.dtb.expect
create mode 100644 tests/metadata_reflocal.dts
create mode 100644 tests/metadata_reflocal.dts.dts.expect
diff --git a/tests/meson.build b/tests/meson.build
index 37bfd47..e81a2e1 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -140,7 +140,8 @@ run_test_types = [
'fdtget',
'fdtput',
'fdtdump',
- 'fdtoverlay'
+ 'fdtoverlay',
+ 'metadata'
]
run_test_deps = [
dtc_tools, dumptrees_dtb, tests_exe
diff --git a/tests/metadata_reflocal.dtb.dts.expect b/tests/metadata_reflocal.dtb.dts.expect
new file mode 100644
index 0000000..076c17a
--- /dev/null
+++ b/tests/metadata_reflocal.dtb.dts.expect
@@ -0,0 +1,23 @@
+/dts-v1/;
+
+/ {
+
+ node-a {
+
+ subnode-a {
+ phandle = <0x01>;
+ };
+ };
+
+ node-b {
+ phandle = <0x02>;
+ };
+
+ node-c {
+ };
+
+ node-d {
+ ref-subnode-a = <&{/node-a/subnode-a}>;
+ ref-node-b = <0x123 0x456 &{/node-b} 0x789>;
+ };
+};
diff --git a/tests/metadata_reflocal.dtb.expect b/tests/metadata_reflocal.dtb.expect
new file mode 100644
index 0000000..33b3896
--- /dev/null
+++ b/tests/metadata_reflocal.dtb.expect
@@ -0,0 +1,20 @@
+/dts-v1/;
+
+/ {
+ node-a {
+ subnode-a {
+ phandle = <0x00000001>;
+ };
+ };
+ node-b {
+ phandle = <0x00000002>;
+ };
+ node-c {
+ };
+ node-d {
+ ref-subnode-a = <0x00000001>;
+ // [FDT_REF_LOCAL] ref-subnode-a[0]
+ ref-node-b = <0x00000123 0x00000456 0x00000002 0x00000789>;
+ // [FDT_REF_LOCAL] ref-node-b[8]
+ };
+};
diff --git a/tests/metadata_reflocal.dts b/tests/metadata_reflocal.dts
new file mode 100644
index 0000000..f04d24f
--- /dev/null
+++ b/tests/metadata_reflocal.dts
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+
+/ {
+ node-a {
+ subnode_a: subnode-a {
+ };
+ };
+
+ node_b: node-b {
+ };
+
+ node-c {
+ };
+
+ node_d: node-d {
+ ref-subnode-a = <&subnode_a>;
+ };
+};
+
+&node_d {
+ ref-node-b = <0x123 0x456 &node_b 0x789>;
+};
diff --git a/tests/metadata_reflocal.dts.dts.expect b/tests/metadata_reflocal.dts.dts.expect
new file mode 100644
index 0000000..b72b545
--- /dev/null
+++ b/tests/metadata_reflocal.dts.dts.expect
@@ -0,0 +1,23 @@
+/dts-v1/;
+
+/ {
+
+ node-a {
+
+ subnode_a: subnode-a {
+ phandle = <0x01>;
+ };
+ };
+
+ node_b: node-b {
+ phandle = <0x02>;
+ };
+
+ node-c {
+ };
+
+ node_d: node-d {
+ ref-subnode-a = <&subnode_a>;
+ ref-node-b = <0x123 0x456 &node_b 0x789>;
+ };
+};
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index f07092b..7a8bdbc 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1090,6 +1090,59 @@ fdtoverlay_tests() {
run_wrap_test test "$bd" = "$pd"
}
+# $1: f1 file
+# $2: f2 file
+check_diff () {
+ printf "diff $1 $2: "
+ local f1="$1"
+ local f2="$2"
+ (
+ if diff $f1 $f2 >/dev/null; then
+ PASS
+ else
+ if [ -z "$QUIET_TEST" ]; then
+ echo "DIFF :-:"
+ diff -u $f1 $f2
+ fi
+ FAIL "Results differ from expected"
+ fi
+ )
+}
+
+# $1: dtb file
+# $2: out file
+wrap_fdtdump () {
+ printf "wrap_fdtdump $1: "
+ local dtb="$1"
+ local out="$2"
+ (
+ if $FDTDUMP ${dtb} 2>/dev/null >${out}; then
+ PASS
+ else
+ FAIL
+ fi
+ )
+}
+
+metadata_tests() {
+ for dt in metadata_reflocal; do
+ run_dtc_test -I dts -O dts -o $dt.dts.dts "$SRCDIR/$dt.dts"
+ base_run_test check_diff $dt.dts.dts "$SRCDIR/$dt.dts.dts.expect"
+ run_dtc_test -I dts -O dtb -o $dt.dtb "$SRCDIR/$dt.dts"
+ base_run_test wrap_fdtdump $dt.dtb $dt.dtb.out
+ # Remove unneeded comments
+ sed -i '/^\/\/ /d' $dt.dtb.out
+ base_run_test check_diff $dt.dtb.out "$SRCDIR/$dt.dtb.expect"
+ run_dtc_test -I dtb -O dts -o $dt.dtb.dts $dt.dtb
+ base_run_test check_diff $dt.dtb.dts "$SRCDIR/$dt.dtb.dts.expect"
+ run_dtc_test -I dts -O dtb -o $dt.dtb.dts.dtb $dt.dtb.dts
+ base_run_test wrap_fdtdump $dt.dtb.dts.dtb $dt.dtb.dts.dtb.out
+ # Remove unneeded comments
+ sed -i '/^\/\/ /d' $dt.dtb.dts.dtb.out
+ base_run_test check_diff $dt.dtb.dts.dtb.out "$SRCDIR/$dt.dtb.expect"
+ done
+}
+
pylibfdt_tests () {
run_dtc_test -I dts -O dtb -o test_props.dtb "$SRCDIR/test_props.dts"
TMP=/tmp/tests.stderr.$$
@@ -1129,7 +1182,7 @@ while getopts "vt:me" ARG ; do
done
if [ -z "$TESTSETS" ]; then
- TESTSETS="libfdt utilfdt dtc dtbs_equal fdtget fdtput fdtdump fdtoverlay"
+ TESTSETS="libfdt utilfdt dtc dtbs_equal fdtget fdtput fdtdump fdtoverlay metadata"
# Test pylibfdt if the libfdt Python module is available.
if ! $no_python; then
@@ -1169,6 +1222,9 @@ for set in $TESTSETS; do
"fdtoverlay")
fdtoverlay_tests
;;
+ "metadata")
+ metadata_tests
+ ;;
esac
done
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 10/77] tests: Add basic metadata tests
2026-01-12 14:19 ` [RFC PATCH 10/77] tests: Add basic metadata tests Herve Codina
@ 2026-01-15 0:50 ` David Gibson
2026-01-16 13:36 ` Herve Codina
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-15 0:50 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 7494 bytes --]
On Mon, Jan 12, 2026 at 03:19:00PM +0100, Herve Codina wrote:
> This first test is related to local phandle references (FDT_REF_LOCAL
> dtb tag).
>
> The test pattern used is
> - Generate a dts (xxx.dts.dts) from an input dts
> - Check this generated dts against expected contents
> - Generate a dtb (xxx.dtb) from the same input dts
> - Check this generated dtb against expected contents
> - Generate a dts (xxx.dtb.dts) from the generated dtb
> - Check this generated dts against expected contents
> - Generate a dtb (xxx.dtb.dts.dtb) from the generated dts
> - Check this generated dtb, expect the same contents as for xxx.dtb
>
> Even if only one meta-data feature is currently tested in this tests
> introduction, use a loop in order to ease future addition consisting in
> adding new input dts as soon as new meta-data feature are supported.
As a rule of tumb, I prefer tests to be introduced in the same patch
that introduces the feature tested. Usually, I don't care that much,
but in a giant series like this, it would really help review (the
tests help to document the feature being added without switching
between patches).
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> tests/meson.build | 3 +-
> tests/metadata_reflocal.dtb.dts.expect | 23 ++++++++++
> tests/metadata_reflocal.dtb.expect | 20 +++++++++
> tests/metadata_reflocal.dts | 27 ++++++++++++
> tests/metadata_reflocal.dts.dts.expect | 23 ++++++++++
> tests/run_tests.sh | 58 +++++++++++++++++++++++++-
> 6 files changed, 152 insertions(+), 2 deletions(-)
> create mode 100644 tests/metadata_reflocal.dtb.dts.expect
> create mode 100644 tests/metadata_reflocal.dtb.expect
> create mode 100644 tests/metadata_reflocal.dts
> create mode 100644 tests/metadata_reflocal.dts.dts.expect
>
> diff --git a/tests/meson.build b/tests/meson.build
> index 37bfd47..e81a2e1 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -140,7 +140,8 @@ run_test_types = [
> 'fdtget',
> 'fdtput',
> 'fdtdump',
> - 'fdtoverlay'
> + 'fdtoverlay',
> + 'metadata'
> ]
> run_test_deps = [
> dtc_tools, dumptrees_dtb, tests_exe
> diff --git a/tests/metadata_reflocal.dtb.dts.expect b/tests/metadata_reflocal.dtb.dts.expect
> new file mode 100644
> index 0000000..076c17a
> --- /dev/null
> +++ b/tests/metadata_reflocal.dtb.dts.expect
> @@ -0,0 +1,23 @@
> +/dts-v1/;
> +
> +/ {
> +
> + node-a {
> +
> + subnode-a {
> + phandle = <0x01>;
> + };
> + };
> +
> + node-b {
> + phandle = <0x02>;
> + };
> +
> + node-c {
> + };
> +
> + node-d {
> + ref-subnode-a = <&{/node-a/subnode-a}>;
> + ref-node-b = <0x123 0x456 &{/node-b} 0x789>;
> + };
> +};
> diff --git a/tests/metadata_reflocal.dtb.expect b/tests/metadata_reflocal.dtb.expect
> new file mode 100644
> index 0000000..33b3896
> --- /dev/null
> +++ b/tests/metadata_reflocal.dtb.expect
> @@ -0,0 +1,20 @@
> +/dts-v1/;
> +
> +/ {
> + node-a {
> + subnode-a {
> + phandle = <0x00000001>;
> + };
> + };
> + node-b {
> + phandle = <0x00000002>;
> + };
> + node-c {
> + };
> + node-d {
> + ref-subnode-a = <0x00000001>;
> + // [FDT_REF_LOCAL] ref-subnode-a[0]
> + ref-node-b = <0x00000123 0x00000456 0x00000002 0x00000789>;
> + // [FDT_REF_LOCAL] ref-node-b[8]
> + };
> +};
> diff --git a/tests/metadata_reflocal.dts b/tests/metadata_reflocal.dts
> new file mode 100644
> index 0000000..f04d24f
> --- /dev/null
> +++ b/tests/metadata_reflocal.dts
> @@ -0,0 +1,27 @@
> +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
> +/*
> + * Copyright (C) 2026 Bootlin
> + */
> +
> +/dts-v1/;
> +
> +/ {
> + node-a {
> + subnode_a: subnode-a {
> + };
> + };
> +
> + node_b: node-b {
> + };
> +
> + node-c {
> + };
> +
> + node_d: node-d {
> + ref-subnode-a = <&subnode_a>;
> + };
> +};
> +
> +&node_d {
> + ref-node-b = <0x123 0x456 &node_b 0x789>;
> +};
> diff --git a/tests/metadata_reflocal.dts.dts.expect b/tests/metadata_reflocal.dts.dts.expect
> new file mode 100644
> index 0000000..b72b545
> --- /dev/null
> +++ b/tests/metadata_reflocal.dts.dts.expect
> @@ -0,0 +1,23 @@
> +/dts-v1/;
> +
> +/ {
> +
> + node-a {
> +
> + subnode_a: subnode-a {
> + phandle = <0x01>;
> + };
> + };
> +
> + node_b: node-b {
> + phandle = <0x02>;
> + };
> +
> + node-c {
> + };
> +
> + node_d: node-d {
> + ref-subnode-a = <&subnode_a>;
> + ref-node-b = <0x123 0x456 &node_b 0x789>;
> + };
> +};
> diff --git a/tests/run_tests.sh b/tests/run_tests.sh
> index f07092b..7a8bdbc 100755
> --- a/tests/run_tests.sh
> +++ b/tests/run_tests.sh
> @@ -1090,6 +1090,59 @@ fdtoverlay_tests() {
> run_wrap_test test "$bd" = "$pd"
> }
>
> +# $1: f1 file
> +# $2: f2 file
> +check_diff () {
> + printf "diff $1 $2: "
> + local f1="$1"
> + local f2="$2"
> + (
> + if diff $f1 $f2 >/dev/null; then
> + PASS
> + else
> + if [ -z "$QUIET_TEST" ]; then
> + echo "DIFF :-:"
> + diff -u $f1 $f2
> + fi
> + FAIL "Results differ from expected"
> + fi
> + )
> +}
> +
> +# $1: dtb file
> +# $2: out file
> +wrap_fdtdump () {
> + printf "wrap_fdtdump $1: "
> + local dtb="$1"
> + local out="$2"
> + (
> + if $FDTDUMP ${dtb} 2>/dev/null >${out}; then
> + PASS
> + else
> + FAIL
> + fi
> + )
> +}
> +
> +metadata_tests() {
> + for dt in metadata_reflocal; do
> + run_dtc_test -I dts -O dts -o $dt.dts.dts "$SRCDIR/$dt.dts"
> + base_run_test check_diff $dt.dts.dts "$SRCDIR/$dt.dts.dts.expect"
> + run_dtc_test -I dts -O dtb -o $dt.dtb "$SRCDIR/$dt.dts"
> + base_run_test wrap_fdtdump $dt.dtb $dt.dtb.out
> + # Remove unneeded comments
> + sed -i '/^\/\/ /d' $dt.dtb.out
> + base_run_test check_diff $dt.dtb.out "$SRCDIR/$dt.dtb.expect"
> + run_dtc_test -I dtb -O dts -o $dt.dtb.dts $dt.dtb
> + base_run_test check_diff $dt.dtb.dts "$SRCDIR/$dt.dtb.dts.expect"
> + run_dtc_test -I dts -O dtb -o $dt.dtb.dts.dtb $dt.dtb.dts
> + base_run_test wrap_fdtdump $dt.dtb.dts.dtb $dt.dtb.dts.dtb.out
> + # Remove unneeded comments
> + sed -i '/^\/\/ /d' $dt.dtb.dts.dtb.out
> + base_run_test check_diff $dt.dtb.dts.dtb.out "$SRCDIR/$dt.dtb.expect"
> + done
> +}
> +
> pylibfdt_tests () {
> run_dtc_test -I dts -O dtb -o test_props.dtb "$SRCDIR/test_props.dts"
> TMP=/tmp/tests.stderr.$$
> @@ -1129,7 +1182,7 @@ while getopts "vt:me" ARG ; do
> done
>
> if [ -z "$TESTSETS" ]; then
> - TESTSETS="libfdt utilfdt dtc dtbs_equal fdtget fdtput fdtdump fdtoverlay"
> + TESTSETS="libfdt utilfdt dtc dtbs_equal fdtget fdtput fdtdump fdtoverlay metadata"
>
> # Test pylibfdt if the libfdt Python module is available.
> if ! $no_python; then
> @@ -1169,6 +1222,9 @@ for set in $TESTSETS; do
> "fdtoverlay")
> fdtoverlay_tests
> ;;
> + "metadata")
> + metadata_tests
> + ;;
> esac
> done
>
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 10/77] tests: Add basic metadata tests
2026-01-15 0:50 ` David Gibson
@ 2026-01-16 13:36 ` Herve Codina
2026-01-19 5:32 ` David Gibson
0 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-16 13:36 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
On Thu, 15 Jan 2026 11:50:56 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Mon, Jan 12, 2026 at 03:19:00PM +0100, Herve Codina wrote:
> > This first test is related to local phandle references (FDT_REF_LOCAL
> > dtb tag).
> >
> > The test pattern used is
> > - Generate a dts (xxx.dts.dts) from an input dts
> > - Check this generated dts against expected contents
> > - Generate a dtb (xxx.dtb) from the same input dts
> > - Check this generated dtb against expected contents
> > - Generate a dts (xxx.dtb.dts) from the generated dtb
> > - Check this generated dts against expected contents
> > - Generate a dtb (xxx.dtb.dts.dtb) from the generated dts
> > - Check this generated dtb, expect the same contents as for xxx.dtb
> >
> > Even if only one meta-data feature is currently tested in this tests
> > introduction, use a loop in order to ease future addition consisting in
> > adding new input dts as soon as new meta-data feature are supported.
>
> As a rule of tumb, I prefer tests to be introduced in the same patch
> that introduces the feature tested. Usually, I don't care that much,
> but in a giant series like this, it would really help review (the
> tests help to document the feature being added without switching
> between patches).
Hum ok but it is worth noting that a feature needs several patches to be
fully supported.
In order to ease the review (maybe I was wrong), I chose to have distinct
patches for modification related to new dts keywords and for modification
related to new dtb tag and tried to have patches as small as possible.
The last patch of a new feature was a patch adding test.
I am open to remove patches that just add tests. In that case tests will be
added in the last patch related to a new feature. You still need to switch
between patches in that case.
Further more, during iteration, the last patch of a new feature could be
modified just because the test part is present in this patch even if other
part of the patch itself is not impacted.
I mean:
- patch 1: related to dts keyword
- patch 2: related to dtb + test
Update patch 1 will imply an update to patch 2.
I am not sure that this will ease the review.
To avoid that, I can merge all patches related to feature into only one
patch. This patch can be quite huge and I am not sure that it will be easy
to review it.
Once again, I am open to merging patches. Let me know what do you prefer
in terms of patch granularity.
Best regards,
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 10/77] tests: Add basic metadata tests
2026-01-16 13:36 ` Herve Codina
@ 2026-01-19 5:32 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-19 5:32 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 4377 bytes --]
On Fri, Jan 16, 2026 at 02:36:00PM +0100, Herve Codina wrote:
> On Thu, 15 Jan 2026 11:50:56 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > On Mon, Jan 12, 2026 at 03:19:00PM +0100, Herve Codina wrote:
> > > This first test is related to local phandle references (FDT_REF_LOCAL
> > > dtb tag).
> > >
> > > The test pattern used is
> > > - Generate a dts (xxx.dts.dts) from an input dts
> > > - Check this generated dts against expected contents
> > > - Generate a dtb (xxx.dtb) from the same input dts
> > > - Check this generated dtb against expected contents
> > > - Generate a dts (xxx.dtb.dts) from the generated dtb
> > > - Check this generated dts against expected contents
> > > - Generate a dtb (xxx.dtb.dts.dtb) from the generated dts
> > > - Check this generated dtb, expect the same contents as for xxx.dtb
> > >
> > > Even if only one meta-data feature is currently tested in this tests
> > > introduction, use a loop in order to ease future addition consisting in
> > > adding new input dts as soon as new meta-data feature are supported.
> >
> > As a rule of tumb, I prefer tests to be introduced in the same patch
> > that introduces the feature tested. Usually, I don't care that much,
> > but in a giant series like this, it would really help review (the
> > tests help to document the feature being added without switching
> > between patches).
>
> Hum ok but it is worth noting that a feature needs several patches to be
> fully supported.
Right, it's a general guideline, not a hard and fast rule.
In most cases I'd suggest putting the tests in with the patch that
adds the piece they need to work. That does mean that if some of the
simpler tests can operate with only some of the patches, moving those
tests earlier.
Again, only a guideline, but it helps review because the tests act as
documentation for the functionality the patch is adding.
> In order to ease the review (maybe I was wrong), I chose to have distinct
> patches for modification related to new dts keywords and for modification
> related to new dtb tag and tried to have patches as small as
> possible.
Small is usually good. However, if it's so small that the patch
doesn't express a complete idea so you have to keep referencing
surrounding patches to make sense of it, then it's no longer good.
Fwiw, think these patches are mostly well divided, but as above,
folding tests in with code changes is usually better because the tests
help show what the new code is expected to do.
[I will note that having the tests as a separate patch, usuallly
*before* the code changes is very useful during development. But git
makes it pretty easy to re-order and fold things together when you're
ready to post]
> The last patch of a new feature was a patch adding test.
>
> I am open to remove patches that just add tests. In that case tests will be
> added in the last patch related to a new feature. You still need to switch
> between patches in that case.
Yes, but not quite as much. And even less if those tests which can be
moved earlier are moved earlier.
> Further more, during iteration, the last patch of a new feature could be
> modified just because the test part is present in this patch even if other
> part of the patch itself is not impacted.
>
> I mean:
> - patch 1: related to dts keyword
> - patch 2: related to dtb + test
>
> Update patch 1 will imply an update to patch 2.
> I am not sure that this will ease the review.
Point taken. For tests that intrinsically require things from
multiple earlier patches, having them separate probably makes sense.
Often at least some of the tests can be more closely related to a
single patch though. When possible, that's generally preferable.
> To avoid that, I can merge all patches related to feature into only one
> patch. This patch can be quite huge and I am not sure that it will be easy
> to review it.
No, definitely don't do that.
> Once again, I am open to merging patches. Let me know what do you prefer
> in terms of patch granularity.
>
> Best regards,
> Hervé
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 11/77] Add support for FDT_REF_PHANDLE dtb tag
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (9 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 10/77] tests: Add basic metadata tests Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-15 1:24 ` David Gibson
2026-01-12 14:19 ` [RFC PATCH 12/77] tests: metadata: Add external phandle reference tests Herve Codina
` (68 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The FDT_REF_PHANDLE dtb tag is similar to the FDT_REF_LOCAL tag except
that it identifies a reference to an external phandle. The node
referenced by the phandle is not present in the device-tree blob.
The FDT_REF_PHANDLE dtb tag is a meta-data tag attached to a property.
It indicates that the property defined before this tag (FDT_PROP) uses a
phandle value and the node related to this phandle value is not local
node (i.e. the node is not present in the device-tree blob). This tag
can be available only in overlay or addon device-tree blobs. The phandle
value used in the property has to be resolved when the device-tree blob
is applied on top of a base device-tree.
It is followed by two values and a possible alignment padding:
- offset (32bit):
Offset in the property data where the phandle is available.
- label (string including \0):
The label to use to resolve the phandle value.
- padding:
Padding (0x00) added to have the next tag aligned on 32bit.
Example:
FDT_PROP 0x00000008 xxxxxxxx 0x00 0x01 0x02 0x03 0xff 0xff 0xff 0xff
FDT_REF_PHANDLE 0x00000004 "foo1" 0x00 0x00 0x00
This means that at the offset 4 of the property data, the value
(0xffffffff) is an unresolved phandle value and the related node is
the node referenced by "foo1".
This is what is encoded in the dtb when the related dts has a property
with the value set to <0x00010203 &foo1> with 'foo1' a reference
to an non local node.
If several non local phandles are used in the property data, several
FDT_REF_PHANDLE are present after the FDT_PROP tag. Each of them points
with its offset value to the position of one phandle.
For instance, if a first property with 8 bytes of data has a
unresolved phandle value at offset 4 referenced by "foo" and a second
property with 16 bytes of data has unresolved phandle values at offset 0
and 8 referenced by "bar" and "baz", the following tags sequence is
present:
FDT_PROP 0x00000008 xxxxxxxx <data bytes>
FDT_REF_PHANDLE 0x00000004 "foo" 0x00 0x00 0x00
FDT_PROP 0x00000010 xxxxxxxx <data bytes>
FDT_REF_LOCAL 0x00000000 "bar" 0x00 0x00 0x00
FDT_REF_LOCAL 0x00000008 "baz" 0x00 0x00 0x00
Add support for this new dtb tag.
Suggested-by: David Gibson <david@gibson.dropbear.id.au>
Link: https://lore.kernel.org/all/aL-2fmYsbexEtpNp@zatzit/
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
dtc.c | 12 ++++++++++++
fdtdump.c | 10 ++++++++++
flattree.c | 37 +++++++++++++++++++++++++++++++++++++
libfdt/fdt.c | 16 ++++++++++++++++
libfdt/fdt.h | 2 ++
5 files changed, 77 insertions(+)
diff --git a/dtc.c b/dtc.c
index d0b4de3..fe8e8e4 100644
--- a/dtc.c
+++ b/dtc.c
@@ -336,6 +336,18 @@ int main(int argc, char *argv[])
update_phandles_ref(dti);
mark_local_phandles(dti);
+ /*
+ * With FDT_REF_PHANDLE added in dtbs, we need to identified
+ * if some unresolved phandle references are allowed in the dtb
+ * we have parsed (needed for process_check() to run properly).
+ *
+ * Identify plugin device-trees (overlays) based on specific node
+ * presence.
+ */
+ if (get_subnode(dti->dt, "__fixups__") ||
+ get_subnode(dti->dt, "__local_fixups__"))
+ dti->dtsflags |= DTSF_PLUGIN;
+
process_checks(force, dti);
if (auto_label_aliases)
diff --git a/fdtdump.c b/fdtdump.c
index dffa9a6..7300280 100644
--- a/fdtdump.c
+++ b/fdtdump.c
@@ -158,6 +158,16 @@ static void dump_blob(void *blob, bool debug)
continue;
}
+ if (tag == FDT_REF_PHANDLE) {
+ offset = fdt32_to_cpu(GET_CELL(p));
+ s = p;
+ p = PALIGN(p + strlen(s) + 1, 4);
+
+ printf("%*s// [FDT_REF_PHANDLE] %s[%"PRIu32"], ref = %s\n",
+ depth * shift, "", last_prop_name, offset, s);
+ continue;
+ }
+
fprintf(stderr, "%*s ** Unknown tag 0x%08"PRIx32"\n", depth * shift, "", tag);
break;
}
diff --git a/flattree.c b/flattree.c
index 5c597ad..07f7545 100644
--- a/flattree.c
+++ b/flattree.c
@@ -44,6 +44,7 @@ struct emitter {
void (*endnode)(void *, struct label *labels);
void (*property)(void *, struct label *labels);
void (*ref_local)(void *);
+ void (*ref_phandle)(void *);
};
static void bin_emit_cell(void *e, cell_t val)
@@ -98,6 +99,11 @@ static void bin_emit_ref_local(void *e)
bin_emit_cell(e, FDT_REF_LOCAL);
}
+static void bin_emit_ref_phandle(void *e)
+{
+ bin_emit_cell(e, FDT_REF_PHANDLE);
+}
+
static struct emitter bin_emitter = {
.cell = bin_emit_cell,
.string = bin_emit_string,
@@ -107,6 +113,7 @@ static struct emitter bin_emitter = {
.endnode = bin_emit_endnode,
.property = bin_emit_property,
.ref_local = bin_emit_ref_local,
+ .ref_phandle = bin_emit_ref_phandle,
};
static void emit_label(FILE *f, const char *prefix, const char *label)
@@ -226,6 +233,14 @@ static void asm_emit_ref_local(void *e)
asm_emit_cell(e, FDT_REF_LOCAL);
}
+static void asm_emit_ref_phandle(void *e)
+{
+ FILE *f = e;
+
+ fprintf(f, "\t/* FDT_REF_PHANDLE */\n");
+ asm_emit_cell(e, FDT_REF_PHANDLE);
+}
+
static struct emitter asm_emitter = {
.cell = asm_emit_cell,
.string = asm_emit_string,
@@ -235,6 +250,7 @@ static struct emitter asm_emitter = {
.endnode = asm_emit_endnode,
.property = asm_emit_property,
.ref_local = asm_emit_ref_local,
+ .ref_phandle = asm_emit_ref_phandle,
};
static int stringtable_insert(struct data *d, const char *str)
@@ -299,6 +315,15 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
emit->cell(etarget, m->offset);
continue;
}
+
+ if (m->ref[0] == '/')
+ die("Phandle uses a non local reference by path (%s)\n",
+ m->ref);
+
+ emit->ref_phandle(etarget);
+ emit->cell(etarget, m->offset);
+ emit->string(etarget, m->ref, 0);
+ emit->align(etarget, sizeof(cell_t));
}
}
}
@@ -767,6 +792,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
const char *flatname;
uint32_t val;
uint32_t offset;
+ const char *str;
node = build_node(NULL, NULL, NULL);
@@ -824,6 +850,17 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
prop->val = data_append_markers(prop->val, m);
break;
+ case FDT_REF_PHANDLE:
+ if (!(flags & FTF_REF_XXX))
+ die("REF_PHANDLE tag found in flat tree"
+ " version <18\n");
+
+ offset = flat_read_word(dtbuf);
+ str = flat_read_string(dtbuf);
+ m = alloc_marker(offset, REF_PHANDLE, xstrdup(str));
+ prop->val = data_append_markers(prop->val, m);
+ break;
+
default:
die("Invalid opcode word %08x in device tree blob\n",
val);
diff --git a/libfdt/fdt.c b/libfdt/fdt.c
index 7268fb6..8f3c35d 100644
--- a/libfdt/fdt.c
+++ b/libfdt/fdt.c
@@ -217,6 +217,21 @@ uint32_t fdt_next_tag_full(const void *fdt, int startoffset, int *nextoffset)
offset += sizeof(fdt32_t);
break;
+ case FDT_REF_PHANDLE:
+ /* Skip offset value */
+ tmp32p = fdt_offset_ptr(fdt, offset, sizeof(*tmp32p));
+ if (!can_assume(VALID_DTB) && !tmp32p)
+ return FDT_END; /* premature end */
+ offset += sizeof(fdt32_t);
+
+ /* Skip ref */
+ do {
+ p = fdt_offset_ptr(fdt, offset++, 1);
+ } while (p && (*p != '\0'));
+ if (!can_assume(VALID_DTB) && !p)
+ return FDT_END; /* premature end */
+ break;
+
default:
return FDT_END;
}
@@ -257,6 +272,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
return tag;
case FDT_REF_LOCAL:
+ case FDT_REF_PHANDLE:
/*
* Next tag is a meta-data tag present in the middle
* of the structure -> Skip it and look at next one
diff --git a/libfdt/fdt.h b/libfdt/fdt.h
index f8efdf1..530d2e5 100644
--- a/libfdt/fdt.h
+++ b/libfdt/fdt.h
@@ -56,6 +56,8 @@ struct fdt_property {
size, content */
#define FDT_NOP 0x4 /* nop */
#define FDT_REF_LOCAL 0x5 /* local phandle reference: offset */
+#define FDT_REF_PHANDLE 0x6 /* external phandle reference: offset,
+ external label */
#define FDT_END 0x9
#define FDT_V1_SIZE (7*sizeof(fdt32_t))
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 11/77] Add support for FDT_REF_PHANDLE dtb tag
2026-01-12 14:19 ` [RFC PATCH 11/77] Add support for FDT_REF_PHANDLE dtb tag Herve Codina
@ 2026-01-15 1:24 ` David Gibson
2026-01-16 15:17 ` Herve Codina
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-15 1:24 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 9554 bytes --]
On Mon, Jan 12, 2026 at 03:19:01PM +0100, Herve Codina wrote:
> The FDT_REF_PHANDLE dtb tag is similar to the FDT_REF_LOCAL tag except
> that it identifies a reference to an external phandle. The node
> referenced by the phandle is not present in the device-tree blob.
The names FDT_REF_PHANDLE and FDT_REF_LOCAL are perhaps a little
misleading - both are marking a phandle, the difference is in the form
of reference. That's quite difference from the distinction between
the REF_PHANDLE and REF_PATH marker types, where the difference is in
what the reference expands to in the property.
> The FDT_REF_PHANDLE dtb tag is a meta-data tag attached to a property.
>
> It indicates that the property defined before this tag (FDT_PROP) uses a
> phandle value and the node related to this phandle value is not local
> node (i.e. the node is not present in the device-tree blob). This tag
> can be available only in overlay or addon device-tree blobs. The phandle
> value used in the property has to be resolved when the device-tree blob
> is applied on top of a base device-tree.
This is kind of looking ahead, but does that imply that this tag is
only valid in addon dtbs?
> It is followed by two values and a possible alignment padding:
> - offset (32bit):
> Offset in the property data where the phandle is available.
> - label (string including \0):
> The label to use to resolve the phandle value.
I expect it will become apparent later in the series, but it would be
helpful to clarify what the scope of that label is. A single node?
The whole tree? Across a tree and all its possible addons?
> - padding:
> Padding (0x00) added to have the next tag aligned on 32bit.
>
> Example:
> FDT_PROP 0x00000008 xxxxxxxx 0x00 0x01 0x02 0x03 0xff 0xff 0xff 0xff
> FDT_REF_PHANDLE 0x00000004 "foo1" 0x00 0x00 0x00
>
> This means that at the offset 4 of the property data, the value
> (0xffffffff) is an unresolved phandle value and the related node is
> the node referenced by "foo1".
>
> This is what is encoded in the dtb when the related dts has a property
> with the value set to <0x00010203 &foo1> with 'foo1' a reference
> to an non local node.
>
> If several non local phandles are used in the property data, several
> FDT_REF_PHANDLE are present after the FDT_PROP tag. Each of them points
> with its offset value to the position of one phandle.
>
> For instance, if a first property with 8 bytes of data has a
> unresolved phandle value at offset 4 referenced by "foo" and a second
> property with 16 bytes of data has unresolved phandle values at offset 0
> and 8 referenced by "bar" and "baz", the following tags sequence is
> present:
> FDT_PROP 0x00000008 xxxxxxxx <data bytes>
> FDT_REF_PHANDLE 0x00000004 "foo" 0x00 0x00 0x00
> FDT_PROP 0x00000010 xxxxxxxx <data bytes>
> FDT_REF_LOCAL 0x00000000 "bar" 0x00 0x00 0x00
> FDT_REF_LOCAL 0x00000008 "baz" 0x00 0x00 0x00
>
> Add support for this new dtb tag.
>
> Suggested-by: David Gibson <david@gibson.dropbear.id.au>
> Link: https://lore.kernel.org/all/aL-2fmYsbexEtpNp@zatzit/
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> dtc.c | 12 ++++++++++++
> fdtdump.c | 10 ++++++++++
> flattree.c | 37 +++++++++++++++++++++++++++++++++++++
> libfdt/fdt.c | 16 ++++++++++++++++
> libfdt/fdt.h | 2 ++
> 5 files changed, 77 insertions(+)
>
> diff --git a/dtc.c b/dtc.c
> index d0b4de3..fe8e8e4 100644
> --- a/dtc.c
> +++ b/dtc.c
> @@ -336,6 +336,18 @@ int main(int argc, char *argv[])
> update_phandles_ref(dti);
> mark_local_phandles(dti);
>
> + /*
> + * With FDT_REF_PHANDLE added in dtbs, we need to identified
> + * if some unresolved phandle references are allowed in the dtb
> + * we have parsed (needed for process_check() to run properly).
> + *
> + * Identify plugin device-trees (overlays) based on specific node
> + * presence.
> + */
> + if (get_subnode(dti->dt, "__fixups__") ||
> + get_subnode(dti->dt, "__local_fixups__"))
> + dti->dtsflags |= DTSF_PLUGIN;
> +
> process_checks(force, dti);
>
> if (auto_label_aliases)
> diff --git a/fdtdump.c b/fdtdump.c
> index dffa9a6..7300280 100644
> --- a/fdtdump.c
> +++ b/fdtdump.c
> @@ -158,6 +158,16 @@ static void dump_blob(void *blob, bool debug)
> continue;
> }
>
> + if (tag == FDT_REF_PHANDLE) {
> + offset = fdt32_to_cpu(GET_CELL(p));
> + s = p;
> + p = PALIGN(p + strlen(s) + 1, 4);
> +
> + printf("%*s// [FDT_REF_PHANDLE] %s[%"PRIu32"], ref = %s\n",
> + depth * shift, "", last_prop_name, offset, s);
> + continue;
> + }
> +
> fprintf(stderr, "%*s ** Unknown tag 0x%08"PRIx32"\n", depth * shift, "", tag);
> break;
> }
> diff --git a/flattree.c b/flattree.c
> index 5c597ad..07f7545 100644
> --- a/flattree.c
> +++ b/flattree.c
> @@ -44,6 +44,7 @@ struct emitter {
> void (*endnode)(void *, struct label *labels);
> void (*property)(void *, struct label *labels);
> void (*ref_local)(void *);
> + void (*ref_phandle)(void *);
> };
>
> static void bin_emit_cell(void *e, cell_t val)
> @@ -98,6 +99,11 @@ static void bin_emit_ref_local(void *e)
> bin_emit_cell(e, FDT_REF_LOCAL);
> }
>
> +static void bin_emit_ref_phandle(void *e)
> +{
> + bin_emit_cell(e, FDT_REF_PHANDLE);
> +}
> +
> static struct emitter bin_emitter = {
> .cell = bin_emit_cell,
> .string = bin_emit_string,
> @@ -107,6 +113,7 @@ static struct emitter bin_emitter = {
> .endnode = bin_emit_endnode,
> .property = bin_emit_property,
> .ref_local = bin_emit_ref_local,
> + .ref_phandle = bin_emit_ref_phandle,
> };
>
> static void emit_label(FILE *f, const char *prefix, const char *label)
> @@ -226,6 +233,14 @@ static void asm_emit_ref_local(void *e)
> asm_emit_cell(e, FDT_REF_LOCAL);
> }
>
> +static void asm_emit_ref_phandle(void *e)
> +{
> + FILE *f = e;
> +
> + fprintf(f, "\t/* FDT_REF_PHANDLE */\n");
> + asm_emit_cell(e, FDT_REF_PHANDLE);
> +}
> +
> static struct emitter asm_emitter = {
> .cell = asm_emit_cell,
> .string = asm_emit_string,
> @@ -235,6 +250,7 @@ static struct emitter asm_emitter = {
> .endnode = asm_emit_endnode,
> .property = asm_emit_property,
> .ref_local = asm_emit_ref_local,
> + .ref_phandle = asm_emit_ref_phandle,
> };
>
> static int stringtable_insert(struct data *d, const char *str)
> @@ -299,6 +315,15 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
> emit->cell(etarget, m->offset);
> continue;
> }
> +
> + if (m->ref[0] == '/')
> + die("Phandle uses a non local reference by path (%s)\n",
> + m->ref);
> +
> + emit->ref_phandle(etarget);
> + emit->cell(etarget, m->offset);
> + emit->string(etarget, m->ref, 0);
> + emit->align(etarget, sizeof(cell_t));
> }
> }
> }
> @@ -767,6 +792,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
> const char *flatname;
> uint32_t val;
> uint32_t offset;
> + const char *str;
>
> node = build_node(NULL, NULL, NULL);
>
> @@ -824,6 +850,17 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
> prop->val = data_append_markers(prop->val, m);
> break;
>
> + case FDT_REF_PHANDLE:
> + if (!(flags & FTF_REF_XXX))
> + die("REF_PHANDLE tag found in flat tree"
> + " version <18\n");
> +
> + offset = flat_read_word(dtbuf);
> + str = flat_read_string(dtbuf);
> + m = alloc_marker(offset, REF_PHANDLE, xstrdup(str));
> + prop->val = data_append_markers(prop->val, m);
> + break;
> +
> default:
> die("Invalid opcode word %08x in device tree blob\n",
> val);
> diff --git a/libfdt/fdt.c b/libfdt/fdt.c
> index 7268fb6..8f3c35d 100644
> --- a/libfdt/fdt.c
> +++ b/libfdt/fdt.c
> @@ -217,6 +217,21 @@ uint32_t fdt_next_tag_full(const void *fdt, int startoffset, int *nextoffset)
> offset += sizeof(fdt32_t);
> break;
>
> + case FDT_REF_PHANDLE:
> + /* Skip offset value */
> + tmp32p = fdt_offset_ptr(fdt, offset, sizeof(*tmp32p));
> + if (!can_assume(VALID_DTB) && !tmp32p)
> + return FDT_END; /* premature end */
> + offset += sizeof(fdt32_t);
> +
> + /* Skip ref */
> + do {
> + p = fdt_offset_ptr(fdt, offset++, 1);
> + } while (p && (*p != '\0'));
> + if (!can_assume(VALID_DTB) && !p)
> + return FDT_END; /* premature end */
> + break;
> +
> default:
> return FDT_END;
> }
> @@ -257,6 +272,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
> return tag;
>
> case FDT_REF_LOCAL:
> + case FDT_REF_PHANDLE:
> /*
> * Next tag is a meta-data tag present in the middle
> * of the structure -> Skip it and look at next one
> diff --git a/libfdt/fdt.h b/libfdt/fdt.h
> index f8efdf1..530d2e5 100644
> --- a/libfdt/fdt.h
> +++ b/libfdt/fdt.h
> @@ -56,6 +56,8 @@ struct fdt_property {
> size, content */
> #define FDT_NOP 0x4 /* nop */
> #define FDT_REF_LOCAL 0x5 /* local phandle reference: offset */
> +#define FDT_REF_PHANDLE 0x6 /* external phandle reference: offset,
> + external label */
> #define FDT_END 0x9
>
> #define FDT_V1_SIZE (7*sizeof(fdt32_t))
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 11/77] Add support for FDT_REF_PHANDLE dtb tag
2026-01-15 1:24 ` David Gibson
@ 2026-01-16 15:17 ` Herve Codina
2026-01-19 5:40 ` David Gibson
0 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-16 15:17 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
Hi David,
On Thu, 15 Jan 2026 12:24:49 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Mon, Jan 12, 2026 at 03:19:01PM +0100, Herve Codina wrote:
> > The FDT_REF_PHANDLE dtb tag is similar to the FDT_REF_LOCAL tag except
> > that it identifies a reference to an external phandle. The node
> > referenced by the phandle is not present in the device-tree blob.
>
> The names FDT_REF_PHANDLE and FDT_REF_LOCAL are perhaps a little
> misleading - both are marking a phandle, the difference is in the form
> of reference. That's quite difference from the distinction between
> the REF_PHANDLE and REF_PATH marker types, where the difference is in
> what the reference expands to in the property.
I am agree.
FDT_PHANDLE: A local phandle with the value known.
FDT_PHANDLE_REF: An external phandle, its value need to be resolved ?
This is aligned with FDT_EXPORT_SYM / FDT_EXPORT_SYM_REF.
Or maybe:
FDT_TYPE_PHANDLE
FDT_TYPE_PHANDLE_REF
"TYPE" has been mentioned by Rob in the "FDT_TYPE_U32" context.
Any other ideas are welcome.
>
> > The FDT_REF_PHANDLE dtb tag is a meta-data tag attached to a property.
> >
> > It indicates that the property defined before this tag (FDT_PROP) uses a
> > phandle value and the node related to this phandle value is not local
> > node (i.e. the node is not present in the device-tree blob). This tag
> > can be available only in overlay or addon device-tree blobs. The phandle
> > value used in the property has to be resolved when the device-tree blob
> > is applied on top of a base device-tree.
>
> This is kind of looking ahead, but does that imply that this tag is
> only valid in addon dtbs?
addon dtbs for sure but also overlay (plugin) dtbs.
>
> > It is followed by two values and a possible alignment padding:
> > - offset (32bit):
> > Offset in the property data where the phandle is available.
> > - label (string including \0):
> > The label to use to resolve the phandle value.
>
> I expect it will become apparent later in the series, but it would be
> helpful to clarify what the scope of that label is. A single node?
> The whole tree? Across a tree and all its possible addons?
This label is the unresolved reference. Its scope is the dtb.
For instance, "prop = < 0 1 &foo>;" in a dts with the node referenced by
&foo not present in this dts (possible for addons and plugins) will lead
to 'FDT_REF_PHANDLE 8 "foo"'
The way "foo" is used when the dtb is applied is covered later in the
series.
It will be resolved with import/export mechanism (when the addon is
applied).
Also it can be a namespace label reference (see patch 66 for the definition
of namespace label reference) and here also it will be resolved thanks to
import/export mechanism. Namespace label references can only be present in
addons.
Best regards,
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 11/77] Add support for FDT_REF_PHANDLE dtb tag
2026-01-16 15:17 ` Herve Codina
@ 2026-01-19 5:40 ` David Gibson
2026-01-19 13:19 ` Herve Codina
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-19 5:40 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 4306 bytes --]
On Fri, Jan 16, 2026 at 04:17:27PM +0100, Herve Codina wrote:
> Hi David,
>
> On Thu, 15 Jan 2026 12:24:49 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > On Mon, Jan 12, 2026 at 03:19:01PM +0100, Herve Codina wrote:
> > > The FDT_REF_PHANDLE dtb tag is similar to the FDT_REF_LOCAL tag except
> > > that it identifies a reference to an external phandle. The node
> > > referenced by the phandle is not present in the device-tree blob.
> >
> > The names FDT_REF_PHANDLE and FDT_REF_LOCAL are perhaps a little
> > misleading - both are marking a phandle, the difference is in the form
> > of reference. That's quite difference from the distinction between
> > the REF_PHANDLE and REF_PATH marker types, where the difference is in
> > what the reference expands to in the property.
>
> I am agree.
>
> FDT_PHANDLE: A local phandle with the value known.
> FDT_PHANDLE_REF: An external phandle, its value need to be resolved ?
Yeah, I think that works.
> This is aligned with FDT_EXPORT_SYM / FDT_EXPORT_SYM_REF.
>
> Or maybe:
> FDT_TYPE_PHANDLE
> FDT_TYPE_PHANDLE_REF
>
> "TYPE" has been mentioned by Rob in the "FDT_TYPE_U32" context.
I don't especially like this. phandles do have a bearing on types.
But as I said to Rob, I think they're a sufficiently special case,
that I'd prefer not to handle them as just an aspect of a more general
"types" system.
Btw, since we're looking at dtb changes anyway, one possibility would
be to no longer encode a node's phandle as a property, but include it
as a new field in the FDT_BEGIN_NODE tag. Putting it in a property
was always a bit of a hack - in traditional OF, it was generally the
node's address in memory, not something from a property. Doing it
that way might side step some messy edge cases like dealing with
improperly encoded "linux,phandle" properties.
> Any other ideas are welcome.
>
> > > The FDT_REF_PHANDLE dtb tag is a meta-data tag attached to a property.
> > >
> > > It indicates that the property defined before this tag (FDT_PROP) uses a
> > > phandle value and the node related to this phandle value is not local
> > > node (i.e. the node is not present in the device-tree blob). This tag
> > > can be available only in overlay or addon device-tree blobs. The phandle
> > > value used in the property has to be resolved when the device-tree blob
> > > is applied on top of a base device-tree.
> >
> > This is kind of looking ahead, but does that imply that this tag is
> > only valid in addon dtbs?
>
> addon dtbs for sure but also overlay (plugin) dtbs.
I don't really understand how they would be used for plugins - I
thought the idea was that addons would more or less obsolete plugins.
> >
> > > It is followed by two values and a possible alignment padding:
> > > - offset (32bit):
> > > Offset in the property data where the phandle is available.
> > > - label (string including \0):
> > > The label to use to resolve the phandle value.
> >
> > I expect it will become apparent later in the series, but it would be
> > helpful to clarify what the scope of that label is. A single node?
> > The whole tree? Across a tree and all its possible addons?
>
> This label is the unresolved reference. Its scope is the dtb.
"the dtb" being a single addon, yes? That could have several meanings
in the base tree depending on where the addon is attached, yes?
> For instance, "prop = < 0 1 &foo>;" in a dts with the node referenced by
> &foo not present in this dts (possible for addons and plugins) will lead
> to 'FDT_REF_PHANDLE 8 "foo"'
>
> The way "foo" is used when the dtb is applied is covered later in the
> series.
>
> It will be resolved with import/export mechanism (when the addon is
> applied).
>
> Also it can be a namespace label reference (see patch 66 for the definition
> of namespace label reference) and here also it will be resolved thanks to
> import/export mechanism. Namespace label references can only be present in
> addons.
>
> Best regards,
> Hervé
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 11/77] Add support for FDT_REF_PHANDLE dtb tag
2026-01-19 5:40 ` David Gibson
@ 2026-01-19 13:19 ` Herve Codina
0 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-19 13:19 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
Hi David,
On Mon, 19 Jan 2026 16:40:12 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Fri, Jan 16, 2026 at 04:17:27PM +0100, Herve Codina wrote:
> > Hi David,
> >
> > On Thu, 15 Jan 2026 12:24:49 +1100
> > David Gibson <david@gibson.dropbear.id.au> wrote:
> >
> > > On Mon, Jan 12, 2026 at 03:19:01PM +0100, Herve Codina wrote:
> > > > The FDT_REF_PHANDLE dtb tag is similar to the FDT_REF_LOCAL tag except
> > > > that it identifies a reference to an external phandle. The node
> > > > referenced by the phandle is not present in the device-tree blob.
> > >
> > > The names FDT_REF_PHANDLE and FDT_REF_LOCAL are perhaps a little
> > > misleading - both are marking a phandle, the difference is in the form
> > > of reference. That's quite difference from the distinction between
> > > the REF_PHANDLE and REF_PATH marker types, where the difference is in
> > > what the reference expands to in the property.
> >
> > I am agree.
> >
> > FDT_PHANDLE: A local phandle with the value known.
> > FDT_PHANDLE_REF: An external phandle, its value need to be resolved ?
>
> Yeah, I think that works.
>
> > This is aligned with FDT_EXPORT_SYM / FDT_EXPORT_SYM_REF.
> >
> > Or maybe:
> > FDT_TYPE_PHANDLE
> > FDT_TYPE_PHANDLE_REF
> >
> > "TYPE" has been mentioned by Rob in the "FDT_TYPE_U32" context.
>
> I don't especially like this. phandles do have a bearing on types.
> But as I said to Rob, I think they're a sufficiently special case,
> that I'd prefer not to handle them as just an aspect of a more general
> "types" system.
Ok, I will not use 'TYPE' in the name of those tags.
>
> Btw, since we're looking at dtb changes anyway, one possibility would
> be to no longer encode a node's phandle as a property, but include it
> as a new field in the FDT_BEGIN_NODE tag. Putting it in a property
> was always a bit of a hack - in traditional OF, it was generally the
> node's address in memory, not something from a property. Doing it
> that way might side step some messy edge cases like dealing with
> improperly encoded "linux,phandle" properties.
>
> > Any other ideas are welcome.
> >
> > > > The FDT_REF_PHANDLE dtb tag is a meta-data tag attached to a property.
> > > >
> > > > It indicates that the property defined before this tag (FDT_PROP) uses a
> > > > phandle value and the node related to this phandle value is not local
> > > > node (i.e. the node is not present in the device-tree blob). This tag
> > > > can be available only in overlay or addon device-tree blobs. The phandle
> > > > value used in the property has to be resolved when the device-tree blob
> > > > is applied on top of a base device-tree.
> > >
> > > This is kind of looking ahead, but does that imply that this tag is
> > > only valid in addon dtbs?
> >
> > addon dtbs for sure but also overlay (plugin) dtbs.
>
> I don't really understand how they would be used for plugins - I
> thought the idea was that addons would more or less obsolete plugins.
They won't be used in plugins. Other mechanism are available in plugind.
My idea was to to keep things consistent.
I mean, pluggin dtb can have metadata. Having metadata doesn't mean that
they must be used.
FDT_REF_PHANDLE (or other name) makes sense in plugin dtb.
Is FDT_REF_PHANDLE valid for plugin dtb, the answer is yes.
Will FDT_REF_PHANDLE be used for symbol resolution in the plugin case, the
answer is no, other mechanisme are used (__fixups__ node).
>
> > >
> > > > It is followed by two values and a possible alignment padding:
> > > > - offset (32bit):
> > > > Offset in the property data where the phandle is available.
> > > > - label (string including \0):
> > > > The label to use to resolve the phandle value.
> > >
> > > I expect it will become apparent later in the series, but it would be
> > > helpful to clarify what the scope of that label is. A single node?
> > > The whole tree? Across a tree and all its possible addons?
> >
> > This label is the unresolved reference. Its scope is the dtb.
>
> "the dtb" being a single addon, yes? That could have several meanings
> in the base tree depending on where the addon is attached, yes?
yes, the addon dtb is for a single addon.
yes, depending on where the addon is attached, the symbol resolution can reach
different nodes. Is that several "meanings", not sure.
From the addon: prop = <&i2c>;
Depending on node the addon is applied this could be resolved to the node
i2c@xxxx or i2c@yyyy but for sure it will be resolved to a node describing
an i2c controller.
>
> > For instance, "prop = < 0 1 &foo>;" in a dts with the node referenced by
> > &foo not present in this dts (possible for addons and plugins) will lead
> > to 'FDT_REF_PHANDLE 8 "foo"'
> >
> > The way "foo" is used when the dtb is applied is covered later in the
> > series.
> >
> > It will be resolved with import/export mechanism (when the addon is
> > applied).
> >
> > Also it can be a namespace label reference (see patch 66 for the definition
> > of namespace label reference) and here also it will be resolved thanks to
> > import/export mechanism. Namespace label references can only be present in
> > addons.
> >
Best regards,
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 12/77] tests: metadata: Add external phandle reference tests
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (10 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 11/77] Add support for FDT_REF_PHANDLE dtb tag Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 13/77] Introduce dt_flags field in dtb header Herve Codina
` (67 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Add tests related to external phandle references (FDT_REF_PHANDLE dtb
tag).
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
tests/metadata_refphandle.dtb.dts.expect | 17 +++++++++++++++++
tests/metadata_refphandle.dtb.expect | 16 ++++++++++++++++
tests/metadata_refphandle.dts | 11 +++++++++++
tests/metadata_refphandle.dts.dts.expect | 17 +++++++++++++++++
tests/run_tests.sh | 2 +-
5 files changed, 62 insertions(+), 1 deletion(-)
create mode 100644 tests/metadata_refphandle.dtb.dts.expect
create mode 100644 tests/metadata_refphandle.dtb.expect
create mode 100644 tests/metadata_refphandle.dts
create mode 100644 tests/metadata_refphandle.dts.dts.expect
diff --git a/tests/metadata_refphandle.dtb.dts.expect b/tests/metadata_refphandle.dtb.dts.expect
new file mode 100644
index 0000000..c229ec1
--- /dev/null
+++ b/tests/metadata_refphandle.dtb.dts.expect
@@ -0,0 +1,17 @@
+/dts-v1/;
+
+/ {
+
+ fragment@0 {
+ target = <&test>;
+
+ __overlay__ {
+ ref = <&node_a>;
+ };
+ };
+
+ __fixups__ {
+ test = "/fragment@0:target:0";
+ node_a = "/fragment@0/__overlay__:ref:0";
+ };
+};
diff --git a/tests/metadata_refphandle.dtb.expect b/tests/metadata_refphandle.dtb.expect
new file mode 100644
index 0000000..b2f5f95
--- /dev/null
+++ b/tests/metadata_refphandle.dtb.expect
@@ -0,0 +1,16 @@
+/dts-v1/;
+
+/ {
+ fragment@0 {
+ target = <0xffffffff>;
+ // [FDT_REF_PHANDLE] target[0], ref = test
+ __overlay__ {
+ ref = <0xffffffff>;
+ // [FDT_REF_PHANDLE] ref[0], ref = node_a
+ };
+ };
+ __fixups__ {
+ test = "/fragment@0:target:0";
+ node_a = "/fragment@0/__overlay__:ref:0";
+ };
+};
diff --git a/tests/metadata_refphandle.dts b/tests/metadata_refphandle.dts
new file mode 100644
index 0000000..b8aa650
--- /dev/null
+++ b/tests/metadata_refphandle.dts
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+/plugin/;
+
+&test {
+ ref = <&node_a>;
+};
diff --git a/tests/metadata_refphandle.dts.dts.expect b/tests/metadata_refphandle.dts.dts.expect
new file mode 100644
index 0000000..c229ec1
--- /dev/null
+++ b/tests/metadata_refphandle.dts.dts.expect
@@ -0,0 +1,17 @@
+/dts-v1/;
+
+/ {
+
+ fragment@0 {
+ target = <&test>;
+
+ __overlay__ {
+ ref = <&node_a>;
+ };
+ };
+
+ __fixups__ {
+ test = "/fragment@0:target:0";
+ node_a = "/fragment@0/__overlay__:ref:0";
+ };
+};
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 7a8bdbc..423812e 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1125,7 +1125,7 @@ wrap_fdtdump () {
}
metadata_tests() {
- for dt in metadata_reflocal; do
+ for dt in metadata_reflocal metadata_refphandle; do
run_dtc_test -I dts -O dts -o $dt.dts.dts "$SRCDIR/$dt.dts"
base_run_test check_diff $dt.dts.dts "$SRCDIR/$dt.dts.dts.expect"
run_dtc_test -I dts -O dtb -o $dt.dtb "$SRCDIR/$dt.dts"
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 13/77] Introduce dt_flags field in dtb header
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (11 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 12/77] tests: metadata: Add external phandle reference tests Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-15 1:29 ` David Gibson
2026-01-12 14:19 ` [RFC PATCH 14/77] tests: metadata: Add a first test related to the dt_flags header field Herve Codina
` (66 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
There is no simple way to identify a kind of dtb.
A dtb can be a "standard" device-tree blob but with the future support
for addon dtb, a dtb could be an addon dtb.
Whereas, looking at node structures and name, we can identify if a
"standard" dtb is a pure base device-tree or an overlay device-tree,
this will be no more possible with addons. Indeed, specific node such as
__local_fixups__ and/or __fixups__ present in overlays will be no more
present in addons.
In order to avoid any complex and error prone searches in the dtb
structure to identify whether or not a dtb is an addon, encode this
information directly in the dtb itself.
This is the purpose of the dt_flags field.
Prepare the support for 'addon' flag introducing the dt_flags field
in the dtb header.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
fdtdump.c | 4 ++++
flattree.c | 17 +++++++++++++----
libfdt/fdt.h | 5 ++++-
libfdt/fdt_rw.c | 4 ++++
libfdt/libfdt.h | 1 +
tests/pylibfdt_tests.py | 6 +++---
tests/testutils.c | 2 +-
tests/trees.S | 1 +
8 files changed, 31 insertions(+), 9 deletions(-)
diff --git a/fdtdump.c b/fdtdump.c
index 7300280..5c78559 100644
--- a/fdtdump.c
+++ b/fdtdump.c
@@ -87,6 +87,10 @@ static void dump_blob(void *blob, bool debug)
if (version >= 17)
printf("// size_dt_struct:\t0x%"PRIx32"\n",
fdt32_to_cpu(bph->size_dt_struct));
+ if (version >= 18) {
+ printf("// dt_flags:\t\t0x%"PRIx32"\n",
+ fdt32_to_cpu(bph->dt_flags));
+ }
printf("\n");
for (i = 0; ; i++) {
diff --git a/flattree.c b/flattree.c
index 07f7545..2e2ffcb 100644
--- a/flattree.c
+++ b/flattree.c
@@ -14,6 +14,7 @@
#define FTF_STRUCTSIZE 0x20
#define FTF_NOPS 0x40
#define FTF_REF_XXX 0x80
+#define FTF_DTFLAGS 0x100
static struct version_info {
int version;
@@ -32,7 +33,8 @@ static struct version_info {
{17, 16, FDT_V17_SIZE,
FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS},
{18, 18, FDT_V18_SIZE,
- FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS|FTF_REF_XXX},
+ FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS|FTF_REF_XXX|
+ FTF_DTFLAGS},
};
struct emitter {
@@ -370,7 +372,7 @@ static struct data flatten_reserve_list(struct reserve_info *reservelist,
static void make_fdt_header(struct fdt_header *fdt,
struct version_info *vi,
int reservesize, int dtsize, int strsize,
- int boot_cpuid_phys)
+ int boot_cpuid_phys, uint32_t dt_flags)
{
int reserve_off;
@@ -397,6 +399,8 @@ static void make_fdt_header(struct fdt_header *fdt,
fdt->size_dt_strings = cpu_to_fdt32(strsize);
if (vi->flags & FTF_STRUCTSIZE)
fdt->size_dt_struct = cpu_to_fdt32(dtsize);
+ if (vi->flags & FTF_DTFLAGS)
+ fdt->dt_flags = cpu_to_fdt32(dt_flags);
}
void dt_to_blob(FILE *f, struct dt_info *dti, int version)
@@ -424,7 +428,7 @@ void dt_to_blob(FILE *f, struct dt_info *dti, int version)
/* Make header */
make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
- dti->boot_cpuid_phys);
+ dti->boot_cpuid_phys, 0);
/*
* If the user asked for more space than is used, adjust the totalsize.
@@ -555,6 +559,11 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
symprefix, symprefix);
}
+ if (vi->flags & FTF_DTFLAGS) {
+ fprintf(f, "\t/* dt_flags */\n");
+ asm_emit_cell(f, 0);
+ }
+
/*
* Reserve map entries.
* Align the reserve map to a doubleword boundary.
@@ -980,7 +989,7 @@ struct dt_info *dt_from_blob(const char *fname)
}
if (version >= 18)
- flags |= FTF_REF_XXX;
+ flags |= FTF_REF_XXX | FTF_DTFLAGS;
inbuf_init(&memresvbuf,
blob + off_mem_rsvmap, blob + totalsize);
diff --git a/libfdt/fdt.h b/libfdt/fdt.h
index 530d2e5..128e7bc 100644
--- a/libfdt/fdt.h
+++ b/libfdt/fdt.h
@@ -26,6 +26,9 @@ struct fdt_header {
/* version 17 fields below */
fdt32_t size_dt_struct; /* size of the structure block */
+
+ /* version 18 fields below */
+ fdt32_t dt_flags; /* Ored value of FDT_FLAG_XXXX */
};
struct fdt_reserve_entry {
@@ -65,6 +68,6 @@ struct fdt_property {
#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t))
#define FDT_V16_SIZE FDT_V3_SIZE
#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t))
-#define FDT_V18_SIZE FDT_V17_SIZE
+#define FDT_V18_SIZE (FDT_V17_SIZE + sizeof(fdt32_t))
#endif /* FDT_H */
diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c
index 00e32bb..1528b33 100644
--- a/libfdt/fdt_rw.c
+++ b/libfdt/fdt_rw.c
@@ -457,6 +457,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
return err;
fdt_set_version(buf, 18);
fdt_set_last_comp_version(buf, 18);
+ if (can_assume(LATEST) || fdt_version(fdt) < 18)
+ fdt_set_dt_flags(buf, 0);
fdt_set_size_dt_struct(buf, struct_size);
fdt_set_totalsize(buf, bufsize);
return 0;
@@ -487,6 +489,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
fdt_set_totalsize(buf, bufsize);
fdt_set_version(buf, 18);
fdt_set_last_comp_version(buf, 18);
+ if (can_assume(LATEST) || fdt_version(fdt) < 18)
+ fdt_set_dt_flags(buf, 0);
fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
return 0;
diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h
index d1a9cd5..9777f32 100644
--- a/libfdt/libfdt.h
+++ b/libfdt/libfdt.h
@@ -319,6 +319,7 @@ fdt_set_hdr_(last_comp_version)
fdt_set_hdr_(boot_cpuid_phys)
fdt_set_hdr_(size_dt_strings)
fdt_set_hdr_(size_dt_struct)
+fdt_set_hdr_(dt_flags)
#undef fdt_set_hdr_
/**
diff --git a/tests/pylibfdt_tests.py b/tests/pylibfdt_tests.py
index 373e11a..7d5ab0b 100644
--- a/tests/pylibfdt_tests.py
+++ b/tests/pylibfdt_tests.py
@@ -285,9 +285,9 @@ class PyLibfdtBasicTests(unittest.TestCase):
"""Test that we can access the header values"""
self.assertEqual(self.fdt.magic(), 0xd00dfeed)
self.assertEqual(self.fdt.totalsize(), len(self.fdt._fdt))
- self.assertEqual(self.fdt.off_dt_struct(), 88)
- self.assertEqual(self.fdt.off_dt_strings(), 652)
- self.assertEqual(self.fdt.off_mem_rsvmap(), 40)
+ self.assertEqual(self.fdt.off_dt_struct(), 96)
+ self.assertEqual(self.fdt.off_dt_strings(), 660)
+ self.assertEqual(self.fdt.off_mem_rsvmap(), 48)
self.assertEqual(self.fdt.version(), 18)
self.assertEqual(self.fdt.last_comp_version(), 16)
self.assertEqual(self.fdt.boot_cpuid_phys(), 0)
diff --git a/tests/testutils.c b/tests/testutils.c
index 54da2e4..2d5cfb3 100644
--- a/tests/testutils.c
+++ b/tests/testutils.c
@@ -344,7 +344,7 @@ void *open_blob_rw(const void *blob)
{
int err;
void *buf;
- int newsize = fdt_totalsize(blob) + 8;
+ int newsize = fdt_totalsize(blob) + 8 + 4;
buf = xmalloc(newsize);
err = fdt_open_into(blob, buf, newsize);
diff --git a/tests/trees.S b/tests/trees.S
index ecd43bc..56c1002 100644
--- a/tests/trees.S
+++ b/tests/trees.S
@@ -22,6 +22,7 @@
fdtlong 0
fdtlong (\tree\()_strings_end - \tree\()_strings)
fdtlong (\tree\()_struct_end - \tree\()_struct)
+ fdtlong 0
.endm
.macro rsvmape addrh, addrl, lenh, lenl
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 13/77] Introduce dt_flags field in dtb header
2026-01-12 14:19 ` [RFC PATCH 13/77] Introduce dt_flags field in dtb header Herve Codina
@ 2026-01-15 1:29 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-15 1:29 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 8231 bytes --]
On Mon, Jan 12, 2026 at 03:19:03PM +0100, Herve Codina wrote:
> There is no simple way to identify a kind of dtb.
>
> A dtb can be a "standard" device-tree blob but with the future support
> for addon dtb, a dtb could be an addon dtb.
>
> Whereas, looking at node structures and name, we can identify if a
> "standard" dtb is a pure base device-tree or an overlay device-tree,
> this will be no more possible with addons. Indeed, specific node such as
> __local_fixups__ and/or __fixups__ present in overlays will be no more
> present in addons.
>
> In order to avoid any complex and error prone searches in the dtb
> structure to identify whether or not a dtb is an addon, encode this
> information directly in the dtb itself.
>
> This is the purpose of the dt_flags field.
>
> Prepare the support for 'addon' flag introducing the dt_flags field
> in the dtb header.
Do you have any more flags in mind?
If this is just for identifying addons, I'd suggest using a different
magic number, instead.
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> fdtdump.c | 4 ++++
> flattree.c | 17 +++++++++++++----
> libfdt/fdt.h | 5 ++++-
> libfdt/fdt_rw.c | 4 ++++
> libfdt/libfdt.h | 1 +
> tests/pylibfdt_tests.py | 6 +++---
> tests/testutils.c | 2 +-
> tests/trees.S | 1 +
> 8 files changed, 31 insertions(+), 9 deletions(-)
>
> diff --git a/fdtdump.c b/fdtdump.c
> index 7300280..5c78559 100644
> --- a/fdtdump.c
> +++ b/fdtdump.c
> @@ -87,6 +87,10 @@ static void dump_blob(void *blob, bool debug)
> if (version >= 17)
> printf("// size_dt_struct:\t0x%"PRIx32"\n",
> fdt32_to_cpu(bph->size_dt_struct));
> + if (version >= 18) {
> + printf("// dt_flags:\t\t0x%"PRIx32"\n",
> + fdt32_to_cpu(bph->dt_flags));
> + }
> printf("\n");
>
> for (i = 0; ; i++) {
> diff --git a/flattree.c b/flattree.c
> index 07f7545..2e2ffcb 100644
> --- a/flattree.c
> +++ b/flattree.c
> @@ -14,6 +14,7 @@
> #define FTF_STRUCTSIZE 0x20
> #define FTF_NOPS 0x40
> #define FTF_REF_XXX 0x80
> +#define FTF_DTFLAGS 0x100
>
> static struct version_info {
> int version;
> @@ -32,7 +33,8 @@ static struct version_info {
> {17, 16, FDT_V17_SIZE,
> FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS},
> {18, 18, FDT_V18_SIZE,
> - FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS|FTF_REF_XXX},
> + FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS|FTF_REF_XXX|
> + FTF_DTFLAGS},
> };
>
> struct emitter {
> @@ -370,7 +372,7 @@ static struct data flatten_reserve_list(struct reserve_info *reservelist,
> static void make_fdt_header(struct fdt_header *fdt,
> struct version_info *vi,
> int reservesize, int dtsize, int strsize,
> - int boot_cpuid_phys)
> + int boot_cpuid_phys, uint32_t dt_flags)
> {
> int reserve_off;
>
> @@ -397,6 +399,8 @@ static void make_fdt_header(struct fdt_header *fdt,
> fdt->size_dt_strings = cpu_to_fdt32(strsize);
> if (vi->flags & FTF_STRUCTSIZE)
> fdt->size_dt_struct = cpu_to_fdt32(dtsize);
> + if (vi->flags & FTF_DTFLAGS)
> + fdt->dt_flags = cpu_to_fdt32(dt_flags);
> }
>
> void dt_to_blob(FILE *f, struct dt_info *dti, int version)
> @@ -424,7 +428,7 @@ void dt_to_blob(FILE *f, struct dt_info *dti, int version)
>
> /* Make header */
> make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
> - dti->boot_cpuid_phys);
> + dti->boot_cpuid_phys, 0);
>
> /*
> * If the user asked for more space than is used, adjust the totalsize.
> @@ -555,6 +559,11 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
> symprefix, symprefix);
> }
>
> + if (vi->flags & FTF_DTFLAGS) {
> + fprintf(f, "\t/* dt_flags */\n");
> + asm_emit_cell(f, 0);
> + }
> +
> /*
> * Reserve map entries.
> * Align the reserve map to a doubleword boundary.
> @@ -980,7 +989,7 @@ struct dt_info *dt_from_blob(const char *fname)
> }
>
> if (version >= 18)
> - flags |= FTF_REF_XXX;
> + flags |= FTF_REF_XXX | FTF_DTFLAGS;
>
> inbuf_init(&memresvbuf,
> blob + off_mem_rsvmap, blob + totalsize);
> diff --git a/libfdt/fdt.h b/libfdt/fdt.h
> index 530d2e5..128e7bc 100644
> --- a/libfdt/fdt.h
> +++ b/libfdt/fdt.h
> @@ -26,6 +26,9 @@ struct fdt_header {
>
> /* version 17 fields below */
> fdt32_t size_dt_struct; /* size of the structure block */
> +
> + /* version 18 fields below */
> + fdt32_t dt_flags; /* Ored value of FDT_FLAG_XXXX */
> };
>
> struct fdt_reserve_entry {
> @@ -65,6 +68,6 @@ struct fdt_property {
> #define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t))
> #define FDT_V16_SIZE FDT_V3_SIZE
> #define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t))
> -#define FDT_V18_SIZE FDT_V17_SIZE
> +#define FDT_V18_SIZE (FDT_V17_SIZE + sizeof(fdt32_t))
>
> #endif /* FDT_H */
> diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c
> index 00e32bb..1528b33 100644
> --- a/libfdt/fdt_rw.c
> +++ b/libfdt/fdt_rw.c
> @@ -457,6 +457,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
> return err;
> fdt_set_version(buf, 18);
> fdt_set_last_comp_version(buf, 18);
> + if (can_assume(LATEST) || fdt_version(fdt) < 18)
> + fdt_set_dt_flags(buf, 0);
> fdt_set_size_dt_struct(buf, struct_size);
> fdt_set_totalsize(buf, bufsize);
> return 0;
> @@ -487,6 +489,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
> fdt_set_totalsize(buf, bufsize);
> fdt_set_version(buf, 18);
> fdt_set_last_comp_version(buf, 18);
> + if (can_assume(LATEST) || fdt_version(fdt) < 18)
> + fdt_set_dt_flags(buf, 0);
> fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
>
> return 0;
> diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h
> index d1a9cd5..9777f32 100644
> --- a/libfdt/libfdt.h
> +++ b/libfdt/libfdt.h
> @@ -319,6 +319,7 @@ fdt_set_hdr_(last_comp_version)
> fdt_set_hdr_(boot_cpuid_phys)
> fdt_set_hdr_(size_dt_strings)
> fdt_set_hdr_(size_dt_struct)
> +fdt_set_hdr_(dt_flags)
> #undef fdt_set_hdr_
>
> /**
> diff --git a/tests/pylibfdt_tests.py b/tests/pylibfdt_tests.py
> index 373e11a..7d5ab0b 100644
> --- a/tests/pylibfdt_tests.py
> +++ b/tests/pylibfdt_tests.py
> @@ -285,9 +285,9 @@ class PyLibfdtBasicTests(unittest.TestCase):
> """Test that we can access the header values"""
> self.assertEqual(self.fdt.magic(), 0xd00dfeed)
> self.assertEqual(self.fdt.totalsize(), len(self.fdt._fdt))
> - self.assertEqual(self.fdt.off_dt_struct(), 88)
> - self.assertEqual(self.fdt.off_dt_strings(), 652)
> - self.assertEqual(self.fdt.off_mem_rsvmap(), 40)
> + self.assertEqual(self.fdt.off_dt_struct(), 96)
> + self.assertEqual(self.fdt.off_dt_strings(), 660)
> + self.assertEqual(self.fdt.off_mem_rsvmap(), 48)
> self.assertEqual(self.fdt.version(), 18)
> self.assertEqual(self.fdt.last_comp_version(), 16)
> self.assertEqual(self.fdt.boot_cpuid_phys(), 0)
> diff --git a/tests/testutils.c b/tests/testutils.c
> index 54da2e4..2d5cfb3 100644
> --- a/tests/testutils.c
> +++ b/tests/testutils.c
> @@ -344,7 +344,7 @@ void *open_blob_rw(const void *blob)
> {
> int err;
> void *buf;
> - int newsize = fdt_totalsize(blob) + 8;
> + int newsize = fdt_totalsize(blob) + 8 + 4;
Kind of pre-existing, but a comment explaining where the 8 and the 4
come from would be nice.
> buf = xmalloc(newsize);
> err = fdt_open_into(blob, buf, newsize);
> diff --git a/tests/trees.S b/tests/trees.S
> index ecd43bc..56c1002 100644
> --- a/tests/trees.S
> +++ b/tests/trees.S
> @@ -22,6 +22,7 @@
> fdtlong 0
> fdtlong (\tree\()_strings_end - \tree\()_strings)
> fdtlong (\tree\()_struct_end - \tree\()_struct)
> + fdtlong 0
> .endm
>
> .macro rsvmape addrh, addrl, lenh, lenl
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 14/77] tests: metadata: Add a first test related to the dt_flags header field
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (12 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 13/77] Introduce dt_flags field in dtb header Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 15/77] Add support for /addon/ keyword Herve Codina
` (65 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
A new field has been recently added to the dtb header: dt_flags.
Even if this field is not yet used to encode meaningful information,
add a basic test related to this field (presence and its 0 default
value).
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
tests/metadata_dtflags0.dtb.expect | 1 +
tests/metadata_dtflags0.dts | 10 ++++++++++
tests/run_tests.sh | 6 ++++++
3 files changed, 17 insertions(+)
create mode 100644 tests/metadata_dtflags0.dtb.expect
create mode 100644 tests/metadata_dtflags0.dts
diff --git a/tests/metadata_dtflags0.dtb.expect b/tests/metadata_dtflags0.dtb.expect
new file mode 100644
index 0000000..cefed4d
--- /dev/null
+++ b/tests/metadata_dtflags0.dtb.expect
@@ -0,0 +1 @@
+// dt_flags: 0x0
diff --git a/tests/metadata_dtflags0.dts b/tests/metadata_dtflags0.dts
new file mode 100644
index 0000000..3ef867e
--- /dev/null
+++ b/tests/metadata_dtflags0.dts
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+
+/ {
+ prop = <1>;
+};
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 423812e..496fcb9 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1141,6 +1141,12 @@ metadata_tests() {
sed -i '/^\/\/ /d' $dt.dtb.dts.dtb.out
base_run_test check_diff $dt.dtb.dts.dtb.out "$SRCDIR/$dt.dtb.expect"
done
+
+ run_dtc_test -I dts -O dtb -o metadata_dtflags0.dtb "$SRCDIR/metadata_dtflags0.dts"
+ base_run_test wrap_fdtdump metadata_dtflags0.dtb metadata_dtflags0.dtb.out
+ # Keep only lines containing 'dt_flags'
+ sed -i '/dt_flags/!d' metadata_dtflags0.dtb.out
+ base_run_test check_diff metadata_dtflags0.dtb.out "$SRCDIR/metadata_dtflags0.dtb.expect"
}
pylibfdt_tests () {
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 15/77] Add support for /addon/ keyword
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (13 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 14/77] tests: metadata: Add a first test related to the dt_flags header field Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 16/77] tests: metadata: Add a test related to addon dt_flags header value Herve Codina
` (64 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The dts /addon/ keyword allows to mark a dts as an addon dts.
This is similar to /plugin/ used for overlay dts but specific to addon
dts.
It is also worth noting that a dts tagged with /addon/ will lead to a
dtb with the dt_flags set to FDT_FLAG_ADDON (0x1).
This allows to identify without any ambiguity an addon dts and an addon
dtb.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
checks.c | 26 +++++++++++++-------------
dtc-lexer.l | 5 +++++
dtc-parser.y | 5 +++++
dtc.h | 1 +
fdtdump.c | 6 +++++-
flattree.c | 18 ++++++++++++++----
libfdt/fdt.h | 1 +
libfdt/libfdt.h | 1 +
treesource.c | 5 ++++-
9 files changed, 49 insertions(+), 19 deletions(-)
diff --git a/checks.c b/checks.c
index 041e565..2be19c0 100644
--- a/checks.c
+++ b/checks.c
@@ -616,7 +616,7 @@ static void fixup_phandle_references(struct check *c, struct dt_info *dti,
refnode = get_node_by_ref(dt, m->ref);
if (! refnode) {
- if (!(dti->dtsflags & DTSF_PLUGIN))
+ if (!(dti->dtsflags & (DTSF_PLUGIN | DTSF_ADDON)))
FAIL(c, dti, node, "Reference to non-existent node or "
"label \"%s\"\n", m->ref);
else /* mark the entry as unresolved */
@@ -718,8 +718,8 @@ static void check_alias_paths(struct check *c, struct dt_info *dti,
continue;
}
- /* This check does not work for overlays with external paths */
- if (!(dti->dtsflags & DTSF_PLUGIN) &&
+ /* This check does not work for overlays nor addons with external paths */
+ if (!(dti->dtsflags & (DTSF_PLUGIN | DTSF_ADDON)) &&
(!prop->val.val || !get_node_by_path(dti->dt, prop->val.val))) {
FAIL_PROP(c, dti, node, prop, "aliases property is not a valid node (%s)",
prop->val.val);
@@ -1417,8 +1417,8 @@ static void check_property_phandle_args(struct check *c,
* entries when each index position has a specific definition.
*/
if (!phandle_is_valid(phandle)) {
- /* Give up if this is an overlay with external references */
- if (dti->dtsflags & DTSF_PLUGIN)
+ /* Give up if this is an overlay or addon with external references */
+ if (dti->dtsflags & (DTSF_PLUGIN | DTSF_ADDON))
break;
cellsize = 0;
@@ -1651,8 +1651,8 @@ static void check_interrupt_map(struct check *c,
phandle = propval_cell_n(irq_map_prop, cell);
if (!phandle_is_valid(phandle)) {
- /* Give up if this is an overlay with external references */
- if (!(dti->dtsflags & DTSF_PLUGIN))
+ /* Give up if this is an overlay or an addon with external references */
+ if (!(dti->dtsflags & (DTSF_PLUGIN | DTSF_ADDON)))
FAIL_PROP(c, dti, node, irq_map_prop,
"Cell %zu is not a phandle(%d)",
cell, phandle);
@@ -1720,9 +1720,9 @@ static void check_interrupts_property(struct check *c,
if (prop) {
phandle = propval_cell(prop);
if (!phandle_is_valid(phandle)) {
- /* Give up if this is an overlay with
+ /* Give up if this is an overlay with or an addon
* external references */
- if (dti->dtsflags & DTSF_PLUGIN)
+ if (dti->dtsflags & (DTSF_PLUGIN | DTSF_ADDON))
return;
FAIL_PROP(c, dti, parent, prop, "Invalid phandle");
continue;
@@ -1838,8 +1838,8 @@ static void check_graph_port(struct check *c, struct dt_info *dti,
check_graph_reg(c, dti, node);
- /* skip checks below for overlays */
- if (dti->dtsflags & DTSF_PLUGIN)
+ /* skip checks below for overlays or addons */
+ if (dti->dtsflags & (DTSF_PLUGIN | DTSF_ADDON))
return;
if (!strprefixeq(node->name, node->basenamelen, "port"))
@@ -1880,8 +1880,8 @@ static void check_graph_endpoint(struct check *c, struct dt_info *dti,
check_graph_reg(c, dti, node);
- /* skip checks below for overlays */
- if (dti->dtsflags & DTSF_PLUGIN)
+ /* skip checks below for overlays or addons */
+ if (dti->dtsflags & (DTSF_PLUGIN | DTSF_ADDON))
return;
if (!strprefixeq(node->name, node->basenamelen, "endpoint"))
diff --git a/dtc-lexer.l b/dtc-lexer.l
index 15d585c..a4a8e0b 100644
--- a/dtc-lexer.l
+++ b/dtc-lexer.l
@@ -111,6 +111,11 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
return DT_PLUGIN;
}
+<*>"/addon/" {
+ DPRINT("Keyword: /addon/\n");
+ return DT_ADDON;
+ }
+
<*>"/memreserve/" {
DPRINT("Keyword: /memreserve/\n");
BEGIN_DEFAULT();
diff --git a/dtc-parser.y b/dtc-parser.y
index 4d5eece..d8914d2 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -53,6 +53,7 @@ static bool is_ref_relative(const char *ref)
%token DT_V1
%token DT_PLUGIN
+%token DT_ADDON
%token DT_MEMRESERVE
%token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
%token DT_BITS
@@ -120,6 +121,10 @@ header:
{
$$ = DTSF_V1 | DTSF_PLUGIN;
}
+ | DT_V1 ';' DT_ADDON ';'
+ {
+ $$ = DTSF_V1 | DTSF_ADDON;
+ }
;
headers:
diff --git a/dtc.h b/dtc.h
index 08c9f07..c0fffd2 100644
--- a/dtc.h
+++ b/dtc.h
@@ -336,6 +336,7 @@ struct dt_info {
/* DTS version flags definitions */
#define DTSF_V1 0x0001 /* /dts-v1/ */
#define DTSF_PLUGIN 0x0002 /* /plugin/ */
+#define DTSF_ADDON 0x0004 /* /addon/ */
struct dt_info *build_dt_info(unsigned int dtsflags,
struct reserve_info *reservelist,
diff --git a/fdtdump.c b/fdtdump.c
index 5c78559..9b6f41a 100644
--- a/fdtdump.c
+++ b/fdtdump.c
@@ -67,7 +67,6 @@ static void dump_blob(void *blob, bool debug)
depth = 0;
shift = 4;
- printf("/dts-v1/;\n");
printf("// magic:\t\t0x%"PRIx32"\n", fdt32_to_cpu(bph->magic));
printf("// totalsize:\t\t0x%"PRIx32" (%"PRIu32")\n",
totalsize, totalsize);
@@ -91,6 +90,11 @@ static void dump_blob(void *blob, bool debug)
printf("// dt_flags:\t\t0x%"PRIx32"\n",
fdt32_to_cpu(bph->dt_flags));
}
+ printf("/dts-v1/;\n");
+ if (version >= 18) {
+ if (fdt32_to_cpu(bph->dt_flags) & FDT_FLAG_ADDON)
+ printf("/addon/;\n");
+ }
printf("\n");
for (i = 0; ; i++) {
diff --git a/flattree.c b/flattree.c
index 2e2ffcb..bedb286 100644
--- a/flattree.c
+++ b/flattree.c
@@ -412,6 +412,7 @@ void dt_to_blob(FILE *f, struct dt_info *dti, int version)
struct data dtbuf = empty_data;
struct data strbuf = empty_data;
struct fdt_header fdt;
+ uint32_t dt_flags = 0;
int padlen = 0;
for (i = 0; i < ARRAY_SIZE(version_table); i++) {
@@ -421,6 +422,8 @@ void dt_to_blob(FILE *f, struct dt_info *dti, int version)
if (!vi)
die("Unknown device tree blob version %d\n", version);
+ dt_flags |= dti->dtsflags & DTSF_ADDON ? FDT_FLAG_ADDON : 0;
+
flatten_tree(dti->dt, &bin_emitter, &dtbuf, &strbuf, vi);
bin_emit_cell(&dtbuf, FDT_END);
@@ -428,7 +431,7 @@ void dt_to_blob(FILE *f, struct dt_info *dti, int version)
/* Make header */
make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
- dti->boot_cpuid_phys, 0);
+ dti->boot_cpuid_phys, dt_flags);
/*
* If the user asked for more space than is used, adjust the totalsize.
@@ -511,6 +514,7 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
struct data strbuf = empty_data;
struct reserve_info *re;
const char *symprefix = "dt";
+ uint32_t dt_flags = 0;
for (i = 0; i < ARRAY_SIZE(version_table); i++) {
if (version_table[i].version == version)
@@ -519,6 +523,8 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
if (!vi)
die("Unknown device tree blob version %d\n", version);
+ dt_flags |= dti->dtsflags & DTSF_ADDON ? FDT_FLAG_ADDON : 0;
+
fprintf(f, "/* autogenerated by dtc, do not edit */\n\n");
emit_label(f, symprefix, "blob_start");
@@ -561,7 +567,7 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
if (vi->flags & FTF_DTFLAGS) {
fprintf(f, "\t/* dt_flags */\n");
- asm_emit_cell(f, 0);
+ asm_emit_cell(f, dt_flags);
}
/*
@@ -897,6 +903,7 @@ struct dt_info *dt_from_blob(const char *fname)
struct node *tree;
uint32_t val;
int flags = 0;
+ unsigned int dtsflags = 0;
f = srcfile_relative_open(fname, NULL);
@@ -988,8 +995,11 @@ struct dt_info *dt_from_blob(const char *fname)
flags |= FTF_NOPS;
}
- if (version >= 18)
+ if (version >= 18) {
flags |= FTF_REF_XXX | FTF_DTFLAGS;
+ dtsflags |= fdt32_to_cpu(fdt->dt_flags) & FDT_FLAG_ADDON ?
+ DTSF_ADDON : 0;
+ }
inbuf_init(&memresvbuf,
blob + off_mem_rsvmap, blob + totalsize);
@@ -1012,5 +1022,5 @@ struct dt_info *dt_from_blob(const char *fname)
fclose(f);
- return build_dt_info(DTSF_V1, reservelist, tree, boot_cpuid_phys);
+ return build_dt_info(DTSF_V1 | dtsflags, reservelist, tree, boot_cpuid_phys);
}
diff --git a/libfdt/fdt.h b/libfdt/fdt.h
index 128e7bc..94f65e6 100644
--- a/libfdt/fdt.h
+++ b/libfdt/fdt.h
@@ -51,6 +51,7 @@ struct fdt_property {
#endif /* !__ASSEMBLER__ */
#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
+#define FDT_FLAG_ADDON 0x1
#define FDT_TAGSIZE sizeof(fdt32_t)
#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h
index 9777f32..37459a6 100644
--- a/libfdt/libfdt.h
+++ b/libfdt/libfdt.h
@@ -302,6 +302,7 @@ int fdt_next_subnode(const void *fdt, int offset);
#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys))
#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings))
#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct))
+#define fdt_dt_flags(fdt) (fdt_get_header(fdt, dt_flags))
#define fdt_set_hdr_(name) \
static inline void fdt_set_##name(void *fdt, uint32_t val) \
diff --git a/treesource.c b/treesource.c
index d25f01f..1db6390 100644
--- a/treesource.c
+++ b/treesource.c
@@ -369,7 +369,10 @@ void dt_to_source(FILE *f, struct dt_info *dti)
{
struct reserve_info *re;
- fprintf(f, "/dts-v1/;\n\n");
+ fprintf(f, "/dts-v1/;\n");
+ if (dti->dtsflags & DTSF_ADDON)
+ fprintf(f, "/addon/;\n");
+ fprintf(f, "\n");
for (re = dti->reservelist; re; re = re->next) {
struct label *l;
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 16/77] tests: metadata: Add a test related to addon dt_flags header value
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (14 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 15/77] Add support for /addon/ keyword Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 17/77] tests: metadata: Add a basic addon test Herve Codina
` (63 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Addon dtbs leads to the dt_flags header field set to FDT_FLAG_ADDON
(0x1).
Add a specific test to check this value.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
tests/metadata_dtflags1.dtb.expect | 1 +
tests/metadata_dtflags1.dts | 11 +++++++++++
tests/run_tests.sh | 6 ++++++
3 files changed, 18 insertions(+)
create mode 100644 tests/metadata_dtflags1.dtb.expect
create mode 100644 tests/metadata_dtflags1.dts
diff --git a/tests/metadata_dtflags1.dtb.expect b/tests/metadata_dtflags1.dtb.expect
new file mode 100644
index 0000000..00f98f3
--- /dev/null
+++ b/tests/metadata_dtflags1.dtb.expect
@@ -0,0 +1 @@
+// dt_flags: 0x1
diff --git a/tests/metadata_dtflags1.dts b/tests/metadata_dtflags1.dts
new file mode 100644
index 0000000..d2b2295
--- /dev/null
+++ b/tests/metadata_dtflags1.dts
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+/addon/;
+
+/ {
+ prop = <1>;
+};
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 496fcb9..688d81d 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1147,6 +1147,12 @@ metadata_tests() {
# Keep only lines containing 'dt_flags'
sed -i '/dt_flags/!d' metadata_dtflags0.dtb.out
base_run_test check_diff metadata_dtflags0.dtb.out "$SRCDIR/metadata_dtflags0.dtb.expect"
+
+ run_dtc_test -I dts -O dtb -o metadata_dtflags1.dtb "$SRCDIR/metadata_dtflags1.dts"
+ base_run_test wrap_fdtdump metadata_dtflags1.dtb metadata_dtflags1.dtb.out
+ # Keep only lines containing 'dt_flags'
+ sed -i '/dt_flags/!d' metadata_dtflags1.dtb.out
+ base_run_test check_diff metadata_dtflags1.dtb.out "$SRCDIR/metadata_dtflags1.dtb.expect"
}
pylibfdt_tests () {
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 17/77] tests: metadata: Add a basic addon test
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (15 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 16/77] tests: metadata: Add a test related to addon dt_flags header value Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 18/77] dtc-parser.y: Avoid an empty proplist Herve Codina
` (62 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Support for addon dts (/addon/ keyword) and addon dtb (FDT_FLAG_ADDON
header flag) have been recently introduced.
Even if the FDT_FLAG_ADDON dtb flag itself has its own test already
available, add a basic addon test in the metadata 'dts->dts and
dts->dtb->dts' test patterns to check that addon dts/dtb are
handled correctly.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
tests/metadata_addon_base.dtb.dts.expect | 10 ++++++++++
tests/metadata_addon_base.dtb.expect | 10 ++++++++++
tests/metadata_addon_base.dts | 14 ++++++++++++++
tests/metadata_addon_base.dts.dts.expect | 10 ++++++++++
tests/run_tests.sh | 3 ++-
5 files changed, 46 insertions(+), 1 deletion(-)
create mode 100644 tests/metadata_addon_base.dtb.dts.expect
create mode 100644 tests/metadata_addon_base.dtb.expect
create mode 100644 tests/metadata_addon_base.dts
create mode 100644 tests/metadata_addon_base.dts.dts.expect
diff --git a/tests/metadata_addon_base.dtb.dts.expect b/tests/metadata_addon_base.dtb.dts.expect
new file mode 100644
index 0000000..739f9db
--- /dev/null
+++ b/tests/metadata_addon_base.dtb.dts.expect
@@ -0,0 +1,10 @@
+/dts-v1/;
+/addon/;
+
+/ {
+
+ node-a {
+ prop = <0x01>;
+ ref-base = <&base>;
+ };
+};
diff --git a/tests/metadata_addon_base.dtb.expect b/tests/metadata_addon_base.dtb.expect
new file mode 100644
index 0000000..6c2a89a
--- /dev/null
+++ b/tests/metadata_addon_base.dtb.expect
@@ -0,0 +1,10 @@
+/dts-v1/;
+/addon/;
+
+/ {
+ node-a {
+ prop = <0x00000001>;
+ ref-base = <0xffffffff>;
+ // [FDT_REF_PHANDLE] ref-base[0], ref = base
+ };
+};
diff --git a/tests/metadata_addon_base.dts b/tests/metadata_addon_base.dts
new file mode 100644
index 0000000..5e29cef
--- /dev/null
+++ b/tests/metadata_addon_base.dts
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+/addon/;
+
+/ {
+ node-a {
+ prop = <1>;
+ ref-base = <&base>;
+ };
+};
diff --git a/tests/metadata_addon_base.dts.dts.expect b/tests/metadata_addon_base.dts.dts.expect
new file mode 100644
index 0000000..739f9db
--- /dev/null
+++ b/tests/metadata_addon_base.dts.dts.expect
@@ -0,0 +1,10 @@
+/dts-v1/;
+/addon/;
+
+/ {
+
+ node-a {
+ prop = <0x01>;
+ ref-base = <&base>;
+ };
+};
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 688d81d..def1a7e 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1125,7 +1125,8 @@ wrap_fdtdump () {
}
metadata_tests() {
- for dt in metadata_reflocal metadata_refphandle; do
+ for dt in metadata_reflocal metadata_refphandle \
+ metadata_addon_base; do
run_dtc_test -I dts -O dts -o $dt.dts.dts "$SRCDIR/$dt.dts"
base_run_test check_diff $dt.dts.dts "$SRCDIR/$dt.dts.dts.expect"
run_dtc_test -I dts -O dtb -o $dt.dtb "$SRCDIR/$dt.dts"
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 18/77] dtc-parser.y: Avoid an empty proplist
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (16 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 17/77] tests: metadata: Add a basic addon test Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-15 1:34 ` David Gibson
2026-01-12 14:19 ` [RFC PATCH 19/77] dtc: Introduce export symbols Herve Codina
` (61 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
In the dts parser grammar, a nodedef is defined by
'{' proplist subnodes '}' ';'
with both proplist and subnodes that can be empty lists.
Soon a new list will be added in the nodedef related to export symbol
list.
Having all those lists with support for empty lists will lead to some
Bison warnings:
warning: 4 shift/reduce conflicts [-Wconflicts-sr]
warning: 1 reduce/reduce conflict [-Wconflicts-rr]
The simpler way to remove those warning and thus have a robust parsing
is to avoid those empty lists.
Update the proplist definition and nodedef definition to avoid those
multiple empty lists. Instead of allowing a proplist to be an empty
list, force the list to be a non empty one and update the nodedef to
handle explicitly the absence of the proplist to support the case where
no properties are available, i.e. the case of a node composed only of
sub-nodes.
This doesn't change the functional behavior.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
dtc-parser.y | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/dtc-parser.y b/dtc-parser.y
index d8914d2..2e152b0 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -272,12 +272,16 @@ nodedef:
{
$$ = build_node($2, $3, &@$);
}
+ | '{' subnodes '}' ';'
+ {
+ $$ = build_node(NULL, $2, &@$);
+ }
;
proplist:
- /* empty */
+ propdef
{
- $$ = NULL;
+ $$ = chain_property($1, NULL);
}
| proplist propdef
{
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 18/77] dtc-parser.y: Avoid an empty proplist
2026-01-12 14:19 ` [RFC PATCH 18/77] dtc-parser.y: Avoid an empty proplist Herve Codina
@ 2026-01-15 1:34 ` David Gibson
2026-01-16 16:22 ` Herve Codina
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-15 1:34 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 2030 bytes --]
On Mon, Jan 12, 2026 at 03:19:08PM +0100, Herve Codina wrote:
> In the dts parser grammar, a nodedef is defined by
> '{' proplist subnodes '}' ';'
> with both proplist and subnodes that can be empty lists.
>
> Soon a new list will be added in the nodedef related to export symbol
> list.
>
> Having all those lists with support for empty lists will lead to some
> Bison warnings:
> warning: 4 shift/reduce conflicts [-Wconflicts-sr]
> warning: 1 reduce/reduce conflict [-Wconflicts-rr]
>
> The simpler way to remove those warning and thus have a robust parsing
> is to avoid those empty lists.
>
> Update the proplist definition and nodedef definition to avoid those
> multiple empty lists. Instead of allowing a proplist to be an empty
> list, force the list to be a non empty one and update the nodedef to
> handle explicitly the absence of the proplist to support the case where
> no properties are available, i.e. the case of a node composed only of
> sub-nodes.
>
> This doesn't change the functional behavior.
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
I think it makes sense to apply this on its own before the rest of the
series, but the commit message will want rewording for that context.
> ---
> dtc-parser.y | 8 ++++++--
> 1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/dtc-parser.y b/dtc-parser.y
> index d8914d2..2e152b0 100644
> --- a/dtc-parser.y
> +++ b/dtc-parser.y
> @@ -272,12 +272,16 @@ nodedef:
> {
> $$ = build_node($2, $3, &@$);
> }
> + | '{' subnodes '}' ';'
> + {
> + $$ = build_node(NULL, $2, &@$);
> + }
> ;
>
> proplist:
> - /* empty */
> + propdef
> {
> - $$ = NULL;
> + $$ = chain_property($1, NULL);
> }
> | proplist propdef
> {
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 18/77] dtc-parser.y: Avoid an empty proplist
2026-01-15 1:34 ` David Gibson
@ 2026-01-16 16:22 ` Herve Codina
0 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-16 16:22 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
Hi David,
On Thu, 15 Jan 2026 12:34:19 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
...
>
> I think it makes sense to apply this on its own before the rest of the
> series, but the commit message will want rewording for that context.
>
I will do this rewording and I will move the patch at the begining of the
series in the next iteration.
Best regards,
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 19/77] dtc: Introduce export symbols
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (17 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 18/77] dtc-parser.y: Avoid an empty proplist Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-15 5:52 ` David Gibson
2026-01-12 14:19 ` [RFC PATCH 20/77] dtc: Add support for /export/ dts keyword parsing Herve Codina
` (60 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Export symbols allow to define a list of symbols exported at a given
node level. Those exported symbols can be used by an addon when the
addon is applied on the node exporting the symbols. In order to perform
its symbol resolution. Any unresolved phandle value will be resolved
using those exported symbols.
The feature is similar to __symbols__ involved with overlay but while
all symbols are visible with __symbols__, only specific symbols
(exported symbols) are visible with export symbols.
Also an exported symbol has a specific name and this name has to
used for symbol resolution. Having this specific name allows to:
- Have several nodes providing the same exported symbols
name but each of them pointing to different nodes.
Without looking at the detail of the syntax, node-a and node-b
export the same symbol foo but pointing to different node.
node-a {
/* export foo -> /path/foo1 */
};
node-b {
/* export foo -> /path/foo2 */
};
This allow to have the exact same addon referencing 'foo' applied
either on node-a or node-b.
- Have several board describing a well defined node even if resources
needed for exported symbols are not the same.
On board A, the 'ctrl' exported symbols points to some ctrl device
available on the SoC:
node {
/* export 'ctrl' -> /soc/ctrl@1000
};
On board B, the ctrl device used is on a i2c bus
node {
/* export 'ctrl' -> /soc/i2c@5000/ctrl@10
};
The addon can be used on board A and board B without any
modification. It uses 'ctrl' exported by the node the it is applied
to.
Introduce the 'symbol' internal data structure and the export symbol
list related to a node.
No functional change yet but preparation for the future support
for export symbol parsing.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
dtc-parser.y | 6 +++---
dtc.h | 13 ++++++++++++-
flattree.c | 2 +-
fstree.c | 2 +-
livetree.c | 7 ++++---
5 files changed, 21 insertions(+), 9 deletions(-)
diff --git a/dtc-parser.y b/dtc-parser.y
index 2e152b0..9c93673 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -183,7 +183,7 @@ devicetree:
else if (is_ref_relative($1))
ERROR(&@2, "Label-relative reference %s not supported in plugin", $1);
$$ = add_orphan_node(
- name_node(build_node(NULL, NULL, NULL),
+ name_node(build_node(NULL, NULL, NULL, NULL),
""),
$2, $1);
}
@@ -270,11 +270,11 @@ devicetree:
nodedef:
'{' proplist subnodes '}' ';'
{
- $$ = build_node($2, $3, &@$);
+ $$ = build_node($2, $3, NULL, &@$);
}
| '{' subnodes '}' ';'
{
- $$ = build_node(NULL, $2, &@$);
+ $$ = build_node(NULL, $2, NULL, &@$);
}
;
diff --git a/dtc.h b/dtc.h
index c0fffd2..6508694 100644
--- a/dtc.h
+++ b/dtc.h
@@ -204,6 +204,16 @@ struct label {
struct label *next;
};
+struct symbol {
+ bool is_local;
+ char *name;
+ char *ref;
+ cell_t phandle;
+ char *fullpath;
+ struct symbol *next;
+ struct srcpos *srcpos;
+};
+
struct bus_type {
const char *name;
};
@@ -224,6 +234,7 @@ struct node {
char *name;
struct property *proplist;
struct node *children;
+ struct symbol *exportsymlist;
struct node *parent;
struct node *next_sibling;
@@ -272,7 +283,7 @@ struct property *chain_property(struct property *first, struct property *list);
struct property *reverse_properties(struct property *first);
struct node *build_node(struct property *proplist, struct node *children,
- struct srcpos *srcpos);
+ struct symbol *exportsymlist, struct srcpos *srcpos);
struct node *build_node_delete(struct srcpos *srcpos);
struct node *name_node(struct node *node, const char *name);
struct node *omit_node_if_unused(struct node *node);
diff --git a/flattree.c b/flattree.c
index bedb286..36b795d 100644
--- a/flattree.c
+++ b/flattree.c
@@ -809,7 +809,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
uint32_t offset;
const char *str;
- node = build_node(NULL, NULL, NULL);
+ node = build_node(NULL, NULL, NULL, NULL);
flatname = flat_read_string(dtbuf);
diff --git a/fstree.c b/fstree.c
index 0f9a534..445ae53 100644
--- a/fstree.c
+++ b/fstree.c
@@ -19,7 +19,7 @@ static struct node *read_fstree(const char *dirname)
if (!d)
die("Couldn't opendir() \"%s\": %s\n", dirname, strerror(errno));
- tree = build_node(NULL, NULL, NULL);
+ tree = build_node(NULL, NULL, NULL, NULL);
while ((de = readdir(d)) != NULL) {
char *tmpname;
diff --git a/livetree.c b/livetree.c
index 2a0a7ed..0050492 100644
--- a/livetree.c
+++ b/livetree.c
@@ -86,7 +86,7 @@ struct property *reverse_properties(struct property *first)
}
struct node *build_node(struct property *proplist, struct node *children,
- struct srcpos *srcpos)
+ struct symbol *exportsymlist, struct srcpos *srcpos)
{
struct node *new = xmalloc(sizeof(*new));
struct node *child;
@@ -95,6 +95,7 @@ struct node *build_node(struct property *proplist, struct node *children,
new->proplist = reverse_properties(proplist);
new->children = children;
+ new->exportsymlist = exportsymlist;
new->srcpos = srcpos_copy(srcpos);
for_each_child(new, child) {
@@ -248,7 +249,7 @@ struct node * add_orphan_node(struct node *dt, struct node *new_node, char *ref)
xasprintf(&name, "fragment@%u",
next_orphan_fragment++);
name_node(new_node, "__overlay__");
- node = build_node(p, new_node, NULL);
+ node = build_node(p, new_node, NULL, NULL);
name_node(node, name);
free(name);
@@ -892,7 +893,7 @@ static struct node *build_and_name_child_node(struct node *parent, const char *n
{
struct node *node;
- node = build_node(NULL, NULL, NULL);
+ node = build_node(NULL, NULL, NULL, NULL);
name_node(node, name);
add_child(parent, node);
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 19/77] dtc: Introduce export symbols
2026-01-12 14:19 ` [RFC PATCH 19/77] dtc: Introduce export symbols Herve Codina
@ 2026-01-15 5:52 ` David Gibson
2026-01-16 16:27 ` Herve Codina
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-15 5:52 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 7097 bytes --]
On Mon, Jan 12, 2026 at 03:19:09PM +0100, Herve Codina wrote:
> Export symbols allow to define a list of symbols exported at a given
> node level. Those exported symbols can be used by an addon when the
> addon is applied on the node exporting the symbols.
This seems to imply an addon always applies at a single node location.
I'm not sure that's a good design choice, since I don't see how it
covers the case of something that connects to several connectors.
> In order to perform
> its symbol resolution. Any unresolved phandle value will be resolved
> using those exported symbols.
>
> The feature is similar to __symbols__ involved with overlay but while
> all symbols are visible with __symbols__, only specific symbols
> (exported symbols) are visible with export symbols.
This paragraph doesn't make sense to me. What's a "symbol" if it's
not something in __symbols__ or export symbols?
> Also an exported symbol has a specific name and this name has to
> used for symbol resolution. Having this specific name allows to:
>
> - Have several nodes providing the same exported symbols
> name but each of them pointing to different nodes.
That's not a property of having a specific name, that's a property of
being local to a node.
> Without looking at the detail of the syntax, node-a and node-b
> export the same symbol foo but pointing to different node.
> node-a {
> /* export foo -> /path/foo1 */
> };
> node-b {
> /* export foo -> /path/foo2 */
> };
>
> This allow to have the exact same addon referencing 'foo' applied
> either on node-a or node-b.
>
> - Have several board describing a well defined node even if resources
> needed for exported symbols are not the same.
>
> On board A, the 'ctrl' exported symbols points to some ctrl device
> available on the SoC:
> node {
> /* export 'ctrl' -> /soc/ctrl@1000
> };
>
> On board B, the ctrl device used is on a i2c bus
> node {
> /* export 'ctrl' -> /soc/i2c@5000/ctrl@10
> };
>
> The addon can be used on board A and board B without any
> modification. It uses 'ctrl' exported by the node the it is applied
> to.
>
> Introduce the 'symbol' internal data structure and the export symbol
> list related to a node.
>
> No functional change yet but preparation for the future support
> for export symbol parsing.
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> dtc-parser.y | 6 +++---
> dtc.h | 13 ++++++++++++-
> flattree.c | 2 +-
> fstree.c | 2 +-
> livetree.c | 7 ++++---
> 5 files changed, 21 insertions(+), 9 deletions(-)
>
> diff --git a/dtc-parser.y b/dtc-parser.y
> index 2e152b0..9c93673 100644
> --- a/dtc-parser.y
> +++ b/dtc-parser.y
> @@ -183,7 +183,7 @@ devicetree:
> else if (is_ref_relative($1))
> ERROR(&@2, "Label-relative reference %s not supported in plugin", $1);
> $$ = add_orphan_node(
> - name_node(build_node(NULL, NULL, NULL),
> + name_node(build_node(NULL, NULL, NULL, NULL),
> ""),
> $2, $1);
> }
> @@ -270,11 +270,11 @@ devicetree:
> nodedef:
> '{' proplist subnodes '}' ';'
> {
> - $$ = build_node($2, $3, &@$);
> + $$ = build_node($2, $3, NULL, &@$);
> }
> | '{' subnodes '}' ';'
> {
> - $$ = build_node(NULL, $2, &@$);
> + $$ = build_node(NULL, $2, NULL, &@$);
> }
> ;
>
> diff --git a/dtc.h b/dtc.h
> index c0fffd2..6508694 100644
> --- a/dtc.h
> +++ b/dtc.h
> @@ -204,6 +204,16 @@ struct label {
> struct label *next;
> };
>
> +struct symbol {
> + bool is_local;
> + char *name;
> + char *ref;
> + cell_t phandle;
> + char *fullpath;
> + struct symbol *next;
> + struct srcpos *srcpos;
> +};
> +
> struct bus_type {
> const char *name;
> };
> @@ -224,6 +234,7 @@ struct node {
> char *name;
> struct property *proplist;
> struct node *children;
> + struct symbol *exportsymlist;
>
> struct node *parent;
> struct node *next_sibling;
> @@ -272,7 +283,7 @@ struct property *chain_property(struct property *first, struct property *list);
> struct property *reverse_properties(struct property *first);
>
> struct node *build_node(struct property *proplist, struct node *children,
> - struct srcpos *srcpos);
> + struct symbol *exportsymlist, struct srcpos *srcpos);
> struct node *build_node_delete(struct srcpos *srcpos);
> struct node *name_node(struct node *node, const char *name);
> struct node *omit_node_if_unused(struct node *node);
> diff --git a/flattree.c b/flattree.c
> index bedb286..36b795d 100644
> --- a/flattree.c
> +++ b/flattree.c
> @@ -809,7 +809,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
> uint32_t offset;
> const char *str;
>
> - node = build_node(NULL, NULL, NULL);
> + node = build_node(NULL, NULL, NULL, NULL);
>
> flatname = flat_read_string(dtbuf);
>
> diff --git a/fstree.c b/fstree.c
> index 0f9a534..445ae53 100644
> --- a/fstree.c
> +++ b/fstree.c
> @@ -19,7 +19,7 @@ static struct node *read_fstree(const char *dirname)
> if (!d)
> die("Couldn't opendir() \"%s\": %s\n", dirname, strerror(errno));
>
> - tree = build_node(NULL, NULL, NULL);
> + tree = build_node(NULL, NULL, NULL, NULL);
>
> while ((de = readdir(d)) != NULL) {
> char *tmpname;
> diff --git a/livetree.c b/livetree.c
> index 2a0a7ed..0050492 100644
> --- a/livetree.c
> +++ b/livetree.c
> @@ -86,7 +86,7 @@ struct property *reverse_properties(struct property *first)
> }
>
> struct node *build_node(struct property *proplist, struct node *children,
> - struct srcpos *srcpos)
> + struct symbol *exportsymlist, struct srcpos *srcpos)
> {
> struct node *new = xmalloc(sizeof(*new));
> struct node *child;
> @@ -95,6 +95,7 @@ struct node *build_node(struct property *proplist, struct node *children,
>
> new->proplist = reverse_properties(proplist);
> new->children = children;
> + new->exportsymlist = exportsymlist;
> new->srcpos = srcpos_copy(srcpos);
>
> for_each_child(new, child) {
> @@ -248,7 +249,7 @@ struct node * add_orphan_node(struct node *dt, struct node *new_node, char *ref)
> xasprintf(&name, "fragment@%u",
> next_orphan_fragment++);
> name_node(new_node, "__overlay__");
> - node = build_node(p, new_node, NULL);
> + node = build_node(p, new_node, NULL, NULL);
> name_node(node, name);
> free(name);
>
> @@ -892,7 +893,7 @@ static struct node *build_and_name_child_node(struct node *parent, const char *n
> {
> struct node *node;
>
> - node = build_node(NULL, NULL, NULL);
> + node = build_node(NULL, NULL, NULL, NULL);
> name_node(node, name);
> add_child(parent, node);
>
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 19/77] dtc: Introduce export symbols
2026-01-15 5:52 ` David Gibson
@ 2026-01-16 16:27 ` Herve Codina
2026-01-19 5:51 ` David Gibson
0 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-16 16:27 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
Hi David,
On Thu, 15 Jan 2026 16:52:26 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Mon, Jan 12, 2026 at 03:19:09PM +0100, Herve Codina wrote:
> > Export symbols allow to define a list of symbols exported at a given
> > node level. Those exported symbols can be used by an addon when the
> > addon is applied on the node exporting the symbols.
>
> This seems to imply an addon always applies at a single node location.
> I'm not sure that's a good design choice, since I don't see how it
> covers the case of something that connects to several connectors.
Apply the addon on a node that knows about those connectors.
>
> > In order to perform
> > its symbol resolution. Any unresolved phandle value will be resolved
> > using those exported symbols.
> >
> > The feature is similar to __symbols__ involved with overlay but while
> > all symbols are visible with __symbols__, only specific symbols
> > (exported symbols) are visible with export symbols.
>
> This paragraph doesn't make sense to me. What's a "symbol" if it's
> not something in __symbols__ or export symbols?
An imported symbols ?
/import/ foo "blabla";
from the addon point of view where this /import/ is present, 'foo' is a
symbol.
>
> > Also an exported symbol has a specific name and this name has to
> > used for symbol resolution. Having this specific name allows to:
> >
> > - Have several nodes providing the same exported symbols
> > name but each of them pointing to different nodes.
>
> That's not a property of having a specific name, that's a property of
> being local to a node.
Yes, exactly. I will reword.
Best regards,
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 19/77] dtc: Introduce export symbols
2026-01-16 16:27 ` Herve Codina
@ 2026-01-19 5:51 ` David Gibson
2026-01-19 13:51 ` Herve Codina
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-19 5:51 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 2903 bytes --]
On Fri, Jan 16, 2026 at 05:27:35PM +0100, Herve Codina wrote:
> Hi David,
>
> On Thu, 15 Jan 2026 16:52:26 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > On Mon, Jan 12, 2026 at 03:19:09PM +0100, Herve Codina wrote:
> > > Export symbols allow to define a list of symbols exported at a given
> > > node level. Those exported symbols can be used by an addon when the
> > > addon is applied on the node exporting the symbols.
> >
> > This seems to imply an addon always applies at a single node location.
> > I'm not sure that's a good design choice, since I don't see how it
> > covers the case of something that connects to several connectors.
>
> Apply the addon on a node that knows about those connectors.
That seems limiting to me, because it requires the base tree to know
about all possible connector combinations, which I'm not sure is
feasible. If I understood Geert(?)'s case properly, there are use
cases where a board might have, say, six "type foo" connectors, and an
addon board could connect to any two of those. Of a board might have
3 "type foo" and 3 "type bar" connectors and an addon board needs to
connect to (any) of each. It seems much more natural to me that at
attach time you say
"addon foo 0 => board foo 1, addon foo 1 => board foo 5"
or "addon foo 0 => board foo 2, addon bar 0 => board bar 1"
Rather than the board itself having to anticipate all combinations.
> > > In order to perform
> > > its symbol resolution. Any unresolved phandle value will be resolved
> > > using those exported symbols.
> > >
> > > The feature is similar to __symbols__ involved with overlay but while
> > > all symbols are visible with __symbols__, only specific symbols
> > > (exported symbols) are visible with export symbols.
> >
> > This paragraph doesn't make sense to me. What's a "symbol" if it's
> > not something in __symbols__ or export symbols?
>
> An imported symbols ?
>
> /import/ foo "blabla";
>
> from the addon point of view where this /import/ is present, 'foo' is a
> symbol.
I guess, but existing plugin stuff doesn't really have imported
symbols, so the example doesn't really illuminate the difference from
the status quo.
> > > Also an exported symbol has a specific name and this name has to
> > > used for symbol resolution. Having this specific name allows to:
> > >
> > > - Have several nodes providing the same exported symbols
> > > name but each of them pointing to different nodes.
> >
> > That's not a property of having a specific name, that's a property of
> > being local to a node.
>
> Yes, exactly. I will reword.
>
> Best regards,
> Hervé
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 19/77] dtc: Introduce export symbols
2026-01-19 5:51 ` David Gibson
@ 2026-01-19 13:51 ` Herve Codina
2026-01-21 2:35 ` David Gibson
0 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-19 13:51 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
Hi David,
On Mon, 19 Jan 2026 16:51:21 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Fri, Jan 16, 2026 at 05:27:35PM +0100, Herve Codina wrote:
> > Hi David,
> >
> > On Thu, 15 Jan 2026 16:52:26 +1100
> > David Gibson <david@gibson.dropbear.id.au> wrote:
> >
> > > On Mon, Jan 12, 2026 at 03:19:09PM +0100, Herve Codina wrote:
> > > > Export symbols allow to define a list of symbols exported at a given
> > > > node level. Those exported symbols can be used by an addon when the
> > > > addon is applied on the node exporting the symbols.
> > >
> > > This seems to imply an addon always applies at a single node location.
> > > I'm not sure that's a good design choice, since I don't see how it
> > > covers the case of something that connects to several connectors.
> >
> > Apply the addon on a node that knows about those connectors.
>
> That seems limiting to me, because it requires the base tree to know
> about all possible connector combinations, which I'm not sure is
> feasible. If I understood Geert(?)'s case properly, there are use
> cases where a board might have, say, six "type foo" connectors, and an
> addon board could connect to any two of those. Of a board might have
> 3 "type foo" and 3 "type bar" connectors and an addon board needs to
> connect to (any) of each. It seems much more natural to me that at
> attach time you say
> "addon foo 0 => board foo 1, addon foo 1 => board foo 5"
> or "addon foo 0 => board foo 2, addon bar 0 => board bar 1"
Who can perform this mapping ?
The user applying the addon if a tool is used such as fdtaddon for instance
(even if this kind of mapping is not yet available in fdtaddon I proposed).
Or a driver that knows about the board connectors.
This driver will apply the addon dtb and provide custom mapping between
symbols expected by the addon (/import/) and symbols provided by the board.
>
> Rather than the board itself having to anticipate all combinations.
>
> > > > In order to perform
> > > > its symbol resolution. Any unresolved phandle value will be resolved
> > > > using those exported symbols.
> > > >
> > > > The feature is similar to __symbols__ involved with overlay but while
> > > > all symbols are visible with __symbols__, only specific symbols
> > > > (exported symbols) are visible with export symbols.
> > >
> > > This paragraph doesn't make sense to me. What's a "symbol" if it's
> > > not something in __symbols__ or export symbols?
> >
> > An imported symbols ?
> >
> > /import/ foo "blabla";
> >
> > from the addon point of view where this /import/ is present, 'foo' is a
> > symbol.
>
> I guess, but existing plugin stuff doesn't really have imported
> symbols, so the example doesn't really illuminate the difference from
> the status quo.
A plugin need to know about all possible symbols available on the board
is applied too. This is the purpose of __symbols__. This just means that for
plugin all possible symbols are imported and symbol translation is not possible.
A plugin is designed for a specific base board. It needs to know about each
busses and how they are wired.
I mean a plugin references i2c5, the i2c controller number 5, and i2c5 needs
to be present in __symbols__.
The target property in __overlay__ identify the target node. Here also, this
is dependent on the board the plugin is applied to.
Addons depend only on the node, describing the connector, they are applied
to. They do not depend on the full specific board where this connector is
available.
Two different boards can have the same connector available and a given board
can have two connectors of the same family the addon can be connected to.
Best regards,
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 19/77] dtc: Introduce export symbols
2026-01-19 13:51 ` Herve Codina
@ 2026-01-21 2:35 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-21 2:35 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 4583 bytes --]
On Mon, Jan 19, 2026 at 02:51:20PM +0100, Herve Codina wrote:
> Hi David,
>
> On Mon, 19 Jan 2026 16:51:21 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > On Fri, Jan 16, 2026 at 05:27:35PM +0100, Herve Codina wrote:
> > > Hi David,
> > >
> > > On Thu, 15 Jan 2026 16:52:26 +1100
> > > David Gibson <david@gibson.dropbear.id.au> wrote:
> > >
> > > > On Mon, Jan 12, 2026 at 03:19:09PM +0100, Herve Codina wrote:
> > > > > Export symbols allow to define a list of symbols exported at a given
> > > > > node level. Those exported symbols can be used by an addon when the
> > > > > addon is applied on the node exporting the symbols.
> > > >
> > > > This seems to imply an addon always applies at a single node location.
> > > > I'm not sure that's a good design choice, since I don't see how it
> > > > covers the case of something that connects to several connectors.
> > >
> > > Apply the addon on a node that knows about those connectors.
> >
> > That seems limiting to me, because it requires the base tree to know
> > about all possible connector combinations, which I'm not sure is
> > feasible. If I understood Geert(?)'s case properly, there are use
> > cases where a board might have, say, six "type foo" connectors, and an
> > addon board could connect to any two of those. Of a board might have
> > 3 "type foo" and 3 "type bar" connectors and an addon board needs to
> > connect to (any) of each. It seems much more natural to me that at
> > attach time you say
> > "addon foo 0 => board foo 1, addon foo 1 => board foo 5"
> > or "addon foo 0 => board foo 2, addon bar 0 => board bar 1"
>
> Who can perform this mapping ?
>
> The user applying the addon if a tool is used such as fdtaddon for instance
> (even if this kind of mapping is not yet available in fdtaddon I proposed).
>
> Or a driver that knows about the board connectors.
Either or. From the point of view of the design, I'm thinking of this
being specified by the "client" - that is by whatever is initiating
the application of the addon. That could come directly from user
input, but in cases where the connectors are sufficiently probable,
something automated could also supply the information.
> This driver will apply the addon dtb and provide custom mapping between
> symbols expected by the addon (/import/) and symbols provided by the board.
>
> >
> > Rather than the board itself having to anticipate all combinations.
> >
> > > > > In order to perform
> > > > > its symbol resolution. Any unresolved phandle value will be resolved
> > > > > using those exported symbols.
> > > > >
> > > > > The feature is similar to __symbols__ involved with overlay but while
> > > > > all symbols are visible with __symbols__, only specific symbols
> > > > > (exported symbols) are visible with export symbols.
> > > >
> > > > This paragraph doesn't make sense to me. What's a "symbol" if it's
> > > > not something in __symbols__ or export symbols?
> > >
> > > An imported symbols ?
> > >
> > > /import/ foo "blabla";
> > >
> > > from the addon point of view where this /import/ is present, 'foo' is a
> > > symbol.
> >
> > I guess, but existing plugin stuff doesn't really have imported
> > symbols, so the example doesn't really illuminate the difference from
> > the status quo.
>
> A plugin need to know about all possible symbols available on the board
> is applied too. This is the purpose of __symbols__. This just means that for
> plugin all possible symbols are imported and symbol translation is not possible.
>
> A plugin is designed for a specific base board. It needs to know about each
> busses and how they are wired.
>
> I mean a plugin references i2c5, the i2c controller number 5, and i2c5 needs
> to be present in __symbols__.
>
> The target property in __overlay__ identify the target node. Here also, this
> is dependent on the board the plugin is applied to.
>
> Addons depend only on the node, describing the connector, they are applied
> to. They do not depend on the full specific board where this connector is
> available.
>
> Two different boards can have the same connector available and a given board
> can have two connectors of the same family the addon can be connected to.
Ok, I think I see what you're getting at.
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 20/77] dtc: Add support for /export/ dts keyword parsing
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (18 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 19/77] dtc: Introduce export symbols Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-15 5:57 ` David Gibson
2026-01-12 14:19 ` [RFC PATCH 21/77] checks: Handle export symbols in fixup_phandle_references() Herve Codina
` (59 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The /export/ dts keyword is the keyword used to define an exported
symbol at a given node level.
This keyword can be present in a node definition (after properties and
before subnodes) to export a symbol. If several symbols need to be
exported, several /export/ keywords are present.
The syntax used is the following:
/export/ name: reference;
with:
name: The name of the exported symbol
reference: The reference of a node the symbol is pointing to.
For instance:
- Reference by label:
/export/ foo: &foo1;
The exported symbol foo references the node identified by
the label foo1.
- Reference by path:
/export/ foo: &{/path/to/foo@100};
The exported symbol foo references the node at /path/to/foo@100.
Add support for /export/ dts keyword.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
dtc-lexer.l | 6 ++++
dtc-parser.y | 53 ++++++++++++++++++++++++++++++++++
dtc.h | 8 ++++++
livetree.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 147 insertions(+)
diff --git a/dtc-lexer.l b/dtc-lexer.l
index a4a8e0b..90fe70e 100644
--- a/dtc-lexer.l
+++ b/dtc-lexer.l
@@ -149,6 +149,12 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
return DT_OMIT_NO_REF;
}
+<*>"/export/" {
+ DPRINT("Keyword: /export/\n");
+ BEGIN_DEFAULT();
+ return DT_EXPORT;
+ }
+
<*>{LABEL}: {
DPRINT("Label: %s\n", yytext);
yylval.labelref = xstrdup(yytext);
diff --git a/dtc-parser.y b/dtc-parser.y
index 9c93673..a0d0aef 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -46,6 +46,8 @@ static bool is_ref_relative(const char *ref)
struct property *proplist;
struct node *node;
struct node *nodelist;
+ struct symbol *symbol;
+ struct symbol *exportlist;
struct reserve_info *re;
uint64_t integer;
unsigned int flags;
@@ -60,6 +62,7 @@ static bool is_ref_relative(const char *ref)
%token DT_DEL_PROP
%token DT_DEL_NODE
%token DT_OMIT_NO_REF
+%token DT_EXPORT
%token <propnodename> DT_PROPNODENAME
%token <integer> DT_LITERAL
%token <integer> DT_CHAR_LITERAL
@@ -80,6 +83,8 @@ static bool is_ref_relative(const char *ref)
%type <data> bytestring
%type <prop> propdef
%type <proplist> proplist
+%type <symbol> exportdef
+%type <exportlist> exportlist
%type <labelref> dt_ref
%type <node> devicetree
@@ -276,6 +281,49 @@ nodedef:
{
$$ = build_node(NULL, $2, NULL, &@$);
}
+ | '{' proplist exportlist subnodes '}' ';'
+ {
+ /*
+ * exportlist is created with chain_symbol() and so it
+ * is created in reverse order. Reverse it now to have
+ * it in correct order
+ */
+ $$ = build_node($2, $4, reverse_symbol($3), &@$);
+ }
+ | '{' exportlist subnodes '}' ';'
+ {
+ /*
+ * exportlist is created with chain_symbol() and so it
+ * is created in reverse order. Reverse it now to have
+ * it in correct order
+ */
+ $$ = build_node(NULL, $3, reverse_symbol($2), &@$);
+ }
+ ;
+
+exportlist:
+ exportdef
+ {
+ $$ = chain_symbol($1, NULL);
+ }
+ | exportlist exportdef
+ {
+ $$ = chain_symbol($2, $1);
+ }
+ | exportlist propdef
+ {
+ ERROR(&@2, "Properties must precede exports");
+ YYERROR;
+ }
+ ;
+
+exportdef:
+ DT_EXPORT DT_LABEL dt_ref ';'
+ {
+ $$ = build_exportsym($2, $3, 0, &@$);
+ free($2);
+ free($3);
+ }
;
proplist:
@@ -576,6 +624,11 @@ subnodes:
ERROR(&@2, "Properties must precede subnodes");
YYERROR;
}
+ | subnode exportdef
+ {
+ ERROR(&@2, "Exports must precede subnodes");
+ YYERROR;
+ }
;
subnode:
diff --git a/dtc.h b/dtc.h
index 6508694..0bf5ba5 100644
--- a/dtc.h
+++ b/dtc.h
@@ -273,6 +273,9 @@ struct node {
for_each_child_withdel(n, c) \
if (!(c)->deleted)
+#define for_each_symbol(s0, s) \
+ for ((s) = (s0); (s); (s) = (s)->next)
+
void add_label(struct label **labels, char *label);
void delete_labels(struct label **labels);
@@ -282,6 +285,11 @@ struct property *build_property_delete(const char *name);
struct property *chain_property(struct property *first, struct property *list);
struct property *reverse_properties(struct property *first);
+struct symbol *build_exportsym(const char *name, const char *ref, cell_t phandle,
+ struct srcpos *srcpos);
+struct symbol *chain_symbol(struct symbol *first, struct symbol *list);
+struct symbol *reverse_symbol(struct symbol *list);
+
struct node *build_node(struct property *proplist, struct node *children,
struct symbol *exportsymlist, struct srcpos *srcpos);
struct node *build_node_delete(struct srcpos *srcpos);
diff --git a/livetree.c b/livetree.c
index 0050492..4458437 100644
--- a/livetree.c
+++ b/livetree.c
@@ -36,6 +36,57 @@ void delete_labels(struct label **labels)
label->deleted = 1;
}
+struct symbol *build_exportsym(const char *name, const char *ref, cell_t phandle,
+ struct srcpos *srcpos)
+{
+ struct symbol *new = xmalloc(sizeof(*new));
+
+ memset(new, 0, sizeof(*new));
+
+ new->name = xstrdup(name);
+ new->ref = ref ? xstrdup(ref) : NULL;
+ new->phandle = phandle;
+ new->srcpos = srcpos_copy(srcpos);
+
+ return new;
+}
+
+struct symbol *chain_symbol(struct symbol *first, struct symbol *list)
+{
+ assert(first->next == NULL);
+
+ first->next = list;
+ return first;
+}
+
+struct symbol *reverse_symbol(struct symbol *list)
+{
+ struct symbol *p = list;
+ struct symbol *head = NULL;
+ struct symbol *next;
+
+ while (p) {
+ next = p->next;
+ p->next = head;
+ head = p;
+ p = next;
+ }
+ return head;
+}
+
+static void add_symbol(struct symbol **list, struct symbol *new)
+{
+ struct symbol **s;
+
+ new->next = NULL;
+
+ s = list;
+ while (*s)
+ s = &((*s)->next);
+
+ *s = new;
+}
+
struct property *build_property(const char *name, struct data val,
struct srcpos *srcpos)
{
@@ -144,6 +195,7 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
{
struct property *new_prop, *old_prop;
struct node *new_child, *old_child;
+ struct symbol *new_sym, *old_sym;
struct label *l;
old_node->deleted = 0;
@@ -217,6 +269,34 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
add_child(old_node, new_child);
}
+ /* Merge exported symbols. If there is a collision, keep the new one */
+ while (new_node->exportsymlist) {
+ /* Pop the symbol off the list */
+ new_sym = new_node->exportsymlist;
+ new_node->exportsymlist = new_sym->next;
+ new_sym->next = NULL;
+
+ /* Look for a collision, set new value if there is */
+ for_each_symbol(old_node->exportsymlist, old_sym) {
+ if (streq(old_sym->name, new_sym->name)) {
+ old_sym->is_local = new_sym->is_local;
+ free(old_sym->ref);
+ old_sym->ref = new_sym->ref;
+ old_sym->phandle = new_sym->phandle;
+ old_sym->fullpath = new_sym->fullpath;
+ srcpos_free(old_sym->srcpos);
+ old_sym->srcpos = new_sym->srcpos;
+ free(new_sym);
+ new_sym = NULL;
+ break;
+ }
+ }
+
+ /* if no collision occurred, add symbol to the old node list. */
+ if (new_sym)
+ add_symbol(&old_node->exportsymlist, new_sym);
+ }
+
old_node->srcpos = srcpos_extend(old_node->srcpos, new_node->srcpos);
/* The new node contents are now merged into the old node. Free
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 20/77] dtc: Add support for /export/ dts keyword parsing
2026-01-12 14:19 ` [RFC PATCH 20/77] dtc: Add support for /export/ dts keyword parsing Herve Codina
@ 2026-01-15 5:57 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-15 5:57 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 8465 bytes --]
On Mon, Jan 12, 2026 at 03:19:10PM +0100, Herve Codina wrote:
> The /export/ dts keyword is the keyword used to define an exported
> symbol at a given node level.
>
> This keyword can be present in a node definition (after properties and
> before subnodes) to export a symbol. If several symbols need to be
> exported, several /export/ keywords are present.
>
> The syntax used is the following:
> /export/ name: reference;
>
> with:
> name: The name of the exported symbol
> reference: The reference of a node the symbol is pointing to.
>
> For instance:
> - Reference by label:
> /export/ foo: &foo1;
>
> The exported symbol foo references the node identified by
> the label foo1.
>
> - Reference by path:
> /export/ foo: &{/path/to/foo@100};
>
> The exported symbol foo references the node at /path/to/foo@100.
>
> Add support for /export/ dts keyword.
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> dtc-lexer.l | 6 ++++
> dtc-parser.y | 53 ++++++++++++++++++++++++++++++++++
> dtc.h | 8 ++++++
> livetree.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 147 insertions(+)
>
> diff --git a/dtc-lexer.l b/dtc-lexer.l
> index a4a8e0b..90fe70e 100644
> --- a/dtc-lexer.l
> +++ b/dtc-lexer.l
> @@ -149,6 +149,12 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
> return DT_OMIT_NO_REF;
> }
>
> +<*>"/export/" {
> + DPRINT("Keyword: /export/\n");
> + BEGIN_DEFAULT();
> + return DT_EXPORT;
> + }
> +
> <*>{LABEL}: {
> DPRINT("Label: %s\n", yytext);
> yylval.labelref = xstrdup(yytext);
> diff --git a/dtc-parser.y b/dtc-parser.y
> index 9c93673..a0d0aef 100644
> --- a/dtc-parser.y
> +++ b/dtc-parser.y
> @@ -46,6 +46,8 @@ static bool is_ref_relative(const char *ref)
> struct property *proplist;
> struct node *node;
> struct node *nodelist;
> + struct symbol *symbol;
> + struct symbol *exportlist;
> struct reserve_info *re;
> uint64_t integer;
> unsigned int flags;
> @@ -60,6 +62,7 @@ static bool is_ref_relative(const char *ref)
> %token DT_DEL_PROP
> %token DT_DEL_NODE
> %token DT_OMIT_NO_REF
> +%token DT_EXPORT
> %token <propnodename> DT_PROPNODENAME
> %token <integer> DT_LITERAL
> %token <integer> DT_CHAR_LITERAL
> @@ -80,6 +83,8 @@ static bool is_ref_relative(const char *ref)
> %type <data> bytestring
> %type <prop> propdef
> %type <proplist> proplist
> +%type <symbol> exportdef
> +%type <exportlist> exportlist
> %type <labelref> dt_ref
>
> %type <node> devicetree
> @@ -276,6 +281,49 @@ nodedef:
> {
> $$ = build_node(NULL, $2, NULL, &@$);
> }
> + | '{' proplist exportlist subnodes '}' ';'
> + {
> + /*
> + * exportlist is created with chain_symbol() and so it
> + * is created in reverse order. Reverse it now to have
> + * it in correct order
> + */
> + $$ = build_node($2, $4, reverse_symbol($3), &@$);
> + }
> + | '{' exportlist subnodes '}' ';'
> + {
> + /*
> + * exportlist is created with chain_symbol() and so it
> + * is created in reverse order. Reverse it now to have
> + * it in correct order
> + */
> + $$ = build_node(NULL, $3, reverse_symbol($2), &@$);
> + }
> + ;
> +
> +exportlist:
> + exportdef
> + {
> + $$ = chain_symbol($1, NULL);
> + }
> + | exportlist exportdef
> + {
> + $$ = chain_symbol($2, $1);
> + }
> + | exportlist propdef
> + {
> + ERROR(&@2, "Properties must precede exports");
> + YYERROR;
> + }
> + ;
> +
> +exportdef:
> + DT_EXPORT DT_LABEL dt_ref ';'
> + {
> + $$ = build_exportsym($2, $3, 0, &@$);
> + free($2);
> + free($3);
I mostly don't bother with free()s in dtc, on the grounds that it's
generally a short-lived process - essentially using the process
context as a crude pool allocator.
> + }
> ;
>
> proplist:
> @@ -576,6 +624,11 @@ subnodes:
> ERROR(&@2, "Properties must precede subnodes");
> YYERROR;
> }
> + | subnode exportdef
> + {
> + ERROR(&@2, "Exports must precede subnodes");
> + YYERROR;
> + }
> ;
>
> subnode:
> diff --git a/dtc.h b/dtc.h
> index 6508694..0bf5ba5 100644
> --- a/dtc.h
> +++ b/dtc.h
> @@ -273,6 +273,9 @@ struct node {
> for_each_child_withdel(n, c) \
> if (!(c)->deleted)
>
> +#define for_each_symbol(s0, s) \
> + for ((s) = (s0); (s); (s) = (s)->next)
> +
> void add_label(struct label **labels, char *label);
> void delete_labels(struct label **labels);
>
> @@ -282,6 +285,11 @@ struct property *build_property_delete(const char *name);
> struct property *chain_property(struct property *first, struct property *list);
> struct property *reverse_properties(struct property *first);
>
> +struct symbol *build_exportsym(const char *name, const char *ref, cell_t phandle,
> + struct srcpos *srcpos);
> +struct symbol *chain_symbol(struct symbol *first, struct symbol *list);
> +struct symbol *reverse_symbol(struct symbol *list);
> +
> struct node *build_node(struct property *proplist, struct node *children,
> struct symbol *exportsymlist, struct srcpos *srcpos);
> struct node *build_node_delete(struct srcpos *srcpos);
> diff --git a/livetree.c b/livetree.c
> index 0050492..4458437 100644
> --- a/livetree.c
> +++ b/livetree.c
> @@ -36,6 +36,57 @@ void delete_labels(struct label **labels)
> label->deleted = 1;
> }
>
> +struct symbol *build_exportsym(const char *name, const char *ref, cell_t phandle,
> + struct srcpos *srcpos)
> +{
> + struct symbol *new = xmalloc(sizeof(*new));
> +
> + memset(new, 0, sizeof(*new));
> +
> + new->name = xstrdup(name);
> + new->ref = ref ? xstrdup(ref) : NULL;
> + new->phandle = phandle;
> + new->srcpos = srcpos_copy(srcpos);
> +
> + return new;
> +}
> +
> +struct symbol *chain_symbol(struct symbol *first, struct symbol *list)
> +{
> + assert(first->next == NULL);
> +
> + first->next = list;
> + return first;
> +}
> +
> +struct symbol *reverse_symbol(struct symbol *list)
> +{
> + struct symbol *p = list;
> + struct symbol *head = NULL;
> + struct symbol *next;
> +
> + while (p) {
> + next = p->next;
> + p->next = head;
> + head = p;
> + p = next;
> + }
> + return head;
> +}
> +
> +static void add_symbol(struct symbol **list, struct symbol *new)
> +{
> + struct symbol **s;
> +
> + new->next = NULL;
> +
> + s = list;
> + while (*s)
> + s = &((*s)->next);
> +
> + *s = new;
> +}
> +
> struct property *build_property(const char *name, struct data val,
> struct srcpos *srcpos)
> {
> @@ -144,6 +195,7 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
> {
> struct property *new_prop, *old_prop;
> struct node *new_child, *old_child;
> + struct symbol *new_sym, *old_sym;
> struct label *l;
>
> old_node->deleted = 0;
> @@ -217,6 +269,34 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
> add_child(old_node, new_child);
> }
>
> + /* Merge exported symbols. If there is a collision, keep the new one */
> + while (new_node->exportsymlist) {
> + /* Pop the symbol off the list */
> + new_sym = new_node->exportsymlist;
> + new_node->exportsymlist = new_sym->next;
> + new_sym->next = NULL;
> +
> + /* Look for a collision, set new value if there is */
> + for_each_symbol(old_node->exportsymlist, old_sym) {
> + if (streq(old_sym->name, new_sym->name)) {
> + old_sym->is_local = new_sym->is_local;
> + free(old_sym->ref);
> + old_sym->ref = new_sym->ref;
> + old_sym->phandle = new_sym->phandle;
> + old_sym->fullpath = new_sym->fullpath;
> + srcpos_free(old_sym->srcpos);
> + old_sym->srcpos = new_sym->srcpos;
> + free(new_sym);
> + new_sym = NULL;
> + break;
> + }
> + }
> +
> + /* if no collision occurred, add symbol to the old node list. */
> + if (new_sym)
> + add_symbol(&old_node->exportsymlist, new_sym);
> + }
> +
> old_node->srcpos = srcpos_extend(old_node->srcpos, new_node->srcpos);
>
> /* The new node contents are now merged into the old node. Free
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 21/77] checks: Handle export symbols in fixup_phandle_references()
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (19 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 20/77] dtc: Add support for /export/ dts keyword parsing Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 22/77] dtc: Add export symbols (/export/ keyword) in generated dts file Herve Codina
` (58 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Export symbols use phandle references.
Referenced nodes must have a phandle property set in order to have those
references working.
fixup_phandle_references() does the needed operation for properties
that use a phandle.
Extend fixup_phandle_references() to perform exact same operation for
export symbols.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
checks.c | 24 ++++++++++++++++++++++--
1 file changed, 22 insertions(+), 2 deletions(-)
diff --git a/checks.c b/checks.c
index 2be19c0..d1e215e 100644
--- a/checks.c
+++ b/checks.c
@@ -604,12 +604,13 @@ static void fixup_phandle_references(struct check *c, struct dt_info *dti,
struct node *node)
{
struct node *dt = dti->dt;
+ struct symbol *exportsym;
struct property *prop;
+ struct node *refnode;
+ cell_t phandle;
for_each_property(node, prop) {
struct marker *m = prop->val.markers;
- struct node *refnode;
- cell_t phandle;
for_each_marker_of_type(m, REF_PHANDLE) {
assert(m->offset + sizeof(cell_t) <= prop->val.len);
@@ -631,6 +632,25 @@ static void fixup_phandle_references(struct check *c, struct dt_info *dti,
reference_node(refnode);
}
}
+
+ for_each_symbol(node->exportsymlist, exportsym) {
+ refnode = get_node_by_ref(dt, exportsym->ref);
+ if (!refnode) {
+ if (!(dti->dtsflags & (DTSF_PLUGIN | DTSF_ADDON))) {
+ FAIL(c, dti, node,
+ "Export \"%s\" references to non-existent node or label \"%s\"\n",
+ exportsym->name, exportsym->ref);
+ }
+ exportsym->phandle = cpu_to_fdt32(0xffffffff);
+ continue;
+ }
+
+ /* Create the phandle property for this referenced node */
+ phandle = get_node_phandle(dt, refnode);
+ exportsym->phandle = phandle;
+
+ reference_node(refnode);
+ }
}
ERROR(phandle_references, fixup_phandle_references, NULL,
&duplicate_node_names, &explicit_phandles);
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 22/77] dtc: Add export symbols (/export/ keyword) in generated dts file
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (20 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 21/77] checks: Handle export symbols in fixup_phandle_references() Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 23/77] dtc: Introduce mark_local_exports() Herve Codina
` (57 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The export symbols (/export/ keyword) parsing from a dts file is
supported.
Add the support for this keyword in the dts file generation.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
treesource.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/treesource.c b/treesource.c
index 1db6390..9effe38 100644
--- a/treesource.c
+++ b/treesource.c
@@ -320,6 +320,7 @@ static void write_propval(FILE *f, struct property *prop)
static void write_tree_source_node(FILE *f, struct node *tree, int level)
{
+ struct symbol *exportsym;
struct property *prop;
struct node *child;
struct label *l;
@@ -349,6 +350,18 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)
fprintf(f, "%s", prop->name);
write_propval(f, prop);
}
+
+ if (tree->exportsymlist)
+ fprintf(f, "\n");
+ for_each_symbol(tree->exportsymlist, exportsym) {
+ write_prefix(f, level+1);
+ fprintf(f, "/export/ %s: ", exportsym->name);
+ if (exportsym->ref[0] == '/')
+ fprintf(f, "&{%s};\n", exportsym->ref);
+ else
+ fprintf(f, "&%s;\n", exportsym->ref);
+ }
+
for_each_child(tree, child) {
fprintf(f, "\n");
write_tree_source_node(f, child, level+1);
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 23/77] dtc: Introduce mark_local_exports()
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (21 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 22/77] dtc: Add export symbols (/export/ keyword) in generated dts file Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-15 6:01 ` David Gibson
2026-01-12 14:19 ` [RFC PATCH 24/77] dtc: Introduce update_exports_ref() Herve Codina
` (56 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
In order to have correct tags set in dtb, an export symbol has to
be identified as a "local" export symbol when it references a local
node.
This is done for phandles used by properties in mark_local_phandles().
The same operation is needed for export symbols. This is the purpose of
mark_local_exports().
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
dtc.c | 2 ++
dtc.h | 2 ++
livetree.c | 23 +++++++++++++++++++++++
3 files changed, 27 insertions(+)
diff --git a/dtc.c b/dtc.c
index fe8e8e4..030bfa2 100644
--- a/dtc.c
+++ b/dtc.c
@@ -336,6 +336,8 @@ int main(int argc, char *argv[])
update_phandles_ref(dti);
mark_local_phandles(dti);
+ mark_local_exports(dti);
+
/*
* With FDT_REF_PHANDLE added in dtbs, we need to identified
* if some unresolved phandle references are allowed in the dtb
diff --git a/dtc.h b/dtc.h
index 0bf5ba5..ea073c2 100644
--- a/dtc.h
+++ b/dtc.h
@@ -368,6 +368,8 @@ void generate_local_fixups_tree(struct dt_info *dti, const char *name);
void update_phandles_ref(struct dt_info *dti);
void mark_local_phandles(struct dt_info *dti);
+void mark_local_exports(struct dt_info *dti);
+
/* Checks */
void parse_checks_option(bool warn, bool error, const char *arg);
diff --git a/livetree.c b/livetree.c
index 4458437..0e756b8 100644
--- a/livetree.c
+++ b/livetree.c
@@ -1303,3 +1303,26 @@ void mark_local_phandles(struct dt_info *dti)
{
mark_local_phandles_internal(dti, dti->dt);
}
+
+static void mark_local_exports_internal(struct dt_info *dti,
+ struct node *node)
+{
+ struct node *c;
+ struct symbol *exportsym;
+ struct node *refnode;
+
+ for_each_symbol(node->exportsymlist, exportsym) {
+ refnode = get_node_by_ref(dti->dt, exportsym->ref);
+ if (refnode)
+ exportsym->is_local = true;
+ }
+
+ for_each_child(node, c)
+ mark_local_exports_internal(dti, c);
+}
+
+void mark_local_exports(struct dt_info *dti)
+{
+ mark_local_exports_internal(dti, dti->dt);
+
+}
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 23/77] dtc: Introduce mark_local_exports()
2026-01-12 14:19 ` [RFC PATCH 23/77] dtc: Introduce mark_local_exports() Herve Codina
@ 2026-01-15 6:01 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-15 6:01 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 2582 bytes --]
On Mon, Jan 12, 2026 at 03:19:13PM +0100, Herve Codina wrote:
> In order to have correct tags set in dtb, an export symbol has to
> be identified as a "local" export symbol when it references a local
> node.
>
> This is done for phandles used by properties in mark_local_phandles().
>
> The same operation is needed for export symbols. This is the purpose of
> mark_local_exports().
Again, I don't like caching this information. Can you determine this
just at the time you specifically use it?
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> dtc.c | 2 ++
> dtc.h | 2 ++
> livetree.c | 23 +++++++++++++++++++++++
> 3 files changed, 27 insertions(+)
>
> diff --git a/dtc.c b/dtc.c
> index fe8e8e4..030bfa2 100644
> --- a/dtc.c
> +++ b/dtc.c
> @@ -336,6 +336,8 @@ int main(int argc, char *argv[])
> update_phandles_ref(dti);
> mark_local_phandles(dti);
>
> + mark_local_exports(dti);
> +
> /*
> * With FDT_REF_PHANDLE added in dtbs, we need to identified
> * if some unresolved phandle references are allowed in the dtb
> diff --git a/dtc.h b/dtc.h
> index 0bf5ba5..ea073c2 100644
> --- a/dtc.h
> +++ b/dtc.h
> @@ -368,6 +368,8 @@ void generate_local_fixups_tree(struct dt_info *dti, const char *name);
> void update_phandles_ref(struct dt_info *dti);
> void mark_local_phandles(struct dt_info *dti);
>
> +void mark_local_exports(struct dt_info *dti);
> +
> /* Checks */
>
> void parse_checks_option(bool warn, bool error, const char *arg);
> diff --git a/livetree.c b/livetree.c
> index 4458437..0e756b8 100644
> --- a/livetree.c
> +++ b/livetree.c
> @@ -1303,3 +1303,26 @@ void mark_local_phandles(struct dt_info *dti)
> {
> mark_local_phandles_internal(dti, dti->dt);
> }
> +
> +static void mark_local_exports_internal(struct dt_info *dti,
> + struct node *node)
> +{
> + struct node *c;
> + struct symbol *exportsym;
> + struct node *refnode;
> +
> + for_each_symbol(node->exportsymlist, exportsym) {
> + refnode = get_node_by_ref(dti->dt, exportsym->ref);
> + if (refnode)
> + exportsym->is_local = true;
> + }
> +
> + for_each_child(node, c)
> + mark_local_exports_internal(dti, c);
> +}
> +
> +void mark_local_exports(struct dt_info *dti)
> +{
> + mark_local_exports_internal(dti, dti->dt);
> +
> +}
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 24/77] dtc: Introduce update_exports_ref()
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (22 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 23/77] dtc: Introduce mark_local_exports() Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 25/77] Add support for FDT_EXPORT_SYM dtb tag Herve Codina
` (55 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
In order to have consistent internal data when a export symbol using a
local phandle is parsed from a dtb, the reference related to this
phandle usage needs to be updated based on the phandle value.
This is done for phandles used by properties in update_phandles_ref().
The same operation is needed for export symbols. This is the purpose of
update_exports_ref().
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
dtc.c | 1 +
dtc.h | 1 +
livetree.c | 30 ++++++++++++++++++++++++++++++
3 files changed, 32 insertions(+)
diff --git a/dtc.c b/dtc.c
index 030bfa2..e0a0b54 100644
--- a/dtc.c
+++ b/dtc.c
@@ -336,6 +336,7 @@ int main(int argc, char *argv[])
update_phandles_ref(dti);
mark_local_phandles(dti);
+ update_exports_ref(dti);
mark_local_exports(dti);
/*
diff --git a/dtc.h b/dtc.h
index ea073c2..024e172 100644
--- a/dtc.h
+++ b/dtc.h
@@ -368,6 +368,7 @@ void generate_local_fixups_tree(struct dt_info *dti, const char *name);
void update_phandles_ref(struct dt_info *dti);
void mark_local_phandles(struct dt_info *dti);
+void update_exports_ref(struct dt_info *dti);
void mark_local_exports(struct dt_info *dti);
/* Checks */
diff --git a/livetree.c b/livetree.c
index 0e756b8..7cf3ee5 100644
--- a/livetree.c
+++ b/livetree.c
@@ -1304,6 +1304,36 @@ void mark_local_phandles(struct dt_info *dti)
mark_local_phandles_internal(dti, dti->dt);
}
+static void update_exports_ref_internal(struct dt_info *dti, struct node *node)
+{
+ struct node *c;
+ struct symbol *exportsym;
+ struct node *refnode;
+
+ for_each_symbol(node->exportsymlist, exportsym) {
+ if (exportsym->ref)
+ continue;
+
+ if (exportsym->is_local) {
+ refnode = get_node_by_phandle(dti->dt, exportsym->phandle);
+ if (!refnode)
+ die("Node not found for phandle 0x%"PRIx32"\n", exportsym->phandle);
+
+ exportsym->ref = refnode->fullpath;
+ } else {
+ die("Found a non local phandle without a reference\n");
+ }
+ }
+
+ for_each_child(node, c)
+ update_exports_ref_internal(dti, c);
+}
+
+void update_exports_ref(struct dt_info *dti)
+{
+ update_exports_ref_internal(dti, dti->dt);
+}
+
static void mark_local_exports_internal(struct dt_info *dti,
struct node *node)
{
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 25/77] Add support for FDT_EXPORT_SYM dtb tag
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (23 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 24/77] dtc: Introduce update_exports_ref() Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-15 6:23 ` David Gibson
2026-01-12 14:19 ` [RFC PATCH 26/77] tests: metadata: Add export symbols with local references tests Herve Codina
` (54 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The FDT_EXPORT_SYM dtb tag is a meta-data tag defining an exported
symbol. It can be present in a node bloc meaning that a symbol is
exported at this node level. The node pointed to by this symbol is a
local node and identified by a phandle value.
The tag is followed by two values and a possible alignment padding:
- name (string including \0)
The export symbol name. I.e. the name used to reference this
exported symbol.
- padding:
Padding (0x00) added to have the next value aligned on 32bit.
- phandle (32bit)
The phandle value identifying the node referenced by this symbol.
Example:
FDT_EXPORT_SYM 'foo1' 0x00 0x00 0x00 0x00000004
This means that 'foo1' is an exported symbol and the node referenced
by this symbol is the node with the phandle value equals 4.
This is what is encoded in the dtb when the related dts has the
following exported symbol defined:
/export/ foo1: &foo;
with 'foo' a reference to an existing node where the phandle value is
0x0000004.
If several symbols are exported at a given node level, several
FDT_EXPORT_SYM are present. Each of them defining one symbol.
For instance, exporting 'foo' pointing to phandle 4 and 'bar' pointing
to phandle 8 leads to the following sequence:
FDT_EXPORT_SYM 'foo' 0x00 0x00 0x00 0x00000004
FDT_EXPORT_SYM 'bar' 0x00 0x00 0x00 0x00000008
Add support for this new dtb tag.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
dtc.h | 1 +
fdtdump.c | 12 +++++++++-
flattree.c | 47 ++++++++++++++++++++++++++++++++++++++--
libfdt/fdt.c | 17 +++++++++++++++
libfdt/fdt.h | 2 ++
libfdt/libfdt_internal.h | 1 +
livetree.c | 2 +-
7 files changed, 78 insertions(+), 4 deletions(-)
diff --git a/dtc.h b/dtc.h
index 024e172..22816ba 100644
--- a/dtc.h
+++ b/dtc.h
@@ -289,6 +289,7 @@ struct symbol *build_exportsym(const char *name, const char *ref, cell_t phandle
struct srcpos *srcpos);
struct symbol *chain_symbol(struct symbol *first, struct symbol *list);
struct symbol *reverse_symbol(struct symbol *list);
+void add_symbol(struct symbol **list, struct symbol *new);
struct node *build_node(struct property *proplist, struct node *children,
struct symbol *exportsymlist, struct srcpos *srcpos);
diff --git a/fdtdump.c b/fdtdump.c
index 9b6f41a..d1af5b6 100644
--- a/fdtdump.c
+++ b/fdtdump.c
@@ -57,7 +57,7 @@ static void dump_blob(void *blob, bool debug)
const char *p_strings = (const char *)blob + off_str;
uint32_t version = fdt32_to_cpu(bph->version);
uint32_t totalsize = fdt32_to_cpu(bph->totalsize);
- uint32_t tag, offset;
+ uint32_t tag, offset, val32;
const char *p, *s, *t;
const char *last_prop_name = NULL;
int depth, sz, shift;
@@ -176,6 +176,16 @@ static void dump_blob(void *blob, bool debug)
continue;
}
+ if (tag == FDT_EXPORT_SYM) {
+ s = p;
+ p = PALIGN(p + strlen(s) + 1, 4);
+ val32 = fdt32_to_cpu(GET_CELL(p));
+
+ printf("%*s// [FDT_EXPORT_SYM] '%s' -> phandle 0x%08"PRIx32"\n",
+ depth * shift, "", s, val32);
+ continue;
+ }
+
fprintf(stderr, "%*s ** Unknown tag 0x%08"PRIx32"\n", depth * shift, "", tag);
break;
}
diff --git a/flattree.c b/flattree.c
index 36b795d..bd52e81 100644
--- a/flattree.c
+++ b/flattree.c
@@ -15,6 +15,7 @@
#define FTF_NOPS 0x40
#define FTF_REF_XXX 0x80
#define FTF_DTFLAGS 0x100
+#define FTF_EXPORT_IMPORT_SYM 0x200
static struct version_info {
int version;
@@ -34,7 +35,7 @@ static struct version_info {
FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS},
{18, 18, FDT_V18_SIZE,
FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS|FTF_REF_XXX|
- FTF_DTFLAGS},
+ FTF_DTFLAGS|FTF_EXPORT_IMPORT_SYM},
};
struct emitter {
@@ -47,6 +48,7 @@ struct emitter {
void (*property)(void *, struct label *labels);
void (*ref_local)(void *);
void (*ref_phandle)(void *);
+ void (*export_sym)(void *);
};
static void bin_emit_cell(void *e, cell_t val)
@@ -106,6 +108,11 @@ static void bin_emit_ref_phandle(void *e)
bin_emit_cell(e, FDT_REF_PHANDLE);
}
+static void bin_emit_export_sym(void *e)
+{
+ bin_emit_cell(e, FDT_EXPORT_SYM);
+}
+
static struct emitter bin_emitter = {
.cell = bin_emit_cell,
.string = bin_emit_string,
@@ -116,6 +123,7 @@ static struct emitter bin_emitter = {
.property = bin_emit_property,
.ref_local = bin_emit_ref_local,
.ref_phandle = bin_emit_ref_phandle,
+ .export_sym = bin_emit_export_sym,
};
static void emit_label(FILE *f, const char *prefix, const char *label)
@@ -243,6 +251,14 @@ static void asm_emit_ref_phandle(void *e)
asm_emit_cell(e, FDT_REF_PHANDLE);
}
+static void asm_emit_export_sym(void *e)
+{
+ FILE *f = e;
+
+ fprintf(f, "\t/* FDT_EXPORT_SYM */\n");
+ asm_emit_cell(e, FDT_EXPORT_SYM);
+}
+
static struct emitter asm_emitter = {
.cell = asm_emit_cell,
.string = asm_emit_string,
@@ -253,6 +269,7 @@ static struct emitter asm_emitter = {
.property = asm_emit_property,
.ref_local = asm_emit_ref_local,
.ref_phandle = asm_emit_ref_phandle,
+ .export_sym = asm_emit_export_sym,
};
static int stringtable_insert(struct data *d, const char *str)
@@ -274,6 +291,7 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
void *etarget, struct data *strbuf,
struct version_info *vi)
{
+ struct symbol *exportsym;
struct property *prop;
struct node *child;
bool seen_name_prop = false;
@@ -342,6 +360,18 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
emit->align(etarget, sizeof(cell_t));
}
+ if (vi->flags & FTF_EXPORT_IMPORT_SYM) {
+ for_each_symbol(tree->exportsymlist, exportsym) {
+ if (exportsym->is_local) {
+ emit->export_sym(etarget);
+ emit->string(etarget, exportsym->name, 0);
+ emit->align(etarget, sizeof(cell_t));
+ emit->cell(etarget, exportsym->phandle);
+ continue;
+ }
+ }
+ }
+
for_each_child(tree, child) {
flatten_tree(child, emit, etarget, strbuf, vi);
}
@@ -820,9 +850,11 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
node->name = xstrdup(flatname);
do {
+ struct symbol *exportsym;
struct property *prop;
struct node *child;
struct marker *m;
+ cell_t phandle;
val = flat_read_word(dtbuf);
switch (val) {
@@ -876,6 +908,17 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
prop->val = data_append_markers(prop->val, m);
break;
+ case FDT_EXPORT_SYM:
+ if (!(flags & FTF_EXPORT_IMPORT_SYM))
+ die("FDT_EXPORT_SYM tag found in flat tree"
+ " version <18\n");
+ str = flat_read_string(dtbuf);
+ phandle = flat_read_word(dtbuf);
+ exportsym = build_exportsym(str, NULL, phandle, NULL);
+ exportsym->is_local = true;
+ add_symbol(&node->exportsymlist, exportsym);
+ break;
+
default:
die("Invalid opcode word %08x in device tree blob\n",
val);
@@ -996,7 +1039,7 @@ struct dt_info *dt_from_blob(const char *fname)
}
if (version >= 18) {
- flags |= FTF_REF_XXX | FTF_DTFLAGS;
+ flags |= FTF_REF_XXX | FTF_DTFLAGS | FTF_EXPORT_IMPORT_SYM;
dtsflags |= fdt32_to_cpu(fdt->dt_flags) & FDT_FLAG_ADDON ?
DTSF_ADDON : 0;
}
diff --git a/libfdt/fdt.c b/libfdt/fdt.c
index 8f3c35d..44d7399 100644
--- a/libfdt/fdt.c
+++ b/libfdt/fdt.c
@@ -232,6 +232,22 @@ uint32_t fdt_next_tag_full(const void *fdt, int startoffset, int *nextoffset)
return FDT_END; /* premature end */
break;
+ case FDT_EXPORT_SYM:
+ /* Skip name */
+ do {
+ p = fdt_offset_ptr(fdt, offset++, 1);
+ } while (p && (*p != '\0'));
+ if (!can_assume(VALID_DTB) && !p)
+ return FDT_END; /* premature end */
+ offset = FDT_CELLALIGN(offset);
+
+ /* Skip phandle */
+ tmp32p = fdt_offset_ptr(fdt, offset, sizeof(*tmp32p));
+ if (!can_assume(VALID_DTB) && !tmp32p)
+ return FDT_END; /* premature end */
+ offset += sizeof(fdt32_t);
+ break;
+
default:
return FDT_END;
}
@@ -273,6 +289,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
case FDT_REF_LOCAL:
case FDT_REF_PHANDLE:
+ case FDT_EXPORT_SYM:
/*
* Next tag is a meta-data tag present in the middle
* of the structure -> Skip it and look at next one
diff --git a/libfdt/fdt.h b/libfdt/fdt.h
index 94f65e6..e85bc07 100644
--- a/libfdt/fdt.h
+++ b/libfdt/fdt.h
@@ -53,6 +53,7 @@ struct fdt_property {
#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
#define FDT_FLAG_ADDON 0x1
#define FDT_TAGSIZE sizeof(fdt32_t)
+#define FDT_CELLSIZE sizeof(fdt32_t)
#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
#define FDT_END_NODE 0x2 /* End node */
@@ -63,6 +64,7 @@ struct fdt_property {
#define FDT_REF_PHANDLE 0x6 /* external phandle reference: offset,
external label */
#define FDT_END 0x9
+#define FDT_EXPORT_SYM 0xa /* export symbol: name, phandle value */
#define FDT_V1_SIZE (7*sizeof(fdt32_t))
#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t))
diff --git a/libfdt/libfdt_internal.h b/libfdt/libfdt_internal.h
index 0e103ca..d80d218 100644
--- a/libfdt/libfdt_internal.h
+++ b/libfdt/libfdt_internal.h
@@ -9,6 +9,7 @@
#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
+#define FDT_CELLALIGN(x) (FDT_ALIGN((x), FDT_CELLSIZE))
int32_t fdt_ro_probe_(const void *fdt);
#define FDT_RO_PROBE(fdt) \
diff --git a/livetree.c b/livetree.c
index 7cf3ee5..7efa1da 100644
--- a/livetree.c
+++ b/livetree.c
@@ -74,7 +74,7 @@ struct symbol *reverse_symbol(struct symbol *list)
return head;
}
-static void add_symbol(struct symbol **list, struct symbol *new)
+void add_symbol(struct symbol **list, struct symbol *new)
{
struct symbol **s;
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 25/77] Add support for FDT_EXPORT_SYM dtb tag
2026-01-12 14:19 ` [RFC PATCH 25/77] Add support for FDT_EXPORT_SYM dtb tag Herve Codina
@ 2026-01-15 6:23 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-15 6:23 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 11001 bytes --]
On Mon, Jan 12, 2026 at 03:19:15PM +0100, Herve Codina wrote:
> The FDT_EXPORT_SYM dtb tag is a meta-data tag defining an exported
> symbol. It can be present in a node bloc meaning that a symbol is
> exported at this node level. The node pointed to by this symbol is a
> local node and identified by a phandle value.
>
> The tag is followed by two values and a possible alignment padding:
> - name (string including \0)
> The export symbol name. I.e. the name used to reference this
> exported symbol.
> - padding:
> Padding (0x00) added to have the next value aligned on 32bit.
> - phandle (32bit)
> The phandle value identifying the node referenced by this
> symbol.
I'd suggest putting the phandle before the name, to avoid internal
padding.
>
> Example:
> FDT_EXPORT_SYM 'foo1' 0x00 0x00 0x00 0x00000004
>
> This means that 'foo1' is an exported symbol and the node referenced
> by this symbol is the node with the phandle value equals 4.
>
> This is what is encoded in the dtb when the related dts has the
> following exported symbol defined:
> /export/ foo1: &foo;
> with 'foo' a reference to an existing node where the phandle value is
> 0x0000004.
>
> If several symbols are exported at a given node level, several
> FDT_EXPORT_SYM are present. Each of them defining one symbol.
>
> For instance, exporting 'foo' pointing to phandle 4 and 'bar' pointing
> to phandle 8 leads to the following sequence:
> FDT_EXPORT_SYM 'foo' 0x00 0x00 0x00 0x00000004
> FDT_EXPORT_SYM 'bar' 0x00 0x00 0x00 0x00000008
>
> Add support for this new dtb tag.
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> dtc.h | 1 +
> fdtdump.c | 12 +++++++++-
> flattree.c | 47 ++++++++++++++++++++++++++++++++++++++--
> libfdt/fdt.c | 17 +++++++++++++++
> libfdt/fdt.h | 2 ++
> libfdt/libfdt_internal.h | 1 +
> livetree.c | 2 +-
> 7 files changed, 78 insertions(+), 4 deletions(-)
>
> diff --git a/dtc.h b/dtc.h
> index 024e172..22816ba 100644
> --- a/dtc.h
> +++ b/dtc.h
> @@ -289,6 +289,7 @@ struct symbol *build_exportsym(const char *name, const char *ref, cell_t phandle
> struct srcpos *srcpos);
> struct symbol *chain_symbol(struct symbol *first, struct symbol *list);
> struct symbol *reverse_symbol(struct symbol *list);
> +void add_symbol(struct symbol **list, struct symbol *new);
>
> struct node *build_node(struct property *proplist, struct node *children,
> struct symbol *exportsymlist, struct srcpos *srcpos);
> diff --git a/fdtdump.c b/fdtdump.c
> index 9b6f41a..d1af5b6 100644
> --- a/fdtdump.c
> +++ b/fdtdump.c
> @@ -57,7 +57,7 @@ static void dump_blob(void *blob, bool debug)
> const char *p_strings = (const char *)blob + off_str;
> uint32_t version = fdt32_to_cpu(bph->version);
> uint32_t totalsize = fdt32_to_cpu(bph->totalsize);
> - uint32_t tag, offset;
> + uint32_t tag, offset, val32;
> const char *p, *s, *t;
> const char *last_prop_name = NULL;
> int depth, sz, shift;
> @@ -176,6 +176,16 @@ static void dump_blob(void *blob, bool debug)
> continue;
> }
>
> + if (tag == FDT_EXPORT_SYM) {
> + s = p;
> + p = PALIGN(p + strlen(s) + 1, 4);
> + val32 = fdt32_to_cpu(GET_CELL(p));
> +
> + printf("%*s// [FDT_EXPORT_SYM] '%s' -> phandle 0x%08"PRIx32"\n",
> + depth * shift, "", s, val32);
> + continue;
> + }
> +
> fprintf(stderr, "%*s ** Unknown tag 0x%08"PRIx32"\n", depth * shift, "", tag);
> break;
> }
> diff --git a/flattree.c b/flattree.c
> index 36b795d..bd52e81 100644
> --- a/flattree.c
> +++ b/flattree.c
> @@ -15,6 +15,7 @@
> #define FTF_NOPS 0x40
> #define FTF_REF_XXX 0x80
> #define FTF_DTFLAGS 0x100
> +#define FTF_EXPORT_IMPORT_SYM 0x200
>
> static struct version_info {
> int version;
> @@ -34,7 +35,7 @@ static struct version_info {
> FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS},
> {18, 18, FDT_V18_SIZE,
> FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS|FTF_REF_XXX|
> - FTF_DTFLAGS},
> + FTF_DTFLAGS|FTF_EXPORT_IMPORT_SYM},
> };
>
> struct emitter {
> @@ -47,6 +48,7 @@ struct emitter {
> void (*property)(void *, struct label *labels);
> void (*ref_local)(void *);
> void (*ref_phandle)(void *);
> + void (*export_sym)(void *);
> };
>
> static void bin_emit_cell(void *e, cell_t val)
> @@ -106,6 +108,11 @@ static void bin_emit_ref_phandle(void *e)
> bin_emit_cell(e, FDT_REF_PHANDLE);
> }
>
> +static void bin_emit_export_sym(void *e)
> +{
> + bin_emit_cell(e, FDT_EXPORT_SYM);
> +}
> +
> static struct emitter bin_emitter = {
> .cell = bin_emit_cell,
> .string = bin_emit_string,
> @@ -116,6 +123,7 @@ static struct emitter bin_emitter = {
> .property = bin_emit_property,
> .ref_local = bin_emit_ref_local,
> .ref_phandle = bin_emit_ref_phandle,
> + .export_sym = bin_emit_export_sym,
> };
>
> static void emit_label(FILE *f, const char *prefix, const char *label)
> @@ -243,6 +251,14 @@ static void asm_emit_ref_phandle(void *e)
> asm_emit_cell(e, FDT_REF_PHANDLE);
> }
>
> +static void asm_emit_export_sym(void *e)
> +{
> + FILE *f = e;
> +
> + fprintf(f, "\t/* FDT_EXPORT_SYM */\n");
> + asm_emit_cell(e, FDT_EXPORT_SYM);
> +}
> +
> static struct emitter asm_emitter = {
> .cell = asm_emit_cell,
> .string = asm_emit_string,
> @@ -253,6 +269,7 @@ static struct emitter asm_emitter = {
> .property = asm_emit_property,
> .ref_local = asm_emit_ref_local,
> .ref_phandle = asm_emit_ref_phandle,
> + .export_sym = asm_emit_export_sym,
> };
>
> static int stringtable_insert(struct data *d, const char *str)
> @@ -274,6 +291,7 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
> void *etarget, struct data *strbuf,
> struct version_info *vi)
> {
> + struct symbol *exportsym;
> struct property *prop;
> struct node *child;
> bool seen_name_prop = false;
> @@ -342,6 +360,18 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
> emit->align(etarget, sizeof(cell_t));
> }
>
> + if (vi->flags & FTF_EXPORT_IMPORT_SYM) {
> + for_each_symbol(tree->exportsymlist, exportsym) {
> + if (exportsym->is_local) {
> + emit->export_sym(etarget);
> + emit->string(etarget, exportsym->name, 0);
> + emit->align(etarget, sizeof(cell_t));
> + emit->cell(etarget, exportsym->phandle);
> + continue;
> + }
> + }
> + }
> +
> for_each_child(tree, child) {
> flatten_tree(child, emit, etarget, strbuf, vi);
> }
> @@ -820,9 +850,11 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
> node->name = xstrdup(flatname);
>
> do {
> + struct symbol *exportsym;
> struct property *prop;
> struct node *child;
> struct marker *m;
> + cell_t phandle;
>
> val = flat_read_word(dtbuf);
> switch (val) {
> @@ -876,6 +908,17 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
> prop->val = data_append_markers(prop->val, m);
> break;
>
> + case FDT_EXPORT_SYM:
> + if (!(flags & FTF_EXPORT_IMPORT_SYM))
> + die("FDT_EXPORT_SYM tag found in flat tree"
> + " version <18\n");
> + str = flat_read_string(dtbuf);
> + phandle = flat_read_word(dtbuf);
> + exportsym = build_exportsym(str, NULL, phandle, NULL);
> + exportsym->is_local = true;
> + add_symbol(&node->exportsymlist, exportsym);
> + break;
> +
> default:
> die("Invalid opcode word %08x in device tree blob\n",
> val);
> @@ -996,7 +1039,7 @@ struct dt_info *dt_from_blob(const char *fname)
> }
>
> if (version >= 18) {
> - flags |= FTF_REF_XXX | FTF_DTFLAGS;
> + flags |= FTF_REF_XXX | FTF_DTFLAGS | FTF_EXPORT_IMPORT_SYM;
> dtsflags |= fdt32_to_cpu(fdt->dt_flags) & FDT_FLAG_ADDON ?
> DTSF_ADDON : 0;
> }
> diff --git a/libfdt/fdt.c b/libfdt/fdt.c
> index 8f3c35d..44d7399 100644
> --- a/libfdt/fdt.c
> +++ b/libfdt/fdt.c
> @@ -232,6 +232,22 @@ uint32_t fdt_next_tag_full(const void *fdt, int startoffset, int *nextoffset)
> return FDT_END; /* premature end */
> break;
>
> + case FDT_EXPORT_SYM:
> + /* Skip name */
> + do {
> + p = fdt_offset_ptr(fdt, offset++, 1);
> + } while (p && (*p != '\0'));
> + if (!can_assume(VALID_DTB) && !p)
> + return FDT_END; /* premature end */
> + offset = FDT_CELLALIGN(offset);
> +
> + /* Skip phandle */
> + tmp32p = fdt_offset_ptr(fdt, offset, sizeof(*tmp32p));
> + if (!can_assume(VALID_DTB) && !tmp32p)
> + return FDT_END; /* premature end */
> + offset += sizeof(fdt32_t);
> + break;
> +
> default:
> return FDT_END;
> }
> @@ -273,6 +289,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
>
> case FDT_REF_LOCAL:
> case FDT_REF_PHANDLE:
> + case FDT_EXPORT_SYM:
> /*
> * Next tag is a meta-data tag present in the middle
> * of the structure -> Skip it and look at next one
> diff --git a/libfdt/fdt.h b/libfdt/fdt.h
> index 94f65e6..e85bc07 100644
> --- a/libfdt/fdt.h
> +++ b/libfdt/fdt.h
> @@ -53,6 +53,7 @@ struct fdt_property {
> #define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
> #define FDT_FLAG_ADDON 0x1
> #define FDT_TAGSIZE sizeof(fdt32_t)
> +#define FDT_CELLSIZE sizeof(fdt32_t)
>
> #define FDT_BEGIN_NODE 0x1 /* Start node: full name */
> #define FDT_END_NODE 0x2 /* End node */
> @@ -63,6 +64,7 @@ struct fdt_property {
> #define FDT_REF_PHANDLE 0x6 /* external phandle reference: offset,
> external label */
> #define FDT_END 0x9
> +#define FDT_EXPORT_SYM 0xa /* export symbol: name, phandle value */
>
> #define FDT_V1_SIZE (7*sizeof(fdt32_t))
> #define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t))
> diff --git a/libfdt/libfdt_internal.h b/libfdt/libfdt_internal.h
> index 0e103ca..d80d218 100644
> --- a/libfdt/libfdt_internal.h
> +++ b/libfdt/libfdt_internal.h
> @@ -9,6 +9,7 @@
>
> #define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
> #define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
> +#define FDT_CELLALIGN(x) (FDT_ALIGN((x), FDT_CELLSIZE))
>
> int32_t fdt_ro_probe_(const void *fdt);
> #define FDT_RO_PROBE(fdt) \
> diff --git a/livetree.c b/livetree.c
> index 7cf3ee5..7efa1da 100644
> --- a/livetree.c
> +++ b/livetree.c
> @@ -74,7 +74,7 @@ struct symbol *reverse_symbol(struct symbol *list)
> return head;
> }
>
> -static void add_symbol(struct symbol **list, struct symbol *new)
> +void add_symbol(struct symbol **list, struct symbol *new)
> {
> struct symbol **s;
>
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 26/77] tests: metadata: Add export symbols with local references tests
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (24 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 25/77] Add support for FDT_EXPORT_SYM dtb tag Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 27/77] dtc: Add support for export symbols sorting Herve Codina
` (53 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Add tests related to export symbols using local phandle references
(FDT_EXPORT_SYM dtb tag).
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
.../metadata_exportsyms_local.dtb.dts.expect | 26 +++++++++++++++++
tests/metadata_exportsyms_local.dtb.expect | 20 +++++++++++++
tests/metadata_exportsyms_local.dts | 28 +++++++++++++++++++
.../metadata_exportsyms_local.dts.dts.expect | 26 +++++++++++++++++
tests/run_tests.sh | 2 +-
5 files changed, 101 insertions(+), 1 deletion(-)
create mode 100644 tests/metadata_exportsyms_local.dtb.dts.expect
create mode 100644 tests/metadata_exportsyms_local.dtb.expect
create mode 100644 tests/metadata_exportsyms_local.dts
create mode 100644 tests/metadata_exportsyms_local.dts.dts.expect
diff --git a/tests/metadata_exportsyms_local.dtb.dts.expect b/tests/metadata_exportsyms_local.dtb.dts.expect
new file mode 100644
index 0000000..ac3d5b3
--- /dev/null
+++ b/tests/metadata_exportsyms_local.dtb.dts.expect
@@ -0,0 +1,26 @@
+/dts-v1/;
+
+/ {
+
+ node-a {
+ };
+
+ node-b {
+ phandle = <0x03>;
+ };
+
+ node-c {
+
+ sub-node {
+ phandle = <0x02>;
+ };
+ };
+
+ node-d {
+ phandle = <0x01>;
+
+ /export/ node_d: &{/node-d};
+ /export/ subnode_c: &{/node-c/sub-node};
+ /export/ node_b: &{/node-b};
+ };
+};
diff --git a/tests/metadata_exportsyms_local.dtb.expect b/tests/metadata_exportsyms_local.dtb.expect
new file mode 100644
index 0000000..2002553
--- /dev/null
+++ b/tests/metadata_exportsyms_local.dtb.expect
@@ -0,0 +1,20 @@
+/dts-v1/;
+
+/ {
+ node-a {
+ };
+ node-b {
+ phandle = <0x00000003>;
+ };
+ node-c {
+ sub-node {
+ phandle = <0x00000002>;
+ };
+ };
+ node-d {
+ phandle = <0x00000001>;
+ // [FDT_EXPORT_SYM] 'node_d' -> phandle 0x00000001
+ // [FDT_EXPORT_SYM] 'subnode_c' -> phandle 0x00000002
+ // [FDT_EXPORT_SYM] 'node_b' -> phandle 0x00000003
+ };
+};
diff --git a/tests/metadata_exportsyms_local.dts b/tests/metadata_exportsyms_local.dts
new file mode 100644
index 0000000..10e6e47
--- /dev/null
+++ b/tests/metadata_exportsyms_local.dts
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+
+/ {
+ node-a {
+ };
+
+ node_b: node-b {
+ };
+
+ node-c {
+ sub_node: sub-node {
+ };
+ };
+
+ node_d: node-d {
+ /export/ node_d: &node_d;
+ /export/ subnode_c: &sub_node;
+ };
+};
+
+&node_d {
+ /export/ node_b: &node_b;
+};
diff --git a/tests/metadata_exportsyms_local.dts.dts.expect b/tests/metadata_exportsyms_local.dts.dts.expect
new file mode 100644
index 0000000..4723e7e
--- /dev/null
+++ b/tests/metadata_exportsyms_local.dts.dts.expect
@@ -0,0 +1,26 @@
+/dts-v1/;
+
+/ {
+
+ node-a {
+ };
+
+ node_b: node-b {
+ phandle = <0x03>;
+ };
+
+ node-c {
+
+ sub_node: sub-node {
+ phandle = <0x02>;
+ };
+ };
+
+ node_d: node-d {
+ phandle = <0x01>;
+
+ /export/ node_d: &node_d;
+ /export/ subnode_c: &sub_node;
+ /export/ node_b: &node_b;
+ };
+};
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index def1a7e..ed3a240 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1126,7 +1126,7 @@ wrap_fdtdump () {
metadata_tests() {
for dt in metadata_reflocal metadata_refphandle \
- metadata_addon_base; do
+ metadata_addon_base metadata_exportsyms_local; do
run_dtc_test -I dts -O dts -o $dt.dts.dts "$SRCDIR/$dt.dts"
base_run_test check_diff $dt.dts.dts "$SRCDIR/$dt.dts.dts.expect"
run_dtc_test -I dts -O dtb -o $dt.dtb "$SRCDIR/$dt.dts"
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 27/77] dtc: Add support for export symbols sorting
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (25 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 26/77] tests: metadata: Add export symbols with local references tests Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 28/77] tests: metadata: Add a test " Herve Codina
` (52 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
dtc can sort items when the command line --sort option is set.
Add support for export symbols sorting when this option is used.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
livetree.c | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/livetree.c b/livetree.c
index 7efa1da..1de5990 100644
--- a/livetree.c
+++ b/livetree.c
@@ -916,6 +916,42 @@ static void sort_properties(struct node *node)
free(tbl);
}
+static int cmp_symbol(const void *ax, const void *bx)
+{
+ const struct symbol *a, *b;
+
+ a = *((const struct symbol * const *)ax);
+ b = *((const struct symbol * const *)bx);
+
+ return strcmp(a->name, b->name);
+}
+
+static void sort_exportsyms(struct node *node)
+{
+ int n = 0, i = 0;
+ struct symbol *symbol, **tbl;
+
+ for_each_symbol(node->exportsymlist, symbol)
+ n++;
+
+ if (n == 0)
+ return;
+
+ tbl = xmalloc(n * sizeof(*tbl));
+
+ for_each_symbol(node->exportsymlist, symbol)
+ tbl[i++] = symbol;
+
+ qsort(tbl, n, sizeof(*tbl), cmp_symbol);
+
+ node->exportsymlist = tbl[0];
+ for (i = 0; i < (n-1); i++)
+ tbl[i]->next = tbl[i+1];
+ tbl[n-1]->next = NULL;
+
+ free(tbl);
+}
+
static int cmp_subnode(const void *ax, const void *bx)
{
const struct node *a, *b;
@@ -957,6 +993,7 @@ static void sort_node(struct node *node)
struct node *c;
sort_properties(node);
+ sort_exportsyms(node);
sort_subnodes(node);
for_each_child_withdel(node, c)
sort_node(c);
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 28/77] tests: metadata: Add a test for export symbols sorting
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (26 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 27/77] dtc: Add support for export symbols sorting Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 29/77] Add support for FDT_EXPORT_SYM_REF dtb tag Herve Codina
` (51 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
dtc is able to sort the export symbols list when the --sort option is
used.
Add a test for this feature.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
tests/metadata_sort.dtb.dts.expect | 18 ++++++++++++++++++
tests/metadata_sort.dtb.expect | 15 +++++++++++++++
tests/metadata_sort.dts | 21 +++++++++++++++++++++
tests/run_tests.sh | 8 ++++++++
4 files changed, 62 insertions(+)
create mode 100644 tests/metadata_sort.dtb.dts.expect
create mode 100644 tests/metadata_sort.dtb.expect
create mode 100644 tests/metadata_sort.dts
diff --git a/tests/metadata_sort.dtb.dts.expect b/tests/metadata_sort.dtb.dts.expect
new file mode 100644
index 0000000..f07a42b
--- /dev/null
+++ b/tests/metadata_sort.dtb.dts.expect
@@ -0,0 +1,18 @@
+/dts-v1/;
+/addon/;
+
+/ {
+
+ node-a {
+ prop_a = <0x1c8>;
+ prop_b = <0x7b>;
+
+ /export/ a: &{/node-b};
+ /export/ ba: &{/node-b};
+ /export/ bb: &{/node-b};
+ };
+
+ node-b {
+ phandle = <0x01>;
+ };
+};
diff --git a/tests/metadata_sort.dtb.expect b/tests/metadata_sort.dtb.expect
new file mode 100644
index 0000000..7856894
--- /dev/null
+++ b/tests/metadata_sort.dtb.expect
@@ -0,0 +1,15 @@
+/dts-v1/;
+/addon/;
+
+/ {
+ node-a {
+ prop_a = <0x000001c8>;
+ prop_b = <0x0000007b>;
+ // [FDT_EXPORT_SYM] 'a' -> phandle 0x00000001
+ // [FDT_EXPORT_SYM] 'ba' -> phandle 0x00000001
+ // [FDT_EXPORT_SYM] 'bb' -> phandle 0x00000001
+ };
+ node-b {
+ phandle = <0x00000001>;
+ };
+};
diff --git a/tests/metadata_sort.dts b/tests/metadata_sort.dts
new file mode 100644
index 0000000..7d1cca7
--- /dev/null
+++ b/tests/metadata_sort.dts
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+/addon/;
+
+/ {
+ node_b: node-b {
+ };
+
+ node-a {
+ prop_b = <123>;
+ prop_a = <456>;
+
+ /export/ ba: &node_b;
+ /export/ bb: &node_b;
+ /export/ a: &node_b;
+ };
+};
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index ed3a240..fc270e2 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1154,6 +1154,14 @@ metadata_tests() {
# Keep only lines containing 'dt_flags'
sed -i '/dt_flags/!d' metadata_dtflags1.dtb.out
base_run_test check_diff metadata_dtflags1.dtb.out "$SRCDIR/metadata_dtflags1.dtb.expect"
+
+ run_dtc_test -I dts -O dtb -s -o metadata_sort.dtb "$SRCDIR/metadata_sort.dts"
+ base_run_test wrap_fdtdump metadata_sort.dtb metadata_sort.dtb.out
+ # Remove unneeded comments
+ sed -i '/^\/\/ /d' metadata_sort.dtb.out
+ base_run_test check_diff metadata_sort.dtb.out "$SRCDIR/metadata_sort.dtb.expect"
+ run_dtc_test -I dtb -O dts -o metadata_sort.dtb.dts metadata_sort.dtb
+ base_run_test check_diff metadata_sort.dtb.dts "$SRCDIR/metadata_sort.dtb.dts.expect"
}
pylibfdt_tests () {
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 29/77] Add support for FDT_EXPORT_SYM_REF dtb tag
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (27 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 28/77] tests: metadata: Add a test " Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-15 6:25 ` David Gibson
2026-01-12 14:19 ` [RFC PATCH 30/77] tests: metadata: Add export symbols with external references tests Herve Codina
` (50 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The FDT_EXPORT_SYM_REF dtb tag is similar to the FDT_EXPORT_SYM tag
except that it identifies a reference to an external phandle. The node
referenced by the phandle is not present in the device-tree blob.
The FDT_EXPORT_SYM_REF dtb tag is a meta-data tag defining an exported
symbol. It can be present in a node bloc meaning that a symbol is
exported at this node level. The node pointed to by this symbol is not a
local node (i.e. the node is not present in the device-tree blob.). This
tag can be available only in overlay or addon device-tree blobs. The
symbol has to be resolved when the device-tree blob is applied on top of
a base device-tree.
It is followed by three values and a possible alignment padding:
- name (string including \0)
The export symbol name. I.e. the name used to reference this
exported symbol.
- padding:
Padding (0x00) added to have the next value aligned on 32bit.
- phandle (32bit)
A placeholder for a phandle value.
This placeholder can be used during some dtb manipulation to store
a temporary phandle value.
In terms of FDT_EXPORT_SYM_REF definition, it has no meaningful
signification and will be probably set to 0xffffffff, the
unresolved phandle value.
- label (string including \0):
The label to use to resolve this symbol. This label is the
reference to the external phandle.
- padding:
Padding (0x00) added to have the next value aligned on 32bit.
Example:
FDT_EXPORT_SYM_REF 'foo1' 0x00 0x00 0x00 0xffffffff 'foo_a' 0x00 0x00
This means that 'foo1' is an exported symbol and the node referenced
by this symbol is external to the dtb (unresolved symbol). This
external node is referenced by the "foo_a" label.
This is what is encoded in the dtb when the related dts has the
following exported symbol defined:
/export/ foo1: &foo_a;
with 'foo_a' a reference to a non local node.
If several non local symbols are exported at a given node level, several
FDT_EXPORT_SYM_REF are present. Each of them defining one symbol.
For instance, exporting 'foo1' pointing the node referenced by 'foo_a'
and exporting 'bar1' pointing to the node referenced by 'bar_b' leads to
the following sequence:
FDT_EXPORT_SYM_REF 'foo1' 0x00 0x00 0x00 'foo_a' 0x00 0x00
FDT_EXPORT_SYM_REF 'bar1' 0x00 0x00 0x00 'bar_b' 0x00 0x00
Add support for this new dtb tag.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
fdtdump.c | 12 ++++++++++++
flattree.c | 40 ++++++++++++++++++++++++++++++++++++++++
libfdt/fdt.c | 24 ++++++++++++++++++++++++
libfdt/fdt.h | 2 ++
4 files changed, 78 insertions(+)
diff --git a/fdtdump.c b/fdtdump.c
index d1af5b6..8baadc4 100644
--- a/fdtdump.c
+++ b/fdtdump.c
@@ -186,6 +186,18 @@ static void dump_blob(void *blob, bool debug)
continue;
}
+ if (tag == FDT_EXPORT_SYM_REF) {
+ s = p;
+ p = PALIGN(p + strlen(s) + 1, 4);
+ val32 = fdt32_to_cpu(GET_CELL(p));
+ t = p;
+ p = PALIGN(p + strlen(t) + 1, 4);
+
+ printf("%*s// [FDT_EXPORT_SYM_REF] '%s' -> '%s'\n", depth * shift, "",
+ s, t);
+ continue;
+ }
+
fprintf(stderr, "%*s ** Unknown tag 0x%08"PRIx32"\n", depth * shift, "", tag);
break;
}
diff --git a/flattree.c b/flattree.c
index bd52e81..d970259 100644
--- a/flattree.c
+++ b/flattree.c
@@ -49,6 +49,7 @@ struct emitter {
void (*ref_local)(void *);
void (*ref_phandle)(void *);
void (*export_sym)(void *);
+ void (*export_sym_ref)(void *);
};
static void bin_emit_cell(void *e, cell_t val)
@@ -113,6 +114,11 @@ static void bin_emit_export_sym(void *e)
bin_emit_cell(e, FDT_EXPORT_SYM);
}
+static void bin_emit_export_sym_ref(void *e)
+{
+ bin_emit_cell(e, FDT_EXPORT_SYM_REF);
+}
+
static struct emitter bin_emitter = {
.cell = bin_emit_cell,
.string = bin_emit_string,
@@ -124,6 +130,7 @@ static struct emitter bin_emitter = {
.ref_local = bin_emit_ref_local,
.ref_phandle = bin_emit_ref_phandle,
.export_sym = bin_emit_export_sym,
+ .export_sym_ref = bin_emit_export_sym_ref,
};
static void emit_label(FILE *f, const char *prefix, const char *label)
@@ -259,6 +266,14 @@ static void asm_emit_export_sym(void *e)
asm_emit_cell(e, FDT_EXPORT_SYM);
}
+static void asm_emit_export_sym_ref(void *e)
+{
+ FILE *f = e;
+
+ fprintf(f, "\t/* FDT_EXPORT_SYM_REF */\n");
+ asm_emit_cell(e, FDT_EXPORT_SYM_REF);
+}
+
static struct emitter asm_emitter = {
.cell = asm_emit_cell,
.string = asm_emit_string,
@@ -270,6 +285,7 @@ static struct emitter asm_emitter = {
.ref_local = asm_emit_ref_local,
.ref_phandle = asm_emit_ref_phandle,
.export_sym = asm_emit_export_sym,
+ .export_sym = asm_emit_export_sym_ref,
};
static int stringtable_insert(struct data *d, const char *str)
@@ -369,6 +385,18 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
emit->cell(etarget, exportsym->phandle);
continue;
}
+
+ if (exportsym->ref[0] == '/')
+ die("Export symbol uses a non local reference by path (%s)\n",
+ m->ref);
+
+ emit->export_sym_ref(etarget);
+ emit->string(etarget, exportsym->name, 0);
+ emit->align(etarget, sizeof(cell_t));
+ /* Placeholder for the phandle */
+ emit->cell(etarget, exportsym->phandle);
+ emit->string(etarget, exportsym->ref, 0);
+ emit->align(etarget, sizeof(cell_t));
}
}
@@ -838,6 +866,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
uint32_t val;
uint32_t offset;
const char *str;
+ const char *str2;
node = build_node(NULL, NULL, NULL, NULL);
@@ -919,6 +948,17 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
add_symbol(&node->exportsymlist, exportsym);
break;
+ case FDT_EXPORT_SYM_REF:
+ if (!(flags & FTF_EXPORT_IMPORT_SYM))
+ die("FDT_EXPORT_SYM_REF tag found in flat tree"
+ " version <18\n");
+ str = flat_read_string(dtbuf); /* Name */
+ phandle = flat_read_word(dtbuf); /* Phandle */
+ str2 = flat_read_string(dtbuf); /* Ref */
+ exportsym = build_exportsym(str, str2, phandle, NULL);
+ add_symbol(&node->exportsymlist, exportsym);
+ break;
+
default:
die("Invalid opcode word %08x in device tree blob\n",
val);
diff --git a/libfdt/fdt.c b/libfdt/fdt.c
index 44d7399..febfa71 100644
--- a/libfdt/fdt.c
+++ b/libfdt/fdt.c
@@ -248,6 +248,29 @@ uint32_t fdt_next_tag_full(const void *fdt, int startoffset, int *nextoffset)
offset += sizeof(fdt32_t);
break;
+ case FDT_EXPORT_SYM_REF:
+ /* Skip name */
+ do {
+ p = fdt_offset_ptr(fdt, offset++, 1);
+ } while (p && (*p != '\0'));
+ if (!can_assume(VALID_DTB) && !p)
+ return FDT_END; /* premature end */
+ offset = FDT_CELLALIGN(offset);
+
+ /* Skip phandle */
+ tmp32p = fdt_offset_ptr(fdt, offset, sizeof(*tmp32p));
+ if (!can_assume(VALID_DTB) && !tmp32p)
+ return FDT_END; /* premature end */
+ offset += sizeof(fdt32_t);
+
+ /* Skip external name */
+ do {
+ p = fdt_offset_ptr(fdt, offset++, 1);
+ } while (p && (*p != '\0'));
+ if (!can_assume(VALID_DTB) && !p)
+ return FDT_END; /* premature end */
+ break;
+
default:
return FDT_END;
}
@@ -290,6 +313,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
case FDT_REF_LOCAL:
case FDT_REF_PHANDLE:
case FDT_EXPORT_SYM:
+ case FDT_EXPORT_SYM_REF:
/*
* Next tag is a meta-data tag present in the middle
* of the structure -> Skip it and look at next one
diff --git a/libfdt/fdt.h b/libfdt/fdt.h
index e85bc07..c23723b 100644
--- a/libfdt/fdt.h
+++ b/libfdt/fdt.h
@@ -65,6 +65,8 @@ struct fdt_property {
external label */
#define FDT_END 0x9
#define FDT_EXPORT_SYM 0xa /* export symbol: name, phandle value */
+#define FDT_EXPORT_SYM_REF 0xb /* export symbol: name, phandle value (maybe
+ unresolved), external label */
#define FDT_V1_SIZE (7*sizeof(fdt32_t))
#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t))
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 29/77] Add support for FDT_EXPORT_SYM_REF dtb tag
2026-01-12 14:19 ` [RFC PATCH 29/77] Add support for FDT_EXPORT_SYM_REF dtb tag Herve Codina
@ 2026-01-15 6:25 ` David Gibson
2026-01-19 15:46 ` Herve Codina
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-15 6:25 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 8885 bytes --]
On Mon, Jan 12, 2026 at 03:19:19PM +0100, Herve Codina wrote:
> The FDT_EXPORT_SYM_REF dtb tag is similar to the FDT_EXPORT_SYM tag
> except that it identifies a reference to an external phandle. The node
> referenced by the phandle is not present in the device-tree blob.
>
> The FDT_EXPORT_SYM_REF dtb tag is a meta-data tag defining an exported
> symbol. It can be present in a node bloc meaning that a symbol is
> exported at this node level. The node pointed to by this symbol is not a
> local node (i.e. the node is not present in the device-tree blob.). This
> tag can be available only in overlay or addon device-tree blobs. The
> symbol has to be resolved when the device-tree blob is applied on top of
> a base device-tree.
>
> It is followed by three values and a possible alignment padding:
> - name (string including \0)
> The export symbol name. I.e. the name used to reference this
> exported symbol.
> - padding:
> Padding (0x00) added to have the next value aligned on 32bit.
> - phandle (32bit)
> A placeholder for a phandle value.
> This placeholder can be used during some dtb manipulation to store
> a temporary phandle value.
Yuck.
> In terms of FDT_EXPORT_SYM_REF definition, it has no meaningful
> signification and will be probably set to 0xffffffff, the
> unresolved phandle value.
> - label (string including \0):
> The label to use to resolve this symbol. This label is the
> reference to the external phandle.
> - padding:
> Padding (0x00) added to have the next value aligned on 32bit.
>
> Example:
> FDT_EXPORT_SYM_REF 'foo1' 0x00 0x00 0x00 0xffffffff 'foo_a' 0x00 0x00
>
> This means that 'foo1' is an exported symbol and the node referenced
> by this symbol is external to the dtb (unresolved symbol). This
> external node is referenced by the "foo_a" label.
>
> This is what is encoded in the dtb when the related dts has the
> following exported symbol defined:
> /export/ foo1: &foo_a;
> with 'foo_a' a reference to a non local node.
>
> If several non local symbols are exported at a given node level, several
> FDT_EXPORT_SYM_REF are present. Each of them defining one symbol.
>
> For instance, exporting 'foo1' pointing the node referenced by 'foo_a'
> and exporting 'bar1' pointing to the node referenced by 'bar_b' leads to
> the following sequence:
> FDT_EXPORT_SYM_REF 'foo1' 0x00 0x00 0x00 'foo_a' 0x00 0x00
> FDT_EXPORT_SYM_REF 'bar1' 0x00 0x00 0x00 'bar_b' 0x00 0x00
>
> Add support for this new dtb tag.
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> fdtdump.c | 12 ++++++++++++
> flattree.c | 40 ++++++++++++++++++++++++++++++++++++++++
> libfdt/fdt.c | 24 ++++++++++++++++++++++++
> libfdt/fdt.h | 2 ++
> 4 files changed, 78 insertions(+)
>
> diff --git a/fdtdump.c b/fdtdump.c
> index d1af5b6..8baadc4 100644
> --- a/fdtdump.c
> +++ b/fdtdump.c
> @@ -186,6 +186,18 @@ static void dump_blob(void *blob, bool debug)
> continue;
> }
>
> + if (tag == FDT_EXPORT_SYM_REF) {
> + s = p;
> + p = PALIGN(p + strlen(s) + 1, 4);
> + val32 = fdt32_to_cpu(GET_CELL(p));
> + t = p;
> + p = PALIGN(p + strlen(t) + 1, 4);
> +
> + printf("%*s// [FDT_EXPORT_SYM_REF] '%s' -> '%s'\n", depth * shift, "",
> + s, t);
> + continue;
> + }
> +
> fprintf(stderr, "%*s ** Unknown tag 0x%08"PRIx32"\n", depth * shift, "", tag);
> break;
> }
> diff --git a/flattree.c b/flattree.c
> index bd52e81..d970259 100644
> --- a/flattree.c
> +++ b/flattree.c
> @@ -49,6 +49,7 @@ struct emitter {
> void (*ref_local)(void *);
> void (*ref_phandle)(void *);
> void (*export_sym)(void *);
> + void (*export_sym_ref)(void *);
> };
>
> static void bin_emit_cell(void *e, cell_t val)
> @@ -113,6 +114,11 @@ static void bin_emit_export_sym(void *e)
> bin_emit_cell(e, FDT_EXPORT_SYM);
> }
>
> +static void bin_emit_export_sym_ref(void *e)
> +{
> + bin_emit_cell(e, FDT_EXPORT_SYM_REF);
> +}
> +
> static struct emitter bin_emitter = {
> .cell = bin_emit_cell,
> .string = bin_emit_string,
> @@ -124,6 +130,7 @@ static struct emitter bin_emitter = {
> .ref_local = bin_emit_ref_local,
> .ref_phandle = bin_emit_ref_phandle,
> .export_sym = bin_emit_export_sym,
> + .export_sym_ref = bin_emit_export_sym_ref,
> };
>
> static void emit_label(FILE *f, const char *prefix, const char *label)
> @@ -259,6 +266,14 @@ static void asm_emit_export_sym(void *e)
> asm_emit_cell(e, FDT_EXPORT_SYM);
> }
>
> +static void asm_emit_export_sym_ref(void *e)
> +{
> + FILE *f = e;
> +
> + fprintf(f, "\t/* FDT_EXPORT_SYM_REF */\n");
> + asm_emit_cell(e, FDT_EXPORT_SYM_REF);
> +}
> +
> static struct emitter asm_emitter = {
> .cell = asm_emit_cell,
> .string = asm_emit_string,
> @@ -270,6 +285,7 @@ static struct emitter asm_emitter = {
> .ref_local = asm_emit_ref_local,
> .ref_phandle = asm_emit_ref_phandle,
> .export_sym = asm_emit_export_sym,
> + .export_sym = asm_emit_export_sym_ref,
> };
>
> static int stringtable_insert(struct data *d, const char *str)
> @@ -369,6 +385,18 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
> emit->cell(etarget, exportsym->phandle);
> continue;
> }
> +
> + if (exportsym->ref[0] == '/')
> + die("Export symbol uses a non local reference by path (%s)\n",
> + m->ref);
> +
> + emit->export_sym_ref(etarget);
> + emit->string(etarget, exportsym->name, 0);
> + emit->align(etarget, sizeof(cell_t));
> + /* Placeholder for the phandle */
> + emit->cell(etarget, exportsym->phandle);
> + emit->string(etarget, exportsym->ref, 0);
> + emit->align(etarget, sizeof(cell_t));
> }
> }
>
> @@ -838,6 +866,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
> uint32_t val;
> uint32_t offset;
> const char *str;
> + const char *str2;
>
> node = build_node(NULL, NULL, NULL, NULL);
>
> @@ -919,6 +948,17 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
> add_symbol(&node->exportsymlist, exportsym);
> break;
>
> + case FDT_EXPORT_SYM_REF:
> + if (!(flags & FTF_EXPORT_IMPORT_SYM))
> + die("FDT_EXPORT_SYM_REF tag found in flat tree"
> + " version <18\n");
> + str = flat_read_string(dtbuf); /* Name */
> + phandle = flat_read_word(dtbuf); /* Phandle */
> + str2 = flat_read_string(dtbuf); /* Ref */
> + exportsym = build_exportsym(str, str2, phandle, NULL);
> + add_symbol(&node->exportsymlist, exportsym);
> + break;
> +
> default:
> die("Invalid opcode word %08x in device tree blob\n",
> val);
> diff --git a/libfdt/fdt.c b/libfdt/fdt.c
> index 44d7399..febfa71 100644
> --- a/libfdt/fdt.c
> +++ b/libfdt/fdt.c
> @@ -248,6 +248,29 @@ uint32_t fdt_next_tag_full(const void *fdt, int startoffset, int *nextoffset)
> offset += sizeof(fdt32_t);
> break;
>
> + case FDT_EXPORT_SYM_REF:
> + /* Skip name */
> + do {
> + p = fdt_offset_ptr(fdt, offset++, 1);
> + } while (p && (*p != '\0'));
> + if (!can_assume(VALID_DTB) && !p)
> + return FDT_END; /* premature end */
> + offset = FDT_CELLALIGN(offset);
> +
> + /* Skip phandle */
> + tmp32p = fdt_offset_ptr(fdt, offset, sizeof(*tmp32p));
> + if (!can_assume(VALID_DTB) && !tmp32p)
> + return FDT_END; /* premature end */
> + offset += sizeof(fdt32_t);
> +
> + /* Skip external name */
> + do {
> + p = fdt_offset_ptr(fdt, offset++, 1);
> + } while (p && (*p != '\0'));
> + if (!can_assume(VALID_DTB) && !p)
> + return FDT_END; /* premature end */
> + break;
> +
> default:
> return FDT_END;
> }
> @@ -290,6 +313,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
> case FDT_REF_LOCAL:
> case FDT_REF_PHANDLE:
> case FDT_EXPORT_SYM:
> + case FDT_EXPORT_SYM_REF:
> /*
> * Next tag is a meta-data tag present in the middle
> * of the structure -> Skip it and look at next one
> diff --git a/libfdt/fdt.h b/libfdt/fdt.h
> index e85bc07..c23723b 100644
> --- a/libfdt/fdt.h
> +++ b/libfdt/fdt.h
> @@ -65,6 +65,8 @@ struct fdt_property {
> external label */
> #define FDT_END 0x9
> #define FDT_EXPORT_SYM 0xa /* export symbol: name, phandle value */
> +#define FDT_EXPORT_SYM_REF 0xb /* export symbol: name, phandle value (maybe
> + unresolved), external label */
>
> #define FDT_V1_SIZE (7*sizeof(fdt32_t))
> #define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t))
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 29/77] Add support for FDT_EXPORT_SYM_REF dtb tag
2026-01-15 6:25 ` David Gibson
@ 2026-01-19 15:46 ` Herve Codina
2026-01-29 1:36 ` David Gibson
0 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-19 15:46 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
Hi David,
On Thu, 15 Jan 2026 17:25:58 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Mon, Jan 12, 2026 at 03:19:19PM +0100, Herve Codina wrote:
> > The FDT_EXPORT_SYM_REF dtb tag is similar to the FDT_EXPORT_SYM tag
> > except that it identifies a reference to an external phandle. The node
> > referenced by the phandle is not present in the device-tree blob.
> >
> > The FDT_EXPORT_SYM_REF dtb tag is a meta-data tag defining an exported
> > symbol. It can be present in a node bloc meaning that a symbol is
> > exported at this node level. The node pointed to by this symbol is not a
> > local node (i.e. the node is not present in the device-tree blob.). This
> > tag can be available only in overlay or addon device-tree blobs. The
> > symbol has to be resolved when the device-tree blob is applied on top of
> > a base device-tree.
> >
> > It is followed by three values and a possible alignment padding:
> > - name (string including \0)
> > The export symbol name. I.e. the name used to reference this
> > exported symbol.
> > - padding:
> > Padding (0x00) added to have the next value aligned on 32bit.
> > - phandle (32bit)
> > A placeholder for a phandle value.
> > This placeholder can be used during some dtb manipulation to store
> > a temporary phandle value.
>
> Yuck.
Will see what I can do to avoid this placeholder.
I need to store the phandle value related to this symbol during the symbol
resolution. This is done by addon_resolve_phandles() available in
libfdt/fdt_addon.c in patch 70.
libfdt is not designed to perform allocation to store temporary values. It
manipulates data directly mapped from dtb working with offset in dtb blob
without any other kind of object. No specific objects (C struct) for node,
properties, markers, ...
To have an area for this phandle value, a room reserved in dtb was really
the easier way.
But well, I understand your "yuck".
I think it will be quite tricky to store this temporary phandle value
without allocating some additional data.
This placeholder simplified a lot of things but well, I think I need to find
an other solution.
If anyone has any ideas to store the temporary phandle value, I am all ears.
Best regards,
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 29/77] Add support for FDT_EXPORT_SYM_REF dtb tag
2026-01-19 15:46 ` Herve Codina
@ 2026-01-29 1:36 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-29 1:36 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 3286 bytes --]
On Mon, Jan 19, 2026 at 04:46:28PM +0100, Herve Codina wrote:
> Hi David,
>
> On Thu, 15 Jan 2026 17:25:58 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > On Mon, Jan 12, 2026 at 03:19:19PM +0100, Herve Codina wrote:
> > > The FDT_EXPORT_SYM_REF dtb tag is similar to the FDT_EXPORT_SYM tag
> > > except that it identifies a reference to an external phandle. The node
> > > referenced by the phandle is not present in the device-tree blob.
> > >
> > > The FDT_EXPORT_SYM_REF dtb tag is a meta-data tag defining an exported
> > > symbol. It can be present in a node bloc meaning that a symbol is
> > > exported at this node level. The node pointed to by this symbol is not a
> > > local node (i.e. the node is not present in the device-tree blob.). This
> > > tag can be available only in overlay or addon device-tree blobs. The
> > > symbol has to be resolved when the device-tree blob is applied on top of
> > > a base device-tree.
> > >
> > > It is followed by three values and a possible alignment padding:
> > > - name (string including \0)
> > > The export symbol name. I.e. the name used to reference this
> > > exported symbol.
> > > - padding:
> > > Padding (0x00) added to have the next value aligned on 32bit.
> > > - phandle (32bit)
> > > A placeholder for a phandle value.
> > > This placeholder can be used during some dtb manipulation to store
> > > a temporary phandle value.
> >
> > Yuck.
>
> Will see what I can do to avoid this placeholder.
>
> I need to store the phandle value related to this symbol during the symbol
> resolution. This is done by addon_resolve_phandles() available in
> libfdt/fdt_addon.c in patch 70.
>
> libfdt is not designed to perform allocation to store temporary values. It
> manipulates data directly mapped from dtb working with offset in dtb blob
> without any other kind of object. No specific objects (C struct) for node,
> properties, markers, ...
I know. I designed it that way.
Tangent: I have thought that it might be useful to have a diffferent
dt library designed for non-flat trees - i.e. using allocations and
pointers to allow O(1) edits (as well as import/export to flat tree,
of course). I think that would better suit some of the more complex
tree manipulation many things are doing these days. I've never had
remotely enough time to look into it, but fwiw, I think the idea's
good.
> To have an area for this phandle value, a room reserved in dtb was really
> the easier way.
>
> But well, I understand your "yuck".
Yeah, I do realise that lack of free space to put things can make
things really tricky. I hope we can find a way around this.
> I think it will be quite tricky to store this temporary phandle value
> without allocating some additional data.
>
> This placeholder simplified a lot of things but well, I think I need to find
> an other solution.
>
> If anyone has any ideas to store the temporary phandle value, I am all ears.
>
> Best regards,
> Hervé
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 30/77] tests: metadata: Add export symbols with external references tests
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (28 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 29/77] Add support for FDT_EXPORT_SYM_REF dtb tag Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 31/77] dtc: Introduce import symbols Herve Codina
` (49 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Add tests related to export symbols using external references
(FDT_EXPORT_SYM_REF dtb tag).
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
tests/metadata_exportsyms_ref.dtb.dts.expect | 25 +++++++++++++++++++
tests/metadata_exportsyms_ref.dtb.expect | 18 ++++++++++++++
tests/metadata_exportsyms_ref.dts | 26 ++++++++++++++++++++
tests/metadata_exportsyms_ref.dts.dts.expect | 25 +++++++++++++++++++
tests/run_tests.sh | 3 ++-
5 files changed, 96 insertions(+), 1 deletion(-)
create mode 100644 tests/metadata_exportsyms_ref.dtb.dts.expect
create mode 100644 tests/metadata_exportsyms_ref.dtb.expect
create mode 100644 tests/metadata_exportsyms_ref.dts
create mode 100644 tests/metadata_exportsyms_ref.dts.dts.expect
diff --git a/tests/metadata_exportsyms_ref.dtb.dts.expect b/tests/metadata_exportsyms_ref.dtb.dts.expect
new file mode 100644
index 0000000..d2c3320
--- /dev/null
+++ b/tests/metadata_exportsyms_ref.dtb.dts.expect
@@ -0,0 +1,25 @@
+/dts-v1/;
+/addon/;
+
+/ {
+
+ node-a {
+ };
+
+ node-b {
+ };
+
+ node-c {
+
+ sub-node {
+
+ /export/ ref_base_node_a: &base_node_a;
+ /export/ ref_base_node_b: &base_node_b;
+ };
+ };
+
+ node-d {
+
+ /export/ ref_base_node_c: &base_node_c;
+ };
+};
diff --git a/tests/metadata_exportsyms_ref.dtb.expect b/tests/metadata_exportsyms_ref.dtb.expect
new file mode 100644
index 0000000..395861b
--- /dev/null
+++ b/tests/metadata_exportsyms_ref.dtb.expect
@@ -0,0 +1,18 @@
+/dts-v1/;
+/addon/;
+
+/ {
+ node-a {
+ };
+ node-b {
+ };
+ node-c {
+ sub-node {
+ // [FDT_EXPORT_SYM_REF] 'ref_base_node_a' -> 'base_node_a'
+ // [FDT_EXPORT_SYM_REF] 'ref_base_node_b' -> 'base_node_b'
+ };
+ };
+ node-d {
+ // [FDT_EXPORT_SYM_REF] 'ref_base_node_c' -> 'base_node_c'
+ };
+};
diff --git a/tests/metadata_exportsyms_ref.dts b/tests/metadata_exportsyms_ref.dts
new file mode 100644
index 0000000..c094be1
--- /dev/null
+++ b/tests/metadata_exportsyms_ref.dts
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+/addon/;
+
+/ {
+ node-a {
+ };
+
+ node-b {
+ };
+
+ node-c {
+ sub_node: sub-node {
+ /export/ ref_base_node_a: &base_node_a;
+ /export/ ref_base_node_b: &base_node_b;
+ };
+ };
+
+ node-d {
+ /export/ ref_base_node_c: &base_node_c;
+ };
+};
diff --git a/tests/metadata_exportsyms_ref.dts.dts.expect b/tests/metadata_exportsyms_ref.dts.dts.expect
new file mode 100644
index 0000000..2654df1
--- /dev/null
+++ b/tests/metadata_exportsyms_ref.dts.dts.expect
@@ -0,0 +1,25 @@
+/dts-v1/;
+/addon/;
+
+/ {
+
+ node-a {
+ };
+
+ node-b {
+ };
+
+ node-c {
+
+ sub_node: sub-node {
+
+ /export/ ref_base_node_a: &base_node_a;
+ /export/ ref_base_node_b: &base_node_b;
+ };
+ };
+
+ node-d {
+
+ /export/ ref_base_node_c: &base_node_c;
+ };
+};
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index fc270e2..1973525 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1126,7 +1126,8 @@ wrap_fdtdump () {
metadata_tests() {
for dt in metadata_reflocal metadata_refphandle \
- metadata_addon_base metadata_exportsyms_local; do
+ metadata_addon_base metadata_exportsyms_local \
+ metadata_exportsyms_ref; do
run_dtc_test -I dts -O dts -o $dt.dts.dts "$SRCDIR/$dt.dts"
base_run_test check_diff $dt.dts.dts "$SRCDIR/$dt.dts.dts.expect"
run_dtc_test -I dts -O dtb -o $dt.dtb "$SRCDIR/$dt.dts"
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 31/77] dtc: Introduce import symbols
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (29 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 30/77] tests: metadata: Add export symbols with external references tests Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 32/77] dtc-parser: Introduce last_header_flags Herve Codina
` (48 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Import symbols allow to define a list of symbols imported and used by an
addon.
Those symbols have to be resolved when the addon is applied on a base
device-tree and will involved exported symbols provided at the node the
addon is applied to.
Import symbols are similar in term of feature to __fixups__ available
in device-tree overlays.
The goal is to identify symbols which are used by an addon but not
defined by the addon itself. Those specific symbols are the imported
symbols.
Introduce the import symbols list related to an addon. No functional
change yet but preparation for the future support for import symbol
parsing.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
dtc-parser.y | 3 ++-
dtc.h | 4 +++-
flattree.c | 2 +-
fstree.c | 2 +-
livetree.c | 4 +++-
5 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/dtc-parser.y b/dtc-parser.y
index a0d0aef..4e46e9d 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -113,7 +113,8 @@ sourcefile:
headers memreserves devicetree
{
parser_output = build_dt_info($1, $2, $3,
- guess_boot_cpuid($3));
+ guess_boot_cpuid($3),
+ NULL);
}
;
diff --git a/dtc.h b/dtc.h
index 22816ba..796ed51 100644
--- a/dtc.h
+++ b/dtc.h
@@ -350,6 +350,7 @@ struct dt_info {
struct reserve_info *reservelist;
uint32_t boot_cpuid_phys;
struct node *dt; /* the device tree */
+ struct symbol *importsymlist; /* Import symbol list */
const char *outname; /* filename being written to, "-" for stdout */
};
@@ -360,7 +361,8 @@ struct dt_info {
struct dt_info *build_dt_info(unsigned int dtsflags,
struct reserve_info *reservelist,
- struct node *tree, uint32_t boot_cpuid_phys);
+ struct node *tree, uint32_t boot_cpuid_phys,
+ struct symbol *importsymlist);
void sort_tree(struct dt_info *dti);
void generate_label_tree(struct dt_info *dti, const char *name, bool allocph);
void generate_fixups_tree(struct dt_info *dti, const char *name);
diff --git a/flattree.c b/flattree.c
index d970259..47a289f 100644
--- a/flattree.c
+++ b/flattree.c
@@ -1105,5 +1105,5 @@ struct dt_info *dt_from_blob(const char *fname)
fclose(f);
- return build_dt_info(DTSF_V1 | dtsflags, reservelist, tree, boot_cpuid_phys);
+ return build_dt_info(DTSF_V1 | dtsflags, reservelist, tree, boot_cpuid_phys, NULL);
}
diff --git a/fstree.c b/fstree.c
index 445ae53..a6aaf1e 100644
--- a/fstree.c
+++ b/fstree.c
@@ -72,5 +72,5 @@ struct dt_info *dt_from_fs(const char *dirname)
tree = read_fstree(dirname);
tree = name_node(tree, "");
- return build_dt_info(DTSF_V1, NULL, tree, guess_boot_cpuid(tree));
+ return build_dt_info(DTSF_V1, NULL, tree, guess_boot_cpuid(tree), NULL);
}
diff --git a/livetree.c b/livetree.c
index 1de5990..4ec9609 100644
--- a/livetree.c
+++ b/livetree.c
@@ -531,7 +531,8 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
struct dt_info *build_dt_info(unsigned int dtsflags,
struct reserve_info *reservelist,
- struct node *tree, uint32_t boot_cpuid_phys)
+ struct node *tree, uint32_t boot_cpuid_phys,
+ struct symbol *importsymlist)
{
struct dt_info *dti;
@@ -540,6 +541,7 @@ struct dt_info *build_dt_info(unsigned int dtsflags,
dti->reservelist = reservelist;
dti->dt = tree;
dti->boot_cpuid_phys = boot_cpuid_phys;
+ dti->importsymlist = importsymlist;
return dti;
}
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 32/77] dtc-parser: Introduce last_header_flags
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (30 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 31/77] dtc: Introduce import symbols Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-15 6:31 ` David Gibson
2026-01-12 14:19 ` [RFC PATCH 33/77] dtc: Add support for /import/ dts keyword parsing Herve Codina
` (47 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The parser needs to get header flags value in different places.
It relies on the fact that the rule used to parse the dts file is always
headers memreserves devicetree
With that only rule to parse the file, it uses '$<flags>-1' construct to
get the flags value.
With the future introduction of import symbols parsing, this rule will
change and the parser couldn't rely anymore on '$<flags>-1' to get flags
value. Indeed, import symbols parsing will add a new optional symbol in
this rule leading to two possible rules (with and without the new
symbol) to parse the source file.
Introduce the last_header_flags variable to explicitly keep track of
flags while also being agnostic of the rule structure and use this new
variable instead of '$<flags>-1'.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
dtc-parser.y | 28 +++++++++-------------------
1 file changed, 9 insertions(+), 19 deletions(-)
diff --git a/dtc-parser.y b/dtc-parser.y
index 4e46e9d..48c40e8 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -24,6 +24,8 @@ extern void yyerror(char const *s);
extern struct dt_info *parser_output;
extern bool treesource_error;
+unsigned int last_header_flags;
+
static bool is_ref_relative(const char *ref)
{
return ref[0] != '/' && strchr(&ref[1], '/');
@@ -122,14 +124,17 @@ header:
DT_V1 ';'
{
$$ = DTSF_V1;
+ last_header_flags = $$;
}
| DT_V1 ';' DT_PLUGIN ';'
{
$$ = DTSF_V1 | DTSF_PLUGIN;
+ last_header_flags = $$;
}
| DT_V1 ';' DT_ADDON ';'
{
$$ = DTSF_V1 | DTSF_ADDON;
+ last_header_flags = $$;
}
;
@@ -179,12 +184,7 @@ devicetree:
}
| dt_ref nodedef
{
- /*
- * We rely on the rule being always:
- * versioninfo plugindecl memreserves devicetree
- * so $-1 is what we want (plugindecl)
- */
- if (!($<flags>-1 & DTSF_PLUGIN))
+ if (!(last_header_flags & DTSF_PLUGIN))
ERROR(&@2, "Label or path %s not found", $1);
else if (is_ref_relative($1))
ERROR(&@2, "Label-relative reference %s not supported in plugin", $1);
@@ -197,7 +197,7 @@ devicetree:
{
struct node *target = get_node_by_ref($1, $3);
- if (($<flags>-1 & DTSF_PLUGIN) && is_ref_relative($3))
+ if ((last_header_flags & DTSF_PLUGIN) && is_ref_relative($3))
ERROR(&@2, "Label-relative reference %s not supported in plugin", $3);
if (target) {
@@ -209,12 +209,7 @@ devicetree:
}
| devicetree DT_PATH_REF nodedef
{
- /*
- * We rely on the rule being always:
- * versioninfo plugindecl memreserves devicetree
- * so $-1 is what we want (plugindecl)
- */
- if ($<flags>-1 & DTSF_PLUGIN) {
+ if (last_header_flags & DTSF_PLUGIN) {
if (is_ref_relative($2))
ERROR(&@2, "Label-relative reference %s not supported in plugin", $2);
add_orphan_node($1, $3, $2);
@@ -235,12 +230,7 @@ devicetree:
if (target) {
merge_nodes(target, $3);
} else {
- /*
- * We rely on the rule being always:
- * versioninfo plugindecl memreserves devicetree
- * so $-1 is what we want (plugindecl)
- */
- if ($<flags>-1 & DTSF_PLUGIN)
+ if (last_header_flags & DTSF_PLUGIN)
add_orphan_node($1, $3, $2);
else
ERROR(&@2, "Label or path %s not found", $2);
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 32/77] dtc-parser: Introduce last_header_flags
2026-01-12 14:19 ` [RFC PATCH 32/77] dtc-parser: Introduce last_header_flags Herve Codina
@ 2026-01-15 6:31 ` David Gibson
2026-01-19 14:11 ` Herve Codina
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-15 6:31 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 4005 bytes --]
On Mon, Jan 12, 2026 at 03:19:22PM +0100, Herve Codina wrote:
> The parser needs to get header flags value in different places.
>
> It relies on the fact that the rule used to parse the dts file is always
> headers memreserves devicetree
>
> With that only rule to parse the file, it uses '$<flags>-1' construct to
> get the flags value.
>
> With the future introduction of import symbols parsing, this rule will
> change and the parser couldn't rely anymore on '$<flags>-1' to get flags
> value. Indeed, import symbols parsing will add a new optional symbol in
> this rule leading to two possible rules (with and without the new
> symbol) to parse the source file.
>
> Introduce the last_header_flags variable to explicitly keep track of
> flags while also being agnostic of the rule structure and use this new
> variable instead of '$<flags>-1'.
I'm not sure this approach is safe: I'm not sure bison guarantees that
semantic rules will always be executed in the same order, so using
global variables is risky.
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> dtc-parser.y | 28 +++++++++-------------------
> 1 file changed, 9 insertions(+), 19 deletions(-)
>
> diff --git a/dtc-parser.y b/dtc-parser.y
> index 4e46e9d..48c40e8 100644
> --- a/dtc-parser.y
> +++ b/dtc-parser.y
> @@ -24,6 +24,8 @@ extern void yyerror(char const *s);
> extern struct dt_info *parser_output;
> extern bool treesource_error;
>
> +unsigned int last_header_flags;
> +
> static bool is_ref_relative(const char *ref)
> {
> return ref[0] != '/' && strchr(&ref[1], '/');
> @@ -122,14 +124,17 @@ header:
> DT_V1 ';'
> {
> $$ = DTSF_V1;
> + last_header_flags = $$;
> }
> | DT_V1 ';' DT_PLUGIN ';'
> {
> $$ = DTSF_V1 | DTSF_PLUGIN;
> + last_header_flags = $$;
> }
> | DT_V1 ';' DT_ADDON ';'
> {
> $$ = DTSF_V1 | DTSF_ADDON;
> + last_header_flags = $$;
> }
> ;
>
> @@ -179,12 +184,7 @@ devicetree:
> }
> | dt_ref nodedef
> {
> - /*
> - * We rely on the rule being always:
> - * versioninfo plugindecl memreserves devicetree
> - * so $-1 is what we want (plugindecl)
> - */
> - if (!($<flags>-1 & DTSF_PLUGIN))
> + if (!(last_header_flags & DTSF_PLUGIN))
> ERROR(&@2, "Label or path %s not found", $1);
> else if (is_ref_relative($1))
> ERROR(&@2, "Label-relative reference %s not supported in plugin", $1);
> @@ -197,7 +197,7 @@ devicetree:
> {
> struct node *target = get_node_by_ref($1, $3);
>
> - if (($<flags>-1 & DTSF_PLUGIN) && is_ref_relative($3))
> + if ((last_header_flags & DTSF_PLUGIN) && is_ref_relative($3))
> ERROR(&@2, "Label-relative reference %s not supported in plugin", $3);
>
> if (target) {
> @@ -209,12 +209,7 @@ devicetree:
> }
> | devicetree DT_PATH_REF nodedef
> {
> - /*
> - * We rely on the rule being always:
> - * versioninfo plugindecl memreserves devicetree
> - * so $-1 is what we want (plugindecl)
> - */
> - if ($<flags>-1 & DTSF_PLUGIN) {
> + if (last_header_flags & DTSF_PLUGIN) {
> if (is_ref_relative($2))
> ERROR(&@2, "Label-relative reference %s not supported in plugin", $2);
> add_orphan_node($1, $3, $2);
> @@ -235,12 +230,7 @@ devicetree:
> if (target) {
> merge_nodes(target, $3);
> } else {
> - /*
> - * We rely on the rule being always:
> - * versioninfo plugindecl memreserves devicetree
> - * so $-1 is what we want (plugindecl)
> - */
> - if ($<flags>-1 & DTSF_PLUGIN)
> + if (last_header_flags & DTSF_PLUGIN)
> add_orphan_node($1, $3, $2);
> else
> ERROR(&@2, "Label or path %s not found", $2);
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 32/77] dtc-parser: Introduce last_header_flags
2026-01-15 6:31 ` David Gibson
@ 2026-01-19 14:11 ` Herve Codina
2026-01-21 2:37 ` David Gibson
0 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-19 14:11 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
On Thu, 15 Jan 2026 17:31:24 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Mon, Jan 12, 2026 at 03:19:22PM +0100, Herve Codina wrote:
> > The parser needs to get header flags value in different places.
> >
> > It relies on the fact that the rule used to parse the dts file is always
> > headers memreserves devicetree
> >
> > With that only rule to parse the file, it uses '$<flags>-1' construct to
> > get the flags value.
> >
> > With the future introduction of import symbols parsing, this rule will
> > change and the parser couldn't rely anymore on '$<flags>-1' to get flags
> > value. Indeed, import symbols parsing will add a new optional symbol in
> > this rule leading to two possible rules (with and without the new
> > symbol) to parse the source file.
> >
> > Introduce the last_header_flags variable to explicitly keep track of
> > flags while also being agnostic of the rule structure and use this new
> > variable instead of '$<flags>-1'.
>
> I'm not sure this approach is safe: I'm not sure bison guarantees that
> semantic rules will always be executed in the same order, so using
> global variables is risky.
if rules were not executed in the same order '$<flags>-1' construct would
not work.
The problem is not the order. I don't think the order will change. The
problem is related to the number of items on stack.
With import symbols, that the stack will be:
header memreserved devicetree
or
header memreserved importsyms devicetree
Using '$-1' will no more be possible. Indeed, '$-1' from the devicetree
rule will reference 'header' in one case and 'memreserved' in the other
case.
Without a global variable, I don't know how to reference 'header' (or flags
value) in all cases.
Any better ideas are welcome.
Best regards,
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 32/77] dtc-parser: Introduce last_header_flags
2026-01-19 14:11 ` Herve Codina
@ 2026-01-21 2:37 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-21 2:37 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 2372 bytes --]
On Mon, Jan 19, 2026 at 03:11:45PM +0100, Herve Codina wrote:
> On Thu, 15 Jan 2026 17:31:24 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > On Mon, Jan 12, 2026 at 03:19:22PM +0100, Herve Codina wrote:
> > > The parser needs to get header flags value in different places.
> > >
> > > It relies on the fact that the rule used to parse the dts file is always
> > > headers memreserves devicetree
> > >
> > > With that only rule to parse the file, it uses '$<flags>-1' construct to
> > > get the flags value.
> > >
> > > With the future introduction of import symbols parsing, this rule will
> > > change and the parser couldn't rely anymore on '$<flags>-1' to get flags
> > > value. Indeed, import symbols parsing will add a new optional symbol in
> > > this rule leading to two possible rules (with and without the new
> > > symbol) to parse the source file.
> > >
> > > Introduce the last_header_flags variable to explicitly keep track of
> > > flags while also being agnostic of the rule structure and use this new
> > > variable instead of '$<flags>-1'.
> >
> > I'm not sure this approach is safe: I'm not sure bison guarantees that
> > semantic rules will always be executed in the same order, so using
> > global variables is risky.
>
> if rules were not executed in the same order '$<flags>-1' construct would
> not work.
Uhh.. I'm pretty sure $<flags>-1 only depends on the parse tree
structure, not the order in which the actual semantic rule code
fragments run.
> The problem is not the order. I don't think the order will change. The
> problem is related to the number of items on stack.
>
> With import symbols, that the stack will be:
> header memreserved devicetree
> or
> header memreserved importsyms devicetree
>
> Using '$-1' will no more be possible. Indeed, '$-1' from the devicetree
> rule will reference 'header' in one case and 'memreserved' in the other
> case.
>
> Without a global variable, I don't know how to reference 'header' (or flags
> value) in all cases.
>
> Any better ideas are welcome.
Ok, I'll try to look into it and see what I can come up with.
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 33/77] dtc: Add support for /import/ dts keyword parsing
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (31 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 32/77] dtc-parser: Introduce last_header_flags Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 34/77] dtc: Add import symbols (/import/ keyword) in generated dts file Herve Codina
` (46 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The /import/ dts keyword is the keyword used to define an imported
symbol used by an addon device-tree.
An imported symbol is not related to a specific node and it is global to
a whole addon. It can be present after the header definition (and the
possible memreserves definition) and before the devicetree nodes
definition.
If several symbols are imported, several /import/ keyword are present.
The syntax used is the following:
/import/ name: compatible;
with:
name: The name of the imported symbol
compatible: a string indicating the kind of symbol is expected. This
compatible string can be used when the addon is applied in
order to help the symbol resolution.
For instance:
/import/ foo: "bar, foo";
The foo symbol is expected by the addon and should be "bar, foo"
compatible.
The addon uses this symbol (i.e. it references it) but it doesn't
define the symbol itself.
From the addon point of view, foo is an unresolved symbol and it will
be resolved when the addon is applied.
Add support for /import/ dts keyword.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
dtc-lexer.l | 6 ++++++
dtc-parser.y | 45 +++++++++++++++++++++++++++++++++++++++++++++
dtc.h | 3 +++
livetree.c | 13 +++++++++++++
4 files changed, 67 insertions(+)
diff --git a/dtc-lexer.l b/dtc-lexer.l
index 90fe70e..cb616f9 100644
--- a/dtc-lexer.l
+++ b/dtc-lexer.l
@@ -155,6 +155,12 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
return DT_EXPORT;
}
+<*>"/import/" {
+ DPRINT("Keyword: /import/\n");
+ BEGIN_DEFAULT();
+ return DT_IMPORT;
+ }
+
<*>{LABEL}: {
DPRINT("Label: %s\n", yytext);
yylval.labelref = xstrdup(yytext);
diff --git a/dtc-parser.y b/dtc-parser.y
index 48c40e8..61ebde2 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -50,6 +50,7 @@ static bool is_ref_relative(const char *ref)
struct node *nodelist;
struct symbol *symbol;
struct symbol *exportlist;
+ struct symbol *importlist;
struct reserve_info *re;
uint64_t integer;
unsigned int flags;
@@ -65,6 +66,7 @@ static bool is_ref_relative(const char *ref)
%token DT_DEL_NODE
%token DT_OMIT_NO_REF
%token DT_EXPORT
+%token DT_IMPORT
%token <propnodename> DT_PROPNODENAME
%token <integer> DT_LITERAL
%token <integer> DT_CHAR_LITERAL
@@ -87,6 +89,8 @@ static bool is_ref_relative(const char *ref)
%type <proplist> proplist
%type <symbol> exportdef
%type <exportlist> exportlist
+%type <symbol> importdef
+%type <exportlist> importlist
%type <labelref> dt_ref
%type <node> devicetree
@@ -118,6 +122,17 @@ sourcefile:
guess_boot_cpuid($3),
NULL);
}
+ | headers memreserves importlist devicetree
+ {
+ /*
+ * importlist is created with chain_symbol() and so it
+ * is created in reverse order. Reverse it now to have
+ * it in correct order
+ */
+ parser_output = build_dt_info($1, $2, $4,
+ $4 ? guess_boot_cpuid($4) : 0,
+ reverse_symbol($3));
+ }
;
header:
@@ -171,6 +186,36 @@ memreserve:
}
;
+importlist:
+ importdef
+ {
+ $$ = chain_symbol($1, NULL);
+ }
+ | importlist importdef
+ {
+ $$ = chain_symbol($2, $1);
+ }
+ | importlist memreserve
+ {
+ ERROR(&@2, "Mem reserve must precede imports");
+ YYERROR;
+ }
+ ;
+
+importdef:
+ DT_IMPORT DT_LABEL DT_STRING ';'
+ {
+ struct data d = $3;
+
+ if (!(last_header_flags & DTSF_ADDON))
+ ERROR(&@2, "Import symbols supported only in addon");
+
+ $$ = build_importsym($2, d.val, &@$);
+ free($2);
+ data_free($3);
+ }
+ ;
+
dt_ref: DT_LABEL_REF | DT_PATH_REF;
devicetree:
diff --git a/dtc.h b/dtc.h
index 796ed51..4ebe576 100644
--- a/dtc.h
+++ b/dtc.h
@@ -207,6 +207,7 @@ struct label {
struct symbol {
bool is_local;
char *name;
+ char *compatible;
char *ref;
cell_t phandle;
char *fullpath;
@@ -287,6 +288,8 @@ struct property *reverse_properties(struct property *first);
struct symbol *build_exportsym(const char *name, const char *ref, cell_t phandle,
struct srcpos *srcpos);
+struct symbol *build_importsym(const char *name, const char *compatible,
+ struct srcpos *srcpos);
struct symbol *chain_symbol(struct symbol *first, struct symbol *list);
struct symbol *reverse_symbol(struct symbol *list);
void add_symbol(struct symbol **list, struct symbol *new);
diff --git a/livetree.c b/livetree.c
index 4ec9609..dac5359 100644
--- a/livetree.c
+++ b/livetree.c
@@ -51,6 +51,19 @@ struct symbol *build_exportsym(const char *name, const char *ref, cell_t phandle
return new;
}
+struct symbol *build_importsym(const char *name, const char *compatible, struct srcpos *srcpos)
+{
+ struct symbol *new = xmalloc(sizeof(*new));
+
+ memset(new, 0, sizeof(*new));
+
+ new->name = xstrdup(name);
+ new->compatible = xstrdup(compatible);
+ new->srcpos = srcpos_copy(srcpos);
+
+ return new;
+}
+
struct symbol *chain_symbol(struct symbol *first, struct symbol *list)
{
assert(first->next == NULL);
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 34/77] dtc: Add import symbols (/import/ keyword) in generated dts file
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (32 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 33/77] dtc: Add support for /import/ dts keyword parsing Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 35/77] Add support for FDT_IMPORT_SYM dtb tag Herve Codina
` (45 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The import symbols (/import/ keyword) parsing from a dts file is
supported.
Add the support for this keyword in the dts file generation.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
treesource.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/treesource.c b/treesource.c
index 9effe38..04f65bb 100644
--- a/treesource.c
+++ b/treesource.c
@@ -381,6 +381,7 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)
void dt_to_source(FILE *f, struct dt_info *dti)
{
struct reserve_info *re;
+ struct symbol *importsym;
fprintf(f, "/dts-v1/;\n");
if (dti->dtsflags & DTSF_ADDON)
@@ -397,5 +398,14 @@ void dt_to_source(FILE *f, struct dt_info *dti)
(unsigned long long)re->size);
}
+ if (dti->importsymlist) {
+ for_each_symbol(dti->importsymlist, importsym) {
+ fprintf(f, "/import/ %s: \"%s\";\n",
+ importsym->name,
+ importsym->compatible);
+ }
+ fprintf(f, "\n");
+ }
+
write_tree_source_node(f, dti->dt, 0);
}
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 35/77] Add support for FDT_IMPORT_SYM dtb tag
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (33 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 34/77] dtc: Add import symbols (/import/ keyword) in generated dts file Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-15 6:41 ` David Gibson
2026-01-12 14:19 ` [RFC PATCH 36/77] tests: metadata: Add import symbols tests Herve Codina
` (44 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The FDT_IMPORT_SYM dtb tag is a meta-data tag defining an imported
symbol. It can be present globally in an addon dtb (i.e. outside nodes
definition) meaning that this symbol needs to be resolved when the dtb
is applied.
The tag is followed by two values and possible alignment paddings:
- name (string including \0)
The import symbol name. I.e. the name used to reference this
imported symbol.
- padding:
Padding (0x00) added to have the next value aligned on 32bit.
- compatible (string including \0)
The compatible string that can be used for symbol resolution.
This string can be an empty string if it is not relevant.
- padding:
Padding (0x00) added to have the next value aligned on 32bit.
Example:
FDT_IMPORT_SYM 'foo1' 0x00 0x00 0x00 'bar,foo'
This means that 'foo1' is an imported symbol and it is 'bar,foo'
compatible.
This is what is encoded in the dtb when the related dts has the
following imported symbol defined:
/import/ foo1: "bar,foo";
If several symbols are imported, several FDT_IMPORT_SYM are present.
Each of them defining one imported symbol. For instance, importing
'foo1' ("bar,foo" compatible) and 'baz1' ("bar,baz" compatible) leads
to the following sequence:
FDT_IMPORT_SYM 'foo1' 0x00 0x00 0x00 'bar,foo'
FDT_IMPORT_SYM 'baz1' 0x00 0x00 0x00 'bar,baz'
If FDT_IMPORT_SYM tags are present in the dtb, they are present after
the root node definition (i.e. after the FDT_END_NODE related to the
first FDT_BEGIN_NODE).
Add support for this new dtb tag.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
fdtdump.c | 11 +++++++++
flattree.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++-
libfdt/fdt.c | 28 ++++++++++++++++++++++
libfdt/fdt.h | 1 +
4 files changed, 107 insertions(+), 1 deletion(-)
diff --git a/fdtdump.c b/fdtdump.c
index 8baadc4..04e6e38 100644
--- a/fdtdump.c
+++ b/fdtdump.c
@@ -198,6 +198,17 @@ static void dump_blob(void *blob, bool debug)
continue;
}
+ if (tag == FDT_IMPORT_SYM) {
+ s = p;
+ p = PALIGN(p + strlen(s) + 1, 4);
+ t = p;
+ p = PALIGN(p + strlen(t) + 1, 4);
+
+ printf("%*s// [FDT_IMPORT_SYM] '%s' (%s)\n", depth * shift, "",
+ s, t);
+ continue;
+ }
+
fprintf(stderr, "%*s ** Unknown tag 0x%08"PRIx32"\n", depth * shift, "", tag);
break;
}
diff --git a/flattree.c b/flattree.c
index 47a289f..add02f0 100644
--- a/flattree.c
+++ b/flattree.c
@@ -50,6 +50,7 @@ struct emitter {
void (*ref_phandle)(void *);
void (*export_sym)(void *);
void (*export_sym_ref)(void *);
+ void (*import_sym)(void *);
};
static void bin_emit_cell(void *e, cell_t val)
@@ -119,6 +120,11 @@ static void bin_emit_export_sym_ref(void *e)
bin_emit_cell(e, FDT_EXPORT_SYM_REF);
}
+static void bin_emit_import_sym(void *e)
+{
+ bin_emit_cell(e, FDT_IMPORT_SYM);
+}
+
static struct emitter bin_emitter = {
.cell = bin_emit_cell,
.string = bin_emit_string,
@@ -131,6 +137,7 @@ static struct emitter bin_emitter = {
.ref_phandle = bin_emit_ref_phandle,
.export_sym = bin_emit_export_sym,
.export_sym_ref = bin_emit_export_sym_ref,
+ .import_sym = bin_emit_import_sym,
};
static void emit_label(FILE *f, const char *prefix, const char *label)
@@ -274,6 +281,17 @@ static void asm_emit_export_sym_ref(void *e)
asm_emit_cell(e, FDT_EXPORT_SYM_REF);
}
+static void asm_emit_import_sym(void *e)
+{
+ /*
+ * Import symbols are an feature introduced for addons.
+ * Addons device-tree blob have to reason to be in the asm format.
+ *
+ * Need to be implemented if really needed.
+ */
+ die("FDT_IMPORT_SYM not supported in asm output\n");
+}
+
static struct emitter asm_emitter = {
.cell = asm_emit_cell,
.string = asm_emit_string,
@@ -286,6 +304,7 @@ static struct emitter asm_emitter = {
.ref_phandle = asm_emit_ref_phandle,
.export_sym = asm_emit_export_sym,
.export_sym = asm_emit_export_sym_ref,
+ .import_sym = asm_emit_import_sym,
};
static int stringtable_insert(struct data *d, const char *str)
@@ -461,6 +480,26 @@ static void make_fdt_header(struct fdt_header *fdt,
fdt->dt_flags = cpu_to_fdt32(dt_flags);
}
+static void flatten_imports(struct symbol *importsymlist, struct emitter *emit,
+ void *etarget, struct version_info *vi, uint32_t dt_flags)
+{
+ struct symbol *importsym;
+
+ if (!(vi->flags & FTF_EXPORT_IMPORT_SYM))
+ return;
+
+ if (!(dt_flags & FDT_FLAG_ADDON) && importsymlist)
+ die("Only addons can have an import list\n");
+
+ for_each_symbol(importsymlist, importsym) {
+ emit->import_sym(etarget);
+ emit->string(etarget, importsym->name, 0);
+ emit->align(etarget, sizeof(cell_t));
+ emit->string(etarget, importsym->compatible, 0);
+ emit->align(etarget, sizeof(cell_t));
+ }
+}
+
void dt_to_blob(FILE *f, struct dt_info *dti, int version)
{
struct version_info *vi = NULL;
@@ -483,6 +522,7 @@ void dt_to_blob(FILE *f, struct dt_info *dti, int version)
dt_flags |= dti->dtsflags & DTSF_ADDON ? FDT_FLAG_ADDON : 0;
flatten_tree(dti->dt, &bin_emitter, &dtbuf, &strbuf, vi);
+ flatten_imports(dti->importsymlist, &bin_emitter, &dtbuf, vi, dt_flags);
bin_emit_cell(&dtbuf, FDT_END);
reservebuf = flatten_reserve_list(dti->reservelist, vi);
@@ -574,6 +614,9 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
const char *symprefix = "dt";
uint32_t dt_flags = 0;
+ if (dti->importsymlist)
+ die("Import symbols not supported in asm format\n");
+
for (i = 0; i < ARRAY_SIZE(version_table); i++) {
if (version_table[i].version == version)
vi = &version_table[i];
@@ -810,6 +853,16 @@ static struct property *flat_read_property(struct inbuf *dtbuf,
return build_property(name, val, NULL);
}
+static struct symbol *flat_read_importsym(struct inbuf *inb)
+{
+ const char *name;
+ const char *compatible;
+
+ name = flat_read_string(inb);
+ compatible = flat_read_string(inb);
+
+ return build_importsym(name, compatible, NULL);
+}
static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
{
@@ -984,6 +1037,8 @@ struct dt_info *dt_from_blob(const char *fname)
int sizeleft;
struct reserve_info *reservelist;
struct node *tree;
+ struct symbol *importsymlist = NULL;
+ struct symbol *importsym;
uint32_t val;
int flags = 0;
unsigned int dtsflags = 0;
@@ -1098,6 +1153,17 @@ struct dt_info *dt_from_blob(const char *fname)
tree = unflatten_tree(&dtbuf, &strbuf, "", flags);
val = flat_read_word(&dtbuf);
+
+ if (dtsflags & DTSF_ADDON) {
+ if (flags & FTF_EXPORT_IMPORT_SYM) {
+ while (val == FDT_IMPORT_SYM) {
+ importsym = flat_read_importsym(&dtbuf);
+ add_symbol(&importsymlist, importsym);
+ val = flat_read_word(&dtbuf);
+ }
+ }
+ }
+
if (val != FDT_END)
die("Device tree blob doesn't end with FDT_END\n");
@@ -1105,5 +1171,5 @@ struct dt_info *dt_from_blob(const char *fname)
fclose(f);
- return build_dt_info(DTSF_V1 | dtsflags, reservelist, tree, boot_cpuid_phys, NULL);
+ return build_dt_info(DTSF_V1 | dtsflags, reservelist, tree, boot_cpuid_phys, importsymlist);
}
diff --git a/libfdt/fdt.c b/libfdt/fdt.c
index febfa71..c169dd9 100644
--- a/libfdt/fdt.c
+++ b/libfdt/fdt.c
@@ -271,6 +271,23 @@ uint32_t fdt_next_tag_full(const void *fdt, int startoffset, int *nextoffset)
return FDT_END; /* premature end */
break;
+ case FDT_IMPORT_SYM:
+ /* Skip name */
+ do {
+ p = fdt_offset_ptr(fdt, offset++, 1);
+ } while (p && (*p != '\0'));
+ if (!can_assume(VALID_DTB) && !p)
+ return FDT_END; /* premature end */
+ offset = FDT_CELLALIGN(offset);
+
+ /* Skip compatible */
+ do {
+ p = fdt_offset_ptr(fdt, offset++, 1);
+ } while (p && (*p != '\0'));
+ if (!can_assume(VALID_DTB) && !p)
+ return FDT_END; /* premature end */
+ break;
+
default:
return FDT_END;
}
@@ -286,6 +303,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
{
uint32_t tag, tmp_tag;
int tmp_offset, tmp_next;
+ int is_skip_to_end = 0;
/* Retrieve next tag */
tag = fdt_next_tag_full(fdt, startoffset, nextoffset);
@@ -300,6 +318,9 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
case FDT_END_NODE:
case FDT_PROP:
case FDT_NOP:
+ if (is_skip_to_end)
+ break;
+
case FDT_END:
/*
* Next tag is not a meta-data tag -> Ok this next tag
@@ -320,6 +341,13 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
*/
break;
+ case FDT_IMPORT_SYM:
+ /* Those tags are available at the root level, after the
+ * root node -> Skip everything until FDT_END
+ */
+ is_skip_to_end = 1;
+ break;
+
default:
break;
}
diff --git a/libfdt/fdt.h b/libfdt/fdt.h
index c23723b..b6c23ef 100644
--- a/libfdt/fdt.h
+++ b/libfdt/fdt.h
@@ -67,6 +67,7 @@ struct fdt_property {
#define FDT_EXPORT_SYM 0xa /* export symbol: name, phandle value */
#define FDT_EXPORT_SYM_REF 0xb /* export symbol: name, phandle value (maybe
unresolved), external label */
+#define FDT_IMPORT_SYM 0xc /* import symbol: name, compatible */
#define FDT_V1_SIZE (7*sizeof(fdt32_t))
#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t))
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 35/77] Add support for FDT_IMPORT_SYM dtb tag
2026-01-12 14:19 ` [RFC PATCH 35/77] Add support for FDT_IMPORT_SYM dtb tag Herve Codina
@ 2026-01-15 6:41 ` David Gibson
2026-01-19 14:36 ` Herve Codina
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-15 6:41 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 10371 bytes --]
On Mon, Jan 12, 2026 at 03:19:25PM +0100, Herve Codina wrote:
> The FDT_IMPORT_SYM dtb tag is a meta-data tag defining an imported
> symbol. It can be present globally in an addon dtb (i.e. outside nodes
> definition) meaning that this symbol needs to be resolved when the dtb
> is applied.
>
> The tag is followed by two values and possible alignment paddings:
> - name (string including \0)
> The import symbol name. I.e. the name used to reference this
> imported symbol.
> - padding:
> Padding (0x00) added to have the next value aligned on 32bit.
> - compatible (string including \0)
> The compatible string that can be used for symbol resolution.
> This string can be an empty string if it is not relevant.
> - padding:
> Padding (0x00) added to have the next value aligned on 32bit.
>
> Example:
> FDT_IMPORT_SYM 'foo1' 0x00 0x00 0x00 'bar,foo'
>
> This means that 'foo1' is an imported symbol and it is 'bar,foo'
> compatible.
>
> This is what is encoded in the dtb when the related dts has the
> following imported symbol defined:
> /import/ foo1: "bar,foo";
>
> If several symbols are imported, several FDT_IMPORT_SYM are present.
> Each of them defining one imported symbol. For instance, importing
> 'foo1' ("bar,foo" compatible) and 'baz1' ("bar,baz" compatible) leads
> to the following sequence:
> FDT_IMPORT_SYM 'foo1' 0x00 0x00 0x00 'bar,foo'
> FDT_IMPORT_SYM 'baz1' 0x00 0x00 0x00 'bar,baz'
>
> If FDT_IMPORT_SYM tags are present in the dtb, they are present after
> the root node definition (i.e. after the FDT_END_NODE related to the
> first FDT_BEGIN_NODE).
>
> Add support for this new dtb tag.
Since these are global to the whole tree, would a new block make more
sense?
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> fdtdump.c | 11 +++++++++
> flattree.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++-
> libfdt/fdt.c | 28 ++++++++++++++++++++++
> libfdt/fdt.h | 1 +
> 4 files changed, 107 insertions(+), 1 deletion(-)
>
> diff --git a/fdtdump.c b/fdtdump.c
> index 8baadc4..04e6e38 100644
> --- a/fdtdump.c
> +++ b/fdtdump.c
> @@ -198,6 +198,17 @@ static void dump_blob(void *blob, bool debug)
> continue;
> }
>
> + if (tag == FDT_IMPORT_SYM) {
> + s = p;
> + p = PALIGN(p + strlen(s) + 1, 4);
> + t = p;
> + p = PALIGN(p + strlen(t) + 1, 4);
> +
> + printf("%*s// [FDT_IMPORT_SYM] '%s' (%s)\n", depth * shift, "",
> + s, t);
> + continue;
> + }
> +
> fprintf(stderr, "%*s ** Unknown tag 0x%08"PRIx32"\n", depth * shift, "", tag);
> break;
> }
> diff --git a/flattree.c b/flattree.c
> index 47a289f..add02f0 100644
> --- a/flattree.c
> +++ b/flattree.c
> @@ -50,6 +50,7 @@ struct emitter {
> void (*ref_phandle)(void *);
> void (*export_sym)(void *);
> void (*export_sym_ref)(void *);
> + void (*import_sym)(void *);
> };
>
> static void bin_emit_cell(void *e, cell_t val)
> @@ -119,6 +120,11 @@ static void bin_emit_export_sym_ref(void *e)
> bin_emit_cell(e, FDT_EXPORT_SYM_REF);
> }
>
> +static void bin_emit_import_sym(void *e)
> +{
> + bin_emit_cell(e, FDT_IMPORT_SYM);
> +}
> +
> static struct emitter bin_emitter = {
> .cell = bin_emit_cell,
> .string = bin_emit_string,
> @@ -131,6 +137,7 @@ static struct emitter bin_emitter = {
> .ref_phandle = bin_emit_ref_phandle,
> .export_sym = bin_emit_export_sym,
> .export_sym_ref = bin_emit_export_sym_ref,
> + .import_sym = bin_emit_import_sym,
> };
>
> static void emit_label(FILE *f, const char *prefix, const char *label)
> @@ -274,6 +281,17 @@ static void asm_emit_export_sym_ref(void *e)
> asm_emit_cell(e, FDT_EXPORT_SYM_REF);
> }
>
> +static void asm_emit_import_sym(void *e)
> +{
> + /*
> + * Import symbols are an feature introduced for addons.
> + * Addons device-tree blob have to reason to be in the asm format.
> + *
> + * Need to be implemented if really needed.
> + */
> + die("FDT_IMPORT_SYM not supported in asm output\n");
> +}
> +
> static struct emitter asm_emitter = {
> .cell = asm_emit_cell,
> .string = asm_emit_string,
> @@ -286,6 +304,7 @@ static struct emitter asm_emitter = {
> .ref_phandle = asm_emit_ref_phandle,
> .export_sym = asm_emit_export_sym,
> .export_sym = asm_emit_export_sym_ref,
> + .import_sym = asm_emit_import_sym,
> };
>
> static int stringtable_insert(struct data *d, const char *str)
> @@ -461,6 +480,26 @@ static void make_fdt_header(struct fdt_header *fdt,
> fdt->dt_flags = cpu_to_fdt32(dt_flags);
> }
>
> +static void flatten_imports(struct symbol *importsymlist, struct emitter *emit,
> + void *etarget, struct version_info *vi, uint32_t dt_flags)
> +{
> + struct symbol *importsym;
> +
> + if (!(vi->flags & FTF_EXPORT_IMPORT_SYM))
> + return;
> +
> + if (!(dt_flags & FDT_FLAG_ADDON) && importsymlist)
> + die("Only addons can have an import list\n");
> +
> + for_each_symbol(importsymlist, importsym) {
> + emit->import_sym(etarget);
> + emit->string(etarget, importsym->name, 0);
> + emit->align(etarget, sizeof(cell_t));
> + emit->string(etarget, importsym->compatible, 0);
> + emit->align(etarget, sizeof(cell_t));
> + }
> +}
> +
> void dt_to_blob(FILE *f, struct dt_info *dti, int version)
> {
> struct version_info *vi = NULL;
> @@ -483,6 +522,7 @@ void dt_to_blob(FILE *f, struct dt_info *dti, int version)
> dt_flags |= dti->dtsflags & DTSF_ADDON ? FDT_FLAG_ADDON : 0;
>
> flatten_tree(dti->dt, &bin_emitter, &dtbuf, &strbuf, vi);
> + flatten_imports(dti->importsymlist, &bin_emitter, &dtbuf, vi, dt_flags);
> bin_emit_cell(&dtbuf, FDT_END);
>
> reservebuf = flatten_reserve_list(dti->reservelist, vi);
> @@ -574,6 +614,9 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
> const char *symprefix = "dt";
> uint32_t dt_flags = 0;
>
> + if (dti->importsymlist)
> + die("Import symbols not supported in asm format\n");
> +
> for (i = 0; i < ARRAY_SIZE(version_table); i++) {
> if (version_table[i].version == version)
> vi = &version_table[i];
> @@ -810,6 +853,16 @@ static struct property *flat_read_property(struct inbuf *dtbuf,
> return build_property(name, val, NULL);
> }
>
> +static struct symbol *flat_read_importsym(struct inbuf *inb)
> +{
> + const char *name;
> + const char *compatible;
> +
> + name = flat_read_string(inb);
> + compatible = flat_read_string(inb);
> +
> + return build_importsym(name, compatible, NULL);
> +}
>
> static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
> {
> @@ -984,6 +1037,8 @@ struct dt_info *dt_from_blob(const char *fname)
> int sizeleft;
> struct reserve_info *reservelist;
> struct node *tree;
> + struct symbol *importsymlist = NULL;
> + struct symbol *importsym;
> uint32_t val;
> int flags = 0;
> unsigned int dtsflags = 0;
> @@ -1098,6 +1153,17 @@ struct dt_info *dt_from_blob(const char *fname)
> tree = unflatten_tree(&dtbuf, &strbuf, "", flags);
>
> val = flat_read_word(&dtbuf);
> +
> + if (dtsflags & DTSF_ADDON) {
> + if (flags & FTF_EXPORT_IMPORT_SYM) {
> + while (val == FDT_IMPORT_SYM) {
> + importsym = flat_read_importsym(&dtbuf);
> + add_symbol(&importsymlist, importsym);
> + val = flat_read_word(&dtbuf);
> + }
> + }
> + }
> +
> if (val != FDT_END)
> die("Device tree blob doesn't end with FDT_END\n");
>
> @@ -1105,5 +1171,5 @@ struct dt_info *dt_from_blob(const char *fname)
>
> fclose(f);
>
> - return build_dt_info(DTSF_V1 | dtsflags, reservelist, tree, boot_cpuid_phys, NULL);
> + return build_dt_info(DTSF_V1 | dtsflags, reservelist, tree, boot_cpuid_phys, importsymlist);
> }
> diff --git a/libfdt/fdt.c b/libfdt/fdt.c
> index febfa71..c169dd9 100644
> --- a/libfdt/fdt.c
> +++ b/libfdt/fdt.c
> @@ -271,6 +271,23 @@ uint32_t fdt_next_tag_full(const void *fdt, int startoffset, int *nextoffset)
> return FDT_END; /* premature end */
> break;
>
> + case FDT_IMPORT_SYM:
> + /* Skip name */
> + do {
> + p = fdt_offset_ptr(fdt, offset++, 1);
> + } while (p && (*p != '\0'));
> + if (!can_assume(VALID_DTB) && !p)
> + return FDT_END; /* premature end */
> + offset = FDT_CELLALIGN(offset);
> +
> + /* Skip compatible */
> + do {
> + p = fdt_offset_ptr(fdt, offset++, 1);
> + } while (p && (*p != '\0'));
> + if (!can_assume(VALID_DTB) && !p)
> + return FDT_END; /* premature end */
> + break;
> +
> default:
> return FDT_END;
> }
> @@ -286,6 +303,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
> {
> uint32_t tag, tmp_tag;
> int tmp_offset, tmp_next;
> + int is_skip_to_end = 0;
>
> /* Retrieve next tag */
> tag = fdt_next_tag_full(fdt, startoffset, nextoffset);
> @@ -300,6 +318,9 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
> case FDT_END_NODE:
> case FDT_PROP:
> case FDT_NOP:
> + if (is_skip_to_end)
> + break;
> +
> case FDT_END:
> /*
> * Next tag is not a meta-data tag -> Ok this next tag
> @@ -320,6 +341,13 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
> */
> break;
>
> + case FDT_IMPORT_SYM:
> + /* Those tags are available at the root level, after the
> + * root node -> Skip everything until FDT_END
> + */
> + is_skip_to_end = 1;
> + break;
> +
> default:
> break;
> }
> diff --git a/libfdt/fdt.h b/libfdt/fdt.h
> index c23723b..b6c23ef 100644
> --- a/libfdt/fdt.h
> +++ b/libfdt/fdt.h
> @@ -67,6 +67,7 @@ struct fdt_property {
> #define FDT_EXPORT_SYM 0xa /* export symbol: name, phandle value */
> #define FDT_EXPORT_SYM_REF 0xb /* export symbol: name, phandle value (maybe
> unresolved), external label */
> +#define FDT_IMPORT_SYM 0xc /* import symbol: name, compatible */
>
> #define FDT_V1_SIZE (7*sizeof(fdt32_t))
> #define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t))
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 35/77] Add support for FDT_IMPORT_SYM dtb tag
2026-01-15 6:41 ` David Gibson
@ 2026-01-19 14:36 ` Herve Codina
2026-01-28 2:25 ` David Gibson
0 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-19 14:36 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
Hi David,
On Thu, 15 Jan 2026 17:41:11 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Mon, Jan 12, 2026 at 03:19:25PM +0100, Herve Codina wrote:
> > The FDT_IMPORT_SYM dtb tag is a meta-data tag defining an imported
> > symbol. It can be present globally in an addon dtb (i.e. outside nodes
> > definition) meaning that this symbol needs to be resolved when the dtb
> > is applied.
> >
> > The tag is followed by two values and possible alignment paddings:
> > - name (string including \0)
> > The import symbol name. I.e. the name used to reference this
> > imported symbol.
> > - padding:
> > Padding (0x00) added to have the next value aligned on 32bit.
> > - compatible (string including \0)
> > The compatible string that can be used for symbol resolution.
> > This string can be an empty string if it is not relevant.
> > - padding:
> > Padding (0x00) added to have the next value aligned on 32bit.
> >
> > Example:
> > FDT_IMPORT_SYM 'foo1' 0x00 0x00 0x00 'bar,foo'
> >
> > This means that 'foo1' is an imported symbol and it is 'bar,foo'
> > compatible.
> >
> > This is what is encoded in the dtb when the related dts has the
> > following imported symbol defined:
> > /import/ foo1: "bar,foo";
> >
> > If several symbols are imported, several FDT_IMPORT_SYM are present.
> > Each of them defining one imported symbol. For instance, importing
> > 'foo1' ("bar,foo" compatible) and 'baz1' ("bar,baz" compatible) leads
> > to the following sequence:
> > FDT_IMPORT_SYM 'foo1' 0x00 0x00 0x00 'bar,foo'
> > FDT_IMPORT_SYM 'baz1' 0x00 0x00 0x00 'bar,baz'
> >
> > If FDT_IMPORT_SYM tags are present in the dtb, they are present after
> > the root node definition (i.e. after the FDT_END_NODE related to the
> > first FDT_BEGIN_NODE).
> >
> > Add support for this new dtb tag.
>
> Since these are global to the whole tree, would a new block make more
> sense?
I don't know.
Exports symbols are in node blocs and that makes sense. I wouldn't expect
imports out of the dtb "structure block".
They could be grouped into an other tag, FDT_INFO_DTB for instance (part of
the "structure block").
If you think that a new block is really relevant, I can implement this new
block.
Best regards,
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 35/77] Add support for FDT_IMPORT_SYM dtb tag
2026-01-19 14:36 ` Herve Codina
@ 2026-01-28 2:25 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-28 2:25 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 2965 bytes --]
On Mon, Jan 19, 2026 at 03:36:29PM +0100, Herve Codina wrote:
> Hi David,
>
> On Thu, 15 Jan 2026 17:41:11 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > On Mon, Jan 12, 2026 at 03:19:25PM +0100, Herve Codina wrote:
> > > The FDT_IMPORT_SYM dtb tag is a meta-data tag defining an imported
> > > symbol. It can be present globally in an addon dtb (i.e. outside nodes
> > > definition) meaning that this symbol needs to be resolved when the dtb
> > > is applied.
> > >
> > > The tag is followed by two values and possible alignment paddings:
> > > - name (string including \0)
> > > The import symbol name. I.e. the name used to reference this
> > > imported symbol.
> > > - padding:
> > > Padding (0x00) added to have the next value aligned on 32bit.
> > > - compatible (string including \0)
> > > The compatible string that can be used for symbol resolution.
> > > This string can be an empty string if it is not relevant.
> > > - padding:
> > > Padding (0x00) added to have the next value aligned on 32bit.
> > >
> > > Example:
> > > FDT_IMPORT_SYM 'foo1' 0x00 0x00 0x00 'bar,foo'
> > >
> > > This means that 'foo1' is an imported symbol and it is 'bar,foo'
> > > compatible.
> > >
> > > This is what is encoded in the dtb when the related dts has the
> > > following imported symbol defined:
> > > /import/ foo1: "bar,foo";
> > >
> > > If several symbols are imported, several FDT_IMPORT_SYM are present.
> > > Each of them defining one imported symbol. For instance, importing
> > > 'foo1' ("bar,foo" compatible) and 'baz1' ("bar,baz" compatible) leads
> > > to the following sequence:
> > > FDT_IMPORT_SYM 'foo1' 0x00 0x00 0x00 'bar,foo'
> > > FDT_IMPORT_SYM 'baz1' 0x00 0x00 0x00 'bar,baz'
> > >
> > > If FDT_IMPORT_SYM tags are present in the dtb, they are present after
> > > the root node definition (i.e. after the FDT_END_NODE related to the
> > > first FDT_BEGIN_NODE).
> > >
> > > Add support for this new dtb tag.
> >
> > Since these are global to the whole tree, would a new block make more
> > sense?
>
> I don't know.
>
> Exports symbols are in node blocs and that makes sense. I wouldn't expect
> imports out of the dtb "structure block".
>
> They could be grouped into an other tag, FDT_INFO_DTB for instance (part of
> the "structure block").
>
> If you think that a new block is really relevant, I can implement this new
> block.
On further thought, I don't think this is a good idea. For one thing
adding an extra block makes resizing edits way harder to implement.
For another adding support for multiple upstream connectors might mean
they're no longer quite as global as they are.
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 36/77] tests: metadata: Add import symbols tests
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (34 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 35/77] Add support for FDT_IMPORT_SYM dtb tag Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 37/77] dtc: Add support for import symbols sorting Herve Codina
` (43 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Add tests related to import symbols (FDT_IMPORT_SYM dtb tag).
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
tests/metadata_importsyms.dtb.dts.expect | 9 +++++++++
tests/metadata_importsyms.dtb.expect | 8 ++++++++
tests/metadata_importsyms.dts | 14 ++++++++++++++
tests/metadata_importsyms.dts.dts.expect | 9 +++++++++
tests/run_tests.sh | 10 +++++-----
5 files changed, 45 insertions(+), 5 deletions(-)
create mode 100644 tests/metadata_importsyms.dtb.dts.expect
create mode 100644 tests/metadata_importsyms.dtb.expect
create mode 100644 tests/metadata_importsyms.dts
create mode 100644 tests/metadata_importsyms.dts.dts.expect
diff --git a/tests/metadata_importsyms.dtb.dts.expect b/tests/metadata_importsyms.dtb.dts.expect
new file mode 100644
index 0000000..eabf8c7
--- /dev/null
+++ b/tests/metadata_importsyms.dtb.dts.expect
@@ -0,0 +1,9 @@
+/dts-v1/;
+/addon/;
+
+/import/ base_a: "foo,bar";
+/import/ base_b: "foo,baz";
+
+/ {
+ prop = <0x01>;
+};
diff --git a/tests/metadata_importsyms.dtb.expect b/tests/metadata_importsyms.dtb.expect
new file mode 100644
index 0000000..2177026
--- /dev/null
+++ b/tests/metadata_importsyms.dtb.expect
@@ -0,0 +1,8 @@
+/dts-v1/;
+/addon/;
+
+/ {
+ prop = <0x00000001>;
+};
+// [FDT_IMPORT_SYM] 'base_a' (foo,bar)
+// [FDT_IMPORT_SYM] 'base_b' (foo,baz)
diff --git a/tests/metadata_importsyms.dts b/tests/metadata_importsyms.dts
new file mode 100644
index 0000000..671586d
--- /dev/null
+++ b/tests/metadata_importsyms.dts
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+/addon/;
+
+/import/ base_a: "foo,bar";
+/import/ base_b: "foo,baz";
+
+/ {
+ prop = <1>;
+};
diff --git a/tests/metadata_importsyms.dts.dts.expect b/tests/metadata_importsyms.dts.dts.expect
new file mode 100644
index 0000000..eabf8c7
--- /dev/null
+++ b/tests/metadata_importsyms.dts.dts.expect
@@ -0,0 +1,9 @@
+/dts-v1/;
+/addon/;
+
+/import/ base_a: "foo,bar";
+/import/ base_b: "foo,baz";
+
+/ {
+ prop = <0x01>;
+};
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 1973525..5368db9 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1127,20 +1127,20 @@ wrap_fdtdump () {
metadata_tests() {
for dt in metadata_reflocal metadata_refphandle \
metadata_addon_base metadata_exportsyms_local \
- metadata_exportsyms_ref; do
+ metadata_exportsyms_ref metadata_importsyms; do
run_dtc_test -I dts -O dts -o $dt.dts.dts "$SRCDIR/$dt.dts"
base_run_test check_diff $dt.dts.dts "$SRCDIR/$dt.dts.dts.expect"
run_dtc_test -I dts -O dtb -o $dt.dtb "$SRCDIR/$dt.dts"
base_run_test wrap_fdtdump $dt.dtb $dt.dtb.out
- # Remove unneeded comments
- sed -i '/^\/\/ /d' $dt.dtb.out
+ # Remove unneeded comments, keep comments in the form '// [xxxx'
+ sed -i '/^\/\/ [^\[]/d' $dt.dtb.out
base_run_test check_diff $dt.dtb.out "$SRCDIR/$dt.dtb.expect"
run_dtc_test -I dtb -O dts -o $dt.dtb.dts $dt.dtb
base_run_test check_diff $dt.dtb.dts "$SRCDIR/$dt.dtb.dts.expect"
run_dtc_test -I dts -O dtb -o $dt.dtb.dts.dtb $dt.dtb.dts
base_run_test wrap_fdtdump $dt.dtb.dts.dtb $dt.dtb.dts.dtb.out
- # Remove unneeded comments
- sed -i '/^\/\/ /d' $dt.dtb.dts.dtb.out
+ # Remove unneeded comments, keep comments in the form '// [xxxx'
+ sed -i '/^\/\/ [^\[]/d' $dt.dtb.dts.dtb.out
base_run_test check_diff $dt.dtb.dts.dtb.out "$SRCDIR/$dt.dtb.expect"
done
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 37/77] dtc: Add support for import symbols sorting
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (35 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 36/77] tests: metadata: Add import symbols tests Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 38/77] tests: metadata: Improve sort test to check " Herve Codina
` (42 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
dtc can sort items when the command line --sort option is set.
Add support for import symbols sorting when this option is used.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
livetree.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/livetree.c b/livetree.c
index dac5359..285f6e1 100644
--- a/livetree.c
+++ b/livetree.c
@@ -1014,9 +1014,36 @@ static void sort_node(struct node *node)
sort_node(c);
}
+static void sort_importsyms(struct dt_info *dti)
+{
+ int n = 0, i = 0;
+ struct symbol *symbol, **tbl;
+
+ for_each_symbol(dti->importsymlist, symbol)
+ n++;
+
+ if (n == 0)
+ return;
+
+ tbl = xmalloc(n * sizeof(*tbl));
+
+ for_each_symbol(dti->importsymlist, symbol)
+ tbl[i++] = symbol;
+
+ qsort(tbl, n, sizeof(*tbl), cmp_symbol);
+
+ dti->importsymlist = tbl[0];
+ for (i = 0; i < (n-1); i++)
+ tbl[i]->next = tbl[i+1];
+ tbl[n-1]->next = NULL;
+
+ free(tbl);
+}
+
void sort_tree(struct dt_info *dti)
{
sort_reserve_entries(dti);
+ sort_importsyms(dti);
sort_node(dti->dt);
}
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 38/77] tests: metadata: Improve sort test to check for import symbols sorting
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (36 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 37/77] dtc: Add support for import symbols sorting Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 39/77] check: Get 'chosen' node using get_subnode() Herve Codina
` (41 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
dtc is able to sort the import symbols list when the --sort option is
used.
Improve the metadata sort test to perform a check for this feature.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
tests/metadata_sort.dtb.dts.expect | 4 ++++
tests/metadata_sort.dtb.expect | 3 +++
tests/metadata_sort.dts | 4 ++++
tests/run_tests.sh | 4 ++--
4 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/tests/metadata_sort.dtb.dts.expect b/tests/metadata_sort.dtb.dts.expect
index f07a42b..270c06d 100644
--- a/tests/metadata_sort.dtb.dts.expect
+++ b/tests/metadata_sort.dtb.dts.expect
@@ -1,6 +1,10 @@
/dts-v1/;
/addon/;
+/import/ abc: "foo,bar";
+/import/ de1: "foo,bar";
+/import/ de2: "foo,bar";
+
/ {
node-a {
diff --git a/tests/metadata_sort.dtb.expect b/tests/metadata_sort.dtb.expect
index 7856894..0dacab7 100644
--- a/tests/metadata_sort.dtb.expect
+++ b/tests/metadata_sort.dtb.expect
@@ -13,3 +13,6 @@
phandle = <0x00000001>;
};
};
+// [FDT_IMPORT_SYM] 'abc' (foo,bar)
+// [FDT_IMPORT_SYM] 'de1' (foo,bar)
+// [FDT_IMPORT_SYM] 'de2' (foo,bar)
diff --git a/tests/metadata_sort.dts b/tests/metadata_sort.dts
index 7d1cca7..e523e20 100644
--- a/tests/metadata_sort.dts
+++ b/tests/metadata_sort.dts
@@ -6,6 +6,10 @@
/dts-v1/;
/addon/;
+/import/ de1: "foo,bar";
+/import/ abc: "foo,bar";
+/import/ de2: "foo,bar";
+
/ {
node_b: node-b {
};
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 5368db9..a5e31df 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1158,8 +1158,8 @@ metadata_tests() {
run_dtc_test -I dts -O dtb -s -o metadata_sort.dtb "$SRCDIR/metadata_sort.dts"
base_run_test wrap_fdtdump metadata_sort.dtb metadata_sort.dtb.out
- # Remove unneeded comments
- sed -i '/^\/\/ /d' metadata_sort.dtb.out
+ # Remove unneeded comments, keep comments in the form '// [xxxx'
+ sed -i '/^\/\/ [^\[]/d' metadata_sort.dtb.out
base_run_test check_diff metadata_sort.dtb.out "$SRCDIR/metadata_sort.dtb.expect"
run_dtc_test -I dtb -O dts -o metadata_sort.dtb.dts metadata_sort.dtb
base_run_test check_diff metadata_sort.dtb.dts "$SRCDIR/metadata_sort.dtb.dts.expect"
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 39/77] check: Get 'chosen' node using get_subnode()
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (37 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 38/77] tests: metadata: Improve sort test to check " Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 40/77] dtc: Introduce dti_get_node_by_path() Herve Codina
` (40 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
get_node_by_path() is going to be replaced by a more generic function in
order to handle orphan node support for addon device-tree.
The 'chosen' node is a subnode of the root node and can perfectly be
retrieved using get_subnode().
In preparation of the future change related to get_node_by_path(),
replace its usage to get the 'chosen' node by call to get_subnode().
The modification doesn't introduce any functional changes.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
checks.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/checks.c b/checks.c
index d1e215e..9744431 100644
--- a/checks.c
+++ b/checks.c
@@ -1341,8 +1341,7 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c,
if (node != dt)
return;
-
- chosen = get_node_by_path(dt, "/chosen");
+ chosen = get_subnode(dt, "chosen");
if (!chosen)
return;
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 40/77] dtc: Introduce dti_get_node_by_path()
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (38 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 39/77] check: Get 'chosen' node using get_subnode() Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-15 6:47 ` David Gibson
2026-01-12 14:19 ` [RFC PATCH 41/77] dtc: Introduce dti_get_node_by_label() Herve Codina
` (39 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The future introduction of orphan nodes for addons device-tree will lead
to more than one tree in the addons data. Those trees will be:
- the classical root tree starting at the root node
- trees related to orphan nodes
Also, an addon device-tree can have only trees based on orphan nodes. In
other words an addon device-tree is valid without having the classical
'root' tree.
To prepare this change, introduce and use dti_get_node_by_path().
dti_get_node_by_path() retrieves a node by its path like
get_node_by_path() but it works at the struct dt_info level.
It handles the case where a 'root' device-tree is not present and will
handle orphan nodes trees as soon as they will be introduced.
This introduction doesn't lead to any functional changes.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
checks.c | 2 +-
dtc.h | 3 ++-
livetree.c | 15 ++++++++++++++-
3 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/checks.c b/checks.c
index 9744431..b2b1bf7 100644
--- a/checks.c
+++ b/checks.c
@@ -740,7 +740,7 @@ static void check_alias_paths(struct check *c, struct dt_info *dti,
/* This check does not work for overlays nor addons with external paths */
if (!(dti->dtsflags & (DTSF_PLUGIN | DTSF_ADDON)) &&
- (!prop->val.val || !get_node_by_path(dti->dt, prop->val.val))) {
+ (!prop->val.val || !dti_get_node_by_path(dti, prop->val.val))) {
FAIL_PROP(c, dti, node, prop, "aliases property is not a valid node (%s)",
prop->val.val);
continue;
diff --git a/dtc.h b/dtc.h
index 4ebe576..8ba093f 100644
--- a/dtc.h
+++ b/dtc.h
@@ -323,7 +323,6 @@ struct property *get_property_by_label(struct node *tree, const char *label,
struct marker *get_marker_label(struct node *tree, const char *label,
struct node **node, struct property **prop);
struct node *get_subnode(struct node *node, const char *nodename);
-struct node *get_node_by_path(struct node *tree, const char *path);
struct node *get_node_by_label(struct node *tree, const char *label);
struct node *get_node_by_phandle(struct node *tree, cell_t phandle);
struct node *get_node_by_ref(struct node *tree, const char *ref);
@@ -357,6 +356,8 @@ struct dt_info {
const char *outname; /* filename being written to, "-" for stdout */
};
+struct node *dti_get_node_by_path(struct dt_info *dti, const char *path);
+
/* DTS version flags definitions */
#define DTSF_V1 0x0001 /* /dts-v1/ */
#define DTSF_PLUGIN 0x0002 /* /plugin/ */
diff --git a/livetree.c b/livetree.c
index 285f6e1..23ba957 100644
--- a/livetree.c
+++ b/livetree.c
@@ -659,7 +659,7 @@ struct node *get_subnode(struct node *node, const char *nodename)
return NULL;
}
-struct node *get_node_by_path(struct node *tree, const char *path)
+static struct node *get_node_by_path(struct node *tree, const char *path)
{
const char *p;
struct node *child;
@@ -785,6 +785,19 @@ struct node *get_node_by_ref(struct node *tree, const char *ref)
return target;
}
+struct node *dti_get_node_by_path(struct dt_info *dti, const char *path)
+{
+ struct node *node;
+
+ if (dti->dt) {
+ node = get_node_by_path(dti->dt, path);
+ if (node)
+ return node;
+ }
+
+ return NULL;
+}
+
static void add_phandle_property(struct node *node,
const char *name, int format)
{
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 40/77] dtc: Introduce dti_get_node_by_path()
2026-01-12 14:19 ` [RFC PATCH 40/77] dtc: Introduce dti_get_node_by_path() Herve Codina
@ 2026-01-15 6:47 ` David Gibson
2026-01-19 15:52 ` Herve Codina
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-15 6:47 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 4106 bytes --]
On Mon, Jan 12, 2026 at 03:19:30PM +0100, Herve Codina wrote:
> The future introduction of orphan nodes for addons device-tree will lead
> to more than one tree in the addons data. Those trees will be:
> - the classical root tree starting at the root node
> - trees related to orphan nodes
This doesn't make sense to me. The new function still just takes a
single path, nothing to specify which tree that path is looked up in.
You can probably guarantee that labels and phandles are unique across
all the trees. Not paths, though.
>
> Also, an addon device-tree can have only trees based on orphan nodes. In
> other words an addon device-tree is valid without having the classical
> 'root' tree.
>
> To prepare this change, introduce and use dti_get_node_by_path().
>
> dti_get_node_by_path() retrieves a node by its path like
> get_node_by_path() but it works at the struct dt_info level.
>
> It handles the case where a 'root' device-tree is not present and will
> handle orphan nodes trees as soon as they will be introduced.
>
> This introduction doesn't lead to any functional changes.
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> checks.c | 2 +-
> dtc.h | 3 ++-
> livetree.c | 15 ++++++++++++++-
> 3 files changed, 17 insertions(+), 3 deletions(-)
>
> diff --git a/checks.c b/checks.c
> index 9744431..b2b1bf7 100644
> --- a/checks.c
> +++ b/checks.c
> @@ -740,7 +740,7 @@ static void check_alias_paths(struct check *c, struct dt_info *dti,
>
> /* This check does not work for overlays nor addons with external paths */
> if (!(dti->dtsflags & (DTSF_PLUGIN | DTSF_ADDON)) &&
> - (!prop->val.val || !get_node_by_path(dti->dt, prop->val.val))) {
> + (!prop->val.val || !dti_get_node_by_path(dti, prop->val.val))) {
> FAIL_PROP(c, dti, node, prop, "aliases property is not a valid node (%s)",
> prop->val.val);
> continue;
> diff --git a/dtc.h b/dtc.h
> index 4ebe576..8ba093f 100644
> --- a/dtc.h
> +++ b/dtc.h
> @@ -323,7 +323,6 @@ struct property *get_property_by_label(struct node *tree, const char *label,
> struct marker *get_marker_label(struct node *tree, const char *label,
> struct node **node, struct property **prop);
> struct node *get_subnode(struct node *node, const char *nodename);
> -struct node *get_node_by_path(struct node *tree, const char *path);
> struct node *get_node_by_label(struct node *tree, const char *label);
> struct node *get_node_by_phandle(struct node *tree, cell_t phandle);
> struct node *get_node_by_ref(struct node *tree, const char *ref);
> @@ -357,6 +356,8 @@ struct dt_info {
> const char *outname; /* filename being written to, "-" for stdout */
> };
>
> +struct node *dti_get_node_by_path(struct dt_info *dti, const char *path);
> +
> /* DTS version flags definitions */
> #define DTSF_V1 0x0001 /* /dts-v1/ */
> #define DTSF_PLUGIN 0x0002 /* /plugin/ */
> diff --git a/livetree.c b/livetree.c
> index 285f6e1..23ba957 100644
> --- a/livetree.c
> +++ b/livetree.c
> @@ -659,7 +659,7 @@ struct node *get_subnode(struct node *node, const char *nodename)
> return NULL;
> }
>
> -struct node *get_node_by_path(struct node *tree, const char *path)
> +static struct node *get_node_by_path(struct node *tree, const char *path)
> {
> const char *p;
> struct node *child;
> @@ -785,6 +785,19 @@ struct node *get_node_by_ref(struct node *tree, const char *ref)
> return target;
> }
>
> +struct node *dti_get_node_by_path(struct dt_info *dti, const char *path)
> +{
> + struct node *node;
> +
> + if (dti->dt) {
> + node = get_node_by_path(dti->dt, path);
> + if (node)
> + return node;
> + }
> +
> + return NULL;
> +}
> +
> static void add_phandle_property(struct node *node,
> const char *name, int format)
> {
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 40/77] dtc: Introduce dti_get_node_by_path()
2026-01-15 6:47 ` David Gibson
@ 2026-01-19 15:52 ` Herve Codina
2026-01-29 1:38 ` David Gibson
0 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-19 15:52 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
Hi David,
On Thu, 15 Jan 2026 17:47:29 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Mon, Jan 12, 2026 at 03:19:30PM +0100, Herve Codina wrote:
> > The future introduction of orphan nodes for addons device-tree will lead
> > to more than one tree in the addons data. Those trees will be:
> > - the classical root tree starting at the root node
> > - trees related to orphan nodes
>
> This doesn't make sense to me. The new function still just takes a
> single path, nothing to specify which tree that path is looked up in.
>
> You can probably guarantee that labels and phandles are unique across
> all the trees. Not paths, though.
>
Paths can be unique across all trees. The tree needs to be indicated in the
path. Starting by '/' is the root tree.
For orphans, I proposed "$<orphan_name>/<path>" in patch 64 introducing
references by path for orphan nodes and so, for orphan trees.
Best regards,
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 40/77] dtc: Introduce dti_get_node_by_path()
2026-01-19 15:52 ` Herve Codina
@ 2026-01-29 1:38 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-29 1:38 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 1480 bytes --]
On Mon, Jan 19, 2026 at 04:52:44PM +0100, Herve Codina wrote:
> Hi David,
>
> On Thu, 15 Jan 2026 17:47:29 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > On Mon, Jan 12, 2026 at 03:19:30PM +0100, Herve Codina wrote:
> > > The future introduction of orphan nodes for addons device-tree will lead
> > > to more than one tree in the addons data. Those trees will be:
> > > - the classical root tree starting at the root node
> > > - trees related to orphan nodes
> >
> > This doesn't make sense to me. The new function still just takes a
> > single path, nothing to specify which tree that path is looked up in.
> >
> > You can probably guarantee that labels and phandles are unique across
> > all the trees. Not paths, though.
> >
>
> Paths can be unique across all trees. The tree needs to be indicated in the
> path. Starting by '/' is the root tree.
Oh, ok. That wasn't clear from this patch, and I must have missed it
in my cursory look at the later patches. I had the mistaken
impression this just looked for the same path in each orphan tree.
> For orphans, I proposed "$<orphan_name>/<path>" in patch 64 introducing
> references by path for orphan nodes and so, for orphan trees.
>
> Best regards,
> Hervé
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 41/77] dtc: Introduce dti_get_node_by_label()
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (39 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 40/77] dtc: Introduce dti_get_node_by_path() Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 42/77] dtc: Introduce dti_get_node_by_phandle() Herve Codina
` (38 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The future introduction of orphan nodes for addons device-tree will lead
to more than one tree in the addons data. Those trees will be:
- the classical root tree starting at the root node
- trees related to orphan nodes
Also, an addon device-tree can have only trees based on orphan nodes. In
other words an addon device-tree is valid without having the classical
'root' tree.
To prepare this change, introduce and use dti_get_node_by_label().
dti_get_node_by_label() retrieves a node by its label like
get_node_by_label() but it works at the struct dt_info level.
It handles the case where a 'root' device-tree is not present and will
handle orphan nodes trees as soon as they will be introduced.
This introduction doesn't lead to any functional changes.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
checks.c | 2 +-
dtc.h | 2 +-
livetree.c | 15 ++++++++++++++-
3 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/checks.c b/checks.c
index b2b1bf7..a76e96a 100644
--- a/checks.c
+++ b/checks.c
@@ -444,7 +444,7 @@ static void check_duplicate_label(struct check *c, struct dt_info *dti,
struct property *otherprop = NULL;
struct marker *othermark = NULL;
- othernode = get_node_by_label(dt, label);
+ othernode = dti_get_node_by_label(dti, label);
if (!othernode)
otherprop = get_property_by_label(dt, label, &othernode);
diff --git a/dtc.h b/dtc.h
index 8ba093f..3dce237 100644
--- a/dtc.h
+++ b/dtc.h
@@ -323,7 +323,6 @@ struct property *get_property_by_label(struct node *tree, const char *label,
struct marker *get_marker_label(struct node *tree, const char *label,
struct node **node, struct property **prop);
struct node *get_subnode(struct node *node, const char *nodename);
-struct node *get_node_by_label(struct node *tree, const char *label);
struct node *get_node_by_phandle(struct node *tree, cell_t phandle);
struct node *get_node_by_ref(struct node *tree, const char *ref);
cell_t get_node_phandle(struct node *root, struct node *node);
@@ -357,6 +356,7 @@ struct dt_info {
};
struct node *dti_get_node_by_path(struct dt_info *dti, const char *path);
+struct node *dti_get_node_by_label(struct dt_info *dti, const char *label);
/* DTS version flags definitions */
#define DTSF_V1 0x0001 /* /dts-v1/ */
diff --git a/livetree.c b/livetree.c
index 23ba957..771ff3d 100644
--- a/livetree.c
+++ b/livetree.c
@@ -685,7 +685,7 @@ static struct node *get_node_by_path(struct node *tree, const char *path)
return NULL;
}
-struct node *get_node_by_label(struct node *tree, const char *label)
+static struct node *get_node_by_label(struct node *tree, const char *label)
{
struct node *child, *node;
struct label *l;
@@ -798,6 +798,19 @@ struct node *dti_get_node_by_path(struct dt_info *dti, const char *path)
return NULL;
}
+struct node *dti_get_node_by_label(struct dt_info *dti, const char *label)
+{
+ struct node *node;
+
+ if (dti->dt) {
+ node = get_node_by_label(dti->dt, label);
+ if (node)
+ return node;
+ }
+
+ return NULL;
+}
+
static void add_phandle_property(struct node *node,
const char *name, int format)
{
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 42/77] dtc: Introduce dti_get_node_by_phandle()
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (40 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 41/77] dtc: Introduce dti_get_node_by_label() Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 43/77] dtc: Introduce dti_get_node_by_ref() Herve Codina
` (37 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The future introduction of orphan nodes for addons device-tree will lead
to more than one tree in the addons data. Those trees will be:
- the classical root tree starting at the root node
- trees related to orphan nodes
Also, an addon device-tree can have only trees based on orphan nodes. In
other words an addon device-tree is valid without having the classical
'root' tree.
To prepare this change, introduce and use dti_get_node_by_phandle().
dti_get_node_by_phandle() retrieves a node by its phandle value like
get_node_by_phandle() but it works at the struct dt_info level.
It handles the case where a 'root' device-tree is not present and will
handle orphan nodes trees as soon as they will be introduced.
This introduction doesn't lead to any functional changes.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
checks.c | 14 +++++---------
dtc.h | 2 +-
livetree.c | 19 ++++++++++++++++---
3 files changed, 22 insertions(+), 13 deletions(-)
diff --git a/checks.c b/checks.c
index a76e96a..fd22524 100644
--- a/checks.c
+++ b/checks.c
@@ -533,7 +533,6 @@ static cell_t check_phandle_prop(struct check *c, struct dt_info *dti,
static void check_explicit_phandles(struct check *c, struct dt_info *dti,
struct node *node)
{
- struct node *root = dti->dt;
struct node *other;
cell_t phandle, linux_phandle;
@@ -555,7 +554,7 @@ static void check_explicit_phandles(struct check *c, struct dt_info *dti,
if (linux_phandle && !phandle)
phandle = linux_phandle;
- other = get_node_by_phandle(root, phandle);
+ other = dti_get_node_by_phandle(dti, phandle);
if (other && (other != node)) {
FAIL(c, dti, node, "duplicated phandle 0x%x (seen before at %s)",
phandle, other->fullpath);
@@ -1414,7 +1413,6 @@ static void check_property_phandle_args(struct check *c,
struct property *prop,
const struct provider *provider)
{
- struct node *root = dti->dt;
unsigned int cell, cellsize = 0;
if (!is_multiple_of(prop->val.len, sizeof(cell_t))) {
@@ -1457,7 +1455,7 @@ static void check_property_phandle_args(struct check *c,
cell);
}
- provider_node = get_node_by_phandle(root, phandle);
+ provider_node = dti_get_node_by_phandle(dti, phandle);
if (!provider_node) {
FAIL_PROP(c, dti, node, prop,
"Could not get phandle node for (cell %d)",
@@ -1624,7 +1622,6 @@ static void check_interrupt_map(struct check *c,
struct dt_info *dti,
struct node *node)
{
- struct node *root = dti->dt;
struct property *prop, *irq_map_prop;
size_t cellsize, cell, map_cells;
@@ -1678,7 +1675,7 @@ static void check_interrupt_map(struct check *c,
break;
}
- provider_node = get_node_by_phandle(root, phandle);
+ provider_node = dti_get_node_by_phandle(dti, phandle);
if (!provider_node) {
FAIL_PROP(c, dti, node, irq_map_prop,
"Could not get phandle(%d) node for (cell %zu)",
@@ -1716,7 +1713,6 @@ static void check_interrupts_property(struct check *c,
struct dt_info *dti,
struct node *node)
{
- struct node *root = dti->dt;
struct node *irq_node = NULL, *parent = node;
struct property *irq_prop, *prop = NULL;
cell_t irq_cells, phandle;
@@ -1747,7 +1743,7 @@ static void check_interrupts_property(struct check *c,
continue;
}
- irq_node = get_node_by_phandle(root, phandle);
+ irq_node = dti_get_node_by_phandle(dti, phandle);
if (!irq_node) {
FAIL_PROP(c, dti, parent, prop, "Bad phandle");
return;
@@ -1882,7 +1878,7 @@ static struct node *get_remote_endpoint(struct check *c, struct dt_info *dti,
if (!phandle_is_valid(phandle))
return NULL;
- node = get_node_by_phandle(dti->dt, phandle);
+ node = dti_get_node_by_phandle(dti, phandle);
if (!node)
FAIL_PROP(c, dti, endpoint, prop, "graph phandle is not valid");
diff --git a/dtc.h b/dtc.h
index 3dce237..7d53fcb 100644
--- a/dtc.h
+++ b/dtc.h
@@ -323,7 +323,6 @@ struct property *get_property_by_label(struct node *tree, const char *label,
struct marker *get_marker_label(struct node *tree, const char *label,
struct node **node, struct property **prop);
struct node *get_subnode(struct node *node, const char *nodename);
-struct node *get_node_by_phandle(struct node *tree, cell_t phandle);
struct node *get_node_by_ref(struct node *tree, const char *ref);
cell_t get_node_phandle(struct node *root, struct node *node);
@@ -357,6 +356,7 @@ struct dt_info {
struct node *dti_get_node_by_path(struct dt_info *dti, const char *path);
struct node *dti_get_node_by_label(struct dt_info *dti, const char *label);
+struct node *dti_get_node_by_phandle(struct dt_info *dti, cell_t phandle);
/* DTS version flags definitions */
#define DTSF_V1 0x0001 /* /dts-v1/ */
diff --git a/livetree.c b/livetree.c
index 771ff3d..a551307 100644
--- a/livetree.c
+++ b/livetree.c
@@ -722,7 +722,7 @@ static cell_t get_node_phandle_existing(struct node *node)
return propval_cell(prop);
}
-struct node *get_node_by_phandle(struct node *tree, cell_t phandle)
+static struct node *get_node_by_phandle(struct node *tree, cell_t phandle)
{
struct node *child, *node;
cell_t tree_phandle;
@@ -811,6 +811,19 @@ struct node *dti_get_node_by_label(struct dt_info *dti, const char *label)
return NULL;
}
+struct node *dti_get_node_by_phandle(struct dt_info *dti, cell_t phandle)
+{
+ struct node *node;
+
+ if (dti->dt) {
+ node = get_node_by_phandle(dti->dt, phandle);
+ if (node)
+ return node;
+ }
+
+ return NULL;
+}
+
static void add_phandle_property(struct node *node,
const char *name, int format)
{
@@ -1362,7 +1375,7 @@ static void update_phandles_ref_internal(struct dt_info *dti, struct node *node)
if (m->is_local) {
phandle = propval_cell_n(prop,
m->offset / sizeof(cell_t));
- refnode = get_node_by_phandle(dti->dt, phandle);
+ refnode = dti_get_node_by_phandle(dti, phandle);
if (!refnode)
die("Node not found for phandle 0x%"PRIx32"\n", phandle);
@@ -1420,7 +1433,7 @@ static void update_exports_ref_internal(struct dt_info *dti, struct node *node)
continue;
if (exportsym->is_local) {
- refnode = get_node_by_phandle(dti->dt, exportsym->phandle);
+ refnode = dti_get_node_by_phandle(dti, exportsym->phandle);
if (!refnode)
die("Node not found for phandle 0x%"PRIx32"\n", exportsym->phandle);
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 43/77] dtc: Introduce dti_get_node_by_ref()
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (41 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 42/77] dtc: Introduce dti_get_node_by_phandle() Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 44/77] dtc: Introduce dti_get_node_phandle() Herve Codina
` (36 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The future introduction of orphan nodes for addons device-tree will lead
to more than one tree in the addons data. Those trees will be:
- the classical root tree starting at the root node
- trees related to orphan nodes
Also, an addon device-tree can have only trees based on orphan nodes. In
other words an addon device-tree is valid without having the classical
'root' tree.
To prepare this change, introduce and use dti_get_node_by_ref().
dti_get_node_by_ref() retrieves a node by a reference (a label or a
path) like get_node_by_ref() but it works at the struct dt_info level.
It handles the case where a 'root' device-tree is not present and will
handle orphan nodes trees as soon as they will be introduced.
This introduction doesn't lead to any functional changes.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
checks.c | 10 ++++------
dtc-parser.y | 22 +++++++++++++++++-----
dtc.h | 2 +-
livetree.c | 19 ++++++++++++++++---
4 files changed, 38 insertions(+), 15 deletions(-)
diff --git a/checks.c b/checks.c
index fd22524..a47870d 100644
--- a/checks.c
+++ b/checks.c
@@ -486,7 +486,6 @@ ERROR(duplicate_label, check_duplicate_label_node, NULL);
static cell_t check_phandle_prop(struct check *c, struct dt_info *dti,
struct node *node, const char *propname)
{
- struct node *root = dti->dt;
struct property *prop;
struct marker *m;
cell_t phandle;
@@ -504,7 +503,7 @@ static cell_t check_phandle_prop(struct check *c, struct dt_info *dti,
m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) {
assert(m->offset == 0);
- if (node != get_node_by_ref(root, m->ref))
+ if (node != dti_get_node_by_ref(dti, m->ref))
/* "Set this node's phandle equal to some
* other node's phandle". That's nonsensical
* by construction. */ {
@@ -614,7 +613,7 @@ static void fixup_phandle_references(struct check *c, struct dt_info *dti,
for_each_marker_of_type(m, REF_PHANDLE) {
assert(m->offset + sizeof(cell_t) <= prop->val.len);
- refnode = get_node_by_ref(dt, m->ref);
+ refnode = dti_get_node_by_ref(dti, m->ref);
if (! refnode) {
if (!(dti->dtsflags & (DTSF_PLUGIN | DTSF_ADDON)))
FAIL(c, dti, node, "Reference to non-existent node or "
@@ -633,7 +632,7 @@ static void fixup_phandle_references(struct check *c, struct dt_info *dti,
}
for_each_symbol(node->exportsymlist, exportsym) {
- refnode = get_node_by_ref(dt, exportsym->ref);
+ refnode = dti_get_node_by_ref(dti, exportsym->ref);
if (!refnode) {
if (!(dti->dtsflags & (DTSF_PLUGIN | DTSF_ADDON))) {
FAIL(c, dti, node,
@@ -657,7 +656,6 @@ ERROR(phandle_references, fixup_phandle_references, NULL,
static void fixup_path_references(struct check *c, struct dt_info *dti,
struct node *node)
{
- struct node *dt = dti->dt;
struct property *prop;
for_each_property(node, prop) {
@@ -668,7 +666,7 @@ static void fixup_path_references(struct check *c, struct dt_info *dti,
for_each_marker_of_type(m, REF_PATH) {
assert(m->offset <= prop->val.len);
- refnode = get_node_by_ref(dt, m->ref);
+ refnode = dti_get_node_by_ref(dti, m->ref);
if (!refnode) {
FAIL(c, dti, node, "Reference to non-existent node or label \"%s\"\n",
m->ref);
diff --git a/dtc-parser.y b/dtc-parser.y
index 61ebde2..08b3642 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -31,6 +31,18 @@ static bool is_ref_relative(const char *ref)
return ref[0] != '/' && strchr(&ref[1], '/');
}
+static struct node *parser_get_node_by_ref(struct node *dt, const char *ref)
+{
+ /*
+ * Use a temporary dt_info in order to use dti_get_node_by_ref()
+ */
+ struct dt_info dti = {};
+
+ dti.dt = dt;
+
+ return dti_get_node_by_ref(&dti, ref);
+}
+
%}
%union {
@@ -240,7 +252,7 @@ devicetree:
}
| devicetree DT_LABEL dt_ref nodedef
{
- struct node *target = get_node_by_ref($1, $3);
+ struct node *target = parser_get_node_by_ref($1, $3);
if ((last_header_flags & DTSF_PLUGIN) && is_ref_relative($3))
ERROR(&@2, "Label-relative reference %s not supported in plugin", $3);
@@ -259,7 +271,7 @@ devicetree:
ERROR(&@2, "Label-relative reference %s not supported in plugin", $2);
add_orphan_node($1, $3, $2);
} else {
- struct node *target = get_node_by_ref($1, $2);
+ struct node *target = parser_get_node_by_ref($1, $2);
if (target)
merge_nodes(target, $3);
@@ -270,7 +282,7 @@ devicetree:
}
| devicetree DT_LABEL_REF nodedef
{
- struct node *target = get_node_by_ref($1, $2);
+ struct node *target = parser_get_node_by_ref($1, $2);
if (target) {
merge_nodes(target, $3);
@@ -284,7 +296,7 @@ devicetree:
}
| devicetree DT_DEL_NODE dt_ref ';'
{
- struct node *target = get_node_by_ref($1, $3);
+ struct node *target = parser_get_node_by_ref($1, $3);
if (target)
delete_node(target);
@@ -296,7 +308,7 @@ devicetree:
}
| devicetree DT_OMIT_NO_REF dt_ref ';'
{
- struct node *target = get_node_by_ref($1, $3);
+ struct node *target = parser_get_node_by_ref($1, $3);
if (target)
omit_node_if_unused(target);
diff --git a/dtc.h b/dtc.h
index 7d53fcb..832265c 100644
--- a/dtc.h
+++ b/dtc.h
@@ -323,7 +323,6 @@ struct property *get_property_by_label(struct node *tree, const char *label,
struct marker *get_marker_label(struct node *tree, const char *label,
struct node **node, struct property **prop);
struct node *get_subnode(struct node *node, const char *nodename);
-struct node *get_node_by_ref(struct node *tree, const char *ref);
cell_t get_node_phandle(struct node *root, struct node *node);
uint32_t guess_boot_cpuid(struct node *tree);
@@ -357,6 +356,7 @@ struct dt_info {
struct node *dti_get_node_by_path(struct dt_info *dti, const char *path);
struct node *dti_get_node_by_label(struct dt_info *dti, const char *label);
struct node *dti_get_node_by_phandle(struct dt_info *dti, cell_t phandle);
+struct node *dti_get_node_by_ref(struct dt_info *dti, const char *ref);
/* DTS version flags definitions */
#define DTSF_V1 0x0001 /* /dts-v1/ */
diff --git a/livetree.c b/livetree.c
index a551307..f1c7e27 100644
--- a/livetree.c
+++ b/livetree.c
@@ -748,7 +748,7 @@ static struct node *get_node_by_phandle(struct node *tree, cell_t phandle)
return NULL;
}
-struct node *get_node_by_ref(struct node *tree, const char *ref)
+static struct node *get_node_by_ref(struct node *tree, const char *ref)
{
struct node *target = tree;
const char *label = NULL, *path = NULL;
@@ -824,6 +824,19 @@ struct node *dti_get_node_by_phandle(struct dt_info *dti, cell_t phandle)
return NULL;
}
+struct node *dti_get_node_by_ref(struct dt_info *dti, const char *ref)
+{
+ struct node *node;
+
+ if (dti->dt) {
+ node = get_node_by_ref(dti->dt, ref);
+ if (node)
+ return node;
+ }
+
+ return NULL;
+}
+
static void add_phandle_property(struct node *node,
const char *name, int format)
{
@@ -1407,7 +1420,7 @@ static void mark_local_phandles_internal(struct dt_info *dti,
for_each_property(node, prop) {
m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) {
- refnode = get_node_by_ref(dti->dt, m->ref);
+ refnode = dti_get_node_by_ref(dti, m->ref);
if (refnode)
m->is_local = true;
}
@@ -1460,7 +1473,7 @@ static void mark_local_exports_internal(struct dt_info *dti,
struct node *refnode;
for_each_symbol(node->exportsymlist, exportsym) {
- refnode = get_node_by_ref(dti->dt, exportsym->ref);
+ refnode = dti_get_node_by_ref(dti, exportsym->ref);
if (refnode)
exportsym->is_local = true;
}
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 44/77] dtc: Introduce dti_get_node_phandle()
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (42 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 43/77] dtc: Introduce dti_get_node_by_ref() Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 45/77] dtc: Introduce dti_get_property_by_label() Herve Codina
` (35 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The future introduction of orphan nodes for addons device-tree will lead
to more than one tree in the addons data. Those trees will be:
- the classical root tree starting at the root node
- trees related to orphan nodes
Also, an addon device-tree can have only trees based on orphan nodes. In
other words an addon device-tree is valid without having the classical
'root' tree.
To prepare this change, introduce and use dti_get_node_phandle().
dti_get_node_phandle() get the phandle value related to a node and
allocate a new value if the node doesn't have yet a phandle value.
It behaves in the same way as get_node_phandle() but it works at the
struct dt_info level.
It handles the case where a 'root' device-tree is not present and will
handle orphan nodes trees as soon as they will be introduced.
This introduction doesn't lead to any functional changes.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
checks.c | 5 ++---
dtc.h | 2 +-
livetree.c | 7 +++----
3 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/checks.c b/checks.c
index a47870d..7dd5032 100644
--- a/checks.c
+++ b/checks.c
@@ -601,7 +601,6 @@ ERROR(name_properties, check_name_properties, NULL, &name_is_string);
static void fixup_phandle_references(struct check *c, struct dt_info *dti,
struct node *node)
{
- struct node *dt = dti->dt;
struct symbol *exportsym;
struct property *prop;
struct node *refnode;
@@ -624,7 +623,7 @@ static void fixup_phandle_references(struct check *c, struct dt_info *dti,
continue;
}
- phandle = get_node_phandle(dt, refnode);
+ phandle = dti_get_node_phandle(dti, refnode);
*((fdt32_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
reference_node(refnode);
@@ -644,7 +643,7 @@ static void fixup_phandle_references(struct check *c, struct dt_info *dti,
}
/* Create the phandle property for this referenced node */
- phandle = get_node_phandle(dt, refnode);
+ phandle = dti_get_node_phandle(dti, refnode);
exportsym->phandle = phandle;
reference_node(refnode);
diff --git a/dtc.h b/dtc.h
index 832265c..f7b0b23 100644
--- a/dtc.h
+++ b/dtc.h
@@ -323,7 +323,6 @@ struct property *get_property_by_label(struct node *tree, const char *label,
struct marker *get_marker_label(struct node *tree, const char *label,
struct node **node, struct property **prop);
struct node *get_subnode(struct node *node, const char *nodename);
-cell_t get_node_phandle(struct node *root, struct node *node);
uint32_t guess_boot_cpuid(struct node *tree);
@@ -357,6 +356,7 @@ struct node *dti_get_node_by_path(struct dt_info *dti, const char *path);
struct node *dti_get_node_by_label(struct dt_info *dti, const char *label);
struct node *dti_get_node_by_phandle(struct dt_info *dti, cell_t phandle);
struct node *dti_get_node_by_ref(struct dt_info *dti, const char *ref);
+cell_t dti_get_node_phandle(struct dt_info *dti, struct node *node);
/* DTS version flags definitions */
#define DTSF_V1 0x0001 /* /dts-v1/ */
diff --git a/livetree.c b/livetree.c
index f1c7e27..a4917d1 100644
--- a/livetree.c
+++ b/livetree.c
@@ -853,14 +853,14 @@ static void add_phandle_property(struct node *node,
add_property(node, build_property(name, d, NULL));
}
-cell_t get_node_phandle(struct node *root, struct node *node)
+cell_t dti_get_node_phandle(struct dt_info *dti, struct node *node)
{
static cell_t phandle = 1; /* FIXME: ick, static local */
if (phandle_is_valid(node->phandle))
return node->phandle;
- while (get_node_by_phandle(root, phandle))
+ while (dti_get_node_by_phandle(dti, phandle))
phandle++;
node->phandle = phandle;
@@ -1143,7 +1143,6 @@ static void generate_label_tree_internal(struct dt_info *dti,
struct node *an, struct node *node,
bool allocph)
{
- struct node *dt = dti->dt;
struct node *c;
struct property *p;
struct label *l;
@@ -1173,7 +1172,7 @@ static void generate_label_tree_internal(struct dt_info *dti,
/* force allocation of a phandle for this node */
if (allocph)
- (void)get_node_phandle(dt, node);
+ (void)dti_get_node_phandle(dti, node);
}
for_each_child(node, c)
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 45/77] dtc: Introduce dti_get_property_by_label()
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (43 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 44/77] dtc: Introduce dti_get_node_phandle() Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 46/77] dtc: Introduce dti_get_marker_label() Herve Codina
` (34 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The future introduction of orphan nodes for addons device-tree will lead
to more than one tree in the addons data. Those trees will be:
- the classical root tree starting at the root node
- trees related to orphan nodes
Also, an addon device-tree can have only trees based on orphan nodes. In
other words an addon device-tree is valid without having the classical
'root' tree.
To prepare this change, introduce and use dti_get_property_by_label().
dti_get_property_by_label() retrieves a property (and the related
node) by its label like get_property_by_label() but it works at the
struct dt_info level.
It handles the case where a 'root' device-tree is not present and will
handle orphan nodes trees as soon as they will be introduced.
This introduction doesn't lead to any functional changes.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
checks.c | 2 +-
dtc.h | 5 +++--
livetree.c | 18 +++++++++++++++++-
3 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/checks.c b/checks.c
index 7dd5032..75040c0 100644
--- a/checks.c
+++ b/checks.c
@@ -447,7 +447,7 @@ static void check_duplicate_label(struct check *c, struct dt_info *dti,
othernode = dti_get_node_by_label(dti, label);
if (!othernode)
- otherprop = get_property_by_label(dt, label, &othernode);
+ otherprop = dti_get_property_by_label(dti, label, &othernode);
if (!othernode)
othermark = get_marker_label(dt, label, &othernode,
&otherprop);
diff --git a/dtc.h b/dtc.h
index f7b0b23..399e7fa 100644
--- a/dtc.h
+++ b/dtc.h
@@ -318,8 +318,6 @@ const char *get_unitname(struct node *node);
struct property *get_property(struct node *node, const char *propname);
cell_t propval_cell(struct property *prop);
cell_t propval_cell_n(struct property *prop, unsigned int n);
-struct property *get_property_by_label(struct node *tree, const char *label,
- struct node **node);
struct marker *get_marker_label(struct node *tree, const char *label,
struct node **node, struct property **prop);
struct node *get_subnode(struct node *node, const char *nodename);
@@ -357,6 +355,9 @@ struct node *dti_get_node_by_label(struct dt_info *dti, const char *label);
struct node *dti_get_node_by_phandle(struct dt_info *dti, cell_t phandle);
struct node *dti_get_node_by_ref(struct dt_info *dti, const char *ref);
cell_t dti_get_node_phandle(struct dt_info *dti, struct node *node);
+struct property *dti_get_property_by_label(struct dt_info *dti,
+ const char *label,
+ struct node **node);
/* DTS version flags definitions */
#define DTSF_V1 0x0001 /* /dts-v1/ */
diff --git a/livetree.c b/livetree.c
index a4917d1..d023075 100644
--- a/livetree.c
+++ b/livetree.c
@@ -594,7 +594,7 @@ cell_t propval_cell_n(struct property *prop, unsigned int n)
return fdt32_to_cpu(*((fdt32_t *)prop->val.val + n));
}
-struct property *get_property_by_label(struct node *tree, const char *label,
+static struct property *get_property_by_label(struct node *tree, const char *label,
struct node **node)
{
struct property *prop;
@@ -837,6 +837,22 @@ struct node *dti_get_node_by_ref(struct dt_info *dti, const char *ref)
return NULL;
}
+struct property *dti_get_property_by_label(struct dt_info *dti,
+ const char *label,
+ struct node **node)
+{
+ struct property *property;
+
+ if (dti->dt) {
+ property = get_property_by_label(dti->dt, label, node);
+ if (property)
+ return property;
+ }
+
+ *node = NULL;
+ return NULL;
+}
+
static void add_phandle_property(struct node *node,
const char *name, int format)
{
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 46/77] dtc: Introduce dti_get_marker_label()
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (44 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 45/77] dtc: Introduce dti_get_property_by_label() Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-15 6:51 ` David Gibson
2026-01-12 14:19 ` [RFC PATCH 47/77] dtc: Introduce dti_fill_fullpaths() Herve Codina
` (33 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The future introduction of orphan nodes for addons device-tree will lead
to more than one tree in the addons data. Those trees will be:
- the classical root tree starting at the root node
- trees related to orphan nodes
Also, an addon device-tree can have only trees based on orphan nodes. In
other words an addon device-tree is valid without having the classical
'root' tree.
To prepare this change, introduce and use dti_get_marker_label().
dti_get_marker_label() retrieves a marker and its related node and
property based on the label value. It behaves in the same way as
get_marker_label() but it works at the struct dt_info level.
It handles the case where a 'root' device-tree is not present and will
handle orphan nodes trees as soon as they will be introduced.
This introduction doesn't lead to any functional changes.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
checks.c | 5 ++---
dtc.h | 4 ++--
livetree.c | 18 +++++++++++++++++-
3 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/checks.c b/checks.c
index 75040c0..0a855f9 100644
--- a/checks.c
+++ b/checks.c
@@ -439,7 +439,6 @@ static void check_duplicate_label(struct check *c, struct dt_info *dti,
const char *label, struct node *node,
struct property *prop, struct marker *mark)
{
- struct node *dt = dti->dt;
struct node *othernode = NULL;
struct property *otherprop = NULL;
struct marker *othermark = NULL;
@@ -449,8 +448,8 @@ static void check_duplicate_label(struct check *c, struct dt_info *dti,
if (!othernode)
otherprop = dti_get_property_by_label(dti, label, &othernode);
if (!othernode)
- othermark = get_marker_label(dt, label, &othernode,
- &otherprop);
+ othermark = dti_get_marker_label(dti, label, &othernode,
+ &otherprop);
if (!othernode)
return;
diff --git a/dtc.h b/dtc.h
index 399e7fa..d45a84c 100644
--- a/dtc.h
+++ b/dtc.h
@@ -318,8 +318,6 @@ const char *get_unitname(struct node *node);
struct property *get_property(struct node *node, const char *propname);
cell_t propval_cell(struct property *prop);
cell_t propval_cell_n(struct property *prop, unsigned int n);
-struct marker *get_marker_label(struct node *tree, const char *label,
- struct node **node, struct property **prop);
struct node *get_subnode(struct node *node, const char *nodename);
uint32_t guess_boot_cpuid(struct node *tree);
@@ -358,6 +356,8 @@ cell_t dti_get_node_phandle(struct dt_info *dti, struct node *node);
struct property *dti_get_property_by_label(struct dt_info *dti,
const char *label,
struct node **node);
+struct marker *dti_get_marker_label(struct dt_info *dti, const char *label,
+ struct node **node, struct property **prop);
/* DTS version flags definitions */
#define DTSF_V1 0x0001 /* /dts-v1/ */
diff --git a/livetree.c b/livetree.c
index d023075..79f7b55 100644
--- a/livetree.c
+++ b/livetree.c
@@ -620,7 +620,7 @@ static struct property *get_property_by_label(struct node *tree, const char *lab
return NULL;
}
-struct marker *get_marker_label(struct node *tree, const char *label,
+static struct marker *get_marker_label(struct node *tree, const char *label,
struct node **node, struct property **prop)
{
struct marker *m;
@@ -853,6 +853,22 @@ struct property *dti_get_property_by_label(struct dt_info *dti,
return NULL;
}
+struct marker *dti_get_marker_label(struct dt_info *dti, const char *label,
+ struct node **node, struct property **prop)
+{
+ struct marker *marker;
+
+ if (dti->dt) {
+ marker = get_marker_label(dti->dt, label, node, prop);
+ if (marker)
+ return marker;
+ }
+
+ *prop = NULL;
+ *node = NULL;
+ return NULL;
+}
+
static void add_phandle_property(struct node *node,
const char *name, int format)
{
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 46/77] dtc: Introduce dti_get_marker_label()
2026-01-12 14:19 ` [RFC PATCH 46/77] dtc: Introduce dti_get_marker_label() Herve Codina
@ 2026-01-15 6:51 ` David Gibson
2026-01-19 16:02 ` Herve Codina
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-15 6:51 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 4533 bytes --]
On Mon, Jan 12, 2026 at 03:19:36PM +0100, Herve Codina wrote:
> The future introduction of orphan nodes for addons device-tree will lead
> to more than one tree in the addons data. Those trees will be:
> - the classical root tree starting at the root node
> - trees related to orphan nodes
>
> Also, an addon device-tree can have only trees based on orphan nodes. In
> other words an addon device-tree is valid without having the classical
> 'root' tree.
>
> To prepare this change, introduce and use dti_get_marker_label().
>
> dti_get_marker_label() retrieves a marker and its related node and
> property based on the label value. It behaves in the same way as
> get_marker_label() but it works at the struct dt_info level.
>
> It handles the case where a 'root' device-tree is not present and will
> handle orphan nodes trees as soon as they will be introduced.
>
> This introduction doesn't lead to any functional changes.
For all of these functions, if the new one is basically replacing the
old one, don't change the name, just change the signature.
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> checks.c | 5 ++---
> dtc.h | 4 ++--
> livetree.c | 18 +++++++++++++++++-
> 3 files changed, 21 insertions(+), 6 deletions(-)
>
> diff --git a/checks.c b/checks.c
> index 75040c0..0a855f9 100644
> --- a/checks.c
> +++ b/checks.c
> @@ -439,7 +439,6 @@ static void check_duplicate_label(struct check *c, struct dt_info *dti,
> const char *label, struct node *node,
> struct property *prop, struct marker *mark)
> {
> - struct node *dt = dti->dt;
> struct node *othernode = NULL;
> struct property *otherprop = NULL;
> struct marker *othermark = NULL;
> @@ -449,8 +448,8 @@ static void check_duplicate_label(struct check *c, struct dt_info *dti,
> if (!othernode)
> otherprop = dti_get_property_by_label(dti, label, &othernode);
> if (!othernode)
> - othermark = get_marker_label(dt, label, &othernode,
> - &otherprop);
> + othermark = dti_get_marker_label(dti, label, &othernode,
> + &otherprop);
>
> if (!othernode)
> return;
> diff --git a/dtc.h b/dtc.h
> index 399e7fa..d45a84c 100644
> --- a/dtc.h
> +++ b/dtc.h
> @@ -318,8 +318,6 @@ const char *get_unitname(struct node *node);
> struct property *get_property(struct node *node, const char *propname);
> cell_t propval_cell(struct property *prop);
> cell_t propval_cell_n(struct property *prop, unsigned int n);
> -struct marker *get_marker_label(struct node *tree, const char *label,
> - struct node **node, struct property **prop);
> struct node *get_subnode(struct node *node, const char *nodename);
>
> uint32_t guess_boot_cpuid(struct node *tree);
> @@ -358,6 +356,8 @@ cell_t dti_get_node_phandle(struct dt_info *dti, struct node *node);
> struct property *dti_get_property_by_label(struct dt_info *dti,
> const char *label,
> struct node **node);
> +struct marker *dti_get_marker_label(struct dt_info *dti, const char *label,
> + struct node **node, struct property **prop);
>
> /* DTS version flags definitions */
> #define DTSF_V1 0x0001 /* /dts-v1/ */
> diff --git a/livetree.c b/livetree.c
> index d023075..79f7b55 100644
> --- a/livetree.c
> +++ b/livetree.c
> @@ -620,7 +620,7 @@ static struct property *get_property_by_label(struct node *tree, const char *lab
> return NULL;
> }
>
> -struct marker *get_marker_label(struct node *tree, const char *label,
> +static struct marker *get_marker_label(struct node *tree, const char *label,
> struct node **node, struct property **prop)
> {
> struct marker *m;
> @@ -853,6 +853,22 @@ struct property *dti_get_property_by_label(struct dt_info *dti,
> return NULL;
> }
>
> +struct marker *dti_get_marker_label(struct dt_info *dti, const char *label,
> + struct node **node, struct property **prop)
> +{
> + struct marker *marker;
> +
> + if (dti->dt) {
> + marker = get_marker_label(dti->dt, label, node, prop);
> + if (marker)
> + return marker;
> + }
> +
> + *prop = NULL;
> + *node = NULL;
> + return NULL;
> +}
> +
> static void add_phandle_property(struct node *node,
> const char *name, int format)
> {
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 46/77] dtc: Introduce dti_get_marker_label()
2026-01-15 6:51 ` David Gibson
@ 2026-01-19 16:02 ` Herve Codina
2026-01-21 9:02 ` David Gibson
0 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-19 16:02 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
On Thu, 15 Jan 2026 17:51:30 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Mon, Jan 12, 2026 at 03:19:36PM +0100, Herve Codina wrote:
> > The future introduction of orphan nodes for addons device-tree will lead
> > to more than one tree in the addons data. Those trees will be:
> > - the classical root tree starting at the root node
> > - trees related to orphan nodes
> >
> > Also, an addon device-tree can have only trees based on orphan nodes. In
> > other words an addon device-tree is valid without having the classical
> > 'root' tree.
> >
> > To prepare this change, introduce and use dti_get_marker_label().
> >
> > dti_get_marker_label() retrieves a marker and its related node and
> > property based on the label value. It behaves in the same way as
> > get_marker_label() but it works at the struct dt_info level.
> >
> > It handles the case where a 'root' device-tree is not present and will
> > handle orphan nodes trees as soon as they will be introduced.
> >
> > This introduction doesn't lead to any functional changes.
>
> For all of these functions, if the new one is basically replacing the
> old one, don't change the name, just change the signature.
The old function is kept an used internally (move to static).
It is not a simple replacement.
When I introduce orphan node later on, those dti_xxxx() functions call
the old function multiple times. One call for the root tree and other calls
for orphan trees.
But anyway, If you prefer keeping the old name with a new signature,
I can do the following:
- move function_name() to __function_name()
- Update the function_name() signature and call __function_name().
Best regards
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 46/77] dtc: Introduce dti_get_marker_label()
2026-01-19 16:02 ` Herve Codina
@ 2026-01-21 9:02 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-21 9:02 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 2317 bytes --]
On Mon, Jan 19, 2026 at 05:02:40PM +0100, Herve Codina wrote:
> On Thu, 15 Jan 2026 17:51:30 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > On Mon, Jan 12, 2026 at 03:19:36PM +0100, Herve Codina wrote:
> > > The future introduction of orphan nodes for addons device-tree will lead
> > > to more than one tree in the addons data. Those trees will be:
> > > - the classical root tree starting at the root node
> > > - trees related to orphan nodes
> > >
> > > Also, an addon device-tree can have only trees based on orphan nodes. In
> > > other words an addon device-tree is valid without having the classical
> > > 'root' tree.
> > >
> > > To prepare this change, introduce and use dti_get_marker_label().
> > >
> > > dti_get_marker_label() retrieves a marker and its related node and
> > > property based on the label value. It behaves in the same way as
> > > get_marker_label() but it works at the struct dt_info level.
> > >
> > > It handles the case where a 'root' device-tree is not present and will
> > > handle orphan nodes trees as soon as they will be introduced.
> > >
> > > This introduction doesn't lead to any functional changes.
> >
> > For all of these functions, if the new one is basically replacing the
> > old one, don't change the name, just change the signature.
>
> The old function is kept an used internally (move to static).
> It is not a simple replacement.
It's a replacement in the sense that all the existing callers are
moving to the new function.
> When I introduce orphan node later on, those dti_xxxx() functions call
> the old function multiple times. One call for the root tree and other calls
> for orphan trees.
> But anyway, If you prefer keeping the old name with a new signature,
> I can do the following:
> - move function_name() to __function_name()
> - Update the function_name() signature and call __function_name().
That's a better plan. Except don't use __function_name(). _ prefixed
names are reserved for the C library. Use a _ suffix instead
(e.g. see fdt_get_property_by_offset_()).
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 47/77] dtc: Introduce dti_fill_fullpaths()
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (45 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 46/77] dtc: Introduce dti_get_marker_label() Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 48/77] dtc: Introduce orphan nodes Herve Codina
` (32 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The future introduction of orphan nodes for addons device-tree will lead
to more than one tree in the addons data. Those trees will be:
- the classical root tree starting at the root node
- trees related to orphan nodes
Also, an addon device-tree can have only trees based on orphan nodes. In
other words an addon device-tree is valid without having the classical
'root' tree.
To prepare this change, introduce and use dti_fill_fullpaths().
dti_fill_fullpaths() builds fullpaths of nodes available in a
tree like fill_fullpaths() but it works at the struct dt_info level.
It handles the case where a 'root' device-tree is not present and will
handle orphan nodes trees as soon as they will be introduced.
This introduction doesn't lead to any functional changes.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
dtc.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/dtc.c b/dtc.c
index e0a0b54..59f4d77 100644
--- a/dtc.c
+++ b/dtc.c
@@ -45,6 +45,13 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
fill_fullpaths(child, tree->fullpath);
}
+static void dti_fill_fullpaths(struct dt_info *dti)
+{
+ /* Fill fullpaths for the root node */
+ if (dti->dt)
+ fill_fullpaths(dti->dt, "");
+}
+
/* Usage related data. */
static const char usage_synopsis[] = "dtc [options] <input file>";
static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@LAThv";
@@ -326,7 +333,7 @@ int main(int argc, char *argv[])
if (cmdline_boot_cpuid != -1)
dti->boot_cpuid_phys = cmdline_boot_cpuid;
- fill_fullpaths(dti->dt, "");
+ dti_fill_fullpaths(dti);
/* on a plugin, generate by default */
if (dti->dtsflags & DTSF_PLUGIN) {
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 48/77] dtc: Introduce orphan nodes
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (46 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 47/77] dtc: Introduce dti_fill_fullpaths() Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 49/77] dtc: Handle orphan nodes in dti_get_xxx_by_yyy() Herve Codina
` (31 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Orphans nodes can be present in plugin and addon device-trees.
Those nodes are nodes without a parent. The root device-tree node is a
particular orphan node and is not part of those 'orphan' nodes group.
The orphan nodes group is related to nodes identified by a reference in
addons or plugins device-trees. For instance, the following node can be
described in addons and plugins (overlay) device-trees:
--- 8< ---
&foo {
subnode {
prop = <1>;
};
};
--- 8< ---
The foo referenced node described here has no parent. Indeed, it is not
a child of the root node.
This kind of node is legit in plugins and addons device-tree in order to
perform modification on existing node when the plugin or addon dtb is
applied. The foo referenced node is an existing node in the base tree an
the subnode node is added to the foo referenced node chen the dtb is
applied. Even if foo itself doesn't exists in the plugin or addon
device-tree, it needs to be referenced and modifications expected need
to be described (new sub-node for instance).
In plugin dts, when a orphan node is parsed, the dts structure is
changed and the orphan node is merged in the /fragment@n/__overlay__
node. The foo referenced node mentioned in the previous snippet is
transformed to:
--- 8< ---
/ {
fragment@0 {
target = <&foo>;
__overlay__ {
subnode {
prop = <0x01>;
};
};
};
__fixups__ {
foo = "/fragment@0:target:0";
};
};
--- 8< ---
With this mechanism, the orphan node itself doesn't exist anymore in
resulting plugin dtb but the resulting device-tree contains meta-data
mixed with pure 'device-tree' data.
Addons have been introduced to avoid this kind of mixing.
For addons, instead of changing the device-tree structure to add
something similar to fragments and __overlay__ present in plugins, the
orphan node will be present as a new dtb block and will be identified as
orphan thanks to meta-data added in dtb.
Modification done in this commit doesn't add functional changes but just
introduce orphan nodes entry points in data structures and functions in
order to prepare future changes related to parsing/generating dts and
dtb files.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
dtc-parser.y | 4 ++--
dtc.h | 7 ++++++-
flattree.c | 3 ++-
fstree.c | 3 ++-
livetree.c | 4 +++-
5 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/dtc-parser.y b/dtc-parser.y
index 08b3642..626a232 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -132,7 +132,7 @@ sourcefile:
{
parser_output = build_dt_info($1, $2, $3,
guess_boot_cpuid($3),
- NULL);
+ NULL, NULL);
}
| headers memreserves importlist devicetree
{
@@ -143,7 +143,7 @@ sourcefile:
*/
parser_output = build_dt_info($1, $2, $4,
$4 ? guess_boot_cpuid($4) : 0,
- reverse_symbol($3));
+ reverse_symbol($3), NULL);
}
;
diff --git a/dtc.h b/dtc.h
index d45a84c..399beee 100644
--- a/dtc.h
+++ b/dtc.h
@@ -277,6 +277,9 @@ struct node {
#define for_each_symbol(s0, s) \
for ((s) = (s0); (s); (s) = (s)->next)
+#define for_each_orphan(o0, o) \
+ for ((o) = (o0); (o); (o) = (o)->next_sibling)
+
void add_label(struct label **labels, char *label);
void delete_labels(struct label **labels);
@@ -345,6 +348,7 @@ struct dt_info {
uint32_t boot_cpuid_phys;
struct node *dt; /* the device tree */
struct symbol *importsymlist; /* Import symbol list */
+ struct node *orphanlist; /* orphan nodes list */
const char *outname; /* filename being written to, "-" for stdout */
};
@@ -367,7 +371,8 @@ struct marker *dti_get_marker_label(struct dt_info *dti, const char *label,
struct dt_info *build_dt_info(unsigned int dtsflags,
struct reserve_info *reservelist,
struct node *tree, uint32_t boot_cpuid_phys,
- struct symbol *importsymlist);
+ struct symbol *importsymlist,
+ struct node *orphanlist);
void sort_tree(struct dt_info *dti);
void generate_label_tree(struct dt_info *dti, const char *name, bool allocph);
void generate_fixups_tree(struct dt_info *dti, const char *name);
diff --git a/flattree.c b/flattree.c
index add02f0..412c7f8 100644
--- a/flattree.c
+++ b/flattree.c
@@ -1171,5 +1171,6 @@ struct dt_info *dt_from_blob(const char *fname)
fclose(f);
- return build_dt_info(DTSF_V1 | dtsflags, reservelist, tree, boot_cpuid_phys, importsymlist);
+ return build_dt_info(DTSF_V1 | dtsflags, reservelist, tree, boot_cpuid_phys,
+ importsymlist, NULL);
}
diff --git a/fstree.c b/fstree.c
index a6aaf1e..2be1ffa 100644
--- a/fstree.c
+++ b/fstree.c
@@ -72,5 +72,6 @@ struct dt_info *dt_from_fs(const char *dirname)
tree = read_fstree(dirname);
tree = name_node(tree, "");
- return build_dt_info(DTSF_V1, NULL, tree, guess_boot_cpuid(tree), NULL);
+ return build_dt_info(DTSF_V1, NULL, tree, guess_boot_cpuid(tree), NULL,
+ NULL);
}
diff --git a/livetree.c b/livetree.c
index 79f7b55..057997a 100644
--- a/livetree.c
+++ b/livetree.c
@@ -545,7 +545,8 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
struct dt_info *build_dt_info(unsigned int dtsflags,
struct reserve_info *reservelist,
struct node *tree, uint32_t boot_cpuid_phys,
- struct symbol *importsymlist)
+ struct symbol *importsymlist,
+ struct node *orphanlist)
{
struct dt_info *dti;
@@ -555,6 +556,7 @@ struct dt_info *build_dt_info(unsigned int dtsflags,
dti->dt = tree;
dti->boot_cpuid_phys = boot_cpuid_phys;
dti->importsymlist = importsymlist;
+ dti->orphanlist = orphanlist;
return dti;
}
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 49/77] dtc: Handle orphan nodes in dti_get_xxx_by_yyy()
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (47 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 48/77] dtc: Introduce orphan nodes Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-15 6:55 ` David Gibson
2026-01-12 14:19 ` [RFC PATCH 50/77] dtc: Handle orphan nodes in mark_local_xxx() and update_xxx_ref() Herve Codina
` (30 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Orphan nodes have been introduced recently.
Retrieving a node, a property and/or a marker from an orphan node tree
is perfectly legit.
Those retrievals are performed by the dti_get_xxx_by_yyy() functions
family.
Update them to handle orphan nodes.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
livetree.c | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/livetree.c b/livetree.c
index 057997a..fa9daff 100644
--- a/livetree.c
+++ b/livetree.c
@@ -789,6 +789,7 @@ static struct node *get_node_by_ref(struct node *tree, const char *ref)
struct node *dti_get_node_by_path(struct dt_info *dti, const char *path)
{
+ struct node *orphan;
struct node *node;
if (dti->dt) {
@@ -797,11 +798,18 @@ struct node *dti_get_node_by_path(struct dt_info *dti, const char *path)
return node;
}
+ for_each_orphan(dti->orphanlist, orphan) {
+ node = get_node_by_path(orphan, path);
+ if (node)
+ return node;
+ }
+
return NULL;
}
struct node *dti_get_node_by_label(struct dt_info *dti, const char *label)
{
+ struct node *orphan;
struct node *node;
if (dti->dt) {
@@ -810,11 +818,18 @@ struct node *dti_get_node_by_label(struct dt_info *dti, const char *label)
return node;
}
+ for_each_orphan(dti->orphanlist, orphan) {
+ node = get_node_by_label(orphan, label);
+ if (node)
+ return node;
+ }
+
return NULL;
}
struct node *dti_get_node_by_phandle(struct dt_info *dti, cell_t phandle)
{
+ struct node *orphan;
struct node *node;
if (dti->dt) {
@@ -823,11 +838,18 @@ struct node *dti_get_node_by_phandle(struct dt_info *dti, cell_t phandle)
return node;
}
+ for_each_orphan(dti->orphanlist, orphan) {
+ node = get_node_by_phandle(orphan, phandle);
+ if (node)
+ return node;
+ }
+
return NULL;
}
struct node *dti_get_node_by_ref(struct dt_info *dti, const char *ref)
{
+ struct node *orphan;
struct node *node;
if (dti->dt) {
@@ -836,6 +858,12 @@ struct node *dti_get_node_by_ref(struct dt_info *dti, const char *ref)
return node;
}
+ for_each_orphan(dti->orphanlist, orphan) {
+ node = get_node_by_ref(orphan, ref);
+ if (node)
+ return node;
+ }
+
return NULL;
}
@@ -844,6 +872,7 @@ struct property *dti_get_property_by_label(struct dt_info *dti,
struct node **node)
{
struct property *property;
+ struct node *orphan;
if (dti->dt) {
property = get_property_by_label(dti->dt, label, node);
@@ -851,6 +880,12 @@ struct property *dti_get_property_by_label(struct dt_info *dti,
return property;
}
+ for_each_orphan(dti->orphanlist, orphan) {
+ property = get_property_by_label(orphan, label, node);
+ if (property)
+ return property;
+ }
+
*node = NULL;
return NULL;
}
@@ -859,6 +894,7 @@ struct marker *dti_get_marker_label(struct dt_info *dti, const char *label,
struct node **node, struct property **prop)
{
struct marker *marker;
+ struct node *orphan;
if (dti->dt) {
marker = get_marker_label(dti->dt, label, node, prop);
@@ -866,6 +902,12 @@ struct marker *dti_get_marker_label(struct dt_info *dti, const char *label,
return marker;
}
+ for_each_orphan(dti->orphanlist, orphan) {
+ marker = get_marker_label(orphan, label, node, prop);
+ if (marker)
+ return marker;
+ }
+
*prop = NULL;
*node = NULL;
return NULL;
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 49/77] dtc: Handle orphan nodes in dti_get_xxx_by_yyy()
2026-01-12 14:19 ` [RFC PATCH 49/77] dtc: Handle orphan nodes in dti_get_xxx_by_yyy() Herve Codina
@ 2026-01-15 6:55 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-15 6:55 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 4514 bytes --]
On Mon, Jan 12, 2026 at 03:19:39PM +0100, Herve Codina wrote:
> Orphan nodes have been introduced recently.
>
> Retrieving a node, a property and/or a marker from an orphan node tree
> is perfectly legit.
>
> Those retrievals are performed by the dti_get_xxx_by_yyy() functions
> family.
>
> Update them to handle orphan nodes.
I think at least some of the orphan node stuff can be separated from
the import/export symbol stuff, and dtb changes. That can be reviewed
and merged first, which will simplify the review task.
The idea is this: at the moment, when we have multiple tree sections
in the dts, we merge them all together into a single tree as we parse.
The idea would be that we first make a list of all those sections,
then perform the merge as a separate step from parsing.
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> livetree.c | 42 ++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 42 insertions(+)
>
> diff --git a/livetree.c b/livetree.c
> index 057997a..fa9daff 100644
> --- a/livetree.c
> +++ b/livetree.c
> @@ -789,6 +789,7 @@ static struct node *get_node_by_ref(struct node *tree, const char *ref)
>
> struct node *dti_get_node_by_path(struct dt_info *dti, const char *path)
> {
> + struct node *orphan;
> struct node *node;
>
> if (dti->dt) {
> @@ -797,11 +798,18 @@ struct node *dti_get_node_by_path(struct dt_info *dti, const char *path)
> return node;
> }
>
> + for_each_orphan(dti->orphanlist, orphan) {
> + node = get_node_by_path(orphan, path);
> + if (node)
> + return node;
> + }
> +
> return NULL;
> }
>
> struct node *dti_get_node_by_label(struct dt_info *dti, const char *label)
> {
> + struct node *orphan;
> struct node *node;
>
> if (dti->dt) {
> @@ -810,11 +818,18 @@ struct node *dti_get_node_by_label(struct dt_info *dti, const char *label)
> return node;
> }
>
> + for_each_orphan(dti->orphanlist, orphan) {
> + node = get_node_by_label(orphan, label);
> + if (node)
> + return node;
> + }
> +
> return NULL;
> }
>
> struct node *dti_get_node_by_phandle(struct dt_info *dti, cell_t phandle)
> {
> + struct node *orphan;
> struct node *node;
>
> if (dti->dt) {
> @@ -823,11 +838,18 @@ struct node *dti_get_node_by_phandle(struct dt_info *dti, cell_t phandle)
> return node;
> }
>
> + for_each_orphan(dti->orphanlist, orphan) {
> + node = get_node_by_phandle(orphan, phandle);
> + if (node)
> + return node;
> + }
> +
> return NULL;
> }
>
> struct node *dti_get_node_by_ref(struct dt_info *dti, const char *ref)
> {
> + struct node *orphan;
> struct node *node;
>
> if (dti->dt) {
> @@ -836,6 +858,12 @@ struct node *dti_get_node_by_ref(struct dt_info *dti, const char *ref)
> return node;
> }
>
> + for_each_orphan(dti->orphanlist, orphan) {
> + node = get_node_by_ref(orphan, ref);
> + if (node)
> + return node;
> + }
> +
> return NULL;
> }
>
> @@ -844,6 +872,7 @@ struct property *dti_get_property_by_label(struct dt_info *dti,
> struct node **node)
> {
> struct property *property;
> + struct node *orphan;
>
> if (dti->dt) {
> property = get_property_by_label(dti->dt, label, node);
> @@ -851,6 +880,12 @@ struct property *dti_get_property_by_label(struct dt_info *dti,
> return property;
> }
>
> + for_each_orphan(dti->orphanlist, orphan) {
> + property = get_property_by_label(orphan, label, node);
> + if (property)
> + return property;
> + }
> +
> *node = NULL;
> return NULL;
> }
> @@ -859,6 +894,7 @@ struct marker *dti_get_marker_label(struct dt_info *dti, const char *label,
> struct node **node, struct property **prop)
> {
> struct marker *marker;
> + struct node *orphan;
>
> if (dti->dt) {
> marker = get_marker_label(dti->dt, label, node, prop);
> @@ -866,6 +902,12 @@ struct marker *dti_get_marker_label(struct dt_info *dti, const char *label,
> return marker;
> }
>
> + for_each_orphan(dti->orphanlist, orphan) {
> + marker = get_marker_label(orphan, label, node, prop);
> + if (marker)
> + return marker;
> + }
> +
> *prop = NULL;
> *node = NULL;
> return NULL;
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 50/77] dtc: Handle orphan nodes in mark_local_xxx() and update_xxx_ref()
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (48 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 49/77] dtc: Handle orphan nodes in dti_get_xxx_by_yyy() Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 51/77] dtc: Avoid NULL fullpath for nodes in orphan trees Herve Codina
` (29 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Orphan nodes have been introduced recently.
mark_local_phandles() and mark_local_exports() mark phandles and export
symbols as local when they reference a local node (i.e. a node in the
current device-tree).
update_phandles_ref() and update_exports_ref() update references
pointing to local nodes.
Those phandles, export symbols and references can involve orphan trees.
Indeed, even if an orphan node itself is not present in the current
device-tree, its subnodes are fully described in the current device-tree
and so, those subnodes have to be considered as local nodes.
Update those functions to handle orphan nodes.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
livetree.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/livetree.c b/livetree.c
index fa9daff..52c55be 100644
--- a/livetree.c
+++ b/livetree.c
@@ -1481,7 +1481,12 @@ static void update_phandles_ref_internal(struct dt_info *dti, struct node *node)
void update_phandles_ref(struct dt_info *dti)
{
+ struct node *orphan;
+
update_phandles_ref_internal(dti, dti->dt);
+
+ for_each_orphan(dti->orphanlist, orphan)
+ update_phandles_ref_internal(dti, orphan);
}
static void mark_local_phandles_internal(struct dt_info *dti,
@@ -1507,7 +1512,12 @@ static void mark_local_phandles_internal(struct dt_info *dti,
void mark_local_phandles(struct dt_info *dti)
{
+ struct node *orphan;
+
mark_local_phandles_internal(dti, dti->dt);
+
+ for_each_orphan(dti->orphanlist, orphan)
+ mark_local_phandles_internal(dti, orphan);
}
static void update_exports_ref_internal(struct dt_info *dti, struct node *node)
@@ -1537,7 +1547,12 @@ static void update_exports_ref_internal(struct dt_info *dti, struct node *node)
void update_exports_ref(struct dt_info *dti)
{
+ struct node *orphan;
+
update_exports_ref_internal(dti, dti->dt);
+
+ for_each_orphan(dti->orphanlist, orphan)
+ update_exports_ref_internal(dti, orphan);
}
static void mark_local_exports_internal(struct dt_info *dti,
@@ -1559,6 +1574,10 @@ static void mark_local_exports_internal(struct dt_info *dti,
void mark_local_exports(struct dt_info *dti)
{
+ struct node *orphan;
+
mark_local_exports_internal(dti, dti->dt);
+ for_each_orphan(dti->orphanlist, orphan)
+ mark_local_exports_internal(dti, orphan);
}
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 51/77] dtc: Avoid NULL fullpath for nodes in orphan trees
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (49 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 50/77] dtc: Handle orphan nodes in mark_local_xxx() and update_xxx_ref() Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-15 6:56 ` David Gibson
2026-01-12 14:19 ` [RFC PATCH 52/77] checks: Perform checks for orphan nodes Herve Codina
` (28 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Orphan nodes have been introduced recently.
The process_checks() function uses fullpath in several places and
crashes due NULL pointer dereferences if fullpath is NULL.
In order to have process_checks() function running without crashes with
orphan trees (i.e. trees based on orphan nodes), the fullpath of node
available in those orphan trees must not be NULL.
Fullpath values are built by dti_fill_fullpaths(). Update it to handle
fullpath in trees based on orphan nodes.
Use a simple "__orphan__/" prefix to avoid the NULL pointer and to be
distinct from the root node ("/" prefix).
It is worth noting that this "__orphan__/" prefix is a temporary prefix
and it will be change later when support for reference by path involving
nodes in orphan tree is added.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
dtc.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/dtc.c b/dtc.c
index 59f4d77..5cf8f31 100644
--- a/dtc.c
+++ b/dtc.c
@@ -47,9 +47,14 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
static void dti_fill_fullpaths(struct dt_info *dti)
{
+ struct node *orphan;
+
/* Fill fullpaths for the root node */
if (dti->dt)
fill_fullpaths(dti->dt, "");
+
+ for_each_orphan(dti->orphanlist, orphan)
+ fill_fullpaths(orphan, "__orphan__/");
}
/* Usage related data. */
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 51/77] dtc: Avoid NULL fullpath for nodes in orphan trees
2026-01-12 14:19 ` [RFC PATCH 51/77] dtc: Avoid NULL fullpath for nodes in orphan trees Herve Codina
@ 2026-01-15 6:56 ` David Gibson
2026-01-19 16:11 ` Herve Codina
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-15 6:56 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 1899 bytes --]
On Mon, Jan 12, 2026 at 03:19:41PM +0100, Herve Codina wrote:
> Orphan nodes have been introduced recently.
>
> The process_checks() function uses fullpath in several places and
> crashes due NULL pointer dereferences if fullpath is NULL.
>
> In order to have process_checks() function running without crashes with
> orphan trees (i.e. trees based on orphan nodes), the fullpath of node
> available in those orphan trees must not be NULL.
>
> Fullpath values are built by dti_fill_fullpaths(). Update it to handle
> fullpath in trees based on orphan nodes.
>
> Use a simple "__orphan__/" prefix to avoid the NULL pointer and to be
> distinct from the root node ("/" prefix).
>
> It is worth noting that this "__orphan__/" prefix is a temporary prefix
> and it will be change later when support for reference by path involving
> nodes in orphan tree is added.
It might be simpler to eliminate the fullpath field entirely, and
instead have a function that calculates fullpaths at the point you
need them.
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> dtc.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/dtc.c b/dtc.c
> index 59f4d77..5cf8f31 100644
> --- a/dtc.c
> +++ b/dtc.c
> @@ -47,9 +47,14 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
>
> static void dti_fill_fullpaths(struct dt_info *dti)
> {
> + struct node *orphan;
> +
> /* Fill fullpaths for the root node */
> if (dti->dt)
> fill_fullpaths(dti->dt, "");
> +
> + for_each_orphan(dti->orphanlist, orphan)
> + fill_fullpaths(orphan, "__orphan__/");
> }
>
> /* Usage related data. */
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 51/77] dtc: Avoid NULL fullpath for nodes in orphan trees
2026-01-15 6:56 ` David Gibson
@ 2026-01-19 16:11 ` Herve Codina
0 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-19 16:11 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
On Thu, 15 Jan 2026 17:56:07 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Mon, Jan 12, 2026 at 03:19:41PM +0100, Herve Codina wrote:
> > Orphan nodes have been introduced recently.
> >
> > The process_checks() function uses fullpath in several places and
> > crashes due NULL pointer dereferences if fullpath is NULL.
> >
> > In order to have process_checks() function running without crashes with
> > orphan trees (i.e. trees based on orphan nodes), the fullpath of node
> > available in those orphan trees must not be NULL.
> >
> > Fullpath values are built by dti_fill_fullpaths(). Update it to handle
> > fullpath in trees based on orphan nodes.
> >
> > Use a simple "__orphan__/" prefix to avoid the NULL pointer and to be
> > distinct from the root node ("/" prefix).
> >
> > It is worth noting that this "__orphan__/" prefix is a temporary prefix
> > and it will be change later when support for reference by path involving
> > nodes in orphan tree is added.
>
> It might be simpler to eliminate the fullpath field entirely, and
> instead have a function that calculates fullpaths at the point you
> need them.
I am not sure it will be simpler.
I would prefer keeping dti_fill_fullpaths() for the moment.
This could be change later when things are more stable.
Many thinks are under discussion and changing all users of the the fullpath
field now will introduce more complexity which is not needed right now.
Best regards,
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 52/77] checks: Perform checks for orphan nodes
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (50 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 51/77] dtc: Avoid NULL fullpath for nodes in orphan trees Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 53/77] dtc: Rename add_orphan_node() to plugin_add_orphan_node() Herve Codina
` (27 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Orphan nodes have been introduced recently.
Those nodes and related trees need to be handled by the check process.
Indeed, in addition to performing checks, phandles are allocated and
referenced nodes are marked 'referenced' during the check process.
Take into account orphan nodes in check process.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
checks.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/checks.c b/checks.c
index 0a855f9..3ed3a0c 100644
--- a/checks.c
+++ b/checks.c
@@ -155,6 +155,7 @@ static bool is_multiple_of(int multiple, int divisor)
static bool run_check(struct check *c, struct dt_info *dti)
{
struct node *dt = dti->dt;
+ struct node *orphan;
bool error = false;
int i;
@@ -180,6 +181,9 @@ static bool run_check(struct check *c, struct dt_info *dti)
check_nodes_props(c, dti, dt);
+ for_each_orphan(dti->orphanlist, orphan)
+ check_nodes_props(c, dti, orphan);
+
if (c->status == UNCHECKED)
c->status = PASSED;
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 53/77] dtc: Rename add_orphan_node() to plugin_add_orphan_node()
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (51 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 52/77] checks: Perform checks for orphan nodes Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 54/77] dtc: Add basic support for addon orphan nodes dts parsing Herve Codina
` (26 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
add_orphan_node() is used when a orphan node is parsed in a plugin
(overlay) device-tree.
This function creates some device-tree nodes (/fragment@n/__overlay__)
in order to merge the parsed orphan node.
This is specific to plugin device-trees and cannot be used for addon
device-trees.
In order to clarify that add_orphan_node() is specific to plugin
device-trees and to prepare the support for orphan node parsing
in the addon context, rename current add_orphan_node() to
plugin_add_orphan_node().
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
dtc-parser.y | 6 +++---
dtc.h | 3 ++-
livetree.c | 3 ++-
3 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/dtc-parser.y b/dtc-parser.y
index 626a232..2b5b3c4 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -245,7 +245,7 @@ devicetree:
ERROR(&@2, "Label or path %s not found", $1);
else if (is_ref_relative($1))
ERROR(&@2, "Label-relative reference %s not supported in plugin", $1);
- $$ = add_orphan_node(
+ $$ = plugin_add_orphan_node(
name_node(build_node(NULL, NULL, NULL, NULL),
""),
$2, $1);
@@ -269,7 +269,7 @@ devicetree:
if (last_header_flags & DTSF_PLUGIN) {
if (is_ref_relative($2))
ERROR(&@2, "Label-relative reference %s not supported in plugin", $2);
- add_orphan_node($1, $3, $2);
+ plugin_add_orphan_node($1, $3, $2);
} else {
struct node *target = parser_get_node_by_ref($1, $2);
@@ -288,7 +288,7 @@ devicetree:
merge_nodes(target, $3);
} else {
if (last_header_flags & DTSF_PLUGIN)
- add_orphan_node($1, $3, $2);
+ plugin_add_orphan_node($1, $3, $2);
else
ERROR(&@2, "Label or path %s not found", $2);
}
diff --git a/dtc.h b/dtc.h
index 399beee..e463756 100644
--- a/dtc.h
+++ b/dtc.h
@@ -305,7 +305,8 @@ struct node *omit_node_if_unused(struct node *node);
struct node *reference_node(struct node *node);
struct node *chain_node(struct node *first, struct node *list);
struct node *merge_nodes(struct node *old_node, struct node *new_node);
-struct node *add_orphan_node(struct node *old_node, struct node *new_node, char *ref);
+struct node *plugin_add_orphan_node(struct node *old_node, struct node *new_node,
+ char *ref);
void add_property(struct node *node, struct property *prop);
void delete_property_by_name(struct node *node, char *name);
diff --git a/livetree.c b/livetree.c
index 52c55be..a21dfc1 100644
--- a/livetree.c
+++ b/livetree.c
@@ -319,7 +319,8 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
return old_node;
}
-struct node * add_orphan_node(struct node *dt, struct node *new_node, char *ref)
+struct node *plugin_add_orphan_node(struct node *dt, struct node *new_node,
+ char *ref)
{
static unsigned int next_orphan_fragment = 0;
struct node *node;
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 54/77] dtc: Add basic support for addon orphan nodes dts parsing
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (52 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 53/77] dtc: Rename add_orphan_node() to plugin_add_orphan_node() Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 55/77] dtc: Add orphan nodes in generated dts file Herve Codina
` (25 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Orphan nodes are nodes without a parent. The root device-tree node is a
particular orphan node and is not part of those 'orphan' nodes group.
The orphan nodes group is related to nodes identified by a reference in
addons or plugins device-trees. For instance, int the following snippet,
foo is an orphan node:
--- 8< ---
/addon/
&foo {
subnode {
prop = <1>;
};
};
--- 8< ---
The foo referenced node described has no parent. Indeed, it is not
a child of the root node.
This kind of node is legit in addons device-tree in order to perform
modification on existing node when the addon dtb is applied.
Add support for addon orphan node in dts parsing.
Compared to plugin (overlay) orphan node parsing, the orphan node parsed
in the addon context do not lead to any change in the device-tree
structure. '/fragment@0/__overlay__' or similar kind of structure is not
needed for addons.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
checks.c | 14 ++++++++++--
dtc-parser.y | 60 +++++++++++++++++++++++++++++++++++-----------------
dtc.h | 4 ++++
livetree.c | 30 ++++++++++++++++++++++++++
treesource.c | 2 ++
5 files changed, 89 insertions(+), 21 deletions(-)
diff --git a/checks.c b/checks.c
index 3ed3a0c..83a0f6e 100644
--- a/checks.c
+++ b/checks.c
@@ -317,7 +317,12 @@ ERROR(duplicate_property_names, check_duplicate_property_names, NULL);
static void check_node_name_chars(struct check *c, struct dt_info *dti,
struct node *node)
{
- size_t n = strspn(node->name, c->data);
+ size_t n;
+
+ if ((dti->dtsflags & DTSF_ADDON) && node->ref)
+ return; /* Checking name doesn't make sense for an orphan node */
+
+ n = strspn(node->name, c->data);
if (n < strlen(node->name))
FAIL(c, dti, node, "Bad character '%c' in node name",
@@ -328,7 +333,12 @@ ERROR(node_name_chars, check_node_name_chars, NODECHARS);
static void check_node_name_chars_strict(struct check *c, struct dt_info *dti,
struct node *node)
{
- size_t n = strspn(node->name, c->data);
+ size_t n;
+
+ if ((dti->dtsflags & DTSF_ADDON) && node->ref)
+ return; /* Checking name doesn't make sense for an orphan node */
+
+ n = strspn(node->name, c->data);
if (n < node->basenamelen)
FAIL(c, dti, node, "Character '%c' not recommended in node name",
diff --git a/dtc-parser.y b/dtc-parser.y
index 2b5b3c4..10ca6d4 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -23,6 +23,7 @@ extern void yyerror(char const *s);
extern struct dt_info *parser_output;
extern bool treesource_error;
+extern struct node *parser_orphanlist;
unsigned int last_header_flags;
@@ -31,7 +32,8 @@ static bool is_ref_relative(const char *ref)
return ref[0] != '/' && strchr(&ref[1], '/');
}
-static struct node *parser_get_node_by_ref(struct node *dt, const char *ref)
+static struct node *parser_get_node_by_ref(struct node *dt, struct node *orphanlist,
+ const char *ref)
{
/*
* Use a temporary dt_info in order to use dti_get_node_by_ref()
@@ -39,6 +41,7 @@ static struct node *parser_get_node_by_ref(struct node *dt, const char *ref)
struct dt_info dti = {};
dti.dt = dt;
+ dti.orphanlist = orphanlist;
return dti_get_node_by_ref(&dti, ref);
}
@@ -132,7 +135,7 @@ sourcefile:
{
parser_output = build_dt_info($1, $2, $3,
guess_boot_cpuid($3),
- NULL, NULL);
+ NULL, parser_orphanlist);
}
| headers memreserves importlist devicetree
{
@@ -143,7 +146,8 @@ sourcefile:
*/
parser_output = build_dt_info($1, $2, $4,
$4 ? guess_boot_cpuid($4) : 0,
- reverse_symbol($3), NULL);
+ reverse_symbol($3),
+ parser_orphanlist);
}
;
@@ -241,21 +245,28 @@ devicetree:
}
| dt_ref nodedef
{
- if (!(last_header_flags & DTSF_PLUGIN))
+ if (!(last_header_flags & (DTSF_PLUGIN | DTSF_ADDON)))
ERROR(&@2, "Label or path %s not found", $1);
else if (is_ref_relative($1))
- ERROR(&@2, "Label-relative reference %s not supported in plugin", $1);
- $$ = plugin_add_orphan_node(
- name_node(build_node(NULL, NULL, NULL, NULL),
- ""),
- $2, $1);
+ ERROR(&@2, "Label-relative reference %s not supported in plugin nor addon", $1);
+
+ if (last_header_flags & DTSF_PLUGIN) {
+ $$ = plugin_add_orphan_node(
+ name_node(build_node(NULL, NULL, NULL, NULL),
+ ""),
+ $2, $1);
+ } else {
+ ERROR(&@2, "Orphan node %s without a root node not yet supported", $1);
+ YYERROR;
+ }
}
| devicetree DT_LABEL dt_ref nodedef
{
- struct node *target = parser_get_node_by_ref($1, $3);
+ struct node *target = parser_get_node_by_ref(
+ $1, parser_orphanlist, $3);
- if ((last_header_flags & DTSF_PLUGIN) && is_ref_relative($3))
- ERROR(&@2, "Label-relative reference %s not supported in plugin", $3);
+ if ((last_header_flags & (DTSF_PLUGIN | DTSF_ADDON)) && is_ref_relative($3))
+ ERROR(&@2, "Label-relative reference %s not supported in plugin nor addon", $3);
if (target) {
add_label(&target->labels, $2);
@@ -266,12 +277,17 @@ devicetree:
}
| devicetree DT_PATH_REF nodedef
{
- if (last_header_flags & DTSF_PLUGIN) {
+ if (last_header_flags & (DTSF_PLUGIN | DTSF_ADDON)) {
if (is_ref_relative($2))
- ERROR(&@2, "Label-relative reference %s not supported in plugin", $2);
- plugin_add_orphan_node($1, $3, $2);
+ ERROR(&@2, "Label-relative reference %s not supported in plugin nor addon", $2);
+ if(last_header_flags & DTSF_PLUGIN)
+ plugin_add_orphan_node($1, $3, $2);
+ else
+ addon_add_orphan_node(&parser_orphanlist,
+ orphan_node($3, $2));
} else {
- struct node *target = parser_get_node_by_ref($1, $2);
+ struct node *target = parser_get_node_by_ref(
+ $1, parser_orphanlist, $2);
if (target)
merge_nodes(target, $3);
@@ -282,13 +298,17 @@ devicetree:
}
| devicetree DT_LABEL_REF nodedef
{
- struct node *target = parser_get_node_by_ref($1, $2);
+ struct node *target = parser_get_node_by_ref(
+ $1, parser_orphanlist, $2);
if (target) {
merge_nodes(target, $3);
} else {
if (last_header_flags & DTSF_PLUGIN)
plugin_add_orphan_node($1, $3, $2);
+ else if (last_header_flags & DTSF_ADDON)
+ addon_add_orphan_node(&parser_orphanlist,
+ orphan_node($3, $2));
else
ERROR(&@2, "Label or path %s not found", $2);
}
@@ -296,7 +316,8 @@ devicetree:
}
| devicetree DT_DEL_NODE dt_ref ';'
{
- struct node *target = parser_get_node_by_ref($1, $3);
+ struct node *target = parser_get_node_by_ref(
+ $1, parser_orphanlist, $3);
if (target)
delete_node(target);
@@ -308,7 +329,8 @@ devicetree:
}
| devicetree DT_OMIT_NO_REF dt_ref ';'
{
- struct node *target = parser_get_node_by_ref($1, $3);
+ struct node *target = parser_get_node_by_ref(
+ $1, parser_orphanlist, $3);
if (target)
omit_node_if_unused(target);
diff --git a/dtc.h b/dtc.h
index e463756..a3e29a6 100644
--- a/dtc.h
+++ b/dtc.h
@@ -250,6 +250,8 @@ struct node {
const struct bus_type *bus;
struct srcpos *srcpos;
+ const char *ref; /* Use only for orphan nodes */
+
bool omit_if_unused, is_referenced;
};
@@ -307,6 +309,8 @@ struct node *chain_node(struct node *first, struct node *list);
struct node *merge_nodes(struct node *old_node, struct node *new_node);
struct node *plugin_add_orphan_node(struct node *old_node, struct node *new_node,
char *ref);
+struct node *orphan_node(struct node *node, const char *ref);
+void addon_add_orphan_node(struct node **dt_orphan, struct node *new_orphan);
void add_property(struct node *node, struct property *prop);
void delete_property_by_name(struct node *node, char *name);
diff --git a/livetree.c b/livetree.c
index a21dfc1..eaface5 100644
--- a/livetree.c
+++ b/livetree.c
@@ -351,6 +351,36 @@ struct node *plugin_add_orphan_node(struct node *dt, struct node *new_node,
return dt;
}
+struct node *orphan_node(struct node *node, const char *ref)
+{
+ node->ref = xstrdup(ref);
+
+ return node;
+}
+
+void addon_add_orphan_node(struct node **dt_orphan, struct node *new_orphan)
+{
+ struct node **last_orphan;
+ char *name;
+
+ /*
+ * For addon orphan node, the node name is set to '&reference'
+ * This ease the dts file generation and the usage of existing code
+ */
+ xasprintf(&name, "&%s", new_orphan->ref);
+
+ name_node(new_orphan, name);
+ free(name);
+
+ new_orphan->next_sibling = NULL;
+
+ last_orphan = dt_orphan;
+ while (*last_orphan)
+ last_orphan = &((*last_orphan)->next_sibling);
+
+ *last_orphan = new_orphan;
+}
+
struct node *chain_node(struct node *first, struct node *list)
{
assert(first->next_sibling == NULL);
diff --git a/treesource.c b/treesource.c
index 04f65bb..77ff4fb 100644
--- a/treesource.c
+++ b/treesource.c
@@ -12,11 +12,13 @@ extern YYLTYPE yylloc;
struct dt_info *parser_output;
bool treesource_error;
+struct node *parser_orphanlist;
struct dt_info *dt_from_source(const char *fname)
{
parser_output = NULL;
treesource_error = false;
+ parser_orphanlist = NULL;
srcfile_push(fname);
yyin = current_srcfile->f;
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 55/77] dtc: Add orphan nodes in generated dts file
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (53 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 54/77] dtc: Add basic support for addon orphan nodes dts parsing Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 56/77] Add support for FDT_BEGIN_NODE_REF_SYM dtb tag Herve Codina
` (24 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Orphan nodes parsing from an addon dts file is supported.
Add the support for orphan nodes in the dts file generation.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
treesource.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/treesource.c b/treesource.c
index 77ff4fb..bc5d847 100644
--- a/treesource.c
+++ b/treesource.c
@@ -384,6 +384,7 @@ void dt_to_source(FILE *f, struct dt_info *dti)
{
struct reserve_info *re;
struct symbol *importsym;
+ struct node *orphan;
fprintf(f, "/dts-v1/;\n");
if (dti->dtsflags & DTSF_ADDON)
@@ -410,4 +411,9 @@ void dt_to_source(FILE *f, struct dt_info *dti)
}
write_tree_source_node(f, dti->dt, 0);
+
+ for_each_orphan(dti->orphanlist, orphan) {
+ fprintf(f, "\n");
+ write_tree_source_node(f, orphan, 0);
+ }
}
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 56/77] Add support for FDT_BEGIN_NODE_REF_SYM dtb tag
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (54 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 55/77] dtc: Add orphan nodes in generated dts file Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 57/77] tests: metadata: Add basic test for addon orphan nodes Herve Codina
` (23 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The FDT_BEGIN_NODE_REF dtb tag is a meta-data tag defining a referenced
node.
This kind of nodes can be present in addon dtbs and identifies a node
external to the addon dtb but modified by the addon.
For instance, if an addon adds a sub-node a node existing in the
device-tree the addon is applied to, the existing node needs to be
referenced by the addon dtb. This is the purpose of FDT_BEGIN_NODE_REF.
This tag typically identifies what we call orphan nodes in dts.
The structure of FDT_BEGIN_NODE_REF is identical to the structure of
FDT_BEGIN_NODE except that the node name is not present and it is
replaced by the node symbol reference needed to reference the node in
the base device-tree when the addon device-tree blob is applied.
The FDT_BEGIN_NODE_REF block is terminated by a FDT_END_NODE tag.
The FDT_BEGIN_NODE_REF tag is followed by:
- node symbol name (string including \0)
The symbol name used to reference the node in the base device-tree
when the addon is applied.
- padding:
Padding (0x00) added to have the next value aligned on 32bit.
- Node structure (see FDT_BEGIN_NODE):
Items provided by the addon to be merged in the referenced
node when the addon is applied.
- FDT_END_NODE tag
Example:
FDT_BEGIN_NODE_REF 'foo1' 0x00 0x00 0x00 ... FDT_END_NODE
This means that the external node referenced by 'foo1' is modified by
the addon. Items to merge when the addon is applied are represented by
the '...' part.
This is what is encoded in the dtb when the related dts has the
following orphan node:
&foo1 {
...
};
If several external nodes are modified by the addon (several orphan
nodes described in the addon), several FDT_BEGIN_NODE_REF are present.
Each of them related to an external node. For instance, having 'foo1'
and 'bar1' as external nodes leads to the following sequence:
FDT_BEGIN_NODE_REF 'foo1' 0x00 0x00 0x00 ... FDT_END_NODE
FDT_BEGIN_NODE_REF 'bar1' 0x00 0x00 0x00 ... FDT_END_NODE
The FDT_BEGIN_NODE_REF can be present only for a top level node.
Subnodes are identified by a FDT_BEGIN_NODE tag.
If FDT_BEGIN_NODE_REF tags are present in the dtb, they are present
after the root node definition (i.e. after the first FDT_BEGIN_NODE
/ FDT_END_NODE block).
Add support for this new dtb tag.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
fdtdump.c | 11 ++++++
flattree.c | 103 ++++++++++++++++++++++++++++++++++++++++++---------
libfdt/fdt.c | 10 +++++
libfdt/fdt.h | 2 +
4 files changed, 108 insertions(+), 18 deletions(-)
diff --git a/fdtdump.c b/fdtdump.c
index 04e6e38..7d58e3d 100644
--- a/fdtdump.c
+++ b/fdtdump.c
@@ -176,6 +176,17 @@ static void dump_blob(void *blob, bool debug)
continue;
}
+ if (tag == FDT_BEGIN_NODE_REF) {
+ last_prop_name = NULL;
+ s = p;
+ p = PALIGN(p + strlen(s) + 1, 4);
+
+ printf("%*s&%s {\n", depth * shift, "", s);
+
+ depth++;
+ continue;
+ }
+
if (tag == FDT_EXPORT_SYM) {
s = p;
p = PALIGN(p + strlen(s) + 1, 4);
diff --git a/flattree.c b/flattree.c
index 412c7f8..27f7608 100644
--- a/flattree.c
+++ b/flattree.c
@@ -51,6 +51,7 @@ struct emitter {
void (*export_sym)(void *);
void (*export_sym_ref)(void *);
void (*import_sym)(void *);
+ void (*beginnode_ref)(void *, struct label *labels);
};
static void bin_emit_cell(void *e, cell_t val)
@@ -125,6 +126,11 @@ static void bin_emit_import_sym(void *e)
bin_emit_cell(e, FDT_IMPORT_SYM);
}
+static void bin_emit_beginnode_ref(void *e, struct label *labels)
+{
+ bin_emit_cell(e, FDT_BEGIN_NODE_REF);
+}
+
static struct emitter bin_emitter = {
.cell = bin_emit_cell,
.string = bin_emit_string,
@@ -138,6 +144,7 @@ static struct emitter bin_emitter = {
.export_sym = bin_emit_export_sym,
.export_sym_ref = bin_emit_export_sym_ref,
.import_sym = bin_emit_import_sym,
+ .beginnode_ref = bin_emit_beginnode_ref,
};
static void emit_label(FILE *f, const char *prefix, const char *label)
@@ -292,6 +299,18 @@ static void asm_emit_import_sym(void *e)
die("FDT_IMPORT_SYM not supported in asm output\n");
}
+static void asm_emit_beginnode_ref(void *e, struct label *labels)
+{
+ /*
+ * Orphan nodes (FDT_BEGIN_NODE_REF tags) are an feature
+ * introduced for addons.
+ * Addons device-tree blob have to reason to be in the asm format.
+ *
+ * Need to be implemented if really needed.
+ */
+ die("FDT_BEGIN_NODE_REF not supported in asm output\n");
+}
+
static struct emitter asm_emitter = {
.cell = asm_emit_cell,
.string = asm_emit_string,
@@ -305,6 +324,7 @@ static struct emitter asm_emitter = {
.export_sym = asm_emit_export_sym,
.export_sym = asm_emit_export_sym_ref,
.import_sym = asm_emit_import_sym,
+ .beginnode_ref = asm_emit_beginnode_ref,
};
static int stringtable_insert(struct data *d, const char *str)
@@ -335,13 +355,17 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
if (tree->deleted)
return;
- emit->beginnode(etarget, tree->labels);
-
- if (vi->flags & FTF_FULLPATH)
- emit->string(etarget, tree->fullpath, 0);
- else
- emit->string(etarget, tree->name, 0);
+ if ((vi->flags & FTF_REF_XXX) && tree->ref) {
+ emit->beginnode_ref(etarget, tree->labels);
+ emit->string(etarget, tree->ref, 0);
+ } else {
+ emit->beginnode(etarget, tree->labels);
+ if (vi->flags & FTF_FULLPATH)
+ emit->string(etarget, tree->fullpath, 0);
+ else
+ emit->string(etarget, tree->name, 0);
+ }
emit->align(etarget, sizeof(cell_t));
for_each_property(tree, prop) {
@@ -500,6 +524,22 @@ static void flatten_imports(struct symbol *importsymlist, struct emitter *emit,
}
}
+static void flatten_orphans(struct node *orphanlist, struct emitter *emit,
+ void *etarget, struct data *strbuf,
+ struct version_info *vi, uint32_t dt_flags)
+{
+ struct node *orphan;
+
+ if (!(vi->flags & FTF_REF_XXX))
+ return;
+
+ if (!(dt_flags & FDT_FLAG_ADDON) && orphanlist)
+ die("Only addons can have orphan nodes\n");
+
+ for_each_orphan(orphanlist, orphan)
+ flatten_tree(orphan, emit, etarget, strbuf, vi);
+}
+
void dt_to_blob(FILE *f, struct dt_info *dti, int version)
{
struct version_info *vi = NULL;
@@ -523,6 +563,9 @@ void dt_to_blob(FILE *f, struct dt_info *dti, int version)
flatten_tree(dti->dt, &bin_emitter, &dtbuf, &strbuf, vi);
flatten_imports(dti->importsymlist, &bin_emitter, &dtbuf, vi, dt_flags);
+ flatten_orphans(dti->orphanlist, &bin_emitter, &dtbuf, &strbuf, vi,
+ dt_flags);
+
bin_emit_cell(&dtbuf, FDT_END);
reservebuf = flatten_reserve_list(dti->reservelist, vi);
@@ -616,6 +659,9 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
if (dti->importsymlist)
die("Import symbols not supported in asm format\n");
+ if (dti->orphanlist)
+ die("Orphan nodes not supported in asm format\n");
+
for (i = 0; i < ARRAY_SIZE(version_table); i++) {
if (version_table[i].version == version)
@@ -912,7 +958,8 @@ static const char *nodename_from_path(const char *ppath, const char *cpath)
static struct node *unflatten_tree(struct inbuf *dtbuf,
struct inbuf *strbuf,
- const char *parent_flatname, int flags)
+ const char *parent_flatname, int flags,
+ bool is_orphan_node)
{
struct node *node;
const char *flatname;
@@ -922,14 +969,18 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
const char *str2;
node = build_node(NULL, NULL, NULL, NULL);
-
- flatname = flat_read_string(dtbuf);
-
- if (flags & FTF_FULLPATH)
- node->name = xstrdup(nodename_from_path(parent_flatname,
- flatname));
- else
- node->name = xstrdup(flatname);
+ if (is_orphan_node) {
+ str = flat_read_string(dtbuf);
+ orphan_node(node, str);
+ flatname = "";
+ } else {
+ flatname = flat_read_string(dtbuf);
+ if (flags & FTF_FULLPATH)
+ node->name = xstrdup(nodename_from_path(parent_flatname,
+ flatname));
+ else
+ node->name = xstrdup(flatname);
+ }
do {
struct symbol *exportsym;
@@ -949,7 +1000,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
break;
case FDT_BEGIN_NODE:
- child = unflatten_tree(dtbuf,strbuf, flatname, flags);
+ child = unflatten_tree(dtbuf, strbuf, flatname, flags, false);
add_child(node, child);
break;
@@ -1012,6 +1063,11 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
add_symbol(&node->exportsymlist, exportsym);
break;
+ case FDT_BEGIN_NODE_REF:
+ /* FDT_BEGIN_NODE_REF can only be at the FDT top level. */
+ die("Unexpected FDT_BEGIN_NODE_REF tag\n");
+ break;
+
default:
die("Invalid opcode word %08x in device tree blob\n",
val);
@@ -1039,6 +1095,8 @@ struct dt_info *dt_from_blob(const char *fname)
struct node *tree;
struct symbol *importsymlist = NULL;
struct symbol *importsym;
+ struct node *orphanlist = NULL;
+ struct node *orphan;
uint32_t val;
int flags = 0;
unsigned int dtsflags = 0;
@@ -1150,7 +1208,7 @@ struct dt_info *dt_from_blob(const char *fname)
if (val != FDT_BEGIN_NODE)
die("Device tree blob doesn't begin with FDT_BEGIN_NODE (begins with 0x%08x)\n", val);
- tree = unflatten_tree(&dtbuf, &strbuf, "", flags);
+ tree = unflatten_tree(&dtbuf, &strbuf, "", flags, false);
val = flat_read_word(&dtbuf);
@@ -1162,6 +1220,15 @@ struct dt_info *dt_from_blob(const char *fname)
val = flat_read_word(&dtbuf);
}
}
+
+ if (flags & FTF_REF_XXX) {
+ while (val == FDT_BEGIN_NODE_REF) {
+ orphan = unflatten_tree(&dtbuf, &strbuf, "", flags,
+ true);
+ addon_add_orphan_node(&orphanlist, orphan);
+ val = flat_read_word(&dtbuf);
+ }
+ }
}
if (val != FDT_END)
@@ -1172,5 +1239,5 @@ struct dt_info *dt_from_blob(const char *fname)
fclose(f);
return build_dt_info(DTSF_V1 | dtsflags, reservelist, tree, boot_cpuid_phys,
- importsymlist, NULL);
+ importsymlist, orphanlist);
}
diff --git a/libfdt/fdt.c b/libfdt/fdt.c
index c169dd9..dc58d2d 100644
--- a/libfdt/fdt.c
+++ b/libfdt/fdt.c
@@ -232,6 +232,15 @@ uint32_t fdt_next_tag_full(const void *fdt, int startoffset, int *nextoffset)
return FDT_END; /* premature end */
break;
+ case FDT_BEGIN_NODE_REF:
+ /* Skip ref */
+ do {
+ p = fdt_offset_ptr(fdt, offset++, 1);
+ } while (p && (*p != '\0'));
+ if (!can_assume(VALID_DTB) && !p)
+ return FDT_END; /* premature end */
+ break;
+
case FDT_EXPORT_SYM:
/* Skip name */
do {
@@ -342,6 +351,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
break;
case FDT_IMPORT_SYM:
+ case FDT_BEGIN_NODE_REF:
/* Those tags are available at the root level, after the
* root node -> Skip everything until FDT_END
*/
diff --git a/libfdt/fdt.h b/libfdt/fdt.h
index b6c23ef..8a39458 100644
--- a/libfdt/fdt.h
+++ b/libfdt/fdt.h
@@ -63,6 +63,8 @@ struct fdt_property {
#define FDT_REF_LOCAL 0x5 /* local phandle reference: offset */
#define FDT_REF_PHANDLE 0x6 /* external phandle reference: offset,
external label */
+#define FDT_BEGIN_NODE_REF 0x7 /* Same as FDT_BEGIN_NODE but with
+ reference instead of name */
#define FDT_END 0x9
#define FDT_EXPORT_SYM 0xa /* export symbol: name, phandle value */
#define FDT_EXPORT_SYM_REF 0xb /* export symbol: name, phandle value (maybe
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 57/77] tests: metadata: Add basic test for addon orphan nodes
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (55 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 56/77] Add support for FDT_BEGIN_NODE_REF_SYM dtb tag Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 58/77] dtc: Add support for missing root node in addon device-tree Herve Codina
` (22 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Add tests related to addon orphan nodes (FDT_BEGIN_NODE_REF dtb tag).
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
tests/metadata_addon_orphan1.dtb.dts.expect | 16 ++++++++++++++++
tests/metadata_addon_orphan1.dtb.expect | 13 +++++++++++++
tests/metadata_addon_orphan1.dts | 19 +++++++++++++++++++
tests/metadata_addon_orphan1.dts.dts.expect | 16 ++++++++++++++++
tests/run_tests.sh | 3 ++-
5 files changed, 66 insertions(+), 1 deletion(-)
create mode 100644 tests/metadata_addon_orphan1.dtb.dts.expect
create mode 100644 tests/metadata_addon_orphan1.dtb.expect
create mode 100644 tests/metadata_addon_orphan1.dts
create mode 100644 tests/metadata_addon_orphan1.dts.dts.expect
diff --git a/tests/metadata_addon_orphan1.dtb.dts.expect b/tests/metadata_addon_orphan1.dtb.dts.expect
new file mode 100644
index 0000000..c24a00f
--- /dev/null
+++ b/tests/metadata_addon_orphan1.dtb.dts.expect
@@ -0,0 +1,16 @@
+/dts-v1/;
+/addon/;
+
+/ {
+
+ node-a {
+ prop = <0x01>;
+ };
+};
+
+&base {
+
+ addon-node {
+ prop = <0x02>;
+ };
+};
diff --git a/tests/metadata_addon_orphan1.dtb.expect b/tests/metadata_addon_orphan1.dtb.expect
new file mode 100644
index 0000000..7058a2e
--- /dev/null
+++ b/tests/metadata_addon_orphan1.dtb.expect
@@ -0,0 +1,13 @@
+/dts-v1/;
+/addon/;
+
+/ {
+ node-a {
+ prop = <0x00000001>;
+ };
+};
+&base {
+ addon-node {
+ prop = <0x00000002>;
+ };
+};
diff --git a/tests/metadata_addon_orphan1.dts b/tests/metadata_addon_orphan1.dts
new file mode 100644
index 0000000..f20d179
--- /dev/null
+++ b/tests/metadata_addon_orphan1.dts
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+/addon/;
+
+/ {
+ node-a {
+ prop = <1>;
+ };
+};
+
+&base {
+ addon-node {
+ prop = <2>;
+ };
+};
diff --git a/tests/metadata_addon_orphan1.dts.dts.expect b/tests/metadata_addon_orphan1.dts.dts.expect
new file mode 100644
index 0000000..c24a00f
--- /dev/null
+++ b/tests/metadata_addon_orphan1.dts.dts.expect
@@ -0,0 +1,16 @@
+/dts-v1/;
+/addon/;
+
+/ {
+
+ node-a {
+ prop = <0x01>;
+ };
+};
+
+&base {
+
+ addon-node {
+ prop = <0x02>;
+ };
+};
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index a5e31df..659b42b 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1127,7 +1127,8 @@ wrap_fdtdump () {
metadata_tests() {
for dt in metadata_reflocal metadata_refphandle \
metadata_addon_base metadata_exportsyms_local \
- metadata_exportsyms_ref metadata_importsyms; do
+ metadata_exportsyms_ref metadata_importsyms \
+ metadata_addon_orphan1; do
run_dtc_test -I dts -O dts -o $dt.dts.dts "$SRCDIR/$dt.dts"
base_run_test check_diff $dt.dts.dts "$SRCDIR/$dt.dts.dts.expect"
run_dtc_test -I dts -O dtb -o $dt.dtb "$SRCDIR/$dt.dts"
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 58/77] dtc: Add support for missing root node in addon device-tree
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (56 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 57/77] tests: metadata: Add basic test for addon orphan nodes Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 59/77] tests: metadata: Add a test for addon without root node Herve Codina
` (21 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Addon can have orphan nodes fully described (dts) and encoded (dtb)
without the need for a root device tree.
Contrary to plugin (overlay), addon doesn't need any specific root tree
structure to described the orphans. Indeed, /fragment@n/__overlay__
doesn't exist for addons. Orphans are encoded in dtb using the
FDT_BEGIN_NODE_REF tag without any impact on the root tree.
The following snippet is fully legit for addon:
--- 8< ---
/addon/;
&foo {
subnode {
prop = <1>;
};
}
--- 8< ---
This snippet doesn't contains a root device tree, and the related dtb
doesn't need any root device tree to encode the snippet.
The root device is no more mandatory for addon.
Add support for addon without a root device-tree.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
checks.c | 28 ++++++++++++++++++++++++++--
dtc-parser.y | 18 ++++++++++++++----
dtc.c | 36 +++++++++++++++++++++++-------------
flattree.c | 42 +++++++++++++++++++++++++++++-------------
livetree.c | 22 +++++++++++++++++-----
treesource.c | 3 ++-
6 files changed, 111 insertions(+), 38 deletions(-)
diff --git a/checks.c b/checks.c
index 83a0f6e..f98f153 100644
--- a/checks.c
+++ b/checks.c
@@ -154,7 +154,6 @@ static bool is_multiple_of(int multiple, int divisor)
static bool run_check(struct check *c, struct dt_info *dti)
{
- struct node *dt = dti->dt;
struct node *orphan;
bool error = false;
int i;
@@ -179,7 +178,8 @@ static bool run_check(struct check *c, struct dt_info *dti)
if (c->status != UNCHECKED)
goto out;
- check_nodes_props(c, dti, dt);
+ if (dti->dt)
+ check_nodes_props(c, dti, dti->dt);
for_each_orphan(dti->orphanlist, orphan)
check_nodes_props(c, dti, orphan);
@@ -2079,6 +2079,30 @@ void process_checks(bool force, struct dt_info *dti)
unsigned int i;
int error = 0;
+ if (!dti->dt) {
+ /* No root node is only allowed for addons */
+ if (dti->dtsflags & DTSF_ADDON) {
+ if (!dti->orphanlist) {
+ /*
+ * but addons without a root node and without
+ * orphan nodes is really incorrect
+ */
+ fprintf(stderr,
+ "ERROR: Input tree has no root or orphan nodes, aborting\n");
+ exit(2);
+ }
+ } else {
+ fprintf(stderr, "ERROR: Input tree has no root node, aborting\n");
+ exit(2);
+ }
+ }
+ if (!(dti->dtsflags & DTSF_ADDON)) {
+ if (dti->orphanlist) {
+ fprintf(stderr, "ERROR: Input tree has orphan nodes, aborting\n");
+ exit(2);
+ }
+ }
+
for (i = 0; i < ARRAY_SIZE(check_table); i++) {
struct check *c = check_table[i];
diff --git a/dtc-parser.y b/dtc-parser.y
index 10ca6d4..cf5447a 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -133,12 +133,18 @@ static struct node *parser_get_node_by_ref(struct node *dt, struct node *orphanl
sourcefile:
headers memreserves devicetree
{
+ if (!($1 & DTSF_ADDON) && !$3)
+ ERROR(&@3, "Only addon support missing root node");
+
parser_output = build_dt_info($1, $2, $3,
- guess_boot_cpuid($3),
+ $3 ? guess_boot_cpuid($3) : 0,
NULL, parser_orphanlist);
}
| headers memreserves importlist devicetree
{
+ if (!($1 & DTSF_ADDON) && !$4)
+ ERROR(&@4, "Only addon support missing root node");
+
/*
* importlist is created with chain_symbol() and so it
* is created in reverse order. Reverse it now to have
@@ -241,7 +247,10 @@ devicetree:
}
| devicetree '/' nodedef
{
- $$ = merge_nodes($1, $3);
+ if ($1)
+ $$ = merge_nodes($1, $3);
+ else
+ $$ = name_node($3, "");
}
| dt_ref nodedef
{
@@ -256,8 +265,9 @@ devicetree:
""),
$2, $1);
} else {
- ERROR(&@2, "Orphan node %s without a root node not yet supported", $1);
- YYERROR;
+ addon_add_orphan_node(&parser_orphanlist,
+ orphan_node($2, $1));
+ $$ = NULL;
}
}
| devicetree DT_LABEL dt_ref nodedef
diff --git a/dtc.c b/dtc.c
index 5cf8f31..63725bf 100644
--- a/dtc.c
+++ b/dtc.c
@@ -351,27 +351,37 @@ int main(int argc, char *argv[])
update_exports_ref(dti);
mark_local_exports(dti);
- /*
- * With FDT_REF_PHANDLE added in dtbs, we need to identified
- * if some unresolved phandle references are allowed in the dtb
- * we have parsed (needed for process_check() to run properly).
- *
- * Identify plugin device-trees (overlays) based on specific node
- * presence.
- */
- if (get_subnode(dti->dt, "__fixups__") ||
- get_subnode(dti->dt, "__local_fixups__"))
- dti->dtsflags |= DTSF_PLUGIN;
+ if (dti->dt) {
+ /*
+ * With FDT_REF_PHANDLE added in dtbs, we need to identified
+ * if some unresolved phandle references are allowed in the dtb
+ * we have parsed (needed for process_check() to run properly).
+ *
+ * Identify plugin device-trees (overlays) based on specific node
+ * presence.
+ */
+ if (get_subnode(dti->dt, "__fixups__") ||
+ get_subnode(dti->dt, "__local_fixups__"))
+ dti->dtsflags |= DTSF_PLUGIN;
+ }
process_checks(force, dti);
- if (auto_label_aliases)
+ if (auto_label_aliases) {
+ if (!dti->dt)
+ die("auto-alias not supported without a root node\n");
generate_label_tree(dti, "aliases", false);
+ }
- if (generate_symbols)
+ if (generate_symbols) {
+ if (!dti->dt)
+ die("generation of symbols not supported without a root node\n");
generate_label_tree(dti, "__symbols__", true);
+ }
if (generate_fixups) {
+ if (!dti->dt)
+ die("generation of fixups not supported without a root node\n");
generate_fixups_tree(dti, "__fixups__");
generate_local_fixups_tree(dti, "__local_fixups__");
}
diff --git a/flattree.c b/flattree.c
index 27f7608..11447b1 100644
--- a/flattree.c
+++ b/flattree.c
@@ -561,7 +561,9 @@ void dt_to_blob(FILE *f, struct dt_info *dti, int version)
dt_flags |= dti->dtsflags & DTSF_ADDON ? FDT_FLAG_ADDON : 0;
- flatten_tree(dti->dt, &bin_emitter, &dtbuf, &strbuf, vi);
+ if (dti->dt)
+ flatten_tree(dti->dt, &bin_emitter, &dtbuf, &strbuf, vi);
+
flatten_imports(dti->importsymlist, &bin_emitter, &dtbuf, vi, dt_flags);
flatten_orphans(dti->orphanlist, &bin_emitter, &dtbuf, &strbuf, vi,
dt_flags);
@@ -752,7 +754,9 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
emit_label(f, symprefix, "struct_start");
- flatten_tree(dti->dt, &asm_emitter, f, &strbuf, vi);
+
+ if (dti->dt)
+ flatten_tree(dti->dt, &asm_emitter, f, &strbuf, vi);
fprintf(f, "\t/* FDT_END */\n");
asm_emit_cell(f, FDT_END);
@@ -1092,7 +1096,7 @@ struct dt_info *dt_from_blob(const char *fname)
struct inbuf memresvbuf;
int sizeleft;
struct reserve_info *reservelist;
- struct node *tree;
+ struct node *tree = NULL;
struct symbol *importsymlist = NULL;
struct symbol *importsym;
struct node *orphanlist = NULL;
@@ -1203,16 +1207,24 @@ struct dt_info *dt_from_blob(const char *fname)
reservelist = flat_read_mem_reserve(&memresvbuf);
- val = flat_read_word(&dtbuf);
-
- if (val != FDT_BEGIN_NODE)
- die("Device tree blob doesn't begin with FDT_BEGIN_NODE (begins with 0x%08x)\n", val);
+ if (!(dtsflags & DTSF_ADDON)) {
+ val = flat_read_word(&dtbuf);
+ if (val != FDT_BEGIN_NODE)
+ die("Device tree blob doesn't begin with FDT_BEGIN_NODE (begins with 0x%08x)\n",
+ val);
- tree = unflatten_tree(&dtbuf, &strbuf, "", flags, false);
+ tree = unflatten_tree(&dtbuf, &strbuf, "", flags, false);
- val = flat_read_word(&dtbuf);
+ val = flat_read_word(&dtbuf);
+ if (val != FDT_END)
+ die("Device tree blob doesn't end with FDT_END\n");
+ } else {
+ val = flat_read_word(&dtbuf);
+ if (val == FDT_BEGIN_NODE) {
+ tree = unflatten_tree(&dtbuf, &strbuf, "", flags, false);
+ val = flat_read_word(&dtbuf);
+ }
- if (dtsflags & DTSF_ADDON) {
if (flags & FTF_EXPORT_IMPORT_SYM) {
while (val == FDT_IMPORT_SYM) {
importsym = flat_read_importsym(&dtbuf);
@@ -1229,10 +1241,14 @@ struct dt_info *dt_from_blob(const char *fname)
val = flat_read_word(&dtbuf);
}
}
- }
- if (val != FDT_END)
- die("Device tree blob doesn't end with FDT_END\n");
+ if (!tree && !orphanlist)
+ die("Device tree blob has 0x%08x tag instead of FDT_BEGIN_NODE or FDT_BEGIN_NODE_REF\n",
+ val);
+
+ if (val != FDT_END)
+ die("Device tree blob doesn't end with FDT_END\n");
+ }
free(blob);
diff --git a/livetree.c b/livetree.c
index eaface5..00274c5 100644
--- a/livetree.c
+++ b/livetree.c
@@ -1203,7 +1203,9 @@ void sort_tree(struct dt_info *dti)
{
sort_reserve_entries(dti);
sort_importsyms(dti);
- sort_node(dti->dt);
+
+ if (dti->dt)
+ sort_node(dti->dt);
}
/* utility helper to avoid code duplication */
@@ -1451,6 +1453,8 @@ static int generate_local_fixups_tree_internal(struct dt_info *dti,
void generate_label_tree(struct dt_info *dti, const char *name, bool allocph)
{
+ assert(dti->dt);
+
if (!any_label_tree(dti, dti->dt))
return;
generate_label_tree_internal(dti, build_root_node(dti->dt, name),
@@ -1459,6 +1463,8 @@ void generate_label_tree(struct dt_info *dti, const char *name, bool allocph)
void generate_fixups_tree(struct dt_info *dti, const char *name)
{
+ assert(dti->dt);
+
if (!any_fixup_tree(dti, dti->dt))
return;
if (generate_fixups_tree_internal(dti, build_root_node(dti->dt, name), dti->dt))
@@ -1469,6 +1475,8 @@ void generate_fixups_tree(struct dt_info *dti, const char *name)
void generate_local_fixups_tree(struct dt_info *dti, const char *name)
{
+ assert(dti->dt);
+
if (!any_local_fixup_tree(dti, dti->dt))
return;
if (generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name), dti->dt))
@@ -1514,7 +1522,8 @@ void update_phandles_ref(struct dt_info *dti)
{
struct node *orphan;
- update_phandles_ref_internal(dti, dti->dt);
+ if (dti->dt)
+ update_phandles_ref_internal(dti, dti->dt);
for_each_orphan(dti->orphanlist, orphan)
update_phandles_ref_internal(dti, orphan);
@@ -1545,7 +1554,8 @@ void mark_local_phandles(struct dt_info *dti)
{
struct node *orphan;
- mark_local_phandles_internal(dti, dti->dt);
+ if (dti->dt)
+ mark_local_phandles_internal(dti, dti->dt);
for_each_orphan(dti->orphanlist, orphan)
mark_local_phandles_internal(dti, orphan);
@@ -1580,7 +1590,8 @@ void update_exports_ref(struct dt_info *dti)
{
struct node *orphan;
- update_exports_ref_internal(dti, dti->dt);
+ if (dti->dt)
+ update_exports_ref_internal(dti, dti->dt);
for_each_orphan(dti->orphanlist, orphan)
update_exports_ref_internal(dti, orphan);
@@ -1607,7 +1618,8 @@ void mark_local_exports(struct dt_info *dti)
{
struct node *orphan;
- mark_local_exports_internal(dti, dti->dt);
+ if (dti->dt)
+ mark_local_exports_internal(dti, dti->dt);
for_each_orphan(dti->orphanlist, orphan)
mark_local_exports_internal(dti, orphan);
diff --git a/treesource.c b/treesource.c
index bc5d847..71dbd5f 100644
--- a/treesource.c
+++ b/treesource.c
@@ -410,7 +410,8 @@ void dt_to_source(FILE *f, struct dt_info *dti)
fprintf(f, "\n");
}
- write_tree_source_node(f, dti->dt, 0);
+ if (dti->dt)
+ write_tree_source_node(f, dti->dt, 0);
for_each_orphan(dti->orphanlist, orphan) {
fprintf(f, "\n");
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 59/77] tests: metadata: Add a test for addon without root node
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (57 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 58/77] dtc: Add support for missing root node in addon device-tree Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 60/77] dtc: Allow parser_get_node_by_ref() to return an orphan node for merging purpose Herve Codina
` (20 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The root device-tree node is no more mandatory for addons.
Indeed, addons can be composed of only orphan nodes without any needs
for the root device-tree node presence.
Add a test related to addon dts and dtb without root node.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
tests/metadata_addon_orphan2.dtb.dts.expect | 10 ++++++++++
tests/metadata_addon_orphan2.dtb.expect | 8 ++++++++
tests/metadata_addon_orphan2.dts | 13 +++++++++++++
tests/metadata_addon_orphan2.dts.dts.expect | 10 ++++++++++
tests/run_tests.sh | 2 +-
5 files changed, 42 insertions(+), 1 deletion(-)
create mode 100644 tests/metadata_addon_orphan2.dtb.dts.expect
create mode 100644 tests/metadata_addon_orphan2.dtb.expect
create mode 100644 tests/metadata_addon_orphan2.dts
create mode 100644 tests/metadata_addon_orphan2.dts.dts.expect
diff --git a/tests/metadata_addon_orphan2.dtb.dts.expect b/tests/metadata_addon_orphan2.dtb.dts.expect
new file mode 100644
index 0000000..32c1b1e
--- /dev/null
+++ b/tests/metadata_addon_orphan2.dtb.dts.expect
@@ -0,0 +1,10 @@
+/dts-v1/;
+/addon/;
+
+
+&base {
+
+ addon-node {
+ prop = <0x02>;
+ };
+};
diff --git a/tests/metadata_addon_orphan2.dtb.expect b/tests/metadata_addon_orphan2.dtb.expect
new file mode 100644
index 0000000..46e67d0
--- /dev/null
+++ b/tests/metadata_addon_orphan2.dtb.expect
@@ -0,0 +1,8 @@
+/dts-v1/;
+/addon/;
+
+&base {
+ addon-node {
+ prop = <0x00000002>;
+ };
+};
diff --git a/tests/metadata_addon_orphan2.dts b/tests/metadata_addon_orphan2.dts
new file mode 100644
index 0000000..d4ff42f
--- /dev/null
+++ b/tests/metadata_addon_orphan2.dts
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+/addon/;
+
+&base {
+ addon-node {
+ prop = <2>;
+ };
+};
diff --git a/tests/metadata_addon_orphan2.dts.dts.expect b/tests/metadata_addon_orphan2.dts.dts.expect
new file mode 100644
index 0000000..32c1b1e
--- /dev/null
+++ b/tests/metadata_addon_orphan2.dts.dts.expect
@@ -0,0 +1,10 @@
+/dts-v1/;
+/addon/;
+
+
+&base {
+
+ addon-node {
+ prop = <0x02>;
+ };
+};
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 659b42b..5edc58b 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1128,7 +1128,7 @@ metadata_tests() {
for dt in metadata_reflocal metadata_refphandle \
metadata_addon_base metadata_exportsyms_local \
metadata_exportsyms_ref metadata_importsyms \
- metadata_addon_orphan1; do
+ metadata_addon_orphan1 metadata_addon_orphan2; do
run_dtc_test -I dts -O dts -o $dt.dts.dts "$SRCDIR/$dt.dts"
base_run_test check_diff $dt.dts.dts "$SRCDIR/$dt.dts.dts.expect"
run_dtc_test -I dts -O dtb -o $dt.dtb "$SRCDIR/$dt.dts"
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 60/77] dtc: Allow parser_get_node_by_ref() to return an orphan node for merging purpose
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (58 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 59/77] tests: metadata: Add a test for addon without root node Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 61/77] tests: metadata: Add a test related to orphan node merging Herve Codina
` (19 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
When the same orphan node is described multiple times in an addon dts,
those multiple descriptions should be merged.
For instance, in the following snippet:
--- 8< ---
/addon/;
&foo {
prop1 = <1>;
};
&foo {
prop2 = <2>;
};
--- 8< ---
The foo orphan node is described twice and should be merged in only one
instance:
--- 8< ---
&foo {
prop1 = <1>;
prop2 = <2>;
};
--- 8< ---
The current mecanisme used to find a node for merging is based on label.
Indeed, without orphan nodes, '&foo' is a reference to a node with the
label 'foo'. This node labeled foo is the node found for merging.
With addons and orphan nodes, '&foo' is not a reference to an existing
node. Indeed, this node is an orphan one because the node referenced by
foo is an external node (i.e. not available in the addon itself).
The label 'foo' doesn't exist. No node in the addon are defined with a
foo label attached.
Take this orphan nodes specificity into account in order to find a
possible orphan node candidate for merging.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
dtc-parser.y | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/dtc-parser.y b/dtc-parser.y
index cf5447a..7f8c294 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -39,11 +39,32 @@ static struct node *parser_get_node_by_ref(struct node *dt, struct node *orphanl
* Use a temporary dt_info in order to use dti_get_node_by_ref()
*/
struct dt_info dti = {};
+ struct node *target;
+ struct node *orphan;
dti.dt = dt;
dti.orphanlist = orphanlist;
- return dti_get_node_by_ref(&dti, ref);
+ target = dti_get_node_by_ref(&dti, ref);
+ if (target)
+ return target;
+
+ /*
+ * No node were found by dti_get_node_by_ref().
+ *
+ * parser_get_node_by_ref() is called by the parser only to get a node
+ * in order to perform a possible merge.
+ *
+ * The referenced used can be a label matching an orphan node. In this
+ * merge context, returning a matching orphan node makes sense even if
+ * no label are defined for the orphan node.
+ */
+ for_each_orphan(orphanlist, orphan) {
+ if (streq(orphan->ref, ref))
+ return orphan;
+ }
+
+ return NULL;
}
%}
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 61/77] tests: metadata: Add a test related to orphan node merging
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (59 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 60/77] dtc: Allow parser_get_node_by_ref() to return an orphan node for merging purpose Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 62/77] dtc: Add support for orphan nodes sorting Herve Codina
` (18 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Merging orphan node is supported.
Add a test for this feature.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
tests/metadata_addon_orphan3.dtb.dts.expect | 22 ++++++++++++++++
tests/metadata_addon_orphan3.dtb.expect | 17 +++++++++++++
tests/metadata_addon_orphan3.dts | 28 +++++++++++++++++++++
tests/metadata_addon_orphan3.dts.dts.expect | 22 ++++++++++++++++
tests/run_tests.sh | 3 ++-
5 files changed, 91 insertions(+), 1 deletion(-)
create mode 100644 tests/metadata_addon_orphan3.dtb.dts.expect
create mode 100644 tests/metadata_addon_orphan3.dtb.expect
create mode 100644 tests/metadata_addon_orphan3.dts
create mode 100644 tests/metadata_addon_orphan3.dts.dts.expect
diff --git a/tests/metadata_addon_orphan3.dtb.dts.expect b/tests/metadata_addon_orphan3.dtb.dts.expect
new file mode 100644
index 0000000..2605e1b
--- /dev/null
+++ b/tests/metadata_addon_orphan3.dtb.dts.expect
@@ -0,0 +1,22 @@
+/dts-v1/;
+/addon/;
+
+
+&base1 {
+
+ addon-node1 {
+ prop1 = <0x01>;
+ prop2 = <0x02>;
+ };
+
+ addon-node2 {
+ prop3 = <0x03>;
+ };
+};
+
+&base2 {
+
+ addon-node {
+ prop = <0x00>;
+ };
+};
diff --git a/tests/metadata_addon_orphan3.dtb.expect b/tests/metadata_addon_orphan3.dtb.expect
new file mode 100644
index 0000000..5a65483
--- /dev/null
+++ b/tests/metadata_addon_orphan3.dtb.expect
@@ -0,0 +1,17 @@
+/dts-v1/;
+/addon/;
+
+&base1 {
+ addon-node1 {
+ prop1 = <0x00000001>;
+ prop2 = <0x00000002>;
+ };
+ addon-node2 {
+ prop3 = <0x00000003>;
+ };
+};
+&base2 {
+ addon-node {
+ prop = <0x00000000>;
+ };
+};
diff --git a/tests/metadata_addon_orphan3.dts b/tests/metadata_addon_orphan3.dts
new file mode 100644
index 0000000..0fe52ec
--- /dev/null
+++ b/tests/metadata_addon_orphan3.dts
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+/addon/;
+
+&base1 {
+ addon-node1 {
+ prop1 = <1>;
+ };
+};
+
+&base2 {
+ addon-node {
+ prop = <0>;
+ };
+};
+
+&base1 {
+ addon-node1 {
+ prop2 = <2>;
+ };
+ addon-node2 {
+ prop3 = <3>;
+ };
+};
diff --git a/tests/metadata_addon_orphan3.dts.dts.expect b/tests/metadata_addon_orphan3.dts.dts.expect
new file mode 100644
index 0000000..2605e1b
--- /dev/null
+++ b/tests/metadata_addon_orphan3.dts.dts.expect
@@ -0,0 +1,22 @@
+/dts-v1/;
+/addon/;
+
+
+&base1 {
+
+ addon-node1 {
+ prop1 = <0x01>;
+ prop2 = <0x02>;
+ };
+
+ addon-node2 {
+ prop3 = <0x03>;
+ };
+};
+
+&base2 {
+
+ addon-node {
+ prop = <0x00>;
+ };
+};
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 5edc58b..12418bf 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1128,7 +1128,8 @@ metadata_tests() {
for dt in metadata_reflocal metadata_refphandle \
metadata_addon_base metadata_exportsyms_local \
metadata_exportsyms_ref metadata_importsyms \
- metadata_addon_orphan1 metadata_addon_orphan2; do
+ metadata_addon_orphan1 metadata_addon_orphan2 \
+ metadata_addon_orphan3; do
run_dtc_test -I dts -O dts -o $dt.dts.dts "$SRCDIR/$dt.dts"
base_run_test check_diff $dt.dts.dts "$SRCDIR/$dt.dts.dts.expect"
run_dtc_test -I dts -O dtb -o $dt.dtb "$SRCDIR/$dt.dts"
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 62/77] dtc: Add support for orphan nodes sorting
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (60 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 61/77] tests: metadata: Add a test related to orphan node merging Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 63/77] tests: metadata: Improve sort test to check " Herve Codina
` (17 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
dtc can sort items when the command line --sort option is set.
Add support for orphan nodes sorting when this option is used.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
livetree.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/livetree.c b/livetree.c
index 00274c5..59b912d 100644
--- a/livetree.c
+++ b/livetree.c
@@ -1199,6 +1199,34 @@ static void sort_importsyms(struct dt_info *dti)
free(tbl);
}
+static void sort_orphans(struct dt_info *dti)
+{
+ int n = 0, i = 0;
+ struct node *orphan, **tbl;
+
+ for_each_orphan(dti->orphanlist, orphan) {
+ sort_node(orphan);
+ n++;
+ }
+
+ if (n == 0)
+ return;
+
+ tbl = xmalloc(n * sizeof(*tbl));
+
+ for_each_orphan(dti->orphanlist, orphan)
+ tbl[i++] = orphan;
+
+ qsort(tbl, n, sizeof(*tbl), cmp_subnode);
+
+ dti->orphanlist = tbl[0];
+ for (i = 0; i < (n-1); i++)
+ tbl[i]->next_sibling = tbl[i+1];
+ tbl[n-1]->next_sibling = NULL;
+
+ free(tbl);
+}
+
void sort_tree(struct dt_info *dti)
{
sort_reserve_entries(dti);
@@ -1206,6 +1234,8 @@ void sort_tree(struct dt_info *dti)
if (dti->dt)
sort_node(dti->dt);
+
+ sort_orphans(dti);
}
/* utility helper to avoid code duplication */
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 63/77] tests: metadata: Improve sort test to check for orphan nodes sorting
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (61 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 62/77] dtc: Add support for orphan nodes sorting Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 64/77] dtc: Add support for references by path involving orphan nodes Herve Codina
` (16 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
dtc is able to sort orphan nodes when the --sort option is used.
Improve the metadata sort test to perform a check for this feature.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
tests/metadata_sort.dtb.dts.expect | 39 ++++++++++++++++++++++++++++++
tests/metadata_sort.dtb.expect | 30 +++++++++++++++++++++++
tests/metadata_sort.dts | 33 +++++++++++++++++++++++++
3 files changed, 102 insertions(+)
diff --git a/tests/metadata_sort.dtb.dts.expect b/tests/metadata_sort.dtb.dts.expect
index 270c06d..df3c02b 100644
--- a/tests/metadata_sort.dtb.dts.expect
+++ b/tests/metadata_sort.dtb.dts.expect
@@ -20,3 +20,42 @@
phandle = <0x01>;
};
};
+
+&abc {
+ prop-a = "a";
+ prop-b = "b";
+
+ node-a {
+ prop = <0x01>;
+ };
+
+ node-b {
+ prop = <0x02>;
+ };
+
+ node-c {
+ prop = <0x03>;
+ };
+};
+
+&de1 {
+ prop-a = "a";
+ prop-b = "b";
+
+ node-a {
+ prop = <0x01>;
+ };
+
+ node-b {
+ prop = <0x02>;
+ };
+
+ node-c {
+ prop = <0x03>;
+ };
+};
+
+&de2 {
+ prop-a = "a";
+ prop-b = "b";
+};
diff --git a/tests/metadata_sort.dtb.expect b/tests/metadata_sort.dtb.expect
index 0dacab7..47002fe 100644
--- a/tests/metadata_sort.dtb.expect
+++ b/tests/metadata_sort.dtb.expect
@@ -16,3 +16,33 @@
// [FDT_IMPORT_SYM] 'abc' (foo,bar)
// [FDT_IMPORT_SYM] 'de1' (foo,bar)
// [FDT_IMPORT_SYM] 'de2' (foo,bar)
+&abc {
+ prop-a = "a";
+ prop-b = "b";
+ node-a {
+ prop = <0x00000001>;
+ };
+ node-b {
+ prop = <0x00000002>;
+ };
+ node-c {
+ prop = <0x00000003>;
+ };
+};
+&de1 {
+ prop-a = "a";
+ prop-b = "b";
+ node-a {
+ prop = <0x00000001>;
+ };
+ node-b {
+ prop = <0x00000002>;
+ };
+ node-c {
+ prop = <0x00000003>;
+ };
+};
+&de2 {
+ prop-a = "a";
+ prop-b = "b";
+};
diff --git a/tests/metadata_sort.dts b/tests/metadata_sort.dts
index e523e20..3b690a5 100644
--- a/tests/metadata_sort.dts
+++ b/tests/metadata_sort.dts
@@ -23,3 +23,36 @@
/export/ a: &node_b;
};
};
+
+&de2 {
+ prop-b = "b";
+ prop-a = "a";
+};
+
+&abc {
+ prop-b = "b";
+ prop-a = "a";
+ node-b {
+ prop = <2>;
+ };
+ node-a {
+ prop = <1>;
+ };
+ node-c {
+ prop = <3>;
+ };
+};
+
+&de1 {
+ prop-b = "b";
+ prop-a = "a";
+ node-b {
+ prop = <2>;
+ };
+ node-a {
+ prop = <1>;
+ };
+ node-c {
+ prop = <3>;
+ };
+};
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 64/77] dtc: Add support for references by path involving orphan nodes
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (62 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 63/77] tests: metadata: Improve sort test to check " Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-15 7:01 ` David Gibson
2026-01-12 14:19 ` [RFC PATCH 65/77] tests: metadata: Add a test " Herve Codina
` (15 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Referencing a sub-node from an orphan node using a path is needed.
Indeed, using the following snippet:
--- 8< ---
/addon/;
&node1 {
subnode {
foo-phandle = <&foo_label>;
};
};
&node2 {
foo_label: foo {
prop = <1>;
};
};
--- 8< ---
Even if node2 is an orphan node, foo is a local node. foo-phandle
references the foo node using a label.
Once converted to a dtb, the label is lost. Only the phandle of the foo
node is used in the foo-phandle property and this property is marked
FDT_REF_LOCAL.
Converting back this dtb to a dts, the marked local phandle should be
translated to a path to the related local node.
The issue is that this local node is not in a root device tree. We need
to identify the orphan node the foo node belongs to.
We cannot use a path starting by '/'. This kind of path identify node in
the root tree.
This new syntax allows to identify the orphan node in a path:
$<orphan_name>/<path>
This leads to a reference by path in the form &{$<orphan_name>/<path>}.
Using the previous example, those both phandles points to the same node:
foo-phandle1 = <&foo_label>; /* Reference by label */
foo-phandle2 = <&{$node2/foo}>; /* Reference by path */
When the dtb is converted back to a dts, the marked local phandle
involving subnode available from orphan nodes can be translated to a
reference by path thanks to the new syntax.
Add support for this &{$<orphan_name>/<path>} syntax to reference by
path a local node from an orphan node.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
dtc-lexer.l | 7 +++++++
dtc-parser.y | 19 +++++++++++++++++++
dtc.c | 22 ++++++++++++++++++++--
livetree.c | 14 +++++++++++++-
treesource.c | 3 ++-
5 files changed, 61 insertions(+), 4 deletions(-)
diff --git a/dtc-lexer.l b/dtc-lexer.l
index cb616f9..540bfdf 100644
--- a/dtc-lexer.l
+++ b/dtc-lexer.l
@@ -239,6 +239,13 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
return DT_PATH_REF;
}
+<*>"&{\$"{LABEL}([/]{PATHCHAR}*)?\} { /* orphan path reference */
+ yytext[yyleng-1] = '\0';
+ DPRINT("Ref orphan path: %s\n", yytext+1);
+ yylval.labelref = xstrdup(yytext+2);
+ return DT_ORPHAN_PATH_REF;
+ }
+
<BYTESTRING>[0-9a-fA-F]{2} {
yylval.byte = strtol(yytext, NULL, 16);
DPRINT("Byte: %02x\n", (int)yylval.byte);
diff --git a/dtc-parser.y b/dtc-parser.y
index 7f8c294..9d619cd 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -111,6 +111,7 @@ static struct node *parser_get_node_by_ref(struct node *dt, struct node *orphanl
%token <labelref> DT_LABEL
%token <labelref> DT_LABEL_REF
%token <labelref> DT_PATH_REF
+%token <labelref> DT_ORPHAN_PATH_REF
%token DT_INCBIN
%type <data> propdata
@@ -589,6 +590,24 @@ arrayprefix:
ERROR(&@2, "References are only allowed in "
"arrays with 32-bit elements.");
+ $$.data = data_append_integer($1.data, val, $1.bits);
+ }
+ | arrayprefix DT_ORPHAN_PATH_REF
+ {
+ uint64_t val = ~0ULL >> (64 - $1.bits);
+
+ if ($1.bits == 32) {
+ if (!(last_header_flags & DTSF_ADDON))
+ ERROR(&@2, "Orphan path reference %s supported only in addon", $2);
+
+ $1.data = data_add_marker($1.data,
+ REF_PHANDLE,
+ $2);
+ } else {
+ ERROR(&@2, "References are only allowed in "
+ "arrays with 32-bit elements.");
+ }
+
$$.data = data_append_integer($1.data, val, $1.bits);
}
| arrayprefix DT_LABEL
diff --git a/dtc.c b/dtc.c
index 63725bf..72d85e4 100644
--- a/dtc.c
+++ b/dtc.c
@@ -48,13 +48,31 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
static void dti_fill_fullpaths(struct dt_info *dti)
{
struct node *orphan;
+ struct node *child;
/* Fill fullpaths for the root node */
if (dti->dt)
fill_fullpaths(dti->dt, "");
- for_each_orphan(dti->orphanlist, orphan)
- fill_fullpaths(orphan, "__orphan__/");
+ /* Fill fullpaths for orphan nodes */
+ for_each_orphan(dti->orphanlist, orphan) {
+ if (orphan->name[0] == '\0')
+ die("orphan node has an empty name\n");
+
+ /*
+ * An orphan node name is set with its reference.
+ * Its name is in the form "&xxxxxx".
+ * For its full path, we use "$xxxxx" to make a clear
+ * distinction between a reference (&xxxx) where a resolution
+ * could be involved vs a "simple" path where we just need to
+ * identified the orphan ($xxxx).
+ */
+ xasprintf(&orphan->fullpath, "$%s", orphan->name + 1);
+ orphan->basenamelen = strlen(orphan->name);
+
+ for_each_child(orphan, child)
+ fill_fullpaths(child, orphan->fullpath);
+ }
}
/* Usage related data. */
diff --git a/livetree.c b/livetree.c
index 59b912d..263da1f 100644
--- a/livetree.c
+++ b/livetree.c
@@ -804,7 +804,19 @@ static struct node *get_node_by_ref(struct node *tree, const char *ref)
path = slash + 1;
}
- target = get_node_by_label(tree, label);
+ if (label[0] == '$' && tree->name[0] == '&') {
+ /*
+ * We search for an orphan and the given tree is an
+ * orphan. Use the given tree only if it matches the
+ * expected orphan.
+ */
+ if (streq(label + 1, tree->name + 1))
+ target = tree;
+ else
+ target = NULL;
+ } else {
+ target = get_node_by_label(tree, label);
+ }
free(buf);
diff --git a/treesource.c b/treesource.c
index 71dbd5f..44de0db 100644
--- a/treesource.c
+++ b/treesource.c
@@ -278,7 +278,8 @@ static void write_propval(FILE *f, struct property *prop)
break;
if (m_phandle) {
- if (m_phandle->ref[0] == '/')
+ if (m_phandle->ref[0] == '/' /* Root node */ ||
+ m_phandle->ref[0] == '$' /* Orphan node */)
fprintf(f, "&{%s}", m_phandle->ref);
else
fprintf(f, "&%s", m_phandle->ref);
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 64/77] dtc: Add support for references by path involving orphan nodes
2026-01-12 14:19 ` [RFC PATCH 64/77] dtc: Add support for references by path involving orphan nodes Herve Codina
@ 2026-01-15 7:01 ` David Gibson
2026-01-19 16:38 ` Herve Codina
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-15 7:01 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 6680 bytes --]
On Mon, Jan 12, 2026 at 03:19:54PM +0100, Herve Codina wrote:
> Referencing a sub-node from an orphan node using a path is needed.
>
> Indeed, using the following snippet:
> --- 8< ---
> /addon/;
>
> &node1 {
> subnode {
> foo-phandle = <&foo_label>;
> };
> };
>
> &node2 {
> foo_label: foo {
> prop = <1>;
> };
> };
> --- 8< ---
>
> Even if node2 is an orphan node, foo is a local node. foo-phandle
> references the foo node using a label.
Another option would be to eliminate the idea of local references, and
require a symbol be attached to things that you want to reference by
label.
>
> Once converted to a dtb, the label is lost. Only the phandle of the foo
> node is used in the foo-phandle property and this property is marked
> FDT_REF_LOCAL.
>
> Converting back this dtb to a dts, the marked local phandle should be
> translated to a path to the related local node.
>
> The issue is that this local node is not in a root device tree. We need
> to identify the orphan node the foo node belongs to.
>
> We cannot use a path starting by '/'. This kind of path identify node in
> the root tree.
>
> This new syntax allows to identify the orphan node in a path:
> $<orphan_name>/<path>
>
> This leads to a reference by path in the form &{$<orphan_name>/<path>}.
>
> Using the previous example, those both phandles points to the same node:
> foo-phandle1 = <&foo_label>; /* Reference by label */
> foo-phandle2 = <&{$node2/foo}>; /* Reference by path */
>
> When the dtb is converted back to a dts, the marked local phandle
> involving subnode available from orphan nodes can be translated to a
> reference by path thanks to the new syntax.
>
> Add support for this &{$<orphan_name>/<path>} syntax to reference by
> path a local node from an orphan node.
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> dtc-lexer.l | 7 +++++++
> dtc-parser.y | 19 +++++++++++++++++++
> dtc.c | 22 ++++++++++++++++++++--
> livetree.c | 14 +++++++++++++-
> treesource.c | 3 ++-
> 5 files changed, 61 insertions(+), 4 deletions(-)
>
> diff --git a/dtc-lexer.l b/dtc-lexer.l
> index cb616f9..540bfdf 100644
> --- a/dtc-lexer.l
> +++ b/dtc-lexer.l
> @@ -239,6 +239,13 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
> return DT_PATH_REF;
> }
>
> +<*>"&{\$"{LABEL}([/]{PATHCHAR}*)?\} { /* orphan path reference */
> + yytext[yyleng-1] = '\0';
> + DPRINT("Ref orphan path: %s\n", yytext+1);
> + yylval.labelref = xstrdup(yytext+2);
> + return DT_ORPHAN_PATH_REF;
> + }
> +
> <BYTESTRING>[0-9a-fA-F]{2} {
> yylval.byte = strtol(yytext, NULL, 16);
> DPRINT("Byte: %02x\n", (int)yylval.byte);
> diff --git a/dtc-parser.y b/dtc-parser.y
> index 7f8c294..9d619cd 100644
> --- a/dtc-parser.y
> +++ b/dtc-parser.y
> @@ -111,6 +111,7 @@ static struct node *parser_get_node_by_ref(struct node *dt, struct node *orphanl
> %token <labelref> DT_LABEL
> %token <labelref> DT_LABEL_REF
> %token <labelref> DT_PATH_REF
> +%token <labelref> DT_ORPHAN_PATH_REF
> %token DT_INCBIN
>
> %type <data> propdata
> @@ -589,6 +590,24 @@ arrayprefix:
> ERROR(&@2, "References are only allowed in "
> "arrays with 32-bit elements.");
>
> + $$.data = data_append_integer($1.data, val, $1.bits);
> + }
> + | arrayprefix DT_ORPHAN_PATH_REF
> + {
> + uint64_t val = ~0ULL >> (64 - $1.bits);
> +
> + if ($1.bits == 32) {
> + if (!(last_header_flags & DTSF_ADDON))
> + ERROR(&@2, "Orphan path reference %s supported only in addon", $2);
> +
> + $1.data = data_add_marker($1.data,
> + REF_PHANDLE,
> + $2);
> + } else {
> + ERROR(&@2, "References are only allowed in "
> + "arrays with 32-bit elements.");
> + }
> +
> $$.data = data_append_integer($1.data, val, $1.bits);
> }
> | arrayprefix DT_LABEL
> diff --git a/dtc.c b/dtc.c
> index 63725bf..72d85e4 100644
> --- a/dtc.c
> +++ b/dtc.c
> @@ -48,13 +48,31 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
> static void dti_fill_fullpaths(struct dt_info *dti)
> {
> struct node *orphan;
> + struct node *child;
>
> /* Fill fullpaths for the root node */
> if (dti->dt)
> fill_fullpaths(dti->dt, "");
>
> - for_each_orphan(dti->orphanlist, orphan)
> - fill_fullpaths(orphan, "__orphan__/");
> + /* Fill fullpaths for orphan nodes */
> + for_each_orphan(dti->orphanlist, orphan) {
> + if (orphan->name[0] == '\0')
> + die("orphan node has an empty name\n");
> +
> + /*
> + * An orphan node name is set with its reference.
> + * Its name is in the form "&xxxxxx".
> + * For its full path, we use "$xxxxx" to make a clear
> + * distinction between a reference (&xxxx) where a resolution
> + * could be involved vs a "simple" path where we just need to
> + * identified the orphan ($xxxx).
> + */
> + xasprintf(&orphan->fullpath, "$%s", orphan->name + 1);
> + orphan->basenamelen = strlen(orphan->name);
> +
> + for_each_child(orphan, child)
> + fill_fullpaths(child, orphan->fullpath);
> + }
> }
>
> /* Usage related data. */
> diff --git a/livetree.c b/livetree.c
> index 59b912d..263da1f 100644
> --- a/livetree.c
> +++ b/livetree.c
> @@ -804,7 +804,19 @@ static struct node *get_node_by_ref(struct node *tree, const char *ref)
> path = slash + 1;
> }
>
> - target = get_node_by_label(tree, label);
> + if (label[0] == '$' && tree->name[0] == '&') {
> + /*
> + * We search for an orphan and the given tree is an
> + * orphan. Use the given tree only if it matches the
> + * expected orphan.
> + */
> + if (streq(label + 1, tree->name + 1))
> + target = tree;
> + else
> + target = NULL;
> + } else {
> + target = get_node_by_label(tree, label);
> + }
>
> free(buf);
>
> diff --git a/treesource.c b/treesource.c
> index 71dbd5f..44de0db 100644
> --- a/treesource.c
> +++ b/treesource.c
> @@ -278,7 +278,8 @@ static void write_propval(FILE *f, struct property *prop)
> break;
>
> if (m_phandle) {
> - if (m_phandle->ref[0] == '/')
> + if (m_phandle->ref[0] == '/' /* Root node */ ||
> + m_phandle->ref[0] == '$' /* Orphan node */)
> fprintf(f, "&{%s}", m_phandle->ref);
> else
> fprintf(f, "&%s", m_phandle->ref);
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 64/77] dtc: Add support for references by path involving orphan nodes
2026-01-15 7:01 ` David Gibson
@ 2026-01-19 16:38 ` Herve Codina
2026-01-21 9:06 ` David Gibson
0 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-19 16:38 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
On Thu, 15 Jan 2026 18:01:39 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Mon, Jan 12, 2026 at 03:19:54PM +0100, Herve Codina wrote:
> > Referencing a sub-node from an orphan node using a path is needed.
> >
> > Indeed, using the following snippet:
> > --- 8< ---
> > /addon/;
> >
> > &node1 {
> > subnode {
> > foo-phandle = <&foo_label>;
> > };
> > };
> >
> > &node2 {
> > foo_label: foo {
> > prop = <1>;
> > };
> > };
> > --- 8< ---
> >
> > Even if node2 is an orphan node, foo is a local node. foo-phandle
> > references the foo node using a label.
>
> Another option would be to eliminate the idea of local references, and
> require a symbol be attached to things that you want to reference by
> label.
Hum, new kind of references.
We have reference by phandle to local nodes. Reference by symbol for
external nodes (i.e. nodes not present in current dtb).
Now new kind of reference for node available in the current dtb but
in a different tree (orphan tree).
For that we need to:
- Mark the phandle value in the property as a cross-tree phandle
reference
- Add the symbol label in the referenced node.
When the addon is applied, this new kind of reference need to be taken
into account in a new way:
- The phandle value in the referenced node need to be updated in the
same way as all other phandle value in nodes to avoid collisions.
- The cross-tree reference needs to be resolved.
This adds an unneeded complexity.
IMHO, we shouldn't eliminate local references.
We need to reference all possible local nodes by path even if cross-tree
due to orphan tree is involved.
Best regards,
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 64/77] dtc: Add support for references by path involving orphan nodes
2026-01-19 16:38 ` Herve Codina
@ 2026-01-21 9:06 ` David Gibson
2026-01-21 16:30 ` Herve Codina
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-21 9:06 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 2391 bytes --]
On Mon, Jan 19, 2026 at 05:38:31PM +0100, Herve Codina wrote:
> On Thu, 15 Jan 2026 18:01:39 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > On Mon, Jan 12, 2026 at 03:19:54PM +0100, Herve Codina wrote:
> > > Referencing a sub-node from an orphan node using a path is needed.
> > >
> > > Indeed, using the following snippet:
> > > --- 8< ---
> > > /addon/;
> > >
> > > &node1 {
> > > subnode {
> > > foo-phandle = <&foo_label>;
> > > };
> > > };
> > >
> > > &node2 {
> > > foo_label: foo {
> > > prop = <1>;
> > > };
> > > };
> > > --- 8< ---
> > >
> > > Even if node2 is an orphan node, foo is a local node. foo-phandle
> > > references the foo node using a label.
> >
> > Another option would be to eliminate the idea of local references, and
> > require a symbol be attached to things that you want to reference by
> > label.
>
> Hum, new kind of references.
No, I'm trying to remove a type of reference: I'm suggesting using the
same format as for external references on local references as well.
That might mean things referenced need to be both exported and
imported by the tree creating them. That might be worth it to reduce
the number of cases.
> We have reference by phandle to local nodes. Reference by symbol for
> external nodes (i.e. nodes not present in current dtb).
>
> Now new kind of reference for node available in the current dtb but
> in a different tree (orphan tree).
>
> For that we need to:
> - Mark the phandle value in the property as a cross-tree phandle
> reference
> - Add the symbol label in the referenced node.
>
> When the addon is applied, this new kind of reference need to be taken
> into account in a new way:
> - The phandle value in the referenced node need to be updated in the
> same way as all other phandle value in nodes to avoid collisions.
> - The cross-tree reference needs to be resolved.
>
> This adds an unneeded complexity.
>
> IMHO, we shouldn't eliminate local references.
>
> We need to reference all possible local nodes by path even if cross-tree
> due to orphan tree is involved.
>
> Best regards,
> Hervé
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 64/77] dtc: Add support for references by path involving orphan nodes
2026-01-21 9:06 ` David Gibson
@ 2026-01-21 16:30 ` Herve Codina
2026-01-29 2:00 ` David Gibson
0 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-21 16:30 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
Hi David,
On Wed, 21 Jan 2026 20:06:11 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Mon, Jan 19, 2026 at 05:38:31PM +0100, Herve Codina wrote:
> > On Thu, 15 Jan 2026 18:01:39 +1100
> > David Gibson <david@gibson.dropbear.id.au> wrote:
> >
> > > On Mon, Jan 12, 2026 at 03:19:54PM +0100, Herve Codina wrote:
> > > > Referencing a sub-node from an orphan node using a path is needed.
> > > >
> > > > Indeed, using the following snippet:
> > > > --- 8< ---
> > > > /addon/;
> > > >
> > > > &node1 {
> > > > subnode {
> > > > foo-phandle = <&foo_label>;
> > > > };
> > > > };
> > > >
> > > > &node2 {
> > > > foo_label: foo {
> > > > prop = <1>;
> > > > };
> > > > };
> > > > --- 8< ---
> > > >
> > > > Even if node2 is an orphan node, foo is a local node. foo-phandle
> > > > references the foo node using a label.
> > >
> > > Another option would be to eliminate the idea of local references, and
> > > require a symbol be attached to things that you want to reference by
> > > label.
> >
> > Hum, new kind of references.
>
> No, I'm trying to remove a type of reference: I'm suggesting using the
> same format as for external references on local references as well.
> That might mean things referenced need to be both exported and
> imported by the tree creating them. That might be worth it to reduce
> the number of cases.
Hum, this means a new tags.
local references: ok, phandle to to local node.
external references: phandle to external node.
This has to be resolved based on exports available in the device-tree the
addon is applied to.
Here, the node is not external. It is available in the addon and so it is
a local node.
No import/export mechanism is needed to resolve the phandle. Indeed, this
phandle is already well defined (resolved) in the addon blob.
Having a kind of 'local' import/export to allow local cross-tree references
is going to add an extra complexity where it is not needed.
Look at the related test (patch 65).
In the tests/metadata_addon_references.dts, you can find:
--- 8< ---
&base1 {
b1_addon: addon-node {
prop = <2>;
};
};
&base2 {
addon-node1 {
ref-base1-addon-node = <&b1_addon>;
};
...
};
--- 8< ---
Converted to dtb and analyzed by fdtdump, this leads to
(tests/metadata_addon_references.dtb.expect):
--- 8< ---
&base1 {
addon-node {
prop = <0x00000002>;
phandle = <0x00000001>;
};
};
&base2 {
addon-node1 {
ref-base1-addon-node = <0x00000001>;
// [FDT_REF_LOCAL] ref-base1-addon-node[0]
};
...
};
--- 8< ---
This dtb, as all dtbs, can be converted back to a dts.
Having a syntax to reference orphan node by path allows to use this
syntax in the 'ref-base1-addon-node' property. You can find it in
tests/metadata_addon_references.dtb.dts.expect
--- 8< ---
&base1 {
addon-node {
prop = <0x02>;
phandle = <0x01>;
};
};
&base2 {
addon-node1 {
ref-base1-addon-node = <&{$base1/addon-node}>;
};
...
};
--- 8< ---
We could only use the phandle value:
ref-base1-addon-node = <0x01>;
Which is perfectly legit and fully matches what is encoded in the dtb.
But I think it was very interesting, thanks to meta-data, to identify that
this is a phandle and so use a reference instead of a integer (phandle).
No label are stored in the dtb and there is no need to store them. Further
more, a node, in a dts can have several label. Which one to store? The
first one, all, ...
Using export, lead to the node visible to any addon applied. That's not the
expectation.
Using import, means the symbol is external. That's not the case.
A local node exists in the dtb. We should be able to reference it by path.
/ {
foo {
bar {
...
};
}
};
With the root tree, the 'bar' node, can be referenced by /foo/bar.
Now, with orphan:
&orphan {
foo {
bar {
....
};
};
};
How to reference 'bar' by path?
We need to identify 'orphan' instead of root ('/') $orphan/foo/bar is the
syntax I propose to do that. Of course, this syntax can be discussed.
IMHO, I thing the feature consisting in referencing by path a node in an
orphan tree is needed and avoid extra complexity.
Best regards,
Hervé
>
> > We have reference by phandle to local nodes. Reference by symbol for
> > external nodes (i.e. nodes not present in current dtb).
> >
> > Now new kind of reference for node available in the current dtb but
> > in a different tree (orphan tree).
> >
> > For that we need to:
> > - Mark the phandle value in the property as a cross-tree phandle
> > reference
> > - Add the symbol label in the referenced node.
> >
> > When the addon is applied, this new kind of reference need to be taken
> > into account in a new way:
> > - The phandle value in the referenced node need to be updated in the
> > same way as all other phandle value in nodes to avoid collisions.
> > - The cross-tree reference needs to be resolved.
> >
> > This adds an unneeded complexity.
> >
> > IMHO, we shouldn't eliminate local references.
> >
> > We need to reference all possible local nodes by path even if cross-tree
> > due to orphan tree is involved.
> >
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 64/77] dtc: Add support for references by path involving orphan nodes
2026-01-21 16:30 ` Herve Codina
@ 2026-01-29 2:00 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-29 2:00 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 4602 bytes --]
On Wed, Jan 21, 2026 at 05:30:12PM +0100, Herve Codina wrote:
> Hi David,
>
> On Wed, 21 Jan 2026 20:06:11 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > On Mon, Jan 19, 2026 at 05:38:31PM +0100, Herve Codina wrote:
> > > On Thu, 15 Jan 2026 18:01:39 +1100
> > > David Gibson <david@gibson.dropbear.id.au> wrote:
> > >
> > > > On Mon, Jan 12, 2026 at 03:19:54PM +0100, Herve Codina wrote:
> > > > > Referencing a sub-node from an orphan node using a path is needed.
> > > > >
> > > > > Indeed, using the following snippet:
> > > > > --- 8< ---
> > > > > /addon/;
> > > > >
> > > > > &node1 {
> > > > > subnode {
> > > > > foo-phandle = <&foo_label>;
> > > > > };
> > > > > };
> > > > >
> > > > > &node2 {
> > > > > foo_label: foo {
> > > > > prop = <1>;
> > > > > };
> > > > > };
> > > > > --- 8< ---
> > > > >
> > > > > Even if node2 is an orphan node, foo is a local node. foo-phandle
> > > > > references the foo node using a label.
> > > >
> > > > Another option would be to eliminate the idea of local references, and
> > > > require a symbol be attached to things that you want to reference by
> > > > label.
> > >
> > > Hum, new kind of references.
> >
> > No, I'm trying to remove a type of reference: I'm suggesting using the
> > same format as for external references on local references as well.
> > That might mean things referenced need to be both exported and
> > imported by the tree creating them. That might be worth it to reduce
> > the number of cases.
>
> Hum, this means a new tags.
Either I'm missing something, or I'm not explaining what I have in
mind well. My itention here is to *reduce* the number of tags.
The proposal has two ways of adjusting a property referring to a
phandle: a) if the referenced node is within this tree fragment
(local), b) if the referenced node is external.
Clearly we need (b), but I'm wondering if there's any way we can
remove (a), using the method for (b) instead. i.e. do local
references via label, just like external references.
Here's one possible idea: I've said elsewhere that I'm not convinced
the current proposal adequately handles the case of an addon that
requires several upstream connectors. The obvious way of addressing
that would mean that imported / referenced symbols aren't global to
the whole addon, but instead are specific to a specified upstream
connector. So, say each phandle fixup tag contained both a namespace
and a label. The namespace selects which upstream connector we're
referrring to, the label says what symbol within that connector we're
referring to.
If we went with a scheme like that, we could reserve a special
namespace id to mean "this addon itself". So, we can use the same
sort of fixup tag for both local and external references, at the cost
of having to explicitly "export" symbols/labels for the locally
referenced nodes. So, something like
Base tree:
...
foo0: foobus@12345 {
/export/ bridge = &foo0;
/export/ intc = &/path/to/board/intc;
compatible = "foobus";
...
};
bar0: barbus@abcde {
/export/ gpio = &/path/to/gpio/mux;
compatible = "barbus";
...
};
Addon:
/* Declare our upstream connectors */
/requires/ foo "foobus";
/requires/ bar "barbus";
&foo.bridge {
local_intc: local-intc@XXX {
interrupt-parent = <&foo.intc>;
...
};
widget@YYY {
compatible = "widget31415", "widget3000";
interrupt-parent = <&LOCAL.local_intc>;
interrupts = <...>;
gpio = <&bar.gpio>;
}
}
By the time we compile to dtb, those namespace IDs could likely be
ints, rather than strings.
> local references: ok, phandle to to local node.
>
> external references: phandle to external node.
> This has to be resolved based on exports available in the device-tree the
> addon is applied to.
>
> Here, the node is not external. It is available in the addon and so it is
> a local node.
>
> No import/export mechanism is needed to resolve the phandle. Indeed, this
> phandle is already well defined (resolved) in the addon blob.
> Having a kind of 'local' import/export to allow local cross-tree references
> is going to add an extra complexity where it is not needed.
Does it, though? We already need the import/export mechanism, so what
prevents us from using it locally?
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 65/77] tests: metadata: Add a test for references by path involving orphan nodes
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (63 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 64/77] dtc: Add support for references by path involving orphan nodes Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 66/77] dtc: Add support for namespace labels references Herve Codina
` (14 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The syntax '&{$<orphan_name>/<path>}' allows to reference by path a node
that belongs to an orphan node.
Add a test related to this kind of references.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
.../metadata_addon_references.dtb.dts.expect | 48 +++++++++++++++++++
tests/metadata_addon_references.dtb.expect | 48 +++++++++++++++++++
tests/metadata_addon_references.dts | 43 +++++++++++++++++
.../metadata_addon_references.dts.dts.expect | 48 +++++++++++++++++++
tests/run_tests.sh | 2 +-
5 files changed, 188 insertions(+), 1 deletion(-)
create mode 100644 tests/metadata_addon_references.dtb.dts.expect
create mode 100644 tests/metadata_addon_references.dtb.expect
create mode 100644 tests/metadata_addon_references.dts
create mode 100644 tests/metadata_addon_references.dts.dts.expect
diff --git a/tests/metadata_addon_references.dtb.dts.expect b/tests/metadata_addon_references.dtb.dts.expect
new file mode 100644
index 0000000..267a929
--- /dev/null
+++ b/tests/metadata_addon_references.dtb.dts.expect
@@ -0,0 +1,48 @@
+/dts-v1/;
+/addon/;
+
+/ {
+
+ sub-node {
+ ref1-base1 = <&base1>;
+ ref2-base1-addon-node = <&{$base1/addon-node}>;
+ ref3-base1-addon-node = <&{$base1/addon-node}>;
+ ref4-base1-addon-node = <&{$base1/addon-node}>;
+ ref5-base3 = <&{$base3}>;
+ ref6-base3 = <&{$base3}>;
+ ref7-base3-subsubnode = <&{$base3/sub-node/sub-subnode}>;
+ phandle = <0x04>;
+ };
+};
+
+&base1 {
+
+ addon-node {
+ prop = <0x02>;
+ phandle = <0x01>;
+ };
+};
+
+&base2 {
+
+ addon-node1 {
+ ref-base1-addon-node = <&{$base1/addon-node}>;
+ };
+
+ addon-node2 {
+ ref-root-sub-node = <&{/sub-node}>;
+ };
+};
+
+&base3 {
+ phandle = <0x02>;
+
+ sub-node {
+ prop = <0x03>;
+
+ sub-subnode {
+ prop = <0x04>;
+ phandle = <0x03>;
+ };
+ };
+};
diff --git a/tests/metadata_addon_references.dtb.expect b/tests/metadata_addon_references.dtb.expect
new file mode 100644
index 0000000..d8db6cb
--- /dev/null
+++ b/tests/metadata_addon_references.dtb.expect
@@ -0,0 +1,48 @@
+/dts-v1/;
+/addon/;
+
+/ {
+ sub-node {
+ ref1-base1 = <0xffffffff>;
+ // [FDT_REF_PHANDLE] ref1-base1[0], ref = base1
+ ref2-base1-addon-node = <0x00000001>;
+ // [FDT_REF_LOCAL] ref2-base1-addon-node[0]
+ ref3-base1-addon-node = <0x00000001>;
+ // [FDT_REF_LOCAL] ref3-base1-addon-node[0]
+ ref4-base1-addon-node = <0x00000001>;
+ // [FDT_REF_LOCAL] ref4-base1-addon-node[0]
+ ref5-base3 = <0x00000002>;
+ // [FDT_REF_LOCAL] ref5-base3[0]
+ ref6-base3 = <0x00000002>;
+ // [FDT_REF_LOCAL] ref6-base3[0]
+ ref7-base3-subsubnode = <0x00000003>;
+ // [FDT_REF_LOCAL] ref7-base3-subsubnode[0]
+ phandle = <0x00000004>;
+ };
+};
+&base1 {
+ addon-node {
+ prop = <0x00000002>;
+ phandle = <0x00000001>;
+ };
+};
+&base2 {
+ addon-node1 {
+ ref-base1-addon-node = <0x00000001>;
+ // [FDT_REF_LOCAL] ref-base1-addon-node[0]
+ };
+ addon-node2 {
+ ref-root-sub-node = <0x00000004>;
+ // [FDT_REF_LOCAL] ref-root-sub-node[0]
+ };
+};
+&base3 {
+ phandle = <0x00000002>;
+ sub-node {
+ prop = <0x00000003>;
+ sub-subnode {
+ prop = <0x00000004>;
+ phandle = <0x00000003>;
+ };
+ };
+};
diff --git a/tests/metadata_addon_references.dts b/tests/metadata_addon_references.dts
new file mode 100644
index 0000000..239c141
--- /dev/null
+++ b/tests/metadata_addon_references.dts
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+/addon/;
+
+/ {
+ sub_node: sub-node {
+ ref1-base1 = <&base1>;
+ ref2-base1-addon-node = <&b1_addon>;
+ ref3-base1-addon-node = <&{$base1/addon-node}>;
+ ref4-base1-addon-node = <&{$base1/addon-node/}>;
+ ref5-base3 = <&{$base3}>;
+ ref6-base3 = <&{$base3/}>;
+ ref7-base3-subsubnode = <&{$base3/sub-node/sub-subnode}>;
+ };
+};
+
+&base1 {
+ b1_addon: addon-node {
+ prop = <2>;
+ };
+};
+
+&base2 {
+ addon-node1 {
+ ref-base1-addon-node = <&b1_addon>;
+ };
+ addon-node2 {
+ ref-root-sub-node = <&sub_node>;
+ };
+};
+
+&base3 {
+ sub-node {
+ prop = <3>;
+ sub-subnode {
+ prop = <4>;
+ };
+ };
+};
diff --git a/tests/metadata_addon_references.dts.dts.expect b/tests/metadata_addon_references.dts.dts.expect
new file mode 100644
index 0000000..dff893e
--- /dev/null
+++ b/tests/metadata_addon_references.dts.dts.expect
@@ -0,0 +1,48 @@
+/dts-v1/;
+/addon/;
+
+/ {
+
+ sub_node: sub-node {
+ ref1-base1 = <&base1>;
+ ref2-base1-addon-node = <&b1_addon>;
+ ref3-base1-addon-node = <&{$base1/addon-node}>;
+ ref4-base1-addon-node = <&{$base1/addon-node/}>;
+ ref5-base3 = <&{$base3}>;
+ ref6-base3 = <&{$base3/}>;
+ ref7-base3-subsubnode = <&{$base3/sub-node/sub-subnode}>;
+ phandle = <0x04>;
+ };
+};
+
+&base1 {
+
+ b1_addon: addon-node {
+ prop = <0x02>;
+ phandle = <0x01>;
+ };
+};
+
+&base2 {
+
+ addon-node1 {
+ ref-base1-addon-node = <&b1_addon>;
+ };
+
+ addon-node2 {
+ ref-root-sub-node = <&sub_node>;
+ };
+};
+
+&base3 {
+ phandle = <0x02>;
+
+ sub-node {
+ prop = <0x03>;
+
+ sub-subnode {
+ prop = <0x04>;
+ phandle = <0x03>;
+ };
+ };
+};
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 12418bf..a371377 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1129,7 +1129,7 @@ metadata_tests() {
metadata_addon_base metadata_exportsyms_local \
metadata_exportsyms_ref metadata_importsyms \
metadata_addon_orphan1 metadata_addon_orphan2 \
- metadata_addon_orphan3; do
+ metadata_addon_orphan3 metadata_addon_references; do
run_dtc_test -I dts -O dts -o $dt.dts.dts "$SRCDIR/$dt.dts"
base_run_test check_diff $dt.dts.dts "$SRCDIR/$dt.dts.dts.expect"
run_dtc_test -I dts -O dtb -o $dt.dtb "$SRCDIR/$dt.dts"
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 66/77] dtc: Add support for namespace labels references
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (64 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 65/77] tests: metadata: Add a test " Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 67/77] tests: metadata: Add a test " Herve Codina
` (13 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Namespace labels references can only be present in addons and involves
import/exported symbols.
They allow to 'jump' from node to node based on exported symbols defined
at each node.
When a label reference contains a dot ('.') char, it becomes a namespace
labels reference.
For instance &foo.bar.baz is a namespace label reference. The resolution
of this reference is performed in a recursive way.
- Get the node referenced by foo.
- From this node get the node referenced by bar in exported symbols
from foo.
- From this node get the node referenced by baz in exported symbols
from bar.
- ...
The first item (foo) involves import symbols defined in the addon and
export symbols defined in the node the addon is applied to.
Other items involves only exported symbols in referenced nodes to
perform the resolution chain.
We leave the addon thanks to the first item and import symbols. Other
items allow to perform jumps from node to node in the base device-tree
without leaving it.
The full resolution can be summarized with the following diagram:
(addon DT)
&foo.bar.baz
| | |
| | +--------------------------------------------+
| | |
| +-------------------------------+ |
| | |
| (addon DT) | |
+-> /import/ foo: --+ | |
| | |
| | |
addon applied at | | |
target node in the | | |
base DT | | |
| | | |
| (base DT) | | |
+---> target { v | |
/export/ foo: &n1; | |
| | |
| | |
v (base DT) | |
n1 { v |
/export/ bar: &n2; |
| |
v (base DT) |
n2 { v
/export/ baz: &n3;
|
|
v
n3 { ... };
'&foo.bar.baz' references, in the end, the n3 node from the base DT.
Implement support for namespace references parsing in dtc.
The resolution part is out of dtc. Indeed, dtc has no support for
applying an addon.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
dtc-lexer.l | 13 +++++++++++++
dtc-parser.y | 49 ++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 59 insertions(+), 3 deletions(-)
diff --git a/dtc-lexer.l b/dtc-lexer.l
index 540bfdf..14b5488 100644
--- a/dtc-lexer.l
+++ b/dtc-lexer.l
@@ -232,6 +232,12 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
return DT_LABEL_REF;
}
+<*>\&{LABEL}(\.{LABEL})+ { /* namespace label reference */
+ DPRINT("Ref namespace: %s\n", yytext+1);
+ yylval.labelref = xstrdup(yytext+1);
+ return DT_LABEL_NAMESPACE_REF;
+ }
+
<*>"&{"{PATHCHAR}*\} { /* new-style path reference */
yytext[yyleng-1] = '\0';
DPRINT("Ref: %s\n", yytext+2);
@@ -246,6 +252,13 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
return DT_ORPHAN_PATH_REF;
}
+<*>"&{\$"{LABEL}(\.{LABEL})+([/]{PATHCHAR}*)?\} { /* orphan path reference */
+ yytext[yyleng-1] = '\0';
+ DPRINT("Ref (namespace) orphan path: %s\n", yytext+1);
+ yylval.labelref = xstrdup(yytext+2);
+ return DT_ORPHAN_PATH_REF;
+ }
+
<BYTESTRING>[0-9a-fA-F]{2} {
yylval.byte = strtol(yytext, NULL, 16);
DPRINT("Byte: %02x\n", (int)yylval.byte);
diff --git a/dtc-parser.y b/dtc-parser.y
index 9d619cd..8c63e83 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -32,6 +32,11 @@ static bool is_ref_relative(const char *ref)
return ref[0] != '/' && strchr(&ref[1], '/');
}
+static bool is_ref_namespace(const char *ref)
+{
+ return strchr(ref, '.');
+}
+
static struct node *parser_get_node_by_ref(struct node *dt, struct node *orphanlist,
const char *ref)
{
@@ -110,6 +115,7 @@ static struct node *parser_get_node_by_ref(struct node *dt, struct node *orphanl
%token <data> DT_STRING
%token <labelref> DT_LABEL
%token <labelref> DT_LABEL_REF
+%token <labelref> DT_LABEL_NAMESPACE_REF
%token <labelref> DT_PATH_REF
%token <labelref> DT_ORPHAN_PATH_REF
%token DT_INCBIN
@@ -260,7 +266,7 @@ importdef:
}
;
-dt_ref: DT_LABEL_REF | DT_PATH_REF;
+dt_ref: DT_LABEL_REF | DT_PATH_REF | DT_LABEL_NAMESPACE_REF;
devicetree:
'/' nodedef
@@ -281,6 +287,9 @@ devicetree:
else if (is_ref_relative($1))
ERROR(&@2, "Label-relative reference %s not supported in plugin nor addon", $1);
+ if (!(last_header_flags & DTSF_ADDON) && is_ref_namespace($1))
+ ERROR(&@2, "Namespaced label reference %s supported only in addon", $1);
+
if (last_header_flags & DTSF_PLUGIN) {
$$ = plugin_add_orphan_node(
name_node(build_node(NULL, NULL, NULL, NULL),
@@ -300,6 +309,10 @@ devicetree:
if ((last_header_flags & (DTSF_PLUGIN | DTSF_ADDON)) && is_ref_relative($3))
ERROR(&@2, "Label-relative reference %s not supported in plugin nor addon", $3);
+ if (!(last_header_flags & DTSF_ADDON) && is_ref_namespace($3))
+ ERROR(&@2, "Namespaced label reference %s supported only in addon", $3);
+
+
if (target) {
add_label(&target->labels, $2);
merge_nodes(target, $4);
@@ -346,6 +359,25 @@ devicetree:
}
$$ = $1;
}
+ | devicetree DT_LABEL_NAMESPACE_REF nodedef
+ {
+ struct node *target = parser_get_node_by_ref(
+ $1, parser_orphanlist, $2);
+
+ if (!(last_header_flags & DTSF_ADDON))
+ ERROR(&@2, "Namespaced label reference %s supported only in addon", $2);
+
+ if (target) {
+ merge_nodes(target, $3);
+ } else {
+ if (last_header_flags & DTSF_ADDON)
+ addon_add_orphan_node(&parser_orphanlist,
+ orphan_node($3, $2));
+ else
+ ERROR(&@2, "Label or path %s not found", $2);
+ }
+ $$ = $1;
+ }
| devicetree DT_DEL_NODE dt_ref ';'
{
struct node *target = parser_get_node_by_ref(
@@ -422,6 +454,10 @@ exportlist:
exportdef:
DT_EXPORT DT_LABEL dt_ref ';'
{
+ /* Only an addon can use namespaced labels references */
+ if (!(last_header_flags & DTSF_ADDON) && is_ref_namespace($3))
+ ERROR(&@2, "Namespaced label reference %s supported only in addon", $3);
+
$$ = build_exportsym($2, $3, 0, &@$);
free($2);
free($3);
@@ -477,6 +513,9 @@ propdata:
}
| propdataprefix dt_ref
{
+ if (!(last_header_flags & DTSF_ADDON) && is_ref_namespace($2))
+ ERROR(&@2, "Namespaced label reference %s supported only in addon", $2);
+
$1 = data_add_marker($1, TYPE_STRING, $2);
$$ = data_add_marker($1, REF_PATH, $2);
}
@@ -582,13 +621,17 @@ arrayprefix:
{
uint64_t val = ~0ULL >> (64 - $1.bits);
- if ($1.bits == 32)
+ if ($1.bits == 32) {
+ if (!(last_header_flags & DTSF_ADDON) && is_ref_namespace($2))
+ ERROR(&@2, "Namespaced label reference %s supported only in addon", $2);
+
$1.data = data_add_marker($1.data,
REF_PHANDLE,
$2);
- else
+ } else {
ERROR(&@2, "References are only allowed in "
"arrays with 32-bit elements.");
+ }
$$.data = data_append_integer($1.data, val, $1.bits);
}
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 67/77] tests: metadata: Add a test for namespace labels references
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (65 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 66/77] dtc: Add support for namespace labels references Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:19 ` [RFC PATCH 68/77] libfdt: Introduce fdt_getprop_by_offset_w() Herve Codina
` (12 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Namespace labels references are references in the form '&foo.bar.baz'.
Support for namespace labels references has been recently added to dtc.
Add a test related to this kind of references.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
...metadata_addon_refnamespace.dtb.dts.expect | 32 ++++++++++++++++
tests/metadata_addon_refnamespace.dtb.expect | 29 ++++++++++++++
tests/metadata_addon_refnamespace.dts | 38 +++++++++++++++++++
...metadata_addon_refnamespace.dts.dts.expect | 32 ++++++++++++++++
tests/run_tests.sh | 3 +-
5 files changed, 133 insertions(+), 1 deletion(-)
create mode 100644 tests/metadata_addon_refnamespace.dtb.dts.expect
create mode 100644 tests/metadata_addon_refnamespace.dtb.expect
create mode 100644 tests/metadata_addon_refnamespace.dts
create mode 100644 tests/metadata_addon_refnamespace.dts.dts.expect
diff --git a/tests/metadata_addon_refnamespace.dtb.dts.expect b/tests/metadata_addon_refnamespace.dtb.dts.expect
new file mode 100644
index 0000000..111a746
--- /dev/null
+++ b/tests/metadata_addon_refnamespace.dtb.dts.expect
@@ -0,0 +1,32 @@
+/dts-v1/;
+/addon/;
+
+/import/ foo: "abc,foo";
+/import/ bar: "abc,bar";
+
+
+&foo.x {
+
+ addon-node {
+ ref0 = <&foo.x.y>;
+ ref1 = <0x0a &bar.other 0x14>;
+ ref2 = <&{$foo.x.y.z/addon-node}>;
+ ref3 = <&{$foo.x.y.z/addon-node}>;
+ };
+};
+
+&foo.x.y.z {
+
+ addon-node {
+ prop = <0x00>;
+ phandle = <0x01>;
+ };
+};
+
+&foo.x.y {
+
+ node {
+ prop1 = <0x01>;
+ prop2 = <0x02>;
+ };
+};
diff --git a/tests/metadata_addon_refnamespace.dtb.expect b/tests/metadata_addon_refnamespace.dtb.expect
new file mode 100644
index 0000000..5fceb61
--- /dev/null
+++ b/tests/metadata_addon_refnamespace.dtb.expect
@@ -0,0 +1,29 @@
+/dts-v1/;
+/addon/;
+
+// [FDT_IMPORT_SYM] 'foo' (abc,foo)
+// [FDT_IMPORT_SYM] 'bar' (abc,bar)
+&foo.x {
+ addon-node {
+ ref0 = <0xffffffff>;
+ // [FDT_REF_PHANDLE] ref0[0], ref = foo.x.y
+ ref1 = <0x0000000a 0xffffffff 0x00000014>;
+ // [FDT_REF_PHANDLE] ref1[4], ref = bar.other
+ ref2 = <0x00000001>;
+ // [FDT_REF_LOCAL] ref2[0]
+ ref3 = <0x00000001>;
+ // [FDT_REF_LOCAL] ref3[0]
+ };
+};
+&foo.x.y.z {
+ addon-node {
+ prop = <0x00000000>;
+ phandle = <0x00000001>;
+ };
+};
+&foo.x.y {
+ node {
+ prop1 = <0x00000001>;
+ prop2 = <0x00000002>;
+ };
+};
diff --git a/tests/metadata_addon_refnamespace.dts b/tests/metadata_addon_refnamespace.dts
new file mode 100644
index 0000000..51a17a9
--- /dev/null
+++ b/tests/metadata_addon_refnamespace.dts
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+/addon/;
+
+/import/ foo: "abc,foo";
+/import/ bar: "abc,bar";
+
+
+&foo.x {
+ addon-node {
+ ref0 = <&foo.x.y>;
+ ref1 = <10 &bar.other 20>;
+ ref2 = <&addon_node>;
+ ref3 = <&{$foo.x.y.z/addon-node}>;
+ };
+};
+
+&foo.x.y.z {
+ addon_node: addon-node {
+ prop = <0>;
+ };
+};
+
+&foo.x.y {
+ node {
+ prop1 = <1>;
+ };
+};
+
+&foo.x.y {
+ node {
+ prop2 = <2>;
+ };
+};
diff --git a/tests/metadata_addon_refnamespace.dts.dts.expect b/tests/metadata_addon_refnamespace.dts.dts.expect
new file mode 100644
index 0000000..94861c3
--- /dev/null
+++ b/tests/metadata_addon_refnamespace.dts.dts.expect
@@ -0,0 +1,32 @@
+/dts-v1/;
+/addon/;
+
+/import/ foo: "abc,foo";
+/import/ bar: "abc,bar";
+
+
+&foo.x {
+
+ addon-node {
+ ref0 = <&foo.x.y>;
+ ref1 = <0x0a &bar.other 0x14>;
+ ref2 = <&addon_node>;
+ ref3 = <&{$foo.x.y.z/addon-node}>;
+ };
+};
+
+&foo.x.y.z {
+
+ addon_node: addon-node {
+ prop = <0x00>;
+ phandle = <0x01>;
+ };
+};
+
+&foo.x.y {
+
+ node {
+ prop1 = <0x01>;
+ prop2 = <0x02>;
+ };
+};
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index a371377..4392752 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1129,7 +1129,8 @@ metadata_tests() {
metadata_addon_base metadata_exportsyms_local \
metadata_exportsyms_ref metadata_importsyms \
metadata_addon_orphan1 metadata_addon_orphan2 \
- metadata_addon_orphan3 metadata_addon_references; do
+ metadata_addon_orphan3 metadata_addon_references \
+ metadata_addon_refnamespace; do
run_dtc_test -I dts -O dts -o $dt.dts.dts "$SRCDIR/$dt.dts"
base_run_test check_diff $dt.dts.dts "$SRCDIR/$dt.dts.dts.expect"
run_dtc_test -I dts -O dtb -o $dt.dtb "$SRCDIR/$dt.dts"
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 68/77] libfdt: Introduce fdt_getprop_by_offset_w()
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (66 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 67/77] tests: metadata: Add a test " Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-15 7:05 ` David Gibson
2026-01-12 14:19 ` [RFC PATCH 69/77] libfdt: Introduce fdt_getprop_offset() Herve Codina
` (11 subsequent siblings)
79 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The future support for applying a addon on a base device-tree needs to
modify properties retrieved by their offset.
fdt_getprop_by_offset() already exists to get a preperty by its offset
but the property returned is read-only. A writable returned property is
needed.
Fill the lack and introduce fdt_getprop_by_offset_w(), the write enabled
variant of fdt_getprop_by_offset().
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
libfdt/libfdt.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h
index 37459a6..0c654b1 100644
--- a/libfdt/libfdt.h
+++ b/libfdt/libfdt.h
@@ -858,6 +858,12 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
#ifndef SWIG /* This function is not useful in Python */
const void *fdt_getprop_by_offset(const void *fdt, int offset,
const char **namep, int *lenp);
+static inline void *fdt_getprop_by_offset_w(const void *fdt, int offset,
+ const char **namep, int *lenp)
+{
+ return (void *)(uintptr_t)fdt_getprop_by_offset(fdt, offset, namep,
+ lenp);
+}
#endif
/**
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 68/77] libfdt: Introduce fdt_getprop_by_offset_w()
2026-01-12 14:19 ` [RFC PATCH 68/77] libfdt: Introduce fdt_getprop_by_offset_w() Herve Codina
@ 2026-01-15 7:05 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-15 7:05 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 1572 bytes --]
On Mon, Jan 12, 2026 at 03:19:58PM +0100, Herve Codina wrote:
> The future support for applying a addon on a base device-tree needs to
> modify properties retrieved by their offset.
>
> fdt_getprop_by_offset() already exists to get a preperty by its offset
> but the property returned is read-only. A writable returned property is
> needed.
>
> Fill the lack and introduce fdt_getprop_by_offset_w(), the write enabled
> variant of fdt_getprop_by_offset().
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
Add a testcase, and this could be merged regardless of the rest of
the series.
> ---
> libfdt/libfdt.h | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h
> index 37459a6..0c654b1 100644
> --- a/libfdt/libfdt.h
> +++ b/libfdt/libfdt.h
> @@ -858,6 +858,12 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
> #ifndef SWIG /* This function is not useful in Python */
> const void *fdt_getprop_by_offset(const void *fdt, int offset,
> const char **namep, int *lenp);
> +static inline void *fdt_getprop_by_offset_w(const void *fdt, int offset,
> + const char **namep, int *lenp)
> +{
> + return (void *)(uintptr_t)fdt_getprop_by_offset(fdt, offset, namep,
> + lenp);
> +}
> #endif
>
> /**
> --
> 2.52.0
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* [RFC PATCH 69/77] libfdt: Introduce fdt_getprop_offset()
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (67 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 68/77] libfdt: Introduce fdt_getprop_by_offset_w() Herve Codina
@ 2026-01-12 14:19 ` Herve Codina
2026-01-12 14:20 ` [RFC PATCH 70/77] libfdt: Add support for applying an addon on a base device-tree blob Herve Codina
` (10 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:19 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The future support for applying a addon on a base device-tree needs to
get an offset to a property based on the node offset and the
property name.
Several function exists to get a property but none of them allows to
get the property offset.
Fill the lack and introduce fdt_getprop_offset()
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
libfdt/fdt_ro.c | 12 ++++++++++++
libfdt/libfdt_internal.h | 2 ++
2 files changed, 14 insertions(+)
diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c
index 63494fb..29692f9 100644
--- a/libfdt/fdt_ro.c
+++ b/libfdt/fdt_ro.c
@@ -508,6 +508,18 @@ const void *fdt_getprop(const void *fdt, int nodeoffset,
return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
}
+int fdt_getprop_offset(const void *fdt, int nodeoffset, const char *name)
+{
+ const struct fdt_property *prop;
+ int lenp, offset;
+
+ prop = fdt_get_property_namelen_(fdt, nodeoffset, name, strlen(name),
+ &lenp, &offset);
+ if (!prop)
+ return lenp;
+ return offset;
+}
+
uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
{
const fdt32_t *php;
diff --git a/libfdt/libfdt_internal.h b/libfdt/libfdt_internal.h
index d80d218..499e821 100644
--- a/libfdt/libfdt_internal.h
+++ b/libfdt/libfdt_internal.h
@@ -24,6 +24,8 @@ int32_t fdt_ro_probe_(const void *fdt);
int fdt_check_node_offset_(const void *fdt, int offset);
int fdt_check_prop_offset_(const void *fdt, int offset);
+int fdt_getprop_offset(const void *fdt, int nodeoffset, const char *name);
+
const char *fdt_find_string_len_(const char *strtab, int tabsize, const char *s,
int s_len);
static inline const char *fdt_find_string_(const char *strtab, int tabsize,
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 70/77] libfdt: Add support for applying an addon on a base device-tree blob
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (68 preceding siblings ...)
2026-01-12 14:19 ` [RFC PATCH 69/77] libfdt: Introduce fdt_getprop_offset() Herve Codina
@ 2026-01-12 14:20 ` Herve Codina
2026-01-12 14:20 ` [RFC PATCH 71/77] Add fdtaddon tool to apply an addon Herve Codina
` (9 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:20 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Addon dtbs have been recently supported. The missing part is having some
support for addon usage.
The goal of addons is to extend a base device-tree. This feature is
similar to the overlay feature but addons and recent modifications
offer metadata and import/export symbol mechanism.
This import/export symbol mechanism allow a fine tuning of symbols
exported (i.e. symbol seen from the addon).
To extend the base device-tree, an addon needs to be applied to this
base device-tree at a specific node. The specific node, target node of
the addon, is not encoded in the addon dtb.
Indeed, addons do not depends on the exact base device tree structure.
An addon can be applied on top of any base device tree as soon as the
target node matches expectations of the addon. Exported symbols at
this target node has to match imported symbols defined in the addon.
When the addon is applied three macro operations have to be done:
- Avoid phandle conflict avoidance
The conflict avoidance consists in fixing local phandle to avoid
conflict with already existing phandle available in the base
device-tree. This operation involved metadata recently added in dtb
format.
- Resolve unresolved symbols
The symbol resolution consists in replacing unresolved symbol
references present in the addon dtb by a reference to an existing
node in the base device tree. This operation involved metadata and
import/export symbols.
- Merge addon nodes into base device-tree
This merging consists in adding additional nodes described in the
addon into the base device-tree.
fdt_addon_apply() allows to apply an addon on a base device-tree and
performs internally all the needed operations.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
libfdt/Makefile.libfdt | 2 +-
libfdt/fdt_addon.c | 1636 ++++++++++++++++++++++++++++++++++++++
libfdt/fdt_rw.c | 85 ++
libfdt/libfdt.h | 32 +
libfdt/libfdt_internal.h | 4 +
libfdt/meson.build | 1 +
libfdt/version.lds | 1 +
7 files changed, 1760 insertions(+), 1 deletion(-)
create mode 100644 libfdt/fdt_addon.c
diff --git a/libfdt/Makefile.libfdt b/libfdt/Makefile.libfdt
index b763b2e..437d5b5 100644
--- a/libfdt/Makefile.libfdt
+++ b/libfdt/Makefile.libfdt
@@ -10,7 +10,7 @@ LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1
LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h
LIBFDT_VERSION = version.lds
LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \
- fdt_addresses.c fdt_overlay.c fdt_check.c
+ fdt_addresses.c fdt_overlay.c fdt_addon.c fdt_check.c
LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
LIBFDT_LIB = libfdt.$(SHAREDLIB_EXT).$(DTC_VERSION)
diff --git a/libfdt/fdt_addon.c b/libfdt/fdt_addon.c
new file mode 100644
index 0000000..351d063
--- /dev/null
+++ b/libfdt/fdt_addon.c
@@ -0,0 +1,1636 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2025 Bootlin
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+/**
+ * fdt_skip_string - Skip a string
+ * @fdt: device tree blob
+ * @offset: Offset of the string to skip
+ *
+ * fdt_skip_string() returns the offset of the first byte after the skipped
+ * string.
+ *
+ * returns:
+ * offset of the first byte after the skipped string
+ */
+static int fdt_skip_string(const void *fdt, int offset)
+{
+ const char *p;
+ int next;
+
+ next = offset;
+ do {
+ p = fdt_offset_ptr(fdt, next++, 1);
+ } while (p && (*p != '\0'));
+
+ return next;
+}
+
+/**
+ * addon_phandle_add_offset - Increases a phandle by an offset
+ * @fdta: Addon device tree blob
+ * @node: Device tree addon blob
+ * @name: Name of the property to modify (phandle or linux,phandle)
+ * @delta: offset to apply
+ *
+ * addon_phandle_add_offset() increments a node phandle by a given
+ * offset.
+ *
+ * returns:
+ * 0 on success.
+ * Negative error code on error
+ */
+static int addon_phandle_add_offset(void *fdta, int node, const char *name,
+ uint32_t delta)
+{
+ fdt32_t *valp, val;
+ int len;
+
+ valp = fdt_getprop_w(fdta, node, name, &len);
+ if (!valp)
+ return len;
+ if (len != sizeof(val))
+ return -FDT_ERR_BADPHANDLE;
+
+ val = fdt32_ld(valp);
+ if (val + delta < val || val + delta == (uint32_t)-1)
+ return -FDT_ERR_NOPHANDLES;
+ fdt32_st(valp, val + delta);
+ return 0;
+}
+
+/**
+ * addon_phandle_set_val - Set a phandle value
+ * @fdt: Addon device tree blob
+ * @node: Device tree addon blob
+ * @name: Name of the property to modify (phandle or linux,phandle)
+ * @val: Value to set
+ *
+ * addon_phandle_set_val() set a node phandle to a given offset.
+ *
+ * returns:
+ * 0 on success.
+ * Negative error code on error
+ */
+static int addon_phandle_set_val(void *fdta, int node, const char *name,
+ uint32_t val)
+{
+ fdt32_t *valp;
+ int len;
+
+ valp = fdt_getprop_w(fdta, node, name, &len);
+ if (!valp)
+ return len;
+ if (len != sizeof(val))
+ return -FDT_ERR_BADPHANDLE;
+
+ fdt32_st(valp, val);
+ return 0;
+}
+
+/**
+ * addon_property_add_offset - Increases a property value (a phandle reference)
+ * by an offset
+ * @fdta: Addon device tree blob
+ * @prop_offset: Property to update
+ * @data_offset: Offset in the property data to update
+ * @delta: Offset to apply
+ *
+ * returns:
+ * 0 on success.
+ * Negative error code on error
+ */
+static int addon_property_add_offset(void *fdta, int prop_offset,
+ int data_offset, uint32_t delta)
+{
+ char *propval;
+ uint32_t val;
+ int proplen;
+ fdt32_t *p;
+
+ propval = fdt_getprop_by_offset_w(fdta, prop_offset, NULL, &proplen);
+ if (!propval)
+ return proplen;
+ if (proplen < data_offset + sizeof(fdt32_t))
+ return -FDT_ERR_BADSTRUCTURE;
+
+ /* Get the phandle pointer */
+ p = (fdt32_t *)(propval + data_offset);
+
+ /* Update the phandle value */
+ val = fdt32_ld(p);
+ if (val + delta < val || val + delta == (uint32_t)-1)
+ return -FDT_ERR_NOPHANDLES;
+ fdt32_st(p, val + delta);
+ return 0;
+}
+
+/**
+ * addon_property_set_val - Set a property value (a phandle reference)
+ * @fdta: Addon device tree blob
+ * @prop_offset: Property to update
+ * @data_offset: Offset in the property data to update
+ * @value: Value to set
+ *
+ * returns:
+ * 0 on success.
+ * Negative error code on error
+ */
+static int addon_property_set_val(void *fdta, int prop_offset, int data_offset,
+ uint32_t val)
+{
+ char *propval;
+ int proplen;
+ fdt32_t *p;
+
+ propval = fdt_getprop_by_offset_w(fdta, prop_offset, NULL, &proplen);
+ if (!propval)
+ return proplen;
+ if (proplen < data_offset + sizeof(fdt32_t))
+ return -FDT_ERR_BADSTRUCTURE;
+
+ /* Get the phandle pointer and update it */
+ p = (fdt32_t *)(propval + data_offset);
+ fdt32_st(p, val);
+ return 0;
+}
+
+/**
+ * addon_property_replace - Replace a property value (a phandle reference) if
+ * the old value matches the current value.
+ * @fdta: Addon device tree blob
+ * @prop_offset: Property to update
+ * @data_offset: Offset in the property data to update
+ * @old_val: Old value
+ * @new_val: New value to set if the @old_val matches
+ *
+ * returns:
+ * 0 on success.
+ * Negative error code on error
+ */
+static int addon_property_replace(void *fdt, int prop_offset, int data_offset,
+ uint32_t old_val, uint32_t new_val)
+{
+ char *propval;
+ uint32_t val;
+ int proplen;
+ fdt32_t *p;
+
+ propval = fdt_getprop_by_offset_w(fdt, prop_offset, NULL, &proplen);
+ if (!propval)
+ return proplen;
+ if (proplen < data_offset + sizeof(fdt32_t))
+ return -FDT_ERR_BADSTRUCTURE;
+
+ /* Get the phandle pointer */
+ p = (fdt32_t *)(propval + data_offset);
+
+ val = fdt32_ld(p);
+ if (val == old_val)
+ fdt32_st(p, new_val);
+
+ return 0;
+}
+
+/**
+ * addon_adjust_local_phandles - Adjust the local phandles of a whole addon blob
+ * @fdta: Addon device tree blob
+ * @delta: Offset to shift the phandles of
+ *
+ * addon_adjust_local_phandles() adds a constant to all the local phandles of
+ * an addon. This is mainly use as part of the addon application process, when
+ * we want to update all the local phandles of the addon to not conflict with
+ * phandles of the base device tree.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int addon_adjust_local_phandles(void *fdta, uint32_t delta)
+{
+ int offset, next_offset;
+ int prop_phandle_offset;
+ const fdt32_t *pfdt32;
+ int last_prop_offset;
+ fdt32_t *pfdt32w;
+ uint32_t tag;
+ uint32_t val;
+ int ret;
+
+ /*
+ * phandles that need to be updated are:
+ * - phandles properties in nodes
+ * - phandles in properties where a FDT_REF_LOCAL tag is available
+ * - phandles in FDT_EXPORT_SYM tags
+ */
+
+ next_offset = 0;
+ do {
+ offset = next_offset;
+ tag = fdt_next_tag_full(fdta, offset, &next_offset);
+ switch (tag) {
+ case FDT_BEGIN_NODE:
+ ret = addon_phandle_add_offset(fdta, offset, "phandle", delta);
+ if (ret && ret != -FDT_ERR_NOTFOUND)
+ return ret;
+
+ ret = addon_phandle_add_offset(fdta, offset, "linux,phandle", delta);
+ if (ret && ret != -FDT_ERR_NOTFOUND)
+ return ret;
+ break;
+
+ case FDT_END_NODE:
+ break;
+
+ case FDT_PROP:
+ last_prop_offset = offset;
+ break;
+
+ case FDT_NOP:
+ break;
+
+ case FDT_REF_LOCAL:
+ /*
+ * The property references a phandle. Get the offset
+ * of this phandle reference in the property data area.
+ */
+ pfdt32 = fdt_offset_ptr(fdta, offset + FDT_TAGSIZE,
+ sizeof(*pfdt32));
+ prop_phandle_offset = fdt32_to_cpu(*pfdt32);
+
+ /* Update the phandle reference */
+ ret = addon_property_add_offset(fdta, last_prop_offset,
+ prop_phandle_offset,
+ delta);
+ if (ret)
+ return ret;
+ break;
+
+ case FDT_REF_PHANDLE:
+ break;
+
+ case FDT_BEGIN_NODE_REF:
+ break;
+
+ case FDT_END:
+ ret = (next_offset < 0) ? next_offset : 0;
+ break;
+
+ case FDT_EXPORT_SYM:
+ /* Skip name */
+ offset += FDT_TAGSIZE;
+ offset = FDT_CELLALIGN(fdt_skip_string(fdta, offset));
+
+ /* Get phandle pointer */
+ pfdt32w = fdt_offset_ptr_w(fdta, offset, sizeof(*pfdt32));
+
+ /* Update the phandle value */
+ val = fdt32_ld(pfdt32w);
+ if (val + delta < val || val + delta == (uint32_t)-1)
+ return -FDT_ERR_NOPHANDLES;
+
+ fdt32_st(pfdt32w, val + delta);
+ break;
+
+ case FDT_EXPORT_SYM_REF:
+ break;
+ case FDT_IMPORT_SYM:
+ break;
+
+ default:
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+ } while (tag != FDT_END);
+
+ return ret;
+}
+
+static int fdt_check_exportsym_offset(const void *fdt, int offset)
+{
+ int nextoffset;
+ uint32_t tag;
+
+ tag = fdt_next_tag_full(fdt, offset, &nextoffset);
+ if ((tag != FDT_EXPORT_SYM) && (tag != FDT_EXPORT_SYM_REF))
+ return -FDT_ERR_BADOFFSET;
+ return nextoffset;
+}
+
+static int fdt_next_exportsym_nextoffset_(const void *fdt, int nextoffset)
+{
+ uint32_t tag;
+ int offset;
+
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag_full(fdt, offset, &nextoffset);
+ switch (tag) {
+ case FDT_EXPORT_SYM:
+ return offset;
+
+ case FDT_EXPORT_SYM_REF:
+ return offset;
+
+ case FDT_BEGIN_NODE:
+ /* We are going to leave the current node (sub-node) */
+ return -FDT_ERR_NOTFOUND;
+
+ case FDT_BEGIN_NODE_REF:
+ /* We cannot have a node ref inside an other node */
+ return -FDT_ERR_BADSTRUCTURE;
+
+ case FDT_END_NODE:
+ /* We are going to leave the current node (parent node) */
+ return -FDT_ERR_NOTFOUND;
+
+ case FDT_END:
+ if (nextoffset < 0)
+ return nextoffset;
+
+ return -FDT_ERR_NOTFOUND;
+ }
+ } while (tag != FDT_END);
+
+ return offset;
+}
+
+static int fdt_next_exportsym_offset(const void *fdt, int offset)
+{
+ int nextoffset;
+
+ if (offset < 0)
+ return offset;
+
+ nextoffset = fdt_check_exportsym_offset(fdt, offset);
+ if (nextoffset < 0)
+ return nextoffset;
+
+ return fdt_next_exportsym_nextoffset_(fdt, nextoffset);
+}
+
+static int fdt_check_node_offset_full(const void *fdt, int node_offset)
+{
+ int nextoffset;
+
+ nextoffset = fdt_check_node_offset_(fdt, node_offset);
+ if (nextoffset < 0)
+ return nextoffset;
+
+ /*
+ * We need the export symbols meta data.
+ * fdt_check_node_offset_() uses fdt_next_tag() to check the node.
+ * fdt_next_tag() skips meta data.
+ * Get potential meta data using an explicitly call to
+ * fdt_next_tag_full()
+ */
+ fdt_next_tag_full(fdt, node_offset, &nextoffset);
+ return nextoffset;
+}
+
+static int fdt_first_exportsym_offset(const void *fdt, int node_offset)
+{
+ int nextoffset;
+
+ if (node_offset < 0)
+ return node_offset;
+
+ nextoffset = fdt_check_node_offset_full(fdt, node_offset);
+ if (nextoffset < 0)
+ return nextoffset;
+
+ return fdt_next_exportsym_nextoffset_(fdt, nextoffset);
+}
+
+static const char *fdt_exportsym_get_name(const void *fdt, int offset)
+{
+ if (fdt_check_exportsym_offset(fdt, offset) < 0)
+ return NULL;
+
+ return fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, 1);
+}
+
+static uint32_t fdt_exportsym_get_phandle(const void *fdt, int offset)
+{
+ const fdt32_t *pfdt32;
+
+ if (fdt_check_exportsym_offset(fdt, offset) < 0)
+ return 0;
+
+ /* Skip name */
+ offset += FDT_TAGSIZE;
+ offset = FDT_CELLALIGN(fdt_skip_string(fdt, offset));
+
+ pfdt32 = fdt_offset_ptr(fdt, offset, sizeof(*pfdt32));
+ if (!pfdt32)
+ return 0;
+
+ return fdt32_ld_(pfdt32);
+}
+
+#define fdt_for_each_exportsym(exportsym, fdt, node) \
+ for (exportsym = fdt_first_exportsym_offset(fdt, node); \
+ exportsym >= 0; \
+ exportsym = fdt_next_exportsym_offset(fdt, exportsym))
+
+/**
+ * fdt_resolve_symbol - Resolve a symbol
+ * @fdt: base device tree blob
+ * @target_node: Target node offset in the base device tree blob containing
+ * the exported symbols used for the resolution.
+ * @sym_name: Symbol name
+ * @sym_namelen: Length of the symbol name
+ *
+ * fdt_resolve_symbol() searches for a matching export symbol exported by the
+ * @target_node. It returns the node offset in @fdt referenced by the matching
+ * export symbol.
+ *
+ * returns:
+ * offset of the node matching the symbol after the resolution on success.
+ * Negative error code on failure
+ */
+static int fdt_resolve_symbol(const void *fdt, int target_node,
+ const char *sym_name, int sym_namelen)
+{
+ const char *exportsym_name;
+ uint32_t phandle;
+ int exportsym;
+ int ref_node;
+
+ /* Look at export available at the target node */
+ fdt_for_each_exportsym(exportsym, fdt, target_node) {
+ exportsym_name = fdt_exportsym_get_name(fdt, exportsym);
+ if (!exportsym_name)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ phandle = fdt_exportsym_get_phandle(fdt, exportsym);
+ if ((phandle == 0) || (phandle == ~0U))
+ return -FDT_ERR_BADPHANDLE;
+
+ if ((strlen(exportsym_name) != sym_namelen) ||
+ (memcmp(exportsym_name, sym_name, sym_namelen) != 0))
+ continue;
+
+ ref_node = fdt_node_offset_by_phandle(fdt, phandle);
+ if (ref_node < 0)
+ return -FDT_ERR_NOTFOUND;
+
+ return ref_node;
+ }
+
+ return -FDT_ERR_NOTFOUND;
+}
+
+/**
+ * fdt_resolve_import - Resolve an imported symbol
+ * @fdt: base device tree blob
+ * @target_node: Target node offset in the base device tree blob containing
+ * the exported symbols used for the resolution.
+ * @importsym_name: Import symbol name
+ * @importsym_compatible: Import symbol compatible string
+ *
+ * returns:
+ * offset of the node matching the symbol after the resolution on success.
+ * Negative error code on failure.
+ */
+static int fdt_resolve_import(const void *fdt, int target_node,
+ const char *importsym_name,
+ const char *importsym_compatible)
+{
+ /*
+ * Do not check the import symbol compatible string against the found
+ * node. Indeed, the found node can be a node without any compatible
+ * string and this is perfectly legit.
+ *
+ * The purpose of the import symbol compatible string is to give
+ * information related to the symbol imported.
+ *
+ * This can be use by a driver when it wants to dynamically resolve
+ * imported symbols based on some specific criteria. In that case, the
+ * compatible string helps the driver to identify the kind of symbol
+ * expected by the addon.
+ *
+ * Here, in libfdt, no driver are available to perform this dynamic
+ * resolution. Resolve the symbol using only its name.
+ */
+ return fdt_resolve_symbol(fdt, target_node, importsym_name,
+ strlen(importsym_name));
+}
+
+static int fdt_check_importsym_offset(const void *fdt, int offset)
+{
+ int nextoffset;
+ uint32_t tag;
+
+ tag = fdt_next_tag_full(fdt, offset, &nextoffset);
+ if (tag != FDT_IMPORT_SYM)
+ return -FDT_ERR_BADOFFSET;
+ return nextoffset;
+}
+
+static int fdt_next_importsym_nextoffset_(const void *fdt, int nextoffset)
+{
+ uint32_t tag;
+ int offset;
+
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag_full(fdt, offset, &nextoffset);
+
+ switch (tag) {
+ case FDT_IMPORT_SYM:
+ return offset;
+
+ case FDT_END:
+ if (nextoffset < 0)
+ return nextoffset;
+
+ return -FDT_ERR_NOTFOUND;
+ }
+ } while (tag != FDT_IMPORT_SYM);
+
+ return offset;
+}
+
+static int fdt_next_importsym_offset(const void *fdt, int offset)
+{
+ int nextoffset;
+
+ if (offset < 0)
+ return offset;
+
+ nextoffset = fdt_check_importsym_offset(fdt, offset);
+ if (nextoffset < 0)
+ return nextoffset;
+
+ return fdt_next_importsym_nextoffset_(fdt, nextoffset);
+}
+
+static int fdt_first_importsym_offset(const void *fdt)
+{
+ return fdt_next_importsym_nextoffset_(fdt, 0);
+}
+
+
+static const char *fdt_importsym_get_name(const void *fdt, int offset)
+{
+ if (fdt_check_importsym_offset(fdt, offset) < 0)
+ return NULL;
+
+ return fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, 1);
+}
+
+static const char *fdt_importsym_get_compatible(const void *fdt, int offset)
+{
+ if (fdt_check_importsym_offset(fdt, offset) < 0)
+ return NULL;
+
+ /* Skip name */
+ offset += FDT_TAGSIZE;
+ offset = FDT_CELLALIGN(fdt_skip_string(fdt, offset));
+
+ return fdt_offset_ptr(fdt, offset, 1);
+}
+
+#define fdt_for_each_importsym(importsym, fdt) \
+ for (importsym = fdt_first_importsym_offset(fdt); \
+ importsym >= 0; \
+ importsym = fdt_next_importsym_offset(fdt, importsym))
+
+/**
+ * addon_resolve_symbol - Resolve a symbol from an addon
+ * @fdta: Addon device tree blob.
+ * @fdt: base device tree blob
+ * @target_node: Target node the addon is applied to. This node, in the base
+ * device tree blob, must have exported symbols needed for the
+ * resolution.
+ * @sym_name: Symbol name
+ * @sym_namelen: Length of the symbol name
+ *
+ * addon_resolve_symbol() resolved a symbol used by an addon using the import
+ * symbol table available in the addon device tree blob.
+ *
+ * returns:
+ * offset (in the fdt device tree blob) of the node matching the symbol
+ * after the resolution on success.
+ * Negative error code on failure.
+ */
+static int addon_resolve_symbol(const void *fdta, const void *fdt, int target_node,
+ const char *sym_name, int sym_namelen)
+{
+ const char *importsym_compat;
+ const char *importsym_name;
+ int importsym;
+
+ /* Look at imported symbols */
+ fdt_for_each_importsym(importsym, fdta) {
+ importsym_name = fdt_importsym_get_name(fdta, importsym);
+ if (!importsym_name)
+ return -FDT_ERR_BADSTRUCTURE;
+ importsym_compat = fdt_importsym_get_compatible(fdta, importsym);
+ if (!importsym_compat)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ if ((strlen(importsym_name) != sym_namelen) ||
+ (memcmp(importsym_name, sym_name, sym_namelen) != 0))
+ continue;
+
+ return fdt_resolve_import(fdt, target_node, importsym_name,
+ importsym_compat);
+ }
+ /* Not found ... */
+ return -FDT_ERR_NOTFOUND;
+}
+
+/**
+ * addon_resolve_ref - Resolve a reference from an addon
+ * @fdta: Addon device tree blob.
+ * @fdt: base device tree blob
+ * @target_node: Target node the addon is applied to. This node, in the base
+ * device tree blob, must have exported symbols needed for the
+ * resolution.
+ * @ref: The reference to resolve
+ *
+ * addon_resolve_ref() resolves a reference used by an addon.
+ * A reference can be composed of several symbols separated by a '.' char.
+ * For instance "foo.bar.baz". To resolve this reference, addon_resolve_ref()
+ * resolves the "foo" symbol the based on node retrieve from this resolution,
+ * it resolves "bar" and so on up to the last symbol available on the reference.
+ *
+ * This last symbol resolution leads to the node offset returned by
+ * addon_resolve_ref().
+ *
+ * returns:
+ * offset (in the fdt device tree blob) of the node matching the reference
+ * after the resolution on success.
+ * Negative error code on failure.
+ */
+static int addon_resolve_ref(const void *fdta, const void *fdt, int target_node,
+ const char *ref)
+{
+ const char *end = ref + strlen(ref);
+ const char *r = ref;
+ const char *d;
+ int tmp_node;
+
+ /*
+ * A reference can be "foo.bar.baz" for instance.
+ * In that case, we need to resolve foo from the target_node exported
+ * symbols then bar from exported symbols defined in the node retrieve
+ * from foo resolution and so on to resolve the given reference.
+ *
+ * The first symbol (foo in the previous example reference) need to be
+ * resolved through import symbols to "jump" from the addon to the base
+ * device tree. The other ones are "jumps" in the base device tree
+ * without leaving it and so, import symbols are not involved for them.
+ */
+ tmp_node = target_node;
+ while (r < end) {
+ d = memchr(r, '.', end - r);
+ if (!d)
+ d = end;
+
+ if (r == ref)
+ tmp_node = addon_resolve_symbol(fdta, fdt, tmp_node, r, d-r);
+ else
+ tmp_node = fdt_resolve_symbol(fdt, tmp_node, r, d-r);
+
+ if (tmp_node < 0)
+ return tmp_node;
+
+ r = d + 1;
+ }
+
+ return tmp_node;
+}
+
+/**
+ * addon_resolve_phandles - Resolve addon external references
+ * @fdta: Addon device tree blob
+ * @fdt: Device tree blob the addon is going to be applied to
+ * @target_node: Offset of the node in fdt the addon is going to be applied to
+ *
+ * addon_resolve_phandles() resolved unresolved phandle symbols available in
+ * the addon.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int addon_resolve_phandles(void *fdta, const void *fdt, int target_node)
+{
+ int last_prop_offset, prop_phandle_offset;
+ int offset, next_offset;
+ const fdt32_t *pfdt32;
+ uint32_t phandle;
+ fdt32_t *pfdt32w;
+ const char *ref;
+ uint32_t tag;
+ int ref_node;
+ int ret;
+
+ /*
+ * phandles symbols that need to be resolved are:
+ * - reference in properties where a FDT_REF_PHANDLE tag is available
+ * - reference in export symbols
+ */
+
+ next_offset = 0;
+ do {
+ offset = next_offset;
+ tag = fdt_next_tag_full(fdta, offset, &next_offset);
+ switch (tag) {
+ case FDT_BEGIN_NODE:
+ break;
+
+ case FDT_END_NODE:
+ break;
+
+ case FDT_PROP:
+ last_prop_offset = offset;
+ break;
+
+ case FDT_NOP:
+ break;
+
+ case FDT_REF_LOCAL:
+ break;
+
+ case FDT_REF_PHANDLE:
+ /*
+ * A property references an unresolver phandle. Get
+ * the offset of this phandle in the property data area
+ * and the reference of the phandle
+ */
+ offset += FDT_TAGSIZE;
+ pfdt32 = fdt_offset_ptr(fdta, offset, sizeof(*pfdt32));
+ prop_phandle_offset = fdt32_to_cpu(*pfdt32);
+
+ offset += sizeof(*pfdt32);
+ ref = fdt_offset_ptr(fdta, offset, 1);
+
+ /* Resolve this phandle */
+ ref_node = addon_resolve_ref(fdta, fdt, target_node, ref);
+ if (ref_node < 0)
+ return ref_node;
+
+ phandle = fdt_get_phandle(fdt, ref_node);
+ if ((phandle == 0) || (phandle == ~0U))
+ return -FDT_ERR_BADPHANDLE;
+
+ /* Update property value */
+ ret = addon_property_set_val(fdta, last_prop_offset,
+ prop_phandle_offset,
+ phandle);
+ if (ret)
+ return ret;
+
+ break;
+
+ case FDT_BEGIN_NODE_REF:
+ break;
+
+ case FDT_END:
+ ret = (next_offset < 0) ? next_offset : 0;
+ break;
+
+ case FDT_EXPORT_SYM:
+ break;
+
+ case FDT_EXPORT_SYM_REF:
+ /*
+ * The export symbol references an unresolver phandle.
+ * Get the offset of this phandle and the reference of
+ * the phandle
+ */
+
+ /* Skip name */
+ offset += FDT_TAGSIZE;
+ offset = FDT_CELLALIGN(fdt_skip_string(fdta, offset));
+
+ /* Get pointer to the phandle */
+ pfdt32w = fdt_offset_ptr_w(fdta, offset, sizeof(*pfdt32w));
+ offset += sizeof(*pfdt32w);
+
+ /* Get the reference */
+ ref = fdt_offset_ptr(fdta, offset, 1);
+
+ /* Resolve the phandle */
+ ref_node = addon_resolve_ref(fdta, fdt, target_node, ref);
+ if (ref_node < 0)
+ return ref_node;
+
+ phandle = fdt_get_phandle(fdt, ref_node);
+ if ((phandle == 0) || (phandle == ~0U))
+ return -FDT_ERR_BADPHANDLE;
+
+ /* Update the FDT_EXPORT_SYM_REF phandle value */
+ fdt32_st(pfdt32w, phandle);
+ break;
+
+ case FDT_IMPORT_SYM:
+ break;
+
+ default:
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+ } while (tag != FDT_END);
+
+ return ret;
+}
+
+/**
+ * addon_replace_local_phandles - Replace the old value of phandles by a new one
+ * for a whole addon
+ * @fdta: Device tree addon blob
+ * @old_phandle: Old phandle value
+ * @new_phandle: New phandle value
+ *
+ * addon_replace_local_phandles() replaces phandle values only if the
+ * old_phandle_value matches the current phandle value.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int addon_replace_local_phandles(void *fdta, uint32_t old_phandle,
+ uint32_t new_phandle)
+{
+ int last_prop_offset, prop_phandle_offset;
+ int offset, next_offset;
+ const fdt32_t *pfdt32;
+ fdt32_t *pfdt32w;
+ uint32_t tag;
+ uint32_t val;
+ int ret;
+
+ /*
+ * phandles that need to be updated are:
+ * - phandles in properties where a FDT_REF_LOCAL tag is available
+ * - phandles in FDT_EXPORT_SYM tags
+ *
+ * phandles properties in nodes are replace by
+ * addon_prevent_phandle_overwrite_node()
+ */
+
+ next_offset = 0;
+ do {
+ offset = next_offset;
+ tag = fdt_next_tag_full(fdta, offset, &next_offset);
+ switch (tag) {
+ case FDT_BEGIN_NODE:
+ /*
+ * "phandle" and/of "linux,phandle" properties are
+ * already updated by addon_prevent_phandle_overwrite_node()
+ * Nothing more to update here.
+ */
+ break;
+
+ case FDT_END_NODE:
+ break;
+
+ case FDT_PROP:
+ last_prop_offset = offset;
+ break;
+
+ case FDT_NOP:
+ break;
+
+ case FDT_REF_LOCAL:
+ /*
+ * The property references a phandle. Get the offset
+ * of this phandle in the property data area.
+ */
+ pfdt32 = fdt_offset_ptr(fdta, offset + FDT_TAGSIZE, sizeof(*pfdt32));
+ prop_phandle_offset = fdt32_to_cpu(*pfdt32);
+
+ /* Update the phandle value */
+ ret = addon_property_replace(fdta, last_prop_offset,
+ prop_phandle_offset,
+ old_phandle, new_phandle);
+ if (ret)
+ return ret;
+ break;
+
+ case FDT_REF_PHANDLE:
+ break;
+
+ case FDT_BEGIN_NODE_REF:
+ break;
+
+ case FDT_END:
+ ret = (next_offset < 0) ? next_offset : 0;
+ break;
+
+ case FDT_EXPORT_SYM:
+ /* Skip name */
+ offset += FDT_TAGSIZE;
+ offset = FDT_CELLALIGN(fdt_skip_string(fdta, offset));
+
+ /* Get phandle pointer */
+ pfdt32w = fdt_offset_ptr_w(fdta, offset, sizeof(*pfdt32));
+
+ /* Update the phandle value */
+ val = fdt32_ld(pfdt32w);
+ if (val == old_phandle)
+ fdt32_st(pfdt32w, new_phandle);
+ break;
+
+ case FDT_EXPORT_SYM_REF:
+ break;
+ case FDT_IMPORT_SYM:
+ break;
+
+ default:
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+ } while (tag != FDT_END);
+
+ return ret;
+}
+
+/**
+ * addon_prevent_phandle_overwrite_node - Prevents phandle overwrite for a given
+ * addon node.
+ * @fdta: Addon Device tree blob
+ * @fdta_node: Node in fdta
+ * @fdt: Base device tree blob
+ * @fdt_node: Node in fdt that could be overwrite by the fdta_node
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int addon_prevent_phandle_overwrite_node(void *fdta, int fdta_node,
+ const void *fdt, int fdt_node)
+{
+ uint32_t fdta_phandle, fdt_phandle;
+ int fdta_child, fdt_child;
+ const char *name;
+ int ret;
+
+ fdta_phandle = fdt_get_phandle(fdta, fdta_node);
+ fdt_phandle = fdt_get_phandle(fdt, fdt_node);
+
+ if (fdta_phandle && fdt_phandle) {
+ ret = addon_phandle_set_val(fdta, fdta_node, "phandle", fdt_phandle);
+ if (ret && ret != -FDT_ERR_NOTFOUND)
+ return ret;
+
+ ret = addon_phandle_set_val(fdta, fdta_node, "linux,phandle", fdt_phandle);
+ if (ret && ret != -FDT_ERR_NOTFOUND)
+ return ret;
+
+ ret = addon_replace_local_phandles(fdta, fdta_phandle, fdt_phandle);
+ if (ret)
+ return ret;
+ }
+
+ fdt_for_each_subnode(fdta_child, fdta, fdta_node) {
+ name = fdt_get_name(fdta, fdta_child, NULL);
+ if (!name)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ fdt_child = fdt_subnode_offset(fdt, fdt_node, name);
+ if (fdt_child == -FDT_ERR_NOTFOUND) {
+ /*
+ * No further overwrites possible here as the addon node
+ * is new node.
+ */
+ continue;
+ }
+
+ ret = addon_prevent_phandle_overwrite_node(fdta, fdta_child,
+ fdt, fdt_child);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int fdt_check_orphan_offset(const void *fdt, int offset)
+{
+ int nextoffset;
+ uint32_t tag;
+
+ tag = fdt_next_tag_full(fdt, offset, &nextoffset);
+ if (tag != FDT_BEGIN_NODE_REF)
+ return -FDT_ERR_BADOFFSET;
+ return nextoffset;
+}
+
+static int fdt_next_orphan_offset(const void *fdt, int offset)
+{
+ int nextoffset = 0;
+ uint32_t tag;
+
+ if (offset < 0)
+ return offset;
+
+ if (offset != 0) {
+ nextoffset = fdt_check_orphan_offset(fdt, offset);
+ if (nextoffset < 0)
+ return nextoffset;
+ }
+
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag_full(fdt, offset, &nextoffset);
+
+ switch (tag) {
+ case FDT_BEGIN_NODE_REF:
+ return offset;
+
+ case FDT_END:
+ if (nextoffset < 0)
+ return nextoffset;
+
+ return -FDT_ERR_NOTFOUND;
+ }
+ } while (tag != FDT_BEGIN_NODE_REF);
+
+ return offset;
+}
+
+static const char *fdt_orphan_get_ref(const void *fdt, int offset)
+{
+ if (fdt_check_orphan_offset(fdt, offset) < 0)
+ return NULL;
+
+ return fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, 1);
+}
+
+#define fdt_for_each_orphan(orphan, fdt) \
+ for (orphan = fdt_next_orphan_offset(fdt, 0); \
+ orphan >= 0; \
+ orphan = fdt_next_orphan_offset(fdt, orphan))
+
+static int fdt_set_tag(void *fdt, int offset, uint32_t new_tag, uint32_t *old_tag)
+{
+ uint32_t oldtag;
+ fdt32_t *tagp;
+
+ tagp = fdt_offset_ptr_w(fdt, offset, FDT_TAGSIZE);
+ if (!tagp) {
+ if (old_tag)
+ *old_tag = FDT_END;
+ return -FDT_ERR_BADOFFSET;
+ }
+ oldtag = fdt32_to_cpu(*tagp);
+ *tagp = cpu_to_fdt32(new_tag);
+ if (old_tag)
+ *old_tag = oldtag;
+ return 0;
+}
+
+/**
+ * addon_prevent_phandles_overwrite - Fixes addon phandles to not overwrite base
+ * phandles
+ * @fdta Addon Device tree blob
+ * @fdt: Base Device Tree blob
+ * @target_node: Target node in the base device tree the addon is going to be
+ * applied to
+ *
+ * Checks recursively if applying fdta overwrites phandle values in the base
+ * fdt. When such a phandle is found, the fdta is changed to use the fdt's
+ * phandle value to not break references in the base.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int addon_prevent_phandles_overwrite(void *fdta, const void *fdt,
+ int target_node)
+{
+ int fdt_orphan_target;
+ const char *ref;
+ uint32_t oldtag;
+ int fdta_orphan;
+ int ret;
+ /*
+ * addon root node is going to applied at base target_node
+ * Check phandles overwrite with those nodes
+ */
+ ret = addon_prevent_phandle_overwrite_node(fdta, 0,
+ fdt, target_node);
+ if (ret < 0)
+ return ret;
+
+ fdt_for_each_orphan(fdta_orphan, fdta) {
+ ref = fdt_orphan_get_ref(fdta, fdta_orphan);
+ if (!ref)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ fdt_orphan_target = addon_resolve_ref(fdta, fdt, target_node, ref);
+ if (fdt_orphan_target < 0)
+ return fdt_orphan_target;
+
+ /* Force an orphan node to be considered as a standard node */
+ ret = fdt_set_tag(fdta, fdta_orphan, FDT_BEGIN_NODE, &oldtag);
+ if (ret)
+ return ret;
+
+ ret = addon_prevent_phandle_overwrite_node(fdta, fdta_orphan,
+ fdt, fdt_orphan_target);
+ /* Restore orphan node tag */
+ fdt_set_tag(fdta, fdta_orphan, oldtag, NULL);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int fdt_check_propmarker_offset(const void *fdt, int offset)
+{
+ int nextoffset;
+ uint32_t tag;
+
+ tag = fdt_next_tag_full(fdt, offset, &nextoffset);
+ if ((tag != FDT_REF_LOCAL) && (tag != FDT_REF_PHANDLE))
+ return -FDT_ERR_BADOFFSET;
+ return nextoffset;
+}
+
+static int fdt_next_propmarker_nextoffset_(const void *fdt, int nextoffset)
+{
+ uint32_t tag;
+ int offset;
+
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag_full(fdt, offset, &nextoffset);
+ switch (tag) {
+ case FDT_EXPORT_SYM:
+ /* We are going to leave the current property (enter an export symbol) */
+ return -FDT_ERR_NOTFOUND;
+
+ case FDT_EXPORT_SYM_REF:
+ /* We are going to leave the current property (enter an export symbol) */
+ return -FDT_ERR_NOTFOUND;
+
+ case FDT_BEGIN_NODE:
+ /* We are going to leave the current property (new sub-node) */
+ return -FDT_ERR_NOTFOUND;
+
+ case FDT_BEGIN_NODE_REF:
+ /* We cannot have a node ref inside an other node */
+ return -FDT_ERR_BADSTRUCTURE;
+
+ case FDT_END_NODE:
+ /* We are going to leave the current node (parent node) */
+ return -FDT_ERR_NOTFOUND;
+
+ case FDT_PROP:
+ /* We are going to leave the current property (enter a new property) */
+ return -FDT_ERR_NOTFOUND;
+
+ case FDT_REF_LOCAL:
+ return offset;
+
+ case FDT_REF_PHANDLE:
+ return offset;
+
+ case FDT_END:
+ if (nextoffset < 0)
+ return nextoffset;
+
+ return -FDT_ERR_NOTFOUND;
+ }
+ } while (tag != FDT_END);
+
+ return offset;
+}
+
+static int fdt_next_propmarker_offset(const void *fdt, int offset)
+{
+ int nextoffset;
+
+ if (offset < 0)
+ return offset;
+
+ nextoffset = fdt_check_propmarker_offset(fdt, offset);
+ if (nextoffset < 0)
+ return nextoffset;
+
+ return fdt_next_propmarker_nextoffset_(fdt, nextoffset);
+}
+
+static int fdt_check_prop_offset_full(const void *fdt, int prop_offset)
+{
+ int nextoffset;
+
+ nextoffset = fdt_check_prop_offset_(fdt, prop_offset);
+ if (nextoffset < 0)
+ return nextoffset;
+
+ /*
+ * We need the properties meta data.
+ * fdt_check_prop_offset_() uses fdt_next_tag() to check the property.
+ * fdt_next_tag() skipped meta data.
+ * Get potential meta data using an explicitly call to
+ * fdt_next_tag_full()
+ */
+ fdt_next_tag_full(fdt, prop_offset, &nextoffset);
+ return nextoffset;
+}
+
+
+static int fdt_first_propmarker_offset(const void *fdt, int prop_offset)
+{
+ int nextoffset;
+
+ if (prop_offset < 0)
+ return prop_offset;
+
+ nextoffset = fdt_check_prop_offset_full(fdt, prop_offset);
+ if (nextoffset < 0)
+ return nextoffset;
+
+ return fdt_next_propmarker_nextoffset_(fdt, nextoffset);
+
+}
+
+static int fdt_propmarker_is_ref_marker(const void *fdt, int offset)
+{
+ int nextoffset;
+ uint32_t tag;
+
+ /*
+ * Only property 'reference' marker are currently supported but well
+ * prevent some issue that would happen if some other markers are
+ * add in the future.
+ */
+
+ /* A propmarker reference has to be propmarker ... */
+ if (fdt_check_propmarker_offset(fdt, offset) < 0)
+ return 0;
+
+ /* ... and a 'reference' */
+ tag = fdt_next_tag_full(fdt, offset, &nextoffset);
+ if ((tag != FDT_REF_LOCAL) && (tag != FDT_REF_PHANDLE))
+ return 0;
+
+ return 1;
+}
+
+static uint32_t fdt_propmarker_ref_get_propoffset(const void *fdt, int offset)
+{
+ const fdt32_t *pfdt32;
+
+ if (fdt_check_propmarker_offset(fdt, offset) < 0)
+ return ~0U;
+
+ pfdt32 = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, sizeof(*pfdt32));
+ if (!pfdt32)
+ return ~0U;
+
+ return fdt32_ld_(pfdt32);
+}
+
+#define fdt_for_each_propmarker(propmarker, fdt, prop) \
+ for (propmarker = fdt_first_propmarker_offset(fdt, prop); \
+ propmarker >= 0; \
+ propmarker = fdt_next_propmarker_offset(fdt, propmarker))
+
+static int fdt_mark_property_ref_local(void *fdt, int fdt_property,
+ uint32_t propoffset)
+{
+ int propmarker;
+ uint32_t tmp;
+
+ fdt_for_each_propmarker(propmarker, fdt, fdt_property) {
+ tmp = fdt_propmarker_ref_get_propoffset(fdt, propmarker);
+ if (tmp == ~0U)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ if (tmp == propoffset)
+ return -FDT_ERR_EXISTS;
+ }
+
+ return fdt_mark_property_ref_local_(fdt, fdt_property, propoffset);
+}
+
+static int fdt_add_exportsym(void *fdt, int fdt_node,
+ const char *exportsym_name, uint32_t phandle)
+{
+ const char *tmp;
+ int exportsym;
+
+ fdt_for_each_propmarker(exportsym, fdt, fdt_node) {
+ tmp = fdt_exportsym_get_name(fdt, exportsym);
+ if (!tmp)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ if (!strcmp(tmp, exportsym_name))
+ return -FDT_ERR_EXISTS;
+ }
+
+ return fdt_add_exportsym_(fdt, fdt_node, exportsym_name, phandle);
+}
+
+/**
+ * addon_merge_node_properties - Merges properties available in an addon node
+ * into the base device tree node
+ * @fdta: Addon Device Tree blob
+ * @fdta_node: Addon node whose properties have to be merged
+ * @fdt: Base Device Tree blob
+ * @fdt_node: Base node the addon node properties have to be merged into
+ * @is_existing_node: True if the node was already existing in the base device
+ * tree blob.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int addon_merge_node_properties(const void *fdta, int fdta_node,
+ void *fdt, int fdt_node,
+ bool is_existing_node)
+{
+ uint32_t propoffset;
+ int fdta_property;
+ int fdt_property;
+ const char *name;
+ const void *prop;
+ int propmarker;
+ int prop_len;
+ int ret;
+
+ fdt_for_each_property_offset(fdta_property, fdta, fdta_node) {
+ prop = fdt_getprop_by_offset(fdta, fdta_property, &name,
+ &prop_len);
+ if (prop_len == -FDT_ERR_NOTFOUND)
+ return -FDT_ERR_INTERNAL;
+ if (prop_len < 0)
+ return prop_len;
+
+ if (is_existing_node) {
+ if (!strcmp(name, "phandle") ||
+ !strcmp(name, "linux,phandle")) {
+ /*
+ * phandles available in both addon and base dtb
+ * have the same values. This is ensured by
+ * previous operation related to phandle
+ * resolution done in addon_prevent_phandles_overwrite().
+ * Just skip the property merge.
+ */
+ continue;
+ }
+ /*
+ * It is not allowed to add or modify properties in
+ * existing nodes.
+ */
+ return -FDT_ERR_EXISTS;
+ }
+
+ ret = fdt_setprop(fdt, fdt_node, name, prop, prop_len);
+ if (ret)
+ return ret;
+
+ /* Retrieve the newly created fdt property offset */
+ fdt_property = fdt_getprop_offset(fdt, fdt_node, name);
+ if (fdt_property < 0)
+ return -FDT_ERR_INTERNAL;
+
+ fdt_for_each_propmarker(propmarker, fdta, fdta_property) {
+ if (!fdt_propmarker_is_ref_marker(fdta, propmarker))
+ continue;
+
+ propoffset = fdt_propmarker_ref_get_propoffset(fdta, propmarker);
+ /*
+ * Mark the property as a local phandle reference.
+ * Either it was already a local phandle reference in
+ * the addon or it was an external phandle reference in
+ * the addon and has been resolved.
+ * In all cases it is local in the merged device tree
+ * blob.
+ */
+ ret = fdt_mark_property_ref_local(fdt, fdt_property,
+ propoffset);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * addon_merge_node_exports - Merges exported symbols in an addon node
+ * into the base device tree node
+ * @fdta: Addon Device Tree blob
+ * @fdta_node: Addon node whose exported symbols have to be merged
+ * @fdt: Base Device Tree blob
+ * @fdt_node: Base node the addon node exported symbols have to be merged into
+ * @is_existing_node: True if the node was already existing in the base device
+ * tree blob.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int addon_merge_node_exports(const void *fdta, int fdta_node,
+ void *fdt, int fdt_node,
+ bool is_existing_node)
+{
+ const char *exportsym_name;
+ uint32_t phandle;
+ int exportsym;
+ int ret;
+
+ fdt_for_each_exportsym(exportsym, fdta, fdta_node) {
+ exportsym_name = fdt_exportsym_get_name(fdta, exportsym);
+ if (!exportsym_name)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ phandle = fdt_exportsym_get_phandle(fdta, exportsym);
+ if ((phandle == 0) || (phandle == ~0U))
+ return -FDT_ERR_BADPHANDLE;
+
+ if (is_existing_node) {
+ /*
+ * It is not allowed to add or modify export symbols in
+ * existing nodes.
+ */
+ return -FDT_ERR_EXISTS;
+ }
+
+ ret = fdt_add_exportsym(fdt, fdt_node, exportsym_name, phandle);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+
+/**
+ * addon_merge_node - Merges an addon node and its sub-nodes into the base
+ * device tree
+ * @fdta: Addon Device Tree blob
+ * @fdta_node: Addon node to be merged
+ * @fdt: Base Device Tree blob
+ * @fdt_node: Base node the addon node has to be merged into
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int addon_merge_node(const void *fdta, int fdta_node, void *fdt,
+ int fdt_node, bool is_existing_node)
+{
+ bool is_existing;
+ int fdta_subnode;
+ const char *name;
+ int fdt_subnode;
+ int ret;
+
+ ret = addon_merge_node_properties(fdta, fdta_node, fdt, fdt_node,
+ is_existing_node);
+ if (ret)
+ return ret;
+
+ ret = addon_merge_node_exports(fdta, fdta_node, fdt, fdt_node,
+ is_existing_node);
+ if (ret)
+ return ret;
+
+ fdt_for_each_subnode(fdta_subnode, fdta, fdta_node) {
+ name = fdt_get_name(fdta, fdta_subnode, NULL);
+
+ is_existing = false;
+ fdt_subnode = fdt_add_subnode(fdt, fdt_node, name);
+ if (fdt_subnode == -FDT_ERR_EXISTS) {
+ is_existing = true;
+ fdt_subnode = fdt_subnode_offset(fdt, fdt_node, name);
+ if (fdt_subnode == -FDT_ERR_NOTFOUND)
+ return -FDT_ERR_INTERNAL;
+ }
+
+ if (fdt_subnode < 0)
+ return fdt_subnode;
+
+ ret = addon_merge_node(fdta, fdta_subnode, fdt, fdt_subnode, is_existing);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int addon_merge(void *fdta, void *fdt, const char *target_path)
+{
+ int fdt_orphan_target;
+ int fdta_orphan;
+ const char *ref;
+ uint32_t oldtag;
+ int target_node;
+ int ret;
+
+ /* Get the target node from its path*/
+ target_node = fdt_path_offset(fdt, target_path);
+ if (target_node < 0)
+ return target_node;
+
+ /* Merge the addon root node into the base target_node */
+ ret = addon_merge_node(fdta, 0, fdt, target_node, true);
+ if (ret < 0)
+ return ret;
+
+ fdt_for_each_orphan(fdta_orphan, fdta) {
+ ref = fdt_orphan_get_ref(fdta, fdta_orphan);
+ if (!ref)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ fdt_orphan_target = addon_resolve_ref(fdta, fdt, target_node, ref);
+ if (fdt_orphan_target < 0)
+ return fdt_orphan_target;
+
+ /* Force an orphan node to be considered as a standard node */
+ ret = fdt_set_tag(fdta, fdta_orphan, FDT_BEGIN_NODE, &oldtag);
+ if (ret)
+ return ret;
+
+ ret = addon_merge_node(fdta, fdta_orphan, fdt, fdt_orphan_target, true);
+ /* Restore orphan node tag */
+ fdt_set_tag(fdta, fdta_orphan, oldtag, NULL);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * An orphan node has been merged. The merged node can be
+ * anywhere in the fdt. Depending on the location of the merged
+ * node in the fdt, the target node offset can be no longer
+ * valid.
+ *
+ * Reload the offset from the target path to have a valid value.
+ */
+ target_node = fdt_path_offset(fdt, target_path);
+ if (target_node < 0)
+ return target_node;
+ }
+
+ return 0;
+}
+
+int fdt_addon_apply(void *fdt, void *fdta, const char *target)
+{
+ int target_node;
+ uint32_t delta;
+ int ret;
+
+ FDT_RO_PROBE(fdt);
+ FDT_RO_PROBE(fdta);
+
+ ret = fdt_find_max_phandle(fdt, &delta);
+ if (ret)
+ goto err;
+
+ /* Increase all phandles in the fdta by delta */
+ ret = addon_adjust_local_phandles(fdta, delta);
+ if (ret)
+ goto err;
+
+ /* Get the target node */
+ ret = fdt_path_offset(fdt, target);
+ if (ret < 0)
+ goto err;
+
+ target_node = ret;
+
+ /* Resolve phandles */
+ ret = addon_resolve_phandles(fdta, fdt, target_node);
+ if (ret < 0)
+ goto err;
+
+ /* Don't overwrite phandles in fdt */
+ ret = addon_prevent_phandles_overwrite(fdta, fdt, target_node);
+ if (ret < 0)
+ goto err;
+
+ ret = addon_merge(fdta, fdt, target);
+ if (ret < 0)
+ goto err;
+
+ /* The addon has been damaged, erase its magic */
+ fdt_set_magic(fdta, ~0);
+
+ return 0;
+
+err:
+ /* The addon might have been damaged, erase its magic */
+ fdt_set_magic(fdta, ~0);
+
+ /* The base device tree might have been damaged, erase its magic */
+ fdt_set_magic(fdt, ~0);
+
+ return ret;
+}
diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c
index 1528b33..101faaa 100644
--- a/libfdt/fdt_rw.c
+++ b/libfdt/fdt_rw.c
@@ -337,6 +337,91 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name)
return fdt_splice_struct_(fdt, prop, proplen, 0);
}
+int fdt_mark_property_ref_local_(void *fdt, int fdt_property,
+ uint32_t propoffset)
+{
+ fdt32_t *markerp;
+ int nextoffset;
+ int err;
+
+ FDT_RW_PROBE(fdt);
+
+ nextoffset = fdt_check_prop_offset_(fdt, fdt_property);
+ if (nextoffset < 0)
+ return nextoffset;
+
+ /*
+ * We need the properties meta data.
+ * fdt_check_prop_offset_() uses fdt_next_tag() to check the property.
+ * fdt_next_tag() skipped meta data.
+ * Get the tag right after the property using an explicitly call to
+ * fdt_next_tag_full()
+ */
+ fdt_next_tag_full(fdt, fdt_property, &nextoffset);
+ if (nextoffset < 0)
+ return nextoffset;
+
+ markerp = fdt_offset_ptr_w_(fdt, nextoffset);
+
+ /* Insert the propmarker at next_offset */
+ err = fdt_splice_struct_(fdt, markerp, 0, FDT_TAGSIZE + FDT_CELLSIZE);
+ if (err)
+ return err;
+
+ *(markerp++) = cpu_to_fdt32(FDT_REF_LOCAL);
+ *markerp = cpu_to_fdt32(propoffset);
+
+ return 0;
+}
+
+int fdt_add_exportsym_(void *fdt, int nodeoffset, const char *name,
+ uint32_t phandle)
+{
+ int offset, nextoffset;
+ int namelen, exportlen;
+ uint32_t tag;
+ char *p;
+ int err;
+
+ FDT_RW_PROBE(fdt);
+
+ nextoffset = fdt_check_node_offset_(fdt, nodeoffset);
+ if (nextoffset < 0)
+ return nextoffset;
+
+ /*
+ * Try to place the new export tag after the node's properties (if any)
+ * get_next_tag() skipped meta data and so already present meta-data
+ * will be skipped.
+ * This is ok. The new export tag will be place after potential existing
+ * meta data.
+ */
+ tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
+ /* the fdt_check_node_offset_() should ensure this never hits */
+ if (!can_assume(LIBFDT_FLAWLESS) && (tag != FDT_BEGIN_NODE))
+ return -FDT_ERR_INTERNAL;
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+ } while ((tag == FDT_PROP) || (tag == FDT_NOP));
+
+ p = fdt_offset_ptr_w_(fdt, offset);
+ namelen = strlen(name);
+ exportlen = FDT_TAGSIZE + FDT_CELLALIGN(namelen+1) + FDT_CELLSIZE;
+
+ err = fdt_splice_struct_(fdt, p, 0, exportlen);
+ if (err)
+ return err;
+
+ *((fdt32_t *)p) = cpu_to_fdt32(FDT_EXPORT_SYM);
+ memset(p + FDT_TAGSIZE, 0, FDT_CELLALIGN(namelen+1));
+ memcpy(p + FDT_TAGSIZE, name, namelen);
+ p += exportlen - FDT_CELLSIZE;
+ *((fdt32_t *)p) = cpu_to_fdt32(phandle);
+
+ return 0;
+}
+
int fdt_add_subnode_namelen(void *fdt, int parentoffset,
const char *name, int namelen)
{
diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h
index 0c654b1..f278380 100644
--- a/libfdt/libfdt.h
+++ b/libfdt/libfdt.h
@@ -2543,6 +2543,38 @@ int fdt_overlay_apply(void *fdt, void *fdto);
int fdt_overlay_target_offset(const void *fdt, const void *fdto,
int fragment_offset, char const **pathp);
+/**
+ * fdt_addon_apply - Applies a DT addon on a base DT
+ * @fdt: pointer to the base device tree blob
+ * @fdta: pointer to the device tree addon blob
+ * @target: target node path
+ *
+ * fdt_addon_apply() will apply the given device tree addon on the given target
+ * node in base device tree.
+ *
+ * Expect the base device tree to be modified, even if the function
+ * returns an error.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there's not enough space in the base device tree
+ * -FDT_ERR_NOTFOUND, the overlay points to some nonexistent nodes or
+ * properties in the base DT
+ * -FDT_ERR_BADPHANDLE,
+ * -FDT_ERR_BADOVERLAY,
+ * -FDT_ERR_NOPHANDLES,
+ * -FDT_ERR_INTERNAL,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADOFFSET,
+ * -FDT_ERR_BADPATH,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_addon_apply(void *fdt, void *fdta, const char *target);
+
/**********************************************************************/
/* Debugging / informational functions */
/**********************************************************************/
diff --git a/libfdt/libfdt_internal.h b/libfdt/libfdt_internal.h
index 499e821..f35b506 100644
--- a/libfdt/libfdt_internal.h
+++ b/libfdt/libfdt_internal.h
@@ -25,6 +25,10 @@ int fdt_check_node_offset_(const void *fdt, int offset);
int fdt_check_prop_offset_(const void *fdt, int offset);
int fdt_getprop_offset(const void *fdt, int nodeoffset, const char *name);
+int fdt_mark_property_ref_local_(void *fdt, int fdt_property,
+ uint32_t propoffset);
+int fdt_add_exportsym_(void *fdt, int nodeoffset, const char *name,
+ uint32_t phandle);
const char *fdt_find_string_len_(const char *strtab, int tabsize, const char *s,
int s_len);
diff --git a/libfdt/meson.build b/libfdt/meson.build
index 68d4c1d..a6e875f 100644
--- a/libfdt/meson.build
+++ b/libfdt/meson.build
@@ -9,6 +9,7 @@ sources = files(
'fdt_check.c',
'fdt_empty_tree.c',
'fdt_overlay.c',
+ 'fdt_addon.c',
'fdt_ro.c',
'fdt_rw.c',
'fdt_strerror.c',
diff --git a/libfdt/version.lds b/libfdt/version.lds
index 7e2dde2..f83b2f9 100644
--- a/libfdt/version.lds
+++ b/libfdt/version.lds
@@ -83,6 +83,7 @@ LIBFDT_1.2 {
fdt_overlay_target_offset;
fdt_get_symbol;
fdt_get_symbol_namelen;
+ fdt_addon_apply;
local:
*;
};
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 71/77] Add fdtaddon tool to apply an addon
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (69 preceding siblings ...)
2026-01-12 14:20 ` [RFC PATCH 70/77] libfdt: Add support for applying an addon on a base device-tree blob Herve Codina
@ 2026-01-12 14:20 ` Herve Codina
2026-01-12 14:20 ` [RFC PATCH 72/77] tests: Add a first basic test for fdtaddon Herve Codina
` (8 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:20 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
libfdt has support for applying an addon on top of a base device-tree.
This is provided by the libfdt fdt_addon_apply() function.
The fdtaddon tool is command line tool which allows to apply addon dtb
file to a base device-tree dtb file. It relies on fdt_addon_apply().
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
Makefile | 5 ++
fdtaddon.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++++
meson.build | 2 +-
3 files changed, 203 insertions(+), 1 deletion(-)
create mode 100644 fdtaddon.c
diff --git a/Makefile b/Makefile
index 83d8220..1137cee 100644
--- a/Makefile
+++ b/Makefile
@@ -159,6 +159,7 @@ BIN += fdtdump
BIN += fdtget
BIN += fdtput
BIN += fdtoverlay
+BIN += fdtaddon
SCRIPTS = dtdiff
@@ -172,6 +173,7 @@ ifneq ($(MAKECMDGOALS),libfdt)
-include $(FDTGET_OBJS:%.o=%.d)
-include $(FDTPUT_OBJS:%.o=%.d)
-include $(FDTOVERLAY_OBJS:%.o=%.d)
+-include $(FDTADDON_OBJS:%.o=%.d)
endif
endif
@@ -255,6 +257,8 @@ fdtput: $(FDTPUT_OBJS) $(LIBFDT_dep)
fdtoverlay: $(FDTOVERLAY_OBJS) $(LIBFDT_dep)
+fdtaddon: $(FDTADDON_OBJS) $(LIBFDT_dep)
+
dist:
git archive --format=tar --prefix=dtc-$(dtc_version)/ HEAD \
> ../dtc-$(dtc_version).tar
@@ -295,6 +299,7 @@ TESTS_BIN += fdtput
TESTS_BIN += fdtget
TESTS_BIN += fdtdump
TESTS_BIN += fdtoverlay
+TESTS_BIN += fdtaddon
ifneq ($(MAKECMDGOALS),libfdt)
include tests/Makefile.tests
diff --git a/fdtaddon.c b/fdtaddon.c
new file mode 100644
index 0000000..c2fefa3
--- /dev/null
+++ b/fdtaddon.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2025 Bootlin. All rights reserved.
+ *
+ * Author:
+ * Herve Codina <herve.codina@bootlin.com>
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <libfdt.h>
+
+#include "util.h"
+
+/* Usage related data. */
+static const char usage_synopsis[] =
+ "apply an addon to a base blob\n"
+ " fdtaddon <options> <addon.dtba>";
+static const char usage_short_opts[] = "i:o:t:v" USAGE_COMMON_SHORT_OPTS;
+static const struct option usage_long_opts[] = {
+ { "input", required_argument, NULL, 'i' },
+ { "output", required_argument, NULL, 'o' },
+ { "target", required_argument, NULL, 't' },
+ { "verbose", no_argument, NULL, 'v' },
+ USAGE_COMMON_LONG_OPTS,
+};
+static const char *const usage_opts_help[] = { "Input base DT blob",
+ "Output DT blob", "Target node",
+ "Verbose messages",
+ USAGE_COMMON_OPTS_HELP };
+
+int verbose;
+
+static void *do_apply(void *base, const void *addon, const char *target)
+{
+ void *tmp_merged;
+ void *tmp_addon;
+ size_t max_merged_size;
+ int ret;
+
+ /*
+ * We take copies first, because a failed apply can trash
+ * both the base blob and the overlay.
+ */
+
+ /*
+ * The merged size should not be greater than the sum of the size of
+ * individual items.
+ */
+ max_merged_size = fdt_totalsize(base) + fdt_totalsize(addon);
+
+ tmp_merged = xmalloc(max_merged_size);
+ ret = fdt_open_into(base, tmp_merged, max_merged_size);
+ if (ret) {
+ fprintf(stderr,
+ "\nFailed to make temporary copy: %s\n",
+ fdt_strerror(ret));
+ goto fail;
+ }
+
+ tmp_addon = xmalloc(fdt_totalsize(addon));
+ memcpy(tmp_addon, addon, fdt_totalsize(addon));
+
+ if (!(fdt_dt_flags(tmp_addon) & FDT_FLAG_ADDON)) {
+ fprintf(stderr,
+ "\nAddon dtb is not an 'addon'\n");
+ goto fail;
+ }
+
+ ret = fdt_addon_apply(tmp_merged, tmp_addon, target);
+ if (ret) {
+ fprintf(stderr, "\nFailed to apply %s\n", fdt_strerror(ret));
+ goto fail;
+ }
+
+ free(tmp_addon);
+ return tmp_merged;
+
+fail:
+ free(tmp_merged);
+ free(tmp_addon);
+ return NULL;
+}
+
+static int do_fdtaddon(const char *input_filename, const char *output_filename,
+ const char *addon_filename, const char *target)
+{
+ void *base_blob = NULL;
+ void *addon_blob = NULL;
+ void *merged_blob = NULL;
+ size_t base_buflen;
+ size_t addon_buflen;
+ int ret = -1;
+
+ base_blob = utilfdt_read(input_filename, &base_buflen);
+ if (!base_blob) {
+ fprintf(stderr, "\nFailed to read '%s'\n", input_filename);
+ goto out_err;
+ }
+ if (fdt_totalsize(base_blob) > base_buflen) {
+ fprintf(stderr,
+ "\nBase blob is incomplete (%zu / %"PRIu32" bytes read)\n",
+ base_buflen, fdt_totalsize(base_blob));
+ goto out_err;
+ }
+
+ addon_blob = utilfdt_read(addon_filename, &addon_buflen);
+ if (!addon_blob) {
+ fprintf(stderr, "\nFailed to read '%s'\n", addon_filename);
+ goto out_err;
+ }
+ if (fdt_totalsize(addon_blob) > addon_buflen) {
+ fprintf(stderr,
+ "\nAddon blob is incomplete (%zu / %"PRIu32" bytes read)\n",
+ addon_buflen, fdt_totalsize(addon_blob));
+ goto out_err;
+ }
+
+ /* apply the addon */
+ merged_blob = do_apply(base_blob, addon_blob, target);
+ if (!merged_blob)
+ goto out_err;
+
+ fdt_pack(merged_blob);
+ ret = utilfdt_write(output_filename, merged_blob);
+ if (ret)
+ fprintf(stderr, "\nFailed to write '%s'\n", output_filename);
+
+out_err:
+ free(merged_blob);
+ free(addon_blob);
+ free(base_blob);
+
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ char *input_filename = NULL;
+ char *output_filename = NULL;
+ char *addon_filename = NULL;
+ const char *target = NULL;
+ int opt;
+
+ while ((opt = util_getopt_long()) != EOF) {
+ switch (opt) {
+ case_USAGE_COMMON_FLAGS
+
+ case 'i':
+ input_filename = optarg;
+ break;
+ case 'o':
+ output_filename = optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 't':
+ target = optarg;
+ break;
+ }
+ }
+
+ if (!input_filename)
+ usage("missing input file");
+
+ if (!output_filename)
+ usage("missing output file");
+
+ if (!target)
+ usage("missing target");
+
+ argv += optind;
+ argc -= optind;
+
+ if (argc != 1)
+ usage("missing addon file");
+
+ addon_filename = argv[0];
+
+ if (verbose) {
+ printf("input = %s\n", input_filename);
+ printf("output = %s\n", output_filename);
+ printf("addon = %s\n", addon_filename);
+ }
+
+ if (do_fdtaddon(input_filename, output_filename, addon_filename, target))
+ return 1;
+
+ return 0;
+}
diff --git a/meson.build b/meson.build
index 66b44e8..c108514 100644
--- a/meson.build
+++ b/meson.build
@@ -107,7 +107,7 @@ if get_option('tools') and not wheel_only
install: true,
)
- foreach e: ['fdtdump', 'fdtget', 'fdtput', 'fdtoverlay']
+ foreach e: ['fdtdump', 'fdtget', 'fdtput', 'fdtoverlay', 'fdtaddon']
dtc_tools += executable(e, files(e + '.c'), dependencies: util_dep, install: true)
endforeach
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 72/77] tests: Add a first basic test for fdtaddon
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (70 preceding siblings ...)
2026-01-12 14:20 ` [RFC PATCH 71/77] Add fdtaddon tool to apply an addon Herve Codina
@ 2026-01-12 14:20 ` Herve Codina
2026-01-12 14:20 ` [RFC PATCH 73/77] tests: fdtaddon: Add a basic test for addons using an orphan nodes Herve Codina
` (7 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:20 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The fdtaddon tests family goal is to test features related the
application of an addon to a base device tree.
This first basic test added in fdtaddon tests is related to the
application of a simple addon.
The terminology used in the test is the following:
- dts: A 'full' device tree source.
This can be either a base device tree or a merged device tree (i.e. a
base device tree where an addon has been applied to).
- dtb: A 'full' device tree blob
This can be either a dtb generated by dtc from a dts or the output of
the fdtaddon command.
- dtsa: An addon device tree source
A dts with the '/addon/' keyword.
- dtba: An addon device tree blob
This a device tree blob generated from a dtsa.
With this terminology in mind, the test pattern is the following:
- Generate the base tree dtb (fdtaddon_base.dtb)
- Check this generated dtb against expected contents
- Generate a dtba (xxx.dtba) from an input dtsa
- Check this generated dtba against expected contents
- Apply the dtba to the base tree dtb at node-a1 (xxx-merged1.dtb)
- Check this generated dtb against expected contents
- Generate a dts (xxx-merged1.dtb.dts) from the generated xxx-merged1.dtb
- Check this generated dts against expected contents
- Apply the dtba to the base tree dtb at node-a2 (xxx-merged2.dtb)
- Check this generated dtb against expected contents
- Generate a dts (xxx-merged2.dtb.dts) from the generated xxx-merged2.dtb
- Check this generated dts against expected contents
Even if only one basic addon dsta is currently provided in this tests
introduction, use a loop in order to ease future addition consisting in
testing other features based on more complex addon dtsa.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
tests/fdtaddon_base.dtb.expect | 24 ++++++++++
tests/fdtaddon_base.dts | 27 +++++++++++
tests/fdtaddon_basics1-merged1.dtb.dts.expect | 35 ++++++++++++++
tests/fdtaddon_basics1-merged1.dtb.expect | 27 +++++++++++
tests/fdtaddon_basics1-merged2.dtb.dts.expect | 35 ++++++++++++++
tests/fdtaddon_basics1-merged2.dtb.expect | 27 +++++++++++
tests/fdtaddon_basics1.dtba.expect | 8 ++++
tests/fdtaddon_basics1.dtsa | 13 ++++++
tests/meson.build | 3 +-
tests/run_tests.sh | 46 ++++++++++++++++++-
tests/testutils.sh | 1 +
11 files changed, 244 insertions(+), 2 deletions(-)
create mode 100644 tests/fdtaddon_base.dtb.expect
create mode 100644 tests/fdtaddon_base.dts
create mode 100644 tests/fdtaddon_basics1-merged1.dtb.dts.expect
create mode 100644 tests/fdtaddon_basics1-merged1.dtb.expect
create mode 100644 tests/fdtaddon_basics1-merged2.dtb.dts.expect
create mode 100644 tests/fdtaddon_basics1-merged2.dtb.expect
create mode 100644 tests/fdtaddon_basics1.dtba.expect
create mode 100644 tests/fdtaddon_basics1.dtsa
diff --git a/tests/fdtaddon_base.dtb.expect b/tests/fdtaddon_base.dtb.expect
new file mode 100644
index 0000000..eb8cd40
--- /dev/null
+++ b/tests/fdtaddon_base.dtb.expect
@@ -0,0 +1,24 @@
+/dts-v1/;
+
+/ {
+ base-node {
+ sub-node {
+ prop = <0x00000000>;
+ phandle = <0x00000002>;
+ };
+ };
+ somewhere {
+ node-a1 {
+ compatible = "abc,aaa";
+ phandle = <0x00000001>;
+ // [FDT_EXPORT_SYM] 'node_a' -> phandle 0x00000001
+ // [FDT_EXPORT_SYM] 'other' -> phandle 0x00000002
+ };
+ node-a2 {
+ compatible = "abc,aaa";
+ phandle = <0x00000003>;
+ // [FDT_EXPORT_SYM] 'node_a' -> phandle 0x00000003
+ // [FDT_EXPORT_SYM] 'other' -> phandle 0x00000002
+ };
+ };
+};
diff --git a/tests/fdtaddon_base.dts b/tests/fdtaddon_base.dts
new file mode 100644
index 0000000..3b00146
--- /dev/null
+++ b/tests/fdtaddon_base.dts
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+
+/ {
+ base-node {
+ other_a: sub-node {
+ prop = <0>;
+ };
+ };
+
+ somewhere {
+ node_a1: node-a1 {
+ compatible = "abc,aaa";
+ /export/ node_a: &node_a1;
+ /export/ other: &other_a;
+ };
+ node_a2: node-a2 {
+ compatible = "abc,aaa";
+ /export/ node_a: &node_a2;
+ /export/ other: &other_a;
+ };
+ };
+};
diff --git a/tests/fdtaddon_basics1-merged1.dtb.dts.expect b/tests/fdtaddon_basics1-merged1.dtb.dts.expect
new file mode 100644
index 0000000..927733c
--- /dev/null
+++ b/tests/fdtaddon_basics1-merged1.dtb.dts.expect
@@ -0,0 +1,35 @@
+/dts-v1/;
+
+/ {
+
+ base-node {
+
+ sub-node {
+ prop = <0x00>;
+ phandle = <0x02>;
+ };
+ };
+
+ somewhere {
+
+ node-a1 {
+ compatible = "abc,aaa";
+ phandle = <0x01>;
+
+ /export/ node_a: &{/somewhere/node-a1};
+ /export/ other: &{/base-node/sub-node};
+
+ addon-node {
+ prop = <0x00>;
+ };
+ };
+
+ node-a2 {
+ compatible = "abc,aaa";
+ phandle = <0x03>;
+
+ /export/ node_a: &{/somewhere/node-a2};
+ /export/ other: &{/base-node/sub-node};
+ };
+ };
+};
diff --git a/tests/fdtaddon_basics1-merged1.dtb.expect b/tests/fdtaddon_basics1-merged1.dtb.expect
new file mode 100644
index 0000000..bee1397
--- /dev/null
+++ b/tests/fdtaddon_basics1-merged1.dtb.expect
@@ -0,0 +1,27 @@
+/dts-v1/;
+
+/ {
+ base-node {
+ sub-node {
+ prop = <0x00000000>;
+ phandle = <0x00000002>;
+ };
+ };
+ somewhere {
+ node-a1 {
+ compatible = "abc,aaa";
+ phandle = <0x00000001>;
+ // [FDT_EXPORT_SYM] 'node_a' -> phandle 0x00000001
+ // [FDT_EXPORT_SYM] 'other' -> phandle 0x00000002
+ addon-node {
+ prop = <0x00000000>;
+ };
+ };
+ node-a2 {
+ compatible = "abc,aaa";
+ phandle = <0x00000003>;
+ // [FDT_EXPORT_SYM] 'node_a' -> phandle 0x00000003
+ // [FDT_EXPORT_SYM] 'other' -> phandle 0x00000002
+ };
+ };
+};
diff --git a/tests/fdtaddon_basics1-merged2.dtb.dts.expect b/tests/fdtaddon_basics1-merged2.dtb.dts.expect
new file mode 100644
index 0000000..d85567b
--- /dev/null
+++ b/tests/fdtaddon_basics1-merged2.dtb.dts.expect
@@ -0,0 +1,35 @@
+/dts-v1/;
+
+/ {
+
+ base-node {
+
+ sub-node {
+ prop = <0x00>;
+ phandle = <0x02>;
+ };
+ };
+
+ somewhere {
+
+ node-a1 {
+ compatible = "abc,aaa";
+ phandle = <0x01>;
+
+ /export/ node_a: &{/somewhere/node-a1};
+ /export/ other: &{/base-node/sub-node};
+ };
+
+ node-a2 {
+ compatible = "abc,aaa";
+ phandle = <0x03>;
+
+ /export/ node_a: &{/somewhere/node-a2};
+ /export/ other: &{/base-node/sub-node};
+
+ addon-node {
+ prop = <0x00>;
+ };
+ };
+ };
+};
diff --git a/tests/fdtaddon_basics1-merged2.dtb.expect b/tests/fdtaddon_basics1-merged2.dtb.expect
new file mode 100644
index 0000000..34a4b36
--- /dev/null
+++ b/tests/fdtaddon_basics1-merged2.dtb.expect
@@ -0,0 +1,27 @@
+/dts-v1/;
+
+/ {
+ base-node {
+ sub-node {
+ prop = <0x00000000>;
+ phandle = <0x00000002>;
+ };
+ };
+ somewhere {
+ node-a1 {
+ compatible = "abc,aaa";
+ phandle = <0x00000001>;
+ // [FDT_EXPORT_SYM] 'node_a' -> phandle 0x00000001
+ // [FDT_EXPORT_SYM] 'other' -> phandle 0x00000002
+ };
+ node-a2 {
+ compatible = "abc,aaa";
+ phandle = <0x00000003>;
+ // [FDT_EXPORT_SYM] 'node_a' -> phandle 0x00000003
+ // [FDT_EXPORT_SYM] 'other' -> phandle 0x00000002
+ addon-node {
+ prop = <0x00000000>;
+ };
+ };
+ };
+};
diff --git a/tests/fdtaddon_basics1.dtba.expect b/tests/fdtaddon_basics1.dtba.expect
new file mode 100644
index 0000000..1102923
--- /dev/null
+++ b/tests/fdtaddon_basics1.dtba.expect
@@ -0,0 +1,8 @@
+/dts-v1/;
+/addon/;
+
+/ {
+ addon-node {
+ prop = <0x00000000>;
+ };
+};
diff --git a/tests/fdtaddon_basics1.dtsa b/tests/fdtaddon_basics1.dtsa
new file mode 100644
index 0000000..84621c9
--- /dev/null
+++ b/tests/fdtaddon_basics1.dtsa
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+/addon/;
+
+/ {
+ addon-node {
+ prop = <0>;
+ };
+};
diff --git a/tests/meson.build b/tests/meson.build
index e81a2e1..f0ae98a 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -141,7 +141,8 @@ run_test_types = [
'fdtput',
'fdtdump',
'fdtoverlay',
- 'metadata'
+ 'metadata',
+ 'fdtaddon'
]
run_test_deps = [
dtc_tools, dumptrees_dtb, tests_exe
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 4392752..32c40cf 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1168,6 +1168,47 @@ metadata_tests() {
base_run_test check_diff metadata_sort.dtb.dts "$SRCDIR/metadata_sort.dtb.dts.expect"
}
+run_fdtaddon_test () {
+ printf "fdtaddon $*: "
+ base_run_test wrap_test $VALGRIND $FDTADDON "$@"
+}
+
+check_dtb () {
+ local dtb="$1"
+ base_run_test wrap_fdtdump "$dtb" "$dtb.out"
+ sed -i '/^\/\/ [^\[]/d' "$dtb.out"
+ base_run_test check_diff "$dtb.out" "$SRCDIR/$dtb.expect"
+}
+
+check_dts () {
+ local dts="$1"
+ base_run_test check_diff "$dts" "$SRCDIR/$dts.expect"
+}
+
+fdtaddon_tests() {
+ run_dtc_test -I dts -O dtb -o fdtaddon_base.dtb "$SRCDIR/fdtaddon_base.dts"
+ check_dtb fdtaddon_base.dtb
+
+ for dt in fdtaddon_basics1; do
+ run_dtc_test -I dts -O dtb -o $dt.dtba "$SRCDIR/$dt.dtsa"
+ check_dtb $dt.dtba
+
+ run_fdtaddon_test -i fdtaddon_base.dtb -o $dt-merged1.dtb \
+ -t "/somewhere/node-a1" $dt.dtba
+ check_dtb $dt-merged1.dtb
+
+ run_dtc_test -I dtb -O dts -o $dt-merged1.dtb.dts $dt-merged1.dtb
+ check_dts $dt-merged1.dtb.dts
+
+ run_fdtaddon_test -i fdtaddon_base.dtb -o $dt-merged2.dtb \
+ -t "/somewhere/node-a2" $dt.dtba
+ check_dtb $dt-merged2.dtb
+
+ run_dtc_test -I dtb -O dts -o $dt-merged2.dtb.dts $dt-merged2.dtb
+ check_dts $dt-merged2.dtb.dts
+ done
+}
+
pylibfdt_tests () {
run_dtc_test -I dts -O dtb -o test_props.dtb "$SRCDIR/test_props.dts"
TMP=/tmp/tests.stderr.$$
@@ -1207,7 +1248,7 @@ while getopts "vt:me" ARG ; do
done
if [ -z "$TESTSETS" ]; then
- TESTSETS="libfdt utilfdt dtc dtbs_equal fdtget fdtput fdtdump fdtoverlay metadata"
+ TESTSETS="libfdt utilfdt dtc dtbs_equal fdtget fdtput fdtdump fdtoverlay metadata fdtaddon"
# Test pylibfdt if the libfdt Python module is available.
if ! $no_python; then
@@ -1250,6 +1291,9 @@ for set in $TESTSETS; do
"metadata")
metadata_tests
;;
+ "fdtaddon")
+ fdtaddon_tests
+ ;;
esac
done
diff --git a/tests/testutils.sh b/tests/testutils.sh
index 6b2f0d1..b5e121e 100644
--- a/tests/testutils.sh
+++ b/tests/testutils.sh
@@ -27,6 +27,7 @@ DTGET=${TEST_BINDIR}/fdtget
DTPUT=${TEST_BINDIR}/fdtput
FDTDUMP=${TEST_BINDIR}/fdtdump
FDTOVERLAY=${TEST_BINDIR}/fdtoverlay
+FDTADDON=${TEST_BINDIR}/fdtaddon
verbose_run () {
if [ -z "$QUIET_TEST" ]; then
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 73/77] tests: fdtaddon: Add a basic test for addons using an orphan nodes
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (71 preceding siblings ...)
2026-01-12 14:20 ` [RFC PATCH 72/77] tests: Add a first basic test for fdtaddon Herve Codina
@ 2026-01-12 14:20 ` Herve Codina
2026-01-12 14:20 ` [RFC PATCH 74/77] tests: fdtaddon: Add a basic test for addons with unresolved phandle references Herve Codina
` (6 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:20 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Orphan nodes are available in addons.
Add a test checking the application of an addon when orphan nodes are
involved.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
tests/fdtaddon_basics2-merged1.dtb.dts.expect | 35 +++++++++++++++++++
tests/fdtaddon_basics2-merged1.dtb.expect | 27 ++++++++++++++
tests/fdtaddon_basics2-merged2.dtb.dts.expect | 35 +++++++++++++++++++
tests/fdtaddon_basics2-merged2.dtb.expect | 27 ++++++++++++++
tests/fdtaddon_basics2.dtba.expect | 9 +++++
tests/fdtaddon_basics2.dtsa | 15 ++++++++
tests/run_tests.sh | 2 +-
7 files changed, 149 insertions(+), 1 deletion(-)
create mode 100644 tests/fdtaddon_basics2-merged1.dtb.dts.expect
create mode 100644 tests/fdtaddon_basics2-merged1.dtb.expect
create mode 100644 tests/fdtaddon_basics2-merged2.dtb.dts.expect
create mode 100644 tests/fdtaddon_basics2-merged2.dtb.expect
create mode 100644 tests/fdtaddon_basics2.dtba.expect
create mode 100644 tests/fdtaddon_basics2.dtsa
diff --git a/tests/fdtaddon_basics2-merged1.dtb.dts.expect b/tests/fdtaddon_basics2-merged1.dtb.dts.expect
new file mode 100644
index 0000000..927733c
--- /dev/null
+++ b/tests/fdtaddon_basics2-merged1.dtb.dts.expect
@@ -0,0 +1,35 @@
+/dts-v1/;
+
+/ {
+
+ base-node {
+
+ sub-node {
+ prop = <0x00>;
+ phandle = <0x02>;
+ };
+ };
+
+ somewhere {
+
+ node-a1 {
+ compatible = "abc,aaa";
+ phandle = <0x01>;
+
+ /export/ node_a: &{/somewhere/node-a1};
+ /export/ other: &{/base-node/sub-node};
+
+ addon-node {
+ prop = <0x00>;
+ };
+ };
+
+ node-a2 {
+ compatible = "abc,aaa";
+ phandle = <0x03>;
+
+ /export/ node_a: &{/somewhere/node-a2};
+ /export/ other: &{/base-node/sub-node};
+ };
+ };
+};
diff --git a/tests/fdtaddon_basics2-merged1.dtb.expect b/tests/fdtaddon_basics2-merged1.dtb.expect
new file mode 100644
index 0000000..bee1397
--- /dev/null
+++ b/tests/fdtaddon_basics2-merged1.dtb.expect
@@ -0,0 +1,27 @@
+/dts-v1/;
+
+/ {
+ base-node {
+ sub-node {
+ prop = <0x00000000>;
+ phandle = <0x00000002>;
+ };
+ };
+ somewhere {
+ node-a1 {
+ compatible = "abc,aaa";
+ phandle = <0x00000001>;
+ // [FDT_EXPORT_SYM] 'node_a' -> phandle 0x00000001
+ // [FDT_EXPORT_SYM] 'other' -> phandle 0x00000002
+ addon-node {
+ prop = <0x00000000>;
+ };
+ };
+ node-a2 {
+ compatible = "abc,aaa";
+ phandle = <0x00000003>;
+ // [FDT_EXPORT_SYM] 'node_a' -> phandle 0x00000003
+ // [FDT_EXPORT_SYM] 'other' -> phandle 0x00000002
+ };
+ };
+};
diff --git a/tests/fdtaddon_basics2-merged2.dtb.dts.expect b/tests/fdtaddon_basics2-merged2.dtb.dts.expect
new file mode 100644
index 0000000..d85567b
--- /dev/null
+++ b/tests/fdtaddon_basics2-merged2.dtb.dts.expect
@@ -0,0 +1,35 @@
+/dts-v1/;
+
+/ {
+
+ base-node {
+
+ sub-node {
+ prop = <0x00>;
+ phandle = <0x02>;
+ };
+ };
+
+ somewhere {
+
+ node-a1 {
+ compatible = "abc,aaa";
+ phandle = <0x01>;
+
+ /export/ node_a: &{/somewhere/node-a1};
+ /export/ other: &{/base-node/sub-node};
+ };
+
+ node-a2 {
+ compatible = "abc,aaa";
+ phandle = <0x03>;
+
+ /export/ node_a: &{/somewhere/node-a2};
+ /export/ other: &{/base-node/sub-node};
+
+ addon-node {
+ prop = <0x00>;
+ };
+ };
+ };
+};
diff --git a/tests/fdtaddon_basics2-merged2.dtb.expect b/tests/fdtaddon_basics2-merged2.dtb.expect
new file mode 100644
index 0000000..34a4b36
--- /dev/null
+++ b/tests/fdtaddon_basics2-merged2.dtb.expect
@@ -0,0 +1,27 @@
+/dts-v1/;
+
+/ {
+ base-node {
+ sub-node {
+ prop = <0x00000000>;
+ phandle = <0x00000002>;
+ };
+ };
+ somewhere {
+ node-a1 {
+ compatible = "abc,aaa";
+ phandle = <0x00000001>;
+ // [FDT_EXPORT_SYM] 'node_a' -> phandle 0x00000001
+ // [FDT_EXPORT_SYM] 'other' -> phandle 0x00000002
+ };
+ node-a2 {
+ compatible = "abc,aaa";
+ phandle = <0x00000003>;
+ // [FDT_EXPORT_SYM] 'node_a' -> phandle 0x00000003
+ // [FDT_EXPORT_SYM] 'other' -> phandle 0x00000002
+ addon-node {
+ prop = <0x00000000>;
+ };
+ };
+ };
+};
diff --git a/tests/fdtaddon_basics2.dtba.expect b/tests/fdtaddon_basics2.dtba.expect
new file mode 100644
index 0000000..ec1582e
--- /dev/null
+++ b/tests/fdtaddon_basics2.dtba.expect
@@ -0,0 +1,9 @@
+/dts-v1/;
+/addon/;
+
+// [FDT_IMPORT_SYM] 'node_a' (abc,aaa)
+&node_a {
+ addon-node {
+ prop = <0x00000000>;
+ };
+};
diff --git a/tests/fdtaddon_basics2.dtsa b/tests/fdtaddon_basics2.dtsa
new file mode 100644
index 0000000..0dc70af
--- /dev/null
+++ b/tests/fdtaddon_basics2.dtsa
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+/addon/;
+
+/import/ node_a: "abc,aaa";
+
+&node_a {
+ addon-node {
+ prop = <0>;
+ };
+};
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 32c40cf..d62496c 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1189,7 +1189,7 @@ fdtaddon_tests() {
run_dtc_test -I dts -O dtb -o fdtaddon_base.dtb "$SRCDIR/fdtaddon_base.dts"
check_dtb fdtaddon_base.dtb
- for dt in fdtaddon_basics1; do
+ for dt in fdtaddon_basics1 fdtaddon_basics2; do
run_dtc_test -I dts -O dtb -o $dt.dtba "$SRCDIR/$dt.dtsa"
check_dtb $dt.dtba
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 74/77] tests: fdtaddon: Add a basic test for addons with unresolved phandle references
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (72 preceding siblings ...)
2026-01-12 14:20 ` [RFC PATCH 73/77] tests: fdtaddon: Add a basic test for addons using an orphan nodes Herve Codina
@ 2026-01-12 14:20 ` Herve Codina
2026-01-12 14:20 ` [RFC PATCH 75/77] tests: fdtaddon: Add a test for addons using namespace label references Herve Codina
` (5 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:20 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Addons can have unresolved phandle references. Those references are
resolved when the addon is applied.
Add a basic test for this feature.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
tests/fdtaddon_basics3-merged1.dtb.dts.expect | 36 +++++++++++++++++++
tests/fdtaddon_basics3-merged1.dtb.expect | 29 +++++++++++++++
tests/fdtaddon_basics3-merged2.dtb.dts.expect | 36 +++++++++++++++++++
tests/fdtaddon_basics3-merged2.dtb.expect | 29 +++++++++++++++
tests/fdtaddon_basics3.dtba.expect | 12 +++++++
tests/fdtaddon_basics3.dtsa | 17 +++++++++
tests/run_tests.sh | 2 +-
7 files changed, 160 insertions(+), 1 deletion(-)
create mode 100644 tests/fdtaddon_basics3-merged1.dtb.dts.expect
create mode 100644 tests/fdtaddon_basics3-merged1.dtb.expect
create mode 100644 tests/fdtaddon_basics3-merged2.dtb.dts.expect
create mode 100644 tests/fdtaddon_basics3-merged2.dtb.expect
create mode 100644 tests/fdtaddon_basics3.dtba.expect
create mode 100644 tests/fdtaddon_basics3.dtsa
diff --git a/tests/fdtaddon_basics3-merged1.dtb.dts.expect b/tests/fdtaddon_basics3-merged1.dtb.dts.expect
new file mode 100644
index 0000000..c1bf3cc
--- /dev/null
+++ b/tests/fdtaddon_basics3-merged1.dtb.dts.expect
@@ -0,0 +1,36 @@
+/dts-v1/;
+
+/ {
+
+ base-node {
+
+ sub-node {
+ prop = <0x00>;
+ phandle = <0x02>;
+ };
+ };
+
+ somewhere {
+
+ node-a1 {
+ compatible = "abc,aaa";
+ phandle = <0x01>;
+
+ /export/ node_a: &{/somewhere/node-a1};
+ /export/ other: &{/base-node/sub-node};
+
+ addon-node {
+ ref-other = <&{/base-node/sub-node} 0x0a>;
+ prop = <0x00>;
+ };
+ };
+
+ node-a2 {
+ compatible = "abc,aaa";
+ phandle = <0x03>;
+
+ /export/ node_a: &{/somewhere/node-a2};
+ /export/ other: &{/base-node/sub-node};
+ };
+ };
+};
diff --git a/tests/fdtaddon_basics3-merged1.dtb.expect b/tests/fdtaddon_basics3-merged1.dtb.expect
new file mode 100644
index 0000000..cb2ab03
--- /dev/null
+++ b/tests/fdtaddon_basics3-merged1.dtb.expect
@@ -0,0 +1,29 @@
+/dts-v1/;
+
+/ {
+ base-node {
+ sub-node {
+ prop = <0x00000000>;
+ phandle = <0x00000002>;
+ };
+ };
+ somewhere {
+ node-a1 {
+ compatible = "abc,aaa";
+ phandle = <0x00000001>;
+ // [FDT_EXPORT_SYM] 'node_a' -> phandle 0x00000001
+ // [FDT_EXPORT_SYM] 'other' -> phandle 0x00000002
+ addon-node {
+ ref-other = <0x00000002 0x0000000a>;
+ // [FDT_REF_LOCAL] ref-other[0]
+ prop = <0x00000000>;
+ };
+ };
+ node-a2 {
+ compatible = "abc,aaa";
+ phandle = <0x00000003>;
+ // [FDT_EXPORT_SYM] 'node_a' -> phandle 0x00000003
+ // [FDT_EXPORT_SYM] 'other' -> phandle 0x00000002
+ };
+ };
+};
diff --git a/tests/fdtaddon_basics3-merged2.dtb.dts.expect b/tests/fdtaddon_basics3-merged2.dtb.dts.expect
new file mode 100644
index 0000000..8dc9fd2
--- /dev/null
+++ b/tests/fdtaddon_basics3-merged2.dtb.dts.expect
@@ -0,0 +1,36 @@
+/dts-v1/;
+
+/ {
+
+ base-node {
+
+ sub-node {
+ prop = <0x00>;
+ phandle = <0x02>;
+ };
+ };
+
+ somewhere {
+
+ node-a1 {
+ compatible = "abc,aaa";
+ phandle = <0x01>;
+
+ /export/ node_a: &{/somewhere/node-a1};
+ /export/ other: &{/base-node/sub-node};
+ };
+
+ node-a2 {
+ compatible = "abc,aaa";
+ phandle = <0x03>;
+
+ /export/ node_a: &{/somewhere/node-a2};
+ /export/ other: &{/base-node/sub-node};
+
+ addon-node {
+ ref-other = <&{/base-node/sub-node} 0x0a>;
+ prop = <0x00>;
+ };
+ };
+ };
+};
diff --git a/tests/fdtaddon_basics3-merged2.dtb.expect b/tests/fdtaddon_basics3-merged2.dtb.expect
new file mode 100644
index 0000000..0bc106e
--- /dev/null
+++ b/tests/fdtaddon_basics3-merged2.dtb.expect
@@ -0,0 +1,29 @@
+/dts-v1/;
+
+/ {
+ base-node {
+ sub-node {
+ prop = <0x00000000>;
+ phandle = <0x00000002>;
+ };
+ };
+ somewhere {
+ node-a1 {
+ compatible = "abc,aaa";
+ phandle = <0x00000001>;
+ // [FDT_EXPORT_SYM] 'node_a' -> phandle 0x00000001
+ // [FDT_EXPORT_SYM] 'other' -> phandle 0x00000002
+ };
+ node-a2 {
+ compatible = "abc,aaa";
+ phandle = <0x00000003>;
+ // [FDT_EXPORT_SYM] 'node_a' -> phandle 0x00000003
+ // [FDT_EXPORT_SYM] 'other' -> phandle 0x00000002
+ addon-node {
+ ref-other = <0x00000002 0x0000000a>;
+ // [FDT_REF_LOCAL] ref-other[0]
+ prop = <0x00000000>;
+ };
+ };
+ };
+};
diff --git a/tests/fdtaddon_basics3.dtba.expect b/tests/fdtaddon_basics3.dtba.expect
new file mode 100644
index 0000000..14dad9c
--- /dev/null
+++ b/tests/fdtaddon_basics3.dtba.expect
@@ -0,0 +1,12 @@
+/dts-v1/;
+/addon/;
+
+// [FDT_IMPORT_SYM] 'node_a' (abc,aaa)
+// [FDT_IMPORT_SYM] 'other' ()
+&node_a {
+ addon-node {
+ prop = <0x00000000>;
+ ref-other = <0xffffffff 0x0000000a>;
+ // [FDT_REF_PHANDLE] ref-other[0], ref = other
+ };
+};
diff --git a/tests/fdtaddon_basics3.dtsa b/tests/fdtaddon_basics3.dtsa
new file mode 100644
index 0000000..8658b45
--- /dev/null
+++ b/tests/fdtaddon_basics3.dtsa
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+/addon/;
+
+/import/ node_a: "abc,aaa";
+/import/ other: "";
+
+&node_a {
+ addon-node {
+ prop = <0>;
+ ref-other = <&other 10>;
+ };
+};
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index d62496c..65b1abe 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1189,7 +1189,7 @@ fdtaddon_tests() {
run_dtc_test -I dts -O dtb -o fdtaddon_base.dtb "$SRCDIR/fdtaddon_base.dts"
check_dtb fdtaddon_base.dtb
- for dt in fdtaddon_basics1 fdtaddon_basics2; do
+ for dt in fdtaddon_basics1 fdtaddon_basics2 fdtaddon_basics3; do
run_dtc_test -I dts -O dtb -o $dt.dtba "$SRCDIR/$dt.dtsa"
check_dtb $dt.dtba
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 75/77] tests: fdtaddon: Add a test for addons using namespace label references
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (73 preceding siblings ...)
2026-01-12 14:20 ` [RFC PATCH 74/77] tests: fdtaddon: Add a basic test for addons with unresolved phandle references Herve Codina
@ 2026-01-12 14:20 ` Herve Codina
2026-01-12 14:20 ` [RFC PATCH 76/77] tests: fdtaddon: Add a test for using 'stacked' addons Herve Codina
` (4 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:20 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Namespace label references are labels in the form &foo.bar.baz
Those kind of labels allow to 'jump' from node to node based on
exported symbols defined at each nodes.
Add a test for this feature.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
...ddon_addon_namespace-merged.dtb.dts.expect | 57 +++++++++++++++++++
...fdtaddon_addon_namespace-merged.dtb.expect | 49 ++++++++++++++++
tests/fdtaddon_addon_namespace.dtba.expect | 31 ++++++++++
tests/fdtaddon_addon_namespace.dtsa | 34 +++++++++++
tests/fdtaddon_base_namespace.dtb.expect | 29 ++++++++++
tests/fdtaddon_base_namespace.dts | 33 +++++++++++
tests/run_tests.sh | 14 +++++
7 files changed, 247 insertions(+)
create mode 100644 tests/fdtaddon_addon_namespace-merged.dtb.dts.expect
create mode 100644 tests/fdtaddon_addon_namespace-merged.dtb.expect
create mode 100644 tests/fdtaddon_addon_namespace.dtba.expect
create mode 100644 tests/fdtaddon_addon_namespace.dtsa
create mode 100644 tests/fdtaddon_base_namespace.dtb.expect
create mode 100644 tests/fdtaddon_base_namespace.dts
diff --git a/tests/fdtaddon_addon_namespace-merged.dtb.dts.expect b/tests/fdtaddon_addon_namespace-merged.dtb.dts.expect
new file mode 100644
index 0000000..ff0e5ff
--- /dev/null
+++ b/tests/fdtaddon_addon_namespace-merged.dtb.dts.expect
@@ -0,0 +1,57 @@
+/dts-v1/;
+
+/ {
+
+ other_n1 {
+ prop = <0x00>;
+ phandle = <0x05>;
+
+ /export/ a: &{/other-a};
+ /export/ b: &{/other-b};
+ };
+
+ other-a {
+ prop = <0x00>;
+ phandle = <0x01>;
+
+ addon-node-1a {
+ phandle = <0x06>;
+ prop = <0x1a>;
+ };
+ };
+
+ other-b {
+ prop = <0x00>;
+ phandle = <0x02>;
+
+ /export/ x: &{/other-x};
+ };
+
+ other-x {
+ prop = <0x00>;
+ phandle = <0x03>;
+
+ addon-node-1bx {
+ phandle = <0x07>;
+ prop = <0x1b>;
+ };
+ };
+
+ node {
+ compatible = "abc,aaa";
+ phandle = <0x04>;
+
+ /export/ node: &{/node};
+ /export/ n1: &{/other_n1};
+
+ addon-node2 {
+ ref-addon-n1bx = <&{/other-x/addon-node-1bx}>;
+ ref-n1bx = <&{/other-x}>;
+ };
+
+ addon-node1 {
+ ref-addon-n1a = <&{/other-a/addon-node-1a}>;
+ ref-n1a = <&{/other-a}>;
+ };
+ };
+};
diff --git a/tests/fdtaddon_addon_namespace-merged.dtb.expect b/tests/fdtaddon_addon_namespace-merged.dtb.expect
new file mode 100644
index 0000000..947a088
--- /dev/null
+++ b/tests/fdtaddon_addon_namespace-merged.dtb.expect
@@ -0,0 +1,49 @@
+/dts-v1/;
+
+/ {
+ other_n1 {
+ prop = <0x00000000>;
+ phandle = <0x00000005>;
+ // [FDT_EXPORT_SYM] 'a' -> phandle 0x00000001
+ // [FDT_EXPORT_SYM] 'b' -> phandle 0x00000002
+ };
+ other-a {
+ prop = <0x00000000>;
+ phandle = <0x00000001>;
+ addon-node-1a {
+ phandle = <0x00000006>;
+ prop = <0x0000001a>;
+ };
+ };
+ other-b {
+ prop = <0x00000000>;
+ phandle = <0x00000002>;
+ // [FDT_EXPORT_SYM] 'x' -> phandle 0x00000003
+ };
+ other-x {
+ prop = <0x00000000>;
+ phandle = <0x00000003>;
+ addon-node-1bx {
+ phandle = <0x00000007>;
+ prop = <0x0000001b>;
+ };
+ };
+ node {
+ compatible = "abc,aaa";
+ phandle = <0x00000004>;
+ // [FDT_EXPORT_SYM] 'node' -> phandle 0x00000004
+ // [FDT_EXPORT_SYM] 'n1' -> phandle 0x00000005
+ addon-node2 {
+ ref-addon-n1bx = <0x00000007>;
+ // [FDT_REF_LOCAL] ref-addon-n1bx[0]
+ ref-n1bx = <0x00000003>;
+ // [FDT_REF_LOCAL] ref-n1bx[0]
+ };
+ addon-node1 {
+ ref-addon-n1a = <0x00000006>;
+ // [FDT_REF_LOCAL] ref-addon-n1a[0]
+ ref-n1a = <0x00000001>;
+ // [FDT_REF_LOCAL] ref-n1a[0]
+ };
+ };
+};
diff --git a/tests/fdtaddon_addon_namespace.dtba.expect b/tests/fdtaddon_addon_namespace.dtba.expect
new file mode 100644
index 0000000..426bfe0
--- /dev/null
+++ b/tests/fdtaddon_addon_namespace.dtba.expect
@@ -0,0 +1,31 @@
+/dts-v1/;
+/addon/;
+
+// [FDT_IMPORT_SYM] 'node' (abc,aaa)
+// [FDT_IMPORT_SYM] 'n1' ()
+&node {
+ addon-node1 {
+ ref-n1a = <0xffffffff>;
+ // [FDT_REF_PHANDLE] ref-n1a[0], ref = n1.a
+ ref-addon-n1a = <0x00000001>;
+ // [FDT_REF_LOCAL] ref-addon-n1a[0]
+ };
+ addon-node2 {
+ ref-n1bx = <0xffffffff>;
+ // [FDT_REF_PHANDLE] ref-n1bx[0], ref = n1.b.x
+ ref-addon-n1bx = <0x00000002>;
+ // [FDT_REF_LOCAL] ref-addon-n1bx[0]
+ };
+};
+&n1.a {
+ addon-node-1a {
+ prop = <0x0000001a>;
+ phandle = <0x00000001>;
+ };
+};
+&n1.b.x {
+ addon-node-1bx {
+ prop = <0x0000001b>;
+ phandle = <0x00000002>;
+ };
+};
diff --git a/tests/fdtaddon_addon_namespace.dtsa b/tests/fdtaddon_addon_namespace.dtsa
new file mode 100644
index 0000000..8c25d3d
--- /dev/null
+++ b/tests/fdtaddon_addon_namespace.dtsa
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+/addon/;
+
+/import/ node: "abc,aaa";
+/import/ n1: "";
+
+&node {
+ addon-node1 {
+ ref-n1a = <&n1.a>;
+ ref-addon-n1a = <&addon_n1a>;
+ };
+
+ addon-node2 {
+ ref-n1bx = <&n1.b.x>;
+ ref-addon-n1bx = <&addon_n1bx>;
+ };
+};
+
+&n1.a {
+ addon_n1a: addon-node-1a {
+ prop = <0x1a>;
+ };
+};
+
+&n1.b.x {
+ addon_n1bx: addon-node-1bx {
+ prop = <0x1b>;
+ };
+};
diff --git a/tests/fdtaddon_base_namespace.dtb.expect b/tests/fdtaddon_base_namespace.dtb.expect
new file mode 100644
index 0000000..8383ab0
--- /dev/null
+++ b/tests/fdtaddon_base_namespace.dtb.expect
@@ -0,0 +1,29 @@
+/dts-v1/;
+
+/ {
+ other_n1 {
+ prop = <0x00000000>;
+ phandle = <0x00000005>;
+ // [FDT_EXPORT_SYM] 'a' -> phandle 0x00000001
+ // [FDT_EXPORT_SYM] 'b' -> phandle 0x00000002
+ };
+ other-a {
+ prop = <0x00000000>;
+ phandle = <0x00000001>;
+ };
+ other-b {
+ prop = <0x00000000>;
+ phandle = <0x00000002>;
+ // [FDT_EXPORT_SYM] 'x' -> phandle 0x00000003
+ };
+ other-x {
+ prop = <0x00000000>;
+ phandle = <0x00000003>;
+ };
+ node {
+ compatible = "abc,aaa";
+ phandle = <0x00000004>;
+ // [FDT_EXPORT_SYM] 'node' -> phandle 0x00000004
+ // [FDT_EXPORT_SYM] 'n1' -> phandle 0x00000005
+ };
+};
diff --git a/tests/fdtaddon_base_namespace.dts b/tests/fdtaddon_base_namespace.dts
new file mode 100644
index 0000000..e2bc4f0
--- /dev/null
+++ b/tests/fdtaddon_base_namespace.dts
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+
+/ {
+ n1: other_n1 {
+ prop = <0>;
+ /export/ a: &other_a;
+ /export/ b: &other_b;
+ };
+
+ other_a: other-a {
+ prop = <0>;
+ };
+
+ other_b: other-b {
+ prop = <0>;
+ /export/ x: &other_x;
+ };
+
+ other_x: other-x {
+ prop = <0>;
+ };
+
+ node: node {
+ compatible = "abc,aaa";
+ /export/ node: &node;
+ /export/ n1: &n1;
+ };
+};
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 65b1abe..2cdfd89 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1207,6 +1207,20 @@ fdtaddon_tests() {
run_dtc_test -I dtb -O dts -o $dt-merged2.dtb.dts $dt-merged2.dtb
check_dts $dt-merged2.dtb.dts
done
+
+ # Test namespace label reference
+ run_dtc_test -I dts -O dtb -o fdtaddon_base_namespace.dtb "$SRCDIR/fdtaddon_base_namespace.dts"
+ check_dtb fdtaddon_base_namespace.dtb
+
+ run_dtc_test -I dts -O dtb -o fdtaddon_addon_namespace.dtba "$SRCDIR/fdtaddon_addon_namespace.dtsa"
+ check_dtb fdtaddon_addon_namespace.dtba
+
+ run_fdtaddon_test -i fdtaddon_base_namespace.dtb -o fdtaddon_addon_namespace-merged.dtb \
+ -t "/node" fdtaddon_addon_namespace.dtba
+ check_dtb fdtaddon_addon_namespace-merged.dtb
+
+ run_dtc_test -I dtb -O dts -o fdtaddon_addon_namespace-merged.dtb.dts fdtaddon_addon_namespace-merged.dtb
+ check_dts fdtaddon_addon_namespace-merged.dtb.dts
}
pylibfdt_tests () {
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 76/77] tests: fdtaddon: Add a test for using 'stacked' addons
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (74 preceding siblings ...)
2026-01-12 14:20 ` [RFC PATCH 75/77] tests: fdtaddon: Add a test for addons using namespace label references Herve Codina
@ 2026-01-12 14:20 ` Herve Codina
2026-01-12 14:20 ` [RFC PATCH 77/77] tests: fdtaddon: Add a test using more realistic dts and dtsa Herve Codina
` (3 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:20 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Addon can be stacked on top of each other.
A first addon can be applied. This first addon exports some symbols and
those exported symbols can be used by a second addon.
Add a test for this feature.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
.../fdtaddon_stack_1st-merged.dtb.dts.expect | 51 ++++++++++++++
tests/fdtaddon_stack_1st-merged.dtb.expect | 41 +++++++++++
tests/fdtaddon_stack_1st.dtba.expect | 24 +++++++
tests/fdtaddon_stack_1st.dtsa | 27 +++++++
.../fdtaddon_stack_2nd-merged.dtb.dts.expect | 70 +++++++++++++++++++
tests/fdtaddon_stack_2nd-merged.dtb.expect | 59 ++++++++++++++++
tests/fdtaddon_stack_2nd.dtba.expect | 30 ++++++++
tests/fdtaddon_stack_2nd.dtsa | 35 ++++++++++
tests/run_tests.sh | 21 ++++++
9 files changed, 358 insertions(+)
create mode 100644 tests/fdtaddon_stack_1st-merged.dtb.dts.expect
create mode 100644 tests/fdtaddon_stack_1st-merged.dtb.expect
create mode 100644 tests/fdtaddon_stack_1st.dtba.expect
create mode 100644 tests/fdtaddon_stack_1st.dtsa
create mode 100644 tests/fdtaddon_stack_2nd-merged.dtb.dts.expect
create mode 100644 tests/fdtaddon_stack_2nd-merged.dtb.expect
create mode 100644 tests/fdtaddon_stack_2nd.dtba.expect
create mode 100644 tests/fdtaddon_stack_2nd.dtsa
diff --git a/tests/fdtaddon_stack_1st-merged.dtb.dts.expect b/tests/fdtaddon_stack_1st-merged.dtb.dts.expect
new file mode 100644
index 0000000..eb6ee30
--- /dev/null
+++ b/tests/fdtaddon_stack_1st-merged.dtb.dts.expect
@@ -0,0 +1,51 @@
+/dts-v1/;
+
+/ {
+
+ base-node {
+
+ sub-node {
+ prop = <0x00>;
+ phandle = <0x02>;
+ };
+ };
+
+ somewhere {
+
+ node-a1 {
+ compatible = "abc,aaa";
+ phandle = <0x01>;
+
+ /export/ node_a: &{/somewhere/node-a1};
+ /export/ other: &{/base-node/sub-node};
+
+ addon1-node {
+ ref-other = <&{/base-node/sub-node} 0x0a>;
+ prop = <0x00>;
+
+ sub-node-other {
+ phandle = <0x05>;
+ prop = <0x01>;
+ };
+
+ sub-node-stack1 {
+ phandle = <0x04>;
+ prop = <0x00>;
+ compatible = "abc,bbb";
+
+ /export/ stack: &{/somewhere/node-a1/addon1-node/sub-node-stack1};
+ /export/ other: &{/somewhere/node-a1/addon1-node/sub-node-other};
+ /export/ base_other: &{/base-node/sub-node};
+ };
+ };
+ };
+
+ node-a2 {
+ compatible = "abc,aaa";
+ phandle = <0x03>;
+
+ /export/ node_a: &{/somewhere/node-a2};
+ /export/ other: &{/base-node/sub-node};
+ };
+ };
+};
diff --git a/tests/fdtaddon_stack_1st-merged.dtb.expect b/tests/fdtaddon_stack_1st-merged.dtb.expect
new file mode 100644
index 0000000..332bb26
--- /dev/null
+++ b/tests/fdtaddon_stack_1st-merged.dtb.expect
@@ -0,0 +1,41 @@
+/dts-v1/;
+
+/ {
+ base-node {
+ sub-node {
+ prop = <0x00000000>;
+ phandle = <0x00000002>;
+ };
+ };
+ somewhere {
+ node-a1 {
+ compatible = "abc,aaa";
+ phandle = <0x00000001>;
+ // [FDT_EXPORT_SYM] 'node_a' -> phandle 0x00000001
+ // [FDT_EXPORT_SYM] 'other' -> phandle 0x00000002
+ addon1-node {
+ ref-other = <0x00000002 0x0000000a>;
+ // [FDT_REF_LOCAL] ref-other[0]
+ prop = <0x00000000>;
+ sub-node-other {
+ phandle = <0x00000005>;
+ prop = <0x00000001>;
+ };
+ sub-node-stack1 {
+ phandle = <0x00000004>;
+ prop = <0x00000000>;
+ compatible = "abc,bbb";
+ // [FDT_EXPORT_SYM] 'stack' -> phandle 0x00000004
+ // [FDT_EXPORT_SYM] 'other' -> phandle 0x00000005
+ // [FDT_EXPORT_SYM] 'base_other' -> phandle 0x00000002
+ };
+ };
+ };
+ node-a2 {
+ compatible = "abc,aaa";
+ phandle = <0x00000003>;
+ // [FDT_EXPORT_SYM] 'node_a' -> phandle 0x00000003
+ // [FDT_EXPORT_SYM] 'other' -> phandle 0x00000002
+ };
+ };
+};
diff --git a/tests/fdtaddon_stack_1st.dtba.expect b/tests/fdtaddon_stack_1st.dtba.expect
new file mode 100644
index 0000000..1e1ce57
--- /dev/null
+++ b/tests/fdtaddon_stack_1st.dtba.expect
@@ -0,0 +1,24 @@
+/dts-v1/;
+/addon/;
+
+// [FDT_IMPORT_SYM] 'node_a' (abc,aaa)
+// [FDT_IMPORT_SYM] 'other' ()
+&node_a {
+ addon1-node {
+ prop = <0x00000000>;
+ ref-other = <0xffffffff 0x0000000a>;
+ // [FDT_REF_PHANDLE] ref-other[0], ref = other
+ sub-node-stack1 {
+ compatible = "abc,bbb";
+ prop = <0x00000000>;
+ phandle = <0x00000001>;
+ // [FDT_EXPORT_SYM] 'stack' -> phandle 0x00000001
+ // [FDT_EXPORT_SYM] 'other' -> phandle 0x00000002
+ // [FDT_EXPORT_SYM_REF] 'base_other' -> 'other'
+ };
+ sub-node-other {
+ prop = <0x00000001>;
+ phandle = <0x00000002>;
+ };
+ };
+};
diff --git a/tests/fdtaddon_stack_1st.dtsa b/tests/fdtaddon_stack_1st.dtsa
new file mode 100644
index 0000000..5529dde
--- /dev/null
+++ b/tests/fdtaddon_stack_1st.dtsa
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+/addon/;
+
+/import/ node_a: "abc,aaa";
+/import/ other: "";
+
+&node_a {
+ addon1-node {
+ prop = <0>;
+ ref-other = <&other 10>;
+ stack1: sub-node-stack1 {
+ compatible = "abc,bbb";
+ prop = <0>;
+ /export/ stack: &stack1;
+ /export/ other: &new_other;
+ /export/ base_other: &other;
+ };
+ new_other: sub-node-other {
+ prop = <1>;
+ };
+ };
+};
diff --git a/tests/fdtaddon_stack_2nd-merged.dtb.dts.expect b/tests/fdtaddon_stack_2nd-merged.dtb.dts.expect
new file mode 100644
index 0000000..af31f05
--- /dev/null
+++ b/tests/fdtaddon_stack_2nd-merged.dtb.dts.expect
@@ -0,0 +1,70 @@
+/dts-v1/;
+
+/ {
+
+ base-node {
+
+ sub-node {
+ prop = <0x00>;
+ phandle = <0x02>;
+
+ addon2-node-base-other {
+ ref = <&{/somewhere/node-a1/addon1-node/sub-node-stack1/addon2-node}>;
+ prop = <0x01>;
+ };
+ };
+ };
+
+ somewhere {
+
+ node-a1 {
+ compatible = "abc,aaa";
+ phandle = <0x01>;
+
+ /export/ node_a: &{/somewhere/node-a1};
+ /export/ other: &{/base-node/sub-node};
+
+ addon1-node {
+ ref-other = <&{/base-node/sub-node} 0x0a>;
+ prop = <0x00>;
+
+ sub-node-other {
+ phandle = <0x05>;
+ prop = <0x01>;
+
+ addon2-node-other {
+ prop = <&{/base-node/sub-node}>;
+
+ addon2-subnode {
+ prop = <0x02>;
+ };
+ };
+ };
+
+ sub-node-stack1 {
+ phandle = <0x04>;
+ prop = <0x00>;
+ compatible = "abc,bbb";
+
+ /export/ stack: &{/somewhere/node-a1/addon1-node/sub-node-stack1};
+ /export/ other: &{/somewhere/node-a1/addon1-node/sub-node-other};
+ /export/ base_other: &{/base-node/sub-node};
+
+ addon2-node {
+ phandle = <0x06>;
+ ref-other = <&{/somewhere/node-a1/addon1-node/sub-node-other} 0x0a>;
+ prop = <0x00>;
+ };
+ };
+ };
+ };
+
+ node-a2 {
+ compatible = "abc,aaa";
+ phandle = <0x03>;
+
+ /export/ node_a: &{/somewhere/node-a2};
+ /export/ other: &{/base-node/sub-node};
+ };
+ };
+};
diff --git a/tests/fdtaddon_stack_2nd-merged.dtb.expect b/tests/fdtaddon_stack_2nd-merged.dtb.expect
new file mode 100644
index 0000000..ccae793
--- /dev/null
+++ b/tests/fdtaddon_stack_2nd-merged.dtb.expect
@@ -0,0 +1,59 @@
+/dts-v1/;
+
+/ {
+ base-node {
+ sub-node {
+ prop = <0x00000000>;
+ phandle = <0x00000002>;
+ addon2-node-base-other {
+ ref = <0x00000006>;
+ // [FDT_REF_LOCAL] ref[0]
+ prop = <0x00000001>;
+ };
+ };
+ };
+ somewhere {
+ node-a1 {
+ compatible = "abc,aaa";
+ phandle = <0x00000001>;
+ // [FDT_EXPORT_SYM] 'node_a' -> phandle 0x00000001
+ // [FDT_EXPORT_SYM] 'other' -> phandle 0x00000002
+ addon1-node {
+ ref-other = <0x00000002 0x0000000a>;
+ // [FDT_REF_LOCAL] ref-other[0]
+ prop = <0x00000000>;
+ sub-node-other {
+ phandle = <0x00000005>;
+ prop = <0x00000001>;
+ addon2-node-other {
+ prop = <0x00000002>;
+ // [FDT_REF_LOCAL] prop[0]
+ addon2-subnode {
+ prop = <0x00000002>;
+ };
+ };
+ };
+ sub-node-stack1 {
+ phandle = <0x00000004>;
+ prop = <0x00000000>;
+ compatible = "abc,bbb";
+ // [FDT_EXPORT_SYM] 'stack' -> phandle 0x00000004
+ // [FDT_EXPORT_SYM] 'other' -> phandle 0x00000005
+ // [FDT_EXPORT_SYM] 'base_other' -> phandle 0x00000002
+ addon2-node {
+ phandle = <0x00000006>;
+ ref-other = <0x00000005 0x0000000a>;
+ // [FDT_REF_LOCAL] ref-other[0]
+ prop = <0x00000000>;
+ };
+ };
+ };
+ };
+ node-a2 {
+ compatible = "abc,aaa";
+ phandle = <0x00000003>;
+ // [FDT_EXPORT_SYM] 'node_a' -> phandle 0x00000003
+ // [FDT_EXPORT_SYM] 'other' -> phandle 0x00000002
+ };
+ };
+};
diff --git a/tests/fdtaddon_stack_2nd.dtba.expect b/tests/fdtaddon_stack_2nd.dtba.expect
new file mode 100644
index 0000000..dbb8afa
--- /dev/null
+++ b/tests/fdtaddon_stack_2nd.dtba.expect
@@ -0,0 +1,30 @@
+/dts-v1/;
+/addon/;
+
+// [FDT_IMPORT_SYM] 'stack' (abc,bbb)
+// [FDT_IMPORT_SYM] 'other' ()
+// [FDT_IMPORT_SYM] 'base_other' ()
+&stack {
+ addon2-node {
+ prop = <0x00000000>;
+ ref-other = <0xffffffff 0x0000000a>;
+ // [FDT_REF_PHANDLE] ref-other[0], ref = other
+ phandle = <0x00000001>;
+ };
+};
+&other {
+ addon2-node-other {
+ prop = <0xffffffff>;
+ // [FDT_REF_PHANDLE] prop[0], ref = base_other
+ addon2-subnode {
+ prop = <0x00000002>;
+ };
+ };
+};
+&base_other {
+ addon2-node-base-other {
+ prop = <0x00000001>;
+ ref = <0x00000001>;
+ // [FDT_REF_LOCAL] ref[0]
+ };
+};
diff --git a/tests/fdtaddon_stack_2nd.dtsa b/tests/fdtaddon_stack_2nd.dtsa
new file mode 100644
index 0000000..21d80d2
--- /dev/null
+++ b/tests/fdtaddon_stack_2nd.dtsa
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+/addon/;
+
+/import/ stack: "abc,bbb";
+/import/ other: "";
+/import/ base_other: "";
+
+&stack {
+ addon2_node: addon2-node {
+ prop = <0>;
+ ref-other = <&other 10>;
+ };
+};
+
+&other {
+ addon2-node-other {
+ prop = <&base_other>;
+
+ addon2-subnode {
+ prop = <2>;
+ };
+ };
+};
+
+&base_other {
+ addon2-node-base-other {
+ prop = <1>;
+ ref = <&addon2_node>;
+ };
+};
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 2cdfd89..69ca39e 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1221,6 +1221,27 @@ fdtaddon_tests() {
run_dtc_test -I dtb -O dts -o fdtaddon_addon_namespace-merged.dtb.dts fdtaddon_addon_namespace-merged.dtb
check_dts fdtaddon_addon_namespace-merged.dtb.dts
+
+ # test stacked addons
+ run_dtc_test -I dts -O dtb -o fdtaddon_stack_1st.dtba "$SRCDIR/fdtaddon_stack_1st.dtsa"
+ check_dtb fdtaddon_stack_1st.dtba
+
+ run_fdtaddon_test -i fdtaddon_base.dtb -o fdtaddon_stack_1st-merged.dtb \
+ -t "/somewhere/node-a1" fdtaddon_stack_1st.dtba
+ check_dtb fdtaddon_stack_1st-merged.dtb
+
+ run_dtc_test -I dtb -O dts -o fdtaddon_stack_1st-merged.dtb.dts fdtaddon_stack_1st-merged.dtb
+ check_dts fdtaddon_stack_1st-merged.dtb.dts
+
+ run_dtc_test -I dts -O dtb -o fdtaddon_stack_2nd.dtba "$SRCDIR/fdtaddon_stack_2nd.dtsa"
+ check_dtb fdtaddon_stack_2nd.dtba
+
+ run_fdtaddon_test -i fdtaddon_stack_1st-merged.dtb -o fdtaddon_stack_2nd-merged.dtb \
+ -t "/somewhere/node-a1/addon1-node/sub-node-stack1" fdtaddon_stack_2nd.dtba
+ check_dtb fdtaddon_stack_2nd-merged.dtb
+
+ run_dtc_test -I dtb -O dts -o fdtaddon_stack_2nd-merged.dtb.dts fdtaddon_stack_2nd-merged.dtb
+ check_dts fdtaddon_stack_2nd-merged.dtb.dts
}
pylibfdt_tests () {
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* [RFC PATCH 77/77] tests: fdtaddon: Add a test using more realistic dts and dtsa
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (75 preceding siblings ...)
2026-01-12 14:20 ` [RFC PATCH 76/77] tests: fdtaddon: Add a test for using 'stacked' addons Herve Codina
@ 2026-01-12 14:20 ` Herve Codina
2026-01-12 14:49 ` [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Ayush Singh
` (2 subsequent siblings)
79 siblings, 0 replies; 160+ messages in thread
From: Herve Codina @ 2026-01-12 14:20 UTC (permalink / raw)
To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
The dts and dtsa files used in the fdtaddon tests were centered on
specific addon features in order to test those specific features.
In term of structure or naming, they are not representative of real
use-cases.
This new test uses realistic dts and dtsa files with naming and
structures tradidionally found in real cases.
The dts describes the hardware of the base board.
The hardware structure of the base board is the following:
+--------------+
| 5V regulator +-------+
+--------------+ |
|
+----------------------+ | +----------------+
| SOC | | | Connector A |
| | | | |
| +-----------------+ | +-------+ 5v |
| + i2c1 controller +---------------+ i2c bus |
| +-----------------+ | +-------+ gpio 0 / irq 0 |
| | | +---+ gpio 1 / irq 1 |
| +------------------+ | | | +----------------+
| | gpio1 controller | | | |
| | gpio #10 +------+ |
| +------------------+ | |
| | |
| +---------------- -+ | |
| | gpio2 controller | | |
| | gpio #3 +----------+
| +------------------+ |
+----------------------+
The connector 'Connector A' is the connector where the
pluggable board can be connected to. It is described in the dts and
related export symbols are set in order to be usable by the dtsa
describing the pluggable board.
The hardware structure of the pluggable board is the following:
+---------------+
| EEPROM |
| i2c addr 0x51 |
| +
+-------+ i2c |
| +---------------+
|
| +---------------+
| | Expander IO |
+----------------+ | | i2c addr 0x23 |
| Connector | | | |
| | | +---+ Vcc1 |
| 5v +---|---+---+ Vcc2 |
| i2c bus +---+-------+ i2c |
| gpio 0 / irq 0 +-----------+ irq |
| gpio 1 / irq 1 +-----------+ reset |
+----------------+ +---------------+
This structure is described in the addon dtsa. This addon dtsa is
expected to be applied to the base device tree node describing the
connector the pluggable board is connected to.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
...ddon_realistic_addon-merged.dtb.dts.expect | 91 ++++++++++++++++++
...fdtaddon_realistic_addon-merged.dtb.expect | 93 +++++++++++++++++++
tests/fdtaddon_realistic_addon.dtba.expect | 32 +++++++
tests/fdtaddon_realistic_addon.dtsa | 50 ++++++++++
tests/fdtaddon_realistic_base.dtb.expect | 72 ++++++++++++++
tests/fdtaddon_realistic_base.dts | 74 +++++++++++++++
tests/run_tests.sh | 14 +++
7 files changed, 426 insertions(+)
create mode 100644 tests/fdtaddon_realistic_addon-merged.dtb.dts.expect
create mode 100644 tests/fdtaddon_realistic_addon-merged.dtb.expect
create mode 100644 tests/fdtaddon_realistic_addon.dtba.expect
create mode 100644 tests/fdtaddon_realistic_addon.dtsa
create mode 100644 tests/fdtaddon_realistic_base.dtb.expect
create mode 100644 tests/fdtaddon_realistic_base.dts
diff --git a/tests/fdtaddon_realistic_addon-merged.dtb.dts.expect b/tests/fdtaddon_realistic_addon-merged.dtb.dts.expect
new file mode 100644
index 0000000..49aa950
--- /dev/null
+++ b/tests/fdtaddon_realistic_addon-merged.dtb.dts.expect
@@ -0,0 +1,91 @@
+/dts-v1/;
+
+/ {
+
+ regulator {
+ compatible = "regulator-fixed";
+ regulator-min-microvolt = <0x4c4b40>;
+ regulator-max-microvolt = <0x4c4b40>;
+ gpios = <&{/soc/gpio@2000} 0x05 0x00>;
+ phandle = <0x05>;
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <0x01>;
+ #size-cells = <0x01>;
+
+ i2c@1000 {
+ compatible = "xyz,i2c-controller";
+ reg = <0x1000 0x100>;
+ #address-cells = <0x01>;
+ #size-cells = <0x00>;
+ phandle = <0x06>;
+ };
+
+ gpio@2000 {
+ compatible = "xyz,gpio-controller";
+ reg = <0x2000 0x100>;
+ gpio-controller;
+ #gpio-cells = <0x02>;
+ interrupt-controller;
+ #interrupt-cells = <0x02>;
+ #address-cells = <0x00>;
+ phandle = <0x01>;
+ };
+
+ gpio@3000 {
+ compatible = "xyz,gpio-controller";
+ reg = <0x3000 0x100>;
+ gpio-controller;
+ #gpio-cells = <0x02>;
+ interrupt-controller;
+ #interrupt-cells = <0x02>;
+ #address-cells = <0x00>;
+ phandle = <0x02>;
+ };
+ };
+
+ connector-a {
+ compatible = "abc,foo-connector";
+ #address-cells = <0x00>;
+ #interrupt-cells = <0x02>;
+ interrupt-map = <0x00 0x00 &{/soc/gpio@2000} 0x0a 0x00 0x00 0x100 &{/soc/gpio@2000} 0x0a 0x100 0x01 0x00 &{/soc/gpio@3000} 0x03 0x00 0x01 0x100 &{/soc/gpio@3000} 0x03 0x100>;
+ #gpio-cells = <0x02>;
+ gpio-map-mask = <0x0f 0x00>;
+ gpio-map-pass-thru = <0x00 0x0f>;
+ gpio-map = <0x00 0x00 &{/soc/gpio@2000} 0x0a 0x00 0x01 0x00 &{/soc/gpio@3000} 0x03 0x00>;
+ phandle = <0x03>;
+
+ /export/ connector: &{/connector-a};
+ /export/ conn_i2c: &{/connector-a/conn-i2c};
+ /export/ conn_5v: &{/regulator};
+
+ conn-i2c {
+ compatible = "i2c-bus-extension";
+ i2c-parent = <&{/soc/i2c@1000}>;
+ #address-cells = <0x01>;
+ #size-cells = <0x00>;
+ phandle = <0x04>;
+
+ eeprom@51 {
+ reg = <0x51>;
+ compatible = "xxx,eeprom";
+ };
+
+ gpio@23 {
+ reset-gpios = <&{/connector-a} 0x01 0x00>;
+ vcc2-supply = <&{/regulator}>;
+ vcc1-supply = <&{/regulator}>;
+ #interrupt-cells = <0x02>;
+ interrupt-controller;
+ interrupts = <0x00 0x100>;
+ interrupt-parent = <&{/connector-a}>;
+ #gpio-cells = <0x02>;
+ gpio-controller;
+ reg = <0x23>;
+ compatible = "xxx,expander-io";
+ };
+ };
+ };
+};
diff --git a/tests/fdtaddon_realistic_addon-merged.dtb.expect b/tests/fdtaddon_realistic_addon-merged.dtb.expect
new file mode 100644
index 0000000..fbebb4c
--- /dev/null
+++ b/tests/fdtaddon_realistic_addon-merged.dtb.expect
@@ -0,0 +1,93 @@
+/dts-v1/;
+
+/ {
+ regulator {
+ compatible = "regulator-fixed";
+ regulator-min-microvolt = <0x004c4b40>;
+ regulator-max-microvolt = <0x004c4b40>;
+ gpios = <0x00000001 0x00000005 0x00000000>;
+ // [FDT_REF_LOCAL] gpios[0]
+ phandle = <0x00000005>;
+ };
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <0x00000001>;
+ #size-cells = <0x00000001>;
+ i2c@1000 {
+ compatible = "xyz,i2c-controller";
+ reg = <0x00001000 0x00000100>;
+ #address-cells = <0x00000001>;
+ #size-cells = <0x00000000>;
+ phandle = <0x00000006>;
+ };
+ gpio@2000 {
+ compatible = "xyz,gpio-controller";
+ reg = <0x00002000 0x00000100>;
+ gpio-controller;
+ #gpio-cells = <0x00000002>;
+ interrupt-controller;
+ #interrupt-cells = <0x00000002>;
+ #address-cells = <0x00000000>;
+ phandle = <0x00000001>;
+ };
+ gpio@3000 {
+ compatible = "xyz,gpio-controller";
+ reg = <0x00003000 0x00000100>;
+ gpio-controller;
+ #gpio-cells = <0x00000002>;
+ interrupt-controller;
+ #interrupt-cells = <0x00000002>;
+ #address-cells = <0x00000000>;
+ phandle = <0x00000002>;
+ };
+ };
+ connector-a {
+ compatible = "abc,foo-connector";
+ #address-cells = <0x00000000>;
+ #interrupt-cells = <0x00000002>;
+ interrupt-map = <0x00000000 0x00000000 0x00000001 0x0000000a 0x00000000 0x00000000 0x00000100 0x00000001 0x0000000a 0x00000100 0x00000001 0x00000000 0x00000002 0x00000003 0x00000000 0x00000001 0x00000100 0x00000002 0x00000003 0x00000100>;
+ // [FDT_REF_LOCAL] interrupt-map[8]
+ // [FDT_REF_LOCAL] interrupt-map[28]
+ // [FDT_REF_LOCAL] interrupt-map[48]
+ // [FDT_REF_LOCAL] interrupt-map[68]
+ #gpio-cells = <0x00000002>;
+ gpio-map-mask = <0x0000000f 0x00000000>;
+ gpio-map-pass-thru = <0x00000000 0x0000000f>;
+ gpio-map = <0x00000000 0x00000000 0x00000001 0x0000000a 0x00000000 0x00000001 0x00000000 0x00000002 0x00000003 0x00000000>;
+ // [FDT_REF_LOCAL] gpio-map[8]
+ // [FDT_REF_LOCAL] gpio-map[28]
+ phandle = <0x00000003>;
+ // [FDT_EXPORT_SYM] 'connector' -> phandle 0x00000003
+ // [FDT_EXPORT_SYM] 'conn_i2c' -> phandle 0x00000004
+ // [FDT_EXPORT_SYM] 'conn_5v' -> phandle 0x00000005
+ conn-i2c {
+ compatible = "i2c-bus-extension";
+ i2c-parent = <0x00000006>;
+ // [FDT_REF_LOCAL] i2c-parent[0]
+ #address-cells = <0x00000001>;
+ #size-cells = <0x00000000>;
+ phandle = <0x00000004>;
+ eeprom@51 {
+ reg = <0x00000051>;
+ compatible = "xxx,eeprom";
+ };
+ gpio@23 {
+ reset-gpios = <0x00000003 0x00000001 0x00000000>;
+ // [FDT_REF_LOCAL] reset-gpios[0]
+ vcc2-supply = <0x00000005>;
+ // [FDT_REF_LOCAL] vcc2-supply[0]
+ vcc1-supply = <0x00000005>;
+ // [FDT_REF_LOCAL] vcc1-supply[0]
+ #interrupt-cells = <0x00000002>;
+ interrupt-controller;
+ interrupts = <0x00000000 0x00000100>;
+ interrupt-parent = <0x00000003>;
+ // [FDT_REF_LOCAL] interrupt-parent[0]
+ #gpio-cells = <0x00000002>;
+ gpio-controller;
+ reg = <0x00000023>;
+ compatible = "xxx,expander-io";
+ };
+ };
+ };
+};
diff --git a/tests/fdtaddon_realistic_addon.dtba.expect b/tests/fdtaddon_realistic_addon.dtba.expect
new file mode 100644
index 0000000..bc2efd4
--- /dev/null
+++ b/tests/fdtaddon_realistic_addon.dtba.expect
@@ -0,0 +1,32 @@
+/dts-v1/;
+/addon/;
+
+// [FDT_IMPORT_SYM] 'connector' (abc,foo-connector)
+// [FDT_IMPORT_SYM] 'conn_5v' ()
+&connector {
+ conn-i2c {
+ gpio@23 {
+ compatible = "xxx,expander-io";
+ reg = <0x00000023>;
+ gpio-controller;
+ #gpio-cells = <0x00000002>;
+ interrupt-parent = <0xffffffff>;
+ // [FDT_REF_PHANDLE] interrupt-parent[0], ref = connector
+ interrupts = <0x00000000 0x00000100>;
+ interrupt-controller;
+ #interrupt-cells = <0x00000002>;
+ vcc1-supply = <0xffffffff>;
+ // [FDT_REF_PHANDLE] vcc1-supply[0], ref = conn_5v
+ vcc2-supply = <0xffffffff>;
+ // [FDT_REF_PHANDLE] vcc2-supply[0], ref = connector.conn_5v
+ reset-gpios = <0xffffffff 0x00000001 0x00000000>;
+ // [FDT_REF_PHANDLE] reset-gpios[0], ref = connector
+ };
+ };
+};
+&connector.conn_i2c {
+ eeprom@51 {
+ compatible = "xxx,eeprom";
+ reg = <0x00000051>;
+ };
+};
diff --git a/tests/fdtaddon_realistic_addon.dtsa b/tests/fdtaddon_realistic_addon.dtsa
new file mode 100644
index 0000000..255a1ff
--- /dev/null
+++ b/tests/fdtaddon_realistic_addon.dtsa
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+/addon/;
+
+/import/ connector: "abc,foo-connector";
+/import/ conn_5v: "";
+
+&connector {
+ /*
+ * Add a gpio expander at the conn-i2c node (i2c extension bus)
+ * available at the connector node
+ */
+ conn-i2c {
+ gpio@23 {
+ compatible = "xxx,expander-io";
+ reg = <0x23>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ /* Use the connector interrupt number 0 */
+ interrupt-parent = <&connector>;
+ interrupts = <0 0x100>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ /* Use 5V power-supply wired to the connector */
+ vcc1-supply = <&conn_5v>; /* Need to be an imported symbol */
+ vcc2-supply = <&connector.conn_5v>; /* Only connector need to be imported */
+
+ /* Use the connector gpio number 1 */
+ reset-gpios = <&connector 1 0>;
+ };
+ };
+};
+
+/*
+ * Use namespace reference to add an EEPROM at i2c bus connected
+ * to the connector. It can be an i2c extension or the i2c controller itself.
+ * We don't know and we don't have to know.
+ */
+&connector.conn_i2c {
+ eeprom@51 {
+ compatible = "xxx,eeprom";
+ reg = <0x51>;
+ };
+};
diff --git a/tests/fdtaddon_realistic_base.dtb.expect b/tests/fdtaddon_realistic_base.dtb.expect
new file mode 100644
index 0000000..9064a7a
--- /dev/null
+++ b/tests/fdtaddon_realistic_base.dtb.expect
@@ -0,0 +1,72 @@
+/dts-v1/;
+
+/ {
+ regulator {
+ compatible = "regulator-fixed";
+ regulator-min-microvolt = <0x004c4b40>;
+ regulator-max-microvolt = <0x004c4b40>;
+ gpios = <0x00000001 0x00000005 0x00000000>;
+ // [FDT_REF_LOCAL] gpios[0]
+ phandle = <0x00000005>;
+ };
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <0x00000001>;
+ #size-cells = <0x00000001>;
+ i2c@1000 {
+ compatible = "xyz,i2c-controller";
+ reg = <0x00001000 0x00000100>;
+ #address-cells = <0x00000001>;
+ #size-cells = <0x00000000>;
+ phandle = <0x00000006>;
+ };
+ gpio@2000 {
+ compatible = "xyz,gpio-controller";
+ reg = <0x00002000 0x00000100>;
+ gpio-controller;
+ #gpio-cells = <0x00000002>;
+ interrupt-controller;
+ #interrupt-cells = <0x00000002>;
+ #address-cells = <0x00000000>;
+ phandle = <0x00000001>;
+ };
+ gpio@3000 {
+ compatible = "xyz,gpio-controller";
+ reg = <0x00003000 0x00000100>;
+ gpio-controller;
+ #gpio-cells = <0x00000002>;
+ interrupt-controller;
+ #interrupt-cells = <0x00000002>;
+ #address-cells = <0x00000000>;
+ phandle = <0x00000002>;
+ };
+ };
+ connector-a {
+ compatible = "abc,foo-connector";
+ #address-cells = <0x00000000>;
+ #interrupt-cells = <0x00000002>;
+ interrupt-map = <0x00000000 0x00000000 0x00000001 0x0000000a 0x00000000 0x00000000 0x00000100 0x00000001 0x0000000a 0x00000100 0x00000001 0x00000000 0x00000002 0x00000003 0x00000000 0x00000001 0x00000100 0x00000002 0x00000003 0x00000100>;
+ // [FDT_REF_LOCAL] interrupt-map[8]
+ // [FDT_REF_LOCAL] interrupt-map[28]
+ // [FDT_REF_LOCAL] interrupt-map[48]
+ // [FDT_REF_LOCAL] interrupt-map[68]
+ #gpio-cells = <0x00000002>;
+ gpio-map-mask = <0x0000000f 0x00000000>;
+ gpio-map-pass-thru = <0x00000000 0x0000000f>;
+ gpio-map = <0x00000000 0x00000000 0x00000001 0x0000000a 0x00000000 0x00000001 0x00000000 0x00000002 0x00000003 0x00000000>;
+ // [FDT_REF_LOCAL] gpio-map[8]
+ // [FDT_REF_LOCAL] gpio-map[28]
+ phandle = <0x00000003>;
+ // [FDT_EXPORT_SYM] 'connector' -> phandle 0x00000003
+ // [FDT_EXPORT_SYM] 'conn_i2c' -> phandle 0x00000004
+ // [FDT_EXPORT_SYM] 'conn_5v' -> phandle 0x00000005
+ conn-i2c {
+ compatible = "i2c-bus-extension";
+ i2c-parent = <0x00000006>;
+ // [FDT_REF_LOCAL] i2c-parent[0]
+ #address-cells = <0x00000001>;
+ #size-cells = <0x00000000>;
+ phandle = <0x00000004>;
+ };
+ };
+};
diff --git a/tests/fdtaddon_realistic_base.dts b/tests/fdtaddon_realistic_base.dts
new file mode 100644
index 0000000..0c13f1a
--- /dev/null
+++ b/tests/fdtaddon_realistic_base.dts
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (C) 2026 Bootlin
+ */
+
+/dts-v1/;
+
+/ {
+ conn_a_5v: regulator {
+ compatible = "regulator-fixed";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpios = <&gpio1 5 0>;
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ i2c1: i2c@1000 {
+ compatible = "xyz,i2c-controller";
+ reg = <0x1000 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ gpio1: gpio@2000 {
+ compatible = "xyz,gpio-controller";
+ reg = <0x2000 0x100>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ #address-cells = <0>; /* interrupt-map usage */
+ };
+
+ gpio2: gpio@3000 {
+ compatible = "xyz,gpio-controller";
+ reg = <0x3000 0x100>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ #address-cells = <0>; /* interrupt-map usage */
+ };
+ };
+
+ conn_a: connector-a {
+ compatible = "abc,foo-connector";
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupt-map = <0 0 &gpio1 10 0>,
+ <0 0x100 &gpio1 10 0x100>,
+ <1 0 &gpio2 3 0>,
+ <1 0x100 &gpio2 3 0x100>;
+ #gpio-cells = <2>;
+ gpio-map-mask = <0xf 0x0>;
+ gpio-map-pass-thru = <0x0 0xf>;
+ gpio-map = <0 0 &gpio1 10 0>,
+ <1 0 &gpio2 3 0>;
+
+ /export/ connector: &conn_a;
+ /export/ conn_i2c: &conn_a_i2c;
+ /export/ conn_5v: &conn_a_5v;
+
+ conn_a_i2c: conn-i2c {
+ compatible = "i2c-bus-extension";
+ i2c-parent = <&i2c1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+};
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 69ca39e..a6213ab 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1242,6 +1242,20 @@ fdtaddon_tests() {
run_dtc_test -I dtb -O dts -o fdtaddon_stack_2nd-merged.dtb.dts fdtaddon_stack_2nd-merged.dtb
check_dts fdtaddon_stack_2nd-merged.dtb.dts
+
+ # More realistic dts and dtsa input files
+ run_dtc_test -I dts -O dtb -o fdtaddon_realistic_base.dtb "$SRCDIR/fdtaddon_realistic_base.dts"
+ check_dtb fdtaddon_realistic_base.dtb
+
+ run_dtc_test -I dts -O dtb -o fdtaddon_realistic_addon.dtba "$SRCDIR/fdtaddon_realistic_addon.dtsa"
+ check_dtb fdtaddon_realistic_addon.dtba
+
+ run_fdtaddon_test -i fdtaddon_realistic_base.dtb -o fdtaddon_realistic_addon-merged.dtb \
+ -t "/connector-a" fdtaddon_realistic_addon.dtba
+ check_dtb fdtaddon_realistic_addon-merged.dtb
+
+ run_dtc_test -I dtb -O dts -o fdtaddon_realistic_addon-merged.dtb.dts fdtaddon_realistic_addon-merged.dtb
+ check_dts fdtaddon_realistic_addon-merged.dtb.dts
}
pylibfdt_tests () {
--
2.52.0
^ permalink raw reply related [flat|nested] 160+ messages in thread* Re: [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (76 preceding siblings ...)
2026-01-12 14:20 ` [RFC PATCH 77/77] tests: fdtaddon: Add a test using more realistic dts and dtsa Herve Codina
@ 2026-01-12 14:49 ` Ayush Singh
2026-01-13 18:44 ` Rob Herring
2026-01-15 0:08 ` David Gibson
79 siblings, 0 replies; 160+ messages in thread
From: Ayush Singh @ 2026-01-12 14:49 UTC (permalink / raw)
To: Herve Codina, David Gibson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
On 1/12/26 7:48 PM, Herve Codina wrote:
> This big picture series adds support for dtb metadata and addon
> device-trees.
>
> Before giving details about the series content, let me give a little bit
> of context.
>
> The use-case is to support additional boards that can be hot-plugged to
> a connector available in a base board. This connector is standardized in
> terms of resources available on each pin. Any additional boards
> compatible with the connector should be able to be connected to base
> board and all base boards where this connector is implemented should
> support any additional boards.
>
> TLDR: The last patch, patch 77, gives an example of dts and dtsa (new
> addon device-tree) handling this use-case. It provides an example
> of a realistic base board description (dts) and an realistic
> additional board description (dtsa).
>
> Each base board is described by its own device-tree and the real
> resource connected to the connector depends on each board. For instance
> an i2c bus on the connector can come from the i2c1 controller from base
> board A and i2c5 controller from base board B. This is obviously the
> case for all resources wired to the connector.
>
> On the other hand, the device-tree describing the additional board has
> no reason to be changed based on the base board the additional board is
> going to be connected. Indeed this device-tree describes the additional
> board hardware and this hardware doesn't change if the additional board
> is connected to the base board A or the base board B.
>
> In order to extend a device-tree at runtime, a device-tree overlay can
> be used. The drawback of current overlay implementation is that an
> overlay is tightly coupled with the base device-tree it is applied to.
>
> If a symbol of the base device-tree has to be used by the overlay, all
> symbols available in the base device-tree need to be visible by the
> overlay and the overlay can use only those symbol without any kind of
> name translation.
>
> With current overlay implementation, a overlay depends on the base
> board. Indeed, if an overlay wants to add an I2C device on the I2C bus
> available on the base board A connector, it needs to reference the i2c1
> bus whereas it needs to reference the i2c5 bus if it used with the base
> board B.
>
> In order to fix the issue, the 'export symbol' concept has been
> proposed. This concept allows some specific node to 'export' symbols in
> order to be seen by an overlay applied to this node.
>
> The use-case and the export symbol proposal have been detailed during
> a talk at ELCE 2025. Have a look at the slides [1] and/or the video [2]
> to have a clear view of the topic
>
> [1] https://bootlin.com/pub/conferences/2025/elce/ceresoli-hotplug-status.pdf
> [2] https://www.youtube.com/watch?v=C8dEQ4OzMnc
>
> The export symbol proposal based on an export-symbol node in the
> device-tree have been rejected by device-tree and dtc maintainers.
>
> A discussion about the topic has been started on the mailing-list [3].
> This discussions led to:
>
> - The addition of meta-data in dtb instead of having __fixup__, __local__fixup__,
> an similar nodes in the device-tree used by overlays
>
> - A new kind of device-tree, an addon device-tree, in order to replace the
> usage of the overlay device-tree in this 'hot-plugging additional board'
> use-case.
>
> [3] https://lore.kernel.org/all/20250902105710.00512c6d@booty/
>
> This current RFC is the implementation of features discussed on the
> mailing-list. A lot of things are new in dtb format (new tags) and dts
> format (new keyword, new kind of references) and not yet mentioned in
> the standard.
>
> The purpose of this big picture RFC is to move forward on this topic
> based on code and some concrete dts / dtb example. Indeed, this RFC also
> adds tests for each feature introduced. Those tests are performed using
> dts files and the content of those dts files can also help in the
> discussion.
>
> The first patch is just a simple fix and can probably be merged out of this
> meta-data and addon discussion.
>
> - Patches 2..12: Introduce new meta-data dtb tags based on markers
>
> Those new tags are FDT_REF_LOCAL and FDT_REF_PHANDLE.
>
> FDT_REF_LOCAL (details in patch 6) is used to tag property using a
> phandle and this phandle points to a local node (i.e. a node
> existing in the dtb).
>
> FDT_REF_PHANDLE (details in patch 11) is used to tag a property
> using a phandle but this phandle points to a non local node (i.e.
> the node doesn't exist in the dtb). The reference to the node is
> present with the tag and the phandle value has to be fixed when the
> dtb is applied. This tag can only be present in plugins (overlays)
> and addons dtb.
>
> - Patches 13..17: Introduce addons device-tree
>
> This part introduce the new /addon/ dts keyword
>
> - Patches 18..30: Introduce /export/ keyword and related dtb tags
>
> This part introduces the new /export/ dts keyword (details in patch
> 20) and the related FDT_EXPORT_SYM and FDT_EXPORT_SYM_REF dtb tags.
>
> FDT_EXPORT_SYM (details in patch 25) is used when the exported
> symbol involved is a local node and FDT_EXPORT_SYM_REF (details in
> patch 29) is used when the node involved is a non local node.
>
> - Patches 31..38: Introduce /import/ keyword and related dtb tags
>
> This part introduces the new /import/ dts keyword (details in patch
> 33) and the related FDT_IMPORT_SYM dtb tag (details in patch 35).
>
> - Patches 39..63: Introduce orphan nodes
>
> Even if the orphan nodes concept was already present in overlays,
> the final encoding of those nodes in addon dtbs is different
> compared to overlays dtbs.
>
> In overlays, orphan nodes are transformed to a /fragment@n/__overlay__
> node. This is not the way used in addons.
>
> Indeed, in addons, orphan nodes are not transformed to fit in
> something like /fragment@n/__overlay__. They are encoded in the dtb
> using a specific tag.
>
> This part, after some preparation, introduces orphan nodes (details
> in patch 48) and the related FDT_BEGIN_NODE_REF_SYM dtb tag (details
> in patch 56).
>
> It also adds support for addons dts/dtb without a 'root' (details in
> patch 58).
>
> This part ended with the support for merging orphan node described
> in dts when relevant (details patch 60).
>
> - Patches 64..65: Reference orphan nodes and its sub-nodes by path
>
> A new syntax is needed to be able to reference a an orphan node and
> its sub-nodes by path.
>
> This new syntax is '${$<orphan_name>/<path>}' (details in patch #60)
>
> - Patches 66..67: Namespace labels references
>
> Add Namespace labels references with the new syntax '&foo.bar.baz'.
>
> This new syntax, only allowed in addons, allows to 'jump' from node
> to node based on exported symbols defined at each node (details in
> patch 66).
>
> - Patches 68..71: Support for applying an addon
>
> First, add fdt_addon_apply() in libfdt (details in patch 70) and
> then the fdtaddon command line tool (details in patch 71).
>
> - Patches 72..76: fdtaddon test
>
> Several tests related to addon application
>
> - Patch 77: A more Realistic test
>
> A last test based on use-case we want to handle.
>
> This last patch (and its dts and dtsa files) shows the kind of usage
> is expected for addons.
>
> Also it proves that metadata and addons features handles our
> use-case.
>
> I know this series is a huge series but I would like to give the big
> picture in this RFC (I hope this was a good idea). Of course, this
> series can be split for the upstreaming step and handled by parts by
> parts. Let me know.
>
> Tests are provided for each feature. In addition to be used for testing,
> tests input source files and expected output files can be used to see
> the expected behavior related to each feature.
>
> I hope also that this first RFC will help in moving forward regarding
> this 'handling an additional board described by a device-tree' topic.
>
> Best regards,
> Hervé
Hello Herve,
I was just in the process of typing out a reply in the old thread for
the topic regarding restarting discussion and how we should move towards
extending DT. So imagine my surprise when this lands in my mailbox.
Thanks for all this work.
I will go through this series and check things in reference with my
connector + addon baord setups.
Best Regards,
Ayush Singh
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (77 preceding siblings ...)
2026-01-12 14:49 ` [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Ayush Singh
@ 2026-01-13 18:44 ` Rob Herring
2026-01-14 16:18 ` Herve Codina
2026-01-15 0:08 ` David Gibson
79 siblings, 1 reply; 160+ messages in thread
From: Rob Herring @ 2026-01-13 18:44 UTC (permalink / raw)
To: Herve Codina
Cc: David Gibson, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni,
Saravana Kannan
On Mon, Jan 12, 2026 at 8:20 AM Herve Codina <herve.codina@bootlin.com> wrote:
>
> This big picture series adds support for dtb metadata and addon
> device-trees.
>
> Before giving details about the series content, let me give a little bit
> of context.
>
> The use-case is to support additional boards that can be hot-plugged to
> a connector available in a base board. This connector is standardized in
> terms of resources available on each pin. Any additional boards
> compatible with the connector should be able to be connected to base
> board and all base boards where this connector is implemented should
> support any additional boards.
>
> TLDR: The last patch, patch 77, gives an example of dts and dtsa (new
> addon device-tree) handling this use-case. It provides an example
> of a realistic base board description (dts) and an realistic
> additional board description (dtsa).
From a quick scan, that seems reasonable looking to me. The main thing
that got my attention was the namespace labels thing which I'll need
to study more.
> Each base board is described by its own device-tree and the real
> resource connected to the connector depends on each board. For instance
> an i2c bus on the connector can come from the i2c1 controller from base
> board A and i2c5 controller from base board B. This is obviously the
> case for all resources wired to the connector.
>
> On the other hand, the device-tree describing the additional board has
> no reason to be changed based on the base board the additional board is
> going to be connected. Indeed this device-tree describes the additional
> board hardware and this hardware doesn't change if the additional board
> is connected to the base board A or the base board B.
>
> In order to extend a device-tree at runtime, a device-tree overlay can
> be used. The drawback of current overlay implementation is that an
> overlay is tightly coupled with the base device-tree it is applied to.
>
> If a symbol of the base device-tree has to be used by the overlay, all
> symbols available in the base device-tree need to be visible by the
> overlay and the overlay can use only those symbol without any kind of
> name translation.
>
> With current overlay implementation, a overlay depends on the base
> board. Indeed, if an overlay wants to add an I2C device on the I2C bus
> available on the base board A connector, it needs to reference the i2c1
> bus whereas it needs to reference the i2c5 bus if it used with the base
> board B.
>
> In order to fix the issue, the 'export symbol' concept has been
> proposed. This concept allows some specific node to 'export' symbols in
> order to be seen by an overlay applied to this node.
>
> The use-case and the export symbol proposal have been detailed during
> a talk at ELCE 2025. Have a look at the slides [1] and/or the video [2]
> to have a clear view of the topic
>
> [1] https://bootlin.com/pub/conferences/2025/elce/ceresoli-hotplug-status.pdf
> [2] https://www.youtube.com/watch?v=C8dEQ4OzMnc
>
> The export symbol proposal based on an export-symbol node in the
> device-tree have been rejected by device-tree and dtc maintainers.
>
> A discussion about the topic has been started on the mailing-list [3].
> This discussions led to:
>
> - The addition of meta-data in dtb instead of having __fixup__, __local__fixup__,
> an similar nodes in the device-tree used by overlays
>
> - A new kind of device-tree, an addon device-tree, in order to replace the
> usage of the overlay device-tree in this 'hot-plugging additional board'
> use-case.
I guess "addons" is overlays 2.0. Do you envision any use for overlays
1.0 after this? I wouldn't think so other than compatibility for
existing overlays.
Maybe a conversion tool and/or function would be useful (not asking
for that now).
> [3] https://lore.kernel.org/all/20250902105710.00512c6d@booty/
>
> This current RFC is the implementation of features discussed on the
> mailing-list. A lot of things are new in dtb format (new tags) and dts
> format (new keyword, new kind of references) and not yet mentioned in
> the standard.
spec follows code. :)
> The purpose of this big picture RFC is to move forward on this topic
> based on code and some concrete dts / dtb example. Indeed, this RFC also
> adds tests for each feature introduced. Those tests are performed using
> dts files and the content of those dts files can also help in the
> discussion.
>
> The first patch is just a simple fix and can probably be merged out of this
> meta-data and addon discussion.
>
> - Patches 2..12: Introduce new meta-data dtb tags based on markers
>
> Those new tags are FDT_REF_LOCAL and FDT_REF_PHANDLE.
>
> FDT_REF_LOCAL (details in patch 6) is used to tag property using a
> phandle and this phandle points to a local node (i.e. a node
> existing in the dtb).
>
> FDT_REF_PHANDLE (details in patch 11) is used to tag a property
> using a phandle but this phandle points to a non local node (i.e.
> the node doesn't exist in the dtb). The reference to the node is
> present with the tag and the phandle value has to be fixed when the
> dtb is applied. This tag can only be present in plugins (overlays)
> and addons dtb.
This is very much aligned with what I would like to see. We've
discussed new DTB formats in the past and it becomes a laundry list of
changes likely resulting in something entirely different. I think
that's never going to move forward (it's only been discussed for 10+
years). I think doing something like this is much easier to define and
deploy.
I think the first step is just allowing the FDT format to have
additional tags with metadata that's not yet defined. Ideally that
would be just "allow unknown tags" instead of giving a parsing error.
However, I think we have to at least know the length of data for
unknown tags, so maybe we define a range of tag values which are
followed by a length. Either way, that should be a pretty small change
and easily deployed everywhere (that uses libfdt). After that, then we
can start to define the specific tags and meta-data we want. I would
like to see not just phandle info, but all type information for
example.
The addition of phandle info is also useful for fw_devlink (which is
the kernel's device dependency tracking), and I've been talking with
Saravana some about an approach like this.
> - Patches 13..17: Introduce addons device-tree
>
> This part introduce the new /addon/ dts keyword
>
> - Patches 18..30: Introduce /export/ keyword and related dtb tags
>
> This part introduces the new /export/ dts keyword (details in patch
> 20) and the related FDT_EXPORT_SYM and FDT_EXPORT_SYM_REF dtb tags.
>
> FDT_EXPORT_SYM (details in patch 25) is used when the exported
> symbol involved is a local node and FDT_EXPORT_SYM_REF (details in
> patch 29) is used when the node involved is a non local node.
More generally, would these just be "node metadata" tags?
Rob
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees
2026-01-13 18:44 ` Rob Herring
@ 2026-01-14 16:18 ` Herve Codina
2026-01-19 6:00 ` David Gibson
0 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-14 16:18 UTC (permalink / raw)
To: Rob Herring
Cc: David Gibson, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni,
Saravana Kannan
Hi Rob,
On Tue, 13 Jan 2026 12:44:07 -0600
Rob Herring <robh@kernel.org> wrote:
> On Mon, Jan 12, 2026 at 8:20 AM Herve Codina <herve.codina@bootlin.com> wrote:
...
> >
> > - A new kind of device-tree, an addon device-tree, in order to replace the
> > usage of the overlay device-tree in this 'hot-plugging additional board'
> > use-case.
>
> I guess "addons" is overlays 2.0. Do you envision any use for overlays
> 1.0 after this? I wouldn't think so other than compatibility for
> existing overlays.
On my side, with use cases I know about, I plan to switch to addons.
Of course, our connector use case which was the use case that leads to
series will use addons.
Also, I plan to move the overlay used in the LAN966x PCI use case (overlay on
top of PCI devices) to addons. I will do that when all needed support for this
feature will be available in the Linux kernel.
>
> Maybe a conversion tool and/or function would be useful (not asking
> for that now).
Indeed, this kind of tool could be a nice to have.
>
> > [3] https://lore.kernel.org/all/20250902105710.00512c6d@booty/
> >
> > This current RFC is the implementation of features discussed on the
> > mailing-list. A lot of things are new in dtb format (new tags) and dts
> > format (new keyword, new kind of references) and not yet mentioned in
> > the standard.
>
> spec follows code. :)
>
> > The purpose of this big picture RFC is to move forward on this topic
> > based on code and some concrete dts / dtb example. Indeed, this RFC also
> > adds tests for each feature introduced. Those tests are performed using
> > dts files and the content of those dts files can also help in the
> > discussion.
> >
> > The first patch is just a simple fix and can probably be merged out of this
> > meta-data and addon discussion.
> >
> > - Patches 2..12: Introduce new meta-data dtb tags based on markers
> >
> > Those new tags are FDT_REF_LOCAL and FDT_REF_PHANDLE.
> >
> > FDT_REF_LOCAL (details in patch 6) is used to tag property using a
> > phandle and this phandle points to a local node (i.e. a node
> > existing in the dtb).
> >
> > FDT_REF_PHANDLE (details in patch 11) is used to tag a property
> > using a phandle but this phandle points to a non local node (i.e.
> > the node doesn't exist in the dtb). The reference to the node is
> > present with the tag and the phandle value has to be fixed when the
> > dtb is applied. This tag can only be present in plugins (overlays)
> > and addons dtb.
>
> This is very much aligned with what I would like to see. We've
> discussed new DTB formats in the past and it becomes a laundry list of
> changes likely resulting in something entirely different. I think
> that's never going to move forward (it's only been discussed for 10+
> years). I think doing something like this is much easier to define and
> deploy.
>
> I think the first step is just allowing the FDT format to have
> additional tags with metadata that's not yet defined. Ideally that
> would be just "allow unknown tags" instead of giving a parsing error.
> However, I think we have to at least know the length of data for
> unknown tags, so maybe we define a range of tag values which are
> followed by a length. Either way, that should be a pretty small change
> and easily deployed everywhere (that uses libfdt). After that, then we
> can start to define the specific tags and meta-data we want. I would
> like to see not just phandle info, but all type information for
> example.
>
> The addition of phandle info is also useful for fw_devlink (which is
> the kernel's device dependency tracking), and I've been talking with
> Saravana some about an approach like this.
>
> > - Patches 13..17: Introduce addons device-tree
> >
> > This part introduce the new /addon/ dts keyword
> >
> > - Patches 18..30: Introduce /export/ keyword and related dtb tags
> >
> > This part introduces the new /export/ dts keyword (details in patch
> > 20) and the related FDT_EXPORT_SYM and FDT_EXPORT_SYM_REF dtb tags.
> >
> > FDT_EXPORT_SYM (details in patch 25) is used when the exported
> > symbol involved is a local node and FDT_EXPORT_SYM_REF (details in
> > patch 29) is used when the node involved is a non local node.
>
> More generally, would these just be "node metadata" tags?
>
I think we can have metadata at 3 differents levels:
- Property
- Node
- Global dtb
With the suggestion you did on patch 6 related to FDT_REF_LOCAL and if I
understood correctly, you expect to have a kind of "container" tag to group
metadata on each level.
Also you expect to have the ability to handle all 'for now unknown' tag
smoothly and so, I agree, the length of the data related to a tag are
needed to be present with the tag itself. I see to kind of tag, some with
the length of data available in the u32 following the tag and other without
the length encoded.
Tags without length encoded are followed by one u32 field containing data
related to the tag. This allow to avoid a lot of 'TAG_XXX 0x04 u32_data'
Indeed, I have the feeling that quite a lot of tags will have only one u32
field as data part and so, having 0x04 encoded (cell aligned) each time.
A tag value is on 32bits. We can define the structure of this value.
- bit 31 (msb):
- 0: This is not a new kind to tag and so it doesn't follow this definition.
All existing tags are in this categorie
- 1: New kind of tag adopting this definition
- bits 30..28:
tag data length encoding
0b000: No data related to the tag
0b001: 1 data cell (u32) directly follows the tag
0b010: 2 data cells (2 u32) directly follow the tag
...
0b110: 6 data cells (6 u32) directly follow the tag
0b111: Tag is followed by a cell (u32) indicating the size (in bytes)
of data available just after this cell (including any padding
if needed).
Because this size include some possible padding, its value is a
multiple of 4 bytes.
The offset of the tag + 4 + size points to the next tag.
- bit 27..0
tag specific identifier
With that definition, the following tags can be defined:
- FDT_INFO_PROPERTY (new tag, length encoding): 0xf0000001
This tag is available after a property.
It is followed by a cell for the length of data, the data part is a
sequence of tags (and related data) giving information related to the
last property available before the tag.
- FDT_REF_LOCAL (new tag, 1 cell data): 0x90000002:
The cell after this tag is the offset in the property where a local
phandle is available
- FDT_REF_PHANDLE (new tag, length encoding): 0xf0000003
Cf. patch 11 for definition
It is followed by a cell for the length of data. The data part is
composed of:
- offset (u32)
- label (string including \0)
- padding if needed to have next item aligned on 32bits
With that defined, supposing the following dts example:
--- 8< ---
/* 'foo' is a reference to local node,
* 'bar' is a reference to an external node
*/
prop = <1 2 &foo &bar1>;
--- 8< ---
The dtb will see the following structure:
FDT_PROP ...
FDT_INFO_PROPERTY (0xf0000001)
28 (length = (4+4)+(4+4+12) bytes)
FDT_REF_LOCAL (0x90000002)
0x8 <--- offset of &foo
FDT_REF_PHANDLE (0xf0000003)
12 (length = 4+4+1+3 bytes)
0xc <--- offset of &bar
"bar1" + its \0 <-- reference to resolve
0x00 0x00 0x00 <-- 3 bytes padding
Adding FDT_TYPE_U32 later will consist in defining
its value, probably a 0x9 family (1 cell after the tag for the
offset value)
At any point, only looking at the higher part of the tag (i.e. 0xN.......), we
can skip the tag and its data if don't know about the tag.
- 0x0: Old tag format
-> Error if unknown
- 0x8 to 0xe: New format followed by 0 (0x8) to 6 cells of data
-> Ignore if unknown and skip the N cells of data to look at the next
- 0xf: New format followed by 1 cell giving the size of following data.
-> Ignore if unknown and read the length available in the cell after the
tag, skip length byte of data to look at the next.
If the length read is not a multiple of 4: Error, invalid tag.
For this series we need the container tags:
- FDT_INFO_PROPERTY for information related to a property
Among known tags defined in this series, only FDT_REF_LOCAL and
FDT_REF_PHANDLE can be grouped into a FDT_INFO_PROPERTY.
- FDT_INFO_NODE for information related to a node
Among known tags defined in this series, only FDT_EXPORT_SYM_LOCAL
and FDT_EXPORT_SYM_REF can be grouped into a FDT_INFO_NODE.
- FDT_INFO_DTB for information related to the dtb
Among known tags defined in this series, only FDT_IMPORT_SYM can
be present into a FDT_INFO_DTB.
IMHO, the new tag FDT_BEGIN_NODE_REF related to orphan nodes doesn't
have to be in one of those containers. Indeed, FDT_BEGIN_NODE_REF
is more a node definition than a metadata.
Rob, does this could fit with what you expect?
If it does, is it relevant to keep the length cell available in 0xf
family to be in bytes. It should be a multiple of 4 in all cases and
so it can be given in the number of 32bit words instead of bytes.
Best regards,
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees
2026-01-14 16:18 ` Herve Codina
@ 2026-01-19 6:00 ` David Gibson
2026-01-27 15:19 ` Herve Codina
0 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-19 6:00 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni,
Saravana Kannan
[-- Attachment #1: Type: text/plain, Size: 7571 bytes --]
On Wed, Jan 14, 2026 at 05:18:22PM +0100, Herve Codina wrote:
> Hi Rob,
>
> On Tue, 13 Jan 2026 12:44:07 -0600
> Rob Herring <robh@kernel.org> wrote:
>
> > On Mon, Jan 12, 2026 at 8:20 AM Herve Codina <herve.codina@bootlin.com> wrote:
[snip]
> > > - Patches 13..17: Introduce addons device-tree
> > >
> > > This part introduce the new /addon/ dts keyword
> > >
> > > - Patches 18..30: Introduce /export/ keyword and related dtb tags
> > >
> > > This part introduces the new /export/ dts keyword (details in patch
> > > 20) and the related FDT_EXPORT_SYM and FDT_EXPORT_SYM_REF dtb tags.
> > >
> > > FDT_EXPORT_SYM (details in patch 25) is used when the exported
> > > symbol involved is a local node and FDT_EXPORT_SYM_REF (details in
> > > patch 29) is used when the node involved is a non local node.
> >
> > More generally, would these just be "node metadata" tags?
> >
>
> I think we can have metadata at 3 differents levels:
> - Property
> - Node
> - Global dtb
This is a really minor point, but I don't especially like the term
"metadata" for the symbol / fixup information. Although it's
technically accurate that it's metadata for the property bytestrings,
in most contexts "metadata" makes me think only of tree global
metadata. By analogy, symbols and fixup information in a .so or .a
could be seen as metadata to the raw code / data bytes, but I wouldn't
normally use that term for it (whereas I might for, say, the soname or
certain .note sections).
> With the suggestion you did on patch 6 related to FDT_REF_LOCAL and if I
> understood correctly, you expect to have a kind of "container" tag to group
> metadata on each level.
>
> Also you expect to have the ability to handle all 'for now unknown' tag
> smoothly and so, I agree, the length of the data related to a tag are
> needed to be present with the tag itself. I see to kind of tag, some with
> the length of data available in the u32 following the tag and other without
> the length encoded.
>
> Tags without length encoded are followed by one u32 field containing data
> related to the tag. This allow to avoid a lot of 'TAG_XXX 0x04 u32_data'
> Indeed, I have the feeling that quite a lot of tags will have only one u32
> field as data part and so, having 0x04 encoded (cell aligned) each time.
>
> A tag value is on 32bits. We can define the structure of this value.
> - bit 31 (msb):
> - 0: This is not a new kind to tag and so it doesn't follow this definition.
> All existing tags are in this categorie
> - 1: New kind of tag adopting this definition
>
> - bits 30..28:
> tag data length encoding
> 0b000: No data related to the tag
> 0b001: 1 data cell (u32) directly follows the tag
> 0b010: 2 data cells (2 u32) directly follow the tag
> ...
> 0b110: 6 data cells (6 u32) directly follow the tag
> 0b111: Tag is followed by a cell (u32) indicating the size (in bytes)
> of data available just after this cell (including any padding
> if needed).
> Because this size include some possible padding, its value is a
> multiple of 4 bytes.
> The offset of the tag + 4 + size points to the next tag.
>
>
> - bit 27..0
> tag specific identifier
As noted elsewhere, I'm not necessarily opposed to having a general
length encoding. However, for each new tag I think we need to think
carefully about whether it really is safe for older software that
doesn't understand it to just skip it.
> With that definition, the following tags can be defined:
> - FDT_INFO_PROPERTY (new tag, length encoding): 0xf0000001
> This tag is available after a property.
> It is followed by a cell for the length of data, the data part is a
> sequence of tags (and related data) giving information related to the
> last property available before the tag.
I'd prefer to avoid an additional layer of nesting here - I'd rather
just have multiple top level tags.
> - FDT_REF_LOCAL (new tag, 1 cell data): 0x90000002:
> The cell after this tag is the offset in the property where a local
> phandle is available
>
> - FDT_REF_PHANDLE (new tag, length encoding): 0xf0000003
> Cf. patch 11 for definition
> It is followed by a cell for the length of data. The data part is
> composed of:
> - offset (u32)
> - label (string including \0)
> - padding if needed to have next item aligned on 32bits
>
>
> With that defined, supposing the following dts example:
> --- 8< ---
> /* 'foo' is a reference to local node,
> * 'bar' is a reference to an external node
> */
> prop = <1 2 &foo &bar1>;
> --- 8< ---
>
> The dtb will see the following structure:
> FDT_PROP ...
> FDT_INFO_PROPERTY (0xf0000001)
> 28 (length = (4+4)+(4+4+12) bytes)
> FDT_REF_LOCAL (0x90000002)
> 0x8 <--- offset of &foo
> FDT_REF_PHANDLE (0xf0000003)
> 12 (length = 4+4+1+3 bytes)
> 0xc <--- offset of &bar
> "bar1" + its \0 <-- reference to resolve
> 0x00 0x00 0x00 <-- 3 bytes padding
>
> Adding FDT_TYPE_U32 later will consist in defining
> its value, probably a 0x9 family (1 cell after the tag for the
> offset value)
>
> At any point, only looking at the higher part of the tag (i.e. 0xN.......), we
> can skip the tag and its data if don't know about the tag.
> - 0x0: Old tag format
> -> Error if unknown
>
> - 0x8 to 0xe: New format followed by 0 (0x8) to 6 cells of data
> -> Ignore if unknown and skip the N cells of data to look at the next
>
> - 0xf: New format followed by 1 cell giving the size of following data.
> -> Ignore if unknown and read the length available in the cell after the
> tag, skip length byte of data to look at the next.
> If the length read is not a multiple of 4: Error, invalid tag.
>
>
> For this series we need the container tags:
> - FDT_INFO_PROPERTY for information related to a property
> Among known tags defined in this series, only FDT_REF_LOCAL and
> FDT_REF_PHANDLE can be grouped into a FDT_INFO_PROPERTY.
>
> - FDT_INFO_NODE for information related to a node
> Among known tags defined in this series, only FDT_EXPORT_SYM_LOCAL
> and FDT_EXPORT_SYM_REF can be grouped into a FDT_INFO_NODE.
>
> - FDT_INFO_DTB for information related to the dtb
> Among known tags defined in this series, only FDT_IMPORT_SYM can
> be present into a FDT_INFO_DTB.
>
> IMHO, the new tag FDT_BEGIN_NODE_REF related to orphan nodes doesn't
> have to be in one of those containers. Indeed, FDT_BEGIN_NODE_REF
> is more a node definition than a metadata.
That's a perfect example of a new tag that absolutely cannot be just
skipped if not understood. Software *must* hard error if they
encounter this and don't understand it.
> Rob, does this could fit with what you expect?
>
> If it does, is it relevant to keep the length cell available in 0xf
> family to be in bytes. It should be a multiple of 4 in all cases and
> so it can be given in the number of 32bit words instead of bytes.
>
> Best regards,
> Hervé
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees
2026-01-19 6:00 ` David Gibson
@ 2026-01-27 15:19 ` Herve Codina
2026-01-27 22:06 ` Rob Herring
0 siblings, 1 reply; 160+ messages in thread
From: Herve Codina @ 2026-01-27 15:19 UTC (permalink / raw)
To: David Gibson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni,
Saravana Kannan
Hi Rob, David,
On Mon, 19 Jan 2026 17:00:44 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
...
> >
> > I think we can have metadata at 3 differents levels:
> > - Property
> > - Node
> > - Global dtb
>
> This is a really minor point, but I don't especially like the term
> "metadata" for the symbol / fixup information. Although it's
> technically accurate that it's metadata for the property bytestrings,
> in most contexts "metadata" makes me think only of tree global
> metadata. By analogy, symbols and fixup information in a .so or .a
> could be seen as metadata to the raw code / data bytes, but I wouldn't
> normally use that term for it (whereas I might for, say, the soname or
> certain .note sections).
>
> > With the suggestion you did on patch 6 related to FDT_REF_LOCAL and if I
> > understood correctly, you expect to have a kind of "container" tag to group
> > metadata on each level.
> >
> > Also you expect to have the ability to handle all 'for now unknown' tag
> > smoothly and so, I agree, the length of the data related to a tag are
> > needed to be present with the tag itself. I see to kind of tag, some with
> > the length of data available in the u32 following the tag and other without
> > the length encoded.
> >
> > Tags without length encoded are followed by one u32 field containing data
> > related to the tag. This allow to avoid a lot of 'TAG_XXX 0x04 u32_data'
> > Indeed, I have the feeling that quite a lot of tags will have only one u32
> > field as data part and so, having 0x04 encoded (cell aligned) each time.
> >
> > A tag value is on 32bits. We can define the structure of this value.
> > - bit 31 (msb):
> > - 0: This is not a new kind to tag and so it doesn't follow this definition.
> > All existing tags are in this categorie
> > - 1: New kind of tag adopting this definition
> >
> > - bits 30..28:
> > tag data length encoding
> > 0b000: No data related to the tag
> > 0b001: 1 data cell (u32) directly follows the tag
> > 0b010: 2 data cells (2 u32) directly follow the tag
> > ...
> > 0b110: 6 data cells (6 u32) directly follow the tag
> > 0b111: Tag is followed by a cell (u32) indicating the size (in bytes)
> > of data available just after this cell (including any padding
> > if needed).
> > Because this size include some possible padding, its value is a
> > multiple of 4 bytes.
> > The offset of the tag + 4 + size points to the next tag.
> >
> >
> > - bit 27..0
> > tag specific identifier
>
> As noted elsewhere, I'm not necessarily opposed to having a general
> length encoding. However, for each new tag I think we need to think
> carefully about whether it really is safe for older software that
> doesn't understand it to just skip it.
>
> > With that definition, the following tags can be defined:
> > - FDT_INFO_PROPERTY (new tag, length encoding): 0xf0000001
> > This tag is available after a property.
> > It is followed by a cell for the length of data, the data part is a
> > sequence of tags (and related data) giving information related to the
> > last property available before the tag.
>
> I'd prefer to avoid an additional layer of nesting here - I'd rather
> just have multiple top level tags.
>
> > - FDT_REF_LOCAL (new tag, 1 cell data): 0x90000002:
> > The cell after this tag is the offset in the property where a local
> > phandle is available
> >
> > - FDT_REF_PHANDLE (new tag, length encoding): 0xf0000003
> > Cf. patch 11 for definition
> > It is followed by a cell for the length of data. The data part is
> > composed of:
> > - offset (u32)
> > - label (string including \0)
> > - padding if needed to have next item aligned on 32bits
> >
> >
> > With that defined, supposing the following dts example:
> > --- 8< ---
> > /* 'foo' is a reference to local node,
> > * 'bar' is a reference to an external node
> > */
> > prop = <1 2 &foo &bar1>;
> > --- 8< ---
> >
> > The dtb will see the following structure:
> > FDT_PROP ...
> > FDT_INFO_PROPERTY (0xf0000001)
> > 28 (length = (4+4)+(4+4+12) bytes)
> > FDT_REF_LOCAL (0x90000002)
> > 0x8 <--- offset of &foo
> > FDT_REF_PHANDLE (0xf0000003)
> > 12 (length = 4+4+1+3 bytes)
> > 0xc <--- offset of &bar
> > "bar1" + its \0 <-- reference to resolve
> > 0x00 0x00 0x00 <-- 3 bytes padding
> >
> > Adding FDT_TYPE_U32 later will consist in defining
> > its value, probably a 0x9 family (1 cell after the tag for the
> > offset value)
> >
> > At any point, only looking at the higher part of the tag (i.e. 0xN.......), we
> > can skip the tag and its data if don't know about the tag.
> > - 0x0: Old tag format
> > -> Error if unknown
> >
> > - 0x8 to 0xe: New format followed by 0 (0x8) to 6 cells of data
> > -> Ignore if unknown and skip the N cells of data to look at the next
> >
> > - 0xf: New format followed by 1 cell giving the size of following data.
> > -> Ignore if unknown and read the length available in the cell after the
> > tag, skip length byte of data to look at the next.
> > If the length read is not a multiple of 4: Error, invalid tag.
> >
> >
> > For this series we need the container tags:
> > - FDT_INFO_PROPERTY for information related to a property
> > Among known tags defined in this series, only FDT_REF_LOCAL and
> > FDT_REF_PHANDLE can be grouped into a FDT_INFO_PROPERTY.
> >
> > - FDT_INFO_NODE for information related to a node
> > Among known tags defined in this series, only FDT_EXPORT_SYM_LOCAL
> > and FDT_EXPORT_SYM_REF can be grouped into a FDT_INFO_NODE.
> >
> > - FDT_INFO_DTB for information related to the dtb
> > Among known tags defined in this series, only FDT_IMPORT_SYM can
> > be present into a FDT_INFO_DTB.
> >
> > IMHO, the new tag FDT_BEGIN_NODE_REF related to orphan nodes doesn't
> > have to be in one of those containers. Indeed, FDT_BEGIN_NODE_REF
> > is more a node definition than a metadata.
>
> That's a perfect example of a new tag that absolutely cannot be just
> skipped if not understood. Software *must* hard error if they
> encounter this and don't understand it.
>
I have started to implement this "unknown tag" feature based on the tag
values definition presented here and with complementary feature (bit
allowing to skip an unknown tag) as presented in patch 2 discussion [1].
I didn't introduce any FDT_INFO_xxx tags. They introduce nesting tags
and David seems not agree with that.
I use simple test tags to have some "unknown tags" in dtb and looked at
the way to handle them.
When we read a dtb, no problem, we just skip "unknown tags" if we are
allowed to (flag in tag value).
The issue comes when we modify a dtb.
libftd allows to modify a dtb. It allows to add/modify/remove properties
and nodes. Bootloaders for instance use this capability to update a dtb
before passing it to the kernel.
How should we handle unknown tags in this context?
We don't knwow about the meaning of those tags (unknown tags) and so, we
don't know if those tags are still consistent with modifications done?
A property can be followed by an unknown tags related to this property.
Also a property can be followed by an unknown tag related to the node.
We simply don't know.
Any modification can impact unknown tags and make them inconsistent.
Here again, we simply don't know.
Should we avoid any modification when a dtb contains unknown tags?
Should we simply remove all unknown tags when a modification is done?
Bootloaders need to modify the dtb. Avoiding modification is a no-go.
Removing "unknown tags" when a modification is done will lead to removing
all unknown tags at bootloader stage.
Rob, David, any opinion related to this specific issue and the strategy we
should follow when modification are involved?
[1] https://lore.kernel.org/all/20260119104852.3e7043ee@bootlin.com/
Best regards,
Hervé
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees
2026-01-27 15:19 ` Herve Codina
@ 2026-01-27 22:06 ` Rob Herring
2026-01-29 5:08 ` David Gibson
0 siblings, 1 reply; 160+ messages in thread
From: Rob Herring @ 2026-01-27 22:06 UTC (permalink / raw)
To: Herve Codina
Cc: David Gibson, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni,
Saravana Kannan
On Tue, Jan 27, 2026 at 9:19 AM Herve Codina <herve.codina@bootlin.com> wrote:
>
> Hi Rob, David,
>
> On Mon, 19 Jan 2026 17:00:44 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> ...
> > >
> > > I think we can have metadata at 3 differents levels:
> > > - Property
> > > - Node
> > > - Global dtb
> >
> > This is a really minor point, but I don't especially like the term
> > "metadata" for the symbol / fixup information. Although it's
> > technically accurate that it's metadata for the property bytestrings,
> > in most contexts "metadata" makes me think only of tree global
> > metadata. By analogy, symbols and fixup information in a .so or .a
> > could be seen as metadata to the raw code / data bytes, but I wouldn't
> > normally use that term for it (whereas I might for, say, the soname or
> > certain .note sections).
> >
> > > With the suggestion you did on patch 6 related to FDT_REF_LOCAL and if I
> > > understood correctly, you expect to have a kind of "container" tag to group
> > > metadata on each level.
> > >
> > > Also you expect to have the ability to handle all 'for now unknown' tag
> > > smoothly and so, I agree, the length of the data related to a tag are
> > > needed to be present with the tag itself. I see to kind of tag, some with
> > > the length of data available in the u32 following the tag and other without
> > > the length encoded.
> > >
> > > Tags without length encoded are followed by one u32 field containing data
> > > related to the tag. This allow to avoid a lot of 'TAG_XXX 0x04 u32_data'
> > > Indeed, I have the feeling that quite a lot of tags will have only one u32
> > > field as data part and so, having 0x04 encoded (cell aligned) each time.
> > >
> > > A tag value is on 32bits. We can define the structure of this value.
> > > - bit 31 (msb):
> > > - 0: This is not a new kind to tag and so it doesn't follow this definition.
> > > All existing tags are in this categorie
> > > - 1: New kind of tag adopting this definition
> > >
> > > - bits 30..28:
> > > tag data length encoding
> > > 0b000: No data related to the tag
> > > 0b001: 1 data cell (u32) directly follows the tag
> > > 0b010: 2 data cells (2 u32) directly follow the tag
> > > ...
> > > 0b110: 6 data cells (6 u32) directly follow the tag
> > > 0b111: Tag is followed by a cell (u32) indicating the size (in bytes)
> > > of data available just after this cell (including any padding
> > > if needed).
> > > Because this size include some possible padding, its value is a
> > > multiple of 4 bytes.
> > > The offset of the tag + 4 + size points to the next tag.
> > >
> > >
> > > - bit 27..0
> > > tag specific identifier
> >
> > As noted elsewhere, I'm not necessarily opposed to having a general
> > length encoding. However, for each new tag I think we need to think
> > carefully about whether it really is safe for older software that
> > doesn't understand it to just skip it.
> >
> > > With that definition, the following tags can be defined:
> > > - FDT_INFO_PROPERTY (new tag, length encoding): 0xf0000001
> > > This tag is available after a property.
> > > It is followed by a cell for the length of data, the data part is a
> > > sequence of tags (and related data) giving information related to the
> > > last property available before the tag.
> >
> > I'd prefer to avoid an additional layer of nesting here - I'd rather
> > just have multiple top level tags.
> >
> > > - FDT_REF_LOCAL (new tag, 1 cell data): 0x90000002:
> > > The cell after this tag is the offset in the property where a local
> > > phandle is available
> > >
> > > - FDT_REF_PHANDLE (new tag, length encoding): 0xf0000003
> > > Cf. patch 11 for definition
> > > It is followed by a cell for the length of data. The data part is
> > > composed of:
> > > - offset (u32)
> > > - label (string including \0)
> > > - padding if needed to have next item aligned on 32bits
> > >
> > >
> > > With that defined, supposing the following dts example:
> > > --- 8< ---
> > > /* 'foo' is a reference to local node,
> > > * 'bar' is a reference to an external node
> > > */
> > > prop = <1 2 &foo &bar1>;
> > > --- 8< ---
> > >
> > > The dtb will see the following structure:
> > > FDT_PROP ...
> > > FDT_INFO_PROPERTY (0xf0000001)
> > > 28 (length = (4+4)+(4+4+12) bytes)
> > > FDT_REF_LOCAL (0x90000002)
> > > 0x8 <--- offset of &foo
> > > FDT_REF_PHANDLE (0xf0000003)
> > > 12 (length = 4+4+1+3 bytes)
> > > 0xc <--- offset of &bar
> > > "bar1" + its \0 <-- reference to resolve
> > > 0x00 0x00 0x00 <-- 3 bytes padding
> > >
> > > Adding FDT_TYPE_U32 later will consist in defining
> > > its value, probably a 0x9 family (1 cell after the tag for the
> > > offset value)
> > >
> > > At any point, only looking at the higher part of the tag (i.e. 0xN.......), we
> > > can skip the tag and its data if don't know about the tag.
> > > - 0x0: Old tag format
> > > -> Error if unknown
> > >
> > > - 0x8 to 0xe: New format followed by 0 (0x8) to 6 cells of data
> > > -> Ignore if unknown and skip the N cells of data to look at the next
> > >
> > > - 0xf: New format followed by 1 cell giving the size of following data.
> > > -> Ignore if unknown and read the length available in the cell after the
> > > tag, skip length byte of data to look at the next.
> > > If the length read is not a multiple of 4: Error, invalid tag.
> > >
> > >
> > > For this series we need the container tags:
> > > - FDT_INFO_PROPERTY for information related to a property
> > > Among known tags defined in this series, only FDT_REF_LOCAL and
> > > FDT_REF_PHANDLE can be grouped into a FDT_INFO_PROPERTY.
> > >
> > > - FDT_INFO_NODE for information related to a node
> > > Among known tags defined in this series, only FDT_EXPORT_SYM_LOCAL
> > > and FDT_EXPORT_SYM_REF can be grouped into a FDT_INFO_NODE.
> > >
> > > - FDT_INFO_DTB for information related to the dtb
> > > Among known tags defined in this series, only FDT_IMPORT_SYM can
> > > be present into a FDT_INFO_DTB.
> > >
> > > IMHO, the new tag FDT_BEGIN_NODE_REF related to orphan nodes doesn't
> > > have to be in one of those containers. Indeed, FDT_BEGIN_NODE_REF
> > > is more a node definition than a metadata.
> >
> > That's a perfect example of a new tag that absolutely cannot be just
> > skipped if not understood. Software *must* hard error if they
> > encounter this and don't understand it.
> >
>
> I have started to implement this "unknown tag" feature based on the tag
> values definition presented here and with complementary feature (bit
> allowing to skip an unknown tag) as presented in patch 2 discussion [1].
>
> I didn't introduce any FDT_INFO_xxx tags. They introduce nesting tags
> and David seems not agree with that.
>
> I use simple test tags to have some "unknown tags" in dtb and looked at
> the way to handle them.
>
> When we read a dtb, no problem, we just skip "unknown tags" if we are
> allowed to (flag in tag value).
>
> The issue comes when we modify a dtb.
>
> libftd allows to modify a dtb. It allows to add/modify/remove properties
> and nodes. Bootloaders for instance use this capability to update a dtb
> before passing it to the kernel.
>
> How should we handle unknown tags in this context?
>
> We don't knwow about the meaning of those tags (unknown tags) and so, we
> don't know if those tags are still consistent with modifications done?
I don't think we have any choice, but to remove the tags.
> A property can be followed by an unknown tags related to this property.
> Also a property can be followed by an unknown tag related to the node.
> We simply don't know.
We should be able to distinguish between node and property tags at
least. Either by value or location. IOW, node tags must follow a
BEGIN_NODE tag and property tags must follow a property.
> Any modification can impact unknown tags and make them inconsistent.
> Here again, we simply don't know.
>
> Should we avoid any modification when a dtb contains unknown tags?
You answered that below. :)
> Should we simply remove all unknown tags when a modification is done?
For that node or property, yes. For the whole DTB, no. Though does
modifying a property constitute modifying a node?
>
> Bootloaders need to modify the dtb. Avoiding modification is a no-go.
> Removing "unknown tags" when a modification is done will lead to removing
> all unknown tags at bootloader stage.
>
> Rob, David, any opinion related to this specific issue and the strategy we
> should follow when modification are involved?
Perhaps we should separate the 'version we can read' and the 'version
we can write'. Let's say it is v18 that allows unknown tags, but v19
that actually adds any specific tags (or adds tags that are not safe
to ignore). Then a DTB with last_compat_version=v18 and version=v19
can be read by libfdt supporting v18+, but requires v19 libfdt to
write it. We'd still have to allow writing a v19 DTB with v18 libfdt,
but we'd have to downgrade the version to v18 (or downgrade if we had
to drop some tags).
The DT and bootloader/firmware are typically bundled together and in
that case there shouldn't be an issue of different versions. You can
have a newer DTB instead of the firmware one, but that doesn't need to
have the new tags (if the OS does require them, then it broke
compatibility).
Even with this series, I think everything can be ignored if you are
only looking for compatibility with what we have now. It's only if you
want to support the addons, then you need v?? which defines the set of
tags for addons. So I'm not certain a tag bit is the right way to say
safe to ignore or not. I think if we have a new tag that every client
has to understand and handle, then that's a major version change. I
think the original intent with the versions was 0x10 (aka 16) was a
new major version, 0x13(v18) would be another minor rev, and 0x20
would be the next major version.
Rob
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees
2026-01-27 22:06 ` Rob Herring
@ 2026-01-29 5:08 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-29 5:08 UTC (permalink / raw)
To: Rob Herring
Cc: Herve Codina, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni,
Saravana Kannan
[-- Attachment #1: Type: text/plain, Size: 11834 bytes --]
On Tue, Jan 27, 2026 at 04:06:12PM -0600, Rob Herring wrote:
> On Tue, Jan 27, 2026 at 9:19 AM Herve Codina <herve.codina@bootlin.com> wrote:
> >
> > Hi Rob, David,
> >
> > On Mon, 19 Jan 2026 17:00:44 +1100
> > David Gibson <david@gibson.dropbear.id.au> wrote:
> >
> > ...
> > > >
> > > > I think we can have metadata at 3 differents levels:
> > > > - Property
> > > > - Node
> > > > - Global dtb
> > >
> > > This is a really minor point, but I don't especially like the term
> > > "metadata" for the symbol / fixup information. Although it's
> > > technically accurate that it's metadata for the property bytestrings,
> > > in most contexts "metadata" makes me think only of tree global
> > > metadata. By analogy, symbols and fixup information in a .so or .a
> > > could be seen as metadata to the raw code / data bytes, but I wouldn't
> > > normally use that term for it (whereas I might for, say, the soname or
> > > certain .note sections).
> > >
> > > > With the suggestion you did on patch 6 related to FDT_REF_LOCAL and if I
> > > > understood correctly, you expect to have a kind of "container" tag to group
> > > > metadata on each level.
> > > >
> > > > Also you expect to have the ability to handle all 'for now unknown' tag
> > > > smoothly and so, I agree, the length of the data related to a tag are
> > > > needed to be present with the tag itself. I see to kind of tag, some with
> > > > the length of data available in the u32 following the tag and other without
> > > > the length encoded.
> > > >
> > > > Tags without length encoded are followed by one u32 field containing data
> > > > related to the tag. This allow to avoid a lot of 'TAG_XXX 0x04 u32_data'
> > > > Indeed, I have the feeling that quite a lot of tags will have only one u32
> > > > field as data part and so, having 0x04 encoded (cell aligned) each time.
> > > >
> > > > A tag value is on 32bits. We can define the structure of this value.
> > > > - bit 31 (msb):
> > > > - 0: This is not a new kind to tag and so it doesn't follow this definition.
> > > > All existing tags are in this categorie
> > > > - 1: New kind of tag adopting this definition
> > > >
> > > > - bits 30..28:
> > > > tag data length encoding
> > > > 0b000: No data related to the tag
> > > > 0b001: 1 data cell (u32) directly follows the tag
> > > > 0b010: 2 data cells (2 u32) directly follow the tag
> > > > ...
> > > > 0b110: 6 data cells (6 u32) directly follow the tag
> > > > 0b111: Tag is followed by a cell (u32) indicating the size (in bytes)
> > > > of data available just after this cell (including any padding
> > > > if needed).
> > > > Because this size include some possible padding, its value is a
> > > > multiple of 4 bytes.
> > > > The offset of the tag + 4 + size points to the next tag.
> > > >
> > > >
> > > > - bit 27..0
> > > > tag specific identifier
> > >
> > > As noted elsewhere, I'm not necessarily opposed to having a general
> > > length encoding. However, for each new tag I think we need to think
> > > carefully about whether it really is safe for older software that
> > > doesn't understand it to just skip it.
> > >
> > > > With that definition, the following tags can be defined:
> > > > - FDT_INFO_PROPERTY (new tag, length encoding): 0xf0000001
> > > > This tag is available after a property.
> > > > It is followed by a cell for the length of data, the data part is a
> > > > sequence of tags (and related data) giving information related to the
> > > > last property available before the tag.
> > >
> > > I'd prefer to avoid an additional layer of nesting here - I'd rather
> > > just have multiple top level tags.
> > >
> > > > - FDT_REF_LOCAL (new tag, 1 cell data): 0x90000002:
> > > > The cell after this tag is the offset in the property where a local
> > > > phandle is available
> > > >
> > > > - FDT_REF_PHANDLE (new tag, length encoding): 0xf0000003
> > > > Cf. patch 11 for definition
> > > > It is followed by a cell for the length of data. The data part is
> > > > composed of:
> > > > - offset (u32)
> > > > - label (string including \0)
> > > > - padding if needed to have next item aligned on 32bits
> > > >
> > > >
> > > > With that defined, supposing the following dts example:
> > > > --- 8< ---
> > > > /* 'foo' is a reference to local node,
> > > > * 'bar' is a reference to an external node
> > > > */
> > > > prop = <1 2 &foo &bar1>;
> > > > --- 8< ---
> > > >
> > > > The dtb will see the following structure:
> > > > FDT_PROP ...
> > > > FDT_INFO_PROPERTY (0xf0000001)
> > > > 28 (length = (4+4)+(4+4+12) bytes)
> > > > FDT_REF_LOCAL (0x90000002)
> > > > 0x8 <--- offset of &foo
> > > > FDT_REF_PHANDLE (0xf0000003)
> > > > 12 (length = 4+4+1+3 bytes)
> > > > 0xc <--- offset of &bar
> > > > "bar1" + its \0 <-- reference to resolve
> > > > 0x00 0x00 0x00 <-- 3 bytes padding
> > > >
> > > > Adding FDT_TYPE_U32 later will consist in defining
> > > > its value, probably a 0x9 family (1 cell after the tag for the
> > > > offset value)
> > > >
> > > > At any point, only looking at the higher part of the tag (i.e. 0xN.......), we
> > > > can skip the tag and its data if don't know about the tag.
> > > > - 0x0: Old tag format
> > > > -> Error if unknown
> > > >
> > > > - 0x8 to 0xe: New format followed by 0 (0x8) to 6 cells of data
> > > > -> Ignore if unknown and skip the N cells of data to look at the next
> > > >
> > > > - 0xf: New format followed by 1 cell giving the size of following data.
> > > > -> Ignore if unknown and read the length available in the cell after the
> > > > tag, skip length byte of data to look at the next.
> > > > If the length read is not a multiple of 4: Error, invalid tag.
> > > >
> > > >
> > > > For this series we need the container tags:
> > > > - FDT_INFO_PROPERTY for information related to a property
> > > > Among known tags defined in this series, only FDT_REF_LOCAL and
> > > > FDT_REF_PHANDLE can be grouped into a FDT_INFO_PROPERTY.
> > > >
> > > > - FDT_INFO_NODE for information related to a node
> > > > Among known tags defined in this series, only FDT_EXPORT_SYM_LOCAL
> > > > and FDT_EXPORT_SYM_REF can be grouped into a FDT_INFO_NODE.
> > > >
> > > > - FDT_INFO_DTB for information related to the dtb
> > > > Among known tags defined in this series, only FDT_IMPORT_SYM can
> > > > be present into a FDT_INFO_DTB.
> > > >
> > > > IMHO, the new tag FDT_BEGIN_NODE_REF related to orphan nodes doesn't
> > > > have to be in one of those containers. Indeed, FDT_BEGIN_NODE_REF
> > > > is more a node definition than a metadata.
> > >
> > > That's a perfect example of a new tag that absolutely cannot be just
> > > skipped if not understood. Software *must* hard error if they
> > > encounter this and don't understand it.
> > >
> >
> > I have started to implement this "unknown tag" feature based on the tag
> > values definition presented here and with complementary feature (bit
> > allowing to skip an unknown tag) as presented in patch 2 discussion [1].
> >
> > I didn't introduce any FDT_INFO_xxx tags. They introduce nesting tags
> > and David seems not agree with that.
Right. I don't see that they provide any advantage, so it's just
extra complexity. I'm open to persuasion if it turns out there's a
concrete reason for it.
> > I use simple test tags to have some "unknown tags" in dtb and looked at
> > the way to handle them.
> >
> > When we read a dtb, no problem, we just skip "unknown tags" if we are
> > allowed to (flag in tag value).
> >
> > The issue comes when we modify a dtb.
> >
> > libftd allows to modify a dtb. It allows to add/modify/remove properties
> > and nodes. Bootloaders for instance use this capability to update a dtb
> > before passing it to the kernel.
> >
> > How should we handle unknown tags in this context?
> >
> > We don't knwow about the meaning of those tags (unknown tags) and so, we
> > don't know if those tags are still consistent with modifications done?
>
> I don't think we have any choice, but to remove the tags.
Agreed.
> > A property can be followed by an unknown tags related to this property.
> > Also a property can be followed by an unknown tag related to the node.
> > We simply don't know.
>
> We should be able to distinguish between node and property tags at
> least. Either by value or location. IOW, node tags must follow a
> BEGIN_NODE tag and property tags must follow a property.
This seems reasonable to me. The fact that these properties are
considered tied to a specific node or property should be stated
explicitly in the general description of "ignorable" tags, though. As
Herve pointed out, we still have the option of adding more "old style"
tags if we need something that doesn't fit the new constraints.
> > Any modification can impact unknown tags and make them inconsistent.
> > Here again, we simply don't know.
> >
> > Should we avoid any modification when a dtb contains unknown tags?
>
> You answered that below. :)
>
> > Should we simply remove all unknown tags when a modification is done?
>
> For that node or property, yes. For the whole DTB, no. Though does
> modifying a property constitute modifying a node?
>
> >
> > Bootloaders need to modify the dtb. Avoiding modification is a no-go.
> > Removing "unknown tags" when a modification is done will lead to removing
> > all unknown tags at bootloader stage.
> >
> > Rob, David, any opinion related to this specific issue and the strategy we
> > should follow when modification are involved?
>
> Perhaps we should separate the 'version we can read' and the 'version
> we can write'. Let's say it is v18 that allows unknown tags, but v19
> that actually adds any specific tags (or adds tags that are not safe
> to ignore). Then a DTB with last_compat_version=v18 and version=v19
> can be read by libfdt supporting v18+, but requires v19 libfdt to
> write it. We'd still have to allow writing a v19 DTB with v18 libfdt,
> but we'd have to downgrade the version to v18 (or downgrade if we had
> to drop some tags).
>
> The DT and bootloader/firmware are typically bundled together and in
> that case there shouldn't be an issue of different versions. You can
> have a newer DTB instead of the firmware one, but that doesn't need to
> have the new tags (if the OS does require them, then it broke
> compatibility).
>
> Even with this series, I think everything can be ignored if you are
> only looking for compatibility with what we have now.
Not if you rely on reading phandle values.
> It's only if you
> want to support the addons, then you need v?? which defines the set of
> tags for addons. So I'm not certain a tag bit is the right way to say
> safe to ignore or not. I think if we have a new tag that every client
> has to understand and handle, then that's a major version change. I
> think the original intent with the versions was 0x10 (aka 16) was a
> new major version, 0x13(v18) would be another minor rev, and 0x20
> would be the next major version.
I don't think it was thought out in that much detail at the time, but
that seems a reasonable approach to me.
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread
* Re: [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees
2026-01-12 14:18 [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees Herve Codina
` (78 preceding siblings ...)
2026-01-13 18:44 ` Rob Herring
@ 2026-01-15 0:08 ` David Gibson
2026-01-15 7:11 ` David Gibson
79 siblings, 1 reply; 160+ messages in thread
From: David Gibson @ 2026-01-15 0:08 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 698 bytes --]
On Mon, Jan 12, 2026 at 03:18:50PM +0100, Herve Codina wrote:
> This big picture series adds support for dtb metadata and addon
> device-trees.
Oof. So, I lobbied for (at least aspects of) this approach, I think
it's a better idea than more ad-hoc extensions to overlays.
Now I'm reaping what I sowed: reviewing 77 patches for dtc/libfdt is
going to be a real challenge - I've been struggling to find time to
review a 6 patch series for months. Well, I guess we'll see what we
can do.
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread* Re: [RFC PATCH 00/77] Add support for dtb metadata and addon device-trees
2026-01-15 0:08 ` David Gibson
@ 2026-01-15 7:11 ` David Gibson
0 siblings, 0 replies; 160+ messages in thread
From: David Gibson @ 2026-01-15 7:11 UTC (permalink / raw)
To: Herve Codina
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ayush Singh,
Geert Uytterhoeven, devicetree-compiler, devicetree, linux-kernel,
devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli, Thomas Petazzoni
[-- Attachment #1: Type: text/plain, Size: 1037 bytes --]
On Thu, Jan 15, 2026 at 11:08:51AM +1100, David Gibson wrote:
> On Mon, Jan 12, 2026 at 03:18:50PM +0100, Herve Codina wrote:
> > This big picture series adds support for dtb metadata and addon
> > device-trees.
>
> Oof. So, I lobbied for (at least aspects of) this approach, I think
> it's a better idea than more ad-hoc extensions to overlays.
>
> Now I'm reaping what I sowed: reviewing 77 patches for dtc/libfdt is
> going to be a real challenge - I've been struggling to find time to
> review a 6 patch series for months. Well, I guess we'll see what we
> can do.
Jsyk
In line with the above, the review I've done so far is, deliberately,
a shallow, first-pass approach. I'm looking primarily at the commit
messages rather than code, and I'm focussing on generalities and
reviewability, rather than details.
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 160+ messages in thread