xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/broadcom/b43legacy/debugfs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun   Broadcom B43legacy wireless driver
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun   debugfs driver debugging code
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun   Copyright (c) 2005-2007 Michael Buesch <m@bues.ch>
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun */
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <linux/fs.h>
14*4882a593Smuzhiyun #include <linux/debugfs.h>
15*4882a593Smuzhiyun #include <linux/slab.h>
16*4882a593Smuzhiyun #include <linux/netdevice.h>
17*4882a593Smuzhiyun #include <linux/pci.h>
18*4882a593Smuzhiyun #include <linux/mutex.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include "b43legacy.h"
21*4882a593Smuzhiyun #include "main.h"
22*4882a593Smuzhiyun #include "debugfs.h"
23*4882a593Smuzhiyun #include "dma.h"
24*4882a593Smuzhiyun #include "pio.h"
25*4882a593Smuzhiyun #include "xmit.h"
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun /* The root directory. */
29*4882a593Smuzhiyun static struct dentry *rootdir;
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun struct b43legacy_debugfs_fops {
32*4882a593Smuzhiyun 	ssize_t (*read)(struct b43legacy_wldev *dev, char *buf, size_t bufsize);
33*4882a593Smuzhiyun 	int (*write)(struct b43legacy_wldev *dev, const char *buf, size_t count);
34*4882a593Smuzhiyun 	struct file_operations fops;
35*4882a593Smuzhiyun 	/* Offset of struct b43legacy_dfs_file in struct b43legacy_dfsentry */
36*4882a593Smuzhiyun 	size_t file_struct_offset;
37*4882a593Smuzhiyun 	/* Take wl->irq_lock before calling read/write? */
38*4882a593Smuzhiyun 	bool take_irqlock;
39*4882a593Smuzhiyun };
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun static inline
fops_to_dfs_file(struct b43legacy_wldev * dev,const struct b43legacy_debugfs_fops * dfops)42*4882a593Smuzhiyun struct b43legacy_dfs_file * fops_to_dfs_file(struct b43legacy_wldev *dev,
43*4882a593Smuzhiyun 				       const struct b43legacy_debugfs_fops *dfops)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun 	void *p;
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	p = dev->dfsentry;
48*4882a593Smuzhiyun 	p += dfops->file_struct_offset;
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	return p;
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun #define fappend(fmt, x...)	\
55*4882a593Smuzhiyun 	do {							\
56*4882a593Smuzhiyun 		if (bufsize - count)				\
57*4882a593Smuzhiyun 			count += scnprintf(buf + count,		\
58*4882a593Smuzhiyun 					  bufsize - count,	\
59*4882a593Smuzhiyun 					  fmt , ##x);		\
60*4882a593Smuzhiyun 		else						\
61*4882a593Smuzhiyun 			printk(KERN_ERR "b43legacy: fappend overflow\n"); \
62*4882a593Smuzhiyun 	} while (0)
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun /* wl->irq_lock is locked */
tsf_read_file(struct b43legacy_wldev * dev,char * buf,size_t bufsize)66*4882a593Smuzhiyun static ssize_t tsf_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun 	ssize_t count = 0;
69*4882a593Smuzhiyun 	u64 tsf;
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	b43legacy_tsf_read(dev, &tsf);
72*4882a593Smuzhiyun 	fappend("0x%08x%08x\n",
73*4882a593Smuzhiyun 		(unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32),
74*4882a593Smuzhiyun 		(unsigned int)(tsf & 0xFFFFFFFFULL));
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	return count;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun /* wl->irq_lock is locked */
tsf_write_file(struct b43legacy_wldev * dev,const char * buf,size_t count)80*4882a593Smuzhiyun static int tsf_write_file(struct b43legacy_wldev *dev, const char *buf, size_t count)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	u64 tsf;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1)
85*4882a593Smuzhiyun 		return -EINVAL;
86*4882a593Smuzhiyun 	b43legacy_tsf_write(dev, tsf);
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	return 0;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun /* wl->irq_lock is locked */
ucode_regs_read_file(struct b43legacy_wldev * dev,char * buf,size_t bufsize)92*4882a593Smuzhiyun static ssize_t ucode_regs_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	ssize_t count = 0;
95*4882a593Smuzhiyun 	int i;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	for (i = 0; i < 64; i++) {
98*4882a593Smuzhiyun 		fappend("r%d = 0x%04x\n", i,
99*4882a593Smuzhiyun 			b43legacy_shm_read16(dev, B43legacy_SHM_WIRELESS, i));
100*4882a593Smuzhiyun 	}
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	return count;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun /* wl->irq_lock is locked */
shm_read_file(struct b43legacy_wldev * dev,char * buf,size_t bufsize)106*4882a593Smuzhiyun static ssize_t shm_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	ssize_t count = 0;
109*4882a593Smuzhiyun 	int i;
110*4882a593Smuzhiyun 	u16 tmp;
111*4882a593Smuzhiyun 	__le16 *le16buf = (__le16 *)buf;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	for (i = 0; i < 0x1000; i++) {
114*4882a593Smuzhiyun 		if (bufsize < sizeof(tmp))
115*4882a593Smuzhiyun 			break;
116*4882a593Smuzhiyun 		tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 2 * i);
117*4882a593Smuzhiyun 		le16buf[i] = cpu_to_le16(tmp);
118*4882a593Smuzhiyun 		count += sizeof(tmp);
119*4882a593Smuzhiyun 		bufsize -= sizeof(tmp);
120*4882a593Smuzhiyun 	}
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	return count;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
txstat_read_file(struct b43legacy_wldev * dev,char * buf,size_t bufsize)125*4882a593Smuzhiyun static ssize_t txstat_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	struct b43legacy_txstatus_log *log = &dev->dfsentry->txstatlog;
128*4882a593Smuzhiyun 	ssize_t count = 0;
129*4882a593Smuzhiyun 	unsigned long flags;
130*4882a593Smuzhiyun 	int i, idx;
131*4882a593Smuzhiyun 	struct b43legacy_txstatus *stat;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	spin_lock_irqsave(&log->lock, flags);
134*4882a593Smuzhiyun 	if (log->end < 0) {
135*4882a593Smuzhiyun 		fappend("Nothing transmitted, yet\n");
136*4882a593Smuzhiyun 		goto out_unlock;
137*4882a593Smuzhiyun 	}
138*4882a593Smuzhiyun 	fappend("b43legacy TX status reports:\n\n"
139*4882a593Smuzhiyun 		"index | cookie | seq | phy_stat | frame_count | "
140*4882a593Smuzhiyun 		"rts_count | supp_reason | pm_indicated | "
141*4882a593Smuzhiyun 		"intermediate | for_ampdu | acked\n" "---\n");
142*4882a593Smuzhiyun 	i = log->end + 1;
143*4882a593Smuzhiyun 	idx = 0;
144*4882a593Smuzhiyun 	while (1) {
145*4882a593Smuzhiyun 		if (i == B43legacy_NR_LOGGED_TXSTATUS)
146*4882a593Smuzhiyun 			i = 0;
147*4882a593Smuzhiyun 		stat = &(log->log[i]);
148*4882a593Smuzhiyun 		if (stat->cookie) {
149*4882a593Smuzhiyun 			fappend("%03d | "
150*4882a593Smuzhiyun 				"0x%04X | 0x%04X | 0x%02X | "
151*4882a593Smuzhiyun 				"0x%X | 0x%X | "
152*4882a593Smuzhiyun 				"%u | %u | "
153*4882a593Smuzhiyun 				"%u | %u | %u\n",
154*4882a593Smuzhiyun 				idx,
155*4882a593Smuzhiyun 				stat->cookie, stat->seq, stat->phy_stat,
156*4882a593Smuzhiyun 				stat->frame_count, stat->rts_count,
157*4882a593Smuzhiyun 				stat->supp_reason, stat->pm_indicated,
158*4882a593Smuzhiyun 				stat->intermediate, stat->for_ampdu,
159*4882a593Smuzhiyun 				stat->acked);
160*4882a593Smuzhiyun 			idx++;
161*4882a593Smuzhiyun 		}
162*4882a593Smuzhiyun 		if (i == log->end)
163*4882a593Smuzhiyun 			break;
164*4882a593Smuzhiyun 		i++;
165*4882a593Smuzhiyun 	}
166*4882a593Smuzhiyun out_unlock:
167*4882a593Smuzhiyun 	spin_unlock_irqrestore(&log->lock, flags);
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	return count;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun /* wl->irq_lock is locked */
restart_write_file(struct b43legacy_wldev * dev,const char * buf,size_t count)173*4882a593Smuzhiyun static int restart_write_file(struct b43legacy_wldev *dev, const char *buf, size_t count)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun 	int err = 0;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	if (count > 0 && buf[0] == '1') {
178*4882a593Smuzhiyun 		b43legacy_controller_restart(dev, "manually restarted");
179*4882a593Smuzhiyun 	} else
180*4882a593Smuzhiyun 		err = -EINVAL;
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	return err;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun #undef fappend
186*4882a593Smuzhiyun 
b43legacy_debugfs_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)187*4882a593Smuzhiyun static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf,
188*4882a593Smuzhiyun 				size_t count, loff_t *ppos)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun 	struct b43legacy_wldev *dev;
191*4882a593Smuzhiyun 	struct b43legacy_debugfs_fops *dfops;
192*4882a593Smuzhiyun 	struct b43legacy_dfs_file *dfile;
193*4882a593Smuzhiyun 	ssize_t ret;
194*4882a593Smuzhiyun 	char *buf;
195*4882a593Smuzhiyun 	const size_t bufsize = 1024 * 16; /* 16 KiB buffer */
196*4882a593Smuzhiyun 	const size_t buforder = get_order(bufsize);
197*4882a593Smuzhiyun 	int err = 0;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	if (!count)
200*4882a593Smuzhiyun 		return 0;
201*4882a593Smuzhiyun 	dev = file->private_data;
202*4882a593Smuzhiyun 	if (!dev)
203*4882a593Smuzhiyun 		return -ENODEV;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	mutex_lock(&dev->wl->mutex);
206*4882a593Smuzhiyun 	if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
207*4882a593Smuzhiyun 		err = -ENODEV;
208*4882a593Smuzhiyun 		goto out_unlock;
209*4882a593Smuzhiyun 	}
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	dfops = container_of(debugfs_real_fops(file),
212*4882a593Smuzhiyun 			     struct b43legacy_debugfs_fops, fops);
213*4882a593Smuzhiyun 	if (!dfops->read) {
214*4882a593Smuzhiyun 		err = -ENOSYS;
215*4882a593Smuzhiyun 		goto out_unlock;
216*4882a593Smuzhiyun 	}
217*4882a593Smuzhiyun 	dfile = fops_to_dfs_file(dev, dfops);
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	if (!dfile->buffer) {
220*4882a593Smuzhiyun 		buf = (char *)__get_free_pages(GFP_KERNEL, buforder);
221*4882a593Smuzhiyun 		if (!buf) {
222*4882a593Smuzhiyun 			err = -ENOMEM;
223*4882a593Smuzhiyun 			goto out_unlock;
224*4882a593Smuzhiyun 		}
225*4882a593Smuzhiyun 		memset(buf, 0, bufsize);
226*4882a593Smuzhiyun 		if (dfops->take_irqlock) {
227*4882a593Smuzhiyun 			spin_lock_irq(&dev->wl->irq_lock);
228*4882a593Smuzhiyun 			ret = dfops->read(dev, buf, bufsize);
229*4882a593Smuzhiyun 			spin_unlock_irq(&dev->wl->irq_lock);
230*4882a593Smuzhiyun 		} else
231*4882a593Smuzhiyun 			ret = dfops->read(dev, buf, bufsize);
232*4882a593Smuzhiyun 		if (ret <= 0) {
233*4882a593Smuzhiyun 			free_pages((unsigned long)buf, buforder);
234*4882a593Smuzhiyun 			err = ret;
235*4882a593Smuzhiyun 			goto out_unlock;
236*4882a593Smuzhiyun 		}
237*4882a593Smuzhiyun 		dfile->data_len = ret;
238*4882a593Smuzhiyun 		dfile->buffer = buf;
239*4882a593Smuzhiyun 	}
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	ret = simple_read_from_buffer(userbuf, count, ppos,
242*4882a593Smuzhiyun 				      dfile->buffer,
243*4882a593Smuzhiyun 				      dfile->data_len);
244*4882a593Smuzhiyun 	if (*ppos >= dfile->data_len) {
245*4882a593Smuzhiyun 		free_pages((unsigned long)dfile->buffer, buforder);
246*4882a593Smuzhiyun 		dfile->buffer = NULL;
247*4882a593Smuzhiyun 		dfile->data_len = 0;
248*4882a593Smuzhiyun 	}
249*4882a593Smuzhiyun out_unlock:
250*4882a593Smuzhiyun 	mutex_unlock(&dev->wl->mutex);
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	return err ? err : ret;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun 
b43legacy_debugfs_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)255*4882a593Smuzhiyun static ssize_t b43legacy_debugfs_write(struct file *file,
256*4882a593Smuzhiyun 				 const char __user *userbuf,
257*4882a593Smuzhiyun 				 size_t count, loff_t *ppos)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun 	struct b43legacy_wldev *dev;
260*4882a593Smuzhiyun 	struct b43legacy_debugfs_fops *dfops;
261*4882a593Smuzhiyun 	char *buf;
262*4882a593Smuzhiyun 	int err = 0;
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	if (!count)
265*4882a593Smuzhiyun 		return 0;
266*4882a593Smuzhiyun 	if (count > PAGE_SIZE)
267*4882a593Smuzhiyun 		return -E2BIG;
268*4882a593Smuzhiyun 	dev = file->private_data;
269*4882a593Smuzhiyun 	if (!dev)
270*4882a593Smuzhiyun 		return -ENODEV;
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	mutex_lock(&dev->wl->mutex);
273*4882a593Smuzhiyun 	if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
274*4882a593Smuzhiyun 		err = -ENODEV;
275*4882a593Smuzhiyun 		goto out_unlock;
276*4882a593Smuzhiyun 	}
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	dfops = container_of(debugfs_real_fops(file),
279*4882a593Smuzhiyun 			     struct b43legacy_debugfs_fops, fops);
280*4882a593Smuzhiyun 	if (!dfops->write) {
281*4882a593Smuzhiyun 		err = -ENOSYS;
282*4882a593Smuzhiyun 		goto out_unlock;
283*4882a593Smuzhiyun 	}
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	buf = (char *)get_zeroed_page(GFP_KERNEL);
286*4882a593Smuzhiyun 	if (!buf) {
287*4882a593Smuzhiyun 		err = -ENOMEM;
288*4882a593Smuzhiyun 		goto out_unlock;
289*4882a593Smuzhiyun 	}
290*4882a593Smuzhiyun 	if (copy_from_user(buf, userbuf, count)) {
291*4882a593Smuzhiyun 		err = -EFAULT;
292*4882a593Smuzhiyun 		goto out_freepage;
293*4882a593Smuzhiyun 	}
294*4882a593Smuzhiyun 	if (dfops->take_irqlock) {
295*4882a593Smuzhiyun 		spin_lock_irq(&dev->wl->irq_lock);
296*4882a593Smuzhiyun 		err = dfops->write(dev, buf, count);
297*4882a593Smuzhiyun 		spin_unlock_irq(&dev->wl->irq_lock);
298*4882a593Smuzhiyun 	} else
299*4882a593Smuzhiyun 		err = dfops->write(dev, buf, count);
300*4882a593Smuzhiyun 	if (err)
301*4882a593Smuzhiyun 		goto out_freepage;
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun out_freepage:
304*4882a593Smuzhiyun 	free_page((unsigned long)buf);
305*4882a593Smuzhiyun out_unlock:
306*4882a593Smuzhiyun 	mutex_unlock(&dev->wl->mutex);
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	return err ? err : count;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun #define B43legacy_DEBUGFS_FOPS(name, _read, _write, _take_irqlock)	\
313*4882a593Smuzhiyun 	static struct b43legacy_debugfs_fops fops_##name = {		\
314*4882a593Smuzhiyun 		.read	= _read,				\
315*4882a593Smuzhiyun 		.write	= _write,				\
316*4882a593Smuzhiyun 		.fops	= {					\
317*4882a593Smuzhiyun 			.open	= simple_open,				\
318*4882a593Smuzhiyun 			.read	= b43legacy_debugfs_read,		\
319*4882a593Smuzhiyun 			.write	= b43legacy_debugfs_write,		\
320*4882a593Smuzhiyun 			.llseek = generic_file_llseek,			\
321*4882a593Smuzhiyun 		},						\
322*4882a593Smuzhiyun 		.file_struct_offset = offsetof(struct b43legacy_dfsentry, \
323*4882a593Smuzhiyun 					       file_##name),	\
324*4882a593Smuzhiyun 		.take_irqlock	= _take_irqlock,		\
325*4882a593Smuzhiyun 	}
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun B43legacy_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1);
328*4882a593Smuzhiyun B43legacy_DEBUGFS_FOPS(ucode_regs, ucode_regs_read_file, NULL, 1);
329*4882a593Smuzhiyun B43legacy_DEBUGFS_FOPS(shm, shm_read_file, NULL, 1);
330*4882a593Smuzhiyun B43legacy_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0);
331*4882a593Smuzhiyun B43legacy_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1);
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 
b43legacy_debug(struct b43legacy_wldev * dev,enum b43legacy_dyndbg feature)334*4882a593Smuzhiyun int b43legacy_debug(struct b43legacy_wldev *dev, enum b43legacy_dyndbg feature)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun 	return !!(dev->dfsentry && dev->dfsentry->dyn_debug[feature]);
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun 
b43legacy_remove_dynamic_debug(struct b43legacy_wldev * dev)339*4882a593Smuzhiyun static void b43legacy_remove_dynamic_debug(struct b43legacy_wldev *dev)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun 	struct b43legacy_dfsentry *e = dev->dfsentry;
342*4882a593Smuzhiyun 	int i;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	for (i = 0; i < __B43legacy_NR_DYNDBG; i++)
345*4882a593Smuzhiyun 		debugfs_remove(e->dyn_debug_dentries[i]);
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun 
b43legacy_add_dynamic_debug(struct b43legacy_wldev * dev)348*4882a593Smuzhiyun static void b43legacy_add_dynamic_debug(struct b43legacy_wldev *dev)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun 	struct b43legacy_dfsentry *e = dev->dfsentry;
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun #define add_dyn_dbg(name, id, initstate) do {			\
353*4882a593Smuzhiyun 	e->dyn_debug[id] = (initstate);				\
354*4882a593Smuzhiyun 	e->dyn_debug_dentries[id] =				\
355*4882a593Smuzhiyun 		debugfs_create_bool(name, 0600, e->subdir,	\
356*4882a593Smuzhiyun 				&(e->dyn_debug[id]));		\
357*4882a593Smuzhiyun 	} while (0)
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	add_dyn_dbg("debug_xmitpower", B43legacy_DBG_XMITPOWER, false);
360*4882a593Smuzhiyun 	add_dyn_dbg("debug_dmaoverflow", B43legacy_DBG_DMAOVERFLOW, false);
361*4882a593Smuzhiyun 	add_dyn_dbg("debug_dmaverbose", B43legacy_DBG_DMAVERBOSE, false);
362*4882a593Smuzhiyun 	add_dyn_dbg("debug_pwork_fast", B43legacy_DBG_PWORK_FAST, false);
363*4882a593Smuzhiyun 	add_dyn_dbg("debug_pwork_stop", B43legacy_DBG_PWORK_STOP, false);
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun #undef add_dyn_dbg
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun 
b43legacy_debugfs_add_device(struct b43legacy_wldev * dev)368*4882a593Smuzhiyun void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun 	struct b43legacy_dfsentry *e;
371*4882a593Smuzhiyun 	struct b43legacy_txstatus_log *log;
372*4882a593Smuzhiyun 	char devdir[16];
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	B43legacy_WARN_ON(!dev);
375*4882a593Smuzhiyun 	e = kzalloc(sizeof(*e), GFP_KERNEL);
376*4882a593Smuzhiyun 	if (!e) {
377*4882a593Smuzhiyun 		b43legacyerr(dev->wl, "debugfs: add device OOM\n");
378*4882a593Smuzhiyun 		return;
379*4882a593Smuzhiyun 	}
380*4882a593Smuzhiyun 	e->dev = dev;
381*4882a593Smuzhiyun 	log = &e->txstatlog;
382*4882a593Smuzhiyun 	log->log = kcalloc(B43legacy_NR_LOGGED_TXSTATUS,
383*4882a593Smuzhiyun 			   sizeof(struct b43legacy_txstatus), GFP_KERNEL);
384*4882a593Smuzhiyun 	if (!log->log) {
385*4882a593Smuzhiyun 		b43legacyerr(dev->wl, "debugfs: add device txstatus OOM\n");
386*4882a593Smuzhiyun 		kfree(e);
387*4882a593Smuzhiyun 		return;
388*4882a593Smuzhiyun 	}
389*4882a593Smuzhiyun 	log->end = -1;
390*4882a593Smuzhiyun 	spin_lock_init(&log->lock);
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	dev->dfsentry = e;
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy));
395*4882a593Smuzhiyun 	e->subdir = debugfs_create_dir(devdir, rootdir);
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun #define ADD_FILE(name, mode)	\
398*4882a593Smuzhiyun 	do {							\
399*4882a593Smuzhiyun 		e->file_##name.dentry =				\
400*4882a593Smuzhiyun 			debugfs_create_file(__stringify(name),	\
401*4882a593Smuzhiyun 					mode, e->subdir, dev,	\
402*4882a593Smuzhiyun 					&fops_##name.fops);	\
403*4882a593Smuzhiyun 		e->file_##name.dentry = NULL;			\
404*4882a593Smuzhiyun 	} while (0)
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	ADD_FILE(tsf, 0600);
408*4882a593Smuzhiyun 	ADD_FILE(ucode_regs, 0400);
409*4882a593Smuzhiyun 	ADD_FILE(shm, 0400);
410*4882a593Smuzhiyun 	ADD_FILE(txstat, 0400);
411*4882a593Smuzhiyun 	ADD_FILE(restart, 0200);
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun #undef ADD_FILE
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	b43legacy_add_dynamic_debug(dev);
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun 
b43legacy_debugfs_remove_device(struct b43legacy_wldev * dev)418*4882a593Smuzhiyun void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev)
419*4882a593Smuzhiyun {
420*4882a593Smuzhiyun 	struct b43legacy_dfsentry *e;
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	if (!dev)
423*4882a593Smuzhiyun 		return;
424*4882a593Smuzhiyun 	e = dev->dfsentry;
425*4882a593Smuzhiyun 	if (!e)
426*4882a593Smuzhiyun 		return;
427*4882a593Smuzhiyun 	b43legacy_remove_dynamic_debug(dev);
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	debugfs_remove(e->file_tsf.dentry);
430*4882a593Smuzhiyun 	debugfs_remove(e->file_ucode_regs.dentry);
431*4882a593Smuzhiyun 	debugfs_remove(e->file_shm.dentry);
432*4882a593Smuzhiyun 	debugfs_remove(e->file_txstat.dentry);
433*4882a593Smuzhiyun 	debugfs_remove(e->file_restart.dentry);
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	debugfs_remove(e->subdir);
436*4882a593Smuzhiyun 	kfree(e->txstatlog.log);
437*4882a593Smuzhiyun 	kfree(e);
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun 
b43legacy_debugfs_log_txstat(struct b43legacy_wldev * dev,const struct b43legacy_txstatus * status)440*4882a593Smuzhiyun void b43legacy_debugfs_log_txstat(struct b43legacy_wldev *dev,
441*4882a593Smuzhiyun 			    const struct b43legacy_txstatus *status)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun 	struct b43legacy_dfsentry *e = dev->dfsentry;
444*4882a593Smuzhiyun 	struct b43legacy_txstatus_log *log;
445*4882a593Smuzhiyun 	struct b43legacy_txstatus *cur;
446*4882a593Smuzhiyun 	int i;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	if (!e)
449*4882a593Smuzhiyun 		return;
450*4882a593Smuzhiyun 	log = &e->txstatlog;
451*4882a593Smuzhiyun 	B43legacy_WARN_ON(!irqs_disabled());
452*4882a593Smuzhiyun 	spin_lock(&log->lock);
453*4882a593Smuzhiyun 	i = log->end + 1;
454*4882a593Smuzhiyun 	if (i == B43legacy_NR_LOGGED_TXSTATUS)
455*4882a593Smuzhiyun 		i = 0;
456*4882a593Smuzhiyun 	log->end = i;
457*4882a593Smuzhiyun 	cur = &(log->log[i]);
458*4882a593Smuzhiyun 	memcpy(cur, status, sizeof(*cur));
459*4882a593Smuzhiyun 	spin_unlock(&log->lock);
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun 
b43legacy_debugfs_init(void)462*4882a593Smuzhiyun void b43legacy_debugfs_init(void)
463*4882a593Smuzhiyun {
464*4882a593Smuzhiyun 	rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun 
b43legacy_debugfs_exit(void)467*4882a593Smuzhiyun void b43legacy_debugfs_exit(void)
468*4882a593Smuzhiyun {
469*4882a593Smuzhiyun 	debugfs_remove(rootdir);
470*4882a593Smuzhiyun }
471