diff mbox series

[v2,17/20] thunderbolt: Enable CL2 low power state

Message ID 20230612082145.62218-18-mika.westerberg@linux.intel.com (mailing list archive)
State Accepted
Commit fd4d58d1fef9ae9b0ee235eaad73d2e0a6a73025
Headers show
Series thunderbolt: Initial USB4 v2 support | expand

Commit Message

Mika Westerberg June 12, 2023, 8:21 a.m. UTC
For USB4 v2 routers we can also enable CL2 which allows better power
savings and thermal management than CL0s and CL1.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
 drivers/thunderbolt/clx.c | 31 +++++++++++++++++++------------
 drivers/thunderbolt/tb.c  |  9 ++++++---
 2 files changed, 25 insertions(+), 15 deletions(-)
diff mbox series

Patch

diff --git a/drivers/thunderbolt/clx.c b/drivers/thunderbolt/clx.c
index 604cceb23659..13d217ae98e6 100644
--- a/drivers/thunderbolt/clx.c
+++ b/drivers/thunderbolt/clx.c
@@ -17,17 +17,22 @@  MODULE_PARM_DESC(clx, "allow low power states on the high-speed lanes (default:
 
 static const char *clx_name(unsigned int clx)
 {
-	if (!clx)
-		return "disabled";
-
-	if (clx & TB_CL2)
+	switch (clx) {
+	case TB_CL0S | TB_CL1 | TB_CL2:
 		return "CL0s/CL1/CL2";
-	if (clx & TB_CL1)
+	case TB_CL1 | TB_CL2:
+		return "CL1/CL2";
+	case TB_CL0S | TB_CL2:
+		return "CL0s/CL2";
+	case TB_CL0S | TB_CL1:
 		return "CL0s/CL1";
-	if (clx & TB_CL0S)
+	case TB_CL0S:
 		return "CL0s";
-
-	return "unknown";
+	case 0:
+		return "disabled";
+	default:
+		return "unknown";
+	}
 }
 
 static int tb_port_pm_secondary_set(struct tb_port *port, bool secondary)
@@ -104,6 +109,8 @@  static int tb_port_clx_set(struct tb_port *port, unsigned int clx, bool enable)
 		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 (!mask)
 		return -EOPNOTSUPP;
@@ -291,8 +298,6 @@  bool tb_switch_clx_is_supported(const struct tb_switch *sw)
 static bool validate_mask(unsigned int clx)
 {
 	/* Previous states need to be enabled */
-	if (clx & TB_CL2)
-		return (clx & (TB_CL0S | TB_CL1)) == (TB_CL0S | TB_CL1);
 	if (clx & TB_CL1)
 		return (clx & TB_CL0S) == TB_CL0S;
 	return true;
@@ -331,8 +336,10 @@  int tb_switch_clx_enable(struct tb_switch *sw, unsigned int clx)
 	    !tb_switch_clx_is_supported(sw))
 		return 0;
 
-	/* CL2 is not yet supported */
-	if (clx & TB_CL2)
+	/* Only support CL2 for v2 routers */
+	if ((clx & TB_CL2) &&
+	    (usb4_switch_version(parent_sw) < 2 ||
+	     usb4_switch_version(sw) < 2))
 		return -EOPNOTSUPP;
 
 	ret = tb_switch_pm_secondary_resolve(sw);
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index ff034975a87e..79efc85db38b 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -244,6 +244,7 @@  static void tb_discover_dp_resources(struct tb *tb)
 static int tb_enable_clx(struct tb_switch *sw)
 {
 	struct tb_cm *tcm = tb_priv(sw->tb);
+	unsigned int clx = TB_CL0S | TB_CL1;
 	const struct tb_tunnel *tunnel;
 	int ret;
 
@@ -275,10 +276,12 @@  static int tb_enable_clx(struct tb_switch *sw)
 	}
 
 	/*
-	 * CL0s and CL1 are enabled and supported together.
-	 * Silently ignore CLx enabling in case CLx is not supported.
+	 * Initially try with CL2. If that's not supported by the
+	 * topology try with CL0s and CL1 and then give up.
 	 */
-	ret = tb_switch_clx_enable(sw, TB_CL0S | TB_CL1);
+	ret = tb_switch_clx_enable(sw, clx | TB_CL2);
+	if (ret == -EOPNOTSUPP)
+		ret = tb_switch_clx_enable(sw, clx);
 	return ret == -EOPNOTSUPP ? 0 : ret;
 }