18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2013 - 2017 Intel Corporation. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 58c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 118c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 128c2ecf20Sopenharmony_ci * conditions are met: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 158c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 168c2ecf20Sopenharmony_ci * disclaimer. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 198c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 208c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 218c2ecf20Sopenharmony_ci * provided with the distribution. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 308c2ecf20Sopenharmony_ci * SOFTWARE. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 338c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 348c2ecf20Sopenharmony_ci#include <linux/kernel.h> 358c2ecf20Sopenharmony_ci#include <linux/export.h> 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include "qib.h" 388c2ecf20Sopenharmony_ci#include "qib_verbs.h" 398c2ecf20Sopenharmony_ci#include "qib_debugfs.h" 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic struct dentry *qib_dbg_root; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define DEBUGFS_FILE(name) \ 448c2ecf20Sopenharmony_cistatic const struct seq_operations _##name##_seq_ops = { \ 458c2ecf20Sopenharmony_ci .start = _##name##_seq_start, \ 468c2ecf20Sopenharmony_ci .next = _##name##_seq_next, \ 478c2ecf20Sopenharmony_ci .stop = _##name##_seq_stop, \ 488c2ecf20Sopenharmony_ci .show = _##name##_seq_show \ 498c2ecf20Sopenharmony_ci}; \ 508c2ecf20Sopenharmony_cistatic int _##name##_open(struct inode *inode, struct file *s) \ 518c2ecf20Sopenharmony_ci{ \ 528c2ecf20Sopenharmony_ci struct seq_file *seq; \ 538c2ecf20Sopenharmony_ci int ret; \ 548c2ecf20Sopenharmony_ci ret = seq_open(s, &_##name##_seq_ops); \ 558c2ecf20Sopenharmony_ci if (ret) \ 568c2ecf20Sopenharmony_ci return ret; \ 578c2ecf20Sopenharmony_ci seq = s->private_data; \ 588c2ecf20Sopenharmony_ci seq->private = inode->i_private; \ 598c2ecf20Sopenharmony_ci return 0; \ 608c2ecf20Sopenharmony_ci} \ 618c2ecf20Sopenharmony_cistatic const struct file_operations _##name##_file_ops = { \ 628c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 638c2ecf20Sopenharmony_ci .open = _##name##_open, \ 648c2ecf20Sopenharmony_ci .read = seq_read, \ 658c2ecf20Sopenharmony_ci .llseek = seq_lseek, \ 668c2ecf20Sopenharmony_ci .release = seq_release \ 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic void *_opcode_stats_seq_start(struct seq_file *s, loff_t *pos) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci struct qib_opcode_stats_perctx *opstats; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (*pos >= ARRAY_SIZE(opstats->stats)) 748c2ecf20Sopenharmony_ci return NULL; 758c2ecf20Sopenharmony_ci return pos; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic void *_opcode_stats_seq_next(struct seq_file *s, void *v, loff_t *pos) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci struct qib_opcode_stats_perctx *opstats; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci ++*pos; 838c2ecf20Sopenharmony_ci if (*pos >= ARRAY_SIZE(opstats->stats)) 848c2ecf20Sopenharmony_ci return NULL; 858c2ecf20Sopenharmony_ci return pos; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic void _opcode_stats_seq_stop(struct seq_file *s, void *v) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci /* nothing allocated */ 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic int _opcode_stats_seq_show(struct seq_file *s, void *v) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci loff_t *spos = v; 978c2ecf20Sopenharmony_ci loff_t i = *spos, j; 988c2ecf20Sopenharmony_ci u64 n_packets = 0, n_bytes = 0; 998c2ecf20Sopenharmony_ci struct qib_ibdev *ibd = (struct qib_ibdev *)s->private; 1008c2ecf20Sopenharmony_ci struct qib_devdata *dd = dd_from_dev(ibd); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci for (j = 0; j < dd->first_user_ctxt; j++) { 1038c2ecf20Sopenharmony_ci if (!dd->rcd[j]) 1048c2ecf20Sopenharmony_ci continue; 1058c2ecf20Sopenharmony_ci n_packets += dd->rcd[j]->opstats->stats[i].n_packets; 1068c2ecf20Sopenharmony_ci n_bytes += dd->rcd[j]->opstats->stats[i].n_bytes; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci if (!n_packets && !n_bytes) 1098c2ecf20Sopenharmony_ci return SEQ_SKIP; 1108c2ecf20Sopenharmony_ci seq_printf(s, "%02llx %llu/%llu\n", i, 1118c2ecf20Sopenharmony_ci (unsigned long long) n_packets, 1128c2ecf20Sopenharmony_ci (unsigned long long) n_bytes); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return 0; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ciDEBUGFS_FILE(opcode_stats) 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic void *_ctx_stats_seq_start(struct seq_file *s, loff_t *pos) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct qib_ibdev *ibd = (struct qib_ibdev *)s->private; 1228c2ecf20Sopenharmony_ci struct qib_devdata *dd = dd_from_dev(ibd); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (!*pos) 1258c2ecf20Sopenharmony_ci return SEQ_START_TOKEN; 1268c2ecf20Sopenharmony_ci if (*pos >= dd->first_user_ctxt) 1278c2ecf20Sopenharmony_ci return NULL; 1288c2ecf20Sopenharmony_ci return pos; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic void *_ctx_stats_seq_next(struct seq_file *s, void *v, loff_t *pos) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct qib_ibdev *ibd = (struct qib_ibdev *)s->private; 1348c2ecf20Sopenharmony_ci struct qib_devdata *dd = dd_from_dev(ibd); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (v == SEQ_START_TOKEN) 1378c2ecf20Sopenharmony_ci return pos; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci ++*pos; 1408c2ecf20Sopenharmony_ci if (*pos >= dd->first_user_ctxt) 1418c2ecf20Sopenharmony_ci return NULL; 1428c2ecf20Sopenharmony_ci return pos; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic void _ctx_stats_seq_stop(struct seq_file *s, void *v) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci /* nothing allocated */ 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic int _ctx_stats_seq_show(struct seq_file *s, void *v) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci loff_t *spos; 1538c2ecf20Sopenharmony_ci loff_t i, j; 1548c2ecf20Sopenharmony_ci u64 n_packets = 0; 1558c2ecf20Sopenharmony_ci struct qib_ibdev *ibd = (struct qib_ibdev *)s->private; 1568c2ecf20Sopenharmony_ci struct qib_devdata *dd = dd_from_dev(ibd); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (v == SEQ_START_TOKEN) { 1598c2ecf20Sopenharmony_ci seq_puts(s, "Ctx:npkts\n"); 1608c2ecf20Sopenharmony_ci return 0; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci spos = v; 1648c2ecf20Sopenharmony_ci i = *spos; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci if (!dd->rcd[i]) 1678c2ecf20Sopenharmony_ci return SEQ_SKIP; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(dd->rcd[i]->opstats->stats); j++) 1708c2ecf20Sopenharmony_ci n_packets += dd->rcd[i]->opstats->stats[j].n_packets; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (!n_packets) 1738c2ecf20Sopenharmony_ci return SEQ_SKIP; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci seq_printf(s, " %llu:%llu\n", i, n_packets); 1768c2ecf20Sopenharmony_ci return 0; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ciDEBUGFS_FILE(ctx_stats) 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic void *_qp_stats_seq_start(struct seq_file *s, loff_t *pos) 1828c2ecf20Sopenharmony_ci __acquires(RCU) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct rvt_qp_iter *iter; 1858c2ecf20Sopenharmony_ci loff_t n = *pos; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci iter = rvt_qp_iter_init(s->private, 0, NULL); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* stop calls rcu_read_unlock */ 1908c2ecf20Sopenharmony_ci rcu_read_lock(); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (!iter) 1938c2ecf20Sopenharmony_ci return NULL; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci do { 1968c2ecf20Sopenharmony_ci if (rvt_qp_iter_next(iter)) { 1978c2ecf20Sopenharmony_ci kfree(iter); 1988c2ecf20Sopenharmony_ci return NULL; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci } while (n--); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci return iter; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic void *_qp_stats_seq_next(struct seq_file *s, void *iter_ptr, 2068c2ecf20Sopenharmony_ci loff_t *pos) 2078c2ecf20Sopenharmony_ci __must_hold(RCU) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci struct rvt_qp_iter *iter = iter_ptr; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci (*pos)++; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (rvt_qp_iter_next(iter)) { 2148c2ecf20Sopenharmony_ci kfree(iter); 2158c2ecf20Sopenharmony_ci return NULL; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return iter; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic void _qp_stats_seq_stop(struct seq_file *s, void *iter_ptr) 2228c2ecf20Sopenharmony_ci __releases(RCU) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci rcu_read_unlock(); 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic int _qp_stats_seq_show(struct seq_file *s, void *iter_ptr) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci struct rvt_qp_iter *iter = iter_ptr; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (!iter) 2328c2ecf20Sopenharmony_ci return 0; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci qib_qp_iter_print(s, iter); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci return 0; 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ciDEBUGFS_FILE(qp_stats) 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_civoid qib_dbg_ibdev_init(struct qib_ibdev *ibd) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct dentry *root; 2448c2ecf20Sopenharmony_ci char name[10]; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "qib%d", dd_from_dev(ibd)->unit); 2478c2ecf20Sopenharmony_ci root = debugfs_create_dir(name, qib_dbg_root); 2488c2ecf20Sopenharmony_ci ibd->qib_ibdev_dbg = root; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci debugfs_create_file("opcode_stats", 0400, root, ibd, 2518c2ecf20Sopenharmony_ci &_opcode_stats_file_ops); 2528c2ecf20Sopenharmony_ci debugfs_create_file("ctx_stats", 0400, root, ibd, &_ctx_stats_file_ops); 2538c2ecf20Sopenharmony_ci debugfs_create_file("qp_stats", 0400, root, ibd, &_qp_stats_file_ops); 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_civoid qib_dbg_ibdev_exit(struct qib_ibdev *ibd) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci if (!qib_dbg_root) 2598c2ecf20Sopenharmony_ci goto out; 2608c2ecf20Sopenharmony_ci debugfs_remove_recursive(ibd->qib_ibdev_dbg); 2618c2ecf20Sopenharmony_ciout: 2628c2ecf20Sopenharmony_ci ibd->qib_ibdev_dbg = NULL; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_civoid qib_dbg_init(void) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci qib_dbg_root = debugfs_create_dir(QIB_DRV_NAME, NULL); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_civoid qib_dbg_exit(void) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci debugfs_remove_recursive(qib_dbg_root); 2738c2ecf20Sopenharmony_ci qib_dbg_root = NULL; 2748c2ecf20Sopenharmony_ci} 275