summaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc3
diff options
context:
space:
mode:
authorThinh Nguyen <Thinh.Nguyen@synopsys.com>2020-09-02 18:42:58 -0700
committerFelipe Balbi <balbi@kernel.org>2020-09-24 11:56:00 +0300
commitc503672abe1348f10f5a54a662336358c6e1a297 (patch)
tree88ed4d03a4aa0f1001a3e911637714d90f87ca82 /drivers/usb/dwc3
parentba4f184e126b751d1bffad5897f263108befc780 (diff)
downloadlinux-stable-c503672abe1348f10f5a54a662336358c6e1a297.tar.gz
linux-stable-c503672abe1348f10f5a54a662336358c6e1a297.tar.bz2
linux-stable-c503672abe1348f10f5a54a662336358c6e1a297.zip
usb: dwc3: gadget: Resume pending requests after CLEAR_STALL
The function driver may queue new requests right after halting the endpoint (i.e. queue new requests while the endpoint is stalled). There's no restriction preventing it from doing so. However, dwc3 currently drops those requests after CLEAR_STALL. The driver should only drop started requests. Keep the pending requests in the pending list to resume and process them after the host issues ClearFeature(Halt) to the endpoint. Cc: stable@vger.kernel.org Fixes: cb11ea56f37a ("usb: dwc3: gadget: Properly handle ClearFeature(halt)") Signed-off-by: Thinh Nguyen <thinhn@synopsys.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
Diffstat (limited to 'drivers/usb/dwc3')
-rw-r--r--drivers/usb/dwc3/gadget.c22
1 files changed, 14 insertions, 8 deletions
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index c2a0f64f8d1e..c04f7b29535e 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1628,8 +1628,13 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
if (dep->flags & DWC3_EP_WAIT_TRANSFER_COMPLETE)
return 0;
- /* Start the transfer only after the END_TRANSFER is completed */
- if (dep->flags & DWC3_EP_END_TRANSFER_PENDING) {
+ /*
+ * Start the transfer only after the END_TRANSFER is completed
+ * and endpoint STALL is cleared.
+ */
+ if ((dep->flags & DWC3_EP_END_TRANSFER_PENDING) ||
+ (dep->flags & DWC3_EP_WEDGE) ||
+ (dep->flags & DWC3_EP_STALL)) {
dep->flags |= DWC3_EP_DELAY_START;
return 0;
}
@@ -1836,13 +1841,14 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
list_for_each_entry_safe(req, tmp, &dep->started_list, list)
dwc3_gadget_move_cancelled_request(req);
- list_for_each_entry_safe(req, tmp, &dep->pending_list, list)
- dwc3_gadget_move_cancelled_request(req);
-
- if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING)) {
- dep->flags &= ~DWC3_EP_DELAY_START;
+ if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING))
dwc3_gadget_ep_cleanup_cancelled_requests(dep);
- }
+
+ if ((dep->flags & DWC3_EP_DELAY_START) &&
+ !usb_endpoint_xfer_isoc(dep->endpoint.desc))
+ __dwc3_gadget_kick_transfer(dep);
+
+ dep->flags &= ~DWC3_EP_DELAY_START;
}
return ret;