From a7027ca69d82ae10d9e5899b74e809e32d04d48b Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Thu, 5 Mar 2020 13:24:08 -0800 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. Signed-off-by: Thinh Nguyen Signed-off-by: Felipe Balbi --- 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 d90a8a552542..a99152e6dd68 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1560,6 +1560,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; @@ -1571,13 +1576,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 -- 2.11.0