Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

thunderbolt: Improve redrive mode handling

When USB-C monitor is connected directly to Intel Barlow Ridge host, it
goes into "redrive" mode that basically routes the DisplayPort signals
directly from the GPU to the USB-C monitor without any tunneling needed.
However, the host router must be powered on for this to work. Aaron
reported that there are a couple of cases where this will not work with
the current code:

- Booting with USB-C monitor plugged in.
- Plugging in USB-C monitor when the host router is in sleep state
(runtime suspended).
- Plugging in USB-C device while the system is in system sleep state.

In all these cases once the host router is runtime suspended the picture
on the connected USB-C display disappears too. This is certainly not
what the user expected.

For this reason improve the redrive mode handling to keep the host
router from runtime suspending when detect that any of the above cases
is happening.

Fixes: a75e0684efe5 ("thunderbolt: Keep the domain powered when USB4 port is in redrive mode")
Reported-by: Aaron Rainbolt <arainbolt@kfocus.org>
Closes: https://lore.kernel.org/linux-usb/20241009220118.70bfedd0@kf-ir16/
Cc: stable@vger.kernel.org
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>

+41
+41
drivers/thunderbolt/tb.c
··· 2059 2059 } 2060 2060 } 2061 2061 2062 + static void tb_switch_enter_redrive(struct tb_switch *sw) 2063 + { 2064 + struct tb_port *port; 2065 + 2066 + tb_switch_for_each_port(sw, port) 2067 + tb_enter_redrive(port); 2068 + } 2069 + 2070 + /* 2071 + * Called during system and runtime suspend to forcefully exit redrive 2072 + * mode without querying whether the resource is available. 2073 + */ 2074 + static void tb_switch_exit_redrive(struct tb_switch *sw) 2075 + { 2076 + struct tb_port *port; 2077 + 2078 + if (!(sw->quirks & QUIRK_KEEP_POWER_IN_DP_REDRIVE)) 2079 + return; 2080 + 2081 + tb_switch_for_each_port(sw, port) { 2082 + if (!tb_port_is_dpin(port)) 2083 + continue; 2084 + 2085 + if (port->redrive) { 2086 + port->redrive = false; 2087 + pm_runtime_put(&sw->dev); 2088 + tb_port_dbg(port, "exit redrive mode\n"); 2089 + } 2090 + } 2091 + } 2092 + 2062 2093 static void tb_dp_resource_unavailable(struct tb *tb, struct tb_port *port) 2063 2094 { 2064 2095 struct tb_port *in, *out; ··· 2940 2909 tb_create_usb3_tunnels(tb->root_switch); 2941 2910 /* Add DP IN resources for the root switch */ 2942 2911 tb_add_dp_resources(tb->root_switch); 2912 + tb_switch_enter_redrive(tb->root_switch); 2943 2913 /* Make the discovered switches available to the userspace */ 2944 2914 device_for_each_child(&tb->root_switch->dev, NULL, 2945 2915 tb_scan_finalize_switch); ··· 2956 2924 2957 2925 tb_dbg(tb, "suspending...\n"); 2958 2926 tb_disconnect_and_release_dp(tb); 2927 + tb_switch_exit_redrive(tb->root_switch); 2959 2928 tb_switch_suspend(tb->root_switch, false); 2960 2929 tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */ 2961 2930 tb_dbg(tb, "suspend finished\n"); ··· 3049 3016 tb_dbg(tb, "tunnels restarted, sleeping for 100ms\n"); 3050 3017 msleep(100); 3051 3018 } 3019 + tb_switch_enter_redrive(tb->root_switch); 3052 3020 /* Allow tb_handle_hotplug to progress events */ 3053 3021 tcm->hotplug_active = true; 3054 3022 tb_dbg(tb, "resume finished\n"); ··· 3113 3079 struct tb_cm *tcm = tb_priv(tb); 3114 3080 3115 3081 mutex_lock(&tb->lock); 3082 + /* 3083 + * The below call only releases DP resources to allow exiting and 3084 + * re-entering redrive mode. 3085 + */ 3086 + tb_disconnect_and_release_dp(tb); 3087 + tb_switch_exit_redrive(tb->root_switch); 3116 3088 tb_switch_suspend(tb->root_switch, true); 3117 3089 tcm->hotplug_active = false; 3118 3090 mutex_unlock(&tb->lock); ··· 3150 3110 tb_restore_children(tb->root_switch); 3151 3111 list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) 3152 3112 tb_tunnel_restart(tunnel); 3113 + tb_switch_enter_redrive(tb->root_switch); 3153 3114 tcm->hotplug_active = true; 3154 3115 mutex_unlock(&tb->lock); 3155 3116