WIP FPC-III support
[linux/fpc-iii.git] / drivers / net / ethernet / brocade / bna / bnad_debugfs.c
blob04ad0f2b9677e1405a85e160935acc5ae757acc2
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
12 #include <linux/debugfs.h>
13 #include <linux/module.h>
14 #include "bnad.h"
17 * BNA debufs interface
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
23 * BNA Hierarchy:
24 * - bna/pci_dev:<pci_name>
25 * where the pci_name corresponds to the one under /sys/bus/pci/drivers/bna
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.
34 struct bnad_debug_info {
35 char *debug_buffer;
36 void *i_private;
37 int buffer_len;
40 static int
41 bnad_debugfs_open_fwtrc(struct inode *inode, struct file *file)
43 struct bnad *bnad = inode->i_private;
44 struct bnad_debug_info *fw_debug;
45 unsigned long flags;
46 int rc;
48 fw_debug = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL);
49 if (!fw_debug)
50 return -ENOMEM;
52 fw_debug->buffer_len = BNA_DBG_FWTRC_LEN;
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;
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;
75 file->private_data = fw_debug;
77 return 0;
80 static int
81 bnad_debugfs_open_fwsave(struct inode *inode, struct file *file)
83 struct bnad *bnad = inode->i_private;
84 struct bnad_debug_info *fw_debug;
85 unsigned long flags;
86 int rc;
88 fw_debug = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL);
89 if (!fw_debug)
90 return -ENOMEM;
92 fw_debug->buffer_len = BNA_DBG_FWTRC_LEN;
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;
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;
115 file->private_data = fw_debug;
117 return 0;
120 static int
121 bnad_debugfs_open_reg(struct inode *inode, struct file *file)
123 struct bnad_debug_info *reg_debug;
125 reg_debug = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL);
126 if (!reg_debug)
127 return -ENOMEM;
129 reg_debug->i_private = inode->i_private;
131 file->private_data = reg_debug;
133 return 0;
136 static int
137 bnad_get_debug_drvinfo(struct bnad *bnad, void *buffer, u32 len)
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;
144 /* Get IOC info */
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);
149 /* Retrieve CEE related info */
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;
160 spin_unlock_irqrestore(&bnad->bna_lock, flags);
161 wait_for_completion(&fcomp.comp);
162 drvinfo->cee_status = fcomp.comp_status;
164 /* Retrieve flash partition info */
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;
174 spin_unlock_irqrestore(&bnad->bna_lock, flags);
175 wait_for_completion(&fcomp.comp);
176 drvinfo->flash_status = fcomp.comp_status;
177 out:
178 return ret;
181 static int
182 bnad_debugfs_open_drvinfo(struct inode *inode, struct file *file)
184 struct bnad *bnad = inode->i_private;
185 struct bnad_debug_info *drv_info;
186 int rc;
188 drv_info = kzalloc(sizeof(struct bnad_debug_info), GFP_KERNEL);
189 if (!drv_info)
190 return -ENOMEM;
192 drv_info->buffer_len = sizeof(struct bnad_drvinfo);
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;
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;
214 file->private_data = drv_info;
216 return 0;
219 /* Changes the current file position */
220 static loff_t
221 bnad_debugfs_lseek(struct file *file, loff_t offset, int orig)
223 struct bnad_debug_info *debug = file->private_data;
225 if (!debug)
226 return -EINVAL;
228 return fixed_size_llseek(file, offset, orig, debug->buffer_len);
231 static ssize_t
232 bnad_debugfs_read(struct file *file, char __user *buf,
233 size_t nbytes, loff_t *pos)
235 struct bnad_debug_info *debug = file->private_data;
237 if (!debug || !debug->debug_buffer)
238 return 0;
240 return simple_read_from_buffer(buf, nbytes, pos,
241 debug->debug_buffer, debug->buffer_len);
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)
252 * Function to check if the register offset passed is valid.
254 static int
255 bna_reg_offset_check(struct bfa_ioc *ioc, u32 offset, u32 len)
257 u8 area;
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;
274 return BFA_STATUS_OK;
277 static ssize_t
278 bnad_debugfs_read_regrd(struct file *file, char __user *buf,
279 size_t nbytes, loff_t *pos)
281 struct bnad_debug_info *regrd_debug = file->private_data;
282 struct bnad *bnad = (struct bnad *)regrd_debug->i_private;
283 ssize_t rc;
285 if (!bnad->regdata)
286 return 0;
288 rc = simple_read_from_buffer(buf, nbytes, pos,
289 bnad->regdata, bnad->reglen);
291 if ((*pos + nbytes) >= bnad->reglen) {
292 kfree(bnad->regdata);
293 bnad->regdata = NULL;
294 bnad->reglen = 0;
297 return rc;
300 static ssize_t
301 bnad_debugfs_write_regrd(struct file *file, const char __user *buf,
302 size_t nbytes, loff_t *ppos)
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;
314 /* Copy the user space buf */
315 kern_buf = memdup_user(buf, nbytes);
316 if (IS_ERR(kern_buf))
317 return PTR_ERR(kern_buf);
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;
326 kfree(kern_buf);
327 kfree(bnad->regdata);
328 bnad->reglen = 0;
330 bnad->regdata = kzalloc(len << 2, GFP_KERNEL);
331 if (!bnad->regdata)
332 return -ENOMEM;
334 bnad->reglen = len << 2;
335 rb = bfa_ioc_bar0(ioc);
336 addr &= BFA_REG_ADDRMSK(ioc);
338 /* offset and len sanity check */
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;
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);
356 spin_unlock_irqrestore(&bnad->bna_lock, flags);
358 return nbytes;
361 static ssize_t
362 bnad_debugfs_write_regwr(struct file *file, const char __user *buf,
363 size_t nbytes, loff_t *ppos)
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;
374 /* Copy the user space buf */
375 kern_buf = memdup_user(buf, nbytes);
376 if (IS_ERR(kern_buf))
377 return PTR_ERR(kern_buf);
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;
385 kfree(kern_buf);
387 addr &= BFA_REG_ADDRMSK(ioc); /* offset only 17 bit and word align */
389 /* offset and len sanity check */
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;
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);
401 return nbytes;
404 static int
405 bnad_debugfs_release(struct inode *inode, struct file *file)
407 struct bnad_debug_info *debug = file->private_data;
409 if (!debug)
410 return 0;
412 file->private_data = NULL;
413 kfree(debug);
414 return 0;
417 static int
418 bnad_debugfs_buffer_release(struct inode *inode, struct file *file)
420 struct bnad_debug_info *debug = file->private_data;
422 if (!debug)
423 return 0;
425 kfree(debug->debug_buffer);
427 file->private_data = NULL;
428 kfree(debug);
429 debug = NULL;
430 return 0;
433 static 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,
441 static 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,
449 static 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,
458 static 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,
466 static 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,
474 struct bnad_debugfs_entry {
475 const char *name;
476 umode_t mode;
477 const struct file_operations *fops;
480 static 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, },
488 static struct dentry *bna_debugfs_root;
489 static atomic_t bna_debugfs_port_count;
491 /* Initialize debugfs interface for BNA */
492 void
493 bnad_debugfs_init(struct bnad *bnad)
495 const struct bnad_debugfs_entry *file;
496 char name[64];
497 int i;
499 /* Setup the BNA debugfs root directory*/
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;
510 /* Setup the pci_dev debugfs directory for the port */
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;
521 atomic_inc(&bna_debugfs_port_count);
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;
541 /* Uninitialize debugfs interface for BNA */
542 void
543 bnad_debugfs_uninit(struct bnad *bnad)
545 int i;
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;
554 /* Remove the pci_dev debugfs directory for the port */
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);
561 /* Remove the BNA debugfs root directory */
562 if (atomic_read(&bna_debugfs_port_count) == 0) {
563 debugfs_remove(bna_debugfs_root);
564 bna_debugfs_root = NULL;