Commit 768e6fe6 authored by Mika Westerberg's avatar Mika Westerberg
Browse files

thunderbolt: Initialize CL states from the hardware



In case the boot firmware enabled any of them, read the currently
configured CL states and update the router structure accordingly.

Signed-off-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
parent b5d15961
Loading
Loading
Loading
Loading
+73 −27
Original line number Diff line number Diff line
@@ -15,6 +15,21 @@ static bool clx_enabled = true;
module_param_named(clx, clx_enabled, bool, 0444);
MODULE_PARM_DESC(clx, "allow low power states on the high-speed lanes (default: true)");

static const char *clx_name(unsigned int clx)
{
	if (!clx)
		return "disabled";

	if (clx & TB_CL2)
		return "CL0s/CL1/CL2";
	if (clx & TB_CL1)
		return "CL0s/CL1";
	if (clx & TB_CL0S)
		return "CL0s";

	return "unknown";
}

static int tb_port_pm_secondary_set(struct tb_port *port, bool secondary)
{
	u32 phy;
@@ -117,6 +132,29 @@ static int tb_port_clx_enable(struct tb_port *port, unsigned int clx)
	return tb_port_clx_set(port, clx, true);
}

static int tb_port_clx(struct tb_port *port)
{
	u32 val;
	int ret;

	if (!tb_port_clx_supported(port, TB_CL0S | TB_CL1 | TB_CL2))
		return 0;

	ret = tb_port_read(port, &val, TB_CFG_PORT,
			   port->cap_phy + LANE_ADP_CS_1, 1);
	if (ret)
		return ret;

	if (val & LANE_ADP_CS_1_CL0S_ENABLE)
		ret |= TB_CL0S;
	if (val & LANE_ADP_CS_1_CL1_ENABLE)
		ret |= TB_CL1;
	if (val & LANE_ADP_CS_1_CL2_ENABLE)
		ret |= TB_CL2;

	return ret;
}

/**
 * tb_port_clx_is_enabled() - Is given CL state enabled
 * @port: USB4 port to check
@@ -126,25 +164,45 @@ static int tb_port_clx_enable(struct tb_port *port, unsigned int clx)
 */
bool tb_port_clx_is_enabled(struct tb_port *port, unsigned int clx)
{
	u32 val, mask = 0;
	int ret;
	return !!(tb_port_clx(port) & clx);
}

	if (!tb_port_clx_supported(port, clx))
		return false;
/**
 * tb_switch_clx_init() - Initialize router CL states
 * @sw: Router
 *
 * Can be called for any router. Initializes the current CL state by
 * reading it from the hardware.
 *
 * Returns %0 in case of success and negative errno in case of failure.
 */
int tb_switch_clx_init(struct tb_switch *sw)
{
	struct tb_port *up, *down;
	unsigned int clx, tmp;

	if (clx & TB_CL0S)
		mask |= LANE_ADP_CS_1_CL0S_ENABLE;
	if (clx & TB_CL1)
		mask |= LANE_ADP_CS_1_CL1_ENABLE;
	if (clx & TB_CL2)
		mask |= LANE_ADP_CS_1_CL2_ENABLE;
	if (tb_switch_is_icm(sw))
		return 0;

	ret = tb_port_read(port, &val, TB_CFG_PORT,
			   port->cap_phy + LANE_ADP_CS_1, 1);
	if (ret)
		return false;
	if (!tb_route(sw))
		return 0;

	return !!(val & mask);
	if (!tb_switch_clx_is_supported(sw))
		return 0;

	up = tb_upstream_port(sw);
	down = tb_switch_downstream_port(sw);

	clx = tb_port_clx(up);
	tmp = tb_port_clx(down);
	if (clx != tmp)
		tb_sw_warn(sw, "CLx: inconsistent configuration %#x != %#x\n",
			   clx, tmp);

	tb_sw_dbg(sw, "CLx: current mode: %s\n", clx_name(clx));

	sw->clx = clx;
	return 0;
}

static int tb_switch_pm_secondary_resolve(struct tb_switch *sw)
@@ -240,18 +298,6 @@ static bool validate_mask(unsigned int clx)
	return true;
}

static const char *clx_name(unsigned int clx)
{
	if (clx & TB_CL2)
		return "CL0s/CL1/CL2";
	if (clx & TB_CL1)
		return "CL0s/CL1";
	if (clx & TB_CL0S)
		return "CL0s";

	return "unknown";
}

/**
 * tb_switch_clx_enable() - Enable CLx on upstream port of specified router
 * @sw: Router to enable CLx for
+4 −0
Original line number Diff line number Diff line
@@ -2859,6 +2859,10 @@ int tb_switch_add(struct tb_switch *sw)
		if (ret)
			return ret;

		ret = tb_switch_clx_init(sw);
		if (ret)
			return ret;

		ret = tb_switch_tmu_init(sw);
		if (ret)
			return ret;
+1 −0
Original line number Diff line number Diff line
@@ -1002,6 +1002,7 @@ static inline bool tb_switch_tmu_is_enabled(const struct tb_switch *sw)

bool tb_port_clx_is_enabled(struct tb_port *port, unsigned int clx);

int tb_switch_clx_init(struct tb_switch *sw);
bool tb_switch_clx_is_supported(const struct tb_switch *sw);
int tb_switch_clx_enable(struct tb_switch *sw, unsigned int clx);
int tb_switch_clx_disable(struct tb_switch *sw);