Commit 0e14dd5e authored by Mika Westerberg's avatar Mika Westerberg

thunderbolt: Split setting link width and lane bonding into own functions

When bonding lanes over XDomain the host that has "higher" UUID triggers
link re-train for bonding, and the host that has "lower" UUID just waits
for this to happen. To support this split setting the link width and
triggering the actual bonding a separate functions that can be called as
needed.

While there remove duplicated empty line in the kernel-doc comment of
tb_port_lane_bonding_disable().
Signed-off-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
parent 94581b25
...@@ -999,7 +999,17 @@ static bool tb_port_is_width_supported(struct tb_port *port, int width) ...@@ -999,7 +999,17 @@ static bool tb_port_is_width_supported(struct tb_port *port, int width)
return !!(widths & width); return !!(widths & width);
} }
static int tb_port_set_link_width(struct tb_port *port, unsigned int width) /**
* tb_port_set_link_width() - Set target link width of the lane adapter
* @port: Lane adapter
* @width: Target link width (%1 or %2)
*
* Sets the target link width of the lane adapter to @width. Does not
* enable/disable lane bonding. For that call tb_port_set_lane_bonding().
*
* Return: %0 in case of success and negative errno in case of error
*/
int tb_port_set_link_width(struct tb_port *port, unsigned int width)
{ {
u32 val; u32 val;
int ret; int ret;
...@@ -1026,12 +1036,58 @@ static int tb_port_set_link_width(struct tb_port *port, unsigned int width) ...@@ -1026,12 +1036,58 @@ static int tb_port_set_link_width(struct tb_port *port, unsigned int width)
return -EINVAL; return -EINVAL;
} }
val |= LANE_ADP_CS_1_LB;
return tb_port_write(port, &val, TB_CFG_PORT, return tb_port_write(port, &val, TB_CFG_PORT,
port->cap_phy + LANE_ADP_CS_1, 1); port->cap_phy + LANE_ADP_CS_1, 1);
} }
/**
* tb_port_set_lane_bonding() - Enable/disable lane bonding
* @port: Lane adapter
* @bonding: enable/disable bonding
*
* Enables or disables lane bonding. This should be called after target
* link width has been set (tb_port_set_link_width()). Note in most
* cases one should use tb_port_lane_bonding_enable() instead to enable
* lane bonding.
*
* As a side effect sets @port->bonding accordingly (and does the same
* for lane 1 too).
*
* Return: %0 in case of success and negative errno in case of error
*/
int tb_port_set_lane_bonding(struct tb_port *port, bool bonding)
{
u32 val;
int ret;
if (!port->cap_phy)
return -EINVAL;
ret = tb_port_read(port, &val, TB_CFG_PORT,
port->cap_phy + LANE_ADP_CS_1, 1);
if (ret)
return ret;
if (bonding)
val |= LANE_ADP_CS_1_LB;
else
val &= ~LANE_ADP_CS_1_LB;
ret = tb_port_write(port, &val, TB_CFG_PORT,
port->cap_phy + LANE_ADP_CS_1, 1);
if (ret)
return ret;
/*
* When lane 0 bonding is set it will affect lane 1 too so
* update both.
*/
port->bonded = bonding;
port->dual_link_port->bonded = bonding;
return 0;
}
/** /**
* tb_port_lane_bonding_enable() - Enable bonding on port * tb_port_lane_bonding_enable() - Enable bonding on port
* @port: port to enable * @port: port to enable
...@@ -1056,22 +1112,27 @@ int tb_port_lane_bonding_enable(struct tb_port *port) ...@@ -1056,22 +1112,27 @@ int tb_port_lane_bonding_enable(struct tb_port *port)
if (ret == 1) { if (ret == 1) {
ret = tb_port_set_link_width(port, 2); ret = tb_port_set_link_width(port, 2);
if (ret) if (ret)
return ret; goto err_lane0;
} }
ret = tb_port_get_link_width(port->dual_link_port); ret = tb_port_get_link_width(port->dual_link_port);
if (ret == 1) { if (ret == 1) {
ret = tb_port_set_link_width(port->dual_link_port, 2); ret = tb_port_set_link_width(port->dual_link_port, 2);
if (ret) { if (ret)
tb_port_set_link_width(port, 1); goto err_lane0;
return ret;
}
} }
port->bonded = true; ret = tb_port_set_lane_bonding(port, true);
port->dual_link_port->bonded = true; if (ret)
goto err_lane1;
return 0; return 0;
err_lane1:
tb_port_set_link_width(port->dual_link_port, 1);
err_lane0:
tb_port_set_link_width(port, 1);
return ret;
} }
/** /**
...@@ -1080,13 +1141,10 @@ int tb_port_lane_bonding_enable(struct tb_port *port) ...@@ -1080,13 +1141,10 @@ int tb_port_lane_bonding_enable(struct tb_port *port)
* *
* Disable bonding by setting the link width of the port and the * Disable bonding by setting the link width of the port and the
* other port in case of dual link port. * other port in case of dual link port.
*
*/ */
void tb_port_lane_bonding_disable(struct tb_port *port) void tb_port_lane_bonding_disable(struct tb_port *port)
{ {
port->dual_link_port->bonded = false; tb_port_set_lane_bonding(port, false);
port->bonded = false;
tb_port_set_link_width(port->dual_link_port, 1); tb_port_set_link_width(port->dual_link_port, 1);
tb_port_set_link_width(port, 1); tb_port_set_link_width(port, 1);
} }
......
...@@ -1024,6 +1024,8 @@ static inline bool tb_port_use_credit_allocation(const struct tb_port *port) ...@@ -1024,6 +1024,8 @@ static inline bool tb_port_use_credit_allocation(const struct tb_port *port)
int tb_port_get_link_speed(struct tb_port *port); int tb_port_get_link_speed(struct tb_port *port);
int tb_port_get_link_width(struct tb_port *port); int tb_port_get_link_width(struct tb_port *port);
int tb_port_set_link_width(struct tb_port *port, unsigned int width);
int tb_port_set_lane_bonding(struct tb_port *port, bool bonding);
int tb_port_lane_bonding_enable(struct tb_port *port); int tb_port_lane_bonding_enable(struct tb_port *port);
void tb_port_lane_bonding_disable(struct tb_port *port); void tb_port_lane_bonding_disable(struct tb_port *port);
int tb_port_wait_for_link_width(struct tb_port *port, int width, int tb_port_wait_for_link_width(struct tb_port *port, int width,
......
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