diff options
author | Ming Lei <tom.leiming@gmail.com> | 2009-01-21 23:27:47 +0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-03-24 16:38:24 -0700 |
commit | 49b420a13ff95b449947181190b08367348e3e1b (patch) | |
tree | 5feec1d1eac071e46c9aacec4255d891fa4f7ed2 | |
parent | 4a67a1bc0b3a0db017b560cee27370d141c58e25 (diff) |
driver core: check bus->match without holding device lock
This patch moves bus->match out from driver_probe_device and
does not hold device lock to check the match between a device
and a driver.
The idea has been verified by the commit 6cd495860901,
which leads to a faster boot. But the commit 6cd495860901 has
the following drawbacks: 1),only does the quick check in
the path of __driver_attach->driver_probe_device, not in other
paths; 2),for a matched device and driver, check the same match
twice. It is a waste of cpu ,especially for some drivers with long
device id table (eg. usb-storage driver).
This patch adds a helper of driver_match_device to check the match
in all paths, and testes the match only once.
Signed-off-by: Ming Lei <tom.leiming@gmail.com>
Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/base/base.h | 5 | ||||
-rw-r--r-- | drivers/base/bus.c | 2 | ||||
-rw-r--r-- | drivers/base/dd.c | 19 |
3 files changed, 13 insertions, 13 deletions
diff --git a/drivers/base/base.h b/drivers/base/base.h index 9f50f1b545dc..ca2b0376685b 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -86,6 +86,11 @@ extern void bus_remove_driver(struct device_driver *drv); extern void driver_detach(struct device_driver *drv); extern int driver_probe_device(struct device_driver *drv, struct device *dev); +static inline int driver_match_device(struct device_driver *drv, + struct device *dev) +{ + return drv->bus->match && drv->bus->match(dev, drv); +} extern void sysdev_shutdown(void); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 83f32b891fa9..8547b780bb5a 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -198,7 +198,7 @@ static ssize_t driver_bind(struct device_driver *drv, int err = -ENODEV; dev = bus_find_device_by_name(bus, NULL, buf); - if (dev && dev->driver == NULL) { + if (dev && dev->driver == NULL && driver_match_device(drv, dev)) { if (dev->parent) /* Needed for USB */ down(&dev->parent->sem); down(&dev->sem); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 135231239103..3f32df7ed373 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -189,14 +189,8 @@ int wait_for_device_probe(void) * @drv: driver to bind a device to * @dev: device to try to bind to the driver * - * First, we call the bus's match function, if one present, which should - * compare the device IDs the driver supports with the device IDs of the - * device. Note we don't do this ourselves because we don't know the - * format of the ID structures, nor what is to be considered a match and - * what is not. - * - * This function returns 1 if a match is found, -ENODEV if the device is - * not registered, and 0 otherwise. + * This function returns -ENODEV if the device is not registered, + * 1 if the device is bound sucessfully and 0 otherwise. * * This function must be called with @dev->sem held. When called for a * USB interface, @dev->parent->sem must be held as well. @@ -207,21 +201,22 @@ int driver_probe_device(struct device_driver *drv, struct device *dev) if (!device_is_registered(dev)) return -ENODEV; - if (drv->bus->match && !drv->bus->match(dev, drv)) - goto done; pr_debug("bus: '%s': %s: matched device %s with driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name); ret = really_probe(dev, drv); -done: return ret; } static int __device_attach(struct device_driver *drv, void *data) { struct device *dev = data; + + if (!driver_match_device(drv, dev)) + return 0; + return driver_probe_device(drv, dev); } @@ -274,7 +269,7 @@ static int __driver_attach(struct device *dev, void *data) * is an error. */ - if (drv->bus->match && !drv->bus->match(dev, drv)) + if (!driver_match_device(drv, dev)) return 0; if (dev->parent) /* Needed for USB */ |