Skip to content

Commit b331a3d

Browse files
matnymangregkh
authored andcommitted
xhci: Handle spurious events on Etron host isoc enpoints
Unplugging a USB3.0 webcam from Etron hosts while streaming results in errors like this: [ 2.646387] xhci_hcd 0000:03:00.0: ERROR Transfer event TRB DMA ptr not part of current TD ep_index 18 comp_code 13 [ 2.646446] xhci_hcd 0000:03:00.0: Looking for event-dma 000000002fdf8630 trb-start 000000002fdf8640 trb-end 000000002fdf8650 [ 2.646560] xhci_hcd 0000:03:00.0: ERROR Transfer event TRB DMA ptr not part of current TD ep_index 18 comp_code 13 [ 2.646568] xhci_hcd 0000:03:00.0: Looking for event-dma 000000002fdf8660 trb-start 000000002fdf8670 trb-end 000000002fdf8670 Etron xHC generates two transfer events for the TRB if an error is detected while processing the last TRB of an isoc TD. The first event can be any sort of error (like USB Transaction or Babble Detected, etc), and the final event is Success. The xHCI driver will handle the TD after the first event and remove it from its internal list, and then print an "Transfer event TRB DMA ptr not part of current TD" error message after the final event. Commit 5372c65 ("xhci: process isoc TD properly when there was a transaction error mid TD.") is designed to address isoc transaction errors, but unfortunately it doesn't account for this scenario. This issue is similar to the XHCI_SPURIOUS_SUCCESS case where a success event follows a 'short transfer' event, but the TD the event points to is already given back. Expand the spurious success 'short transfer' event handling to cover the spurious success after error on Etron hosts. Kuangyi Chiang reported this issue and submitted a different solution based on using error_mid_td. This commit message is mostly taken from that patch. Reported-by: Kuangyi Chiang <ki.chiang65@gmail.com> Closes: https://lore.kernel.org/linux-usb/20241028025337.6372-6-ki.chiang65@gmail.com/ Tested-by: Kuangyi Chiang <ki.chiang65@gmail.com> Tested-by: Michal Pecio <michal.pecio@gmail.com> Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Link: https://lore.kernel.org/r/20250306144954.3507700-16-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 118abe0 commit b331a3d

File tree

2 files changed

+27
-13
lines changed

2 files changed

+27
-13
lines changed

drivers/usb/host/xhci-ring.c

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2611,6 +2611,22 @@ static int handle_transferless_tx_event(struct xhci_hcd *xhci, struct xhci_virt_
26112611
return 0;
26122612
}
26132613

2614+
static bool xhci_spurious_success_tx_event(struct xhci_hcd *xhci,
2615+
struct xhci_ring *ring)
2616+
{
2617+
switch (ring->old_trb_comp_code) {
2618+
case COMP_SHORT_PACKET:
2619+
return xhci->quirks & XHCI_SPURIOUS_SUCCESS;
2620+
case COMP_USB_TRANSACTION_ERROR:
2621+
case COMP_BABBLE_DETECTED_ERROR:
2622+
case COMP_ISOCH_BUFFER_OVERRUN:
2623+
return xhci->quirks & XHCI_ETRON_HOST &&
2624+
ring->type == TYPE_ISOC;
2625+
default:
2626+
return false;
2627+
}
2628+
}
2629+
26142630
/*
26152631
* If this function returns an error condition, it means it got a Transfer
26162632
* event with a corrupted Slot ID, Endpoint ID, or TRB DMA address.
@@ -2665,8 +2681,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
26652681
case COMP_SUCCESS:
26662682
if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
26672683
trb_comp_code = COMP_SHORT_PACKET;
2668-
xhci_dbg(xhci, "Successful completion on short TX for slot %u ep %u with last td short %d\n",
2669-
slot_id, ep_index, ep_ring->last_td_was_short);
2684+
xhci_dbg(xhci, "Successful completion on short TX for slot %u ep %u with last td comp code %d\n",
2685+
slot_id, ep_index, ep_ring->old_trb_comp_code);
26702686
}
26712687
break;
26722688
case COMP_SHORT_PACKET:
@@ -2817,7 +2833,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
28172833
if (trb_comp_code != COMP_STOPPED &&
28182834
trb_comp_code != COMP_STOPPED_LENGTH_INVALID &&
28192835
!ring_xrun_event &&
2820-
!ep_ring->last_td_was_short) {
2836+
!xhci_spurious_success_tx_event(xhci, ep_ring)) {
28212837
xhci_warn(xhci, "Event TRB for slot %u ep %u with no TDs queued\n",
28222838
slot_id, ep_index);
28232839
}
@@ -2882,11 +2898,12 @@ static int handle_tx_event(struct xhci_hcd *xhci,
28822898

28832899
/*
28842900
* Some hosts give a spurious success event after a short
2885-
* transfer. Ignore it.
2901+
* transfer or error on last TRB. Ignore it.
28862902
*/
2887-
if ((xhci->quirks & XHCI_SPURIOUS_SUCCESS) &&
2888-
ep_ring->last_td_was_short) {
2889-
ep_ring->last_td_was_short = false;
2903+
if (xhci_spurious_success_tx_event(xhci, ep_ring)) {
2904+
xhci_dbg(xhci, "Spurious event dma %pad, comp_code %u after %u\n",
2905+
&ep_trb_dma, trb_comp_code, ep_ring->old_trb_comp_code);
2906+
ep_ring->old_trb_comp_code = trb_comp_code;
28902907
return 0;
28912908
}
28922909

@@ -2909,15 +2926,12 @@ static int handle_tx_event(struct xhci_hcd *xhci,
29092926
*/
29102927
} while (ep->skip);
29112928

2929+
ep_ring->old_trb_comp_code = trb_comp_code;
2930+
29122931
/* Get out if a TD was queued at enqueue after the xrun occurred */
29132932
if (ring_xrun_event)
29142933
return 0;
29152934

2916-
if (trb_comp_code == COMP_SHORT_PACKET)
2917-
ep_ring->last_td_was_short = true;
2918-
else
2919-
ep_ring->last_td_was_short = false;
2920-
29212935
ep_trb = &ep_seg->trbs[(ep_trb_dma - ep_seg->dma) / sizeof(*ep_trb)];
29222936
trace_xhci_handle_transfer(ep_ring, (struct xhci_generic_trb *) ep_trb, ep_trb_dma);
29232937

drivers/usb/host/xhci.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1375,7 +1375,7 @@ struct xhci_ring {
13751375
unsigned int num_trbs_free; /* used only by xhci DbC */
13761376
unsigned int bounce_buf_len;
13771377
enum xhci_ring_type type;
1378-
bool last_td_was_short;
1378+
u32 old_trb_comp_code;
13791379
struct radix_tree_root *trb_address_map;
13801380
};
13811381

0 commit comments

Comments
 (0)