1 // SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause 2 /* 3 * Copyright (c) 2024, Broadcom. All rights reserved. The term 4 * Broadcom refers to Broadcom Limited and/or its subsidiaries. 5 * 6 * Description: Debugfs component of the bnxt_re driver 7 */ 8 9 #include <linux/debugfs.h> 10 #include <linux/pci.h> 11 #include <linux/seq_file.h> 12 #include <rdma/ib_addr.h> 13 14 #include "bnxt_ulp.h" 15 #include "roce_hsi.h" 16 #include "qplib_res.h" 17 #include "qplib_sp.h" 18 #include "qplib_fp.h" 19 #include "qplib_rcfw.h" 20 #include "bnxt_re.h" 21 #include "ib_verbs.h" 22 #include "debugfs.h" 23 24 static struct dentry *bnxt_re_debugfs_root; 25 26 static const char * const bnxt_re_cq_coal_str[] = { 27 "buf_maxtime", 28 "normal_maxbuf", 29 "during_maxbuf", 30 "en_ring_idle_mode", 31 "enable", 32 }; 33 34 static const char * const bnxt_re_cc_gen0_name[] = { 35 "enable_cc", 36 "run_avg_weight_g", 37 "num_phase_per_state", 38 "init_cr", 39 "init_tr", 40 "tos_ecn", 41 "tos_dscp", 42 "alt_vlan_pcp", 43 "alt_vlan_dscp", 44 "rtt", 45 "cc_mode", 46 "tcp_cp", 47 "tx_queue", 48 "inactivity_cp", 49 }; 50 51 static inline const char *bnxt_re_qp_state_str(u8 state) 52 { 53 switch (state) { 54 case CMDQ_MODIFY_QP_NEW_STATE_RESET: 55 return "RST"; 56 case CMDQ_MODIFY_QP_NEW_STATE_INIT: 57 return "INIT"; 58 case CMDQ_MODIFY_QP_NEW_STATE_RTR: 59 return "RTR"; 60 case CMDQ_MODIFY_QP_NEW_STATE_RTS: 61 return "RTS"; 62 case CMDQ_MODIFY_QP_NEW_STATE_SQE: 63 return "SQER"; 64 case CMDQ_MODIFY_QP_NEW_STATE_SQD: 65 return "SQD"; 66 case CMDQ_MODIFY_QP_NEW_STATE_ERR: 67 return "ERR"; 68 default: 69 return "Invalid QP state"; 70 } 71 } 72 73 static inline const char *bnxt_re_qp_type_str(u8 type) 74 { 75 switch (type) { 76 case CMDQ_CREATE_QP1_TYPE_GSI: return "QP1"; 77 case CMDQ_CREATE_QP_TYPE_GSI: return "QP1"; 78 case CMDQ_CREATE_QP_TYPE_RC: return "RC"; 79 case CMDQ_CREATE_QP_TYPE_UD: return "UD"; 80 case CMDQ_CREATE_QP_TYPE_RAW_ETHERTYPE: return "RAW_ETHERTYPE"; 81 default: return "Invalid transport type"; 82 } 83 } 84 85 static ssize_t qp_info_read(struct file *filep, 86 char __user *buffer, 87 size_t count, loff_t *ppos) 88 { 89 struct bnxt_re_qp *qp = filep->private_data; 90 char *buf; 91 int len; 92 93 if (*ppos) 94 return 0; 95 96 buf = kasprintf(GFP_KERNEL, 97 "QPN\t\t: %d\n" 98 "transport\t: %s\n" 99 "state\t\t: %s\n" 100 "mtu\t\t: %d\n" 101 "timeout\t\t: %d\n" 102 "remote QPN\t: %d\n", 103 qp->qplib_qp.id, 104 bnxt_re_qp_type_str(qp->qplib_qp.type), 105 bnxt_re_qp_state_str(qp->qplib_qp.state), 106 qp->qplib_qp.mtu, 107 qp->qplib_qp.timeout, 108 qp->qplib_qp.dest_qpn); 109 if (!buf) 110 return -ENOMEM; 111 if (count < strlen(buf)) { 112 kfree(buf); 113 return -ENOSPC; 114 } 115 len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf)); 116 kfree(buf); 117 return len; 118 } 119 120 static const struct file_operations debugfs_qp_fops = { 121 .owner = THIS_MODULE, 122 .open = simple_open, 123 .read = qp_info_read, 124 }; 125 126 void bnxt_re_debug_add_qpinfo(struct bnxt_re_dev *rdev, struct bnxt_re_qp *qp) 127 { 128 char resn[32]; 129 130 sprintf(resn, "0x%x", qp->qplib_qp.id); 131 qp->dentry = debugfs_create_file(resn, 0400, rdev->qp_debugfs, qp, &debugfs_qp_fops); 132 } 133 134 void bnxt_re_debug_rem_qpinfo(struct bnxt_re_dev *rdev, struct bnxt_re_qp *qp) 135 { 136 debugfs_remove(qp->dentry); 137 } 138 139 static int map_cc_config_offset_gen0_ext0(u32 offset, struct bnxt_qplib_cc_param *ccparam, u32 *val) 140 { 141 u64 map_offset; 142 143 map_offset = BIT(offset); 144 145 switch (map_offset) { 146 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ENABLE_CC: 147 *val = ccparam->enable; 148 break; 149 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_G: 150 *val = ccparam->g; 151 break; 152 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_NUMPHASEPERSTATE: 153 *val = ccparam->nph_per_state; 154 break; 155 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INIT_CR: 156 *val = ccparam->init_cr; 157 break; 158 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INIT_TR: 159 *val = ccparam->init_tr; 160 break; 161 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TOS_ECN: 162 *val = ccparam->tos_ecn; 163 break; 164 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TOS_DSCP: 165 *val = ccparam->tos_dscp; 166 break; 167 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ALT_VLAN_PCP: 168 *val = ccparam->alt_vlan_pcp; 169 break; 170 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ALT_TOS_DSCP: 171 *val = ccparam->alt_tos_dscp; 172 break; 173 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_RTT: 174 *val = ccparam->rtt; 175 break; 176 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_CC_MODE: 177 *val = ccparam->cc_mode; 178 break; 179 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TCP_CP: 180 *val = ccparam->tcp_cp; 181 break; 182 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INACTIVITY_CP: 183 *val = ccparam->inact_th; 184 break; 185 default: 186 return -EINVAL; 187 } 188 189 return 0; 190 } 191 192 static ssize_t bnxt_re_cc_config_get(struct file *filp, char __user *buffer, 193 size_t usr_buf_len, loff_t *ppos) 194 { 195 struct bnxt_re_cc_param *dbg_cc_param = filp->private_data; 196 struct bnxt_re_dev *rdev = dbg_cc_param->rdev; 197 struct bnxt_qplib_cc_param ccparam = {}; 198 u32 offset = dbg_cc_param->offset; 199 char buf[16]; 200 u32 val; 201 int rc; 202 203 rc = bnxt_qplib_query_cc_param(&rdev->qplib_res, &ccparam); 204 if (rc) 205 return rc; 206 207 rc = map_cc_config_offset_gen0_ext0(offset, &ccparam, &val); 208 if (rc) 209 return rc; 210 211 rc = snprintf(buf, sizeof(buf), "%d\n", val); 212 if (rc < 0) 213 return rc; 214 215 return simple_read_from_buffer(buffer, usr_buf_len, ppos, (u8 *)(buf), rc); 216 } 217 218 static int bnxt_re_fill_gen0_ext0(struct bnxt_qplib_cc_param *ccparam, u32 offset, u32 val) 219 { 220 u32 modify_mask; 221 222 modify_mask = BIT(offset); 223 224 switch (modify_mask) { 225 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ENABLE_CC: 226 ccparam->enable = val; 227 break; 228 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_G: 229 ccparam->g = val; 230 break; 231 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_NUMPHASEPERSTATE: 232 ccparam->nph_per_state = val; 233 break; 234 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INIT_CR: 235 ccparam->init_cr = val; 236 break; 237 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INIT_TR: 238 ccparam->init_tr = val; 239 break; 240 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TOS_ECN: 241 ccparam->tos_ecn = val; 242 break; 243 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TOS_DSCP: 244 ccparam->tos_dscp = val; 245 break; 246 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ALT_VLAN_PCP: 247 ccparam->alt_vlan_pcp = val; 248 break; 249 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ALT_TOS_DSCP: 250 ccparam->alt_tos_dscp = val; 251 break; 252 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_RTT: 253 ccparam->rtt = val; 254 break; 255 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_CC_MODE: 256 ccparam->cc_mode = val; 257 break; 258 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TCP_CP: 259 ccparam->tcp_cp = val; 260 break; 261 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TX_QUEUE: 262 return -EOPNOTSUPP; 263 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INACTIVITY_CP: 264 ccparam->inact_th = val; 265 break; 266 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TIME_PER_PHASE: 267 ccparam->time_pph = val; 268 break; 269 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_PKTS_PER_PHASE: 270 ccparam->pkts_pph = val; 271 break; 272 } 273 274 ccparam->mask = modify_mask; 275 return 0; 276 } 277 278 static int bnxt_re_configure_cc(struct bnxt_re_dev *rdev, u32 gen_ext, u32 offset, u32 val) 279 { 280 struct bnxt_qplib_cc_param ccparam = { }; 281 int rc; 282 283 if (gen_ext != CC_CONFIG_GEN0_EXT0) 284 return -EOPNOTSUPP; 285 286 rc = bnxt_re_fill_gen0_ext0(&ccparam, offset, val); 287 if (rc) 288 return rc; 289 290 bnxt_qplib_modify_cc(&rdev->qplib_res, &ccparam); 291 return 0; 292 } 293 294 static ssize_t bnxt_re_cc_config_set(struct file *filp, const char __user *buffer, 295 size_t count, loff_t *ppos) 296 { 297 struct bnxt_re_cc_param *dbg_cc_param = filp->private_data; 298 struct bnxt_re_dev *rdev = dbg_cc_param->rdev; 299 u32 offset = dbg_cc_param->offset; 300 u8 cc_gen = dbg_cc_param->cc_gen; 301 char buf[16]; 302 u32 val; 303 int rc; 304 305 if (count >= sizeof(buf)) 306 return -EINVAL; 307 308 if (copy_from_user(buf, buffer, count)) 309 return -EFAULT; 310 311 buf[count] = '\0'; 312 if (kstrtou32(buf, 0, &val)) 313 return -EINVAL; 314 315 rc = bnxt_re_configure_cc(rdev, cc_gen, offset, val); 316 return rc ? rc : count; 317 } 318 319 static const struct file_operations bnxt_re_cc_config_ops = { 320 .owner = THIS_MODULE, 321 .open = simple_open, 322 .read = bnxt_re_cc_config_get, 323 .write = bnxt_re_cc_config_set, 324 }; 325 326 static int info_show(struct seq_file *m, void *unused) 327 { 328 struct bnxt_re_dev *rdev = m->private; 329 struct bnxt_re_res_cntrs *res_s = &rdev->stats.res; 330 331 seq_puts(m, "Info:\n"); 332 seq_printf(m, "Device Name\t\t: %s\n", dev_name(&rdev->ibdev.dev)); 333 seq_printf(m, "PD Watermark\t\t: %llu\n", res_s->pd_watermark); 334 seq_printf(m, "AH Watermark\t\t: %llu\n", res_s->ah_watermark); 335 seq_printf(m, "QP Watermark\t\t: %llu\n", res_s->qp_watermark); 336 seq_printf(m, "RC QP Watermark\t\t: %llu\n", res_s->rc_qp_watermark); 337 seq_printf(m, "UD QP Watermark\t\t: %llu\n", res_s->ud_qp_watermark); 338 seq_printf(m, "SRQ Watermark\t\t: %llu\n", res_s->srq_watermark); 339 seq_printf(m, "CQ Watermark\t\t: %llu\n", res_s->cq_watermark); 340 seq_printf(m, "MR Watermark\t\t: %llu\n", res_s->mr_watermark); 341 seq_printf(m, "MW Watermark\t\t: %llu\n", res_s->mw_watermark); 342 seq_printf(m, "CQ Resize Count\t\t: %d\n", atomic_read(&res_s->resize_count)); 343 if (rdev->pacing.dbr_pacing) { 344 seq_printf(m, "DB Pacing Reschedule\t: %llu\n", rdev->stats.pacing.resched); 345 seq_printf(m, "DB Pacing Complete\t: %llu\n", rdev->stats.pacing.complete); 346 seq_printf(m, "DB Pacing Alerts\t: %llu\n", rdev->stats.pacing.alerts); 347 seq_printf(m, "DB FIFO Register\t: 0x%x\n", 348 readl(rdev->en_dev->bar0 + rdev->pacing.dbr_db_fifo_reg_off)); 349 } 350 351 return 0; 352 } 353 DEFINE_SHOW_ATTRIBUTE(info); 354 355 static void bnxt_re_debugfs_add_info(struct bnxt_re_dev *rdev) 356 { 357 debugfs_create_file("info", 0400, rdev->dbg_root, rdev, &info_fops); 358 } 359 360 static ssize_t cq_coal_cfg_write(struct file *file, 361 const char __user *buf, 362 size_t count, loff_t *pos) 363 { 364 struct seq_file *s = file->private_data; 365 struct bnxt_re_cq_coal_param *param = s->private; 366 struct bnxt_re_dev *rdev = param->rdev; 367 int offset = param->offset; 368 char lbuf[16] = { }; 369 u32 val; 370 371 if (count > sizeof(lbuf)) 372 return -EINVAL; 373 374 if (copy_from_user(lbuf, buf, count)) 375 return -EFAULT; 376 377 lbuf[sizeof(lbuf) - 1] = '\0'; 378 379 if (kstrtou32(lbuf, 0, &val)) 380 return -EINVAL; 381 382 switch (offset) { 383 case BNXT_RE_COAL_CQ_BUF_MAXTIME: 384 if (val < 1 || val > BNXT_QPLIB_CQ_COAL_MAX_BUF_MAXTIME) 385 return -EINVAL; 386 rdev->cq_coalescing.buf_maxtime = val; 387 break; 388 case BNXT_RE_COAL_CQ_NORMAL_MAXBUF: 389 if (val < 1 || val > BNXT_QPLIB_CQ_COAL_MAX_NORMAL_MAXBUF) 390 return -EINVAL; 391 rdev->cq_coalescing.normal_maxbuf = val; 392 break; 393 case BNXT_RE_COAL_CQ_DURING_MAXBUF: 394 if (val < 1 || val > BNXT_QPLIB_CQ_COAL_MAX_DURING_MAXBUF) 395 return -EINVAL; 396 rdev->cq_coalescing.during_maxbuf = val; 397 break; 398 case BNXT_RE_COAL_CQ_EN_RING_IDLE_MODE: 399 if (val > BNXT_QPLIB_CQ_COAL_MAX_EN_RING_IDLE_MODE) 400 return -EINVAL; 401 rdev->cq_coalescing.en_ring_idle_mode = val; 402 break; 403 case BNXT_RE_COAL_CQ_ENABLE: 404 if (val > 1) 405 return -EINVAL; 406 rdev->cq_coalescing.enable = val; 407 break; 408 default: 409 return -EINVAL; 410 } 411 return count; 412 } 413 414 static int cq_coal_cfg_show(struct seq_file *s, void *unused) 415 { 416 struct bnxt_re_cq_coal_param *param = s->private; 417 struct bnxt_re_dev *rdev = param->rdev; 418 int offset = param->offset; 419 u32 val = 0; 420 421 switch (offset) { 422 case BNXT_RE_COAL_CQ_BUF_MAXTIME: 423 val = rdev->cq_coalescing.buf_maxtime; 424 break; 425 case BNXT_RE_COAL_CQ_NORMAL_MAXBUF: 426 val = rdev->cq_coalescing.normal_maxbuf; 427 break; 428 case BNXT_RE_COAL_CQ_DURING_MAXBUF: 429 val = rdev->cq_coalescing.during_maxbuf; 430 break; 431 case BNXT_RE_COAL_CQ_EN_RING_IDLE_MODE: 432 val = rdev->cq_coalescing.en_ring_idle_mode; 433 break; 434 case BNXT_RE_COAL_CQ_ENABLE: 435 val = rdev->cq_coalescing.enable; 436 break; 437 default: 438 return -EINVAL; 439 } 440 441 seq_printf(s, "%u\n", val); 442 return 0; 443 } 444 DEFINE_SHOW_STORE_ATTRIBUTE(cq_coal_cfg); 445 446 static void bnxt_re_cleanup_cq_coal_debugfs(struct bnxt_re_dev *rdev) 447 { 448 debugfs_remove_recursive(rdev->cq_coal_cfg); 449 kfree(rdev->cq_coal_cfg_params); 450 } 451 452 static void bnxt_re_init_cq_coal_debugfs(struct bnxt_re_dev *rdev) 453 { 454 struct bnxt_re_dbg_cq_coal_params *dbg_cq_coal_params; 455 int i; 456 457 if (!_is_cq_coalescing_supported(rdev->dev_attr->dev_cap_flags2)) 458 return; 459 460 dbg_cq_coal_params = kzalloc(sizeof(*dbg_cq_coal_params), GFP_KERNEL); 461 if (!dbg_cq_coal_params) 462 return; 463 464 rdev->cq_coal_cfg = debugfs_create_dir("cq_coal_cfg", rdev->dbg_root); 465 rdev->cq_coal_cfg_params = dbg_cq_coal_params; 466 467 for (i = 0; i < BNXT_RE_COAL_CQ_MAX; i++) { 468 dbg_cq_coal_params->params[i].offset = i; 469 dbg_cq_coal_params->params[i].rdev = rdev; 470 debugfs_create_file(bnxt_re_cq_coal_str[i], 471 0600, rdev->cq_coal_cfg, 472 &dbg_cq_coal_params->params[i], 473 &cq_coal_cfg_fops); 474 } 475 } 476 477 void bnxt_re_debugfs_add_pdev(struct bnxt_re_dev *rdev) 478 { 479 struct pci_dev *pdev = rdev->en_dev->pdev; 480 struct bnxt_re_dbg_cc_config_params *cc_params; 481 int i; 482 483 rdev->dbg_root = debugfs_create_dir(dev_name(&pdev->dev), bnxt_re_debugfs_root); 484 485 rdev->qp_debugfs = debugfs_create_dir("QPs", rdev->dbg_root); 486 rdev->cc_config = debugfs_create_dir("cc_config", rdev->dbg_root); 487 488 bnxt_re_debugfs_add_info(rdev); 489 490 rdev->cc_config_params = kzalloc(sizeof(*cc_params), GFP_KERNEL); 491 492 for (i = 0; i < BNXT_RE_CC_PARAM_GEN0; i++) { 493 struct bnxt_re_cc_param *tmp_params = &rdev->cc_config_params->gen0_parms[i]; 494 495 tmp_params->rdev = rdev; 496 tmp_params->offset = i; 497 tmp_params->cc_gen = CC_CONFIG_GEN0_EXT0; 498 tmp_params->dentry = debugfs_create_file(bnxt_re_cc_gen0_name[i], 0400, 499 rdev->cc_config, tmp_params, 500 &bnxt_re_cc_config_ops); 501 } 502 503 bnxt_re_init_cq_coal_debugfs(rdev); 504 } 505 506 void bnxt_re_debugfs_rem_pdev(struct bnxt_re_dev *rdev) 507 { 508 bnxt_re_cleanup_cq_coal_debugfs(rdev); 509 debugfs_remove_recursive(rdev->qp_debugfs); 510 debugfs_remove_recursive(rdev->cc_config); 511 kfree(rdev->cc_config_params); 512 debugfs_remove_recursive(rdev->dbg_root); 513 rdev->dbg_root = NULL; 514 } 515 516 void bnxt_re_register_debugfs(void) 517 { 518 bnxt_re_debugfs_root = debugfs_create_dir("bnxt_re", NULL); 519 } 520 521 void bnxt_re_unregister_debugfs(void) 522 { 523 debugfs_remove(bnxt_re_debugfs_root); 524 } 525