Skip to content

Commit d56b0b2

Browse files
Epicuriusgregkh
authored andcommitted
usb: xhci: ensure skipped isoc TDs are returned when isoc ring is stopped
Missed service event tells the driver that the hardware wasn't able to process some queued isoc TDs in their right time slots, and some TDs will be skipped. The driver sets a 'skip' flag to indicate that the next transfer event after this event will point to some future TD instead of the next queued TD. Once the driver receives the next event, it will skip and give back all those hardware skipped TDs. However, should this subsequent event be a stop endpoint which does not point to the next pending TD, the driver fails to return the skipped TDs. Instead, it loops for a period before outputting an erroneous message. Fix this by repositioning the 'stop endpoint' check to follow the isoc skip check, ensuring the skipped TDs are properly returned. Signed-off-by: Niklas Neronin <[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 21b224d commit d56b0b2

File tree

1 file changed

+12
-13
lines changed

1 file changed

+12
-13
lines changed

drivers/usb/host/xhci-ring.c

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2819,26 +2819,25 @@ static int handle_tx_event(struct xhci_hcd *xhci,
28192819
/* Is this a TRB in the currently executing TD? */
28202820
ep_seg = trb_in_td(xhci, td, ep_trb_dma, false);
28212821

2822-
/*
2823-
* Skip the Force Stopped Event. The event_trb(event_dma) of FSE
2824-
* is not in the current TD pointed by ep_ring->dequeue because
2825-
* that the hardware dequeue pointer still at the previous TRB
2826-
* of the current TD. The previous TRB maybe a Link TD or the
2827-
* last TRB of the previous TD. The command completion handle
2828-
* will take care the rest.
2829-
*/
2830-
if (!ep_seg && (trb_comp_code == COMP_STOPPED ||
2831-
trb_comp_code == COMP_STOPPED_LENGTH_INVALID)) {
2832-
continue;
2833-
}
2834-
28352822
if (!ep_seg) {
28362823

28372824
if (ep->skip && usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
28382825
skip_isoc_td(xhci, td, ep, status);
28392826
continue;
28402827
}
28412828

2829+
/*
2830+
* Skip the Force Stopped Event. The 'ep_trb' of FSE is not in the current
2831+
* TD pointed by 'ep_ring->dequeue' because that the hardware dequeue
2832+
* pointer still at the previous TRB of the current TD. The previous TRB
2833+
* maybe a Link TD or the last TRB of the previous TD. The command
2834+
* completion handle will take care the rest.
2835+
*/
2836+
if (trb_comp_code == COMP_STOPPED ||
2837+
trb_comp_code == COMP_STOPPED_LENGTH_INVALID) {
2838+
return 0;
2839+
}
2840+
28422841
/*
28432842
* Some hosts give a spurious success event after a short
28442843
* transfer. Ignore it.

0 commit comments

Comments
 (0)