Merge tag 'reset-for-v5.3' of git://git.pengutronix.de/git/pza/linux into arm/drivers
[sfrench/cifs-2.6.git] / drivers / net / ethernet / brocade / bna / bnad_debugfs.c
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
34 struct bnad_debug_info {
35         char *debug_buffer;
36         void *i_private;
37         int buffer_len;
38 };
39
40 static int
41 bnad_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
80 static int
81 bnad_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
120 static int
121 bnad_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
136 static int
137 bnad_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(&bnad->bna.ioceth.ioc, &drvinfo->ioc_attr);
147         spin_unlock_irqrestore(&bnad->bna_lock, flags);
148
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;
159         }
160         spin_unlock_irqrestore(&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(&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;
177 out:
178         return ret;
179 }
180
181 static int
182 bnad_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 /* Changes the current file position */
220 static loff_t
221 bnad_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
231 static ssize_t
232 bnad_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  * Function to check if the register offset passed is valid.
253  */
254 static int
255 bna_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
277 static ssize_t
278 bnad_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
300 static ssize_t
301 bnad_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(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         /* 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;
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
361 static ssize_t
362 bnad_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(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); /* offset only 17 bit and word align */
388
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;
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
404 static int
405 bnad_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
417 static int
418 bnad_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
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,
439 };
440
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,
447 };
448
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,
456 };
457
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,
464 };
465
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,
472 };
473
474 struct bnad_debugfs_entry {
475         const char *name;
476         umode_t  mode;
477         const struct file_operations *fops;
478 };
479
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, },
486 };
487
488 static struct dentry *bna_debugfs_root;
489 static atomic_t bna_debugfs_port_count;
490
491 /* Initialize debugfs interface for BNA */
492 void
493 bnad_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("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         /* 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;
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 /* Uninitialize debugfs interface for BNA */
542 void
543 bnad_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         /* 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);
559         }
560
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;
565         }
566 }