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