From 3c1f00db028e9a4c246a3f0113f8d9a3b36f7b2b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 3 Dec 2024 09:21:30 +0100 Subject: [PATCH] 5.15-stable patches added patches: usb-xhci-fix-td-invalidation-under-pending-set-tr-dequeue.patch --- queue-5.15/series | 2 +- ...idation-under-pending-set-tr-dequeue.patch | 102 ++++++++++++++++++ 2 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 queue-5.15/usb-xhci-fix-td-invalidation-under-pending-set-tr-dequeue.patch diff --git a/queue-5.15/series b/queue-5.15/series index da73a6ba07f..12fdbbefde5 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -308,5 +308,5 @@ apparmor-test-fix-memory-leak-for-aa_unpack_strdup.patch tty-ldsic-fix-tty_ldisc_autoload-sysctl-s-proc_handler.patch locking-lockdep-avoid-creating-new-name-string-literals-in-lockdep_set_subclass.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-5.15/usb-xhci-fix-td-invalidation-under-pending-set-tr-dequeue.patch b/queue-5.15/usb-xhci-fix-td-invalidation-under-pending-set-tr-dequeue.patch new file mode 100644 index 00000000000..98e4114bd8b --- /dev/null +++ b/queue-5.15/usb-xhci-fix-td-invalidation-under-pending-set-tr-dequeue.patch @@ -0,0 +1,102 @@ +From 484c3bab2d5dfa13ff659a51a06e9a393141eefc Mon Sep 17 00:00:00 2001 +From: Michal Pecio +Date: Wed, 6 Nov 2024 12:14:58 +0200 +Subject: usb: xhci: Fix TD invalidation under pending Set TR Dequeue + +From: Michal Pecio + +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 +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20241106101459.775897-33-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -961,6 +961,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) { +@@ -1386,7 +1393,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])); +@@ -1487,8 +1493,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); +@@ -1499,11 +1503,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__); -- 2.47.3