1
2
3
4
5
6
7
8
9
10
11
12#include <linux/debugfs.h>
13#include <linux/module.h>
14#include "bnad.h"
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34struct bnad_debug_info {
35 char *debug_buffer;
36 void *i_private;
37 int buffer_len;
38};
39
40static int
41bnad_debugfs_open_fwtrc(struct inode *inode, struct file *file)
42{
43 struct bnad *bnad = inode->i_private;
44 struct bnad_debug_info *fw_debug;
45 unsigned long flags;
46 int rc;
47
48 fw_debug = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL);
49 if (!fw_debug)
50 return -ENOMEM;
51
52 fw_debug->buffer_len = BNA_DBG_FWTRC_LEN;
53
54 fw_debug->debug_buffer = kzalloc(fw_debug->buffer_len, GFP_KERNEL);
55 if (!fw_debug->debug_buffer) {
56 kfree(fw_debug);
57 fw_debug = NULL;
58 return -ENOMEM;
59 }
60
61 spin_lock_irqsave(&bnad->bna_lock, flags);
62 rc = bfa_nw_ioc_debug_fwtrc(&bnad->bna.ioceth.ioc,
63 fw_debug->debug_buffer,
64 &fw_debug->buffer_len);
65 spin_unlock_irqrestore(&bnad->bna_lock, flags);
66 if (rc != BFA_STATUS_OK) {
67 kfree(fw_debug->debug_buffer);
68 fw_debug->debug_buffer = NULL;
69 kfree(fw_debug);
70 fw_debug = NULL;
71 netdev_warn(bnad->netdev, "failed to collect fwtrc\n");
72 return -ENOMEM;
73 }
74
75 file->private_data = fw_debug;
76
77 return 0;
78}
79
80static int
81bnad_debugfs_open_fwsave(struct inode *inode, struct file *file)
82{
83 struct bnad *bnad = inode->i_private;
84 struct bnad_debug_info *fw_debug;
85 unsigned long flags;
86 int rc;
87
88 fw_debug = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL);
89 if (!fw_debug)
90 return -ENOMEM;
91
92 fw_debug->buffer_len = BNA_DBG_FWTRC_LEN;
93
94 fw_debug->debug_buffer = kzalloc(fw_debug->buffer_len, GFP_KERNEL);
95 if (!fw_debug->debug_buffer) {
96 kfree(fw_debug);
97 fw_debug = NULL;
98 return -ENOMEM;
99 }
100
101 spin_lock_irqsave(&bnad->bna_lock, flags);
102 rc = bfa_nw_ioc_debug_fwsave(&bnad->bna.ioceth.ioc,
103 fw_debug->debug_buffer,
104 &fw_debug->buffer_len);
105 spin_unlock_irqrestore(&bnad->bna_lock, flags);
106 if (rc != BFA_STATUS_OK && rc != BFA_STATUS_ENOFSAVE) {
107 kfree(fw_debug->debug_buffer);
108 fw_debug->debug_buffer = NULL;
109 kfree(fw_debug);
110 fw_debug = NULL;
111 netdev_warn(bnad->netdev, "failed to collect fwsave\n");
112 return -ENOMEM;
113 }
114
115 file->private_data = fw_debug;
116
117 return 0;
118}
119
120static int
121bnad_debugfs_open_reg(struct inode *inode, struct file *file)
122{
123 struct bnad_debug_info *reg_debug;
124
125 reg_debug = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL);
126 if (!reg_debug)
127 return -ENOMEM;
128
129 reg_debug->i_private = inode->i_private;
130
131 file->private_data = reg_debug;
132
133 return 0;
134}
135
136static int
137bnad_get_debug_drvinfo(struct bnad *bnad, void *buffer, u32 len)
138{
139 struct bnad_drvinfo *drvinfo = (struct bnad_drvinfo *) buffer;
140 struct bnad_iocmd_comp fcomp;
141 unsigned long flags = 0;
142 int ret = BFA_STATUS_FAILED;
143
144
145 spin_lock_irqsave(&bnad->bna_lock, flags);
146 bfa_nw_ioc_get_attr(&bnad->bna.ioceth.ioc, &drvinfo->ioc_attr);
147 spin_unlock_irqrestore(&bnad->bna_lock, flags);
148
149
150 fcomp.bnad = bnad;
151 fcomp.comp_status = 0;
152 init_completion(&fcomp.comp);
153 spin_lock_irqsave(&bnad->bna_lock, flags);
154 ret = bfa_nw_cee_get_attr(&bnad->bna.cee, &drvinfo->cee_attr,
155 bnad_cb_completion, &fcomp);
156 if (ret != BFA_STATUS_OK) {
157 spin_unlock_irqrestore(&bnad->bna_lock, flags);
158 goto out;
159 }
160 spin_unlock_irqrestore(&bnad->bna_lock, flags);
161 wait_for_completion(&fcomp.comp);
162 drvinfo->cee_status = fcomp.comp_status;
163
164
165 fcomp.comp_status = 0;
166 reinit_completion(&fcomp.comp);
167 spin_lock_irqsave(&bnad->bna_lock, flags);
168 ret = bfa_nw_flash_get_attr(&bnad->bna.flash, &drvinfo->flash_attr,
169 bnad_cb_completion, &fcomp);
170 if (ret != BFA_STATUS_OK) {
171 spin_unlock_irqrestore(&bnad->bna_lock, flags);
172 goto out;
173 }
174 spin_unlock_irqrestore(&bnad->bna_lock, flags);
175 wait_for_completion(&fcomp.comp);
176 drvinfo->flash_status = fcomp.comp_status;
177out:
178 return ret;
179}
180
181static int
182bnad_debugfs_open_drvinfo(struct inode *inode, struct file *file)
183{
184 struct bnad *bnad = inode->i_private;
185 struct bnad_debug_info *drv_info;
186 int rc;
187
188 drv_info = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL);
189 if (!drv_info)
190 return -ENOMEM;
191
192 drv_info->buffer_len = sizeof(struct bnad_drvinfo);
193
194 drv_info->debug_buffer = kzalloc(drv_info->buffer_len, GFP_KERNEL);
195 if (!drv_info->debug_buffer) {
196 kfree(drv_info);
197 drv_info = NULL;
198 return -ENOMEM;
199 }
200
201 mutex_lock(&bnad->conf_mutex);
202 rc = bnad_get_debug_drvinfo(bnad, drv_info->debug_buffer,
203 drv_info->buffer_len);
204 mutex_unlock(&bnad->conf_mutex);
205 if (rc != BFA_STATUS_OK) {
206 kfree(drv_info->debug_buffer);
207 drv_info->debug_buffer = NULL;
208 kfree(drv_info);
209 drv_info = NULL;
210 netdev_warn(bnad->netdev, "failed to collect drvinfo\n");
211 return -ENOMEM;
212 }
213
214 file->private_data = drv_info;
215
216 return 0;
217}
218
219
220static loff_t
221bnad_debugfs_lseek(struct file *file, loff_t offset, int orig)
222{
223 struct bnad_debug_info *debug = file->private_data;
224
225 if (!debug)
226 return -EINVAL;
227
228 return fixed_size_llseek(file, offset, orig, debug->buffer_len);
229}
230
231static ssize_t
232bnad_debugfs_read(struct file *file, char __user *buf,
233 size_t nbytes, loff_t *pos)
234{
235 struct bnad_debug_info *debug = file->private_data;
236
237 if (!debug || !debug->debug_buffer)
238 return 0;
239
240 return simple_read_from_buffer(buf, nbytes, pos,
241 debug->debug_buffer, debug->buffer_len);
242}
243
244#define BFA_REG_CT_ADDRSZ (0x40000)
245#define BFA_REG_CB_ADDRSZ (0x20000)
246#define BFA_REG_ADDRSZ(__ioc) \
247 ((u32)(bfa_asic_id_ctc(bfa_ioc_devid(__ioc)) ? \
248 BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ))
249#define BFA_REG_ADDRMSK(__ioc) (BFA_REG_ADDRSZ(__ioc) - 1)
250
251
252
253
254static int
255bna_reg_offset_check(struct bfa_ioc *ioc, u32 offset, u32 len)
256{
257 u8 area;
258
259
260 area = (offset >> 15) & 0x7;
261 if (area == 0) {
262
263 if (offset + (len << 2) > 0x8000)
264 return BFA_STATUS_EINVAL;
265 } else if (area == 0x1) {
266
267 if (offset + (len << 2) > 0x10000)
268 return BFA_STATUS_EINVAL;
269 } else {
270
271 if (offset + (len << 2) > BFA_REG_ADDRMSK(ioc))
272 return BFA_STATUS_EINVAL;
273 }
274 return BFA_STATUS_OK;
275}
276
277static ssize_t
278bnad_debugfs_read_regrd(struct file *file, char __user *buf,
279 size_t nbytes, loff_t *pos)
280{
281 struct bnad_debug_info *regrd_debug = file->private_data;
282 struct bnad *bnad = (struct bnad *)regrd_debug->i_private;
283 ssize_t rc;
284
285 if (!bnad->regdata)
286 return 0;
287
288 rc = simple_read_from_buffer(buf, nbytes, pos,
289 bnad->regdata, bnad->reglen);
290
291 if ((*pos + nbytes) >= bnad->reglen) {
292 kfree(bnad->regdata);
293 bnad->regdata = NULL;
294 bnad->reglen = 0;
295 }
296
297 return rc;
298}
299
300static ssize_t
301bnad_debugfs_write_regrd(struct file *file, const char __user *buf,
302 size_t nbytes, loff_t *ppos)
303{
304 struct bnad_debug_info *regrd_debug = file->private_data;
305 struct bnad *bnad = (struct bnad *)regrd_debug->i_private;
306 struct bfa_ioc *ioc = &bnad->bna.ioceth.ioc;
307 int rc, i;
308 u32 addr, len;
309 u32 *regbuf;
310 void __iomem *rb, *reg_addr;
311 unsigned long flags;
312 void *kern_buf;
313
314
315 kern_buf = memdup_user(buf, nbytes);
316 if (IS_ERR(kern_buf))
317 return PTR_ERR(kern_buf);
318
319 rc = sscanf(kern_buf, "%x:%x", &addr, &len);
320 if (rc < 2 || len > UINT_MAX >> 2) {
321 netdev_warn(bnad->netdev, "failed to read user buffer\n");
322 kfree(kern_buf);
323 return -EINVAL;
324 }
325
326 kfree(kern_buf);
327 kfree(bnad->regdata);
328 bnad->reglen = 0;
329
330 bnad->regdata = kzalloc(len << 2, GFP_KERNEL);
331 if (!bnad->regdata)
332 return -ENOMEM;
333
334 bnad->reglen = len << 2;
335 rb = bfa_ioc_bar0(ioc);
336 addr &= BFA_REG_ADDRMSK(ioc);
337
338
339 rc = bna_reg_offset_check(ioc, addr, len);
340 if (rc) {
341 netdev_warn(bnad->netdev, "failed reg offset check\n");
342 kfree(bnad->regdata);
343 bnad->regdata = NULL;
344 bnad->reglen = 0;
345 return -EINVAL;
346 }
347
348 reg_addr = rb + addr;
349 regbuf = (u32 *)bnad->regdata;
350 spin_lock_irqsave(&bnad->bna_lock, flags);
351 for (i = 0; i < len; i++) {
352 *regbuf = readl(reg_addr);
353 regbuf++;
354 reg_addr += sizeof(u32);
355 }
356 spin_unlock_irqrestore(&bnad->bna_lock, flags);
357
358 return nbytes;
359}
360
361static ssize_t
362bnad_debugfs_write_regwr(struct file *file, const char __user *buf,
363 size_t nbytes, loff_t *ppos)
364{
365 struct bnad_debug_info *debug = file->private_data;
366 struct bnad *bnad = (struct bnad *)debug->i_private;
367 struct bfa_ioc *ioc = &bnad->bna.ioceth.ioc;
368 int rc;
369 u32 addr, val;
370 void __iomem *reg_addr;
371 unsigned long flags;
372 void *kern_buf;
373
374
375 kern_buf = memdup_user(buf, nbytes);
376 if (IS_ERR(kern_buf))
377 return PTR_ERR(kern_buf);
378
379 rc = sscanf(kern_buf, "%x:%x", &addr, &val);
380 if (rc < 2) {
381 netdev_warn(bnad->netdev, "failed to read user buffer\n");
382 kfree(kern_buf);
383 return -EINVAL;
384 }
385 kfree(kern_buf);
386
387 addr &= BFA_REG_ADDRMSK(ioc);
388
389
390 rc = bna_reg_offset_check(ioc, addr, 1);
391 if (rc) {
392 netdev_warn(bnad->netdev, "failed reg offset check\n");
393 return -EINVAL;
394 }
395
396 reg_addr = (bfa_ioc_bar0(ioc)) + addr;
397 spin_lock_irqsave(&bnad->bna_lock, flags);
398 writel(val, reg_addr);
399 spin_unlock_irqrestore(&bnad->bna_lock, flags);
400
401 return nbytes;
402}
403
404static int
405bnad_debugfs_release(struct inode *inode, struct file *file)
406{
407 struct bnad_debug_info *debug = file->private_data;
408
409 if (!debug)
410 return 0;
411
412 file->private_data = NULL;
413 kfree(debug);
414 return 0;
415}
416
417static int
418bnad_debugfs_buffer_release(struct inode *inode, struct file *file)
419{
420 struct bnad_debug_info *debug = file->private_data;
421
422 if (!debug)
423 return 0;
424
425 kfree(debug->debug_buffer);
426
427 file->private_data = NULL;
428 kfree(debug);
429 debug = NULL;
430 return 0;
431}
432
433static const struct file_operations bnad_debugfs_op_fwtrc = {
434 .owner = THIS_MODULE,
435 .open = bnad_debugfs_open_fwtrc,
436 .llseek = bnad_debugfs_lseek,
437 .read = bnad_debugfs_read,
438 .release = bnad_debugfs_buffer_release,
439};
440
441static const struct file_operations bnad_debugfs_op_fwsave = {
442 .owner = THIS_MODULE,
443 .open = bnad_debugfs_open_fwsave,
444 .llseek = bnad_debugfs_lseek,
445 .read = bnad_debugfs_read,
446 .release = bnad_debugfs_buffer_release,
447};
448
449static const struct file_operations bnad_debugfs_op_regrd = {
450 .owner = THIS_MODULE,
451 .open = bnad_debugfs_open_reg,
452 .llseek = bnad_debugfs_lseek,
453 .read = bnad_debugfs_read_regrd,
454 .write = bnad_debugfs_write_regrd,
455 .release = bnad_debugfs_release,
456};
457
458static const struct file_operations bnad_debugfs_op_regwr = {
459 .owner = THIS_MODULE,
460 .open = bnad_debugfs_open_reg,
461 .llseek = bnad_debugfs_lseek,
462 .write = bnad_debugfs_write_regwr,
463 .release = bnad_debugfs_release,
464};
465
466static const struct file_operations bnad_debugfs_op_drvinfo = {
467 .owner = THIS_MODULE,
468 .open = bnad_debugfs_open_drvinfo,
469 .llseek = bnad_debugfs_lseek,
470 .read = bnad_debugfs_read,
471 .release = bnad_debugfs_buffer_release,
472};
473
474struct bnad_debugfs_entry {
475 const char *name;
476 umode_t mode;
477 const struct file_operations *fops;
478};
479
480static const struct bnad_debugfs_entry bnad_debugfs_files[] = {
481 { "fwtrc", S_IFREG | 0444, &bnad_debugfs_op_fwtrc, },
482 { "fwsave", S_IFREG | 0444, &bnad_debugfs_op_fwsave, },
483 { "regrd", S_IFREG | 0644, &bnad_debugfs_op_regrd, },
484 { "regwr", S_IFREG | 0200, &bnad_debugfs_op_regwr, },
485 { "drvinfo", S_IFREG | 0444, &bnad_debugfs_op_drvinfo, },
486};
487
488static struct dentry *bna_debugfs_root;
489static atomic_t bna_debugfs_port_count;
490
491
492void
493bnad_debugfs_init(struct bnad *bnad)
494{
495 const struct bnad_debugfs_entry *file;
496 char name[64];
497 int i;
498
499
500 if (!bna_debugfs_root) {
501 bna_debugfs_root = debugfs_create_dir("bna", NULL);
502 atomic_set(&bna_debugfs_port_count, 0);
503 if (!bna_debugfs_root) {
504 netdev_warn(bnad->netdev,
505 "debugfs root dir creation failed\n");
506 return;
507 }
508 }
509
510
511 snprintf(name, sizeof(name), "pci_dev:%s", pci_name(bnad->pcidev));
512 if (!bnad->port_debugfs_root) {
513 bnad->port_debugfs_root =
514 debugfs_create_dir(name, bna_debugfs_root);
515 if (!bnad->port_debugfs_root) {
516 netdev_warn(bnad->netdev,
517 "debugfs root dir creation failed\n");
518 return;
519 }
520
521 atomic_inc(&bna_debugfs_port_count);
522
523 for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) {
524 file = &bnad_debugfs_files[i];
525 bnad->bnad_dentry_files[i] =
526 debugfs_create_file(file->name,
527 file->mode,
528 bnad->port_debugfs_root,
529 bnad,
530 file->fops);
531 if (!bnad->bnad_dentry_files[i]) {
532 netdev_warn(bnad->netdev,
533 "create %s entry failed\n",
534 file->name);
535 return;
536 }
537 }
538 }
539}
540
541
542void
543bnad_debugfs_uninit(struct bnad *bnad)
544{
545 int i;
546
547 for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) {
548 if (bnad->bnad_dentry_files[i]) {
549 debugfs_remove(bnad->bnad_dentry_files[i]);
550 bnad->bnad_dentry_files[i] = NULL;
551 }
552 }
553
554
555 if (bnad->port_debugfs_root) {
556 debugfs_remove(bnad->port_debugfs_root);
557 bnad->port_debugfs_root = NULL;
558 atomic_dec(&bna_debugfs_port_count);
559 }
560
561
562 if (atomic_read(&bna_debugfs_port_count) == 0) {
563 debugfs_remove(bna_debugfs_root);
564 bna_debugfs_root = NULL;
565 }
566}
567