| From c503672abe1348f10f5a54a662336358c6e1a297 Mon Sep 17 00:00:00 2001 |
| From: Thinh Nguyen <Thinh.Nguyen@synopsys.com> |
| Date: Wed, 2 Sep 2020 18:42:58 -0700 |
| Subject: usb: dwc3: gadget: Resume pending requests after CLEAR_STALL |
| |
| From: Thinh Nguyen <Thinh.Nguyen@synopsys.com> |
| |
| commit c503672abe1348f10f5a54a662336358c6e1a297 upstream. |
| |
| 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> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/usb/dwc3/gadget.c | 22 ++++++++++++++-------- |
| 1 file changed, 14 insertions(+), 8 deletions(-) |
| |
| --- a/drivers/usb/dwc3/gadget.c |
| +++ b/drivers/usb/dwc3/gadget.c |
| @@ -1628,8 +1628,13 @@ static int __dwc3_gadget_ep_queue(struct |
| 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 dwc |
| 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; |