diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 7f0c9176b495..3526665575af 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -924,7 +924,7 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port, return -EINVAL; } /* did port event handler already start resume timing? */ - if (!port->resume_done) { + if (!bus_state->resume_done[wIndex]) { /* If not, maybe we are in a host initated resume? */ if (test_bit(wIndex, &bus_state->resuming_ports)) { /* Host initated resume doesn't time the resume @@ -941,27 +941,28 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port, msecs_to_jiffies(USB_RESUME_TIMEOUT); set_bit(wIndex, &bus_state->resuming_ports); - port->resume_done = timeout; + bus_state->resume_done[wIndex] = timeout; mod_timer(&hcd->rh_timer, timeout); usb_hcd_start_port_resume(&hcd->self, wIndex); } /* Has resume been signalled for USB_RESUME_TIME yet? */ - } else if (time_after_eq(jiffies, port->resume_done)) { + } else if (time_after_eq(jiffies, bus_state->resume_done[wIndex])) { int time_left; xhci_dbg(xhci, "resume USB2 port %d-%d\n", hcd->self.busnum, wIndex + 1); - port->resume_done = 0; + bus_state->resume_done[wIndex] = 0; clear_bit(wIndex, &bus_state->resuming_ports); - port->rexit_active = true; + + set_bit(wIndex, &bus_state->rexit_ports); xhci_test_and_clear_bit(xhci, port, PORT_PLC); xhci_set_link_state(xhci, port, XDEV_U0); spin_unlock_irqrestore(&xhci->lock, *flags); time_left = wait_for_completion_timeout( - &port->rexit_done, + &bus_state->rexit_done[wIndex], msecs_to_jiffies(XHCI_MAX_REXIT_TIMEOUT_MS)); spin_lock_irqsave(&xhci->lock, *flags); @@ -980,7 +981,7 @@ 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; + clear_bit(wIndex, &bus_state->rexit_ports); } usb_hcd_end_port_resume(&hcd->self, wIndex); @@ -1087,10 +1088,10 @@ static void xhci_get_usb2_port_status(struct xhci_port *port, u32 *status, if (link_state == XDEV_U2) *status |= USB_PORT_STAT_L1; if (link_state == XDEV_U0) { - if (port->resume_done) + if (bus_state->resume_done[portnum]) usb_hcd_end_port_resume(&port->rhub->hcd->self, portnum); - port->resume_done = 0; + bus_state->resume_done[portnum] = 0; clear_bit(portnum, &bus_state->resuming_ports); if (bus_state->suspended_ports & (1 << portnum)) { bus_state->suspended_ports &= ~(1 << portnum); @@ -1162,11 +1163,11 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, * Clear stale usb2 resume signalling variables in case port changed * state during resume signalling. For example on error */ - if ((port->resume_done || + if ((bus_state->resume_done[wIndex] || test_bit(wIndex, &bus_state->resuming_ports)) && (raw_port_status & PORT_PLS_MASK) != XDEV_U3 && (raw_port_status & PORT_PLS_MASK) != XDEV_RESUME) { - port->resume_done = 0; + bus_state->resume_done[wIndex] = 0; clear_bit(wIndex, &bus_state->resuming_ports); usb_hcd_end_port_resume(&hcd->self, wIndex); } @@ -1425,7 +1426,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, pls == XDEV_RESUME || pls == XDEV_RECOVERY) { wait_u0 = true; - reinit_completion(&port->u3exit_done); + reinit_completion(&bus_state->u3exit_done[wIndex]); } if (pls <= XDEV_U3) /* U1, U2, U3 */ xhci_set_link_state(xhci, port, USB_SS_PORT_LS_U0); @@ -1435,7 +1436,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, break; } spin_unlock_irqrestore(&xhci->lock, flags); - if (!wait_for_completion_timeout(&port->u3exit_done, + if (!wait_for_completion_timeout(&bus_state->u3exit_done[wIndex], msecs_to_jiffies(500))) xhci_dbg(xhci, "missing U0 port change event for port %d-%d\n", hcd->self.busnum, portnum1); @@ -1674,8 +1675,8 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) if ((temp & mask) != 0 || (bus_state->port_c_suspend & 1 << i) || - (ports[i]->resume_done && time_after_eq( - jiffies, ports[i]->resume_done))) { + (bus_state->resume_done[i] && time_after_eq( + jiffies, bus_state->resume_done[i]))) { buf[(i + 1) / 8] |= 1 << (i + 1) % 8; status = 1; } diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 883a0cd8c03f..34985e4c31b8 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -2324,9 +2324,6 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) xhci->hw_ports[i].addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS * i; xhci->hw_ports[i].hw_portnum = i; - - init_completion(&xhci->hw_ports[i].rexit_done); - init_completion(&xhci->hw_ports[i].u3exit_done); } xhci->rh_bw = kcalloc_node(num_ports, sizeof(*xhci->rh_bw), flags, @@ -2596,6 +2593,13 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) */ for (i = 0; i < MAX_HC_SLOTS; i++) xhci->devs[i] = NULL; + for (i = 0; i < USB_MAXCHILDREN; i++) { + xhci->usb2_rhub.bus_state.resume_done[i] = 0; + xhci->usb3_rhub.bus_state.resume_done[i] = 0; + /* Only the USB 2.0 completions will ever be used. */ + init_completion(&xhci->usb2_rhub.bus_state.rexit_done[i]); + init_completion(&xhci->usb3_rhub.bus_state.u3exit_done[i]); + } if (scratchpad_alloc(xhci, flags)) goto fail; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 9458930dcba7..a2a0c88ef4eb 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1989,7 +1989,7 @@ static void handle_port_status(struct xhci_hcd *xhci, goto cleanup; } else if (!test_bit(hcd_portnum, &bus_state->resuming_ports)) { xhci_dbg(xhci, "resume HS port %d\n", port_id); - port->resume_done = jiffies + + bus_state->resume_done[hcd_portnum] = jiffies + msecs_to_jiffies(USB_RESUME_TIMEOUT); set_bit(hcd_portnum, &bus_state->resuming_ports); /* Do the rest in GetPortStatus after resume time delay. @@ -1998,7 +1998,7 @@ static void handle_port_status(struct xhci_hcd *xhci, */ set_bit(HCD_FLAG_POLL_RH, &hcd->flags); mod_timer(&hcd->rh_timer, - port->resume_done); + bus_state->resume_done[hcd_portnum]); usb_hcd_start_port_resume(&hcd->self, hcd_portnum); bogus_port_status = true; } @@ -2010,7 +2010,7 @@ static void handle_port_status(struct xhci_hcd *xhci, (portsc & PORT_PLS_MASK) == XDEV_U1 || (portsc & PORT_PLS_MASK) == XDEV_U2)) { xhci_dbg(xhci, "resume SS port %d finished\n", port_id); - complete(&port->u3exit_done); + complete(&bus_state->u3exit_done[hcd_portnum]); /* We've just brought the device into U0/1/2 through either the * Resume state after a device remote wakeup, or through the * U3Exit state after a host-initiated resume. If it's a device @@ -2035,9 +2035,10 @@ static void handle_port_status(struct xhci_hcd *xhci, * RExit to a disconnect state). If so, let the the driver know it's * out of the RExit state. */ - if (hcd->speed < HCD_USB3 && port->rexit_active) { - complete(&port->rexit_done); - port->rexit_active = false; + if (!DEV_SUPERSPEED_ANY(portsc) && hcd->speed < HCD_USB3 && + test_and_clear_bit(hcd_portnum, + &bus_state->rexit_ports)) { + complete(&bus_state->rexit_done[hcd_portnum]); bogus_port_status = true; goto cleanup; } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index e0be20d6a62a..a4b9283423f2 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1719,8 +1719,13 @@ struct xhci_bus_state { u32 port_c_suspend; u32 suspended_ports; u32 port_remote_wakeup; + unsigned long resume_done[USB_MAXCHILDREN]; /* which ports have started to resume */ unsigned long resuming_ports; + /* Which ports are waiting on RExit to U0 transition. */ + unsigned long rexit_ports; + struct completion rexit_done[USB_MAXCHILDREN]; + struct completion u3exit_done[USB_MAXCHILDREN]; }; @@ -1744,10 +1749,6 @@ struct xhci_port { struct xhci_hub *rhub; struct xhci_port_cap *port_cap; unsigned int lpm_incapable:1; - unsigned long resume_done; - bool rexit_active; - struct completion rexit_done; - struct completion u3exit_done; }; struct xhci_hub {