Blob Blame History Raw
From 479a75dec190b731a87007bd37bd654e2b9103c3 Mon Sep 17 00:00:00 2001
From: Mathias Nyman <mathias.nyman@linux.intel.com>
Date: Thu, 15 Jun 2017 11:55:46 +0300
Subject: [PATCH 13/26] xhci: handle transfer events without TRB pointer
Git-commit: ade2e3a148a1740a6f3abea9c54f11630b9d7d1e
Patch-mainline: v4.13-rc1
References: FATE#321327

Most transfer events have a TRB pointer indicating which TRB caused
the event.
In the case of streams, transfer events such as
USB Transaction error may have its TRB pointer set to zero.

driver won't know which stream or what TRB on that stream caused
the error, but it can issue a soft reset to recover the transfer.
A soft reset will clear the host side halt of the endpoint without
clearing Data toggle or sequence number, and let the transfer
continue from where it halted.

see xhci section 4.12 streams and 4.6.8.2 soft retry.

USB Transaction errors with a zero TRB pointer are seen with
UAS usb devices.

Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Oliver Neukum <oneukum@suse.com>
---
 drivers/usb/host/xhci-ring.c | 24 ++++++++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 870e5e19f9a7..385eed0e4c29 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2320,13 +2320,33 @@ static int handle_tx_event(struct xhci_hcd *xhci,
 	ep_ring = xhci_dma_to_transfer_ring(ep, ep_trb_dma);
 	ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
 
-	if (!ep_ring || GET_EP_CTX_STATE(ep_ctx) == EP_STATE_DISABLED) {
+	if (GET_EP_CTX_STATE(ep_ctx) == EP_STATE_DISABLED) {
 		xhci_err(xhci,
-			 "ERROR Transfer event for disabled endpoint slot %u ep %u or incorrect stream ring\n",
+			 "ERROR Transfer event for disabled endpoint slot %u ep %u\n",
 			  slot_id, ep_index);
 		goto err_out;
 	}
 
+	/* Some transfer events don't always point to a trb, see xhci 4.17.4 */
+	if (!ep_ring) {
+		switch (trb_comp_code) {
+		case COMP_STALL_ERROR:
+		case COMP_USB_TRANSACTION_ERROR:
+		case COMP_INVALID_STREAM_TYPE_ERROR:
+		case COMP_INVALID_STREAM_ID_ERROR:
+			xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index, 0,
+						     NULL, NULL, EP_SOFT_RESET);
+			goto cleanup;
+		case COMP_RING_UNDERRUN:
+		case COMP_RING_OVERRUN:
+			goto cleanup;
+		default:
+			xhci_err(xhci, "ERROR Transfer event for unknown stream ring slot %u ep %u\n",
+				 slot_id, ep_index);
+			goto err_out;
+		}
+	}
+
 	/* Count current td numbers if ep->skip is set */
 	if (ep->skip) {
 		list_for_each(tmp, &ep_ring->td_list)
-- 
2.12.3