diff mbox series

[SRU,F/raspi,H/raspi,1/2] usb: xhci: workaround for bogus SET_DEQ_PENDING endpoint state

Message ID 20210830151630.289267-2-juergh@canonical.com
State New
Headers show
Series Raspberry pi 4 USB controller randomly crashes (LP: #1930629) | expand

Commit Message

Juerg Haefliger Aug. 30, 2021, 3:16 p.m. UTC
From: Jonathan Bell <jonathan@raspberrypi.com>

BugLink: https://bugs.launchpad.net/bugs/1930629

See https://github.com/raspberrypi/linux/issues/3981

An unknown unsafe memory access can result in the ep_state variable
in xhci_virt_ep being trampled with a stuck SET_DEQ_PENDING state
despite successful completion of a Set TR Deq Pointer command.

All URB enqueue/dequeue calls for the endpoint will fail in this state
so no transfers are possible until the device is reconnected.

As a workaround, clear the flag if we see it set and issue a new Set
TR Deq command anyway - this should be harmless, as a prior Set TR Deq
command will only have been issued in the Stopped state, and if the
endpoint is Running then the controller is required to ignore it and
respond with a Context State Error event TRB.

Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>

(cherry picked from commit 9d6d498b5b5471fe9bab3e60bf2800c7490241b9 rpi-5.10.y)
Signed-off-by: Juerg Haefliger <juergh@canonical.com>
---
 drivers/usb/host/xhci-ring.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 9e15e442a4eb..96144c5077f8 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -4225,9 +4225,9 @@  void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
 	}
 	ep = &xhci->devs[slot_id]->eps[ep_index];
 	if ((ep->ep_state & SET_DEQ_PENDING)) {
-		xhci_warn(xhci, "WARN Cannot submit Set TR Deq Ptr\n");
-		xhci_warn(xhci, "A Set TR Deq Ptr command is pending.\n");
-		return;
+		xhci_warn(xhci, "WARN A Set TR Deq Ptr command is pending for slot %u ep %u\n",
+			  slot_id, ep_index);
+		ep->ep_state &= ~SET_DEQ_PENDING;
 	}
 
 	/* This function gets called from contexts where it cannot sleep */