diff options
author | Thinh Nguyen <Thinh.Nguyen@synopsys.com> | 2020-03-29 16:13:10 -0700 |
---|---|---|
committer | Felipe Balbi <balbi@kernel.org> | 2020-05-05 11:00:13 +0300 |
commit | 36f05d36b03523da906cf2ae70ec31af6f57e94c (patch) | |
tree | 537e53d1011e697ce3c6f5bace11ec148fd49d3c /drivers/usb/dwc3 | |
parent | 9bc3395c24962e8c8e4f590ca2740c56e4a7a4fe (diff) | |
download | linux-36f05d36b03523da906cf2ae70ec31af6f57e94c.tar.bz2 |
usb: dwc3: gadget: Issue END_TRANSFER to retry isoc transfer
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>
Diffstat (limited to 'drivers/usb/dwc3')
-rw-r--r-- | drivers/usb/dwc3/gadget.c | 36 |
1 files changed, 35 insertions, 1 deletions
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index a6aebe55db4a..dc03c04677b2 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -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(¶ms, 0, sizeof(params)); + + ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); + 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); } |