debugfs.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  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. #include <linux/module.h>
  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. enum {
  39. QP_PID,
  40. QP_STATE,
  41. QP_XPORT,
  42. QP_MTU,
  43. QP_N_RECV,
  44. QP_RECV_SZ,
  45. QP_N_SEND,
  46. QP_LOG_PG_SZ,
  47. QP_RQPN,
  48. };
  49. static char *qp_fields[] = {
  50. [QP_PID] = "pid",
  51. [QP_STATE] = "state",
  52. [QP_XPORT] = "transport",
  53. [QP_MTU] = "mtu",
  54. [QP_N_RECV] = "num_recv",
  55. [QP_RECV_SZ] = "rcv_wqe_sz",
  56. [QP_N_SEND] = "num_send",
  57. [QP_LOG_PG_SZ] = "log2_page_sz",
  58. [QP_RQPN] = "remote_qpn",
  59. };
  60. enum {
  61. EQ_NUM_EQES,
  62. EQ_INTR,
  63. EQ_LOG_PG_SZ,
  64. };
  65. static char *eq_fields[] = {
  66. [EQ_NUM_EQES] = "num_eqes",
  67. [EQ_INTR] = "intr",
  68. [EQ_LOG_PG_SZ] = "log_page_size",
  69. };
  70. enum {
  71. CQ_PID,
  72. CQ_NUM_CQES,
  73. CQ_LOG_PG_SZ,
  74. };
  75. static char *cq_fields[] = {
  76. [CQ_PID] = "pid",
  77. [CQ_NUM_CQES] = "num_cqes",
  78. [CQ_LOG_PG_SZ] = "log_page_size",
  79. };
  80. struct dentry *mlx5_debugfs_root;
  81. EXPORT_SYMBOL(mlx5_debugfs_root);
  82. void mlx5_register_debugfs(void)
  83. {
  84. mlx5_debugfs_root = debugfs_create_dir("mlx5", NULL);
  85. if (IS_ERR_OR_NULL(mlx5_debugfs_root))
  86. mlx5_debugfs_root = NULL;
  87. }
  88. void mlx5_unregister_debugfs(void)
  89. {
  90. debugfs_remove(mlx5_debugfs_root);
  91. }
  92. int mlx5_qp_debugfs_init(struct mlx5_core_dev *dev)
  93. {
  94. if (!mlx5_debugfs_root)
  95. return 0;
  96. atomic_set(&dev->num_qps, 0);
  97. dev->priv.qp_debugfs = debugfs_create_dir("QPs", dev->priv.dbg_root);
  98. if (!dev->priv.qp_debugfs)
  99. return -ENOMEM;
  100. return 0;
  101. }
  102. void mlx5_qp_debugfs_cleanup(struct mlx5_core_dev *dev)
  103. {
  104. if (!mlx5_debugfs_root)
  105. return;
  106. debugfs_remove_recursive(dev->priv.qp_debugfs);
  107. }
  108. int mlx5_eq_debugfs_init(struct mlx5_core_dev *dev)
  109. {
  110. if (!mlx5_debugfs_root)
  111. return 0;
  112. dev->priv.eq_debugfs = debugfs_create_dir("EQs", dev->priv.dbg_root);
  113. if (!dev->priv.eq_debugfs)
  114. return -ENOMEM;
  115. return 0;
  116. }
  117. void mlx5_eq_debugfs_cleanup(struct mlx5_core_dev *dev)
  118. {
  119. if (!mlx5_debugfs_root)
  120. return;
  121. debugfs_remove_recursive(dev->priv.eq_debugfs);
  122. }
  123. static ssize_t average_read(struct file *filp, char __user *buf, size_t count,
  124. loff_t *pos)
  125. {
  126. struct mlx5_cmd_stats *stats;
  127. u64 field = 0;
  128. int ret;
  129. char tbuf[22];
  130. if (*pos)
  131. return 0;
  132. stats = filp->private_data;
  133. spin_lock_irq(&stats->lock);
  134. if (stats->n)
  135. field = div64_u64(stats->sum, stats->n);
  136. spin_unlock_irq(&stats->lock);
  137. ret = snprintf(tbuf, sizeof(tbuf), "%llu\n", field);
  138. if (ret > 0) {
  139. if (copy_to_user(buf, tbuf, ret))
  140. return -EFAULT;
  141. }
  142. *pos += ret;
  143. return ret;
  144. }
  145. static ssize_t average_write(struct file *filp, const char __user *buf,
  146. size_t count, loff_t *pos)
  147. {
  148. struct mlx5_cmd_stats *stats;
  149. stats = filp->private_data;
  150. spin_lock_irq(&stats->lock);
  151. stats->sum = 0;
  152. stats->n = 0;
  153. spin_unlock_irq(&stats->lock);
  154. *pos += count;
  155. return count;
  156. }
  157. static const struct file_operations stats_fops = {
  158. .owner = THIS_MODULE,
  159. .open = simple_open,
  160. .read = average_read,
  161. .write = average_write,
  162. };
  163. int mlx5_cmdif_debugfs_init(struct mlx5_core_dev *dev)
  164. {
  165. struct mlx5_cmd_stats *stats;
  166. struct dentry **cmd;
  167. const char *namep;
  168. int err;
  169. int i;
  170. if (!mlx5_debugfs_root)
  171. return 0;
  172. cmd = &dev->priv.cmdif_debugfs;
  173. *cmd = debugfs_create_dir("commands", dev->priv.dbg_root);
  174. if (!*cmd)
  175. return -ENOMEM;
  176. for (i = 0; i < ARRAY_SIZE(dev->cmd.stats); i++) {
  177. stats = &dev->cmd.stats[i];
  178. namep = mlx5_command_str(i);
  179. if (strcmp(namep, "unknown command opcode")) {
  180. stats->root = debugfs_create_dir(namep, *cmd);
  181. if (!stats->root) {
  182. mlx5_core_warn(dev, "failed adding command %d\n",
  183. i);
  184. err = -ENOMEM;
  185. goto out;
  186. }
  187. stats->avg = debugfs_create_file("average", 0400,
  188. stats->root, stats,
  189. &stats_fops);
  190. if (!stats->avg) {
  191. mlx5_core_warn(dev, "failed creating debugfs file\n");
  192. err = -ENOMEM;
  193. goto out;
  194. }
  195. stats->count = debugfs_create_u64("n", 0400,
  196. stats->root,
  197. &stats->n);
  198. if (!stats->count) {
  199. mlx5_core_warn(dev, "failed creating debugfs file\n");
  200. err = -ENOMEM;
  201. goto out;
  202. }
  203. }
  204. }
  205. return 0;
  206. out:
  207. debugfs_remove_recursive(dev->priv.cmdif_debugfs);
  208. return err;
  209. }
  210. void mlx5_cmdif_debugfs_cleanup(struct mlx5_core_dev *dev)
  211. {
  212. if (!mlx5_debugfs_root)
  213. return;
  214. debugfs_remove_recursive(dev->priv.cmdif_debugfs);
  215. }
  216. int mlx5_cq_debugfs_init(struct mlx5_core_dev *dev)
  217. {
  218. if (!mlx5_debugfs_root)
  219. return 0;
  220. dev->priv.cq_debugfs = debugfs_create_dir("CQs", dev->priv.dbg_root);
  221. if (!dev->priv.cq_debugfs)
  222. return -ENOMEM;
  223. return 0;
  224. }
  225. void mlx5_cq_debugfs_cleanup(struct mlx5_core_dev *dev)
  226. {
  227. if (!mlx5_debugfs_root)
  228. return;
  229. debugfs_remove_recursive(dev->priv.cq_debugfs);
  230. }
  231. static u64 qp_read_field(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp,
  232. int index, int *is_str)
  233. {
  234. struct mlx5_query_qp_mbox_out *out;
  235. struct mlx5_qp_context *ctx;
  236. u64 param = 0;
  237. int err;
  238. int no_sq;
  239. out = kzalloc(sizeof(*out), GFP_KERNEL);
  240. if (!out)
  241. return param;
  242. err = mlx5_core_qp_query(dev, qp, out, sizeof(*out));
  243. if (err) {
  244. mlx5_core_warn(dev, "failed to query qp\n");
  245. goto out;
  246. }
  247. *is_str = 0;
  248. ctx = &out->ctx;
  249. switch (index) {
  250. case QP_PID:
  251. param = qp->pid;
  252. break;
  253. case QP_STATE:
  254. param = (unsigned long)mlx5_qp_state_str(be32_to_cpu(ctx->flags) >> 28);
  255. *is_str = 1;
  256. break;
  257. case QP_XPORT:
  258. param = (unsigned long)mlx5_qp_type_str((be32_to_cpu(ctx->flags) >> 16) & 0xff);
  259. *is_str = 1;
  260. break;
  261. case QP_MTU:
  262. switch (ctx->mtu_msgmax >> 5) {
  263. case IB_MTU_256:
  264. param = 256;
  265. break;
  266. case IB_MTU_512:
  267. param = 512;
  268. break;
  269. case IB_MTU_1024:
  270. param = 1024;
  271. break;
  272. case IB_MTU_2048:
  273. param = 2048;
  274. break;
  275. case IB_MTU_4096:
  276. param = 4096;
  277. break;
  278. default:
  279. param = 0;
  280. }
  281. break;
  282. case QP_N_RECV:
  283. param = 1 << ((ctx->rq_size_stride >> 3) & 0xf);
  284. break;
  285. case QP_RECV_SZ:
  286. param = 1 << ((ctx->rq_size_stride & 7) + 4);
  287. break;
  288. case QP_N_SEND:
  289. no_sq = be16_to_cpu(ctx->sq_crq_size) >> 15;
  290. if (!no_sq)
  291. param = 1 << (be16_to_cpu(ctx->sq_crq_size) >> 11);
  292. else
  293. param = 0;
  294. break;
  295. case QP_LOG_PG_SZ:
  296. param = (be32_to_cpu(ctx->log_pg_sz_remote_qpn) >> 24) & 0x1f;
  297. param += 12;
  298. break;
  299. case QP_RQPN:
  300. param = be32_to_cpu(ctx->log_pg_sz_remote_qpn) & 0xffffff;
  301. break;
  302. }
  303. out:
  304. kfree(out);
  305. return param;
  306. }
  307. static u64 eq_read_field(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
  308. int index)
  309. {
  310. struct mlx5_query_eq_mbox_out *out;
  311. struct mlx5_eq_context *ctx;
  312. u64 param = 0;
  313. int err;
  314. out = kzalloc(sizeof(*out), GFP_KERNEL);
  315. if (!out)
  316. return param;
  317. ctx = &out->ctx;
  318. err = mlx5_core_eq_query(dev, eq, out, sizeof(*out));
  319. if (err) {
  320. mlx5_core_warn(dev, "failed to query eq\n");
  321. goto out;
  322. }
  323. switch (index) {
  324. case EQ_NUM_EQES:
  325. param = 1 << ((be32_to_cpu(ctx->log_sz_usr_page) >> 24) & 0x1f);
  326. break;
  327. case EQ_INTR:
  328. param = ctx->intr;
  329. break;
  330. case EQ_LOG_PG_SZ:
  331. param = (ctx->log_page_size & 0x1f) + 12;
  332. break;
  333. }
  334. out:
  335. kfree(out);
  336. return param;
  337. }
  338. static u64 cq_read_field(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
  339. int index)
  340. {
  341. struct mlx5_query_cq_mbox_out *out;
  342. struct mlx5_cq_context *ctx;
  343. u64 param = 0;
  344. int err;
  345. out = kzalloc(sizeof(*out), GFP_KERNEL);
  346. if (!out)
  347. return param;
  348. ctx = &out->ctx;
  349. err = mlx5_core_query_cq(dev, cq, out);
  350. if (err) {
  351. mlx5_core_warn(dev, "failed to query cq\n");
  352. goto out;
  353. }
  354. switch (index) {
  355. case CQ_PID:
  356. param = cq->pid;
  357. break;
  358. case CQ_NUM_CQES:
  359. param = 1 << ((be32_to_cpu(ctx->log_sz_usr_page) >> 24) & 0x1f);
  360. break;
  361. case CQ_LOG_PG_SZ:
  362. param = (ctx->log_pg_sz & 0x1f) + 12;
  363. break;
  364. }
  365. out:
  366. kfree(out);
  367. return param;
  368. }
  369. static ssize_t dbg_read(struct file *filp, char __user *buf, size_t count,
  370. loff_t *pos)
  371. {
  372. struct mlx5_field_desc *desc;
  373. struct mlx5_rsc_debug *d;
  374. char tbuf[18];
  375. int is_str = 0;
  376. u64 field;
  377. int ret;
  378. if (*pos)
  379. return 0;
  380. desc = filp->private_data;
  381. d = (void *)(desc - desc->i) - sizeof(*d);
  382. switch (d->type) {
  383. case MLX5_DBG_RSC_QP:
  384. field = qp_read_field(d->dev, d->object, desc->i, &is_str);
  385. break;
  386. case MLX5_DBG_RSC_EQ:
  387. field = eq_read_field(d->dev, d->object, desc->i);
  388. break;
  389. case MLX5_DBG_RSC_CQ:
  390. field = cq_read_field(d->dev, d->object, desc->i);
  391. break;
  392. default:
  393. mlx5_core_warn(d->dev, "invalid resource type %d\n", d->type);
  394. return -EINVAL;
  395. }
  396. if (is_str)
  397. ret = snprintf(tbuf, sizeof(tbuf), "%s\n", (const char *)(unsigned long)field);
  398. else
  399. ret = snprintf(tbuf, sizeof(tbuf), "0x%llx\n", field);
  400. if (ret > 0) {
  401. if (copy_to_user(buf, tbuf, ret))
  402. return -EFAULT;
  403. }
  404. *pos += ret;
  405. return ret;
  406. }
  407. static const struct file_operations fops = {
  408. .owner = THIS_MODULE,
  409. .open = simple_open,
  410. .read = dbg_read,
  411. };
  412. static int add_res_tree(struct mlx5_core_dev *dev, enum dbg_rsc_type type,
  413. struct dentry *root, struct mlx5_rsc_debug **dbg,
  414. int rsn, char **field, int nfile, void *data)
  415. {
  416. struct mlx5_rsc_debug *d;
  417. char resn[32];
  418. int err;
  419. int i;
  420. d = kzalloc(sizeof(*d) + nfile * sizeof(d->fields[0]), GFP_KERNEL);
  421. if (!d)
  422. return -ENOMEM;
  423. d->dev = dev;
  424. d->object = data;
  425. d->type = type;
  426. sprintf(resn, "0x%x", rsn);
  427. d->root = debugfs_create_dir(resn, root);
  428. if (!d->root) {
  429. err = -ENOMEM;
  430. goto out_free;
  431. }
  432. for (i = 0; i < nfile; i++) {
  433. d->fields[i].i = i;
  434. d->fields[i].dent = debugfs_create_file(field[i], 0400,
  435. d->root, &d->fields[i],
  436. &fops);
  437. if (!d->fields[i].dent) {
  438. err = -ENOMEM;
  439. goto out_rem;
  440. }
  441. }
  442. *dbg = d;
  443. return 0;
  444. out_rem:
  445. debugfs_remove_recursive(d->root);
  446. out_free:
  447. kfree(d);
  448. return err;
  449. }
  450. static void rem_res_tree(struct mlx5_rsc_debug *d)
  451. {
  452. debugfs_remove_recursive(d->root);
  453. kfree(d);
  454. }
  455. int mlx5_debug_qp_add(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp)
  456. {
  457. int err;
  458. if (!mlx5_debugfs_root)
  459. return 0;
  460. err = add_res_tree(dev, MLX5_DBG_RSC_QP, dev->priv.qp_debugfs,
  461. &qp->dbg, qp->qpn, qp_fields,
  462. ARRAY_SIZE(qp_fields), qp);
  463. if (err)
  464. qp->dbg = NULL;
  465. return err;
  466. }
  467. void mlx5_debug_qp_remove(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp)
  468. {
  469. if (!mlx5_debugfs_root)
  470. return;
  471. if (qp->dbg)
  472. rem_res_tree(qp->dbg);
  473. }
  474. int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
  475. {
  476. int err;
  477. if (!mlx5_debugfs_root)
  478. return 0;
  479. err = add_res_tree(dev, MLX5_DBG_RSC_EQ, dev->priv.eq_debugfs,
  480. &eq->dbg, eq->eqn, eq_fields,
  481. ARRAY_SIZE(eq_fields), eq);
  482. if (err)
  483. eq->dbg = NULL;
  484. return err;
  485. }
  486. void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
  487. {
  488. if (!mlx5_debugfs_root)
  489. return;
  490. if (eq->dbg)
  491. rem_res_tree(eq->dbg);
  492. }
  493. int mlx5_debug_cq_add(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)
  494. {
  495. int err;
  496. if (!mlx5_debugfs_root)
  497. return 0;
  498. err = add_res_tree(dev, MLX5_DBG_RSC_CQ, dev->priv.cq_debugfs,
  499. &cq->dbg, cq->cqn, cq_fields,
  500. ARRAY_SIZE(cq_fields), cq);
  501. if (err)
  502. cq->dbg = NULL;
  503. return err;
  504. }
  505. void mlx5_debug_cq_remove(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)
  506. {
  507. if (!mlx5_debugfs_root)
  508. return;
  509. if (cq->dbg)
  510. rem_res_tree(cq->dbg);
  511. }