From: Thinh Nguyen <thinh.ngu...@synopsys.com>

[ Upstream commit 8d99087c2db863c5fa3a4a1f3cb82b3a493705ca ]

If dwc3 fails to issue START_TRANSFER/UPDATE_TRANSFER command, then we
should properly end an active transfer and give back all the started
requests. However if it's for an isoc endpoint, the failure maybe due to
bus-expiry status. In this case, don't give back the requests and wait
for the next retry.

Fixes: 72246da40f37 ("usb: Introduce DesignWare USB3 DRD Driver")
Signed-off-by: Thinh Nguyen <thi...@synopsys.com>
Signed-off-by: Felipe Balbi <ba...@kernel.org>
Signed-off-by: Sasha Levin <sas...@kernel.org>
---
 drivers/usb/dwc3/gadget.c | 24 ++++++++++++++++--------
 1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 05180a09e70d4..17340864a5408 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1217,6 +1217,8 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep)
        }
 }
 
+static void dwc3_gadget_ep_cleanup_cancelled_requests(struct dwc3_ep *dep);
+
 static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep)
 {
        struct dwc3_gadget_ep_cmd_params params;
@@ -1256,14 +1258,20 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep 
*dep)
 
        ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
        if (ret < 0) {
-               /*
-                * FIXME we need to iterate over the list of requests
-                * here and stop, unmap, free and del each of the linked
-                * requests instead of what we do now.
-                */
-               if (req->trb)
-                       memset(req->trb, 0, sizeof(struct dwc3_trb));
-               dwc3_gadget_del_and_unmap_request(dep, req, ret);
+               struct dwc3_request *tmp;
+
+               if (ret == -EAGAIN)
+                       return ret;
+
+               dwc3_stop_active_transfer(dep, true, true);
+
+               list_for_each_entry_safe(req, tmp, &dep->started_list, list)
+                       dwc3_gadget_move_cancelled_request(req);
+
+               /* If ep isn't started, then there's no end transfer pending */
+               if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING))
+                       dwc3_gadget_ep_cleanup_cancelled_requests(dep);
+
                return ret;
        }
 
-- 
2.25.1



Reply via email to