Skip to content

Commit 3b1407c

Browse files
Kuen-Han Tsaigregkh
authored andcommitted
usb: dwc3: Abort suspend on soft disconnect failure
commit 630a1de upstream. When dwc3_gadget_soft_disconnect() fails, dwc3_suspend_common() keeps going with the suspend, resulting in a period where the power domain is off, but the gadget driver remains connected. Within this time frame, invoking vbus_event_work() will cause an error as it attempts to access DWC3 registers for endpoint disabling after the power domain has been completely shut down. Abort the suspend sequence when dwc3_gadget_suspend() cannot halt the controller and proceeds with a soft connect. Fixes: 9f8a67b ("usb: dwc3: gadget: fix gadget suspend/resume") Cc: stable <stable@kernel.org> Acked-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com> Signed-off-by: Kuen-Han Tsai <khtsai@google.com> Link: https://lore.kernel.org/r/20250528100315.2162699-1-khtsai@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 27199ab commit 3b1407c

File tree

2 files changed

+16
-15
lines changed

2 files changed

+16
-15
lines changed

drivers/usb/dwc3/core.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2364,6 +2364,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
23642364
{
23652365
u32 reg;
23662366
int i;
2367+
int ret;
23672368

23682369
if (!pm_runtime_suspended(dwc->dev) && !PMSG_IS_AUTO(msg)) {
23692370
dwc->susphy_state = (dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)) &
@@ -2382,7 +2383,9 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
23822383
case DWC3_GCTL_PRTCAP_DEVICE:
23832384
if (pm_runtime_suspended(dwc->dev))
23842385
break;
2385-
dwc3_gadget_suspend(dwc);
2386+
ret = dwc3_gadget_suspend(dwc);
2387+
if (ret)
2388+
return ret;
23862389
synchronize_irq(dwc->irq_gadget);
23872390
dwc3_core_exit(dwc);
23882391
break;
@@ -2417,7 +2420,9 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
24172420
break;
24182421

24192422
if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) {
2420-
dwc3_gadget_suspend(dwc);
2423+
ret = dwc3_gadget_suspend(dwc);
2424+
if (ret)
2425+
return ret;
24212426
synchronize_irq(dwc->irq_gadget);
24222427
}
24232428

drivers/usb/dwc3/gadget.c

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4788,26 +4788,22 @@ int dwc3_gadget_suspend(struct dwc3 *dwc)
47884788
int ret;
47894789

47904790
ret = dwc3_gadget_soft_disconnect(dwc);
4791-
if (ret)
4792-
goto err;
4793-
4794-
spin_lock_irqsave(&dwc->lock, flags);
4795-
if (dwc->gadget_driver)
4796-
dwc3_disconnect_gadget(dwc);
4797-
spin_unlock_irqrestore(&dwc->lock, flags);
4798-
4799-
return 0;
4800-
4801-
err:
48024791
/*
48034792
* Attempt to reset the controller's state. Likely no
48044793
* communication can be established until the host
48054794
* performs a port reset.
48064795
*/
4807-
if (dwc->softconnect)
4796+
if (ret && dwc->softconnect) {
48084797
dwc3_gadget_soft_connect(dwc);
4798+
return -EAGAIN;
4799+
}
48094800

4810-
return ret;
4801+
spin_lock_irqsave(&dwc->lock, flags);
4802+
if (dwc->gadget_driver)
4803+
dwc3_disconnect_gadget(dwc);
4804+
spin_unlock_irqrestore(&dwc->lock, flags);
4805+
4806+
return 0;
48114807
}
48124808

48134809
int dwc3_gadget_resume(struct dwc3 *dwc)

0 commit comments

Comments
 (0)