[PATCH 0/2] usb: dwc3: Keep the host bus across suspend-to-idle

From: Arun Iyengar via B4 Relay

Date: Tue Nov 10 2026 - 02:17:15 EST


In host mode, dwc3_suspend_common() tears the core down for every
system suspend unless the controller is a wakeup source
(dwc3_core_exit(): PHYs off, core reset). That has two consequences
for xhci-plat on top of it:

1. xhci_resume() is not told that the controller was reset. It writes
the saved operational registers back and asks for a state restore
(USBCMD.CRS), which fails on a freshly reset core, and only then
falls back to a reinit:

xhci-hcd xhci-hcd.1.auto: xHC error in resume, USBSTS 0x401, Reinit

xhci-plat already has xhci_plat_priv.power_lost for this (cdns3 sets
it). Patch 1 sets it from dwc3 whenever the core was re-initialised
and clears it when the core was kept for wakeup.

2. Every device behind the root ports was put into U3 by the bus
suspend and expects to keep its power session; resetting the core
ends all of them. On resume the USB core has to reset-resume every
device, which only works for devices that come back within the 2 s
usb_port_resume() waits. A SanDisk Extreme SSD and a card reader
behind a hub do not (2.4-3 s, measured): they are disconnected and
enumerated again after each resume, which kills a mounted filesystem.
Patch 2 keeps the core, its PHYs and the suspended bus across
suspend-to-idle, as the wakeup path already does and as PCI xHCI
controllers do, and marks the device as being on the awake path so a
power domain with GENPD_FLAG_ACTIVE_WAKEUP stays on. Suspend-to-RAM,
hibernation and needs_full_reinit controllers are unchanged.

Patch 2 depends on patch 1 (it clears power_lost on the kept-core path).
Both are changes to the dwc3 core; no glue driver is involved (the
RK3588 nodes bind to the "snps,dwc3" core driver directly).

Tested on an Orange Pi 5 (RK3588S), suspend-to-idle through rtcwake:
- Patch 1: 55 cycles on a kernel with patch 1 (and an ohci-platform
change sent separately); the "xHC error in resume, USBSTS 0x401"
message is gone, the controller re-initialises without the failed
restore, no other change in behaviour.
- Patch 2: 47 cycles on a kernel with both patches: every USB device
kept its device number, all 7 SuperSpeed links were back after each
resume, no "root hub lost power or was reset" and no re-enumeration
in dmesg, USB drives readable afterwards. Without patch 2 the SSD and
the card reader were disconnected and re-enumerated after every
resume and their mounted filesystems went offline.
- Not tested: suspend-to-RAM and hibernation (unchanged by this series;
the test platform has no working deep suspend), other dwc3 platforms.

This series was developed with Claude (Anthropic) as a coding assistant:
it wrote the code and the commit messages, and I reviewed and tested
every change as described above.

Signed-off-by: Arun Iyengar <aiyengar1990@xxxxxxxxx>
---
Arun Iyengar (2):
usb: dwc3: Tell xhci-plat when the core lost its state on resume
usb: dwc3: Keep the host bus suspended, not torn down, across suspend-to-idle

drivers/usb/dwc3/core.c | 43 +++++++++++++++++++++++++++++++++++++++----
drivers/usb/dwc3/core.h | 5 +++++
drivers/usb/dwc3/host.c | 29 ++++++++++++++++++++++++++---
3 files changed, 70 insertions(+), 7 deletions(-)
---
base-commit: 6628e7d4c6b25c8d18f1345e3a20d21829aae7e4
change-id: 20261110-dwc3-s2idle-6e332174c57b

Best regards,
--
Arun Iyengar <aiyengar1990@xxxxxxxxx>