+++ /dev/null
-From f379b0f4937323cbd8bfc85811fb3e68ecfd64a0 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 15 Aug 2023 10:19:59 -0700
-Subject: of: overlay: Extend of_overlay_fdt_apply() to specify the target node
-
-From: Lizhi Hou <lizhi.hou@amd.com>
-
-[ Upstream commit 47284862bfc7fd5672e731e827f43f26bdbd155c ]
-
-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>
-Stable-dep-of: c9260693aa0c ("PCI: Lengthen reset delay for VideoPropulsion Torrent QN16e card")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/of/overlay.c | 42 +++++++++++++++++++++++++++++++-----------
- drivers/of/unittest.c | 3 ++-
- include/linux/of.h | 2 +-
- 3 files changed, 34 insertions(+), 13 deletions(-)
-
-diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
-index 28b479afd506f..dfb6fb962fc70 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,7 +916,8 @@ 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;
-
-@@ -906,7 +925,7 @@ static int of_overlay_apply(struct overlay_changeset *ovcs)
- if (ret)
- goto out;
-
-- ret = init_overlay_changeset(ovcs);
-+ ret = init_overlay_changeset(ovcs, base);
- if (ret)
- goto out;
-
-@@ -950,6 +969,7 @@ static int of_overlay_apply(struct overlay_changeset *ovcs)
- * @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.
- *
-@@ -965,7 +985,7 @@ static int of_overlay_apply(struct overlay_changeset *ovcs)
- */
-
- 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;
-@@ -1036,7 +1056,7 @@ int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
- }
- ovcs->overlay_mem = overlay_mem;
-
-- ret = of_overlay_apply(ovcs);
-+ 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
-diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
-index 68e58b085c3db..c812a0175d1d3 100644
---- a/drivers/of/unittest.c
-+++ b/drivers/of/unittest.c
-@@ -3480,7 +3480,8 @@ static int __init overlay_data_apply(const char *overlay_name, int *ovcs_id)
- if (!size)
- pr_err("no overlay data for %s\n", overlay_name);
-
-- ret = of_overlay_fdt_apply(info->dtbo_begin, size, &info->ovcs_id);
-+ ret = of_overlay_fdt_apply(info->dtbo_begin, size, &info->ovcs_id,
-+ NULL);
- if (ovcs_id)
- *ovcs_id = info->ovcs_id;
- if (ret < 0)
-diff --git a/include/linux/of.h b/include/linux/of.h
-index 9b82a6b0f3f55..722140b2e8abd 100644
---- a/include/linux/of.h
-+++ b/include/linux/of.h
-@@ -1668,7 +1668,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);
-
---
-2.42.0
-
+++ /dev/null
-From 56b0b554be0b5d4fb8148a4071bf9eaa48bed3c8 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 15 Aug 2023 10:20:00 -0700
-Subject: of: unittest: Add pci_dt_testdrv pci driver
-
-From: Lizhi Hou <lizhi.hou@amd.com>
-
-[ Upstream commit 26409dd045892904b059dc411403e9c8ce7543ca ]
-
-pci_dt_testdrv is bound to QEMU PCI Test Device. It reads
-overlay_pci_node fdt fragment and apply it to Test Device. Then it
-calls of_platform_default_populate() to populate the platform
-devices.
-
-Tested-by: Herve Codina <herve.codina@bootlin.com>
-Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
-Link: https://lore.kernel.org/r/1692120000-46900-6-git-send-email-lizhi.hou@amd.com
-Signed-off-by: Rob Herring <robh@kernel.org>
-Stable-dep-of: c9260693aa0c ("PCI: Lengthen reset delay for VideoPropulsion Torrent QN16e card")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/of/unittest-data/Makefile | 3 +-
- .../of/unittest-data/overlay_pci_node.dtso | 22 ++
- drivers/of/unittest.c | 189 ++++++++++++++++++
- drivers/pci/quirks.c | 1 +
- 4 files changed, 214 insertions(+), 1 deletion(-)
- create mode 100644 drivers/of/unittest-data/overlay_pci_node.dtso
-
-diff --git a/drivers/of/unittest-data/Makefile b/drivers/of/unittest-data/Makefile
-index ea5f4da68e23a..1aa8750881598 100644
---- a/drivers/of/unittest-data/Makefile
-+++ b/drivers/of/unittest-data/Makefile
-@@ -32,7 +32,8 @@ obj-$(CONFIG_OF_OVERLAY) += overlay.dtbo.o \
- overlay_gpio_02b.dtbo.o \
- overlay_gpio_03.dtbo.o \
- overlay_gpio_04a.dtbo.o \
-- overlay_gpio_04b.dtbo.o
-+ overlay_gpio_04b.dtbo.o \
-+ overlay_pci_node.dtbo.o
-
- # enable creation of __symbols__ node
- DTC_FLAGS_overlay += -@
-diff --git a/drivers/of/unittest-data/overlay_pci_node.dtso b/drivers/of/unittest-data/overlay_pci_node.dtso
-new file mode 100644
-index 0000000000000..c05e52e9e44a9
---- /dev/null
-+++ b/drivers/of/unittest-data/overlay_pci_node.dtso
-@@ -0,0 +1,22 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/dts-v1/;
-+/ {
-+ fragment@0 {
-+ target-path="";
-+ __overlay__ {
-+ #address-cells = <3>;
-+ #size-cells = <2>;
-+ pci-ep-bus@0 {
-+ compatible = "simple-bus";
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+ ranges = <0x0 0x0 0x0 0x0 0x1000>;
-+ reg = <0 0 0 0 0>;
-+ unittest-pci@100 {
-+ compatible = "unittest-pci";
-+ reg = <0x100 0x200>;
-+ };
-+ };
-+ };
-+ };
-+};
-diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
-index c812a0175d1d3..f5faabf320ec9 100644
---- a/drivers/of/unittest.c
-+++ b/drivers/of/unittest.c
-@@ -22,6 +22,7 @@
- #include <linux/slab.h>
- #include <linux/device.h>
- #include <linux/platform_device.h>
-+#include <linux/pci.h>
- #include <linux/kernel.h>
-
- #include <linux/i2c.h>
-@@ -3326,6 +3327,7 @@ OVERLAY_INFO_EXTERN(overlay_gpio_02b);
- OVERLAY_INFO_EXTERN(overlay_gpio_03);
- OVERLAY_INFO_EXTERN(overlay_gpio_04a);
- OVERLAY_INFO_EXTERN(overlay_gpio_04b);
-+OVERLAY_INFO_EXTERN(overlay_pci_node);
- OVERLAY_INFO_EXTERN(overlay_bad_add_dup_node);
- OVERLAY_INFO_EXTERN(overlay_bad_add_dup_prop);
- OVERLAY_INFO_EXTERN(overlay_bad_phandle);
-@@ -3361,6 +3363,7 @@ static struct overlay_info overlays[] = {
- OVERLAY_INFO(overlay_gpio_03, 0),
- OVERLAY_INFO(overlay_gpio_04a, 0),
- OVERLAY_INFO(overlay_gpio_04b, 0),
-+ OVERLAY_INFO(overlay_pci_node, 0),
- OVERLAY_INFO(overlay_bad_add_dup_node, -EINVAL),
- OVERLAY_INFO(overlay_bad_add_dup_prop, -EINVAL),
- OVERLAY_INFO(overlay_bad_phandle, -EINVAL),
-@@ -3731,6 +3734,191 @@ static inline __init void of_unittest_overlay_high_level(void) {}
-
- #endif
-
-+#ifdef CONFIG_PCI_DYNAMIC_OF_NODES
-+
-+static int of_unittest_pci_dev_num;
-+static int of_unittest_pci_child_num;
-+
-+/*
-+ * PCI device tree node test driver
-+ */
-+static const struct pci_device_id testdrv_pci_ids[] = {
-+ { PCI_DEVICE(PCI_VENDOR_ID_REDHAT, 0x5), }, /* PCI_VENDOR_ID_REDHAT */
-+ { 0, }
-+};
-+
-+static int testdrv_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-+{
-+ struct overlay_info *info;
-+ struct device_node *dn;
-+ int ret, ovcs_id;
-+ u32 size;
-+
-+ dn = pdev->dev.of_node;
-+ if (!dn) {
-+ dev_err(&pdev->dev, "does not find bus endpoint");
-+ return -EINVAL;
-+ }
-+
-+ for (info = overlays; info && info->name; info++) {
-+ if (!strcmp(info->name, "overlay_pci_node"))
-+ break;
-+ }
-+ if (!info || !info->name) {
-+ dev_err(&pdev->dev, "no overlay data for overlay_pci_node");
-+ return -ENODEV;
-+ }
-+
-+ size = info->dtbo_end - info->dtbo_begin;
-+ ret = of_overlay_fdt_apply(info->dtbo_begin, size, &ovcs_id, dn);
-+ of_node_put(dn);
-+ if (ret)
-+ return ret;
-+
-+ of_platform_default_populate(dn, NULL, &pdev->dev);
-+ pci_set_drvdata(pdev, (void *)(uintptr_t)ovcs_id);
-+
-+ return 0;
-+}
-+
-+static void testdrv_remove(struct pci_dev *pdev)
-+{
-+ int ovcs_id = (int)(uintptr_t)pci_get_drvdata(pdev);
-+
-+ of_platform_depopulate(&pdev->dev);
-+ of_overlay_remove(&ovcs_id);
-+}
-+
-+static struct pci_driver testdrv_driver = {
-+ .name = "pci_dt_testdrv",
-+ .id_table = testdrv_pci_ids,
-+ .probe = testdrv_probe,
-+ .remove = testdrv_remove,
-+};
-+
-+static int unittest_pci_probe(struct platform_device *pdev)
-+{
-+ struct resource *res;
-+ struct device *dev;
-+ u64 exp_addr;
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!res)
-+ return -ENODEV;
-+
-+ dev = &pdev->dev;
-+ while (dev && !dev_is_pci(dev))
-+ dev = dev->parent;
-+ if (!dev) {
-+ pr_err("unable to find parent device\n");
-+ return -ENODEV;
-+ }
-+
-+ exp_addr = pci_resource_start(to_pci_dev(dev), 0) + 0x100;
-+ unittest(res->start == exp_addr, "Incorrect translated address %llx, expected %llx\n",
-+ (u64)res->start, exp_addr);
-+
-+ of_unittest_pci_child_num++;
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id unittest_pci_of_match[] = {
-+ { .compatible = "unittest-pci" },
-+ { }
-+};
-+
-+static struct platform_driver unittest_pci_driver = {
-+ .probe = unittest_pci_probe,
-+ .driver = {
-+ .name = "unittest-pci",
-+ .of_match_table = unittest_pci_of_match,
-+ },
-+};
-+
-+static int of_unittest_pci_node_verify(struct pci_dev *pdev, bool add)
-+{
-+ struct device_node *pnp, *np = NULL;
-+ struct device *child_dev;
-+ char *path = NULL;
-+ const __be32 *reg;
-+ int rc = 0;
-+
-+ pnp = pdev->dev.of_node;
-+ unittest(pnp, "Failed creating PCI dt node\n");
-+ if (!pnp)
-+ return -ENODEV;
-+
-+ if (add) {
-+ path = kasprintf(GFP_KERNEL, "%pOF/pci-ep-bus@0/unittest-pci@100", pnp);
-+ np = of_find_node_by_path(path);
-+ unittest(np, "Failed to get unittest-pci node under PCI node\n");
-+ if (!np) {
-+ rc = -ENODEV;
-+ goto failed;
-+ }
-+
-+ reg = of_get_property(np, "reg", NULL);
-+ unittest(reg, "Failed to get reg property\n");
-+ if (!reg)
-+ rc = -ENODEV;
-+ } else {
-+ path = kasprintf(GFP_KERNEL, "%pOF/pci-ep-bus@0", pnp);
-+ np = of_find_node_by_path(path);
-+ unittest(!np, "Child device tree node is not removed\n");
-+ child_dev = device_find_any_child(&pdev->dev);
-+ unittest(!child_dev, "Child device is not removed\n");
-+ }
-+
-+failed:
-+ kfree(path);
-+ if (np)
-+ of_node_put(np);
-+
-+ return rc;
-+}
-+
-+static void __init of_unittest_pci_node(void)
-+{
-+ struct pci_dev *pdev = NULL;
-+ int rc;
-+
-+ rc = pci_register_driver(&testdrv_driver);
-+ unittest(!rc, "Failed to register pci test driver; rc = %d\n", rc);
-+ if (rc)
-+ return;
-+
-+ rc = platform_driver_register(&unittest_pci_driver);
-+ if (unittest(!rc, "Failed to register unittest pci driver\n")) {
-+ pci_unregister_driver(&testdrv_driver);
-+ return;
-+ }
-+
-+ while ((pdev = pci_get_device(PCI_VENDOR_ID_REDHAT, 0x5, pdev)) != NULL) {
-+ of_unittest_pci_node_verify(pdev, true);
-+ of_unittest_pci_dev_num++;
-+ }
-+ if (pdev)
-+ pci_dev_put(pdev);
-+
-+ unittest(of_unittest_pci_dev_num,
-+ "No test PCI device been found. Please run QEMU with '-device pci-testdev'\n");
-+ unittest(of_unittest_pci_dev_num == of_unittest_pci_child_num,
-+ "Child device number %d is not expected %d", of_unittest_pci_child_num,
-+ of_unittest_pci_dev_num);
-+
-+ platform_driver_unregister(&unittest_pci_driver);
-+ pci_unregister_driver(&testdrv_driver);
-+
-+ while ((pdev = pci_get_device(PCI_VENDOR_ID_REDHAT, 0x5, pdev)) != NULL)
-+ of_unittest_pci_node_verify(pdev, false);
-+ if (pdev)
-+ pci_dev_put(pdev);
-+}
-+#else
-+static void __init of_unittest_pci_node(void) { }
-+#endif
-+
- static int __init of_unittest(void)
- {
- struct device_node *np;
-@@ -3781,6 +3969,7 @@ static int __init of_unittest(void)
- of_unittest_platform_populate();
- of_unittest_overlay();
- of_unittest_lifecycle();
-+ of_unittest_pci_node();
-
- /* Double check linkage after removing testcase data */
- of_unittest_check_tree_linkage();
-diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
-index 3ec7bcfbf4dc0..7e9a14e430195 100644
---- a/drivers/pci/quirks.c
-+++ b/drivers/pci/quirks.c
-@@ -6172,3 +6172,4 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a31, dpc_log_size);
- */
- 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);
-+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_REDHAT, 0x0005, of_pci_make_dev_node);
---
-2.42.0
-