xref: /OK3568_Linux_fs/kernel/drivers/scsi/bfa/bfad_debugfs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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