diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 544749b607a4..656ed6470e4a 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -986,14 +986,16 @@ static int xhci_handle_halted_endpoint(struct xhci_hcd *xhci, struct xhci_td *td, enum xhci_ep_reset_type reset_type) { + struct xhci_port *rhub_port = ep->vdev->rhub_port; unsigned int slot_id = ep->vdev->slot_id; int err; /* - * Avoid resetting endpoint if link is inactive. Can cause host hang. - * Device will be reset soon to recover the link so don't do anything + * Avoid resetting endpoint if link is inactive or device disonnected. + * Can cause host hang. + * Device will be reset to recover an inactive link, so don't do anything */ - if (ep->vdev->rhub_port->link_inactive) + if (rhub_port->link_inactive || !rhub_port->connected) return -ENODEV; /* add td to cancelled list and let reset ep handler take care of it */ @@ -2053,8 +2055,10 @@ static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event) * Tag broken links to avoid retries while hub driver sorts it out. * Link status is not relible while port is in reset. */ - if (!(portsc & PORT_RESET)) + if (!(portsc & PORT_RESET)) { port->link_inactive = (pls == XDEV_INACTIVE); + port->connected = !!(portsc & PORT_CONNECT); + } if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_RESUME) { xhci_dbg(xhci, "port resume event for port %d\n", port_id); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 9b6c7aeb1dca..0cc9edfd86f3 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1478,6 +1478,7 @@ struct xhci_port { struct xhci_hub *rhub; struct xhci_port_cap *port_cap; unsigned int link_inactive:1; + unsigned int connected:1; unsigned int lpm_incapable:1; unsigned long resume_timestamp; bool rexit_active;