FILE
debugfs.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c
1/* 2 * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 */ 32 33#include <linux/debugfs.h> 34#include <linux/mlx5/qp.h> 35#include <linux/mlx5/cq.h> 36#include <linux/mlx5/driver.h> 37#include "mlx5_core.h" 38#include "lib/eq.h" 39 40enum { 41 QP_PID, 42 QP_STATE, 43 QP_XPORT, 44 QP_MTU, 45 QP_N_RECV, 46 QP_RECV_SZ, 47 QP_N_SEND, 48 QP_LOG_PG_SZ, 49 QP_RQPN, 50}; 51 52static char *qp_fields[] = { 53 [QP_PID] = "pid", 54 [QP_STATE] = "state", 55 [QP_XPORT] = "transport", 56 [QP_MTU] = "mtu", 57 [QP_N_RECV] = "num_recv", 58 [QP_RECV_SZ] = "rcv_wqe_sz", 59 [QP_N_SEND] = "num_send", 60 [QP_LOG_PG_SZ] = "log2_page_sz", 61 [QP_RQPN] = "remote_qpn", 62}; 63 64enum { 65 EQ_NUM_EQES, 66 EQ_INTR, 67 EQ_LOG_PG_SZ, 68}; 69 70static char *eq_fields[] = { 71 [EQ_NUM_EQES] = "num_eqes", 72 [EQ_INTR] = "intr", 73 [EQ_LOG_PG_SZ] = "log_page_size", 74}; 75 76enum { 77 CQ_PID, 78 CQ_NUM_CQES, 79 CQ_LOG_PG_SZ, 80}; 81 82static char *cq_fields[] = { 83 [CQ_PID] = "pid", 84 [CQ_NUM_CQES] = "num_cqes", 85 [CQ_LOG_PG_SZ] = "log_page_size", 86}; 87 88struct dentry *mlx5_debugfs_root; 89EXPORT_SYMBOL(mlx5_debugfs_root); 90 91void mlx5_register_debugfs(void) 92{ 93 mlx5_debugfs_root = debugfs_create_dir("mlx5", NULL); 94} 95 96void mlx5_unregister_debugfs(void) 97{ 98 debugfs_remove(mlx5_debugfs_root); 99} 100 101struct dentry *mlx5_debugfs_get_dev_root(struct mlx5_core_dev *dev) 102{ 103 return dev->priv.dbg.dbg_root; 104} 105EXPORT_SYMBOL(mlx5_debugfs_get_dev_root); 106 107void mlx5_qp_debugfs_init(struct mlx5_core_dev *dev) 108{ 109 dev->priv.dbg.qp_debugfs = debugfs_create_dir("QPs", dev->priv.dbg.dbg_root); 110} 111EXPORT_SYMBOL(mlx5_qp_debugfs_init); 112 113void mlx5_qp_debugfs_cleanup(struct mlx5_core_dev *dev) 114{ 115 debugfs_remove_recursive(dev->priv.dbg.qp_debugfs); 116} 117EXPORT_SYMBOL(mlx5_qp_debugfs_cleanup); 118 119void mlx5_eq_debugfs_init(struct mlx5_core_dev *dev) 120{ 121 dev->priv.dbg.eq_debugfs = debugfs_create_dir("EQs", dev->priv.dbg.dbg_root); 122} 123 124void mlx5_eq_debugfs_cleanup(struct mlx5_core_dev *dev) 125{ 126 debugfs_remove_recursive(dev->priv.dbg.eq_debugfs); 127} 128 129static ssize_t average_read(struct file *filp, char __user *buf, size_t count, 130 loff_t *pos) 131{ 132 struct mlx5_cmd_stats *stats; 133 u64 field = 0; 134 int ret; 135 char tbuf[22]; 136 137 stats = filp->private_data; 138 spin_lock_irq(&stats->lock); 139 if (stats->n) 140 field = div64_u64(stats->sum, stats->n); 141 spin_unlock_irq(&stats->lock); 142 ret = snprintf(tbuf, sizeof(tbuf), "%llu\n", field); 143 return simple_read_from_buffer(buf, count, pos, tbuf, ret); 144} 145 146static ssize_t reset_write(struct file *filp, const char __user *buf, 147 size_t count, loff_t *pos) 148{ 149 struct mlx5_cmd_stats *stats; 150 151 stats = filp->private_data; 152 spin_lock_irq(&stats->lock); 153 stats->sum = 0; 154 stats->n = 0; 155 stats->failed = 0; 156 stats->failed_mbox_status = 0; 157 stats->last_failed_errno = 0; 158 stats->last_failed_mbox_status = 0; 159 stats->last_failed_syndrome = 0; 160 spin_unlock_irq(&stats->lock); 161 162 *pos += count; 163 164 return count; 165} 166 167static const struct file_operations reset_fops = { 168 .owner = THIS_MODULE, 169 .open = simple_open, 170 .write = reset_write, 171}; 172 173static const struct file_operations average_fops = { 174 .owner = THIS_MODULE, 175 .open = simple_open, 176 .read = average_read, 177}; 178 179static ssize_t slots_read(struct file *filp, char __user *buf, size_t count, 180 loff_t *pos) 181{ 182 struct mlx5_cmd *cmd; 183 char tbuf[6]; 184 int weight; 185 int field; 186 int ret; 187 188 cmd = filp->private_data; 189 weight = bitmap_weight(&cmd->vars.bitmask, cmd->vars.max_reg_cmds); 190 field = cmd->vars.max_reg_cmds - weight; 191 ret = snprintf(tbuf, sizeof(tbuf), "%d\n", field); 192 return simple_read_from_buffer(buf, count, pos, tbuf, ret); 193} 194 195static const struct file_operations slots_fops = { 196 .owner = THIS_MODULE, 197 .open = simple_open, 198 .read = slots_read, 199}; 200 201static struct mlx5_cmd_stats * 202mlx5_cmdif_alloc_stats(struct xarray *stats_xa, int opcode) 203{ 204 struct mlx5_cmd_stats *stats = kzalloc(sizeof(*stats), GFP_KERNEL); 205 int err; 206 207 if (!stats) 208 return NULL; 209 210 err = xa_insert(stats_xa, opcode, stats, GFP_KERNEL); 211 if (err) { 212 kfree(stats); 213 return NULL; 214 } 215 spin_lock_init(&stats->lock); 216 return stats; 217} 218 219void mlx5_cmdif_debugfs_init(struct mlx5_core_dev *dev) 220{ 221 struct mlx5_cmd_stats *stats; 222 struct dentry **cmd; 223 const char *namep; 224 int i; 225 226 cmd = &dev->priv.dbg.cmdif_debugfs; 227 *cmd = debugfs_create_dir("commands", dev->priv.dbg.dbg_root); 228 229 debugfs_create_file("slots_inuse", 0400, *cmd, &dev->cmd, &slots_fops); 230 231 xa_init(&dev->cmd.stats); 232 233 for (i = 0; i < MLX5_CMD_OP_MAX; i++) { 234 namep = mlx5_command_str(i); 235 if (strcmp(namep, "unknown command opcode")) { 236 stats = mlx5_cmdif_alloc_stats(&dev->cmd.stats, i); 237 if (!stats) 238 continue; 239 stats->root = debugfs_create_dir(namep, *cmd); 240 241 debugfs_create_file("reset", 0200, stats->root, stats, 242 &reset_fops); 243 debugfs_create_file("average", 0400, stats->root, stats, 244 &average_fops); 245 debugfs_create_u64("n", 0400, stats->root, &stats->n); 246 debugfs_create_u64("failed", 0400, stats->root, &stats->failed); 247 debugfs_create_u64("failed_mbox_status", 0400, stats->root, 248 &stats->failed_mbox_status); 249 debugfs_create_u32("last_failed_errno", 0400, stats->root, 250 &stats->last_failed_errno); 251 debugfs_create_u8("last_failed_mbox_status", 0400, stats->root, 252 &stats->last_failed_mbox_status); 253 debugfs_create_x32("last_failed_syndrome", 0400, stats->root, 254 &stats->last_failed_syndrome); 255 } 256 } 257} 258 259void mlx5_cmdif_debugfs_cleanup(struct mlx5_core_dev *dev) 260{ 261 struct mlx5_cmd_stats *stats; 262 unsigned long i; 263 264 debugfs_remove_recursive(dev->priv.dbg.cmdif_debugfs); 265 xa_for_each(&dev->cmd.stats, i, stats) 266 kfree(stats); 267 xa_destroy(&dev->cmd.stats); 268} 269 270void mlx5_cq_debugfs_init(struct mlx5_core_dev *dev) 271{ 272 dev->priv.dbg.cq_debugfs = debugfs_create_dir("CQs", dev->priv.dbg.dbg_root); 273} 274 275void mlx5_cq_debugfs_cleanup(struct mlx5_core_dev *dev) 276{ 277 debugfs_remove_recursive(dev->priv.dbg.cq_debugfs); 278} 279 280void mlx5_pages_debugfs_init(struct mlx5_core_dev *dev) 281{ 282 struct dentry *pages; 283 284 dev->priv.dbg.pages_debugfs = debugfs_create_dir("pages", dev->priv.dbg.dbg_root); 285 pages = dev->priv.dbg.pages_debugfs; 286 287 debugfs_create_u32("fw_pages_total", 0400, pages, &dev->priv.fw_pages); 288 debugfs_create_u32("fw_pages_vfs", 0400, pages, &dev->priv.page_counters[MLX5_VF]); 289 debugfs_create_u32("fw_pages_ec_vfs", 0400, pages, &dev->priv.page_counters[MLX5_EC_VF]); 290 debugfs_create_u32("fw_pages_sfs", 0400, pages, &dev->priv.page_counters[MLX5_SF]); 291 debugfs_create_u32("fw_pages_host_pf", 0400, pages, &dev->priv.page_counters[MLX5_HOST_PF]); 292 debugfs_create_u32("fw_pages_alloc_failed", 0400, pages, &dev->priv.fw_pages_alloc_failed); 293 debugfs_create_u32("fw_pages_give_dropped", 0400, pages, &dev->priv.give_pages_dropped); 294 debugfs_create_u32("fw_pages_reclaim_discard", 0400, pages, 295 &dev->priv.reclaim_pages_discard); 296} 297 298void mlx5_pages_debugfs_cleanup(struct mlx5_core_dev *dev) 299{ 300 debugfs_remove_recursive(dev->priv.dbg.pages_debugfs); 301} 302 303static u64 qp_read_field(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp, 304 int index, int *is_str) 305{ 306 int outlen = MLX5_ST_SZ_BYTES(query_qp_out); 307 u32 in[MLX5_ST_SZ_DW(query_qp_in)] = {}; 308 u64 param = 0; 309 u32 *out; 310 int state; 311 u32 *qpc; 312 int err; 313 314 out = kzalloc(outlen, GFP_KERNEL); 315 if (!out) 316 return 0; 317 318 MLX5_SET(query_qp_in, in, opcode, MLX5_CMD_OP_QUERY_QP); 319 MLX5_SET(query_qp_in, in, qpn, qp->qpn); 320 err = mlx5_cmd_exec_inout(dev, query_qp, in, out); 321 if (err) 322 goto out; 323 324 *is_str = 0; 325 326 qpc = MLX5_ADDR_OF(query_qp_out, out, qpc); 327 switch (index) { 328 case QP_PID: 329 param = qp->pid; 330 break; 331 case QP_STATE: 332 state = MLX5_GET(qpc, qpc, state); 333 param = (unsigned long)mlx5_qp_state_str(state); 334 *is_str = 1; 335 break; 336 case QP_XPORT: 337 param = (unsigned long)mlx5_qp_type_str(MLX5_GET(qpc, qpc, st)); 338 *is_str = 1; 339 break; 340 case QP_MTU: 341 switch (MLX5_GET(qpc, qpc, mtu)) { 342 case IB_MTU_256: 343 param = 256; 344 break; 345 case IB_MTU_512: 346 param = 512; 347 break; 348 case IB_MTU_1024: 349 param = 1024; 350 break; 351 case IB_MTU_2048: 352 param = 2048; 353 break; 354 case IB_MTU_4096: 355 param = 4096; 356 break; 357 default: 358 param = 0; 359 } 360 break; 361 case QP_N_RECV: 362 param = 1 << MLX5_GET(qpc, qpc, log_rq_size); 363 break; 364 case QP_RECV_SZ: 365 param = 1 << (MLX5_GET(qpc, qpc, log_rq_stride) + 4); 366 break; 367 case QP_N_SEND: 368 if (!MLX5_GET(qpc, qpc, no_sq)) 369 param = 1 << MLX5_GET(qpc, qpc, log_sq_size); 370 break; 371 case QP_LOG_PG_SZ: 372 param = MLX5_GET(qpc, qpc, log_page_size) + 12; 373 break; 374 case QP_RQPN: 375 param = MLX5_GET(qpc, qpc, remote_qpn); 376 break; 377 } 378out: 379 kfree(out); 380 return param; 381} 382 383static u64 eq_read_field(struct mlx5_core_dev *dev, struct mlx5_eq *eq, 384 int index) 385{ 386 int outlen = MLX5_ST_SZ_BYTES(query_eq_out); 387 u32 in[MLX5_ST_SZ_DW(query_eq_in)] = {}; 388 u64 param = 0; 389 void *ctx; 390 u32 *out; 391 int err; 392 393 out = kzalloc(outlen, GFP_KERNEL); 394 if (!out) 395 return param; 396 397 MLX5_SET(query_eq_in, in, opcode, MLX5_CMD_OP_QUERY_EQ); 398 MLX5_SET(query_eq_in, in, eq_number, eq->eqn); 399 err = mlx5_cmd_exec_inout(dev, query_eq, in, out); 400 if (err) { 401 mlx5_core_warn(dev, "failed to query eq\n"); 402 goto out; 403 } 404 ctx = MLX5_ADDR_OF(query_eq_out, out, eq_context_entry); 405 406 switch (index) { 407 case EQ_NUM_EQES: 408 param = 1 << MLX5_GET(eqc, ctx, log_eq_size); 409 break; 410 case EQ_INTR: 411 param = MLX5_GET(eqc, ctx, intr); 412 break; 413 case EQ_LOG_PG_SZ: 414 param = MLX5_GET(eqc, ctx, log_page_size) + 12; 415 break; 416 } 417 418out: 419 kfree(out); 420 return param; 421} 422 423static u64 cq_read_field(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, 424 int index) 425{ 426 int outlen = MLX5_ST_SZ_BYTES(query_cq_out); 427 u64 param = 0; 428 void *ctx; 429 u32 *out; 430 int err; 431 432 out = kvzalloc(outlen, GFP_KERNEL); 433 if (!out) 434 return param; 435 436 err = mlx5_core_query_cq(dev, cq, out); 437 if (err) { 438 mlx5_core_warn(dev, "failed to query cq\n"); 439 goto out; 440 } 441 ctx = MLX5_ADDR_OF(query_cq_out, out, cq_context); 442 443 switch (index) { 444 case CQ_PID: 445 param = cq->pid; 446 break; 447 case CQ_NUM_CQES: 448 param = 1 << MLX5_GET(cqc, ctx, log_cq_size); 449 break; 450 case CQ_LOG_PG_SZ: 451 param = MLX5_GET(cqc, ctx, log_page_size); 452 break; 453 } 454 455out: 456 kvfree(out); 457 return param; 458} 459 460static ssize_t dbg_read(struct file *filp, char __user *buf, size_t count, 461 loff_t *pos) 462{ 463 struct mlx5_field_desc *desc; 464 struct mlx5_rsc_debug *d; 465 char tbuf[18]; 466 int is_str = 0; 467 u64 field; 468 int ret; 469 470 desc = filp->private_data; 471 d = (void *)(desc - desc->i) - sizeof(*d); 472 switch (d->type) { 473 case MLX5_DBG_RSC_QP: 474 field = qp_read_field(d->dev, d->object, desc->i, &is_str); 475 break; 476 477 case MLX5_DBG_RSC_EQ: 478 field = eq_read_field(d->dev, d->object, desc->i); 479 break; 480 481 case MLX5_DBG_RSC_CQ: 482 field = cq_read_field(d->dev, d->object, desc->i); 483 break; 484 485 default: 486 mlx5_core_warn(d->dev, "invalid resource type %d\n", d->type); 487 return -EINVAL; 488 } 489 490 if (is_str) 491 ret = snprintf(tbuf, sizeof(tbuf), "%s\n", (const char *)(unsigned long)field); 492 else 493 ret = snprintf(tbuf, sizeof(tbuf), "0x%llx\n", field); 494 495 return simple_read_from_buffer(buf, count, pos, tbuf, ret); 496} 497 498static const struct file_operations fops = { 499 .owner = THIS_MODULE, 500 .open = simple_open, 501 .read = dbg_read, 502}; 503 504static int add_res_tree(struct mlx5_core_dev *dev, enum dbg_rsc_type type, 505 struct dentry *root, struct mlx5_rsc_debug **dbg, 506 int rsn, char **field, int nfile, void *data) 507{ 508 struct mlx5_rsc_debug *d; 509 char resn[32]; 510 int i; 511 512 d = kzalloc(struct_size(d, fields, nfile), GFP_KERNEL); 513 if (!d) 514 return -ENOMEM; 515 516 d->dev = dev; 517 d->object = data; 518 d->type = type; 519 sprintf(resn, "0x%x", rsn); 520 d->root = debugfs_create_dir(resn, root); 521 522 for (i = 0; i < nfile; i++) { 523 d->fields[i].i = i; 524 debugfs_create_file(field[i], 0400, d->root, &d->fields[i], 525 &fops); 526 } 527 *dbg = d; 528 529 return 0; 530} 531 532static void rem_res_tree(struct mlx5_rsc_debug *d) 533{ 534 debugfs_remove_recursive(d->root); 535 kfree(d); 536} 537 538int mlx5_debug_qp_add(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp) 539{ 540 int err; 541 542 if (!mlx5_debugfs_root) 543 return 0; 544 545 err = add_res_tree(dev, MLX5_DBG_RSC_QP, dev->priv.dbg.qp_debugfs, 546 &qp->dbg, qp->qpn, qp_fields, 547 ARRAY_SIZE(qp_fields), qp); 548 if (err) 549 qp->dbg = NULL; 550 551 return err; 552} 553EXPORT_SYMBOL(mlx5_debug_qp_add); 554 555void mlx5_debug_qp_remove(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp) 556{ 557 if (!mlx5_debugfs_root || !qp->dbg) 558 return; 559 560 rem_res_tree(qp->dbg); 561 qp->dbg = NULL; 562} 563EXPORT_SYMBOL(mlx5_debug_qp_remove); 564 565int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq) 566{ 567 int err; 568 569 if (!mlx5_debugfs_root) 570 return 0; 571 572 err = add_res_tree(dev, MLX5_DBG_RSC_EQ, dev->priv.dbg.eq_debugfs, 573 &eq->dbg, eq->eqn, eq_fields, 574 ARRAY_SIZE(eq_fields), eq); 575 if (err) 576 eq->dbg = NULL; 577 578 return err; 579} 580 581void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq) 582{ 583 if (!mlx5_debugfs_root) 584 return; 585 586 if (eq->dbg) 587 rem_res_tree(eq->dbg); 588} 589 590int mlx5_debug_cq_add(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq) 591{ 592 int err; 593 594 if (!mlx5_debugfs_root) 595 return 0; 596 597 err = add_res_tree(dev, MLX5_DBG_RSC_CQ, dev->priv.dbg.cq_debugfs, 598 &cq->dbg, cq->cqn, cq_fields, 599 ARRAY_SIZE(cq_fields), cq); 600 if (err) 601 cq->dbg = NULL; 602 603 return err; 604} 605 606void mlx5_debug_cq_remove(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq) 607{ 608 if (!mlx5_debugfs_root) 609 return; 610 611 if (cq->dbg) { 612 rem_res_tree(cq->dbg); 613 cq->dbg = NULL; 614 } 615} 616 617static int vhca_id_show(struct seq_file *file, void *priv) 618{ 619 struct mlx5_core_dev *dev = file->private; 620 621 seq_printf(file, "0x%x\n", MLX5_CAP_GEN(dev, vhca_id)); 622 return 0; 623} 624 625DEFINE_SHOW_ATTRIBUTE(vhca_id); 626 627void mlx5_vhca_debugfs_init(struct mlx5_core_dev *dev) 628{ 629 debugfs_create_file("vhca_id", 0400, dev->priv.dbg.dbg_root, dev, 630 &vhca_id_fops); 631}
~/
Read-only file preview.