Re: [PATCH 2/7] thunderbolt: Add CL0s support for USB4

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

On Thu, Nov 25, 2021 at 04:38:16PM +0200, Gil Fine wrote:
> +static int tb_switch_enable_cl0s(struct tb_switch *sw)
> +{
> +	struct tb_switch *parent = tb_switch_parent(sw);
> +	bool up_cl0s_support, down_cl0s_support;
> +	struct tb_port *up, *down;
> +	int ret;
> +
> +	if (!tb_switch_is_usb4(sw))
> +		return 0;
> +
> +	/*
> +	 * Enable CLx for host router's downstream port as part of the
> +	 * downstream router enabling procedure.
> +	 */
> +	if (!tb_route(sw))
> +		return 0;
> +
> +	/* Enable CLx only for first hop router (depth = 1) */
> +	if (tb_route(parent))
> +		return 0;
> +
> +	if (tb_switch_pm_secondary_resolve(sw))
> +		return -EINVAL;
> +
> +	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);
> +
> +	tb_port_dbg(up, "CL0s %ssupported\n",
> +		    up_cl0s_support ? "" : "not ");
> +	tb_port_dbg(down, "CL0s %ssupported\n",
> +		    down_cl0s_support ? "" : "not ");
> +
> +	if (!up_cl0s_support || !down_cl0s_support)
> +		return -EOPNOTSUPP;
> +
> +	ret = tb_port_cl0s_enable(up);
> +	if (ret)
> +		return ret;
> +
> +	ret = tb_port_cl0s_enable(down);
> +	if (ret)

Better to get rid of the goto here and do:

	if (ret) {
		tb_port_cl0s_disable(up);
		return ret;
	}

> +		goto out;
> +
> +	sw->clx = TB_CL0S;
> +	tb_sw_dbg(sw, "enabled CL0s on upstream port\n");
> +	return 0;
> +out:
> +	tb_port_cl0s_disable(up);
> +	return ret;
> +}
> +
> +/**
> + * tb_switch_enable_clx() - Enable CLx on upstream port of specified router
> + * @sw: The switch to enable CLx for
> + * @clx: The CLx state to enable
> + *
> + * Enable CLx state only for first hop router. This is because of the HW
> + * limitation on Intel platforms.

Okay but in general do we need to enable it over the whole topology or
is it enough to enable it for the first hop router? I think most of this
is because it allows better thermal management which probably is
applicable for any USB4 host.

> + * CLx is enabled only if both sides of the link support CLx, and if
> + * both sides of the link are not configured as two single lane links
> + * and only if the link is not inter-domain link.
> + * The conditions are descibed in CM Guide 1.0 section 8.1.
> + *
> + * Return: Returns 0 on success or an error code on failure.
> + */
> +int tb_switch_enable_clx(struct tb_switch *sw, enum tb_clx clx)
> +{
> +	struct tb_switch *root_sw = sw->tb->root_switch;
> +
> +	/* CLx is not enabled and validated on USB4 platforms before ADL */
> +	if (root_sw->generation < 4 ||
> +	    tb_switch_is_tiger_lake(root_sw))
> +		return 0;
> +
> +	switch (clx) {
> +	case TB_CL0S:
> +		return tb_switch_enable_cl0s(sw);
> +
> +	case TB_CL1:
> +	case TB_CL2:

You can drpo the two lines above.

> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +}
> +
> +static int tb_switch_disable_cl0s(struct tb_switch *sw)
> +{
> +	struct tb_switch *parent = tb_switch_parent(sw);
> +	struct tb_port *up, *down;
> +	int ret;
> +
> +	if (!tb_switch_is_usb4(sw))
> +		return 0;
> +
> +	/*
> +	 * Disable CLx for host router's downstream port as part of the
> +	 * downstream router enabling procedure.
> +	 */
> +	if (!tb_route(sw))
> +		return 0;
> +
> +	/* Disable CLx only for first hop router (depth = 1) */
> +	if (tb_route(parent))
> +		return 0;
> +
> +	up = tb_upstream_port(sw);
> +	down = tb_port_at(tb_route(sw), parent);
> +	ret = tb_port_cl0s_disable(up);
> +	if (ret)
> +		return ret;
> +
> +	ret = tb_port_cl0s_disable(down);
> +	if (ret)
> +		return ret;
> +
> +	sw->clx = TB_CLX_DISABLE;
> +	tb_sw_dbg(sw, "disabled CL0s on upstream port\n");
> +	return 0;
> +}
> +
> +/**
> + * tb_switch_disable_clx() - Disable CLx on upstream port of specified router
> + * @sw: The switch to disable CLx for
> + * @clx: The CLx state to disable
> + *
> + * Return: Returns 0 on success or an error code on failure.
> + */
> +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:
> +	case TB_CL2:
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +}
> +
> +/**
> + * tb_switch_is_clx_enabled() - Checks if the CLx is enabled
> + * @sw: Router to check the CLx state for
> + *
> + * Checks if the CLx is enabled on the router upstream link.
> + * Not applicable for a host router.
> + */
> +bool tb_switch_is_clx_enabled(struct tb_switch *sw)
> +{
> +	return sw->clx != TB_CLX_DISABLE;
> +}
> +
> +/**
> + * tb_switch_is_cl0s_enabled() - Checks if the CL0s is enabled
> + * @sw: Router to check the CLx state for
> + *
> + * Checks if the CL0s is enabled on the router upstream link.
> + * Not applicable for a host router.
> + */
> +bool tb_switch_is_cl0s_enabled(struct tb_switch *sw)
> +{
> +	return sw->clx == TB_CL0S;
> +}
> diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
> index 533fe48e85be..f241d42c1c6e 100644
> --- a/drivers/thunderbolt/tb.c
> +++ b/drivers/thunderbolt/tb.c
> @@ -669,7 +669,11 @@ static void tb_scan_port(struct tb_port *port)
>  	tb_switch_lane_bonding_enable(sw);
>  	/* Set the link configured */
>  	tb_switch_configure_link(sw);
> -	tb_switch_tmu_configure(sw, TB_SWITCH_TMU_RATE_HIFI, false);
> +	if (tb_switch_enable_clx(sw, TB_CL0S))
> +		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) ? true : false);

tb_switch_is_clx_enabled() returns boolean so you can use it directly
here.



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux