[PATCH 4/4] thunderbolt: prevent pcie tunnel activation/teardown warnings

Chunfeng Yun (云春峰) Chunfeng.Yun at mediatek.com
Tue Nov 3 00:33:51 PST 2026


On Fri, 2026-10-30 at 09:56 +0100, Mika Westerberg wrote:
> On Fri, Oct 30, 2026 at 04:25:39PM +0800, Chunfeng Yun wrote:
> > When usb4 enter sleep mode, echo 1 to authorized of sysfile,
> > will wakeup usb4 driver, but fail to create pcie tunnel, cause
> > the warning due to a race condition between switch disconnect
> 
> It's router
will modify it.

> 
> > during resume and user authorization
[  278.831186] usb4_hi NVDA8100:00: 0:1: is unplugged (state: 7),
retrying...
[  278.943031] usb4_hi NVDA8100:00: 0:1: failed to reach state
TB_PORT_UP. Ignoring port...
[  278.951125] usb4_hi NVDA8100:00: 0:1: lost during suspend,
disconnecting
[  278.957819] usb4_hi NVDA8100:00: 0:4 <-> 1:16 (USB3): deactivating
[  278.964794] usb4_hi NVDA8100:00: deactivating USB3 Down path from
0:4 to 1:16
[  278.972737] usb4_hi NVDA8100:00: deactivating USB3 Up path from 1:16
to 0:4
[  278.980504] usb4_hi NVDA8100:00: 0: TMU: mode change off -> bi-
directional, HiFi requested
[  278.991265] usb4_hi NVDA8100:00: 0: TMU: mode set to: bi-
directional, HiFi
[  278.999511] usb4_hi NVDA8100:00: 0:1: total credits changed 66 -> 66
[  279.006408] usb4_hi NVDA8100:00: 1: link width set to symmetric,
dual lanes
[  279.013763] usb4_hi NVDA8100:00: 0:7 <-> 1:9 (PCI): activating
[  279.019587] usb4_hi NVDA8100:00: activating PCIe Down path from 0:7
to 1:9
[  279.026468] usb4_hi NVDA8100:00: 1:1: Writing hop 1
[  279.031335] usb4_hi NVDA8100:00: 1:1:  In HopID: 8 => Out port: 9
Out HopID: 8
[  279.038546] usb4_hi NVDA8100:00: 1:1:   Weight: 1 Priority: 3
Credits: 32 Drop: 0 PM: 0
[  279.046536] usb4_hi NVDA8100:00: 1:1:    Counter enabled: 0 Counter
index: 2047
[  279.053834] usb4_hi NVDA8100:00: 1:1:   Flow Control (In/Eg): 1/0
Shared Buffer (In/Eg): 0/0
[  279.062259] usb4_hi NVDA8100:00: 1:1:   Unknown1: 0x0 Unknown2: 0x0
Unknown3: 0x0
[  279.069730] ------------[ cut here ]------------
[  279.074335] usb4_hi NVDA8100:00: PCIe Down path activation failed
[  279.080426] WARNING: CPU: 5 PID: 2433 at
drivers/thunderbolt/path.c:587 tb_path_activate+0x1a4/0x5b0
...
[  279.220285] Call trace:
[  279.222722]  tb_path_activate+0x1a4/0x5b0 (P)
[  279.227068]  tb_tunnel_activate+0x140/0x498
[  279.231241]  tb_tunnel_pci+0x180/0x490
[  279.234980]  tb_domain_approve_switch+0x74/0xb0
[  279.239500]  authorized_store+0x214/0x270
[  279.243498]  dev_attr_store+0x20/0x70
...
[  279.288888] ---[ end trace 0000000000000000 ]---
[  279.293497] usb4_hi NVDA8100:00: 0:7 <-> 1:9 (PCI): activation
failed


root cause:

The warning were caused by a race condition between switch disconnect
during resume and user authorization:

   1. While the system was in runtime suspend, userspace executed:

       echo 1 > /sys/bus/thunderbolt/devices/0-1/authorized
   2. Writing to this sysfs attribute woke up the USB4 controller
(nhi_runtime_resume).
   3. During resume, the downstream port 0:1 failed to complete link
training within the timeout and was declared lost:

       [  278.943031] usb4_hi NVDA8100:00: 0:1: failed to reach state
TB_PORT_UP. Ignoring port...
       [  278.951125] usb4_hi NVDA8100:00: 0:1: lost during suspend,
disconnecting
     This called tb_sw_set_unplugged(port->remote->sw), setting sw-
>is_unplugged = true on switch 0-1.
   4. However, authorized_store() had already taken the lock and
proceeded to create the PCIe tunnel via tb_tunnel_pci() ->
tb_tunnel_activate() -> tb_path_activate().
   5. When tb_path_activate() tried to program routing Hop 1 into port
1:1 of switch 0-1, tb_port_write() refused because the switch was
marked unplugged:

       /* include/linux/thunderbolt.h / tb.h */
       static inline int tb_port_write(...) {
           if (port->sw->is_unplugged)
               return -ENODEV;  /* Returns -19 (0xffffffed) */
           ...
       }
   6. Because tb_port_write() returned -ENODEV, tb_path_activate()
bailed out to err: and triggered the kernel warning:

       /* drivers/thunderbolt/path.c:587 */
       err:
           tb_WARN(path->tb, "%s path activation failed\n", path-
>name);
           return res;

     Userspace received -EIO (-bash: echo: write error: Input/output
error).


> 
> > 
> > When usb4 enter sleep mode, echo 0 to authorized of sysfile,
> > will wakeup usb4 driver, but fail to disconnect pcie due to
> > the PCIe tunnel had already been torn down and freed if the port
> > is fail to resume:
> 
> So this is runtime resume when there is no PCIe tunnel yet, 
It is already destroyed before due to the lane link timeout

> the device is
> unplugged and the userspace is at the same time writing to the
> "authorized"
> attribute? 
[  545.887822] usb4_hi NVDA8100:00: 0:1: is unplugged (state: 7),
retrying...
[  545.998689] usb4_hi NVDA8100:00: 0:1: failed to reach state
TB_PORT_UP. Ignoring port...
[  546.006778] usb4_hi NVDA8100:00: 0:1: lost during suspend,
disconnecting
[  546.013474] usb4_hi NVDA8100:00: 0:4 <-> 1:16 (USB3): deactivating
[  546.020449] usb4_hi NVDA8100:00: deactivating USB3 Down path from
0:4 to 1:16
[  546.027959] usb4_hi NVDA8100:00: deactivating USB3 Up path from 1:16
to 0:4
[  546.035649] usb4_hi NVDA8100:00: 0:7 <-> 1:9 (PCI): deactivating
[  546.042463] usb4_hi NVDA8100:00: deactivating PCIe Down path from
0:7 to 1:9
[  546.050320] usb4_hi NVDA8100:00: deactivating PCIe Up path from 1:9
to 0:7
[  546.057790] usb4_hi NVDA8100:00: 0: TMU: mode change off -> bi-
directional, HiFi requested
[  546.067910] usb4_hi NVDA8100:00: 0: TMU: mode set to: bi-
directional, HiFi
[  546.076120] usb4_hi NVDA8100:00: 0:1: total credits changed 66 -> 66
[  546.082844] usb4_hi NVDA8100:00: 1: link width set to symmetric,
dual lanes
[  546.089815] ------------[ cut here ]------------
[  546.094420] WARNING: CPU: 7 PID: 2433 at
drivers/thunderbolt/tb.c:2245 tb_disconnect_pci+0x108/0x120
...
[  546.238810] Call trace:
[  546.241246]  tb_disconnect_pci+0x108/0x120 (P)
[  546.245680]  tb_domain_disapprove_switch+0x24/0x60
[  546.250464]  disapprove_switch+0xbc/0xe8
[  546.254378]  authorized_store+0x19c/0x270
[  546.258378]  dev_attr_store+0x20/0x70
...
[  546.303767] ---[ end trace 0000000000000000 ]---

root cause:
  The warning occurred because the PCIe tunnel had already been torn
down and freed by tb_free_invalid_tunnels() just milliseconds before
tb_disconnect_pci() was called,

  tb_disconnect_pci() assumes that if userspace writes 0 to authorized
on an authorized switch, the corresponding PCIe tunnel must still exist
in tcm->tunnel_list. However, in this scenario, the tunnel was already
destroyed during the wake-up sequence, leaving tunnel == NULL.


> 
> Then the PCIe tunnel creation fails as expected.
> 
> What warning you are trying to silence?
if we find the router is disconnect, no need find the PCIe tunnel
anymore.

Thanks

> 
> > 
> > The check prevents a redundant lookup and eliminates the warning
> > 
> > Signed-off-by: Chunfeng Yun <chunfeng.yun at mediatek.com>
> > ---
> >  drivers/thunderbolt/switch.c | 5 +++++
> >  drivers/thunderbolt/tb.c     | 7 +++++++
> >  2 files changed, 12 insertions(+)
> > 
> > diff --git a/drivers/thunderbolt/switch.c
> > b/drivers/thunderbolt/switch.c
> > index e7ee9639c54c..7902172f4e99 100644
> > --- a/drivers/thunderbolt/switch.c
> > +++ b/drivers/thunderbolt/switch.c
> > @@ -1849,6 +1849,11 @@ static int tb_switch_set_authorized(struct
> > tb_switch *sw, unsigned int val)
> >  	if (!!sw->authorized == !!val)
> >  		goto unlock;
> >  
> > +	if (sw->is_unplugged) {
> > +		ret = -ENODEV;
> > +		goto unlock;
> > +	}
> > +
> >  	switch (val) {
> >  	/* Disapprove switch */
> >  	case 0:
> > diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
> > index 57c11ba13459..69310622d786 100644
> > --- a/drivers/thunderbolt/tb.c
> > +++ b/drivers/thunderbolt/tb.c
> > @@ -2266,6 +2266,10 @@ static int tb_disconnect_pci(struct tb *tb,
> > struct tb_switch *sw)
> >  	struct tb_tunnel *tunnel;
> >  	struct tb_port *up;
> >  
> > +	/* If the switch has already been unplugged, tunnels are
> > already freed */
> > +	if (sw->is_unplugged)
> > +		return 0;
> > +
> >  	up = tb_switch_find_port(sw, TB_TYPE_PCIE_UP);
> >  	if (WARN_ON(!up))
> >  		return -ENODEV;
> > @@ -2288,6 +2292,9 @@ static int tb_tunnel_pci(struct tb *tb,
> > struct tb_switch *sw)
> >  	struct tb_cm *tcm = tb_priv(tb);
> >  	struct tb_tunnel *tunnel;
> >  
> > +	if (sw->is_unplugged)
> > +		return -ENODEV;
> > +
> >  	up = tb_switch_find_port(sw, TB_TYPE_PCIE_UP);
> >  	if (!up)
> >  		return 0;
> > -- 
> > 2.43.0



More information about the linux-arm-kernel mailing list