1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
4*4882a593Smuzhiyun * Copyright (c) 2014- QLogic Corporation.
5*4882a593Smuzhiyun * All rights reserved
6*4882a593Smuzhiyun * www.qlogic.com
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <linux/debugfs.h>
12*4882a593Smuzhiyun #include <linux/export.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #include "bfad_drv.h"
15*4882a593Smuzhiyun #include "bfad_im.h"
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun /*
18*4882a593Smuzhiyun * BFA debufs interface
19*4882a593Smuzhiyun *
20*4882a593Smuzhiyun * To access the interface, debugfs file system should be mounted
21*4882a593Smuzhiyun * if not already mounted using:
22*4882a593Smuzhiyun * mount -t debugfs none /sys/kernel/debug
23*4882a593Smuzhiyun *
24*4882a593Smuzhiyun * BFA Hierarchy:
25*4882a593Smuzhiyun * - bfa/pci_dev:<pci_name>
26*4882a593Smuzhiyun * where the pci_name corresponds to the one under /sys/bus/pci/drivers/bfa
27*4882a593Smuzhiyun *
28*4882a593Smuzhiyun * Debugging service available per pci_dev:
29*4882a593Smuzhiyun * fwtrc: To collect current firmware trace.
30*4882a593Smuzhiyun * drvtrc: To collect current driver trace
31*4882a593Smuzhiyun * fwsave: To collect last saved fw trace as a result of firmware crash.
32*4882a593Smuzhiyun * regwr: To write one word to chip register
33*4882a593Smuzhiyun * regrd: To read one or more words from chip register.
34*4882a593Smuzhiyun */
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun struct bfad_debug_info {
37*4882a593Smuzhiyun char *debug_buffer;
38*4882a593Smuzhiyun void *i_private;
39*4882a593Smuzhiyun int buffer_len;
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun static int
bfad_debugfs_open_drvtrc(struct inode * inode,struct file * file)43*4882a593Smuzhiyun bfad_debugfs_open_drvtrc(struct inode *inode, struct file *file)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun struct bfad_port_s *port = inode->i_private;
46*4882a593Smuzhiyun struct bfad_s *bfad = port->bfad;
47*4882a593Smuzhiyun struct bfad_debug_info *debug;
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
50*4882a593Smuzhiyun if (!debug)
51*4882a593Smuzhiyun return -ENOMEM;
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun debug->debug_buffer = (void *) bfad->trcmod;
54*4882a593Smuzhiyun debug->buffer_len = sizeof(struct bfa_trc_mod_s);
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun file->private_data = debug;
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun return 0;
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun static int
bfad_debugfs_open_fwtrc(struct inode * inode,struct file * file)62*4882a593Smuzhiyun bfad_debugfs_open_fwtrc(struct inode *inode, struct file *file)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun struct bfad_port_s *port = inode->i_private;
65*4882a593Smuzhiyun struct bfad_s *bfad = port->bfad;
66*4882a593Smuzhiyun struct bfad_debug_info *fw_debug;
67*4882a593Smuzhiyun unsigned long flags;
68*4882a593Smuzhiyun int rc;
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
71*4882a593Smuzhiyun if (!fw_debug)
72*4882a593Smuzhiyun return -ENOMEM;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun fw_debug->buffer_len = sizeof(struct bfa_trc_mod_s);
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun fw_debug->debug_buffer = vzalloc(fw_debug->buffer_len);
77*4882a593Smuzhiyun if (!fw_debug->debug_buffer) {
78*4882a593Smuzhiyun kfree(fw_debug);
79*4882a593Smuzhiyun printk(KERN_INFO "bfad[%d]: Failed to allocate fwtrc buffer\n",
80*4882a593Smuzhiyun bfad->inst_no);
81*4882a593Smuzhiyun return -ENOMEM;
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun spin_lock_irqsave(&bfad->bfad_lock, flags);
85*4882a593Smuzhiyun rc = bfa_ioc_debug_fwtrc(&bfad->bfa.ioc,
86*4882a593Smuzhiyun fw_debug->debug_buffer,
87*4882a593Smuzhiyun &fw_debug->buffer_len);
88*4882a593Smuzhiyun spin_unlock_irqrestore(&bfad->bfad_lock, flags);
89*4882a593Smuzhiyun if (rc != BFA_STATUS_OK) {
90*4882a593Smuzhiyun vfree(fw_debug->debug_buffer);
91*4882a593Smuzhiyun fw_debug->debug_buffer = NULL;
92*4882a593Smuzhiyun kfree(fw_debug);
93*4882a593Smuzhiyun printk(KERN_INFO "bfad[%d]: Failed to collect fwtrc\n",
94*4882a593Smuzhiyun bfad->inst_no);
95*4882a593Smuzhiyun return -ENOMEM;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun file->private_data = fw_debug;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun return 0;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun static int
bfad_debugfs_open_fwsave(struct inode * inode,struct file * file)104*4882a593Smuzhiyun bfad_debugfs_open_fwsave(struct inode *inode, struct file *file)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun struct bfad_port_s *port = inode->i_private;
107*4882a593Smuzhiyun struct bfad_s *bfad = port->bfad;
108*4882a593Smuzhiyun struct bfad_debug_info *fw_debug;
109*4882a593Smuzhiyun unsigned long flags;
110*4882a593Smuzhiyun int rc;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
113*4882a593Smuzhiyun if (!fw_debug)
114*4882a593Smuzhiyun return -ENOMEM;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun fw_debug->buffer_len = sizeof(struct bfa_trc_mod_s);
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun fw_debug->debug_buffer = vzalloc(fw_debug->buffer_len);
119*4882a593Smuzhiyun if (!fw_debug->debug_buffer) {
120*4882a593Smuzhiyun kfree(fw_debug);
121*4882a593Smuzhiyun printk(KERN_INFO "bfad[%d]: Failed to allocate fwsave buffer\n",
122*4882a593Smuzhiyun bfad->inst_no);
123*4882a593Smuzhiyun return -ENOMEM;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun spin_lock_irqsave(&bfad->bfad_lock, flags);
127*4882a593Smuzhiyun rc = bfa_ioc_debug_fwsave(&bfad->bfa.ioc,
128*4882a593Smuzhiyun fw_debug->debug_buffer,
129*4882a593Smuzhiyun &fw_debug->buffer_len);
130*4882a593Smuzhiyun spin_unlock_irqrestore(&bfad->bfad_lock, flags);
131*4882a593Smuzhiyun if (rc != BFA_STATUS_OK) {
132*4882a593Smuzhiyun vfree(fw_debug->debug_buffer);
133*4882a593Smuzhiyun fw_debug->debug_buffer = NULL;
134*4882a593Smuzhiyun kfree(fw_debug);
135*4882a593Smuzhiyun printk(KERN_INFO "bfad[%d]: Failed to collect fwsave\n",
136*4882a593Smuzhiyun bfad->inst_no);
137*4882a593Smuzhiyun return -ENOMEM;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun file->private_data = fw_debug;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun return 0;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun static int
bfad_debugfs_open_reg(struct inode * inode,struct file * file)146*4882a593Smuzhiyun bfad_debugfs_open_reg(struct inode *inode, struct file *file)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun struct bfad_debug_info *reg_debug;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun reg_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
151*4882a593Smuzhiyun if (!reg_debug)
152*4882a593Smuzhiyun return -ENOMEM;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun reg_debug->i_private = inode->i_private;
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun file->private_data = reg_debug;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun return 0;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun /* Changes the current file position */
162*4882a593Smuzhiyun static loff_t
bfad_debugfs_lseek(struct file * file,loff_t offset,int orig)163*4882a593Smuzhiyun bfad_debugfs_lseek(struct file *file, loff_t offset, int orig)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun struct bfad_debug_info *debug = file->private_data;
166*4882a593Smuzhiyun return fixed_size_llseek(file, offset, orig,
167*4882a593Smuzhiyun debug->buffer_len);
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun static ssize_t
bfad_debugfs_read(struct file * file,char __user * buf,size_t nbytes,loff_t * pos)171*4882a593Smuzhiyun bfad_debugfs_read(struct file *file, char __user *buf,
172*4882a593Smuzhiyun size_t nbytes, loff_t *pos)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun struct bfad_debug_info *debug = file->private_data;
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun if (!debug || !debug->debug_buffer)
177*4882a593Smuzhiyun return 0;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun return simple_read_from_buffer(buf, nbytes, pos,
180*4882a593Smuzhiyun debug->debug_buffer, debug->buffer_len);
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun #define BFA_REG_CT_ADDRSZ (0x40000)
184*4882a593Smuzhiyun #define BFA_REG_CB_ADDRSZ (0x20000)
185*4882a593Smuzhiyun #define BFA_REG_ADDRSZ(__ioc) \
186*4882a593Smuzhiyun ((u32)(bfa_asic_id_ctc(bfa_ioc_devid(__ioc)) ? \
187*4882a593Smuzhiyun BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ))
188*4882a593Smuzhiyun #define BFA_REG_ADDRMSK(__ioc) (BFA_REG_ADDRSZ(__ioc) - 1)
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun static bfa_status_t
bfad_reg_offset_check(struct bfa_s * bfa,u32 offset,u32 len)191*4882a593Smuzhiyun bfad_reg_offset_check(struct bfa_s *bfa, u32 offset, u32 len)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun u8 area;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun /* check [16:15] */
196*4882a593Smuzhiyun area = (offset >> 15) & 0x7;
197*4882a593Smuzhiyun if (area == 0) {
198*4882a593Smuzhiyun /* PCIe core register */
199*4882a593Smuzhiyun if ((offset + (len<<2)) > 0x8000) /* 8k dwords or 32KB */
200*4882a593Smuzhiyun return BFA_STATUS_EINVAL;
201*4882a593Smuzhiyun } else if (area == 0x1) {
202*4882a593Smuzhiyun /* CB 32 KB memory page */
203*4882a593Smuzhiyun if ((offset + (len<<2)) > 0x10000) /* 8k dwords or 32KB */
204*4882a593Smuzhiyun return BFA_STATUS_EINVAL;
205*4882a593Smuzhiyun } else {
206*4882a593Smuzhiyun /* CB register space 64KB */
207*4882a593Smuzhiyun if ((offset + (len<<2)) > BFA_REG_ADDRMSK(&bfa->ioc))
208*4882a593Smuzhiyun return BFA_STATUS_EINVAL;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun return BFA_STATUS_OK;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun static ssize_t
bfad_debugfs_read_regrd(struct file * file,char __user * buf,size_t nbytes,loff_t * pos)214*4882a593Smuzhiyun bfad_debugfs_read_regrd(struct file *file, char __user *buf,
215*4882a593Smuzhiyun size_t nbytes, loff_t *pos)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun struct bfad_debug_info *regrd_debug = file->private_data;
218*4882a593Smuzhiyun struct bfad_port_s *port = (struct bfad_port_s *)regrd_debug->i_private;
219*4882a593Smuzhiyun struct bfad_s *bfad = port->bfad;
220*4882a593Smuzhiyun ssize_t rc;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun if (!bfad->regdata)
223*4882a593Smuzhiyun return 0;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun rc = simple_read_from_buffer(buf, nbytes, pos,
226*4882a593Smuzhiyun bfad->regdata, bfad->reglen);
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun if ((*pos + nbytes) >= bfad->reglen) {
229*4882a593Smuzhiyun kfree(bfad->regdata);
230*4882a593Smuzhiyun bfad->regdata = NULL;
231*4882a593Smuzhiyun bfad->reglen = 0;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun return rc;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun static ssize_t
bfad_debugfs_write_regrd(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)238*4882a593Smuzhiyun bfad_debugfs_write_regrd(struct file *file, const char __user *buf,
239*4882a593Smuzhiyun size_t nbytes, loff_t *ppos)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun struct bfad_debug_info *regrd_debug = file->private_data;
242*4882a593Smuzhiyun struct bfad_port_s *port = (struct bfad_port_s *)regrd_debug->i_private;
243*4882a593Smuzhiyun struct bfad_s *bfad = port->bfad;
244*4882a593Smuzhiyun struct bfa_s *bfa = &bfad->bfa;
245*4882a593Smuzhiyun struct bfa_ioc_s *ioc = &bfa->ioc;
246*4882a593Smuzhiyun int addr, rc, i;
247*4882a593Smuzhiyun u32 len;
248*4882a593Smuzhiyun u32 *regbuf;
249*4882a593Smuzhiyun void __iomem *rb, *reg_addr;
250*4882a593Smuzhiyun unsigned long flags;
251*4882a593Smuzhiyun void *kern_buf;
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun kern_buf = memdup_user(buf, nbytes);
254*4882a593Smuzhiyun if (IS_ERR(kern_buf))
255*4882a593Smuzhiyun return PTR_ERR(kern_buf);
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun rc = sscanf(kern_buf, "%x:%x", &addr, &len);
258*4882a593Smuzhiyun if (rc < 2 || len > (UINT_MAX >> 2)) {
259*4882a593Smuzhiyun printk(KERN_INFO
260*4882a593Smuzhiyun "bfad[%d]: %s failed to read user buf\n",
261*4882a593Smuzhiyun bfad->inst_no, __func__);
262*4882a593Smuzhiyun kfree(kern_buf);
263*4882a593Smuzhiyun return -EINVAL;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun kfree(kern_buf);
267*4882a593Smuzhiyun kfree(bfad->regdata);
268*4882a593Smuzhiyun bfad->regdata = NULL;
269*4882a593Smuzhiyun bfad->reglen = 0;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun bfad->regdata = kzalloc(len << 2, GFP_KERNEL);
272*4882a593Smuzhiyun if (!bfad->regdata) {
273*4882a593Smuzhiyun printk(KERN_INFO "bfad[%d]: Failed to allocate regrd buffer\n",
274*4882a593Smuzhiyun bfad->inst_no);
275*4882a593Smuzhiyun return -ENOMEM;
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun bfad->reglen = len << 2;
279*4882a593Smuzhiyun rb = bfa_ioc_bar0(ioc);
280*4882a593Smuzhiyun addr &= BFA_REG_ADDRMSK(ioc);
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun /* offset and len sanity check */
283*4882a593Smuzhiyun rc = bfad_reg_offset_check(bfa, addr, len);
284*4882a593Smuzhiyun if (rc) {
285*4882a593Smuzhiyun printk(KERN_INFO "bfad[%d]: Failed reg offset check\n",
286*4882a593Smuzhiyun bfad->inst_no);
287*4882a593Smuzhiyun kfree(bfad->regdata);
288*4882a593Smuzhiyun bfad->regdata = NULL;
289*4882a593Smuzhiyun bfad->reglen = 0;
290*4882a593Smuzhiyun return -EINVAL;
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun reg_addr = rb + addr;
294*4882a593Smuzhiyun regbuf = (u32 *)bfad->regdata;
295*4882a593Smuzhiyun spin_lock_irqsave(&bfad->bfad_lock, flags);
296*4882a593Smuzhiyun for (i = 0; i < len; i++) {
297*4882a593Smuzhiyun *regbuf = readl(reg_addr);
298*4882a593Smuzhiyun regbuf++;
299*4882a593Smuzhiyun reg_addr += sizeof(u32);
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun spin_unlock_irqrestore(&bfad->bfad_lock, flags);
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun return nbytes;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun static ssize_t
bfad_debugfs_write_regwr(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)307*4882a593Smuzhiyun bfad_debugfs_write_regwr(struct file *file, const char __user *buf,
308*4882a593Smuzhiyun size_t nbytes, loff_t *ppos)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun struct bfad_debug_info *debug = file->private_data;
311*4882a593Smuzhiyun struct bfad_port_s *port = (struct bfad_port_s *)debug->i_private;
312*4882a593Smuzhiyun struct bfad_s *bfad = port->bfad;
313*4882a593Smuzhiyun struct bfa_s *bfa = &bfad->bfa;
314*4882a593Smuzhiyun struct bfa_ioc_s *ioc = &bfa->ioc;
315*4882a593Smuzhiyun int addr, val, rc;
316*4882a593Smuzhiyun void __iomem *reg_addr;
317*4882a593Smuzhiyun unsigned long flags;
318*4882a593Smuzhiyun void *kern_buf;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun kern_buf = memdup_user(buf, nbytes);
321*4882a593Smuzhiyun if (IS_ERR(kern_buf))
322*4882a593Smuzhiyun return PTR_ERR(kern_buf);
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun rc = sscanf(kern_buf, "%x:%x", &addr, &val);
325*4882a593Smuzhiyun if (rc < 2) {
326*4882a593Smuzhiyun printk(KERN_INFO
327*4882a593Smuzhiyun "bfad[%d]: %s failed to read user buf\n",
328*4882a593Smuzhiyun bfad->inst_no, __func__);
329*4882a593Smuzhiyun kfree(kern_buf);
330*4882a593Smuzhiyun return -EINVAL;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun kfree(kern_buf);
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun addr &= BFA_REG_ADDRMSK(ioc); /* offset only 17 bit and word align */
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun /* offset and len sanity check */
337*4882a593Smuzhiyun rc = bfad_reg_offset_check(bfa, addr, 1);
338*4882a593Smuzhiyun if (rc) {
339*4882a593Smuzhiyun printk(KERN_INFO
340*4882a593Smuzhiyun "bfad[%d]: Failed reg offset check\n",
341*4882a593Smuzhiyun bfad->inst_no);
342*4882a593Smuzhiyun return -EINVAL;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun reg_addr = (bfa_ioc_bar0(ioc)) + addr;
346*4882a593Smuzhiyun spin_lock_irqsave(&bfad->bfad_lock, flags);
347*4882a593Smuzhiyun writel(val, reg_addr);
348*4882a593Smuzhiyun spin_unlock_irqrestore(&bfad->bfad_lock, flags);
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun return nbytes;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun static int
bfad_debugfs_release(struct inode * inode,struct file * file)354*4882a593Smuzhiyun bfad_debugfs_release(struct inode *inode, struct file *file)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun struct bfad_debug_info *debug = file->private_data;
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun if (!debug)
359*4882a593Smuzhiyun return 0;
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun file->private_data = NULL;
362*4882a593Smuzhiyun kfree(debug);
363*4882a593Smuzhiyun return 0;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun static int
bfad_debugfs_release_fwtrc(struct inode * inode,struct file * file)367*4882a593Smuzhiyun bfad_debugfs_release_fwtrc(struct inode *inode, struct file *file)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun struct bfad_debug_info *fw_debug = file->private_data;
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun if (!fw_debug)
372*4882a593Smuzhiyun return 0;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun if (fw_debug->debug_buffer)
375*4882a593Smuzhiyun vfree(fw_debug->debug_buffer);
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun file->private_data = NULL;
378*4882a593Smuzhiyun kfree(fw_debug);
379*4882a593Smuzhiyun return 0;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun static const struct file_operations bfad_debugfs_op_drvtrc = {
383*4882a593Smuzhiyun .owner = THIS_MODULE,
384*4882a593Smuzhiyun .open = bfad_debugfs_open_drvtrc,
385*4882a593Smuzhiyun .llseek = bfad_debugfs_lseek,
386*4882a593Smuzhiyun .read = bfad_debugfs_read,
387*4882a593Smuzhiyun .release = bfad_debugfs_release,
388*4882a593Smuzhiyun };
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun static const struct file_operations bfad_debugfs_op_fwtrc = {
391*4882a593Smuzhiyun .owner = THIS_MODULE,
392*4882a593Smuzhiyun .open = bfad_debugfs_open_fwtrc,
393*4882a593Smuzhiyun .llseek = bfad_debugfs_lseek,
394*4882a593Smuzhiyun .read = bfad_debugfs_read,
395*4882a593Smuzhiyun .release = bfad_debugfs_release_fwtrc,
396*4882a593Smuzhiyun };
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun static const struct file_operations bfad_debugfs_op_fwsave = {
399*4882a593Smuzhiyun .owner = THIS_MODULE,
400*4882a593Smuzhiyun .open = bfad_debugfs_open_fwsave,
401*4882a593Smuzhiyun .llseek = bfad_debugfs_lseek,
402*4882a593Smuzhiyun .read = bfad_debugfs_read,
403*4882a593Smuzhiyun .release = bfad_debugfs_release_fwtrc,
404*4882a593Smuzhiyun };
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun static const struct file_operations bfad_debugfs_op_regrd = {
407*4882a593Smuzhiyun .owner = THIS_MODULE,
408*4882a593Smuzhiyun .open = bfad_debugfs_open_reg,
409*4882a593Smuzhiyun .llseek = bfad_debugfs_lseek,
410*4882a593Smuzhiyun .read = bfad_debugfs_read_regrd,
411*4882a593Smuzhiyun .write = bfad_debugfs_write_regrd,
412*4882a593Smuzhiyun .release = bfad_debugfs_release,
413*4882a593Smuzhiyun };
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun static const struct file_operations bfad_debugfs_op_regwr = {
416*4882a593Smuzhiyun .owner = THIS_MODULE,
417*4882a593Smuzhiyun .open = bfad_debugfs_open_reg,
418*4882a593Smuzhiyun .llseek = bfad_debugfs_lseek,
419*4882a593Smuzhiyun .write = bfad_debugfs_write_regwr,
420*4882a593Smuzhiyun .release = bfad_debugfs_release,
421*4882a593Smuzhiyun };
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun struct bfad_debugfs_entry {
424*4882a593Smuzhiyun const char *name;
425*4882a593Smuzhiyun umode_t mode;
426*4882a593Smuzhiyun const struct file_operations *fops;
427*4882a593Smuzhiyun };
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun static const struct bfad_debugfs_entry bfad_debugfs_files[] = {
430*4882a593Smuzhiyun { "drvtrc", S_IFREG|S_IRUGO, &bfad_debugfs_op_drvtrc, },
431*4882a593Smuzhiyun { "fwtrc", S_IFREG|S_IRUGO, &bfad_debugfs_op_fwtrc, },
432*4882a593Smuzhiyun { "fwsave", S_IFREG|S_IRUGO, &bfad_debugfs_op_fwsave, },
433*4882a593Smuzhiyun { "regrd", S_IFREG|S_IRUGO|S_IWUSR, &bfad_debugfs_op_regrd, },
434*4882a593Smuzhiyun { "regwr", S_IFREG|S_IWUSR, &bfad_debugfs_op_regwr, },
435*4882a593Smuzhiyun };
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun static struct dentry *bfa_debugfs_root;
438*4882a593Smuzhiyun static atomic_t bfa_debugfs_port_count;
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun inline void
bfad_debugfs_init(struct bfad_port_s * port)441*4882a593Smuzhiyun bfad_debugfs_init(struct bfad_port_s *port)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun struct bfad_s *bfad = port->bfad;
444*4882a593Smuzhiyun const struct bfad_debugfs_entry *file;
445*4882a593Smuzhiyun char name[64];
446*4882a593Smuzhiyun int i;
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun if (!bfa_debugfs_enable)
449*4882a593Smuzhiyun return;
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun /* Setup the BFA debugfs root directory*/
452*4882a593Smuzhiyun if (!bfa_debugfs_root) {
453*4882a593Smuzhiyun bfa_debugfs_root = debugfs_create_dir("bfa", NULL);
454*4882a593Smuzhiyun atomic_set(&bfa_debugfs_port_count, 0);
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun /* Setup the pci_dev debugfs directory for the port */
458*4882a593Smuzhiyun snprintf(name, sizeof(name), "pci_dev:%s", bfad->pci_name);
459*4882a593Smuzhiyun if (!port->port_debugfs_root) {
460*4882a593Smuzhiyun port->port_debugfs_root =
461*4882a593Smuzhiyun debugfs_create_dir(name, bfa_debugfs_root);
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun atomic_inc(&bfa_debugfs_port_count);
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) {
466*4882a593Smuzhiyun file = &bfad_debugfs_files[i];
467*4882a593Smuzhiyun bfad->bfad_dentry_files[i] =
468*4882a593Smuzhiyun debugfs_create_file(file->name,
469*4882a593Smuzhiyun file->mode,
470*4882a593Smuzhiyun port->port_debugfs_root,
471*4882a593Smuzhiyun port,
472*4882a593Smuzhiyun file->fops);
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun return;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun inline void
bfad_debugfs_exit(struct bfad_port_s * port)480*4882a593Smuzhiyun bfad_debugfs_exit(struct bfad_port_s *port)
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun struct bfad_s *bfad = port->bfad;
483*4882a593Smuzhiyun int i;
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) {
486*4882a593Smuzhiyun if (bfad->bfad_dentry_files[i]) {
487*4882a593Smuzhiyun debugfs_remove(bfad->bfad_dentry_files[i]);
488*4882a593Smuzhiyun bfad->bfad_dentry_files[i] = NULL;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun /* Remove the pci_dev debugfs directory for the port */
493*4882a593Smuzhiyun if (port->port_debugfs_root) {
494*4882a593Smuzhiyun debugfs_remove(port->port_debugfs_root);
495*4882a593Smuzhiyun port->port_debugfs_root = NULL;
496*4882a593Smuzhiyun atomic_dec(&bfa_debugfs_port_count);
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun /* Remove the BFA debugfs root directory */
500*4882a593Smuzhiyun if (atomic_read(&bfa_debugfs_port_count) == 0) {
501*4882a593Smuzhiyun debugfs_remove(bfa_debugfs_root);
502*4882a593Smuzhiyun bfa_debugfs_root = NULL;
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun }
505