1 // SPDX-License-Identifier: GPL-2.0-or-later
4 Broadcom B43 wireless driver
6 debugfs driver debugging code
8 Copyright (c) 2005-2007 Michael Buesch <m@bues.ch>
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>
27 /* The root directory. */
28 static struct dentry
*rootdir
;
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
;
39 struct b43_dfs_file
*fops_to_dfs_file(struct b43_wldev
*dev
,
40 const struct b43_debugfs_fops
*dfops
)
45 p
+= dfops
->file_struct_offset
;
51 #define fappend(fmt, x...) \
53 if (bufsize - count) \
54 count += snprintf(buf + count, \
58 printk(KERN_ERR "b43: fappend overflow\n"); \
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
66 static ssize_t
shm16read__read_file(struct b43_wldev
*dev
,
67 char *buf
, size_t bufsize
)
70 unsigned int routing
, addr
;
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
))
79 val
= b43_shm_read16(dev
, routing
, addr
);
80 fappend("0x%04X\n", val
);
85 static int shm16read__write_file(struct b43_wldev
*dev
,
86 const char *buf
, size_t count
)
88 unsigned int routing
, addr
;
91 res
= sscanf(buf
, "0x%X 0x%X", &routing
, &addr
);
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
) {
100 return -EADDRNOTAVAIL
;
103 dev
->dfsentry
->shm16read_routing_next
= routing
;
104 dev
->dfsentry
->shm16read_addr_next
= addr
;
109 static int shm16write__write_file(struct b43_wldev
*dev
,
110 const char *buf
, size_t count
)
112 unsigned int routing
, addr
, mask
, set
;
116 res
= sscanf(buf
, "0x%X 0x%X 0x%X 0x%X",
117 &routing
, &addr
, &mask
, &set
);
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
) {
126 return -EADDRNOTAVAIL
;
128 if ((mask
> 0xFFFF) || (set
> 0xFFFF))
134 val
= b43_shm_read16(dev
, routing
, addr
);
137 b43_shm_write16(dev
, routing
, addr
, val
);
142 static ssize_t
shm32read__read_file(struct b43_wldev
*dev
,
143 char *buf
, size_t bufsize
)
146 unsigned int routing
, addr
;
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
;
155 val
= b43_shm_read32(dev
, routing
, addr
);
156 fappend("0x%08X\n", val
);
161 static int shm32read__write_file(struct b43_wldev
*dev
,
162 const char *buf
, size_t count
)
164 unsigned int routing
, addr
;
167 res
= sscanf(buf
, "0x%X 0x%X", &routing
, &addr
);
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
) {
176 return -EADDRNOTAVAIL
;
179 dev
->dfsentry
->shm32read_routing_next
= routing
;
180 dev
->dfsentry
->shm32read_addr_next
= addr
;
185 static int shm32write__write_file(struct b43_wldev
*dev
,
186 const char *buf
, size_t count
)
188 unsigned int routing
, addr
, mask
, set
;
192 res
= sscanf(buf
, "0x%X 0x%X 0x%X 0x%X",
193 &routing
, &addr
, &mask
, &set
);
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
) {
202 return -EADDRNOTAVAIL
;
204 if ((mask
> 0xFFFFFFFF) || (set
> 0xFFFFFFFF))
210 val
= b43_shm_read32(dev
, routing
, addr
);
213 b43_shm_write32(dev
, routing
, addr
, val
);
218 /* The biggest MMIO address that we allow access to from the debugfs files. */
219 #define B43_MAX_MMIO_ACCESS (0xF00 - 1)
221 static ssize_t
mmio16read__read_file(struct b43_wldev
*dev
,
222 char *buf
, size_t bufsize
)
228 addr
= dev
->dfsentry
->mmio16read_next
;
229 if (addr
> B43_MAX_MMIO_ACCESS
)
230 return -EDESTADDRREQ
;
232 val
= b43_read16(dev
, addr
);
233 fappend("0x%04X\n", val
);
238 static int mmio16read__write_file(struct b43_wldev
*dev
,
239 const char *buf
, size_t count
)
244 res
= sscanf(buf
, "0x%X", &addr
);
247 if (addr
> B43_MAX_MMIO_ACCESS
)
248 return -EADDRNOTAVAIL
;
252 dev
->dfsentry
->mmio16read_next
= addr
;
257 static int mmio16write__write_file(struct b43_wldev
*dev
,
258 const char *buf
, size_t count
)
260 unsigned int addr
, mask
, set
;
264 res
= sscanf(buf
, "0x%X 0x%X 0x%X", &addr
, &mask
, &set
);
267 if (addr
> B43_MAX_MMIO_ACCESS
)
268 return -EADDRNOTAVAIL
;
269 if ((mask
> 0xFFFF) || (set
> 0xFFFF))
277 val
= b43_read16(dev
, addr
);
280 b43_write16(dev
, addr
, val
);
285 static ssize_t
mmio32read__read_file(struct b43_wldev
*dev
,
286 char *buf
, size_t bufsize
)
292 addr
= dev
->dfsentry
->mmio32read_next
;
293 if (addr
> B43_MAX_MMIO_ACCESS
)
294 return -EDESTADDRREQ
;
296 val
= b43_read32(dev
, addr
);
297 fappend("0x%08X\n", val
);
302 static int mmio32read__write_file(struct b43_wldev
*dev
,
303 const char *buf
, size_t count
)
308 res
= sscanf(buf
, "0x%X", &addr
);
311 if (addr
> B43_MAX_MMIO_ACCESS
)
312 return -EADDRNOTAVAIL
;
316 dev
->dfsentry
->mmio32read_next
= addr
;
321 static int mmio32write__write_file(struct b43_wldev
*dev
,
322 const char *buf
, size_t count
)
324 unsigned int addr
, mask
, set
;
328 res
= sscanf(buf
, "0x%X 0x%X 0x%X", &addr
, &mask
, &set
);
331 if (addr
> B43_MAX_MMIO_ACCESS
)
332 return -EADDRNOTAVAIL
;
333 if ((mask
> 0xFFFFFFFF) || (set
> 0xFFFFFFFF))
341 val
= b43_read32(dev
, addr
);
344 b43_write32(dev
, addr
, val
);
349 static ssize_t
txstat_read_file(struct b43_wldev
*dev
,
350 char *buf
, size_t bufsize
)
352 struct b43_txstatus_log
*log
= &dev
->dfsentry
->txstatlog
;
355 struct b43_txstatus
*stat
;
358 fappend("Nothing transmitted, yet\n");
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");
368 if (i
== B43_NR_LOGGED_TXSTATUS
)
370 stat
= &(log
->log
[i
]);
373 "0x%04X | 0x%04X | 0x%02X | "
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
,
394 static int restart_write_file(struct b43_wldev
*dev
,
395 const char *buf
, size_t count
)
399 if (count
> 0 && buf
[0] == '1') {
400 b43_controller_restart(dev
, "manually restarted");
407 static unsigned long calc_expire_secs(unsigned long now
,
409 unsigned long expire
)
411 expire
= time
+ expire
;
413 if (time_after(now
, expire
))
414 return 0; /* expired */
416 /* jiffies wrapped */
417 expire
-= MAX_JIFFY_OFFSET
;
418 now
-= MAX_JIFFY_OFFSET
;
420 B43_WARN_ON(expire
< now
);
422 return (expire
- now
) / HZ
;
425 static ssize_t
loctls_read_file(struct b43_wldev
*dev
,
426 char *buf
, size_t bufsize
)
429 struct b43_txpower_lo_control
*lo
;
431 struct b43_lo_calib
*cal
;
432 unsigned long now
= jiffies
;
433 struct b43_phy
*phy
= &dev
->phy
;
435 if (phy
->type
!= B43_PHYTYPE_G
) {
436 fappend("Device is not a G-PHY\n");
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
));
454 fappend("\nCalibrated settings:\n");
455 list_for_each_entry(cal
, &lo
->calib_list
, list
) {
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",
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" : "");
470 fappend("\nUsed RF attenuation values: Value(WithPadmix flag)\n");
471 for (i
= 0; i
< lo
->rfatt_list
.len
; i
++) {
473 lo
->rfatt_list
.list
[i
].att
,
474 lo
->rfatt_list
.list
[i
].with_padmix
);
477 fappend("\nUsed Baseband attenuation values:\n");
478 for (i
= 0; i
< lo
->bbatt_list
.len
; i
++) {
480 lo
->bbatt_list
.list
[i
].att
);
485 return err
? err
: count
;
490 static ssize_t
b43_debugfs_read(struct file
*file
, char __user
*userbuf
,
491 size_t count
, loff_t
*ppos
)
493 struct b43_wldev
*dev
;
494 struct b43_debugfs_fops
*dfops
;
495 struct b43_dfs_file
*dfile
;
496 ssize_t
uninitialized_var(ret
);
498 const size_t bufsize
= 1024 * 16; /* 16 kiB buffer */
499 const size_t buforder
= get_order(bufsize
);
504 dev
= file
->private_data
;
508 mutex_lock(&dev
->wl
->mutex
);
509 if (b43_status(dev
) < B43_STAT_INITIALIZED
) {
514 dfops
= container_of(debugfs_real_fops(file
),
515 struct b43_debugfs_fops
, fops
);
520 dfile
= fops_to_dfs_file(dev
, dfops
);
522 if (!dfile
->buffer
) {
523 buf
= (char *)__get_free_pages(GFP_KERNEL
, buforder
);
528 memset(buf
, 0, bufsize
);
529 ret
= dfops
->read(dev
, buf
, bufsize
);
531 free_pages((unsigned long)buf
, buforder
);
535 dfile
->data_len
= ret
;
539 ret
= simple_read_from_buffer(userbuf
, count
, ppos
,
542 if (*ppos
>= dfile
->data_len
) {
543 free_pages((unsigned long)dfile
->buffer
, buforder
);
544 dfile
->buffer
= NULL
;
548 mutex_unlock(&dev
->wl
->mutex
);
550 return err
? err
: ret
;
553 static ssize_t
b43_debugfs_write(struct file
*file
,
554 const char __user
*userbuf
,
555 size_t count
, loff_t
*ppos
)
557 struct b43_wldev
*dev
;
558 struct b43_debugfs_fops
*dfops
;
564 if (count
> PAGE_SIZE
)
566 dev
= file
->private_data
;
570 mutex_lock(&dev
->wl
->mutex
);
571 if (b43_status(dev
) < B43_STAT_INITIALIZED
) {
576 dfops
= container_of(debugfs_real_fops(file
),
577 struct b43_debugfs_fops
, fops
);
583 buf
= (char *)get_zeroed_page(GFP_KERNEL
);
588 if (copy_from_user(buf
, userbuf
, count
)) {
592 err
= dfops
->write(dev
, buf
, count
);
597 free_page((unsigned long)buf
);
599 mutex_unlock(&dev
->wl
->mutex
);
601 return err
? err
: count
;
605 #define B43_DEBUGFS_FOPS(name, _read, _write) \
606 static struct b43_debugfs_fops fops_##name = { \
610 .open = simple_open, \
611 .read = b43_debugfs_read, \
612 .write = b43_debugfs_write, \
613 .llseek = generic_file_llseek, \
615 .file_struct_offset = offsetof(struct b43_dfsentry, \
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
);
632 bool b43_debug(struct b43_wldev
*dev
, enum b43_dyndbg feature
)
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
;
646 static void b43_remove_dynamic_debug(struct b43_wldev
*dev
)
648 struct b43_dfsentry
*e
= dev
->dfsentry
;
651 for (i
= 0; i
< __B43_NR_DYNDBG
; i
++)
652 debugfs_remove(e
->dyn_debug_dentries
[i
]);
655 static void b43_add_dynamic_debug(struct b43_wldev
*dev
)
657 struct b43_dfsentry
*e
= dev
->dfsentry
;
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])); \
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);
679 void b43_debugfs_add_device(struct b43_wldev
*dev
)
681 struct b43_dfsentry
*e
;
682 struct b43_txstatus_log
*log
;
686 e
= kzalloc(sizeof(*e
), GFP_KERNEL
);
688 b43err(dev
->wl
, "debugfs: add device OOM\n");
693 log
->log
= kcalloc(B43_NR_LOGGED_TXSTATUS
,
694 sizeof(struct b43_txstatus
), GFP_KERNEL
);
696 b43err(dev
->wl
, "debugfs: add device txstatus OOM\n");
704 snprintf(devdir
, sizeof(devdir
), "%s", wiphy_name(dev
->wl
->hw
->wiphy
));
705 e
->subdir
= debugfs_create_dir(devdir
, rootdir
);
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 */
714 #define ADD_FILE(name, mode) \
716 e->file_##name.dentry = \
717 debugfs_create_file(__stringify(name), \
718 mode, e->subdir, dev, \
719 &fops_##name.fops); \
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);
737 b43_add_dynamic_debug(dev
);
740 void b43_debugfs_remove_device(struct b43_wldev
*dev
)
742 struct b43_dfsentry
*e
;
749 b43_remove_dynamic_debug(dev
);
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
);
763 debugfs_remove(e
->subdir
);
764 kfree(e
->txstatlog
.log
);
768 void b43_debugfs_log_txstat(struct b43_wldev
*dev
,
769 const struct b43_txstatus
*status
)
771 struct b43_dfsentry
*e
= dev
->dfsentry
;
772 struct b43_txstatus_log
*log
;
773 struct b43_txstatus
*cur
;
780 if (i
== B43_NR_LOGGED_TXSTATUS
)
783 cur
= &(log
->log
[i
]);
784 memcpy(cur
, status
, sizeof(*cur
));
787 void b43_debugfs_init(void)
789 rootdir
= debugfs_create_dir(KBUILD_MODNAME
, NULL
);
792 void b43_debugfs_exit(void)
794 debugfs_remove(rootdir
);