3
Broadcom B43 wireless driver
5
debugfs driver debugging code
7
Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
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.
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.
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.
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>
40
/* The root directory. */
41
static struct dentry *rootdir;
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;
52
struct b43_dfs_file *fops_to_dfs_file(struct b43_wldev *dev,
53
const struct b43_debugfs_fops *dfops)
58
p += dfops->file_struct_offset;
64
#define fappend(fmt, x...) \
66
if (bufsize - count) \
67
count += snprintf(buf + count, \
71
printk(KERN_ERR "b43: fappend overflow\n"); \
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
79
static ssize_t shm16read__read_file(struct b43_wldev *dev,
80
char *buf, size_t bufsize)
83
unsigned int routing, addr;
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))
92
val = b43_shm_read16(dev, routing, addr);
93
fappend("0x%04X\n", val);
98
static int shm16read__write_file(struct b43_wldev *dev,
99
const char *buf, size_t count)
101
unsigned int routing, addr;
104
res = sscanf(buf, "0x%X 0x%X", &routing, &addr);
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) {
113
return -EADDRNOTAVAIL;
116
dev->dfsentry->shm16read_routing_next = routing;
117
dev->dfsentry->shm16read_addr_next = addr;
122
static int shm16write__write_file(struct b43_wldev *dev,
123
const char *buf, size_t count)
125
unsigned int routing, addr, mask, set;
129
res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X",
130
&routing, &addr, &mask, &set);
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) {
139
return -EADDRNOTAVAIL;
141
if ((mask > 0xFFFF) || (set > 0xFFFF))
147
val = b43_shm_read16(dev, routing, addr);
150
b43_shm_write16(dev, routing, addr, val);
155
static ssize_t shm32read__read_file(struct b43_wldev *dev,
156
char *buf, size_t bufsize)
159
unsigned int routing, addr;
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;
168
val = b43_shm_read32(dev, routing, addr);
169
fappend("0x%08X\n", val);
174
static int shm32read__write_file(struct b43_wldev *dev,
175
const char *buf, size_t count)
177
unsigned int routing, addr;
180
res = sscanf(buf, "0x%X 0x%X", &routing, &addr);
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) {
189
return -EADDRNOTAVAIL;
192
dev->dfsentry->shm32read_routing_next = routing;
193
dev->dfsentry->shm32read_addr_next = addr;
198
static int shm32write__write_file(struct b43_wldev *dev,
199
const char *buf, size_t count)
201
unsigned int routing, addr, mask, set;
205
res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X",
206
&routing, &addr, &mask, &set);
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) {
215
return -EADDRNOTAVAIL;
217
if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF))
223
val = b43_shm_read32(dev, routing, addr);
226
b43_shm_write32(dev, routing, addr, val);
231
/* The biggest MMIO address that we allow access to from the debugfs files. */
232
#define B43_MAX_MMIO_ACCESS (0xF00 - 1)
234
static ssize_t mmio16read__read_file(struct b43_wldev *dev,
235
char *buf, size_t bufsize)
241
addr = dev->dfsentry->mmio16read_next;
242
if (addr > B43_MAX_MMIO_ACCESS)
243
return -EDESTADDRREQ;
245
val = b43_read16(dev, addr);
246
fappend("0x%04X\n", val);
251
static int mmio16read__write_file(struct b43_wldev *dev,
252
const char *buf, size_t count)
257
res = sscanf(buf, "0x%X", &addr);
260
if (addr > B43_MAX_MMIO_ACCESS)
261
return -EADDRNOTAVAIL;
265
dev->dfsentry->mmio16read_next = addr;
270
static int mmio16write__write_file(struct b43_wldev *dev,
271
const char *buf, size_t count)
273
unsigned int addr, mask, set;
277
res = sscanf(buf, "0x%X 0x%X 0x%X", &addr, &mask, &set);
280
if (addr > B43_MAX_MMIO_ACCESS)
281
return -EADDRNOTAVAIL;
282
if ((mask > 0xFFFF) || (set > 0xFFFF))
290
val = b43_read16(dev, addr);
293
b43_write16(dev, addr, val);
298
static ssize_t mmio32read__read_file(struct b43_wldev *dev,
299
char *buf, size_t bufsize)
305
addr = dev->dfsentry->mmio32read_next;
306
if (addr > B43_MAX_MMIO_ACCESS)
307
return -EDESTADDRREQ;
309
val = b43_read32(dev, addr);
310
fappend("0x%08X\n", val);
315
static int mmio32read__write_file(struct b43_wldev *dev,
316
const char *buf, size_t count)
321
res = sscanf(buf, "0x%X", &addr);
324
if (addr > B43_MAX_MMIO_ACCESS)
325
return -EADDRNOTAVAIL;
329
dev->dfsentry->mmio32read_next = addr;
334
static int mmio32write__write_file(struct b43_wldev *dev,
335
const char *buf, size_t count)
337
unsigned int addr, mask, set;
341
res = sscanf(buf, "0x%X 0x%X 0x%X", &addr, &mask, &set);
344
if (addr > B43_MAX_MMIO_ACCESS)
345
return -EADDRNOTAVAIL;
346
if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF))
354
val = b43_read32(dev, addr);
357
b43_write32(dev, addr, val);
362
static ssize_t txstat_read_file(struct b43_wldev *dev,
363
char *buf, size_t bufsize)
365
struct b43_txstatus_log *log = &dev->dfsentry->txstatlog;
368
struct b43_txstatus *stat;
371
fappend("Nothing transmitted, yet\n");
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");
381
if (i == B43_NR_LOGGED_TXSTATUS)
383
stat = &(log->log[i]);
386
"0x%04X | 0x%04X | 0x%02X | "
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,
407
static int restart_write_file(struct b43_wldev *dev,
408
const char *buf, size_t count)
412
if (count > 0 && buf[0] == '1') {
413
b43_controller_restart(dev, "manually restarted");
420
static unsigned long calc_expire_secs(unsigned long now,
422
unsigned long expire)
424
expire = time + expire;
426
if (time_after(now, expire))
427
return 0; /* expired */
429
/* jiffies wrapped */
430
expire -= MAX_JIFFY_OFFSET;
431
now -= MAX_JIFFY_OFFSET;
433
B43_WARN_ON(expire < now);
435
return (expire - now) / HZ;
438
static ssize_t loctls_read_file(struct b43_wldev *dev,
439
char *buf, size_t bufsize)
442
struct b43_txpower_lo_control *lo;
444
struct b43_lo_calib *cal;
445
unsigned long now = jiffies;
446
struct b43_phy *phy = &dev->phy;
448
if (phy->type != B43_PHYTYPE_G) {
449
fappend("Device is not a G-PHY\n");
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));
467
fappend("\nCalibrated settings:\n");
468
list_for_each_entry(cal, &lo->calib_list, list) {
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",
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" : "");
483
fappend("\nUsed RF attenuation values: Value(WithPadmix flag)\n");
484
for (i = 0; i < lo->rfatt_list.len; i++) {
486
lo->rfatt_list.list[i].att,
487
lo->rfatt_list.list[i].with_padmix);
490
fappend("\nUsed Baseband attenuation values:\n");
491
for (i = 0; i < lo->bbatt_list.len; i++) {
493
lo->bbatt_list.list[i].att);
498
return err ? err : count;
503
static int b43_debugfs_open(struct inode *inode, struct file *file)
505
file->private_data = inode->i_private;
509
static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
510
size_t count, loff_t *ppos)
512
struct b43_wldev *dev;
513
struct b43_debugfs_fops *dfops;
514
struct b43_dfs_file *dfile;
515
ssize_t uninitialized_var(ret);
517
const size_t bufsize = 1024 * 16; /* 16 kiB buffer */
518
const size_t buforder = get_order(bufsize);
523
dev = file->private_data;
527
mutex_lock(&dev->wl->mutex);
528
if (b43_status(dev) < B43_STAT_INITIALIZED) {
533
dfops = container_of(file->f_op, struct b43_debugfs_fops, fops);
538
dfile = fops_to_dfs_file(dev, dfops);
540
if (!dfile->buffer) {
541
buf = (char *)__get_free_pages(GFP_KERNEL, buforder);
546
memset(buf, 0, bufsize);
547
ret = dfops->read(dev, buf, bufsize);
549
free_pages((unsigned long)buf, buforder);
553
dfile->data_len = ret;
557
ret = simple_read_from_buffer(userbuf, count, ppos,
560
if (*ppos >= dfile->data_len) {
561
free_pages((unsigned long)dfile->buffer, buforder);
562
dfile->buffer = NULL;
566
mutex_unlock(&dev->wl->mutex);
568
return err ? err : ret;
571
static ssize_t b43_debugfs_write(struct file *file,
572
const char __user *userbuf,
573
size_t count, loff_t *ppos)
575
struct b43_wldev *dev;
576
struct b43_debugfs_fops *dfops;
582
if (count > PAGE_SIZE)
584
dev = file->private_data;
588
mutex_lock(&dev->wl->mutex);
589
if (b43_status(dev) < B43_STAT_INITIALIZED) {
594
dfops = container_of(file->f_op, struct b43_debugfs_fops, fops);
600
buf = (char *)get_zeroed_page(GFP_KERNEL);
605
if (copy_from_user(buf, userbuf, count)) {
609
err = dfops->write(dev, buf, count);
614
free_page((unsigned long)buf);
616
mutex_unlock(&dev->wl->mutex);
618
return err ? err : count;
622
#define B43_DEBUGFS_FOPS(name, _read, _write) \
623
static struct b43_debugfs_fops fops_##name = { \
627
.open = b43_debugfs_open, \
628
.read = b43_debugfs_read, \
629
.write = b43_debugfs_write, \
631
.file_struct_offset = offsetof(struct b43_dfsentry, \
635
B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file);
636
B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file);
637
B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file);
638
B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file);
639
B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file);
640
B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file);
641
B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file);
642
B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file);
643
B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL);
644
B43_DEBUGFS_FOPS(restart, NULL, restart_write_file);
645
B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL);
648
bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature)
652
enabled = (dev->dfsentry && dev->dfsentry->dyn_debug[feature]);
653
if (unlikely(enabled)) {
654
/* Force full debugging messages, if the user enabled
655
* some dynamic debugging feature. */
656
b43_modparam_verbose = B43_VERBOSITY_MAX;
662
static void b43_remove_dynamic_debug(struct b43_wldev *dev)
664
struct b43_dfsentry *e = dev->dfsentry;
667
for (i = 0; i < __B43_NR_DYNDBG; i++)
668
debugfs_remove(e->dyn_debug_dentries[i]);
671
static void b43_add_dynamic_debug(struct b43_wldev *dev)
673
struct b43_dfsentry *e = dev->dfsentry;
676
#define add_dyn_dbg(name, id, initstate) do { \
677
e->dyn_debug[id] = (initstate); \
678
d = debugfs_create_bool(name, 0600, e->subdir, \
679
&(e->dyn_debug[id])); \
681
e->dyn_debug_dentries[id] = d; \
684
add_dyn_dbg("debug_xmitpower", B43_DBG_XMITPOWER, 0);
685
add_dyn_dbg("debug_dmaoverflow", B43_DBG_DMAOVERFLOW, 0);
686
add_dyn_dbg("debug_dmaverbose", B43_DBG_DMAVERBOSE, 0);
687
add_dyn_dbg("debug_pwork_fast", B43_DBG_PWORK_FAST, 0);
688
add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0);
689
add_dyn_dbg("debug_lo", B43_DBG_LO, 0);
690
add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, 0);
691
add_dyn_dbg("debug_keys", B43_DBG_KEYS, 0);
692
add_dyn_dbg("debug_verbose_stats", B43_DBG_VERBOSESTATS, 0);
697
void b43_debugfs_add_device(struct b43_wldev *dev)
699
struct b43_dfsentry *e;
700
struct b43_txstatus_log *log;
704
e = kzalloc(sizeof(*e), GFP_KERNEL);
706
b43err(dev->wl, "debugfs: add device OOM\n");
711
log->log = kcalloc(B43_NR_LOGGED_TXSTATUS,
712
sizeof(struct b43_txstatus), GFP_KERNEL);
714
b43err(dev->wl, "debugfs: add device txstatus OOM\n");
722
snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy));
723
e->subdir = debugfs_create_dir(devdir, rootdir);
724
if (!e->subdir || IS_ERR(e->subdir)) {
725
if (e->subdir == ERR_PTR(-ENODEV)) {
726
b43dbg(dev->wl, "DebugFS (CONFIG_DEBUG_FS) not "
727
"enabled in kernel config\n");
729
b43err(dev->wl, "debugfs: cannot create %s directory\n",
732
dev->dfsentry = NULL;
738
e->mmio16read_next = 0xFFFF; /* invalid address */
739
e->mmio32read_next = 0xFFFF; /* invalid address */
740
e->shm16read_routing_next = 0xFFFFFFFF; /* invalid routing */
741
e->shm16read_addr_next = 0xFFFFFFFF; /* invalid address */
742
e->shm32read_routing_next = 0xFFFFFFFF; /* invalid routing */
743
e->shm32read_addr_next = 0xFFFFFFFF; /* invalid address */
745
#define ADD_FILE(name, mode) \
748
d = debugfs_create_file(__stringify(name), \
749
mode, e->subdir, dev, \
750
&fops_##name.fops); \
751
e->file_##name.dentry = NULL; \
753
e->file_##name.dentry = d; \
757
ADD_FILE(shm16read, 0600);
758
ADD_FILE(shm16write, 0200);
759
ADD_FILE(shm32read, 0600);
760
ADD_FILE(shm32write, 0200);
761
ADD_FILE(mmio16read, 0600);
762
ADD_FILE(mmio16write, 0200);
763
ADD_FILE(mmio32read, 0600);
764
ADD_FILE(mmio32write, 0200);
765
ADD_FILE(txstat, 0400);
766
ADD_FILE(restart, 0200);
767
ADD_FILE(loctls, 0400);
771
b43_add_dynamic_debug(dev);
774
void b43_debugfs_remove_device(struct b43_wldev *dev)
776
struct b43_dfsentry *e;
783
b43_remove_dynamic_debug(dev);
785
debugfs_remove(e->file_shm16read.dentry);
786
debugfs_remove(e->file_shm16write.dentry);
787
debugfs_remove(e->file_shm32read.dentry);
788
debugfs_remove(e->file_shm32write.dentry);
789
debugfs_remove(e->file_mmio16read.dentry);
790
debugfs_remove(e->file_mmio16write.dentry);
791
debugfs_remove(e->file_mmio32read.dentry);
792
debugfs_remove(e->file_mmio32write.dentry);
793
debugfs_remove(e->file_txstat.dentry);
794
debugfs_remove(e->file_restart.dentry);
795
debugfs_remove(e->file_loctls.dentry);
797
debugfs_remove(e->subdir);
798
kfree(e->txstatlog.log);
802
void b43_debugfs_log_txstat(struct b43_wldev *dev,
803
const struct b43_txstatus *status)
805
struct b43_dfsentry *e = dev->dfsentry;
806
struct b43_txstatus_log *log;
807
struct b43_txstatus *cur;
814
if (i == B43_NR_LOGGED_TXSTATUS)
817
cur = &(log->log[i]);
818
memcpy(cur, status, sizeof(*cur));
821
void b43_debugfs_init(void)
823
rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
828
void b43_debugfs_exit(void)
830
debugfs_remove(rootdir);