Skip to content

Commit 1acfc07

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 efbd9f1 commit 1acfc07

2 files changed

Lines changed: 16 additions & 15 deletions

File tree

drivers/usb/dwc3/core.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2388,6 +2388,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
23882388
{
23892389
u32 reg;
23902390
int i;
2391+
int ret;
23912392

23922393
if (!pm_runtime_suspended(dwc->dev) && !PMSG_IS_AUTO(msg)) {
23932394
dwc->susphy_state = (dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)) &
@@ -2406,7 +2407,9 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
24062407
case DWC3_GCTL_PRTCAP_DEVICE:
24072408
if (pm_runtime_suspended(dwc->dev))
24082409
break;
2409-
dwc3_gadget_suspend(dwc);
2410+
ret = dwc3_gadget_suspend(dwc);
2411+
if (ret)
2412+
return ret;
24102413
synchronize_irq(dwc->irq_gadget);
24112414
dwc3_core_exit(dwc);
24122415
break;
@@ -2441,7 +2444,9 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
24412444
break;
24422445

24432446
if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) {
2444-
dwc3_gadget_suspend(dwc);
2447+
ret = dwc3_gadget_suspend(dwc);
2448+
if (ret)
2449+
return ret;
24452450
synchronize_irq(dwc->irq_gadget);
24462451
}
24472452

drivers/usb/dwc3/gadget.c

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

48234823
ret = dwc3_gadget_soft_disconnect(dwc);
4824-
if (ret)
4825-
goto err;
4826-
4827-
spin_lock_irqsave(&dwc->lock, flags);
4828-
if (dwc->gadget_driver)
4829-
dwc3_disconnect_gadget(dwc);
4830-
spin_unlock_irqrestore(&dwc->lock, flags);
4831-
4832-
return 0;
4833-
4834-
err:
48354824
/*
48364825
* Attempt to reset the controller's state. Likely no
48374826
* communication can be established until the host
48384827
* performs a port reset.
48394828
*/
4840-
if (dwc->softconnect)
4829+
if (ret && dwc->softconnect) {
48414830
dwc3_gadget_soft_connect(dwc);
4831+
return -EAGAIN;
4832+
}
48424833

4843-
return ret;
4834+
spin_lock_irqsave(&dwc->lock, flags);
4835+
if (dwc->gadget_driver)
4836+
dwc3_disconnect_gadget(dwc);
4837+
spin_unlock_irqrestore(&dwc->lock, flags);
4838+
4839+
return 0;
48444840
}
48454841

48464842
int dwc3_gadget_resume(struct dwc3 *dwc)

0 commit comments

Comments
 (0)