usb: dwc3: Abort suspend on soft disconnect failure
commit 630a1dec3b0eba2a695b9063f1c205d585cbfec9 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: 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:
committed by
Greg Kroah-Hartman
parent
27199ab790
commit
3b1407caac
@@ -2364,6 +2364,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
|
|||||||
{
|
{
|
||||||
u32 reg;
|
u32 reg;
|
||||||
int i;
|
int i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!pm_runtime_suspended(dwc->dev) && !PMSG_IS_AUTO(msg)) {
|
if (!pm_runtime_suspended(dwc->dev) && !PMSG_IS_AUTO(msg)) {
|
||||||
dwc->susphy_state = (dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)) &
|
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)
|
|||||||
case DWC3_GCTL_PRTCAP_DEVICE:
|
case DWC3_GCTL_PRTCAP_DEVICE:
|
||||||
if (pm_runtime_suspended(dwc->dev))
|
if (pm_runtime_suspended(dwc->dev))
|
||||||
break;
|
break;
|
||||||
dwc3_gadget_suspend(dwc);
|
ret = dwc3_gadget_suspend(dwc);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
synchronize_irq(dwc->irq_gadget);
|
synchronize_irq(dwc->irq_gadget);
|
||||||
dwc3_core_exit(dwc);
|
dwc3_core_exit(dwc);
|
||||||
break;
|
break;
|
||||||
@@ -2417,7 +2420,9 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) {
|
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);
|
synchronize_irq(dwc->irq_gadget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4788,8 +4788,15 @@ int dwc3_gadget_suspend(struct dwc3 *dwc)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = dwc3_gadget_soft_disconnect(dwc);
|
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);
|
spin_lock_irqsave(&dwc->lock, flags);
|
||||||
if (dwc->gadget_driver)
|
if (dwc->gadget_driver)
|
||||||
@@ -4797,17 +4804,6 @@ int dwc3_gadget_suspend(struct dwc3 *dwc)
|
|||||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||||
|
|
||||||
return 0;
|
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)
|
int dwc3_gadget_resume(struct dwc3 *dwc)
|
||||||
|
|||||||
Reference in New Issue
Block a user