|
@@ -4758,6 +4758,8 @@ static void hub_events(void)
|
|
|
|
|
|
/* deal with port status changes */
|
|
|
for (i = 1; i <= hdev->maxchild; i++) {
|
|
|
+ struct usb_device *udev = hub->ports[i - 1]->child;
|
|
|
+
|
|
|
if (test_bit(i, hub->busy_bits))
|
|
|
continue;
|
|
|
connect_change = test_bit(i, hub->change_bits);
|
|
@@ -4856,8 +4858,6 @@ static void hub_events(void)
|
|
|
*/
|
|
|
if (hub_port_warm_reset_required(hub, portstatus)) {
|
|
|
int status;
|
|
|
- struct usb_device *udev =
|
|
|
- hub->ports[i - 1]->child;
|
|
|
|
|
|
dev_dbg(hub_dev, "warm reset port %d\n", i);
|
|
|
if (!udev ||
|
|
@@ -4874,6 +4874,24 @@ static void hub_events(void)
|
|
|
usb_unlock_device(udev);
|
|
|
connect_change = 0;
|
|
|
}
|
|
|
+ /*
|
|
|
+ * On disconnect USB3 protocol ports transit from U0 to
|
|
|
+ * SS.Inactive to Rx.Detect. If this happens a warm-
|
|
|
+ * reset is not needed, but a (re)connect may happen
|
|
|
+ * before khubd runs and sees the disconnect, and the
|
|
|
+ * device may be an unknown state.
|
|
|
+ *
|
|
|
+ * If the port went through SS.Inactive without khubd
|
|
|
+ * seeing it the C_LINK_STATE change flag will be set,
|
|
|
+ * and we reset the dev to put it in a known state.
|
|
|
+ */
|
|
|
+ } else if (udev && hub_is_superspeed(hub->hdev) &&
|
|
|
+ (portchange & USB_PORT_STAT_C_LINK_STATE) &&
|
|
|
+ (portstatus & USB_PORT_STAT_CONNECTION)) {
|
|
|
+ usb_lock_device(udev);
|
|
|
+ usb_reset_device(udev);
|
|
|
+ usb_unlock_device(udev);
|
|
|
+ connect_change = 0;
|
|
|
}
|
|
|
|
|
|
if (connect_change)
|