aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2006-07-18 13:59:59 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-09-26 00:08:40 -0400
commitd779249ed4cb3b50690de6de8448829d65a1cd08 (patch)
tree0494df3b68a28ce0b23a1577758b583409621a7d
parentf20a9ead0d005fbeeae3fc21a96f9bf197ac1c1c (diff)
Driver Core: add ability for drivers to do a threaded probe
This adds the infrastructure for drivers to do a threaded probe, and waits at init time for all currently outstanding probes to complete. A new kernel thread will be created when the probe() function for the driver is called, if the multithread_probe bit is set in the driver saying it can support this kind of operation. I have tested this with USB and PCI, and it works, and shaves off a lot of time in the boot process, but there are issues with finding root boot disks, and some USB drivers assume that this can never happen, so it is currently not enabled for any bus type. Individual drivers can enable this right now if they wish, and bus authors can selectivly turn it on as well, once they determine that their subsystem will work properly with it. Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/base/dd.c108
-rw-r--r--include/linux/device.h3
-rw-r--r--init/do_mounts.c5
3 files changed, 89 insertions, 27 deletions
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 9f6f11ca0ab6..319a73be4180 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -17,6 +17,7 @@
17 17
18#include <linux/device.h> 18#include <linux/device.h>
19#include <linux/module.h> 19#include <linux/module.h>
20#include <linux/kthread.h>
20 21
21#include "base.h" 22#include "base.h"
22#include "power/power.h" 23#include "power/power.h"
@@ -63,44 +64,35 @@ int device_bind_driver(struct device *dev)
63 return ret; 64 return ret;
64} 65}
65 66
66/** 67struct stupid_thread_structure {
67 * driver_probe_device - attempt to bind device & driver. 68 struct device_driver *drv;
68 * @drv: driver. 69 struct device *dev;
69 * @dev: device. 70};
70 * 71
71 * First, we call the bus's match function, if one present, which 72static atomic_t probe_count = ATOMIC_INIT(0);
72 * should compare the device IDs the driver supports with the 73static int really_probe(void *void_data)
73 * device IDs of the device. Note we don't do this ourselves
74 * because we don't know the format of the ID structures, nor what
75 * is to be considered a match and what is not.
76 *
77 * This function returns 1 if a match is found, an error if one
78 * occurs (that is not -ENODEV or -ENXIO), and 0 otherwise.
79 *
80 * This function must be called with @dev->sem held. When called
81 * for a USB interface, @dev->parent->sem must be held as well.
82 */
83int driver_probe_device(struct device_driver * drv, struct device * dev)
84{ 74{
75 struct stupid_thread_structure *data = void_data;
76 struct device_driver *drv = data->drv;
77 struct device *dev = data->dev;
85 int ret = 0; 78 int ret = 0;
86 79
87 if (drv->bus->match && !drv->bus->match(dev, drv)) 80 atomic_inc(&probe_count);
88 goto Done; 81 pr_debug("%s: Probing driver %s with device %s\n",
82 drv->bus->name, drv->name, dev->bus_id);
89 83
90 pr_debug("%s: Matched Device %s with Driver %s\n",
91 drv->bus->name, dev->bus_id, drv->name);
92 dev->driver = drv; 84 dev->driver = drv;
93 if (dev->bus->probe) { 85 if (dev->bus->probe) {
94 ret = dev->bus->probe(dev); 86 ret = dev->bus->probe(dev);
95 if (ret) { 87 if (ret) {
96 dev->driver = NULL; 88 dev->driver = NULL;
97 goto ProbeFailed; 89 goto probe_failed;
98 } 90 }
99 } else if (drv->probe) { 91 } else if (drv->probe) {
100 ret = drv->probe(dev); 92 ret = drv->probe(dev);
101 if (ret) { 93 if (ret) {
102 dev->driver = NULL; 94 dev->driver = NULL;
103 goto ProbeFailed; 95 goto probe_failed;
104 } 96 }
105 } 97 }
106 if (device_bind_driver(dev)) { 98 if (device_bind_driver(dev)) {
@@ -111,9 +103,9 @@ int driver_probe_device(struct device_driver * drv, struct device * dev)
111 ret = 1; 103 ret = 1;
112 pr_debug("%s: Bound Device %s to Driver %s\n", 104 pr_debug("%s: Bound Device %s to Driver %s\n",
113 drv->bus->name, dev->bus_id, drv->name); 105 drv->bus->name, dev->bus_id, drv->name);
114 goto Done; 106 goto done;
115 107
116 ProbeFailed: 108probe_failed:
117 if (ret == -ENODEV || ret == -ENXIO) { 109 if (ret == -ENODEV || ret == -ENXIO) {
118 /* Driver matched, but didn't support device 110 /* Driver matched, but didn't support device
119 * or device not found. 111 * or device not found.
@@ -126,7 +118,69 @@ int driver_probe_device(struct device_driver * drv, struct device * dev)
126 "%s: probe of %s failed with error %d\n", 118 "%s: probe of %s failed with error %d\n",
127 drv->name, dev->bus_id, ret); 119 drv->name, dev->bus_id, ret);
128 } 120 }
129 Done: 121done:
122 kfree(data);
123 atomic_dec(&probe_count);
124 return ret;
125}
126
127/**
128 * driver_probe_done
129 * Determine if the probe sequence is finished or not.
130 *
131 * Should somehow figure out how to use a semaphore, not an atomic variable...
132 */
133int driver_probe_done(void)
134{
135 pr_debug("%s: probe_count = %d\n", __FUNCTION__,
136 atomic_read(&probe_count));
137 if (atomic_read(&probe_count))
138 return -EBUSY;
139 return 0;
140}
141
142/**
143 * driver_probe_device - attempt to bind device & driver together
144 * @drv: driver to bind a device to
145 * @dev: device to try to bind to the driver
146 *
147 * First, we call the bus's match function, if one present, which should
148 * compare the device IDs the driver supports with the device IDs of the
149 * device. Note we don't do this ourselves because we don't know the
150 * format of the ID structures, nor what is to be considered a match and
151 * what is not.
152 *
153 * This function returns 1 if a match is found, an error if one occurs
154 * (that is not -ENODEV or -ENXIO), and 0 otherwise.
155 *
156 * This function must be called with @dev->sem held. When called for a
157 * USB interface, @dev->parent->sem must be held as well.
158 */
159int driver_probe_device(struct device_driver * drv, struct device * dev)
160{
161 struct stupid_thread_structure *data;
162 struct task_struct *probe_task;
163 int ret = 0;
164
165 if (drv->bus->match && !drv->bus->match(dev, drv))
166 goto done;
167
168 pr_debug("%s: Matched Device %s with Driver %s\n",
169 drv->bus->name, dev->bus_id, drv->name);
170
171 data = kmalloc(sizeof(*data), GFP_KERNEL);
172 data->drv = drv;
173 data->dev = dev;
174
175 if (drv->multithread_probe) {
176 probe_task = kthread_run(really_probe, data,
177 "probe-%s", dev->bus_id);
178 if (IS_ERR(probe_task))
179 ret = PTR_ERR(probe_task);
180 } else
181 ret = really_probe(data);
182
183done:
130 return ret; 184 return ret;
131} 185}
132 186
diff --git a/include/linux/device.h b/include/linux/device.h
index b3da9a870cfc..74246efba931 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -106,6 +106,8 @@ struct device_driver {
106 void (*shutdown) (struct device * dev); 106 void (*shutdown) (struct device * dev);
107 int (*suspend) (struct device * dev, pm_message_t state); 107 int (*suspend) (struct device * dev, pm_message_t state);
108 int (*resume) (struct device * dev); 108 int (*resume) (struct device * dev);
109
110 unsigned int multithread_probe:1;
109}; 111};
110 112
111 113
@@ -115,6 +117,7 @@ extern void driver_unregister(struct device_driver * drv);
115extern struct device_driver * get_driver(struct device_driver * drv); 117extern struct device_driver * get_driver(struct device_driver * drv);
116extern void put_driver(struct device_driver * drv); 118extern void put_driver(struct device_driver * drv);
117extern struct device_driver *driver_find(const char *name, struct bus_type *bus); 119extern struct device_driver *driver_find(const char *name, struct bus_type *bus);
120extern int driver_probe_done(void);
118 121
119/* driverfs interface for exporting driver attributes */ 122/* driverfs interface for exporting driver attributes */
120 123
diff --git a/init/do_mounts.c b/init/do_mounts.c
index 94aeec7aa917..b290aadb1d3f 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -8,6 +8,7 @@
8#include <linux/security.h> 8#include <linux/security.h>
9#include <linux/delay.h> 9#include <linux/delay.h>
10#include <linux/mount.h> 10#include <linux/mount.h>
11#include <linux/device.h>
11 12
12#include <linux/nfs_fs.h> 13#include <linux/nfs_fs.h>
13#include <linux/nfs_fs_sb.h> 14#include <linux/nfs_fs_sb.h>
@@ -403,6 +404,10 @@ void __init prepare_namespace(void)
403 ssleep(root_delay); 404 ssleep(root_delay);
404 } 405 }
405 406
407 /* wait for the known devices to complete their probing */
408 while (driver_probe_done() != 0)
409 msleep(100);
410
406 md_run_setup(); 411 md_run_setup();
407 412
408 if (saved_root_name[0]) { 413 if (saved_root_name[0]) {