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 40 enum { 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 52 static 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 64 enum { 65 EQ_NUM_EQES, 66 EQ_INTR, 67 EQ_LOG_PG_SZ, 68 }; 69 70 static char *eq_fields[] = { 71 [EQ_NUM_EQES] = "num_eqes", 72 [EQ_INTR] = "intr", 73 [EQ_LOG_PG_SZ] = "log_page_size", 74 }; 75 76 enum { 77 CQ_PID, 78 CQ_NUM_CQES, 79 CQ_LOG_PG_SZ, 80 }; 81 82 static char *cq_fields[] = { 83 [CQ_PID] = "pid", 84 [CQ_NUM_CQES] = "num_cqes", 85 [CQ_LOG_PG_SZ] = "log_page_size", 86 }; 87 88 struct dentry *mlx5_debugfs_root; 89 EXPORT_SYMBOL(mlx5_debugfs_root); 90 91 void mlx5_register_debugfs(void) 92 { 93 mlx5_debugfs_root = debugfs_create_dir("mlx5", NULL); 94 } 95 96 void mlx5_unregister_debugfs(void) 97 { 98 debugfs_remove(mlx5_debugfs_root); 99 } 100 101 struct dentry *mlx5_debugfs_get_dev_root(struct mlx5_core_dev *dev) 102 { 103 return dev->priv.dbg.dbg_root; 104 } 105 EXPORT_SYMBOL(mlx5_debugfs_get_dev_root); 106 107 void 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 } 111 EXPORT_SYMBOL(mlx5_qp_debugfs_init); 112 113 void mlx5_qp_debugfs_cleanup(struct mlx5_core_dev *dev) 114 { 115 debugfs_remove_recursive(dev->priv.dbg.qp_debugfs); 116 } 117 EXPORT_SYMBOL(mlx5_qp_debugfs_cleanup); 118 119 void 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 124 void mlx5_eq_debugfs_cleanup(struct mlx5_core_dev *dev) 125 { 126 debugfs_remove_recursive(dev->priv.dbg.eq_debugfs); 127 } 128 129 static 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 146 static 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 167 static const struct file_operations reset_fops = { 168 .owner = THIS_MODULE, 169 .open = simple_open, 170 .write = reset_write, 171 }; 172 173 static const struct file_operations average_fops = { 174 .owner = THIS_MODULE, 175 .open = simple_open, 176 .read = average_read, 177 }; 178 179 static 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 195 static const struct file_operations slots_fops = { 196 .owner = THIS_MODULE, 197 .open = simple_open, 198 .read = slots_read, 199 }; 200 201 static struct mlx5_cmd_stats * 202 mlx5_cmdif_alloc_stats(struct xarray *stats_xa, int opcode) 203 { 204 struct mlx5_cmd_stats *stats = kzalloc_obj(*stats); 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 219 void 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 259 void 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 270 void 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 275 void mlx5_cq_debugfs_cleanup(struct mlx5_core_dev *dev) 276 { 277 debugfs_remove_recursive(dev->priv.dbg.cq_debugfs); 278 } 279 280 void 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_alloc_failed", 0400, pages, &dev->priv.fw_pages_alloc_failed); 289 debugfs_create_u32("fw_pages_give_dropped", 0400, pages, &dev->priv.give_pages_dropped); 290 debugfs_create_u32("fw_pages_reclaim_discard", 0400, pages, 291 &dev->priv.reclaim_pages_discard); 292 } 293 294 void mlx5_pages_debugfs_cleanup(struct mlx5_core_dev *dev) 295 { 296 debugfs_remove_recursive(dev->priv.dbg.pages_debugfs); 297 } 298 299 void mlx5_pages_by_func_type_debugfs_init(struct mlx5_core_dev *dev) 300 { 301 struct dentry *pages = dev->priv.dbg.pages_debugfs; 302 303 if (!pages) 304 return; 305 306 if (!dev->priv.eswitch && 307 MLX5_CAP_GEN(dev, icm_mng_function_id_mode) == 308 MLX5_ID_MODE_FUNCTION_VHCA_ID) 309 return; 310 311 debugfs_create_u32("fw_pages_vfs", 0400, pages, 312 &dev->priv.page_counters[MLX5_VF]); 313 debugfs_create_u32("fw_pages_ec_vfs", 0400, pages, 314 &dev->priv.page_counters[MLX5_EC_VF]); 315 debugfs_create_u32("fw_pages_sfs", 0400, pages, 316 &dev->priv.page_counters[MLX5_SF]); 317 debugfs_create_u32("fw_pages_host_pf", 0400, pages, 318 &dev->priv.page_counters[MLX5_HOST_PF]); 319 debugfs_create_u32("fw_pages_spfs", 0400, pages, 320 &dev->priv.page_counters[MLX5_SPF]); 321 } 322 323 void mlx5_pages_by_func_type_debugfs_cleanup(struct mlx5_core_dev *dev) 324 { 325 struct dentry *pages = dev->priv.dbg.pages_debugfs; 326 327 if (!pages) 328 return; 329 330 debugfs_lookup_and_remove("fw_pages_vfs", pages); 331 debugfs_lookup_and_remove("fw_pages_ec_vfs", pages); 332 debugfs_lookup_and_remove("fw_pages_sfs", pages); 333 debugfs_lookup_and_remove("fw_pages_host_pf", pages); 334 debugfs_lookup_and_remove("fw_pages_spfs", pages); 335 } 336 337 static u64 qp_read_field(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp, 338 int index, int *is_str) 339 { 340 int outlen = MLX5_ST_SZ_BYTES(query_qp_out); 341 u32 in[MLX5_ST_SZ_DW(query_qp_in)] = {}; 342 u64 param = 0; 343 u32 *out; 344 int state; 345 u32 *qpc; 346 int err; 347 348 out = kzalloc(outlen, GFP_KERNEL); 349 if (!out) 350 return 0; 351 352 MLX5_SET(query_qp_in, in, opcode, MLX5_CMD_OP_QUERY_QP); 353 MLX5_SET(query_qp_in, in, qpn, qp->qpn); 354 err = mlx5_cmd_exec_inout(dev, query_qp, in, out); 355 if (err) 356 goto out; 357 358 *is_str = 0; 359 360 qpc = MLX5_ADDR_OF(query_qp_out, out, qpc); 361 switch (index) { 362 case QP_PID: 363 param = qp->pid; 364 break; 365 case QP_STATE: 366 state = MLX5_GET(qpc, qpc, state); 367 param = (unsigned long)mlx5_qp_state_str(state); 368 *is_str = 1; 369 break; 370 case QP_XPORT: 371 param = (unsigned long)mlx5_qp_type_str(MLX5_GET(qpc, qpc, st)); 372 *is_str = 1; 373 break; 374 case QP_MTU: 375 switch (MLX5_GET(qpc, qpc, mtu)) { 376 case IB_MTU_256: 377 param = 256; 378 break; 379 case IB_MTU_512: 380 param = 512; 381 break; 382 case IB_MTU_1024: 383 param = 1024; 384 break; 385 case IB_MTU_2048: 386 param = 2048; 387 break; 388 case IB_MTU_4096: 389 param = 4096; 390 break; 391 default: 392 param = 0; 393 } 394 break; 395 case QP_N_RECV: 396 param = 1 << MLX5_GET(qpc, qpc, log_rq_size); 397 break; 398 case QP_RECV_SZ: 399 param = 1 << (MLX5_GET(qpc, qpc, log_rq_stride) + 4); 400 break; 401 case QP_N_SEND: 402 if (!MLX5_GET(qpc, qpc, no_sq)) 403 param = 1 << MLX5_GET(qpc, qpc, log_sq_size); 404 break; 405 case QP_LOG_PG_SZ: 406 param = MLX5_GET(qpc, qpc, log_page_size) + 12; 407 break; 408 case QP_RQPN: 409 param = MLX5_GET(qpc, qpc, remote_qpn); 410 break; 411 } 412 out: 413 kfree(out); 414 return param; 415 } 416 417 static u64 eq_read_field(struct mlx5_core_dev *dev, struct mlx5_eq *eq, 418 int index) 419 { 420 int outlen = MLX5_ST_SZ_BYTES(query_eq_out); 421 u32 in[MLX5_ST_SZ_DW(query_eq_in)] = {}; 422 u64 param = 0; 423 void *ctx; 424 u32 *out; 425 int err; 426 427 out = kzalloc(outlen, GFP_KERNEL); 428 if (!out) 429 return param; 430 431 MLX5_SET(query_eq_in, in, opcode, MLX5_CMD_OP_QUERY_EQ); 432 MLX5_SET(query_eq_in, in, eq_number, eq->eqn); 433 err = mlx5_cmd_exec_inout(dev, query_eq, in, out); 434 if (err) { 435 mlx5_core_warn(dev, "failed to query eq\n"); 436 goto out; 437 } 438 ctx = MLX5_ADDR_OF(query_eq_out, out, eq_context_entry); 439 440 switch (index) { 441 case EQ_NUM_EQES: 442 param = 1 << MLX5_GET(eqc, ctx, log_eq_size); 443 break; 444 case EQ_INTR: 445 param = MLX5_GET(eqc, ctx, intr); 446 break; 447 case EQ_LOG_PG_SZ: 448 param = MLX5_GET(eqc, ctx, log_page_size) + 12; 449 break; 450 } 451 452 out: 453 kfree(out); 454 return param; 455 } 456 457 static u64 cq_read_field(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, 458 int index) 459 { 460 int outlen = MLX5_ST_SZ_BYTES(query_cq_out); 461 u64 param = 0; 462 void *ctx; 463 u32 *out; 464 int err; 465 466 out = kvzalloc(outlen, GFP_KERNEL); 467 if (!out) 468 return param; 469 470 err = mlx5_core_query_cq(dev, cq, out); 471 if (err) { 472 mlx5_core_warn(dev, "failed to query cq\n"); 473 goto out; 474 } 475 ctx = MLX5_ADDR_OF(query_cq_out, out, cq_context); 476 477 switch (index) { 478 case CQ_PID: 479 param = cq->pid; 480 break; 481 case CQ_NUM_CQES: 482 param = 1 << MLX5_GET(cqc, ctx, log_cq_size); 483 break; 484 case CQ_LOG_PG_SZ: 485 param = MLX5_GET(cqc, ctx, log_page_size); 486 break; 487 } 488 489 out: 490 kvfree(out); 491 return param; 492 } 493 494 static ssize_t dbg_read(struct file *filp, char __user *buf, size_t count, 495 loff_t *pos) 496 { 497 struct mlx5_field_desc *desc; 498 struct mlx5_rsc_debug *d; 499 char tbuf[18]; 500 int is_str = 0; 501 u64 field; 502 int ret; 503 504 desc = filp->private_data; 505 d = (void *)(desc - desc->i) - sizeof(*d); 506 switch (d->type) { 507 case MLX5_DBG_RSC_QP: 508 field = qp_read_field(d->dev, d->object, desc->i, &is_str); 509 break; 510 511 case MLX5_DBG_RSC_EQ: 512 field = eq_read_field(d->dev, d->object, desc->i); 513 break; 514 515 case MLX5_DBG_RSC_CQ: 516 field = cq_read_field(d->dev, d->object, desc->i); 517 break; 518 519 default: 520 mlx5_core_warn(d->dev, "invalid resource type %d\n", d->type); 521 return -EINVAL; 522 } 523 524 if (is_str) 525 ret = snprintf(tbuf, sizeof(tbuf), "%s\n", (const char *)(unsigned long)field); 526 else 527 ret = snprintf(tbuf, sizeof(tbuf), "0x%llx\n", field); 528 529 return simple_read_from_buffer(buf, count, pos, tbuf, ret); 530 } 531 532 static const struct file_operations fops = { 533 .owner = THIS_MODULE, 534 .open = simple_open, 535 .read = dbg_read, 536 }; 537 538 static int add_res_tree(struct mlx5_core_dev *dev, enum dbg_rsc_type type, 539 struct dentry *root, struct mlx5_rsc_debug **dbg, 540 int rsn, char **field, int nfile, void *data) 541 { 542 struct mlx5_rsc_debug *d; 543 char resn[32]; 544 int i; 545 546 d = kzalloc_flex(*d, fields, nfile); 547 if (!d) 548 return -ENOMEM; 549 550 d->dev = dev; 551 d->object = data; 552 d->type = type; 553 sprintf(resn, "0x%x", rsn); 554 d->root = debugfs_create_dir(resn, root); 555 556 for (i = 0; i < nfile; i++) { 557 d->fields[i].i = i; 558 debugfs_create_file(field[i], 0400, d->root, &d->fields[i], 559 &fops); 560 } 561 *dbg = d; 562 563 return 0; 564 } 565 566 static void rem_res_tree(struct mlx5_rsc_debug *d) 567 { 568 debugfs_remove_recursive(d->root); 569 kfree(d); 570 } 571 572 int mlx5_debug_qp_add(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp) 573 { 574 int err; 575 576 if (!mlx5_debugfs_root) 577 return 0; 578 579 err = add_res_tree(dev, MLX5_DBG_RSC_QP, dev->priv.dbg.qp_debugfs, 580 &qp->dbg, qp->qpn, qp_fields, 581 ARRAY_SIZE(qp_fields), qp); 582 if (err) 583 qp->dbg = NULL; 584 585 return err; 586 } 587 EXPORT_SYMBOL(mlx5_debug_qp_add); 588 589 void mlx5_debug_qp_remove(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp) 590 { 591 if (!mlx5_debugfs_root || !qp->dbg) 592 return; 593 594 rem_res_tree(qp->dbg); 595 qp->dbg = NULL; 596 } 597 EXPORT_SYMBOL(mlx5_debug_qp_remove); 598 599 int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq) 600 { 601 int err; 602 603 if (!mlx5_debugfs_root) 604 return 0; 605 606 err = add_res_tree(dev, MLX5_DBG_RSC_EQ, dev->priv.dbg.eq_debugfs, 607 &eq->dbg, eq->eqn, eq_fields, 608 ARRAY_SIZE(eq_fields), eq); 609 if (err) 610 eq->dbg = NULL; 611 612 return err; 613 } 614 615 void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq) 616 { 617 if (!mlx5_debugfs_root) 618 return; 619 620 if (eq->dbg) 621 rem_res_tree(eq->dbg); 622 } 623 624 int mlx5_debug_cq_add(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq) 625 { 626 int err; 627 628 if (!mlx5_debugfs_root) 629 return 0; 630 631 err = add_res_tree(dev, MLX5_DBG_RSC_CQ, dev->priv.dbg.cq_debugfs, 632 &cq->dbg, cq->cqn, cq_fields, 633 ARRAY_SIZE(cq_fields), cq); 634 if (err) 635 cq->dbg = NULL; 636 637 return err; 638 } 639 640 void mlx5_debug_cq_remove(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq) 641 { 642 if (!mlx5_debugfs_root) 643 return; 644 645 if (cq->dbg) { 646 rem_res_tree(cq->dbg); 647 cq->dbg = NULL; 648 } 649 } 650 651 static int vhca_id_show(struct seq_file *file, void *priv) 652 { 653 struct mlx5_core_dev *dev = file->private; 654 655 seq_printf(file, "0x%x\n", MLX5_CAP_GEN(dev, vhca_id)); 656 return 0; 657 } 658 659 DEFINE_SHOW_ATTRIBUTE(vhca_id); 660 661 void mlx5_vhca_debugfs_init(struct mlx5_core_dev *dev) 662 { 663 debugfs_create_file("vhca_id", 0400, dev->priv.dbg.dbg_root, dev, 664 &vhca_id_fops); 665 } 666