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

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
Loading
Loading
Loading
Loading
+72 −14
Original line number Diff line number Diff line
@@ -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,10 +1036,56 @@ static int tb_port_set_link_width(struct tb_port *port, unsigned int width)
		return -EINVAL;
	}

	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;

	return tb_port_write(port, &val, TB_CFG_PORT,
	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;
}

/**
@@ -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);
}
+2 −0
Original line number Diff line number Diff line
@@ -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,