It was noticed that on plugging a low-power USB source on Steam Deck USB-C port (handled by dwc3), if such port is on device role, the HW somehow keep asseting the PCIe PME line and triggering a wakeup event on S3/deep suspend (that manifests as a PME wakeup interrupt, failing the suspend path). That doesn't happen when the USB port is on host mode or if the USB device connected is not a low-power type (for example, a connected keyboard doesn't reproduce that). Even by masking all maskable ACPI GPEs, the problem still reproduces; also by having the PCIe PME mechanism using non-MSI interrupts, the symptom is observed as the HW succeeding to S3/suspend but waking up right after. By changing the PRTCAP mode to DWC3_GCTL_PRTCAP_HOST in the controller (as one of the latest steps on gadget common suspend), we managed to circumvent the issue. The mode restore is already done in the common resume function. Notice that this patch does not change the in-driver port state on suspend, or else the resume path "thinks" the port was in host mode prior to suspend and resume it on a wrong fashion. Cc: Andrey Smirnov <andrew.smirnov@xxxxxxxxx> Cc: Vivek Dasmohapatra <vivek@xxxxxxxxxxxxx> Signed-off-by: Guilherme G. Piccoli <gpiccoli@xxxxxxxxxx> --- Hi folks, first of all thanks in advance for reviews/feedback on this one. This patch is the result of a debug approach with no datasheet access. With that said, I'm not 100% sure writing to this register is free of undesired side-effects; one thing I'm considering is the following scenario: imagine a device A with the USB port on device/peripheral mode, and a device B connected to it, acting as host. What if we want device B be able to wakeup device A? Would this patch prevent that for all cases, always? I appreciate ideas in case this is not the best approach to fix the problem. We could also gate this approach to the HW board as a first step, for example. Thanks, Guilherme drivers/usb/dwc3/core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 0328c86ef806..5801d3ebbbcb 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -104,7 +104,7 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc) return 0; } -void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode) +static void __dwc3_set_prtcap(struct dwc3 *dwc, u32 mode) { u32 reg; @@ -112,7 +112,11 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode) reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); reg |= DWC3_GCTL_PRTCAPDIR(mode); dwc3_writel(dwc->regs, DWC3_GCTL, reg); +} +void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode) +{ + __dwc3_set_prtcap(dwc, mode); dwc->current_dr_role = mode; } @@ -2128,6 +2132,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) break; dwc3_gadget_suspend(dwc); synchronize_irq(dwc->irq_gadget); + __dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); dwc3_core_exit(dwc); break; case DWC3_GCTL_PRTCAP_HOST: -- 2.42.0