Commit 765230b5 authored by Dmitry Torokhov's avatar Dmitry Torokhov Committed by Greg Kroah-Hartman

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: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent ecc86170
...@@ -116,6 +116,7 @@ static inline int driver_match_device(struct device_driver *drv, ...@@ -116,6 +116,7 @@ static inline int driver_match_device(struct device_driver *drv,
{ {
return drv->bus->match ? drv->bus->match(dev, drv) : 1; return drv->bus->match ? drv->bus->match(dev, drv) : 1;
} }
extern bool driver_allows_async_probing(struct device_driver *drv);
extern int driver_add_groups(struct device_driver *drv, extern int driver_add_groups(struct device_driver *drv,
const struct attribute_group **groups); const struct attribute_group **groups);
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
* *
*/ */
#include <linux/async.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -549,15 +550,12 @@ void bus_probe_device(struct device *dev) ...@@ -549,15 +550,12 @@ void bus_probe_device(struct device *dev)
{ {
struct bus_type *bus = dev->bus; struct bus_type *bus = dev->bus;
struct subsys_interface *sif; struct subsys_interface *sif;
int ret;
if (!bus) if (!bus)
return; return;
if (bus->p->drivers_autoprobe) { if (bus->p->drivers_autoprobe)
ret = device_attach(dev); device_initial_probe(dev);
WARN_ON(ret < 0);
}
mutex_lock(&bus->p->mutex); mutex_lock(&bus->p->mutex);
list_for_each_entry(sif, &bus->p->interfaces, node) 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,6 +657,17 @@ static ssize_t uevent_store(struct device_driver *drv, const char *buf,
} }
static DRIVER_ATTR_WO(uevent); static DRIVER_ATTR_WO(uevent);
static void driver_attach_async(void *_drv, async_cookie_t cookie)
{
struct device_driver *drv = _drv;
int ret;
ret = driver_attach(drv);
pr_debug("bus: '%s': driver %s async attach completed: %d\n",
drv->bus->name, drv->name, ret);
}
/** /**
* bus_add_driver - Add a driver to the bus. * bus_add_driver - Add a driver to the bus.
* @drv: driver. * @drv: driver.
...@@ -691,10 +700,16 @@ int bus_add_driver(struct device_driver *drv) ...@@ -691,10 +700,16 @@ int bus_add_driver(struct device_driver *drv)
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
if (drv->bus->p->drivers_autoprobe) { if (drv->bus->p->drivers_autoprobe) {
if (driver_allows_async_probing(drv)) {
pr_debug("bus: '%s': probing driver %s asynchronously\n",
drv->bus->name, drv->name);
async_schedule(driver_attach_async, drv);
} else {
error = driver_attach(drv); error = driver_attach(drv);
if (error) if (error)
goto out_unregister; goto out_unregister;
} }
}
module_add_driver(drv->owner, drv); module_add_driver(drv->owner, drv);
error = driver_create_file(drv, &driver_attr_uevent); error = driver_create_file(drv, &driver_attr_uevent);
......
...@@ -417,31 +417,95 @@ int driver_probe_device(struct device_driver *drv, struct device *dev) ...@@ -417,31 +417,95 @@ int driver_probe_device(struct device_driver *drv, struct device *dev)
return ret; return ret;
} }
static int __device_attach(struct device_driver *drv, void *data) bool driver_allows_async_probing(struct device_driver *drv)
{ {
struct device *dev = data; return drv->probe_type == PROBE_PREFER_ASYNCHRONOUS;
}
struct device_attach_data {
struct device *dev;
/*
* Indicates whether we are are considering asynchronous probing or
* not. Only initial binding after device or driver registration
* (including deferral processing) may be done asynchronously, the
* rest is always synchronous, as we expect it is being done by
* request from userspace.
*/
bool check_async;
/*
* Indicates if we are binding synchronous or asynchronous drivers.
* When asynchronous probing is enabled we'll execute 2 passes
* over drivers: first pass doing synchronous probing and second
* doing asynchronous probing (if synchronous did not succeed -
* most likely because there was no driver requiring synchronous
* probing - and we found asynchronous driver during first pass).
* The 2 passes are done because we can't shoot asynchronous
* probe for given device and driver from bus_for_each_drv() since
* driver pointer is not guaranteed to stay valid once
* bus_for_each_drv() iterates to the next driver on the bus.
*/
bool want_async;
/*
* We'll set have_async to 'true' if, while scanning for matching
* driver, we'll encounter one that requests asynchronous probing.
*/
bool have_async;
};
static int __device_attach_driver(struct device_driver *drv, void *_data)
{
struct device_attach_data *data = _data;
struct device *dev = data->dev;
bool async_allowed;
/*
* Check if device has already been claimed. This may
* happen with driver loading, device discovery/registration,
* and deferred probe processing happens all at once with
* multiple threads.
*/
if (dev->driver)
return -EBUSY;
if (!driver_match_device(drv, dev)) if (!driver_match_device(drv, dev))
return 0; return 0;
async_allowed = driver_allows_async_probing(drv);
if (async_allowed)
data->have_async = true;
if (data->check_async && async_allowed != data->want_async)
return 0;
return driver_probe_device(drv, dev); return driver_probe_device(drv, dev);
} }
/** static void __device_attach_async_helper(void *_dev, async_cookie_t cookie)
* device_attach - try to attach device to a driver. {
* @dev: device. struct device *dev = _dev;
* struct device_attach_data data = {
* Walk the list of drivers that the bus has and call .dev = dev,
* driver_probe_device() for each pair. If a compatible .check_async = true,
* pair is found, break out and return. .want_async = true,
* };
* Returns 1 if the device was bound to a driver;
* 0 if no matching driver was found; device_lock(dev);
* -ENODEV if the device is not registered.
* bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver);
* When called for a USB interface, @dev->parent lock must be held. dev_dbg(dev, "async probe completed\n");
*/
int device_attach(struct device *dev) pm_request_idle(dev);
device_unlock(dev);
put_device(dev);
}
int __device_attach(struct device *dev, bool allow_async)
{ {
int ret = 0; int ret = 0;
...@@ -459,15 +523,59 @@ int device_attach(struct device *dev) ...@@ -459,15 +523,59 @@ int device_attach(struct device *dev)
ret = 0; ret = 0;
} }
} else { } else {
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); struct device_attach_data data = {
.dev = dev,
.check_async = allow_async,
.want_async = false,
};
ret = bus_for_each_drv(dev->bus, NULL, &data,
__device_attach_driver);
if (!ret && allow_async && data.have_async) {
/*
* If we could not find appropriate driver
* synchronously and we are allowed to do
* async probes and there are drivers that
* want to probe asynchronously, we'll
* try them.
*/
dev_dbg(dev, "scheduling asynchronous probe\n");
get_device(dev);
async_schedule(__device_attach_async_helper, dev);
} else {
pm_request_idle(dev); pm_request_idle(dev);
} }
}
out_unlock: out_unlock:
device_unlock(dev); device_unlock(dev);
return ret; return ret;
} }
/**
* device_attach - try to attach device to a driver.
* @dev: device.
*
* Walk the list of drivers that the bus has and call
* driver_probe_device() for each pair. If a compatible
* pair is found, break out and return.
*
* Returns 1 if the device was bound to a driver;
* 0 if no matching driver was found;
* -ENODEV if the device is not registered.
*
* When called for a USB interface, @dev->parent lock must be held.
*/
int device_attach(struct device *dev)
{
return __device_attach(dev, false);
}
EXPORT_SYMBOL_GPL(device_attach); EXPORT_SYMBOL_GPL(device_attach);
void device_initial_probe(struct device *dev)
{
__device_attach(dev, true);
}
static int __driver_attach(struct device *dev, void *data) static int __driver_attach(struct device *dev, void *data)
{ {
struct device_driver *drv = data; struct device_driver *drv = data;
...@@ -522,6 +630,9 @@ static void __device_release_driver(struct device *dev) ...@@ -522,6 +630,9 @@ static void __device_release_driver(struct device *dev)
drv = dev->driver; drv = dev->driver;
if (drv) { if (drv) {
if (driver_allows_async_probing(drv))
async_synchronize_full();
pm_runtime_get_sync(dev); pm_runtime_get_sync(dev);
driver_sysfs_remove(dev); driver_sysfs_remove(dev);
......
...@@ -195,6 +195,31 @@ extern int bus_unregister_notifier(struct bus_type *bus, ...@@ -195,6 +195,31 @@ extern int bus_unregister_notifier(struct bus_type *bus,
extern struct kset *bus_get_kset(struct bus_type *bus); extern struct kset *bus_get_kset(struct bus_type *bus);
extern struct klist *bus_get_device_klist(struct bus_type *bus); extern struct klist *bus_get_device_klist(struct bus_type *bus);
/**
* enum probe_type - device driver probe type to try
* Device drivers may opt in for special handling of their
* respective probe routines. This tells the core what to
* expect and prefer.
*
* @PROBE_SYNCHRONOUS: Default. Drivers expect their probe routines
* to run synchronously with driver and device registration
* (with the exception of -EPROBE_DEFER handling - re-probing
* always ends up being done asynchronously).
* @PROBE_PREFER_ASYNCHRONOUS: Drivers for "slow" devices which
* probing order is not essential for booting the system may
* opt into executing their probes asynchronously.
*
* Note that the end goal is to switch the kernel to use asynchronous
* probing by default, so annotating drivers with
* %PROBE_PREFER_ASYNCHRONOUS is a temporary measure that allows us
* to speed up boot process while we are validating the rest of the
* drivers.
*/
enum probe_type {
PROBE_SYNCHRONOUS,
PROBE_PREFER_ASYNCHRONOUS,
};
/** /**
* struct device_driver - The basic device driver structure * struct device_driver - The basic device driver structure
* @name: Name of the device driver. * @name: Name of the device driver.
...@@ -202,6 +227,7 @@ extern struct klist *bus_get_device_klist(struct bus_type *bus); ...@@ -202,6 +227,7 @@ extern struct klist *bus_get_device_klist(struct bus_type *bus);
* @owner: The module owner. * @owner: The module owner.
* @mod_name: Used for built-in modules. * @mod_name: Used for built-in modules.
* @suppress_bind_attrs: Disables bind/unbind via sysfs. * @suppress_bind_attrs: Disables bind/unbind via sysfs.
* @probe_type: Type of the probe (synchronous or asynchronous) to use.
* @of_match_table: The open firmware table. * @of_match_table: The open firmware table.
* @acpi_match_table: The ACPI match table. * @acpi_match_table: The ACPI match table.
* @probe: Called to query the existence of a specific device, * @probe: Called to query the existence of a specific device,
...@@ -235,6 +261,7 @@ struct device_driver { ...@@ -235,6 +261,7 @@ struct device_driver {
const char *mod_name; /* used for built-in modules */ const char *mod_name; /* used for built-in modules */
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
enum probe_type probe_type;
const struct of_device_id *of_match_table; const struct of_device_id *of_match_table;
const struct acpi_device_id *acpi_match_table; const struct acpi_device_id *acpi_match_table;
...@@ -975,6 +1002,7 @@ extern int __must_check device_bind_driver(struct device *dev); ...@@ -975,6 +1002,7 @@ extern int __must_check device_bind_driver(struct device *dev);
extern void device_release_driver(struct device *dev); extern void device_release_driver(struct device *dev);
extern int __must_check device_attach(struct device *dev); extern int __must_check device_attach(struct device *dev);
extern int __must_check driver_attach(struct device_driver *drv); extern int __must_check driver_attach(struct device_driver *drv);
extern void device_initial_probe(struct device *dev);
extern int __must_check device_reprobe(struct device *dev); extern int __must_check device_reprobe(struct device *dev);
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment