]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
thunderbolt: Split out margining from USB4 port
authorMika Westerberg <mika.westerberg@linux.intel.com>
Tue, 14 Mar 2023 16:35:12 +0000 (18:35 +0200)
committerMika Westerberg <mika.westerberg@linux.intel.com>
Mon, 17 Jun 2024 09:47:11 +0000 (12:47 +0300)
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

index 5196ece2ded732cd583caac3c3a78cc96ca8826e..0e871c7ae9c03d0e18bf97d1ffdefae16a948c2a 100644 (file)
@@ -379,6 +379,7 @@ out_rpm_put:
 #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 @@ out_rpm_put:
  *             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 @@ out_free:
 
 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 @@ out_free:
 
 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 @@ out_free:
 
 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 @@ out_free:
 
 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)