diff options
author | Ming Lei <tom.leiming@gmail.com> | 2009-01-21 10:27:47 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-03-24 19:38:24 -0400 |
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); | |||
86 | 86 | ||
87 | extern void driver_detach(struct device_driver *drv); | 87 | extern void driver_detach(struct device_driver *drv); |
88 | extern int driver_probe_device(struct device_driver *drv, struct device *dev); | 88 | extern int driver_probe_device(struct device_driver *drv, struct device *dev); |
89 | static inline int driver_match_device(struct device_driver *drv, | ||
90 | struct device *dev) | ||
91 | { | ||
92 | return drv->bus->match && drv->bus->match(dev, drv); | ||
93 | } | ||
89 | 94 | ||
90 | extern void sysdev_shutdown(void); | 95 | extern void sysdev_shutdown(void); |
91 | 96 | ||
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, | |||
198 | int err = -ENODEV; | 198 | int err = -ENODEV; |
199 | 199 | ||
200 | dev = bus_find_device_by_name(bus, NULL, buf); | 200 | dev = bus_find_device_by_name(bus, NULL, buf); |
201 | if (dev && dev->driver == NULL) { | 201 | if (dev && dev->driver == NULL && driver_match_device(drv, dev)) { |
202 | if (dev->parent) /* Needed for USB */ | 202 | if (dev->parent) /* Needed for USB */ |
203 | down(&dev->parent->sem); | 203 | down(&dev->parent->sem); |
204 | down(&dev->sem); | 204 | 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) | |||
189 | * @drv: driver to bind a device to | 189 | * @drv: driver to bind a device to |
190 | * @dev: device to try to bind to the driver | 190 | * @dev: device to try to bind to the driver |
191 | * | 191 | * |
192 | * First, we call the bus's match function, if one present, which should | 192 | * This function returns -ENODEV if the device is not registered, |
193 | * compare the device IDs the driver supports with the device IDs of the | 193 | * 1 if the device is bound sucessfully and 0 otherwise. |
194 | * device. Note we don't do this ourselves because we don't know the | ||
195 | * format of the ID structures, nor what is to be considered a match and | ||
196 | * what is not. | ||
197 | * | ||
198 | * This function returns 1 if a match is found, -ENODEV if the device is | ||
199 | * not registered, and 0 otherwise. | ||
200 | * | 194 | * |
201 | * This function must be called with @dev->sem held. When called for a | 195 | * This function must be called with @dev->sem held. When called for a |
202 | * USB interface, @dev->parent->sem must be held as well. | 196 | * 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) | |||
207 | 201 | ||
208 | if (!device_is_registered(dev)) | 202 | if (!device_is_registered(dev)) |
209 | return -ENODEV; | 203 | return -ENODEV; |
210 | if (drv->bus->match && !drv->bus->match(dev, drv)) | ||
211 | goto done; | ||
212 | 204 | ||
213 | pr_debug("bus: '%s': %s: matched device %s with driver %s\n", | 205 | pr_debug("bus: '%s': %s: matched device %s with driver %s\n", |
214 | drv->bus->name, __func__, dev_name(dev), drv->name); | 206 | drv->bus->name, __func__, dev_name(dev), drv->name); |
215 | 207 | ||
216 | ret = really_probe(dev, drv); | 208 | ret = really_probe(dev, drv); |
217 | 209 | ||
218 | done: | ||
219 | return ret; | 210 | return ret; |
220 | } | 211 | } |
221 | 212 | ||
222 | static int __device_attach(struct device_driver *drv, void *data) | 213 | static int __device_attach(struct device_driver *drv, void *data) |
223 | { | 214 | { |
224 | struct device *dev = data; | 215 | struct device *dev = data; |
216 | |||
217 | if (!driver_match_device(drv, dev)) | ||
218 | return 0; | ||
219 | |||
225 | return driver_probe_device(drv, dev); | 220 | return driver_probe_device(drv, dev); |
226 | } | 221 | } |
227 | 222 | ||
@@ -274,7 +269,7 @@ static int __driver_attach(struct device *dev, void *data) | |||
274 | * is an error. | 269 | * is an error. |
275 | */ | 270 | */ |
276 | 271 | ||
277 | if (drv->bus->match && !drv->bus->match(dev, drv)) | 272 | if (!driver_match_device(drv, dev)) |
278 | return 0; | 273 | return 0; |
279 | 274 | ||
280 | if (dev->parent) /* Needed for USB */ | 275 | if (dev->parent) /* Needed for USB */ |