]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/net/ethernet/brocade/bna/bnad_debugfs.c
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[mirror_ubuntu-jammy-kernel.git] / drivers / net / ethernet / brocade / bna / bnad_debugfs.c
CommitLineData
52fa7bf9 1// SPDX-License-Identifier: GPL-2.0-only
7afc5dbd 2/*
2732ba56 3 * Linux network driver for QLogic BR-series Converged Network Adapter.
7afc5dbd
KG
4 */
5/*
2732ba56
RM
6 * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
7 * Copyright (c) 2014-2015 QLogic Corporation
7afc5dbd 8 * All rights reserved
2732ba56 9 * www.qlogic.com
7afc5dbd
KG
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(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;
7afc5dbd
KG
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;
ecc46789 71 netdev_warn(bnad->netdev, "failed to collect fwtrc\n");
7afc5dbd
KG
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;
7afc5dbd
KG
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;
ecc46789 111 netdev_warn(bnad->netdev, "failed to collect fwsave\n");
7afc5dbd
KG
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 /* 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;
6e4ab361 166 reinit_completion(&fcomp.comp);
7afc5dbd
KG
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;
7afc5dbd
KG
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;
ecc46789 210 netdev_warn(bnad->netdev, "failed to collect drvinfo\n");
7afc5dbd
KG
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{
7afc5dbd
KG
223 struct bnad_debug_info *debug = file->private_data;
224
225 if (!debug)
226 return -EINVAL;
227
c0caa07b 228 return fixed_size_llseek(file, offset, orig, debug->buffer_len);
7afc5dbd
KG
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 * 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 */
ebb56d37 263 if (offset + (len << 2) > 0x8000) /* 8k dwords or 32KB */
7afc5dbd
KG
264 return BFA_STATUS_EINVAL;
265 } else if (area == 0x1) {
266 /* CB 32 KB memory page */
ebb56d37 267 if (offset + (len << 2) > 0x10000) /* 8k dwords or 32KB */
7afc5dbd
KG
268 return BFA_STATUS_EINVAL;
269 } else {
270 /* CB register space 64KB */
ebb56d37 271 if (offset + (len << 2) > BFA_REG_ADDRMSK(ioc))
7afc5dbd
KG
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;
112b6b79 307 int rc, i;
308 u32 addr, len;
7afc5dbd
KG
309 u32 *regbuf;
310 void __iomem *rb, *reg_addr;
311 unsigned long flags;
312 void *kern_buf;
313
d0e6a806
IV
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);
7afc5dbd
KG
318
319 rc = sscanf(kern_buf, "%x:%x", &addr, &len);
13e2d518 320 if (rc < 2 || len > UINT_MAX >> 2) {
ecc46789 321 netdev_warn(bnad->netdev, "failed to read user buffer\n");
7afc5dbd
KG
322 kfree(kern_buf);
323 return -EINVAL;
324 }
325
326 kfree(kern_buf);
327 kfree(bnad->regdata);
7afc5dbd
KG
328 bnad->reglen = 0;
329
330 bnad->regdata = kzalloc(len << 2, GFP_KERNEL);
e404decb 331 if (!bnad->regdata)
7afc5dbd 332 return -ENOMEM;
7afc5dbd
KG
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) {
ecc46789 341 netdev_warn(bnad->netdev, "failed reg offset check\n");
7afc5dbd
KG
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;
4c2e9e29 368 int rc;
369 u32 addr, val;
7afc5dbd
KG
370 void __iomem *reg_addr;
371 unsigned long flags;
372 void *kern_buf;
373
d0e6a806
IV
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);
7afc5dbd
KG
378
379 rc = sscanf(kern_buf, "%x:%x", &addr, &val);
380 if (rc < 2) {
ecc46789 381 netdev_warn(bnad->netdev, "failed to read user buffer\n");
7afc5dbd
KG
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) {
ecc46789 392 netdev_warn(bnad->netdev, "failed reg offset check\n");
7afc5dbd
KG
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;
88187398 476 umode_t mode;
7afc5dbd
KG
477 const struct file_operations *fops;
478};
479
480static const struct bnad_debugfs_entry bnad_debugfs_files[] = {
d3757ba4
JP
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, },
7afc5dbd
KG
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("bna", NULL);
502 atomic_set(&bna_debugfs_port_count, 0);
503 if (!bna_debugfs_root) {
ecc46789
IV
504 netdev_warn(bnad->netdev,
505 "debugfs root dir creation failed\n");
7afc5dbd
KG
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) {
ecc46789
IV
516 netdev_warn(bnad->netdev,
517 "debugfs root dir creation failed\n");
7afc5dbd
KG
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]) {
ecc46789
IV
532 netdev_warn(bnad->netdev,
533 "create %s entry failed\n",
534 file->name);
7afc5dbd
KG
535 return;
536 }
537 }
538 }
539}
540
541/* Uninitialize debugfs interface for BNA */
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 /* 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}