usb: dwc3: gadget: Fix controller timeout at dwc3_gadget_suspend()
Subsystems (2)
PATCH 1/1 usb: dwc3: gadget: Fix controller timeout at dwc3_gadget_suspend()
If gadget driver is loaded and we are connected to a USB host, all transfers must be stopped before stopping the controller else we will not get a clean stop i.e. dwc3_gadget_run_stop() will take several seconds to complete and will return -ETIMEDOUT. Fix this.
No need to stop the controller at dwc3_gadget_suspend() if dwc->softconnect is 0 as controller is already stopped.
Handle error cases properly in dwc3_gadget_suspend().
--- drivers/usb/dwc3/gadget.c | 69 ++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 34 deletions(-)
drivers/usb/dwc3/gadget.c +35 -34
@@ -2668,6 +2668,21 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc)return dwc3_gadget_run_stop (dwc, false, false); } +static int dwc3_gadget_soft_connect (struct dwc3 *dwc) +{ +/* +* In the Synopsys DWC_usb31 1.90a programming guide section +* 4.1.9, it specifies that for a reconnect after a +* device-initiated disconnect requires a core soft reset +* (DCTL.CSftRst) before enabling the run/stop bit. +*/ +dwc3_core_soft_reset (dwc); + +dwc3_event_buffers_setup (dwc); +__dwc3_gadget_start (dwc); +return dwc3_gadget_run_stop (dwc, true, false); +} +static int dwc3_gadget_pullup (struct usb_gadget *g,int is_on) {struct dwc3 *dwc =gadget_to_dwc (g);
@@ -2706,21 +2721,10 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)synchronize_irq (dwc->irq_gadget); -if (!is_on) { +if (!is_on) ret =dwc3_gadget_soft_disconnect (dwc); - }else { -/* -* In the Synopsys DWC_usb31 1.90a programming guide section -* 4.1.9, it specifies that for a reconnect after a -* device-initiated disconnect requires a core soft reset -* (DCTL.CSftRst) before enabling the run/stop bit. -*/ -dwc3_core_soft_reset (dwc); - -dwc3_event_buffers_setup (dwc); -__dwc3_gadget_start (dwc); - ret =dwc3_gadget_run_stop (dwc, true, false); - } +else + ret =dwc3_gadget_soft_connect (dwc);pm_runtime_put (dwc->dev);
@@ -4674,42 +4678,39 @@ void dwc3_gadget_exit(struct dwc3 *dwc)int dwc3_gadget_suspend (struct dwc3 *dwc) {unsigned long flags; +int ret; -if (!dwc->gadget_driver) +if (!dwc->gadget_driver || !dwc->softconnect)return 0 ; -dwc3_gadget_run_stop (dwc, false, false); + ret =dwc3_gadget_soft_disconnect (dwc); +if (ret) + goto err;spin_lock_irqsave (&dwc->lock, flags);dwc3_disconnect_gadget (dwc); -__dwc3_gadget_stop (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) { -int ret; -if (!dwc->gadget_driver || !dwc->softconnect)return 0 ; - ret =__dwc3_gadget_start (dwc); -if (ret <0 ) - goto err0; - - ret =dwc3_gadget_run_stop (dwc, true, false); -if (ret <0 ) - goto err1; - -return 0 ; - -err1: -__dwc3_gadget_stop (dwc); - -err0: -return ret; +return dwc3_gadget_soft_connect (dwc); }void dwc3_gadget_process_pending_events (struct dwc3 *dwc)
Signature · 1 line
2.34.1
Thinh Nguyen
maintainerQuoted 9 lines · Roger Quadros
If gadget driver is loaded and we are connected to a USB host, all transfers must be stopped before stopping the controller else we will not get a clean stop i.e.
dwc3_gadget_run_stop()will take several seconds to complete and will return-ETIMEDOUT. Fix this.No need to stop the controller at
dwc3_gadget_suspend()ifdwc->softconnectis 0 as controller is already stopped.Handle error cases properly in
dwc3_gadget_suspend().
We also fix the dwc3_gadget_resume() in this change. Either create a separate change or note it in the $subject and commit message.
Quoted 3 lines
Suggested-by Thinh Nguyen <[email protected]>Signed-off-by Roger Quadros <[email protected]>
Perhaps this needs a fixes tag? (Even though it can't be backported cleanly without some modifications)
Also, please rebase your change to Greg's usb-next.
Thanks!
Thinh