PCI: Limit visibility of match_driver flag to PCI core
authorLukas Wunner <lukas@wunner.de>
Fri, 25 Apr 2025 09:24:22 +0000 (11:24 +0200)
committerKrzysztof Wilczyński <kwilczynski@kernel.org>
Thu, 15 May 2025 13:40:52 +0000 (13:40 +0000)
Since commit 58d9a38f6fac ("PCI: Skip attaching driver in device_add()"),
PCI enumeration is split into two steps:  In the first step, all devices
are published in sysfs with device_add().  In the second step, drivers are
bound to the devices with device_attach().  To delay driver binding until
the second step, a "bool match_driver" in struct pci_dev is used.

Instead of a bool, use a bit in the "unsigned long priv_flags" to shrink
struct pci_dev a little and prevent use of the bool outside the PCI core
(as has happened with commit cbbc00be2ce3 ("iommu/amd: Prevent binding
other PCI drivers to IOMMU PCI devices")).

Signed-off-by: Lukas Wunner <lukas@wunner.de>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
Link: https://patch.msgid.link/d22a9e5b81d6bd8dd1837607d6156679b3b1199c.1745572340.git.lukas@wunner.de
drivers/pci/bus.c
drivers/pci/pci-driver.c
drivers/pci/pci.h
drivers/pci/probe.c
include/linux/pci.h

index b6851101ac36425e3d9004a901ee0e5ff01f4df8..69048869ef1c378454f86091ddb2b59a3c3d53ec 100644 (file)
@@ -369,7 +369,9 @@ void pci_bus_add_device(struct pci_dev *dev)
                                pdev->name);
        }
 
-       dev->match_driver = !dn || of_device_is_available(dn);
+       if (!dn || of_device_is_available(dn))
+               pci_dev_allow_binding(dev);
+
        retval = device_attach(&dev->dev);
        if (retval < 0 && retval != -EPROBE_DEFER)
                pci_warn(dev, "device attach failed (%d)\n", retval);
index c8bd71a739f724e09b4dd773fb0cf74bddda1728..0c5bdb8c2c07b0a58f395def6af5408f38ef1c26 100644 (file)
@@ -1507,7 +1507,7 @@ static int pci_bus_match(struct device *dev, const struct device_driver *drv)
        struct pci_driver *pci_drv;
        const struct pci_device_id *found_id;
 
-       if (!pci_dev->match_driver)
+       if (pci_dev_binding_disallowed(pci_dev))
                return 0;
 
        pci_drv = (struct pci_driver *)to_pci_driver(drv);
index b81e99cd4b62a3022c8b07a09f212f6888674487..de5d4ef943b2917c9d7dd8c8d2582459c0b15407 100644 (file)
@@ -557,6 +557,7 @@ static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused)
 #define PCI_DPC_RECOVERED 1
 #define PCI_DPC_RECOVERING 2
 #define PCI_DEV_REMOVED 3
+#define PCI_DEV_ALLOW_BINDING 7
 
 static inline void pci_dev_assign_added(struct pci_dev *dev)
 {
@@ -580,6 +581,16 @@ static inline bool pci_dev_test_and_set_removed(struct pci_dev *dev)
        return test_and_set_bit(PCI_DEV_REMOVED, &dev->priv_flags);
 }
 
+static inline void pci_dev_allow_binding(struct pci_dev *dev)
+{
+       set_bit(PCI_DEV_ALLOW_BINDING, &dev->priv_flags);
+}
+
+static inline bool pci_dev_binding_disallowed(struct pci_dev *dev)
+{
+       return !test_bit(PCI_DEV_ALLOW_BINDING, &dev->priv_flags);
+}
+
 #ifdef CONFIG_PCIEAER
 #include <linux/aer.h>
 
index 08971fca08193558648c52de5baf12e2b584e5fe..4b8693ec9e4c67fc1655e0057b3b96b4098e6630 100644 (file)
@@ -2711,7 +2711,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
        pci_set_msi_domain(dev);
 
        /* Notifier could use PCI capabilities */
-       dev->match_driver = false;
        ret = device_add(&dev->dev);
        WARN_ON(ret < 0);
 
index d26e6611bd00457c8537ba372076fbc6fb3a52ef..053d9dd494d4595e6ec31314add62cb623e4cfca 100644 (file)
@@ -423,8 +423,6 @@ struct pci_dev {
        struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
        struct resource driver_exclusive_resource;       /* driver exclusive resource ranges */
 
-       bool            match_driver;           /* Skip attaching driver */
-
        unsigned int    transparent:1;          /* Subtractive decode bridge */
        unsigned int    io_window:1;            /* Bridge has I/O window */
        unsigned int    pref_window:1;          /* Bridge has pref mem window */