aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorCornelia Huck <cornelia.huck@de.ibm.com>2007-02-05 19:15:25 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2007-04-27 13:57:28 -0400
commit21c7f30b1d3f8a3de3128478daca3ce203fc8733 (patch)
treeff84247ba68f82906182a214273dd330c6d1970f /drivers/base
parent460f7e9a1bde2c74f060f7ce0a308dab4be6a56b (diff)
driver core: per-subsystem multithreaded probing
Make multithreaded probing work per subsystem instead of per driver. It doesn't make much sense to probe the same device for multiple drivers in parallel (after all, only one driver can bind to the device). Instead, create a probing thread for each device that probes the drivers one after another. Also make the decision to use multi-threaded probe per bus instead of per device and adapt the pci code. Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/dd.c62
1 files changed, 31 insertions, 31 deletions
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 6a48824e43ff..616b4bbacf1b 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -94,19 +94,11 @@ int device_bind_driver(struct device *dev)
94 return ret; 94 return ret;
95} 95}
96 96
97struct stupid_thread_structure {
98 struct device_driver *drv;
99 struct device *dev;
100};
101
102static atomic_t probe_count = ATOMIC_INIT(0); 97static atomic_t probe_count = ATOMIC_INIT(0);
103static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); 98static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
104 99
105static int really_probe(void *void_data) 100static int really_probe(struct device *dev, struct device_driver *drv)
106{ 101{
107 struct stupid_thread_structure *data = void_data;
108 struct device_driver *drv = data->drv;
109 struct device *dev = data->dev;
110 int ret = 0; 102 int ret = 0;
111 103
112 atomic_inc(&probe_count); 104 atomic_inc(&probe_count);
@@ -154,7 +146,6 @@ probe_failed:
154 */ 146 */
155 ret = 0; 147 ret = 0;
156done: 148done:
157 kfree(data);
158 atomic_dec(&probe_count); 149 atomic_dec(&probe_count);
159 wake_up(&probe_waitqueue); 150 wake_up(&probe_waitqueue);
160 return ret; 151 return ret;
@@ -186,16 +177,14 @@ int driver_probe_done(void)
186 * format of the ID structures, nor what is to be considered a match and 177 * format of the ID structures, nor what is to be considered a match and
187 * what is not. 178 * what is not.
188 * 179 *
189 * This function returns 1 if a match is found, an error if one occurs 180 * This function returns 1 if a match is found, -ENODEV if the device is
190 * (that is not -ENODEV or -ENXIO), and 0 otherwise. 181 * not registered, and 0 otherwise.
191 * 182 *
192 * This function must be called with @dev->sem held. When called for a 183 * This function must be called with @dev->sem held. When called for a
193 * USB interface, @dev->parent->sem must be held as well. 184 * USB interface, @dev->parent->sem must be held as well.
194 */ 185 */
195int driver_probe_device(struct device_driver * drv, struct device * dev) 186int driver_probe_device(struct device_driver * drv, struct device * dev)
196{ 187{
197 struct stupid_thread_structure *data;
198 struct task_struct *probe_task;
199 int ret = 0; 188 int ret = 0;
200 189
201 if (!device_is_registered(dev)) 190 if (!device_is_registered(dev))
@@ -206,19 +195,7 @@ int driver_probe_device(struct device_driver * drv, struct device * dev)
206 pr_debug("%s: Matched Device %s with Driver %s\n", 195 pr_debug("%s: Matched Device %s with Driver %s\n",
207 drv->bus->name, dev->bus_id, drv->name); 196 drv->bus->name, dev->bus_id, drv->name);
208 197
209 data = kmalloc(sizeof(*data), GFP_KERNEL); 198 ret = really_probe(dev, drv);
210 if (!data)
211 return -ENOMEM;
212 data->drv = drv;
213 data->dev = dev;
214
215 if (drv->multithread_probe) {
216 probe_task = kthread_run(really_probe, data,
217 "probe-%s", dev->bus_id);
218 if (IS_ERR(probe_task))
219 ret = really_probe(data);
220 } else
221 ret = really_probe(data);
222 199
223done: 200done:
224 return ret; 201 return ret;
@@ -230,30 +207,53 @@ static int __device_attach(struct device_driver * drv, void * data)
230 return driver_probe_device(drv, dev); 207 return driver_probe_device(drv, dev);
231} 208}
232 209
210static int device_probe_drivers(void *data)
211{
212 struct device *dev = data;
213 int ret = 0;
214
215 if (dev->bus) {
216 down(&dev->sem);
217 ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
218 up(&dev->sem);
219 }
220 return ret;
221}
222
233/** 223/**
234 * device_attach - try to attach device to a driver. 224 * device_attach - try to attach device to a driver.
235 * @dev: device. 225 * @dev: device.
236 * 226 *
237 * Walk the list of drivers that the bus has and call 227 * Walk the list of drivers that the bus has and call
238 * driver_probe_device() for each pair. If a compatible 228 * driver_probe_device() for each pair. If a compatible
239 * pair is found, break out and return. 229 * pair is found, break out and return. If the bus specifies
230 * multithreaded probing, walking the list of drivers is done
231 * on a probing thread.
240 * 232 *
241 * Returns 1 if the device was bound to a driver; 233 * Returns 1 if the device was bound to a driver;
242 * 0 if no matching device was found; error code otherwise. 234 * 0 if no matching device was found or multithreaded probing is done;
235 * error code otherwise.
243 * 236 *
244 * When called for a USB interface, @dev->parent->sem must be held. 237 * When called for a USB interface, @dev->parent->sem must be held.
245 */ 238 */
246int device_attach(struct device * dev) 239int device_attach(struct device * dev)
247{ 240{
248 int ret = 0; 241 int ret = 0;
242 struct task_struct *probe_task = ERR_PTR(-ENOMEM);
249 243
250 down(&dev->sem); 244 down(&dev->sem);
251 if (dev->driver) { 245 if (dev->driver) {
252 ret = device_bind_driver(dev); 246 ret = device_bind_driver(dev);
253 if (ret == 0) 247 if (ret == 0)
254 ret = 1; 248 ret = 1;
255 } else 249 } else {
256 ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); 250 if (dev->bus->multithread_probe)
251 probe_task = kthread_run(device_probe_drivers, dev,
252 "probe-%s", dev->bus_id);
253 if(IS_ERR(probe_task))
254 ret = bus_for_each_drv(dev->bus, NULL, dev,
255 __device_attach);
256 }
257 up(&dev->sem); 257 up(&dev->sem);
258 return ret; 258 return ret;
259} 259}