Skip to content

Commit d0b6195

Browse files
Michal Peciogregkh
authored andcommitted
usb: xhci: Expedite skipping missed isoch TDs on modern HCs
xHCI spec rev. 1.0 allowed the TRB pointer of Missed Service events to be NULL. Having no idea which of the queued TDs were missed and which are waiting, we can only set a flag to skip missed TDs later. But HCs are also allowed to give us pointer to the last missed TRB, and this became mandatory in spec rev. 1.1 and later. Use this pointer, if available, to immediately skip all missed TDs. This reduces latency and risk of skipping-related bugs, because we can now leave the skip flag cleared for future events. Handle Missed Service Error events as 'error mid TD', if applicable, because rev. 1.0 spec excplicitly says so in notes to 4.10.3.2 and later revs in 4.10.3.2 and 4.11.2.5.2. Notes to 4.9.1 seem to apply. Tested on ASM1142 and ASM3142 v1.1 xHCs which provide TRB pointers. Tested on AMD, Etron, Renesas v1.0 xHCs which provide TRB pointers. Tested on NEC v0.96 and VIA v1.0 xHCs which send a NULL pointer. Change inspired by a discussion about realtime USB audio. Link: https://lore.kernel.org/linux-usb/[email protected]/T/ Signed-off-by: Michal Pecio <[email protected]> Signed-off-by: Mathias Nyman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 906dec1 commit d0b6195

File tree

1 file changed

+10
-4
lines changed

1 file changed

+10
-4
lines changed

drivers/usb/host/xhci-ring.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2439,6 +2439,12 @@ static void process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
24392439
if (ep_trb != td->end_trb)
24402440
td->error_mid_td = true;
24412441
break;
2442+
case COMP_MISSED_SERVICE_ERROR:
2443+
frame->status = -EXDEV;
2444+
sum_trbs_for_length = true;
2445+
if (ep_trb != td->end_trb)
2446+
td->error_mid_td = true;
2447+
break;
24422448
case COMP_INCOMPATIBLE_DEVICE_ERROR:
24432449
case COMP_STALL_ERROR:
24442450
frame->status = -EPROTO;
@@ -2749,8 +2755,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
27492755
*/
27502756
ep->skip = true;
27512757
xhci_dbg(xhci,
2752-
"Miss service interval error for slot %u ep %u, set skip flag\n",
2753-
slot_id, ep_index);
2758+
"Miss service interval error for slot %u ep %u, set skip flag%s\n",
2759+
slot_id, ep_index, ep_trb_dma ? ", skip now" : "");
27542760
break;
27552761
case COMP_NO_PING_RESPONSE_ERROR:
27562762
ep->skip = true;
@@ -2799,8 +2805,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
27992805
xhci_dequeue_td(xhci, td, ep_ring, td->status);
28002806
}
28012807

2802-
/* Missed TDs will be skipped on the next event */
2803-
if (trb_comp_code == COMP_MISSED_SERVICE_ERROR)
2808+
/* If the TRB pointer is NULL, missed TDs will be skipped on the next event */
2809+
if (trb_comp_code == COMP_MISSED_SERVICE_ERROR && !ep_trb_dma)
28042810
return 0;
28052811

28062812
if (list_empty(&ep_ring->td_list)) {

0 commit comments

Comments
 (0)