aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc3/gadget.c
diff options
context:
space:
mode:
authorThinh Nguyen <Thinh.Nguyen@synopsys.com>2022-04-21 19:22:57 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2022-05-05 22:03:24 +0200
commitace17b6ee4f92ab0375d12a1b42494f8590a96b6 (patch)
tree64e6bc9ed49dc674d274ee6a7ef6ed6d7d47112a /drivers/usb/dwc3/gadget.c
parentusb: dwc3: ep0: Don't prepare beyond Setup stage (diff)
downloadlinux-dev-ace17b6ee4f92ab0375d12a1b42494f8590a96b6.tar.xz
linux-dev-ace17b6ee4f92ab0375d12a1b42494f8590a96b6.zip
usb: dwc3: gadget: Only End Transfer for ep0 data phase
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>
Diffstat (limited to 'drivers/usb/dwc3/gadget.c')
-rw-r--r--drivers/usb/dwc3/gadget.c11
1 files changed, 11 insertions, 0 deletions
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 5e3311e3cc16..4f445f836d32 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -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))