usb: dwc3: gadget: Issue END_TRANSFER to retry isoc transfer
authorThinh Nguyen <Thinh.Nguyen@synopsys.com>
Sun, 29 Mar 2020 23:13:10 +0000 (16:13 -0700)
committerFelipe Balbi <balbi@kernel.org>
Tue, 5 May 2020 08:00:13 +0000 (11:00 +0300)
After a number of unsuccessful start isoc attempts due to bus-expiry
status, issue END_TRANSFER command and retry on the next XferNotReady
event.

Signed-off-by: Thinh Nguyen <thinhn@synopsys.com>
Signed-off-by: Felipe Balbi <balbi@kernel.org>
drivers/usb/dwc3/gadget.c

index a6aebe5..dc03c04 100644 (file)
@@ -1413,7 +1413,8 @@ static int __dwc3_gadget_start_isoc(struct dwc3_ep *dep)
        int ret;
        int i;
 
-       if (list_empty(&dep->pending_list)) {
+       if (list_empty(&dep->pending_list) &&
+           list_empty(&dep->started_list)) {
                dep->flags |= DWC3_EP_PENDING_REQUEST;
                return -EAGAIN;
        }
@@ -1436,6 +1437,27 @@ static int __dwc3_gadget_start_isoc(struct dwc3_ep *dep)
                        break;
        }
 
+       /*
+        * After a number of unsuccessful start attempts due to bus-expiry
+        * status, issue END_TRANSFER command and retry on the next XferNotReady
+        * event.
+        */
+       if (ret == -EAGAIN) {
+               struct dwc3_gadget_ep_cmd_params params;
+               u32 cmd;
+
+               cmd = DWC3_DEPCMD_ENDTRANSFER |
+                       DWC3_DEPCMD_CMDIOC |
+                       DWC3_DEPCMD_PARAM(dep->resource_index);
+
+               dep->resource_index = 0;
+               memset(&params, 0, sizeof(params));
+
+               ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
+               if (!ret)
+                       dep->flags |= DWC3_EP_END_TRANSFER_PENDING;
+       }
+
        return ret;
 }
 
@@ -2663,6 +2685,18 @@ static void dwc3_gadget_endpoint_transfer_not_ready(struct dwc3_ep *dep,
                const struct dwc3_event_depevt *event)
 {
        dwc3_gadget_endpoint_frame_from_event(dep, event);
+
+       /*
+        * The XferNotReady event is generated only once before the endpoint
+        * starts. It will be generated again when END_TRANSFER command is
+        * issued. For some controller versions, the XferNotReady event may be
+        * generated while the END_TRANSFER command is still in process. Ignore
+        * it and wait for the next XferNotReady event after the command is
+        * completed.
+        */
+       if (dep->flags & DWC3_EP_END_TRANSFER_PENDING)
+               return;
+
        (void) __dwc3_gadget_start_isoc(dep);
 }