]> git.itanic.dy.fi Git - linux-stable/commitdiff
xhci: Add grace period after xHC start to prevent premature runtime suspend.
authorMathias Nyman <mathias.nyman@linux.intel.com>
Thu, 25 Aug 2022 15:08:39 +0000 (18:08 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 15 Sep 2022 10:04:52 +0000 (12:04 +0200)
commit 33e321586e37b642ad10594b9ef25a613555cd08 upstream.

After xHC controller is started, either in probe or resume, it can take
a while before any of the connected usb devices are visible to the roothub
due to link training.

It's possible xhci driver loads, sees no acivity and suspends the host
before the USB device is visible.

In one testcase with a hotplugged xHC controller the host finally detected
the connected USB device and generated a wake 500ms after host initial
start.

If hosts didn't suspend the device duringe training it probablty wouldn't
take up to 500ms to detect it, but looking at specs reveal USB3 link
training has a couple long timeout values, such as 120ms
RxDetectQuietTimeout, and 360ms PollingLFPSTimeout.

So Add a 500ms grace period that keeps polling the roothub for 500ms after
start, preventing runtime suspend until USB devices are detected.

Cc: stable@vger.kernel.org
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20220825150840.132216-3-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h

index dd46c15c4853f4f84c1f472cc5a00dd799dbc9e1..66cb9f08bff103bcfe0de40065981c5f0f336cc1 100644 (file)
@@ -1555,6 +1555,17 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
 
        status = bus_state->resuming_ports;
 
+       /*
+        * SS devices are only visible to roothub after link training completes.
+        * Keep polling roothubs for a grace period after xHC start
+        */
+       if (xhci->run_graceperiod) {
+               if (time_before(jiffies, xhci->run_graceperiod))
+                       status = 1;
+               else
+                       xhci->run_graceperiod = 0;
+       }
+
        mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC | PORT_CEC;
 
        /* For each port, did anything change?  If so, set that bit in buf. */
index 2f59d447411b50e3f4b8d84518603ac20eb5e441..5ce16a259e61223f0fbb8eaa47347f2da80ed7a1 100644 (file)
@@ -149,9 +149,11 @@ int xhci_start(struct xhci_hcd *xhci)
                xhci_err(xhci, "Host took too long to start, "
                                "waited %u microseconds.\n",
                                XHCI_MAX_HALT_USEC);
-       if (!ret)
+       if (!ret) {
                /* clear state flags. Including dying, halted or removing */
                xhci->xhc_state = 0;
+               xhci->run_graceperiod = jiffies + msecs_to_jiffies(500);
+       }
 
        return ret;
 }
index 05ae3361e4d0fce9cccfb25364bf5f9f545d273d..0dc448630197c564e2edb60cc0bc3a97f6d2a031 100644 (file)
@@ -1814,7 +1814,7 @@ struct xhci_hcd {
 
        /* Host controller watchdog timer structures */
        unsigned int            xhc_state;
-
+       unsigned long           run_graceperiod;
        u32                     command;
        struct s3_save          s3;
 /* Host controller is dying - not responding to commands. "I'm not dead yet!"