2007-09-18 23:39:42 +04:00
/*
Broadcom B43 wireless driver
debugfs driver debugging code
2011-07-04 22:50:05 +04:00
Copyright ( c ) 2005 - 2007 Michael Buesch < m @ bues . ch >
2007-09-18 23:39:42 +04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; see the file COPYING . If not , write to
the Free Software Foundation , Inc . , 51 Franklin Steet , Fifth Floor ,
Boston , MA 02110 - 1301 , USA .
*/
# include <linux/fs.h>
# include <linux/debugfs.h>
# include <linux/slab.h>
# include <linux/netdevice.h>
# include <linux/pci.h>
# include <linux/mutex.h>
# include "b43.h"
# include "main.h"
# include "debugfs.h"
# include "dma.h"
# include "xmit.h"
/* The root directory. */
2007-09-20 22:13:40 +04:00
static struct dentry * rootdir ;
2007-09-18 23:39:42 +04:00
struct b43_debugfs_fops {
ssize_t ( * read ) ( struct b43_wldev * dev , char * buf , size_t bufsize ) ;
int ( * write ) ( struct b43_wldev * dev , const char * buf , size_t count ) ;
struct file_operations fops ;
/* Offset of struct b43_dfs_file in struct b43_dfsentry */
size_t file_struct_offset ;
} ;
static inline
2009-02-24 13:16:42 +03:00
struct b43_dfs_file * fops_to_dfs_file ( struct b43_wldev * dev ,
const struct b43_debugfs_fops * dfops )
2007-09-18 23:39:42 +04:00
{
void * p ;
p = dev - > dfsentry ;
p + = dfops - > file_struct_offset ;
return p ;
}
# define fappend(fmt, x...) \
do { \
if ( bufsize - count ) \
count + = snprintf ( buf + count , \
bufsize - count , \
fmt , # # x ) ; \
else \
printk ( KERN_ERR " b43: fappend overflow \n " ) ; \
} while ( 0 )
2008-06-19 21:33:51 +04:00
/* The biggest address values for SHM access from the debugfs files. */
# define B43_MAX_SHM_ROUTING 4
# define B43_MAX_SHM_ADDR 0xFFFF
static ssize_t shm16read__read_file ( struct b43_wldev * dev ,
char * buf , size_t bufsize )
{
ssize_t count = 0 ;
unsigned int routing , addr ;
u16 val ;
routing = dev - > dfsentry - > shm16read_routing_next ;
addr = dev - > dfsentry - > shm16read_addr_next ;
if ( ( routing > B43_MAX_SHM_ROUTING ) | |
( addr > B43_MAX_SHM_ADDR ) )
return - EDESTADDRREQ ;
val = b43_shm_read16 ( dev , routing , addr ) ;
fappend ( " 0x%04X \n " , val ) ;
return count ;
}
static int shm16read__write_file ( struct b43_wldev * dev ,
const char * buf , size_t count )
{
unsigned int routing , addr ;
int res ;
res = sscanf ( buf , " 0x%X 0x%X " , & routing , & addr ) ;
if ( res ! = 2 )
return - EINVAL ;
if ( routing > B43_MAX_SHM_ROUTING )
return - EADDRNOTAVAIL ;
if ( addr > B43_MAX_SHM_ADDR )
return - EADDRNOTAVAIL ;
if ( routing = = B43_SHM_SHARED ) {
if ( ( addr % 2 ) ! = 0 )
return - EADDRNOTAVAIL ;
}
dev - > dfsentry - > shm16read_routing_next = routing ;
dev - > dfsentry - > shm16read_addr_next = addr ;
return 0 ;
}
static int shm16write__write_file ( struct b43_wldev * dev ,
const char * buf , size_t count )
{
unsigned int routing , addr , mask , set ;
u16 val ;
int res ;
res = sscanf ( buf , " 0x%X 0x%X 0x%X 0x%X " ,
& routing , & addr , & mask , & set ) ;
if ( res ! = 4 )
return - EINVAL ;
if ( routing > B43_MAX_SHM_ROUTING )
return - EADDRNOTAVAIL ;
if ( addr > B43_MAX_SHM_ADDR )
return - EADDRNOTAVAIL ;
if ( routing = = B43_SHM_SHARED ) {
if ( ( addr % 2 ) ! = 0 )
return - EADDRNOTAVAIL ;
}
if ( ( mask > 0xFFFF ) | | ( set > 0xFFFF ) )
return - E2BIG ;
if ( mask = = 0 )
val = 0 ;
else
2009-09-05 00:57:26 +04:00
val = b43_shm_read16 ( dev , routing , addr ) ;
2008-06-19 21:33:51 +04:00
val & = mask ;
val | = set ;
2009-09-05 00:57:26 +04:00
b43_shm_write16 ( dev , routing , addr , val ) ;
2008-06-19 21:33:51 +04:00
return 0 ;
}
static ssize_t shm32read__read_file ( struct b43_wldev * dev ,
char * buf , size_t bufsize )
{
ssize_t count = 0 ;
unsigned int routing , addr ;
u32 val ;
routing = dev - > dfsentry - > shm32read_routing_next ;
addr = dev - > dfsentry - > shm32read_addr_next ;
if ( ( routing > B43_MAX_SHM_ROUTING ) | |
( addr > B43_MAX_SHM_ADDR ) )
return - EDESTADDRREQ ;
val = b43_shm_read32 ( dev , routing , addr ) ;
fappend ( " 0x%08X \n " , val ) ;
return count ;
}
static int shm32read__write_file ( struct b43_wldev * dev ,
const char * buf , size_t count )
{
unsigned int routing , addr ;
int res ;
res = sscanf ( buf , " 0x%X 0x%X " , & routing , & addr ) ;
if ( res ! = 2 )
return - EINVAL ;
if ( routing > B43_MAX_SHM_ROUTING )
return - EADDRNOTAVAIL ;
if ( addr > B43_MAX_SHM_ADDR )
return - EADDRNOTAVAIL ;
if ( routing = = B43_SHM_SHARED ) {
if ( ( addr % 2 ) ! = 0 )
return - EADDRNOTAVAIL ;
}
dev - > dfsentry - > shm32read_routing_next = routing ;
dev - > dfsentry - > shm32read_addr_next = addr ;
return 0 ;
}
static int shm32write__write_file ( struct b43_wldev * dev ,
const char * buf , size_t count )
{
unsigned int routing , addr , mask , set ;
u32 val ;
int res ;
res = sscanf ( buf , " 0x%X 0x%X 0x%X 0x%X " ,
& routing , & addr , & mask , & set ) ;
if ( res ! = 4 )
return - EINVAL ;
if ( routing > B43_MAX_SHM_ROUTING )
return - EADDRNOTAVAIL ;
if ( addr > B43_MAX_SHM_ADDR )
return - EADDRNOTAVAIL ;
if ( routing = = B43_SHM_SHARED ) {
if ( ( addr % 2 ) ! = 0 )
return - EADDRNOTAVAIL ;
}
if ( ( mask > 0xFFFFFFFF ) | | ( set > 0xFFFFFFFF ) )
return - E2BIG ;
if ( mask = = 0 )
val = 0 ;
else
2009-09-05 00:57:26 +04:00
val = b43_shm_read32 ( dev , routing , addr ) ;
2008-06-19 21:33:51 +04:00
val & = mask ;
val | = set ;
2009-09-05 00:57:26 +04:00
b43_shm_write32 ( dev , routing , addr , val ) ;
2008-06-19 21:33:51 +04:00
return 0 ;
}
2008-06-19 02:35:49 +04:00
/* The biggest MMIO address that we allow access to from the debugfs files. */
# define B43_MAX_MMIO_ACCESS (0xF00 - 1)
static ssize_t mmio16read__read_file ( struct b43_wldev * dev ,
char * buf , size_t bufsize )
{
ssize_t count = 0 ;
unsigned int addr ;
u16 val ;
addr = dev - > dfsentry - > mmio16read_next ;
if ( addr > B43_MAX_MMIO_ACCESS )
return - EDESTADDRREQ ;
val = b43_read16 ( dev , addr ) ;
fappend ( " 0x%04X \n " , val ) ;
return count ;
}
static int mmio16read__write_file ( struct b43_wldev * dev ,
const char * buf , size_t count )
{
unsigned int addr ;
int res ;
res = sscanf ( buf , " 0x%X " , & addr ) ;
if ( res ! = 1 )
return - EINVAL ;
if ( addr > B43_MAX_MMIO_ACCESS )
return - EADDRNOTAVAIL ;
2008-06-19 21:38:32 +04:00
if ( ( addr % 2 ) ! = 0 )
return - EINVAL ;
2008-06-19 02:35:49 +04:00
dev - > dfsentry - > mmio16read_next = addr ;
return 0 ;
}
static int mmio16write__write_file ( struct b43_wldev * dev ,
const char * buf , size_t count )
{
2008-06-19 21:38:32 +04:00
unsigned int addr , mask , set ;
2008-06-19 02:35:49 +04:00
int res ;
2008-06-19 21:38:32 +04:00
u16 val ;
2008-06-19 02:35:49 +04:00
2008-06-19 21:38:32 +04:00
res = sscanf ( buf , " 0x%X 0x%X 0x%X " , & addr , & mask , & set ) ;
if ( res ! = 3 )
2008-06-19 02:35:49 +04:00
return - EINVAL ;
if ( addr > B43_MAX_MMIO_ACCESS )
return - EADDRNOTAVAIL ;
2008-06-19 21:38:32 +04:00
if ( ( mask > 0xFFFF ) | | ( set > 0xFFFF ) )
2008-06-19 02:35:49 +04:00
return - E2BIG ;
2008-06-19 21:38:32 +04:00
if ( ( addr % 2 ) ! = 0 )
return - EINVAL ;
2008-06-19 02:35:49 +04:00
2008-06-19 21:38:32 +04:00
if ( mask = = 0 )
val = 0 ;
else
val = b43_read16 ( dev , addr ) ;
val & = mask ;
val | = set ;
2008-06-19 02:35:49 +04:00
b43_write16 ( dev , addr , val ) ;
return 0 ;
}
static ssize_t mmio32read__read_file ( struct b43_wldev * dev ,
char * buf , size_t bufsize )
{
ssize_t count = 0 ;
unsigned int addr ;
u32 val ;
addr = dev - > dfsentry - > mmio32read_next ;
if ( addr > B43_MAX_MMIO_ACCESS )
return - EDESTADDRREQ ;
val = b43_read32 ( dev , addr ) ;
fappend ( " 0x%08X \n " , val ) ;
return count ;
}
static int mmio32read__write_file ( struct b43_wldev * dev ,
const char * buf , size_t count )
{
unsigned int addr ;
int res ;
res = sscanf ( buf , " 0x%X " , & addr ) ;
if ( res ! = 1 )
return - EINVAL ;
if ( addr > B43_MAX_MMIO_ACCESS )
return - EADDRNOTAVAIL ;
2008-06-19 21:38:32 +04:00
if ( ( addr % 4 ) ! = 0 )
return - EINVAL ;
2008-06-19 02:35:49 +04:00
dev - > dfsentry - > mmio32read_next = addr ;
return 0 ;
}
static int mmio32write__write_file ( struct b43_wldev * dev ,
const char * buf , size_t count )
{
2008-06-19 21:38:32 +04:00
unsigned int addr , mask , set ;
2008-06-19 02:35:49 +04:00
int res ;
2008-06-19 21:38:32 +04:00
u32 val ;
2008-06-19 02:35:49 +04:00
2008-06-19 21:38:32 +04:00
res = sscanf ( buf , " 0x%X 0x%X 0x%X " , & addr , & mask , & set ) ;
if ( res ! = 3 )
2008-06-19 02:35:49 +04:00
return - EINVAL ;
if ( addr > B43_MAX_MMIO_ACCESS )
return - EADDRNOTAVAIL ;
2008-06-19 21:38:32 +04:00
if ( ( mask > 0xFFFFFFFF ) | | ( set > 0xFFFFFFFF ) )
2008-06-19 02:35:49 +04:00
return - E2BIG ;
2008-06-19 21:38:32 +04:00
if ( ( addr % 4 ) ! = 0 )
return - EINVAL ;
2008-06-19 02:35:49 +04:00
2008-06-19 21:38:32 +04:00
if ( mask = = 0 )
val = 0 ;
else
val = b43_read32 ( dev , addr ) ;
val & = mask ;
val | = set ;
2008-06-19 02:35:49 +04:00
b43_write32 ( dev , addr , val ) ;
return 0 ;
}
2007-09-20 22:13:40 +04:00
static ssize_t txstat_read_file ( struct b43_wldev * dev ,
char * buf , size_t bufsize )
2007-09-18 23:39:42 +04:00
{
struct b43_txstatus_log * log = & dev - > dfsentry - > txstatlog ;
ssize_t count = 0 ;
int i , idx ;
struct b43_txstatus * stat ;
if ( log - > end < 0 ) {
fappend ( " Nothing transmitted, yet \n " ) ;
2009-09-05 00:51:29 +04:00
goto out ;
2007-09-18 23:39:42 +04:00
}
fappend ( " b43 TX status reports: \n \n "
" index | cookie | seq | phy_stat | frame_count | "
" rts_count | supp_reason | pm_indicated | "
" intermediate | for_ampdu | acked \n " " --- \n " ) ;
i = log - > end + 1 ;
idx = 0 ;
while ( 1 ) {
if ( i = = B43_NR_LOGGED_TXSTATUS )
i = 0 ;
stat = & ( log - > log [ i ] ) ;
if ( stat - > cookie ) {
fappend ( " %03d | "
" 0x%04X | 0x%04X | 0x%02X | "
" 0x%X | 0x%X | "
" %u | %u | "
" %u | %u | %u \n " ,
idx ,
stat - > cookie , stat - > seq , stat - > phy_stat ,
stat - > frame_count , stat - > rts_count ,
stat - > supp_reason , stat - > pm_indicated ,
stat - > intermediate , stat - > for_ampdu ,
stat - > acked ) ;
idx + + ;
}
if ( i = = log - > end )
break ;
i + + ;
}
2009-09-05 00:51:29 +04:00
out :
2007-09-18 23:39:42 +04:00
return count ;
}
2007-09-20 22:13:40 +04:00
static int restart_write_file ( struct b43_wldev * dev ,
const char * buf , size_t count )
2007-09-18 23:39:42 +04:00
{
int err = 0 ;
if ( count > 0 & & buf [ 0 ] = = ' 1 ' ) {
b43_controller_restart ( dev , " manually restarted " ) ;
} else
err = - EINVAL ;
return err ;
}
2008-04-20 18:03:32 +04:00
static unsigned long calc_expire_secs ( unsigned long now ,
unsigned long time ,
unsigned long expire )
2007-09-18 23:39:42 +04:00
{
2008-04-20 18:03:32 +04:00
expire = time + expire ;
if ( time_after ( now , expire ) )
return 0 ; /* expired */
if ( expire < now ) {
/* jiffies wrapped */
expire - = MAX_JIFFY_OFFSET ;
now - = MAX_JIFFY_OFFSET ;
2007-09-18 23:39:42 +04:00
}
2008-04-20 18:03:32 +04:00
B43_WARN_ON ( expire < now ) ;
2007-09-18 23:39:42 +04:00
2008-04-20 18:03:32 +04:00
return ( expire - now ) / HZ ;
2007-09-18 23:39:42 +04:00
}
2007-09-20 22:13:40 +04:00
static ssize_t loctls_read_file ( struct b43_wldev * dev ,
char * buf , size_t bufsize )
2007-09-18 23:39:42 +04:00
{
ssize_t count = 0 ;
struct b43_txpower_lo_control * lo ;
int i , err = 0 ;
2008-04-20 18:03:32 +04:00
struct b43_lo_calib * cal ;
unsigned long now = jiffies ;
struct b43_phy * phy = & dev - > phy ;
2007-09-18 23:39:42 +04:00
2008-04-20 18:03:32 +04:00
if ( phy - > type ! = B43_PHYTYPE_G ) {
2007-09-18 23:39:42 +04:00
fappend ( " Device is not a G-PHY \n " ) ;
err = - ENODEV ;
goto out ;
}
2008-08-27 20:53:02 +04:00
lo = phy - > g - > lo_control ;
2007-09-18 23:39:42 +04:00
fappend ( " -- Local Oscillator calibration data -- \n \n " ) ;
2008-04-20 18:03:32 +04:00
fappend ( " HW-power-control enabled: %d \n " ,
2007-09-18 23:39:42 +04:00
dev - > phy . hardware_power_control ) ;
2008-04-20 18:03:32 +04:00
fappend ( " TX Bias: 0x%02X, TX Magn: 0x%02X (expire in %lu sec) \n " ,
lo - > tx_bias , lo - > tx_magn ,
calc_expire_secs ( now , lo - > txctl_measured_time ,
B43_LO_TXCTL_EXPIRE ) ) ;
fappend ( " Power Vector: 0x%08X%08X (expires in %lu sec) \n " ,
2007-09-18 23:39:42 +04:00
( unsigned int ) ( ( lo - > power_vector & 0xFFFFFFFF00000000ULL ) > > 32 ) ,
2008-04-20 18:03:32 +04:00
( unsigned int ) ( lo - > power_vector & 0x00000000FFFFFFFFULL ) ,
calc_expire_secs ( now , lo - > pwr_vec_read_time ,
B43_LO_PWRVEC_EXPIRE ) ) ;
fappend ( " \n Calibrated settings: \n " ) ;
list_for_each_entry ( cal , & lo - > calib_list , list ) {
bool active ;
2008-08-27 20:53:02 +04:00
active = ( b43_compare_bbatt ( & cal - > bbatt , & phy - > g - > bbatt ) & &
b43_compare_rfatt ( & cal - > rfatt , & phy - > g - > rfatt ) ) ;
2008-04-20 18:03:32 +04:00
fappend ( " BB(%d), RF(%d,%d) -> I=%d, Q=%d "
" (expires in %lu sec)%s \n " ,
cal - > bbatt . att ,
cal - > rfatt . att , cal - > rfatt . with_padmix ,
cal - > ctl . i , cal - > ctl . q ,
calc_expire_secs ( now , cal - > calib_time ,
B43_LO_CALIB_EXPIRE ) ,
active ? " ACTIVE " : " " ) ;
}
2007-09-18 23:39:42 +04:00
fappend ( " \n Used RF attenuation values: Value(WithPadmix flag) \n " ) ;
for ( i = 0 ; i < lo - > rfatt_list . len ; i + + ) {
fappend ( " %u(%d), " ,
lo - > rfatt_list . list [ i ] . att ,
lo - > rfatt_list . list [ i ] . with_padmix ) ;
}
fappend ( " \n " ) ;
fappend ( " \n Used Baseband attenuation values: \n " ) ;
for ( i = 0 ; i < lo - > bbatt_list . len ; i + + ) {
fappend ( " %u, " ,
lo - > bbatt_list . list [ i ] . att ) ;
}
fappend ( " \n " ) ;
out :
return err ? err : count ;
}
# undef fappend
static ssize_t b43_debugfs_read ( struct file * file , char __user * userbuf ,
size_t count , loff_t * ppos )
{
struct b43_wldev * dev ;
struct b43_debugfs_fops * dfops ;
struct b43_dfs_file * dfile ;
2007-11-12 13:12:52 +03:00
ssize_t uninitialized_var ( ret ) ;
2007-09-18 23:39:42 +04:00
char * buf ;
2008-04-20 18:03:32 +04:00
const size_t bufsize = 1024 * 16 ; /* 16 kiB buffer */
2007-09-18 23:39:42 +04:00
const size_t buforder = get_order ( bufsize ) ;
int err = 0 ;
if ( ! count )
return 0 ;
dev = file - > private_data ;
if ( ! dev )
return - ENODEV ;
mutex_lock ( & dev - > wl - > mutex ) ;
if ( b43_status ( dev ) < B43_STAT_INITIALIZED ) {
err = - ENODEV ;
goto out_unlock ;
}
dfops = container_of ( file - > f_op , struct b43_debugfs_fops , fops ) ;
if ( ! dfops - > read ) {
err = - ENOSYS ;
goto out_unlock ;
}
dfile = fops_to_dfs_file ( dev , dfops ) ;
if ( ! dfile - > buffer ) {
buf = ( char * ) __get_free_pages ( GFP_KERNEL , buforder ) ;
if ( ! buf ) {
err = - ENOMEM ;
goto out_unlock ;
}
memset ( buf , 0 , bufsize ) ;
2009-09-05 00:51:29 +04:00
ret = dfops - > read ( dev , buf , bufsize ) ;
2007-09-18 23:39:42 +04:00
if ( ret < = 0 ) {
free_pages ( ( unsigned long ) buf , buforder ) ;
err = ret ;
goto out_unlock ;
}
dfile - > data_len = ret ;
dfile - > buffer = buf ;
}
ret = simple_read_from_buffer ( userbuf , count , ppos ,
dfile - > buffer ,
dfile - > data_len ) ;
if ( * ppos > = dfile - > data_len ) {
free_pages ( ( unsigned long ) dfile - > buffer , buforder ) ;
dfile - > buffer = NULL ;
dfile - > data_len = 0 ;
}
out_unlock :
mutex_unlock ( & dev - > wl - > mutex ) ;
return err ? err : ret ;
}
static ssize_t b43_debugfs_write ( struct file * file ,
const char __user * userbuf ,
size_t count , loff_t * ppos )
{
struct b43_wldev * dev ;
struct b43_debugfs_fops * dfops ;
char * buf ;
int err = 0 ;
if ( ! count )
return 0 ;
if ( count > PAGE_SIZE )
return - E2BIG ;
dev = file - > private_data ;
if ( ! dev )
return - ENODEV ;
mutex_lock ( & dev - > wl - > mutex ) ;
if ( b43_status ( dev ) < B43_STAT_INITIALIZED ) {
err = - ENODEV ;
goto out_unlock ;
}
dfops = container_of ( file - > f_op , struct b43_debugfs_fops , fops ) ;
if ( ! dfops - > write ) {
err = - ENOSYS ;
goto out_unlock ;
}
buf = ( char * ) get_zeroed_page ( GFP_KERNEL ) ;
if ( ! buf ) {
err = - ENOMEM ;
goto out_unlock ;
}
if ( copy_from_user ( buf , userbuf , count ) ) {
err = - EFAULT ;
goto out_freepage ;
}
2009-09-05 00:51:29 +04:00
err = dfops - > write ( dev , buf , count ) ;
2007-09-18 23:39:42 +04:00
if ( err )
goto out_freepage ;
out_freepage :
free_page ( ( unsigned long ) buf ) ;
out_unlock :
mutex_unlock ( & dev - > wl - > mutex ) ;
return err ? err : count ;
}
2009-09-05 00:51:29 +04:00
# define B43_DEBUGFS_FOPS(name, _read, _write) \
2007-09-18 23:39:42 +04:00
static struct b43_debugfs_fops fops_ # # name = { \
. read = _read , \
. write = _write , \
. fops = { \
2012-04-06 01:25:11 +04:00
. open = simple_open , \
2007-09-18 23:39:42 +04:00
. read = b43_debugfs_read , \
. write = b43_debugfs_write , \
2010-07-06 21:05:31 +04:00
. llseek = generic_file_llseek , \
2007-09-18 23:39:42 +04:00
} , \
. file_struct_offset = offsetof ( struct b43_dfsentry , \
file_ # # name ) , \
}
2009-09-05 00:51:29 +04:00
B43_DEBUGFS_FOPS ( shm16read , shm16read__read_file , shm16read__write_file ) ;
B43_DEBUGFS_FOPS ( shm16write , NULL , shm16write__write_file ) ;
B43_DEBUGFS_FOPS ( shm32read , shm32read__read_file , shm32read__write_file ) ;
B43_DEBUGFS_FOPS ( shm32write , NULL , shm32write__write_file ) ;
B43_DEBUGFS_FOPS ( mmio16read , mmio16read__read_file , mmio16read__write_file ) ;
B43_DEBUGFS_FOPS ( mmio16write , NULL , mmio16write__write_file ) ;
B43_DEBUGFS_FOPS ( mmio32read , mmio32read__read_file , mmio32read__write_file ) ;
B43_DEBUGFS_FOPS ( mmio32write , NULL , mmio32write__write_file ) ;
B43_DEBUGFS_FOPS ( txstat , txstat_read_file , NULL ) ;
B43_DEBUGFS_FOPS ( restart , NULL , restart_write_file ) ;
B43_DEBUGFS_FOPS ( loctls , loctls_read_file , NULL ) ;
2007-09-18 23:39:42 +04:00
2009-01-25 17:49:59 +03:00
bool b43_debug ( struct b43_wldev * dev , enum b43_dyndbg feature )
2007-09-18 23:39:42 +04:00
{
2009-01-25 17:49:59 +03:00
bool enabled ;
enabled = ( dev - > dfsentry & & dev - > dfsentry - > dyn_debug [ feature ] ) ;
if ( unlikely ( enabled ) ) {
/* Force full debugging messages, if the user enabled
* some dynamic debugging feature . */
b43_modparam_verbose = B43_VERBOSITY_MAX ;
}
return enabled ;
2007-09-18 23:39:42 +04:00
}
static void b43_remove_dynamic_debug ( struct b43_wldev * dev )
{
struct b43_dfsentry * e = dev - > dfsentry ;
int i ;
for ( i = 0 ; i < __B43_NR_DYNDBG ; i + + )
debugfs_remove ( e - > dyn_debug_dentries [ i ] ) ;
}
static void b43_add_dynamic_debug ( struct b43_wldev * dev )
{
struct b43_dfsentry * e = dev - > dfsentry ;
struct dentry * d ;
# define add_dyn_dbg(name, id, initstate) do { \
e - > dyn_debug [ id ] = ( initstate ) ; \
d = debugfs_create_bool ( name , 0600 , e - > subdir , \
& ( e - > dyn_debug [ id ] ) ) ; \
if ( ! IS_ERR ( d ) ) \
e - > dyn_debug_dentries [ id ] = d ; \
} while ( 0 )
add_dyn_dbg ( " debug_xmitpower " , B43_DBG_XMITPOWER , 0 ) ;
add_dyn_dbg ( " debug_dmaoverflow " , B43_DBG_DMAOVERFLOW , 0 ) ;
add_dyn_dbg ( " debug_dmaverbose " , B43_DBG_DMAVERBOSE , 0 ) ;
add_dyn_dbg ( " debug_pwork_fast " , B43_DBG_PWORK_FAST , 0 ) ;
add_dyn_dbg ( " debug_pwork_stop " , B43_DBG_PWORK_STOP , 0 ) ;
2008-04-20 18:03:32 +04:00
add_dyn_dbg ( " debug_lo " , B43_DBG_LO , 0 ) ;
2008-06-20 20:02:08 +04:00
add_dyn_dbg ( " debug_firmware " , B43_DBG_FIRMWARE , 0 ) ;
2008-12-19 22:24:30 +03:00
add_dyn_dbg ( " debug_keys " , B43_DBG_KEYS , 0 ) ;
2009-09-12 02:48:03 +04:00
add_dyn_dbg ( " debug_verbose_stats " , B43_DBG_VERBOSESTATS , 0 ) ;
2007-09-18 23:39:42 +04:00
# undef add_dyn_dbg
}
void b43_debugfs_add_device ( struct b43_wldev * dev )
{
struct b43_dfsentry * e ;
struct b43_txstatus_log * log ;
char devdir [ 16 ] ;
B43_WARN_ON ( ! dev ) ;
e = kzalloc ( sizeof ( * e ) , GFP_KERNEL ) ;
if ( ! e ) {
b43err ( dev - > wl , " debugfs: add device OOM \n " ) ;
return ;
}
e - > dev = dev ;
log = & e - > txstatlog ;
log - > log = kcalloc ( B43_NR_LOGGED_TXSTATUS ,
sizeof ( struct b43_txstatus ) , GFP_KERNEL ) ;
if ( ! log - > log ) {
b43err ( dev - > wl , " debugfs: add device txstatus OOM \n " ) ;
kfree ( e ) ;
return ;
}
log - > end = - 1 ;
dev - > dfsentry = e ;
snprintf ( devdir , sizeof ( devdir ) , " %s " , wiphy_name ( dev - > wl - > hw - > wiphy ) ) ;
e - > subdir = debugfs_create_dir ( devdir , rootdir ) ;
if ( ! e - > subdir | | IS_ERR ( e - > subdir ) ) {
if ( e - > subdir = = ERR_PTR ( - ENODEV ) ) {
b43dbg ( dev - > wl , " DebugFS (CONFIG_DEBUG_FS) not "
" enabled in kernel config \n " ) ;
} else {
b43err ( dev - > wl , " debugfs: cannot create %s directory \n " ,
devdir ) ;
}
dev - > dfsentry = NULL ;
kfree ( log - > log ) ;
kfree ( e ) ;
return ;
}
2008-06-19 02:35:49 +04:00
e - > mmio16read_next = 0xFFFF ; /* invalid address */
e - > mmio32read_next = 0xFFFF ; /* invalid address */
2008-06-19 21:33:51 +04:00
e - > shm16read_routing_next = 0xFFFFFFFF ; /* invalid routing */
e - > shm16read_addr_next = 0xFFFFFFFF ; /* invalid address */
e - > shm32read_routing_next = 0xFFFFFFFF ; /* invalid routing */
e - > shm32read_addr_next = 0xFFFFFFFF ; /* invalid address */
2008-06-19 02:35:49 +04:00
2007-09-18 23:39:42 +04:00
# define ADD_FILE(name, mode) \
do { \
struct dentry * d ; \
d = debugfs_create_file ( __stringify ( name ) , \
mode , e - > subdir , dev , \
& fops_ # # name . fops ) ; \
e - > file_ # # name . dentry = NULL ; \
if ( ! IS_ERR ( d ) ) \
e - > file_ # # name . dentry = d ; \
} while ( 0 )
2008-06-19 21:33:51 +04:00
ADD_FILE ( shm16read , 0600 ) ;
ADD_FILE ( shm16write , 0200 ) ;
ADD_FILE ( shm32read , 0600 ) ;
ADD_FILE ( shm32write , 0200 ) ;
2008-06-19 02:35:49 +04:00
ADD_FILE ( mmio16read , 0600 ) ;
ADD_FILE ( mmio16write , 0200 ) ;
ADD_FILE ( mmio32read , 0600 ) ;
ADD_FILE ( mmio32write , 0200 ) ;
2007-09-18 23:39:42 +04:00
ADD_FILE ( txstat , 0400 ) ;
ADD_FILE ( restart , 0200 ) ;
ADD_FILE ( loctls , 0400 ) ;
# undef ADD_FILE
b43_add_dynamic_debug ( dev ) ;
}
void b43_debugfs_remove_device ( struct b43_wldev * dev )
{
struct b43_dfsentry * e ;
if ( ! dev )
return ;
e = dev - > dfsentry ;
if ( ! e )
return ;
b43_remove_dynamic_debug ( dev ) ;
2008-06-19 21:33:51 +04:00
debugfs_remove ( e - > file_shm16read . dentry ) ;
debugfs_remove ( e - > file_shm16write . dentry ) ;
debugfs_remove ( e - > file_shm32read . dentry ) ;
debugfs_remove ( e - > file_shm32write . dentry ) ;
2008-06-19 02:35:49 +04:00
debugfs_remove ( e - > file_mmio16read . dentry ) ;
debugfs_remove ( e - > file_mmio16write . dentry ) ;
debugfs_remove ( e - > file_mmio32read . dentry ) ;
debugfs_remove ( e - > file_mmio32write . dentry ) ;
2007-09-18 23:39:42 +04:00
debugfs_remove ( e - > file_txstat . dentry ) ;
debugfs_remove ( e - > file_restart . dentry ) ;
debugfs_remove ( e - > file_loctls . dentry ) ;
debugfs_remove ( e - > subdir ) ;
kfree ( e - > txstatlog . log ) ;
kfree ( e ) ;
}
void b43_debugfs_log_txstat ( struct b43_wldev * dev ,
const struct b43_txstatus * status )
{
struct b43_dfsentry * e = dev - > dfsentry ;
struct b43_txstatus_log * log ;
struct b43_txstatus * cur ;
int i ;
if ( ! e )
return ;
log = & e - > txstatlog ;
i = log - > end + 1 ;
if ( i = = B43_NR_LOGGED_TXSTATUS )
i = 0 ;
log - > end = i ;
cur = & ( log - > log [ i ] ) ;
memcpy ( cur , status , sizeof ( * cur ) ) ;
}
void b43_debugfs_init ( void )
{
rootdir = debugfs_create_dir ( KBUILD_MODNAME , NULL ) ;
if ( IS_ERR ( rootdir ) )
rootdir = NULL ;
}
void b43_debugfs_exit ( void )
{
debugfs_remove ( rootdir ) ;
}