From: Mika Westerberg <mika.westerberg@linux.intel.com>
To: Gil Fine <gil.fine@intel.com>
Cc: andreas.noever@gmail.com, michael.jamet@intel.com,
YehezkelShB@gmail.com, linux-usb@vger.kernel.org,
lukas@wunner.de
Subject: Re: [PATCH 4/5] thunderbolt: Add CL1 support for USB4 and Titan Ridge routers
Date: Mon, 2 May 2022 13:04:11 +0300 [thread overview]
Message-ID: <Ym+sm09F9Atu5ghC@lahna> (raw)
In-Reply-To: <20220501203321.19021-5-gil.fine@intel.com>
Hi Gil,
On Sun, May 01, 2022 at 11:33:20PM +0300, Gil Fine wrote:
> In this patch we add support for a second low power state of the link: CL1.
> Low power states (called collectively CLx) are used to reduce
> transmitter and receiver power when a high-speed lane is idle.
> We enable it, if both sides of the link support it,
> and only for the first hop router (i.e. the first device that connected
> to the host router). This is needed for better thermal management.
>
> Signed-off-by: Gil Fine <gil.fine@intel.com>
> ---
> drivers/thunderbolt/switch.c | 79 ++++++++-------
> drivers/thunderbolt/tb.c | 24 +++--
> drivers/thunderbolt/tb.h | 22 ++++-
> drivers/thunderbolt/tb_regs.h | 8 ++
> drivers/thunderbolt/tmu.c | 177 ++++++++++++++++++++++++++++------
> 5 files changed, 237 insertions(+), 73 deletions(-)
>
> diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
> index 42b7daaf9c4d..4288cb5550f8 100644
> --- a/drivers/thunderbolt/switch.c
> +++ b/drivers/thunderbolt/switch.c
> @@ -3064,7 +3064,7 @@ void tb_switch_suspend(struct tb_switch *sw, bool runtime)
> * done for USB4 device too as CLx is re-enabled at resume.
> */
> if (tb_switch_is_clx_enabled(sw)) {
> - if (tb_switch_disable_clx(sw, TB_CL0S))
> + if (tb_switch_disable_clx(sw, TB_CL1))
Hm, what if the router only supports CL0s? Will this still enable CL0s
then?
> tb_sw_warn(sw, "failed to disable CLx on upstream port\n");
> }
>
> @@ -3358,12 +3358,12 @@ static bool tb_port_clx_supported(struct tb_port *port, enum tb_clx clx)
>
> switch (clx) {
> case TB_CL0S:
> + case TB_CL1:
> /* CL0s support requires also CL1 support */
> mask = LANE_ADP_CS_0_CL0S_SUPPORT | LANE_ADP_CS_0_CL1_SUPPORT;
> break;
>
> - /* For now we support only CL0s. Not CL1, CL2 */
> - case TB_CL1:
> + /* For now we support only CL0s and CL1. Not CL2 */
> case TB_CL2:
> default:
> return false;
> @@ -3377,12 +3377,7 @@ static bool tb_port_clx_supported(struct tb_port *port, enum tb_clx clx)
> return !!(val & mask);
> }
>
> -static inline bool tb_port_cl0s_supported(struct tb_port *port)
> -{
> - return tb_port_clx_supported(port, TB_CL0S);
> -}
> -
> -static int __tb_port_cl0s_set(struct tb_port *port, bool enable)
> +static int __tb_port_cl0s_cl1_set(struct tb_port *port, bool enable)
> {
> u32 phy, mask;
> int ret;
> @@ -3403,20 +3398,32 @@ static int __tb_port_cl0s_set(struct tb_port *port, bool enable)
> port->cap_phy + LANE_ADP_CS_1, 1);
> }
>
> -static int tb_port_cl0s_disable(struct tb_port *port)
> +static int tb_port_cl0s_cl1_disable(struct tb_port *port)
> +{
> + return __tb_port_cl0s_cl1_set(port, false);
> +}
> +
> +static int tb_port_cl0s_cl1_enable(struct tb_port *port)
> {
> - return __tb_port_cl0s_set(port, false);
> + return __tb_port_cl0s_cl1_set(port, true);
> }
>
> -static int tb_port_cl0s_enable(struct tb_port *port)
> +static const char *tb_switch_clx_name(enum tb_clx clx)
> {
> - return __tb_port_cl0s_set(port, true);
> + switch (clx) {
> + case TB_CL0S:
> + return "CL0s";
> + case TB_CL1:
> + return "CL1";
> + default:
> + return "Unknown";
> + }
> }
>
> -static int tb_switch_enable_cl0s(struct tb_switch *sw)
> +static int __tb_switch_enable_clx(struct tb_switch *sw, enum tb_clx clx)
> {
> struct tb_switch *parent = tb_switch_parent(sw);
> - bool up_cl0s_support, down_cl0s_support;
> + bool up_clx_support, down_clx_support;
> struct tb_port *up, *down;
> int ret;
>
> @@ -3441,37 +3448,37 @@ static int tb_switch_enable_cl0s(struct tb_switch *sw)
> up = tb_upstream_port(sw);
> down = tb_port_at(tb_route(sw), parent);
>
> - up_cl0s_support = tb_port_cl0s_supported(up);
> - down_cl0s_support = tb_port_cl0s_supported(down);
> + up_clx_support = tb_port_clx_supported(up, clx);
> + down_clx_support = tb_port_clx_supported(down, clx);
>
> - tb_port_dbg(up, "CL0s %ssupported\n",
> - up_cl0s_support ? "" : "not ");
> - tb_port_dbg(down, "CL0s %ssupported\n",
> - down_cl0s_support ? "" : "not ");
> + tb_port_dbg(up, "%s %ssupported\n", tb_switch_clx_name(clx),
> + up_clx_support ? "" : "not ");
> + tb_port_dbg(down, "%s %ssupported\n", tb_switch_clx_name(clx),
> + down_clx_support ? "" : "not ");
>
> - if (!up_cl0s_support || !down_cl0s_support)
> + if (!up_clx_support || !down_clx_support)
> return -EOPNOTSUPP;
>
> - ret = tb_port_cl0s_enable(up);
> + ret = tb_port_cl0s_cl1_enable(up);
> if (ret)
> return ret;
>
> - ret = tb_port_cl0s_enable(down);
> + ret = tb_port_cl0s_cl1_enable(down);
> if (ret) {
> - tb_port_cl0s_disable(up);
> + tb_port_cl0s_cl1_disable(up);
> return ret;
> }
>
> ret = tb_switch_mask_clx_objections(sw);
> if (ret) {
> - tb_port_cl0s_disable(up);
> - tb_port_cl0s_disable(down);
> + tb_port_cl0s_cl1_disable(up);
> + tb_port_cl0s_cl1_disable(down);
> return ret;
> }
>
> - sw->clx = TB_CL0S;
> + sw->clx = clx;
>
> - tb_port_dbg(up, "CL0s enabled\n");
> + tb_port_dbg(up, "%s enabled\n", tb_switch_clx_name(clx));
> return 0;
> }
>
> @@ -3505,14 +3512,15 @@ int tb_switch_enable_clx(struct tb_switch *sw, enum tb_clx clx)
>
> switch (clx) {
> case TB_CL0S:
> - return tb_switch_enable_cl0s(sw);
> + case TB_CL1:
> + return __tb_switch_enable_clx(sw, clx);
>
> default:
> return -EOPNOTSUPP;
> }
> }
>
> -static int tb_switch_disable_cl0s(struct tb_switch *sw)
> +static int tb_switch_disable_cl0s_cl1(struct tb_switch *sw)
> {
> struct tb_switch *parent = tb_switch_parent(sw);
> struct tb_port *up, *down;
> @@ -3534,17 +3542,17 @@ static int tb_switch_disable_cl0s(struct tb_switch *sw)
>
> up = tb_upstream_port(sw);
> down = tb_port_at(tb_route(sw), parent);
> - ret = tb_port_cl0s_disable(up);
> + ret = tb_port_cl0s_cl1_disable(up);
> if (ret)
> return ret;
>
> - ret = tb_port_cl0s_disable(down);
> + ret = tb_port_cl0s_cl1_disable(down);
> if (ret)
> return ret;
>
> sw->clx = TB_CLX_DISABLE;
>
> - tb_port_dbg(up, "CL0s disabled\n");
> + tb_port_dbg(up, "CL0s, CL1 disabled\n");
> return 0;
> }
>
> @@ -3562,7 +3570,8 @@ int tb_switch_disable_clx(struct tb_switch *sw, enum tb_clx clx)
>
> switch (clx) {
> case TB_CL0S:
> - return tb_switch_disable_cl0s(sw);
> + case TB_CL1:
> + return tb_switch_disable_cl0s_cl1(sw);
>
> default:
> return -EOPNOTSUPP;
> diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
> index 7419cd1aefba..05a084e3e9f6 100644
> --- a/drivers/thunderbolt/tb.c
> +++ b/drivers/thunderbolt/tb.c
> @@ -221,7 +221,7 @@ static int tb_enable_tmu(struct tb_switch *sw)
> int ret;
>
> /* If it is already enabled in correct mode, don't touch it */
> - if (tb_switch_tmu_hifi_is_enabled(sw, sw->tmu.unidirectional_request))
> + if (tb_switch_tmu_is_enabled(sw, sw->tmu.unidirectional_request))
> return 0;
>
> ret = tb_switch_tmu_disable(sw);
> @@ -671,12 +671,19 @@ static void tb_scan_port(struct tb_port *port)
> /* Set the link configured */
> tb_switch_configure_link(sw);
> /* Silently ignore CLx enabling in case CLx is not supported */
> - ret = tb_switch_enable_clx(sw, TB_CL0S);
> + ret = tb_switch_enable_clx(sw, TB_CL1);
> if (ret && ret != -EOPNOTSUPP)
> tb_sw_warn(sw, "failed to enable CLx on upstream port\n");
>
> - tb_switch_tmu_configure(sw, TB_SWITCH_TMU_RATE_HIFI,
> - tb_switch_is_clx_enabled(sw));
> + if (tb_switch_is_clx_enabled(sw))
> + /*
> + * To support highest CLx state, we set host router's TMU to
> + * Normal-Uni mode.
> + */
> + tb_switch_tmu_configure(sw, TB_SWITCH_TMU_RATE_NORMAL, true);
> + else
> + /* If CLx disabled, configure router's TMU to HiFi-Bidir mode*/
> + tb_switch_tmu_configure(sw, TB_SWITCH_TMU_RATE_HIFI, false);
>
> if (tb_enable_tmu(sw))
> tb_sw_warn(sw, "failed to enable TMU\n");
> @@ -1416,7 +1423,12 @@ static int tb_start(struct tb *tb)
> return ret;
> }
>
> - tb_switch_tmu_configure(tb->root_switch, TB_SWITCH_TMU_RATE_HIFI, false);
> + /*
> + * To support highest CLx state, we set host router's TMU to
> + * Normal mode.
> + */
> + tb_switch_tmu_configure(tb->root_switch, TB_SWITCH_TMU_RATE_NORMAL,
> + false);
> /* Enable TMU if it is off */
> tb_switch_tmu_enable(tb->root_switch);
> /* Full scan to discover devices added before the driver was loaded. */
> @@ -1462,7 +1474,7 @@ static void tb_restore_children(struct tb_switch *sw)
> return;
>
> /* Silently ignore CLx re-enabling in case CLx is not supported */
> - ret = tb_switch_enable_clx(sw, TB_CL0S);
> + ret = tb_switch_enable_clx(sw, TB_CL1);
> if (ret && ret != -EOPNOTSUPP)
> tb_sw_warn(sw, "failed to re-enable CLx on upstream port\n");
>
> diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
> index ad025ff142ba..6a7204cf67f1 100644
> --- a/drivers/thunderbolt/tb.h
> +++ b/drivers/thunderbolt/tb.h
> @@ -934,17 +934,17 @@ void tb_switch_tmu_configure(struct tb_switch *sw,
> enum tb_switch_tmu_rate rate,
> bool unidirectional);
> /**
> - * tb_switch_tmu_hifi_is_enabled() - Checks if the specified TMU mode is enabled
> + * tb_switch_tmu_is_enabled() - Checks if the specified TMU mode is enabled
> * @sw: Router whose TMU mode to check
> * @unidirectional: If uni-directional (bi-directional otherwise)
> *
> * Return true if hardware TMU configuration matches the one passed in
> - * as parameter. That is HiFi and either uni-directional or bi-directional.
> + * as parameter. That is HiFi/Normal and either uni-directional or bi-directional.
> */
> -static inline bool tb_switch_tmu_hifi_is_enabled(const struct tb_switch *sw,
> - bool unidirectional)
> +static inline bool tb_switch_tmu_is_enabled(const struct tb_switch *sw,
> + bool unidirectional)
> {
> - return sw->tmu.rate == TB_SWITCH_TMU_RATE_HIFI &&
> + return sw->tmu.rate == sw->tmu.rate_request &&
> sw->tmu.unidirectional == unidirectional;
> }
>
> @@ -975,6 +975,18 @@ static inline bool tb_switch_is_cl0s_enabled(const struct tb_switch *sw)
> return sw->clx == TB_CL0S;
> }
>
> +/**
> + * tb_switch_is_cl1_enabled() - Checks if the CL1 is enabled
> + * @sw: Router to check for the CL1
> + *
> + * Checks if the CL1 is enabled on the router upstream link.
> + * Not applicable for a host router.
> + */
> +static inline bool tb_switch_is_cl1_enabled(const struct tb_switch *sw)
> +{
> + return sw->clx == TB_CL1;
> +}
> +
> /**
> * tb_switch_is_clx_supported() - Is CLx supported on this type of router
> * @sw: The router to check CLx support for
> diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h
> index b301eeb0c89b..f88dd27e4f62 100644
> --- a/drivers/thunderbolt/tb_regs.h
> +++ b/drivers/thunderbolt/tb_regs.h
> @@ -234,6 +234,8 @@ enum usb4_switch_op {
>
> /* Router TMU configuration */
> #define TMU_RTR_CS_0 0x00
> +#define TMU_RTR_CS_0_FREQ_WIND_MASK GENMASK(26, 16)
> +#define TMU_RTR_CS_0_FREQ_WIND_SHIFT 16
> #define TMU_RTR_CS_0_TD BIT(27)
> #define TMU_RTR_CS_0_UCAP BIT(30)
> #define TMU_RTR_CS_1 0x01
> @@ -244,6 +246,12 @@ enum usb4_switch_op {
> #define TMU_RTR_CS_3_LOCAL_TIME_NS_MASK GENMASK(15, 0)
> #define TMU_RTR_CS_3_TS_PACKET_INTERVAL_MASK GENMASK(31, 16)
> #define TMU_RTR_CS_3_TS_PACKET_INTERVAL_SHIFT 16
> +#define TMU_RTR_CS_15 0xf
> +#define TMU_RTR_CS_15_AVG_MASK GENMASK(5, 0)
> +#define TMU_RTR_CS_15_FREQ_AVG_SHIFT 0
> +#define TMU_RTR_CS_15_DELAY_AVG_SHIFT 6
> +#define TMU_RTR_CS_15_OFFSET_AVG_SHIFT 12
> +#define TMU_RTR_CS_15_ERROR_AVG_SHIFT 18
> #define TMU_RTR_CS_22 0x16
> #define TMU_RTR_CS_24 0x18
> #define TMU_RTR_CS_25 0x19
> diff --git a/drivers/thunderbolt/tmu.c b/drivers/thunderbolt/tmu.c
> index 985ca43b8f39..a03c57a8728c 100644
> --- a/drivers/thunderbolt/tmu.c
> +++ b/drivers/thunderbolt/tmu.c
> @@ -11,6 +11,55 @@
>
> #include "tb.h"
>
> +static int tb_switch_set_tmu_mode_params(struct tb_switch *sw,
> + enum tb_switch_tmu_rate rate)
> +{
> + u32 freq_meas_wind[2] = { 30, 800 };
> + u32 avg_const[2] = { 4, 8 };
> + u32 freq, avg, val;
> + int ret;
> +
> + if (rate == TB_SWITCH_TMU_RATE_NORMAL) {
> + freq = freq_meas_wind[0];
> + avg = avg_const[0];
> + } else if (rate == TB_SWITCH_TMU_RATE_HIFI) {
> + freq = freq_meas_wind[1];
> + avg = avg_const[1];
> + } else {
> + return 0;
> + }
> +
> + ret = tb_sw_read(sw, &val, TB_CFG_SWITCH,
> + sw->tmu.cap + TMU_RTR_CS_0, 1);
> + if (ret)
> + return ret;
> +
> + val &= ~TMU_RTR_CS_0_FREQ_WIND_MASK;
> + val |= freq << TMU_RTR_CS_0_FREQ_WIND_SHIFT;
> +
> + ret = tb_sw_write(sw, &val, TB_CFG_SWITCH,
> + sw->tmu.cap + TMU_RTR_CS_0, 1);
> + if (ret)
> + return ret;
> +
> + ret = tb_sw_read(sw, &val, TB_CFG_SWITCH,
> + sw->tmu.cap + TMU_RTR_CS_15, 1);
> + if (ret)
> + return ret;
> +
> + val &= ~TMU_RTR_CS_15_AVG_MASK << TMU_RTR_CS_15_FREQ_AVG_SHIFT &
> + ~TMU_RTR_CS_15_AVG_MASK << TMU_RTR_CS_15_DELAY_AVG_SHIFT &
> + ~TMU_RTR_CS_15_AVG_MASK << TMU_RTR_CS_15_OFFSET_AVG_SHIFT &
> + ~TMU_RTR_CS_15_AVG_MASK << TMU_RTR_CS_15_ERROR_AVG_SHIFT;
> + val |= avg << TMU_RTR_CS_15_FREQ_AVG_SHIFT |
> + avg << TMU_RTR_CS_15_DELAY_AVG_SHIFT |
> + avg << TMU_RTR_CS_15_OFFSET_AVG_SHIFT |
> + avg << TMU_RTR_CS_15_ERROR_AVG_SHIFT;
Perhaps use FIELD_x macros from include/linux/bitfield.h?
> +
> + return tb_sw_write(sw, &val, TB_CFG_SWITCH,
> + sw->tmu.cap + TMU_RTR_CS_15, 1);
> +}
> +
> static const char *tb_switch_tmu_mode_name(const struct tb_switch *sw)
> {
> bool root_switch = !tb_route(sw);
> @@ -348,7 +397,7 @@ int tb_switch_tmu_disable(struct tb_switch *sw)
>
>
> if (tb_route(sw)) {
> - bool unidirectional = tb_switch_tmu_hifi_is_enabled(sw, true);
> + bool unidirectional = sw->tmu.unidirectional;
> struct tb_switch *parent = tb_switch_parent(sw);
> struct tb_port *down, *up;
> int ret;
> @@ -412,6 +461,7 @@ static void __tb_switch_tmu_off(struct tb_switch *sw, bool unidirectional)
> else
> tb_switch_tmu_rate_write(sw, TB_SWITCH_TMU_RATE_OFF);
>
> + tb_switch_set_tmu_mode_params(sw, sw->tmu.rate);
> tb_port_tmu_unidirectional_disable(down);
> tb_port_tmu_unidirectional_disable(up);
> }
> @@ -493,7 +543,11 @@ static int __tb_switch_tmu_enable_unidirectional(struct tb_switch *sw)
>
> up = tb_upstream_port(sw);
> down = tb_port_at(tb_route(sw), parent);
> - ret = tb_switch_tmu_rate_write(parent, TB_SWITCH_TMU_RATE_HIFI);
> + ret = tb_switch_tmu_rate_write(parent, sw->tmu.rate_request);
> + if (ret)
> + return ret;
> +
> + ret = tb_switch_set_tmu_mode_params(sw, sw->tmu.rate_request);
> if (ret)
> return ret;
>
> @@ -520,7 +574,85 @@ static int __tb_switch_tmu_enable_unidirectional(struct tb_switch *sw)
> return ret;
> }
>
> -static int tb_switch_tmu_hifi_enable(struct tb_switch *sw)
> +static void __tb_switch_tmu_change_mode_prev(struct tb_switch *sw)
> +{
> + struct tb_switch *parent = tb_switch_parent(sw);
> + struct tb_port *down, *up;
> +
> + down = tb_port_at(tb_route(sw), parent);
> + up = tb_upstream_port(sw);
> + /*
> + * In case of any failure in one of the steps when change mode,
> + * get back to the TMU configurations in previous mode.
> + * In case of additional failures in the functions below,
> + * ignore them since the caller shall already report a failure.
> + */
> + tb_port_tmu_set_unidirectional(down, sw->tmu.unidirectional);
> + if (sw->tmu.unidirectional_request)
> + tb_switch_tmu_rate_write(parent, sw->tmu.rate);
> + else
> + tb_switch_tmu_rate_write(sw, sw->tmu.rate);
> +
> + tb_switch_set_tmu_mode_params(sw, sw->tmu.rate);
> + tb_port_tmu_set_unidirectional(up, sw->tmu.unidirectional);
> +}
> +
> +static int __tb_switch_tmu_change_mode(struct tb_switch *sw)
> +{
> + struct tb_switch *parent = tb_switch_parent(sw);
> + struct tb_port *up, *down;
> + int ret;
> +
> + up = tb_upstream_port(sw);
> + down = tb_port_at(tb_route(sw), parent);
> + ret = tb_port_tmu_set_unidirectional(down,
> + sw->tmu.unidirectional_request);
This looks better if you put them single line:
ret = tb_port_tmu_set_unidirectional(down, sw->tmu.unidirectional_request);
> + if (ret)
> + goto out;
> +
> + if (sw->tmu.unidirectional_request)
> + ret = tb_switch_tmu_rate_write(parent, sw->tmu.rate_request);
> + else
> + ret = tb_switch_tmu_rate_write(sw, sw->tmu.rate_request);
> + if (ret)
> + return ret;
> +
> + ret = tb_switch_set_tmu_mode_params(sw, sw->tmu.rate_request);
> + if (ret)
> + return ret;
> +
> + ret = tb_port_tmu_set_unidirectional(up,
> + sw->tmu.unidirectional_request);
Ditto here.
> + if (ret)
> + goto out;
> +
> + ret = tb_port_tmu_time_sync_enable(down);
> + if (ret)
> + goto out;
> +
> + ret = tb_port_tmu_time_sync_enable(up);
> + if (ret)
> + goto out;
> +
> + return 0;
> +
> +out:
> + __tb_switch_tmu_change_mode_prev(sw);
> + return ret;
> +}
> +
> +/**
> + * tb_switch_tmu_enable() - Enable TMU on a router
> + * @sw: Router whose TMU to enable
> + *
> + * Enables TMU of a router to be in uni-directional Normal/Hifi
> + * or bi-directional HiFi mode. Calling tb_switch_tmu_configure() is required
> + * before calling this function, to select the mode Normal/HiFi and
> + * directionality (uni-directional/bi-directional).
> + * In HiFi mode all tunneling should work. In Normal mode, DP tunneling can't
> + * work. Uni-directional mode is required for CLx (Link Low-Power) to work.
> + */
> +int tb_switch_tmu_enable(struct tb_switch *sw)
> {
> bool unidirectional = sw->tmu.unidirectional_request;
> int ret;
> @@ -536,12 +668,13 @@ static int tb_switch_tmu_hifi_enable(struct tb_switch *sw)
> if (!tb_switch_is_clx_supported(sw))
> return 0;
>
> - if (tb_switch_tmu_hifi_is_enabled(sw, sw->tmu.unidirectional_request))
> + if (tb_switch_tmu_is_enabled(sw, sw->tmu.unidirectional_request))
> return 0;
>
> if (tb_switch_is_titan_ridge(sw) && unidirectional) {
> - /* Titan Ridge supports only CL0s */
> - if (!tb_switch_is_cl0s_enabled(sw))
> + /* Titan Ridge supports CL0s and CL1 only */
> + if (!tb_switch_is_cl0s_enabled(sw) &&
> + !tb_switch_is_cl1_enabled(sw))
I wonder if we can have function like tb_switch_clx_is_enabled() that
takes bitmask:
if (!tb_switch_clx_is_enabled(sw, TB_CL0S | TB_CL1))
...
> return -EOPNOTSUPP;
>
> ret = tb_switch_tmu_objection_mask(sw);
> @@ -558,7 +691,11 @@ static int tb_switch_tmu_hifi_enable(struct tb_switch *sw)
> return ret;
>
> if (tb_route(sw)) {
> - /* The used mode changes are from OFF to HiFi-Uni/HiFi-BiDir */
> + /*
> + * The used mode changes are from OFF to
> + * HiFi-Uni/HiFi-BiDir/Normal-Uni or from Normal-Uni to
> + * Hifi-Uni.
> + */
> if (sw->tmu.rate == TB_SWITCH_TMU_RATE_OFF) {
> if (unidirectional)
> ret = __tb_switch_tmu_enable_unidirectional(sw);
> @@ -566,6 +703,10 @@ static int tb_switch_tmu_hifi_enable(struct tb_switch *sw)
> ret = __tb_switch_tmu_enable_bidirectional(sw);
> if (ret)
> return ret;
> + } else if (sw->tmu.rate == TB_SWITCH_TMU_RATE_NORMAL) {
> + ret = __tb_switch_tmu_change_mode(sw);
> + if (ret)
> + return ret;
> }
> sw->tmu.unidirectional = unidirectional;
> } else {
> @@ -575,35 +716,17 @@ static int tb_switch_tmu_hifi_enable(struct tb_switch *sw)
> * of the child node - see above.
> * Here only the host router' rate configuration is written.
> */
> - ret = tb_switch_tmu_rate_write(sw, TB_SWITCH_TMU_RATE_HIFI);
> + ret = tb_switch_tmu_rate_write(sw, sw->tmu.rate_request);
> if (ret)
> return ret;
> }
>
> - sw->tmu.rate = TB_SWITCH_TMU_RATE_HIFI;
> + sw->tmu.rate = sw->tmu.rate_request;
>
> tb_sw_dbg(sw, "TMU: mode set to: %s\n", tb_switch_tmu_mode_name(sw));
> return tb_switch_tmu_set_time_disruption(sw, false);
> }
>
> -/**
> - * tb_switch_tmu_enable() - Enable TMU on a router
> - * @sw: Router whose TMU to enable
> - *
> - * Enables TMU of a router to be in uni-directional or bi-directional HiFi mode.
> - * Calling tb_switch_tmu_configure() is required before calling this function,
> - * to select the mode HiFi and directionality (uni-directional/bi-directional).
> - * In both modes all tunneling should work. Uni-directional mode is required for
> - * CLx (Link Low-Power) to work.
> - */
> -int tb_switch_tmu_enable(struct tb_switch *sw)
> -{
> - if (sw->tmu.rate_request == TB_SWITCH_TMU_RATE_NORMAL)
> - return -EOPNOTSUPP;
> -
> - return tb_switch_tmu_hifi_enable(sw);
> -}
> -
> /**
> * tb_switch_tmu_configure() - Configure the TMU rate and directionality
> * @sw: Router whose mode to change
> --
> 2.17.1
next prev parent reply other threads:[~2022-05-02 10:04 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-05-01 20:33 [PATCH 0/5] thunderbolt: CL1 support for USB4 and Titan Ridge Gil Fine
2022-05-01 20:33 ` [PATCH 1/5] thunderbolt: Silently ignore CLx enabling in case CLx is not supported Gil Fine
2022-05-02 9:50 ` Mika Westerberg
2022-05-04 10:51 ` Gil Fine
2022-05-04 10:59 ` Mika Westerberg
2022-05-01 20:33 ` [PATCH 2/5] thunderbolt: CLx disable before system suspend only if previously enabled Gil Fine
2022-05-02 9:52 ` Mika Westerberg
2022-05-08 7:51 ` Gil Fine
2022-05-01 20:33 ` [PATCH 3/5] thunderbolt: Change downstream router's TMU rate in both TMU uni/bidir mode Gil Fine
2022-05-01 20:33 ` [PATCH 4/5] thunderbolt: Add CL1 support for USB4 and Titan Ridge routers Gil Fine
2022-05-02 10:04 ` Mika Westerberg [this message]
2022-05-04 10:52 ` Gil Fine
2022-05-04 11:03 ` Mika Westerberg
2022-05-01 20:33 ` [PATCH 5/5] thunderbolt: Change TMU mode to Hifi-Uni once DP tunneled Gil Fine
2022-05-01 23:20 ` kernel test robot
2022-05-02 10:09 ` Mika Westerberg
2022-05-08 12:44 ` Gil Fine
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Ym+sm09F9Atu5ghC@lahna \
--to=mika.westerberg@linux.intel.com \
--cc=YehezkelShB@gmail.com \
--cc=andreas.noever@gmail.com \
--cc=gil.fine@intel.com \
--cc=linux-usb@vger.kernel.org \
--cc=lukas@wunner.de \
--cc=michael.jamet@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox