summaryrefslogtreecommitdiffstats
path: root/drivers/thunderbolt/lc.c
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2020-11-26 10:52:43 +0100
committerMika Westerberg <mika.westerberg@linux.intel.com>2021-01-11 15:15:42 +0100
commitfdb0887c5a87c3a98958d3c5c90f871aa6d1a562 (patch)
tree4dbc78d44f23e68a2af3debe0532dc1635f6663a /drivers/thunderbolt/lc.c
parentthunderbolt: Constify static attribute_group structs (diff)
downloadlinux-fdb0887c5a87c3a98958d3c5c90f871aa6d1a562.tar.xz
linux-fdb0887c5a87c3a98958d3c5c90f871aa6d1a562.zip
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>
Diffstat (limited to 'drivers/thunderbolt/lc.c')
-rw-r--r--drivers/thunderbolt/lc.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/drivers/thunderbolt/lc.c b/drivers/thunderbolt/lc.c
index 41e6c738f6c8..bc671730a11f 100644
--- a/drivers/thunderbolt/lc.c
+++ b/drivers/thunderbolt/lc.c
@@ -158,6 +158,41 @@ void tb_lc_unconfigure_xdomain(struct tb_port *port)
tb_lc_set_xdomain_configured(port, false);
}
+/**
+ * tb_lc_start_lane_initialization() - Start lane initialization
+ * @port: Device router lane 0 adapter
+ *
+ * Starts lane initialization for @port after the router resumed from
+ * sleep. Should be called for those downstream lane adapters that were
+ * not connected (tb_lc_configure_port() was not called) before sleep.
+ *
+ * Returns %0 in success and negative errno in case of failure.
+ */
+int tb_lc_start_lane_initialization(struct tb_port *port)
+{
+ struct tb_switch *sw = port->sw;
+ int ret, cap;
+ u32 ctrl;
+
+ if (!tb_route(sw))
+ return 0;
+
+ if (sw->generation < 2)
+ return 0;
+
+ cap = find_port_lc_cap(port);
+ if (cap < 0)
+ return cap;
+
+ ret = tb_sw_read(sw, &ctrl, TB_CFG_SWITCH, cap + TB_LC_SX_CTRL, 1);
+ if (ret)
+ return ret;
+
+ ctrl |= TB_LC_SX_CTRL_SLI;
+
+ return tb_sw_write(sw, &ctrl, TB_CFG_SWITCH, cap + TB_LC_SX_CTRL, 1);
+}
+
static int tb_lc_set_wake_one(struct tb_switch *sw, unsigned int offset,
unsigned int flags)
{