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 average_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 spin_unlock_irq(&stats->lock); 156 157 *pos += count; 158 159 return count; 160 } 161 162 static const struct file_operations stats_fops = { 163 .owner = THIS_MODULE, 164 .open = simple_open, 165 .read = average_read, 166 .write = average_write, 167 }; 168 169 static ssize_t slots_read(struct file *filp, char __user *buf, size_t count, 170 loff_t *pos) 171 { 172 struct mlx5_cmd *cmd; 173 char tbuf[6]; 174 int weight; 175 int field; 176 int ret; 177 178 cmd = filp->private_data; 179 weight = bitmap_weight(&cmd->bitmask, cmd->max_reg_cmds); 180 field = cmd->max_reg_cmds - weight; 181 ret = snprintf(tbuf, sizeof(tbuf), "%d\n", field); 182 return simple_read_from_buffer(buf, count, pos, tbuf, ret); 183 } 184 185 static const struct file_operations slots_fops = { 186 .owner = THIS_MODULE, 187 .open = simple_open, 188 .read = slots_read, 189 }; 190 191 void mlx5_cmdif_debugfs_init(struct mlx5_core_dev *dev) 192 { 193 struct mlx5_cmd_stats *stats; 194 struct dentry **cmd; 195 const char *namep; 196 int i; 197 198 cmd = &dev->priv.dbg.cmdif_debugfs; 199 *cmd = debugfs_create_dir("commands", dev->priv.dbg.dbg_root); 200 201 debugfs_create_file("slots_inuse", 0400, *cmd, &dev->cmd, &slots_fops); 202 203 for (i = 0; i < MLX5_CMD_OP_MAX; i++) { 204 stats = &dev->cmd.stats[i]; 205 namep = mlx5_command_str(i); 206 if (strcmp(namep, "unknown command opcode")) { 207 stats->root = debugfs_create_dir(namep, *cmd); 208 209 debugfs_create_file("average", 0400, stats->root, stats, 210 &stats_fops); 211 debugfs_create_u64("n", 0400, stats->root, &stats->n); 212 debugfs_create_u64("failed", 0400, stats->root, &stats->failed); 213 debugfs_create_u64("failed_mbox_status", 0400, stats->root, 214 &stats->failed_mbox_status); 215 debugfs_create_u32("last_failed_errno", 0400, stats->root, 216 &stats->last_failed_errno); 217 debugfs_create_u8("last_failed_mbox_status", 0400, stats->root, 218 &stats->last_failed_mbox_status); 219 debugfs_create_x32("last_failed_syndrome", 0400, stats->root, 220 &stats->last_failed_syndrome); 221 } 222 } 223 } 224 225 void mlx5_cmdif_debugfs_cleanup(struct mlx5_core_dev *dev) 226 { 227 debugfs_remove_recursive(dev->priv.dbg.cmdif_debugfs); 228 } 229 230 void mlx5_cq_debugfs_init(struct mlx5_core_dev *dev) 231 { 232 dev->priv.dbg.cq_debugfs = debugfs_create_dir("CQs", dev->priv.dbg.dbg_root); 233 } 234 235 void mlx5_cq_debugfs_cleanup(struct mlx5_core_dev *dev) 236 { 237 debugfs_remove_recursive(dev->priv.dbg.cq_debugfs); 238 } 239 240 void mlx5_pages_debugfs_init(struct mlx5_core_dev *dev) 241 { 242 struct dentry *pages; 243 244 dev->priv.dbg.pages_debugfs = debugfs_create_dir("pages", dev->priv.dbg.dbg_root); 245 pages = dev->priv.dbg.pages_debugfs; 246 247 debugfs_create_u32("fw_pages_total", 0400, pages, &dev->priv.fw_pages); 248 debugfs_create_u32("fw_pages_vfs", 0400, pages, &dev->priv.page_counters[MLX5_VF]); 249 debugfs_create_u32("fw_pages_ec_vfs", 0400, pages, &dev->priv.page_counters[MLX5_EC_VF]); 250 debugfs_create_u32("fw_pages_sfs", 0400, pages, &dev->priv.page_counters[MLX5_SF]); 251 debugfs_create_u32("fw_pages_host_pf", 0400, pages, &dev->priv.page_counters[MLX5_HOST_PF]); 252 debugfs_create_u32("fw_pages_alloc_failed", 0400, pages, &dev->priv.fw_pages_alloc_failed); 253 debugfs_create_u32("fw_pages_give_dropped", 0400, pages, &dev->priv.give_pages_dropped); 254 debugfs_create_u32("fw_pages_reclaim_discard", 0400, pages, 255 &dev->priv.reclaim_pages_discard); 256 } 257 258 void mlx5_pages_debugfs_cleanup(struct mlx5_core_dev *dev) 259 { 260 debugfs_remove_recursive(dev->priv.dbg.pages_debugfs); 261 } 262 263 static u64 qp_read_field(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp, 264 int index, int *is_str) 265 { 266 int outlen = MLX5_ST_SZ_BYTES(query_qp_out); 267 u32 in[MLX5_ST_SZ_DW(query_qp_in)] = {}; 268 u64 param = 0; 269 u32 *out; 270 int state; 271 u32 *qpc; 272 int err; 273 274 out = kzalloc(outlen, GFP_KERNEL); 275 if (!out) 276 return 0; 277 278 MLX5_SET(query_qp_in, in, opcode, MLX5_CMD_OP_QUERY_QP); 279 MLX5_SET(query_qp_in, in, qpn, qp->qpn); 280 err = mlx5_cmd_exec_inout(dev, query_qp, in, out); 281 if (err) 282 goto out; 283 284 *is_str = 0; 285 286 qpc = MLX5_ADDR_OF(query_qp_out, out, qpc); 287 switch (index) { 288 case QP_PID: 289 param = qp->pid; 290 break; 291 case QP_STATE: 292 state = MLX5_GET(qpc, qpc, state); 293 param = (unsigned long)mlx5_qp_state_str(state); 294 *is_str = 1; 295 break; 296 case QP_XPORT: 297 param = (unsigned long)mlx5_qp_type_str(MLX5_GET(qpc, qpc, st)); 298 *is_str = 1; 299 break; 300 case QP_MTU: 301 switch (MLX5_GET(qpc, qpc, mtu)) { 302 case IB_MTU_256: 303 param = 256; 304 break; 305 case IB_MTU_512: 306 param = 512; 307 break; 308 case IB_MTU_1024: 309 param = 1024; 310 break; 311 case IB_MTU_2048: 312 param = 2048; 313 break; 314 case IB_MTU_4096: 315 param = 4096; 316 break; 317 default: 318 param = 0; 319 } 320 break; 321 case QP_N_RECV: 322 param = 1 << MLX5_GET(qpc, qpc, log_rq_size); 323 break; 324 case QP_RECV_SZ: 325 param = 1 << (MLX5_GET(qpc, qpc, log_rq_stride) + 4); 326 break; 327 case QP_N_SEND: 328 if (!MLX5_GET(qpc, qpc, no_sq)) 329 param = 1 << MLX5_GET(qpc, qpc, log_sq_size); 330 break; 331 case QP_LOG_PG_SZ: 332 param = MLX5_GET(qpc, qpc, log_page_size) + 12; 333 break; 334 case QP_RQPN: 335 param = MLX5_GET(qpc, qpc, remote_qpn); 336 break; 337 } 338 out: 339 kfree(out); 340 return param; 341 } 342 343 static u64 eq_read_field(struct mlx5_core_dev *dev, struct mlx5_eq *eq, 344 int index) 345 { 346 int outlen = MLX5_ST_SZ_BYTES(query_eq_out); 347 u32 in[MLX5_ST_SZ_DW(query_eq_in)] = {}; 348 u64 param = 0; 349 void *ctx; 350 u32 *out; 351 int err; 352 353 out = kzalloc(outlen, GFP_KERNEL); 354 if (!out) 355 return param; 356 357 MLX5_SET(query_eq_in, in, opcode, MLX5_CMD_OP_QUERY_EQ); 358 MLX5_SET(query_eq_in, in, eq_number, eq->eqn); 359 err = mlx5_cmd_exec_inout(dev, query_eq, in, out); 360 if (err) { 361 mlx5_core_warn(dev, "failed to query eq\n"); 362 goto out; 363 } 364 ctx = MLX5_ADDR_OF(query_eq_out, out, eq_context_entry); 365 366 switch (index) { 367 case EQ_NUM_EQES: 368 param = 1 << MLX5_GET(eqc, ctx, log_eq_size); 369 break; 370 case EQ_INTR: 371 param = MLX5_GET(eqc, ctx, intr); 372 break; 373 case EQ_LOG_PG_SZ: 374 param = MLX5_GET(eqc, ctx, log_page_size) + 12; 375 break; 376 } 377 378 out: 379 kfree(out); 380 return param; 381 } 382 383 static u64 cq_read_field(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, 384 int index) 385 { 386 int outlen = MLX5_ST_SZ_BYTES(query_cq_out); 387 u64 param = 0; 388 void *ctx; 389 u32 *out; 390 int err; 391 392 out = kvzalloc(outlen, GFP_KERNEL); 393 if (!out) 394 return param; 395 396 err = mlx5_core_query_cq(dev, cq, out); 397 if (err) { 398 mlx5_core_warn(dev, "failed to query cq\n"); 399 goto out; 400 } 401 ctx = MLX5_ADDR_OF(query_cq_out, out, cq_context); 402 403 switch (index) { 404 case CQ_PID: 405 param = cq->pid; 406 break; 407 case CQ_NUM_CQES: 408 param = 1 << MLX5_GET(cqc, ctx, log_cq_size); 409 break; 410 case CQ_LOG_PG_SZ: 411 param = MLX5_GET(cqc, ctx, log_page_size); 412 break; 413 } 414 415 out: 416 kvfree(out); 417 return param; 418 } 419 420 static ssize_t dbg_read(struct file *filp, char __user *buf, size_t count, 421 loff_t *pos) 422 { 423 struct mlx5_field_desc *desc; 424 struct mlx5_rsc_debug *d; 425 char tbuf[18]; 426 int is_str = 0; 427 u64 field; 428 int ret; 429 430 desc = filp->private_data; 431 d = (void *)(desc - desc->i) - sizeof(*d); 432 switch (d->type) { 433 case MLX5_DBG_RSC_QP: 434 field = qp_read_field(d->dev, d->object, desc->i, &is_str); 435 break; 436 437 case MLX5_DBG_RSC_EQ: 438 field = eq_read_field(d->dev, d->object, desc->i); 439 break; 440 441 case MLX5_DBG_RSC_CQ: 442 field = cq_read_field(d->dev, d->object, desc->i); 443 break; 444 445 default: 446 mlx5_core_warn(d->dev, "invalid resource type %d\n", d->type); 447 return -EINVAL; 448 } 449 450 if (is_str) 451 ret = snprintf(tbuf, sizeof(tbuf), "%s\n", (const char *)(unsigned long)field); 452 else 453 ret = snprintf(tbuf, sizeof(tbuf), "0x%llx\n", field); 454 455 return simple_read_from_buffer(buf, count, pos, tbuf, ret); 456 } 457 458 static const struct file_operations fops = { 459 .owner = THIS_MODULE, 460 .open = simple_open, 461 .read = dbg_read, 462 }; 463 464 static int add_res_tree(struct mlx5_core_dev *dev, enum dbg_rsc_type type, 465 struct dentry *root, struct mlx5_rsc_debug **dbg, 466 int rsn, char **field, int nfile, void *data) 467 { 468 struct mlx5_rsc_debug *d; 469 char resn[32]; 470 int i; 471 472 d = kzalloc(struct_size(d, fields, nfile), GFP_KERNEL); 473 if (!d) 474 return -ENOMEM; 475 476 d->dev = dev; 477 d->object = data; 478 d->type = type; 479 sprintf(resn, "0x%x", rsn); 480 d->root = debugfs_create_dir(resn, root); 481 482 for (i = 0; i < nfile; i++) { 483 d->fields[i].i = i; 484 debugfs_create_file(field[i], 0400, d->root, &d->fields[i], 485 &fops); 486 } 487 *dbg = d; 488 489 return 0; 490 } 491 492 static void rem_res_tree(struct mlx5_rsc_debug *d) 493 { 494 debugfs_remove_recursive(d->root); 495 kfree(d); 496 } 497 498 int mlx5_debug_qp_add(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp) 499 { 500 int err; 501 502 if (!mlx5_debugfs_root) 503 return 0; 504 505 err = add_res_tree(dev, MLX5_DBG_RSC_QP, dev->priv.dbg.qp_debugfs, 506 &qp->dbg, qp->qpn, qp_fields, 507 ARRAY_SIZE(qp_fields), qp); 508 if (err) 509 qp->dbg = NULL; 510 511 return err; 512 } 513 EXPORT_SYMBOL(mlx5_debug_qp_add); 514 515 void mlx5_debug_qp_remove(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp) 516 { 517 if (!mlx5_debugfs_root || !qp->dbg) 518 return; 519 520 rem_res_tree(qp->dbg); 521 qp->dbg = NULL; 522 } 523 EXPORT_SYMBOL(mlx5_debug_qp_remove); 524 525 int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq) 526 { 527 int err; 528 529 if (!mlx5_debugfs_root) 530 return 0; 531 532 err = add_res_tree(dev, MLX5_DBG_RSC_EQ, dev->priv.dbg.eq_debugfs, 533 &eq->dbg, eq->eqn, eq_fields, 534 ARRAY_SIZE(eq_fields), eq); 535 if (err) 536 eq->dbg = NULL; 537 538 return err; 539 } 540 541 void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq) 542 { 543 if (!mlx5_debugfs_root) 544 return; 545 546 if (eq->dbg) 547 rem_res_tree(eq->dbg); 548 } 549 550 int mlx5_debug_cq_add(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq) 551 { 552 int err; 553 554 if (!mlx5_debugfs_root) 555 return 0; 556 557 err = add_res_tree(dev, MLX5_DBG_RSC_CQ, dev->priv.dbg.cq_debugfs, 558 &cq->dbg, cq->cqn, cq_fields, 559 ARRAY_SIZE(cq_fields), cq); 560 if (err) 561 cq->dbg = NULL; 562 563 return err; 564 } 565 566 void mlx5_debug_cq_remove(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq) 567 { 568 if (!mlx5_debugfs_root) 569 return; 570 571 if (cq->dbg) { 572 rem_res_tree(cq->dbg); 573 cq->dbg = NULL; 574 } 575 } 576