1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Linux network driver for QLogic BR-series Converged Network Adapter.
4 */
5/*
6 * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
7 * Copyright (c) 2014-2015 QLogic Corporation
8 * All rights reserved
9 * www.qlogic.com
10 */
11
12#include <linux/debugfs.h>
13#include <linux/module.h>
14#include "bnad.h"
15
16/*
17 * BNA debufs interface
18 *
19 * To access the interface, debugfs file system should be mounted
20 * if not already mounted using:
21 * mount -t debugfs none /sys/kernel/debug
22 *
23 * BNA Hierarchy:
24 * - bna/pci_dev:<pci_name>
25 * where the pci_name corresponds to the one under /sys/bus/pci/drivers/bna
26 *
27 * Debugging service available per pci_dev:
28 * fwtrc: To collect current firmware trace.
29 * fwsave: To collect last saved fw trace as a result of firmware crash.
30 * regwr: To write one word to chip register
31 * regrd: To read one or more words from chip register.
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(size: 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(size: fw_debug->buffer_len, GFP_KERNEL);
55 if (!fw_debug->debug_buffer) {
56 kfree(objp: 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(ioc: &bnad->bna.ioceth.ioc,
63 trcdata: fw_debug->debug_buffer,
64 trclen: &fw_debug->buffer_len);
65 spin_unlock_irqrestore(lock: &bnad->bna_lock, flags);
66 if (rc != BFA_STATUS_OK) {
67 kfree(objp: fw_debug->debug_buffer);
68 fw_debug->debug_buffer = NULL;
69 kfree(objp: fw_debug);
70 fw_debug = NULL;
71 netdev_warn(dev: bnad->netdev, format: "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(size: 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(size: fw_debug->buffer_len, GFP_KERNEL);
95 if (!fw_debug->debug_buffer) {
96 kfree(objp: 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(ioc: &bnad->bna.ioceth.ioc,
103 trcdata: fw_debug->debug_buffer,
104 trclen: &fw_debug->buffer_len);
105 spin_unlock_irqrestore(lock: &bnad->bna_lock, flags);
106 if (rc != BFA_STATUS_OK && rc != BFA_STATUS_ENOFSAVE) {
107 kfree(objp: fw_debug->debug_buffer);
108 fw_debug->debug_buffer = NULL;
109 kfree(objp: fw_debug);
110 fw_debug = NULL;
111 netdev_warn(dev: bnad->netdev, format: "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(size: 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 /* Get IOC info */
145 spin_lock_irqsave(&bnad->bna_lock, flags);
146 bfa_nw_ioc_get_attr(ioc: &bnad->bna.ioceth.ioc, ioc_attr: &drvinfo->ioc_attr);
147 spin_unlock_irqrestore(lock: &bnad->bna_lock, flags);
148
149 /* Retrieve CEE related info */
150 fcomp.bnad = bnad;
151 fcomp.comp_status = 0;
152 init_completion(x: &fcomp.comp);
153 spin_lock_irqsave(&bnad->bna_lock, flags);
154 ret = bfa_nw_cee_get_attr(cee: &bnad->bna.cee, attr: &drvinfo->cee_attr,
155 cbfn: bnad_cb_completion, cbarg: &fcomp);
156 if (ret != BFA_STATUS_OK) {
157 spin_unlock_irqrestore(lock: &bnad->bna_lock, flags);
158 goto out;
159 }
160 spin_unlock_irqrestore(lock: &bnad->bna_lock, flags);
161 wait_for_completion(&fcomp.comp);
162 drvinfo->cee_status = fcomp.comp_status;
163
164 /* Retrieve flash partition info */
165 fcomp.comp_status = 0;
166 reinit_completion(x: &fcomp.comp);
167 spin_lock_irqsave(&bnad->bna_lock, flags);
168 ret = bfa_nw_flash_get_attr(flash: &bnad->bna.flash, attr: &drvinfo->flash_attr,
169 cbfn: bnad_cb_completion, cbarg: &fcomp);
170 if (ret != BFA_STATUS_OK) {
171 spin_unlock_irqrestore(lock: &bnad->bna_lock, flags);
172 goto out;
173 }
174 spin_unlock_irqrestore(lock: &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(size: 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(size: drv_info->buffer_len, GFP_KERNEL);
195 if (!drv_info->debug_buffer) {
196 kfree(objp: drv_info);
197 drv_info = NULL;
198 return -ENOMEM;
199 }
200
201 mutex_lock(&bnad->conf_mutex);
202 rc = bnad_get_debug_drvinfo(bnad, buffer: drv_info->debug_buffer,
203 len: drv_info->buffer_len);
204 mutex_unlock(lock: &bnad->conf_mutex);
205 if (rc != BFA_STATUS_OK) {
206 kfree(objp: drv_info->debug_buffer);
207 drv_info->debug_buffer = NULL;
208 kfree(objp: drv_info);
209 drv_info = NULL;
210 netdev_warn(dev: bnad->netdev, format: "failed to collect drvinfo\n");
211 return -ENOMEM;
212 }
213
214 file->private_data = drv_info;
215
216 return 0;
217}
218
219/* Changes the current file position */
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, whence: orig, size: 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(to: buf, count: nbytes, ppos: pos,
241 from: debug->debug_buffer, available: 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 * Function to check if the register offset passed is valid.
253 */
254static int
255bna_reg_offset_check(struct bfa_ioc *ioc, u32 offset, u32 len)
256{
257 u8 area;
258
259 /* check [16:15] */
260 area = (offset >> 15) & 0x7;
261 if (area == 0) {
262 /* PCIe core register */
263 if (offset + (len << 2) > 0x8000) /* 8k dwords or 32KB */
264 return BFA_STATUS_EINVAL;
265 } else if (area == 0x1) {
266 /* CB 32 KB memory page */
267 if (offset + (len << 2) > 0x10000) /* 8k dwords or 32KB */
268 return BFA_STATUS_EINVAL;
269 } else {
270 /* CB register space 64KB */
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(to: buf, count: nbytes, ppos: pos,
289 from: bnad->regdata, available: bnad->reglen);
290
291 if ((*pos + nbytes) >= bnad->reglen) {
292 kfree(objp: 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 /* Copy the user space buf */
315 kern_buf = memdup_user(buf, nbytes);
316 if (IS_ERR(ptr: kern_buf))
317 return PTR_ERR(ptr: kern_buf);
318
319 rc = sscanf(kern_buf, "%x:%x", &addr, &len);
320 if (rc < 2 || len > UINT_MAX >> 2) {
321 netdev_warn(dev: bnad->netdev, format: "failed to read user buffer\n");
322 kfree(objp: kern_buf);
323 return -EINVAL;
324 }
325
326 kfree(objp: kern_buf);
327 kfree(objp: bnad->regdata);
328 bnad->reglen = 0;
329
330 bnad->regdata = kzalloc(size: 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 /* offset and len sanity check */
339 rc = bna_reg_offset_check(ioc, offset: addr, len);
340 if (rc) {
341 netdev_warn(dev: bnad->netdev, format: "failed reg offset check\n");
342 kfree(objp: 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(addr: reg_addr);
353 regbuf++;
354 reg_addr += sizeof(u32);
355 }
356 spin_unlock_irqrestore(lock: &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 /* Copy the user space buf */
375 kern_buf = memdup_user(buf, nbytes);
376 if (IS_ERR(ptr: kern_buf))
377 return PTR_ERR(ptr: kern_buf);
378
379 rc = sscanf(kern_buf, "%x:%x", &addr, &val);
380 if (rc < 2) {
381 netdev_warn(dev: bnad->netdev, format: "failed to read user buffer\n");
382 kfree(objp: kern_buf);
383 return -EINVAL;
384 }
385 kfree(objp: kern_buf);
386
387 addr &= BFA_REG_ADDRMSK(ioc); /* offset only 17 bit and word align */
388
389 /* offset and len sanity check */
390 rc = bna_reg_offset_check(ioc, offset: addr, len: 1);
391 if (rc) {
392 netdev_warn(dev: bnad->netdev, format: "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, addr: reg_addr);
399 spin_unlock_irqrestore(lock: &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(objp: 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(objp: debug->debug_buffer);
426
427 file->private_data = NULL;
428 kfree(objp: 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/* Initialize debugfs interface for BNA */
492void
493bnad_debugfs_init(struct bnad *bnad)
494{
495 const struct bnad_debugfs_entry *file;
496 char name[64];
497 int i;
498
499 /* Setup the BNA debugfs root directory*/
500 if (!bna_debugfs_root) {
501 bna_debugfs_root = debugfs_create_dir(name: "bna", NULL);
502 atomic_set(v: &bna_debugfs_port_count, i: 0);
503 if (!bna_debugfs_root) {
504 netdev_warn(dev: bnad->netdev,
505 format: "debugfs root dir creation failed\n");
506 return;
507 }
508 }
509
510 /* Setup the pci_dev debugfs directory for the port */
511 snprintf(buf: name, size: sizeof(name), fmt: "pci_dev:%s", pci_name(pdev: bnad->pcidev));
512 if (!bnad->port_debugfs_root) {
513 bnad->port_debugfs_root =
514 debugfs_create_dir(name, parent: bna_debugfs_root);
515
516 atomic_inc(v: &bna_debugfs_port_count);
517
518 for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) {
519 file = &bnad_debugfs_files[i];
520 bnad->bnad_dentry_files[i] =
521 debugfs_create_file(name: file->name,
522 mode: file->mode,
523 parent: bnad->port_debugfs_root,
524 data: bnad,
525 fops: file->fops);
526 if (!bnad->bnad_dentry_files[i]) {
527 netdev_warn(dev: bnad->netdev,
528 format: "create %s entry failed\n",
529 file->name);
530 return;
531 }
532 }
533 }
534}
535
536/* Uninitialize debugfs interface for BNA */
537void
538bnad_debugfs_uninit(struct bnad *bnad)
539{
540 int i;
541
542 for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) {
543 if (bnad->bnad_dentry_files[i]) {
544 debugfs_remove(dentry: bnad->bnad_dentry_files[i]);
545 bnad->bnad_dentry_files[i] = NULL;
546 }
547 }
548
549 /* Remove the pci_dev debugfs directory for the port */
550 if (bnad->port_debugfs_root) {
551 debugfs_remove(dentry: bnad->port_debugfs_root);
552 bnad->port_debugfs_root = NULL;
553 atomic_dec(v: &bna_debugfs_port_count);
554 }
555
556 /* Remove the BNA debugfs root directory */
557 if (atomic_read(v: &bna_debugfs_port_count) == 0) {
558 debugfs_remove(dentry: bna_debugfs_root);
559 bna_debugfs_root = NULL;
560 }
561}
562

source code of linux/drivers/net/ethernet/brocade/bna/bnad_debugfs.c