[PATCH AUTOSEL 4.19 031/100] usb: dwc3: gadget: early giveback if End Transfer already completed

From: Sasha Levin
Date: Fri Oct 18 2019 - 18:21:38 EST


From: Felipe Balbi <felipe.balbi@xxxxxxxxxxxxxxx>

[ Upstream commit 9f45581f5eec6786c6eded2b3c85345d82a910c9 ]

There is a rare race condition that may happen during a Disconnect
Interrupt if we have a started request that happens to be
dequeued *after* completion of End Transfer command. If that happens,
that request will be left waiting for completion of an End Transfer
command that will never happen.

If End Transfer command has already completed before, we are safe to
giveback the request straight away.

Tested-by: Thinh Nguyen <thinhn@xxxxxxxxxxxx>
Signed-off-by: Felipe Balbi <felipe.balbi@xxxxxxxxxxxxxxx>
Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>
---
drivers/usb/dwc3/gadget.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index e7461c995116a..7b0957c530485 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1410,7 +1410,10 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
goto out0;

dwc3_gadget_move_cancelled_request(req);
- goto out0;
+ if (dep->flags & DWC3_EP_TRANSFER_STARTED)
+ goto out0;
+ else
+ goto out1;
}
dev_err(dwc->dev, "request %pK was not queued to %s\n",
request, ep->name);
@@ -1418,6 +1421,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
goto out0;
}

+out1:
dwc3_gadget_giveback(dep, req, -ECONNRESET);

out0:
--
2.20.1