Skip to content

Commit 4728486

Browse files
houlz0507robherring
authored andcommitted
of: overlay: Extend of_overlay_fdt_apply() to specify the target node
Currently, in an overlay fdt fragment, it needs to specify the exact location in base DT. In another word, when the fdt fragment is generated, the base DT location for the fragment is already known. There is new use case that the base DT location is unknown when fdt fragment is generated. For example, the add-on device provide a fdt overlay with its firmware to describe its downstream devices. Because it is add-on device which can be plugged to different systems, its firmware will not be able to know the overlay location in base DT. Instead, the device driver will load the overlay fdt and apply it to base DT at runtime. In this case, of_overlay_fdt_apply() needs to be extended to specify the target node for device driver to apply overlay fdt. int overlay_fdt_apply(..., struct device_node *base); Signed-off-by: Lizhi Hou <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Rob Herring <[email protected]>
1 parent ae9813d commit 4728486

File tree

3 files changed

+34
-13
lines changed

3 files changed

+34
-13
lines changed

drivers/of/overlay.c

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -682,9 +682,11 @@ static int build_changeset(struct overlay_changeset *ovcs)
682682
* 1) "target" property containing the phandle of the target
683683
* 2) "target-path" property containing the path of the target
684684
*/
685-
static struct device_node *find_target(struct device_node *info_node)
685+
static struct device_node *find_target(struct device_node *info_node,
686+
struct device_node *target_base)
686687
{
687688
struct device_node *node;
689+
char *target_path;
688690
const char *path;
689691
u32 val;
690692
int ret;
@@ -700,10 +702,23 @@ static struct device_node *find_target(struct device_node *info_node)
700702

701703
ret = of_property_read_string(info_node, "target-path", &path);
702704
if (!ret) {
703-
node = of_find_node_by_path(path);
704-
if (!node)
705-
pr_err("find target, node: %pOF, path '%s' not found\n",
706-
info_node, path);
705+
if (target_base) {
706+
target_path = kasprintf(GFP_KERNEL, "%pOF%s", target_base, path);
707+
if (!target_path)
708+
return NULL;
709+
node = of_find_node_by_path(target_path);
710+
if (!node) {
711+
pr_err("find target, node: %pOF, path '%s' not found\n",
712+
info_node, target_path);
713+
}
714+
kfree(target_path);
715+
} else {
716+
node = of_find_node_by_path(path);
717+
if (!node) {
718+
pr_err("find target, node: %pOF, path '%s' not found\n",
719+
info_node, path);
720+
}
721+
}
707722
return node;
708723
}
709724

@@ -715,6 +730,7 @@ static struct device_node *find_target(struct device_node *info_node)
715730
/**
716731
* init_overlay_changeset() - initialize overlay changeset from overlay tree
717732
* @ovcs: Overlay changeset to build
733+
* @target_base: Point to the target node to apply overlay
718734
*
719735
* Initialize @ovcs. Populate @ovcs->fragments with node information from
720736
* the top level of @overlay_root. The relevant top level nodes are the
@@ -725,7 +741,8 @@ static struct device_node *find_target(struct device_node *info_node)
725741
* detected in @overlay_root. On error return, the caller of
726742
* init_overlay_changeset() must call free_overlay_changeset().
727743
*/
728-
static int init_overlay_changeset(struct overlay_changeset *ovcs)
744+
static int init_overlay_changeset(struct overlay_changeset *ovcs,
745+
struct device_node *target_base)
729746
{
730747
struct device_node *node, *overlay_node;
731748
struct fragment *fragment;
@@ -786,7 +803,7 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs)
786803

787804
fragment = &fragments[cnt];
788805
fragment->overlay = overlay_node;
789-
fragment->target = find_target(node);
806+
fragment->target = find_target(node, target_base);
790807
if (!fragment->target) {
791808
of_node_put(fragment->overlay);
792809
ret = -EINVAL;
@@ -877,6 +894,7 @@ static void free_overlay_changeset(struct overlay_changeset *ovcs)
877894
*
878895
* of_overlay_apply() - Create and apply an overlay changeset
879896
* @ovcs: overlay changeset
897+
* @base: point to the target node to apply overlay
880898
*
881899
* Creates and applies an overlay changeset.
882900
*
@@ -900,15 +918,16 @@ static void free_overlay_changeset(struct overlay_changeset *ovcs)
900918
* the caller of of_overlay_apply() must call free_overlay_changeset().
901919
*/
902920

903-
static int of_overlay_apply(struct overlay_changeset *ovcs)
921+
static int of_overlay_apply(struct overlay_changeset *ovcs,
922+
struct device_node *base)
904923
{
905924
int ret = 0, ret_revert, ret_tmp;
906925

907926
ret = of_resolve_phandles(ovcs->overlay_root);
908927
if (ret)
909928
goto out;
910929

911-
ret = init_overlay_changeset(ovcs);
930+
ret = init_overlay_changeset(ovcs, base);
912931
if (ret)
913932
goto out;
914933

@@ -952,6 +971,7 @@ static int of_overlay_apply(struct overlay_changeset *ovcs)
952971
* @overlay_fdt: pointer to overlay FDT
953972
* @overlay_fdt_size: number of bytes in @overlay_fdt
954973
* @ret_ovcs_id: pointer for returning created changeset id
974+
* @base: pointer for the target node to apply overlay
955975
*
956976
* Creates and applies an overlay changeset.
957977
*
@@ -967,7 +987,7 @@ static int of_overlay_apply(struct overlay_changeset *ovcs)
967987
*/
968988

969989
int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
970-
int *ret_ovcs_id)
990+
int *ret_ovcs_id, struct device_node *base)
971991
{
972992
void *new_fdt;
973993
void *new_fdt_align;
@@ -1037,7 +1057,7 @@ int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
10371057
}
10381058
ovcs->overlay_mem = overlay_mem;
10391059

1040-
ret = of_overlay_apply(ovcs);
1060+
ret = of_overlay_apply(ovcs, base);
10411061
/*
10421062
* If of_overlay_apply() error, calling free_overlay_changeset() may
10431063
* result in a memory leak if the apply partly succeeded, so do NOT

drivers/of/unittest.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3480,7 +3480,8 @@ static int __init overlay_data_apply(const char *overlay_name, int *ovcs_id)
34803480
if (!size)
34813481
pr_err("no overlay data for %s\n", overlay_name);
34823482

3483-
ret = of_overlay_fdt_apply(info->dtbo_begin, size, &info->ovcs_id);
3483+
ret = of_overlay_fdt_apply(info->dtbo_begin, size, &info->ovcs_id,
3484+
NULL);
34843485
if (ovcs_id)
34853486
*ovcs_id = info->ovcs_id;
34863487
if (ret < 0)

include/linux/of.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1667,7 +1667,7 @@ struct of_overlay_notify_data {
16671667
#ifdef CONFIG_OF_OVERLAY
16681668

16691669
int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
1670-
int *ovcs_id);
1670+
int *ovcs_id, struct device_node *target_base);
16711671
int of_overlay_remove(int *ovcs_id);
16721672
int of_overlay_remove_all(void);
16731673

0 commit comments

Comments
 (0)