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@xxxxxxxxxxxx> --- 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 8c27c6ede7c4..42dc4973a997 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1553,6 +1553,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; @@ -1564,13 +1569,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