#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>
 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);
        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),
 
 #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;
        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();