aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc3/gadget.c
diff options
context:
space:
mode:
authorThinh Nguyen <Thinh.Nguyen@synopsys.com>2022-04-21 19:22:50 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2022-05-05 22:03:24 +0200
commitc96683798e272366866a5c0ce3073c0b5a256db7 (patch)
tree53ab1a3e6398753c62b577e6c734c6a12d8ff361 /drivers/usb/dwc3/gadget.c
parentusb: dwc3: gadget: Don't modify GEVNTCOUNT in pullup() (diff)
downloadlinux-dev-c96683798e272366866a5c0ce3073c0b5a256db7.tar.xz
linux-dev-c96683798e272366866a5c0ce3073c0b5a256db7.zip
usb: dwc3: ep0: Don't prepare beyond Setup stage
Since we can't guarantee that the host won't send new Setup packet before going through the device-initiated disconnect, don't prepare beyond the Setup stage and keep the device in EP0_SETUP_PHASE. This ensures that the device-initated disconnect sequence can go through gracefully. Note that the controller won't service the End Transfer command if it can't DMA out the Setup packet. Signed-off-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com> Link: https://lore.kernel.org/r/6bacec56ecabb2c6e49a09cedfcac281fdc97de0.1650593829.git.Thinh.Nguyen@synopsys.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/dwc3/gadget.c')
-rw-r--r--drivers/usb/dwc3/gadget.c29
1 files changed, 17 insertions, 12 deletions
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 3c0a6c83ea43..5e3311e3cc16 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2515,6 +2515,23 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc)
dwc->connected = false;
/*
+ * Per databook, when we want to stop the gadget, if a control transfer
+ * is still in process, complete it and get the core into setup phase.
+ */
+ if (dwc->ep0state != EP0_SETUP_PHASE) {
+ int ret;
+
+ reinit_completion(&dwc->ep0_in_setup);
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ ret = wait_for_completion_timeout(&dwc->ep0_in_setup,
+ msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT));
+ spin_lock_irqsave(&dwc->lock, flags);
+ if (ret == 0)
+ dev_warn(dwc->dev, "timed out waiting for SETUP phase\n");
+ }
+
+ /*
* In the Synopsys DesignWare Cores USB3 Databook Rev. 3.30a
* Section 4.1.8 Table 4-7, it states that for a device-initiated
* disconnect, the SW needs to ensure that it sends "a DEPENDXFER
@@ -2546,18 +2563,6 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
return 0;
dwc->softconnect = is_on;
- /*
- * Per databook, when we want to stop the gadget, if a control transfer
- * is still in process, complete it and get the core into setup phase.
- */
- if (!is_on && dwc->ep0state != EP0_SETUP_PHASE) {
- reinit_completion(&dwc->ep0_in_setup);
-
- ret = wait_for_completion_timeout(&dwc->ep0_in_setup,
- msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT));
- if (ret == 0)
- dev_warn(dwc->dev, "timed out waiting for SETUP phase\n");
- }
/*
* Avoid issuing a runtime resume if the device is already in the