Commit ba2a2a86 authored by Gil Fine's avatar Gil Fine Committed by Mika Westerberg

thunderbolt: Keep link as asymmetric if preferred by hardware

In case of the link is brought up as asymmetric (due to hardware preference), we
honor that and don't transition it to symmetric, unless a router with symmetric
link got plugged below, in the topology (and a bandwidth allows transition to
symmetric).
Signed-off-by: default avatarGil Fine <gil.fine@linux.intel.com>
Signed-off-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
parent 2cd3da4e
......@@ -2773,6 +2773,19 @@ static void tb_switch_link_init(struct tb_switch *sw)
if (down->dual_link_port)
down->dual_link_port->bonded = bonded;
tb_port_update_credits(down);
if (tb_port_get_link_generation(up) < 4)
return;
/*
* Set the Gen 4 preferred link width. This is what the router
* prefers when the link is brought up. If the router does not
* support asymmetric link configuration, this also will be set
* to TB_LINK_WIDTH_DUAL.
*/
sw->preferred_link_width = sw->link_width;
tb_sw_dbg(sw, "preferred link width %s\n",
tb_width_name(sw->preferred_link_width));
}
/**
......
......@@ -1173,14 +1173,15 @@ static int tb_configure_asym(struct tb *tb, struct tb_port *src_port,
* @dst_port: Destination adapter
* @requested_up: New lower bandwidth request upstream (Mb/s)
* @requested_down: New lower bandwidth request downstream (Mb/s)
* @keep_asym: Keep asymmetric link if preferred
*
* Goes over each link from @src_port to @dst_port and tries to
* transition the link to symmetric if the currently consumed bandwidth
* allows.
* allows and link asymmetric preference is ignored (if @keep_asym is %false).
*/
static int tb_configure_sym(struct tb *tb, struct tb_port *src_port,
struct tb_port *dst_port, int requested_up,
int requested_down)
int requested_down, bool keep_asym)
{
bool clx = false, clx_disabled = false, downstream;
struct tb_switch *sw;
......@@ -1229,6 +1230,19 @@ static int tb_configure_sym(struct tb *tb, struct tb_port *src_port,
if (up->sw->link_width == TB_LINK_WIDTH_DUAL)
continue;
/*
* Here consumed < threshold so we can transition the
* link to symmetric.
*
* However, if the router prefers asymmetric link we
* honor that (unless @keep_asym is %false).
*/
if (keep_asym &&
up->sw->preferred_link_width > TB_LINK_WIDTH_DUAL) {
tb_sw_dbg(up->sw, "keeping preferred asymmetric link\n");
continue;
}
/* Disable CL states before doing any transitions */
if (!clx_disabled) {
clx = tb_disable_clx(sw);
......@@ -1282,7 +1296,7 @@ static void tb_configure_link(struct tb_port *down, struct tb_port *up,
struct tb_port *host_port;
host_port = tb_port_at(tb_route(sw), tb->root_switch);
tb_configure_sym(tb, host_port, up, 0, 0);
tb_configure_sym(tb, host_port, up, 0, 0, false);
}
/* Set the link configured */
......@@ -1467,7 +1481,7 @@ static void tb_deactivate_and_free_tunnel(struct tb_tunnel *tunnel)
* If bandwidth on a link is < asym_threshold
* transition the link to symmetric.
*/
tb_configure_sym(tb, src_port, dst_port, 0, 0);
tb_configure_sym(tb, src_port, dst_port, 0, 0, true);
/* Now we can allow the domain to runtime suspend again */
pm_runtime_mark_last_busy(&dst_port->sw->dev);
pm_runtime_put_autosuspend(&dst_port->sw->dev);
......@@ -2289,7 +2303,7 @@ static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up,
* If bandwidth on a link is < asym_threshold transition
* the link to symmetric.
*/
tb_configure_sym(tb, in, out, *requested_up, *requested_down);
tb_configure_sym(tb, in, out, *requested_up, *requested_down, true);
/*
* If requested bandwidth is less or equal than what is
* currently allocated to that tunnel we simply change
......@@ -2332,7 +2346,7 @@ static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up,
ret = tb_configure_asym(tb, in, out, *requested_up,
*requested_down);
if (ret) {
tb_configure_sym(tb, in, out, 0, 0);
tb_configure_sym(tb, in, out, 0, 0, true);
return ret;
}
......@@ -2340,7 +2354,7 @@ static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up,
requested_down);
if (ret) {
tb_tunnel_warn(tunnel, "failed to allocate bandwidth\n");
tb_configure_sym(tb, in, out, 0, 0);
tb_configure_sym(tb, in, out, 0, 0, true);
}
} else {
ret = -ENOBUFS;
......
......@@ -125,6 +125,7 @@ struct tb_switch_tmu {
* @device_name: Name of the device (or %NULL if not known)
* @link_speed: Speed of the link in Gb/s
* @link_width: Width of the upstream facing link
* @preferred_link_width: Router preferred link width (only set for Gen 4 links)
* @link_usb4: Upstream link is USB4
* @generation: Switch Thunderbolt generation
* @cap_plug_events: Offset to the plug events capability (%0 if not found)
......@@ -178,6 +179,7 @@ struct tb_switch {
const char *device_name;
unsigned int link_speed;
enum tb_link_width link_width;
enum tb_link_width preferred_link_width;
bool link_usb4;
unsigned int generation;
int cap_plug_events;
......
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