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 struct bnxt_qplib_qp *qplib_qp; 91 u32 rate_limit = 0; 92 char *buf; 93 int len; 94 95 if (*ppos) 96 return 0; 97 98 qplib_qp = &qp->qplib_qp; 99 if (qplib_qp->shaper_allocation_status) 100 rate_limit = qplib_qp->rate_limit; 101 102 buf = kasprintf(GFP_KERNEL, 103 "QPN\t\t: %d\n" 104 "transport\t: %s\n" 105 "state\t\t: %s\n" 106 "mtu\t\t: %d\n" 107 "timeout\t\t: %d\n" 108 "remote QPN\t: %d\n" 109 "shaper allocated : %d\n" 110 "rate limit\t: %d kbps\n", 111 qp->qplib_qp.id, 112 bnxt_re_qp_type_str(qp->qplib_qp.type), 113 bnxt_re_qp_state_str(qp->qplib_qp.state), 114 qp->qplib_qp.mtu, 115 qp->qplib_qp.timeout, 116 qp->qplib_qp.dest_qpn, 117 qplib_qp->shaper_allocation_status, 118 rate_limit); 119 if (!buf) 120 return -ENOMEM; 121 if (count < strlen(buf)) { 122 kfree(buf); 123 return -ENOSPC; 124 } 125 len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf)); 126 kfree(buf); 127 return len; 128 } 129 130 static const struct file_operations debugfs_qp_fops = { 131 .owner = THIS_MODULE, 132 .open = simple_open, 133 .read = qp_info_read, 134 }; 135 136 void bnxt_re_debug_add_qpinfo(struct bnxt_re_dev *rdev, struct bnxt_re_qp *qp) 137 { 138 char resn[32]; 139 140 sprintf(resn, "0x%x", qp->qplib_qp.id); 141 qp->dentry = debugfs_create_file(resn, 0400, rdev->qp_debugfs, qp, &debugfs_qp_fops); 142 } 143 144 void bnxt_re_debug_rem_qpinfo(struct bnxt_re_dev *rdev, struct bnxt_re_qp *qp) 145 { 146 debugfs_remove(qp->dentry); 147 } 148 149 static int map_cc_config_offset_gen0_ext0(u32 offset, struct bnxt_qplib_cc_param *ccparam, u32 *val) 150 { 151 u64 map_offset; 152 153 map_offset = BIT(offset); 154 155 switch (map_offset) { 156 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ENABLE_CC: 157 *val = ccparam->enable; 158 break; 159 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_G: 160 *val = ccparam->g; 161 break; 162 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_NUMPHASEPERSTATE: 163 *val = ccparam->nph_per_state; 164 break; 165 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INIT_CR: 166 *val = ccparam->init_cr; 167 break; 168 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INIT_TR: 169 *val = ccparam->init_tr; 170 break; 171 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TOS_ECN: 172 *val = ccparam->tos_ecn; 173 break; 174 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TOS_DSCP: 175 *val = ccparam->tos_dscp; 176 break; 177 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ALT_VLAN_PCP: 178 *val = ccparam->alt_vlan_pcp; 179 break; 180 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ALT_TOS_DSCP: 181 *val = ccparam->alt_tos_dscp; 182 break; 183 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_RTT: 184 *val = ccparam->rtt; 185 break; 186 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_CC_MODE: 187 *val = ccparam->cc_mode; 188 break; 189 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TCP_CP: 190 *val = ccparam->tcp_cp; 191 break; 192 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INACTIVITY_CP: 193 *val = ccparam->inact_th; 194 break; 195 default: 196 return -EINVAL; 197 } 198 199 return 0; 200 } 201 202 static ssize_t bnxt_re_cc_config_get(struct file *filp, char __user *buffer, 203 size_t usr_buf_len, loff_t *ppos) 204 { 205 struct bnxt_re_cc_param *dbg_cc_param = filp->private_data; 206 struct bnxt_re_dev *rdev = dbg_cc_param->rdev; 207 struct bnxt_qplib_cc_param ccparam = {}; 208 u32 offset = dbg_cc_param->offset; 209 char buf[16]; 210 u32 val; 211 int rc; 212 213 rc = bnxt_qplib_query_cc_param(&rdev->qplib_res, &ccparam); 214 if (rc) 215 return rc; 216 217 rc = map_cc_config_offset_gen0_ext0(offset, &ccparam, &val); 218 if (rc) 219 return rc; 220 221 rc = snprintf(buf, sizeof(buf), "%d\n", val); 222 if (rc < 0) 223 return rc; 224 225 return simple_read_from_buffer(buffer, usr_buf_len, ppos, (u8 *)(buf), rc); 226 } 227 228 static int bnxt_re_fill_gen0_ext0(struct bnxt_qplib_cc_param *ccparam, u32 offset, u32 val) 229 { 230 u32 modify_mask; 231 232 modify_mask = BIT(offset); 233 234 switch (modify_mask) { 235 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ENABLE_CC: 236 ccparam->enable = val; 237 break; 238 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_G: 239 ccparam->g = val; 240 break; 241 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_NUMPHASEPERSTATE: 242 ccparam->nph_per_state = val; 243 break; 244 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INIT_CR: 245 ccparam->init_cr = val; 246 break; 247 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INIT_TR: 248 ccparam->init_tr = val; 249 break; 250 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TOS_ECN: 251 ccparam->tos_ecn = val; 252 break; 253 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TOS_DSCP: 254 ccparam->tos_dscp = val; 255 break; 256 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ALT_VLAN_PCP: 257 ccparam->alt_vlan_pcp = val; 258 break; 259 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ALT_TOS_DSCP: 260 ccparam->alt_tos_dscp = val; 261 break; 262 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_RTT: 263 ccparam->rtt = val; 264 break; 265 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_CC_MODE: 266 ccparam->cc_mode = val; 267 break; 268 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TCP_CP: 269 ccparam->tcp_cp = val; 270 break; 271 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TX_QUEUE: 272 return -EOPNOTSUPP; 273 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INACTIVITY_CP: 274 ccparam->inact_th = val; 275 break; 276 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TIME_PER_PHASE: 277 ccparam->time_pph = val; 278 break; 279 case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_PKTS_PER_PHASE: 280 ccparam->pkts_pph = val; 281 break; 282 } 283 284 ccparam->mask = modify_mask; 285 return 0; 286 } 287 288 static int bnxt_re_configure_cc(struct bnxt_re_dev *rdev, u32 gen_ext, u32 offset, u32 val) 289 { 290 struct bnxt_qplib_cc_param ccparam = { }; 291 int rc; 292 293 if (gen_ext != CC_CONFIG_GEN0_EXT0) 294 return -EOPNOTSUPP; 295 296 rc = bnxt_re_fill_gen0_ext0(&ccparam, offset, val); 297 if (rc) 298 return rc; 299 300 bnxt_qplib_modify_cc(&rdev->qplib_res, &ccparam); 301 return 0; 302 } 303 304 static ssize_t bnxt_re_cc_config_set(struct file *filp, const char __user *buffer, 305 size_t count, loff_t *ppos) 306 { 307 struct bnxt_re_cc_param *dbg_cc_param = filp->private_data; 308 struct bnxt_re_dev *rdev = dbg_cc_param->rdev; 309 u32 offset = dbg_cc_param->offset; 310 u8 cc_gen = dbg_cc_param->cc_gen; 311 char buf[16]; 312 u32 val; 313 int rc; 314 315 if (count >= sizeof(buf)) 316 return -EINVAL; 317 318 if (copy_from_user(buf, buffer, count)) 319 return -EFAULT; 320 321 buf[count] = '\0'; 322 if (kstrtou32(buf, 0, &val)) 323 return -EINVAL; 324 325 rc = bnxt_re_configure_cc(rdev, cc_gen, offset, val); 326 return rc ? rc : count; 327 } 328 329 static const struct file_operations bnxt_re_cc_config_ops = { 330 .owner = THIS_MODULE, 331 .open = simple_open, 332 .read = bnxt_re_cc_config_get, 333 .write = bnxt_re_cc_config_set, 334 }; 335 336 static int info_show(struct seq_file *m, void *unused) 337 { 338 struct bnxt_re_dev *rdev = m->private; 339 struct bnxt_re_res_cntrs *res_s = &rdev->stats.res; 340 341 seq_puts(m, "Info:\n"); 342 seq_printf(m, "Device Name\t\t: %s\n", dev_name(&rdev->ibdev.dev)); 343 seq_printf(m, "PD Watermark\t\t: %llu\n", res_s->pd_watermark); 344 seq_printf(m, "AH Watermark\t\t: %llu\n", res_s->ah_watermark); 345 seq_printf(m, "QP Watermark\t\t: %llu\n", res_s->qp_watermark); 346 seq_printf(m, "RC QP Watermark\t\t: %llu\n", res_s->rc_qp_watermark); 347 seq_printf(m, "UD QP Watermark\t\t: %llu\n", res_s->ud_qp_watermark); 348 seq_printf(m, "SRQ Watermark\t\t: %llu\n", res_s->srq_watermark); 349 seq_printf(m, "CQ Watermark\t\t: %llu\n", res_s->cq_watermark); 350 seq_printf(m, "MR Watermark\t\t: %llu\n", res_s->mr_watermark); 351 seq_printf(m, "MW Watermark\t\t: %llu\n", res_s->mw_watermark); 352 seq_printf(m, "CQ Resize Count\t\t: %d\n", atomic_read(&res_s->resize_count)); 353 if (rdev->pacing.dbr_pacing) { 354 seq_printf(m, "DB Pacing Reschedule\t: %llu\n", rdev->stats.pacing.resched); 355 seq_printf(m, "DB Pacing Complete\t: %llu\n", rdev->stats.pacing.complete); 356 seq_printf(m, "DB Pacing Alerts\t: %llu\n", rdev->stats.pacing.alerts); 357 seq_printf(m, "DB FIFO Register\t: 0x%x\n", 358 readl(rdev->en_dev->bar0 + rdev->pacing.dbr_db_fifo_reg_off)); 359 } 360 361 return 0; 362 } 363 DEFINE_SHOW_ATTRIBUTE(info); 364 365 static void bnxt_re_debugfs_add_info(struct bnxt_re_dev *rdev) 366 { 367 debugfs_create_file("info", 0400, rdev->dbg_root, rdev, &info_fops); 368 } 369 370 static ssize_t cq_coal_cfg_write(struct file *file, 371 const char __user *buf, 372 size_t count, loff_t *pos) 373 { 374 struct seq_file *s = file->private_data; 375 struct bnxt_re_cq_coal_param *param = s->private; 376 struct bnxt_re_dev *rdev = param->rdev; 377 int offset = param->offset; 378 char lbuf[16] = { }; 379 u32 val; 380 381 if (count > sizeof(lbuf)) 382 return -EINVAL; 383 384 if (copy_from_user(lbuf, buf, count)) 385 return -EFAULT; 386 387 lbuf[sizeof(lbuf) - 1] = '\0'; 388 389 if (kstrtou32(lbuf, 0, &val)) 390 return -EINVAL; 391 392 switch (offset) { 393 case BNXT_RE_COAL_CQ_BUF_MAXTIME: 394 if (val < 1 || val > BNXT_QPLIB_CQ_COAL_MAX_BUF_MAXTIME) 395 return -EINVAL; 396 rdev->cq_coalescing.buf_maxtime = val; 397 break; 398 case BNXT_RE_COAL_CQ_NORMAL_MAXBUF: 399 if (val < 1 || val > BNXT_QPLIB_CQ_COAL_MAX_NORMAL_MAXBUF) 400 return -EINVAL; 401 rdev->cq_coalescing.normal_maxbuf = val; 402 break; 403 case BNXT_RE_COAL_CQ_DURING_MAXBUF: 404 if (val < 1 || val > BNXT_QPLIB_CQ_COAL_MAX_DURING_MAXBUF) 405 return -EINVAL; 406 rdev->cq_coalescing.during_maxbuf = val; 407 break; 408 case BNXT_RE_COAL_CQ_EN_RING_IDLE_MODE: 409 if (val > BNXT_QPLIB_CQ_COAL_MAX_EN_RING_IDLE_MODE) 410 return -EINVAL; 411 rdev->cq_coalescing.en_ring_idle_mode = val; 412 break; 413 case BNXT_RE_COAL_CQ_ENABLE: 414 if (val > 1) 415 return -EINVAL; 416 rdev->cq_coalescing.enable = val; 417 break; 418 default: 419 return -EINVAL; 420 } 421 return count; 422 } 423 424 static int cq_coal_cfg_show(struct seq_file *s, void *unused) 425 { 426 struct bnxt_re_cq_coal_param *param = s->private; 427 struct bnxt_re_dev *rdev = param->rdev; 428 int offset = param->offset; 429 u32 val = 0; 430 431 switch (offset) { 432 case BNXT_RE_COAL_CQ_BUF_MAXTIME: 433 val = rdev->cq_coalescing.buf_maxtime; 434 break; 435 case BNXT_RE_COAL_CQ_NORMAL_MAXBUF: 436 val = rdev->cq_coalescing.normal_maxbuf; 437 break; 438 case BNXT_RE_COAL_CQ_DURING_MAXBUF: 439 val = rdev->cq_coalescing.during_maxbuf; 440 break; 441 case BNXT_RE_COAL_CQ_EN_RING_IDLE_MODE: 442 val = rdev->cq_coalescing.en_ring_idle_mode; 443 break; 444 case BNXT_RE_COAL_CQ_ENABLE: 445 val = rdev->cq_coalescing.enable; 446 break; 447 default: 448 return -EINVAL; 449 } 450 451 seq_printf(s, "%u\n", val); 452 return 0; 453 } 454 DEFINE_SHOW_STORE_ATTRIBUTE(cq_coal_cfg); 455 456 static void bnxt_re_cleanup_cq_coal_debugfs(struct bnxt_re_dev *rdev) 457 { 458 debugfs_remove_recursive(rdev->cq_coal_cfg); 459 kfree(rdev->cq_coal_cfg_params); 460 } 461 462 static void bnxt_re_init_cq_coal_debugfs(struct bnxt_re_dev *rdev) 463 { 464 struct bnxt_re_dbg_cq_coal_params *dbg_cq_coal_params; 465 int i; 466 467 if (!_is_cq_coalescing_supported(rdev->dev_attr->dev_cap_flags2)) 468 return; 469 470 dbg_cq_coal_params = kzalloc_obj(*dbg_cq_coal_params); 471 if (!dbg_cq_coal_params) 472 return; 473 474 rdev->cq_coal_cfg = debugfs_create_dir("cq_coal_cfg", rdev->dbg_root); 475 rdev->cq_coal_cfg_params = dbg_cq_coal_params; 476 477 for (i = 0; i < BNXT_RE_COAL_CQ_MAX; i++) { 478 dbg_cq_coal_params->params[i].offset = i; 479 dbg_cq_coal_params->params[i].rdev = rdev; 480 debugfs_create_file(bnxt_re_cq_coal_str[i], 481 0600, rdev->cq_coal_cfg, 482 &dbg_cq_coal_params->params[i], 483 &cq_coal_cfg_fops); 484 } 485 } 486 487 void bnxt_re_debugfs_add_pdev(struct bnxt_re_dev *rdev) 488 { 489 struct pci_dev *pdev = rdev->en_dev->pdev; 490 struct bnxt_re_dbg_cc_config_params *cc_params; 491 int i; 492 493 rdev->dbg_root = debugfs_create_dir(dev_name(&pdev->dev), bnxt_re_debugfs_root); 494 495 rdev->qp_debugfs = debugfs_create_dir("QPs", rdev->dbg_root); 496 rdev->cc_config = debugfs_create_dir("cc_config", rdev->dbg_root); 497 498 bnxt_re_debugfs_add_info(rdev); 499 500 rdev->cc_config_params = kzalloc_obj(*cc_params); 501 502 for (i = 0; i < BNXT_RE_CC_PARAM_GEN0; i++) { 503 struct bnxt_re_cc_param *tmp_params = &rdev->cc_config_params->gen0_parms[i]; 504 505 tmp_params->rdev = rdev; 506 tmp_params->offset = i; 507 tmp_params->cc_gen = CC_CONFIG_GEN0_EXT0; 508 tmp_params->dentry = debugfs_create_file(bnxt_re_cc_gen0_name[i], 0400, 509 rdev->cc_config, tmp_params, 510 &bnxt_re_cc_config_ops); 511 } 512 513 bnxt_re_init_cq_coal_debugfs(rdev); 514 } 515 516 void bnxt_re_debugfs_rem_pdev(struct bnxt_re_dev *rdev) 517 { 518 bnxt_re_cleanup_cq_coal_debugfs(rdev); 519 debugfs_remove_recursive(rdev->qp_debugfs); 520 debugfs_remove_recursive(rdev->cc_config); 521 kfree(rdev->cc_config_params); 522 debugfs_remove_recursive(rdev->dbg_root); 523 rdev->dbg_root = NULL; 524 } 525 526 void bnxt_re_register_debugfs(void) 527 { 528 bnxt_re_debugfs_root = debugfs_create_dir("bnxt_re", NULL); 529 } 530 531 void bnxt_re_unregister_debugfs(void) 532 { 533 debugfs_remove(bnxt_re_debugfs_root); 534 } 535