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
33337096Shselasky#include <sys/cdefs.h>
34337096Shselasky__FBSDID("$FreeBSD$");
35337096Shselasky
36219820Sjeff#include <linux/err.h>
37219820Sjeff#include <linux/seq_file.h>
38219820Sjeff
39219820Sjeffstruct file_operations;
40219820Sjeff
41219820Sjeff#include <linux/debugfs.h>
42219820Sjeff
43219820Sjeff#include "ipoib.h"
44219820Sjeff
45219820Sjeffstatic struct dentry *ipoib_root;
46219820Sjeff
47219820Sjeffstatic void format_gid(union ib_gid *gid, char *buf)
48219820Sjeff{
49219820Sjeff	int i, n;
50219820Sjeff
51219820Sjeff	for (n = 0, i = 0; i < 8; ++i) {
52219820Sjeff		n += sprintf(buf + n, "%x",
53219820Sjeff			     be16_to_cpu(((__be16 *) gid->raw)[i]));
54219820Sjeff		if (i < 7)
55219820Sjeff			buf[n++] = ':';
56219820Sjeff	}
57219820Sjeff}
58219820Sjeff
59219820Sjeffstatic void *ipoib_mcg_seq_start(struct seq_file *file, loff_t *pos)
60219820Sjeff{
61219820Sjeff	struct ipoib_mcast_iter *iter;
62219820Sjeff	loff_t n = *pos;
63219820Sjeff
64219820Sjeff	iter = ipoib_mcast_iter_init(file->private);
65219820Sjeff	if (!iter)
66219820Sjeff		return NULL;
67219820Sjeff
68219820Sjeff	while (n--) {
69219820Sjeff		if (ipoib_mcast_iter_next(iter)) {
70219820Sjeff			kfree(iter);
71219820Sjeff			return NULL;
72219820Sjeff		}
73219820Sjeff	}
74219820Sjeff
75219820Sjeff	return iter;
76219820Sjeff}
77219820Sjeff
78219820Sjeffstatic void *ipoib_mcg_seq_next(struct seq_file *file, void *iter_ptr,
79219820Sjeff				   loff_t *pos)
80219820Sjeff{
81219820Sjeff	struct ipoib_mcast_iter *iter = iter_ptr;
82219820Sjeff
83219820Sjeff	(*pos)++;
84219820Sjeff
85219820Sjeff	if (ipoib_mcast_iter_next(iter)) {
86219820Sjeff		kfree(iter);
87219820Sjeff		return NULL;
88219820Sjeff	}
89219820Sjeff
90219820Sjeff	return iter;
91219820Sjeff}
92219820Sjeff
93219820Sjeffstatic void ipoib_mcg_seq_stop(struct seq_file *file, void *iter_ptr)
94219820Sjeff{
95219820Sjeff	/* nothing for now */
96219820Sjeff}
97219820Sjeff
98219820Sjeffstatic int ipoib_mcg_seq_show(struct seq_file *file, void *iter_ptr)
99219820Sjeff{
100219820Sjeff	struct ipoib_mcast_iter *iter = iter_ptr;
101219820Sjeff	char gid_buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
102219820Sjeff	union ib_gid mgid;
103219820Sjeff	unsigned long created;
104219820Sjeff	unsigned int queuelen, complete, send_only;
105219820Sjeff
106219820Sjeff	if (!iter)
107219820Sjeff		return 0;
108219820Sjeff
109219820Sjeff	ipoib_mcast_iter_read(iter, &mgid, &created, &queuelen,
110219820Sjeff			      &complete, &send_only);
111219820Sjeff
112219820Sjeff	format_gid(&mgid, gid_buf);
113219820Sjeff
114219820Sjeff	seq_printf(file,
115219820Sjeff		   "GID: %s\n"
116219820Sjeff		   "  created: %10ld\n"
117219820Sjeff		   "  queuelen: %9d\n"
118219820Sjeff		   "  complete: %9s\n"
119219820Sjeff		   "  send_only: %8s\n"
120219820Sjeff		   "\n",
121219820Sjeff		   gid_buf, created, queuelen,
122219820Sjeff		   complete ? "yes" : "no",
123219820Sjeff		   send_only ? "yes" : "no");
124219820Sjeff
125219820Sjeff	return 0;
126219820Sjeff}
127219820Sjeff
128219820Sjeffstatic const struct seq_operations ipoib_mcg_seq_ops = {
129219820Sjeff	.start = ipoib_mcg_seq_start,
130219820Sjeff	.next  = ipoib_mcg_seq_next,
131219820Sjeff	.stop  = ipoib_mcg_seq_stop,
132219820Sjeff	.show  = ipoib_mcg_seq_show,
133219820Sjeff};
134219820Sjeff
135219820Sjeffstatic int ipoib_mcg_open(struct inode *inode, struct file *file)
136219820Sjeff{
137219820Sjeff	struct seq_file *seq;
138219820Sjeff	int ret;
139219820Sjeff
140219820Sjeff	ret = seq_open(file, &ipoib_mcg_seq_ops);
141219820Sjeff	if (ret)
142219820Sjeff		return ret;
143219820Sjeff
144219820Sjeff	seq = file->private_data;
145219820Sjeff	seq->private = inode->i_private;
146219820Sjeff
147219820Sjeff	return 0;
148219820Sjeff}
149219820Sjeff
150219820Sjeffstatic const struct file_operations ipoib_mcg_fops = {
151219820Sjeff	.owner   = THIS_MODULE,
152219820Sjeff	.open    = ipoib_mcg_open,
153219820Sjeff	.read    = seq_read,
154219820Sjeff	.llseek  = seq_lseek,
155219820Sjeff	.release = seq_release
156219820Sjeff};
157219820Sjeff
158219820Sjeffstatic void *ipoib_path_seq_start(struct seq_file *file, loff_t *pos)
159219820Sjeff{
160219820Sjeff	struct ipoib_path_iter *iter;
161219820Sjeff	loff_t n = *pos;
162219820Sjeff
163219820Sjeff	iter = ipoib_path_iter_init(file->private);
164219820Sjeff	if (!iter)
165219820Sjeff		return NULL;
166219820Sjeff
167219820Sjeff	while (n--) {
168219820Sjeff		if (ipoib_path_iter_next(iter)) {
169219820Sjeff			kfree(iter);
170219820Sjeff			return NULL;
171219820Sjeff		}
172219820Sjeff	}
173219820Sjeff
174219820Sjeff	return iter;
175219820Sjeff}
176219820Sjeff
177219820Sjeffstatic void *ipoib_path_seq_next(struct seq_file *file, void *iter_ptr,
178219820Sjeff				   loff_t *pos)
179219820Sjeff{
180219820Sjeff	struct ipoib_path_iter *iter = iter_ptr;
181219820Sjeff
182219820Sjeff	(*pos)++;
183219820Sjeff
184219820Sjeff	if (ipoib_path_iter_next(iter)) {
185219820Sjeff		kfree(iter);
186219820Sjeff		return NULL;
187219820Sjeff	}
188219820Sjeff
189219820Sjeff	return iter;
190219820Sjeff}
191219820Sjeff
192219820Sjeffstatic void ipoib_path_seq_stop(struct seq_file *file, void *iter_ptr)
193219820Sjeff{
194219820Sjeff	/* nothing for now */
195219820Sjeff}
196219820Sjeff
197219820Sjeffstatic int ipoib_path_seq_show(struct seq_file *file, void *iter_ptr)
198219820Sjeff{
199219820Sjeff	struct ipoib_path_iter *iter = iter_ptr;
200219820Sjeff	char gid_buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
201219820Sjeff	struct ipoib_path path;
202219820Sjeff	int rate;
203219820Sjeff
204219820Sjeff	if (!iter)
205219820Sjeff		return 0;
206219820Sjeff
207219820Sjeff	ipoib_path_iter_read(iter, &path);
208219820Sjeff
209219820Sjeff	format_gid(&path.pathrec.dgid, gid_buf);
210219820Sjeff
211219820Sjeff	seq_printf(file,
212219820Sjeff		   "GID: %s\n"
213219820Sjeff		   "  complete: %6s\n",
214219820Sjeff		   gid_buf, path.pathrec.dlid ? "yes" : "no");
215219820Sjeff
216219820Sjeff	if (path.pathrec.dlid) {
217219820Sjeff		rate = ib_rate_to_mult(path.pathrec.rate) * 25;
218219820Sjeff
219219820Sjeff		seq_printf(file,
220219820Sjeff			   "  DLID:     0x%04x\n"
221219820Sjeff			   "  SL: %12d\n"
222219820Sjeff			   "  rate: %*d%s Gb/sec\n",
223219820Sjeff			   be16_to_cpu(path.pathrec.dlid),
224219820Sjeff			   path.pathrec.sl,
225219820Sjeff			   10 - ((rate % 10) ? 2 : 0),
226219820Sjeff			   rate / 10, rate % 10 ? ".5" : "");
227219820Sjeff	}
228219820Sjeff
229219820Sjeff	seq_putc(file, '\n');
230219820Sjeff
231219820Sjeff	return 0;
232219820Sjeff}
233219820Sjeff
234219820Sjeffstatic const struct seq_operations ipoib_path_seq_ops = {
235219820Sjeff	.start = ipoib_path_seq_start,
236219820Sjeff	.next  = ipoib_path_seq_next,
237219820Sjeff	.stop  = ipoib_path_seq_stop,
238219820Sjeff	.show  = ipoib_path_seq_show,
239219820Sjeff};
240219820Sjeff
241219820Sjeffstatic int ipoib_path_open(struct inode *inode, struct file *file)
242219820Sjeff{
243219820Sjeff	struct seq_file *seq;
244219820Sjeff	int ret;
245219820Sjeff
246219820Sjeff	ret = seq_open(file, &ipoib_path_seq_ops);
247219820Sjeff	if (ret)
248219820Sjeff		return ret;
249219820Sjeff
250219820Sjeff	seq = file->private_data;
251219820Sjeff	seq->private = inode->i_private;
252219820Sjeff
253219820Sjeff	return 0;
254219820Sjeff}
255219820Sjeff
256219820Sjeffstatic const struct file_operations ipoib_path_fops = {
257219820Sjeff	.owner   = THIS_MODULE,
258219820Sjeff	.open    = ipoib_path_open,
259219820Sjeff	.read    = seq_read,
260219820Sjeff	.llseek  = seq_lseek,
261219820Sjeff	.release = seq_release
262219820Sjeff};
263219820Sjeff
264219820Sjeffvoid ipoib_create_debug_files(struct ifnet *dev)
265219820Sjeff{
266219820Sjeff	struct ipoib_dev_priv *priv = dev->if_softc;
267219820Sjeff	char name[IFNAMSIZ + sizeof "_path"];
268219820Sjeff
269219820Sjeff	snprintf(name, sizeof name, "%s_mcg", if_name(dev));
270219820Sjeff	priv->mcg_dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
271219820Sjeff					       ipoib_root, dev, &ipoib_mcg_fops);
272219820Sjeff	if (!priv->mcg_dentry)
273219820Sjeff		ipoib_warn(priv, "failed to create mcg debug file\n");
274219820Sjeff
275219820Sjeff	snprintf(name, sizeof name, "%s_path", if_name(dev));
276219820Sjeff	priv->path_dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
277219820Sjeff						ipoib_root, dev, &ipoib_path_fops);
278219820Sjeff	if (!priv->path_dentry)
279219820Sjeff		ipoib_warn(priv, "failed to create path debug file\n");
280219820Sjeff}
281219820Sjeff
282219820Sjeffvoid ipoib_delete_debug_files(struct ifnet *dev)
283219820Sjeff{
284219820Sjeff	struct ipoib_dev_priv *priv = dev->if_softc;
285219820Sjeff
286219820Sjeff	if (priv->mcg_dentry)
287219820Sjeff		debugfs_remove(priv->mcg_dentry);
288219820Sjeff	if (priv->path_dentry)
289219820Sjeff		debugfs_remove(priv->path_dentry);
290219820Sjeff}
291219820Sjeff
292219820Sjeffint ipoib_register_debugfs(void)
293219820Sjeff{
294219820Sjeff	ipoib_root = debugfs_create_dir("ipoib", NULL);
295219820Sjeff	return ipoib_root ? 0 : -ENOMEM;
296219820Sjeff}
297219820Sjeff
298219820Sjeffvoid ipoib_unregister_debugfs(void)
299219820Sjeff{
300219820Sjeff	debugfs_remove(ipoib_root);
301219820Sjeff}
302