PCI: Skip attaching driver in device_add()
authorYinghai Lu <yinghai@kernel.org>
Mon, 21 Jan 2013 21:20:51 +0000 (13:20 -0800)
committerBjorn Helgaas <bhelgaas@google.com>
Fri, 25 Jan 2013 22:10:12 +0000 (15:10 -0700)
We want to add PCI devices to the device tree as early as possible but
delay attaching drivers.

device_add() adds a device to the device hierarchy and (via
device_attach()) attaches a matching driver and calls its .probe() method.
We want to separate adding the device to the hierarchy from attaching the
driver.

This patch does that by adding "match_driver" in struct pci_dev.  When
false, we return failure from pci_bus_match(), which makes device_attach()
believe there's no matching driver.

Later, we set "match_driver = true" and call device_attach() again, which
now attaches the driver and calls its .probe() method.

[bhelgaas: changelog, explicitly init dev->match_driver,
fold device_attach() call into pci_bus_add_device()]
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/pci/bus.c
drivers/pci/pci-driver.c
include/linux/pci.h

index 847f3ca47bb8822a669b104e3f67db883b4566a2..c8709c6fdb7c968bbb29cd27eb2fedfa48793de4 100644 (file)
@@ -177,10 +177,15 @@ int pci_bus_add_device(struct pci_dev *dev)
        if (retval)
                return retval;
 
+       dev->match_driver = false;
        retval = device_add(&dev->dev);
        if (retval)
                return retval;
 
+       dev->match_driver = true;
+       retval = device_attach(&dev->dev);
+       WARN_ON(retval < 0);
+
        dev->is_added = 1;
        pci_proc_attach_device(dev);
        pci_create_sysfs_dev_files(dev);
index f79cbcd3944bf5e61e76a96022331a665e63f93e..acdcc3c6ecddca9c9fbaf9c719aa354f39a6f724 100644 (file)
@@ -1186,9 +1186,13 @@ pci_dev_driver(const struct pci_dev *dev)
 static int pci_bus_match(struct device *dev, struct device_driver *drv)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
-       struct pci_driver *pci_drv = to_pci_driver(drv);
+       struct pci_driver *pci_drv;
        const struct pci_device_id *found_id;
 
+       if (!pci_dev->match_driver)
+               return 0;
+
+       pci_drv = to_pci_driver(drv);
        found_id = pci_match_device(pci_drv, pci_dev);
        if (found_id)
                return 1;
index 907b455ab603381a423571139b6497c8c0db5aef..8ee7e4e465392e0ad274bc8e9c9213a2a8ca1134 100644 (file)
@@ -286,6 +286,7 @@ struct pci_dev {
        unsigned int    irq;
        struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
 
+       bool match_driver;              /* Skip attaching driver */
        /* These fields are used by common fixups */
        unsigned int    transparent:1;  /* Transparent PCI bridge */
        unsigned int    multifunction:1;/* Part of multi-function device */