Work around a remote wakeup vs port poweroff request race. A wakeup request sets the timer, but by the time it expires the port has been turned off, so we hit: if ((raw_port_status & PORT_RESET) || !(raw_port_status & PORT_PE)) return 0xffffffff; ...in xhci_get_port_status When userspace has set the port policy to allow poweroff the assumption is that it no longer cares about remote wakeup requests for that port. If a request happens to collide with autosuspend of the port we need to make sure to cancel an in-flight request otherwise we can end up in an infinite loop. Signed-off-by: Dan Williams <dan.j.williams@xxxxxxxxx> --- drivers/usb/host/xhci-hub.c | 12 ++++++++++-- 1 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 9992fbfec85f..2333ec573594 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1004,9 +1004,16 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, xhci_disable_port(hcd, xhci, wIndex, port_array[wIndex], temp); break; - case USB_PORT_FEAT_POWER: - writel(temp & ~PORT_POWER, port_array[wIndex]); + case USB_PORT_FEAT_POWER: { + struct xhci_bus_state *bus_state; + bus_state = &xhci->bus_state[hcd_index(hcd)]; + writel(temp & ~PORT_POWER, port_array[wIndex]); + if (test_and_clear_bit(wIndex, &bus_state->resuming_ports)) { + bus_state->resume_done[wIndex] = 0; + xhci_dbg(xhci, "port%d: resume cancelled\n", + wIndex); + } spin_unlock_irqrestore(&xhci->lock, flags); temp = usb_acpi_power_manageable(hcd->self.root_hub, wIndex); @@ -1015,6 +1022,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, wIndex, false); spin_lock_irqsave(&xhci->lock, flags); break; + } default: goto error; } -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html