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