Commit de462039 authored by Mika Westerberg's avatar Mika Westerberg

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: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
parent 5cb6ed31
...@@ -94,9 +94,6 @@ int tb_lc_configure_link(struct tb_switch *sw) ...@@ -94,9 +94,6 @@ int tb_lc_configure_link(struct tb_switch *sw)
struct tb_port *up, *down; struct tb_port *up, *down;
int ret; int ret;
if (!tb_route(sw) || tb_switch_is_icm(sw))
return 0;
up = tb_upstream_port(sw); up = tb_upstream_port(sw);
down = tb_port_at(tb_route(sw), tb_to_switch(sw->dev.parent)); down = tb_port_at(tb_route(sw), tb_to_switch(sw->dev.parent));
...@@ -124,9 +121,6 @@ void tb_lc_unconfigure_link(struct tb_switch *sw) ...@@ -124,9 +121,6 @@ void tb_lc_unconfigure_link(struct tb_switch *sw)
{ {
struct tb_port *up, *down; struct tb_port *up, *down;
if (sw->is_unplugged || !tb_route(sw) || tb_switch_is_icm(sw))
return;
up = tb_upstream_port(sw); up = tb_upstream_port(sw);
down = tb_port_at(tb_route(sw), tb_to_switch(sw->dev.parent)); down = tb_port_at(tb_route(sw), tb_to_switch(sw->dev.parent));
......
...@@ -2011,10 +2011,6 @@ int tb_switch_configure(struct tb_switch *sw) ...@@ -2011,10 +2011,6 @@ int tb_switch_configure(struct tb_switch *sw)
return ret; return ret;
ret = usb4_switch_setup(sw); ret = usb4_switch_setup(sw);
if (ret)
return ret;
ret = usb4_switch_configure_link(sw);
} else { } else {
if (sw->config.vendor_id != PCI_VENDOR_ID_INTEL) if (sw->config.vendor_id != PCI_VENDOR_ID_INTEL)
tb_sw_warn(sw, "unknown switch vendor id %#x\n", tb_sw_warn(sw, "unknown switch vendor id %#x\n",
...@@ -2028,10 +2024,6 @@ int tb_switch_configure(struct tb_switch *sw) ...@@ -2028,10 +2024,6 @@ int tb_switch_configure(struct tb_switch *sw)
/* Enumerate the switch */ /* Enumerate the switch */
ret = tb_sw_write(sw, (u32 *)&sw->config + 1, TB_CFG_SWITCH, ret = tb_sw_write(sw, (u32 *)&sw->config + 1, TB_CFG_SWITCH,
ROUTER_CS_1, 3); ROUTER_CS_1, 3);
if (ret)
return ret;
ret = tb_lc_configure_link(sw);
} }
if (ret) if (ret)
return ret; return ret;
...@@ -2314,6 +2306,48 @@ void tb_switch_lane_bonding_disable(struct tb_switch *sw) ...@@ -2314,6 +2306,48 @@ void tb_switch_lane_bonding_disable(struct tb_switch *sw)
tb_sw_dbg(sw, "lane bonding disabled\n"); tb_sw_dbg(sw, "lane bonding disabled\n");
} }
/**
* 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 * tb_switch_add() - Add a switch to the domain
* @sw: Switch to add * @sw: Switch to add
...@@ -2448,11 +2482,6 @@ void tb_switch_remove(struct tb_switch *sw) ...@@ -2448,11 +2482,6 @@ void tb_switch_remove(struct tb_switch *sw)
if (!sw->is_unplugged) if (!sw->is_unplugged)
tb_plug_events_active(sw, false); 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); tb_switch_nvm_remove(sw);
if (tb_route(sw)) if (tb_route(sw))
......
...@@ -593,6 +593,8 @@ static void tb_scan_port(struct tb_port *port) ...@@ -593,6 +593,8 @@ static void tb_scan_port(struct tb_port *port)
/* Enable lane bonding if supported */ /* Enable lane bonding if supported */
tb_switch_lane_bonding_enable(sw); tb_switch_lane_bonding_enable(sw);
/* Set the link configured */
tb_switch_configure_link(sw);
if (tb_enable_tmu(sw)) if (tb_enable_tmu(sw))
tb_sw_warn(sw, "failed to enable TMU\n"); tb_sw_warn(sw, "failed to enable TMU\n");
...@@ -681,6 +683,7 @@ static void tb_free_unplugged_children(struct tb_switch *sw) ...@@ -681,6 +683,7 @@ static void tb_free_unplugged_children(struct tb_switch *sw)
if (port->remote->sw->is_unplugged) { if (port->remote->sw->is_unplugged) {
tb_retimer_remove_all(port); tb_retimer_remove_all(port);
tb_remove_dp_resources(port->remote->sw); tb_remove_dp_resources(port->remote->sw);
tb_switch_unconfigure_link(port->remote->sw);
tb_switch_lane_bonding_disable(port->remote->sw); tb_switch_lane_bonding_disable(port->remote->sw);
tb_switch_remove(port->remote->sw); tb_switch_remove(port->remote->sw);
port->remote = NULL; port->remote = NULL;
...@@ -1076,6 +1079,7 @@ static void tb_handle_hotplug(struct work_struct *work) ...@@ -1076,6 +1079,7 @@ static void tb_handle_hotplug(struct work_struct *work)
tb_free_invalid_tunnels(tb); tb_free_invalid_tunnels(tb);
tb_remove_dp_resources(port->remote->sw); tb_remove_dp_resources(port->remote->sw);
tb_switch_tmu_disable(port->remote->sw); tb_switch_tmu_disable(port->remote->sw);
tb_switch_unconfigure_link(port->remote->sw);
tb_switch_lane_bonding_disable(port->remote->sw); tb_switch_lane_bonding_disable(port->remote->sw);
tb_switch_remove(port->remote->sw); tb_switch_remove(port->remote->sw);
port->remote = NULL; port->remote = NULL;
...@@ -1269,6 +1273,7 @@ static void tb_restore_children(struct tb_switch *sw) ...@@ -1269,6 +1273,7 @@ static void tb_restore_children(struct tb_switch *sw)
continue; continue;
tb_switch_lane_bonding_enable(port->remote->sw); 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);
} }
......
...@@ -767,6 +767,8 @@ static inline bool tb_switch_is_icm(const struct tb_switch *sw) ...@@ -767,6 +767,8 @@ static inline bool tb_switch_is_icm(const struct tb_switch *sw)
int tb_switch_lane_bonding_enable(struct tb_switch *sw); int tb_switch_lane_bonding_enable(struct tb_switch *sw);
void tb_switch_lane_bonding_disable(struct tb_switch *sw); void tb_switch_lane_bonding_disable(struct tb_switch *sw);
int tb_switch_configure_link(struct tb_switch *sw);
void tb_switch_unconfigure_link(struct tb_switch *sw);
bool tb_switch_query_dp_resource(struct tb_switch *sw, struct tb_port *in); bool tb_switch_query_dp_resource(struct tb_switch *sw, struct tb_port *in);
int tb_switch_alloc_dp_resource(struct tb_switch *sw, struct tb_port *in); int tb_switch_alloc_dp_resource(struct tb_switch *sw, struct tb_port *in);
......
...@@ -368,9 +368,6 @@ int usb4_switch_configure_link(struct tb_switch *sw) ...@@ -368,9 +368,6 @@ int usb4_switch_configure_link(struct tb_switch *sw)
{ {
struct tb_port *up; struct tb_port *up;
if (!tb_route(sw))
return 0;
up = tb_upstream_port(sw); up = tb_upstream_port(sw);
return usb4_set_port_configured(up, true); return usb4_set_port_configured(up, true);
} }
...@@ -385,9 +382,6 @@ void usb4_switch_unconfigure_link(struct tb_switch *sw) ...@@ -385,9 +382,6 @@ void usb4_switch_unconfigure_link(struct tb_switch *sw)
{ {
struct tb_port *up; struct tb_port *up;
if (sw->is_unplugged || !tb_route(sw))
return;
up = tb_upstream_port(sw); up = tb_upstream_port(sw);
usb4_set_port_configured(up, false); usb4_set_port_configured(up, false);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment