usb: dwc3: ep0: Don't prepare beyond Setup stage
authorThinh Nguyen <Thinh.Nguyen@synopsys.com>
Fri, 22 Apr 2022 02:22:50 +0000 (19:22 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 5 May 2022 20:03:24 +0000 (22:03 +0200)
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>
drivers/usb/dwc3/ep0.c
drivers/usb/dwc3/gadget.c

index aa8476d..6615f64 100644 (file)
@@ -813,7 +813,7 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
        int ret = -EINVAL;
        u32 len;
 
-       if (!dwc->gadget_driver)
+       if (!dwc->gadget_driver || !dwc->connected)
                goto out;
 
        trace_dwc3_ctrl_req(ctrl);
index 3c0a6c8..5e3311e 100644 (file)
@@ -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