* [PATCH] thunderbolt: Assert downstream port reset on shutdown @ 2026-06-03 18:01 Basavaraj Natikar 2026-06-03 19:02 ` Mario Limonciello 2026-06-04 5:03 ` Mika Westerberg 0 siblings, 2 replies; 10+ messages in thread From: Basavaraj Natikar @ 2026-06-03 18:01 UTC (permalink / raw) To: andreas.noever, westeri, YehezkelShB, linux-usb Cc: Basavaraj Natikar, Sanath S On shutdown the connection manager tears down the switch tree without signalling connected devices. Thunderbolt 3 devices directly connected to a USB4 host never receive a disconnect indication and during shutdown this can cause polling the dead link for up to 60 seconds. On some platforms this behavior leads to a warm reset instead of a shutdown due to this timeout. Fix this by asserting PORT_CS_19.DPR on each connected downstream port before tearing down the switch tree. This drives SBTX low unconditionally (USB4 spec section 6.9), causing the device to detect SBRX low and transition to Uninitialized Unplugged state immediately. Co-developed-by: Sanath S <Sanath.S@amd.com> Signed-off-by: Sanath S <Sanath.S@amd.com> Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com> --- drivers/thunderbolt/switch.c | 2 +- drivers/thunderbolt/tb.c | 11 +++++++++++ drivers/thunderbolt/tb.h | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index c2ad58b19e7b..52812908818b 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -704,7 +704,7 @@ int tb_port_disable(struct tb_port *port) return __tb_port_enable(port, false); } -static int tb_port_reset(struct tb_port *port) +int tb_port_reset(struct tb_port *port) { if (tb_switch_is_usb4(port->sw)) return port->cap_usb4 ? usb4_port_reset(port) : 0; diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index c69c323e6952..ca57b5181422 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -2935,6 +2935,7 @@ static void tb_stop(struct tb *tb) struct tb_cm *tcm = tb_priv(tb); struct tb_tunnel *tunnel; struct tb_tunnel *n; + struct tb_port *port; cancel_delayed_work(&tcm->remove_work); /* tunnels are only present after everything has been initialized */ @@ -2948,6 +2949,16 @@ static void tb_stop(struct tb *tb) tb_tunnel_deactivate(tunnel); tb_tunnel_put(tunnel); } + /* + * Assert DPR to drive SBTX low, signalling disconnect and avoiding + * ~60 s of link polling before warm reset on shutdown. + */ + tb_switch_for_each_port(tb->root_switch, port) { + if (!tb_port_is_null(port) || !tb_port_has_remote(port)) + continue; + if (tb_port_reset(port)) + tb_port_dbg(port, "DPR on shutdown failed, continuing\n"); + } tb_switch_remove(tb->root_switch); tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */ } diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h index 217c3114bec8..875eb538eacf 100644 --- a/drivers/thunderbolt/tb.h +++ b/drivers/thunderbolt/tb.h @@ -1102,6 +1102,7 @@ int tb_port_clear_counter(struct tb_port *port, int counter); int tb_port_unlock(struct tb_port *port); int tb_port_enable(struct tb_port *port); int tb_port_disable(struct tb_port *port); +int tb_port_reset(struct tb_port *port); int tb_port_alloc_in_hopid(struct tb_port *port, int hopid, int max_hopid); void tb_port_release_in_hopid(struct tb_port *port, int hopid); int tb_port_alloc_out_hopid(struct tb_port *port, int hopid, int max_hopid); -- 2.34.1 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH] thunderbolt: Assert downstream port reset on shutdown 2026-06-03 18:01 [PATCH] thunderbolt: Assert downstream port reset on shutdown Basavaraj Natikar @ 2026-06-03 19:02 ` Mario Limonciello 2026-06-04 5:03 ` Mika Westerberg 1 sibling, 0 replies; 10+ messages in thread From: Mario Limonciello @ 2026-06-03 19:02 UTC (permalink / raw) To: Basavaraj Natikar, andreas.noever, westeri, YehezkelShB, linux-usb Cc: Sanath S, Vivek Das Mohapatra, Kovacs, Alexander On 6/3/26 13:01, Basavaraj Natikar wrote: > On shutdown the connection manager tears down the switch tree without > signalling connected devices. Thunderbolt 3 devices directly connected > to a USB4 host never receive a disconnect indication and during shutdown > this can cause polling the dead link for up to 60 seconds. On some > platforms this behavior leads to a warm reset instead of a shutdown due > to this timeout. > > Fix this by asserting PORT_CS_19.DPR on each connected downstream port > before tearing down the switch tree. This drives SBTX low unconditionally > (USB4 spec section 6.9), causing the device to detect SBRX low and > transition to Uninitialized Unplugged state immediately. > > Co-developed-by: Sanath S <Sanath.S@amd.com> > Signed-off-by: Sanath S <Sanath.S@amd.com> > Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com> Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org> > --- > drivers/thunderbolt/switch.c | 2 +- > drivers/thunderbolt/tb.c | 11 +++++++++++ > drivers/thunderbolt/tb.h | 1 + > 3 files changed, 13 insertions(+), 1 deletion(-) > > diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c > index c2ad58b19e7b..52812908818b 100644 > --- a/drivers/thunderbolt/switch.c > +++ b/drivers/thunderbolt/switch.c > @@ -704,7 +704,7 @@ int tb_port_disable(struct tb_port *port) > return __tb_port_enable(port, false); > } > > -static int tb_port_reset(struct tb_port *port) > +int tb_port_reset(struct tb_port *port) > { > if (tb_switch_is_usb4(port->sw)) > return port->cap_usb4 ? usb4_port_reset(port) : 0; > diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c > index c69c323e6952..ca57b5181422 100644 > --- a/drivers/thunderbolt/tb.c > +++ b/drivers/thunderbolt/tb.c > @@ -2935,6 +2935,7 @@ static void tb_stop(struct tb *tb) > struct tb_cm *tcm = tb_priv(tb); > struct tb_tunnel *tunnel; > struct tb_tunnel *n; > + struct tb_port *port; > > cancel_delayed_work(&tcm->remove_work); > /* tunnels are only present after everything has been initialized */ > @@ -2948,6 +2949,16 @@ static void tb_stop(struct tb *tb) > tb_tunnel_deactivate(tunnel); > tb_tunnel_put(tunnel); > } > + /* > + * Assert DPR to drive SBTX low, signalling disconnect and avoiding > + * ~60 s of link polling before warm reset on shutdown. > + */ > + tb_switch_for_each_port(tb->root_switch, port) { > + if (!tb_port_is_null(port) || !tb_port_has_remote(port)) > + continue; > + if (tb_port_reset(port)) > + tb_port_dbg(port, "DPR on shutdown failed, continuing\n"); > + } > tb_switch_remove(tb->root_switch); > tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */ > } > diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h > index 217c3114bec8..875eb538eacf 100644 > --- a/drivers/thunderbolt/tb.h > +++ b/drivers/thunderbolt/tb.h > @@ -1102,6 +1102,7 @@ int tb_port_clear_counter(struct tb_port *port, int counter); > int tb_port_unlock(struct tb_port *port); > int tb_port_enable(struct tb_port *port); > int tb_port_disable(struct tb_port *port); > +int tb_port_reset(struct tb_port *port); > int tb_port_alloc_in_hopid(struct tb_port *port, int hopid, int max_hopid); > void tb_port_release_in_hopid(struct tb_port *port, int hopid); > int tb_port_alloc_out_hopid(struct tb_port *port, int hopid, int max_hopid); ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] thunderbolt: Assert downstream port reset on shutdown 2026-06-03 18:01 [PATCH] thunderbolt: Assert downstream port reset on shutdown Basavaraj Natikar 2026-06-03 19:02 ` Mario Limonciello @ 2026-06-04 5:03 ` Mika Westerberg 2026-06-05 16:27 ` Basavaraj Natikar 1 sibling, 1 reply; 10+ messages in thread From: Mika Westerberg @ 2026-06-04 5:03 UTC (permalink / raw) To: Basavaraj Natikar Cc: andreas.noever, westeri, YehezkelShB, linux-usb, Sanath S Hi, On Wed, Jun 03, 2026 at 11:31:46PM +0530, Basavaraj Natikar wrote: > On shutdown the connection manager tears down the switch tree without router tree > signalling connected devices. Thunderbolt 3 devices directly connected > to a USB4 host never receive a disconnect indication and during shutdown > this can cause polling the dead link for up to 60 seconds. On some > platforms this behavior leads to a warm reset instead of a shutdown due > to this timeout. > > Fix this by asserting PORT_CS_19.DPR on each connected downstream port > before tearing down the switch tree. This drives SBTX low unconditionally router tree > (USB4 spec section 6.9), causing the device to detect SBRX low and > transition to Uninitialized Unplugged state immediately. > > Co-developed-by: Sanath S <Sanath.S@amd.com> > Signed-off-by: Sanath S <Sanath.S@amd.com> > Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com> > --- > drivers/thunderbolt/switch.c | 2 +- > drivers/thunderbolt/tb.c | 11 +++++++++++ > drivers/thunderbolt/tb.h | 1 + > 3 files changed, 13 insertions(+), 1 deletion(-) > > diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c > index c2ad58b19e7b..52812908818b 100644 > --- a/drivers/thunderbolt/switch.c > +++ b/drivers/thunderbolt/switch.c > @@ -704,7 +704,7 @@ int tb_port_disable(struct tb_port *port) > return __tb_port_enable(port, false); > } > > -static int tb_port_reset(struct tb_port *port) > +int tb_port_reset(struct tb_port *port) > { > if (tb_switch_is_usb4(port->sw)) > return port->cap_usb4 ? usb4_port_reset(port) : 0; > diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c > index c69c323e6952..ca57b5181422 100644 > --- a/drivers/thunderbolt/tb.c > +++ b/drivers/thunderbolt/tb.c > @@ -2935,6 +2935,7 @@ static void tb_stop(struct tb *tb) > struct tb_cm *tcm = tb_priv(tb); > struct tb_tunnel *tunnel; > struct tb_tunnel *n; > + struct tb_port *port; > > cancel_delayed_work(&tcm->remove_work); > /* tunnels are only present after everything has been initialized */ > @@ -2948,6 +2949,16 @@ static void tb_stop(struct tb *tb) > tb_tunnel_deactivate(tunnel); > tb_tunnel_put(tunnel); > } > + /* > + * Assert DPR to drive SBTX low, signalling disconnect and avoiding > + * ~60 s of link polling before warm reset on shutdown. > + */ > + tb_switch_for_each_port(tb->root_switch, port) { > + if (!tb_port_is_null(port) || !tb_port_has_remote(port)) > + continue; > + if (tb_port_reset(port)) > + tb_port_dbg(port, "DPR on shutdown failed, continuing\n"); > + } But now this tears down the topology also when the driver is unloaded? If you want to do that in shutdown there is ->shutdown hook for that. > tb_switch_remove(tb->root_switch); > tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */ > } > diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h > index 217c3114bec8..875eb538eacf 100644 > --- a/drivers/thunderbolt/tb.h > +++ b/drivers/thunderbolt/tb.h > @@ -1102,6 +1102,7 @@ int tb_port_clear_counter(struct tb_port *port, int counter); > int tb_port_unlock(struct tb_port *port); > int tb_port_enable(struct tb_port *port); > int tb_port_disable(struct tb_port *port); > +int tb_port_reset(struct tb_port *port); > int tb_port_alloc_in_hopid(struct tb_port *port, int hopid, int max_hopid); > void tb_port_release_in_hopid(struct tb_port *port, int hopid); > int tb_port_alloc_out_hopid(struct tb_port *port, int hopid, int max_hopid); > -- > 2.34.1 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] thunderbolt: Assert downstream port reset on shutdown 2026-06-04 5:03 ` Mika Westerberg @ 2026-06-05 16:27 ` Basavaraj Natikar 2026-06-08 6:40 ` Mika Westerberg 0 siblings, 1 reply; 10+ messages in thread From: Basavaraj Natikar @ 2026-06-05 16:27 UTC (permalink / raw) To: Mika Westerberg, Basavaraj Natikar Cc: andreas.noever, westeri, YehezkelShB, linux-usb, Sanath S, Mario Limonciello Hi, On 6/4/2026 12:03 AM, Mika Westerberg wrote: > Hi, > > On Wed, Jun 03, 2026 at 11:31:46PM +0530, Basavaraj Natikar wrote: >> On shutdown the connection manager tears down the switch tree without > router tree > >> signalling connected devices. Thunderbolt 3 devices directly connected >> to a USB4 host never receive a disconnect indication and during shutdown >> this can cause polling the dead link for up to 60 seconds. On some >> platforms this behavior leads to a warm reset instead of a shutdown due >> to this timeout. >> >> Fix this by asserting PORT_CS_19.DPR on each connected downstream port >> before tearing down the switch tree. This drives SBTX low unconditionally > router tree > >> (USB4 spec section 6.9), causing the device to detect SBRX low and >> transition to Uninitialized Unplugged state immediately. >> >> Co-developed-by: Sanath S <Sanath.S@amd.com> >> Signed-off-by: Sanath S <Sanath.S@amd.com> >> Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com> >> --- >> drivers/thunderbolt/switch.c | 2 +- >> drivers/thunderbolt/tb.c | 11 +++++++++++ >> drivers/thunderbolt/tb.h | 1 + >> 3 files changed, 13 insertions(+), 1 deletion(-) >> >> diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c >> index c2ad58b19e7b..52812908818b 100644 >> --- a/drivers/thunderbolt/switch.c >> +++ b/drivers/thunderbolt/switch.c >> @@ -704,7 +704,7 @@ int tb_port_disable(struct tb_port *port) >> return __tb_port_enable(port, false); >> } >> >> -static int tb_port_reset(struct tb_port *port) >> +int tb_port_reset(struct tb_port *port) >> { >> if (tb_switch_is_usb4(port->sw)) >> return port->cap_usb4 ? usb4_port_reset(port) : 0; >> diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c >> index c69c323e6952..ca57b5181422 100644 >> --- a/drivers/thunderbolt/tb.c >> +++ b/drivers/thunderbolt/tb.c >> @@ -2935,6 +2935,7 @@ static void tb_stop(struct tb *tb) >> struct tb_cm *tcm = tb_priv(tb); >> struct tb_tunnel *tunnel; >> struct tb_tunnel *n; >> + struct tb_port *port; >> >> cancel_delayed_work(&tcm->remove_work); >> /* tunnels are only present after everything has been initialized */ >> @@ -2948,6 +2949,16 @@ static void tb_stop(struct tb *tb) >> tb_tunnel_deactivate(tunnel); >> tb_tunnel_put(tunnel); >> } >> + /* >> + * Assert DPR to drive SBTX low, signalling disconnect and avoiding >> + * ~60 s of link polling before warm reset on shutdown. >> + */ >> + tb_switch_for_each_port(tb->root_switch, port) { >> + if (!tb_port_is_null(port) || !tb_port_has_remote(port)) >> + continue; >> + if (tb_port_reset(port)) >> + tb_port_dbg(port, "DPR on shutdown failed, continuing\n"); >> + } > But now this tears down the topology also when the driver is unloaded? If > you want to do that in shutdown there is ->shutdown hook for that. Asserting DPR on unload is intentional and it is harmless. After a reload the driver re-probes and the router tree comes back up cleanly. It is also needed. Once the driver is unloaded it is unbound, so a later system shutdown has no driver left to assert DPR and the ~60s link polling hang comes back. Doing it in tb_stop() covers both plain shutdown and the unload then shutdown case, so I kept it here instead of the ->shutdown hook. Will fix switch tree to router tree. Thanks, -- Basavaraj > >> tb_switch_remove(tb->root_switch); >> tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */ >> } >> diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h >> index 217c3114bec8..875eb538eacf 100644 >> --- a/drivers/thunderbolt/tb.h >> +++ b/drivers/thunderbolt/tb.h >> @@ -1102,6 +1102,7 @@ int tb_port_clear_counter(struct tb_port *port, int counter); >> int tb_port_unlock(struct tb_port *port); >> int tb_port_enable(struct tb_port *port); >> int tb_port_disable(struct tb_port *port); >> +int tb_port_reset(struct tb_port *port); >> int tb_port_alloc_in_hopid(struct tb_port *port, int hopid, int max_hopid); >> void tb_port_release_in_hopid(struct tb_port *port, int hopid); >> int tb_port_alloc_out_hopid(struct tb_port *port, int hopid, int max_hopid); >> -- >> 2.34.1 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] thunderbolt: Assert downstream port reset on shutdown 2026-06-05 16:27 ` Basavaraj Natikar @ 2026-06-08 6:40 ` Mika Westerberg 2026-06-08 15:13 ` Mario Limonciello 0 siblings, 1 reply; 10+ messages in thread From: Mika Westerberg @ 2026-06-08 6:40 UTC (permalink / raw) To: Basavaraj Natikar Cc: Basavaraj Natikar, andreas.noever, westeri, YehezkelShB, linux-usb, Sanath S, Mario Limonciello On Fri, Jun 05, 2026 at 11:27:52AM -0500, Basavaraj Natikar wrote: > Hi, > > > On 6/4/2026 12:03 AM, Mika Westerberg wrote: > > Hi, > > > > On Wed, Jun 03, 2026 at 11:31:46PM +0530, Basavaraj Natikar wrote: > > > On shutdown the connection manager tears down the switch tree without > > router tree > > > > > signalling connected devices. Thunderbolt 3 devices directly connected > > > to a USB4 host never receive a disconnect indication and during shutdown > > > this can cause polling the dead link for up to 60 seconds. On some > > > platforms this behavior leads to a warm reset instead of a shutdown due > > > to this timeout. > > > > > > Fix this by asserting PORT_CS_19.DPR on each connected downstream port > > > before tearing down the switch tree. This drives SBTX low unconditionally > > router tree > > > > > (USB4 spec section 6.9), causing the device to detect SBRX low and > > > transition to Uninitialized Unplugged state immediately. > > > > > > Co-developed-by: Sanath S <Sanath.S@amd.com> > > > Signed-off-by: Sanath S <Sanath.S@amd.com> > > > Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com> > > > --- > > > drivers/thunderbolt/switch.c | 2 +- > > > drivers/thunderbolt/tb.c | 11 +++++++++++ > > > drivers/thunderbolt/tb.h | 1 + > > > 3 files changed, 13 insertions(+), 1 deletion(-) > > > > > > diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c > > > index c2ad58b19e7b..52812908818b 100644 > > > --- a/drivers/thunderbolt/switch.c > > > +++ b/drivers/thunderbolt/switch.c > > > @@ -704,7 +704,7 @@ int tb_port_disable(struct tb_port *port) > > > return __tb_port_enable(port, false); > > > } > > > -static int tb_port_reset(struct tb_port *port) > > > +int tb_port_reset(struct tb_port *port) > > > { > > > if (tb_switch_is_usb4(port->sw)) > > > return port->cap_usb4 ? usb4_port_reset(port) : 0; > > > diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c > > > index c69c323e6952..ca57b5181422 100644 > > > --- a/drivers/thunderbolt/tb.c > > > +++ b/drivers/thunderbolt/tb.c > > > @@ -2935,6 +2935,7 @@ static void tb_stop(struct tb *tb) > > > struct tb_cm *tcm = tb_priv(tb); > > > struct tb_tunnel *tunnel; > > > struct tb_tunnel *n; > > > + struct tb_port *port; > > > cancel_delayed_work(&tcm->remove_work); > > > /* tunnels are only present after everything has been initialized */ > > > @@ -2948,6 +2949,16 @@ static void tb_stop(struct tb *tb) > > > tb_tunnel_deactivate(tunnel); > > > tb_tunnel_put(tunnel); > > > } > > > + /* > > > + * Assert DPR to drive SBTX low, signalling disconnect and avoiding > > > + * ~60 s of link polling before warm reset on shutdown. > > > + */ > > > + tb_switch_for_each_port(tb->root_switch, port) { > > > + if (!tb_port_is_null(port) || !tb_port_has_remote(port)) > > > + continue; > > > + if (tb_port_reset(port)) > > > + tb_port_dbg(port, "DPR on shutdown failed, continuing\n"); > > > + } > > But now this tears down the topology also when the driver is unloaded? If > > you want to do that in shutdown there is ->shutdown hook for that. > > Asserting DPR on unload is intentional and it is harmless. After a reload > the driver re-probes and the router tree comes back up cleanly. Well not entirely harmless as it also kills the native tunnels and now user cannot get rid of that by passing host_reset=0 during load. Prior this unloading the driver left the tunnels up and that was intentional. > It is also needed. Once the driver is unloaded it is unbound, so a later > system shutdown has no driver left to assert DPR and the ~60s link polling > hang comes back. Doing it in tb_stop() covers both plain shutdown and the > unload then shutdown case, so I kept it here instead of the ->shutdown hook. > > Will fix switch tree to router tree. > > Thanks, > -- > Basavaraj > > > > > > tb_switch_remove(tb->root_switch); > > > tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */ > > > } > > > diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h > > > index 217c3114bec8..875eb538eacf 100644 > > > --- a/drivers/thunderbolt/tb.h > > > +++ b/drivers/thunderbolt/tb.h > > > @@ -1102,6 +1102,7 @@ int tb_port_clear_counter(struct tb_port *port, int counter); > > > int tb_port_unlock(struct tb_port *port); > > > int tb_port_enable(struct tb_port *port); > > > int tb_port_disable(struct tb_port *port); > > > +int tb_port_reset(struct tb_port *port); > > > int tb_port_alloc_in_hopid(struct tb_port *port, int hopid, int max_hopid); > > > void tb_port_release_in_hopid(struct tb_port *port, int hopid); > > > int tb_port_alloc_out_hopid(struct tb_port *port, int hopid, int max_hopid); > > > -- > > > 2.34.1 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] thunderbolt: Assert downstream port reset on shutdown 2026-06-08 6:40 ` Mika Westerberg @ 2026-06-08 15:13 ` Mario Limonciello 2026-06-08 15:22 ` Mika Westerberg 0 siblings, 1 reply; 10+ messages in thread From: Mario Limonciello @ 2026-06-08 15:13 UTC (permalink / raw) To: Mika Westerberg, Basavaraj Natikar Cc: Basavaraj Natikar, andreas.noever, westeri, YehezkelShB, linux-usb, Sanath S On 6/8/26 01:40, Mika Westerberg wrote: > On Fri, Jun 05, 2026 at 11:27:52AM -0500, Basavaraj Natikar wrote: >> Hi, >> >> >> On 6/4/2026 12:03 AM, Mika Westerberg wrote: >>> Hi, >>> >>> On Wed, Jun 03, 2026 at 11:31:46PM +0530, Basavaraj Natikar wrote: >>>> On shutdown the connection manager tears down the switch tree without >>> router tree >>> >>>> signalling connected devices. Thunderbolt 3 devices directly connected >>>> to a USB4 host never receive a disconnect indication and during shutdown >>>> this can cause polling the dead link for up to 60 seconds. On some >>>> platforms this behavior leads to a warm reset instead of a shutdown due >>>> to this timeout. >>>> >>>> Fix this by asserting PORT_CS_19.DPR on each connected downstream port >>>> before tearing down the switch tree. This drives SBTX low unconditionally >>> router tree >>> >>>> (USB4 spec section 6.9), causing the device to detect SBRX low and >>>> transition to Uninitialized Unplugged state immediately. >>>> >>>> Co-developed-by: Sanath S <Sanath.S@amd.com> >>>> Signed-off-by: Sanath S <Sanath.S@amd.com> >>>> Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com> >>>> --- >>>> drivers/thunderbolt/switch.c | 2 +- >>>> drivers/thunderbolt/tb.c | 11 +++++++++++ >>>> drivers/thunderbolt/tb.h | 1 + >>>> 3 files changed, 13 insertions(+), 1 deletion(-) >>>> >>>> diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c >>>> index c2ad58b19e7b..52812908818b 100644 >>>> --- a/drivers/thunderbolt/switch.c >>>> +++ b/drivers/thunderbolt/switch.c >>>> @@ -704,7 +704,7 @@ int tb_port_disable(struct tb_port *port) >>>> return __tb_port_enable(port, false); >>>> } >>>> -static int tb_port_reset(struct tb_port *port) >>>> +int tb_port_reset(struct tb_port *port) >>>> { >>>> if (tb_switch_is_usb4(port->sw)) >>>> return port->cap_usb4 ? usb4_port_reset(port) : 0; >>>> diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c >>>> index c69c323e6952..ca57b5181422 100644 >>>> --- a/drivers/thunderbolt/tb.c >>>> +++ b/drivers/thunderbolt/tb.c >>>> @@ -2935,6 +2935,7 @@ static void tb_stop(struct tb *tb) >>>> struct tb_cm *tcm = tb_priv(tb); >>>> struct tb_tunnel *tunnel; >>>> struct tb_tunnel *n; >>>> + struct tb_port *port; >>>> cancel_delayed_work(&tcm->remove_work); >>>> /* tunnels are only present after everything has been initialized */ >>>> @@ -2948,6 +2949,16 @@ static void tb_stop(struct tb *tb) >>>> tb_tunnel_deactivate(tunnel); >>>> tb_tunnel_put(tunnel); >>>> } >>>> + /* >>>> + * Assert DPR to drive SBTX low, signalling disconnect and avoiding >>>> + * ~60 s of link polling before warm reset on shutdown. >>>> + */ >>>> + tb_switch_for_each_port(tb->root_switch, port) { >>>> + if (!tb_port_is_null(port) || !tb_port_has_remote(port)) >>>> + continue; >>>> + if (tb_port_reset(port)) >>>> + tb_port_dbg(port, "DPR on shutdown failed, continuing\n"); >>>> + } >>> But now this tears down the topology also when the driver is unloaded? If >>> you want to do that in shutdown there is ->shutdown hook for that. >> >> Asserting DPR on unload is intentional and it is harmless. After a reload >> the driver re-probes and the router tree comes back up cleanly. > > Well not entirely harmless as it also kills the native tunnels and now user > cannot get rid of that by passing host_reset=0 during load. > > Prior this unloading the driver left the tunnels up and that was > intentional. I guess I see two approaches. 1) Move to shutdown only (your suggestion). Corner case of user who unloads before shutdown means they could be exposed to this. 2) Link the DPR behavior to host_reset module behavior. IE If a user set host_reset=0 avoid host reset on module load and avoid DPR on module unload/shutdown. If user kept host_reset=1 then do DPR on unload. Always do on shutdown (regardless of host_reset value). What do you think of #2? ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] thunderbolt: Assert downstream port reset on shutdown 2026-06-08 15:13 ` Mario Limonciello @ 2026-06-08 15:22 ` Mika Westerberg 2026-06-08 15:25 ` Mario Limonciello 0 siblings, 1 reply; 10+ messages in thread From: Mika Westerberg @ 2026-06-08 15:22 UTC (permalink / raw) To: Mario Limonciello Cc: Basavaraj Natikar, Basavaraj Natikar, andreas.noever, westeri, YehezkelShB, linux-usb, Sanath S On Mon, Jun 08, 2026 at 10:13:00AM -0500, Mario Limonciello wrote: > > > On 6/8/26 01:40, Mika Westerberg wrote: > > On Fri, Jun 05, 2026 at 11:27:52AM -0500, Basavaraj Natikar wrote: > > > Hi, > > > > > > > > > On 6/4/2026 12:03 AM, Mika Westerberg wrote: > > > > Hi, > > > > > > > > On Wed, Jun 03, 2026 at 11:31:46PM +0530, Basavaraj Natikar wrote: > > > > > On shutdown the connection manager tears down the switch tree without > > > > router tree > > > > > > > > > signalling connected devices. Thunderbolt 3 devices directly connected > > > > > to a USB4 host never receive a disconnect indication and during shutdown > > > > > this can cause polling the dead link for up to 60 seconds. On some > > > > > platforms this behavior leads to a warm reset instead of a shutdown due > > > > > to this timeout. > > > > > > > > > > Fix this by asserting PORT_CS_19.DPR on each connected downstream port > > > > > before tearing down the switch tree. This drives SBTX low unconditionally > > > > router tree > > > > > > > > > (USB4 spec section 6.9), causing the device to detect SBRX low and > > > > > transition to Uninitialized Unplugged state immediately. > > > > > > > > > > Co-developed-by: Sanath S <Sanath.S@amd.com> > > > > > Signed-off-by: Sanath S <Sanath.S@amd.com> > > > > > Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com> > > > > > --- > > > > > drivers/thunderbolt/switch.c | 2 +- > > > > > drivers/thunderbolt/tb.c | 11 +++++++++++ > > > > > drivers/thunderbolt/tb.h | 1 + > > > > > 3 files changed, 13 insertions(+), 1 deletion(-) > > > > > > > > > > diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c > > > > > index c2ad58b19e7b..52812908818b 100644 > > > > > --- a/drivers/thunderbolt/switch.c > > > > > +++ b/drivers/thunderbolt/switch.c > > > > > @@ -704,7 +704,7 @@ int tb_port_disable(struct tb_port *port) > > > > > return __tb_port_enable(port, false); > > > > > } > > > > > -static int tb_port_reset(struct tb_port *port) > > > > > +int tb_port_reset(struct tb_port *port) > > > > > { > > > > > if (tb_switch_is_usb4(port->sw)) > > > > > return port->cap_usb4 ? usb4_port_reset(port) : 0; > > > > > diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c > > > > > index c69c323e6952..ca57b5181422 100644 > > > > > --- a/drivers/thunderbolt/tb.c > > > > > +++ b/drivers/thunderbolt/tb.c > > > > > @@ -2935,6 +2935,7 @@ static void tb_stop(struct tb *tb) > > > > > struct tb_cm *tcm = tb_priv(tb); > > > > > struct tb_tunnel *tunnel; > > > > > struct tb_tunnel *n; > > > > > + struct tb_port *port; > > > > > cancel_delayed_work(&tcm->remove_work); > > > > > /* tunnels are only present after everything has been initialized */ > > > > > @@ -2948,6 +2949,16 @@ static void tb_stop(struct tb *tb) > > > > > tb_tunnel_deactivate(tunnel); > > > > > tb_tunnel_put(tunnel); > > > > > } > > > > > + /* > > > > > + * Assert DPR to drive SBTX low, signalling disconnect and avoiding > > > > > + * ~60 s of link polling before warm reset on shutdown. > > > > > + */ > > > > > + tb_switch_for_each_port(tb->root_switch, port) { > > > > > + if (!tb_port_is_null(port) || !tb_port_has_remote(port)) > > > > > + continue; > > > > > + if (tb_port_reset(port)) > > > > > + tb_port_dbg(port, "DPR on shutdown failed, continuing\n"); > > > > > + } > > > > But now this tears down the topology also when the driver is unloaded? If > > > > you want to do that in shutdown there is ->shutdown hook for that. > > > > > > Asserting DPR on unload is intentional and it is harmless. After a reload > > > the driver re-probes and the router tree comes back up cleanly. > > > > Well not entirely harmless as it also kills the native tunnels and now user > > cannot get rid of that by passing host_reset=0 during load. > > > > Prior this unloading the driver left the tunnels up and that was > > intentional. > > I guess I see two approaches. > > 1) Move to shutdown only (your suggestion). > > Corner case of user who unloads before shutdown means they could be exposed > to this. > > 2) Link the DPR behavior to host_reset module behavior. > > IE If a user set host_reset=0 avoid host reset on module load and avoid DPR > on module unload/shutdown. > > If user kept host_reset=1 then do DPR on unload. > > Always do on shutdown (regardless of host_reset value). > > What do you think of #2? That sounds better. Also we could restrict this more for links that are TB3 e.g no need to do for USB4, assuming that is simple to do. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] thunderbolt: Assert downstream port reset on shutdown 2026-06-08 15:22 ` Mika Westerberg @ 2026-06-08 15:25 ` Mario Limonciello 2026-06-09 6:25 ` Basavaraj Natikar 0 siblings, 1 reply; 10+ messages in thread From: Mario Limonciello @ 2026-06-08 15:25 UTC (permalink / raw) To: Mika Westerberg, Basavaraj Natikar, Basavaraj Natikar Cc: andreas.noever, westeri, YehezkelShB, linux-usb, Sanath S >> >> I guess I see two approaches. >> >> 1) Move to shutdown only (your suggestion). >> >> Corner case of user who unloads before shutdown means they could be exposed >> to this. >> >> 2) Link the DPR behavior to host_reset module behavior. >> >> IE If a user set host_reset=0 avoid host reset on module load and avoid DPR >> on module unload/shutdown. >> >> If user kept host_reset=1 then do DPR on unload. >> >> Always do on shutdown (regardless of host_reset value). >> >> What do you think of #2? > > That sounds better. Also we could restrict this more for links that are TB3 > e.g no need to do for USB4, assuming that is simple to do. OK thanks. Basavaraj, thoughts? The way that this was found was by looking at the traces of what Windows and Linux were doing differently at shutdown. Maybe before we make a decision to tie it only to TBT3 we should double check if Windows was also doing the DPR for USB4 too. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] thunderbolt: Assert downstream port reset on shutdown 2026-06-08 15:25 ` Mario Limonciello @ 2026-06-09 6:25 ` Basavaraj Natikar 2026-06-09 10:05 ` Mika Westerberg 0 siblings, 1 reply; 10+ messages in thread From: Basavaraj Natikar @ 2026-06-09 6:25 UTC (permalink / raw) To: Mario Limonciello, Mika Westerberg, Basavaraj Natikar Cc: andreas.noever, westeri, YehezkelShB, linux-usb, Sanath S On 6/8/2026 10:25 AM, Mario Limonciello wrote: >>> >>> I guess I see two approaches. >>> >>> 1) Move to shutdown only (your suggestion). >>> >>> Corner case of user who unloads before shutdown means they could be >>> exposed >>> to this. >>> >>> 2) Link the DPR behavior to host_reset module behavior. >>> >>> IE If a user set host_reset=0 avoid host reset on module load and >>> avoid DPR >>> on module unload/shutdown. >>> >>> If user kept host_reset=1 then do DPR on unload. >>> >>> Always do on shutdown (regardless of host_reset value). >>> >>> What do you think of #2? >> >> That sounds better. Also we could restrict this more for links that >> are TB3 >> e.g no need to do for USB4, assuming that is simple to do. > > OK thanks. Basavaraj, thoughts? > > The way that this was found was by looking at the traces of what > Windows and Linux were doing differently at shutdown. > > Maybe before we make a decision to tie it only to TBT3 we should > double check if Windows was also doing the DPR for USB4 too. So the traces confirm Windows only asserts DPR for TB3 and not for USB4 docks, which matches what Mika suggested. For v2 I will restrict the reset to legacy TB3 devices (skip USB4 routers) and fold in the host_reset changes (the second approach). Thanks, -- Basavaraj ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] thunderbolt: Assert downstream port reset on shutdown 2026-06-09 6:25 ` Basavaraj Natikar @ 2026-06-09 10:05 ` Mika Westerberg 0 siblings, 0 replies; 10+ messages in thread From: Mika Westerberg @ 2026-06-09 10:05 UTC (permalink / raw) To: Basavaraj Natikar Cc: Mario Limonciello, Basavaraj Natikar, andreas.noever, westeri, YehezkelShB, linux-usb, Sanath S On Tue, Jun 09, 2026 at 01:25:55AM -0500, Basavaraj Natikar wrote: > > On 6/8/2026 10:25 AM, Mario Limonciello wrote: > > > > > > > > I guess I see two approaches. > > > > > > > > 1) Move to shutdown only (your suggestion). > > > > > > > > Corner case of user who unloads before shutdown means they could > > > > be exposed > > > > to this. > > > > > > > > 2) Link the DPR behavior to host_reset module behavior. > > > > > > > > IE If a user set host_reset=0 avoid host reset on module load > > > > and avoid DPR > > > > on module unload/shutdown. > > > > > > > > If user kept host_reset=1 then do DPR on unload. > > > > > > > > Always do on shutdown (regardless of host_reset value). > > > > > > > > What do you think of #2? > > > > > > That sounds better. Also we could restrict this more for links that > > > are TB3 > > > e.g no need to do for USB4, assuming that is simple to do. > > > > OK thanks. Basavaraj, thoughts? > > > > The way that this was found was by looking at the traces of what Windows > > and Linux were doing differently at shutdown. > > > > Maybe before we make a decision to tie it only to TBT3 we should double > > check if Windows was also doing the DPR for USB4 too. > > So the traces confirm Windows only asserts DPR for TB3 and not for USB4 > docks, which matches what Mika suggested. For v2 I will restrict the > reset to legacy TB3 devices (skip USB4 routers) and fold in the > host_reset changes (the second approach). Sounds good to me. ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-06-09 10:05 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-06-03 18:01 [PATCH] thunderbolt: Assert downstream port reset on shutdown Basavaraj Natikar 2026-06-03 19:02 ` Mario Limonciello 2026-06-04 5:03 ` Mika Westerberg 2026-06-05 16:27 ` Basavaraj Natikar 2026-06-08 6:40 ` Mika Westerberg 2026-06-08 15:13 ` Mario Limonciello 2026-06-08 15:22 ` Mika Westerberg 2026-06-08 15:25 ` Mario Limonciello 2026-06-09 6:25 ` Basavaraj Natikar 2026-06-09 10:05 ` Mika Westerberg
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox