Commit 1479cb69 authored by Douglas Anderson's avatar Douglas Anderson Committed by Felipe Balbi

usb: dwc2: host: If using uframe scheduler, end splits better

The microframe scheduler figured out exactly how many transfers we need
for a split transaction.  Let's use this knowledge to know when to end
things.

Without this I found that certain devices would just keep responding
with tons of NYET resonses on their INT_IN endpoint.  These would just
keep going and going and eventually we'd decide to terminate the
transfer (because the whole frame changed), but by that time the
scheduler would decide that we "missed" the start of the next transfer.
I can also imagine that if we blow past the end of our scheduled time we
may mess up other things that were scheduled to happen.

No known test cases are improved by this patch except that the scheduler
code doesn't yell about MISSES constantly anymore.
Acked-by: default avatarJohn Youn <johnyoun@synopsys.com>
Signed-off-by: default avatarDouglas Anderson <dianders@chromium.org>
Tested-by: default avatarHeiko Stuebner <heiko@sntech.de>
Tested-by: default avatarStefan Wahren <stefan.wahren@i2se.com>
Signed-off-by: default avatarFelipe Balbi <balbi@kernel.org>
parent 9f9f09b0
...@@ -1371,14 +1371,50 @@ static void dwc2_hc_nyet_intr(struct dwc2_hsotg *hsotg, ...@@ -1371,14 +1371,50 @@ static void dwc2_hc_nyet_intr(struct dwc2_hsotg *hsotg,
if (chan->ep_type == USB_ENDPOINT_XFER_INT || if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
chan->ep_type == USB_ENDPOINT_XFER_ISOC) { chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
int frnum = dwc2_hcd_get_frame_number(hsotg); struct dwc2_qh *qh = chan->qh;
bool past_end;
if (hsotg->core_params->uframe_sched <= 0) {
int frnum = dwc2_hcd_get_frame_number(hsotg);
/* Don't have num_hs_transfers; simple logic */
past_end = dwc2_full_frame_num(frnum) !=
dwc2_full_frame_num(qh->next_active_frame);
} else {
int end_frnum;
if (dwc2_full_frame_num(frnum) !=
dwc2_full_frame_num(chan->qh->next_active_frame)) {
/* /*
* No longer in the same full speed frame. * Figure out the end frame based on schedule.
* Treat this as a transaction error. *
*/ * We don't want to go on trying again and again
* forever. Let's stop when we've done all the
* transfers that were scheduled.
*
* We're going to be comparing start_active_frame
* and next_active_frame, both of which are 1
* before the time the packet goes on the wire,
* so that cancels out. Basically if had 1
* transfer and we saw 1 NYET then we're done.
* We're getting a NYET here so if next >=
* (start + num_transfers) we're done. The
* complexity is that for all but ISOC_OUT we
* skip one slot.
*/
end_frnum = dwc2_frame_num_inc(
qh->start_active_frame,
qh->num_hs_transfers);
if (qh->ep_type != USB_ENDPOINT_XFER_ISOC ||
qh->ep_is_in)
end_frnum =
dwc2_frame_num_inc(end_frnum, 1);
past_end = dwc2_frame_num_le(
end_frnum, qh->next_active_frame);
}
if (past_end) {
/* Treat this as a transaction error. */
#if 0 #if 0
/* /*
* Todo: Fix system performance so this can * Todo: Fix system performance so this can
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment