diff options
Diffstat (limited to 'drivers/pci/pci-driver.c')
-rw-r--r-- | drivers/pci/pci-driver.c | 47 |
1 files changed, 45 insertions, 2 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 474e9cd0e9e..b1c0c707d96 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -17,6 +17,16 @@ * Registration of PCI drivers and handling of hot-pluggable devices. */ +/* multithreaded probe logic */ +static int pci_multithread_probe = +#ifdef CONFIG_PCI_MULTITHREAD_PROBE + 1; +#else + 0; +#endif +__module_param_call("", pci_multithread_probe, param_set_bool, param_get_bool, &pci_multithread_probe, 0644); + + /* * Dynamic device IDs are disabled for !CONFIG_HOTPLUG */ @@ -46,6 +56,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) subdevice=PCI_ANY_ID, class=0, class_mask=0; unsigned long driver_data=0; int fields=0; + int retval = 0; fields = sscanf(buf, "%x %x %x %x %x %x %lux", &vendor, &device, &subvendor, &subdevice, @@ -72,10 +83,12 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) spin_unlock(&pdrv->dynids.lock); if (get_driver(&pdrv->driver)) { - driver_attach(&pdrv->driver); + retval = driver_attach(&pdrv->driver); put_driver(&pdrv->driver); } + if (retval) + return retval; return count; } static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); @@ -279,6 +292,18 @@ static int pci_device_suspend(struct device * dev, pm_message_t state) return i; } +static int pci_device_suspend_late(struct device * dev, pm_message_t state) +{ + struct pci_dev * pci_dev = to_pci_dev(dev); + struct pci_driver * drv = pci_dev->driver; + int i = 0; + + if (drv && drv->suspend_late) { + i = drv->suspend_late(pci_dev, state); + suspend_report_result(drv->suspend_late, i); + } + return i; +} /* * Default resume method for devices that have no driver provided resume, @@ -313,6 +338,17 @@ static int pci_device_resume(struct device * dev) return error; } +static int pci_device_resume_early(struct device * dev) +{ + int error = 0; + struct pci_dev * pci_dev = to_pci_dev(dev); + struct pci_driver * drv = pci_dev->driver; + + if (drv && drv->resume_early) + error = drv->resume_early(pci_dev); + return error; +} + static void pci_device_shutdown(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); @@ -386,6 +422,11 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner) drv->driver.owner = owner; drv->driver.kobj.ktype = &pci_driver_kobj_type; + if (pci_multithread_probe) + drv->driver.multithread_probe = pci_multithread_probe; + else + drv->driver.multithread_probe = drv->multithread_probe; + spin_lock_init(&drv->dynids.lock); INIT_LIST_HEAD(&drv->dynids.list); @@ -509,8 +550,10 @@ struct bus_type pci_bus_type = { .probe = pci_device_probe, .remove = pci_device_remove, .suspend = pci_device_suspend, - .shutdown = pci_device_shutdown, + .suspend_late = pci_device_suspend_late, + .resume_early = pci_device_resume_early, .resume = pci_device_resume, + .shutdown = pci_device_shutdown, .dev_attrs = pci_dev_attrs, }; |