Linux-USB Archive on lore.kernel.org
 help / color / Atom feed
From: Mika Westerberg <mika.westerberg@linux.intel.com>
To: linux-usb@vger.kernel.org
Cc: Andreas Noever <andreas.noever@gmail.com>,
	Michael Jamet <michael.jamet@intel.com>,
	Mika Westerberg <mika.westerberg@linux.intel.com>,
	Yehezkel Bernat <YehezkelShB@gmail.com>,
	Rajmohan Mani <rajmohan.mani@intel.com>,
	Nicholas Johnson <nicholas.johnson-opensource@outlook.com.au>,
	Lukas Wunner <lukas@wunner.de>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Alan Stern <stern@rowland.harvard.edu>,
	Mario.Limonciello@dell.com,
	Anthony Wong <anthony.wong@canonical.com>,
	linux-kernel@vger.kernel.org
Subject: [RFC PATCH 19/22] thunderbolt: Add support for Time Management Unit
Date: Tue,  1 Oct 2019 14:38:27 +0300
Message-ID: <20191001113830.13028-20-mika.westerberg@linux.intel.com> (raw)
In-Reply-To: <20191001113830.13028-1-mika.westerberg@linux.intel.com>

From: Rajmohan Mani <rajmohan.mani@intel.com>

Time Management Unit (TMU) is included in each USB4 router. It is used
to synchronize time across the USB4 fabric. By default when USB4 router
is plugged to the domain, its TMU is turned off. This differs from
Thunderbolt (1, 2 and 3) devices whose TMU is by default configured to
bi-directional HiFi mode. Since time synchronization is needed for
proper Display Port tunneling this means we need to configure the TMU on
USB4 compliant devices.

The USB4 spec allows some flexibility on how the TMU can be configured.
This makes it possible to enable link power management states (CLx) in
certain topologies, where for example DP tunneling is not used. TMU can
also be re-configured dynamicaly depending on types of tunnels created
over the USB4 fabric.

In this patch we simply configure the TMU to be in bi-directional HiFi
mode. This way we can tunnel any kind of traffic without need to perform
complex steps to re-configure the domain dynamically. We can add more
fine-grained TMU configuration later on when we start enabling CLx
states.

Signed-off-by: Rajmohan Mani <rajmohan.mani@intel.com>
Co-developed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
 drivers/thunderbolt/Makefile  |   2 +-
 drivers/thunderbolt/switch.c  |   4 +
 drivers/thunderbolt/tb.c      |  29 +++
 drivers/thunderbolt/tb.h      |  47 +++++
 drivers/thunderbolt/tb_regs.h |  20 ++
 drivers/thunderbolt/tmu.c     | 380 ++++++++++++++++++++++++++++++++++
 6 files changed, 481 insertions(+), 1 deletion(-)
 create mode 100644 drivers/thunderbolt/tmu.c

diff --git a/drivers/thunderbolt/Makefile b/drivers/thunderbolt/Makefile
index c0b2fd73dfbd..2014bc840b06 100644
--- a/drivers/thunderbolt/Makefile
+++ b/drivers/thunderbolt/Makefile
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-${CONFIG_THUNDERBOLT} := thunderbolt.o
 thunderbolt-objs := nhi.o nhi_ops.o ctl.o tb.o switch.o cap.o path.o tunnel.o eeprom.o
-thunderbolt-objs += domain.o dma_port.o icm.o property.o xdomain.o lc.o usb4.o
+thunderbolt-objs += domain.o dma_port.o icm.o property.o xdomain.o lc.o tmu.o usb4.o
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index 2ccd1004920e..58e3f54ddbb9 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -2278,6 +2278,10 @@ int tb_switch_add(struct tb_switch *sw)
 		ret = tb_switch_update_link_attributes(sw);
 		if (ret)
 			return ret;
+
+		ret = tb_switch_tmu_init(sw);
+		if (ret)
+			return ret;
 	}
 
 	ret = device_add(&sw->dev);
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index 24e37e47dc48..f2868c125637 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -161,6 +161,25 @@ static void tb_scan_xdomain(struct tb_port *port)
 	}
 }
 
+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_is_enabled(sw))
+		return 0;
+
+	ret = tb_switch_tmu_disable(sw);
+	if (ret)
+		return ret;
+
+	ret = tb_switch_tmu_post_time(sw);
+	if (ret)
+		return ret;
+
+	return tb_switch_tmu_enable(sw);
+}
+
 static void tb_scan_port(struct tb_port *port);
 
 /**
@@ -263,6 +282,9 @@ static void tb_scan_port(struct tb_port *port)
 	if (tb_switch_lane_bonding_enable(sw))
 		tb_sw_warn(sw, "failed to enable lane bonding\n");
 
+	if (tb_enable_tmu(sw))
+		tb_sw_warn(sw, "failed to enable TMU\n");
+
 	tb_scan_switch(sw);
 }
 
@@ -713,6 +735,7 @@ static void tb_handle_hotplug(struct work_struct *work)
 			tb_sw_set_unplugged(port->remote->sw);
 			tb_free_invalid_tunnels(tb);
 			tb_remove_dp_resources(port->remote->sw);
+			tb_switch_tmu_disable(port->remote->sw);
 			tb_switch_lane_bonding_disable(port->remote->sw);
 			tb_switch_remove(port->remote->sw);
 			port->remote = NULL;
@@ -860,6 +883,9 @@ static int tb_start(struct tb *tb)
 		return ret;
 	}
 
+	/* Enable TMU if it is off */
+	if (!tb_switch_tmu_is_enabled(tb->root_switch))
+		tb_switch_tmu_enable(tb->root_switch);
 	/* Full scan to discover devices added before the driver was loaded. */
 	tb_scan_switch(tb->root_switch);
 	/* Find out tunnels created by the boot firmware */
@@ -891,6 +917,9 @@ static void tb_restore_children(struct tb_switch *sw)
 {
 	int i;
 
+	if (tb_enable_tmu(sw))
+		tb_sw_warn(sw, "failed to restore TMU configuration\n");
+
 	tb_switch_for_each_remote_port(sw, i) {
 		struct tb_port *port = &sw->ports[i];
 
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index 1488382066fd..087fd6d6ef9a 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -46,6 +46,38 @@ struct tb_switch_nvm {
 #define TB_SWITCH_MAX_DEPTH		6
 #define USB4_SWITCH_MAX_DEPTH		5
 
+/**
+ * enum tb_switch_tmu_rate - TMU refresh rate
+ * @TB_SWITCH_TMU_RATE_OFF: %0 (Disable Time Sync handshake)
+ * @TB_SWITCH_TMU_RATE_HIFI: %16 us time interval between successive
+ *			     transmission of the Delay Request TSNOS
+ *			     (Time Sync Notification Ordered Set) on a Link
+ * @TB_SWITCH_TMU_RATE_NORMAL: %1 ms time interval between successive
+ *			       transmission of the Delay Request TSNOS on
+ *			       a Link
+ */
+enum tb_switch_tmu_rate {
+	TB_SWITCH_TMU_RATE_OFF = 0,
+	TB_SWITCH_TMU_RATE_HIFI = 16,
+	TB_SWITCH_TMU_RATE_NORMAL = 1000,
+};
+
+/**
+ * struct tb_switch_tmu - Structure holding switch TMU configuration
+ * @cap: Offset to the TMU capability (%0 if not found)
+ * @has_ucap: Does the switch support uni-directional mode
+ * @rate: TMU refresh rate related to upstream switch. In case of root
+ *	  switch this holds the domain rate.
+ * @unidirectional: Is the TMU in uni-directional or bi-directional mode
+ *		    related to upstream switch. Don't case for root switch.
+ */
+struct tb_switch_tmu {
+	int cap;
+	bool has_ucap;
+	enum tb_switch_tmu_rate rate;
+	bool unidirectional;
+};
+
 /**
  * struct tb_switch - a thunderbolt switch
  * @dev: Device for the switch
@@ -55,6 +87,7 @@ struct tb_switch_nvm {
  *	      mailbox this will hold the pointer to that (%NULL
  *	      otherwise). If set it also means the switch has
  *	      upgradeable NVM.
+ * @tmu: The switch TMU configuration
  * @tb: Pointer to the domain the switch belongs to
  * @uid: Unique ID of the switch
  * @uuid: UUID of the switch (or %NULL if not supported)
@@ -93,6 +126,7 @@ struct tb_switch {
 	struct tb_regs_switch_header config;
 	struct tb_port *ports;
 	struct tb_dma_port *dma_port;
+	struct tb_switch_tmu tmu;
 	struct tb *tb;
 	u64 uid;
 	uuid_t *uuid;
@@ -129,6 +163,7 @@ struct tb_switch {
  * @remote: Remote port (%NULL if not connected)
  * @xdomain: Remote host (%NULL if not connected)
  * @cap_phy: Offset, zero if not found
+ * @cap_tmu: Offset of the adapter specific TMU capability (%0 if not present)
  * @cap_adap: Offset of the adapter specific capability (%0 if not present)
  * @cap_usb4: Offset to the USB4 port capability (%0 if not present)
  * @port: Port number on switch
@@ -147,6 +182,7 @@ struct tb_port {
 	struct tb_port *remote;
 	struct tb_xdomain *xdomain;
 	int cap_phy;
+	int cap_tmu;
 	int cap_adap;
 	int cap_usb4;
 	u8 port;
@@ -696,6 +732,17 @@ bool tb_switch_query_dp_resource(struct tb_switch *sw, struct tb_port *in);
 int tb_switch_alloc_dp_resource(struct tb_switch *sw, struct tb_port *in);
 void tb_switch_dealloc_dp_resource(struct tb_switch *sw, struct tb_port *in);
 
+int tb_switch_tmu_init(struct tb_switch *sw);
+int tb_switch_tmu_post_time(struct tb_switch *sw);
+int tb_switch_tmu_disable(struct tb_switch *sw);
+int tb_switch_tmu_enable(struct tb_switch *sw);
+
+static inline bool tb_switch_tmu_is_enabled(const struct tb_switch *sw)
+{
+	return sw->tmu.rate == TB_SWITCH_TMU_RATE_HIFI &&
+	       !sw->tmu.unidirectional;
+}
+
 int tb_wait_for_port(struct tb_port *port, bool wait_if_unplugged);
 int tb_port_add_nfc_credits(struct tb_port *port, int credits);
 int tb_port_set_initial_credits(struct tb_port *port, u32 credits);
diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h
index 47f73f992412..ec1a5d1f7c94 100644
--- a/drivers/thunderbolt/tb_regs.h
+++ b/drivers/thunderbolt/tb_regs.h
@@ -26,6 +26,7 @@
 #define TB_MAX_CONFIG_RW_LENGTH 60
 
 enum tb_switch_cap {
+	TB_SWITCH_CAP_TMU		= 0x03,
 	TB_SWITCH_CAP_VSE		= 0x05,
 };
 
@@ -195,6 +196,21 @@ struct tb_regs_switch_header {
 #define ROUTER_CS_26_ONS			BIT(30)
 #define ROUTER_CS_26_OV				BIT(31)
 
+/* Router TMU configuration */
+#define TMU_RTR_CS_0				0x00
+#define TMU_RTR_CS_0_TD				BIT(27)
+#define TMU_RTR_CS_0_UCAP			BIT(30)
+#define TMU_RTR_CS_1				0x01
+#define TMU_RTR_CS_1_LOCAL_TIME_NS_MASK		GENMASK(31, 16)
+#define TMU_RTR_CS_1_LOCAL_TIME_NS_SHIFT	16
+#define TMU_RTR_CS_2				0x02
+#define TMU_RTR_CS_3				0x03
+#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_22				0x16
+#define TMU_RTR_CS_24				0x18
+
 enum tb_port_type {
 	TB_TYPE_INACTIVE	= 0x000000,
 	TB_TYPE_PORT		= 0x000001,
@@ -248,6 +264,10 @@ struct tb_regs_port_header {
 #define ADP_CS_5_LCA_MASK			GENMASK(28, 22)
 #define ADP_CS_5_LCA_SHIFT			22
 
+/* TMU adapter registers */
+#define TMU_ADP_CS_3				0x03
+#define TMU_ADP_CS_3_UDM			BIT(29)
+
 /* Lane adapter registers */
 #define LANE_ADP_CS_0				0x00
 #define LANE_ADP_CS_0_SUPPORTED_WIDTH_MASK	GENMASK(25, 20)
diff --git a/drivers/thunderbolt/tmu.c b/drivers/thunderbolt/tmu.c
new file mode 100644
index 000000000000..d6314f6b20c7
--- /dev/null
+++ b/drivers/thunderbolt/tmu.c
@@ -0,0 +1,380 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Thunderbolt Time Management Unit (TMU) support
+ *
+ * Copyright (C) 2019, Intel Corporation
+ * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
+ *	    Rajmohan Mani <rajmohan.mani@intel.com>
+ */
+
+#include <linux/delay.h>
+
+#include "tb.h"
+
+static const char *tb_switch_tmu_mode_name(const struct tb_switch *sw)
+{
+	bool root_switch = !tb_route(sw);
+
+	switch (sw->tmu.rate) {
+	case TB_SWITCH_TMU_RATE_OFF:
+		return "off";
+
+	case TB_SWITCH_TMU_RATE_HIFI:
+		/* Root switch does not have upstream directionality */
+		if (root_switch)
+			return "HiFi";
+		if (sw->tmu.unidirectional)
+			return "uni-directional, HiFi";
+		return "bi-directional, HiFi";
+
+	case TB_SWITCH_TMU_RATE_NORMAL:
+		if (root_switch)
+			return "normal";
+		return "uni-directional, normal";
+
+	default:
+		return "unknown";
+	}
+}
+
+static bool tb_switch_tmu_ucap_supported(struct tb_switch *sw)
+{
+	int ret;
+	u32 val;
+
+	ret = tb_sw_read(sw, &val, TB_CFG_SWITCH,
+			 sw->tmu.cap + TMU_RTR_CS_0, 1);
+	if (ret)
+		return false;
+
+	return !!(val & TMU_RTR_CS_0_UCAP);
+}
+
+static int tb_switch_tmu_rate_read(struct tb_switch *sw)
+{
+	int ret;
+	u32 val;
+
+	ret = tb_sw_read(sw, &val, TB_CFG_SWITCH,
+			 sw->tmu.cap + TMU_RTR_CS_3, 1);
+	if (ret)
+		return ret;
+
+	val >>= TMU_RTR_CS_3_TS_PACKET_INTERVAL_SHIFT;
+	return val;
+}
+
+static int tb_switch_tmu_rate_write(struct tb_switch *sw, int rate)
+{
+	int ret;
+	u32 val;
+
+	ret = tb_sw_read(sw, &val, TB_CFG_SWITCH,
+			 sw->tmu.cap + TMU_RTR_CS_3, 1);
+	if (ret)
+		return ret;
+
+	val &= ~TMU_RTR_CS_3_TS_PACKET_INTERVAL_MASK;
+	val |= rate << TMU_RTR_CS_3_TS_PACKET_INTERVAL_SHIFT;
+
+	return tb_sw_write(sw, &val, TB_CFG_SWITCH,
+			   sw->tmu.cap + TMU_RTR_CS_3, 1);
+}
+
+static int tb_port_tmu_write(struct tb_port *port, u8 offset, u32 mask,
+			     u32 value)
+{
+	u32 data;
+	int ret;
+
+	ret = tb_port_read(port, &data, TB_CFG_PORT, port->cap_tmu + offset, 1);
+	if (ret)
+		return ret;
+
+	data &= ~mask;
+	data |= value;
+
+	return tb_port_write(port, &data, TB_CFG_PORT,
+			     port->cap_tmu + offset, 1);
+}
+
+static int tb_port_tmu_set_unidirectional(struct tb_port *port,
+					  bool unidirectional)
+{
+	u32 val;
+
+	if (!port->sw->tmu.has_ucap)
+		return 0;
+
+	val = unidirectional ? TMU_ADP_CS_3_UDM : 0;
+	return tb_port_tmu_write(port, TMU_ADP_CS_3, TMU_ADP_CS_3_UDM, val);
+}
+
+static inline int tb_port_tmu_unidirectional_disable(struct tb_port *port)
+{
+	return tb_port_tmu_set_unidirectional(port, false);
+}
+
+static bool tb_port_tmu_is_unidirectional(struct tb_port *port)
+{
+	int ret;
+	u32 val;
+
+	ret = tb_port_read(port, &val, TB_CFG_PORT,
+			   port->cap_tmu + TMU_ADP_CS_3, 1);
+	if (ret)
+		return false;
+
+	return val & TMU_ADP_CS_3_UDM;
+}
+
+static int tb_switch_tmu_set_time_disruption(struct tb_switch *sw, bool set)
+{
+	int ret;
+	u32 val;
+
+	ret = tb_sw_read(sw, &val, TB_CFG_SWITCH,
+			 sw->tmu.cap + TMU_RTR_CS_0, 1);
+	if (ret)
+		return ret;
+
+	if (set)
+		val |= TMU_RTR_CS_0_TD;
+	else
+		val &= ~TMU_RTR_CS_0_TD;
+
+	return tb_sw_write(sw, &val, TB_CFG_SWITCH,
+			   sw->tmu.cap + TMU_RTR_CS_0, 1);
+}
+
+/**
+ * tb_switch_tmu_init() - Initialize switch TMU structures
+ * @sw: Switch to initialized
+ *
+ * This function must be called before other TMU related functions to
+ * makes the internal structures are filled in correctly. Does not
+ * change any hardware configuration.
+ */
+int tb_switch_tmu_init(struct tb_switch *sw)
+{
+	int ret, i;
+
+	if (tb_switch_is_icm(sw))
+		return 0;
+
+	ret = tb_switch_find_cap(sw, TB_SWITCH_CAP_TMU);
+	if (ret > 0)
+		sw->tmu.cap = ret;
+
+	tb_switch_for_each_port(sw, i) {
+		struct tb_port *port = &sw->ports[i];
+		int cap;
+
+		cap = tb_port_find_cap(port, TB_PORT_CAP_TIME1);
+		if (cap > 0)
+			port->cap_tmu = cap;
+	}
+
+	ret = tb_switch_tmu_rate_read(sw);
+	if (ret < 0)
+		return ret;
+
+	sw->tmu.rate = ret;
+
+	sw->tmu.has_ucap = tb_switch_tmu_ucap_supported(sw);
+	if (sw->tmu.has_ucap) {
+		tb_sw_dbg(sw, "TMU: supports uni-directional mode\n");
+
+		if (tb_route(sw)) {
+			struct tb_port *up = tb_upstream_port(sw);
+
+			sw->tmu.unidirectional =
+				tb_port_tmu_is_unidirectional(up);
+		}
+	} else {
+		sw->tmu.unidirectional = false;
+	}
+
+	tb_sw_dbg(sw, "TMU: current mode: %s\n", tb_switch_tmu_mode_name(sw));
+	return 0;
+}
+
+/**
+ * tb_switch_tmu_post_time() - Update switch local time
+ * @sw: Switch whose time to update
+ *
+ * Updates switch local time using time posting procedure.
+ */
+int tb_switch_tmu_post_time(struct tb_switch *sw)
+{
+	unsigned int  post_local_time_offset, post_time_offset;
+	struct tb_switch *root_switch = sw->tb->root_switch;
+	u64 hi, mid, lo, local_time, post_time;
+	int i, ret, retries = 100;
+	u32 gm_local_time[3];
+
+	if (!tb_route(sw))
+		return 0;
+
+	if (!tb_switch_is_usb4(sw))
+		return 0;
+
+	/* Need to be able to read the grand master time */
+	if (!root_switch->tmu.cap)
+		return 0;
+
+	ret = tb_sw_read(root_switch, gm_local_time, TB_CFG_SWITCH,
+			 root_switch->tmu.cap + TMU_RTR_CS_1,
+			 ARRAY_SIZE(gm_local_time));
+	if (ret)
+		return ret;
+
+	for (i = 0; i < ARRAY_SIZE(gm_local_time); i++)
+		tb_sw_dbg(root_switch, "local_time[%d]=0x%08x\n", i,
+			  gm_local_time[i]);
+
+	/* Convert to nanoseconds (drop fractional part) */
+	hi = gm_local_time[2] & TMU_RTR_CS_3_LOCAL_TIME_NS_MASK;
+	mid = gm_local_time[1];
+	lo = (gm_local_time[0] & TMU_RTR_CS_1_LOCAL_TIME_NS_MASK) >>
+		TMU_RTR_CS_1_LOCAL_TIME_NS_SHIFT;
+	local_time = hi << 48 | mid << 16 | lo;
+
+	/* Tell the switch that time sync is disrupted for a while */
+	ret = tb_switch_tmu_set_time_disruption(sw, true);
+	if (ret)
+		return ret;
+
+	post_local_time_offset = sw->tmu.cap + TMU_RTR_CS_22;
+	post_time_offset = sw->tmu.cap + TMU_RTR_CS_24;
+
+	/*
+	 * Write the Grandmaster time to the Post Local Time registers
+	 * of the new switch.
+	 */
+	ret = tb_sw_write(sw, &local_time, TB_CFG_SWITCH,
+			  post_local_time_offset, 2);
+	if (ret)
+		goto out;
+
+	/*
+	 * Have the new switch update its local time (by writing 1 to
+	 * the post_time registers) and wait for the completion of the
+	 * same (post_time register becomes 0). This means the time has
+	 * been converged properly.
+	 */
+	post_time = 1;
+
+	ret = tb_sw_write(sw, &post_time, TB_CFG_SWITCH, post_time_offset, 2);
+	if (ret)
+		goto out;
+
+	do {
+		usleep_range(5, 10);
+		ret = tb_sw_read(sw, &post_time, TB_CFG_SWITCH,
+				 post_time_offset, 2);
+		if (ret)
+			goto out;
+	} while (--retries && post_time);
+
+	if (!retries) {
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	tb_sw_dbg(sw, "TMU: updated local time to %#llx\n", local_time);
+
+out:
+	tb_switch_tmu_set_time_disruption(sw, false);
+	return ret;
+}
+
+/**
+ * tb_switch_tmu_disable() - Disable TMU of a switch
+ * @sw: Switch whose TMU to disable
+ *
+ * Turns off TMU of @sw if it is enabled. If not enabled does nothing.
+ */
+int tb_switch_tmu_disable(struct tb_switch *sw)
+{
+	int ret;
+
+	if (!tb_switch_is_usb4(sw))
+		return 0;
+
+	/* Already disabled? */
+	if (sw->tmu.rate == TB_SWITCH_TMU_RATE_OFF)
+		return 0;
+
+	if (sw->tmu.unidirectional) {
+		struct tb_switch *parent = tb_switch_parent(sw);
+		struct tb_port *up, *down;
+
+		up = tb_upstream_port(sw);
+		down = tb_port_at(tb_route(sw), parent);
+
+		/* The switch may be unplugged so ignore any errors */
+		tb_port_tmu_unidirectional_disable(up);
+		ret = tb_port_tmu_unidirectional_disable(down);
+		if (ret)
+			return ret;
+	}
+
+	tb_switch_tmu_rate_write(sw, TB_SWITCH_TMU_RATE_OFF);
+
+	sw->tmu.unidirectional = false;
+	sw->tmu.rate = TB_SWITCH_TMU_RATE_OFF;
+
+	tb_sw_dbg(sw, "TMU: disabled\n");
+	return 0;
+}
+
+/**
+ * tb_switch_tmu_enable() - Enable TMU on a switch
+ * @sw: Switch whose TMU to enable
+ *
+ * Enables TMU of a switch to be in bi-directional, HiFi mode. In this mode
+ * all tunneling should work.
+ */
+int tb_switch_tmu_enable(struct tb_switch *sw)
+{
+	int ret;
+
+	if (!tb_switch_is_usb4(sw))
+		return 0;
+
+	ret = tb_switch_tmu_set_time_disruption(sw, true);
+	if (ret)
+		return ret;
+
+	/* Change mode to bi-directional */
+	if (tb_route(sw) && sw->tmu.unidirectional) {
+		struct tb_switch *parent = tb_switch_parent(sw);
+		struct tb_port *up, *down;
+
+		up = tb_upstream_port(sw);
+		down = tb_port_at(tb_route(sw), parent);
+
+		ret = tb_port_tmu_unidirectional_disable(down);
+		if (ret)
+			return ret;
+
+		ret = tb_switch_tmu_rate_write(sw, TB_SWITCH_TMU_RATE_HIFI);
+		if (ret)
+			return ret;
+
+		ret = tb_port_tmu_unidirectional_disable(up);
+		if (ret)
+			return ret;
+	} else {
+		ret = tb_switch_tmu_rate_write(sw, TB_SWITCH_TMU_RATE_HIFI);
+		if (ret)
+			return ret;
+	}
+
+	sw->tmu.unidirectional = false;
+	sw->tmu.rate = TB_SWITCH_TMU_RATE_HIFI;
+	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);
+}
-- 
2.23.0


  parent reply index

Thread overview: 95+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-10-01 11:38 [RFC PATCH 00/22] thunderbolt: Add support for USB4 Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 01/22] thunderbolt: Introduce tb_switch_is_icm() Mika Westerberg
2019-10-01 12:10   ` Greg Kroah-Hartman
2019-10-01 12:46     ` Mika Westerberg
2019-10-01 13:36       ` Mario.Limonciello
2019-10-01 13:48         ` Mika Westerberg
2019-10-01 13:50           ` Mario.Limonciello
2019-10-01 13:52             ` Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 02/22] thunderbolt: Log switch route string on config read/write timeout Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 03/22] thunderbolt: Log warning if adding switch fails Mika Westerberg
2019-10-01 12:18   ` Greg Kroah-Hartman
2019-10-01 12:48     ` Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 04/22] thunderbolt: Make tb_sw_write() take const parameter Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 05/22] thunderbolt: Add helper macros to iterate over switch ports Mika Westerberg
2019-10-02 14:17   ` Oliver Neukum
2019-10-02 14:28     ` Mika Westerberg
2019-10-06 12:15       ` Lukas Wunner
2019-10-01 11:38 ` [RFC PATCH 06/22] thunderbolt: Add support for lane bonding Mika Westerberg
2019-10-01 12:38   ` Greg Kroah-Hartman
2019-10-01 12:53     ` Mika Westerberg
2019-10-02 14:21       ` Oliver Neukum
2019-10-02 14:30         ` Mika Westerberg
2019-10-03  8:25           ` Oliver Neukum
2019-10-03  8:53             ` Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 07/22] thunderbolt: Add default linking between ports if not provided by DROM Mika Westerberg
2019-10-01 12:39   ` Greg Kroah-Hartman
2019-10-01 13:14     ` Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 08/22] thunderbolt: Add downstream PCIe port mappings for Alpine and Titan Ridge Mika Westerberg
2019-10-01 12:40   ` Greg Kroah-Hartman
2019-10-01 13:27     ` Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 09/22] thunderbolt: Convert basic adapter register names to follow the USB4 spec Mika Westerberg
2019-10-01 12:41   ` Greg Kroah-Hartman
2019-10-01 13:28     ` Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 10/22] thunderbolt: Convert PCIe adapter register names to use USB4 names Mika Westerberg
2019-10-01 12:42   ` Greg Kroah-Hartman
2019-10-01 11:38 ` [RFC PATCH 11/22] thunderbolt: Convert DP adapter register names to follow the USB4 spec Mika Westerberg
2019-10-01 12:42   ` Greg Kroah-Hartman
2019-10-01 11:38 ` [RFC PATCH 12/22] thunderbolt: Add Display Port CM handshake for Titan Ridge devices Mika Westerberg
2019-10-01 12:44   ` Greg Kroah-Hartman
2019-10-01 13:30     ` Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 13/22] thunderbolt: Add Display Port adapter pairing and resource management Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 14/22] thunderbolt: Add bandwidth management for Display Port tunnels Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 15/22] thunderbolt: Make tb_find_port() available to other files Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 16/22] thunderbolt: Call tb_eeprom_get_drom_offset() from tb_eeprom_read_n() Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 17/22] thunderbolt: Add initial support for USB4 Mika Westerberg
2019-10-01 12:47   ` Greg Kroah-Hartman
2019-10-01 13:09     ` Mika Westerberg
2019-10-01 14:53       ` Greg Kroah-Hartman
2019-10-01 14:59         ` Mario.Limonciello
2019-10-01 15:13           ` Mika Westerberg
2019-10-01 15:22           ` Greg KH
2019-10-01 15:32             ` Mika Westerberg
2019-10-01 15:07         ` Mika Westerberg
2019-10-01 15:19           ` Greg Kroah-Hartman
2019-10-01 15:26             ` Mika Westerberg
2019-10-01 16:27           ` Oliver Neukum
2019-10-02  8:30             ` Mika Westerberg
2019-10-02  8:39               ` Greg Kroah-Hartman
2019-10-02  8:49                 ` Mika Westerberg
2019-10-01 17:05   ` Mario.Limonciello
2019-10-01 18:14     ` Mario.Limonciello
2019-10-02  8:39       ` Mika Westerberg
2019-10-02 15:09         ` Mario.Limonciello
2019-10-02 15:36           ` Yehezkel Bernat
2019-10-02 16:00             ` Mario.Limonciello
2019-10-03  8:00               ` Mika Westerberg
2019-10-03 14:41                 ` Mario.Limonciello
2019-10-04  7:54                   ` Mika Westerberg
2019-10-04  8:07                     ` Yehezkel Bernat
2019-10-04  8:19                       ` Mika Westerberg
2019-10-04 11:19                         ` Yehezkel Bernat
2019-10-04 14:05                           ` Mario.Limonciello
2019-10-04 14:19                             ` Mario.Limonciello
2019-10-04 14:21                             ` Mika Westerberg
     [not found]                               ` <1570201357.2.0@kellner.me>
2019-10-04 15:16                                 ` Mika Westerberg
2019-10-04 15:22                                   ` Christian Kellner
2019-10-02  8:34     ` Mika Westerberg
2019-10-02 15:04       ` Mario.Limonciello
2019-10-01 11:38 ` [RFC PATCH 18/22] thunderbolt: Make tb_switch_find_cap() available to other files Mika Westerberg
2019-10-01 11:38 ` Mika Westerberg [this message]
2019-10-02 16:52   ` [RFC PATCH 19/22] thunderbolt: Add support for Time Management Unit Mani, Rajmohan
2019-10-03  8:01     ` Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 20/22] thunderbolt: Add support for USB tunnels Mika Westerberg
2019-10-03  8:42   ` Oliver Neukum
2019-10-03  8:52     ` Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 21/22] thunderbolt: Update documentation with the USB4 information Mika Westerberg
2019-10-01 14:17   ` Mario.Limonciello
2019-10-01 14:21     ` Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 22/22] thunderbolt: Do not start firmware unless asked by the user Mika Westerberg
2019-10-01 14:43   ` Mario.Limonciello
2019-10-01 14:58     ` Mika Westerberg
2019-10-01 16:53       ` Mario.Limonciello
2019-10-02  8:48         ` Mika Westerberg
2019-10-01 12:49 ` [RFC PATCH 00/22] thunderbolt: Add support for USB4 Greg Kroah-Hartman
2019-10-01 13:42   ` Mika Westerberg

Reply instructions:

You may reply publically 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=20191001113830.13028-20-mika.westerberg@linux.intel.com \
    --to=mika.westerberg@linux.intel.com \
    --cc=Mario.Limonciello@dell.com \
    --cc=YehezkelShB@gmail.com \
    --cc=andreas.noever@gmail.com \
    --cc=anthony.wong@canonical.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=lukas@wunner.de \
    --cc=michael.jamet@intel.com \
    --cc=nicholas.johnson-opensource@outlook.com.au \
    --cc=rajmohan.mani@intel.com \
    --cc=stern@rowland.harvard.edu \
    /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

Linux-USB Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-usb/0 linux-usb/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-usb linux-usb/ https://lore.kernel.org/linux-usb \
		linux-usb@vger.kernel.org
	public-inbox-index linux-usb

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-usb


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git