2274 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Debugfs interface4 *5 * Copyright (C) 2020, Intel Corporation6 * Authors: Gil Fine <gil.fine@intel.com>7 * Mika Westerberg <mika.westerberg@linux.intel.com>8 */9 10#include <linux/bitfield.h>11#include <linux/debugfs.h>12#include <linux/delay.h>13#include <linux/pm_runtime.h>14#include <linux/uaccess.h>15 16#include "tb.h"17#include "sb_regs.h"18 19#define PORT_CAP_V1_PCIE_LEN 120#define PORT_CAP_V2_PCIE_LEN 221#define PORT_CAP_POWER_LEN 222#define PORT_CAP_LANE_LEN 323#define PORT_CAP_USB3_LEN 524#define PORT_CAP_DP_V1_LEN 925#define PORT_CAP_DP_V2_LEN 1426#define PORT_CAP_TMU_V1_LEN 827#define PORT_CAP_TMU_V2_LEN 1028#define PORT_CAP_BASIC_LEN 929#define PORT_CAP_USB4_LEN 2030 31#define SWITCH_CAP_TMU_LEN 2632#define SWITCH_CAP_BASIC_LEN 2733 34#define PATH_LEN 235 36#define COUNTER_SET_LEN 337 38/*39 * USB4 spec doesn't specify dwell range, the range of 100 ms to 500 ms40 * probed to give good results.41 */42#define MIN_DWELL_TIME 100 /* ms */43#define MAX_DWELL_TIME 500 /* ms */44#define DWELL_SAMPLE_INTERVAL 1045 46/* Sideband registers and their sizes as defined in the USB4 spec */47struct sb_reg {48 unsigned int reg;49 unsigned int size;50};51 52#define SB_MAX_SIZE 6453 54/* Sideband registers for router */55static const struct sb_reg port_sb_regs[] = {56 { USB4_SB_VENDOR_ID, 4 },57 { USB4_SB_PRODUCT_ID, 4 },58 { USB4_SB_DEBUG_CONF, 4 },59 { USB4_SB_DEBUG, 54 },60 { USB4_SB_LRD_TUNING, 4 },61 { USB4_SB_OPCODE, 4 },62 { USB4_SB_METADATA, 4 },63 { USB4_SB_LINK_CONF, 3 },64 { USB4_SB_GEN23_TXFFE, 4 },65 { USB4_SB_GEN4_TXFFE, 4 },66 { USB4_SB_VERSION, 4 },67 { USB4_SB_DATA, 64 },68};69 70/* Sideband registers for retimer */71static const struct sb_reg retimer_sb_regs[] = {72 { USB4_SB_VENDOR_ID, 4 },73 { USB4_SB_PRODUCT_ID, 4 },74 { USB4_SB_FW_VERSION, 4 },75 { USB4_SB_LRD_TUNING, 4 },76 { USB4_SB_OPCODE, 4 },77 { USB4_SB_METADATA, 4 },78 { USB4_SB_GEN23_TXFFE, 4 },79 { USB4_SB_GEN4_TXFFE, 4 },80 { USB4_SB_VERSION, 4 },81 { USB4_SB_DATA, 64 },82};83 84#define DEBUGFS_ATTR(__space, __write) \85static int __space ## _open(struct inode *inode, struct file *file) \86{ \87 return single_open(file, __space ## _show, inode->i_private); \88} \89 \90static const struct file_operations __space ## _fops = { \91 .owner = THIS_MODULE, \92 .open = __space ## _open, \93 .release = single_release, \94 .read = seq_read, \95 .write = __write, \96 .llseek = seq_lseek, \97}98 99#define DEBUGFS_ATTR_RO(__space) \100 DEBUGFS_ATTR(__space, NULL)101 102#define DEBUGFS_ATTR_RW(__space) \103 DEBUGFS_ATTR(__space, __space ## _write)104 105static struct dentry *tb_debugfs_root;106 107static void *validate_and_copy_from_user(const void __user *user_buf,108 size_t *count)109{110 size_t nbytes;111 void *buf;112 113 if (!*count)114 return ERR_PTR(-EINVAL);115 116 if (!access_ok(user_buf, *count))117 return ERR_PTR(-EFAULT);118 119 buf = (void *)get_zeroed_page(GFP_KERNEL);120 if (!buf)121 return ERR_PTR(-ENOMEM);122 123 nbytes = min_t(size_t, *count, PAGE_SIZE);124 if (copy_from_user(buf, user_buf, nbytes)) {125 free_page((unsigned long)buf);126 return ERR_PTR(-EFAULT);127 }128 129 *count = nbytes;130 return buf;131}132 133static bool parse_line(char **line, u32 *offs, u32 *val, int short_fmt_len,134 int long_fmt_len)135{136 char *token;137 u32 v[5];138 int ret;139 140 token = strsep(line, "\n");141 if (!token)142 return false;143 144 /*145 * For Adapter/Router configuration space:146 * Short format is: offset value\n147 * v[0] v[1]148 * Long format as produced from the read side:149 * offset relative_offset cap_id vs_cap_id value\n150 * v[0] v[1] v[2] v[3] v[4]151 *152 * For Counter configuration space:153 * Short format is: offset\n154 * v[0]155 * Long format as produced from the read side:156 * offset relative_offset counter_id value\n157 * v[0] v[1] v[2] v[3]158 */159 ret = sscanf(token, "%i %i %i %i %i", &v[0], &v[1], &v[2], &v[3], &v[4]);160 /* In case of Counters, clear counter, "val" content is NA */161 if (ret == short_fmt_len) {162 *offs = v[0];163 *val = v[short_fmt_len - 1];164 return true;165 } else if (ret == long_fmt_len) {166 *offs = v[0];167 *val = v[long_fmt_len - 1];168 return true;169 }170 171 return false;172}173 174#if IS_ENABLED(CONFIG_USB4_DEBUGFS_WRITE)175static ssize_t regs_write(struct tb_switch *sw, struct tb_port *port,176 const char __user *user_buf, size_t count,177 loff_t *ppos)178{179 struct tb *tb = sw->tb;180 char *line, *buf;181 u32 val, offset;182 int ret = 0;183 184 buf = validate_and_copy_from_user(user_buf, &count);185 if (IS_ERR(buf))186 return PTR_ERR(buf);187 188 pm_runtime_get_sync(&sw->dev);189 190 if (mutex_lock_interruptible(&tb->lock)) {191 ret = -ERESTARTSYS;192 goto out;193 }194 195 /* User did hardware changes behind the driver's back */196 add_taint(TAINT_USER, LOCKDEP_STILL_OK);197 198 line = buf;199 while (parse_line(&line, &offset, &val, 2, 5)) {200 if (port)201 ret = tb_port_write(port, &val, TB_CFG_PORT, offset, 1);202 else203 ret = tb_sw_write(sw, &val, TB_CFG_SWITCH, offset, 1);204 if (ret)205 break;206 }207 208 mutex_unlock(&tb->lock);209 210out:211 pm_runtime_mark_last_busy(&sw->dev);212 pm_runtime_put_autosuspend(&sw->dev);213 free_page((unsigned long)buf);214 215 return ret < 0 ? ret : count;216}217 218static ssize_t port_regs_write(struct file *file, const char __user *user_buf,219 size_t count, loff_t *ppos)220{221 struct seq_file *s = file->private_data;222 struct tb_port *port = s->private;223 224 return regs_write(port->sw, port, user_buf, count, ppos);225}226 227static ssize_t switch_regs_write(struct file *file, const char __user *user_buf,228 size_t count, loff_t *ppos)229{230 struct seq_file *s = file->private_data;231 struct tb_switch *sw = s->private;232 233 return regs_write(sw, NULL, user_buf, count, ppos);234}235 236static bool parse_sb_line(char **line, u8 *reg, u8 *data, size_t data_size,237 size_t *bytes_read)238{239 char *field, *token;240 int i;241 242 token = strsep(line, "\n");243 if (!token)244 return false;245 246 /* Parse the register first */247 field = strsep(&token, " ");248 if (!field)249 return false;250 if (kstrtou8(field, 0, reg))251 return false;252 253 /* Then the values for the register, up to data_size */254 for (i = 0; i < data_size; i++) {255 field = strsep(&token, " ");256 if (!field)257 break;258 if (kstrtou8(field, 0, &data[i]))259 return false;260 }261 262 *bytes_read = i;263 return true;264}265 266static ssize_t sb_regs_write(struct tb_port *port, const struct sb_reg *sb_regs,267 size_t size, enum usb4_sb_target target, u8 index,268 char *buf, size_t count, loff_t *ppos)269{270 u8 reg, data[SB_MAX_SIZE];271 size_t bytes_read;272 char *line = buf;273 274 /* User did hardware changes behind the driver's back */275 add_taint(TAINT_USER, LOCKDEP_STILL_OK);276 277 /*278 * For sideband registers we accept:279 * reg b0 b1 b2...\n280 *281 * Here "reg" is the byte offset of the sideband register and "b0"..282 * are the byte values. There can be less byte values than the register283 * size. The leftovers will not be overwritten.284 */285 while (parse_sb_line(&line, ®, data, ARRAY_SIZE(data), &bytes_read)) {286 const struct sb_reg *sb_reg;287 int ret;288 289 /* At least one byte must be passed */290 if (bytes_read < 1)291 return -EINVAL;292 293 /* Find the register */294 sb_reg = NULL;295 for (int i = 0; i < size; i++) {296 if (sb_regs[i].reg == reg) {297 sb_reg = &sb_regs[i];298 break;299 }300 }301 302 if (!sb_reg)303 return -EINVAL;304 305 if (bytes_read > sb_regs->size)306 return -E2BIG;307 308 ret = usb4_port_sb_write(port, target, index, sb_reg->reg, data,309 bytes_read);310 if (ret)311 return ret;312 }313 314 return 0;315}316 317static ssize_t port_sb_regs_write(struct file *file, const char __user *user_buf,318 size_t count, loff_t *ppos)319{320 struct seq_file *s = file->private_data;321 struct tb_port *port = s->private;322 struct tb_switch *sw = port->sw;323 struct tb *tb = sw->tb;324 char *buf;325 int ret;326 327 buf = validate_and_copy_from_user(user_buf, &count);328 if (IS_ERR(buf))329 return PTR_ERR(buf);330 331 pm_runtime_get_sync(&sw->dev);332 333 if (mutex_lock_interruptible(&tb->lock)) {334 ret = -ERESTARTSYS;335 goto out;336 }337 338 ret = sb_regs_write(port, port_sb_regs, ARRAY_SIZE(port_sb_regs),339 USB4_SB_TARGET_ROUTER, 0, buf, count, ppos);340 341 mutex_unlock(&tb->lock);342out:343 pm_runtime_mark_last_busy(&sw->dev);344 pm_runtime_put_autosuspend(&sw->dev);345 free_page((unsigned long)buf);346 347 return ret < 0 ? ret : count;348}349 350static ssize_t retimer_sb_regs_write(struct file *file,351 const char __user *user_buf,352 size_t count, loff_t *ppos)353{354 struct seq_file *s = file->private_data;355 struct tb_retimer *rt = s->private;356 struct tb *tb = rt->tb;357 char *buf;358 int ret;359 360 buf = validate_and_copy_from_user(user_buf, &count);361 if (IS_ERR(buf))362 return PTR_ERR(buf);363 364 pm_runtime_get_sync(&rt->dev);365 366 if (mutex_lock_interruptible(&tb->lock)) {367 ret = -ERESTARTSYS;368 goto out;369 }370 371 ret = sb_regs_write(rt->port, retimer_sb_regs, ARRAY_SIZE(retimer_sb_regs),372 USB4_SB_TARGET_RETIMER, rt->index, buf, count, ppos);373 374 mutex_unlock(&tb->lock);375out:376 pm_runtime_mark_last_busy(&rt->dev);377 pm_runtime_put_autosuspend(&rt->dev);378 free_page((unsigned long)buf);379 380 return ret < 0 ? ret : count;381}382#define DEBUGFS_MODE 0600383#else384#define port_regs_write NULL385#define switch_regs_write NULL386#define port_sb_regs_write NULL387#define retimer_sb_regs_write NULL388#define DEBUGFS_MODE 0400389#endif390 391#if IS_ENABLED(CONFIG_USB4_DEBUGFS_MARGINING)392/**393 * struct tb_margining - Lane margining support394 * @port: USB4 port through which the margining operations are run395 * @target: Sideband target396 * @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER397 * @dev: Pointer to the device that is the target (USB4 port or retimer)398 * @caps: Port lane margining capabilities399 * @results: Last lane margining results400 * @lanes: %0, %1 or %7 (all)401 * @min_ber_level: Minimum supported BER level contour value402 * @max_ber_level: Maximum supported BER level contour value403 * @ber_level: Current BER level contour value404 * @voltage_steps: Number of mandatory voltage steps405 * @max_voltage_offset: Maximum mandatory voltage offset (in mV)406 * @voltage_steps_optional_range: Number of voltage steps for optional range407 * @max_voltage_offset_optional_range: Maximum voltage offset for the optional408 * range (in mV).409 * @time_steps: Number of time margin steps410 * @max_time_offset: Maximum time margin offset (in mUI)411 * @voltage_time_offset: Offset for voltage / time for software margining412 * @dwell_time: Dwell time for software margining (in ms)413 * @error_counter: Error counter operation for software margining414 * @optional_voltage_offset_range: Enable optional extended voltage range415 * @software: %true if software margining is used instead of hardware416 * @time: %true if time margining is used instead of voltage417 * @right_high: %false if left/low margin test is performed, %true if418 * right/high419 */420struct tb_margining {421 struct tb_port *port;422 enum usb4_sb_target target;423 u8 index;424 struct device *dev;425 u32 caps[2];426 u32 results[2];427 unsigned int lanes;428 unsigned int min_ber_level;429 unsigned int max_ber_level;430 unsigned int ber_level;431 unsigned int voltage_steps;432 unsigned int max_voltage_offset;433 unsigned int voltage_steps_optional_range;434 unsigned int max_voltage_offset_optional_range;435 unsigned int time_steps;436 unsigned int max_time_offset;437 unsigned int voltage_time_offset;438 unsigned int dwell_time;439 enum usb4_margin_sw_error_counter error_counter;440 bool optional_voltage_offset_range;441 bool software;442 bool time;443 bool right_high;444};445 446static int margining_modify_error_counter(struct tb_margining *margining,447 u32 lanes, enum usb4_margin_sw_error_counter error_counter)448{449 struct usb4_port_margining_params params = { 0 };450 struct tb_port *port = margining->port;451 u32 result;452 453 if (error_counter != USB4_MARGIN_SW_ERROR_COUNTER_CLEAR &&454 error_counter != USB4_MARGIN_SW_ERROR_COUNTER_STOP)455 return -EOPNOTSUPP;456 457 params.error_counter = error_counter;458 params.lanes = lanes;459 460 return usb4_port_sw_margin(port, margining->target, margining->index,461 ¶ms, &result);462}463 464static bool supports_software(const struct tb_margining *margining)465{466 return margining->caps[0] & USB4_MARGIN_CAP_0_MODES_SW;467}468 469static bool supports_hardware(const struct tb_margining *margining)470{471 return margining->caps[0] & USB4_MARGIN_CAP_0_MODES_HW;472}473 474static bool both_lanes(const struct tb_margining *margining)475{476 return margining->caps[0] & USB4_MARGIN_CAP_0_2_LANES;477}478 479static unsigned int480independent_voltage_margins(const struct tb_margining *margining)481{482 return FIELD_GET(USB4_MARGIN_CAP_0_VOLTAGE_INDP_MASK, margining->caps[0]);483}484 485static bool supports_time(const struct tb_margining *margining)486{487 return margining->caps[0] & USB4_MARGIN_CAP_0_TIME;488}489 490/* Only applicable if supports_time() returns true */491static unsigned int492independent_time_margins(const struct tb_margining *margining)493{494 return FIELD_GET(USB4_MARGIN_CAP_1_TIME_INDP_MASK, margining->caps[1]);495}496 497static bool498supports_optional_voltage_offset_range(const struct tb_margining *margining)499{500 return margining->caps[0] & USB4_MARGIN_CAP_0_OPT_VOLTAGE_SUPPORT;501}502 503static ssize_t504margining_ber_level_write(struct file *file, const char __user *user_buf,505 size_t count, loff_t *ppos)506{507 struct seq_file *s = file->private_data;508 struct tb_margining *margining = s->private;509 struct tb *tb = margining->port->sw->tb;510 unsigned int val;511 int ret = 0;512 char *buf;513 514 if (mutex_lock_interruptible(&tb->lock))515 return -ERESTARTSYS;516 517 if (margining->software) {518 ret = -EINVAL;519 goto out_unlock;520 }521 522 buf = validate_and_copy_from_user(user_buf, &count);523 if (IS_ERR(buf)) {524 ret = PTR_ERR(buf);525 goto out_unlock;526 }527 528 buf[count - 1] = '\0';529 530 ret = kstrtouint(buf, 10, &val);531 if (ret)532 goto out_free;533 534 if (val < margining->min_ber_level ||535 val > margining->max_ber_level) {536 ret = -EINVAL;537 goto out_free;538 }539 540 margining->ber_level = val;541 542out_free:543 free_page((unsigned long)buf);544out_unlock:545 mutex_unlock(&tb->lock);546 547 return ret < 0 ? ret : count;548}549 550static void ber_level_show(struct seq_file *s, unsigned int val)551{552 if (val % 2)553 seq_printf(s, "3 * 1e%d (%u)\n", -12 + (val + 1) / 2, val);554 else555 seq_printf(s, "1e%d (%u)\n", -12 + val / 2, val);556}557 558static int margining_ber_level_show(struct seq_file *s, void *not_used)559{560 const struct tb_margining *margining = s->private;561 562 if (margining->software)563 return -EINVAL;564 ber_level_show(s, margining->ber_level);565 return 0;566}567DEBUGFS_ATTR_RW(margining_ber_level);568 569static int margining_caps_show(struct seq_file *s, void *not_used)570{571 struct tb_margining *margining = s->private;572 struct tb *tb = margining->port->sw->tb;573 u32 cap0, cap1;574 575 if (mutex_lock_interruptible(&tb->lock))576 return -ERESTARTSYS;577 578 /* Dump the raw caps first */579 cap0 = margining->caps[0];580 seq_printf(s, "0x%08x\n", cap0);581 cap1 = margining->caps[1];582 seq_printf(s, "0x%08x\n", cap1);583 584 seq_printf(s, "# software margining: %s\n",585 supports_software(margining) ? "yes" : "no");586 if (supports_hardware(margining)) {587 seq_puts(s, "# hardware margining: yes\n");588 seq_puts(s, "# minimum BER level contour: ");589 ber_level_show(s, margining->min_ber_level);590 seq_puts(s, "# maximum BER level contour: ");591 ber_level_show(s, margining->max_ber_level);592 } else {593 seq_puts(s, "# hardware margining: no\n");594 }595 596 seq_printf(s, "# both lanes simultaneously: %s\n",597 both_lanes(margining) ? "yes" : "no");598 seq_printf(s, "# voltage margin steps: %u\n",599 margining->voltage_steps);600 seq_printf(s, "# maximum voltage offset: %u mV\n",601 margining->max_voltage_offset);602 seq_printf(s, "# optional voltage offset range support: %s\n",603 str_yes_no(supports_optional_voltage_offset_range(margining)));604 if (supports_optional_voltage_offset_range(margining)) {605 seq_printf(s, "# voltage margin steps, optional range: %u\n",606 margining->voltage_steps_optional_range);607 seq_printf(s, "# maximum voltage offset, optional range: %u mV\n",608 margining->max_voltage_offset_optional_range);609 }610 611 switch (independent_voltage_margins(margining)) {612 case USB4_MARGIN_CAP_0_VOLTAGE_MIN:613 seq_puts(s, "# returns minimum between high and low voltage margins\n");614 break;615 case USB4_MARGIN_CAP_0_VOLTAGE_HL:616 seq_puts(s, "# returns high or low voltage margin\n");617 break;618 case USB4_MARGIN_CAP_0_VOLTAGE_BOTH:619 seq_puts(s, "# returns both high and low margins\n");620 break;621 }622 623 if (supports_time(margining)) {624 seq_puts(s, "# time margining: yes\n");625 seq_printf(s, "# time margining is destructive: %s\n",626 cap1 & USB4_MARGIN_CAP_1_TIME_DESTR ? "yes" : "no");627 628 switch (independent_time_margins(margining)) {629 case USB4_MARGIN_CAP_1_TIME_MIN:630 seq_puts(s, "# returns minimum between left and right time margins\n");631 break;632 case USB4_MARGIN_CAP_1_TIME_LR:633 seq_puts(s, "# returns left or right margin\n");634 break;635 case USB4_MARGIN_CAP_1_TIME_BOTH:636 seq_puts(s, "# returns both left and right margins\n");637 break;638 }639 640 seq_printf(s, "# time margin steps: %u\n",641 margining->time_steps);642 seq_printf(s, "# maximum time offset: %u mUI\n",643 margining->max_time_offset);644 } else {645 seq_puts(s, "# time margining: no\n");646 }647 648 mutex_unlock(&tb->lock);649 return 0;650}651DEBUGFS_ATTR_RO(margining_caps);652 653static ssize_t654margining_lanes_write(struct file *file, const char __user *user_buf,655 size_t count, loff_t *ppos)656{657 struct seq_file *s = file->private_data;658 struct tb_margining *margining = s->private;659 struct tb *tb = margining->port->sw->tb;660 int ret = 0;661 char *buf;662 663 buf = validate_and_copy_from_user(user_buf, &count);664 if (IS_ERR(buf))665 return PTR_ERR(buf);666 667 buf[count - 1] = '\0';668 669 if (mutex_lock_interruptible(&tb->lock)) {670 ret = -ERESTARTSYS;671 goto out_free;672 }673 674 if (!strcmp(buf, "0")) {675 margining->lanes = 0;676 } else if (!strcmp(buf, "1")) {677 margining->lanes = 1;678 } else if (!strcmp(buf, "all")) {679 /* Needs to be supported */680 if (both_lanes(margining))681 margining->lanes = 7;682 else683 ret = -EINVAL;684 } else {685 ret = -EINVAL;686 }687 688 mutex_unlock(&tb->lock);689 690out_free:691 free_page((unsigned long)buf);692 return ret < 0 ? ret : count;693}694 695static int margining_lanes_show(struct seq_file *s, void *not_used)696{697 struct tb_margining *margining = s->private;698 struct tb *tb = margining->port->sw->tb;699 unsigned int lanes;700 701 if (mutex_lock_interruptible(&tb->lock))702 return -ERESTARTSYS;703 704 lanes = margining->lanes;705 if (both_lanes(margining)) {706 if (!lanes)707 seq_puts(s, "[0] 1 all\n");708 else if (lanes == 1)709 seq_puts(s, "0 [1] all\n");710 else711 seq_puts(s, "0 1 [all]\n");712 } else {713 if (!lanes)714 seq_puts(s, "[0] 1\n");715 else716 seq_puts(s, "0 [1]\n");717 }718 719 mutex_unlock(&tb->lock);720 return 0;721}722DEBUGFS_ATTR_RW(margining_lanes);723 724static ssize_t725margining_voltage_time_offset_write(struct file *file,726 const char __user *user_buf,727 size_t count, loff_t *ppos)728{729 struct seq_file *s = file->private_data;730 struct tb_margining *margining = s->private;731 struct tb *tb = margining->port->sw->tb;732 unsigned int max_margin;733 unsigned int val;734 int ret;735 736 ret = kstrtouint_from_user(user_buf, count, 10, &val);737 if (ret)738 return ret;739 740 scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) {741 if (!margining->software)742 return -EOPNOTSUPP;743 744 if (margining->time)745 max_margin = margining->time_steps;746 else747 if (margining->optional_voltage_offset_range)748 max_margin = margining->voltage_steps_optional_range;749 else750 max_margin = margining->voltage_steps;751 752 margining->voltage_time_offset = clamp(val, 0, max_margin);753 }754 755 return count;756}757 758static int margining_voltage_time_offset_show(struct seq_file *s,759 void *not_used)760{761 const struct tb_margining *margining = s->private;762 struct tb *tb = margining->port->sw->tb;763 764 scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) {765 if (!margining->software)766 return -EOPNOTSUPP;767 768 seq_printf(s, "%d\n", margining->voltage_time_offset);769 }770 771 return 0;772}773DEBUGFS_ATTR_RW(margining_voltage_time_offset);774 775static ssize_t776margining_error_counter_write(struct file *file, const char __user *user_buf,777 size_t count, loff_t *ppos)778{779 enum usb4_margin_sw_error_counter error_counter;780 struct seq_file *s = file->private_data;781 struct tb_margining *margining = s->private;782 struct tb *tb = margining->port->sw->tb;783 char *buf;784 785 buf = validate_and_copy_from_user(user_buf, &count);786 if (IS_ERR(buf))787 return PTR_ERR(buf);788 789 buf[count - 1] = '\0';790 791 if (!strcmp(buf, "nop"))792 error_counter = USB4_MARGIN_SW_ERROR_COUNTER_NOP;793 else if (!strcmp(buf, "clear"))794 error_counter = USB4_MARGIN_SW_ERROR_COUNTER_CLEAR;795 else if (!strcmp(buf, "start"))796 error_counter = USB4_MARGIN_SW_ERROR_COUNTER_START;797 else if (!strcmp(buf, "stop"))798 error_counter = USB4_MARGIN_SW_ERROR_COUNTER_STOP;799 else800 return -EINVAL;801 802 scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) {803 if (!margining->software)804 return -EOPNOTSUPP;805 806 margining->error_counter = error_counter;807 }808 809 return count;810}811 812static int margining_error_counter_show(struct seq_file *s, void *not_used)813{814 const struct tb_margining *margining = s->private;815 struct tb *tb = margining->port->sw->tb;816 817 scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) {818 if (!margining->software)819 return -EOPNOTSUPP;820 821 switch (margining->error_counter) {822 case USB4_MARGIN_SW_ERROR_COUNTER_NOP:823 seq_puts(s, "[nop] clear start stop\n");824 break;825 case USB4_MARGIN_SW_ERROR_COUNTER_CLEAR:826 seq_puts(s, "nop [clear] start stop\n");827 break;828 case USB4_MARGIN_SW_ERROR_COUNTER_START:829 seq_puts(s, "nop clear [start] stop\n");830 break;831 case USB4_MARGIN_SW_ERROR_COUNTER_STOP:832 seq_puts(s, "nop clear start [stop]\n");833 break;834 }835 }836 837 return 0;838}839DEBUGFS_ATTR_RW(margining_error_counter);840 841static ssize_t842margining_dwell_time_write(struct file *file, const char __user *user_buf,843 size_t count, loff_t *ppos)844{845 struct seq_file *s = file->private_data;846 struct tb_margining *margining = s->private;847 struct tb *tb = margining->port->sw->tb;848 unsigned int val;849 int ret;850 851 ret = kstrtouint_from_user(user_buf, count, 10, &val);852 if (ret)853 return ret;854 855 scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) {856 if (!margining->software)857 return -EOPNOTSUPP;858 859 margining->dwell_time = clamp(val, MIN_DWELL_TIME, MAX_DWELL_TIME);860 }861 862 return count;863}864 865static int margining_dwell_time_show(struct seq_file *s, void *not_used)866{867 struct tb_margining *margining = s->private;868 struct tb *tb = margining->port->sw->tb;869 870 scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) {871 if (!margining->software)872 return -EOPNOTSUPP;873 874 seq_printf(s, "%d\n", margining->dwell_time);875 }876 877 return 0;878}879DEBUGFS_ATTR_RW(margining_dwell_time);880 881static ssize_t882margining_optional_voltage_offset_write(struct file *file, const char __user *user_buf,883 size_t count, loff_t *ppos)884{885 struct seq_file *s = file->private_data;886 struct tb_margining *margining = s->private;887 struct tb *tb = margining->port->sw->tb;888 bool val;889 int ret;890 891 ret = kstrtobool_from_user(user_buf, count, &val);892 if (ret)893 return ret;894 895 scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) {896 margining->optional_voltage_offset_range = val;897 }898 899 return count;900}901 902static int margining_optional_voltage_offset_show(struct seq_file *s,903 void *not_used)904{905 struct tb_margining *margining = s->private;906 struct tb *tb = margining->port->sw->tb;907 908 scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) {909 seq_printf(s, "%u\n", margining->optional_voltage_offset_range);910 }911 912 return 0;913}914DEBUGFS_ATTR_RW(margining_optional_voltage_offset);915 916static ssize_t margining_mode_write(struct file *file,917 const char __user *user_buf,918 size_t count, loff_t *ppos)919{920 struct seq_file *s = file->private_data;921 struct tb_margining *margining = s->private;922 struct tb *tb = margining->port->sw->tb;923 int ret = 0;924 char *buf;925 926 buf = validate_and_copy_from_user(user_buf, &count);927 if (IS_ERR(buf))928 return PTR_ERR(buf);929 930 buf[count - 1] = '\0';931 932 if (mutex_lock_interruptible(&tb->lock)) {933 ret = -ERESTARTSYS;934 goto out_free;935 }936 937 if (!strcmp(buf, "software")) {938 if (supports_software(margining))939 margining->software = true;940 else941 ret = -EINVAL;942 } else if (!strcmp(buf, "hardware")) {943 if (supports_hardware(margining))944 margining->software = false;945 else946 ret = -EINVAL;947 } else {948 ret = -EINVAL;949 }950 951 mutex_unlock(&tb->lock);952 953out_free:954 free_page((unsigned long)buf);955 return ret ? ret : count;956}957 958static int margining_mode_show(struct seq_file *s, void *not_used)959{960 struct tb_margining *margining = s->private;961 struct tb *tb = margining->port->sw->tb;962 const char *space = "";963 964 if (mutex_lock_interruptible(&tb->lock))965 return -ERESTARTSYS;966 967 if (supports_software(margining)) {968 if (margining->software)969 seq_puts(s, "[software]");970 else971 seq_puts(s, "software");972 space = " ";973 }974 if (supports_hardware(margining)) {975 if (margining->software)976 seq_printf(s, "%shardware", space);977 else978 seq_printf(s, "%s[hardware]", space);979 }980 981 mutex_unlock(&tb->lock);982 983 seq_puts(s, "\n");984 return 0;985}986DEBUGFS_ATTR_RW(margining_mode);987 988static int margining_run_sw(struct tb_margining *margining,989 struct usb4_port_margining_params *params)990{991 u32 nsamples = margining->dwell_time / DWELL_SAMPLE_INTERVAL;992 int ret, i;993 994 ret = usb4_port_sw_margin(margining->port, margining->target, margining->index,995 params, margining->results);996 if (ret)997 goto out_stop;998 999 for (i = 0; i <= nsamples; i++) {1000 u32 errors = 0;1001 1002 ret = usb4_port_sw_margin_errors(margining->port, margining->target,1003 margining->index, &margining->results[1]);1004 if (ret)1005 break;1006 1007 if (margining->lanes == USB4_MARGIN_SW_LANE_0)1008 errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_0_MASK,1009 margining->results[1]);1010 else if (margining->lanes == USB4_MARGIN_SW_LANE_1)1011 errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_1_MASK,1012 margining->results[1]);1013 else if (margining->lanes == USB4_MARGIN_SW_ALL_LANES)1014 errors = margining->results[1];1015 1016 /* Any errors stop the test */1017 if (errors)1018 break;1019 1020 fsleep(DWELL_SAMPLE_INTERVAL * USEC_PER_MSEC);1021 }1022 1023out_stop:1024 /*1025 * Stop the counters but don't clear them to allow the1026 * different error counter configurations.1027 */1028 margining_modify_error_counter(margining, margining->lanes,1029 USB4_MARGIN_SW_ERROR_COUNTER_STOP);1030 return ret;1031}1032 1033static int margining_run_write(void *data, u64 val)1034{1035 struct tb_margining *margining = data;1036 struct tb_port *port = margining->port;1037 struct device *dev = margining->dev;1038 struct tb_switch *sw = port->sw;1039 struct tb_switch *down_sw;1040 struct tb *tb = sw->tb;1041 int ret, clx;1042 1043 if (val != 1)1044 return -EINVAL;1045 1046 pm_runtime_get_sync(dev);1047 1048 if (mutex_lock_interruptible(&tb->lock)) {1049 ret = -ERESTARTSYS;1050 goto out_rpm_put;1051 }1052 1053 if (tb_is_upstream_port(port))1054 down_sw = sw;1055 else if (port->remote)1056 down_sw = port->remote->sw;1057 else1058 down_sw = NULL;1059 1060 if (down_sw) {1061 /*1062 * CL states may interfere with lane margining so1063 * disable them temporarily now.1064 */1065 ret = tb_switch_clx_disable(down_sw);1066 if (ret < 0) {1067 tb_sw_warn(down_sw, "failed to disable CL states\n");1068 goto out_unlock;1069 }1070 clx = ret;1071 }1072 1073 /* Clear the results */1074 memset(margining->results, 0, sizeof(margining->results));1075 1076 if (margining->software) {1077 struct usb4_port_margining_params params = {1078 .error_counter = USB4_MARGIN_SW_ERROR_COUNTER_CLEAR,1079 .lanes = margining->lanes,1080 .time = margining->time,1081 .voltage_time_offset = margining->voltage_time_offset,1082 .right_high = margining->right_high,1083 .optional_voltage_offset_range = margining->optional_voltage_offset_range,1084 };1085 1086 tb_port_dbg(port,1087 "running software %s lane margining for %s lanes %u\n",1088 margining->time ? "time" : "voltage", dev_name(dev),1089 margining->lanes);1090 1091 ret = margining_run_sw(margining, ¶ms);1092 } else {1093 struct usb4_port_margining_params params = {1094 .ber_level = margining->ber_level,1095 .lanes = margining->lanes,1096 .time = margining->time,1097 .right_high = margining->right_high,1098 .optional_voltage_offset_range = margining->optional_voltage_offset_range,1099 };1100 1101 tb_port_dbg(port,1102 "running hardware %s lane margining for %s lanes %u\n",1103 margining->time ? "time" : "voltage", dev_name(dev),1104 margining->lanes);1105 1106 ret = usb4_port_hw_margin(port, margining->target, margining->index, ¶ms,1107 margining->results);1108 }1109 1110 if (down_sw)1111 tb_switch_clx_enable(down_sw, clx);1112out_unlock:1113 mutex_unlock(&tb->lock);1114out_rpm_put:1115 pm_runtime_mark_last_busy(dev);1116 pm_runtime_put_autosuspend(dev);1117 1118 return ret;1119}1120DEFINE_DEBUGFS_ATTRIBUTE(margining_run_fops, NULL, margining_run_write,1121 "%llu\n");1122 1123static ssize_t margining_results_write(struct file *file,1124 const char __user *user_buf,1125 size_t count, loff_t *ppos)1126{1127 struct seq_file *s = file->private_data;1128 struct tb_margining *margining = s->private;1129 struct tb *tb = margining->port->sw->tb;1130 1131 if (mutex_lock_interruptible(&tb->lock))1132 return -ERESTARTSYS;1133 1134 /* Just clear the results */1135 margining->results[0] = 0;1136 margining->results[1] = 0;1137 1138 if (margining->software) {1139 /* Clear the error counters */1140 margining_modify_error_counter(margining,1141 USB4_MARGIN_SW_ALL_LANES,1142 USB4_MARGIN_SW_ERROR_COUNTER_CLEAR);1143 }1144 1145 mutex_unlock(&tb->lock);1146 return count;1147}1148 1149static void voltage_margin_show(struct seq_file *s,1150 const struct tb_margining *margining, u8 val)1151{1152 unsigned int tmp, voltage;1153 1154 tmp = FIELD_GET(USB4_MARGIN_HW_RES_1_MARGIN_MASK, val);1155 voltage = tmp * margining->max_voltage_offset / margining->voltage_steps;1156 seq_printf(s, "%u mV (%u)", voltage, tmp);1157 if (val & USB4_MARGIN_HW_RES_1_EXCEEDS)1158 seq_puts(s, " exceeds maximum");1159 seq_puts(s, "\n");1160 if (margining->optional_voltage_offset_range)1161 seq_puts(s, " optional voltage offset range enabled\n");1162}1163 1164static void time_margin_show(struct seq_file *s,1165 const struct tb_margining *margining, u8 val)1166{1167 unsigned int tmp, interval;1168 1169 tmp = FIELD_GET(USB4_MARGIN_HW_RES_1_MARGIN_MASK, val);1170 interval = tmp * margining->max_time_offset / margining->time_steps;1171 seq_printf(s, "%u mUI (%u)", interval, tmp);1172 if (val & USB4_MARGIN_HW_RES_1_EXCEEDS)1173 seq_puts(s, " exceeds maximum");1174 seq_puts(s, "\n");1175}1176 1177static int margining_results_show(struct seq_file *s, void *not_used)1178{1179 struct tb_margining *margining = s->private;1180 struct tb *tb = margining->port->sw->tb;1181 1182 if (mutex_lock_interruptible(&tb->lock))1183 return -ERESTARTSYS;1184 1185 /* Dump the raw results first */1186 seq_printf(s, "0x%08x\n", margining->results[0]);1187 /* Only the hardware margining has two result dwords */1188 if (!margining->software) {1189 unsigned int val;1190 1191 seq_printf(s, "0x%08x\n", margining->results[1]);1192 1193 if (margining->time) {1194 if (!margining->lanes || margining->lanes == 7) {1195 val = margining->results[1];1196 seq_puts(s, "# lane 0 right time margin: ");1197 time_margin_show(s, margining, val);1198 val = margining->results[1] >>1199 USB4_MARGIN_HW_RES_1_L0_LL_MARGIN_SHIFT;1200 seq_puts(s, "# lane 0 left time margin: ");1201 time_margin_show(s, margining, val);1202 }1203 if (margining->lanes == 1 || margining->lanes == 7) {1204 val = margining->results[1] >>1205 USB4_MARGIN_HW_RES_1_L1_RH_MARGIN_SHIFT;1206 seq_puts(s, "# lane 1 right time margin: ");1207 time_margin_show(s, margining, val);1208 val = margining->results[1] >>1209 USB4_MARGIN_HW_RES_1_L1_LL_MARGIN_SHIFT;1210 seq_puts(s, "# lane 1 left time margin: ");1211 time_margin_show(s, margining, val);1212 }1213 } else {1214 if (!margining->lanes || margining->lanes == 7) {1215 val = margining->results[1];1216 seq_puts(s, "# lane 0 high voltage margin: ");1217 voltage_margin_show(s, margining, val);1218 val = margining->results[1] >>1219 USB4_MARGIN_HW_RES_1_L0_LL_MARGIN_SHIFT;1220 seq_puts(s, "# lane 0 low voltage margin: ");1221 voltage_margin_show(s, margining, val);1222 }1223 if (margining->lanes == 1 || margining->lanes == 7) {1224 val = margining->results[1] >>1225 USB4_MARGIN_HW_RES_1_L1_RH_MARGIN_SHIFT;1226 seq_puts(s, "# lane 1 high voltage margin: ");1227 voltage_margin_show(s, margining, val);1228 val = margining->results[1] >>1229 USB4_MARGIN_HW_RES_1_L1_LL_MARGIN_SHIFT;1230 seq_puts(s, "# lane 1 low voltage margin: ");1231 voltage_margin_show(s, margining, val);1232 }1233 }1234 } else {1235 u32 lane_errors, result;1236 1237 seq_printf(s, "0x%08x\n", margining->results[1]);1238 result = FIELD_GET(USB4_MARGIN_SW_LANES_MASK, margining->results[0]);1239 1240 if (result == USB4_MARGIN_SW_LANE_0 ||1241 result == USB4_MARGIN_SW_ALL_LANES) {1242 lane_errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_0_MASK,1243 margining->results[1]);1244 seq_printf(s, "# lane 0 errors: %u\n", lane_errors);1245 }1246 if (result == USB4_MARGIN_SW_LANE_1 ||1247 result == USB4_MARGIN_SW_ALL_LANES) {1248 lane_errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_1_MASK,1249 margining->results[1]);1250 seq_printf(s, "# lane 1 errors: %u\n", lane_errors);1251 }1252 }1253 1254 mutex_unlock(&tb->lock);1255 return 0;1256}1257DEBUGFS_ATTR_RW(margining_results);1258 1259static ssize_t margining_test_write(struct file *file,1260 const char __user *user_buf,1261 size_t count, loff_t *ppos)1262{1263 struct seq_file *s = file->private_data;1264 struct tb_margining *margining = s->private;1265 struct tb *tb = margining->port->sw->tb;1266 int ret = 0;1267 char *buf;1268 1269 buf = validate_and_copy_from_user(user_buf, &count);1270 if (IS_ERR(buf))1271 return PTR_ERR(buf);1272 1273 buf[count - 1] = '\0';1274 1275 if (mutex_lock_interruptible(&tb->lock)) {1276 ret = -ERESTARTSYS;1277 goto out_free;1278 }1279 1280 if (!strcmp(buf, "time") && supports_time(margining))1281 margining->time = true;1282 else if (!strcmp(buf, "voltage"))1283 margining->time = false;1284 else1285 ret = -EINVAL;1286 1287 mutex_unlock(&tb->lock);1288 1289out_free:1290 free_page((unsigned long)buf);1291 return ret ? ret : count;1292}1293 1294static int margining_test_show(struct seq_file *s, void *not_used)1295{1296 struct tb_margining *margining = s->private;1297 struct tb *tb = margining->port->sw->tb;1298 1299 if (mutex_lock_interruptible(&tb->lock))1300 return -ERESTARTSYS;1301 1302 if (supports_time(margining)) {1303 if (margining->time)1304 seq_puts(s, "voltage [time]\n");1305 else1306 seq_puts(s, "[voltage] time\n");1307 } else {1308 seq_puts(s, "[voltage]\n");1309 }1310 1311 mutex_unlock(&tb->lock);1312 return 0;1313}1314DEBUGFS_ATTR_RW(margining_test);1315 1316static ssize_t margining_margin_write(struct file *file,1317 const char __user *user_buf,1318 size_t count, loff_t *ppos)1319{1320 struct seq_file *s = file->private_data;1321 struct tb_margining *margining = s->private;1322 struct tb *tb = margining->port->sw->tb;1323 int ret = 0;1324 char *buf;1325 1326 buf = validate_and_copy_from_user(user_buf, &count);1327 if (IS_ERR(buf))1328 return PTR_ERR(buf);1329 1330 buf[count - 1] = '\0';1331 1332 if (mutex_lock_interruptible(&tb->lock)) {1333 ret = -ERESTARTSYS;1334 goto out_free;1335 }1336 1337 if (margining->time) {1338 if (!strcmp(buf, "left"))1339 margining->right_high = false;1340 else if (!strcmp(buf, "right"))1341 margining->right_high = true;1342 else1343 ret = -EINVAL;1344 } else {1345 if (!strcmp(buf, "low"))1346 margining->right_high = false;1347 else if (!strcmp(buf, "high"))1348 margining->right_high = true;1349 else1350 ret = -EINVAL;1351 }1352 1353 mutex_unlock(&tb->lock);1354 1355out_free:1356 free_page((unsigned long)buf);1357 return ret ? ret : count;1358}1359 1360static int margining_margin_show(struct seq_file *s, void *not_used)1361{1362 struct tb_margining *margining = s->private;1363 struct tb *tb = margining->port->sw->tb;1364 1365 if (mutex_lock_interruptible(&tb->lock))1366 return -ERESTARTSYS;1367 1368 if (margining->time) {1369 if (margining->right_high)1370 seq_puts(s, "left [right]\n");1371 else1372 seq_puts(s, "[left] right\n");1373 } else {1374 if (margining->right_high)1375 seq_puts(s, "low [high]\n");1376 else1377 seq_puts(s, "[low] high\n");1378 }1379 1380 mutex_unlock(&tb->lock);1381 return 0;1382}1383DEBUGFS_ATTR_RW(margining_margin);1384 1385static struct tb_margining *margining_alloc(struct tb_port *port,1386 struct device *dev,1387 enum usb4_sb_target target,1388 u8 index, struct dentry *parent)1389{1390 struct tb_margining *margining;1391 struct dentry *dir;1392 unsigned int val;1393 int ret;1394 1395 margining = kzalloc(sizeof(*margining), GFP_KERNEL);1396 if (!margining)1397 return NULL;1398 1399 margining->port = port;1400 margining->target = target;1401 margining->index = index;1402 margining->dev = dev;1403 1404 ret = usb4_port_margining_caps(port, target, index, margining->caps);1405 if (ret) {1406 kfree(margining);1407 return NULL;1408 }1409 1410 /* Set the initial mode */1411 if (supports_software(margining))1412 margining->software = true;1413 1414 val = FIELD_GET(USB4_MARGIN_CAP_0_VOLTAGE_STEPS_MASK, margining->caps[0]);1415 margining->voltage_steps = val;1416 val = FIELD_GET(USB4_MARGIN_CAP_0_MAX_VOLTAGE_OFFSET_MASK, margining->caps[0]);1417 margining->max_voltage_offset = 74 + val * 2;1418 1419 if (supports_optional_voltage_offset_range(margining)) {1420 val = FIELD_GET(USB4_MARGIN_CAP_0_VOLT_STEPS_OPT_MASK,1421 margining->caps[0]);1422 margining->voltage_steps_optional_range = val;1423 val = FIELD_GET(USB4_MARGIN_CAP_1_MAX_VOLT_OFS_OPT_MASK,1424 margining->caps[1]);1425 margining->max_voltage_offset_optional_range = 74 + val * 2;1426 }1427 1428 if (supports_time(margining)) {1429 val = FIELD_GET(USB4_MARGIN_CAP_1_TIME_STEPS_MASK, margining->caps[1]);1430 margining->time_steps = val;1431 val = FIELD_GET(USB4_MARGIN_CAP_1_TIME_OFFSET_MASK, margining->caps[1]);1432 /*1433 * Store it as mUI (milli Unit Interval) because we want1434 * to keep it as integer.1435 */1436 margining->max_time_offset = 200 + 10 * val;1437 }1438 1439 dir = debugfs_create_dir("margining", parent);1440 if (supports_hardware(margining)) {1441 val = FIELD_GET(USB4_MARGIN_CAP_1_MIN_BER_MASK, margining->caps[1]);1442 margining->min_ber_level = val;1443 val = FIELD_GET(USB4_MARGIN_CAP_1_MAX_BER_MASK, margining->caps[1]);1444 margining->max_ber_level = val;1445 1446 /* Set the default to minimum */1447 margining->ber_level = margining->min_ber_level;1448 1449 debugfs_create_file("ber_level_contour", 0400, dir, margining,1450 &margining_ber_level_fops);1451 }1452 debugfs_create_file("caps", 0400, dir, margining, &margining_caps_fops);1453 debugfs_create_file("lanes", 0600, dir, margining, &margining_lanes_fops);1454 debugfs_create_file("mode", 0600, dir, margining, &margining_mode_fops);1455 debugfs_create_file("run", 0600, dir, margining, &margining_run_fops);1456 debugfs_create_file("results", 0600, dir, margining,1457 &margining_results_fops);1458 debugfs_create_file("test", 0600, dir, margining, &margining_test_fops);1459 if (independent_voltage_margins(margining) == USB4_MARGIN_CAP_0_VOLTAGE_HL ||1460 (supports_time(margining) &&1461 independent_time_margins(margining) == USB4_MARGIN_CAP_1_TIME_LR))1462 debugfs_create_file("margin", 0600, dir, margining,1463 &margining_margin_fops);1464 1465 margining->error_counter = USB4_MARGIN_SW_ERROR_COUNTER_CLEAR;1466 margining->dwell_time = MIN_DWELL_TIME;1467 1468 if (supports_optional_voltage_offset_range(margining))1469 debugfs_create_file("optional_voltage_offset", DEBUGFS_MODE, dir, margining,1470 &margining_optional_voltage_offset_fops);1471 1472 if (supports_software(margining)) {1473 debugfs_create_file("voltage_time_offset", DEBUGFS_MODE, dir, margining,1474 &margining_voltage_time_offset_fops);1475 debugfs_create_file("error_counter", DEBUGFS_MODE, dir, margining,1476 &margining_error_counter_fops);1477 debugfs_create_file("dwell_time", DEBUGFS_MODE, dir, margining,1478 &margining_dwell_time_fops);1479 }1480 return margining;1481}1482 1483static void margining_port_init(struct tb_port *port)1484{1485 struct dentry *parent;1486 char dir_name[10];1487 1488 if (!port->usb4)1489 return;1490 1491 snprintf(dir_name, sizeof(dir_name), "port%d", port->port);1492 parent = debugfs_lookup(dir_name, port->sw->debugfs_dir);1493 port->usb4->margining = margining_alloc(port, &port->usb4->dev,1494 USB4_SB_TARGET_ROUTER, 0,1495 parent);1496}1497 1498static void margining_port_remove(struct tb_port *port)1499{1500 struct dentry *parent;1501 char dir_name[10];1502 1503 if (!port->usb4)1504 return;1505 1506 snprintf(dir_name, sizeof(dir_name), "port%d", port->port);1507 parent = debugfs_lookup(dir_name, port->sw->debugfs_dir);1508 if (parent)1509 debugfs_lookup_and_remove("margining", parent);1510 1511 kfree(port->usb4->margining);1512 port->usb4->margining = NULL;1513}1514 1515static void margining_switch_init(struct tb_switch *sw)1516{1517 struct tb_port *upstream, *downstream;1518 struct tb_switch *parent_sw;1519 u64 route = tb_route(sw);1520 1521 if (!route)1522 return;1523 1524 upstream = tb_upstream_port(sw);1525 parent_sw = tb_switch_parent(sw);1526 downstream = tb_port_at(route, parent_sw);1527 1528 margining_port_init(downstream);1529 margining_port_init(upstream);1530}1531 1532static void margining_switch_remove(struct tb_switch *sw)1533{1534 struct tb_port *upstream, *downstream;1535 struct tb_switch *parent_sw;1536 u64 route = tb_route(sw);1537 1538 if (!route)1539 return;1540 1541 upstream = tb_upstream_port(sw);1542 parent_sw = tb_switch_parent(sw);1543 downstream = tb_port_at(route, parent_sw);1544 1545 margining_port_remove(upstream);1546 margining_port_remove(downstream);1547}1548 1549static void margining_xdomain_init(struct tb_xdomain *xd)1550{1551 struct tb_switch *parent_sw;1552 struct tb_port *downstream;1553 1554 parent_sw = tb_xdomain_parent(xd);1555 downstream = tb_port_at(xd->route, parent_sw);1556 1557 margining_port_init(downstream);1558}1559 1560static void margining_xdomain_remove(struct tb_xdomain *xd)1561{1562 struct tb_switch *parent_sw;1563 struct tb_port *downstream;1564 1565 parent_sw = tb_xdomain_parent(xd);1566 downstream = tb_port_at(xd->route, parent_sw);1567 margining_port_remove(downstream);1568}1569 1570static void margining_retimer_init(struct tb_retimer *rt, struct dentry *debugfs_dir)1571{1572 rt->margining = margining_alloc(rt->port, &rt->dev,1573 USB4_SB_TARGET_RETIMER, rt->index,1574 debugfs_dir);1575}1576 1577static void margining_retimer_remove(struct tb_retimer *rt)1578{1579 kfree(rt->margining);1580 rt->margining = NULL;1581}1582#else1583static inline void margining_switch_init(struct tb_switch *sw) { }1584static inline void margining_switch_remove(struct tb_switch *sw) { }1585static inline void margining_xdomain_init(struct tb_xdomain *xd) { }1586static inline void margining_xdomain_remove(struct tb_xdomain *xd) { }1587static inline void margining_retimer_init(struct tb_retimer *rt,1588 struct dentry *debugfs_dir) { }1589static inline void margining_retimer_remove(struct tb_retimer *rt) { }1590#endif1591 1592static int port_clear_all_counters(struct tb_port *port)1593{1594 u32 *buf;1595 int ret;1596 1597 buf = kcalloc(COUNTER_SET_LEN * port->config.max_counters, sizeof(u32),1598 GFP_KERNEL);1599 if (!buf)1600 return -ENOMEM;1601 1602 ret = tb_port_write(port, buf, TB_CFG_COUNTERS, 0,1603 COUNTER_SET_LEN * port->config.max_counters);1604 kfree(buf);1605 1606 return ret;1607}1608 1609static ssize_t counters_write(struct file *file, const char __user *user_buf,1610 size_t count, loff_t *ppos)1611{1612 struct seq_file *s = file->private_data;1613 struct tb_port *port = s->private;1614 struct tb_switch *sw = port->sw;1615 struct tb *tb = port->sw->tb;1616 char *buf;1617 int ret;1618 1619 buf = validate_and_copy_from_user(user_buf, &count);1620 if (IS_ERR(buf))1621 return PTR_ERR(buf);1622 1623 pm_runtime_get_sync(&sw->dev);1624 1625 if (mutex_lock_interruptible(&tb->lock)) {1626 ret = -ERESTARTSYS;1627 goto out;1628 }1629 1630 /* If written delimiter only, clear all counters in one shot */1631 if (buf[0] == '\n') {1632 ret = port_clear_all_counters(port);1633 } else {1634 char *line = buf;1635 u32 val, offset;1636 1637 ret = -EINVAL;1638 while (parse_line(&line, &offset, &val, 1, 4)) {1639 ret = tb_port_write(port, &val, TB_CFG_COUNTERS,1640 offset, 1);1641 if (ret)1642 break;1643 }1644 }1645 1646 mutex_unlock(&tb->lock);1647 1648out:1649 pm_runtime_mark_last_busy(&sw->dev);1650 pm_runtime_put_autosuspend(&sw->dev);1651 free_page((unsigned long)buf);1652 1653 return ret < 0 ? ret : count;1654}1655 1656static void cap_show_by_dw(struct seq_file *s, struct tb_switch *sw,1657 struct tb_port *port, unsigned int cap,1658 unsigned int offset, u8 cap_id, u8 vsec_id,1659 int dwords)1660{1661 int i, ret;1662 u32 data;1663 1664 for (i = 0; i < dwords; i++) {1665 if (port)1666 ret = tb_port_read(port, &data, TB_CFG_PORT, cap + offset + i, 1);1667 else1668 ret = tb_sw_read(sw, &data, TB_CFG_SWITCH, cap + offset + i, 1);1669 if (ret) {1670 seq_printf(s, "0x%04x <not accessible>\n", cap + offset + i);1671 continue;1672 }1673 1674 seq_printf(s, "0x%04x %4d 0x%02x 0x%02x 0x%08x\n", cap + offset + i,1675 offset + i, cap_id, vsec_id, data);1676 }1677}1678 1679static void cap_show(struct seq_file *s, struct tb_switch *sw,1680 struct tb_port *port, unsigned int cap, u8 cap_id,1681 u8 vsec_id, int length)1682{1683 int ret, offset = 0;1684 1685 while (length > 0) {1686 int i, dwords = min(length, TB_MAX_CONFIG_RW_LENGTH);1687 u32 data[TB_MAX_CONFIG_RW_LENGTH];1688 1689 if (port)1690 ret = tb_port_read(port, data, TB_CFG_PORT, cap + offset,1691 dwords);1692 else1693 ret = tb_sw_read(sw, data, TB_CFG_SWITCH, cap + offset, dwords);1694 if (ret) {1695 cap_show_by_dw(s, sw, port, cap, offset, cap_id, vsec_id, length);1696 return;1697 }1698 1699 for (i = 0; i < dwords; i++) {1700 seq_printf(s, "0x%04x %4d 0x%02x 0x%02x 0x%08x\n",1701 cap + offset + i, offset + i,1702 cap_id, vsec_id, data[i]);1703 }1704 1705 length -= dwords;1706 offset += dwords;1707 }1708}1709 1710static void port_cap_show(struct tb_port *port, struct seq_file *s,1711 unsigned int cap)1712{1713 struct tb_cap_any header;1714 u8 vsec_id = 0;1715 size_t length;1716 int ret;1717 1718 ret = tb_port_read(port, &header, TB_CFG_PORT, cap, 1);1719 if (ret) {1720 seq_printf(s, "0x%04x <capability read failed>\n", cap);1721 return;1722 }1723 1724 switch (header.basic.cap) {1725 case TB_PORT_CAP_PHY:1726 length = PORT_CAP_LANE_LEN;1727 break;1728 1729 case TB_PORT_CAP_TIME1:1730 if (usb4_switch_version(port->sw) < 2)1731 length = PORT_CAP_TMU_V1_LEN;1732 else1733 length = PORT_CAP_TMU_V2_LEN;1734 break;1735 1736 case TB_PORT_CAP_POWER:1737 length = PORT_CAP_POWER_LEN;1738 break;1739 1740 case TB_PORT_CAP_ADAP:1741 if (tb_port_is_pcie_down(port) || tb_port_is_pcie_up(port)) {1742 if (usb4_switch_version(port->sw) < 2)1743 length = PORT_CAP_V1_PCIE_LEN;1744 else1745 length = PORT_CAP_V2_PCIE_LEN;1746 } else if (tb_port_is_dpin(port)) {1747 if (usb4_switch_version(port->sw) < 2)1748 length = PORT_CAP_DP_V1_LEN;1749 else1750 length = PORT_CAP_DP_V2_LEN;1751 } else if (tb_port_is_dpout(port)) {1752 length = PORT_CAP_DP_V1_LEN;1753 } else if (tb_port_is_usb3_down(port) ||1754 tb_port_is_usb3_up(port)) {1755 length = PORT_CAP_USB3_LEN;1756 } else {1757 seq_printf(s, "0x%04x <unsupported capability 0x%02x>\n",1758 cap, header.basic.cap);1759 return;1760 }1761 break;1762 1763 case TB_PORT_CAP_VSE:1764 if (!header.extended_short.length) {1765 ret = tb_port_read(port, (u32 *)&header + 1, TB_CFG_PORT,1766 cap + 1, 1);1767 if (ret) {1768 seq_printf(s, "0x%04x <capability read failed>\n",1769 cap + 1);1770 return;1771 }1772 length = header.extended_long.length;1773 vsec_id = header.extended_short.vsec_id;1774 } else {1775 length = header.extended_short.length;1776 vsec_id = header.extended_short.vsec_id;1777 }1778 break;1779 1780 case TB_PORT_CAP_USB4:1781 length = PORT_CAP_USB4_LEN;1782 break;1783 1784 default:1785 seq_printf(s, "0x%04x <unsupported capability 0x%02x>\n",1786 cap, header.basic.cap);1787 return;1788 }1789 1790 cap_show(s, NULL, port, cap, header.basic.cap, vsec_id, length);1791}1792 1793static void port_caps_show(struct tb_port *port, struct seq_file *s)1794{1795 int cap;1796 1797 cap = tb_port_next_cap(port, 0);1798 while (cap > 0) {1799 port_cap_show(port, s, cap);1800 cap = tb_port_next_cap(port, cap);1801 }1802}1803 1804static int port_basic_regs_show(struct tb_port *port, struct seq_file *s)1805{1806 u32 data[PORT_CAP_BASIC_LEN];1807 int ret, i;1808 1809 ret = tb_port_read(port, data, TB_CFG_PORT, 0, ARRAY_SIZE(data));1810 if (ret)1811 return ret;1812 1813 for (i = 0; i < ARRAY_SIZE(data); i++)1814 seq_printf(s, "0x%04x %4d 0x00 0x00 0x%08x\n", i, i, data[i]);1815 1816 return 0;1817}1818 1819static int port_regs_show(struct seq_file *s, void *not_used)1820{1821 struct tb_port *port = s->private;1822 struct tb_switch *sw = port->sw;1823 struct tb *tb = sw->tb;1824 int ret;1825 1826 pm_runtime_get_sync(&sw->dev);1827 1828 if (mutex_lock_interruptible(&tb->lock)) {1829 ret = -ERESTARTSYS;1830 goto out_rpm_put;1831 }1832 1833 seq_puts(s, "# offset relative_offset cap_id vs_cap_id value\n");1834 1835 ret = port_basic_regs_show(port, s);1836 if (ret)1837 goto out_unlock;1838 1839 port_caps_show(port, s);1840 1841out_unlock:1842 mutex_unlock(&tb->lock);1843out_rpm_put:1844 pm_runtime_mark_last_busy(&sw->dev);1845 pm_runtime_put_autosuspend(&sw->dev);1846 1847 return ret;1848}1849DEBUGFS_ATTR_RW(port_regs);1850 1851static void switch_cap_show(struct tb_switch *sw, struct seq_file *s,1852 unsigned int cap)1853{1854 struct tb_cap_any header;1855 int ret, length;1856 u8 vsec_id = 0;1857 1858 ret = tb_sw_read(sw, &header, TB_CFG_SWITCH, cap, 1);1859 if (ret) {1860 seq_printf(s, "0x%04x <capability read failed>\n", cap);1861 return;1862 }1863 1864 if (header.basic.cap == TB_SWITCH_CAP_VSE) {1865 if (!header.extended_short.length) {1866 ret = tb_sw_read(sw, (u32 *)&header + 1, TB_CFG_SWITCH,1867 cap + 1, 1);1868 if (ret) {1869 seq_printf(s, "0x%04x <capability read failed>\n",1870 cap + 1);1871 return;1872 }1873 length = header.extended_long.length;1874 } else {1875 length = header.extended_short.length;1876 }1877 vsec_id = header.extended_short.vsec_id;1878 } else {1879 if (header.basic.cap == TB_SWITCH_CAP_TMU) {1880 length = SWITCH_CAP_TMU_LEN;1881 } else {1882 seq_printf(s, "0x%04x <unknown capability 0x%02x>\n",1883 cap, header.basic.cap);1884 return;1885 }1886 }1887 1888 cap_show(s, sw, NULL, cap, header.basic.cap, vsec_id, length);1889}1890 1891static void switch_caps_show(struct tb_switch *sw, struct seq_file *s)1892{1893 int cap;1894 1895 cap = tb_switch_next_cap(sw, 0);1896 while (cap > 0) {1897 switch_cap_show(sw, s, cap);1898 cap = tb_switch_next_cap(sw, cap);1899 }1900}1901 1902static int switch_basic_regs_show(struct tb_switch *sw, struct seq_file *s)1903{1904 u32 data[SWITCH_CAP_BASIC_LEN];1905 size_t dwords;1906 int ret, i;1907 1908 /* Only USB4 has the additional registers */1909 if (tb_switch_is_usb4(sw))1910 dwords = ARRAY_SIZE(data);1911 else1912 dwords = 5;1913 1914 ret = tb_sw_read(sw, data, TB_CFG_SWITCH, 0, dwords);1915 if (ret)1916 return ret;1917 1918 for (i = 0; i < dwords; i++)1919 seq_printf(s, "0x%04x %4d 0x00 0x00 0x%08x\n", i, i, data[i]);1920 1921 return 0;1922}1923 1924static int switch_regs_show(struct seq_file *s, void *not_used)1925{1926 struct tb_switch *sw = s->private;1927 struct tb *tb = sw->tb;1928 int ret;1929 1930 pm_runtime_get_sync(&sw->dev);1931 1932 if (mutex_lock_interruptible(&tb->lock)) {1933 ret = -ERESTARTSYS;1934 goto out_rpm_put;1935 }1936 1937 seq_puts(s, "# offset relative_offset cap_id vs_cap_id value\n");1938 1939 ret = switch_basic_regs_show(sw, s);1940 if (ret)1941 goto out_unlock;1942 1943 switch_caps_show(sw, s);1944 1945out_unlock:1946 mutex_unlock(&tb->lock);1947out_rpm_put:1948 pm_runtime_mark_last_busy(&sw->dev);1949 pm_runtime_put_autosuspend(&sw->dev);1950 1951 return ret;1952}1953DEBUGFS_ATTR_RW(switch_regs);1954 1955static int path_show_one(struct tb_port *port, struct seq_file *s, int hopid)1956{1957 u32 data[PATH_LEN];1958 int ret, i;1959 1960 ret = tb_port_read(port, data, TB_CFG_HOPS, hopid * PATH_LEN,1961 ARRAY_SIZE(data));1962 if (ret) {1963 seq_printf(s, "0x%04x <not accessible>\n", hopid * PATH_LEN);1964 return ret;1965 }1966 1967 for (i = 0; i < ARRAY_SIZE(data); i++) {1968 seq_printf(s, "0x%04x %4d 0x%02x 0x%08x\n",1969 hopid * PATH_LEN + i, i, hopid, data[i]);1970 }1971 1972 return 0;1973}1974 1975static int path_show(struct seq_file *s, void *not_used)1976{1977 struct tb_port *port = s->private;1978 struct tb_switch *sw = port->sw;1979 struct tb *tb = sw->tb;1980 int start, i, ret = 0;1981 1982 pm_runtime_get_sync(&sw->dev);1983 1984 if (mutex_lock_interruptible(&tb->lock)) {1985 ret = -ERESTARTSYS;1986 goto out_rpm_put;1987 }1988 1989 seq_puts(s, "# offset relative_offset in_hop_id value\n");1990 1991 /* NHI and lane adapters have entry for path 0 */1992 if (tb_port_is_null(port) || tb_port_is_nhi(port)) {1993 ret = path_show_one(port, s, 0);1994 if (ret)1995 goto out_unlock;1996 }1997 1998 start = tb_port_is_nhi(port) ? 1 : TB_PATH_MIN_HOPID;1999 2000 for (i = start; i <= port->config.max_in_hop_id; i++) {2001 ret = path_show_one(port, s, i);2002 if (ret)2003 break;2004 }2005 2006out_unlock:2007 mutex_unlock(&tb->lock);2008out_rpm_put:2009 pm_runtime_mark_last_busy(&sw->dev);2010 pm_runtime_put_autosuspend(&sw->dev);2011 2012 return ret;2013}2014DEBUGFS_ATTR_RO(path);2015 2016static int counter_set_regs_show(struct tb_port *port, struct seq_file *s,2017 int counter)2018{2019 u32 data[COUNTER_SET_LEN];2020 int ret, i;2021 2022 ret = tb_port_read(port, data, TB_CFG_COUNTERS,2023 counter * COUNTER_SET_LEN, ARRAY_SIZE(data));2024 if (ret) {2025 seq_printf(s, "0x%04x <not accessible>\n",2026 counter * COUNTER_SET_LEN);2027 return ret;2028 }2029 2030 for (i = 0; i < ARRAY_SIZE(data); i++) {2031 seq_printf(s, "0x%04x %4d 0x%02x 0x%08x\n",2032 counter * COUNTER_SET_LEN + i, i, counter, data[i]);2033 }2034 2035 return 0;2036}2037 2038static int counters_show(struct seq_file *s, void *not_used)2039{2040 struct tb_port *port = s->private;2041 struct tb_switch *sw = port->sw;2042 struct tb *tb = sw->tb;2043 int i, ret = 0;2044 2045 pm_runtime_get_sync(&sw->dev);2046 2047 if (mutex_lock_interruptible(&tb->lock)) {2048 ret = -ERESTARTSYS;2049 goto out;2050 }2051 2052 seq_puts(s, "# offset relative_offset counter_id value\n");2053 2054 for (i = 0; i < port->config.max_counters; i++) {2055 ret = counter_set_regs_show(port, s, i);2056 if (ret)2057 break;2058 }2059 2060 mutex_unlock(&tb->lock);2061 2062out:2063 pm_runtime_mark_last_busy(&sw->dev);2064 pm_runtime_put_autosuspend(&sw->dev);2065 2066 return ret;2067}2068DEBUGFS_ATTR_RW(counters);2069 2070static int sb_regs_show(struct tb_port *port, const struct sb_reg *sb_regs,2071 size_t size, enum usb4_sb_target target, u8 index,2072 struct seq_file *s)2073{2074 int ret, i;2075 2076 seq_puts(s, "# register value\n");2077 2078 for (i = 0; i < size; i++) {2079 const struct sb_reg *regs = &sb_regs[i];2080 u8 data[64];2081 int j;2082 2083 memset(data, 0, sizeof(data));2084 ret = usb4_port_sb_read(port, target, index, regs->reg, data,2085 regs->size);2086 if (ret)2087 return ret;2088 2089 seq_printf(s, "0x%02x", regs->reg);2090 for (j = 0; j < regs->size; j++)2091 seq_printf(s, " 0x%02x", data[j]);2092 seq_puts(s, "\n");2093 }2094 2095 return 0;2096}2097 2098static int port_sb_regs_show(struct seq_file *s, void *not_used)2099{2100 struct tb_port *port = s->private;2101 struct tb_switch *sw = port->sw;2102 struct tb *tb = sw->tb;2103 int ret;2104 2105 pm_runtime_get_sync(&sw->dev);2106 2107 if (mutex_lock_interruptible(&tb->lock)) {2108 ret = -ERESTARTSYS;2109 goto out_rpm_put;2110 }2111 2112 ret = sb_regs_show(port, port_sb_regs, ARRAY_SIZE(port_sb_regs),2113 USB4_SB_TARGET_ROUTER, 0, s);2114 2115 mutex_unlock(&tb->lock);2116out_rpm_put:2117 pm_runtime_mark_last_busy(&sw->dev);2118 pm_runtime_put_autosuspend(&sw->dev);2119 2120 return ret;2121}2122DEBUGFS_ATTR_RW(port_sb_regs);2123 2124/**2125 * tb_switch_debugfs_init() - Add debugfs entries for router2126 * @sw: Pointer to the router2127 *2128 * Adds debugfs directories and files for given router.2129 */2130void tb_switch_debugfs_init(struct tb_switch *sw)2131{2132 struct dentry *debugfs_dir;2133 struct tb_port *port;2134 2135 debugfs_dir = debugfs_create_dir(dev_name(&sw->dev), tb_debugfs_root);2136 sw->debugfs_dir = debugfs_dir;2137 debugfs_create_file("regs", DEBUGFS_MODE, debugfs_dir, sw,2138 &switch_regs_fops);2139 2140 tb_switch_for_each_port(sw, port) {2141 struct dentry *debugfs_dir;2142 char dir_name[10];2143 2144 if (port->disabled)2145 continue;2146 if (port->config.type == TB_TYPE_INACTIVE)2147 continue;2148 2149 snprintf(dir_name, sizeof(dir_name), "port%d", port->port);2150 debugfs_dir = debugfs_create_dir(dir_name, sw->debugfs_dir);2151 debugfs_create_file("regs", DEBUGFS_MODE, debugfs_dir,2152 port, &port_regs_fops);2153 debugfs_create_file("path", 0400, debugfs_dir, port,2154 &path_fops);2155 if (port->config.counters_support)2156 debugfs_create_file("counters", 0600, debugfs_dir, port,2157 &counters_fops);2158 if (port->usb4)2159 debugfs_create_file("sb_regs", DEBUGFS_MODE, debugfs_dir,2160 port, &port_sb_regs_fops);2161 }2162 2163 margining_switch_init(sw);2164}2165 2166/**2167 * tb_switch_debugfs_remove() - Remove all router debugfs entries2168 * @sw: Pointer to the router2169 *2170 * Removes all previously added debugfs entries under this router.2171 */2172void tb_switch_debugfs_remove(struct tb_switch *sw)2173{2174 margining_switch_remove(sw);2175 debugfs_remove_recursive(sw->debugfs_dir);2176}2177 2178void tb_xdomain_debugfs_init(struct tb_xdomain *xd)2179{2180 margining_xdomain_init(xd);2181}2182 2183void tb_xdomain_debugfs_remove(struct tb_xdomain *xd)2184{2185 margining_xdomain_remove(xd);2186}2187 2188/**2189 * tb_service_debugfs_init() - Add debugfs directory for service2190 * @svc: Thunderbolt service pointer2191 *2192 * Adds debugfs directory for service.2193 */2194void tb_service_debugfs_init(struct tb_service *svc)2195{2196 svc->debugfs_dir = debugfs_create_dir(dev_name(&svc->dev),2197 tb_debugfs_root);2198}2199 2200/**2201 * tb_service_debugfs_remove() - Remove service debugfs directory2202 * @svc: Thunderbolt service pointer2203 *2204 * Removes the previously created debugfs directory for @svc.2205 */2206void tb_service_debugfs_remove(struct tb_service *svc)2207{2208 debugfs_remove_recursive(svc->debugfs_dir);2209 svc->debugfs_dir = NULL;2210}2211 2212static int retimer_sb_regs_show(struct seq_file *s, void *not_used)2213{2214 struct tb_retimer *rt = s->private;2215 struct tb *tb = rt->tb;2216 int ret;2217 2218 pm_runtime_get_sync(&rt->dev);2219 2220 if (mutex_lock_interruptible(&tb->lock)) {2221 ret = -ERESTARTSYS;2222 goto out_rpm_put;2223 }2224 2225 ret = sb_regs_show(rt->port, retimer_sb_regs, ARRAY_SIZE(retimer_sb_regs),2226 USB4_SB_TARGET_RETIMER, rt->index, s);2227 2228 mutex_unlock(&tb->lock);2229out_rpm_put:2230 pm_runtime_mark_last_busy(&rt->dev);2231 pm_runtime_put_autosuspend(&rt->dev);2232 2233 return ret;2234}2235DEBUGFS_ATTR_RW(retimer_sb_regs);2236 2237/**2238 * tb_retimer_debugfs_init() - Add debugfs directory for retimer2239 * @rt: Pointer to retimer structure2240 *2241 * Adds and populates retimer debugfs directory.2242 */2243void tb_retimer_debugfs_init(struct tb_retimer *rt)2244{2245 struct dentry *debugfs_dir;2246 2247 debugfs_dir = debugfs_create_dir(dev_name(&rt->dev), tb_debugfs_root);2248 debugfs_create_file("sb_regs", DEBUGFS_MODE, debugfs_dir, rt,2249 &retimer_sb_regs_fops);2250 margining_retimer_init(rt, debugfs_dir);2251}2252 2253/**2254 * tb_retimer_debugfs_remove() - Remove retimer debugfs directory2255 * @rt: Pointer to retimer structure2256 *2257 * Removes the retimer debugfs directory along with its contents.2258 */2259void tb_retimer_debugfs_remove(struct tb_retimer *rt)2260{2261 debugfs_lookup_and_remove(dev_name(&rt->dev), tb_debugfs_root);2262 margining_retimer_remove(rt);2263}2264 2265void tb_debugfs_init(void)2266{2267 tb_debugfs_root = debugfs_create_dir("thunderbolt", NULL);2268}2269 2270void tb_debugfs_exit(void)2271{2272 debugfs_remove_recursive(tb_debugfs_root);2273}2274