1 | /* |
2 | * Copyright (c) 2004 Topspin Communications. 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 | |
33 | #include <linux/err.h> |
34 | #include <linux/seq_file.h> |
35 | #include <linux/slab.h> |
36 | |
37 | struct file_operations; |
38 | |
39 | #include <linux/debugfs.h> |
40 | #include <linux/export.h> |
41 | |
42 | #include "ipoib.h" |
43 | |
44 | static struct dentry *ipoib_root; |
45 | |
46 | static void format_gid(union ib_gid *gid, char *buf) |
47 | { |
48 | int i, n; |
49 | |
50 | for (n = 0, i = 0; i < 8; ++i) { |
51 | n += sprintf(buf: buf + n, fmt: "%x" , |
52 | be16_to_cpu(((__be16 *) gid->raw)[i])); |
53 | if (i < 7) |
54 | buf[n++] = ':'; |
55 | } |
56 | } |
57 | |
58 | static void *ipoib_mcg_seq_start(struct seq_file *file, loff_t *pos) |
59 | { |
60 | struct ipoib_mcast_iter *iter; |
61 | loff_t n = *pos; |
62 | |
63 | iter = ipoib_mcast_iter_init(dev: file->private); |
64 | if (!iter) |
65 | return NULL; |
66 | |
67 | while (n--) { |
68 | if (ipoib_mcast_iter_next(iter)) { |
69 | kfree(objp: iter); |
70 | return NULL; |
71 | } |
72 | } |
73 | |
74 | return iter; |
75 | } |
76 | |
77 | static void *ipoib_mcg_seq_next(struct seq_file *file, void *iter_ptr, |
78 | loff_t *pos) |
79 | { |
80 | struct ipoib_mcast_iter *iter = iter_ptr; |
81 | |
82 | (*pos)++; |
83 | |
84 | if (ipoib_mcast_iter_next(iter)) { |
85 | kfree(objp: iter); |
86 | return NULL; |
87 | } |
88 | |
89 | return iter; |
90 | } |
91 | |
92 | static void ipoib_mcg_seq_stop(struct seq_file *file, void *iter_ptr) |
93 | { |
94 | /* nothing for now */ |
95 | } |
96 | |
97 | static int ipoib_mcg_seq_show(struct seq_file *file, void *iter_ptr) |
98 | { |
99 | struct ipoib_mcast_iter *iter = iter_ptr; |
100 | char gid_buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" ]; |
101 | union ib_gid mgid; |
102 | unsigned long created; |
103 | unsigned int queuelen, complete, send_only; |
104 | |
105 | if (!iter) |
106 | return 0; |
107 | |
108 | ipoib_mcast_iter_read(iter, gid: &mgid, created: &created, queuelen: &queuelen, |
109 | complete: &complete, send_only: &send_only); |
110 | |
111 | format_gid(gid: &mgid, buf: gid_buf); |
112 | |
113 | seq_printf(m: file, |
114 | fmt: "GID: %s\n" |
115 | " created: %10ld\n" |
116 | " queuelen: %9d\n" |
117 | " complete: %9s\n" |
118 | " send_only: %8s\n" |
119 | "\n" , |
120 | gid_buf, created, queuelen, |
121 | complete ? "yes" : "no" , |
122 | send_only ? "yes" : "no" ); |
123 | |
124 | return 0; |
125 | } |
126 | |
127 | static const struct seq_operations ipoib_mcg_sops = { |
128 | .start = ipoib_mcg_seq_start, |
129 | .next = ipoib_mcg_seq_next, |
130 | .stop = ipoib_mcg_seq_stop, |
131 | .show = ipoib_mcg_seq_show, |
132 | }; |
133 | |
134 | DEFINE_SEQ_ATTRIBUTE(ipoib_mcg); |
135 | |
136 | static void *ipoib_path_seq_start(struct seq_file *file, loff_t *pos) |
137 | { |
138 | struct ipoib_path_iter *iter; |
139 | loff_t n = *pos; |
140 | |
141 | iter = ipoib_path_iter_init(dev: file->private); |
142 | if (!iter) |
143 | return NULL; |
144 | |
145 | while (n--) { |
146 | if (ipoib_path_iter_next(iter)) { |
147 | kfree(objp: iter); |
148 | return NULL; |
149 | } |
150 | } |
151 | |
152 | return iter; |
153 | } |
154 | |
155 | static void *ipoib_path_seq_next(struct seq_file *file, void *iter_ptr, |
156 | loff_t *pos) |
157 | { |
158 | struct ipoib_path_iter *iter = iter_ptr; |
159 | |
160 | (*pos)++; |
161 | |
162 | if (ipoib_path_iter_next(iter)) { |
163 | kfree(objp: iter); |
164 | return NULL; |
165 | } |
166 | |
167 | return iter; |
168 | } |
169 | |
170 | static void ipoib_path_seq_stop(struct seq_file *file, void *iter_ptr) |
171 | { |
172 | /* nothing for now */ |
173 | } |
174 | |
175 | static int ipoib_path_seq_show(struct seq_file *file, void *iter_ptr) |
176 | { |
177 | struct ipoib_path_iter *iter = iter_ptr; |
178 | char gid_buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" ]; |
179 | struct ipoib_path path; |
180 | int rate; |
181 | |
182 | if (!iter) |
183 | return 0; |
184 | |
185 | ipoib_path_iter_read(iter, path: &path); |
186 | |
187 | format_gid(gid: &path.pathrec.dgid, buf: gid_buf); |
188 | |
189 | seq_printf(m: file, |
190 | fmt: "GID: %s\n" |
191 | " complete: %6s\n" , |
192 | gid_buf, sa_path_get_dlid(rec: &path.pathrec) ? "yes" : "no" ); |
193 | |
194 | if (sa_path_get_dlid(rec: &path.pathrec)) { |
195 | rate = ib_rate_to_mbps(rate: path.pathrec.rate); |
196 | |
197 | seq_printf(m: file, |
198 | fmt: " DLID: 0x%04x\n" |
199 | " SL: %12d\n" |
200 | " rate: %8d.%d Gb/sec\n" , |
201 | be32_to_cpu(sa_path_get_dlid(&path.pathrec)), |
202 | path.pathrec.sl, |
203 | rate / 1000, rate % 1000); |
204 | } |
205 | |
206 | seq_putc(m: file, c: '\n'); |
207 | |
208 | return 0; |
209 | } |
210 | |
211 | static const struct seq_operations ipoib_path_sops = { |
212 | .start = ipoib_path_seq_start, |
213 | .next = ipoib_path_seq_next, |
214 | .stop = ipoib_path_seq_stop, |
215 | .show = ipoib_path_seq_show, |
216 | }; |
217 | |
218 | DEFINE_SEQ_ATTRIBUTE(ipoib_path); |
219 | |
220 | void ipoib_create_debug_files(struct net_device *dev) |
221 | { |
222 | struct ipoib_dev_priv *priv = ipoib_priv(dev); |
223 | char name[IFNAMSIZ + sizeof("_path" )]; |
224 | |
225 | snprintf(buf: name, size: sizeof(name), fmt: "%s_mcg" , dev->name); |
226 | priv->mcg_dentry = debugfs_create_file(name, S_IFREG | S_IRUGO, |
227 | parent: ipoib_root, data: dev, fops: &ipoib_mcg_fops); |
228 | |
229 | snprintf(buf: name, size: sizeof(name), fmt: "%s_path" , dev->name); |
230 | priv->path_dentry = debugfs_create_file(name, S_IFREG | S_IRUGO, |
231 | parent: ipoib_root, data: dev, fops: &ipoib_path_fops); |
232 | } |
233 | |
234 | void ipoib_delete_debug_files(struct net_device *dev) |
235 | { |
236 | struct ipoib_dev_priv *priv = ipoib_priv(dev); |
237 | |
238 | debugfs_remove(dentry: priv->mcg_dentry); |
239 | debugfs_remove(dentry: priv->path_dentry); |
240 | priv->mcg_dentry = priv->path_dentry = NULL; |
241 | } |
242 | |
243 | void ipoib_register_debugfs(void) |
244 | { |
245 | ipoib_root = debugfs_create_dir(name: "ipoib" , NULL); |
246 | } |
247 | |
248 | void ipoib_unregister_debugfs(void) |
249 | { |
250 | debugfs_remove(dentry: ipoib_root); |
251 | } |
252 | |