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.willi...@intel.com>
---
 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to