]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.1-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 3 Dec 2024 08:23:55 +0000 (09:23 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 3 Dec 2024 08:23:55 +0000 (09:23 +0100)
added patches:
usb-xhci-fix-td-invalidation-under-pending-set-tr-dequeue.patch

queue-6.1/series
queue-6.1/usb-xhci-fix-td-invalidation-under-pending-set-tr-dequeue.patch [new file with mode: 0644]

index b911033e2b08a53a80096ad604608780d4b529e9..a73ec07170ba2d0a6418748ef3504f0a5f4d4b41 100644 (file)
@@ -390,5 +390,5 @@ locking-lockdep-avoid-creating-new-name-string-literals-in-lockdep_set_subclass.
 pinctrl-qcom-spmi-fix-debugfs-drive-strength.patch
 dt-bindings-iio-dac-ad3552r-fix-maximum-spi-speed.patch
 exfat-fix-uninit-value-in-__exfat_get_dentry_set.patch
-xhci-don-t-perform-soft-retry-for-etron-xhci-host.patch
 bluetooth-fix-type-of-len-in-rfcomm_sock_getsockopt-_old.patch
+usb-xhci-fix-td-invalidation-under-pending-set-tr-dequeue.patch
diff --git a/queue-6.1/usb-xhci-fix-td-invalidation-under-pending-set-tr-dequeue.patch b/queue-6.1/usb-xhci-fix-td-invalidation-under-pending-set-tr-dequeue.patch
new file mode 100644 (file)
index 0000000..dc454de
--- /dev/null
@@ -0,0 +1,102 @@
+From 484c3bab2d5dfa13ff659a51a06e9a393141eefc Mon Sep 17 00:00:00 2001
+From: Michal Pecio <michal.pecio@gmail.com>
+Date: Wed, 6 Nov 2024 12:14:58 +0200
+Subject: usb: xhci: Fix TD invalidation under pending Set TR Dequeue
+
+From: Michal Pecio <michal.pecio@gmail.com>
+
+commit 484c3bab2d5dfa13ff659a51a06e9a393141eefc upstream.
+
+xhci_invalidate_cancelled_tds() may not work correctly if the hardware
+is modifying endpoint or stream contexts at the same time by executing
+a Set TR Dequeue command. And even if it worked, it would be unable to
+queue Set TR Dequeue for the next stream, failing to clear xHC cache.
+
+On stream endpoints, a chain of Set TR Dequeue commands may take some
+time to execute and we may want to cancel more TDs during this time.
+Currently this leads to Stop Endpoint completion handler calling this
+function without testing for SET_DEQ_PENDING, which will trigger the
+aforementioned problems when it happens.
+
+On all endpoints, a halt condition causes Reset Endpoint to be queued
+and an error status given to the class driver, which may unlink more
+URBs in response. Stop Endpoint is queued and its handler may execute
+concurrently with Set TR Dequeue queued by Reset Endpoint handler.
+
+(Reset Endpoint handler calls this function too, but there seems to
+be no possibility of it running concurrently with Set TR Dequeue).
+
+Fix xhci_invalidate_cancelled_tds() to work correctly under a pending
+Set TR Dequeue. Bail out of the function when SET_DEQ_PENDING is set,
+then make the completion handler call the function again and also call
+xhci_giveback_invalidated_tds(), which needs to be called next.
+
+This seems to fix another potential bug, where the handler would call
+xhci_invalidate_cancelled_tds(), which may clear some deferred TDs if
+a sanity check fails, and the TDs wouldn't be given back promptly.
+
+Said sanity check seems to be wrong and prone to false positives when
+the endpoint halts, but fixing it is beyond the scope of this change,
+besides ensuring that cleared TDs are given back properly.
+
+Fixes: 5ceac4402f5d ("xhci: Handle TD clearing for multiple streams case")
+CC: stable@vger.kernel.org
+Signed-off-by: Michal Pecio <michal.pecio@gmail.com>
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20241106101459.775897-33-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/host/xhci-ring.c |   18 +++++++++++++-----
+ 1 file changed, 13 insertions(+), 5 deletions(-)
+
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -954,6 +954,13 @@ static int xhci_invalidate_cancelled_tds
+       unsigned int            slot_id = ep->vdev->slot_id;
+       int                     err;
++      /*
++       * This is not going to work if the hardware is changing its dequeue
++       * pointers as we look at them. Completion handler will call us later.
++       */
++      if (ep->ep_state & SET_DEQ_PENDING)
++              return 0;
++
+       xhci = ep->xhci;
+       list_for_each_entry_safe(td, tmp_td, &ep->cancelled_td_list, cancelled_td_list) {
+@@ -1324,7 +1331,6 @@ static void xhci_handle_cmd_set_deq(stru
+       struct xhci_ep_ctx *ep_ctx;
+       struct xhci_slot_ctx *slot_ctx;
+       struct xhci_td *td, *tmp_td;
+-      bool deferred = false;
+       ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3]));
+       stream_id = TRB_TO_STREAM_ID(le32_to_cpu(trb->generic.field[2]));
+@@ -1425,8 +1431,6 @@ static void xhci_handle_cmd_set_deq(stru
+                       xhci_dbg(ep->xhci, "%s: Giveback cancelled URB %p TD\n",
+                                __func__, td->urb);
+                       xhci_td_cleanup(ep->xhci, td, ep_ring, td->status);
+-              } else if (td->cancel_status == TD_CLEARING_CACHE_DEFERRED) {
+-                      deferred = true;
+               } else {
+                       xhci_dbg(ep->xhci, "%s: Keep cancelled URB %p TD as cancel_status is %d\n",
+                                __func__, td->urb, td->cancel_status);
+@@ -1437,11 +1441,15 @@ cleanup:
+       ep->queued_deq_seg = NULL;
+       ep->queued_deq_ptr = NULL;
+-      if (deferred) {
+-              /* We have more streams to clear */
++      /* Check for deferred or newly cancelled TDs */
++      if (!list_empty(&ep->cancelled_td_list)) {
+               xhci_dbg(ep->xhci, "%s: Pending TDs to clear, continuing with invalidation\n",
+                        __func__);
+               xhci_invalidate_cancelled_tds(ep);
++              /* Try to restart the endpoint if all is done */
++              ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
++              /* Start giving back any TDs invalidated above */
++              xhci_giveback_invalidated_tds(ep);
+       } else {
+               /* Restart any rings with pending URBs */
+               xhci_dbg(ep->xhci, "%s: All TDs cleared, ring doorbell\n", __func__);