|
22 | 22 | #include <linux/slab.h> |
23 | 23 | #include <linux/device.h> |
24 | 24 | #include <linux/platform_device.h> |
| 25 | +#include <linux/pci.h> |
25 | 26 | #include <linux/kernel.h> |
26 | 27 |
|
27 | 28 | #include <linux/i2c.h> |
@@ -3326,6 +3327,7 @@ OVERLAY_INFO_EXTERN(overlay_gpio_02b); |
3326 | 3327 | OVERLAY_INFO_EXTERN(overlay_gpio_03); |
3327 | 3328 | OVERLAY_INFO_EXTERN(overlay_gpio_04a); |
3328 | 3329 | OVERLAY_INFO_EXTERN(overlay_gpio_04b); |
| 3330 | +OVERLAY_INFO_EXTERN(overlay_pci_node); |
3329 | 3331 | OVERLAY_INFO_EXTERN(overlay_bad_add_dup_node); |
3330 | 3332 | OVERLAY_INFO_EXTERN(overlay_bad_add_dup_prop); |
3331 | 3333 | OVERLAY_INFO_EXTERN(overlay_bad_phandle); |
@@ -3361,6 +3363,7 @@ static struct overlay_info overlays[] = { |
3361 | 3363 | OVERLAY_INFO(overlay_gpio_03, 0), |
3362 | 3364 | OVERLAY_INFO(overlay_gpio_04a, 0), |
3363 | 3365 | OVERLAY_INFO(overlay_gpio_04b, 0), |
| 3366 | + OVERLAY_INFO(overlay_pci_node, 0), |
3364 | 3367 | OVERLAY_INFO(overlay_bad_add_dup_node, -EINVAL), |
3365 | 3368 | OVERLAY_INFO(overlay_bad_add_dup_prop, -EINVAL), |
3366 | 3369 | OVERLAY_INFO(overlay_bad_phandle, -EINVAL), |
@@ -3731,6 +3734,191 @@ static inline __init void of_unittest_overlay_high_level(void) {} |
3731 | 3734 |
|
3732 | 3735 | #endif |
3733 | 3736 |
|
| 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 | + |
3734 | 3922 | static int __init of_unittest(void) |
3735 | 3923 | { |
3736 | 3924 | struct device_node *np; |
@@ -3781,6 +3969,7 @@ static int __init of_unittest(void) |
3781 | 3969 | of_unittest_platform_populate(); |
3782 | 3970 | of_unittest_overlay(); |
3783 | 3971 | of_unittest_lifecycle(); |
| 3972 | + of_unittest_pci_node(); |
3784 | 3973 |
|
3785 | 3974 | /* Double check linkage after removing testcase data */ |
3786 | 3975 | of_unittest_check_tree_linkage(); |
|
0 commit comments