1 /*
2 
3   Broadcom B43 wireless driver
4 
5   debugfs driver debugging code
6 
7   Copyright (c) 2005-2007 Michael Buesch <m@bues.ch>
8 
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13 
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18 
19   You should have received a copy of the GNU General Public License
20   along with this program; see the file COPYING.  If not, write to
21   the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
22   Boston, MA 02110-1301, USA.
23 
24 */
25 
26 #include <linux/fs.h>
27 #include <linux/debugfs.h>
28 #include <linux/slab.h>
29 #include <linux/netdevice.h>
30 #include <linux/pci.h>
31 #include <linux/mutex.h>
32 
33 #include "b43.h"
34 #include "main.h"
35 #include "debugfs.h"
36 #include "dma.h"
37 #include "xmit.h"
38 
39 
40 /* The root directory. */
41 static struct dentry *rootdir;
42 
43 struct b43_debugfs_fops {
44 	ssize_t (*read)(struct b43_wldev *dev, char *buf, size_t bufsize);
45 	int (*write)(struct b43_wldev *dev, const char *buf, size_t count);
46 	struct file_operations fops;
47 	/* Offset of struct b43_dfs_file in struct b43_dfsentry */
48 	size_t file_struct_offset;
49 };
50 
51 static inline
fops_to_dfs_file(struct b43_wldev * dev,const struct b43_debugfs_fops * dfops)52 struct b43_dfs_file *fops_to_dfs_file(struct b43_wldev *dev,
53 				      const struct b43_debugfs_fops *dfops)
54 {
55 	void *p;
56 
57 	p = dev->dfsentry;
58 	p += dfops->file_struct_offset;
59 
60 	return p;
61 }
62 
63 
64 #define fappend(fmt, x...)	\
65 	do {							\
66 		if (bufsize - count)				\
67 			count += snprintf(buf + count,		\
68 					  bufsize - count,	\
69 					  fmt , ##x);		\
70 		else						\
71 			printk(KERN_ERR "b43: fappend overflow\n"); \
72 	} while (0)
73 
74 
75 /* The biggest address values for SHM access from the debugfs files. */
76 #define B43_MAX_SHM_ROUTING	4
77 #define B43_MAX_SHM_ADDR	0xFFFF
78 
shm16read__read_file(struct b43_wldev * dev,char * buf,size_t bufsize)79 static ssize_t shm16read__read_file(struct b43_wldev *dev,
80 				    char *buf, size_t bufsize)
81 {
82 	ssize_t count = 0;
83 	unsigned int routing, addr;
84 	u16 val;
85 
86 	routing = dev->dfsentry->shm16read_routing_next;
87 	addr = dev->dfsentry->shm16read_addr_next;
88 	if ((routing > B43_MAX_SHM_ROUTING) ||
89 	    (addr > B43_MAX_SHM_ADDR))
90 		return -EDESTADDRREQ;
91 
92 	val = b43_shm_read16(dev, routing, addr);
93 	fappend("0x%04X\n", val);
94 
95 	return count;
96 }
97 
shm16read__write_file(struct b43_wldev * dev,const char * buf,size_t count)98 static int shm16read__write_file(struct b43_wldev *dev,
99 				 const char *buf, size_t count)
100 {
101 	unsigned int routing, addr;
102 	int res;
103 
104 	res = sscanf(buf, "0x%X 0x%X", &routing, &addr);
105 	if (res != 2)
106 		return -EINVAL;
107 	if (routing > B43_MAX_SHM_ROUTING)
108 		return -EADDRNOTAVAIL;
109 	if (addr > B43_MAX_SHM_ADDR)
110 		return -EADDRNOTAVAIL;
111 	if (routing == B43_SHM_SHARED) {
112 		if ((addr % 2) != 0)
113 			return -EADDRNOTAVAIL;
114 	}
115 
116 	dev->dfsentry->shm16read_routing_next = routing;
117 	dev->dfsentry->shm16read_addr_next = addr;
118 
119 	return 0;
120 }
121 
shm16write__write_file(struct b43_wldev * dev,const char * buf,size_t count)122 static int shm16write__write_file(struct b43_wldev *dev,
123 				  const char *buf, size_t count)
124 {
125 	unsigned int routing, addr, mask, set;
126 	u16 val;
127 	int res;
128 
129 	res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X",
130 		     &routing, &addr, &mask, &set);
131 	if (res != 4)
132 		return -EINVAL;
133 	if (routing > B43_MAX_SHM_ROUTING)
134 		return -EADDRNOTAVAIL;
135 	if (addr > B43_MAX_SHM_ADDR)
136 		return -EADDRNOTAVAIL;
137 	if (routing == B43_SHM_SHARED) {
138 		if ((addr % 2) != 0)
139 			return -EADDRNOTAVAIL;
140 	}
141 	if ((mask > 0xFFFF) || (set > 0xFFFF))
142 		return -E2BIG;
143 
144 	if (mask == 0)
145 		val = 0;
146 	else
147 		val = b43_shm_read16(dev, routing, addr);
148 	val &= mask;
149 	val |= set;
150 	b43_shm_write16(dev, routing, addr, val);
151 
152 	return 0;
153 }
154 
shm32read__read_file(struct b43_wldev * dev,char * buf,size_t bufsize)155 static ssize_t shm32read__read_file(struct b43_wldev *dev,
156 				    char *buf, size_t bufsize)
157 {
158 	ssize_t count = 0;
159 	unsigned int routing, addr;
160 	u32 val;
161 
162 	routing = dev->dfsentry->shm32read_routing_next;
163 	addr = dev->dfsentry->shm32read_addr_next;
164 	if ((routing > B43_MAX_SHM_ROUTING) ||
165 	    (addr > B43_MAX_SHM_ADDR))
166 		return -EDESTADDRREQ;
167 
168 	val = b43_shm_read32(dev, routing, addr);
169 	fappend("0x%08X\n", val);
170 
171 	return count;
172 }
173 
shm32read__write_file(struct b43_wldev * dev,const char * buf,size_t count)174 static int shm32read__write_file(struct b43_wldev *dev,
175 				 const char *buf, size_t count)
176 {
177 	unsigned int routing, addr;
178 	int res;
179 
180 	res = sscanf(buf, "0x%X 0x%X", &routing, &addr);
181 	if (res != 2)
182 		return -EINVAL;
183 	if (routing > B43_MAX_SHM_ROUTING)
184 		return -EADDRNOTAVAIL;
185 	if (addr > B43_MAX_SHM_ADDR)
186 		return -EADDRNOTAVAIL;
187 	if (routing == B43_SHM_SHARED) {
188 		if ((addr % 2) != 0)
189 			return -EADDRNOTAVAIL;
190 	}
191 
192 	dev->dfsentry->shm32read_routing_next = routing;
193 	dev->dfsentry->shm32read_addr_next = addr;
194 
195 	return 0;
196 }
197 
shm32write__write_file(struct b43_wldev * dev,const char * buf,size_t count)198 static int shm32write__write_file(struct b43_wldev *dev,
199 				  const char *buf, size_t count)
200 {
201 	unsigned int routing, addr, mask, set;
202 	u32 val;
203 	int res;
204 
205 	res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X",
206 		     &routing, &addr, &mask, &set);
207 	if (res != 4)
208 		return -EINVAL;
209 	if (routing > B43_MAX_SHM_ROUTING)
210 		return -EADDRNOTAVAIL;
211 	if (addr > B43_MAX_SHM_ADDR)
212 		return -EADDRNOTAVAIL;
213 	if (routing == B43_SHM_SHARED) {
214 		if ((addr % 2) != 0)
215 			return -EADDRNOTAVAIL;
216 	}
217 	if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF))
218 		return -E2BIG;
219 
220 	if (mask == 0)
221 		val = 0;
222 	else
223 		val = b43_shm_read32(dev, routing, addr);
224 	val &= mask;
225 	val |= set;
226 	b43_shm_write32(dev, routing, addr, val);
227 
228 	return 0;
229 }
230 
231 /* The biggest MMIO address that we allow access to from the debugfs files. */
232 #define B43_MAX_MMIO_ACCESS	(0xF00 - 1)
233 
mmio16read__read_file(struct b43_wldev * dev,char * buf,size_t bufsize)234 static ssize_t mmio16read__read_file(struct b43_wldev *dev,
235 				     char *buf, size_t bufsize)
236 {
237 	ssize_t count = 0;
238 	unsigned int addr;
239 	u16 val;
240 
241 	addr = dev->dfsentry->mmio16read_next;
242 	if (addr > B43_MAX_MMIO_ACCESS)
243 		return -EDESTADDRREQ;
244 
245 	val = b43_read16(dev, addr);
246 	fappend("0x%04X\n", val);
247 
248 	return count;
249 }
250 
mmio16read__write_file(struct b43_wldev * dev,const char * buf,size_t count)251 static int mmio16read__write_file(struct b43_wldev *dev,
252 				  const char *buf, size_t count)
253 {
254 	unsigned int addr;
255 	int res;
256 
257 	res = sscanf(buf, "0x%X", &addr);
258 	if (res != 1)
259 		return -EINVAL;
260 	if (addr > B43_MAX_MMIO_ACCESS)
261 		return -EADDRNOTAVAIL;
262 	if ((addr % 2) != 0)
263 		return -EINVAL;
264 
265 	dev->dfsentry->mmio16read_next = addr;
266 
267 	return 0;
268 }
269 
mmio16write__write_file(struct b43_wldev * dev,const char * buf,size_t count)270 static int mmio16write__write_file(struct b43_wldev *dev,
271 				   const char *buf, size_t count)
272 {
273 	unsigned int addr, mask, set;
274 	int res;
275 	u16 val;
276 
277 	res = sscanf(buf, "0x%X 0x%X 0x%X", &addr, &mask, &set);
278 	if (res != 3)
279 		return -EINVAL;
280 	if (addr > B43_MAX_MMIO_ACCESS)
281 		return -EADDRNOTAVAIL;
282 	if ((mask > 0xFFFF) || (set > 0xFFFF))
283 		return -E2BIG;
284 	if ((addr % 2) != 0)
285 		return -EINVAL;
286 
287 	if (mask == 0)
288 		val = 0;
289 	else
290 		val = b43_read16(dev, addr);
291 	val &= mask;
292 	val |= set;
293 	b43_write16(dev, addr, val);
294 
295 	return 0;
296 }
297 
mmio32read__read_file(struct b43_wldev * dev,char * buf,size_t bufsize)298 static ssize_t mmio32read__read_file(struct b43_wldev *dev,
299 				     char *buf, size_t bufsize)
300 {
301 	ssize_t count = 0;
302 	unsigned int addr;
303 	u32 val;
304 
305 	addr = dev->dfsentry->mmio32read_next;
306 	if (addr > B43_MAX_MMIO_ACCESS)
307 		return -EDESTADDRREQ;
308 
309 	val = b43_read32(dev, addr);
310 	fappend("0x%08X\n", val);
311 
312 	return count;
313 }
314 
mmio32read__write_file(struct b43_wldev * dev,const char * buf,size_t count)315 static int mmio32read__write_file(struct b43_wldev *dev,
316 				  const char *buf, size_t count)
317 {
318 	unsigned int addr;
319 	int res;
320 
321 	res = sscanf(buf, "0x%X", &addr);
322 	if (res != 1)
323 		return -EINVAL;
324 	if (addr > B43_MAX_MMIO_ACCESS)
325 		return -EADDRNOTAVAIL;
326 	if ((addr % 4) != 0)
327 		return -EINVAL;
328 
329 	dev->dfsentry->mmio32read_next = addr;
330 
331 	return 0;
332 }
333 
mmio32write__write_file(struct b43_wldev * dev,const char * buf,size_t count)334 static int mmio32write__write_file(struct b43_wldev *dev,
335 				   const char *buf, size_t count)
336 {
337 	unsigned int addr, mask, set;
338 	int res;
339 	u32 val;
340 
341 	res = sscanf(buf, "0x%X 0x%X 0x%X", &addr, &mask, &set);
342 	if (res != 3)
343 		return -EINVAL;
344 	if (addr > B43_MAX_MMIO_ACCESS)
345 		return -EADDRNOTAVAIL;
346 	if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF))
347 		return -E2BIG;
348 	if ((addr % 4) != 0)
349 		return -EINVAL;
350 
351 	if (mask == 0)
352 		val = 0;
353 	else
354 		val = b43_read32(dev, addr);
355 	val &= mask;
356 	val |= set;
357 	b43_write32(dev, addr, val);
358 
359 	return 0;
360 }
361 
txstat_read_file(struct b43_wldev * dev,char * buf,size_t bufsize)362 static ssize_t txstat_read_file(struct b43_wldev *dev,
363 				char *buf, size_t bufsize)
364 {
365 	struct b43_txstatus_log *log = &dev->dfsentry->txstatlog;
366 	ssize_t count = 0;
367 	int i, idx;
368 	struct b43_txstatus *stat;
369 
370 	if (log->end < 0) {
371 		fappend("Nothing transmitted, yet\n");
372 		goto out;
373 	}
374 	fappend("b43 TX status reports:\n\n"
375 		"index | cookie | seq | phy_stat | frame_count | "
376 		"rts_count | supp_reason | pm_indicated | "
377 		"intermediate | for_ampdu | acked\n" "---\n");
378 	i = log->end + 1;
379 	idx = 0;
380 	while (1) {
381 		if (i == B43_NR_LOGGED_TXSTATUS)
382 			i = 0;
383 		stat = &(log->log[i]);
384 		if (stat->cookie) {
385 			fappend("%03d | "
386 				"0x%04X | 0x%04X | 0x%02X | "
387 				"0x%X | 0x%X | "
388 				"%u | %u | "
389 				"%u | %u | %u\n",
390 				idx,
391 				stat->cookie, stat->seq, stat->phy_stat,
392 				stat->frame_count, stat->rts_count,
393 				stat->supp_reason, stat->pm_indicated,
394 				stat->intermediate, stat->for_ampdu,
395 				stat->acked);
396 			idx++;
397 		}
398 		if (i == log->end)
399 			break;
400 		i++;
401 	}
402 out:
403 
404 	return count;
405 }
406 
restart_write_file(struct b43_wldev * dev,const char * buf,size_t count)407 static int restart_write_file(struct b43_wldev *dev,
408 			      const char *buf, size_t count)
409 {
410 	int err = 0;
411 
412 	if (count > 0 && buf[0] == '1') {
413 		b43_controller_restart(dev, "manually restarted");
414 	} else
415 		err = -EINVAL;
416 
417 	return err;
418 }
419 
calc_expire_secs(unsigned long now,unsigned long time,unsigned long expire)420 static unsigned long calc_expire_secs(unsigned long now,
421 				      unsigned long time,
422 				      unsigned long expire)
423 {
424 	expire = time + expire;
425 
426 	if (time_after(now, expire))
427 		return 0; /* expired */
428 	if (expire < now) {
429 		/* jiffies wrapped */
430 		expire -= MAX_JIFFY_OFFSET;
431 		now -= MAX_JIFFY_OFFSET;
432 	}
433 	B43_WARN_ON(expire < now);
434 
435 	return (expire - now) / HZ;
436 }
437 
loctls_read_file(struct b43_wldev * dev,char * buf,size_t bufsize)438 static ssize_t loctls_read_file(struct b43_wldev *dev,
439 				char *buf, size_t bufsize)
440 {
441 	ssize_t count = 0;
442 	struct b43_txpower_lo_control *lo;
443 	int i, err = 0;
444 	struct b43_lo_calib *cal;
445 	unsigned long now = jiffies;
446 	struct b43_phy *phy = &dev->phy;
447 
448 	if (phy->type != B43_PHYTYPE_G) {
449 		fappend("Device is not a G-PHY\n");
450 		err = -ENODEV;
451 		goto out;
452 	}
453 	lo = phy->g->lo_control;
454 	fappend("-- Local Oscillator calibration data --\n\n");
455 	fappend("HW-power-control enabled: %d\n",
456 		dev->phy.hardware_power_control);
457 	fappend("TX Bias: 0x%02X,  TX Magn: 0x%02X  (expire in %lu sec)\n",
458 		lo->tx_bias, lo->tx_magn,
459 		calc_expire_secs(now, lo->txctl_measured_time,
460 				 B43_LO_TXCTL_EXPIRE));
461 	fappend("Power Vector: 0x%08X%08X  (expires in %lu sec)\n",
462 		(unsigned int)((lo->power_vector & 0xFFFFFFFF00000000ULL) >> 32),
463 		(unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL),
464 		calc_expire_secs(now, lo->pwr_vec_read_time,
465 				 B43_LO_PWRVEC_EXPIRE));
466 
467 	fappend("\nCalibrated settings:\n");
468 	list_for_each_entry(cal, &lo->calib_list, list) {
469 		bool active;
470 
471 		active = (b43_compare_bbatt(&cal->bbatt, &phy->g->bbatt) &&
472 			  b43_compare_rfatt(&cal->rfatt, &phy->g->rfatt));
473 		fappend("BB(%d), RF(%d,%d)  ->  I=%d, Q=%d  "
474 			"(expires in %lu sec)%s\n",
475 			cal->bbatt.att,
476 			cal->rfatt.att, cal->rfatt.with_padmix,
477 			cal->ctl.i, cal->ctl.q,
478 			calc_expire_secs(now, cal->calib_time,
479 					 B43_LO_CALIB_EXPIRE),
480 			active ? "  ACTIVE" : "");
481 	}
482 
483 	fappend("\nUsed RF attenuation values:  Value(WithPadmix flag)\n");
484 	for (i = 0; i < lo->rfatt_list.len; i++) {
485 		fappend("%u(%d), ",
486 			lo->rfatt_list.list[i].att,
487 			lo->rfatt_list.list[i].with_padmix);
488 	}
489 	fappend("\n");
490 	fappend("\nUsed Baseband attenuation values:\n");
491 	for (i = 0; i < lo->bbatt_list.len; i++) {
492 		fappend("%u, ",
493 			lo->bbatt_list.list[i].att);
494 	}
495 	fappend("\n");
496 
497 out:
498 	return err ? err : count;
499 }
500 
501 #undef fappend
502 
b43_debugfs_open(struct inode * inode,struct file * file)503 static int b43_debugfs_open(struct inode *inode, struct file *file)
504 {
505 	file->private_data = inode->i_private;
506 	return 0;
507 }
508 
b43_debugfs_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)509 static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
510 				size_t count, loff_t *ppos)
511 {
512 	struct b43_wldev *dev;
513 	struct b43_debugfs_fops *dfops;
514 	struct b43_dfs_file *dfile;
515 	ssize_t uninitialized_var(ret);
516 	char *buf;
517 	const size_t bufsize = 1024 * 16; /* 16 kiB buffer */
518 	const size_t buforder = get_order(bufsize);
519 	int err = 0;
520 
521 	if (!count)
522 		return 0;
523 	dev = file->private_data;
524 	if (!dev)
525 		return -ENODEV;
526 
527 	mutex_lock(&dev->wl->mutex);
528 	if (b43_status(dev) < B43_STAT_INITIALIZED) {
529 		err = -ENODEV;
530 		goto out_unlock;
531 	}
532 
533 	dfops = container_of(file->f_op, struct b43_debugfs_fops, fops);
534 	if (!dfops->read) {
535 		err = -ENOSYS;
536 		goto out_unlock;
537 	}
538 	dfile = fops_to_dfs_file(dev, dfops);
539 
540 	if (!dfile->buffer) {
541 		buf = (char *)__get_free_pages(GFP_KERNEL, buforder);
542 		if (!buf) {
543 			err = -ENOMEM;
544 			goto out_unlock;
545 		}
546 		memset(buf, 0, bufsize);
547 		ret = dfops->read(dev, buf, bufsize);
548 		if (ret <= 0) {
549 			free_pages((unsigned long)buf, buforder);
550 			err = ret;
551 			goto out_unlock;
552 		}
553 		dfile->data_len = ret;
554 		dfile->buffer = buf;
555 	}
556 
557 	ret = simple_read_from_buffer(userbuf, count, ppos,
558 				      dfile->buffer,
559 				      dfile->data_len);
560 	if (*ppos >= dfile->data_len) {
561 		free_pages((unsigned long)dfile->buffer, buforder);
562 		dfile->buffer = NULL;
563 		dfile->data_len = 0;
564 	}
565 out_unlock:
566 	mutex_unlock(&dev->wl->mutex);
567 
568 	return err ? err : ret;
569 }
570 
b43_debugfs_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)571 static ssize_t b43_debugfs_write(struct file *file,
572 				 const char __user *userbuf,
573 				 size_t count, loff_t *ppos)
574 {
575 	struct b43_wldev *dev;
576 	struct b43_debugfs_fops *dfops;
577 	char *buf;
578 	int err = 0;
579 
580 	if (!count)
581 		return 0;
582 	if (count > PAGE_SIZE)
583 		return -E2BIG;
584 	dev = file->private_data;
585 	if (!dev)
586 		return -ENODEV;
587 
588 	mutex_lock(&dev->wl->mutex);
589 	if (b43_status(dev) < B43_STAT_INITIALIZED) {
590 		err = -ENODEV;
591 		goto out_unlock;
592 	}
593 
594 	dfops = container_of(file->f_op, struct b43_debugfs_fops, fops);
595 	if (!dfops->write) {
596 		err = -ENOSYS;
597 		goto out_unlock;
598 	}
599 
600 	buf = (char *)get_zeroed_page(GFP_KERNEL);
601 	if (!buf) {
602 		err = -ENOMEM;
603 		goto out_unlock;
604 	}
605 	if (copy_from_user(buf, userbuf, count)) {
606 		err = -EFAULT;
607 		goto out_freepage;
608 	}
609 	err = dfops->write(dev, buf, count);
610 	if (err)
611 		goto out_freepage;
612 
613 out_freepage:
614 	free_page((unsigned long)buf);
615 out_unlock:
616 	mutex_unlock(&dev->wl->mutex);
617 
618 	return err ? err : count;
619 }
620 
621 
622 #define B43_DEBUGFS_FOPS(name, _read, _write)			\
623 	static struct b43_debugfs_fops fops_##name = {		\
624 		.read	= _read,				\
625 		.write	= _write,				\
626 		.fops	= {					\
627 			.open	= b43_debugfs_open,		\
628 			.read	= b43_debugfs_read,		\
629 			.write	= b43_debugfs_write,		\
630 			.llseek = generic_file_llseek,		\
631 		},						\
632 		.file_struct_offset = offsetof(struct b43_dfsentry, \
633 					       file_##name),	\
634 	}
635 
636 B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file);
637 B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file);
638 B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file);
639 B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file);
640 B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file);
641 B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file);
642 B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file);
643 B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file);
644 B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL);
645 B43_DEBUGFS_FOPS(restart, NULL, restart_write_file);
646 B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL);
647 
648 
b43_debug(struct b43_wldev * dev,enum b43_dyndbg feature)649 bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature)
650 {
651 	bool enabled;
652 
653 	enabled = (dev->dfsentry && dev->dfsentry->dyn_debug[feature]);
654 	if (unlikely(enabled)) {
655 		/* Force full debugging messages, if the user enabled
656 		 * some dynamic debugging feature. */
657 		b43_modparam_verbose = B43_VERBOSITY_MAX;
658 	}
659 
660 	return enabled;
661 }
662 
b43_remove_dynamic_debug(struct b43_wldev * dev)663 static void b43_remove_dynamic_debug(struct b43_wldev *dev)
664 {
665 	struct b43_dfsentry *e = dev->dfsentry;
666 	int i;
667 
668 	for (i = 0; i < __B43_NR_DYNDBG; i++)
669 		debugfs_remove(e->dyn_debug_dentries[i]);
670 }
671 
b43_add_dynamic_debug(struct b43_wldev * dev)672 static void b43_add_dynamic_debug(struct b43_wldev *dev)
673 {
674 	struct b43_dfsentry *e = dev->dfsentry;
675 	struct dentry *d;
676 
677 #define add_dyn_dbg(name, id, initstate) do {		\
678 	e->dyn_debug[id] = (initstate);			\
679 	d = debugfs_create_bool(name, 0600, e->subdir,	\
680 				&(e->dyn_debug[id]));	\
681 	if (!IS_ERR(d))					\
682 		e->dyn_debug_dentries[id] = d;		\
683 				} while (0)
684 
685 	add_dyn_dbg("debug_xmitpower", B43_DBG_XMITPOWER, 0);
686 	add_dyn_dbg("debug_dmaoverflow", B43_DBG_DMAOVERFLOW, 0);
687 	add_dyn_dbg("debug_dmaverbose", B43_DBG_DMAVERBOSE, 0);
688 	add_dyn_dbg("debug_pwork_fast", B43_DBG_PWORK_FAST, 0);
689 	add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0);
690 	add_dyn_dbg("debug_lo", B43_DBG_LO, 0);
691 	add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, 0);
692 	add_dyn_dbg("debug_keys", B43_DBG_KEYS, 0);
693 	add_dyn_dbg("debug_verbose_stats", B43_DBG_VERBOSESTATS, 0);
694 
695 #undef add_dyn_dbg
696 }
697 
b43_debugfs_add_device(struct b43_wldev * dev)698 void b43_debugfs_add_device(struct b43_wldev *dev)
699 {
700 	struct b43_dfsentry *e;
701 	struct b43_txstatus_log *log;
702 	char devdir[16];
703 
704 	B43_WARN_ON(!dev);
705 	e = kzalloc(sizeof(*e), GFP_KERNEL);
706 	if (!e) {
707 		b43err(dev->wl, "debugfs: add device OOM\n");
708 		return;
709 	}
710 	e->dev = dev;
711 	log = &e->txstatlog;
712 	log->log = kcalloc(B43_NR_LOGGED_TXSTATUS,
713 			   sizeof(struct b43_txstatus), GFP_KERNEL);
714 	if (!log->log) {
715 		b43err(dev->wl, "debugfs: add device txstatus OOM\n");
716 		kfree(e);
717 		return;
718 	}
719 	log->end = -1;
720 
721 	dev->dfsentry = e;
722 
723 	snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy));
724 	e->subdir = debugfs_create_dir(devdir, rootdir);
725 	if (!e->subdir || IS_ERR(e->subdir)) {
726 		if (e->subdir == ERR_PTR(-ENODEV)) {
727 			b43dbg(dev->wl, "DebugFS (CONFIG_DEBUG_FS) not "
728 			       "enabled in kernel config\n");
729 		} else {
730 			b43err(dev->wl, "debugfs: cannot create %s directory\n",
731 			       devdir);
732 		}
733 		dev->dfsentry = NULL;
734 		kfree(log->log);
735 		kfree(e);
736 		return;
737 	}
738 
739 	e->mmio16read_next = 0xFFFF; /* invalid address */
740 	e->mmio32read_next = 0xFFFF; /* invalid address */
741 	e->shm16read_routing_next = 0xFFFFFFFF; /* invalid routing */
742 	e->shm16read_addr_next = 0xFFFFFFFF; /* invalid address */
743 	e->shm32read_routing_next = 0xFFFFFFFF; /* invalid routing */
744 	e->shm32read_addr_next = 0xFFFFFFFF; /* invalid address */
745 
746 #define ADD_FILE(name, mode)	\
747 	do {							\
748 		struct dentry *d;				\
749 		d = debugfs_create_file(__stringify(name),	\
750 					mode, e->subdir, dev,	\
751 					&fops_##name.fops);	\
752 		e->file_##name.dentry = NULL;			\
753 		if (!IS_ERR(d))					\
754 			e->file_##name.dentry = d;		\
755 	} while (0)
756 
757 
758 	ADD_FILE(shm16read, 0600);
759 	ADD_FILE(shm16write, 0200);
760 	ADD_FILE(shm32read, 0600);
761 	ADD_FILE(shm32write, 0200);
762 	ADD_FILE(mmio16read, 0600);
763 	ADD_FILE(mmio16write, 0200);
764 	ADD_FILE(mmio32read, 0600);
765 	ADD_FILE(mmio32write, 0200);
766 	ADD_FILE(txstat, 0400);
767 	ADD_FILE(restart, 0200);
768 	ADD_FILE(loctls, 0400);
769 
770 #undef ADD_FILE
771 
772 	b43_add_dynamic_debug(dev);
773 }
774 
b43_debugfs_remove_device(struct b43_wldev * dev)775 void b43_debugfs_remove_device(struct b43_wldev *dev)
776 {
777 	struct b43_dfsentry *e;
778 
779 	if (!dev)
780 		return;
781 	e = dev->dfsentry;
782 	if (!e)
783 		return;
784 	b43_remove_dynamic_debug(dev);
785 
786 	debugfs_remove(e->file_shm16read.dentry);
787 	debugfs_remove(e->file_shm16write.dentry);
788 	debugfs_remove(e->file_shm32read.dentry);
789 	debugfs_remove(e->file_shm32write.dentry);
790 	debugfs_remove(e->file_mmio16read.dentry);
791 	debugfs_remove(e->file_mmio16write.dentry);
792 	debugfs_remove(e->file_mmio32read.dentry);
793 	debugfs_remove(e->file_mmio32write.dentry);
794 	debugfs_remove(e->file_txstat.dentry);
795 	debugfs_remove(e->file_restart.dentry);
796 	debugfs_remove(e->file_loctls.dentry);
797 
798 	debugfs_remove(e->subdir);
799 	kfree(e->txstatlog.log);
800 	kfree(e);
801 }
802 
b43_debugfs_log_txstat(struct b43_wldev * dev,const struct b43_txstatus * status)803 void b43_debugfs_log_txstat(struct b43_wldev *dev,
804 			    const struct b43_txstatus *status)
805 {
806 	struct b43_dfsentry *e = dev->dfsentry;
807 	struct b43_txstatus_log *log;
808 	struct b43_txstatus *cur;
809 	int i;
810 
811 	if (!e)
812 		return;
813 	log = &e->txstatlog;
814 	i = log->end + 1;
815 	if (i == B43_NR_LOGGED_TXSTATUS)
816 		i = 0;
817 	log->end = i;
818 	cur = &(log->log[i]);
819 	memcpy(cur, status, sizeof(*cur));
820 }
821 
b43_debugfs_init(void)822 void b43_debugfs_init(void)
823 {
824 	rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
825 	if (IS_ERR(rootdir))
826 		rootdir = NULL;
827 }
828 
b43_debugfs_exit(void)829 void b43_debugfs_exit(void)
830 {
831 	debugfs_remove(rootdir);
832 }
833