Commit a1575120 authored by Mathias Nyman's avatar Mathias Nyman Committed by Greg Kroah-Hartman
Browse files

xhci: Prevent infinite loop in transaction errors recovery for streams



Make sure to also limit the amount of soft reset retries for transaction
errors on streams in cases where the transaction error event doesn't point
to any specific TRB.

In these cases we don't know the TRB or stream ring, but we do know which
endpoint had the error.

To keep error counting simple and functional, move the current err_count
from ring structure to endpoint structure.

Cc: stable@vger.kernel.org
Signed-off-by: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20221130091944.2171610-6-mathias.nyman@linux.intel.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c3bbacd6
Loading
Loading
Loading
Loading
+10 −4
Original line number Diff line number Diff line
@@ -2458,7 +2458,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,

	switch (trb_comp_code) {
	case COMP_SUCCESS:
		ep_ring->err_count = 0;
		ep->err_count = 0;
		/* handle success with untransferred data as short packet */
		if (ep_trb != td->last_trb || remaining) {
			xhci_warn(xhci, "WARN Successful completion on short TX\n");
@@ -2484,7 +2484,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
		break;
	case COMP_USB_TRANSACTION_ERROR:
		if (xhci->quirks & XHCI_NO_SOFT_RETRY ||
		    (ep_ring->err_count++ > MAX_SOFT_RETRY) ||
		    (ep->err_count++ > MAX_SOFT_RETRY) ||
		    le32_to_cpu(slot_ctx->tt_info) & TT_SLOT)
			break;

@@ -2565,6 +2565,12 @@ static int handle_tx_event(struct xhci_hcd *xhci,
		case COMP_USB_TRANSACTION_ERROR:
		case COMP_INVALID_STREAM_TYPE_ERROR:
		case COMP_INVALID_STREAM_ID_ERROR:
			xhci_dbg(xhci, "Stream transaction error ep %u no id\n",
				 ep_index);
			if (ep->err_count++ > MAX_SOFT_RETRY)
				xhci_handle_halted_endpoint(xhci, ep, 0, NULL,
							    EP_HARD_RESET);
			else
				xhci_handle_halted_endpoint(xhci, ep, 0, NULL,
							    EP_SOFT_RESET);
			goto cleanup;
+1 −1
Original line number Diff line number Diff line
@@ -933,6 +933,7 @@ struct xhci_virt_ep {
	 * have to restore the device state to the previous state
	 */
	struct xhci_ring		*new_ring;
	unsigned int			err_count;
	unsigned int			ep_state;
#define SET_DEQ_PENDING		(1 << 0)
#define EP_HALTED		(1 << 1)	/* For stall handling */
@@ -1627,7 +1628,6 @@ struct xhci_ring {
	 * if we own the TRB (if we are the consumer).  See section 4.9.1.
	 */
	u32			cycle_state;
	unsigned int            err_count;
	unsigned int		stream_id;
	unsigned int		num_segs;
	unsigned int		num_trbs_free;