All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mika Westerberg <mika.westerberg@linux.intel.com>
To: Yehezkel Bernat <YehezkelShB@gmail.com>,
	Michael Jamet <michael.jamet@intel.com>,
	Lukas Wunner <lukas@wunner.de>,
	Andreas Noever <andreas.noever@gmail.com>
Cc: linux-usb@vger.kernel.org,
	Mika Westerberg <mika.westerberg@linux.intel.com>
Subject: [PATCH 4/6] thunderbolt: Split out margining from USB4 port
Date: Mon, 10 Jun 2024 13:06:25 +0300	[thread overview]
Message-ID: <20240610100627.3521887-5-mika.westerberg@linux.intel.com> (raw)
In-Reply-To: <20240610100627.3521887-1-mika.westerberg@linux.intel.com>

We are going to expand lane margining support for retimers too so split
out the generic margining functionality out of being specific to USB4
ports.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
 drivers/thunderbolt/debugfs.c | 234 ++++++++++++++++------------------
 1 file changed, 112 insertions(+), 122 deletions(-)

diff --git a/drivers/thunderbolt/debugfs.c b/drivers/thunderbolt/debugfs.c
index 8ca0dbfc0117..d1779a667272 100644
--- a/drivers/thunderbolt/debugfs.c
+++ b/drivers/thunderbolt/debugfs.c
@@ -379,6 +379,7 @@ static ssize_t retimer_sb_regs_write(struct file *file,
 #if IS_ENABLED(CONFIG_USB4_DEBUGFS_MARGINING)
 /**
  * struct tb_margining - Lane margining support
+ * @port: USB4 port through which the margining operations are run
  * @caps: Port lane margining capabilities
  * @results: Last lane margining results
  * @lanes: %0, %1 or %7 (all)
@@ -395,6 +396,7 @@ static ssize_t retimer_sb_regs_write(struct file *file,
  *		right/high
  */
 struct tb_margining {
+	struct tb_port *port;
 	u32 caps[2];
 	u32 results[2];
 	unsigned int lanes;
@@ -410,36 +412,38 @@ struct tb_margining {
 	bool right_high;
 };
 
-static bool supports_software(const struct usb4_port *usb4)
+static bool supports_software(const struct tb_margining *margining)
 {
-	return usb4->margining->caps[0] & USB4_MARGIN_CAP_0_MODES_SW;
+	return margining->caps[0] & USB4_MARGIN_CAP_0_MODES_SW;
 }
 
-static bool supports_hardware(const struct usb4_port *usb4)
+static bool supports_hardware(const struct tb_margining *margining)
 {
-	return usb4->margining->caps[0] & USB4_MARGIN_CAP_0_MODES_HW;
+	return margining->caps[0] & USB4_MARGIN_CAP_0_MODES_HW;
 }
 
-static bool both_lanes(const struct usb4_port *usb4)
+static bool both_lanes(const struct tb_margining *margining)
 {
-	return usb4->margining->caps[0] & USB4_MARGIN_CAP_0_2_LANES;
+	return margining->caps[0] & USB4_MARGIN_CAP_0_2_LANES;
 }
 
-static unsigned int independent_voltage_margins(const struct usb4_port *usb4)
+static unsigned int
+independent_voltage_margins(const struct tb_margining *margining)
 {
-	return (usb4->margining->caps[0] & USB4_MARGIN_CAP_0_VOLTAGE_INDP_MASK) >>
+	return (margining->caps[0] & USB4_MARGIN_CAP_0_VOLTAGE_INDP_MASK) >>
 		USB4_MARGIN_CAP_0_VOLTAGE_INDP_SHIFT;
 }
 
-static bool supports_time(const struct usb4_port *usb4)
+static bool supports_time(const struct tb_margining *margining)
 {
-	return usb4->margining->caps[0] & USB4_MARGIN_CAP_0_TIME;
+	return margining->caps[0] & USB4_MARGIN_CAP_0_TIME;
 }
 
 /* Only applicable if supports_time() returns true */
-static unsigned int independent_time_margins(const struct usb4_port *usb4)
+static unsigned int
+independent_time_margins(const struct tb_margining *margining)
 {
-	return (usb4->margining->caps[1] & USB4_MARGIN_CAP_1_TIME_INDP_MASK) >>
+	return (margining->caps[1] & USB4_MARGIN_CAP_1_TIME_INDP_MASK) >>
 		USB4_MARGIN_CAP_1_TIME_INDP_SHIFT;
 }
 
@@ -448,9 +452,8 @@ margining_ber_level_write(struct file *file, const char __user *user_buf,
 			   size_t count, loff_t *ppos)
 {
 	struct seq_file *s = file->private_data;
-	struct tb_port *port = s->private;
-	struct usb4_port *usb4 = port->usb4;
-	struct tb *tb = port->sw->tb;
+	struct tb_margining *margining = s->private;
+	struct tb *tb = margining->port->sw->tb;
 	unsigned int val;
 	int ret = 0;
 	char *buf;
@@ -458,7 +461,7 @@ margining_ber_level_write(struct file *file, const char __user *user_buf,
 	if (mutex_lock_interruptible(&tb->lock))
 		return -ERESTARTSYS;
 
-	if (usb4->margining->software) {
+	if (margining->software) {
 		ret = -EINVAL;
 		goto out_unlock;
 	}
@@ -475,13 +478,13 @@ margining_ber_level_write(struct file *file, const char __user *user_buf,
 	if (ret)
 		goto out_free;
 
-	if (val < usb4->margining->min_ber_level ||
-	    val > usb4->margining->max_ber_level) {
+	if (val < margining->min_ber_level ||
+	    val > margining->max_ber_level) {
 		ret = -EINVAL;
 		goto out_free;
 	}
 
-	usb4->margining->ber_level = val;
+	margining->ber_level = val;
 
 out_free:
 	free_page((unsigned long)buf);
@@ -501,52 +504,50 @@ static void ber_level_show(struct seq_file *s, unsigned int val)
 
 static int margining_ber_level_show(struct seq_file *s, void *not_used)
 {
-	struct tb_port *port = s->private;
-	struct usb4_port *usb4 = port->usb4;
+	const struct tb_margining *margining = s->private;
 
-	if (usb4->margining->software)
+	if (margining->software)
 		return -EINVAL;
-	ber_level_show(s, usb4->margining->ber_level);
+	ber_level_show(s, margining->ber_level);
 	return 0;
 }
 DEBUGFS_ATTR_RW(margining_ber_level);
 
 static int margining_caps_show(struct seq_file *s, void *not_used)
 {
-	struct tb_port *port = s->private;
-	struct usb4_port *usb4 = port->usb4;
-	struct tb *tb = port->sw->tb;
+	struct tb_margining *margining = s->private;
+	struct tb *tb = margining->port->sw->tb;
 	u32 cap0, cap1;
 
 	if (mutex_lock_interruptible(&tb->lock))
 		return -ERESTARTSYS;
 
 	/* Dump the raw caps first */
-	cap0 = usb4->margining->caps[0];
+	cap0 = margining->caps[0];
 	seq_printf(s, "0x%08x\n", cap0);
-	cap1 = usb4->margining->caps[1];
+	cap1 = margining->caps[1];
 	seq_printf(s, "0x%08x\n", cap1);
 
 	seq_printf(s, "# software margining: %s\n",
-		   supports_software(usb4) ? "yes" : "no");
-	if (supports_hardware(usb4)) {
+		   supports_software(margining) ? "yes" : "no");
+	if (supports_hardware(margining)) {
 		seq_puts(s, "# hardware margining: yes\n");
 		seq_puts(s, "# minimum BER level contour: ");
-		ber_level_show(s, usb4->margining->min_ber_level);
+		ber_level_show(s, margining->min_ber_level);
 		seq_puts(s, "# maximum BER level contour: ");
-		ber_level_show(s, usb4->margining->max_ber_level);
+		ber_level_show(s, margining->max_ber_level);
 	} else {
 		seq_puts(s, "# hardware margining: no\n");
 	}
 
 	seq_printf(s, "# both lanes simultaneously: %s\n",
-		  both_lanes(usb4) ? "yes" : "no");
+		  both_lanes(margining) ? "yes" : "no");
 	seq_printf(s, "# voltage margin steps: %u\n",
-		   usb4->margining->voltage_steps);
+		   margining->voltage_steps);
 	seq_printf(s, "# maximum voltage offset: %u mV\n",
-		   usb4->margining->max_voltage_offset);
+		   margining->max_voltage_offset);
 
-	switch (independent_voltage_margins(usb4)) {
+	switch (independent_voltage_margins(margining)) {
 	case USB4_MARGIN_CAP_0_VOLTAGE_MIN:
 		seq_puts(s, "# returns minimum between high and low voltage margins\n");
 		break;
@@ -558,12 +559,12 @@ static int margining_caps_show(struct seq_file *s, void *not_used)
 		break;
 	}
 
-	if (supports_time(usb4)) {
+	if (supports_time(margining)) {
 		seq_puts(s, "# time margining: yes\n");
 		seq_printf(s, "# time margining is destructive: %s\n",
 			   cap1 & USB4_MARGIN_CAP_1_TIME_DESTR ? "yes" : "no");
 
-		switch (independent_time_margins(usb4)) {
+		switch (independent_time_margins(margining)) {
 		case USB4_MARGIN_CAP_1_TIME_MIN:
 			seq_puts(s, "# returns minimum between left and right time margins\n");
 			break;
@@ -576,9 +577,9 @@ static int margining_caps_show(struct seq_file *s, void *not_used)
 		}
 
 		seq_printf(s, "# time margin steps: %u\n",
-			   usb4->margining->time_steps);
+			   margining->time_steps);
 		seq_printf(s, "# maximum time offset: %u mUI\n",
-			   usb4->margining->max_time_offset);
+			   margining->max_time_offset);
 	} else {
 		seq_puts(s, "# time margining: no\n");
 	}
@@ -593,9 +594,8 @@ margining_lanes_write(struct file *file, const char __user *user_buf,
 		      size_t count, loff_t *ppos)
 {
 	struct seq_file *s = file->private_data;
-	struct tb_port *port = s->private;
-	struct usb4_port *usb4 = port->usb4;
-	struct tb *tb = port->sw->tb;
+	struct tb_margining *margining = s->private;
+	struct tb *tb = margining->port->sw->tb;
 	int ret = 0;
 	char *buf;
 
@@ -611,13 +611,13 @@ margining_lanes_write(struct file *file, const char __user *user_buf,
 	}
 
 	if (!strcmp(buf, "0")) {
-		usb4->margining->lanes = 0;
+		margining->lanes = 0;
 	} else if (!strcmp(buf, "1")) {
-		usb4->margining->lanes = 1;
+		margining->lanes = 1;
 	} else if (!strcmp(buf, "all")) {
 		/* Needs to be supported */
-		if (both_lanes(usb4))
-			usb4->margining->lanes = 7;
+		if (both_lanes(margining))
+			margining->lanes = 7;
 		else
 			ret = -EINVAL;
 	} else {
@@ -633,16 +633,15 @@ margining_lanes_write(struct file *file, const char __user *user_buf,
 
 static int margining_lanes_show(struct seq_file *s, void *not_used)
 {
-	struct tb_port *port = s->private;
-	struct usb4_port *usb4 = port->usb4;
-	struct tb *tb = port->sw->tb;
+	struct tb_margining *margining = s->private;
+	struct tb *tb = margining->port->sw->tb;
 	unsigned int lanes;
 
 	if (mutex_lock_interruptible(&tb->lock))
 		return -ERESTARTSYS;
 
-	lanes = usb4->margining->lanes;
-	if (both_lanes(usb4)) {
+	lanes = margining->lanes;
+	if (both_lanes(margining)) {
 		if (!lanes)
 			seq_puts(s, "[0] 1 all\n");
 		else if (lanes == 1)
@@ -666,9 +665,8 @@ static ssize_t margining_mode_write(struct file *file,
 				   size_t count, loff_t *ppos)
 {
 	struct seq_file *s = file->private_data;
-	struct tb_port *port = s->private;
-	struct usb4_port *usb4 = port->usb4;
-	struct tb *tb = port->sw->tb;
+	struct tb_margining *margining = s->private;
+	struct tb *tb = margining->port->sw->tb;
 	int ret = 0;
 	char *buf;
 
@@ -684,13 +682,13 @@ static ssize_t margining_mode_write(struct file *file,
 	}
 
 	if (!strcmp(buf, "software")) {
-		if (supports_software(usb4))
-			usb4->margining->software = true;
+		if (supports_software(margining))
+			margining->software = true;
 		else
 			ret = -EINVAL;
 	} else if (!strcmp(buf, "hardware")) {
-		if (supports_hardware(usb4))
-			usb4->margining->software = false;
+		if (supports_hardware(margining))
+			margining->software = false;
 		else
 			ret = -EINVAL;
 	} else {
@@ -706,23 +704,22 @@ static ssize_t margining_mode_write(struct file *file,
 
 static int margining_mode_show(struct seq_file *s, void *not_used)
 {
-	const struct tb_port *port = s->private;
-	const struct usb4_port *usb4 = port->usb4;
-	struct tb *tb = port->sw->tb;
+	struct tb_margining *margining = s->private;
+	struct tb *tb = margining->port->sw->tb;
 	const char *space = "";
 
 	if (mutex_lock_interruptible(&tb->lock))
 		return -ERESTARTSYS;
 
-	if (supports_software(usb4)) {
-		if (usb4->margining->software)
+	if (supports_software(margining)) {
+		if (margining->software)
 			seq_puts(s, "[software]");
 		else
 			seq_puts(s, "software");
 		space = " ";
 	}
-	if (supports_hardware(usb4)) {
-		if (usb4->margining->software)
+	if (supports_hardware(margining)) {
+		if (margining->software)
 			seq_printf(s, "%shardware", space);
 		else
 			seq_printf(s, "%s[hardware]", space);
@@ -737,10 +734,9 @@ DEBUGFS_ATTR_RW(margining_mode);
 
 static int margining_run_write(void *data, u64 val)
 {
-	struct tb_port *port = data;
-	struct usb4_port *usb4 = port->usb4;
+	struct tb_margining *margining = data;
+	struct tb_port *port = margining->port;
 	struct tb_switch *sw = port->sw;
-	struct tb_margining *margining;
 	struct tb_switch *down_sw;
 	struct tb *tb = sw->tb;
 	int ret, clx;
@@ -775,8 +771,6 @@ static int margining_run_write(void *data, u64 val)
 		clx = ret;
 	}
 
-	margining = usb4->margining;
-
 	if (margining->software) {
 		tb_port_dbg(port, "running software %s lane margining for lanes %u\n",
 			    margining->time ? "time" : "voltage", margining->lanes);
@@ -817,16 +811,15 @@ static ssize_t margining_results_write(struct file *file,
 				       size_t count, loff_t *ppos)
 {
 	struct seq_file *s = file->private_data;
-	struct tb_port *port = s->private;
-	struct usb4_port *usb4 = port->usb4;
-	struct tb *tb = port->sw->tb;
+	struct tb_margining *margining = s->private;
+	struct tb *tb = margining->port->sw->tb;
 
 	if (mutex_lock_interruptible(&tb->lock))
 		return -ERESTARTSYS;
 
 	/* Just clear the results */
-	usb4->margining->results[0] = 0;
-	usb4->margining->results[1] = 0;
+	margining->results[0] = 0;
+	margining->results[1] = 0;
 
 	mutex_unlock(&tb->lock);
 	return count;
@@ -860,15 +853,12 @@ static void time_margin_show(struct seq_file *s,
 
 static int margining_results_show(struct seq_file *s, void *not_used)
 {
-	struct tb_port *port = s->private;
-	struct usb4_port *usb4 = port->usb4;
-	struct tb_margining *margining;
-	struct tb *tb = port->sw->tb;
+	struct tb_margining *margining = s->private;
+	struct tb *tb = margining->port->sw->tb;
 
 	if (mutex_lock_interruptible(&tb->lock))
 		return -ERESTARTSYS;
 
-	margining = usb4->margining;
 	/* Dump the raw results first */
 	seq_printf(s, "0x%08x\n", margining->results[0]);
 	/* Only the hardware margining has two result dwords */
@@ -930,9 +920,8 @@ static ssize_t margining_test_write(struct file *file,
 				    size_t count, loff_t *ppos)
 {
 	struct seq_file *s = file->private_data;
-	struct tb_port *port = s->private;
-	struct usb4_port *usb4 = port->usb4;
-	struct tb *tb = port->sw->tb;
+	struct tb_margining *margining = s->private;
+	struct tb *tb = margining->port->sw->tb;
 	int ret = 0;
 	char *buf;
 
@@ -947,10 +936,10 @@ static ssize_t margining_test_write(struct file *file,
 		goto out_free;
 	}
 
-	if (!strcmp(buf, "time") && supports_time(usb4))
-		usb4->margining->time = true;
+	if (!strcmp(buf, "time") && supports_time(margining))
+		margining->time = true;
 	else if (!strcmp(buf, "voltage"))
-		usb4->margining->time = false;
+		margining->time = false;
 	else
 		ret = -EINVAL;
 
@@ -963,15 +952,14 @@ static ssize_t margining_test_write(struct file *file,
 
 static int margining_test_show(struct seq_file *s, void *not_used)
 {
-	struct tb_port *port = s->private;
-	struct usb4_port *usb4 = port->usb4;
-	struct tb *tb = port->sw->tb;
+	struct tb_margining *margining = s->private;
+	struct tb *tb = margining->port->sw->tb;
 
 	if (mutex_lock_interruptible(&tb->lock))
 		return -ERESTARTSYS;
 
-	if (supports_time(usb4)) {
-		if (usb4->margining->time)
+	if (supports_time(margining)) {
+		if (margining->time)
 			seq_puts(s, "voltage [time]\n");
 		else
 			seq_puts(s, "[voltage] time\n");
@@ -989,9 +977,8 @@ static ssize_t margining_margin_write(struct file *file,
 				    size_t count, loff_t *ppos)
 {
 	struct seq_file *s = file->private_data;
-	struct tb_port *port = s->private;
-	struct usb4_port *usb4 = port->usb4;
-	struct tb *tb = port->sw->tb;
+	struct tb_margining *margining = s->private;
+	struct tb *tb = margining->port->sw->tb;
 	int ret = 0;
 	char *buf;
 
@@ -1006,18 +993,18 @@ static ssize_t margining_margin_write(struct file *file,
 		goto out_free;
 	}
 
-	if (usb4->margining->time) {
+	if (margining->time) {
 		if (!strcmp(buf, "left"))
-			usb4->margining->right_high = false;
+			margining->right_high = false;
 		else if (!strcmp(buf, "right"))
-			usb4->margining->right_high = true;
+			margining->right_high = true;
 		else
 			ret = -EINVAL;
 	} else {
 		if (!strcmp(buf, "low"))
-			usb4->margining->right_high = false;
+			margining->right_high = false;
 		else if (!strcmp(buf, "high"))
-			usb4->margining->right_high = true;
+			margining->right_high = true;
 		else
 			ret = -EINVAL;
 	}
@@ -1031,20 +1018,19 @@ static ssize_t margining_margin_write(struct file *file,
 
 static int margining_margin_show(struct seq_file *s, void *not_used)
 {
-	struct tb_port *port = s->private;
-	struct usb4_port *usb4 = port->usb4;
-	struct tb *tb = port->sw->tb;
+	struct tb_margining *margining = s->private;
+	struct tb *tb = margining->port->sw->tb;
 
 	if (mutex_lock_interruptible(&tb->lock))
 		return -ERESTARTSYS;
 
-	if (usb4->margining->time) {
-		if (usb4->margining->right_high)
+	if (margining->time) {
+		if (margining->right_high)
 			seq_puts(s, "left [right]\n");
 		else
 			seq_puts(s, "[left] right\n");
 	} else {
-		if (usb4->margining->right_high)
+		if (margining->right_high)
 			seq_puts(s, "low [high]\n");
 		else
 			seq_puts(s, "[low] high\n");
@@ -1075,16 +1061,16 @@ static void margining_port_init(struct tb_port *port)
 	if (!margining)
 		return;
 
+	margining->port = port;
+
 	ret = usb4_port_margining_caps(port, margining->caps);
 	if (ret) {
 		kfree(margining);
 		return;
 	}
 
-	usb4->margining = margining;
-
 	/* Set the initial mode */
-	if (supports_software(usb4))
+	if (supports_software(margining))
 		margining->software = true;
 
 	val = (margining->caps[0] & USB4_MARGIN_CAP_0_VOLTAGE_STEPS_MASK) >>
@@ -1094,7 +1080,7 @@ static void margining_port_init(struct tb_port *port)
 		USB4_MARGIN_CAP_0_MAX_VOLTAGE_OFFSET_SHIFT;
 	margining->max_voltage_offset = 74 + val * 2;
 
-	if (supports_time(usb4)) {
+	if (supports_time(margining)) {
 		val = (margining->caps[1] & USB4_MARGIN_CAP_1_TIME_STEPS_MASK) >>
 			USB4_MARGIN_CAP_1_TIME_STEPS_SHIFT;
 		margining->time_steps = val;
@@ -1108,7 +1094,7 @@ static void margining_port_init(struct tb_port *port)
 	}
 
 	dir = debugfs_create_dir("margining", parent);
-	if (supports_hardware(usb4)) {
+	if (supports_hardware(margining)) {
 		val = (margining->caps[1] & USB4_MARGIN_CAP_1_MIN_BER_MASK) >>
 			USB4_MARGIN_CAP_1_MIN_BER_SHIFT;
 		margining->min_ber_level = val;
@@ -1119,19 +1105,23 @@ static void margining_port_init(struct tb_port *port)
 		/* Set the default to minimum */
 		margining->ber_level = margining->min_ber_level;
 
-		debugfs_create_file("ber_level_contour", 0400, dir, port,
+		debugfs_create_file("ber_level_contour", 0400, dir, margining,
 				    &margining_ber_level_fops);
 	}
-	debugfs_create_file("caps", 0400, dir, port, &margining_caps_fops);
-	debugfs_create_file("lanes", 0600, dir, port, &margining_lanes_fops);
-	debugfs_create_file("mode", 0600, dir, port, &margining_mode_fops);
-	debugfs_create_file("run", 0600, dir, port, &margining_run_fops);
-	debugfs_create_file("results", 0600, dir, port, &margining_results_fops);
-	debugfs_create_file("test", 0600, dir, port, &margining_test_fops);
-	if (independent_voltage_margins(usb4) == USB4_MARGIN_CAP_0_VOLTAGE_HL ||
-	    (supports_time(usb4) &&
-	     independent_time_margins(usb4) == USB4_MARGIN_CAP_1_TIME_LR))
-		debugfs_create_file("margin", 0600, dir, port, &margining_margin_fops);
+	debugfs_create_file("caps", 0400, dir, margining, &margining_caps_fops);
+	debugfs_create_file("lanes", 0600, dir, margining, &margining_lanes_fops);
+	debugfs_create_file("mode", 0600, dir, margining, &margining_mode_fops);
+	debugfs_create_file("run", 0600, dir, margining, &margining_run_fops);
+	debugfs_create_file("results", 0600, dir, margining,
+			    &margining_results_fops);
+	debugfs_create_file("test", 0600, dir, margining, &margining_test_fops);
+	if (independent_voltage_margins(margining) == USB4_MARGIN_CAP_0_VOLTAGE_HL ||
+	    (supports_time(margining) &&
+	     independent_time_margins(margining) == USB4_MARGIN_CAP_1_TIME_LR))
+		debugfs_create_file("margin", 0600, dir, margining,
+				    &margining_margin_fops);
+
+	usb4->margining = margining;
 }
 
 static void margining_port_remove(struct tb_port *port)
-- 
2.43.0


  parent reply	other threads:[~2024-06-10 10:06 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-06-10 10:06 [PATCH 0/6] thunderbolt: Sideband access and retimer lane margining support Mika Westerberg
2024-06-10 10:06 ` [PATCH 1/6] thunderbolt: Move usb4_port_margining_caps() declaration into correct place Mika Westerberg
2024-06-10 10:06 ` [PATCH 2/6] thunderbolt: Make usb4_port_sb_read/write() available outside of usb4.c Mika Westerberg
2024-06-10 10:06 ` [PATCH 3/6] thunderbolt: Add sideband register access to debugfs Mika Westerberg
2024-06-10 10:32   ` Greg KH
2024-06-10 11:14     ` Mika Westerberg
2024-06-10 10:06 ` Mika Westerberg [this message]
2024-06-10 10:06 ` [PATCH 5/6] thunderbolt: Make margining functions accept target and retimer index Mika Westerberg
2024-06-10 10:06 ` [PATCH 6/6] thunderbolt: Add receiver lane margining support for retimers Mika Westerberg

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=20240610100627.3521887-5-mika.westerberg@linux.intel.com \
    --to=mika.westerberg@linux.intel.com \
    --cc=YehezkelShB@gmail.com \
    --cc=andreas.noever@gmail.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.