debugfs.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  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. stats = filp->private_data;
  131. spin_lock_irq(&stats->lock);
  132. if (stats->n)
  133. field = div64_u64(stats->sum, stats->n);
  134. spin_unlock_irq(&stats->lock);
  135. ret = snprintf(tbuf, sizeof(tbuf), "%llu\n", field);
  136. return simple_read_from_buffer(buf, count, pos, tbuf, ret);
  137. }
  138. static ssize_t average_write(struct file *filp, const char __user *buf,
  139. size_t count, loff_t *pos)
  140. {
  141. struct mlx5_cmd_stats *stats;
  142. stats = filp->private_data;
  143. spin_lock_irq(&stats->lock);
  144. stats->sum = 0;
  145. stats->n = 0;
  146. spin_unlock_irq(&stats->lock);
  147. *pos += count;
  148. return count;
  149. }
  150. static const struct file_operations stats_fops = {
  151. .owner = THIS_MODULE,
  152. .open = simple_open,
  153. .read = average_read,
  154. .write = average_write,
  155. };
  156. int mlx5_cmdif_debugfs_init(struct mlx5_core_dev *dev)
  157. {
  158. struct mlx5_cmd_stats *stats;
  159. struct dentry **cmd;
  160. const char *namep;
  161. int err;
  162. int i;
  163. if (!mlx5_debugfs_root)
  164. return 0;
  165. cmd = &dev->priv.cmdif_debugfs;
  166. *cmd = debugfs_create_dir("commands", dev->priv.dbg_root);
  167. if (!*cmd)
  168. return -ENOMEM;
  169. for (i = 0; i < ARRAY_SIZE(dev->cmd.stats); i++) {
  170. stats = &dev->cmd.stats[i];
  171. namep = mlx5_command_str(i);
  172. if (strcmp(namep, "unknown command opcode")) {
  173. stats->root = debugfs_create_dir(namep, *cmd);
  174. if (!stats->root) {
  175. mlx5_core_warn(dev, "failed adding command %d\n",
  176. i);
  177. err = -ENOMEM;
  178. goto out;
  179. }
  180. stats->avg = debugfs_create_file("average", 0400,
  181. stats->root, stats,
  182. &stats_fops);
  183. if (!stats->avg) {
  184. mlx5_core_warn(dev, "failed creating debugfs file\n");
  185. err = -ENOMEM;
  186. goto out;
  187. }
  188. stats->count = debugfs_create_u64("n", 0400,
  189. stats->root,
  190. &stats->n);
  191. if (!stats->count) {
  192. mlx5_core_warn(dev, "failed creating debugfs file\n");
  193. err = -ENOMEM;
  194. goto out;
  195. }
  196. }
  197. }
  198. return 0;
  199. out:
  200. debugfs_remove_recursive(dev->priv.cmdif_debugfs);
  201. return err;
  202. }
  203. void mlx5_cmdif_debugfs_cleanup(struct mlx5_core_dev *dev)
  204. {
  205. if (!mlx5_debugfs_root)
  206. return;
  207. debugfs_remove_recursive(dev->priv.cmdif_debugfs);
  208. }
  209. int mlx5_cq_debugfs_init(struct mlx5_core_dev *dev)
  210. {
  211. if (!mlx5_debugfs_root)
  212. return 0;
  213. dev->priv.cq_debugfs = debugfs_create_dir("CQs", dev->priv.dbg_root);
  214. if (!dev->priv.cq_debugfs)
  215. return -ENOMEM;
  216. return 0;
  217. }
  218. void mlx5_cq_debugfs_cleanup(struct mlx5_core_dev *dev)
  219. {
  220. if (!mlx5_debugfs_root)
  221. return;
  222. debugfs_remove_recursive(dev->priv.cq_debugfs);
  223. }
  224. static u64 qp_read_field(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp,
  225. int index, int *is_str)
  226. {
  227. int outlen = MLX5_ST_SZ_BYTES(query_qp_out);
  228. struct mlx5_qp_context *ctx;
  229. u64 param = 0;
  230. u32 *out;
  231. int err;
  232. int no_sq;
  233. out = kzalloc(outlen, GFP_KERNEL);
  234. if (!out)
  235. return param;
  236. err = mlx5_core_qp_query(dev, qp, out, outlen);
  237. if (err) {
  238. mlx5_core_warn(dev, "failed to query qp err=%d\n", err);
  239. goto out;
  240. }
  241. *is_str = 0;
  242. /* FIXME: use MLX5_GET rather than mlx5_qp_context manual struct */
  243. ctx = (struct mlx5_qp_context *)MLX5_ADDR_OF(query_qp_out, out, qpc);
  244. switch (index) {
  245. case QP_PID:
  246. param = qp->pid;
  247. break;
  248. case QP_STATE:
  249. param = (unsigned long)mlx5_qp_state_str(be32_to_cpu(ctx->flags) >> 28);
  250. *is_str = 1;
  251. break;
  252. case QP_XPORT:
  253. param = (unsigned long)mlx5_qp_type_str((be32_to_cpu(ctx->flags) >> 16) & 0xff);
  254. *is_str = 1;
  255. break;
  256. case QP_MTU:
  257. switch (ctx->mtu_msgmax >> 5) {
  258. case IB_MTU_256:
  259. param = 256;
  260. break;
  261. case IB_MTU_512:
  262. param = 512;
  263. break;
  264. case IB_MTU_1024:
  265. param = 1024;
  266. break;
  267. case IB_MTU_2048:
  268. param = 2048;
  269. break;
  270. case IB_MTU_4096:
  271. param = 4096;
  272. break;
  273. default:
  274. param = 0;
  275. }
  276. break;
  277. case QP_N_RECV:
  278. param = 1 << ((ctx->rq_size_stride >> 3) & 0xf);
  279. break;
  280. case QP_RECV_SZ:
  281. param = 1 << ((ctx->rq_size_stride & 7) + 4);
  282. break;
  283. case QP_N_SEND:
  284. no_sq = be16_to_cpu(ctx->sq_crq_size) >> 15;
  285. if (!no_sq)
  286. param = 1 << (be16_to_cpu(ctx->sq_crq_size) >> 11);
  287. else
  288. param = 0;
  289. break;
  290. case QP_LOG_PG_SZ:
  291. param = (be32_to_cpu(ctx->log_pg_sz_remote_qpn) >> 24) & 0x1f;
  292. param += 12;
  293. break;
  294. case QP_RQPN:
  295. param = be32_to_cpu(ctx->log_pg_sz_remote_qpn) & 0xffffff;
  296. break;
  297. }
  298. out:
  299. kfree(out);
  300. return param;
  301. }
  302. static u64 eq_read_field(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
  303. int index)
  304. {
  305. int outlen = MLX5_ST_SZ_BYTES(query_eq_out);
  306. u64 param = 0;
  307. void *ctx;
  308. u32 *out;
  309. int err;
  310. out = kzalloc(outlen, GFP_KERNEL);
  311. if (!out)
  312. return param;
  313. err = mlx5_core_eq_query(dev, eq, out, outlen);
  314. if (err) {
  315. mlx5_core_warn(dev, "failed to query eq\n");
  316. goto out;
  317. }
  318. ctx = MLX5_ADDR_OF(query_eq_out, out, eq_context_entry);
  319. switch (index) {
  320. case EQ_NUM_EQES:
  321. param = 1 << MLX5_GET(eqc, ctx, log_eq_size);
  322. break;
  323. case EQ_INTR:
  324. param = MLX5_GET(eqc, ctx, intr);
  325. break;
  326. case EQ_LOG_PG_SZ:
  327. param = MLX5_GET(eqc, ctx, log_page_size) + 12;
  328. break;
  329. }
  330. out:
  331. kfree(out);
  332. return param;
  333. }
  334. static u64 cq_read_field(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
  335. int index)
  336. {
  337. int outlen = MLX5_ST_SZ_BYTES(query_cq_out);
  338. u64 param = 0;
  339. void *ctx;
  340. u32 *out;
  341. int err;
  342. out = kvzalloc(outlen, GFP_KERNEL);
  343. if (!out)
  344. return param;
  345. err = mlx5_core_query_cq(dev, cq, out, outlen);
  346. if (err) {
  347. mlx5_core_warn(dev, "failed to query cq\n");
  348. goto out;
  349. }
  350. ctx = MLX5_ADDR_OF(query_cq_out, out, cq_context);
  351. switch (index) {
  352. case CQ_PID:
  353. param = cq->pid;
  354. break;
  355. case CQ_NUM_CQES:
  356. param = 1 << MLX5_GET(cqc, ctx, log_cq_size);
  357. break;
  358. case CQ_LOG_PG_SZ:
  359. param = MLX5_GET(cqc, ctx, log_page_size);
  360. break;
  361. }
  362. out:
  363. kvfree(out);
  364. return param;
  365. }
  366. static ssize_t dbg_read(struct file *filp, char __user *buf, size_t count,
  367. loff_t *pos)
  368. {
  369. struct mlx5_field_desc *desc;
  370. struct mlx5_rsc_debug *d;
  371. char tbuf[18];
  372. int is_str = 0;
  373. u64 field;
  374. int ret;
  375. desc = filp->private_data;
  376. d = (void *)(desc - desc->i) - sizeof(*d);
  377. switch (d->type) {
  378. case MLX5_DBG_RSC_QP:
  379. field = qp_read_field(d->dev, d->object, desc->i, &is_str);
  380. break;
  381. case MLX5_DBG_RSC_EQ:
  382. field = eq_read_field(d->dev, d->object, desc->i);
  383. break;
  384. case MLX5_DBG_RSC_CQ:
  385. field = cq_read_field(d->dev, d->object, desc->i);
  386. break;
  387. default:
  388. mlx5_core_warn(d->dev, "invalid resource type %d\n", d->type);
  389. return -EINVAL;
  390. }
  391. if (is_str)
  392. ret = snprintf(tbuf, sizeof(tbuf), "%s\n", (const char *)(unsigned long)field);
  393. else
  394. ret = snprintf(tbuf, sizeof(tbuf), "0x%llx\n", field);
  395. return simple_read_from_buffer(buf, count, pos, tbuf, ret);
  396. }
  397. static const struct file_operations fops = {
  398. .owner = THIS_MODULE,
  399. .open = simple_open,
  400. .read = dbg_read,
  401. };
  402. static int add_res_tree(struct mlx5_core_dev *dev, enum dbg_rsc_type type,
  403. struct dentry *root, struct mlx5_rsc_debug **dbg,
  404. int rsn, char **field, int nfile, void *data)
  405. {
  406. struct mlx5_rsc_debug *d;
  407. char resn[32];
  408. int err;
  409. int i;
  410. d = kzalloc(struct_size(d, fields, nfile), GFP_KERNEL);
  411. if (!d)
  412. return -ENOMEM;
  413. d->dev = dev;
  414. d->object = data;
  415. d->type = type;
  416. sprintf(resn, "0x%x", rsn);
  417. d->root = debugfs_create_dir(resn, root);
  418. if (!d->root) {
  419. err = -ENOMEM;
  420. goto out_free;
  421. }
  422. for (i = 0; i < nfile; i++) {
  423. d->fields[i].i = i;
  424. d->fields[i].dent = debugfs_create_file(field[i], 0400,
  425. d->root, &d->fields[i],
  426. &fops);
  427. if (!d->fields[i].dent) {
  428. err = -ENOMEM;
  429. goto out_rem;
  430. }
  431. }
  432. *dbg = d;
  433. return 0;
  434. out_rem:
  435. debugfs_remove_recursive(d->root);
  436. out_free:
  437. kfree(d);
  438. return err;
  439. }
  440. static void rem_res_tree(struct mlx5_rsc_debug *d)
  441. {
  442. debugfs_remove_recursive(d->root);
  443. kfree(d);
  444. }
  445. int mlx5_debug_qp_add(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp)
  446. {
  447. int err;
  448. if (!mlx5_debugfs_root)
  449. return 0;
  450. err = add_res_tree(dev, MLX5_DBG_RSC_QP, dev->priv.qp_debugfs,
  451. &qp->dbg, qp->qpn, qp_fields,
  452. ARRAY_SIZE(qp_fields), qp);
  453. if (err)
  454. qp->dbg = NULL;
  455. return err;
  456. }
  457. void mlx5_debug_qp_remove(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp)
  458. {
  459. if (!mlx5_debugfs_root)
  460. return;
  461. if (qp->dbg)
  462. rem_res_tree(qp->dbg);
  463. }
  464. int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
  465. {
  466. int err;
  467. if (!mlx5_debugfs_root)
  468. return 0;
  469. err = add_res_tree(dev, MLX5_DBG_RSC_EQ, dev->priv.eq_debugfs,
  470. &eq->dbg, eq->eqn, eq_fields,
  471. ARRAY_SIZE(eq_fields), eq);
  472. if (err)
  473. eq->dbg = NULL;
  474. return err;
  475. }
  476. void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
  477. {
  478. if (!mlx5_debugfs_root)
  479. return;
  480. if (eq->dbg)
  481. rem_res_tree(eq->dbg);
  482. }
  483. int mlx5_debug_cq_add(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)
  484. {
  485. int err;
  486. if (!mlx5_debugfs_root)
  487. return 0;
  488. err = add_res_tree(dev, MLX5_DBG_RSC_CQ, dev->priv.cq_debugfs,
  489. &cq->dbg, cq->cqn, cq_fields,
  490. ARRAY_SIZE(cq_fields), cq);
  491. if (err)
  492. cq->dbg = NULL;
  493. return err;
  494. }
  495. void mlx5_debug_cq_remove(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)
  496. {
  497. if (!mlx5_debugfs_root)
  498. return;
  499. if (cq->dbg)
  500. rem_res_tree(cq->dbg);
  501. }