usb: dwc3: tell xHCI that it lost its state when the core is powered off
Subsystems (2)
PATCH v2 1/1 usb: dwc3: tell xHCI that it lost its state when the core is powered off
dwc3_suspend_common() powers the core off for system suspend (dwc3_core_exit()) in OTG mode (DWC3_GCTL_PRTCAP_OTG), and in host mode when the controller may not wake the system or needs a full re-init. The xHCI registers and the state saved with the Controller Save State command are gone then, but nothing tells xhci-plat: xhci_resume() takes the "state intact" path, writes the saved registers back and asks the controller to restore its state (CRS).
xhci-plat has a flag for exactly this, power_lost (commit 668cc6bc1178 ("usb: host: xhci-plat: allow upper layers to signal power loss"), used by cdns3), but dwc3 never sets it.
On a Lenovo Y700 Gen 5 (TB323FU, SM8850; DWC3 + eUSB2 PHY) with a USB 2.0 hub, a USB 3 flash drive and a Billboard device attached, and USB wakeup disabled, s2idle then broke the host controller on resume: either the controller wrote to an address that was not mapped
arm-smmu 15000000.iommu: Unhandled context fault: fsr=0x402,
iova=0xd85e7c300, fsynr=0x3d0011, cbfrsynra=0x40, cb=13
xhci-hcd xhci-hcd.2.auto: WARNING: Host System Error usb 1-1: hub failed to enable device, error -108
or its command ring would not stop
xhci-hcd xhci-hcd.2.auto: Abort failed to stop command ring: -110 xhci-hcd xhci-hcd.2.auto: xHCI host controller not responding, assume dead xhci-hcd xhci-hcd.2.auto: HC died; cleaning up
usb 1-1: PM: **** DPM device timeout ****
Kernel panic - not syncing: usb 1-1: unrecoverable failure
With wakeup enabled (the core stays powered) the same setup survived every cycle.
Record that the core was powered off and pass this to xhci-plat as power_lost from a resume_quirk, so that xhci_resume() resets the controller and the devices are re-enumerated. Unlike a static XHCI_RESET_ON_RESUME this only applies to the resumes that follow a power-off; resumes with the core kept powered (host mode with wakeup enabled) and runtime resume keep the restore path. Clear the flag once xhci-plat has read it, so that a later system suspend that fails before the dwc3 core is suspended does not reset the controller.
---
v2:
- Also set the flag when the core is powered off in OTG mode with the host role active (Sashiko [1])
- Clear the flag once xhci-plat has read it (Sashiko [1]), instead of in the host branch that keeps the core powered
- Drop the comment above the resume quirk
- Add a Fixes tag for the OTG branch
- Rebased on next-20261111
Testing, 30 s RTC s2idle with wakeup disabled on the setup above:
without this change 1/1 cycles lost the controller; with this version 3/3 cycles reset the controller and re-enumerated all devices. OTG mode (DWC3_GCTL_PRTCAP_OTG) is not tested; this board switches roles through usb-role-switch and never uses it.
host.c now includes xhci.h for hcd_to_xhci_priv().
v1: https://lore.kernel.org/all/[email protected]/
RESEND: https://lore.kernel.org/all/[email protected]/
[1] https://lore.kernel.org/all/[email protected]/
drivers/usb/dwc3/core.c | 3 +++ drivers/usb/dwc3/core.h | 3 +++ drivers/usb/dwc3/host.c | 15 ++++++++++++--- 3 files changed, 18 insertions(+), 3 deletions(-)
drivers/usb/dwc3/core.c +3 -0
@@ -2572,6 +2572,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)if (!PMSG_IS_AUTO (msg) && (!device_may_wakeup (dwc->dev) || dwc->needs_full_reinit)) {dwc3_core_exit (dwc); + dwc->xhci_power_lost =1 ;break ; }
@@ -2608,6 +2609,8 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)dwc3_otg_exit (dwc);dwc3_core_exit (dwc); +if (dwc->current_otg_role ==DWC3_OTG_ROLE_HOST ) + dwc->xhci_power_lost =1 ;break ;default :/* do nothing */
drivers/usb/dwc3/core.h +3 -0
@@ -1185,6 +1185,8 @@ struct dwc3_glue_ops {* @suspended: set to track suspend event due to U3/L2. * @susphy_state: state of DWC3_GUSB2PHYCFG_SUSPHY + DWC3_GUSB3PIPECTL_SUSPHY * before PM suspend. +* @xhci_power_lost: the core was powered off for system suspend; xHCI +* must not try to restore its state on resume * @imod_interval: set the interrupt moderation interval in 250ns * increments or 0 to disable. * @max_cfg_eps: current max number of IN eps used across all USB configs.
@@ -1440,6 +1442,7 @@ struct dwc3 { unsigned wakeup_configured:1; unsigned suspended:1; unsigned susphy_state:1; + unsigned xhci_power_lost:1;u16 imod_interval;
drivers/usb/dwc3/host.c +12 -3
@@ -14,9 +14,7 @@#include <linux/usb/hcd.h> #include <linux/bitfield.h> -#include "../host/xhci-port.h" -#include "../host/xhci-ext-caps.h" -#include "../host/xhci-caps.h" +#include "../host/xhci.h" #include "../host/xhci-plat.h" #include "core.h"
@@ -78,7 +76,18 @@ static void dwc3_xhci_plat_start(struct usb_hcd *hcd)dwc3_enable_susphy (dwc, true); } +static int dwc3_xhci_resume_quirk (struct usb_hcd *hcd) +{ +struct dwc3 *dwc =dev_get_drvdata (hcd->self.controller->parent); + +hcd_to_xhci_priv (hcd)->power_lost = dwc->xhci_power_lost; + dwc->xhci_power_lost =0 ; + +return 0 ; +} +static const struct xhci_plat_priv dwc3_xhci_plat_quirk = { + .resume_quirk = dwc3_xhci_resume_quirk, .plat_start = dwc3_xhci_plat_start, };
base-commit: aaa2f954c21b205a0bcd0961e5b2be4e82e58455
Signature · 1 line
2.53.0
[email protected]
AI reviewSashiko has reviewed this patch and found no issues.
Quoted 18 lines
dwc3_suspend_common()powers the core off for system suspend (dwc3_core_exit()) in OTG mode (DWC3_GCTL_PRTCAP_OTG), and in host mode when the controller may not wake the system or needs a full re-init. The xHCI registers and the state saved with the Controller Save State command are gone then, but nothing tells xhci-plat:xhci_resume()takes the "state intact" path, writes the saved registers back and asks the controller to restore its state (CRS).xhci-plat has a flag for exactly this,
power_lost(commit668cc6bc1178("usb: host: xhci-plat: allow upper layers to signal power loss"), used by cdns3), but dwc3 never sets it.On a Lenovo Y700 Gen 5 (TB323FU, SM8850; DWC3 + eUSB2 PHY) with a USB 2.0 hub, a USB 3 flash drive and a Billboard device attached, and USB wakeup disabled, s2idle then broke the host controller on resume: either [ ... ]
the dwc3 core is suspended does not reset the controller.
Quoted 3 lines
Fixes c4a5153e87fd ("usb: dwc3: core: Power-off core/PHYs on system_suspend in host mode")Fixes f09cc79b4b33 ("usb: dwc3: add dual role support using OTG block")Signed-off-by Joonhoe Kim <[email protected]>
Sashiko has reviewed this patch and found no issues.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1