From: Mika Westerberg <mika.westerberg@linux.intel.com>
To: fy15309206903@gmail.com
Cc: Andreas Noever <andreas.noever@gmail.com>,
Mika Westerberg <westeri@kernel.org>,
Yehezkel Bernat <YehezkelShB@gmail.com>,
linux-usb@vger.kernel.org
Subject: Re: [PATCH v2] thunderbolt: Stop waiting on a path pending bit that never clears
Date: Wed, 12 Aug 2026 06:46:36 +0200 [thread overview]
Message-ID: <20260812044636.GL893316@black.igk.intel.com> (raw)
In-Reply-To: <20260812-b4-tb-pending-v2-v2-1-0667ee84c2d4@gmail.com>
Hi,
On Wed, Aug 12, 2026 at 01:21:52AM +0000, Fan Ye via B4 Relay wrote:
> From: Fan Ye <fy15309206903@gmail.com>
>
> __tb_path_deactivate_hop() waits up to 500 ms for a hop's pending bit to
> read back clear. On an ASMedia ASM4242 host router the host interface
> adapter latches it once enough frames have gone through the DMA ring and
> never clears it again: the teardown finds it already set, seconds after
> the last frame and with the path still up. USB4 v2 table 8-23 has the
> field read only and zero unless packets belonging to the path are waiting
> to be dequeued, so the wait is right and this adapter is not.
>
> Quirk those routers by hardware id and let a quirked adapter that has
> timed out once answer -ETIMEDOUT immediately from then on. Bringing the
> interface down then took 8 ms across 200 cycles, where unpatched it took
> 508 ms in 161 of 162, at an unchanged failure rate of about one per
> cycle.
>
> Assisted-by: Claude:claude-opus-5
> Signed-off-by: Fan Ye <fy15309206903@gmail.com>
> ---
> Measured on two ASM4242 hosts wired to each other, hw_vendor_id 0x174c,
> hw_device_id 0x2428, NVM 200011.250708, on a base that already carries
> 68bf02b6b4ad.
I suppose there is not errata about this?
> Read before the teardown writes anything, path still up and the ring idle
> for seconds: at 200 frames it is clear in 5 of 5 rounds and the hop drains
> on the first read, at 260 it is set in 5 of 5 and the wait runs out. So it
> is set before the teardown starts rather than by it, and the clear case is
> why the flag is learned rather than taken from the quirk alone.
>
> 5.4.1 has a connection manager wait tTeardown after the router sets the
> bit to 0b before making the path valid again. On an adapter where it
> never reads 0b there is no such point, patched or not.
>
> v2:
> - Add the Assisted-by tag.
> - Answer the spec question from USB4 v2 table 8-23.
> - Return -ETIMEDOUT instead of 0; gate the flag on a 0x174c/0x2428 quirk.
> - Drop the ring-wrap claim.
> - Cut the text down.
>
> v1: https://lore.kernel.org/linux-usb/20260809-b4-tb-teardown-v1-2-c88bbfe5c127@gmail.com/
> ---
> drivers/thunderbolt/path.c | 8 ++++++++
> drivers/thunderbolt/quirks.c | 8 ++++++++
> drivers/thunderbolt/tb.h | 4 ++++
> 3 files changed, 20 insertions(+)
>
> diff --git a/drivers/thunderbolt/path.c b/drivers/thunderbolt/path.c
> index b2c322e76b8a..5cf87b8af2b2 100644
> --- a/drivers/thunderbolt/path.c
> +++ b/drivers/thunderbolt/path.c
> @@ -397,6 +397,10 @@ static int __tb_path_deactivate_hop(struct tb_port *port, int hop_index,
> if (ret)
> return ret;
>
> + /* It never clears on this adapter, so the wait would time out again. */
> + if (port->pending_stuck)
> + return -ETIMEDOUT;
Instead of this, let's do it so that you introduce port->pp_timeout_msec
that gets initialized with 500. In the quirk_stuck_pending() you check for
the NHI adapter and then set that to 0. Here you just check that field and
if it is 0 then skip the wait.
I think that would be more "future" proof in case there will be other
issues like this on various vendor's adapters.
> +
> /* Wait until it is drained */
> timeout = ktime_add_ms(ktime_get(), 500);
> do {
> @@ -430,6 +434,10 @@ static int __tb_path_deactivate_hop(struct tb_port *port, int hop_index,
> usleep_range(10, 20);
> } while (ktime_before(ktime_get(), timeout));
>
> + /* Remember it only on an adapter known to latch it. */
> + if (tb_port_is_nhi(port) && (port->sw->quirks & QUIRK_STUCK_PENDING))
> + port->pending_stuck = true;
> +
> return -ETIMEDOUT;
> }
>
> diff --git a/drivers/thunderbolt/quirks.c b/drivers/thunderbolt/quirks.c
> index 9f7914ac2f48..6ec90a85bbaf 100644
> --- a/drivers/thunderbolt/quirks.c
> +++ b/drivers/thunderbolt/quirks.c
> @@ -52,6 +52,12 @@ static void quirk_block_rpm_in_redrive(struct tb_switch *sw)
> tb_sw_dbg(sw, "preventing runtime PM in DP redrive mode\n");
> }
>
> +static void quirk_stuck_pending(struct tb_switch *sw)
> +{
> + sw->quirks |= QUIRK_STUCK_PENDING;
> + tb_sw_dbg(sw, "host interface adapter pending bit does not clear\n");
> +}
> +
> struct tb_quirk {
> u16 hw_vendor_id;
> u16 hw_device_id;
> @@ -114,6 +120,8 @@ static const struct tb_quirk tb_quirks[] = {
> { 0x0438, 0x0209, 0x0000, 0x0000, quirk_clx_disable },
> { 0x0438, 0x020a, 0x0000, 0x0000, quirk_clx_disable },
> { 0x0438, 0x020b, 0x0000, 0x0000, quirk_clx_disable },
> + /* ASM4242 never clears the Pending Packets bit of its NHI adapter */
> + { 0x174c, 0x2428, 0x0000, 0x0000, quirk_stuck_pending },
> };
>
> /**
> diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
> index ec9192b61bc0..00eb8d85755a 100644
> --- a/drivers/thunderbolt/tb.h
> +++ b/drivers/thunderbolt/tb.h
> @@ -26,6 +26,8 @@
> #define QUIRK_NO_CLX BIT(1)
> /* Need to keep power on while USB4 port is in redrive mode */
> #define QUIRK_KEEP_POWER_IN_DP_REDRIVE BIT(2)
> +/* Pending Packets bit of the host interface adapter never clears */
> +#define QUIRK_STUCK_PENDING BIT(3)
>
> /**
> * struct tb_nvm - Structure holding NVM information
> @@ -273,6 +275,7 @@ struct tb_bandwidth_group {
> * @max_bw: Maximum possible bandwidth through this adapter if set to
> * non-zero.
> * @redrive: For DP IN, if true the adapter is in redrive mode.
> + * @pending_stuck: Pending bit did not clear, so it is not waited on again
> *
> * In USB4 terminology this structure represents an adapter (protocol or
> * lane adapter).
> @@ -302,6 +305,7 @@ struct tb_port {
> struct list_head group_list;
> unsigned int max_bw;
> bool redrive;
> + bool pending_stuck;
> };
>
> /**
>
> ---
> base-commit: f5bbbfec59b4e2fb7520a91de3df8a6174325d6a
> change-id: 20260812-b4-tb-pending-v2-78ebc7bb0f58
>
> Best regards,
> --
> Fan Ye <fy15309206903@gmail.com>
>
prev parent reply other threads:[~2026-08-12 4:46 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-12 1:21 [PATCH v2] thunderbolt: Stop waiting on a path pending bit that never clears Fan Ye via B4 Relay
2026-08-12 4:46 ` Mika Westerberg [this message]
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=20260812044636.GL893316@black.igk.intel.com \
--to=mika.westerberg@linux.intel.com \
--cc=YehezkelShB@gmail.com \
--cc=andreas.noever@gmail.com \
--cc=fy15309206903@gmail.com \
--cc=linux-usb@vger.kernel.org \
--cc=westeri@kernel.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox