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.vfs_pages); 249 debugfs_create_u32("fw_pages_host_pf", 0400, pages, &dev->priv.host_pf_pages); 250 debugfs_create_u32("fw_pages_alloc_failed", 0400, pages, &dev->priv.fw_pages_alloc_failed); 251 debugfs_create_u32("fw_pages_give_dropped", 0400, pages, &dev->priv.give_pages_dropped); 252 debugfs_create_u32("fw_pages_reclaim_discard", 0400, pages, 253 &dev->priv.reclaim_pages_discard); 254 } 255 256 void mlx5_pages_debugfs_cleanup(struct mlx5_core_dev *dev) 257 { 258 debugfs_remove_recursive(dev->priv.dbg.pages_debugfs); 259 } 260 261 static u64 qp_read_field(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp, 262 int index, int *is_str) 263 { 264 int outlen = MLX5_ST_SZ_BYTES(query_qp_out); 265 u32 in[MLX5_ST_SZ_DW(query_qp_in)] = {}; 266 u64 param = 0; 267 u32 *out; 268 int state; 269 u32 *qpc; 270 int err; 271 272 out = kzalloc(outlen, GFP_KERNEL); 273 if (!out) 274 return 0; 275 276 MLX5_SET(query_qp_in, in, opcode, MLX5_CMD_OP_QUERY_QP); 277 MLX5_SET(query_qp_in, in, qpn, qp->qpn); 278 err = mlx5_cmd_exec_inout(dev, query_qp, in, out); 279 if (err) 280 goto out; 281 282 *is_str = 0; 283 284 qpc = MLX5_ADDR_OF(query_qp_out, out, qpc); 285 switch (index) { 286 case QP_PID: 287 param = qp->pid; 288 break; 289 case QP_STATE: 290 state = MLX5_GET(qpc, qpc, state); 291 param = (unsigned long)mlx5_qp_state_str(state); 292 *is_str = 1; 293 break; 294 case QP_XPORT: 295 param = (unsigned long)mlx5_qp_type_str(MLX5_GET(qpc, qpc, st)); 296 *is_str = 1; 297 break; 298 case QP_MTU: 299 switch (MLX5_GET(qpc, qpc, mtu)) { 300 case IB_MTU_256: 301 param = 256; 302 break; 303 case IB_MTU_512: 304 param = 512; 305 break; 306 case IB_MTU_1024: 307 param = 1024; 308 break; 309 case IB_MTU_2048: 310 param = 2048; 311 break; 312 case IB_MTU_4096: 313 param = 4096; 314 break; 315 default: 316 param = 0; 317 } 318 break; 319 case QP_N_RECV: 320 param = 1 << MLX5_GET(qpc, qpc, log_rq_size); 321 break; 322 case QP_RECV_SZ: 323 param = 1 << (MLX5_GET(qpc, qpc, log_rq_stride) + 4); 324 break; 325 case QP_N_SEND: 326 if (!MLX5_GET(qpc, qpc, no_sq)) 327 param = 1 << MLX5_GET(qpc, qpc, log_sq_size); 328 break; 329 case QP_LOG_PG_SZ: 330 param = MLX5_GET(qpc, qpc, log_page_size) + 12; 331 break; 332 case QP_RQPN: 333 param = MLX5_GET(qpc, qpc, remote_qpn); 334 break; 335 } 336 out: 337 kfree(out); 338 return param; 339 } 340 341 static u64 eq_read_field(struct mlx5_core_dev *dev, struct mlx5_eq *eq, 342 int index) 343 { 344 int outlen = MLX5_ST_SZ_BYTES(query_eq_out); 345 u32 in[MLX5_ST_SZ_DW(query_eq_in)] = {}; 346 u64 param = 0; 347 void *ctx; 348 u32 *out; 349 int err; 350 351 out = kzalloc(outlen, GFP_KERNEL); 352 if (!out) 353 return param; 354 355 MLX5_SET(query_eq_in, in, opcode, MLX5_CMD_OP_QUERY_EQ); 356 MLX5_SET(query_eq_in, in, eq_number, eq->eqn); 357 err = mlx5_cmd_exec_inout(dev, query_eq, in, out); 358 if (err) { 359 mlx5_core_warn(dev, "failed to query eq\n"); 360 goto out; 361 } 362 ctx = MLX5_ADDR_OF(query_eq_out, out, eq_context_entry); 363 364 switch (index) { 365 case EQ_NUM_EQES: 366 param = 1 << MLX5_GET(eqc, ctx, log_eq_size); 367 break; 368 case EQ_INTR: 369 param = MLX5_GET(eqc, ctx, intr); 370 break; 371 case EQ_LOG_PG_SZ: 372 param = MLX5_GET(eqc, ctx, log_page_size) + 12; 373 break; 374 } 375 376 out: 377 kfree(out); 378 return param; 379 } 380 381 static u64 cq_read_field(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, 382 int index) 383 { 384 int outlen = MLX5_ST_SZ_BYTES(query_cq_out); 385 u64 param = 0; 386 void *ctx; 387 u32 *out; 388 int err; 389 390 out = kvzalloc(outlen, GFP_KERNEL); 391 if (!out) 392 return param; 393 394 err = mlx5_core_query_cq(dev, cq, out); 395 if (err) { 396 mlx5_core_warn(dev, "failed to query cq\n"); 397 goto out; 398 } 399 ctx = MLX5_ADDR_OF(query_cq_out, out, cq_context); 400 401 switch (index) { 402 case CQ_PID: 403 param = cq->pid; 404 break; 405 case CQ_NUM_CQES: 406 param = 1 << MLX5_GET(cqc, ctx, log_cq_size); 407 break; 408 case CQ_LOG_PG_SZ: 409 param = MLX5_GET(cqc, ctx, log_page_size); 410 break; 411 } 412 413 out: 414 kvfree(out); 415 return param; 416 } 417 418 static ssize_t dbg_read(struct file *filp, char __user *buf, size_t count, 419 loff_t *pos) 420 { 421 struct mlx5_field_desc *desc; 422 struct mlx5_rsc_debug *d; 423 char tbuf[18]; 424 int is_str = 0; 425 u64 field; 426 int ret; 427 428 desc = filp->private_data; 429 d = (void *)(desc - desc->i) - sizeof(*d); 430 switch (d->type) { 431 case MLX5_DBG_RSC_QP: 432 field = qp_read_field(d->dev, d->object, desc->i, &is_str); 433 break; 434 435 case MLX5_DBG_RSC_EQ: 436 field = eq_read_field(d->dev, d->object, desc->i); 437 break; 438 439 case MLX5_DBG_RSC_CQ: 440 field = cq_read_field(d->dev, d->object, desc->i); 441 break; 442 443 default: 444 mlx5_core_warn(d->dev, "invalid resource type %d\n", d->type); 445 return -EINVAL; 446 } 447 448 if (is_str) 449 ret = snprintf(tbuf, sizeof(tbuf), "%s\n", (const char *)(unsigned long)field); 450 else 451 ret = snprintf(tbuf, sizeof(tbuf), "0x%llx\n", field); 452 453 return simple_read_from_buffer(buf, count, pos, tbuf, ret); 454 } 455 456 static const struct file_operations fops = { 457 .owner = THIS_MODULE, 458 .open = simple_open, 459 .read = dbg_read, 460 }; 461 462 static int add_res_tree(struct mlx5_core_dev *dev, enum dbg_rsc_type type, 463 struct dentry *root, struct mlx5_rsc_debug **dbg, 464 int rsn, char **field, int nfile, void *data) 465 { 466 struct mlx5_rsc_debug *d; 467 char resn[32]; 468 int i; 469 470 d = kzalloc(struct_size(d, fields, nfile), GFP_KERNEL); 471 if (!d) 472 return -ENOMEM; 473 474 d->dev = dev; 475 d->object = data; 476 d->type = type; 477 sprintf(resn, "0x%x", rsn); 478 d->root = debugfs_create_dir(resn, root); 479 480 for (i = 0; i < nfile; i++) { 481 d->fields[i].i = i; 482 debugfs_create_file(field[i], 0400, d->root, &d->fields[i], 483 &fops); 484 } 485 *dbg = d; 486 487 return 0; 488 } 489 490 static void rem_res_tree(struct mlx5_rsc_debug *d) 491 { 492 debugfs_remove_recursive(d->root); 493 kfree(d); 494 } 495 496 int mlx5_debug_qp_add(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp) 497 { 498 int err; 499 500 if (!mlx5_debugfs_root) 501 return 0; 502 503 err = add_res_tree(dev, MLX5_DBG_RSC_QP, dev->priv.dbg.qp_debugfs, 504 &qp->dbg, qp->qpn, qp_fields, 505 ARRAY_SIZE(qp_fields), qp); 506 if (err) 507 qp->dbg = NULL; 508 509 return err; 510 } 511 EXPORT_SYMBOL(mlx5_debug_qp_add); 512 513 void mlx5_debug_qp_remove(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp) 514 { 515 if (!mlx5_debugfs_root) 516 return; 517 518 if (qp->dbg) 519 rem_res_tree(qp->dbg); 520 } 521 EXPORT_SYMBOL(mlx5_debug_qp_remove); 522 523 int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq) 524 { 525 int err; 526 527 if (!mlx5_debugfs_root) 528 return 0; 529 530 err = add_res_tree(dev, MLX5_DBG_RSC_EQ, dev->priv.dbg.eq_debugfs, 531 &eq->dbg, eq->eqn, eq_fields, 532 ARRAY_SIZE(eq_fields), eq); 533 if (err) 534 eq->dbg = NULL; 535 536 return err; 537 } 538 539 void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq) 540 { 541 if (!mlx5_debugfs_root) 542 return; 543 544 if (eq->dbg) 545 rem_res_tree(eq->dbg); 546 } 547 548 int mlx5_debug_cq_add(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq) 549 { 550 int err; 551 552 if (!mlx5_debugfs_root) 553 return 0; 554 555 err = add_res_tree(dev, MLX5_DBG_RSC_CQ, dev->priv.dbg.cq_debugfs, 556 &cq->dbg, cq->cqn, cq_fields, 557 ARRAY_SIZE(cq_fields), cq); 558 if (err) 559 cq->dbg = NULL; 560 561 return err; 562 } 563 564 void mlx5_debug_cq_remove(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq) 565 { 566 if (!mlx5_debugfs_root) 567 return; 568 569 if (cq->dbg) { 570 rem_res_tree(cq->dbg); 571 cq->dbg = NULL; 572 } 573 } 574