Commit | Line | Data |
---|---|---|
77241056 MM |
1 | #ifdef CONFIG_DEBUG_FS |
2 | /* | |
05d6ac1d | 3 | * Copyright(c) 2015, 2016 Intel Corporation. |
77241056 MM |
4 | * |
5 | * This file is provided under a dual BSD/GPLv2 license. When using or | |
6 | * redistributing this file, you may do so under either license. | |
7 | * | |
8 | * GPL LICENSE SUMMARY | |
9 | * | |
77241056 MM |
10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | |
12 | * published by the Free Software Foundation. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, but | |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * General Public License for more details. | |
18 | * | |
19 | * BSD LICENSE | |
20 | * | |
77241056 MM |
21 | * Redistribution and use in source and binary forms, with or without |
22 | * modification, are permitted provided that the following conditions | |
23 | * are met: | |
24 | * | |
25 | * - Redistributions of source code must retain the above copyright | |
26 | * notice, this list of conditions and the following disclaimer. | |
27 | * - Redistributions in binary form must reproduce the above copyright | |
28 | * notice, this list of conditions and the following disclaimer in | |
29 | * the documentation and/or other materials provided with the | |
30 | * distribution. | |
31 | * - Neither the name of Intel Corporation nor the names of its | |
32 | * contributors may be used to endorse or promote products derived | |
33 | * from this software without specific prior written permission. | |
34 | * | |
35 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
36 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
37 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
38 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
39 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
40 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
41 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
42 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
43 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
44 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
45 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
46 | * | |
47 | */ | |
48 | #include <linux/debugfs.h> | |
49 | #include <linux/seq_file.h> | |
50 | #include <linux/kernel.h> | |
51 | #include <linux/export.h> | |
ae993e7f | 52 | #include <linux/module.h> |
77241056 MM |
53 | |
54 | #include "hfi.h" | |
55 | #include "debugfs.h" | |
56 | #include "device.h" | |
57 | #include "qp.h" | |
58 | #include "sdma.h" | |
59 | ||
60 | static struct dentry *hfi1_dbg_root; | |
61 | ||
62 | #define private2dd(file) (file_inode(file)->i_private) | |
63 | #define private2ppd(file) (file_inode(file)->i_private) | |
64 | ||
65 | #define DEBUGFS_SEQ_FILE_OPS(name) \ | |
66 | static const struct seq_operations _##name##_seq_ops = { \ | |
67 | .start = _##name##_seq_start, \ | |
68 | .next = _##name##_seq_next, \ | |
69 | .stop = _##name##_seq_stop, \ | |
70 | .show = _##name##_seq_show \ | |
71 | } | |
f4d507cd | 72 | |
77241056 MM |
73 | #define DEBUGFS_SEQ_FILE_OPEN(name) \ |
74 | static int _##name##_open(struct inode *inode, struct file *s) \ | |
75 | { \ | |
76 | struct seq_file *seq; \ | |
77 | int ret; \ | |
78 | ret = seq_open(s, &_##name##_seq_ops); \ | |
79 | if (ret) \ | |
80 | return ret; \ | |
81 | seq = s->private_data; \ | |
82 | seq->private = inode->i_private; \ | |
83 | return 0; \ | |
84 | } | |
85 | ||
86 | #define DEBUGFS_FILE_OPS(name) \ | |
87 | static const struct file_operations _##name##_file_ops = { \ | |
88 | .owner = THIS_MODULE, \ | |
89 | .open = _##name##_open, \ | |
90 | .read = seq_read, \ | |
91 | .llseek = seq_lseek, \ | |
92 | .release = seq_release \ | |
93 | } | |
94 | ||
95 | #define DEBUGFS_FILE_CREATE(name, parent, data, ops, mode) \ | |
96 | do { \ | |
97 | struct dentry *ent; \ | |
98 | ent = debugfs_create_file(name, mode, parent, \ | |
99 | data, ops); \ | |
100 | if (!ent) \ | |
101 | pr_warn("create of %s failed\n", name); \ | |
102 | } while (0) | |
103 | ||
77241056 MM |
104 | #define DEBUGFS_SEQ_FILE_CREATE(name, parent, data) \ |
105 | DEBUGFS_FILE_CREATE(#name, parent, data, &_##name##_file_ops, S_IRUGO) | |
106 | ||
107 | static void *_opcode_stats_seq_start(struct seq_file *s, loff_t *pos) | |
108 | __acquires(RCU) | |
109 | { | |
110 | struct hfi1_opcode_stats_perctx *opstats; | |
111 | ||
112 | rcu_read_lock(); | |
113 | if (*pos >= ARRAY_SIZE(opstats->stats)) | |
114 | return NULL; | |
115 | return pos; | |
116 | } | |
117 | ||
118 | static void *_opcode_stats_seq_next(struct seq_file *s, void *v, loff_t *pos) | |
119 | { | |
120 | struct hfi1_opcode_stats_perctx *opstats; | |
121 | ||
122 | ++*pos; | |
123 | if (*pos >= ARRAY_SIZE(opstats->stats)) | |
124 | return NULL; | |
125 | return pos; | |
126 | } | |
127 | ||
77241056 MM |
128 | static void _opcode_stats_seq_stop(struct seq_file *s, void *v) |
129 | __releases(RCU) | |
130 | { | |
131 | rcu_read_unlock(); | |
132 | } | |
133 | ||
134 | static int _opcode_stats_seq_show(struct seq_file *s, void *v) | |
135 | { | |
136 | loff_t *spos = v; | |
137 | loff_t i = *spos, j; | |
138 | u64 n_packets = 0, n_bytes = 0; | |
139 | struct hfi1_ibdev *ibd = (struct hfi1_ibdev *)s->private; | |
140 | struct hfi1_devdata *dd = dd_from_dev(ibd); | |
141 | ||
142 | for (j = 0; j < dd->first_user_ctxt; j++) { | |
143 | if (!dd->rcd[j]) | |
144 | continue; | |
145 | n_packets += dd->rcd[j]->opstats->stats[i].n_packets; | |
146 | n_bytes += dd->rcd[j]->opstats->stats[i].n_bytes; | |
147 | } | |
148 | if (!n_packets && !n_bytes) | |
149 | return SEQ_SKIP; | |
150 | seq_printf(s, "%02llx %llu/%llu\n", i, | |
17fb4f29 JJ |
151 | (unsigned long long)n_packets, |
152 | (unsigned long long)n_bytes); | |
77241056 MM |
153 | |
154 | return 0; | |
155 | } | |
156 | ||
157 | DEBUGFS_SEQ_FILE_OPS(opcode_stats); | |
158 | DEBUGFS_SEQ_FILE_OPEN(opcode_stats) | |
159 | DEBUGFS_FILE_OPS(opcode_stats); | |
160 | ||
161 | static void *_ctx_stats_seq_start(struct seq_file *s, loff_t *pos) | |
162 | { | |
163 | struct hfi1_ibdev *ibd = (struct hfi1_ibdev *)s->private; | |
164 | struct hfi1_devdata *dd = dd_from_dev(ibd); | |
165 | ||
166 | if (!*pos) | |
167 | return SEQ_START_TOKEN; | |
168 | if (*pos >= dd->first_user_ctxt) | |
169 | return NULL; | |
170 | return pos; | |
171 | } | |
172 | ||
173 | static void *_ctx_stats_seq_next(struct seq_file *s, void *v, loff_t *pos) | |
174 | { | |
175 | struct hfi1_ibdev *ibd = (struct hfi1_ibdev *)s->private; | |
176 | struct hfi1_devdata *dd = dd_from_dev(ibd); | |
177 | ||
178 | if (v == SEQ_START_TOKEN) | |
179 | return pos; | |
180 | ||
181 | ++*pos; | |
182 | if (*pos >= dd->first_user_ctxt) | |
183 | return NULL; | |
184 | return pos; | |
185 | } | |
186 | ||
187 | static void _ctx_stats_seq_stop(struct seq_file *s, void *v) | |
188 | { | |
189 | /* nothing allocated */ | |
190 | } | |
191 | ||
192 | static int _ctx_stats_seq_show(struct seq_file *s, void *v) | |
193 | { | |
194 | loff_t *spos; | |
195 | loff_t i, j; | |
196 | u64 n_packets = 0; | |
197 | struct hfi1_ibdev *ibd = (struct hfi1_ibdev *)s->private; | |
198 | struct hfi1_devdata *dd = dd_from_dev(ibd); | |
199 | ||
200 | if (v == SEQ_START_TOKEN) { | |
201 | seq_puts(s, "Ctx:npkts\n"); | |
202 | return 0; | |
203 | } | |
204 | ||
205 | spos = v; | |
206 | i = *spos; | |
207 | ||
208 | if (!dd->rcd[i]) | |
209 | return SEQ_SKIP; | |
210 | ||
211 | for (j = 0; j < ARRAY_SIZE(dd->rcd[i]->opstats->stats); j++) | |
212 | n_packets += dd->rcd[i]->opstats->stats[j].n_packets; | |
213 | ||
214 | if (!n_packets) | |
215 | return SEQ_SKIP; | |
216 | ||
217 | seq_printf(s, " %llu:%llu\n", i, n_packets); | |
218 | return 0; | |
219 | } | |
220 | ||
221 | DEBUGFS_SEQ_FILE_OPS(ctx_stats); | |
222 | DEBUGFS_SEQ_FILE_OPEN(ctx_stats) | |
223 | DEBUGFS_FILE_OPS(ctx_stats); | |
224 | ||
225 | static void *_qp_stats_seq_start(struct seq_file *s, loff_t *pos) | |
c62fb260 | 226 | __acquires(RCU) |
77241056 MM |
227 | { |
228 | struct qp_iter *iter; | |
229 | loff_t n = *pos; | |
230 | ||
77241056 | 231 | iter = qp_iter_init(s->private); |
c62fb260 MM |
232 | |
233 | /* stop calls rcu_read_unlock */ | |
234 | rcu_read_lock(); | |
235 | ||
77241056 MM |
236 | if (!iter) |
237 | return NULL; | |
238 | ||
c62fb260 | 239 | do { |
77241056 MM |
240 | if (qp_iter_next(iter)) { |
241 | kfree(iter); | |
242 | return NULL; | |
243 | } | |
c62fb260 | 244 | } while (n--); |
77241056 MM |
245 | |
246 | return iter; | |
247 | } | |
248 | ||
249 | static void *_qp_stats_seq_next(struct seq_file *s, void *iter_ptr, | |
17fb4f29 | 250 | loff_t *pos) |
c62fb260 | 251 | __must_hold(RCU) |
77241056 MM |
252 | { |
253 | struct qp_iter *iter = iter_ptr; | |
254 | ||
255 | (*pos)++; | |
256 | ||
257 | if (qp_iter_next(iter)) { | |
258 | kfree(iter); | |
259 | return NULL; | |
260 | } | |
261 | ||
262 | return iter; | |
263 | } | |
264 | ||
265 | static void _qp_stats_seq_stop(struct seq_file *s, void *iter_ptr) | |
c62fb260 | 266 | __releases(RCU) |
77241056 MM |
267 | { |
268 | rcu_read_unlock(); | |
269 | } | |
270 | ||
271 | static int _qp_stats_seq_show(struct seq_file *s, void *iter_ptr) | |
272 | { | |
273 | struct qp_iter *iter = iter_ptr; | |
274 | ||
275 | if (!iter) | |
276 | return 0; | |
277 | ||
278 | qp_iter_print(s, iter); | |
279 | ||
280 | return 0; | |
281 | } | |
282 | ||
283 | DEBUGFS_SEQ_FILE_OPS(qp_stats); | |
284 | DEBUGFS_SEQ_FILE_OPEN(qp_stats) | |
285 | DEBUGFS_FILE_OPS(qp_stats); | |
286 | ||
287 | static void *_sdes_seq_start(struct seq_file *s, loff_t *pos) | |
288 | __acquires(RCU) | |
289 | { | |
290 | struct hfi1_ibdev *ibd; | |
291 | struct hfi1_devdata *dd; | |
292 | ||
293 | rcu_read_lock(); | |
294 | ibd = (struct hfi1_ibdev *)s->private; | |
295 | dd = dd_from_dev(ibd); | |
296 | if (!dd->per_sdma || *pos >= dd->num_sdma) | |
297 | return NULL; | |
298 | return pos; | |
299 | } | |
300 | ||
301 | static void *_sdes_seq_next(struct seq_file *s, void *v, loff_t *pos) | |
302 | { | |
303 | struct hfi1_ibdev *ibd = (struct hfi1_ibdev *)s->private; | |
304 | struct hfi1_devdata *dd = dd_from_dev(ibd); | |
305 | ||
306 | ++*pos; | |
307 | if (!dd->per_sdma || *pos >= dd->num_sdma) | |
308 | return NULL; | |
309 | return pos; | |
310 | } | |
311 | ||
77241056 MM |
312 | static void _sdes_seq_stop(struct seq_file *s, void *v) |
313 | __releases(RCU) | |
314 | { | |
315 | rcu_read_unlock(); | |
316 | } | |
317 | ||
318 | static int _sdes_seq_show(struct seq_file *s, void *v) | |
319 | { | |
320 | struct hfi1_ibdev *ibd = (struct hfi1_ibdev *)s->private; | |
321 | struct hfi1_devdata *dd = dd_from_dev(ibd); | |
322 | loff_t *spos = v; | |
323 | loff_t i = *spos; | |
324 | ||
325 | sdma_seqfile_dump_sde(s, &dd->per_sdma[i]); | |
326 | return 0; | |
327 | } | |
328 | ||
329 | DEBUGFS_SEQ_FILE_OPS(sdes); | |
330 | DEBUGFS_SEQ_FILE_OPEN(sdes) | |
331 | DEBUGFS_FILE_OPS(sdes); | |
332 | ||
333 | /* read the per-device counters */ | |
334 | static ssize_t dev_counters_read(struct file *file, char __user *buf, | |
335 | size_t count, loff_t *ppos) | |
336 | { | |
337 | u64 *counters; | |
338 | size_t avail; | |
339 | struct hfi1_devdata *dd; | |
340 | ssize_t rval; | |
341 | ||
342 | rcu_read_lock(); | |
343 | dd = private2dd(file); | |
582e05c3 | 344 | avail = hfi1_read_cntrs(dd, NULL, &counters); |
77241056 MM |
345 | rval = simple_read_from_buffer(buf, count, ppos, counters, avail); |
346 | rcu_read_unlock(); | |
347 | return rval; | |
348 | } | |
349 | ||
350 | /* read the per-device counters */ | |
351 | static ssize_t dev_names_read(struct file *file, char __user *buf, | |
352 | size_t count, loff_t *ppos) | |
353 | { | |
354 | char *names; | |
355 | size_t avail; | |
356 | struct hfi1_devdata *dd; | |
357 | ssize_t rval; | |
358 | ||
359 | rcu_read_lock(); | |
360 | dd = private2dd(file); | |
582e05c3 | 361 | avail = hfi1_read_cntrs(dd, &names, NULL); |
77241056 MM |
362 | rval = simple_read_from_buffer(buf, count, ppos, names, avail); |
363 | rcu_read_unlock(); | |
364 | return rval; | |
365 | } | |
366 | ||
367 | struct counter_info { | |
368 | char *name; | |
369 | const struct file_operations ops; | |
370 | }; | |
371 | ||
372 | /* | |
373 | * Could use file_inode(file)->i_ino to figure out which file, | |
374 | * instead of separate routine for each, but for now, this works... | |
375 | */ | |
376 | ||
377 | /* read the per-port names (same for each port) */ | |
378 | static ssize_t portnames_read(struct file *file, char __user *buf, | |
379 | size_t count, loff_t *ppos) | |
380 | { | |
381 | char *names; | |
382 | size_t avail; | |
383 | struct hfi1_devdata *dd; | |
384 | ssize_t rval; | |
385 | ||
386 | rcu_read_lock(); | |
387 | dd = private2dd(file); | |
582e05c3 | 388 | avail = hfi1_read_portcntrs(dd->pport, &names, NULL); |
77241056 MM |
389 | rval = simple_read_from_buffer(buf, count, ppos, names, avail); |
390 | rcu_read_unlock(); | |
391 | return rval; | |
392 | } | |
393 | ||
394 | /* read the per-port counters */ | |
395 | static ssize_t portcntrs_debugfs_read(struct file *file, char __user *buf, | |
17fb4f29 | 396 | size_t count, loff_t *ppos) |
77241056 MM |
397 | { |
398 | u64 *counters; | |
399 | size_t avail; | |
77241056 MM |
400 | struct hfi1_pportdata *ppd; |
401 | ssize_t rval; | |
402 | ||
403 | rcu_read_lock(); | |
404 | ppd = private2ppd(file); | |
582e05c3 | 405 | avail = hfi1_read_portcntrs(ppd, NULL, &counters); |
77241056 MM |
406 | rval = simple_read_from_buffer(buf, count, ppos, counters, avail); |
407 | rcu_read_unlock(); | |
408 | return rval; | |
409 | } | |
410 | ||
c9c8ea3d DL |
411 | static void check_dyn_flag(u64 scratch0, char *p, int size, int *used, |
412 | int this_hfi, int hfi, u32 flag, const char *what) | |
413 | { | |
414 | u32 mask; | |
415 | ||
416 | mask = flag << (hfi ? CR_DYN_SHIFT : 0); | |
417 | if (scratch0 & mask) { | |
418 | *used += scnprintf(p + *used, size - *used, | |
419 | " 0x%08x - HFI%d %s in use, %s device\n", | |
420 | mask, hfi, what, | |
421 | this_hfi == hfi ? "this" : "other"); | |
422 | } | |
423 | } | |
424 | ||
425 | static ssize_t asic_flags_read(struct file *file, char __user *buf, | |
426 | size_t count, loff_t *ppos) | |
427 | { | |
428 | struct hfi1_pportdata *ppd; | |
429 | struct hfi1_devdata *dd; | |
430 | u64 scratch0; | |
431 | char *tmp; | |
432 | int ret = 0; | |
433 | int size; | |
434 | int used; | |
435 | int i; | |
436 | ||
437 | rcu_read_lock(); | |
438 | ppd = private2ppd(file); | |
439 | dd = ppd->dd; | |
440 | size = PAGE_SIZE; | |
441 | used = 0; | |
442 | tmp = kmalloc(size, GFP_KERNEL); | |
443 | if (!tmp) { | |
444 | rcu_read_unlock(); | |
445 | return -ENOMEM; | |
446 | } | |
447 | ||
448 | scratch0 = read_csr(dd, ASIC_CFG_SCRATCH); | |
449 | used += scnprintf(tmp + used, size - used, | |
450 | "Resource flags: 0x%016llx\n", scratch0); | |
451 | ||
452 | /* check permanent flag */ | |
453 | if (scratch0 & CR_THERM_INIT) { | |
454 | used += scnprintf(tmp + used, size - used, | |
455 | " 0x%08x - thermal monitoring initialized\n", | |
456 | (u32)CR_THERM_INIT); | |
457 | } | |
458 | ||
459 | /* check each dynamic flag on each HFI */ | |
460 | for (i = 0; i < 2; i++) { | |
461 | check_dyn_flag(scratch0, tmp, size, &used, dd->hfi1_id, i, | |
462 | CR_SBUS, "SBus"); | |
463 | check_dyn_flag(scratch0, tmp, size, &used, dd->hfi1_id, i, | |
464 | CR_EPROM, "EPROM"); | |
465 | check_dyn_flag(scratch0, tmp, size, &used, dd->hfi1_id, i, | |
466 | CR_I2C1, "i2c chain 1"); | |
467 | check_dyn_flag(scratch0, tmp, size, &used, dd->hfi1_id, i, | |
468 | CR_I2C2, "i2c chain 2"); | |
469 | } | |
470 | used += scnprintf(tmp + used, size - used, "Write bits to clear\n"); | |
471 | ||
472 | ret = simple_read_from_buffer(buf, count, ppos, tmp, used); | |
473 | rcu_read_unlock(); | |
474 | kfree(tmp); | |
475 | return ret; | |
476 | } | |
477 | ||
478 | static ssize_t asic_flags_write(struct file *file, const char __user *buf, | |
479 | size_t count, loff_t *ppos) | |
480 | { | |
481 | struct hfi1_pportdata *ppd; | |
482 | struct hfi1_devdata *dd; | |
483 | char *buff; | |
484 | int ret; | |
485 | unsigned long long value; | |
486 | u64 scratch0; | |
487 | u64 clear; | |
488 | ||
489 | rcu_read_lock(); | |
490 | ppd = private2ppd(file); | |
491 | dd = ppd->dd; | |
492 | ||
493 | buff = kmalloc(count + 1, GFP_KERNEL); | |
494 | if (!buff) { | |
495 | ret = -ENOMEM; | |
496 | goto do_return; | |
497 | } | |
498 | ||
499 | ret = copy_from_user(buff, buf, count); | |
500 | if (ret > 0) { | |
501 | ret = -EFAULT; | |
502 | goto do_free; | |
503 | } | |
504 | ||
505 | /* zero terminate and read the expected integer */ | |
506 | buff[count] = 0; | |
507 | ret = kstrtoull(buff, 0, &value); | |
508 | if (ret) | |
509 | goto do_free; | |
510 | clear = value; | |
511 | ||
512 | /* obtain exclusive access */ | |
513 | mutex_lock(&dd->asic_data->asic_resource_mutex); | |
514 | acquire_hw_mutex(dd); | |
515 | ||
516 | scratch0 = read_csr(dd, ASIC_CFG_SCRATCH); | |
517 | scratch0 &= ~clear; | |
518 | write_csr(dd, ASIC_CFG_SCRATCH, scratch0); | |
519 | /* force write to be visible to other HFI on another OS */ | |
520 | (void)read_csr(dd, ASIC_CFG_SCRATCH); | |
521 | ||
522 | release_hw_mutex(dd); | |
523 | mutex_unlock(&dd->asic_data->asic_resource_mutex); | |
524 | ||
525 | /* return the number of bytes written */ | |
526 | ret = count; | |
527 | ||
528 | do_free: | |
529 | kfree(buff); | |
530 | do_return: | |
531 | rcu_read_unlock(); | |
532 | return ret; | |
533 | } | |
534 | ||
77241056 MM |
535 | /* |
536 | * read the per-port QSFP data for ppd | |
537 | */ | |
538 | static ssize_t qsfp_debugfs_dump(struct file *file, char __user *buf, | |
17fb4f29 | 539 | size_t count, loff_t *ppos) |
77241056 MM |
540 | { |
541 | struct hfi1_pportdata *ppd; | |
542 | char *tmp; | |
543 | int ret; | |
544 | ||
545 | rcu_read_lock(); | |
546 | ppd = private2ppd(file); | |
547 | tmp = kmalloc(PAGE_SIZE, GFP_KERNEL); | |
548 | if (!tmp) { | |
549 | rcu_read_unlock(); | |
550 | return -ENOMEM; | |
551 | } | |
552 | ||
553 | ret = qsfp_dump(ppd, tmp, PAGE_SIZE); | |
554 | if (ret > 0) | |
555 | ret = simple_read_from_buffer(buf, count, ppos, tmp, ret); | |
556 | rcu_read_unlock(); | |
557 | kfree(tmp); | |
558 | return ret; | |
559 | } | |
560 | ||
561 | /* Do an i2c write operation on the chain for the given HFI. */ | |
562 | static ssize_t __i2c_debugfs_write(struct file *file, const char __user *buf, | |
17fb4f29 | 563 | size_t count, loff_t *ppos, u32 target) |
77241056 MM |
564 | { |
565 | struct hfi1_pportdata *ppd; | |
566 | char *buff; | |
567 | int ret; | |
568 | int i2c_addr; | |
569 | int offset; | |
570 | int total_written; | |
571 | ||
572 | rcu_read_lock(); | |
573 | ppd = private2ppd(file); | |
574 | ||
7b47622d DL |
575 | /* byte offset format: [offsetSize][i2cAddr][offsetHigh][offsetLow] */ |
576 | i2c_addr = (*ppos >> 16) & 0xffff; | |
577 | offset = *ppos & 0xffff; | |
578 | ||
579 | /* explicitly reject invalid address 0 to catch cp and cat */ | |
580 | if (i2c_addr == 0) { | |
581 | ret = -EINVAL; | |
582 | goto _return; | |
583 | } | |
584 | ||
77241056 MM |
585 | buff = kmalloc(count, GFP_KERNEL); |
586 | if (!buff) { | |
587 | ret = -ENOMEM; | |
588 | goto _return; | |
589 | } | |
590 | ||
591 | ret = copy_from_user(buff, buf, count); | |
592 | if (ret > 0) { | |
593 | ret = -EFAULT; | |
594 | goto _free; | |
595 | } | |
596 | ||
77241056 MM |
597 | total_written = i2c_write(ppd, target, i2c_addr, offset, buff, count); |
598 | if (total_written < 0) { | |
599 | ret = total_written; | |
ae993e7f | 600 | goto _free; |
77241056 MM |
601 | } |
602 | ||
603 | *ppos += total_written; | |
604 | ||
605 | ret = total_written; | |
606 | ||
607 | _free: | |
608 | kfree(buff); | |
609 | _return: | |
610 | rcu_read_unlock(); | |
611 | return ret; | |
612 | } | |
613 | ||
614 | /* Do an i2c write operation on chain for HFI 0. */ | |
615 | static ssize_t i2c1_debugfs_write(struct file *file, const char __user *buf, | |
17fb4f29 | 616 | size_t count, loff_t *ppos) |
77241056 MM |
617 | { |
618 | return __i2c_debugfs_write(file, buf, count, ppos, 0); | |
619 | } | |
620 | ||
621 | /* Do an i2c write operation on chain for HFI 1. */ | |
622 | static ssize_t i2c2_debugfs_write(struct file *file, const char __user *buf, | |
17fb4f29 | 623 | size_t count, loff_t *ppos) |
77241056 MM |
624 | { |
625 | return __i2c_debugfs_write(file, buf, count, ppos, 1); | |
626 | } | |
627 | ||
628 | /* Do an i2c read operation on the chain for the given HFI. */ | |
629 | static ssize_t __i2c_debugfs_read(struct file *file, char __user *buf, | |
17fb4f29 | 630 | size_t count, loff_t *ppos, u32 target) |
77241056 MM |
631 | { |
632 | struct hfi1_pportdata *ppd; | |
633 | char *buff; | |
634 | int ret; | |
635 | int i2c_addr; | |
636 | int offset; | |
637 | int total_read; | |
638 | ||
639 | rcu_read_lock(); | |
640 | ppd = private2ppd(file); | |
641 | ||
7b47622d DL |
642 | /* byte offset format: [offsetSize][i2cAddr][offsetHigh][offsetLow] */ |
643 | i2c_addr = (*ppos >> 16) & 0xffff; | |
644 | offset = *ppos & 0xffff; | |
645 | ||
646 | /* explicitly reject invalid address 0 to catch cp and cat */ | |
647 | if (i2c_addr == 0) { | |
648 | ret = -EINVAL; | |
649 | goto _return; | |
650 | } | |
651 | ||
77241056 MM |
652 | buff = kmalloc(count, GFP_KERNEL); |
653 | if (!buff) { | |
654 | ret = -ENOMEM; | |
655 | goto _return; | |
656 | } | |
657 | ||
77241056 MM |
658 | total_read = i2c_read(ppd, target, i2c_addr, offset, buff, count); |
659 | if (total_read < 0) { | |
660 | ret = total_read; | |
ae993e7f | 661 | goto _free; |
77241056 MM |
662 | } |
663 | ||
664 | *ppos += total_read; | |
665 | ||
666 | ret = copy_to_user(buf, buff, total_read); | |
667 | if (ret > 0) { | |
668 | ret = -EFAULT; | |
ae993e7f | 669 | goto _free; |
77241056 MM |
670 | } |
671 | ||
672 | ret = total_read; | |
673 | ||
674 | _free: | |
675 | kfree(buff); | |
676 | _return: | |
677 | rcu_read_unlock(); | |
678 | return ret; | |
679 | } | |
680 | ||
681 | /* Do an i2c read operation on chain for HFI 0. */ | |
682 | static ssize_t i2c1_debugfs_read(struct file *file, char __user *buf, | |
17fb4f29 | 683 | size_t count, loff_t *ppos) |
77241056 MM |
684 | { |
685 | return __i2c_debugfs_read(file, buf, count, ppos, 0); | |
686 | } | |
687 | ||
688 | /* Do an i2c read operation on chain for HFI 1. */ | |
689 | static ssize_t i2c2_debugfs_read(struct file *file, char __user *buf, | |
17fb4f29 | 690 | size_t count, loff_t *ppos) |
77241056 MM |
691 | { |
692 | return __i2c_debugfs_read(file, buf, count, ppos, 1); | |
693 | } | |
694 | ||
695 | /* Do a QSFP write operation on the i2c chain for the given HFI. */ | |
696 | static ssize_t __qsfp_debugfs_write(struct file *file, const char __user *buf, | |
17fb4f29 | 697 | size_t count, loff_t *ppos, u32 target) |
77241056 MM |
698 | { |
699 | struct hfi1_pportdata *ppd; | |
700 | char *buff; | |
701 | int ret; | |
702 | int total_written; | |
703 | ||
704 | rcu_read_lock(); | |
705 | if (*ppos + count > QSFP_PAGESIZE * 4) { /* base page + page00-page03 */ | |
706 | ret = -EINVAL; | |
707 | goto _return; | |
708 | } | |
709 | ||
710 | ppd = private2ppd(file); | |
711 | ||
712 | buff = kmalloc(count, GFP_KERNEL); | |
713 | if (!buff) { | |
714 | ret = -ENOMEM; | |
715 | goto _return; | |
716 | } | |
717 | ||
718 | ret = copy_from_user(buff, buf, count); | |
719 | if (ret > 0) { | |
720 | ret = -EFAULT; | |
721 | goto _free; | |
722 | } | |
723 | ||
ae993e7f | 724 | total_written = qsfp_write(ppd, target, *ppos, buff, count); |
77241056 MM |
725 | if (total_written < 0) { |
726 | ret = total_written; | |
727 | goto _free; | |
728 | } | |
729 | ||
730 | *ppos += total_written; | |
731 | ||
732 | ret = total_written; | |
733 | ||
734 | _free: | |
735 | kfree(buff); | |
736 | _return: | |
737 | rcu_read_unlock(); | |
738 | return ret; | |
739 | } | |
740 | ||
741 | /* Do a QSFP write operation on i2c chain for HFI 0. */ | |
742 | static ssize_t qsfp1_debugfs_write(struct file *file, const char __user *buf, | |
17fb4f29 | 743 | size_t count, loff_t *ppos) |
77241056 MM |
744 | { |
745 | return __qsfp_debugfs_write(file, buf, count, ppos, 0); | |
746 | } | |
747 | ||
748 | /* Do a QSFP write operation on i2c chain for HFI 1. */ | |
749 | static ssize_t qsfp2_debugfs_write(struct file *file, const char __user *buf, | |
17fb4f29 | 750 | size_t count, loff_t *ppos) |
77241056 MM |
751 | { |
752 | return __qsfp_debugfs_write(file, buf, count, ppos, 1); | |
753 | } | |
754 | ||
755 | /* Do a QSFP read operation on the i2c chain for the given HFI. */ | |
756 | static ssize_t __qsfp_debugfs_read(struct file *file, char __user *buf, | |
17fb4f29 | 757 | size_t count, loff_t *ppos, u32 target) |
77241056 MM |
758 | { |
759 | struct hfi1_pportdata *ppd; | |
760 | char *buff; | |
761 | int ret; | |
762 | int total_read; | |
763 | ||
764 | rcu_read_lock(); | |
765 | if (*ppos + count > QSFP_PAGESIZE * 4) { /* base page + page00-page03 */ | |
766 | ret = -EINVAL; | |
767 | goto _return; | |
768 | } | |
769 | ||
770 | ppd = private2ppd(file); | |
771 | ||
772 | buff = kmalloc(count, GFP_KERNEL); | |
773 | if (!buff) { | |
774 | ret = -ENOMEM; | |
775 | goto _return; | |
776 | } | |
777 | ||
ae993e7f | 778 | total_read = qsfp_read(ppd, target, *ppos, buff, count); |
77241056 MM |
779 | if (total_read < 0) { |
780 | ret = total_read; | |
781 | goto _free; | |
782 | } | |
783 | ||
784 | *ppos += total_read; | |
785 | ||
786 | ret = copy_to_user(buf, buff, total_read); | |
787 | if (ret > 0) { | |
788 | ret = -EFAULT; | |
789 | goto _free; | |
790 | } | |
791 | ||
792 | ret = total_read; | |
793 | ||
794 | _free: | |
795 | kfree(buff); | |
796 | _return: | |
797 | rcu_read_unlock(); | |
798 | return ret; | |
799 | } | |
800 | ||
801 | /* Do a QSFP read operation on i2c chain for HFI 0. */ | |
802 | static ssize_t qsfp1_debugfs_read(struct file *file, char __user *buf, | |
17fb4f29 | 803 | size_t count, loff_t *ppos) |
77241056 MM |
804 | { |
805 | return __qsfp_debugfs_read(file, buf, count, ppos, 0); | |
806 | } | |
807 | ||
808 | /* Do a QSFP read operation on i2c chain for HFI 1. */ | |
809 | static ssize_t qsfp2_debugfs_read(struct file *file, char __user *buf, | |
17fb4f29 | 810 | size_t count, loff_t *ppos) |
77241056 MM |
811 | { |
812 | return __qsfp_debugfs_read(file, buf, count, ppos, 1); | |
813 | } | |
814 | ||
ae993e7f DL |
815 | static int __i2c_debugfs_open(struct inode *in, struct file *fp, u32 target) |
816 | { | |
817 | struct hfi1_pportdata *ppd; | |
818 | int ret; | |
819 | ||
820 | if (!try_module_get(THIS_MODULE)) | |
821 | return -ENODEV; | |
822 | ||
823 | ppd = private2ppd(fp); | |
824 | ||
825 | ret = acquire_chip_resource(ppd->dd, i2c_target(target), 0); | |
826 | if (ret) /* failed - release the module */ | |
827 | module_put(THIS_MODULE); | |
828 | ||
829 | return ret; | |
830 | } | |
831 | ||
832 | static int i2c1_debugfs_open(struct inode *in, struct file *fp) | |
833 | { | |
834 | return __i2c_debugfs_open(in, fp, 0); | |
835 | } | |
836 | ||
837 | static int i2c2_debugfs_open(struct inode *in, struct file *fp) | |
838 | { | |
839 | return __i2c_debugfs_open(in, fp, 1); | |
840 | } | |
841 | ||
842 | static int __i2c_debugfs_release(struct inode *in, struct file *fp, u32 target) | |
843 | { | |
844 | struct hfi1_pportdata *ppd; | |
845 | ||
846 | ppd = private2ppd(fp); | |
847 | ||
848 | release_chip_resource(ppd->dd, i2c_target(target)); | |
849 | module_put(THIS_MODULE); | |
850 | ||
851 | return 0; | |
852 | } | |
853 | ||
854 | static int i2c1_debugfs_release(struct inode *in, struct file *fp) | |
855 | { | |
856 | return __i2c_debugfs_release(in, fp, 0); | |
857 | } | |
858 | ||
859 | static int i2c2_debugfs_release(struct inode *in, struct file *fp) | |
860 | { | |
861 | return __i2c_debugfs_release(in, fp, 1); | |
862 | } | |
863 | ||
864 | static int __qsfp_debugfs_open(struct inode *in, struct file *fp, u32 target) | |
865 | { | |
866 | struct hfi1_pportdata *ppd; | |
867 | int ret; | |
868 | ||
869 | if (!try_module_get(THIS_MODULE)) | |
870 | return -ENODEV; | |
871 | ||
872 | ppd = private2ppd(fp); | |
873 | ||
874 | ret = acquire_chip_resource(ppd->dd, i2c_target(target), 0); | |
875 | if (ret) /* failed - release the module */ | |
876 | module_put(THIS_MODULE); | |
877 | ||
878 | return ret; | |
879 | } | |
880 | ||
881 | static int qsfp1_debugfs_open(struct inode *in, struct file *fp) | |
882 | { | |
883 | return __qsfp_debugfs_open(in, fp, 0); | |
884 | } | |
885 | ||
886 | static int qsfp2_debugfs_open(struct inode *in, struct file *fp) | |
887 | { | |
888 | return __qsfp_debugfs_open(in, fp, 1); | |
889 | } | |
890 | ||
891 | static int __qsfp_debugfs_release(struct inode *in, struct file *fp, u32 target) | |
892 | { | |
893 | struct hfi1_pportdata *ppd; | |
894 | ||
895 | ppd = private2ppd(fp); | |
896 | ||
897 | release_chip_resource(ppd->dd, i2c_target(target)); | |
898 | module_put(THIS_MODULE); | |
899 | ||
900 | return 0; | |
901 | } | |
902 | ||
903 | static int qsfp1_debugfs_release(struct inode *in, struct file *fp) | |
904 | { | |
905 | return __qsfp_debugfs_release(in, fp, 0); | |
906 | } | |
907 | ||
908 | static int qsfp2_debugfs_release(struct inode *in, struct file *fp) | |
909 | { | |
910 | return __qsfp_debugfs_release(in, fp, 1); | |
911 | } | |
912 | ||
77241056 MM |
913 | #define DEBUGFS_OPS(nm, readroutine, writeroutine) \ |
914 | { \ | |
915 | .name = nm, \ | |
916 | .ops = { \ | |
917 | .read = readroutine, \ | |
918 | .write = writeroutine, \ | |
919 | .llseek = generic_file_llseek, \ | |
920 | }, \ | |
921 | } | |
922 | ||
ae993e7f DL |
923 | #define DEBUGFS_XOPS(nm, readf, writef, openf, releasef) \ |
924 | { \ | |
925 | .name = nm, \ | |
926 | .ops = { \ | |
927 | .read = readf, \ | |
928 | .write = writef, \ | |
929 | .llseek = generic_file_llseek, \ | |
930 | .open = openf, \ | |
931 | .release = releasef \ | |
932 | }, \ | |
933 | } | |
934 | ||
77241056 MM |
935 | static const struct counter_info cntr_ops[] = { |
936 | DEBUGFS_OPS("counter_names", dev_names_read, NULL), | |
937 | DEBUGFS_OPS("counters", dev_counters_read, NULL), | |
938 | DEBUGFS_OPS("portcounter_names", portnames_read, NULL), | |
939 | }; | |
940 | ||
941 | static const struct counter_info port_cntr_ops[] = { | |
942 | DEBUGFS_OPS("port%dcounters", portcntrs_debugfs_read, NULL), | |
ae993e7f DL |
943 | DEBUGFS_XOPS("i2c1", i2c1_debugfs_read, i2c1_debugfs_write, |
944 | i2c1_debugfs_open, i2c1_debugfs_release), | |
945 | DEBUGFS_XOPS("i2c2", i2c2_debugfs_read, i2c2_debugfs_write, | |
946 | i2c2_debugfs_open, i2c2_debugfs_release), | |
77241056 | 947 | DEBUGFS_OPS("qsfp_dump%d", qsfp_debugfs_dump, NULL), |
ae993e7f DL |
948 | DEBUGFS_XOPS("qsfp1", qsfp1_debugfs_read, qsfp1_debugfs_write, |
949 | qsfp1_debugfs_open, qsfp1_debugfs_release), | |
950 | DEBUGFS_XOPS("qsfp2", qsfp2_debugfs_read, qsfp2_debugfs_write, | |
951 | qsfp2_debugfs_open, qsfp2_debugfs_release), | |
c9c8ea3d | 952 | DEBUGFS_OPS("asic_flags", asic_flags_read, asic_flags_write), |
77241056 MM |
953 | }; |
954 | ||
955 | void hfi1_dbg_ibdev_init(struct hfi1_ibdev *ibd) | |
956 | { | |
957 | char name[sizeof("port0counters") + 1]; | |
958 | char link[10]; | |
959 | struct hfi1_devdata *dd = dd_from_dev(ibd); | |
960 | struct hfi1_pportdata *ppd; | |
961 | int unit = dd->unit; | |
962 | int i, j; | |
963 | ||
964 | if (!hfi1_dbg_root) | |
965 | return; | |
966 | snprintf(name, sizeof(name), "%s_%d", class_name(), unit); | |
967 | snprintf(link, sizeof(link), "%d", unit); | |
968 | ibd->hfi1_ibdev_dbg = debugfs_create_dir(name, hfi1_dbg_root); | |
969 | if (!ibd->hfi1_ibdev_dbg) { | |
970 | pr_warn("create of %s failed\n", name); | |
971 | return; | |
972 | } | |
973 | ibd->hfi1_ibdev_link = | |
974 | debugfs_create_symlink(link, hfi1_dbg_root, name); | |
975 | if (!ibd->hfi1_ibdev_link) { | |
976 | pr_warn("create of %s symlink failed\n", name); | |
977 | return; | |
978 | } | |
979 | DEBUGFS_SEQ_FILE_CREATE(opcode_stats, ibd->hfi1_ibdev_dbg, ibd); | |
980 | DEBUGFS_SEQ_FILE_CREATE(ctx_stats, ibd->hfi1_ibdev_dbg, ibd); | |
981 | DEBUGFS_SEQ_FILE_CREATE(qp_stats, ibd->hfi1_ibdev_dbg, ibd); | |
982 | DEBUGFS_SEQ_FILE_CREATE(sdes, ibd->hfi1_ibdev_dbg, ibd); | |
983 | /* dev counter files */ | |
984 | for (i = 0; i < ARRAY_SIZE(cntr_ops); i++) | |
985 | DEBUGFS_FILE_CREATE(cntr_ops[i].name, | |
986 | ibd->hfi1_ibdev_dbg, | |
987 | dd, | |
988 | &cntr_ops[i].ops, S_IRUGO); | |
989 | /* per port files */ | |
990 | for (ppd = dd->pport, j = 0; j < dd->num_pports; j++, ppd++) | |
991 | for (i = 0; i < ARRAY_SIZE(port_cntr_ops); i++) { | |
992 | snprintf(name, | |
993 | sizeof(name), | |
994 | port_cntr_ops[i].name, | |
995 | j + 1); | |
996 | DEBUGFS_FILE_CREATE(name, | |
997 | ibd->hfi1_ibdev_dbg, | |
998 | ppd, | |
999 | &port_cntr_ops[i].ops, | |
d125a6c6 | 1000 | !port_cntr_ops[i].ops.write ? |
8638b77f | 1001 | S_IRUGO : S_IRUGO | S_IWUSR); |
77241056 MM |
1002 | } |
1003 | } | |
1004 | ||
1005 | void hfi1_dbg_ibdev_exit(struct hfi1_ibdev *ibd) | |
1006 | { | |
1007 | if (!hfi1_dbg_root) | |
1008 | goto out; | |
1009 | debugfs_remove(ibd->hfi1_ibdev_link); | |
1010 | debugfs_remove_recursive(ibd->hfi1_ibdev_dbg); | |
1011 | out: | |
1012 | ibd->hfi1_ibdev_dbg = NULL; | |
1013 | synchronize_rcu(); | |
1014 | } | |
1015 | ||
1016 | /* | |
1017 | * driver stats field names, one line per stat, single string. Used by | |
1018 | * programs like hfistats to print the stats in a way which works for | |
1019 | * different versions of drivers, without changing program source. | |
1020 | * if hfi1_ib_stats changes, this needs to change. Names need to be | |
1021 | * 12 chars or less (w/o newline), for proper display by hfistats utility. | |
1022 | */ | |
1023 | static const char * const hfi1_statnames[] = { | |
1024 | /* must be element 0*/ | |
1025 | "KernIntr", | |
1026 | "ErrorIntr", | |
1027 | "Tx_Errs", | |
1028 | "Rcv_Errs", | |
1029 | "H/W_Errs", | |
1030 | "NoPIOBufs", | |
1031 | "CtxtsOpen", | |
1032 | "RcvLen_Errs", | |
1033 | "EgrBufFull", | |
1034 | "EgrHdrFull" | |
1035 | }; | |
1036 | ||
1037 | static void *_driver_stats_names_seq_start(struct seq_file *s, loff_t *pos) | |
1038 | __acquires(RCU) | |
1039 | { | |
1040 | rcu_read_lock(); | |
1041 | if (*pos >= ARRAY_SIZE(hfi1_statnames)) | |
1042 | return NULL; | |
1043 | return pos; | |
1044 | } | |
1045 | ||
1046 | static void *_driver_stats_names_seq_next( | |
1047 | struct seq_file *s, | |
1048 | void *v, | |
1049 | loff_t *pos) | |
1050 | { | |
1051 | ++*pos; | |
1052 | if (*pos >= ARRAY_SIZE(hfi1_statnames)) | |
1053 | return NULL; | |
1054 | return pos; | |
1055 | } | |
1056 | ||
1057 | static void _driver_stats_names_seq_stop(struct seq_file *s, void *v) | |
1058 | __releases(RCU) | |
1059 | { | |
1060 | rcu_read_unlock(); | |
1061 | } | |
1062 | ||
1063 | static int _driver_stats_names_seq_show(struct seq_file *s, void *v) | |
1064 | { | |
1065 | loff_t *spos = v; | |
1066 | ||
1067 | seq_printf(s, "%s\n", hfi1_statnames[*spos]); | |
1068 | return 0; | |
1069 | } | |
1070 | ||
1071 | DEBUGFS_SEQ_FILE_OPS(driver_stats_names); | |
1072 | DEBUGFS_SEQ_FILE_OPEN(driver_stats_names) | |
1073 | DEBUGFS_FILE_OPS(driver_stats_names); | |
1074 | ||
1075 | static void *_driver_stats_seq_start(struct seq_file *s, loff_t *pos) | |
1076 | __acquires(RCU) | |
1077 | { | |
1078 | rcu_read_lock(); | |
1079 | if (*pos >= ARRAY_SIZE(hfi1_statnames)) | |
1080 | return NULL; | |
1081 | return pos; | |
1082 | } | |
1083 | ||
1084 | static void *_driver_stats_seq_next(struct seq_file *s, void *v, loff_t *pos) | |
1085 | { | |
1086 | ++*pos; | |
1087 | if (*pos >= ARRAY_SIZE(hfi1_statnames)) | |
1088 | return NULL; | |
1089 | return pos; | |
1090 | } | |
1091 | ||
1092 | static void _driver_stats_seq_stop(struct seq_file *s, void *v) | |
1093 | __releases(RCU) | |
1094 | { | |
1095 | rcu_read_unlock(); | |
1096 | } | |
1097 | ||
1098 | static u64 hfi1_sps_ints(void) | |
1099 | { | |
1100 | unsigned long flags; | |
1101 | struct hfi1_devdata *dd; | |
1102 | u64 sps_ints = 0; | |
1103 | ||
1104 | spin_lock_irqsave(&hfi1_devs_lock, flags); | |
1105 | list_for_each_entry(dd, &hfi1_dev_list, list) { | |
1106 | sps_ints += get_all_cpu_total(dd->int_counter); | |
1107 | } | |
1108 | spin_unlock_irqrestore(&hfi1_devs_lock, flags); | |
1109 | return sps_ints; | |
1110 | } | |
1111 | ||
1112 | static int _driver_stats_seq_show(struct seq_file *s, void *v) | |
1113 | { | |
1114 | loff_t *spos = v; | |
1115 | char *buffer; | |
1116 | u64 *stats = (u64 *)&hfi1_stats; | |
1117 | size_t sz = seq_get_buf(s, &buffer); | |
1118 | ||
1119 | if (sz < sizeof(u64)) | |
1120 | return SEQ_SKIP; | |
1121 | /* special case for interrupts */ | |
1122 | if (*spos == 0) | |
1123 | *(u64 *)buffer = hfi1_sps_ints(); | |
1124 | else | |
1125 | *(u64 *)buffer = stats[*spos]; | |
1126 | seq_commit(s, sizeof(u64)); | |
1127 | return 0; | |
1128 | } | |
1129 | ||
1130 | DEBUGFS_SEQ_FILE_OPS(driver_stats); | |
1131 | DEBUGFS_SEQ_FILE_OPEN(driver_stats) | |
1132 | DEBUGFS_FILE_OPS(driver_stats); | |
1133 | ||
1134 | void hfi1_dbg_init(void) | |
1135 | { | |
1136 | hfi1_dbg_root = debugfs_create_dir(DRIVER_NAME, NULL); | |
1137 | if (!hfi1_dbg_root) | |
1138 | pr_warn("init of debugfs failed\n"); | |
1139 | DEBUGFS_SEQ_FILE_CREATE(driver_stats_names, hfi1_dbg_root, NULL); | |
1140 | DEBUGFS_SEQ_FILE_CREATE(driver_stats, hfi1_dbg_root, NULL); | |
1141 | } | |
1142 | ||
1143 | void hfi1_dbg_exit(void) | |
1144 | { | |
1145 | debugfs_remove_recursive(hfi1_dbg_root); | |
1146 | hfi1_dbg_root = NULL; | |
1147 | } | |
1148 | ||
1149 | #endif |