|
Oliver Neukum |
b5c53d |
From c8540870af4ce6ddeb27a7bb5498b75fb29b643c Mon Sep 17 00:00:00 2001
|
|
Oliver Neukum |
b5c53d |
From: Roger Quadros <rogerq@kernel.org>
|
|
Oliver Neukum |
b5c53d |
Date: Wed, 3 May 2023 14:00:48 +0300
|
|
Oliver Neukum |
b5c53d |
Subject: [PATCH] usb: dwc3: gadget: Improve dwc3_gadget_suspend() and
|
|
Oliver Neukum |
b5c53d |
dwc3_gadget_resume()
|
|
Oliver Neukum |
b5c53d |
Git-commit: c8540870af4ce6ddeb27a7bb5498b75fb29b643c
|
|
Oliver Neukum |
b5c53d |
References: git-fixes
|
|
Oliver Neukum |
b5c53d |
Patch-mainline: v6.4-rc3
|
|
Oliver Neukum |
b5c53d |
|
|
Oliver Neukum |
b5c53d |
Prevent -ETIMEDOUT error on .suspend().
|
|
Oliver Neukum |
b5c53d |
e.g. If gadget driver is loaded and we are connected to a USB host,
|
|
Oliver Neukum |
b5c53d |
all transfers must be stopped before stopping the controller else
|
|
Oliver Neukum |
b5c53d |
we will not get a clean stop i.e. dwc3_gadget_run_stop() will take
|
|
Oliver Neukum |
b5c53d |
several seconds to complete and will return -ETIMEDOUT.
|
|
Oliver Neukum |
b5c53d |
|
|
Oliver Neukum |
b5c53d |
Handle error cases properly in dwc3_gadget_suspend().
|
|
Oliver Neukum |
b5c53d |
Simplify dwc3_gadget_resume() by using the introduced helper function.
|
|
Oliver Neukum |
b5c53d |
|
|
Oliver Neukum |
b5c53d |
Fixes: 9f8a67b65a49 ("usb: dwc3: gadget: fix gadget suspend/resume")
|
|
Oliver Neukum |
b5c53d |
Cc: stable@vger.kernel.org
|
|
Oliver Neukum |
b5c53d |
Suggested-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
|
|
Oliver Neukum |
b5c53d |
Signed-off-by: Roger Quadros <rogerq@kernel.org>
|
|
Oliver Neukum |
b5c53d |
Acked-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
|
|
Oliver Neukum |
b5c53d |
Link: https://lore.kernel.org/r/20230503110048.30617-1-rogerq@kernel.org
|
|
Oliver Neukum |
b5c53d |
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
Oliver Neukum |
b5c53d |
Signed-off-by: Oliver Neukum <oneukum@suse.com>
|
|
Oliver Neukum |
b5c53d |
---
|
|
Oliver Neukum |
b5c53d |
drivers/usb/dwc3/gadget.c | 50 ++++++++++++++++++++++++++++++++--------------
|
|
Oliver Neukum |
b5c53d |
1 file changed, 35 insertions(+), 15 deletions(-)
|
|
Oliver Neukum |
b5c53d |
|
|
Oliver Neukum |
b5c53d |
--- a/drivers/usb/dwc3/gadget.c
|
|
Oliver Neukum |
b5c53d |
+++ b/drivers/usb/dwc3/gadget.c
|
|
Oliver Neukum |
b5c53d |
@@ -2352,6 +2352,21 @@ static int dwc3_gadget_soft_disconnect(s
|
|
Oliver Neukum |
b5c53d |
return dwc3_gadget_run_stop(dwc, false, false);
|
|
Oliver Neukum |
b5c53d |
}
|
|
Oliver Neukum |
b5c53d |
|
|
Oliver Neukum |
b5c53d |
+static int dwc3_gadget_soft_connect(struct dwc3 *dwc)
|
|
Oliver Neukum |
b5c53d |
+{
|
|
Oliver Neukum |
b5c53d |
+ /*
|
|
Oliver Neukum |
b5c53d |
+ * In the Synopsys DWC_usb31 1.90a programming guide section
|
|
Oliver Neukum |
b5c53d |
+ * 4.1.9, it specifies that for a reconnect after a
|
|
Oliver Neukum |
b5c53d |
+ * device-initiated disconnect requires a core soft reset
|
|
Oliver Neukum |
b5c53d |
+ * (DCTL.CSftRst) before enabling the run/stop bit.
|
|
Oliver Neukum |
b5c53d |
+ */
|
|
Oliver Neukum |
b5c53d |
+ dwc3_core_soft_reset(dwc);
|
|
Oliver Neukum |
b5c53d |
+
|
|
Oliver Neukum |
b5c53d |
+ dwc3_event_buffers_setup(dwc);
|
|
Oliver Neukum |
b5c53d |
+ __dwc3_gadget_start(dwc);
|
|
Oliver Neukum |
b5c53d |
+ return dwc3_gadget_run_stop(dwc, true, false);
|
|
Oliver Neukum |
b5c53d |
+}
|
|
Oliver Neukum |
b5c53d |
+
|
|
Oliver Neukum |
b5c53d |
static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
|
|
Oliver Neukum |
b5c53d |
{
|
|
Oliver Neukum |
b5c53d |
struct dwc3 *dwc = gadget_to_dwc(g);
|
|
Oliver Neukum |
b5c53d |
@@ -2388,21 +2403,11 @@ static int dwc3_gadget_pullup(struct usb
|
|
Oliver Neukum |
b5c53d |
return 0;
|
|
Oliver Neukum |
b5c53d |
}
|
|
Oliver Neukum |
b5c53d |
|
|
Oliver Neukum |
b5c53d |
- if (!is_on) {
|
|
Oliver Neukum |
b5c53d |
+ if (!is_on)
|
|
Oliver Neukum |
b5c53d |
ret = dwc3_gadget_soft_disconnect(dwc);
|
|
Oliver Neukum |
b5c53d |
- } else {
|
|
Oliver Neukum |
b5c53d |
- /*
|
|
Oliver Neukum |
b5c53d |
- * In the Synopsys DWC_usb31 1.90a programming guide section
|
|
Oliver Neukum |
b5c53d |
- * 4.1.9, it specifies that for a reconnect after a
|
|
Oliver Neukum |
b5c53d |
- * device-initiated disconnect requires a core soft reset
|
|
Oliver Neukum |
b5c53d |
- * (DCTL.CSftRst) before enabling the run/stop bit.
|
|
Oliver Neukum |
b5c53d |
- */
|
|
Oliver Neukum |
b5c53d |
- dwc3_core_soft_reset(dwc);
|
|
Oliver Neukum |
b5c53d |
+ else
|
|
Oliver Neukum |
b5c53d |
+ ret = dwc3_gadget_soft_connect(dwc);
|
|
Oliver Neukum |
b5c53d |
|
|
Oliver Neukum |
b5c53d |
- dwc3_event_buffers_setup(dwc);
|
|
Oliver Neukum |
b5c53d |
- __dwc3_gadget_start(dwc);
|
|
Oliver Neukum |
b5c53d |
- ret = dwc3_gadget_run_stop(dwc, true, false);
|
|
Oliver Neukum |
b5c53d |
- }
|
|
Oliver Neukum |
b5c53d |
|
|
Oliver Neukum |
b5c53d |
pm_runtime_put(dwc->dev);
|
|
Oliver Neukum |
b5c53d |
|
|
Oliver Neukum |
b5c53d |
@@ -4271,14 +4276,29 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
|
|
Oliver Neukum |
b5c53d |
|
|
Oliver Neukum |
b5c53d |
int dwc3_gadget_suspend(struct dwc3 *dwc)
|
|
Oliver Neukum |
b5c53d |
{
|
|
Oliver Neukum |
b5c53d |
+ int ret;
|
|
Oliver Neukum |
b5c53d |
+
|
|
Oliver Neukum |
b5c53d |
if (!dwc->gadget_driver)
|
|
Oliver Neukum |
b5c53d |
return 0;
|
|
Oliver Neukum |
b5c53d |
|
|
Oliver Neukum |
b5c53d |
- dwc3_gadget_run_stop(dwc, false, false);
|
|
Oliver Neukum |
b5c53d |
+ ret = dwc3_gadget_soft_disconnect(dwc);
|
|
Oliver Neukum |
b5c53d |
+ if (ret)
|
|
Oliver Neukum |
b5c53d |
+ goto err;
|
|
Oliver Neukum |
b5c53d |
+
|
|
Oliver Neukum |
b5c53d |
dwc3_disconnect_gadget(dwc);
|
|
Oliver Neukum |
b5c53d |
- __dwc3_gadget_stop(dwc);
|
|
Oliver Neukum |
b5c53d |
|
|
Oliver Neukum |
b5c53d |
return 0;
|
|
Oliver Neukum |
b5c53d |
+
|
|
Oliver Neukum |
b5c53d |
+err:
|
|
Oliver Neukum |
b5c53d |
+ /*
|
|
Oliver Neukum |
b5c53d |
+ * Attempt to reset the controller's state. Likely no
|
|
Oliver Neukum |
b5c53d |
+ * communication can be established until the host
|
|
Oliver Neukum |
b5c53d |
+ * performs a port reset.
|
|
Oliver Neukum |
b5c53d |
+ */
|
|
Oliver Neukum |
b5c53d |
+ if (dwc->softconnect)
|
|
Oliver Neukum |
b5c53d |
+ dwc3_gadget_soft_connect(dwc);
|
|
Oliver Neukum |
b5c53d |
+
|
|
Oliver Neukum |
b5c53d |
+ return ret;
|
|
Oliver Neukum |
b5c53d |
}
|
|
Oliver Neukum |
b5c53d |
|
|
Oliver Neukum |
b5c53d |
int dwc3_gadget_resume(struct dwc3 *dwc)
|