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