aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDouglas Anderson <dianders@chromium.org>2016-01-28 21:20:13 -0500
committerFelipe Balbi <balbi@kernel.org>2016-03-04 08:14:45 -0500
commit1479cb698ac07d5dc4cc2b7de3588d38484267e9 (patch)
tree428c96aed59209f54afc73454b7b126627bfa67c
parent9f9f09b048f5fdfded26149defd61b737b314ba0 (diff)
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: John Youn <johnyoun@synopsys.com> Signed-off-by: Douglas Anderson <dianders@chromium.org> Tested-by: Heiko Stuebner <heiko@sntech.de> Tested-by: Stefan Wahren <stefan.wahren@i2se.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
-rw-r--r--drivers/usb/dwc2/hcd_intr.c48
1 files changed, 42 insertions, 6 deletions
diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c
index 5fc024f2092a..906f223542ee 100644
--- a/drivers/usb/dwc2/hcd_intr.c
+++ b/drivers/usb/dwc2/hcd_intr.c
@@ -1371,14 +1371,50 @@ static void dwc2_hc_nyet_intr(struct dwc2_hsotg *hsotg,
1371 1371
1372 if (chan->ep_type == USB_ENDPOINT_XFER_INT || 1372 if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
1373 chan->ep_type == USB_ENDPOINT_XFER_ISOC) { 1373 chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
1374 int frnum = dwc2_hcd_get_frame_number(hsotg); 1374 struct dwc2_qh *qh = chan->qh;
1375 bool past_end;
1376
1377 if (hsotg->core_params->uframe_sched <= 0) {
1378 int frnum = dwc2_hcd_get_frame_number(hsotg);
1379
1380 /* Don't have num_hs_transfers; simple logic */
1381 past_end = dwc2_full_frame_num(frnum) !=
1382 dwc2_full_frame_num(qh->next_active_frame);
1383 } else {
1384 int end_frnum;
1375 1385
1376 if (dwc2_full_frame_num(frnum) !=
1377 dwc2_full_frame_num(chan->qh->next_active_frame)) {
1378 /* 1386 /*
1379 * No longer in the same full speed frame. 1387 * Figure out the end frame based on schedule.
1380 * Treat this as a transaction error. 1388 *
1381 */ 1389 * We don't want to go on trying again and again
1390 * forever. Let's stop when we've done all the
1391 * transfers that were scheduled.
1392 *
1393 * We're going to be comparing start_active_frame
1394 * and next_active_frame, both of which are 1
1395 * before the time the packet goes on the wire,
1396 * so that cancels out. Basically if had 1
1397 * transfer and we saw 1 NYET then we're done.
1398 * We're getting a NYET here so if next >=
1399 * (start + num_transfers) we're done. The
1400 * complexity is that for all but ISOC_OUT we
1401 * skip one slot.
1402 */
1403 end_frnum = dwc2_frame_num_inc(
1404 qh->start_active_frame,
1405 qh->num_hs_transfers);
1406
1407 if (qh->ep_type != USB_ENDPOINT_XFER_ISOC ||
1408 qh->ep_is_in)
1409 end_frnum =
1410 dwc2_frame_num_inc(end_frnum, 1);
1411
1412 past_end = dwc2_frame_num_le(
1413 end_frnum, qh->next_active_frame);
1414 }
1415
1416 if (past_end) {
1417 /* Treat this as a transaction error. */
1382#if 0 1418#if 0
1383 /* 1419 /*
1384 * Todo: Fix system performance so this can 1420 * Todo: Fix system performance so this can