Commit 637d11bf authored by Luben Tuikov's avatar Luben Tuikov Committed by Greg Kroah-Hartman

USB: Reset USB 3.0 devices on (re)discovery

If the device isn't reset, the XHCI HCD sends
SET ADDRESS to address 0 while the device is
already in Addressed state, and the request is
dropped on the floor as it is addressed to the
default address. This sequence of events, which this
patch fixes looks like this:

usb_reset_and_verify_device()
	hub_port_init()
		hub_set_address()
			SET_ADDRESS to 0 with 1
		usb_get_device_descriptor(udev, 8)
		usb_get_device_descriptor(udev, 18)
	descriptors_changed() --> goto re_enumerate:
		hub_port_logical_disconnect()
			kick_khubd()

And then:

hub_events()
	hub_port_connect_change()
		usb_disconnect()
			usb_disable_device()
		new device struct
		sets device state to Powered
		choose_address()
		hub_port_init() <-- no reset, but SET ADDRESS to 0 with 1, timeout!

The solution is to always reset the device in
hub_port_init() to put it in a known state.
Signed-off-by: default avatarLuben Tuikov <ltuikov@yahoo.com>
Cc: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 72a012ce
...@@ -2681,17 +2681,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, ...@@ -2681,17 +2681,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
mutex_lock(&usb_address0_mutex); mutex_lock(&usb_address0_mutex);
if (!udev->config && oldspeed == USB_SPEED_SUPER) { /* Reset the device; full speed may morph to high speed */
/* Don't reset USB 3.0 devices during an initial setup */ /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
usb_set_device_state(udev, USB_STATE_DEFAULT); retval = hub_port_reset(hub, port1, udev, delay);
} else { if (retval < 0) /* error or disconnect */
/* Reset the device; full speed may morph to high speed */ goto fail;
/* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */ /* success, speed is known */
retval = hub_port_reset(hub, port1, udev, delay);
if (retval < 0) /* error or disconnect */
goto fail;
/* success, speed is known */
}
retval = -ENODEV; retval = -ENODEV;
if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) { if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment