Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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 5372c65e1311 ("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>

authored by

Mathias Nyman and committed by
Greg Kroah-Hartman
b331a3d8 118abe03

+27 -13
+26 -12
drivers/usb/host/xhci-ring.c
··· 2611 2611 return 0; 2612 2612 } 2613 2613 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 + 2614 2630 /* 2615 2631 * If this function returns an error condition, it means it got a Transfer 2616 2632 * event with a corrupted Slot ID, Endpoint ID, or TRB DMA address. ··· 2681 2665 case COMP_SUCCESS: 2682 2666 if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { 2683 2667 trb_comp_code = COMP_SHORT_PACKET; 2684 - xhci_dbg(xhci, "Successful completion on short TX for slot %u ep %u with last td short %d\n", 2685 - slot_id, ep_index, ep_ring->last_td_was_short); 2668 + xhci_dbg(xhci, "Successful completion on short TX for slot %u ep %u with last td comp code %d\n", 2669 + slot_id, ep_index, ep_ring->old_trb_comp_code); 2686 2670 } 2687 2671 break; 2688 2672 case COMP_SHORT_PACKET: ··· 2833 2817 if (trb_comp_code != COMP_STOPPED && 2834 2818 trb_comp_code != COMP_STOPPED_LENGTH_INVALID && 2835 2819 !ring_xrun_event && 2836 - !ep_ring->last_td_was_short) { 2820 + !xhci_spurious_success_tx_event(xhci, ep_ring)) { 2837 2821 xhci_warn(xhci, "Event TRB for slot %u ep %u with no TDs queued\n", 2838 2822 slot_id, ep_index); 2839 2823 } ··· 2898 2882 2899 2883 /* 2900 2884 * Some hosts give a spurious success event after a short 2901 - * transfer. Ignore it. 2885 + * transfer or error on last TRB. Ignore it. 2902 2886 */ 2903 - if ((xhci->quirks & XHCI_SPURIOUS_SUCCESS) && 2904 - ep_ring->last_td_was_short) { 2905 - ep_ring->last_td_was_short = false; 2887 + if (xhci_spurious_success_tx_event(xhci, ep_ring)) { 2888 + xhci_dbg(xhci, "Spurious event dma %pad, comp_code %u after %u\n", 2889 + &ep_trb_dma, trb_comp_code, ep_ring->old_trb_comp_code); 2890 + ep_ring->old_trb_comp_code = trb_comp_code; 2906 2891 return 0; 2907 2892 } 2908 2893 ··· 2926 2909 */ 2927 2910 } while (ep->skip); 2928 2911 2912 + ep_ring->old_trb_comp_code = trb_comp_code; 2913 + 2929 2914 /* Get out if a TD was queued at enqueue after the xrun occurred */ 2930 2915 if (ring_xrun_event) 2931 2916 return 0; 2932 - 2933 - if (trb_comp_code == COMP_SHORT_PACKET) 2934 - ep_ring->last_td_was_short = true; 2935 - else 2936 - ep_ring->last_td_was_short = false; 2937 2917 2938 2918 ep_trb = &ep_seg->trbs[(ep_trb_dma - ep_seg->dma) / sizeof(*ep_trb)]; 2939 2919 trace_xhci_handle_transfer(ep_ring, (struct xhci_generic_trb *) ep_trb, ep_trb_dma);
+1 -1
drivers/usb/host/xhci.h
··· 1375 1375 unsigned int num_trbs_free; /* used only by xhci DbC */ 1376 1376 unsigned int bounce_buf_len; 1377 1377 enum xhci_ring_type type; 1378 - bool last_td_was_short; 1378 + u32 old_trb_comp_code; 1379 1379 struct radix_tree_root *trb_address_map; 1380 1380 }; 1381 1381