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

Configure Feed

Select the types of activity you want to include in your feed.

usb: xhci: improve debug messages during suspend

Improve debug output for suspend failures, particularly when the controller
handshake does not complete. This will become important as upcoming patches
significantly rework the resume path, making more detailed suspend-side
messages valuable for debugging.

Add an explicit check of the Save/Restore Error (SRE) flag after a
successful Save State (CSS) operation. The xHCI specification
(note in section 4.23.2) states:

"After a Save or Restore State operation completes, the
Save/Restore Error (SRE) flag in USBSTS should be checked to
ensure the operation completed successfully."

Currently, the SRE error is only observed and warning is printed.
This patch does not introduce deeper error handling, as the correct
response is unclear and changes to suspend behavior may risk regressions
once the resume path is updated.

Additionally, simplify and clean up the suspend USBSTS CSS/SSS
handling code, improving readability and quirk handling for AMD
SNPS xHC controllers that occasionally do not clear the SSS bit.

Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://patch.msgid.link/20260402131342.2628648-12-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Niklas Neronin and committed by
Greg Kroah-Hartman
951564d2 b4dd01eb

+37 -28
+37 -28
drivers/usb/host/xhci.c
··· 957 957 */ 958 958 int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) 959 959 { 960 - int rc = 0; 960 + int err; 961 961 unsigned int delay = XHCI_MAX_HALT_USEC * 2; 962 962 struct usb_hcd *hcd = xhci_to_hcd(xhci); 963 963 u32 command; 964 - u32 res; 964 + u32 usbsts; 965 965 966 966 if (!hcd->state) 967 967 return 0; ··· 1007 1007 /* Some chips from Fresco Logic need an extraordinary delay */ 1008 1008 delay *= (xhci->quirks & XHCI_SLOW_SUSPEND) ? 10 : 1; 1009 1009 1010 - if (xhci_handshake(&xhci->op_regs->status, 1011 - STS_HALT, STS_HALT, delay)) { 1012 - xhci_warn(xhci, "WARN: xHC CMD_RUN timeout\n"); 1013 - spin_unlock_irq(&xhci->lock); 1014 - return -ETIMEDOUT; 1010 + err = xhci_handshake(&xhci->op_regs->status, STS_HALT, STS_HALT, delay); 1011 + if (err) { 1012 + xhci_warn(xhci, "Clearing Run/Stop bit failed %d\n", err); 1013 + goto handshake_error; 1015 1014 } 1016 1015 xhci_clear_command_ring(xhci); 1017 1016 ··· 1021 1022 command = readl(&xhci->op_regs->command); 1022 1023 command |= CMD_CSS; 1023 1024 writel(command, &xhci->op_regs->command); 1025 + 1026 + err = xhci_handshake(&xhci->op_regs->status, STS_SAVE, 0, 20 * USEC_PER_MSEC); 1027 + usbsts = readl(&xhci->op_regs->status); 1024 1028 xhci->broken_suspend = 0; 1025 - if (xhci_handshake(&xhci->op_regs->status, 1026 - STS_SAVE, 0, 20 * 1000)) { 1027 - /* 1028 - * AMD SNPS xHC 3.0 occasionally does not clear the 1029 - * SSS bit of USBSTS and when driver tries to poll 1030 - * to see if the xHC clears BIT(8) which never happens 1031 - * and driver assumes that controller is not responding 1032 - * and times out. To workaround this, its good to check 1033 - * if SRE and HCE bits are not set (as per xhci 1034 - * Section 5.4.2) and bypass the timeout. 1035 - */ 1036 - res = readl(&xhci->op_regs->status); 1037 - if ((xhci->quirks & XHCI_SNPS_BROKEN_SUSPEND) && 1038 - (((res & STS_SRE) == 0) && 1039 - ((res & STS_HCE) == 0))) { 1040 - xhci->broken_suspend = 1; 1041 - } else { 1042 - xhci_warn(xhci, "WARN: xHC save state timeout\n"); 1043 - spin_unlock_irq(&xhci->lock); 1044 - return -ETIMEDOUT; 1029 + if (err) { 1030 + /* 1031 + * AMD SNPS xHC 3.0 occasionally does not clear the 1032 + * SSS bit of USBSTS and when driver tries to poll 1033 + * to see if the xHC clears BIT(8) which never happens 1034 + * and driver assumes that controller is not responding 1035 + * and times out. To workaround this, its good to check 1036 + * if SRE and HCE bits are not set (as per xhci 1037 + * Section 5.4.2) and bypass the timeout. 1038 + */ 1039 + if (!(xhci->quirks & XHCI_SNPS_BROKEN_SUSPEND)) { 1040 + xhci_warn(xhci, "Controller Save State failed %d\n", err); 1041 + goto handshake_error; 1045 1042 } 1043 + 1044 + if (usbsts & (STS_SRE | STS_HCE)) { 1045 + xhci_warn(xhci, "Controller Save State failed, USBSTS 0x%08x\n", usbsts); 1046 + goto handshake_error; 1047 + } 1048 + 1049 + xhci_dbg(xhci, "SNPS broken suspend, save state unreliable\n"); 1050 + xhci->broken_suspend = 1; 1051 + } else if (usbsts & STS_SRE) { 1052 + xhci_warn(xhci, "Suspend Save Error (SRE), USBSTS 0x%08x\n", usbsts); 1046 1053 } 1047 1054 spin_unlock_irq(&xhci->lock); 1048 1055 ··· 1064 1059 __func__); 1065 1060 } 1066 1061 1067 - return rc; 1062 + return 0; 1063 + 1064 + handshake_error: 1065 + spin_unlock_irq(&xhci->lock); 1066 + return -ETIMEDOUT; 1068 1067 } 1069 1068 EXPORT_SYMBOL_GPL(xhci_suspend); 1070 1069