Skip to content

Commit c854087

Browse files
rogerqgregkh
authored andcommitted
usb: dwc3: gadget: Improve dwc3_gadget_suspend() and dwc3_gadget_resume()
Prevent -ETIMEDOUT error on .suspend(). e.g. 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. Handle error cases properly in dwc3_gadget_suspend(). Simplify dwc3_gadget_resume() by using the introduced helper function. Fixes: 9f8a67b ("usb: dwc3: gadget: fix gadget suspend/resume") Cc: [email protected] Suggested-by: Thinh Nguyen <[email protected]> Signed-off-by: Roger Quadros <[email protected]> Acked-by: Thinh Nguyen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 94d25e9 commit c854087

File tree

1 file changed

+34
-33
lines changed

1 file changed

+34
-33
lines changed

drivers/usb/dwc3/gadget.c

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2699,6 +2699,21 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc)
26992699
return ret;
27002700
}
27012701

2702+
static int dwc3_gadget_soft_connect(struct dwc3 *dwc)
2703+
{
2704+
/*
2705+
* In the Synopsys DWC_usb31 1.90a programming guide section
2706+
* 4.1.9, it specifies that for a reconnect after a
2707+
* device-initiated disconnect requires a core soft reset
2708+
* (DCTL.CSftRst) before enabling the run/stop bit.
2709+
*/
2710+
dwc3_core_soft_reset(dwc);
2711+
2712+
dwc3_event_buffers_setup(dwc);
2713+
__dwc3_gadget_start(dwc);
2714+
return dwc3_gadget_run_stop(dwc, true);
2715+
}
2716+
27022717
static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
27032718
{
27042719
struct dwc3 *dwc = gadget_to_dwc(g);
@@ -2737,21 +2752,10 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
27372752

27382753
synchronize_irq(dwc->irq_gadget);
27392754

2740-
if (!is_on) {
2755+
if (!is_on)
27412756
ret = dwc3_gadget_soft_disconnect(dwc);
2742-
} else {
2743-
/*
2744-
* In the Synopsys DWC_usb31 1.90a programming guide section
2745-
* 4.1.9, it specifies that for a reconnect after a
2746-
* device-initiated disconnect requires a core soft reset
2747-
* (DCTL.CSftRst) before enabling the run/stop bit.
2748-
*/
2749-
dwc3_core_soft_reset(dwc);
2750-
2751-
dwc3_event_buffers_setup(dwc);
2752-
__dwc3_gadget_start(dwc);
2753-
ret = dwc3_gadget_run_stop(dwc, true);
2754-
}
2757+
else
2758+
ret = dwc3_gadget_soft_connect(dwc);
27552759

27562760
pm_runtime_put(dwc->dev);
27572761

@@ -4655,42 +4659,39 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
46554659
int dwc3_gadget_suspend(struct dwc3 *dwc)
46564660
{
46574661
unsigned long flags;
4662+
int ret;
46584663

46594664
if (!dwc->gadget_driver)
46604665
return 0;
46614666

4662-
dwc3_gadget_run_stop(dwc, false);
4667+
ret = dwc3_gadget_soft_disconnect(dwc);
4668+
if (ret)
4669+
goto err;
46634670

46644671
spin_lock_irqsave(&dwc->lock, flags);
46654672
dwc3_disconnect_gadget(dwc);
4666-
__dwc3_gadget_stop(dwc);
46674673
spin_unlock_irqrestore(&dwc->lock, flags);
46684674

46694675
return 0;
4676+
4677+
err:
4678+
/*
4679+
* Attempt to reset the controller's state. Likely no
4680+
* communication can be established until the host
4681+
* performs a port reset.
4682+
*/
4683+
if (dwc->softconnect)
4684+
dwc3_gadget_soft_connect(dwc);
4685+
4686+
return ret;
46704687
}
46714688

46724689
int dwc3_gadget_resume(struct dwc3 *dwc)
46734690
{
4674-
int ret;
4675-
46764691
if (!dwc->gadget_driver || !dwc->softconnect)
46774692
return 0;
46784693

4679-
ret = __dwc3_gadget_start(dwc);
4680-
if (ret < 0)
4681-
goto err0;
4682-
4683-
ret = dwc3_gadget_run_stop(dwc, true);
4684-
if (ret < 0)
4685-
goto err1;
4686-
4687-
return 0;
4688-
4689-
err1:
4690-
__dwc3_gadget_stop(dwc);
4691-
4692-
err0:
4693-
return ret;
4694+
return dwc3_gadget_soft_connect(dwc);
46944695
}
46954696

46964697
void dwc3_gadget_process_pending_events(struct dwc3 *dwc)

0 commit comments

Comments
 (0)