In message: Re: [PATCH linux-yocto] Revert "sdk: consolidating differences with reference" on 23/10/2024 Kevin Hao wrote:
> On Tue, Oct 22, 2024 at 08:41:32AM -0400, Bruce Ashfield wrote: > > On Tue, Oct 22, 2024 at 12:44 AM Kevin Hao <haoke...@gmail.com> wrote: > > > > > > From: Kevin Hao <kexin....@windriver.com> > > > > > > This reverts commit 1d865ddc92bf9b1820a68102ae553404c2d14a2e. > > > > > > The changes overrode by commit 1d865ddc92bf were introduced by pull > > > request [1], they are indeed necessary. So revert that commit. > > > > > > [1] https://lists.yoctoproject.org/g/linux-yocto/topic/109076632 > > > > > > Signed-off-by: Kevin Hao <kexin....@windriver.com> > > > --- > > > Hi Bruce, > > > > > > I merged the v5.15.168 stable kernel into > > > v5.15/standard/cn-sdkv5.15/octeon > > > branch before the pull request [1] was merged, it may have misled you into > > > thinking that these codes was unused. > > > > aha. that explains it. > > > > As you could see, my merging scripts refuse to allow me to continue > > if I give a reference branch and there are differences. Git was sure that > > the histories were merged, but yet, I still saw the code changes. > > > > So I went ahead to make sure that they were the same .. and yes, > > now I see why I undid that change. > > > > At least this one is explained, I won't worry about it happening > > again :) > > Did you forget to merge this patch, or just haven't gotten around to it? A bit of both. I had to step away, and didn't remember that I hadn't done this one yet. It should be done now. Bruce > > Thanks, > Kevin > > > > > Bruce > > > > > > > > Could you apply this revert to the following branch? > > > v5.15/standard/cn-sdkv5.15/octeon > > > --- > > > drivers/gpu/drm/rcar-du/rcar_du_of.c | 4 +- > > > drivers/of/configfs.c | 3 +- > > > drivers/of/dynamic.c | 164 ++++++++++++++++ > > > drivers/of/overlay.c | 91 ++++++--- > > > drivers/of/unittest.c | 22 ++- > > > drivers/pci/Kconfig | 12 ++ > > > drivers/pci/Makefile | 1 + > > > drivers/pci/bus.c | 2 + > > > drivers/pci/of.c | 79 ++++++++ > > > drivers/pci/of_property.c | 366 > > > +++++++++++++++++++++++++++++++++++ > > > drivers/pci/pci.h | 12 ++ > > > drivers/pci/quirks.c | 11 ++ > > > drivers/pci/remove.c | 1 + > > > include/linux/of.h | 25 ++- > > > 14 files changed, 760 insertions(+), 33 deletions(-) > > > > > > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of.c > > > b/drivers/gpu/drm/rcar-du/rcar_du_of.c > > > index afef69669bb4..f8b0a5d5a445 100644 > > > --- a/drivers/gpu/drm/rcar-du/rcar_du_of.c > > > +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.c > > > @@ -59,8 +59,8 @@ static int __init rcar_du_of_apply_overlay(const struct > > > rcar_du_of_overlay *dtbs > > > return -ENODEV; > > > > > > ovcs_id = 0; > > > - return of_overlay_fdt_apply(dtb->begin, dtb->end - dtb->begin, > > > - &ovcs_id); > > > + return of_overlay_fdt_apply(dtb->begin, dtb->end - dtb->begin, > > > &ovcs_id, > > > + NULL); > > > } > > > > > > static int __init rcar_du_of_add_property(struct of_changeset *ocs, > > > diff --git a/drivers/of/configfs.c b/drivers/of/configfs.c > > > index 64caba77a719..cc7b6c344532 100644 > > > --- a/drivers/of/configfs.c > > > +++ b/drivers/of/configfs.c > > > @@ -48,7 +48,8 @@ static int create_overlay(struct cfs_overlay_item > > > *overlay, void *blob) > > > int err; > > > > > > /* FIXME */ > > > - err = of_overlay_fdt_apply(blob, overlay->dtbo_size, > > > &overlay->ov_id); > > > + err = of_overlay_fdt_apply(blob, overlay->dtbo_size, > > > &overlay->ov_id, > > > + NULL); > > > if (err < 0) { > > > pr_err("%s: Failed to create overlay (err=%d)\n", > > > __func__, err); > > > diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c > > > index d027fe109e0a..edd7afb6bc0e 100644 > > > --- a/drivers/of/dynamic.c > > > +++ b/drivers/of/dynamic.c > > > @@ -462,6 +462,38 @@ struct device_node *__of_node_dup(const struct > > > device_node *np, > > > return NULL; > > > } > > > > > > +/** > > > + * of_changeset_create_node - Dynamically create a device node and > > > attach to > > > + * a given changeset. > > > + * > > > + * @ocs: Pointer to changeset > > > + * @parent: Pointer to parent device node > > > + * @full_name: Node full name > > > + * > > > + * Return: Pointer to the created device node or NULL in case of an > > > error. > > > + */ > > > +struct device_node *of_changeset_create_node(struct of_changeset *ocs, > > > + struct device_node *parent, > > > + const char *full_name) > > > +{ > > > + struct device_node *np; > > > + int ret; > > > + > > > + np = __of_node_dup(NULL, full_name); > > > + if (!np) > > > + return NULL; > > > + np->parent = parent; > > > + > > > + ret = of_changeset_attach_node(ocs, np); > > > + if (ret) { > > > + of_node_put(np); > > > + return NULL; > > > + } > > > + > > > + return np; > > > +} > > > +EXPORT_SYMBOL(of_changeset_create_node); > > > + > > > static void __of_changeset_entry_destroy(struct of_changeset_entry *ce) > > > { > > > if (ce->action == OF_RECONFIG_ATTACH_NODE && > > > @@ -934,3 +966,135 @@ int of_changeset_action(struct of_changeset *ocs, > > > unsigned long action, > > > return 0; > > > } > > > EXPORT_SYMBOL_GPL(of_changeset_action); > > > + > > > +static int of_changeset_add_prop_helper(struct of_changeset *ocs, > > > + struct device_node *np, > > > + const struct property *pp) > > > +{ > > > + struct property *new_pp; > > > + int ret; > > > + > > > + new_pp = __of_prop_dup(pp, GFP_KERNEL); > > > + if (!new_pp) > > > + return -ENOMEM; > > > + > > > + ret = of_changeset_add_property(ocs, np, new_pp); > > > + if (ret) { > > > + kfree(new_pp->name); > > > + kfree(new_pp->value); > > > + kfree(new_pp); > > > + } > > > + > > > + return ret; > > > +} > > > + > > > +/** > > > + * of_changeset_add_prop_string - Add a string property to a changeset > > > + * > > > + * @ocs: changeset pointer > > > + * @np: device node pointer > > > + * @prop_name: name of the property to be added > > > + * @str: pointer to null terminated string > > > + * > > > + * Create a string property and add it to a changeset. > > > + * > > > + * Return: 0 on success, a negative error value in case of an error. > > > + */ > > > +int of_changeset_add_prop_string(struct of_changeset *ocs, > > > + struct device_node *np, > > > + const char *prop_name, const char *str) > > > +{ > > > + struct property prop; > > > + > > > + prop.name = (char *)prop_name; > > > + prop.length = strlen(str) + 1; > > > + prop.value = (void *)str; > > > + > > > + return of_changeset_add_prop_helper(ocs, np, &prop); > > > +} > > > +EXPORT_SYMBOL_GPL(of_changeset_add_prop_string); > > > + > > > +/** > > > + * of_changeset_add_prop_string_array - Add a string list property to > > > + * a changeset > > > + * > > > + * @ocs: changeset pointer > > > + * @np: device node pointer > > > + * @prop_name: name of the property to be added > > > + * @str_array: pointer to an array of null terminated strings > > > + * @sz: number of string array elements > > > + * > > > + * Create a string list property and add it to a changeset. > > > + * > > > + * Return: 0 on success, a negative error value in case of an error. > > > + */ > > > +int of_changeset_add_prop_string_array(struct of_changeset *ocs, > > > + struct device_node *np, > > > + const char *prop_name, > > > + const char **str_array, size_t sz) > > > +{ > > > + struct property prop; > > > + int i, ret; > > > + char *vp; > > > + > > > + prop.name = (char *)prop_name; > > > + > > > + prop.length = 0; > > > + for (i = 0; i < sz; i++) > > > + prop.length += strlen(str_array[i]) + 1; > > > + > > > + prop.value = kmalloc(prop.length, GFP_KERNEL); > > > + if (!prop.value) > > > + return -ENOMEM; > > > + > > > + vp = prop.value; > > > + for (i = 0; i < sz; i++) { > > > + vp += snprintf(vp, (char *)prop.value + prop.length - vp, > > > "%s", > > > + str_array[i]) + 1; > > > + } > > > + ret = of_changeset_add_prop_helper(ocs, np, &prop); > > > + kfree(prop.value); > > > + > > > + return ret; > > > +} > > > +EXPORT_SYMBOL_GPL(of_changeset_add_prop_string_array); > > > + > > > +/** > > > + * of_changeset_add_prop_u32_array - Add a property of 32 bit integers > > > + * property to a changeset > > > + * > > > + * @ocs: changeset pointer > > > + * @np: device node pointer > > > + * @prop_name: name of the property to be added > > > + * @array: pointer to an array of 32 bit integers > > > + * @sz: number of array elements > > > + * > > > + * Create a property of 32 bit integers and add it to a changeset. > > > + * > > > + * Return: 0 on success, a negative error value in case of an error. > > > + */ > > > +int of_changeset_add_prop_u32_array(struct of_changeset *ocs, > > > + struct device_node *np, > > > + const char *prop_name, > > > + const u32 *array, size_t sz) > > > +{ > > > + struct property prop; > > > + __be32 *val; > > > + int i, ret; > > > + > > > + val = kcalloc(sz, sizeof(__be32), GFP_KERNEL); > > > + if (!val) > > > + return -ENOMEM; > > > + > > > + for (i = 0; i < sz; i++) > > > + val[i] = cpu_to_be32(array[i]); > > > + prop.name = (char *)prop_name; > > > + prop.length = sizeof(u32) * sz; > > > + prop.value = (void *)val; > > > + > > > + ret = of_changeset_add_prop_helper(ocs, np, &prop); > > > + kfree(val); > > > + > > > + return ret; > > > +} > > > +EXPORT_SYMBOL_GPL(of_changeset_add_prop_u32_array); > > > diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c > > > index cea5ad907235..a9a292d6d59b 100644 > > > --- a/drivers/of/overlay.c > > > +++ b/drivers/of/overlay.c > > > @@ -682,9 +682,11 @@ static int build_changeset(struct overlay_changeset > > > *ovcs) > > > * 1) "target" property containing the phandle of the target > > > * 2) "target-path" property containing the path of the target > > > */ > > > -static struct device_node *find_target(struct device_node *info_node) > > > +static struct device_node *find_target(struct device_node *info_node, > > > + struct device_node *target_base) > > > { > > > struct device_node *node; > > > + char *target_path; > > > const char *path; > > > u32 val; > > > int ret; > > > @@ -700,10 +702,23 @@ static struct device_node *find_target(struct > > > device_node *info_node) > > > > > > ret = of_property_read_string(info_node, "target-path", &path); > > > if (!ret) { > > > - node = of_find_node_by_path(path); > > > - if (!node) > > > - pr_err("find target, node: %pOF, path '%s' not > > > found\n", > > > - info_node, path); > > > + if (target_base) { > > > + target_path = kasprintf(GFP_KERNEL, "%pOF%s", > > > target_base, path); > > > + if (!target_path) > > > + return NULL; > > > + node = of_find_node_by_path(target_path); > > > + if (!node) { > > > + pr_err("find target, node: %pOF, path > > > '%s' not found\n", > > > + info_node, target_path); > > > + } > > > + kfree(target_path); > > > + } else { > > > + node = of_find_node_by_path(path); > > > + if (!node) { > > > + pr_err("find target, node: %pOF, path > > > '%s' not found\n", > > > + info_node, path); > > > + } > > > + } > > > return node; > > > } > > > > > > @@ -715,6 +730,7 @@ static struct device_node *find_target(struct > > > device_node *info_node) > > > /** > > > * init_overlay_changeset() - initialize overlay changeset from overlay > > > tree > > > * @ovcs: Overlay changeset to build > > > + * @target_base: Point to the target node to apply overlay > > > * > > > * Initialize @ovcs. Populate @ovcs->fragments with node information > > > from > > > * 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) > > > * detected in @overlay_root. On error return, the caller of > > > * init_overlay_changeset() must call free_overlay_changeset(). > > > */ > > > -static int init_overlay_changeset(struct overlay_changeset *ovcs) > > > +static int init_overlay_changeset(struct overlay_changeset *ovcs, > > > + struct device_node *target_base) > > > { > > > struct device_node *node, *overlay_node; > > > struct fragment *fragment; > > > @@ -784,7 +801,7 @@ static int init_overlay_changeset(struct > > > overlay_changeset *ovcs) > > > > > > fragment = &fragments[cnt]; > > > fragment->overlay = overlay_node; > > > - fragment->target = find_target(node); > > > + fragment->target = find_target(node, target_base); > > > if (!fragment->target) { > > > of_node_put(fragment->overlay); > > > ret = -EINVAL; > > > @@ -875,6 +892,7 @@ static void free_overlay_changeset(struct > > > overlay_changeset *ovcs) > > > * > > > * of_overlay_apply() - Create and apply an overlay changeset > > > * @ovcs: overlay changeset > > > + * @base: point to the target node to apply overlay > > > * > > > * Creates and applies an overlay changeset. > > > * > > > @@ -898,21 +916,16 @@ static void free_overlay_changeset(struct > > > overlay_changeset *ovcs) > > > * the caller of of_overlay_apply() must call free_overlay_changeset(). > > > */ > > > > > > -static int of_overlay_apply(struct overlay_changeset *ovcs) > > > +static int of_overlay_apply(struct overlay_changeset *ovcs, > > > + struct device_node *base) > > > { > > > int ret = 0, ret_revert, ret_tmp; > > > > > > - if (devicetree_corrupt()) { > > > - pr_err("devicetree state suspect, refuse to apply > > > overlay\n"); > > > - ret = -EBUSY; > > > - goto out; > > > - } > > > - > > > ret = of_resolve_phandles(ovcs->overlay_root); > > > if (ret) > > > goto out; > > > > > > - ret = init_overlay_changeset(ovcs); > > > + ret = init_overlay_changeset(ovcs, base); > > > if (ret) > > > goto out; > > > > > > @@ -951,8 +964,28 @@ static int of_overlay_apply(struct overlay_changeset > > > *ovcs) > > > return ret; > > > } > > > > > > +/* > > > + * of_overlay_fdt_apply() - Create and apply an overlay changeset > > > + * @overlay_fdt: pointer to overlay FDT > > > + * @overlay_fdt_size: number of bytes in @overlay_fdt > > > + * @ret_ovcs_id: pointer for returning created changeset id > > > + * @base: pointer for the target node to apply overlay > > > + * > > > + * Creates and applies an overlay changeset. > > > + * > > > + * See of_overlay_apply() for important behavior information. > > > + * > > > + * Return: 0 on success, or a negative error number. *@ret_ovcs_id is > > > set to > > > + * the value of overlay changeset id, which can be passed to > > > of_overlay_remove() > > > + * to remove the overlay. > > > + * > > > + * On error return, the changeset may be partially applied. This is > > > especially > > > + * likely if an OF_OVERLAY_POST_APPLY notifier returns an error. In > > > this case > > > + * the caller should call of_overlay_remove() with the value in > > > *@ret_ovcs_id. > > > + */ > > > + > > > int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size, > > > - int *ret_ovcs_id) > > > + int *ret_ovcs_id, struct device_node *base) > > > { > > > void *new_fdt; > > > void *new_fdt_align; > > > @@ -963,6 +996,11 @@ int of_overlay_fdt_apply(const void *overlay_fdt, > > > u32 overlay_fdt_size, > > > > > > *ret_ovcs_id = 0; > > > > > > + if (devicetree_corrupt()) { > > > + pr_err("devicetree state suspect, refuse to apply > > > overlay\n"); > > > + return -EBUSY; > > > + } > > > + > > > if (overlay_fdt_size < sizeof(struct fdt_header) || > > > fdt_check_header(overlay_fdt)) { > > > pr_err("Invalid overlay_fdt header\n"); > > > @@ -1018,23 +1056,22 @@ int of_overlay_fdt_apply(const void *overlay_fdt, > > > u32 overlay_fdt_size, > > > } > > > ovcs->overlay_mem = overlay_mem; > > > > > > - ret = of_overlay_apply(ovcs); > > > - if (ret < 0) > > > - goto err_free_ovcs; > > > - > > > - mutex_unlock(&of_mutex); > > > - of_overlay_mutex_unlock(); > > > - > > > + ret = of_overlay_apply(ovcs, base); > > > + /* > > > + * If of_overlay_apply() error, calling free_overlay_changeset() > > > may > > > + * result in a memory leak if the apply partly succeeded, so do > > > NOT > > > + * goto err_free_ovcs. Instead, the caller of > > > of_overlay_fdt_apply() > > > + * can call of_overlay_remove(); > > > + */ > > > *ret_ovcs_id = ovcs->id; > > > - > > > - return 0; > > > + goto out_unlock; > > > > > > err_free_ovcs: > > > free_overlay_changeset(ovcs); > > > > > > +out_unlock: > > > mutex_unlock(&of_mutex); > > > of_overlay_mutex_unlock(); > > > - > > > return ret; > > > } > > > EXPORT_SYMBOL_GPL(of_overlay_fdt_apply); > > > @@ -1104,7 +1141,7 @@ static int node_overlaps_later_cs(struct > > > overlay_changeset *remove_ovcs, > > > * The topmost check is done by exploiting this property. For each > > > * affected device node in the log list we check if this overlay is > > > * the one closest to the tail. If another overlay has affected this > > > - * device node and is closest to the tail, then removal is not permited. > > > + * device node and is closest to the tail, then removal is not permitted. > > > */ > > > static int overlay_removal_is_ok(struct overlay_changeset *remove_ovcs) > > > { > > > diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c > > > index 5a8d37cef0ba..4ad13c6c6711 100644 > > > --- a/drivers/of/unittest.c > > > +++ b/drivers/of/unittest.c > > > @@ -813,7 +813,9 @@ static void __init of_unittest_changeset(void) > > > struct property *ppname_n21, pname_n21 = { .name = "name", > > > .length = 3, .value = "n21" }; > > > struct property *ppupdate, pupdate = { .name = "prop-update", > > > .length = 5, .value = "abcd" }; > > > struct property *ppremove; > > > - struct device_node *n1, *n2, *n21, *nchangeset, *nremove, > > > *parent, *np; > > > + struct device_node *n1, *n2, *n21, *n22, *nchangeset, *nremove, > > > *parent, *np; > > > + static const char * const str_array[] = { "str1", "str2", "str3" > > > }; > > > + const u32 u32_array[] = { 1, 2, 3 }; > > > struct of_changeset chgset; > > > > > > n1 = __of_node_dup(NULL, "n1"); > > > @@ -868,6 +870,17 @@ static void __init of_unittest_changeset(void) > > > unittest(!of_changeset_add_property(&chgset, parent, ppadd), > > > "fail add prop prop-add\n"); > > > unittest(!of_changeset_update_property(&chgset, parent, > > > ppupdate), "fail update prop\n"); > > > unittest(!of_changeset_remove_property(&chgset, parent, > > > ppremove), "fail remove prop\n"); > > > + n22 = of_changeset_create_node(&chgset, n2, "n22"); > > > + unittest(n22, "fail create n22\n"); > > > + unittest(!of_changeset_add_prop_string(&chgset, n22, "prop-str", > > > "abcd"), > > > + "fail add prop prop-str"); > > > + unittest(!of_changeset_add_prop_string_array(&chgset, n22, > > > "prop-str-array", > > > + (const char > > > **)str_array, > > > + > > > ARRAY_SIZE(str_array)), > > > + "fail add prop prop-str-array"); > > > + unittest(!of_changeset_add_prop_u32_array(&chgset, n22, > > > "prop-u32-array", > > > + u32_array, > > > ARRAY_SIZE(u32_array)), > > > + "fail add prop prop-u32-array"); > > > > > > unittest(!of_changeset_apply(&chgset), "apply failed\n"); > > > > > > @@ -877,6 +890,9 @@ static void __init of_unittest_changeset(void) > > > unittest((np = > > > of_find_node_by_path("/testcase-data/changeset/n2/n21")), > > > "'%pOF' not added\n", n21); > > > of_node_put(np); > > > + unittest((np = > > > of_find_node_by_path("/testcase-data/changeset/n2/n22")), > > > + "'%pOF' not added\n", n22); > > > + of_node_put(np); > > > > > > unittest(!of_changeset_revert(&chgset), "revert failed\n"); > > > > > > @@ -885,6 +901,7 @@ static void __init of_unittest_changeset(void) > > > of_node_put(n1); > > > of_node_put(n2); > > > of_node_put(n21); > > > + of_node_put(n22); > > > #endif > > > } > > > > > > @@ -3036,7 +3053,8 @@ static int __init overlay_data_apply(const char > > > *overlay_name, int *overlay_id) > > > if (!size) > > > pr_err("no overlay data for %s\n", overlay_name); > > > > > > - ret = of_overlay_fdt_apply(info->dtb_begin, size, > > > &info->overlay_id); > > > + ret = of_overlay_fdt_apply(info->dtb_begin, size, > > > &info->overlay_id, > > > + NULL); > > > if (overlay_id) > > > *overlay_id = info->overlay_id; > > > if (ret < 0) > > > diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig > > > index 43e615aa12ff..3093e5030c04 100644 > > > --- a/drivers/pci/Kconfig > > > +++ b/drivers/pci/Kconfig > > > @@ -190,6 +190,18 @@ config PCI_HYPERV > > > The PCI device frontend driver allows the kernel to import > > > arbitrary > > > PCI devices from a PCI backend to support PCI driver domains. > > > > > > +config PCI_DYNAMIC_OF_NODES > > > + bool "Create Device tree nodes for PCI devices" > > > + depends on OF > > > + select OF_DYNAMIC > > > + help > > > + This option enables support for generating device tree nodes > > > for some > > > + PCI devices. Thus, the driver of this kind can load and overlay > > > + flattened device tree for its downstream devices. > > > + > > > + Once this option is selected, the device tree nodes will be > > > generated > > > + for all PCI bridges. > > > + > > > choice > > > prompt "PCI Express hierarchy optimization setting" > > > default PCIE_BUS_DEFAULT > > > diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile > > > index d62c4ac4ae1b..98c39f9d813b 100644 > > > --- a/drivers/pci/Makefile > > > +++ b/drivers/pci/Makefile > > > @@ -29,6 +29,7 @@ obj-$(CONFIG_PCI_PF_STUB) += pci-pf-stub.o > > > obj-$(CONFIG_PCI_ECAM) += ecam.o > > > obj-$(CONFIG_PCI_P2PDMA) += p2pdma.o > > > obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o > > > +obj-$(CONFIG_PCI_DYNAMIC_OF_NODES) += of_property.o > > > > > > # Endpoint library must be initialized before its users > > > obj-$(CONFIG_PCI_ENDPOINT) += endpoint/ > > > diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c > > > index feafa378bf8e..54412e142547 100644 > > > --- a/drivers/pci/bus.c > > > +++ b/drivers/pci/bus.c > > > @@ -337,6 +337,8 @@ void pci_bus_add_device(struct pci_dev *dev) > > > */ > > > pcibios_bus_add_device(dev); > > > pci_fixup_device(pci_fixup_final, dev); > > > + if (pci_is_bridge(dev)) > > > + of_pci_make_dev_node(dev); > > > pci_create_sysfs_dev_files(dev); > > > pci_proc_attach_device(dev); > > > pci_bridge_d3_update(dev); > > > diff --git a/drivers/pci/of.c b/drivers/pci/of.c > > > index d84381ce82b5..7bc2d186358e 100644 > > > --- a/drivers/pci/of.c > > > +++ b/drivers/pci/of.c > > > @@ -599,6 +599,85 @@ int devm_of_pci_bridge_init(struct device *dev, > > > struct pci_host_bridge *bridge) > > > return pci_parse_request_of_pci_ranges(dev, bridge); > > > } > > > > > > +#ifdef CONFIG_PCI_DYNAMIC_OF_NODES > > > + > > > +void of_pci_remove_node(struct pci_dev *pdev) > > > +{ > > > + struct device_node *np; > > > + > > > + np = pci_device_to_OF_node(pdev); > > > + if (!np || !of_node_check_flag(np, OF_DYNAMIC)) > > > + return; > > > + pdev->dev.of_node = NULL; > > > + > > > + of_changeset_revert(np->data); > > > + of_changeset_destroy(np->data); > > > + of_node_put(np); > > > +} > > > + > > > +void of_pci_make_dev_node(struct pci_dev *pdev) > > > +{ > > > + struct device_node *ppnode, *np = NULL; > > > + const char *pci_type; > > > + struct of_changeset *cset; > > > + const char *name; > > > + int ret; > > > + > > > + /* > > > + * If there is already a device tree node linked to this device, > > > + * return immediately. > > > + */ > > > + if (pci_device_to_OF_node(pdev)) > > > + return; > > > + > > > + /* Check if there is device tree node for parent device */ > > > + if (!pdev->bus->self) > > > + ppnode = pdev->bus->dev.of_node; > > > + else > > > + ppnode = pdev->bus->self->dev.of_node; > > > + if (!ppnode) > > > + return; > > > + > > > + if (pci_is_bridge(pdev)) > > > + pci_type = "pci"; > > > + else > > > + pci_type = "dev"; > > > + > > > + name = kasprintf(GFP_KERNEL, "%s@%x,%x", pci_type, > > > + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); > > > + if (!name) > > > + return; > > > + > > > + cset = kmalloc(sizeof(*cset), GFP_KERNEL); > > > + if (!cset) > > > + goto failed; > > > + of_changeset_init(cset); > > > + > > > + np = of_changeset_create_node(cset, ppnode, name); > > > + if (!np) > > > + goto failed; > > > + np->data = cset; > > > + > > > + ret = of_pci_add_properties(pdev, cset, np); > > > + if (ret) > > > + goto failed; > > > + > > > + ret = of_changeset_apply(cset); > > > + if (ret) > > > + goto failed; > > > + > > > + pdev->dev.of_node = np; > > > + kfree(name); > > > + > > > + return; > > > + > > > +failed: > > > + if (np) > > > + of_node_put(np); > > > + kfree(name); > > > +} > > > +#endif > > > + > > > #endif /* CONFIG_PCI */ > > > > > > /** > > > diff --git a/drivers/pci/of_property.c b/drivers/pci/of_property.c > > > new file mode 100644 > > > index 000000000000..c2c7334152bc > > > --- /dev/null > > > +++ b/drivers/pci/of_property.c > > > @@ -0,0 +1,366 @@ > > > +// SPDX-License-Identifier: GPL-2.0+ > > > +/* > > > + * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. > > > + */ > > > + > > > +#include <linux/pci.h> > > > +#include <linux/of.h> > > > +#include <linux/of_irq.h> > > > +#include <linux/bitfield.h> > > > +#include <linux/bits.h> > > > +#include "pci.h" > > > + > > > +#define OF_PCI_ADDRESS_CELLS 3 > > > +#define OF_PCI_SIZE_CELLS 2 > > > +#define OF_PCI_MAX_INT_PIN 4 > > > + > > > +struct of_pci_addr_pair { > > > + u32 phys_addr[OF_PCI_ADDRESS_CELLS]; > > > + u32 size[OF_PCI_SIZE_CELLS]; > > > +}; > > > + > > > +/* > > > + * Each entry in the ranges table is a tuple containing the child > > > address, > > > + * the parent address, and the size of the region in the child address > > > space. > > > + * Thus, for PCI, in each entry parent address is an address on the > > > primary > > > + * side and the child address is the corresponding address on the > > > secondary > > > + * side. > > > + */ > > > +struct of_pci_range { > > > + u32 child_addr[OF_PCI_ADDRESS_CELLS]; > > > + u32 parent_addr[OF_PCI_ADDRESS_CELLS]; > > > + u32 size[OF_PCI_SIZE_CELLS]; > > > +}; > > > + > > > +#define OF_PCI_ADDR_SPACE_IO 0x1 > > > +#define OF_PCI_ADDR_SPACE_MEM32 0x2 > > > +#define OF_PCI_ADDR_SPACE_MEM64 0x3 > > > + > > > +#define OF_PCI_ADDR_FIELD_NONRELOC BIT(31) > > > +#define OF_PCI_ADDR_FIELD_SS GENMASK(25, 24) > > > +#define OF_PCI_ADDR_FIELD_PREFETCH BIT(30) > > > +#define OF_PCI_ADDR_FIELD_BUS GENMASK(23, 16) > > > +#define OF_PCI_ADDR_FIELD_DEV GENMASK(15, 11) > > > +#define OF_PCI_ADDR_FIELD_FUNC GENMASK(10, 8) > > > +#define OF_PCI_ADDR_FIELD_REG GENMASK(7, 0) > > > + > > > +enum of_pci_prop_compatible { > > > + PROP_COMPAT_PCI_VVVV_DDDD, > > > + PROP_COMPAT_PCICLASS_CCSSPP, > > > + PROP_COMPAT_PCICLASS_CCSS, > > > + PROP_COMPAT_NUM, > > > +}; > > > + > > > +static void of_pci_set_address(struct pci_dev *pdev, u32 *prop, u64 addr, > > > + u32 reg_num, u32 flags, bool reloc) > > > +{ > > > + prop[0] = FIELD_PREP(OF_PCI_ADDR_FIELD_BUS, pdev->bus->number) | > > > + FIELD_PREP(OF_PCI_ADDR_FIELD_DEV, PCI_SLOT(pdev->devfn)) | > > > + FIELD_PREP(OF_PCI_ADDR_FIELD_FUNC, PCI_FUNC(pdev->devfn)); > > > + prop[0] |= flags | reg_num; > > > + if (!reloc) { > > > + prop[0] |= OF_PCI_ADDR_FIELD_NONRELOC; > > > + prop[1] = upper_32_bits(addr); > > > + prop[2] = lower_32_bits(addr); > > > + } > > > +} > > > + > > > +static int of_pci_get_addr_flags(struct resource *res, u32 *flags) > > > +{ > > > + u32 ss; > > > + > > > + if (res->flags & IORESOURCE_IO) > > > + ss = OF_PCI_ADDR_SPACE_IO; > > > + else if (res->flags & IORESOURCE_MEM_64) > > > + ss = OF_PCI_ADDR_SPACE_MEM64; > > > + else if (res->flags & IORESOURCE_MEM) > > > + ss = OF_PCI_ADDR_SPACE_MEM32; > > > + else > > > + return -EINVAL; > > > + > > > + *flags = 0; > > > + if (res->flags & IORESOURCE_PREFETCH) > > > + *flags |= OF_PCI_ADDR_FIELD_PREFETCH; > > > + > > > + *flags |= FIELD_PREP(OF_PCI_ADDR_FIELD_SS, ss); > > > + > > > + return 0; > > > +} > > > + > > > +static int of_pci_prop_bus_range(struct pci_dev *pdev, > > > + struct of_changeset *ocs, > > > + struct device_node *np) > > > +{ > > > + u32 bus_range[] = { pdev->subordinate->busn_res.start, > > > + pdev->subordinate->busn_res.end }; > > > + > > > + return of_changeset_add_prop_u32_array(ocs, np, "bus-range", > > > bus_range, > > > + ARRAY_SIZE(bus_range)); > > > +} > > > + > > > +static int of_pci_prop_ranges(struct pci_dev *pdev, struct of_changeset > > > *ocs, > > > + struct device_node *np) > > > +{ > > > + struct of_pci_range *rp; > > > + struct resource *res; > > > + int i, j, ret; > > > + u32 flags, num; > > > + u64 val64; > > > + > > > + if (pci_is_bridge(pdev)) { > > > + num = PCI_BRIDGE_RESOURCE_NUM; > > > + res = &pdev->resource[PCI_BRIDGE_RESOURCES]; > > > + } else { > > > + num = PCI_STD_NUM_BARS; > > > + res = &pdev->resource[PCI_STD_RESOURCES]; > > > + } > > > + > > > + rp = kcalloc(num, sizeof(*rp), GFP_KERNEL); > > > + if (!rp) > > > + return -ENOMEM; > > > + > > > + for (i = 0, j = 0; j < num; j++) { > > > + if (!resource_size(&res[j])) > > > + continue; > > > + > > > + if (of_pci_get_addr_flags(&res[j], &flags)) > > > + continue; > > > + > > > + val64 = res[j].start; > > > + of_pci_set_address(pdev, rp[i].parent_addr, val64, 0, > > > flags, > > > + false); > > > + if (pci_is_bridge(pdev)) { > > > + memcpy(rp[i].child_addr, rp[i].parent_addr, > > > + sizeof(rp[i].child_addr)); > > > + } else { > > > + /* > > > + * For endpoint device, the lower 64-bits of child > > > + * address is always zero. > > > + */ > > > + rp[i].child_addr[0] = j; > > > + } > > > + > > > + val64 = resource_size(&res[j]); > > > + rp[i].size[0] = upper_32_bits(val64); > > > + rp[i].size[1] = lower_32_bits(val64); > > > + > > > + i++; > > > + } > > > + > > > + ret = of_changeset_add_prop_u32_array(ocs, np, "ranges", (u32 > > > *)rp, > > > + i * sizeof(*rp) / > > > sizeof(u32)); > > > + kfree(rp); > > > + > > > + return ret; > > > +} > > > + > > > +static int of_pci_prop_reg(struct pci_dev *pdev, struct of_changeset > > > *ocs, > > > + struct device_node *np) > > > +{ > > > + struct of_pci_addr_pair reg = { 0 }; > > > + > > > + /* configuration space */ > > > + of_pci_set_address(pdev, reg.phys_addr, 0, 0, 0, true); > > > + > > > + return of_changeset_add_prop_u32_array(ocs, np, "reg", (u32 > > > *)®, > > > + sizeof(reg) / sizeof(u32)); > > > +} > > > + > > > +static int of_pci_prop_interrupts(struct pci_dev *pdev, > > > + struct of_changeset *ocs, > > > + struct device_node *np) > > > +{ > > > + int ret; > > > + u8 pin; > > > + > > > + ret = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin); > > > + if (ret != 0) > > > + return ret; > > > + > > > + if (!pin) > > > + return 0; > > > + > > > + return of_changeset_add_prop_u32(ocs, np, "interrupts", (u32)pin); > > > +} > > > + > > > +static int of_pci_prop_intr_map(struct pci_dev *pdev, struct > > > of_changeset *ocs, > > > + struct device_node *np) > > > +{ > > > + u32 i, addr_sz[OF_PCI_MAX_INT_PIN] = { 0 }, map_sz = 0; > > > + struct of_phandle_args out_irq[OF_PCI_MAX_INT_PIN]; > > > + __be32 laddr[OF_PCI_ADDRESS_CELLS] = { 0 }; > > > + u32 int_map_mask[] = { 0xffff00, 0, 0, 7 }; > > > + struct device_node *pnode; > > > + struct pci_dev *child; > > > + u32 *int_map, *mapp; > > > + int ret; > > > + u8 pin; > > > + > > > + pnode = pci_device_to_OF_node(pdev->bus->self); > > > + if (!pnode) > > > + pnode = pci_bus_to_OF_node(pdev->bus); > > > + > > > + if (!pnode) { > > > + pci_err(pdev, "failed to get parent device node"); > > > + return -EINVAL; > > > + } > > > + > > > + laddr[0] = cpu_to_be32((pdev->bus->number << 16) | (pdev->devfn > > > << 8)); > > > + for (pin = 1; pin <= OF_PCI_MAX_INT_PIN; pin++) { > > > + i = pin - 1; > > > + out_irq[i].np = pnode; > > > + out_irq[i].args_count = 1; > > > + out_irq[i].args[0] = pin; > > > + ret = of_irq_parse_raw(laddr, &out_irq[i]); > > > + if (ret) { > > > + out_irq[i].np = NULL; > > > + pci_dbg(pdev, "parse irq %d failed, ret %d", pin, > > > ret); > > > + continue; > > > + } > > > + of_property_read_u32(out_irq[i].np, "#address-cells", > > > + &addr_sz[i]); > > > + } > > > + > > > + list_for_each_entry(child, &pdev->subordinate->devices, bus_list) > > > { > > > + for (pin = 1; pin <= OF_PCI_MAX_INT_PIN; pin++) { > > > + i = pci_swizzle_interrupt_pin(child, pin) - 1; > > > + if (!out_irq[i].np) > > > + continue; > > > + map_sz += 5 + addr_sz[i] + out_irq[i].args_count; > > > + } > > > + } > > > + > > > + /* > > > + * Parsing interrupt failed for all pins. In this case, it does > > > not > > > + * need to generate interrupt-map property. > > > + */ > > > + if (!map_sz) > > > + return 0; > > > + > > > + int_map = kcalloc(map_sz, sizeof(u32), GFP_KERNEL); > > > + mapp = int_map; > > > + > > > + list_for_each_entry(child, &pdev->subordinate->devices, bus_list) > > > { > > > + for (pin = 1; pin <= OF_PCI_MAX_INT_PIN; pin++) { > > > + i = pci_swizzle_interrupt_pin(child, pin) - 1; > > > + if (!out_irq[i].np) > > > + continue; > > > + > > > + *mapp = (child->bus->number << 16) | > > > + (child->devfn << 8); > > > + mapp += OF_PCI_ADDRESS_CELLS; > > > + *mapp = pin; > > > + mapp++; > > > + *mapp = out_irq[i].np->phandle; > > > + mapp++; > > > + if (addr_sz[i]) { > > > + ret = > > > of_property_read_u32_array(out_irq[i].np, > > > + "reg", > > > mapp, > > > + > > > addr_sz[i]); > > > + if (ret) > > > + goto failed; > > > + } > > > + mapp += addr_sz[i]; > > > + memcpy(mapp, out_irq[i].args, > > > + out_irq[i].args_count * sizeof(u32)); > > > + mapp += out_irq[i].args_count; > > > + } > > > + } > > > + > > > + ret = of_changeset_add_prop_u32_array(ocs, np, "interrupt-map", > > > int_map, > > > + map_sz); > > > + if (ret) > > > + goto failed; > > > + > > > + ret = of_changeset_add_prop_u32(ocs, np, "#interrupt-cells", 1); > > > + if (ret) > > > + goto failed; > > > + > > > + ret = of_changeset_add_prop_u32_array(ocs, np, > > > "interrupt-map-mask", > > > + int_map_mask, > > > + ARRAY_SIZE(int_map_mask)); > > > + if (ret) > > > + goto failed; > > > + > > > + kfree(int_map); > > > + return 0; > > > + > > > +failed: > > > + kfree(int_map); > > > + return ret; > > > +} > > > + > > > +static int of_pci_prop_compatible(struct pci_dev *pdev, > > > + struct of_changeset *ocs, > > > + struct device_node *np) > > > +{ > > > + const char *compat_strs[PROP_COMPAT_NUM] = { 0 }; > > > + int i, ret; > > > + > > > + compat_strs[PROP_COMPAT_PCI_VVVV_DDDD] = > > > + kasprintf(GFP_KERNEL, "pci%x,%x", pdev->vendor, > > > pdev->device); > > > + compat_strs[PROP_COMPAT_PCICLASS_CCSSPP] = > > > + kasprintf(GFP_KERNEL, "pciclass,%06x", pdev->class); > > > + compat_strs[PROP_COMPAT_PCICLASS_CCSS] = > > > + kasprintf(GFP_KERNEL, "pciclass,%04x", pdev->class >> 8); > > > + > > > + ret = of_changeset_add_prop_string_array(ocs, np, "compatible", > > > + compat_strs, > > > PROP_COMPAT_NUM); > > > + for (i = 0; i < PROP_COMPAT_NUM; i++) > > > + kfree(compat_strs[i]); > > > + > > > + return ret; > > > +} > > > + > > > +int of_pci_add_properties(struct pci_dev *pdev, struct of_changeset *ocs, > > > + struct device_node *np) > > > +{ > > > + int ret; > > > + > > > + /* > > > + * The added properties will be released when the > > > + * changeset is destroyed. > > > + */ > > > + if (pci_is_bridge(pdev)) { > > > + ret = of_changeset_add_prop_string(ocs, np, "device_type", > > > + "pci"); > > > + if (ret) > > > + return ret; > > > + > > > + ret = of_pci_prop_bus_range(pdev, ocs, np); > > > + if (ret) > > > + return ret; > > > + > > > + ret = of_pci_prop_intr_map(pdev, ocs, np); > > > + if (ret) > > > + return ret; > > > + } > > > + > > > + ret = of_pci_prop_ranges(pdev, ocs, np); > > > + if (ret) > > > + return ret; > > > + > > > + ret = of_changeset_add_prop_u32(ocs, np, "#address-cells", > > > + OF_PCI_ADDRESS_CELLS); > > > + if (ret) > > > + return ret; > > > + > > > + ret = of_changeset_add_prop_u32(ocs, np, "#size-cells", > > > + OF_PCI_SIZE_CELLS); > > > + if (ret) > > > + return ret; > > > + > > > + ret = of_pci_prop_reg(pdev, ocs, np); > > > + if (ret) > > > + return ret; > > > + > > > + ret = of_pci_prop_compatible(pdev, ocs, np); > > > + if (ret) > > > + return ret; > > > + > > > + ret = of_pci_prop_interrupts(pdev, ocs, np); > > > + if (ret) > > > + return ret; > > > + > > > + return 0; > > > +} > > > diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h > > > index ec968b14aa2a..1e8f0447f2bf 100644 > > > --- a/drivers/pci/pci.h > > > +++ b/drivers/pci/pci.h > > > @@ -695,6 +695,18 @@ static inline int devm_of_pci_bridge_init(struct > > > device *dev, struct pci_host_br > > > > > > #endif /* CONFIG_OF */ > > > > > > +struct of_changeset; > > > + > > > +#ifdef CONFIG_PCI_DYNAMIC_OF_NODES > > > +void of_pci_make_dev_node(struct pci_dev *pdev); > > > +void of_pci_remove_node(struct pci_dev *pdev); > > > +int of_pci_add_properties(struct pci_dev *pdev, struct of_changeset *ocs, > > > + struct device_node *np); > > > +#else > > > +static inline void of_pci_make_dev_node(struct pci_dev *pdev) { } > > > +static inline void of_pci_remove_node(struct pci_dev *pdev) { } > > > +#endif > > > + > > > #ifdef CONFIG_PCIEAER > > > void pci_no_aer(void); > > > void pci_aer_init(struct pci_dev *dev); > > > diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c > > > index 7c95360ec72b..22efbf10bd38 100644 > > > --- a/drivers/pci/quirks.c > > > +++ b/drivers/pci/quirks.c > > > @@ -6251,3 +6251,14 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, > > > 0x9a31, dpc_log_size); > > > DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0xa73f, dpc_log_size); > > > DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0xa76e, dpc_log_size); > > > #endif > > > + > > > +/* > > > + * For a PCI device with multiple downstream devices, its driver may use > > > + * a flattened device tree to describe the downstream devices. > > > + * To overlay the flattened device tree, the PCI device and all its > > > ancestor > > > + * devices need to have device tree nodes on system base device tree. > > > Thus, > > > + * before driver probing, it might need to add a device tree node as the > > > final > > > + * fixup. > > > + */ > > > +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_XILINX, 0x5020, > > > of_pci_make_dev_node); > > > +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_XILINX, 0x5021, > > > of_pci_make_dev_node); > > > diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c > > > index 4c54c75050dc..0eaa9d9a3609 100644 > > > --- a/drivers/pci/remove.c > > > +++ b/drivers/pci/remove.c > > > @@ -23,6 +23,7 @@ static void pci_stop_dev(struct pci_dev *dev) > > > device_release_driver(&dev->dev); > > > pci_proc_detach_device(dev); > > > pci_remove_sysfs_dev_files(dev); > > > + of_pci_remove_node(dev); > > > > > > pci_dev_assign_added(dev, false); > > > } > > > diff --git a/include/linux/of.h b/include/linux/of.h > > > index 7d3fe595216b..3e414c51d2f3 100644 > > > --- a/include/linux/of.h > > > +++ b/include/linux/of.h > > > @@ -1439,6 +1439,29 @@ static inline int > > > of_changeset_update_property(struct of_changeset *ocs, > > > { > > > return of_changeset_action(ocs, OF_RECONFIG_UPDATE_PROPERTY, np, > > > prop); > > > } > > > + > > > +struct device_node *of_changeset_create_node(struct of_changeset *ocs, > > > + struct device_node *parent, > > > + const char *full_name); > > > +int of_changeset_add_prop_string(struct of_changeset *ocs, > > > + struct device_node *np, > > > + const char *prop_name, const char *str); > > > +int of_changeset_add_prop_string_array(struct of_changeset *ocs, > > > + struct device_node *np, > > > + const char *prop_name, > > > + const char **str_array, size_t sz); > > > +int of_changeset_add_prop_u32_array(struct of_changeset *ocs, > > > + struct device_node *np, > > > + const char *prop_name, > > > + const u32 *array, size_t sz); > > > +static inline int of_changeset_add_prop_u32(struct of_changeset *ocs, > > > + struct device_node *np, > > > + const char *prop_name, > > > + const u32 val) > > > +{ > > > + return of_changeset_add_prop_u32_array(ocs, np, prop_name, &val, > > > 1); > > > +} > > > + > > > #else /* CONFIG_OF_DYNAMIC */ > > > static inline int of_reconfig_notifier_register(struct notifier_block > > > *nb) > > > { > > > @@ -1504,7 +1527,7 @@ 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 *ovcs_id, struct device_node *target_base); > > > int of_overlay_remove(int *ovcs_id); > > > int of_overlay_remove_all(void); > > > > > > > > > --- > > > base-commit: 1d865ddc92bf9b1820a68102ae553404c2d14a2e > > > change-id: 20241022-v5-15-cn96xx-70c15bc23fd3 > > > > > > Best regards, > > > -- > > > Kevin Hao <haoke...@gmail.com> > > > > > > > > > -- > > - Thou shalt not follow the NULL pointer, for chaos and madness await > > thee at its end > > - "Use the force Harry" - Gandalf, Star Trek II
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#14502): https://lists.yoctoproject.org/g/linux-yocto/message/14502 Mute This Topic: https://lists.yoctoproject.org/mt/109147042/21656 Group Owner: linux-yocto+ow...@lists.yoctoproject.org Unsubscribe: https://lists.yoctoproject.org/g/linux-yocto/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-