Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xhci: Add grace period after xHC start to prevent premature runtime suspend.

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>

authored by

Mathias Nyman and committed by
Greg Kroah-Hartman
33e32158 4a593a62

+15 -2
+11
drivers/usb/host/xhci-hub.c
··· 1648 1648 1649 1649 status = bus_state->resuming_ports; 1650 1650 1651 + /* 1652 + * SS devices are only visible to roothub after link training completes. 1653 + * Keep polling roothubs for a grace period after xHC start 1654 + */ 1655 + if (xhci->run_graceperiod) { 1656 + if (time_before(jiffies, xhci->run_graceperiod)) 1657 + status = 1; 1658 + else 1659 + xhci->run_graceperiod = 0; 1660 + } 1661 + 1651 1662 mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC | PORT_CEC; 1652 1663 1653 1664 /* For each port, did anything change? If so, set that bit in buf. */
+3 -1
drivers/usb/host/xhci.c
··· 151 151 xhci_err(xhci, "Host took too long to start, " 152 152 "waited %u microseconds.\n", 153 153 XHCI_MAX_HALT_USEC); 154 - if (!ret) 154 + if (!ret) { 155 155 /* clear state flags. Including dying, halted or removing */ 156 156 xhci->xhc_state = 0; 157 + xhci->run_graceperiod = jiffies + msecs_to_jiffies(500); 158 + } 157 159 158 160 return ret; 159 161 }
+1 -1
drivers/usb/host/xhci.h
··· 1826 1826 1827 1827 /* Host controller watchdog timer structures */ 1828 1828 unsigned int xhc_state; 1829 - 1829 + unsigned long run_graceperiod; 1830 1830 u32 command; 1831 1831 struct s3_save s3; 1832 1832 /* Host controller is dying - not responding to commands. "I'm not dead yet!"