mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-28 11:49:32 +00:00
usb: dwc3: gadget: fix missed isoc
There are two reasons to generate missed isoc. 1. when the host does not poll for all the data. 2. because of application-side delays that prevent all the data from being transferred in programmed microframe. Current code was able to handle first case only. This patch handles scenario 2 as well.Scenario 2 sometime may occur with complex gadget application, however it can be easily reproduced for testing purpose as follows: a. use isoc binterval as 1 in f_sourcesink. b. use pattern=0 c. introduce a delay of 150us deliberately in source_sink_complete, so that after few frames it lands into scenario 2. d. now run testusb 16 (isoc in test). You will notice that if this patch is not applied then isoc transfer is not able to recover after first missed. Current patch's approach is as under: If missed isoc occurs and there is no request queued then issue END TRANSFER, so that core generates next xfernotready and we will issue a fresh START TRANSFER. If there are still queued request then wait, do not issue either END or UPDATE TRANSFER, just attach next request in request_list during giveback. If any future queued request is successfully transferred then we will issue UPDATE TRANSFER for all request in the request_list. Cc: <stable@vger.kernel.org> # v3.6 v3.7 v3.8 Signed-off-by: Pratyush Anand <pratyush.anand@st.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
parent
2b758350af
commit
7efea86c28
2 changed files with 24 additions and 14 deletions
|
@ -407,7 +407,6 @@ struct dwc3_event_buffer {
|
||||||
* @number: endpoint number (1 - 15)
|
* @number: endpoint number (1 - 15)
|
||||||
* @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
|
* @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
|
||||||
* @resource_index: Resource transfer index
|
* @resource_index: Resource transfer index
|
||||||
* @current_uf: Current uf received through last event parameter
|
|
||||||
* @interval: the intervall on which the ISOC transfer is started
|
* @interval: the intervall on which the ISOC transfer is started
|
||||||
* @name: a human readable name e.g. ep1out-bulk
|
* @name: a human readable name e.g. ep1out-bulk
|
||||||
* @direction: true for TX, false for RX
|
* @direction: true for TX, false for RX
|
||||||
|
@ -441,7 +440,6 @@ struct dwc3_ep {
|
||||||
u8 number;
|
u8 number;
|
||||||
u8 type;
|
u8 type;
|
||||||
u8 resource_index;
|
u8 resource_index;
|
||||||
u16 current_uf;
|
|
||||||
u32 interval;
|
u32 interval;
|
||||||
|
|
||||||
char name[20];
|
char name[20];
|
||||||
|
|
|
@ -1115,16 +1115,6 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
||||||
dep->name);
|
dep->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 3. Missed ISOC Handling. We need to start isoc transfer on the saved
|
|
||||||
* uframe number.
|
|
||||||
*/
|
|
||||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
|
|
||||||
(dep->flags & DWC3_EP_MISSED_ISOC)) {
|
|
||||||
__dwc3_gadget_start_isoc(dwc, dep, dep->current_uf);
|
|
||||||
dep->flags &= ~DWC3_EP_MISSED_ISOC;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1686,14 +1676,29 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
||||||
if (trb_status == DWC3_TRBSTS_MISSED_ISOC) {
|
if (trb_status == DWC3_TRBSTS_MISSED_ISOC) {
|
||||||
dev_dbg(dwc->dev, "incomplete IN transfer %s\n",
|
dev_dbg(dwc->dev, "incomplete IN transfer %s\n",
|
||||||
dep->name);
|
dep->name);
|
||||||
dep->current_uf = event->parameters &
|
/*
|
||||||
~(dep->interval - 1);
|
* If missed isoc occurred and there is
|
||||||
|
* no request queued then issue END
|
||||||
|
* TRANSFER, so that core generates
|
||||||
|
* next xfernotready and we will issue
|
||||||
|
* a fresh START TRANSFER.
|
||||||
|
* If there are still queued request
|
||||||
|
* then wait, do not issue either END
|
||||||
|
* or UPDATE TRANSFER, just attach next
|
||||||
|
* request in request_list during
|
||||||
|
* giveback.If any future queued request
|
||||||
|
* is successfully transferred then we
|
||||||
|
* will issue UPDATE TRANSFER for all
|
||||||
|
* request in the request_list.
|
||||||
|
*/
|
||||||
dep->flags |= DWC3_EP_MISSED_ISOC;
|
dep->flags |= DWC3_EP_MISSED_ISOC;
|
||||||
} else {
|
} else {
|
||||||
dev_err(dwc->dev, "incomplete IN transfer %s\n",
|
dev_err(dwc->dev, "incomplete IN transfer %s\n",
|
||||||
dep->name);
|
dep->name);
|
||||||
status = -ECONNRESET;
|
status = -ECONNRESET;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
dep->flags &= ~DWC3_EP_MISSED_ISOC;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (count && (event->status & DEPEVT_STATUS_SHORT))
|
if (count && (event->status & DEPEVT_STATUS_SHORT))
|
||||||
|
@ -1720,6 +1725,13 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
||||||
break;
|
break;
|
||||||
} while (1);
|
} while (1);
|
||||||
|
|
||||||
|
if (list_empty(&dep->req_queued) &&
|
||||||
|
(dep->flags & DWC3_EP_MISSED_ISOC)) {
|
||||||
|
dwc3_stop_active_transfer(dwc, dep->number);
|
||||||
|
dep->flags &= ~DWC3_EP_MISSED_ISOC;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if ((event->status & DEPEVT_STATUS_IOC) &&
|
if ((event->status & DEPEVT_STATUS_IOC) &&
|
||||||
(trb->ctrl & DWC3_TRB_CTRL_IOC))
|
(trb->ctrl & DWC3_TRB_CTRL_IOC))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue