summaryrefslogtreecommitdiff
path: root/drivers/thunderbolt/switch.c
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2020-04-02 14:50:52 +0300
committerMika Westerberg <mika.westerberg@linux.intel.com>2020-09-03 12:06:41 +0300
commitde4620391786513a6971029b61663563c4b7b961 (patch)
treee952bac77413ea9ad271df75f03ab46795323ad0 /drivers/thunderbolt/switch.c
parent5cb6ed31c5d51a4b360ae8aa69fc2457723db27a (diff)
thunderbolt: Configure link after lane bonding is enabled
During testing it was noticed that the link is not properly restored after the domain exits sleep if the link configured bits are set before lane bonding is enabled. The USB4 spec does not say in which order these need to be set but setting link configured afterwards makes the link restoration work so we do that instead. Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Diffstat (limited to 'drivers/thunderbolt/switch.c')
-rw-r--r--drivers/thunderbolt/switch.c55
1 files changed, 42 insertions, 13 deletions
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index 02f981ee88e9..5d99d69107eb 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -2011,10 +2011,6 @@ int tb_switch_configure(struct tb_switch *sw)
return ret;
ret = usb4_switch_setup(sw);
- if (ret)
- return ret;
-
- ret = usb4_switch_configure_link(sw);
} else {
if (sw->config.vendor_id != PCI_VENDOR_ID_INTEL)
tb_sw_warn(sw, "unknown switch vendor id %#x\n",
@@ -2028,10 +2024,6 @@ int tb_switch_configure(struct tb_switch *sw)
/* Enumerate the switch */
ret = tb_sw_write(sw, (u32 *)&sw->config + 1, TB_CFG_SWITCH,
ROUTER_CS_1, 3);
- if (ret)
- return ret;
-
- ret = tb_lc_configure_link(sw);
}
if (ret)
return ret;
@@ -2315,6 +2307,48 @@ void tb_switch_lane_bonding_disable(struct tb_switch *sw)
}
/**
+ * tb_switch_configure_link() - Set link configured
+ * @sw: Switch whose link is configured
+ *
+ * Sets the link upstream from @sw configured (from both ends) so that
+ * it will not be disconnected when the domain exits sleep. Can be
+ * called for any switch.
+ *
+ * It is recommended that this is called after lane bonding is enabled.
+ *
+ * Returns %0 on success and negative errno in case of error.
+ */
+int tb_switch_configure_link(struct tb_switch *sw)
+{
+ if (!tb_route(sw) || tb_switch_is_icm(sw))
+ return 0;
+
+ if (tb_switch_is_usb4(sw))
+ return usb4_switch_configure_link(sw);
+ return tb_lc_configure_link(sw);
+}
+
+/**
+ * tb_switch_unconfigure_link() - Unconfigure link
+ * @sw: Switch whose link is unconfigured
+ *
+ * Sets the link unconfigured so the @sw will be disconnected if the
+ * domain exists sleep.
+ */
+void tb_switch_unconfigure_link(struct tb_switch *sw)
+{
+ if (sw->is_unplugged)
+ return;
+ if (!tb_route(sw) || tb_switch_is_icm(sw))
+ return;
+
+ if (tb_switch_is_usb4(sw))
+ usb4_switch_unconfigure_link(sw);
+ else
+ tb_lc_unconfigure_link(sw);
+}
+
+/**
* tb_switch_add() - Add a switch to the domain
* @sw: Switch to add
*
@@ -2448,11 +2482,6 @@ void tb_switch_remove(struct tb_switch *sw)
if (!sw->is_unplugged)
tb_plug_events_active(sw, false);
- if (tb_switch_is_usb4(sw))
- usb4_switch_unconfigure_link(sw);
- else
- tb_lc_unconfigure_link(sw);
-
tb_switch_nvm_remove(sw);
if (tb_route(sw))