Skip to content

Commit 26409dd

Browse files
houlz0507robherring
authored andcommitted
of: unittest: Add pci_dt_testdrv pci driver
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 <[email protected]> Signed-off-by: Lizhi Hou <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Rob Herring <[email protected]>
1 parent 4728486 commit 26409dd

File tree

4 files changed

+214
-1
lines changed

4 files changed

+214
-1
lines changed

drivers/of/unittest-data/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ obj-$(CONFIG_OF_OVERLAY) += overlay.dtbo.o \
3232
overlay_gpio_02b.dtbo.o \
3333
overlay_gpio_03.dtbo.o \
3434
overlay_gpio_04a.dtbo.o \
35-
overlay_gpio_04b.dtbo.o
35+
overlay_gpio_04b.dtbo.o \
36+
overlay_pci_node.dtbo.o
3637

3738
# enable creation of __symbols__ node
3839
DTC_FLAGS_overlay += -@
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/dts-v1/;
3+
/ {
4+
fragment@0 {
5+
target-path="";
6+
__overlay__ {
7+
#address-cells = <3>;
8+
#size-cells = <2>;
9+
pci-ep-bus@0 {
10+
compatible = "simple-bus";
11+
#address-cells = <1>;
12+
#size-cells = <1>;
13+
ranges = <0x0 0x0 0x0 0x0 0x1000>;
14+
reg = <0 0 0 0 0>;
15+
unittest-pci@100 {
16+
compatible = "unittest-pci";
17+
reg = <0x100 0x200>;
18+
};
19+
};
20+
};
21+
};
22+
};

drivers/of/unittest.c

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/slab.h>
2323
#include <linux/device.h>
2424
#include <linux/platform_device.h>
25+
#include <linux/pci.h>
2526
#include <linux/kernel.h>
2627

2728
#include <linux/i2c.h>
@@ -3326,6 +3327,7 @@ OVERLAY_INFO_EXTERN(overlay_gpio_02b);
33263327
OVERLAY_INFO_EXTERN(overlay_gpio_03);
33273328
OVERLAY_INFO_EXTERN(overlay_gpio_04a);
33283329
OVERLAY_INFO_EXTERN(overlay_gpio_04b);
3330+
OVERLAY_INFO_EXTERN(overlay_pci_node);
33293331
OVERLAY_INFO_EXTERN(overlay_bad_add_dup_node);
33303332
OVERLAY_INFO_EXTERN(overlay_bad_add_dup_prop);
33313333
OVERLAY_INFO_EXTERN(overlay_bad_phandle);
@@ -3361,6 +3363,7 @@ static struct overlay_info overlays[] = {
33613363
OVERLAY_INFO(overlay_gpio_03, 0),
33623364
OVERLAY_INFO(overlay_gpio_04a, 0),
33633365
OVERLAY_INFO(overlay_gpio_04b, 0),
3366+
OVERLAY_INFO(overlay_pci_node, 0),
33643367
OVERLAY_INFO(overlay_bad_add_dup_node, -EINVAL),
33653368
OVERLAY_INFO(overlay_bad_add_dup_prop, -EINVAL),
33663369
OVERLAY_INFO(overlay_bad_phandle, -EINVAL),
@@ -3731,6 +3734,191 @@ static inline __init void of_unittest_overlay_high_level(void) {}
37313734

37323735
#endif
37333736

3737+
#ifdef CONFIG_PCI_DYNAMIC_OF_NODES
3738+
3739+
static int of_unittest_pci_dev_num;
3740+
static int of_unittest_pci_child_num;
3741+
3742+
/*
3743+
* PCI device tree node test driver
3744+
*/
3745+
static const struct pci_device_id testdrv_pci_ids[] = {
3746+
{ PCI_DEVICE(PCI_VENDOR_ID_REDHAT, 0x5), }, /* PCI_VENDOR_ID_REDHAT */
3747+
{ 0, }
3748+
};
3749+
3750+
static int testdrv_probe(struct pci_dev *pdev, const struct pci_device_id *id)
3751+
{
3752+
struct overlay_info *info;
3753+
struct device_node *dn;
3754+
int ret, ovcs_id;
3755+
u32 size;
3756+
3757+
dn = pdev->dev.of_node;
3758+
if (!dn) {
3759+
dev_err(&pdev->dev, "does not find bus endpoint");
3760+
return -EINVAL;
3761+
}
3762+
3763+
for (info = overlays; info && info->name; info++) {
3764+
if (!strcmp(info->name, "overlay_pci_node"))
3765+
break;
3766+
}
3767+
if (!info || !info->name) {
3768+
dev_err(&pdev->dev, "no overlay data for overlay_pci_node");
3769+
return -ENODEV;
3770+
}
3771+
3772+
size = info->dtbo_end - info->dtbo_begin;
3773+
ret = of_overlay_fdt_apply(info->dtbo_begin, size, &ovcs_id, dn);
3774+
of_node_put(dn);
3775+
if (ret)
3776+
return ret;
3777+
3778+
of_platform_default_populate(dn, NULL, &pdev->dev);
3779+
pci_set_drvdata(pdev, (void *)(uintptr_t)ovcs_id);
3780+
3781+
return 0;
3782+
}
3783+
3784+
static void testdrv_remove(struct pci_dev *pdev)
3785+
{
3786+
int ovcs_id = (int)(uintptr_t)pci_get_drvdata(pdev);
3787+
3788+
of_platform_depopulate(&pdev->dev);
3789+
of_overlay_remove(&ovcs_id);
3790+
}
3791+
3792+
static struct pci_driver testdrv_driver = {
3793+
.name = "pci_dt_testdrv",
3794+
.id_table = testdrv_pci_ids,
3795+
.probe = testdrv_probe,
3796+
.remove = testdrv_remove,
3797+
};
3798+
3799+
static int unittest_pci_probe(struct platform_device *pdev)
3800+
{
3801+
struct resource *res;
3802+
struct device *dev;
3803+
u64 exp_addr;
3804+
3805+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3806+
if (!res)
3807+
return -ENODEV;
3808+
3809+
dev = &pdev->dev;
3810+
while (dev && !dev_is_pci(dev))
3811+
dev = dev->parent;
3812+
if (!dev) {
3813+
pr_err("unable to find parent device\n");
3814+
return -ENODEV;
3815+
}
3816+
3817+
exp_addr = pci_resource_start(to_pci_dev(dev), 0) + 0x100;
3818+
unittest(res->start == exp_addr, "Incorrect translated address %llx, expected %llx\n",
3819+
(u64)res->start, exp_addr);
3820+
3821+
of_unittest_pci_child_num++;
3822+
3823+
return 0;
3824+
}
3825+
3826+
static const struct of_device_id unittest_pci_of_match[] = {
3827+
{ .compatible = "unittest-pci" },
3828+
{ }
3829+
};
3830+
3831+
static struct platform_driver unittest_pci_driver = {
3832+
.probe = unittest_pci_probe,
3833+
.driver = {
3834+
.name = "unittest-pci",
3835+
.of_match_table = unittest_pci_of_match,
3836+
},
3837+
};
3838+
3839+
static int of_unittest_pci_node_verify(struct pci_dev *pdev, bool add)
3840+
{
3841+
struct device_node *pnp, *np = NULL;
3842+
struct device *child_dev;
3843+
char *path = NULL;
3844+
const __be32 *reg;
3845+
int rc = 0;
3846+
3847+
pnp = pdev->dev.of_node;
3848+
unittest(pnp, "Failed creating PCI dt node\n");
3849+
if (!pnp)
3850+
return -ENODEV;
3851+
3852+
if (add) {
3853+
path = kasprintf(GFP_KERNEL, "%pOF/pci-ep-bus@0/unittest-pci@100", pnp);
3854+
np = of_find_node_by_path(path);
3855+
unittest(np, "Failed to get unittest-pci node under PCI node\n");
3856+
if (!np) {
3857+
rc = -ENODEV;
3858+
goto failed;
3859+
}
3860+
3861+
reg = of_get_property(np, "reg", NULL);
3862+
unittest(reg, "Failed to get reg property\n");
3863+
if (!reg)
3864+
rc = -ENODEV;
3865+
} else {
3866+
path = kasprintf(GFP_KERNEL, "%pOF/pci-ep-bus@0", pnp);
3867+
np = of_find_node_by_path(path);
3868+
unittest(!np, "Child device tree node is not removed\n");
3869+
child_dev = device_find_any_child(&pdev->dev);
3870+
unittest(!child_dev, "Child device is not removed\n");
3871+
}
3872+
3873+
failed:
3874+
kfree(path);
3875+
if (np)
3876+
of_node_put(np);
3877+
3878+
return rc;
3879+
}
3880+
3881+
static void __init of_unittest_pci_node(void)
3882+
{
3883+
struct pci_dev *pdev = NULL;
3884+
int rc;
3885+
3886+
rc = pci_register_driver(&testdrv_driver);
3887+
unittest(!rc, "Failed to register pci test driver; rc = %d\n", rc);
3888+
if (rc)
3889+
return;
3890+
3891+
rc = platform_driver_register(&unittest_pci_driver);
3892+
if (unittest(!rc, "Failed to register unittest pci driver\n")) {
3893+
pci_unregister_driver(&testdrv_driver);
3894+
return;
3895+
}
3896+
3897+
while ((pdev = pci_get_device(PCI_VENDOR_ID_REDHAT, 0x5, pdev)) != NULL) {
3898+
of_unittest_pci_node_verify(pdev, true);
3899+
of_unittest_pci_dev_num++;
3900+
}
3901+
if (pdev)
3902+
pci_dev_put(pdev);
3903+
3904+
unittest(of_unittest_pci_dev_num,
3905+
"No test PCI device been found. Please run QEMU with '-device pci-testdev'\n");
3906+
unittest(of_unittest_pci_dev_num == of_unittest_pci_child_num,
3907+
"Child device number %d is not expected %d", of_unittest_pci_child_num,
3908+
of_unittest_pci_dev_num);
3909+
3910+
platform_driver_unregister(&unittest_pci_driver);
3911+
pci_unregister_driver(&testdrv_driver);
3912+
3913+
while ((pdev = pci_get_device(PCI_VENDOR_ID_REDHAT, 0x5, pdev)) != NULL)
3914+
of_unittest_pci_node_verify(pdev, false);
3915+
if (pdev)
3916+
pci_dev_put(pdev);
3917+
}
3918+
#else
3919+
static void __init of_unittest_pci_node(void) { }
3920+
#endif
3921+
37343922
static int __init of_unittest(void)
37353923
{
37363924
struct device_node *np;
@@ -3781,6 +3969,7 @@ static int __init of_unittest(void)
37813969
of_unittest_platform_populate();
37823970
of_unittest_overlay();
37833971
of_unittest_lifecycle();
3972+
of_unittest_pci_node();
37843973

37853974
/* Double check linkage after removing testcase data */
37863975
of_unittest_check_tree_linkage();

drivers/pci/quirks.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6149,3 +6149,4 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a31, dpc_log_size);
61496149
*/
61506150
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_XILINX, 0x5020, of_pci_make_dev_node);
61516151
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_XILINX, 0x5021, of_pci_make_dev_node);
6152+
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_REDHAT, 0x0005, of_pci_make_dev_node);

0 commit comments

Comments
 (0)