On Tue, 17 Oct 2017, Mathias Nyman wrote: > If the connect status change is set during reset signaling, but > the status remains connected just retry port reset. > > This solves an issue with connecting a 90W HP Thunderbolt 3 dock > with a Lenovo Carbon x1 (5th generation) which causes a 30min loop > of a high speed device being re-discovererd before usb ports starts > working. > > [...] > [ 389.023845] usb 3-1: new high-speed USB device number 55 using xhci_hcd > [ 389.491841] usb 3-1: new high-speed USB device number 56 using xhci_hcd > [ 389.959928] usb 3-1: new high-speed USB device number 57 using xhci_hcd > [...] > > This is caused by a high speed device that doesn't successfully go to the > enabled state after the second port reset. Instead the connection bounces > (connected, with connect status change), bailing out completely from > enumeration just to restart from scratch. > > Link: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1716332 > > Cc: Stable <stable@xxxxxxxxxxxxxxx> > Signed-off-by: Mathias Nyman <mathias.nyman@xxxxxxxxxxxxxxx> > --- > v2 changes: > clear connect change bit in hub_port_wait_reset() where it was detected > > drivers/usb/core/hub.c | 11 +++++++---- > 1 file changed, 7 insertions(+), 4 deletions(-) > > diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c > index 41eaf0b..763b455 100644 > --- a/drivers/usb/core/hub.c > +++ b/drivers/usb/core/hub.c > @@ -2710,13 +2710,16 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, > if (!(portstatus & USB_PORT_STAT_CONNECTION)) > return -ENOTCONN; > > - /* bomb out completely if the connection bounced. A USB 3.0 > - * connection may bounce if multiple warm resets were issued, > + /* Retry if connect change is set but status is still connected. > + * A USB 3.0 connection may bounce if multiple warm resets were issued, > * but the device may have successfully re-connected. Ignore it. > */ > if (!hub_is_superspeed(hub->hdev) && > - (portchange & USB_PORT_STAT_C_CONNECTION)) > - return -ENOTCONN; > + (portchange & USB_PORT_STAT_C_CONNECTION)) { > + usb_clear_port_feature(hub->hdev, port1, > + USB_PORT_FEAT_C_CONNECTION); > + return -EAGAIN; > + } > > if (!(portstatus & USB_PORT_STAT_ENABLE)) > return -EBUSY; > Acked-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>