162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2013 - 2017 Intel Corporation.  All rights reserved.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * This software is available to you under a choice of one of two
562306a36Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the
862306a36Sopenharmony_ci * OpenIB.org BSD license below:
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
1162306a36Sopenharmony_ci *     without modification, are permitted provided that the following
1262306a36Sopenharmony_ci *     conditions are met:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *      - Redistributions of source code must retain the above
1562306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
1662306a36Sopenharmony_ci *        disclaimer.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
1962306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
2062306a36Sopenharmony_ci *        disclaimer in the documentation and/or other materials
2162306a36Sopenharmony_ci *        provided with the distribution.
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3062306a36Sopenharmony_ci * SOFTWARE.
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_ci#include <linux/debugfs.h>
3362306a36Sopenharmony_ci#include <linux/seq_file.h>
3462306a36Sopenharmony_ci#include <linux/kernel.h>
3562306a36Sopenharmony_ci#include <linux/export.h>
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#include "qib.h"
3862306a36Sopenharmony_ci#include "qib_verbs.h"
3962306a36Sopenharmony_ci#include "qib_debugfs.h"
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic struct dentry *qib_dbg_root;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define DEBUGFS_FILE(name) \
4462306a36Sopenharmony_cistatic const struct seq_operations _##name##_seq_ops = { \
4562306a36Sopenharmony_ci	.start = _##name##_seq_start, \
4662306a36Sopenharmony_ci	.next  = _##name##_seq_next, \
4762306a36Sopenharmony_ci	.stop  = _##name##_seq_stop, \
4862306a36Sopenharmony_ci	.show  = _##name##_seq_show \
4962306a36Sopenharmony_ci}; \
5062306a36Sopenharmony_cistatic int _##name##_open(struct inode *inode, struct file *s) \
5162306a36Sopenharmony_ci{ \
5262306a36Sopenharmony_ci	struct seq_file *seq; \
5362306a36Sopenharmony_ci	int ret; \
5462306a36Sopenharmony_ci	ret =  seq_open(s, &_##name##_seq_ops); \
5562306a36Sopenharmony_ci	if (ret) \
5662306a36Sopenharmony_ci		return ret; \
5762306a36Sopenharmony_ci	seq = s->private_data; \
5862306a36Sopenharmony_ci	seq->private = inode->i_private; \
5962306a36Sopenharmony_ci	return 0; \
6062306a36Sopenharmony_ci} \
6162306a36Sopenharmony_cistatic const struct file_operations _##name##_file_ops = { \
6262306a36Sopenharmony_ci	.owner   = THIS_MODULE, \
6362306a36Sopenharmony_ci	.open    = _##name##_open, \
6462306a36Sopenharmony_ci	.read    = seq_read, \
6562306a36Sopenharmony_ci	.llseek  = seq_lseek, \
6662306a36Sopenharmony_ci	.release = seq_release \
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic void *_opcode_stats_seq_start(struct seq_file *s, loff_t *pos)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	struct qib_opcode_stats_perctx *opstats;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	if (*pos >= ARRAY_SIZE(opstats->stats))
7462306a36Sopenharmony_ci		return NULL;
7562306a36Sopenharmony_ci	return pos;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic void *_opcode_stats_seq_next(struct seq_file *s, void *v, loff_t *pos)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	struct qib_opcode_stats_perctx *opstats;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	++*pos;
8362306a36Sopenharmony_ci	if (*pos >= ARRAY_SIZE(opstats->stats))
8462306a36Sopenharmony_ci		return NULL;
8562306a36Sopenharmony_ci	return pos;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic void _opcode_stats_seq_stop(struct seq_file *s, void *v)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	/* nothing allocated */
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic int _opcode_stats_seq_show(struct seq_file *s, void *v)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	loff_t *spos = v;
9762306a36Sopenharmony_ci	loff_t i = *spos, j;
9862306a36Sopenharmony_ci	u64 n_packets = 0, n_bytes = 0;
9962306a36Sopenharmony_ci	struct qib_ibdev *ibd = (struct qib_ibdev *)s->private;
10062306a36Sopenharmony_ci	struct qib_devdata *dd = dd_from_dev(ibd);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	for (j = 0; j < dd->first_user_ctxt; j++) {
10362306a36Sopenharmony_ci		if (!dd->rcd[j])
10462306a36Sopenharmony_ci			continue;
10562306a36Sopenharmony_ci		n_packets += dd->rcd[j]->opstats->stats[i].n_packets;
10662306a36Sopenharmony_ci		n_bytes += dd->rcd[j]->opstats->stats[i].n_bytes;
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci	if (!n_packets && !n_bytes)
10962306a36Sopenharmony_ci		return SEQ_SKIP;
11062306a36Sopenharmony_ci	seq_printf(s, "%02llx %llu/%llu\n", i,
11162306a36Sopenharmony_ci		(unsigned long long) n_packets,
11262306a36Sopenharmony_ci		(unsigned long long) n_bytes);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	return 0;
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ciDEBUGFS_FILE(opcode_stats)
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic void *_ctx_stats_seq_start(struct seq_file *s, loff_t *pos)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	struct qib_ibdev *ibd = (struct qib_ibdev *)s->private;
12262306a36Sopenharmony_ci	struct qib_devdata *dd = dd_from_dev(ibd);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	if (!*pos)
12562306a36Sopenharmony_ci		return SEQ_START_TOKEN;
12662306a36Sopenharmony_ci	if (*pos >= dd->first_user_ctxt)
12762306a36Sopenharmony_ci		return NULL;
12862306a36Sopenharmony_ci	return pos;
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic void *_ctx_stats_seq_next(struct seq_file *s, void *v, loff_t *pos)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	struct qib_ibdev *ibd = (struct qib_ibdev *)s->private;
13462306a36Sopenharmony_ci	struct qib_devdata *dd = dd_from_dev(ibd);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	if (v == SEQ_START_TOKEN)
13762306a36Sopenharmony_ci		return pos;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	++*pos;
14062306a36Sopenharmony_ci	if (*pos >= dd->first_user_ctxt)
14162306a36Sopenharmony_ci		return NULL;
14262306a36Sopenharmony_ci	return pos;
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic void _ctx_stats_seq_stop(struct seq_file *s, void *v)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	/* nothing allocated */
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic int _ctx_stats_seq_show(struct seq_file *s, void *v)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	loff_t *spos;
15362306a36Sopenharmony_ci	loff_t i, j;
15462306a36Sopenharmony_ci	u64 n_packets = 0;
15562306a36Sopenharmony_ci	struct qib_ibdev *ibd = (struct qib_ibdev *)s->private;
15662306a36Sopenharmony_ci	struct qib_devdata *dd = dd_from_dev(ibd);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	if (v == SEQ_START_TOKEN) {
15962306a36Sopenharmony_ci		seq_puts(s, "Ctx:npkts\n");
16062306a36Sopenharmony_ci		return 0;
16162306a36Sopenharmony_ci	}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	spos = v;
16462306a36Sopenharmony_ci	i = *spos;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	if (!dd->rcd[i])
16762306a36Sopenharmony_ci		return SEQ_SKIP;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	for (j = 0; j < ARRAY_SIZE(dd->rcd[i]->opstats->stats); j++)
17062306a36Sopenharmony_ci		n_packets += dd->rcd[i]->opstats->stats[j].n_packets;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	if (!n_packets)
17362306a36Sopenharmony_ci		return SEQ_SKIP;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	seq_printf(s, "  %llu:%llu\n", i, n_packets);
17662306a36Sopenharmony_ci	return 0;
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ciDEBUGFS_FILE(ctx_stats)
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic void *_qp_stats_seq_start(struct seq_file *s, loff_t *pos)
18262306a36Sopenharmony_ci	__acquires(RCU)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	struct rvt_qp_iter *iter;
18562306a36Sopenharmony_ci	loff_t n = *pos;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	iter = rvt_qp_iter_init(s->private, 0, NULL);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	/* stop calls rcu_read_unlock */
19062306a36Sopenharmony_ci	rcu_read_lock();
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	if (!iter)
19362306a36Sopenharmony_ci		return NULL;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	do {
19662306a36Sopenharmony_ci		if (rvt_qp_iter_next(iter)) {
19762306a36Sopenharmony_ci			kfree(iter);
19862306a36Sopenharmony_ci			return NULL;
19962306a36Sopenharmony_ci		}
20062306a36Sopenharmony_ci	} while (n--);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	return iter;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic void *_qp_stats_seq_next(struct seq_file *s, void *iter_ptr,
20662306a36Sopenharmony_ci				   loff_t *pos)
20762306a36Sopenharmony_ci	__must_hold(RCU)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	struct rvt_qp_iter *iter = iter_ptr;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	(*pos)++;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	if (rvt_qp_iter_next(iter)) {
21462306a36Sopenharmony_ci		kfree(iter);
21562306a36Sopenharmony_ci		return NULL;
21662306a36Sopenharmony_ci	}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	return iter;
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic void _qp_stats_seq_stop(struct seq_file *s, void *iter_ptr)
22262306a36Sopenharmony_ci	__releases(RCU)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	rcu_read_unlock();
22562306a36Sopenharmony_ci}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_cistatic int _qp_stats_seq_show(struct seq_file *s, void *iter_ptr)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	struct rvt_qp_iter *iter = iter_ptr;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if (!iter)
23262306a36Sopenharmony_ci		return 0;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	qib_qp_iter_print(s, iter);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	return 0;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ciDEBUGFS_FILE(qp_stats)
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_civoid qib_dbg_ibdev_init(struct qib_ibdev *ibd)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	struct dentry *root;
24462306a36Sopenharmony_ci	char name[10];
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	snprintf(name, sizeof(name), "qib%d", dd_from_dev(ibd)->unit);
24762306a36Sopenharmony_ci	root = debugfs_create_dir(name, qib_dbg_root);
24862306a36Sopenharmony_ci	ibd->qib_ibdev_dbg = root;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	debugfs_create_file("opcode_stats", 0400, root, ibd,
25162306a36Sopenharmony_ci			    &_opcode_stats_file_ops);
25262306a36Sopenharmony_ci	debugfs_create_file("ctx_stats", 0400, root, ibd, &_ctx_stats_file_ops);
25362306a36Sopenharmony_ci	debugfs_create_file("qp_stats", 0400, root, ibd, &_qp_stats_file_ops);
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_civoid qib_dbg_ibdev_exit(struct qib_ibdev *ibd)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	if (!qib_dbg_root)
25962306a36Sopenharmony_ci		goto out;
26062306a36Sopenharmony_ci	debugfs_remove_recursive(ibd->qib_ibdev_dbg);
26162306a36Sopenharmony_ciout:
26262306a36Sopenharmony_ci	ibd->qib_ibdev_dbg = NULL;
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_civoid qib_dbg_init(void)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	qib_dbg_root = debugfs_create_dir(QIB_DRV_NAME, NULL);
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_civoid qib_dbg_exit(void)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	debugfs_remove_recursive(qib_dbg_root);
27362306a36Sopenharmony_ci	qib_dbg_root = NULL;
27462306a36Sopenharmony_ci}
275