[PATCH] thunderbolt: Reset downstream port after failed link restore
From: Amaan Lalani
Date: Sat Aug 29 2026 - 19:57:37 EST
A directly connected Thunderbolt device may fail to restore
its link after a runtime suspend, therefore leaving the connection
unusable.
Reset the downstream port when the link restoration fails. This drives
SBTX low, causing the partner to observe a USB4 disconnect and allowing
the Type-C/PD firmware to renegotiate the connection. For dual-mode
devices, this may allow the connection to fall back to native USB3.x.
Tested on a Microsoft Surface Pro 11 with a UGreen Thunderbolt
4 external NVMe enclosure, where the device successfully reconnects as a
USB3 device when the Thunderbolt 4 link fails to recover.
Signed-off-by: Amaan Lalani <zlzzm2014@xxxxxxxxxxx>
---
drivers/thunderbolt/switch.c | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index 404c0693df50..7b88aa75a07a 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -3600,7 +3600,27 @@ int tb_switch_resume(struct tb_switch *sw, bool runtime)
if (tb_wait_for_port(port, true) <= 0) {
tb_port_warn(port,
- "lost during suspend, disconnecting\n");
+ "lost during suspend, disconnecting\n");
+ /*
+ * If a directly connected USB4/thunderbolt device did not restore
+ * its link after a runtime suspend, assert a downstream
+ * port reset. This drives SBTX low and makes the partner
+ * observe a real USB4 disconnect. A dual-mode device and
+ * the Type-C/PD firmware will then try to renegotiate
+ * the connection in a native USB 3.x mode.
+ *
+ * Restrict this to the host router's downstream port.
+ * Resetting an intermediate router would not cause the Type-C
+ * to be renegotiated.
+ */
+ if (runtime && !tb_route(sw) &&
+ tb_switch_is_usb4(sw) && port->cap_usb4) {
+ err = tb_port_reset(port);
+ if (err)
+ tb_port_warn(port,
+ "failed to reset port for USB3 fallback: %d\n",
+ err);
+ }
if (tb_port_has_remote(port))
tb_sw_set_unplugged(port->remote->sw);
else if (port->xdomain)
--
2.55.0