]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
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>
Fri, 23 Feb 2024 07:55:11 +0000 (08:55 +0100)
[ Upstream commit ace17b6ee4f92ab0375d12a1b42494f8590a96b6 ]

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>
Stable-dep-of: 730e12fbec53 ("usb: dwc3: gadget: Handle EP0 request dequeuing properly")
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/usb/dwc3/gadget.c

index 2afe6784f1dff30ac22cdf50fb5a985b504057ab..4d830ba7d82441c34087ad4eb730d693581b8b51 100644 (file)
@@ -3647,6 +3647,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))