From: Mathias Nyman <mathias.nyman@linux.intel.com>
To: <gregkh@linuxfoundation.org>
Cc: <linux-usb@vger.kernel.org>,
Michal Pecio <michal.pecio@gmail.com>,
Mathias Nyman <mathias.nyman@linux.intel.com>
Subject: [PATCH 10/23] usb: xhci: Don't unchain link TRBs on quirky HCs
Date: Wed, 19 Nov 2025 16:24:04 +0200 [thread overview]
Message-ID: <20251119142417.2820519-11-mathias.nyman@linux.intel.com> (raw)
In-Reply-To: <20251119142417.2820519-1-mathias.nyman@linux.intel.com>
From: Michal Pecio <michal.pecio@gmail.com>
Some old HCs ignore transfer ring link TRBs whose chain bit is unset.
This breaks endpoint operation and sometimes makes it execute other
ring's TDs, which may corrupt their buffers or cause unwanted device
action. We avoid this by chaining all link TRBs on affected rings.
Fix an omission which allows them to be unchained by cancelling TDs.
The patch was tested by reproducing this condition on an isochronous
endpoint (non-power-of-two TDs are sometimes split not to cross 64K)
and printing link TRBs in trb_to_noop() on good and buggy HCs.
Actual hardware malfunction is rare since it requires Missed Service
Error shortly before the unchained link TRB, at least on NEC and AMD.
I have never seen it after commit bb0ba4cb1065 ("usb: xhci: Apply the
link chain quirk on NEC isoc endpoints"), but it's Russian roulette
and I can't test all affected hosts and workloads. Fairly often MSEs
happen after cancellation because the endpoint was stopped.
Signed-off-by: Michal Pecio <michal.pecio@gmail.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-ring.c | 27 ++++++++++++++++-----------
1 file changed, 16 insertions(+), 11 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 95005f9a3504..5acec9143811 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -145,11 +145,11 @@ static void inc_td_cnt(struct urb *urb)
urb_priv->num_tds_done++;
}
-static void trb_to_noop(union xhci_trb *trb, u32 noop_type)
+static void trb_to_noop(union xhci_trb *trb, u32 noop_type, bool unchain_links)
{
if (trb_is_link(trb)) {
- /* unchain chained link TRBs */
- trb->link.control &= cpu_to_le32(~TRB_CHAIN);
+ if (unchain_links)
+ trb->link.control &= cpu_to_le32(~TRB_CHAIN);
} else {
trb->generic.field[0] = 0;
trb->generic.field[1] = 0;
@@ -466,7 +466,7 @@ static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci,
xhci_dbg(xhci, "Turn aborted command %p to no-op\n",
i_cmd->command_trb);
- trb_to_noop(i_cmd->command_trb, TRB_CMD_NOOP);
+ trb_to_noop(i_cmd->command_trb, TRB_CMD_NOOP, false);
/*
* caller waiting for completion is called when command
@@ -798,13 +798,18 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci,
* (The last TRB actually points to the ring enqueue pointer, which is not part
* of this TD.) This is used to remove partially enqueued isoc TDs from a ring.
*/
-static void td_to_noop(struct xhci_td *td, bool flip_cycle)
+static void td_to_noop(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
+ struct xhci_td *td, bool flip_cycle)
{
+ bool unchain_links;
struct xhci_segment *seg = td->start_seg;
union xhci_trb *trb = td->start_trb;
+ /* link TRBs should now be unchained, but some old HCs expect otherwise */
+ unchain_links = !xhci_link_chain_quirk(xhci, ep->ring ? ep->ring->type : TYPE_STREAM);
+
while (1) {
- trb_to_noop(trb, TRB_TR_NOOP);
+ trb_to_noop(trb, TRB_TR_NOOP, unchain_links);
/* flip cycle if asked to */
if (flip_cycle && trb != td->start_trb && trb != td->end_trb)
@@ -1092,16 +1097,16 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep)
"Found multiple active URBs %p and %p in stream %u?\n",
td->urb, cached_td->urb,
td->urb->stream_id);
- td_to_noop(cached_td, false);
+ td_to_noop(xhci, ep, cached_td, false);
cached_td->cancel_status = TD_CLEARED;
}
- td_to_noop(td, false);
+ td_to_noop(xhci, ep, td, false);
td->cancel_status = TD_CLEARING_CACHE;
cached_td = td;
break;
}
} else {
- td_to_noop(td, false);
+ td_to_noop(xhci, ep, td, false);
td->cancel_status = TD_CLEARED;
}
}
@@ -1126,7 +1131,7 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep)
continue;
xhci_warn(xhci, "Failed to clear cancelled cached URB %p, mark clear anyway\n",
td->urb);
- td_to_noop(td, false);
+ td_to_noop(xhci, ep, td, false);
td->cancel_status = TD_CLEARED;
}
}
@@ -4241,7 +4246,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
*/
urb_priv->td[0].end_trb = ep_ring->enqueue;
/* Every TRB except the first & last will have its cycle bit flipped. */
- td_to_noop(&urb_priv->td[0], true);
+ td_to_noop(xhci, xep, &urb_priv->td[0], true);
/* Reset the ring enqueue back to the first TRB and its cycle bit. */
ep_ring->enqueue = urb_priv->td[0].start_trb;
--
2.43.0
next prev parent reply other threads:[~2025-11-19 14:24 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-19 14:23 [PATCH 00/23] xhci features for usb-next Mathias Nyman
2025-11-19 14:23 ` [PATCH 01/23] usb: xhci: limit run_graceperiod for only usb 3.0 devices Mathias Nyman
2025-11-19 14:23 ` [PATCH 02/23] xhci: Add helper to find trb from its dma address Mathias Nyman
2025-11-19 14:23 ` [PATCH 03/23] xhci: simplify and rework trb_in_td() Mathias Nyman
2025-11-19 14:23 ` [PATCH 04/23] usb: xhci: rework xhci_decode_portsc() Mathias Nyman
2025-11-19 14:23 ` [PATCH 05/23] usb: xhci: add tracing for PORTSC register writes Mathias Nyman
2025-11-19 14:24 ` [PATCH 06/23] usb: xhci: add helper to read PORTSC register Mathias Nyman
2025-11-19 14:24 ` [PATCH 07/23] usb: xhci: add USB Port Register Set struct Mathias Nyman
2025-11-19 14:24 ` [PATCH 08/23] usb: xhci: implement " Mathias Nyman
2025-11-19 14:24 ` [PATCH 09/23] usb: xhci: Assume that endpoints halt as specified Mathias Nyman
2025-11-19 14:24 ` Mathias Nyman [this message]
2025-11-19 14:24 ` [PATCH 11/23] usb: xhci: replace use of system_wq with system_percpu_wq Mathias Nyman
2025-11-19 14:24 ` [PATCH 12/23] usb: xhci: remove deprecated TODO comment Mathias Nyman
2025-11-19 14:24 ` [PATCH 13/23] usb: xhci: remove unused trace operation and argument Mathias Nyman
2025-11-19 14:24 ` [PATCH 14/23] usb: xhci: use cached HCSPARAMS1 value Mathias Nyman
2025-11-19 14:24 ` [PATCH 15/23] usb: xhci: simplify handling of Structural Parameters 1 values Mathias Nyman
2025-11-19 14:24 ` [PATCH 16/23] usb: xhci: limit number of ports to 127 Mathias Nyman
2025-11-19 14:24 ` [PATCH 17/23] usb: xhci: limit number of interrupts to 128 Mathias Nyman
2025-11-19 14:24 ` [PATCH 18/23] usb: xhci: improve xhci-caps.h comments Mathias Nyman
2025-11-19 14:24 ` [PATCH 19/23] usb: xhci: simplify Isochronous Scheduling Threshold handling Mathias Nyman
2025-11-19 14:24 ` [PATCH 20/23] usb: xhci: simplify Max Scratchpad buffer macros Mathias Nyman
2025-11-19 14:24 ` [PATCH 21/23] usb: xhci: drop xhci-caps.h dependence on xhci-ext-caps.h Mathias Nyman
2025-11-19 14:24 ` [PATCH 22/23] usb: xhci: standardize single bit-field macros Mathias Nyman
2025-11-19 14:24 ` [PATCH 23/23] usb: xhci: Add debugfs support for xHCI Port Link Info (PORTLI) register Mathias Nyman
2026-03-04 9:42 ` Michal Pecio
2026-03-04 14:25 ` Mathias Nyman
2026-03-04 16:40 ` Michal Pecio
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251119142417.2820519-11-mathias.nyman@linux.intel.com \
--to=mathias.nyman@linux.intel.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-usb@vger.kernel.org \
--cc=michal.pecio@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.