diff options
author | Aapo Vienamo <aapo.vienamo@iki.fi> | 2024-08-15 21:45:15 +0300 |
---|---|---|
committer | Mika Westerberg <mika.westerberg@linux.intel.com> | 2024-11-01 07:55:38 +0200 |
commit | c8c08fd9c23b5e6a11336675b2584315f87001cc (patch) | |
tree | 9e9a36cd1e77a1d913562c7309dcccac98b6bb26 /drivers/thunderbolt/debugfs.c | |
parent | c9077d59adf43c9e9303e4651248839162fd9be6 (diff) | |
download | lwn-c8c08fd9c23b5e6a11336675b2584315f87001cc.tar.gz lwn-c8c08fd9c23b5e6a11336675b2584315f87001cc.zip |
thunderbolt: debugfs: Implement Gen 4 margining eye selection
Add a debugfs knob for USB4 Gen 4 margining eye selection. Gen 4 uses
3-level pulse amplitude modulation (PAM3) which changes how margining
measurements are made because PAM3 has two eyes per lane from which
the margins can be measured.
Signed-off-by: Aapo Vienamo <aapo.vienamo@iki.fi>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Diffstat (limited to 'drivers/thunderbolt/debugfs.c')
-rw-r--r-- | drivers/thunderbolt/debugfs.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/drivers/thunderbolt/debugfs.c b/drivers/thunderbolt/debugfs.c index 83721ca069a5..699e1632e3f5 100644 --- a/drivers/thunderbolt/debugfs.c +++ b/drivers/thunderbolt/debugfs.c @@ -436,6 +436,8 @@ out: * @time: %true if time margining is used instead of voltage * @right_high: %false if left/low margin test is performed, %true if * right/high + * @upper_eye: %false if the lower PAM3 eye is used, %true if the upper + * eye is used */ struct tb_margining { struct tb_port *port; @@ -462,6 +464,7 @@ struct tb_margining { bool software; bool time; bool right_high; + bool upper_eye; }; static int margining_modify_error_counter(struct tb_margining *margining, @@ -1162,6 +1165,7 @@ static int margining_run_write(void *data, u64 val) .time = margining->time, .voltage_time_offset = margining->voltage_time_offset, .right_high = margining->right_high, + .upper_eye = margining->upper_eye, .optional_voltage_offset_range = margining->optional_voltage_offset_range, }; @@ -1177,6 +1181,7 @@ static int margining_run_write(void *data, u64 val) .lanes = margining->lanes, .time = margining->time, .right_high = margining->right_high, + .upper_eye = margining->upper_eye, .optional_voltage_offset_range = margining->optional_voltage_offset_range, }; @@ -1464,6 +1469,55 @@ static int margining_margin_show(struct seq_file *s, void *not_used) } DEBUGFS_ATTR_RW(margining_margin); +static ssize_t margining_eye_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; + int ret = 0; + char *buf; + + buf = validate_and_copy_from_user(user_buf, &count); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + buf[count - 1] = '\0'; + + scoped_cond_guard(mutex_intr, ret = -ERESTARTSYS, &tb->lock) { + if (!strcmp(buf, "lower")) + usb4->margining->upper_eye = false; + else if (!strcmp(buf, "upper")) + usb4->margining->upper_eye = true; + else + ret = -EINVAL; + } + + free_page((unsigned long)buf); + return ret ? ret : count; +} + +static int margining_eye_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; + + scoped_guard(mutex_intr, &tb->lock) { + if (usb4->margining->upper_eye) + seq_puts(s, "lower [upper]\n"); + else + seq_puts(s, "[lower] upper\n"); + + return 0; + } + + return -ERESTARTSYS; +} +DEBUGFS_ATTR_RW(margining_eye); + static struct tb_margining *margining_alloc(struct tb_port *port, struct device *dev, enum usb4_sb_target target, @@ -1573,6 +1627,10 @@ static struct tb_margining *margining_alloc(struct tb_port *port, debugfs_create_file("dwell_time", DEBUGFS_MODE, dir, margining, &margining_dwell_time_fops); } + + if (margining->gen >= 4) + debugfs_create_file("eye", 0600, dir, port, &margining_eye_fops); + return margining; } |