All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mario Limonciello <superm1@kernel.org>
To: juan.martinez@amd.com, mika.westerberg@linux.intel.com
Cc: westeri@kernel.org, andreas.noever@gmail.com,
	YehezkelShB@gmail.com, Basavaraj.Natikar@amd.com,
	Sanath.S@amd.com, linux-usb@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH v5] thunderbolt: Fix tb->lock deadlock during hot-unplug on AMD USB4 routers
Date: Tue, 1 Sep 2026 17:16:03 -0500	[thread overview]
Message-ID: <ae19d381-0fcd-45fb-9e53-033c7d664d73@kernel.org> (raw)
In-Reply-To: <20260831161610.1322731-1-juan.martinez@amd.com>



On 8/31/26 11:16, juan.martinez@amd.com wrote:
> From: Juan Martinez <juan.martinez@amd.com>
> 
> Commit f1de1fc5f632 ("thunderbolt: Add quirk to reset host interface on
> DMA path teardown for AMD USB4 routers") introduced a deadlock when
> physically unplugging a Thunderbolt cable on AMD systems.
> 
> The problem occurs because tb_handle_hotplug() holds tb->lock while
> processing the unplug event. When it removes the XDomain services,
> tbnet_remove() calls tb_xdomain_disable_paths() which eventually calls
> tb_domain_reset_interface(). That function tries to acquire tb->lock
> via guard(mutex), but the hotplug worker already holds it, causing a
> self-deadlock.
> 
> The deadlock manifests as a complete network hang because
> tb_handle_hotplug() holds RTNL while waiting on its own mutex, blocking
> all network operations system-wide.
> 
> The existing code already handles this scenario partially: when
> xd->is_unplugged is true, tb_disconnect_xdomain_paths() intentionally
> skips the DMA teardown because the hotplug handler tears down the DMA
> tunnels itself. However, the reset was still being called
> unconditionally.
> 
> Fix this by splitting tb_domain_reset_interface() into a locked inner
> function and a locking wrapper. Skip the reset from
> tb_domain_disconnect_xdomain_paths() when xd->is_unplugged is true, and
> instead reset the interface after the hotplug handler tears down the DMA
> tunnel while already holding tb->lock.
> 
> Handle both unplug topologies: reset after the direct XDomain teardown,
> and after invalid DMA tunnels are removed when an upstream router and its
> downstream XDomain are unplugged together.
> 
> This preserves the reset behavior for normal shutdown paths while
> avoiding the deadlock during physical cable unplug.
> 
> Fixes: f1de1fc5f632 ("thunderbolt: Add quirk to reset host interface on DMA path teardown for AMD USB4 routers")
> Signed-off-by: Juan Martinez <juan.martinez@amd.com>

Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>

BTW -

I did take a look through the Sashiko feedback and the first point 
doesn't matter because no pre-USB4 hosts take this quirk.

The second point is a side effect of this reset and accepted behavior.

> ---
> 
> Notes (v5):
>      Changes in v5:
>      - Rebase on the current thunderbolt/next branch.
>      - Reset the host interface after invalid DMA tunnels are removed, covering
>        XDomains below an unplugged router.
> 
>   drivers/thunderbolt/domain.c | 20 +++++++++++++++++---
>   drivers/thunderbolt/tb.c     | 10 +++++++++-
>   drivers/thunderbolt/tb.h     |  1 +
>   3 files changed, 27 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c
> index 12c88509a54f..4cef9f4de523 100644
> --- a/drivers/thunderbolt/domain.c
> +++ b/drivers/thunderbolt/domain.c
> @@ -788,14 +788,22 @@ int tb_domain_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
>   			transmit_ring, receive_path, receive_ring);
>   }
>   
> -static void tb_domain_reset_interface(struct tb *tb)
> +/*
> + * __tb_domain_reset_interface_locked - Reset host interface (lock held)
> + *
> + * Caller must hold tb->lock. Used by hotplug path where lock is already held.
> + */
> +void __tb_domain_reset_interface_locked(struct tb *tb)
>   {
>   	struct tb_nhi *nhi = tb->nhi;
>   
> +	lockdep_assert_held(&tb->lock);
> +
>   	if (!nhi->ops->reset_interface)
>   		return;
>   
> -	guard(mutex)(&tb->lock);
> +	if (!(nhi->quirks & QUIRK_RESET_DMA_ON_TEARDOWN))
> +		return;
>   
>   	/* The reset clears the ring state so stop the control channel */
>   	tb_ctl_stop(tb->ctl);
> @@ -803,6 +811,12 @@ static void tb_domain_reset_interface(struct tb *tb)
>   	tb_ctl_start(tb->ctl);
>   }
>   
> +static void tb_domain_reset_interface(struct tb *tb)
> +{
> +	guard(mutex)(&tb->lock);
> +	__tb_domain_reset_interface_locked(tb);
> +}
> +
>   /**
>    * tb_domain_disconnect_xdomain_paths() - Disable DMA paths for XDomain
>    * @tb: Domain disabling the DMA paths
> @@ -835,7 +849,7 @@ int tb_domain_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
>   	if (ret)
>   		return ret;
>   
> -	if (tb->nhi->quirks & QUIRK_RESET_DMA_ON_TEARDOWN)
> +	if (!xd->is_unplugged)
>   		tb_domain_reset_interface(tb);
>   
>   	return 0;
> diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
> index 47753a5c0f2e..9300cdae10b1 100644
> --- a/drivers/thunderbolt/tb.c
> +++ b/drivers/thunderbolt/tb.c
> @@ -1776,12 +1776,19 @@ static void tb_free_invalid_tunnels(struct tb *tb)
>   {
>   	struct tb_cm *tcm = tb_priv(tb);
>   	struct tb_tunnel *tunnel;
> +	bool reset = false;
>   	struct tb_tunnel *n;
>   
>   	list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) {
> -		if (tb_tunnel_is_invalid(tunnel))
> +		if (tb_tunnel_is_invalid(tunnel)) {
> +			if (tb_tunnel_is_dma(tunnel))
> +				reset = true;
>   			tb_deactivate_and_free_tunnel(tunnel);
> +		}
>   	}
> +
> +	if (reset)
> +		__tb_domain_reset_interface_locked(tb);
>   }
>   
>   /*
> @@ -2489,6 +2496,7 @@ static void tb_handle_hotplug(struct work_struct *work)
>   			tb_xdomain_remove(xd);
>   			port->xdomain = NULL;
>   			__tb_disconnect_xdomain_paths(tb, xd, -1, -1, -1, -1);
> +			__tb_domain_reset_interface_locked(tb);
>   			tb_xdomain_put(xd);
>   			tb_port_unconfigure_xdomain(port);
>   		} else if (tb_port_is_dpout(port) || tb_port_is_dpin(port)) {
> diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
> index c112954ce3fd..5bb448a71407 100644
> --- a/drivers/thunderbolt/tb.h
> +++ b/drivers/thunderbolt/tb.h
> @@ -792,6 +792,7 @@ int tb_domain_disconnect_pcie_paths(struct tb *tb);
>   int tb_domain_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
>   				    int transmit_path, int transmit_ring,
>   				    int receive_path, int receive_ring);
> +void __tb_domain_reset_interface_locked(struct tb *tb);
>   int tb_domain_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
>   				       int transmit_path, int transmit_ring,
>   				       int receive_path, int receive_ring);
> 
> base-commit: 48e989e33b715611438ce4b8d6ff712d4becd84f


  reply	other threads:[~2026-09-01 22:16 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-25 21:42 [PATCH v2] thunderbolt: Fix tb->lock deadlock during hot-unplug on AMD USB4 routers juan.martinez
2026-08-26  3:02 ` Mario Limonciello
2026-08-27 21:57 ` [PATCH v3] " Juan Martinez
2026-08-28  4:43   ` Mario Limonciello
2026-08-28  5:19   ` [PATCH v4] " Juan Martinez
2026-08-28 14:58     ` Mario Limonciello
2026-08-31 11:11     ` Mika Westerberg
2026-08-31 12:55       ` Mario Limonciello
2026-08-31 13:06         ` Mika Westerberg
2026-08-31 13:07           ` Mario Limonciello
2026-08-31 16:16           ` [PATCH v5] " juan.martinez
2026-09-01 22:16             ` Mario Limonciello [this message]
2026-09-02  5:48               ` Mika Westerberg
2026-09-09 19:06                 ` Mario Limonciello
2026-09-10 14:19                   ` S, Sanath
2026-09-10 17:24                     ` Mario Limonciello

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=ae19d381-0fcd-45fb-9e53-033c7d664d73@kernel.org \
    --to=superm1@kernel.org \
    --cc=Basavaraj.Natikar@amd.com \
    --cc=Sanath.S@amd.com \
    --cc=YehezkelShB@gmail.com \
    --cc=andreas.noever@gmail.com \
    --cc=juan.martinez@amd.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=mika.westerberg@linux.intel.com \
    --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 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.