[PATCH 19/44] thunderbolt: Split out margining from USB4 port
Imre Deak
imre.deak at intel.com
Tue Jan 23 13:26:28 UTC 2024
From: Mika Westerberg <mika.westerberg at 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 at linux.intel.com>
---
drivers/thunderbolt/debugfs.c | 232 ++++++++++++++++------------------
1 file changed, 111 insertions(+), 121 deletions(-)
diff --git a/drivers/thunderbolt/debugfs.c b/drivers/thunderbolt/debugfs.c
index e324cd8997193..4f50afd2516f7 100644
--- a/drivers/thunderbolt/debugfs.c
+++ b/drivers/thunderbolt/debugfs.c
@@ -194,6 +194,7 @@ static ssize_t switch_regs_write(struct file *file, const char __user *user_buf,
#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)
@@ -210,6 +211,7 @@ static ssize_t switch_regs_write(struct file *file, const char __user *user_buf,
* right/high
*/
struct tb_margining {
+ struct tb_port *port;
u32 caps[2];
u32 results[2];
unsigned int lanes;
@@ -225,36 +227,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;
}
@@ -263,9 +267,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;
@@ -273,7 +276,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;
}
@@ -290,13 +293,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);
@@ -316,52 +319,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;
@@ -373,12 +374,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;
@@ -391,9 +392,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");
}
@@ -408,9 +409,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;
@@ -426,13 +426,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 {
@@ -448,16 +448,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)
@@ -481,9 +480,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;
@@ -499,13 +497,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 {
@@ -521,23 +519,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);
@@ -552,10 +549,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;
@@ -590,8 +586,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);
@@ -632,16 +626,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;
@@ -675,15 +668,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 */
@@ -745,9 +735,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;
@@ -762,10 +751,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;
@@ -778,15 +767,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");
@@ -804,9 +792,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;
@@ -821,18 +808,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;
}
@@ -846,20 +833,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");
@@ -890,16 +876,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) >>
@@ -909,7 +895,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;
@@ -923,7 +909,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;
@@ -934,18 +920,22 @@ 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) ||
- (supports_time(usb4) && independent_time_margins(usb4)))
- 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) ||
+ (supports_time(margining) && independent_time_margins(margining)))
+ debugfs_create_file("margin", 0600, dir, margining,
+ &margining_margin_fops);
+
+ usb4->margining = margining;
}
static void margining_port_remove(struct tb_port *port)
--
2.39.2
More information about the Intel-gfx-trybot
mailing list