summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/host/xhci-hub.c47
1 files changed, 25 insertions, 22 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 541ccc45ea51..0054d02239e2 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -924,7 +924,7 @@ static void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status,
}
static int xhci_handle_usb2_port_link_resume(struct xhci_port *port,
- u32 *status, u32 portsc,
+ u32 portsc,
unsigned long *flags)
{
struct xhci_bus_state *bus_state;
@@ -939,7 +939,6 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port,
wIndex = port->hcd_portnum;
if ((portsc & PORT_RESET) || !(portsc & PORT_PE)) {
- *status = 0xffffffff;
return -EINVAL;
}
/* did port event handler already start resume timing? */
@@ -973,6 +972,8 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port,
port->resume_timestamp = 0;
clear_bit(wIndex, &bus_state->resuming_ports);
+
+ reinit_completion(&port->rexit_done);
port->rexit_active = true;
xhci_test_and_clear_bit(xhci, port, PORT_PLC);
@@ -989,7 +990,6 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port,
wIndex + 1);
if (!slot_id) {
xhci_dbg(xhci, "slot_id is zero\n");
- *status = 0xffffffff;
return -ENODEV;
}
xhci_ring_device(xhci, slot_id);
@@ -998,22 +998,19 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port,
xhci_warn(xhci, "Port resume timed out, port %d-%d: 0x%x\n",
hcd->self.busnum, wIndex + 1, port_status);
- *status |= USB_PORT_STAT_SUSPEND;
- port->rexit_active = false;
+ /*
+ * keep rexit_active set if U0 transition failed so we
+ * know to report PORT_STAT_SUSPEND status back to
+ * usbcore. It will be cleared later once the port is
+ * out of RESUME/U3 state
+ */
}
usb_hcd_end_port_resume(&hcd->self, wIndex);
bus_state->port_c_suspend |= 1 << wIndex;
bus_state->suspended_ports &= ~(1 << wIndex);
- } else {
- /*
- * The resume has been signaling for less than
- * USB_RESUME_TIME. Report the port status as SUSPEND,
- * let the usbcore check port status again and clear
- * resume signaling later.
- */
- *status |= USB_PORT_STAT_SUSPEND;
}
+
return 0;
}
@@ -1090,6 +1087,7 @@ static void xhci_get_usb2_port_status(struct xhci_port *port, u32 *status,
struct xhci_bus_state *bus_state;
u32 link_state;
u32 portnum;
+ int err;
bus_state = &port->rhub->bus_state;
link_state = portsc & PORT_PLS_MASK;
@@ -1111,8 +1109,12 @@ static void xhci_get_usb2_port_status(struct xhci_port *port, u32 *status,
}
}
if (link_state == XDEV_RESUME) {
- xhci_handle_usb2_port_link_resume(port, status, portsc,
- flags);
+ err = xhci_handle_usb2_port_link_resume(port, portsc,
+ flags);
+ if (err < 0)
+ *status = 0xffffffff;
+ else if (port->resume_timestamp || port->rexit_active)
+ *status |= USB_PORT_STAT_SUSPEND;
}
}
@@ -1121,13 +1123,14 @@ static void xhci_get_usb2_port_status(struct xhci_port *port, u32 *status,
* or resuming. Port either resumed to U0/U1/U2, disconnected, or in a
* error state. Resume related variables should be cleared in all those cases.
*/
- if ((link_state != XDEV_U3 &&
- link_state != XDEV_RESUME) &&
- (port->resume_timestamp ||
- test_bit(portnum, &bus_state->resuming_ports))) {
- port->resume_timestamp = 0;
- clear_bit(portnum, &bus_state->resuming_ports);
- usb_hcd_end_port_resume(&port->rhub->hcd->self, portnum);
+ if (link_state != XDEV_U3 && link_state != XDEV_RESUME) {
+ if (port->resume_timestamp ||
+ test_bit(portnum, &bus_state->resuming_ports)) {
+ port->resume_timestamp = 0;
+ clear_bit(portnum, &bus_state->resuming_ports);
+ usb_hcd_end_port_resume(&port->rhub->hcd->self, portnum);
+ }
+ port->rexit_active = 0;
}
}