[PATCH 3/3] of: overlay: add of_overlay_fdt_apply_to_node()

From: Clément Léger
Date: Wed Apr 27 2022 - 07:00:38 EST


When using a driver which load an overlay and applies it on the of_node
of device it represent, the target node isn't known in advance. This is
for example the case when applying an overlay from a PCI driver. PCI
cards might be plugged on whatever slot the user want and thus, the
target node of the overlay framgents are unknown. This function allows
to specify the node on which the overlay fragments will be applied.

Signed-off-by: Clément Léger <clement.leger@xxxxxxxxxxx>
---
drivers/of/overlay.c | 21 +++++++++++++--------
include/linux/of.h | 17 +++++++++++++----
2 files changed, 26 insertions(+), 12 deletions(-)

diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index d80160cf34bb..4dabe1b65343 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -730,7 +730,8 @@ static struct device_node *find_target(struct device_node *info_node)
* detected in @tree, or -ENOSPC if idr_alloc() error.
*/
static int init_overlay_changeset(struct overlay_changeset *ovcs,
- const void *fdt, struct device_node *tree)
+ const void *fdt, struct device_node *tree,
+ struct device_node *target)
{
struct device_node *node, *overlay_node;
struct fragment *fragment;
@@ -792,7 +793,10 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs,

fragment = &fragments[cnt];
fragment->overlay = overlay_node;
- fragment->target = find_target(node);
+ if (target)
+ fragment->target = target;
+ else
+ fragment->target = find_target(node);
if (!fragment->target) {
of_node_put(fragment->overlay);
ret = -EINVAL;
@@ -877,6 +881,7 @@ static void free_overlay_changeset(struct overlay_changeset *ovcs)
* @fdt: base of memory allocated to hold the aligned FDT
* @tree: Expanded overlay device tree
* @ovcs_id: Pointer to overlay changeset id
+ * @target: Target node to override target-path property value
*
* Creates and applies an overlay changeset.
*
@@ -914,7 +919,7 @@ static void free_overlay_changeset(struct overlay_changeset *ovcs)
*/

static int of_overlay_apply(const void *fdt, struct device_node *tree,
- int *ovcs_id)
+ int *ovcs_id, struct device_node *target)
{
struct overlay_changeset *ovcs;
int ret = 0, ret_revert, ret_tmp;
@@ -947,7 +952,7 @@ static int of_overlay_apply(const void *fdt, struct device_node *tree,
if (ret)
goto err_free_tree;

- ret = init_overlay_changeset(ovcs, fdt, tree);
+ ret = init_overlay_changeset(ovcs, fdt, tree, target);
if (ret)
goto err_free_tree;

@@ -1014,8 +1019,8 @@ static int of_overlay_apply(const void *fdt, struct device_node *tree,
return ret;
}

-int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
- int *ovcs_id)
+int of_overlay_fdt_apply_to_node(const void *overlay_fdt, u32 overlay_fdt_size,
+ int *ovcs_id, struct device_node *target)
{
void *new_fdt;
void *new_fdt_align;
@@ -1053,7 +1058,7 @@ int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
goto out_free_new_fdt;
}

- ret = of_overlay_apply(new_fdt, overlay_root, ovcs_id);
+ ret = of_overlay_apply(new_fdt, overlay_root, ovcs_id, target);
if (ret < 0) {
/*
* new_fdt and overlay_root now belong to the overlay
@@ -1072,7 +1077,7 @@ int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
out:
return ret;
}
-EXPORT_SYMBOL_GPL(of_overlay_fdt_apply);
+EXPORT_SYMBOL_GPL(of_overlay_fdt_apply_to_node);

/*
* Find @np in @tree.
diff --git a/include/linux/of.h b/include/linux/of.h
index 2dc77430a91a..4df653606936 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -1566,8 +1566,8 @@ struct of_overlay_notify_data {

#ifdef CONFIG_OF_OVERLAY

-int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
- int *ovcs_id);
+int of_overlay_fdt_apply_to_node(const void *overlay_fdt, u32 overlay_fdt_size,
+ int *ovcs_id, struct device_node *target);
int of_overlay_remove(int *ovcs_id);
int of_overlay_remove_all(void);

@@ -1576,8 +1576,10 @@ int of_overlay_notifier_unregister(struct notifier_block *nb);

#else

-static inline int of_overlay_fdt_apply(void *overlay_fdt, u32 overlay_fdt_size,
- int *ovcs_id)
+static inline int of_overlay_fdt_apply_to_node(const void *overlay_fdt,
+ u32 overlay_fdt_size,
+ int *ovcs_id,
+ struct device_node *target)
{
return -ENOTSUPP;
}
@@ -1604,4 +1606,11 @@ static inline int of_overlay_notifier_unregister(struct notifier_block *nb)

#endif

+static inline int of_overlay_fdt_apply(const void *overlay_fdt,
+ u32 overlay_fdt_size, int *ovcs_id)
+{
+ return of_overlay_fdt_apply_to_node(overlay_fdt, overlay_fdt_size,
+ ovcs_id, NULL);
+}
+
#endif /* _LINUX_OF_H */
--
2.34.1