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 
> > > *)&reg,
> > > +                                              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]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to