diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2006-08-11 04:55:12 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-12-01 17:25:52 -0500 |
commit | c066475e1fe3b3afbd613ddf5f1eca9be4fb6de0 (patch) | |
tree | 43d9d68fd1d57a3ae376d0d3fe22df32482715d3 | |
parent | 958e8741bf9ff5d0f0b82b7cef578e96c764a288 (diff) |
USB: create a new thread for every USB device found during the probe sequence
Might speed up some systems. If nothing else, a bad driver should not
take the whole USB subsystem down with it.
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/usb/core/Kconfig | 15 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 81 |
2 files changed, 74 insertions, 22 deletions
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 6e3b5358a760..f8324d8d06ac 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig | |||
@@ -72,6 +72,21 @@ config USB_SUSPEND | |||
72 | 72 | ||
73 | If you are unsure about this, say N here. | 73 | If you are unsure about this, say N here. |
74 | 74 | ||
75 | config USB_MULTITHREAD_PROBE | ||
76 | bool "USB Multi-threaded probe (EXPERIMENTAL)" | ||
77 | depends on USB && EXPERIMENTAL | ||
78 | default n | ||
79 | help | ||
80 | Say Y here if you want the USB core to spawn a new thread for | ||
81 | every USB device that is probed. This can cause a small speedup | ||
82 | in boot times on systems with a lot of different USB devices. | ||
83 | |||
84 | This option should be safe to enable, but if any odd probing | ||
85 | problems are found, please disable it, or dynamically turn it | ||
86 | off in the /sys/module/usbcore/parameters/multithread_probe | ||
87 | file | ||
88 | |||
89 | When in doubt, say N. | ||
75 | 90 | ||
76 | config USB_OTG | 91 | config USB_OTG |
77 | bool | 92 | bool |
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index c961a32f3176..f6e692180587 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -87,6 +87,16 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait); | |||
87 | 87 | ||
88 | static struct task_struct *khubd_task; | 88 | static struct task_struct *khubd_task; |
89 | 89 | ||
90 | /* multithreaded probe logic */ | ||
91 | static int multithread_probe = | ||
92 | #ifdef CONFIG_USB_MULTITHREAD_PROBE | ||
93 | 1; | ||
94 | #else | ||
95 | 0; | ||
96 | #endif | ||
97 | module_param(multithread_probe, bool, S_IRUGO); | ||
98 | MODULE_PARM_DESC(multithread_probe, "Run each USB device probe in a new thread"); | ||
99 | |||
90 | /* cycle leds on hubs that aren't blinking for attention */ | 100 | /* cycle leds on hubs that aren't blinking for attention */ |
91 | static int blinkenlights = 0; | 101 | static int blinkenlights = 0; |
92 | module_param (blinkenlights, bool, S_IRUGO); | 102 | module_param (blinkenlights, bool, S_IRUGO); |
@@ -1238,29 +1248,17 @@ static inline void show_string(struct usb_device *udev, char *id, char *string) | |||
1238 | static int __usb_port_suspend(struct usb_device *, int port1); | 1248 | static int __usb_port_suspend(struct usb_device *, int port1); |
1239 | #endif | 1249 | #endif |
1240 | 1250 | ||
1241 | /** | 1251 | static int __usb_new_device(void *void_data) |
1242 | * usb_new_device - perform initial device setup (usbcore-internal) | ||
1243 | * @udev: newly addressed device (in ADDRESS state) | ||
1244 | * | ||
1245 | * This is called with devices which have been enumerated, but not yet | ||
1246 | * configured. The device descriptor is available, but not descriptors | ||
1247 | * for any device configuration. The caller must have locked either | ||
1248 | * the parent hub (if udev is a normal device) or else the | ||
1249 | * usb_bus_list_lock (if udev is a root hub). The parent's pointer to | ||
1250 | * udev has already been installed, but udev is not yet visible through | ||
1251 | * sysfs or other filesystem code. | ||
1252 | * | ||
1253 | * Returns 0 for success (device is configured and listed, with its | ||
1254 | * interfaces, in sysfs); else a negative errno value. | ||
1255 | * | ||
1256 | * This call is synchronous, and may not be used in an interrupt context. | ||
1257 | * | ||
1258 | * Only the hub driver or root-hub registrar should ever call this. | ||
1259 | */ | ||
1260 | int usb_new_device(struct usb_device *udev) | ||
1261 | { | 1252 | { |
1253 | struct usb_device *udev = void_data; | ||
1262 | int err; | 1254 | int err; |
1263 | 1255 | ||
1256 | /* Lock ourself into memory in order to keep a probe sequence | ||
1257 | * sleeping in a new thread from allowing us to be unloaded. | ||
1258 | */ | ||
1259 | if (!try_module_get(THIS_MODULE)) | ||
1260 | return -EINVAL; | ||
1261 | |||
1264 | err = usb_get_configuration(udev); | 1262 | err = usb_get_configuration(udev); |
1265 | if (err < 0) { | 1263 | if (err < 0) { |
1266 | dev_err(&udev->dev, "can't read configurations, error %d\n", | 1264 | dev_err(&udev->dev, "can't read configurations, error %d\n", |
@@ -1356,13 +1354,52 @@ int usb_new_device(struct usb_device *udev) | |||
1356 | goto fail; | 1354 | goto fail; |
1357 | } | 1355 | } |
1358 | 1356 | ||
1359 | return 0; | 1357 | exit: |
1358 | module_put(THIS_MODULE); | ||
1359 | return err; | ||
1360 | 1360 | ||
1361 | fail: | 1361 | fail: |
1362 | usb_set_device_state(udev, USB_STATE_NOTATTACHED); | 1362 | usb_set_device_state(udev, USB_STATE_NOTATTACHED); |
1363 | return err; | 1363 | goto exit; |
1364 | } | 1364 | } |
1365 | 1365 | ||
1366 | /** | ||
1367 | * usb_new_device - perform initial device setup (usbcore-internal) | ||
1368 | * @udev: newly addressed device (in ADDRESS state) | ||
1369 | * | ||
1370 | * This is called with devices which have been enumerated, but not yet | ||
1371 | * configured. The device descriptor is available, but not descriptors | ||
1372 | * for any device configuration. The caller must have locked either | ||
1373 | * the parent hub (if udev is a normal device) or else the | ||
1374 | * usb_bus_list_lock (if udev is a root hub). The parent's pointer to | ||
1375 | * udev has already been installed, but udev is not yet visible through | ||
1376 | * sysfs or other filesystem code. | ||
1377 | * | ||
1378 | * The return value for this function depends on if the | ||
1379 | * multithread_probe variable is set or not. If it's set, it will | ||
1380 | * return a if the probe thread was successfully created or not. If the | ||
1381 | * variable is not set, it will return if the device is configured | ||
1382 | * properly or not. interfaces, in sysfs); else a negative errno value. | ||
1383 | * | ||
1384 | * This call is synchronous, and may not be used in an interrupt context. | ||
1385 | * | ||
1386 | * Only the hub driver or root-hub registrar should ever call this. | ||
1387 | */ | ||
1388 | int usb_new_device(struct usb_device *udev) | ||
1389 | { | ||
1390 | struct task_struct *probe_task; | ||
1391 | int ret = 0; | ||
1392 | |||
1393 | if (multithread_probe) { | ||
1394 | probe_task = kthread_run(__usb_new_device, udev, | ||
1395 | "usb-probe-%s", udev->devnum); | ||
1396 | if (IS_ERR(probe_task)) | ||
1397 | ret = PTR_ERR(probe_task); | ||
1398 | } else | ||
1399 | ret = __usb_new_device(udev); | ||
1400 | |||
1401 | return ret; | ||
1402 | } | ||
1366 | 1403 | ||
1367 | static int hub_port_status(struct usb_hub *hub, int port1, | 1404 | static int hub_port_status(struct usb_hub *hub, int port1, |
1368 | u16 *status, u16 *change) | 1405 | u16 *status, u16 *change) |