summaryrefslogtreecommitdiff
path: root/drivers/thunderbolt
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2022-11-06 13:07:43 +0200
committerMika Westerberg <mika.westerberg@linux.intel.com>2023-06-16 09:53:28 +0300
commitfd4d58d1fef9ae9b0ee235eaad73d2e0a6a73025 (patch)
treeb7f44a45ef98c391c264e16352b634469e98eebb /drivers/thunderbolt
parentd49b4f043d63bddf4c1836623b8ae800878ed2e3 (diff)
thunderbolt: Enable CL2 low power state
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>
Diffstat (limited to 'drivers/thunderbolt')
-rw-r--r--drivers/thunderbolt/clx.c31
-rw-r--r--drivers/thunderbolt/tb.c9
2 files changed, 25 insertions, 15 deletions
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;
}