From d0a1b2c5fe9be9df6005c1034509db2b22b79cd5 Mon Sep 17 00:00:00 2001 From: Jonathan Bell Date: Tue, 15 Apr 2025 14:44:07 +0100 Subject: [PATCH] usb: xhci: default to Intel scheme for calculating U1/U2 timeouts By default, the System Exit Latency and Maximum Exit Latency are used to calculate hub port U1 and U2 timeout values. This has the effect of aggressively power-managing a SuperSpeed link but devices are known to report unfeasibly short device exit latencies in their descriptors, which under certain usage conditions can significantly degrade throughput as the link spends longer retraining than being in a useable state. The Intel heuristic approach calculates a reasonably large endpoint-dependent U1 timeout, and uses a minimum U2 timeout that is several multiples of typical U2 exit latencies. Add a module parameter that defaults to using this scheme. This should have the effect of squelching interop edge-cases where LPM noticeably degrades performance, and avoid the usual workaround where userspace manually disables it. Signed-off-by: Jonathan Bell --- drivers/usb/host/xhci.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 1b6e68f9119cfa..1ba3f4b27104d8 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -39,6 +39,10 @@ static unsigned long long quirks; module_param(quirks, ullong, S_IRUGO); MODULE_PARM_DESC(quirks, "Bit flags for quirks to be enabled as default"); +static int sandbag_lpm = 1; +module_param(sandbag_lpm, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(sandbag_lpm, "Use relaxed U1/U2 port LPM timeouts"); + static bool td_on_ring(struct xhci_td *td, struct xhci_ring *ring) { struct xhci_segment *seg = ring->first_seg; @@ -4807,7 +4811,7 @@ static u16 xhci_calculate_u1_timeout(struct xhci_hcd *xhci, } } - if (xhci->quirks & (XHCI_INTEL_HOST | XHCI_ZHAOXIN_HOST)) + if (sandbag_lpm || xhci->quirks & (XHCI_INTEL_HOST | XHCI_ZHAOXIN_HOST)) timeout_ns = xhci_calculate_intel_u1_timeout(udev, desc); else timeout_ns = udev->u1_params.sel; @@ -4871,7 +4875,7 @@ static u16 xhci_calculate_u2_timeout(struct xhci_hcd *xhci, } } - if (xhci->quirks & (XHCI_INTEL_HOST | XHCI_ZHAOXIN_HOST)) + if (sandbag_lpm || xhci->quirks & (XHCI_INTEL_HOST | XHCI_ZHAOXIN_HOST)) timeout_ns = xhci_calculate_intel_u2_timeout(udev, desc); else timeout_ns = udev->u2_params.sel;