Jiri Slaby e01e9d
From: Alan Stern <stern@rowland.harvard.edu>
Jiri Slaby e01e9d
Date: Tue, 1 Aug 2017 10:41:56 -0400
Jiri Slaby e01e9d
Subject: [PATCH] USB: Check for dropped connection before switching to full
Jiri Slaby e01e9d
 speed
Jiri Slaby e01e9d
References: bnc#1060662
Thomas Zimmermann 1d81d2
Patch-mainline: v4.12.8
Jiri Slaby e01e9d
Git-commit: 94c43b9897abf4ea366ed4dba027494e080c7050
Jiri Slaby e01e9d
Jiri Slaby e01e9d
commit 94c43b9897abf4ea366ed4dba027494e080c7050 upstream.
Jiri Slaby e01e9d
Jiri Slaby e01e9d
Some buggy USB disk adapters disconnect and reconnect multiple times
Jiri Slaby e01e9d
during the enumeration procedure.  This may lead to a device
Jiri Slaby e01e9d
connecting at full speed instead of high speed, because when the USB
Jiri Slaby e01e9d
stack sees that a device isn't able to enumerate at high speed, it
Jiri Slaby e01e9d
tries to hand the connection over to a full-speed companion
Jiri Slaby e01e9d
controller.
Jiri Slaby e01e9d
Jiri Slaby e01e9d
The logic for doing this is careful to check that the device is still
Jiri Slaby e01e9d
connected.  But this check is inadequate if the device disconnects and
Jiri Slaby e01e9d
reconnects before the check is done.  The symptom is that a device
Jiri Slaby e01e9d
works, but much more slowly than it is capable of operating.
Jiri Slaby e01e9d
Jiri Slaby e01e9d
The situation was made worse recently by commit 22547c4cc4fe ("usb:
Jiri Slaby e01e9d
hub: Wait for connection to be reestablished after port reset"), which
Jiri Slaby e01e9d
increases the delay following a reset before a disconnect is
Jiri Slaby e01e9d
recognized, thus giving the device more time to reconnect.
Jiri Slaby e01e9d
Jiri Slaby e01e9d
This patch makes the check more robust.  If the device was
Jiri Slaby e01e9d
disconnected at any time during enumeration, we will now skip the
Jiri Slaby e01e9d
full-speed handover.
Jiri Slaby e01e9d
Jiri Slaby e01e9d
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Jiri Slaby e01e9d
Reported-and-tested-by: Zdenek Kabelac <zkabelac@redhat.com>
Jiri Slaby e01e9d
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Jiri Slaby e01e9d
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Jiri Slaby e01e9d
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Jiri Slaby e01e9d
---
Jiri Slaby e01e9d
 drivers/usb/core/hub.c | 10 ++++++----
Jiri Slaby e01e9d
 1 file changed, 6 insertions(+), 4 deletions(-)
Jiri Slaby e01e9d
Jiri Slaby e01e9d
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
Jiri Slaby e01e9d
index b8bb20d7acdb..0881a3e8131c 100644
Jiri Slaby e01e9d
--- a/drivers/usb/core/hub.c
Jiri Slaby e01e9d
+++ b/drivers/usb/core/hub.c
Jiri Slaby e01e9d
@@ -4730,7 +4730,8 @@ hub_power_remaining(struct usb_hub *hub)
Jiri Slaby e01e9d
 static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
Jiri Slaby e01e9d
 		u16 portchange)
Jiri Slaby e01e9d
 {
Jiri Slaby e01e9d
-	int status, i;
Jiri Slaby e01e9d
+	int status = -ENODEV;
Jiri Slaby e01e9d
+	int i;
Jiri Slaby e01e9d
 	unsigned unit_load;
Jiri Slaby e01e9d
 	struct usb_device *hdev = hub->hdev;
Jiri Slaby e01e9d
 	struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
Jiri Slaby e01e9d
@@ -4934,9 +4935,10 @@ loop:
Jiri Slaby e01e9d
 
Jiri Slaby e01e9d
 done:
Jiri Slaby e01e9d
 	hub_port_disable(hub, port1, 1);
Jiri Slaby e01e9d
-	if (hcd->driver->relinquish_port && !hub->hdev->parent)
Jiri Slaby e01e9d
-		hcd->driver->relinquish_port(hcd, port1);
Jiri Slaby e01e9d
-
Jiri Slaby e01e9d
+	if (hcd->driver->relinquish_port && !hub->hdev->parent) {
Jiri Slaby e01e9d
+		if (status != -ENOTCONN && status != -ENODEV)
Jiri Slaby e01e9d
+			hcd->driver->relinquish_port(hcd, port1);
Jiri Slaby e01e9d
+	}
Jiri Slaby e01e9d
 }
Jiri Slaby e01e9d
 
Jiri Slaby e01e9d
 /* Handle physical or logical connection change events.
Jiri Slaby e01e9d
-- 
Jiri Slaby e01e9d
2.14.2
Jiri Slaby e01e9d