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: Mika Westerberg <mika.westerberg@linux.intel.com>
This commit is contained in:
Mika Westerberg 2022-02-13 11:54:15 +02:00
parent 94581b25d8
commit 0e14dd5e14
2 changed files with 74 additions and 14 deletions

View file

@ -999,7 +999,17 @@ static bool tb_port_is_width_supported(struct tb_port *port, int 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;
int ret;
@ -1026,12 +1036,58 @@ static int tb_port_set_link_width(struct tb_port *port, unsigned int width)
return -EINVAL;
}
val |= LANE_ADP_CS_1_LB;
return tb_port_write(port, &val, TB_CFG_PORT,
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
* @port: port to enable
@ -1056,22 +1112,27 @@ int tb_port_lane_bonding_enable(struct tb_port *port)
if (ret == 1) {
ret = tb_port_set_link_width(port, 2);
if (ret)
return ret;
goto err_lane0;
}
ret = tb_port_get_link_width(port->dual_link_port);
if (ret == 1) {
ret = tb_port_set_link_width(port->dual_link_port, 2);
if (ret) {
tb_port_set_link_width(port, 1);
return ret;
}
if (ret)
goto err_lane0;
}
port->bonded = true;
port->dual_link_port->bonded = true;
ret = tb_port_set_lane_bonding(port, true);
if (ret)
goto err_lane1;
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)
*
* Disable bonding by setting the link width of the port and the
* other port in case of dual link port.
*
*/
void tb_port_lane_bonding_disable(struct tb_port *port)
{
port->dual_link_port->bonded = false;
port->bonded = false;
tb_port_set_lane_bonding(port, false);
tb_port_set_link_width(port->dual_link_port, 1);
tb_port_set_link_width(port, 1);
}

View file

@ -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_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);
void tb_port_lane_bonding_disable(struct tb_port *port);
int tb_port_wait_for_link_width(struct tb_port *port, int width,