diff options
author | Thinh Nguyen <Thinh.Nguyen@synopsys.com> | 2020-03-05 13:24:08 -0800 |
---|---|---|
committer | Felipe Balbi <balbi@kernel.org> | 2020-05-05 10:58:52 +0300 |
commit | a7027ca69d82ae10d9e5899b74e809e32d04d48b (patch) | |
tree | 3d6415cfc1fa4386765940e30161ff97d7eda906 | |
parent | cb11ea56f37a36288cdd0a4799a983ee3aa437dd (diff) |
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 <thinhn@synopsys.com>
Signed-off-by: Felipe Balbi <balbi@kernel.org>
-rw-r--r-- | drivers/usb/dwc3/gadget.c | 15 |
1 files changed, 14 insertions, 1 deletions
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 |