1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004 Topspin Communications.  All rights reserved.
3219820Sjeff *
4219820Sjeff * This software is available to you under a choice of one of two
5219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
6219820Sjeff * General Public License (GPL) Version 2, available from the file
7219820Sjeff * COPYING in the main directory of this source tree, or the
8219820Sjeff * OpenIB.org BSD license below:
9219820Sjeff *
10219820Sjeff *     Redistribution and use in source and binary forms, with or
11219820Sjeff *     without modification, are permitted provided that the following
12219820Sjeff *     conditions are met:
13219820Sjeff *
14219820Sjeff *      - Redistributions of source code must retain the above
15219820Sjeff *        copyright notice, this list of conditions and the following
16219820Sjeff *        disclaimer.
17219820Sjeff *
18219820Sjeff *      - Redistributions in binary form must reproduce the above
19219820Sjeff *        copyright notice, this list of conditions and the following
20219820Sjeff *        disclaimer in the documentation and/or other materials
21219820Sjeff *        provided with the distribution.
22219820Sjeff *
23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30219820Sjeff * SOFTWARE.
31219820Sjeff */
32219820Sjeff
33219820Sjeff#include <linux/err.h>
34219820Sjeff#include <linux/seq_file.h>
35219820Sjeff
36219820Sjeffstruct file_operations;
37219820Sjeff
38219820Sjeff#include <linux/debugfs.h>
39219820Sjeff
40219820Sjeff#include "ipoib.h"
41219820Sjeff
42219820Sjeffstatic struct dentry *ipoib_root;
43219820Sjeff
44219820Sjeffstatic void format_gid(union ib_gid *gid, char *buf)
45219820Sjeff{
46219820Sjeff	int i, n;
47219820Sjeff
48219820Sjeff	for (n = 0, i = 0; i < 8; ++i) {
49219820Sjeff		n += sprintf(buf + n, "%x",
50219820Sjeff			     be16_to_cpu(((__be16 *) gid->raw)[i]));
51219820Sjeff		if (i < 7)
52219820Sjeff			buf[n++] = ':';
53219820Sjeff	}
54219820Sjeff}
55219820Sjeff
56219820Sjeffstatic void *ipoib_mcg_seq_start(struct seq_file *file, loff_t *pos)
57219820Sjeff{
58219820Sjeff	struct ipoib_mcast_iter *iter;
59219820Sjeff	loff_t n = *pos;
60219820Sjeff
61219820Sjeff	iter = ipoib_mcast_iter_init(file->private);
62219820Sjeff	if (!iter)
63219820Sjeff		return NULL;
64219820Sjeff
65219820Sjeff	while (n--) {
66219820Sjeff		if (ipoib_mcast_iter_next(iter)) {
67219820Sjeff			kfree(iter);
68219820Sjeff			return NULL;
69219820Sjeff		}
70219820Sjeff	}
71219820Sjeff
72219820Sjeff	return iter;
73219820Sjeff}
74219820Sjeff
75219820Sjeffstatic void *ipoib_mcg_seq_next(struct seq_file *file, void *iter_ptr,
76219820Sjeff				   loff_t *pos)
77219820Sjeff{
78219820Sjeff	struct ipoib_mcast_iter *iter = iter_ptr;
79219820Sjeff
80219820Sjeff	(*pos)++;
81219820Sjeff
82219820Sjeff	if (ipoib_mcast_iter_next(iter)) {
83219820Sjeff		kfree(iter);
84219820Sjeff		return NULL;
85219820Sjeff	}
86219820Sjeff
87219820Sjeff	return iter;
88219820Sjeff}
89219820Sjeff
90219820Sjeffstatic void ipoib_mcg_seq_stop(struct seq_file *file, void *iter_ptr)
91219820Sjeff{
92219820Sjeff	/* nothing for now */
93219820Sjeff}
94219820Sjeff
95219820Sjeffstatic int ipoib_mcg_seq_show(struct seq_file *file, void *iter_ptr)
96219820Sjeff{
97219820Sjeff	struct ipoib_mcast_iter *iter = iter_ptr;
98219820Sjeff	char gid_buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
99219820Sjeff	union ib_gid mgid;
100219820Sjeff	unsigned long created;
101219820Sjeff	unsigned int queuelen, complete, send_only;
102219820Sjeff
103219820Sjeff	if (!iter)
104219820Sjeff		return 0;
105219820Sjeff
106219820Sjeff	ipoib_mcast_iter_read(iter, &mgid, &created, &queuelen,
107219820Sjeff			      &complete, &send_only);
108219820Sjeff
109219820Sjeff	format_gid(&mgid, gid_buf);
110219820Sjeff
111219820Sjeff	seq_printf(file,
112219820Sjeff		   "GID: %s\n"
113219820Sjeff		   "  created: %10ld\n"
114219820Sjeff		   "  queuelen: %9d\n"
115219820Sjeff		   "  complete: %9s\n"
116219820Sjeff		   "  send_only: %8s\n"
117219820Sjeff		   "\n",
118219820Sjeff		   gid_buf, created, queuelen,
119219820Sjeff		   complete ? "yes" : "no",
120219820Sjeff		   send_only ? "yes" : "no");
121219820Sjeff
122219820Sjeff	return 0;
123219820Sjeff}
124219820Sjeff
125219820Sjeffstatic const struct seq_operations ipoib_mcg_seq_ops = {
126219820Sjeff	.start = ipoib_mcg_seq_start,
127219820Sjeff	.next  = ipoib_mcg_seq_next,
128219820Sjeff	.stop  = ipoib_mcg_seq_stop,
129219820Sjeff	.show  = ipoib_mcg_seq_show,
130219820Sjeff};
131219820Sjeff
132219820Sjeffstatic int ipoib_mcg_open(struct inode *inode, struct file *file)
133219820Sjeff{
134219820Sjeff	struct seq_file *seq;
135219820Sjeff	int ret;
136219820Sjeff
137219820Sjeff	ret = seq_open(file, &ipoib_mcg_seq_ops);
138219820Sjeff	if (ret)
139219820Sjeff		return ret;
140219820Sjeff
141219820Sjeff	seq = file->private_data;
142219820Sjeff	seq->private = inode->i_private;
143219820Sjeff
144219820Sjeff	return 0;
145219820Sjeff}
146219820Sjeff
147219820Sjeffstatic const struct file_operations ipoib_mcg_fops = {
148219820Sjeff	.owner   = THIS_MODULE,
149219820Sjeff	.open    = ipoib_mcg_open,
150219820Sjeff	.read    = seq_read,
151219820Sjeff	.llseek  = seq_lseek,
152219820Sjeff	.release = seq_release
153219820Sjeff};
154219820Sjeff
155219820Sjeffstatic void *ipoib_path_seq_start(struct seq_file *file, loff_t *pos)
156219820Sjeff{
157219820Sjeff	struct ipoib_path_iter *iter;
158219820Sjeff	loff_t n = *pos;
159219820Sjeff
160219820Sjeff	iter = ipoib_path_iter_init(file->private);
161219820Sjeff	if (!iter)
162219820Sjeff		return NULL;
163219820Sjeff
164219820Sjeff	while (n--) {
165219820Sjeff		if (ipoib_path_iter_next(iter)) {
166219820Sjeff			kfree(iter);
167219820Sjeff			return NULL;
168219820Sjeff		}
169219820Sjeff	}
170219820Sjeff
171219820Sjeff	return iter;
172219820Sjeff}
173219820Sjeff
174219820Sjeffstatic void *ipoib_path_seq_next(struct seq_file *file, void *iter_ptr,
175219820Sjeff				   loff_t *pos)
176219820Sjeff{
177219820Sjeff	struct ipoib_path_iter *iter = iter_ptr;
178219820Sjeff
179219820Sjeff	(*pos)++;
180219820Sjeff
181219820Sjeff	if (ipoib_path_iter_next(iter)) {
182219820Sjeff		kfree(iter);
183219820Sjeff		return NULL;
184219820Sjeff	}
185219820Sjeff
186219820Sjeff	return iter;
187219820Sjeff}
188219820Sjeff
189219820Sjeffstatic void ipoib_path_seq_stop(struct seq_file *file, void *iter_ptr)
190219820Sjeff{
191219820Sjeff	/* nothing for now */
192219820Sjeff}
193219820Sjeff
194219820Sjeffstatic int ipoib_path_seq_show(struct seq_file *file, void *iter_ptr)
195219820Sjeff{
196219820Sjeff	struct ipoib_path_iter *iter = iter_ptr;
197219820Sjeff	char gid_buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
198219820Sjeff	struct ipoib_path path;
199219820Sjeff	int rate;
200219820Sjeff
201219820Sjeff	if (!iter)
202219820Sjeff		return 0;
203219820Sjeff
204219820Sjeff	ipoib_path_iter_read(iter, &path);
205219820Sjeff
206219820Sjeff	format_gid(&path.pathrec.dgid, gid_buf);
207219820Sjeff
208219820Sjeff	seq_printf(file,
209219820Sjeff		   "GID: %s\n"
210219820Sjeff		   "  complete: %6s\n",
211219820Sjeff		   gid_buf, path.pathrec.dlid ? "yes" : "no");
212219820Sjeff
213219820Sjeff	if (path.pathrec.dlid) {
214219820Sjeff		rate = ib_rate_to_mult(path.pathrec.rate) * 25;
215219820Sjeff
216219820Sjeff		seq_printf(file,
217219820Sjeff			   "  DLID:     0x%04x\n"
218219820Sjeff			   "  SL: %12d\n"
219219820Sjeff			   "  rate: %*d%s Gb/sec\n",
220219820Sjeff			   be16_to_cpu(path.pathrec.dlid),
221219820Sjeff			   path.pathrec.sl,
222219820Sjeff			   10 - ((rate % 10) ? 2 : 0),
223219820Sjeff			   rate / 10, rate % 10 ? ".5" : "");
224219820Sjeff	}
225219820Sjeff
226219820Sjeff	seq_putc(file, '\n');
227219820Sjeff
228219820Sjeff	return 0;
229219820Sjeff}
230219820Sjeff
231219820Sjeffstatic const struct seq_operations ipoib_path_seq_ops = {
232219820Sjeff	.start = ipoib_path_seq_start,
233219820Sjeff	.next  = ipoib_path_seq_next,
234219820Sjeff	.stop  = ipoib_path_seq_stop,
235219820Sjeff	.show  = ipoib_path_seq_show,
236219820Sjeff};
237219820Sjeff
238219820Sjeffstatic int ipoib_path_open(struct inode *inode, struct file *file)
239219820Sjeff{
240219820Sjeff	struct seq_file *seq;
241219820Sjeff	int ret;
242219820Sjeff
243219820Sjeff	ret = seq_open(file, &ipoib_path_seq_ops);
244219820Sjeff	if (ret)
245219820Sjeff		return ret;
246219820Sjeff
247219820Sjeff	seq = file->private_data;
248219820Sjeff	seq->private = inode->i_private;
249219820Sjeff
250219820Sjeff	return 0;
251219820Sjeff}
252219820Sjeff
253219820Sjeffstatic const struct file_operations ipoib_path_fops = {
254219820Sjeff	.owner   = THIS_MODULE,
255219820Sjeff	.open    = ipoib_path_open,
256219820Sjeff	.read    = seq_read,
257219820Sjeff	.llseek  = seq_lseek,
258219820Sjeff	.release = seq_release
259219820Sjeff};
260219820Sjeff
261219820Sjeffvoid ipoib_create_debug_files(struct ifnet *dev)
262219820Sjeff{
263219820Sjeff	struct ipoib_dev_priv *priv = dev->if_softc;
264219820Sjeff	char name[IFNAMSIZ + sizeof "_path"];
265219820Sjeff
266219820Sjeff	snprintf(name, sizeof name, "%s_mcg", if_name(dev));
267219820Sjeff	priv->mcg_dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
268219820Sjeff					       ipoib_root, dev, &ipoib_mcg_fops);
269219820Sjeff	if (!priv->mcg_dentry)
270219820Sjeff		ipoib_warn(priv, "failed to create mcg debug file\n");
271219820Sjeff
272219820Sjeff	snprintf(name, sizeof name, "%s_path", if_name(dev));
273219820Sjeff	priv->path_dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
274219820Sjeff						ipoib_root, dev, &ipoib_path_fops);
275219820Sjeff	if (!priv->path_dentry)
276219820Sjeff		ipoib_warn(priv, "failed to create path debug file\n");
277219820Sjeff}
278219820Sjeff
279219820Sjeffvoid ipoib_delete_debug_files(struct ifnet *dev)
280219820Sjeff{
281219820Sjeff	struct ipoib_dev_priv *priv = dev->if_softc;
282219820Sjeff
283219820Sjeff	if (priv->mcg_dentry)
284219820Sjeff		debugfs_remove(priv->mcg_dentry);
285219820Sjeff	if (priv->path_dentry)
286219820Sjeff		debugfs_remove(priv->path_dentry);
287219820Sjeff}
288219820Sjeff
289219820Sjeffint ipoib_register_debugfs(void)
290219820Sjeff{
291219820Sjeff	ipoib_root = debugfs_create_dir("ipoib", NULL);
292219820Sjeff	return ipoib_root ? 0 : -ENOMEM;
293219820Sjeff}
294219820Sjeff
295219820Sjeffvoid ipoib_unregister_debugfs(void)
296219820Sjeff{
297219820Sjeff	debugfs_remove(ipoib_root);
298219820Sjeff}
299