usb: dwc3: gadget: Only End Transfer for ep0 data phase
authorThinh Nguyen <Thinh.Nguyen@synopsys.com>
Fri, 22 Apr 2022 02:22:57 +0000 (19:22 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 5 May 2022 20:03:24 +0000 (22:03 +0200)
The driver shouldn't be able to issue End Transfer to the control
endpoint at anytime. Typically we should only do so in error cases such
as invalid/unexpected direction of Data Phase as described in the
control transfer flow of the programming guide. It _may_ end started
data phase during controller deinitialization from soft disconnect or
driver removal. However, that should not happen because the driver
should be maintained in EP0_SETUP_PHASE during driver tear-down. On
soft-connect, the controller should be reset from a soft-reset and there
should be no issue starting the control endpoint.

Signed-off-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
Link: https://lore.kernel.org/r/3c6643678863a26702e4115e9e19d7d94a30d49c.1650593829.git.Thinh.Nguyen@synopsys.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/dwc3/gadget.c

index 5e3311e..4f445f8 100644 (file)
@@ -3685,6 +3685,17 @@ static void dwc3_reset_gadget(struct dwc3 *dwc)
 void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force,
        bool interrupt)
 {
+       struct dwc3 *dwc = dep->dwc;
+
+       /*
+        * Only issue End Transfer command to the control endpoint of a started
+        * Data Phase. Typically we should only do so in error cases such as
+        * invalid/unexpected direction as described in the control transfer
+        * flow of the programming guide.
+        */
+       if (dep->number <= 1 && dwc->ep0state != EP0_DATA_PHASE)
+               return;
+
        if (!(dep->flags & DWC3_EP_TRANSFER_STARTED) ||
            (dep->flags & DWC3_EP_DELAY_STOP) ||
            (dep->flags & DWC3_EP_END_TRANSFER_PENDING))