Skip to content

Commit 17f94b1

Browse files
Kuen-Han Tsaigregkh
authored andcommitted
usb: dwc3: Abort suspend on soft disconnect failure
[ Upstream commit 630a1dec3b0eba2a695b9063f1c205d585cbfec9 ] 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 <[email protected]> Acked-by: Thinh Nguyen <[email protected]> Signed-off-by: Kuen-Han Tsai <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 07acd39 commit 17f94b1

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
@@ -2153,6 +2153,7 @@ static int dwc3_core_init_for_resume(struct dwc3 *dwc)
21532153
static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
21542154
{
21552155
u32 reg;
2156+
int ret;
21562157

21572158
if (!pm_runtime_suspended(dwc->dev) && !PMSG_IS_AUTO(msg)) {
21582159
dwc->susphy_state = (dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)) &
@@ -2171,7 +2172,9 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
21712172
case DWC3_GCTL_PRTCAP_DEVICE:
21722173
if (pm_runtime_suspended(dwc->dev))
21732174
break;
2174-
dwc3_gadget_suspend(dwc);
2175+
ret = dwc3_gadget_suspend(dwc);
2176+
if (ret)
2177+
return ret;
21752178
synchronize_irq(dwc->irq_gadget);
21762179
dwc3_core_exit(dwc);
21772180
break;
@@ -2202,7 +2205,9 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
22022205
break;
22032206

22042207
if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) {
2205-
dwc3_gadget_suspend(dwc);
2208+
ret = dwc3_gadget_suspend(dwc);
2209+
if (ret)
2210+
return ret;
22062211
synchronize_irq(dwc->irq_gadget);
22072212
}
22082213

drivers/usb/dwc3/gadget.c

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

46434643
ret = dwc3_gadget_soft_disconnect(dwc);
4644-
if (ret)
4645-
goto err;
4646-
4647-
spin_lock_irqsave(&dwc->lock, flags);
4648-
if (dwc->gadget_driver)
4649-
dwc3_disconnect_gadget(dwc);
4650-
spin_unlock_irqrestore(&dwc->lock, flags);
4651-
4652-
return 0;
4653-
4654-
err:
46554644
/*
46564645
* Attempt to reset the controller's state. Likely no
46574646
* communication can be established until the host
46584647
* performs a port reset.
46594648
*/
4660-
if (dwc->softconnect)
4649+
if (ret && dwc->softconnect) {
46614650
dwc3_gadget_soft_connect(dwc);
4651+
return -EAGAIN;
4652+
}
46624653

4663-
return ret;
4654+
spin_lock_irqsave(&dwc->lock, flags);
4655+
if (dwc->gadget_driver)
4656+
dwc3_disconnect_gadget(dwc);
4657+
spin_unlock_irqrestore(&dwc->lock, flags);
4658+
4659+
return 0;
46644660
}
46654661

46664662
int dwc3_gadget_resume(struct dwc3 *dwc)

0 commit comments

Comments
 (0)