mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
usb: dwc3: Abort suspend on soft disconnect failure
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: 9f8a67b65a
("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>
This commit is contained in:
parent
7e2c421ef8
commit
630a1dec3b
2 changed files with 16 additions and 15 deletions
|
@ -2422,6 +2422,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
|
|||
{
|
||||
u32 reg;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
if (!pm_runtime_suspended(dwc->dev) && !PMSG_IS_AUTO(msg)) {
|
||||
dwc->susphy_state = (dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)) &
|
||||
|
@ -2440,7 +2441,9 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
|
|||
case DWC3_GCTL_PRTCAP_DEVICE:
|
||||
if (pm_runtime_suspended(dwc->dev))
|
||||
break;
|
||||
dwc3_gadget_suspend(dwc);
|
||||
ret = dwc3_gadget_suspend(dwc);
|
||||
if (ret)
|
||||
return ret;
|
||||
synchronize_irq(dwc->irq_gadget);
|
||||
dwc3_core_exit(dwc);
|
||||
break;
|
||||
|
@ -2475,7 +2478,9 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
|
|||
break;
|
||||
|
||||
if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) {
|
||||
dwc3_gadget_suspend(dwc);
|
||||
ret = dwc3_gadget_suspend(dwc);
|
||||
if (ret)
|
||||
return ret;
|
||||
synchronize_irq(dwc->irq_gadget);
|
||||
}
|
||||
|
||||
|
|
|
@ -4821,8 +4821,15 @@ int dwc3_gadget_suspend(struct dwc3 *dwc)
|
|||
int ret;
|
||||
|
||||
ret = dwc3_gadget_soft_disconnect(dwc);
|
||||
if (ret)
|
||||
goto err;
|
||||
/*
|
||||
* Attempt to reset the controller's state. Likely no
|
||||
* communication can be established until the host
|
||||
* performs a port reset.
|
||||
*/
|
||||
if (ret && dwc->softconnect) {
|
||||
dwc3_gadget_soft_connect(dwc);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
if (dwc->gadget_driver)
|
||||
|
@ -4830,17 +4837,6 @@ int dwc3_gadget_suspend(struct dwc3 *dwc)
|
|||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
/*
|
||||
* Attempt to reset the controller's state. Likely no
|
||||
* communication can be established until the host
|
||||
* performs a port reset.
|
||||
*/
|
||||
if (dwc->softconnect)
|
||||
dwc3_gadget_soft_connect(dwc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dwc3_gadget_resume(struct dwc3 *dwc)
|
||||
|
|
Loading…
Add table
Reference in a new issue