aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2012-11-14 19:10:49 -0500
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2013-01-03 17:10:22 -0500
commit8b8132bc3d1cc3d4c0687e4d638a482fa920d98a (patch)
tree6a5cda1a519510937e2aa64e74618701250fb439
parent1c7439c61fa6516419c32a9824976334ea969d47 (diff)
USB: Ignore xHCI Reset Device status.
When the USB core finishes reseting a USB device, the xHCI driver sends a Reset Device command to the host. The xHC then updates its internal representation of the USB device to the 'Default' device state. If the device was already in the Default state, the xHC will complete the command with an error status. If a device needs to be reset several times during enumeration, the second reset will always fail because of the xHCI Reset Device command. This can cause issues during enumeration. For example, usb_reset_and_verify_device calls into hub_port_init in a loop. Say that on the first call into hub_port_init, the device is successfully reset, but doesn't respond to several set address control transfers. Then the port will be disabled, but the udev will remain in tact. usb_reset_and_verify_device will call into hub_port_init again. On the second call into hub_port_init, the device will be reset, and the xHCI driver will issue a Reset Device command. This command will fail (because the device is already in the Default state), and usb_reset_and_verify_device will fail. The port will be disabled, and the device won't be able to enumerate. Fix this by ignoring the return value of the HCD reset_device callback. This commit should be backported to kernels as old as 3.2, that contain the commit 75d7cf72ab9fa01dc70877aa5c68e8ef477229dc "usbcore: refine warm reset logic". Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Cc: stable@vger.kernel.org
-rw-r--r--drivers/usb/core/hub.c13
1 files changed, 5 insertions, 8 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 7f8f10ec127e..3bc50fc110eb 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2565,14 +2565,11 @@ static void hub_port_finish_reset(struct usb_hub *hub, int port1,
2565 msleep(10 + 40); 2565 msleep(10 + 40);
2566 update_devnum(udev, 0); 2566 update_devnum(udev, 0);
2567 hcd = bus_to_hcd(udev->bus); 2567 hcd = bus_to_hcd(udev->bus);
2568 if (hcd->driver->reset_device) { 2568 /* The xHC may think the device is already reset,
2569 *status = hcd->driver->reset_device(hcd, udev); 2569 * so ignore the status.
2570 if (*status < 0) { 2570 */
2571 dev_err(&udev->dev, "Cannot reset " 2571 if (hcd->driver->reset_device)
2572 "HCD device state\n"); 2572 hcd->driver->reset_device(hcd, udev);
2573 break;
2574 }
2575 }
2576 } 2573 }
2577 /* FALL THROUGH */ 2574 /* FALL THROUGH */
2578 case -ENOTCONN: 2575 case -ENOTCONN: