Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <lizhi.hou@amd.com>
Link: https://lore.kernel.org/r/1692120000-46900-5-git-send-email-lizhi.hou@amd.com
Signed-off-by: Rob Herring <robh@kernel.org>

authored by

Lizhi Hou and committed by
Rob Herring
47284862 ae9813db

+34 -13
+31 -11
drivers/of/overlay.c
··· 682 682 * 1) "target" property containing the phandle of the target 683 683 * 2) "target-path" property containing the path of the target 684 684 */ 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) 686 687 { 687 688 struct device_node *node; 689 + char *target_path; 688 690 const char *path; 689 691 u32 val; 690 692 int ret; ··· 702 700 703 701 ret = of_property_read_string(info_node, "target-path", &path); 704 702 if (!ret) { 705 - node = of_find_node_by_path(path); 706 - if (!node) 707 - pr_err("find target, node: %pOF, path '%s' not found\n", 708 - info_node, path); 703 + if (target_base) { 704 + target_path = kasprintf(GFP_KERNEL, "%pOF%s", target_base, path); 705 + if (!target_path) 706 + return NULL; 707 + node = of_find_node_by_path(target_path); 708 + if (!node) { 709 + pr_err("find target, node: %pOF, path '%s' not found\n", 710 + info_node, target_path); 711 + } 712 + kfree(target_path); 713 + } else { 714 + node = of_find_node_by_path(path); 715 + if (!node) { 716 + pr_err("find target, node: %pOF, path '%s' not found\n", 717 + info_node, path); 718 + } 719 + } 709 720 return node; 710 721 } 711 722 ··· 730 715 /** 731 716 * init_overlay_changeset() - initialize overlay changeset from overlay tree 732 717 * @ovcs: Overlay changeset to build 718 + * @target_base: Point to the target node to apply overlay 733 719 * 734 720 * Initialize @ovcs. Populate @ovcs->fragments with node information from 735 721 * the top level of @overlay_root. The relevant top level nodes are the ··· 741 725 * detected in @overlay_root. On error return, the caller of 742 726 * init_overlay_changeset() must call free_overlay_changeset(). 743 727 */ 744 - static int init_overlay_changeset(struct overlay_changeset *ovcs) 728 + static int init_overlay_changeset(struct overlay_changeset *ovcs, 729 + struct device_node *target_base) 745 730 { 746 731 struct device_node *node, *overlay_node; 747 732 struct fragment *fragment; ··· 803 786 804 787 fragment = &fragments[cnt]; 805 788 fragment->overlay = overlay_node; 806 - fragment->target = find_target(node); 789 + fragment->target = find_target(node, target_base); 807 790 if (!fragment->target) { 808 791 of_node_put(fragment->overlay); 809 792 ret = -EINVAL; ··· 894 877 * 895 878 * of_overlay_apply() - Create and apply an overlay changeset 896 879 * @ovcs: overlay changeset 880 + * @base: point to the target node to apply overlay 897 881 * 898 882 * Creates and applies an overlay changeset. 899 883 * ··· 918 900 * the caller of of_overlay_apply() must call free_overlay_changeset(). 919 901 */ 920 902 921 - static int of_overlay_apply(struct overlay_changeset *ovcs) 903 + static int of_overlay_apply(struct overlay_changeset *ovcs, 904 + struct device_node *base) 922 905 { 923 906 int ret = 0, ret_revert, ret_tmp; 924 907 ··· 927 908 if (ret) 928 909 goto out; 929 910 930 - ret = init_overlay_changeset(ovcs); 911 + ret = init_overlay_changeset(ovcs, base); 931 912 if (ret) 932 913 goto out; 933 914 ··· 971 952 * @overlay_fdt: pointer to overlay FDT 972 953 * @overlay_fdt_size: number of bytes in @overlay_fdt 973 954 * @ret_ovcs_id: pointer for returning created changeset id 955 + * @base: pointer for the target node to apply overlay 974 956 * 975 957 * Creates and applies an overlay changeset. 976 958 * ··· 987 967 */ 988 968 989 969 int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size, 990 - int *ret_ovcs_id) 970 + int *ret_ovcs_id, struct device_node *base) 991 971 { 992 972 void *new_fdt; 993 973 void *new_fdt_align; ··· 1057 1037 } 1058 1038 ovcs->overlay_mem = overlay_mem; 1059 1039 1060 - ret = of_overlay_apply(ovcs); 1040 + ret = of_overlay_apply(ovcs, base); 1061 1041 /* 1062 1042 * If of_overlay_apply() error, calling free_overlay_changeset() may 1063 1043 * result in a memory leak if the apply partly succeeded, so do NOT
+2 -1
drivers/of/unittest.c
··· 3480 3480 if (!size) 3481 3481 pr_err("no overlay data for %s\n", overlay_name); 3482 3482 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); 3484 3485 if (ovcs_id) 3485 3486 *ovcs_id = info->ovcs_id; 3486 3487 if (ret < 0)
+1 -1
include/linux/of.h
··· 1667 1667 #ifdef CONFIG_OF_OVERLAY 1668 1668 1669 1669 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); 1671 1671 int of_overlay_remove(int *ovcs_id); 1672 1672 int of_overlay_remove_all(void); 1673 1673