diff --git a/drivers/thunderbolt/debugfs.c b/drivers/thunderbolt/debugfs.c
index 9899d88b7371..a1d0d8a33f20 100644
--- a/drivers/thunderbolt/debugfs.c
+++ b/drivers/thunderbolt/debugfs.c
@@ -415,6 +415,7 @@ static ssize_t retimer_sb_regs_write(struct file *file,
  * @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER
  * @dev: Pointer to the device that is the target (USB4 port or retimer)
  * @gen: Link generation
+ * @asym_rx: %true% if @port supports asymmetric link with 3 Rx
  * @caps: Port lane margining capabilities
  * @results: Last lane margining results
  * @lanes: %0, %1 or %7 (all)
@@ -445,8 +446,9 @@ struct tb_margining {
 	u8 index;
 	struct device *dev;
 	unsigned int gen;
+	bool asym_rx;
 	u32 caps[3];
-	u32 results[2];
+	u32 results[3];
 	enum usb4_margining_lane lanes;
 	unsigned int min_ber_level;
 	unsigned int max_ber_level;
@@ -735,14 +737,37 @@ static int margining_caps_show(struct seq_file *s, void *not_used)
 }
 DEBUGFS_ATTR_RO(margining_caps);
 
+static const struct {
+	enum usb4_margining_lane lane;
+	const char *name;
+} lane_names[] = {
+	{
+		.lane = USB4_MARGINING_LANE_RX0,
+		.name = "0",
+	},
+	{
+		.lane = USB4_MARGINING_LANE_RX1,
+		.name = "1",
+	},
+	{
+		.lane = USB4_MARGINING_LANE_RX2,
+		.name = "2",
+	},
+	{
+		.lane = USB4_MARGINING_LANE_ALL,
+		.name = "all",
+	},
+};
+
 static ssize_t
 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_margining *margining = s->private;
-	struct tb *tb = margining->port->sw->tb;
-	int ret = 0;
+	struct tb_port *port = margining->port;
+	struct tb *tb = port->sw->tb;
+	int lane = -1;
 	char *buf;
 
 	buf = validate_and_copy_from_user(user_buf, &count);
@@ -751,57 +776,60 @@ margining_lanes_write(struct file *file, const char __user *user_buf,
 
 	buf[count - 1] = '\0';
 
-	if (mutex_lock_interruptible(&tb->lock)) {
-		ret = -ERESTARTSYS;
-		goto out_free;
+	for (int i = 0; i < ARRAY_SIZE(lane_names); i++) {
+		if (!strcmp(buf, lane_names[i].name)) {
+			lane = lane_names[i].lane;
+			break;
+		}
 	}
 
-	if (!strcmp(buf, "0")) {
-		margining->lanes = USB4_MARGINING_LANE_RX0;
-	} else if (!strcmp(buf, "1")) {
-		margining->lanes = USB4_MARGINING_LANE_RX1;
-	} else if (!strcmp(buf, "all")) {
-		/* Needs to be supported */
-		if (all_lanes(margining))
-			margining->lanes = USB4_MARGINING_LANE_ALL;
-		else
-			ret = -EINVAL;
-	} else {
-		ret = -EINVAL;
-	}
+	free_page((unsigned long)buf);
 
-	mutex_unlock(&tb->lock);
+	if (lane == -1)
+		return -EINVAL;
 
-out_free:
-	free_page((unsigned long)buf);
-	return ret < 0 ? ret : count;
+	scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) {
+		if (lane == USB4_MARGINING_LANE_ALL && !all_lanes(margining))
+			return -EINVAL;
+		/*
+		 * Enabling on RX2 requires that it is supported by the
+		 * USB4 port.
+		 */
+		if (lane == USB4_MARGINING_LANE_RX2 && !margining->asym_rx)
+			return -EINVAL;
+
+		margining->lanes = lane;
+	}
+
+	return count;
 }
 
 static int margining_lanes_show(struct seq_file *s, void *not_used)
 {
 	struct tb_margining *margining = s->private;
-	struct tb *tb = margining->port->sw->tb;
-	enum usb4_margining_lane lanes;
-
-	if (mutex_lock_interruptible(&tb->lock))
-		return -ERESTARTSYS;
+	struct tb_port *port = margining->port;
+	struct tb *tb = port->sw->tb;
 
-	lanes = margining->lanes;
-	if (all_lanes(margining)) {
-		if (lanes == USB4_MARGINING_LANE_RX0)
-			seq_puts(s, "[0] 1 all\n");
-		else if (lanes == USB4_MARGINING_LANE_RX1)
-			seq_puts(s, "0 [1] all\n");
-		else
-			seq_puts(s, "0 1 [all]\n");
-	} else {
-		if (lanes == USB4_MARGINING_LANE_RX0)
-			seq_puts(s, "[0] 1\n");
-		else
-			seq_puts(s, "0 [1]\n");
+	scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) {
+		for (int i = 0; i < ARRAY_SIZE(lane_names); i++) {
+			if (lane_names[i].lane == USB4_MARGINING_LANE_ALL &&
+			    !all_lanes(margining))
+				continue;
+			if (lane_names[i].lane == USB4_MARGINING_LANE_RX2 &&
+			    !margining->asym_rx)
+				continue;
+
+			if (i != 0)
+				seq_putc(s, ' ');
+
+			if (lane_names[i].lane == margining->lanes)
+				seq_printf(s, "[%s]", lane_names[i].name);
+			else
+				seq_printf(s, "%s", lane_names[i].name);
+		}
+		seq_puts(s, "\n");
 	}
 
-	mutex_unlock(&tb->lock);
 	return 0;
 }
 DEBUGFS_ATTR_RW(margining_lanes);
@@ -1095,6 +1123,9 @@ static int margining_run_sw(struct tb_margining *margining,
 		else if (margining->lanes == USB4_MARGINING_LANE_RX1)
 			errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_1_MASK,
 					   margining->results[1]);
+		else if (margining->lanes == USB4_MARGINING_LANE_RX2)
+			errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_2_MASK,
+					   margining->results[1]);
 		else if (margining->lanes == USB4_MARGINING_LANE_ALL)
 			errors = margining->results[1];
 
@@ -1115,6 +1146,31 @@ static int margining_run_sw(struct tb_margining *margining,
 	return ret;
 }
 
+static int validate_margining(struct tb_margining *margining)
+{
+	/*
+	 * For running on RX2 the link must be asymmetric with 3
+	 * receivers. Because this is can change dynamically, check it
+	 * here before we start the margining and report back error if
+	 * expectations are not met.
+	 */
+	if (margining->lanes == USB4_MARGINING_LANE_RX2) {
+		int ret;
+
+		ret = tb_port_get_link_width(margining->port);
+		if (ret < 0)
+			return ret;
+		if (ret != TB_LINK_WIDTH_ASYM_RX) {
+			tb_port_warn(margining->port, "link is %s expected %s",
+				     tb_width_name(ret),
+				     tb_width_name(TB_LINK_WIDTH_ASYM_RX));
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int margining_run_write(void *data, u64 val)
 {
 	struct tb_margining *margining = data;
@@ -1135,6 +1191,10 @@ static int margining_run_write(void *data, u64 val)
 		goto out_rpm_put;
 	}
 
+	ret = validate_margining(margining);
+	if (ret)
+		goto out_unlock;
+
 	if (tb_is_upstream_port(port))
 		down_sw = sw;
 	else if (port->remote)
@@ -1270,6 +1330,8 @@ static u8 margining_hw_result_val(const u32 *results,
 		val = results[1];
 	else if (lane == USB4_MARGINING_LANE_RX1)
 		val = results[1] >> USB4_MARGIN_HW_RES_LANE_SHIFT;
+	else if (lane == USB4_MARGINING_LANE_RX2)
+		val = results[2];
 	else
 		val = 0;
 
@@ -1319,6 +1381,9 @@ static int margining_results_show(struct seq_file *s, void *not_used)
 						   USB4_MARGINING_LANE_RX0);
 			margining_hw_result_format(s, margining,
 						   USB4_MARGINING_LANE_RX1);
+			if (margining->asym_rx)
+				margining_hw_result_format(s, margining,
+						USB4_MARGINING_LANE_RX2);
 		} else {
 			margining_hw_result_format(s, margining,
 						   margining->lanes);
@@ -1341,6 +1406,13 @@ static int margining_results_show(struct seq_file *s, void *not_used)
 						margining->results[1]);
 			seq_printf(s, "# lane 1 errors: %u\n", lane_errors);
 		}
+		if (margining->asym_rx &&
+		    (result == USB4_MARGINING_LANE_RX2 ||
+		     result == USB4_MARGINING_LANE_ALL)) {
+			lane_errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_2_MASK,
+						margining->results[1]);
+			seq_printf(s, "# lane 2 errors: %u\n", lane_errors);
+		}
 	}
 
 	mutex_unlock(&tb->lock);
@@ -1548,6 +1620,7 @@ static struct tb_margining *margining_alloc(struct tb_port *port,
 	margining->index = index;
 	margining->dev = dev;
 	margining->gen = ret;
+	margining->asym_rx = tb_port_width_supported(port, TB_LINK_WIDTH_ASYM_RX);
 
 	ret = usb4_port_margining_caps(port, target, index, margining->caps,
 				       ARRAY_SIZE(margining->caps));
diff --git a/drivers/thunderbolt/sb_regs.h b/drivers/thunderbolt/sb_regs.h
index 7b5521ea0f74..5391502a4b87 100644
--- a/drivers/thunderbolt/sb_regs.h
+++ b/drivers/thunderbolt/sb_regs.h
@@ -107,5 +107,6 @@ enum usb4_sb_opcode {
 
 #define USB4_MARGIN_SW_ERR_COUNTER_LANE_0_MASK	GENMASK(3, 0)
 #define USB4_MARGIN_SW_ERR_COUNTER_LANE_1_MASK	GENMASK(7, 4)
+#define USB4_MARGIN_SW_ERR_COUNTER_LANE_2_MASK	GENMASK(11, 8)
 
 #endif
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index 0954b8bafada..ddbf0cd78377 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -1370,6 +1370,7 @@ enum usb4_margin_sw_error_counter {
 enum usb4_margining_lane {
 	USB4_MARGINING_LANE_RX0 = 0,
 	USB4_MARGINING_LANE_RX1 = 1,
+	USB4_MARGINING_LANE_RX2 = 2,
 	USB4_MARGINING_LANE_ALL = 7,
 };
 
