Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c066475e authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

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: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 958e8741
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -72,6 +72,21 @@ config USB_SUSPEND

	  If you are unsure about this, say N here.

config USB_MULTITHREAD_PROBE
	bool "USB Multi-threaded probe (EXPERIMENTAL)"
	depends on USB && EXPERIMENTAL
	default n
	help
	  Say Y here if you want the USB core to spawn a new thread for
	  every USB device that is probed.  This can cause a small speedup
	  in boot times on systems with a lot of different USB devices.

	  This option should be safe to enable, but if any odd probing
	  problems are found, please disable it, or dynamically turn it
	  off in the /sys/module/usbcore/parameters/multithread_probe
	  file

	  When in doubt, say N.

config USB_OTG
	bool
+59 −22
Original line number Diff line number Diff line
@@ -87,6 +87,16 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);

static struct task_struct *khubd_task;

/* multithreaded probe logic */
static int multithread_probe =
#ifdef CONFIG_USB_MULTITHREAD_PROBE
	1;
#else
	0;
#endif
module_param(multithread_probe, bool, S_IRUGO);
MODULE_PARM_DESC(multithread_probe, "Run each USB device probe in a new thread");

/* cycle leds on hubs that aren't blinking for attention */
static int blinkenlights = 0;
module_param (blinkenlights, bool, S_IRUGO);
@@ -1238,29 +1248,17 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
static int __usb_port_suspend(struct usb_device *, int port1);
#endif

/**
 * usb_new_device - perform initial device setup (usbcore-internal)
 * @udev: newly addressed device (in ADDRESS state)
 *
 * This is called with devices which have been enumerated, but not yet
 * configured.  The device descriptor is available, but not descriptors
 * for any device configuration.  The caller must have locked either
 * the parent hub (if udev is a normal device) or else the
 * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
 * udev has already been installed, but udev is not yet visible through
 * sysfs or other filesystem code.
 *
 * Returns 0 for success (device is configured and listed, with its
 * interfaces, in sysfs); else a negative errno value.
 *
 * This call is synchronous, and may not be used in an interrupt context.
 *
 * Only the hub driver or root-hub registrar should ever call this.
 */
int usb_new_device(struct usb_device *udev)
static int __usb_new_device(void *void_data)
{
	struct usb_device *udev = void_data;
	int err;

	/* Lock ourself into memory in order to keep a probe sequence
	 * sleeping in a new thread from allowing us to be unloaded.
	 */
	if (!try_module_get(THIS_MODULE))
		return -EINVAL;

	err = usb_get_configuration(udev);
	if (err < 0) {
		dev_err(&udev->dev, "can't read configurations, error %d\n",
@@ -1356,13 +1354,52 @@ int usb_new_device(struct usb_device *udev)
		goto fail;
	}

	return 0;
exit:
	module_put(THIS_MODULE);
	return err;

fail:
	usb_set_device_state(udev, USB_STATE_NOTATTACHED);
	return err;
	goto exit;
}

/**
 * usb_new_device - perform initial device setup (usbcore-internal)
 * @udev: newly addressed device (in ADDRESS state)
 *
 * This is called with devices which have been enumerated, but not yet
 * configured.  The device descriptor is available, but not descriptors
 * for any device configuration.  The caller must have locked either
 * the parent hub (if udev is a normal device) or else the
 * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
 * udev has already been installed, but udev is not yet visible through
 * sysfs or other filesystem code.
 *
 * The return value for this function depends on if the
 * multithread_probe variable is set or not.  If it's set, it will
 * return a if the probe thread was successfully created or not.  If the
 * variable is not set, it will return if the device is configured
 * properly or not.  interfaces, in sysfs); else a negative errno value.
 *
 * This call is synchronous, and may not be used in an interrupt context.
 *
 * Only the hub driver or root-hub registrar should ever call this.
 */
int usb_new_device(struct usb_device *udev)
{
	struct task_struct *probe_task;
	int ret = 0;

	if (multithread_probe) {
		probe_task = kthread_run(__usb_new_device, udev,
					 "usb-probe-%s", udev->devnum);
		if (IS_ERR(probe_task))
			ret = PTR_ERR(probe_task);
	} else
		ret = __usb_new_device(udev);

	return ret;
}

static int hub_port_status(struct usb_hub *hub, int port1,
			       u16 *status, u16 *change)