[RFC PATCH 07/22] thunderbolt: Add default linking between ports if not provided by DROM

From: Mika Westerberg
Date: Tue Oct 01 2019 - 07:39:34 EST


Some cases the DROM information is not correct or is simply missing.
This prevents establishing lane bonding even if it would be possible
otherwise. To make this work better provide default linking between
ports if DROM has not provided that information.

This works with legacy devices where ports 1 and 2, and 3 and 4 are
linked together and also with USB4.

Signed-off-by: Mika Westerberg <mika.westerberg@xxxxxxxxxxxxxxx>
---
drivers/thunderbolt/eeprom.c | 11 -----------
drivers/thunderbolt/switch.c | 32 ++++++++++++++++++++++++++++++++
2 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c
index ee5196479854..8dd7de0cc826 100644
--- a/drivers/thunderbolt/eeprom.c
+++ b/drivers/thunderbolt/eeprom.c
@@ -514,17 +514,6 @@ int tb_drom_read(struct tb_switch *sw)
* no entries). Hardcode the configuration here.
*/
tb_drom_read_uid_only(sw, &sw->uid);
-
- sw->ports[1].link_nr = 0;
- sw->ports[2].link_nr = 1;
- sw->ports[1].dual_link_port = &sw->ports[2];
- sw->ports[2].dual_link_port = &sw->ports[1];
-
- sw->ports[3].link_nr = 0;
- sw->ports[4].link_nr = 1;
- sw->ports[3].dual_link_port = &sw->ports[4];
- sw->ports[4].dual_link_port = &sw->ports[3];
-
return 0;
}

diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index 2b00ea7a979a..f7547287be68 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -1904,6 +1904,36 @@ static int tb_switch_add_dma_port(struct tb_switch *sw)
return -ESHUTDOWN;
}

+static void tb_switch_default_link_ports(struct tb_switch *sw)
+{
+ int i;
+
+ for (i = 1; i <= sw->config.max_port_number; i += 2) {
+ struct tb_port *port = &sw->ports[i];
+ struct tb_port *subordinate;
+
+ if (!tb_port_is_null(port))
+ continue;
+
+ /* Check for the subordinate port */
+ if (i == sw->config.max_port_number ||
+ !tb_port_is_null(&sw->ports[i + 1]))
+ continue;
+
+ /* Link them if not already done so (by DROM) */
+ subordinate = &sw->ports[i + 1];
+ if (!port->dual_link_port && !subordinate->dual_link_port) {
+ port->link_nr = 0;
+ port->dual_link_port = subordinate;
+ subordinate->link_nr = 1;
+ subordinate->dual_link_port = port;
+
+ tb_sw_dbg(sw, "linked ports %d <-> %d\n",
+ port->port, subordinate->port);
+ }
+ }
+}
+
static bool tb_switch_lane_bonding_possible(struct tb_switch *sw)
{
const struct tb_port *up = tb_upstream_port(sw);
@@ -2071,6 +2101,8 @@ int tb_switch_add(struct tb_switch *sw)
return ret;
}

+ tb_switch_default_link_ports(sw);
+
ret = tb_switch_update_link_attributes(sw);
if (ret)
return ret;
--
2.23.0