dwc3_trace(trace_dwc3_gadget,
"Command Complete --> %d",
DWC3_DEPCMD_STATUS(reg));
- if (DWC3_DEPCMD_STATUS(reg))
+
+ /* SW issues START TRANSFER command to isochronous ep
+ * with future frame interval. If future interval time
+ * has already passed when core recieves command, core
+ * will respond with an error(bit13 in Command complete
+ * event. Hence return error in this case.
+ */
+ if (reg & 0x2000)
+ return -EAGAIN;
+ else if (DWC3_DEPCMD_STATUS(reg))
return -EINVAL;
return 0;
}
int start_new)
{
struct dwc3_gadget_ep_cmd_params params;
- struct dwc3_request *req;
+ struct dwc3_request *req, *req1, *n;
struct dwc3 *dwc = dep->dwc;
int ret;
u32 cmd;
if (ret < 0) {
dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n");
+ if ((ret == -EAGAIN) && start_new &&
+ usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
+ /* If bit13 in Command complete event is set, software
+ * must issue ENDTRANSFER command and wait for
+ * Xfernotready event to queue the requests again.
+ */
+ if (!dep->resource_index) {
+ dep->resource_index =
+ dwc3_gadget_ep_get_transfer_index(dwc,
+ dep->number);
+ WARN_ON_ONCE(!dep->resource_index);
+ }
+ dwc3_stop_active_transfer(dwc, dep->number, true);
+ list_for_each_entry_safe_reverse(req1, n,
+ &dep->req_queued, list) {
+ req1->trb = NULL;
+ dwc3_gadget_move_request_list_front(req1);
+ if (req->request.num_mapped_sgs)
+ dep->busy_slot +=
+ req->request.num_mapped_sgs;
+ else
+ dep->busy_slot++;
+ if ((dep->busy_slot & DWC3_TRB_MASK) ==
+ DWC3_TRB_NUM - 1)
+ dep->busy_slot++;
+ }
+ return ret;
+ }
+
/*
* FIXME we need to iterate over the list of requests
* here and stop, unmap, free and del each of the linked
u32 uf;
int ret;
+ dep->current_uf = cur_uf;
+
if (list_empty(&dep->request_list)) {
dwc3_trace(trace_dwc3_gadget,
"ISOC ep %s run out for requests",
* notion of current microframe.
*/
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
- if (list_empty(&dep->req_queued)) {
+ /* If xfernotready event is recieved before issuing
+ * START TRANSFER command, don't issue END TRANSFER.
+ * Rather start queueing the requests by issuing START
+ * TRANSFER command.
+ */
+ if (list_empty(&dep->req_queued) && dep->resource_index)
dwc3_stop_active_transfer(dwc, dep->number, true);
- dep->flags = DWC3_EP_ENABLED;
- }
+ else
+ __dwc3_gadget_start_isoc(dwc, dep,
+ dep->current_uf);
+ dep->flags &= ~DWC3_EP_PENDING_REQUEST;
return 0;
}
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
list_empty(&dep->req_queued)) {
- if (list_empty(&dep->request_list)) {
+ if (list_empty(&dep->request_list))
/*
* If there is no entry in request list then do
* not issue END TRANSFER now. Just set PENDING
* flag, so that END TRANSFER is issued when an
* entry is added into request list.
*/
- dep->flags = DWC3_EP_PENDING_REQUEST;
- } else {
+ dep->flags |= DWC3_EP_PENDING_REQUEST;
+ else
dwc3_stop_active_transfer(dwc, dep->number, true);
- dep->flags = DWC3_EP_ENABLED;
- }
+ dep->flags &= ~DWC3_EP_MISSED_ISOC;
return 1;
}