2 * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
6 * Linux driver for Brocade Fibre Channel Host Bus Adapter.
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License (GPL) Version 2 as
10 * published by the Free Software Foundation
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
18 #include <linux/debugfs.h>
24 * BFA debufs interface
26 * To access the interface, debugfs file system should be mounted
27 * if not already mounted using:
28 * mount -t debugfs none /sys/kernel/debug
31 * - bfa/pci_dev:<pci_name>
32 * where the pci_name corresponds to the one under /sys/bus/pci/drivers/bfa
34 * Debugging service available per pci_dev:
35 * fwtrc: To collect current firmware trace.
36 * drvtrc: To collect current driver trace
37 * fwsave: To collect last saved fw trace as a result of firmware crash.
38 * regwr: To write one word to chip register
39 * regrd: To read one or more words from chip register.
42 struct bfad_debug_info
{
49 bfad_debugfs_open_drvtrc(struct inode
*inode
, struct file
*file
)
51 struct bfad_port_s
*port
= inode
->i_private
;
52 struct bfad_s
*bfad
= port
->bfad
;
53 struct bfad_debug_info
*debug
;
55 debug
= kzalloc(sizeof(struct bfad_debug_info
), GFP_KERNEL
);
59 debug
->debug_buffer
= (void *) bfad
->trcmod
;
60 debug
->buffer_len
= sizeof(struct bfa_trc_mod_s
);
62 file
->private_data
= debug
;
68 bfad_debugfs_open_fwtrc(struct inode
*inode
, struct file
*file
)
70 struct bfad_port_s
*port
= inode
->i_private
;
71 struct bfad_s
*bfad
= port
->bfad
;
72 struct bfad_debug_info
*fw_debug
;
76 fw_debug
= kzalloc(sizeof(struct bfad_debug_info
), GFP_KERNEL
);
80 fw_debug
->buffer_len
= sizeof(struct bfa_trc_mod_s
);
82 fw_debug
->debug_buffer
= vmalloc(fw_debug
->buffer_len
);
83 if (!fw_debug
->debug_buffer
) {
85 printk(KERN_INFO
"bfad[%d]: Failed to allocate fwtrc buffer\n",
90 memset(fw_debug
->debug_buffer
, 0, fw_debug
->buffer_len
);
92 spin_lock_irqsave(&bfad
->bfad_lock
, flags
);
93 rc
= bfa_ioc_debug_fwtrc(&bfad
->bfa
.ioc
,
94 fw_debug
->debug_buffer
,
95 &fw_debug
->buffer_len
);
96 spin_unlock_irqrestore(&bfad
->bfad_lock
, flags
);
97 if (rc
!= BFA_STATUS_OK
) {
98 vfree(fw_debug
->debug_buffer
);
99 fw_debug
->debug_buffer
= NULL
;
101 printk(KERN_INFO
"bfad[%d]: Failed to collect fwtrc\n",
106 file
->private_data
= fw_debug
;
112 bfad_debugfs_open_fwsave(struct inode
*inode
, struct file
*file
)
114 struct bfad_port_s
*port
= inode
->i_private
;
115 struct bfad_s
*bfad
= port
->bfad
;
116 struct bfad_debug_info
*fw_debug
;
120 fw_debug
= kzalloc(sizeof(struct bfad_debug_info
), GFP_KERNEL
);
124 fw_debug
->buffer_len
= sizeof(struct bfa_trc_mod_s
);
126 fw_debug
->debug_buffer
= vmalloc(fw_debug
->buffer_len
);
127 if (!fw_debug
->debug_buffer
) {
129 printk(KERN_INFO
"bfad[%d]: Failed to allocate fwsave buffer\n",
134 memset(fw_debug
->debug_buffer
, 0, fw_debug
->buffer_len
);
136 spin_lock_irqsave(&bfad
->bfad_lock
, flags
);
137 rc
= bfa_ioc_debug_fwsave(&bfad
->bfa
.ioc
,
138 fw_debug
->debug_buffer
,
139 &fw_debug
->buffer_len
);
140 spin_unlock_irqrestore(&bfad
->bfad_lock
, flags
);
141 if (rc
!= BFA_STATUS_OK
) {
142 vfree(fw_debug
->debug_buffer
);
143 fw_debug
->debug_buffer
= NULL
;
145 printk(KERN_INFO
"bfad[%d]: Failed to collect fwsave\n",
150 file
->private_data
= fw_debug
;
156 bfad_debugfs_open_reg(struct inode
*inode
, struct file
*file
)
158 struct bfad_debug_info
*reg_debug
;
160 reg_debug
= kzalloc(sizeof(struct bfad_debug_info
), GFP_KERNEL
);
164 reg_debug
->i_private
= inode
->i_private
;
166 file
->private_data
= reg_debug
;
171 /* Changes the current file position */
173 bfad_debugfs_lseek(struct file
*file
, loff_t offset
, int orig
)
175 struct bfad_debug_info
*debug
;
176 loff_t pos
= file
->f_pos
;
178 debug
= file
->private_data
;
182 file
->f_pos
= offset
;
185 file
->f_pos
+= offset
;
188 file
->f_pos
= debug
->buffer_len
- offset
;
194 if (file
->f_pos
< 0 || file
->f_pos
> debug
->buffer_len
) {
203 bfad_debugfs_read(struct file
*file
, char __user
*buf
,
204 size_t nbytes
, loff_t
*pos
)
206 struct bfad_debug_info
*debug
= file
->private_data
;
208 if (!debug
|| !debug
->debug_buffer
)
211 return simple_read_from_buffer(buf
, nbytes
, pos
,
212 debug
->debug_buffer
, debug
->buffer_len
);
215 #define BFA_REG_CT_ADDRSZ (0x40000)
216 #define BFA_REG_CB_ADDRSZ (0x20000)
217 #define BFA_REG_ADDRSZ(__ioc) \
218 ((u32)(bfa_asic_id_ctc(bfa_ioc_devid(__ioc)) ? \
219 BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ))
220 #define BFA_REG_ADDRMSK(__ioc) (BFA_REG_ADDRSZ(__ioc) - 1)
223 bfad_reg_offset_check(struct bfa_s
*bfa
, u32 offset
, u32 len
)
228 area
= (offset
>> 15) & 0x7;
230 /* PCIe core register */
231 if ((offset
+ (len
<<2)) > 0x8000) /* 8k dwords or 32KB */
232 return BFA_STATUS_EINVAL
;
233 } else if (area
== 0x1) {
234 /* CB 32 KB memory page */
235 if ((offset
+ (len
<<2)) > 0x10000) /* 8k dwords or 32KB */
236 return BFA_STATUS_EINVAL
;
238 /* CB register space 64KB */
239 if ((offset
+ (len
<<2)) > BFA_REG_ADDRMSK(&bfa
->ioc
))
240 return BFA_STATUS_EINVAL
;
242 return BFA_STATUS_OK
;
246 bfad_debugfs_read_regrd(struct file
*file
, char __user
*buf
,
247 size_t nbytes
, loff_t
*pos
)
249 struct bfad_debug_info
*regrd_debug
= file
->private_data
;
250 struct bfad_port_s
*port
= (struct bfad_port_s
*)regrd_debug
->i_private
;
251 struct bfad_s
*bfad
= port
->bfad
;
257 rc
= simple_read_from_buffer(buf
, nbytes
, pos
,
258 bfad
->regdata
, bfad
->reglen
);
260 if ((*pos
+ nbytes
) >= bfad
->reglen
) {
261 kfree(bfad
->regdata
);
262 bfad
->regdata
= NULL
;
270 bfad_debugfs_write_regrd(struct file
*file
, const char __user
*buf
,
271 size_t nbytes
, loff_t
*ppos
)
273 struct bfad_debug_info
*regrd_debug
= file
->private_data
;
274 struct bfad_port_s
*port
= (struct bfad_port_s
*)regrd_debug
->i_private
;
275 struct bfad_s
*bfad
= port
->bfad
;
276 struct bfa_s
*bfa
= &bfad
->bfa
;
277 struct bfa_ioc_s
*ioc
= &bfa
->ioc
;
278 int addr
, len
, rc
, i
;
280 void __iomem
*rb
, *reg_addr
;
284 kern_buf
= kzalloc(nbytes
, GFP_KERNEL
);
287 printk(KERN_INFO
"bfad[%d]: Failed to allocate buffer\n",
292 if (copy_from_user(kern_buf
, (void __user
*)buf
, nbytes
)) {
297 rc
= sscanf(kern_buf
, "%x:%x", &addr
, &len
);
300 "bfad[%d]: %s failed to read user buf\n",
301 bfad
->inst_no
, __func__
);
307 kfree(bfad
->regdata
);
308 bfad
->regdata
= NULL
;
311 bfad
->regdata
= kzalloc(len
<< 2, GFP_KERNEL
);
312 if (!bfad
->regdata
) {
313 printk(KERN_INFO
"bfad[%d]: Failed to allocate regrd buffer\n",
318 bfad
->reglen
= len
<< 2;
319 rb
= bfa_ioc_bar0(ioc
);
320 addr
&= BFA_REG_ADDRMSK(ioc
);
322 /* offset and len sanity check */
323 rc
= bfad_reg_offset_check(bfa
, addr
, len
);
325 printk(KERN_INFO
"bfad[%d]: Failed reg offset check\n",
327 kfree(bfad
->regdata
);
328 bfad
->regdata
= NULL
;
333 reg_addr
= rb
+ addr
;
334 regbuf
= (u32
*)bfad
->regdata
;
335 spin_lock_irqsave(&bfad
->bfad_lock
, flags
);
336 for (i
= 0; i
< len
; i
++) {
337 *regbuf
= readl(reg_addr
);
339 reg_addr
+= sizeof(u32
);
341 spin_unlock_irqrestore(&bfad
->bfad_lock
, flags
);
347 bfad_debugfs_write_regwr(struct file
*file
, const char __user
*buf
,
348 size_t nbytes
, loff_t
*ppos
)
350 struct bfad_debug_info
*debug
= file
->private_data
;
351 struct bfad_port_s
*port
= (struct bfad_port_s
*)debug
->i_private
;
352 struct bfad_s
*bfad
= port
->bfad
;
353 struct bfa_s
*bfa
= &bfad
->bfa
;
354 struct bfa_ioc_s
*ioc
= &bfa
->ioc
;
356 void __iomem
*reg_addr
;
360 kern_buf
= kzalloc(nbytes
, GFP_KERNEL
);
363 printk(KERN_INFO
"bfad[%d]: Failed to allocate buffer\n",
368 if (copy_from_user(kern_buf
, (void __user
*)buf
, nbytes
)) {
373 rc
= sscanf(kern_buf
, "%x:%x", &addr
, &val
);
376 "bfad[%d]: %s failed to read user buf\n",
377 bfad
->inst_no
, __func__
);
383 addr
&= BFA_REG_ADDRMSK(ioc
); /* offset only 17 bit and word align */
385 /* offset and len sanity check */
386 rc
= bfad_reg_offset_check(bfa
, addr
, 1);
389 "bfad[%d]: Failed reg offset check\n",
394 reg_addr
= (bfa_ioc_bar0(ioc
)) + addr
;
395 spin_lock_irqsave(&bfad
->bfad_lock
, flags
);
396 writel(val
, reg_addr
);
397 spin_unlock_irqrestore(&bfad
->bfad_lock
, flags
);
403 bfad_debugfs_release(struct inode
*inode
, struct file
*file
)
405 struct bfad_debug_info
*debug
= file
->private_data
;
410 file
->private_data
= NULL
;
416 bfad_debugfs_release_fwtrc(struct inode
*inode
, struct file
*file
)
418 struct bfad_debug_info
*fw_debug
= file
->private_data
;
423 if (fw_debug
->debug_buffer
)
424 vfree(fw_debug
->debug_buffer
);
426 file
->private_data
= NULL
;
431 static const struct file_operations bfad_debugfs_op_drvtrc
= {
432 .owner
= THIS_MODULE
,
433 .open
= bfad_debugfs_open_drvtrc
,
434 .llseek
= bfad_debugfs_lseek
,
435 .read
= bfad_debugfs_read
,
436 .release
= bfad_debugfs_release
,
439 static const struct file_operations bfad_debugfs_op_fwtrc
= {
440 .owner
= THIS_MODULE
,
441 .open
= bfad_debugfs_open_fwtrc
,
442 .llseek
= bfad_debugfs_lseek
,
443 .read
= bfad_debugfs_read
,
444 .release
= bfad_debugfs_release_fwtrc
,
447 static const struct file_operations bfad_debugfs_op_fwsave
= {
448 .owner
= THIS_MODULE
,
449 .open
= bfad_debugfs_open_fwsave
,
450 .llseek
= bfad_debugfs_lseek
,
451 .read
= bfad_debugfs_read
,
452 .release
= bfad_debugfs_release_fwtrc
,
455 static const struct file_operations bfad_debugfs_op_regrd
= {
456 .owner
= THIS_MODULE
,
457 .open
= bfad_debugfs_open_reg
,
458 .llseek
= bfad_debugfs_lseek
,
459 .read
= bfad_debugfs_read_regrd
,
460 .write
= bfad_debugfs_write_regrd
,
461 .release
= bfad_debugfs_release
,
464 static const struct file_operations bfad_debugfs_op_regwr
= {
465 .owner
= THIS_MODULE
,
466 .open
= bfad_debugfs_open_reg
,
467 .llseek
= bfad_debugfs_lseek
,
468 .write
= bfad_debugfs_write_regwr
,
469 .release
= bfad_debugfs_release
,
472 struct bfad_debugfs_entry
{
475 const struct file_operations
*fops
;
478 static const struct bfad_debugfs_entry bfad_debugfs_files
[] = {
479 { "drvtrc", S_IFREG
|S_IRUGO
, &bfad_debugfs_op_drvtrc
, },
480 { "fwtrc", S_IFREG
|S_IRUGO
, &bfad_debugfs_op_fwtrc
, },
481 { "fwsave", S_IFREG
|S_IRUGO
, &bfad_debugfs_op_fwsave
, },
482 { "regrd", S_IFREG
|S_IRUGO
|S_IWUSR
, &bfad_debugfs_op_regrd
, },
483 { "regwr", S_IFREG
|S_IWUSR
, &bfad_debugfs_op_regwr
, },
486 static struct dentry
*bfa_debugfs_root
;
487 static atomic_t bfa_debugfs_port_count
;
490 bfad_debugfs_init(struct bfad_port_s
*port
)
492 struct bfad_s
*bfad
= port
->bfad
;
493 const struct bfad_debugfs_entry
*file
;
497 if (!bfa_debugfs_enable
)
500 /* Setup the BFA debugfs root directory*/
501 if (!bfa_debugfs_root
) {
502 bfa_debugfs_root
= debugfs_create_dir("bfa", NULL
);
503 atomic_set(&bfa_debugfs_port_count
, 0);
504 if (!bfa_debugfs_root
) {
506 "BFA debugfs root dir creation failed\n");
511 /* Setup the pci_dev debugfs directory for the port */
512 snprintf(name
, sizeof(name
), "pci_dev:%s", bfad
->pci_name
);
513 if (!port
->port_debugfs_root
) {
514 port
->port_debugfs_root
=
515 debugfs_create_dir(name
, bfa_debugfs_root
);
516 if (!port
->port_debugfs_root
) {
518 "bfa %s: debugfs root creation failed\n",
523 atomic_inc(&bfa_debugfs_port_count
);
525 for (i
= 0; i
< ARRAY_SIZE(bfad_debugfs_files
); i
++) {
526 file
= &bfad_debugfs_files
[i
];
527 bfad
->bfad_dentry_files
[i
] =
528 debugfs_create_file(file
->name
,
530 port
->port_debugfs_root
,
533 if (!bfad
->bfad_dentry_files
[i
]) {
535 "bfa %s: debugfs %s creation failed\n",
536 bfad
->pci_name
, file
->name
);
547 bfad_debugfs_exit(struct bfad_port_s
*port
)
549 struct bfad_s
*bfad
= port
->bfad
;
552 for (i
= 0; i
< ARRAY_SIZE(bfad_debugfs_files
); i
++) {
553 if (bfad
->bfad_dentry_files
[i
]) {
554 debugfs_remove(bfad
->bfad_dentry_files
[i
]);
555 bfad
->bfad_dentry_files
[i
] = NULL
;
560 * Remove the pci_dev debugfs directory for the port */
561 if (port
->port_debugfs_root
) {
562 debugfs_remove(port
->port_debugfs_root
);
563 port
->port_debugfs_root
= NULL
;
564 atomic_dec(&bfa_debugfs_port_count
);
567 /* Remove the BFA debugfs root directory */
568 if (atomic_read(&bfa_debugfs_port_count
) == 0) {
569 debugfs_remove(bfa_debugfs_root
);
570 bfa_debugfs_root
= NULL
;