From b5d521a3df119341b152523008ced0e5e9c54900 Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Thu, 21 May 2020 20:08:31 -0700 Subject: [PATCH] usb: dwc3: gadget: Give back staled requests If a request is dequeued, the transfer is cancelled. Give back all the started requests. In most scenarios, the function driver dequeues all requests of a transfer when there's a failure. If the function driver follows this, then it's fine. If not, then we'd be skipping TRBs at different points within the dequeue and enqueue pointers, making dequeue/enqueue pointers useless. To enforce and make sure that we're properly skipping TRBs, cancel all the started requests and give back all the cancelled requests to the function drivers. Change-Id: Ia344a480048383f3fd7c16afbc9f7b0062492879 Signed-off-by: Thinh Nguyen Patch-mainline: linux-usb @ 05/03/20, 13:24 Signed-off-by: Mayank Rana --- drivers/usb/dwc3/gadget.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 491a3aaa1063..cb0dbb3a6a34 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1682,6 +1682,11 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, spin_lock_irqsave(&dwc->lock, flags); + list_for_each_entry(r, &dep->cancelled_list, list) { + if (r == req) + goto out0; + } + list_for_each_entry(r, &dep->pending_list, list) { if (r == req) break; @@ -1693,13 +1698,21 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, break; } if (r == req) { + struct dwc3_request *t; + /* wait until it is processed */ dwc3_stop_active_transfer(dep, true, true); if (!r->trb) goto out0; - dwc3_gadget_move_cancelled_request(req); + /* + * Remove any started request if the transfer is + * cancelled. + */ + list_for_each_entry_safe(r, t, &dep->started_list, list) + dwc3_gadget_move_cancelled_request(r); + if (dep->flags & DWC3_EP_TRANSFER_STARTED) goto out0; else