summaryrefslogtreecommitdiff
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorMike Looijmans <mike.looijmans@topic.nl>2017-11-09 15:16:46 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-12-10 15:40:44 +0300
commit755532dd5f643f1a1da479bb133a946ce5c97905 (patch)
tree10941ddc50098e451738914e721c19a251defd79 /drivers/usb/core
parenta633c7ed4a4c6097475de05d950e35cf92b8dec7 (diff)
downloadlinux-755532dd5f643f1a1da479bb133a946ce5c97905.tar.xz
usb: hub: Cycle HUB power when initialization fails
commit 973593a960ddac0f14f0d8877d2d0abe0afda795 upstream. Sometimes the USB device gets confused about the state of the initialization and the connection fails. In particular, the device thinks that it's already set up and running while the host thinks the device still needs to be configured. To work around this issue, power-cycle the hub's output to issue a sort of "reset" to the device. This makes the device restart its state machine and then the initialization succeeds. This fixes problems where the kernel reports a list of errors like this: usb 1-1.3: device not accepting address 19, error -71 The end result is a non-functioning device. After this patch, the sequence becomes like this: usb 1-1.3: new high-speed USB device number 18 using ci_hdrc usb 1-1.3: device not accepting address 18, error -71 usb 1-1.3: new high-speed USB device number 19 using ci_hdrc usb 1-1.3: device not accepting address 19, error -71 usb 1-1-port3: attempt power cycle usb 1-1.3: new high-speed USB device number 21 using ci_hdrc usb-storage 1-1.3:1.2: USB Mass Storage device detected Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/hub.c9
1 files changed, 9 insertions, 0 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index e9ce6bb0b22d..8f7d94239ee3 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -4935,6 +4935,15 @@ loop:
usb_put_dev(udev);
if ((status == -ENOTCONN) || (status == -ENOTSUPP))
break;
+
+ /* When halfway through our retry count, power-cycle the port */
+ if (i == (SET_CONFIG_TRIES / 2) - 1) {
+ dev_info(&port_dev->dev, "attempt power cycle\n");
+ usb_hub_set_port_power(hdev, hub, port1, false);
+ msleep(2 * hub_power_on_good_delay(hub));
+ usb_hub_set_port_power(hdev, hub, port1, true);
+ msleep(hub_power_on_good_delay(hub));
+ }
}
if (hub->hdev->parent ||
!hcd->driver->port_handed_over ||