diff options
author | Mika Westerberg <mika.westerberg@linux.intel.com> | 2020-04-09 14:23:32 +0300 |
---|---|---|
committer | Mika Westerberg <mika.westerberg@linux.intel.com> | 2020-09-03 12:06:41 +0300 |
commit | 284652a4a49917e121277a6cacbefed9f65b94ca (patch) | |
tree | d126165f7d01a7c19443ba8aefd3ac810a700a1b /drivers/thunderbolt/tb.c | |
parent | e28178bf566cf7281b513856aa71a8d41aa81154 (diff) | |
download | linux-284652a4a49917e121277a6cacbefed9f65b94ca.tar.xz |
thunderbolt: Configure port for XDomain
When the port is connected to another host it should be marked as such
in the USB4 port capability. This information is used by the router
during sleep and wakeup.
Also do the same for legacy switches via link controller vendor specific
registers.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Diffstat (limited to 'drivers/thunderbolt/tb.c')
-rw-r--r-- | drivers/thunderbolt/tb.c | 32 |
1 files changed, 28 insertions, 4 deletions
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index 54a4daf0b1b4..602e00e0b45e 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -140,6 +140,21 @@ static void tb_discover_tunnels(struct tb_switch *sw) } } +static int tb_port_configure_xdomain(struct tb_port *port) +{ + if (tb_switch_is_usb4(port->sw)) + return usb4_port_configure_xdomain(port); + return tb_lc_configure_xdomain(port); +} + +static void tb_port_unconfigure_xdomain(struct tb_port *port) +{ + if (tb_switch_is_usb4(port->sw)) + usb4_port_unconfigure_xdomain(port); + else + tb_lc_unconfigure_xdomain(port); +} + static void tb_scan_xdomain(struct tb_port *port) { struct tb_switch *sw = port->sw; @@ -158,6 +173,7 @@ static void tb_scan_xdomain(struct tb_port *port) NULL); if (xd) { tb_port_at(route, sw)->xdomain = xd; + tb_port_configure_xdomain(port); tb_xdomain_add(xd); } } @@ -566,6 +582,7 @@ static void tb_scan_port(struct tb_port *port) */ if (port->xdomain) { tb_xdomain_remove(port->xdomain); + tb_port_unconfigure_xdomain(port); port->xdomain = NULL; } @@ -1047,6 +1064,7 @@ static void tb_handle_hotplug(struct work_struct *work) struct tb_cm *tcm = tb_priv(tb); struct tb_switch *sw; struct tb_port *port; + mutex_lock(&tb->lock); if (!tcm->hotplug_active) goto out; /* during init, suspend or shutdown */ @@ -1103,6 +1121,7 @@ static void tb_handle_hotplug(struct work_struct *work) port->xdomain = NULL; __tb_disconnect_xdomain_paths(tb, xd); tb_xdomain_put(xd); + tb_port_unconfigure_xdomain(port); } else if (tb_port_is_dpout(port) || tb_port_is_dpin(port)) { tb_dp_resource_unavailable(tb, port); } else { @@ -1269,13 +1288,17 @@ static void tb_restore_children(struct tb_switch *sw) tb_sw_warn(sw, "failed to restore TMU configuration\n"); tb_switch_for_each_port(sw, port) { - if (!tb_port_has_remote(port)) + if (!tb_port_has_remote(port) && !port->xdomain) continue; - tb_switch_lane_bonding_enable(port->remote->sw); - tb_switch_configure_link(port->remote->sw); + if (port->remote) { + tb_switch_lane_bonding_enable(port->remote->sw); + tb_switch_configure_link(port->remote->sw); - tb_restore_children(port->remote->sw); + tb_restore_children(port->remote->sw); + } else if (port->xdomain) { + tb_port_configure_xdomain(port); + } } } @@ -1321,6 +1344,7 @@ static int tb_free_unplugged_xdomains(struct tb_switch *sw) if (port->xdomain && port->xdomain->is_unplugged) { tb_retimer_remove_all(port); tb_xdomain_remove(port->xdomain); + tb_port_unconfigure_xdomain(port); port->xdomain = NULL; ret++; } else if (port->remote) { |