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

thunderbolt: Start lane initialization after sleep

USB4 spec says that for TBT3 compatible device routers the connection
manager needs to set SLI (Start Lane Initialization) to get the lanes
that were not connected back to functional state after sleep. Same needs
to be done if the link was XDomain.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Yehezkel Bernat <YehezkelShB@gmail.com>

+63 -1
+35
drivers/thunderbolt/lc.c
··· 158 158 tb_lc_set_xdomain_configured(port, false); 159 159 } 160 160 161 + /** 162 + * tb_lc_start_lane_initialization() - Start lane initialization 163 + * @port: Device router lane 0 adapter 164 + * 165 + * Starts lane initialization for @port after the router resumed from 166 + * sleep. Should be called for those downstream lane adapters that were 167 + * not connected (tb_lc_configure_port() was not called) before sleep. 168 + * 169 + * Returns %0 in success and negative errno in case of failure. 170 + */ 171 + int tb_lc_start_lane_initialization(struct tb_port *port) 172 + { 173 + struct tb_switch *sw = port->sw; 174 + int ret, cap; 175 + u32 ctrl; 176 + 177 + if (!tb_route(sw)) 178 + return 0; 179 + 180 + if (sw->generation < 2) 181 + return 0; 182 + 183 + cap = find_port_lc_cap(port); 184 + if (cap < 0) 185 + return cap; 186 + 187 + ret = tb_sw_read(sw, &ctrl, TB_CFG_SWITCH, cap + TB_LC_SX_CTRL, 1); 188 + if (ret) 189 + return ret; 190 + 191 + ctrl |= TB_LC_SX_CTRL_SLI; 192 + 193 + return tb_sw_write(sw, &ctrl, TB_CFG_SWITCH, cap + TB_LC_SX_CTRL, 1); 194 + } 195 + 161 196 static int tb_lc_set_wake_one(struct tb_switch *sw, unsigned int offset, 162 197 unsigned int flags) 163 198 {
+26 -1
drivers/thunderbolt/switch.c
··· 1065 1065 tb_port_set_link_width(port, 1); 1066 1066 } 1067 1067 1068 + static int tb_port_start_lane_initialization(struct tb_port *port) 1069 + { 1070 + int ret; 1071 + 1072 + if (tb_switch_is_usb4(port->sw)) 1073 + return 0; 1074 + 1075 + ret = tb_lc_start_lane_initialization(port); 1076 + return ret == -EINVAL ? 0 : ret; 1077 + } 1078 + 1068 1079 /** 1069 1080 * tb_port_is_enabled() - Is the adapter port enabled 1070 1081 * @port: Port to check ··· 2705 2694 2706 2695 /* check for surviving downstream switches */ 2707 2696 tb_switch_for_each_port(sw, port) { 2708 - if (!tb_port_has_remote(port) && !port->xdomain) 2697 + if (!tb_port_has_remote(port) && !port->xdomain) { 2698 + /* 2699 + * For disconnected downstream lane adapters 2700 + * start lane initialization now so we detect 2701 + * future connects. 2702 + */ 2703 + if (!tb_is_upstream_port(port) && tb_port_is_null(port)) 2704 + tb_port_start_lane_initialization(port); 2709 2705 continue; 2706 + } else if (port->xdomain) { 2707 + /* 2708 + * Start lane initialization for XDomain so the 2709 + * link gets re-established. 2710 + */ 2711 + tb_port_start_lane_initialization(port); 2712 + } 2710 2713 2711 2714 if (tb_wait_for_port(port, true) <= 0) { 2712 2715 tb_port_warn(port,
+1
drivers/thunderbolt/tb.h
··· 923 923 void tb_lc_unconfigure_port(struct tb_port *port); 924 924 int tb_lc_configure_xdomain(struct tb_port *port); 925 925 void tb_lc_unconfigure_xdomain(struct tb_port *port); 926 + int tb_lc_start_lane_initialization(struct tb_port *port); 926 927 int tb_lc_set_wake(struct tb_switch *sw, unsigned int flags); 927 928 int tb_lc_set_sleep(struct tb_switch *sw); 928 929 bool tb_lc_lane_bonding_possible(struct tb_switch *sw);
+1
drivers/thunderbolt/tb_regs.h
··· 464 464 #define TB_LC_SX_CTRL_L1D BIT(17) 465 465 #define TB_LC_SX_CTRL_L2C BIT(20) 466 466 #define TB_LC_SX_CTRL_L2D BIT(21) 467 + #define TB_LC_SX_CTRL_SLI BIT(29) 467 468 #define TB_LC_SX_CTRL_UPSTREAM BIT(30) 468 469 #define TB_LC_SX_CTRL_SLP BIT(31) 469 470