mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH v2 0/3] state: generic devicetree-overlay based state node injection
@ 2026-08-25  0:06 chalianis1
  2026-08-25  0:06 ` [PATCH v2 1/3] state: make of_state_fixup() usable outside common/state/ chalianis1
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: chalianis1 @ 2026-08-25  0:06 UTC (permalink / raw)
  To: s.hauer; +Cc: barebox, Chali Anis

From: Chali Anis <chalianis1@gmail.com>

Boards that want a "barebox,state" node today have exactly one option:
carry it in their own, statically compiled-in devicetree source. That's
fine as long as barebox is built per-board with a maintained dts, but it
is a harder fit for targets that don't have one to begin with: the EFI
payload, deliberately meant to run unmodified across arbitrary
x86/arm64 EFI platforms barebox itself knows nothing about at build
time, and the generic BOARD_ARM_GENERIC_DT ("barebox-dt-2nd") image,
which picks up whatever devicetree a first-stage bootloader or QEMU
hands it in r2 at runtime the same way a Kernel would, rather than
being built against a particular board's dts. Either way there is no
single "board dts" being compiled for a state node to live in.

CONFIG_EXTERNAL_DTS_FRAGMENTS already covers a related need rather well:
an external build system can append dts fragment files to a board's dts
source at build time, scoped to specific boards via a per-dts
preprocessor macro. That remains the more direct choice whenever a
board's own dts is actually part of the build, and this series doesn't
propose changing that. It runs into the same limit as static dts
inclusion for the EFI payload and barebox-dt-2nd cases specifically,
though, since it operates at dts-source/build time on a particular
"main dts" - which neither target, by design, has one of.

This series instead proposes a devicetree *overlay* (.dtso, applied at
runtime via CONFIG_STATE_OVERLAY) for that gap. Applied to whichever
devicetree barebox already ends up live with by boot time - statically
compiled in, EFI-firmware-derived, passed in from a first-stage
bootloader, or the EFI payload's own minimal stub root - it only ever
adds one small node, so it doesn't need a "main dts" to attach to at
build time, and it doesn't need to know a board's memory map or other
devicetree content beyond one stable label (or, for EFI, just a
partition UUID, patch 1) to hook its backend into. In turn, that also
means it never competes with an existing devicetree for ownership,
which the one realistic alternative we considered - loading a full,
standalone state.dtb at runtime - does run into: barebox_register_of()
only accepts a new root if none is registered yet or the incoming tree
is empty, so a real state.dtb collides with whatever root the EFI
payload already registered at boot and is rejected with -EBUSY, and a
rejected tree's /aliases entries never reach the global alias cache
of_alias_get() relies on either.

Happy to discuss trade-offs here, in particular whether it's worth
teaching CONFIG_EXTERNAL_DTS_FRAGMENTS (or a variant of it) to handle
the no-base-dts case instead of adding a separate mechanism - this
series is meant as a concrete starting point for that conversation, not
a claim that overlays are the only reasonable answer.

Patch 1 makes of_state_fixup() able to resolve a partuuid-referenced,
non-hardware-backed backend node, and exports it so it can be called
directly. Patch 2 adds CONFIG_STATE_OVERLAY itself, compiling an
external .dtso into the barebox binary and applying it to the live
devicetree at postcore_initcall time. Patch 3 builds on both to publish
the resolved state description as a UEFI variable once such a node
exists, and makes the standalone state.dtb loading path step aside when
it does, since it's then redundant.

Changes since v1:
- patch 1: fixed the compatible string on the synthesized fixed-partitions
  node ("fixed-partitions", not the barebox-internal
  "barebox,fixed-partitions" alias, which external consumers don't
  recognize), fixed a phandle collision where the synthesized node kept
  the phandle it had in barebox's own live devicetree instead of one
  scoped to the target tree, and resolved non-partuuid backends via the
  reproducible name cached at probe time again instead of recomputing it
  against whatever tree is being fixed up.
- patch 3: publish "BareboxState" under efi_barebox_vendor_guid instead
  of efi_systemd_vendor_guid - it's a barebox-defined variable, not part
  of the systemd-boot loader protocol.
- cover letter: called out BOARD_ARM_GENERIC_DT ("barebox-dt-2nd") as a
  second target that benefits from this alongside the EFI payload, since
  it's in the same "no main dts at build time" situation.

Tested on a Raspberry Pi CM4 natively, and as the EFI payload on a
Jetson Orin NX and under QEMU.

Chali Anis (3):
  state: make of_state_fixup() usable outside common/state/
  state: add CONFIG_STATE_OVERLAY to inject a state node via devicetree
    overlay
  efi: payload: export resolved state as a BareboxState UEFI variable

 .../bindings/barebox/barebox,state.rst        |  9 +++
 Documentation/user/state.rst                  | 32 +++++++++
 common/Kconfig                                | 36 ++++++++++
 common/state/Makefile                         | 20 ++++++
 common/state/state.c                          | 72 +++++++++++++++----
 common/state/state_overlay.c                  | 19 +++++
 efi/payload/init.c                            | 46 +++++++++++-
 include/state.h                               |  5 ++
 8 files changed, 225 insertions(+), 14 deletions(-)
 create mode 100644 common/state/state_overlay.c




^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v2 1/3] state: make of_state_fixup() usable outside common/state/
  2026-08-25  0:06 [PATCH v2 0/3] state: generic devicetree-overlay based state node injection chalianis1
@ 2026-08-25  0:06 ` chalianis1
  2026-08-25  0:06 ` [PATCH v2 2/3] state: add CONFIG_STATE_OVERLAY to inject a state node via devicetree overlay chalianis1
  2026-08-25  0:06 ` [PATCH v2 3/3] efi: payload: export resolved state as a BareboxState UEFI variable chalianis1
  2 siblings, 0 replies; 5+ messages in thread
From: chalianis1 @ 2026-08-25  0:06 UTC (permalink / raw)
  To: s.hauer; +Cc: barebox, Chali Anis

From: Chali Anis <chalianis1@gmail.com>

of_state_fixup() was static, callable only via of_register_fixup().
Export it so other subsystems can invoke it directly to render a
state instance's devicetree representation on demand, without going
through the global fixup-registration/of_fix_tree() machinery.

While exporting it, teach it to resolve backend nodes that are
top-level "barebox,fixed-partitions" subnodes carrying a partuuid
property instead of being tied to a real, already-probed storage
device node in the tree - the same globally-resolvable-by-UUID
binding drivers/of/of_path.c's of_cdev_find() already supports for
EFI, where devices aren't instantiated from devicetree. Without this,
of_state_fixup() could only find a backend reachable by walking real
hardware nodes already present in root, which such a partuuid-only
declaration never is.

Assisted-by: Claude Sonnet 5
Signed-off-by: Chali Anis <chalianis1@gmail.com>
---
 common/state/state.c | 72 ++++++++++++++++++++++++++++++++++++--------
 include/state.h      |  5 +++
 2 files changed, 64 insertions(+), 13 deletions(-)

diff --git a/common/state/state.c b/common/state/state.c
index b421b43da539..5de806b954e9 100644
--- a/common/state/state.c
+++ b/common/state/state.c
@@ -433,14 +433,69 @@ int state_from_node(struct state *state, struct device_node *node, bool create)
 	return ret;
 }
 
-static int of_state_fixup(struct device_node *root, void *ctx)
+static int state_get_backend(struct state *state, struct device_node *root, struct device_node *n)
+{
+	struct device_node *backend_node, *part, *state_root, *np;
+	const char *compatible = "fixed-partitions";
+	struct property *prop;
+	phandle phandle;
+	int ret;
+
+	state_root = of_find_node_by_path(state->of_path);
+	if (!state_root)
+		return -ENODEV;
+
+	backend_node = of_parse_phandle(state_root, "backend", 0);
+	if (!backend_node)
+		return -ENODEV;
+
+	if (of_node_is_fixed_partitions(of_get_parent(backend_node)) &&
+	    of_property_present(backend_node, "partuuid")) {
+		part = of_create_node(root, "/partitions");
+		if (!part)
+			return -ENOMEM;
+
+		prop = of_new_property(part, "compatible", compatible,
+					strlen(compatible) + 1);
+		if (!prop)
+			return -ENOMEM;
+
+		np = of_copy_node(part, backend_node);
+		if (!np)
+			return -ENOMEM;
+
+		/*
+		 * of_copy_node() carries over backend_node's phandle as-is,
+		 * but that phandle was allocated in barebox's own live
+		 * devicetree, a namespace independent of @root's. Assign a
+		 * fresh one scoped to @root instead, so it can't collide
+		 * with an unrelated node already using that value there.
+		 */
+		phandle = of_get_tree_max_phandle(root) + 1;
+		np->phandle = phandle;
+		ret = of_property_write_u32(np, "phandle", phandle);
+		if (ret)
+			return ret;
+
+		return of_property_write_u32(n, "backend", phandle);
+	}
+
+	backend_node = of_find_node_by_reproducible_name(root, state->backend_reproducible_name);
+	if (!backend_node)
+		return -ENODEV;
+
+	phandle = of_node_create_phandle(backend_node);
+
+	return of_property_write_u32(n, "backend", phandle);
+}
+
+int of_state_fixup(struct device_node *root, void *ctx)
 {
 	struct state *state = ctx;
 	const char *compatible = "barebox,state";
-	struct device_node *new_node, *node, *parent, *backend_node, *aliases;
+	struct device_node *new_node, *node, *parent, *aliases;
 	struct property *p;
 	int ret;
-	phandle phandle;
 
 	node = of_find_node_by_path_from(root, state->of_path);
 	if (node) {
@@ -498,16 +553,7 @@ static int of_state_fixup(struct device_node *root, void *ctx)
 		goto out;
 	}
 
-	/* backend phandle */
-	backend_node = of_find_node_by_reproducible_name(root,
-						state->backend_reproducible_name);
-	if (!backend_node) {
-		ret = -ENODEV;
-		goto out;
-	}
-
-	phandle = of_node_create_phandle(backend_node);
-	ret = of_property_write_u32(new_node, "backend", phandle);
+	ret = state_get_backend(state, root, new_node);
 	if (ret)
 		goto out;
 
diff --git a/include/state.h b/include/state.h
index 3daf82c0735f..d0034506f6e3 100644
--- a/include/state.h
+++ b/include/state.h
@@ -22,6 +22,7 @@ void state_info(void);
 
 int state_read_mac(struct state *state, const char *name, u8 *buf);
 
+int of_state_fixup(struct device_node *root, void *ctx);
 #else /* #if IS_ENABLED(CONFIG_STATE) */
 
 static inline struct state *state_new_from_node(struct device_node *node,
@@ -60,6 +61,10 @@ static inline int state_read_mac(struct state *state, const char *name, u8 *buf)
 	return -ENOSYS;
 }
 
+static inline int of_state_fixup(struct device_node *root, void *ctx)
+{
+	return -ENOSYS;
+}
 #endif /* #if IS_ENABLED(CONFIG_STATE) / #else */
 
 #define BAREBOX_STATE_PARTITION_GUID \



^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v2 2/3] state: add CONFIG_STATE_OVERLAY to inject a state node via devicetree overlay
  2026-08-25  0:06 [PATCH v2 0/3] state: generic devicetree-overlay based state node injection chalianis1
  2026-08-25  0:06 ` [PATCH v2 1/3] state: make of_state_fixup() usable outside common/state/ chalianis1
@ 2026-08-25  0:06 ` chalianis1
  2026-08-25  0:06 ` [PATCH v2 3/3] efi: payload: export resolved state as a BareboxState UEFI variable chalianis1
  2 siblings, 0 replies; 5+ messages in thread
From: chalianis1 @ 2026-08-25  0:06 UTC (permalink / raw)
  To: s.hauer; +Cc: barebox, Chali Anis

From: Chali Anis <chalianis1@gmail.com>

Until now, a "barebox,state" node had to be part of a board's own,
statically compiled-in devicetree source. That's a hard requirement
for external build systems (Yocto, buildroot, ...) that want to add a
state layout without carrying a board-specific dts patch.

Add CONFIG_STATE_OVERLAY, which compiles an externally supplied
devicetree overlay (.dtso, pointed to by CONFIG_STATE_OVERLAY_DTS)
into the barebox binary and applies it to barebox's own live
devicetree at postcore_initcall time, mirroring how
CONFIG_EXTERNAL_DTS_FRAGMENTS already lets an external build system
inject plain dts fragments. Once applied, the resulting node is
picked up by the regular state probing like any statically defined
one. This selects CONFIG_OF_OVERLAY_LIVE, required so &label
references in the overlay (e.g. to an existing backend partition)
resolve against the base devicetree's __symbols__ node.

Assisted-by: Claude Sonnet 5
Signed-off-by: Chali Anis <chalianis1@gmail.com>
---
 .../bindings/barebox/barebox,state.rst        |  9 +++++
 Documentation/user/state.rst                  | 32 +++++++++++++++++
 common/Kconfig                                | 36 +++++++++++++++++++
 common/state/Makefile                         | 20 +++++++++++
 common/state/state_overlay.c                  | 19 ++++++++++
 5 files changed, 116 insertions(+)
 create mode 100644 common/state/state_overlay.c

diff --git a/Documentation/devicetree/bindings/barebox/barebox,state.rst b/Documentation/devicetree/bindings/barebox/barebox,state.rst
index 390e148a2879..36b1d9acb038 100644
--- a/Documentation/devicetree/bindings/barebox/barebox,state.rst
+++ b/Documentation/devicetree/bindings/barebox/barebox,state.rst
@@ -23,6 +23,15 @@ Required Properties
 * additionally a *state* node must have an alias in the ``/aliases`` node pointing
   to it.
 
+.. note:: A *state* node does not have to be part of the board's static
+   devicetree source. It can instead be added at runtime via a devicetree
+   overlay, see :ref:`CONFIG_STATE_OVERLAY <state_overlay>`. In that case,
+   the node referenced by ``backend`` must still exist in the board's own
+   devicetree source under a stable, well-known *label* (not merely an
+   ``/aliases`` entry), because overlay phandle resolution works by
+   resolving ``&label`` references against the base devicetree's
+   ``__symbols__`` node, which requires ``CONFIG_OF_OVERLAY_LIVE``.
+
 .. _barebox,state_magic:
 
 The ``magic`` property is a unique number which identifies the *state* variable
diff --git a/Documentation/user/state.rst b/Documentation/user/state.rst
index d97ba4e9f157..a03670dfa68e 100644
--- a/Documentation/user/state.rst
+++ b/Documentation/user/state.rst
@@ -759,6 +759,38 @@ content, its backend-type and *state* variable layout.
 		};
 	};
 
+.. _state_overlay:
+
+Devicetree Overlay based State Node
+------------------------------------
+
+Normally the *state* node is part of the board's own, statically compiled-in
+devicetree source. ``CONFIG_STATE_OVERLAY`` allows a *state* node to instead
+be added at runtime, via a devicetree overlay that is compiled into the
+barebox binary and applied to barebox's own live devicetree during boot.
+Once applied, the resulting node is picked up by the regular *state* probing
+just like a statically defined one, and is fixed up into whatever devicetree
+barebox eventually boots (internal or external), without requiring any
+board-specific code.
+
+This is primarily meant for use by an external build system (Yocto,
+buildroot, ...) that wants to inject a state layout without patching the
+board's dts: set ``CONFIG_STATE_OVERLAY=y`` and point
+``CONFIG_STATE_OVERLAY_DTS`` at the ``.dtso`` overlay file's path, similar to
+how ``CONFIG_EXTERNAL_DTS_FRAGMENTS`` works for regular dts fragments. As
+with that option, it's not intended to be set in barebox's own defconfig
+files.
+
+Because the overlay is applied to barebox's *live* devicetree, its
+``backend`` phandle can only resolve references to nodes that already exist
+in the board's own devicetree source, and only if that devicetree carries a
+``__symbols__`` node - i.e. ``CONFIG_OF_OVERLAY_LIVE`` must be enabled
+(``CONFIG_STATE_OVERLAY`` selects it automatically). This means the
+referenced backend node needs a stable, well-known *label* defined in the
+board's own devicetree source, not merely an ``/aliases`` entry - the
+overlay itself then only needs to add the *state* node and its alias,
+referencing that existing label.
+
 Frontend
 --------
 
diff --git a/common/Kconfig b/common/Kconfig
index 85df7f7daec6..d557709313c7 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -1351,6 +1351,42 @@ config STATE_BACKWARD_COMPATIBLE
 	  compatibility with the state framework of barebox <= v2016.08.0. Newer
 	  revisions expect an additional 'meta header' and fail otherwise.
 
+config STATE_OVERLAY
+	bool "apply an external devicetree overlay to add a state node"
+	depends on STATE
+	select OF_OVERLAY
+	select OF_OVERLAY_LIVE
+	help
+	  Compile an externally supplied devicetree overlay (.dtso) into the
+	  barebox binary and apply it to barebox's own live devicetree at
+	  boot, in order to add a "barebox,state" node (and its /aliases
+	  entry) that isn't part of the board's own compiled-in devicetree.
+
+	  This selects CONFIG_OF_OVERLAY_LIVE, required so the board's own
+	  built-in devicetree carries a __symbols__ node, needed to resolve
+	  &label references from the overlay back into the base devicetree
+	  (e.g. a reference to a backend partition already defined in the
+	  board's static dts).
+
+	  See CONFIG_STATE_OVERLAY_DTS to specify the overlay source file.
+
+config STATE_OVERLAY_DTS
+	string "external state overlay .dtso file"
+	depends on STATE_OVERLAY
+	help
+	  Path to a devicetree overlay source file (.dtso) that will be
+	  compiled and linked into the barebox image and applied to the
+	  live devicetree at boot to add a "barebox,state" node.
+
+	  As with CONFIG_EXTERNAL_DTS_FRAGMENTS, this is not intended to be
+	  put into Barebox's defconfig files. It's an external build
+	  system's job, like Yocto or buildroot, to inject a state overlay
+	  file from outside the Barebox source tree.
+
+	  Any backend node referenced from the overlay via &label must
+	  already exist in the board's own devicetree source, under a
+	  stable, well-known label (not merely an /aliases entry).
+
 config BOOTCHOOSER
 	bool "bootchooser infrastructure"
 	select BOOT
diff --git a/common/state/Makefile b/common/state/Makefile
index 93215dd06921..a906c66a0747 100644
--- a/common/state/Makefile
+++ b/common/state/Makefile
@@ -7,3 +7,23 @@ obj-y += backend_format_raw.o
 obj-y += backend_storage.o
 obj-y += backend_bucket_direct.o
 obj-$(CONFIG_MTD) += backend_bucket_circular.o
+
+# External state devicetree overlay
+# ---------------------------------------------------------------------------
+state-overlay-dts := $(call remove_quotes,$(CONFIG_STATE_OVERLAY_DTS))
+
+ifdef CONFIG_STATE_OVERLAY
+ifeq ($(state-overlay-dts),)
+$(error CONFIG_STATE_OVERLAY is enabled but CONFIG_STATE_OVERLAY_DTS is empty)
+endif
+ifeq ($(wildcard $(state-overlay-dts)),)
+$(error CONFIG_STATE_OVERLAY_DTS="$(state-overlay-dts)" does not exist)
+endif
+
+obj-y += state_overlay.o state-overlay.dtbo.o
+
+$(obj)/state-overlay.dtbo: $(state-overlay-dts) $(DTC) FORCE
+	$(call if_changed_dep,dtc)
+endif
+
+clean-files += *.dtbo *.dtbo.S .*.dtso
diff --git a/common/state/state_overlay.c b/common/state/state_overlay.c
new file mode 100644
index 000000000000..0c5eef830a16
--- /dev/null
+++ b/common/state/state_overlay.c
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <common.h>
+#include <init.h>
+#include <of.h>
+#include <linux/err.h>
+
+extern char __dtbo_state_overlay_start[];
+
+static int state_overlay_apply(void)
+{
+	int ret;
+
+	ret = of_overlay_apply_dtbo(of_get_root_node(), __dtbo_state_overlay_start);
+	if (ret)
+		pr_err("failed to apply state overlay: %pe\n", ERR_PTR(ret));
+
+	return ret;
+}
+postcore_initcall(state_overlay_apply);



^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v2 3/3] efi: payload: export resolved state as a BareboxState UEFI variable
  2026-08-25  0:06 [PATCH v2 0/3] state: generic devicetree-overlay based state node injection chalianis1
  2026-08-25  0:06 ` [PATCH v2 1/3] state: make of_state_fixup() usable outside common/state/ chalianis1
  2026-08-25  0:06 ` [PATCH v2 2/3] state: add CONFIG_STATE_OVERLAY to inject a state node via devicetree overlay chalianis1
@ 2026-08-25  0:06 ` chalianis1
  2 siblings, 0 replies; 5+ messages in thread
From: chalianis1 @ 2026-08-25  0:06 UTC (permalink / raw)
  To: s.hauer; +Cc: barebox, Chali Anis

From: Chali Anis <chalianis1@gmail.com>

When a "barebox,state" node is already reachable via barebox's live
devicetree (statically compiled in, or injected by
CONFIG_STATE_OVERLAY), render its fully resolved description - backend
phandle included - with of_state_fixup() and publish it as a
"BareboxState" UEFI variable, so an OS-side consumer can locate the
state layout without needing a separate state.dtb file on the ESP.

Since a state node reachable this way makes the standalone
/boot/EFI/barebox/state.dtb loading path redundant, skip it whenever
a "state" alias is already present in the live devicetree.

Assisted-by: Claude Sonnet 5
Signed-off-by: Chali Anis <chalianis1@gmail.com>
---
 efi/payload/init.c | 46 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 45 insertions(+), 1 deletion(-)

diff --git a/efi/payload/init.c b/efi/payload/init.c
index f0ce2a82cefc..7c1cb21d9ecd 100644
--- a/efi/payload/init.c
+++ b/efi/payload/init.c
@@ -287,6 +287,50 @@ core_efi_initcall(efi_register_firmware_nodes_fixup);
 #define EFI_LOADER_FEATURE_SECUREBOOT_ENROLL       (1LL << 11)
 #define EFI_LOADER_FEATURE_RETAIN_SHIM             (1LL << 12)
 
+static int state_to_efivars_export(void)
+{
+	struct device_node *np, *state_root;
+	struct state *state;
+	void *fdt;
+	size_t size;
+	int ret;
+
+	state_root = of_find_node_by_alias(NULL, "state");
+	if (!IS_ENABLED(CONFIG_STATE) || !state_root)
+		return 0;
+
+	state = state_by_node(state_root);
+	if (!state)
+		return -ENODEV;
+
+	np = of_new_node(NULL, NULL);
+	if (!np)
+		return -ENOMEM;
+
+	ret = of_state_fixup(np, state);
+	if (ret)
+		goto out;
+
+	fdt = of_flatten_dtb(np);
+	if (!fdt) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	size = fdt_totalsize(fdt);
+
+	efi_set_variable("BareboxState", &efi_barebox_vendor_guid,
+			  EFI_VARIABLE_BOOTSERVICE_ACCESS |
+			  EFI_VARIABLE_RUNTIME_ACCESS,
+			  fdt, size);
+
+	free(fdt);
+	ret = 0;
+out:
+	of_delete_node(np);
+	return ret;
+}
+late_efi_initcall(state_to_efivars_export);
 
 static int efi_postcore_init(void)
 {
@@ -356,7 +400,7 @@ static int efi_late_init(void)
 	void *fdt;
 	int ret;
 
-	if (!IS_ENABLED(CONFIG_STATE))
+	if (!IS_ENABLED(CONFIG_STATE) || of_find_node_by_alias(NULL, "state"))
 		return 0;
 
 	if (!get_mounted_path("/boot")) {



^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v2 1/3] state: make of_state_fixup() usable outside common/state/
  2026-08-24 23:52 [PATCH v2 0/3] state: generic devicetree-overlay based state node injection chalianis1
@ 2026-08-24 23:52 ` chalianis1
  0 siblings, 0 replies; 5+ messages in thread
From: chalianis1 @ 2026-08-24 23:52 UTC (permalink / raw)
  To: s.hauer; +Cc: barebox, Chali Anis

From: Chali Anis <chalianis1@gmail.com>

of_state_fixup() was static, callable only via of_register_fixup().
Export it so other subsystems can invoke it directly to render a
state instance's devicetree representation on demand, without going
through the global fixup-registration/of_fix_tree() machinery.

While exporting it, teach it to resolve backend nodes that are
top-level "barebox,fixed-partitions" subnodes carrying a partuuid
property instead of being tied to a real, already-probed storage
device node in the tree - the same globally-resolvable-by-UUID
binding drivers/of/of_path.c's of_cdev_find() already supports for
EFI, where devices aren't instantiated from devicetree. Without this,
of_state_fixup() could only find a backend reachable by walking real
hardware nodes already present in root, which such a partuuid-only
declaration never is.

Assisted-by: Claude Sonnet 5
Signed-off-by: Chali Anis <chalianis1@gmail.com>
---
 common/state/state.c | 72 ++++++++++++++++++++++++++++++++++++--------
 include/state.h      |  5 +++
 2 files changed, 64 insertions(+), 13 deletions(-)

diff --git a/common/state/state.c b/common/state/state.c
index b421b43da539..5de806b954e9 100644
--- a/common/state/state.c
+++ b/common/state/state.c
@@ -433,14 +433,69 @@ int state_from_node(struct state *state, struct device_node *node, bool create)
 	return ret;
 }
 
-static int of_state_fixup(struct device_node *root, void *ctx)
+static int state_get_backend(struct state *state, struct device_node *root, struct device_node *n)
+{
+	struct device_node *backend_node, *part, *state_root, *np;
+	const char *compatible = "fixed-partitions";
+	struct property *prop;
+	phandle phandle;
+	int ret;
+
+	state_root = of_find_node_by_path(state->of_path);
+	if (!state_root)
+		return -ENODEV;
+
+	backend_node = of_parse_phandle(state_root, "backend", 0);
+	if (!backend_node)
+		return -ENODEV;
+
+	if (of_node_is_fixed_partitions(of_get_parent(backend_node)) &&
+	    of_property_present(backend_node, "partuuid")) {
+		part = of_create_node(root, "/partitions");
+		if (!part)
+			return -ENOMEM;
+
+		prop = of_new_property(part, "compatible", compatible,
+					strlen(compatible) + 1);
+		if (!prop)
+			return -ENOMEM;
+
+		np = of_copy_node(part, backend_node);
+		if (!np)
+			return -ENOMEM;
+
+		/*
+		 * of_copy_node() carries over backend_node's phandle as-is,
+		 * but that phandle was allocated in barebox's own live
+		 * devicetree, a namespace independent of @root's. Assign a
+		 * fresh one scoped to @root instead, so it can't collide
+		 * with an unrelated node already using that value there.
+		 */
+		phandle = of_get_tree_max_phandle(root) + 1;
+		np->phandle = phandle;
+		ret = of_property_write_u32(np, "phandle", phandle);
+		if (ret)
+			return ret;
+
+		return of_property_write_u32(n, "backend", phandle);
+	}
+
+	backend_node = of_find_node_by_reproducible_name(root, state->backend_reproducible_name);
+	if (!backend_node)
+		return -ENODEV;
+
+	phandle = of_node_create_phandle(backend_node);
+
+	return of_property_write_u32(n, "backend", phandle);
+}
+
+int of_state_fixup(struct device_node *root, void *ctx)
 {
 	struct state *state = ctx;
 	const char *compatible = "barebox,state";
-	struct device_node *new_node, *node, *parent, *backend_node, *aliases;
+	struct device_node *new_node, *node, *parent, *aliases;
 	struct property *p;
 	int ret;
-	phandle phandle;
 
 	node = of_find_node_by_path_from(root, state->of_path);
 	if (node) {
@@ -498,16 +553,7 @@ static int of_state_fixup(struct device_node *root, void *ctx)
 		goto out;
 	}
 
-	/* backend phandle */
-	backend_node = of_find_node_by_reproducible_name(root,
-						state->backend_reproducible_name);
-	if (!backend_node) {
-		ret = -ENODEV;
-		goto out;
-	}
-
-	phandle = of_node_create_phandle(backend_node);
-	ret = of_property_write_u32(new_node, "backend", phandle);
+	ret = state_get_backend(state, root, new_node);
 	if (ret)
 		goto out;
 
diff --git a/include/state.h b/include/state.h
index 3daf82c0735f..d0034506f6e3 100644
--- a/include/state.h
+++ b/include/state.h
@@ -22,6 +22,7 @@ void state_info(void);
 
 int state_read_mac(struct state *state, const char *name, u8 *buf);
 
+int of_state_fixup(struct device_node *root, void *ctx);
 #else /* #if IS_ENABLED(CONFIG_STATE) */
 
 static inline struct state *state_new_from_node(struct device_node *node,
@@ -60,6 +61,10 @@ static inline int state_read_mac(struct state *state, const char *name, u8 *buf)
 	return -ENOSYS;
 }
 
+static inline int of_state_fixup(struct device_node *root, void *ctx)
+{
+	return -ENOSYS;
+}
 #endif /* #if IS_ENABLED(CONFIG_STATE) / #else */
 
 #define BAREBOX_STATE_PARTITION_GUID \



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-08-25  0:08 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-25  0:06 [PATCH v2 0/3] state: generic devicetree-overlay based state node injection chalianis1
2026-08-25  0:06 ` [PATCH v2 1/3] state: make of_state_fixup() usable outside common/state/ chalianis1
2026-08-25  0:06 ` [PATCH v2 2/3] state: add CONFIG_STATE_OVERLAY to inject a state node via devicetree overlay chalianis1
2026-08-25  0:06 ` [PATCH v2 3/3] efi: payload: export resolved state as a BareboxState UEFI variable chalianis1
  -- strict thread matches above, loose matches on Subject: below --
2026-08-24 23:52 [PATCH v2 0/3] state: generic devicetree-overlay based state node injection chalianis1
2026-08-24 23:52 ` [PATCH v2 1/3] state: make of_state_fixup() usable outside common/state/ chalianis1

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox