aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/bus.c
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2015-03-30 19:20:04 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-05-20 03:25:24 -0400
commit765230b5f084863183aa8adb3405ab3f32c0b16e (patch)
treeb30ab1e510611cbc2aecfaf853a692b8773fd8ed /drivers/base/bus.c
parentecc8617053e0a97272ef2eee138809f30080e84b (diff)
driver-core: add asynchronous probing support for drivers
Some devices take a long time when initializing, and not all drivers are suited to initialize their devices when they are open. For example, input drivers need to interrogate their devices in order to publish device's capabilities before userspace will open them. When such drivers are compiled into kernel they may stall entire kernel initialization. This change allows drivers request for their probe functions to be called asynchronously during driver and device registration (manual binding is still synchronous). Because async_schedule is used to perform asynchronous calls module loading will still wait for the probing to complete. Note that the end goal is to make the probing asynchronous by default, so annotating drivers with PROBE_PREFER_ASYNCHRONOUS is a temporary measure that allows us to speed up boot process while we validating and fixing the rest of the drivers and preparing userspace. This change is based on earlier patch by "Luis R. Rodriguez" <mcgrof@suse.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/base/bus.c')
-rw-r--r--drivers/base/bus.c31
1 files changed, 23 insertions, 8 deletions
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 79bc203f51ef..500592486e88 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -10,6 +10,7 @@
10 * 10 *
11 */ 11 */
12 12
13#include <linux/async.h>
13#include <linux/device.h> 14#include <linux/device.h>
14#include <linux/module.h> 15#include <linux/module.h>
15#include <linux/errno.h> 16#include <linux/errno.h>
@@ -549,15 +550,12 @@ void bus_probe_device(struct device *dev)
549{ 550{
550 struct bus_type *bus = dev->bus; 551 struct bus_type *bus = dev->bus;
551 struct subsys_interface *sif; 552 struct subsys_interface *sif;
552 int ret;
553 553
554 if (!bus) 554 if (!bus)
555 return; 555 return;
556 556
557 if (bus->p->drivers_autoprobe) { 557 if (bus->p->drivers_autoprobe)
558 ret = device_attach(dev); 558 device_initial_probe(dev);
559 WARN_ON(ret < 0);
560 }
561 559
562 mutex_lock(&bus->p->mutex); 560 mutex_lock(&bus->p->mutex);
563 list_for_each_entry(sif, &bus->p->interfaces, node) 561 list_for_each_entry(sif, &bus->p->interfaces, node)
@@ -659,6 +657,17 @@ static ssize_t uevent_store(struct device_driver *drv, const char *buf,
659} 657}
660static DRIVER_ATTR_WO(uevent); 658static DRIVER_ATTR_WO(uevent);
661 659
660static void driver_attach_async(void *_drv, async_cookie_t cookie)
661{
662 struct device_driver *drv = _drv;
663 int ret;
664
665 ret = driver_attach(drv);
666
667 pr_debug("bus: '%s': driver %s async attach completed: %d\n",
668 drv->bus->name, drv->name, ret);
669}
670
662/** 671/**
663 * bus_add_driver - Add a driver to the bus. 672 * bus_add_driver - Add a driver to the bus.
664 * @drv: driver. 673 * @drv: driver.
@@ -691,9 +700,15 @@ int bus_add_driver(struct device_driver *drv)
691 700
692 klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); 701 klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
693 if (drv->bus->p->drivers_autoprobe) { 702 if (drv->bus->p->drivers_autoprobe) {
694 error = driver_attach(drv); 703 if (driver_allows_async_probing(drv)) {
695 if (error) 704 pr_debug("bus: '%s': probing driver %s asynchronously\n",
696 goto out_unregister; 705 drv->bus->name, drv->name);
706 async_schedule(driver_attach_async, drv);
707 } else {
708 error = driver_attach(drv);
709 if (error)
710 goto out_unregister;
711 }
697 } 712 }
698 module_add_driver(drv->owner, drv); 713 module_add_driver(drv->owner, drv);
699 714