2009-10-27 12:59:03 +01:00
2007-05-05 11:46:38 -07:00
/*
* mac80211 debugfs for wireless PHYs
*
* Copyright 2007 Johannes Berg < johannes @ sipsolutions . net >
*
* GPLv2
*
*/
# include <linux/debugfs.h>
# include <linux/rtnetlink.h>
# include "ieee80211_i.h"
2009-04-23 18:52:52 +02:00
# include "driver-ops.h"
2008-04-08 15:14:40 -04:00
# include "rate.h"
2007-05-05 11:46:38 -07:00
# include "debugfs.h"
int mac80211_open_file_generic ( struct inode * inode , struct file * file )
{
file - > private_data = inode - > i_private ;
return 0 ;
}
# define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \
static ssize_t name # # _read ( struct file * file , char __user * userbuf , \
size_t count , loff_t * ppos ) \
{ \
struct ieee80211_local * local = file - > private_data ; \
char buf [ buflen ] ; \
int res ; \
\
res = scnprintf ( buf , buflen , fmt " \n " , # # value ) ; \
return simple_read_from_buffer ( userbuf , count , ppos , buf , res ) ; \
} \
\
static const struct file_operations name # # _ops = { \
. read = name # # _read , \
. open = mac80211_open_file_generic , \
} ;
# define DEBUGFS_ADD(name) \
2009-10-27 12:59:03 +01:00
debugfs_create_file ( # name , 0400 , phyd , local , & name # # _ops ) ;
2007-05-05 11:46:38 -07:00
2009-03-13 11:44:18 +01:00
# define DEBUGFS_ADD_MODE(name, mode) \
2009-10-27 12:59:03 +01:00
debugfs_create_file ( # name , mode , phyd , local , & name # # _ops ) ;
2007-05-05 11:46:38 -07:00
DEBUGFS_READONLY_FILE ( frequency , 20 , " %d " ,
2008-01-24 19:38:38 +01:00
local - > hw . conf . channel - > center_freq ) ;
2007-05-05 11:46:38 -07:00
DEBUGFS_READONLY_FILE ( total_ps_buffered , 20 , " %d " ,
local - > total_ps_buffered ) ;
2009-01-24 07:09:59 +01:00
DEBUGFS_READONLY_FILE ( wep_iv , 20 , " %#08x " ,
2007-05-05 11:46:38 -07:00
local - > wep_iv & 0xffffff ) ;
DEBUGFS_READONLY_FILE ( rate_ctrl_alg , 100 , " %s " ,
2009-11-17 18:18:36 +01:00
local - > rate_ctrl ? local - > rate_ctrl - > ops - > name : " hw/driver " ) ;
2009-01-24 07:09:59 +01:00
static ssize_t tsf_read ( struct file * file , char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct ieee80211_local * local = file - > private_data ;
2009-04-23 18:52:52 +02:00
u64 tsf ;
2009-01-24 07:09:59 +01:00
char buf [ 100 ] ;
2009-04-23 18:52:52 +02:00
tsf = drv_get_tsf ( local ) ;
2009-01-24 07:09:59 +01:00
snprintf ( buf , sizeof ( buf ) , " 0x%016llx \n " , ( unsigned long long ) tsf ) ;
return simple_read_from_buffer ( user_buf , count , ppos , buf , 19 ) ;
}
static ssize_t tsf_write ( struct file * file ,
const char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct ieee80211_local * local = file - > private_data ;
unsigned long long tsf ;
char buf [ 100 ] ;
size_t len ;
len = min ( count , sizeof ( buf ) - 1 ) ;
if ( copy_from_user ( buf , user_buf , len ) )
return - EFAULT ;
buf [ len ] = ' \0 ' ;
if ( strncmp ( buf , " reset " , 5 ) = = 0 ) {
if ( local - > ops - > reset_tsf ) {
2009-04-23 18:52:52 +02:00
drv_reset_tsf ( local ) ;
2009-01-24 07:09:59 +01:00
printk ( KERN_INFO " %s: debugfs reset TSF \n " , wiphy_name ( local - > hw . wiphy ) ) ;
}
} else {
tsf = simple_strtoul ( buf , NULL , 0 ) ;
if ( local - > ops - > set_tsf ) {
2009-04-23 18:52:52 +02:00
drv_set_tsf ( local , tsf ) ;
2009-01-24 07:09:59 +01:00
printk ( KERN_INFO " %s: debugfs set TSF to %#018llx \n " , wiphy_name ( local - > hw . wiphy ) , tsf ) ;
}
}
return count ;
}
static const struct file_operations tsf_ops = {
. read = tsf_read ,
. write = tsf_write ,
. open = mac80211_open_file_generic
} ;
2007-05-05 11:46:38 -07:00
2009-03-13 11:44:18 +01:00
static ssize_t reset_write ( struct file * file , const char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct ieee80211_local * local = file - > private_data ;
rtnl_lock ( ) ;
__ieee80211_suspend ( & local - > hw ) ;
__ieee80211_resume ( & local - > hw ) ;
rtnl_unlock ( ) ;
return count ;
}
static const struct file_operations reset_ops = {
. write = reset_write ,
. open = mac80211_open_file_generic ,
} ;
2009-05-12 22:05:40 +02:00
static ssize_t noack_read ( struct file * file , char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct ieee80211_local * local = file - > private_data ;
int res ;
char buf [ 10 ] ;
res = scnprintf ( buf , sizeof ( buf ) , " %d \n " , local - > wifi_wme_noack_test ) ;
return simple_read_from_buffer ( user_buf , count , ppos , buf , res ) ;
}
static ssize_t noack_write ( struct file * file ,
const char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct ieee80211_local * local = file - > private_data ;
char buf [ 10 ] ;
size_t len ;
len = min ( count , sizeof ( buf ) - 1 ) ;
if ( copy_from_user ( buf , user_buf , len ) )
return - EFAULT ;
buf [ len ] = ' \0 ' ;
local - > wifi_wme_noack_test = ! ! simple_strtoul ( buf , NULL , 0 ) ;
return count ;
}
static const struct file_operations noack_ops = {
. read = noack_read ,
. write = noack_write ,
. open = mac80211_open_file_generic
} ;
2010-01-12 10:42:39 +02:00
static ssize_t uapsd_queues_read ( struct file * file , char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct ieee80211_local * local = file - > private_data ;
int res ;
char buf [ 10 ] ;
res = scnprintf ( buf , sizeof ( buf ) , " 0x%x \n " , local - > uapsd_queues ) ;
return simple_read_from_buffer ( user_buf , count , ppos , buf , res ) ;
}
static ssize_t uapsd_queues_write ( struct file * file ,
const char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct ieee80211_local * local = file - > private_data ;
unsigned long val ;
char buf [ 10 ] ;
size_t len ;
int ret ;
len = min ( count , sizeof ( buf ) - 1 ) ;
if ( copy_from_user ( buf , user_buf , len ) )
return - EFAULT ;
buf [ len ] = ' \0 ' ;
ret = strict_strtoul ( buf , 0 , & val ) ;
if ( ret )
return - EINVAL ;
if ( val & ~ IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK )
return - ERANGE ;
local - > uapsd_queues = val ;
return count ;
}
static const struct file_operations uapsd_queues_ops = {
. read = uapsd_queues_read ,
. write = uapsd_queues_write ,
. open = mac80211_open_file_generic
} ;
static ssize_t uapsd_max_sp_len_read ( struct file * file , char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct ieee80211_local * local = file - > private_data ;
int res ;
char buf [ 10 ] ;
res = scnprintf ( buf , sizeof ( buf ) , " 0x%x \n " , local - > uapsd_max_sp_len ) ;
return simple_read_from_buffer ( user_buf , count , ppos , buf , res ) ;
}
static ssize_t uapsd_max_sp_len_write ( struct file * file ,
const char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct ieee80211_local * local = file - > private_data ;
unsigned long val ;
char buf [ 10 ] ;
size_t len ;
int ret ;
len = min ( count , sizeof ( buf ) - 1 ) ;
if ( copy_from_user ( buf , user_buf , len ) )
return - EFAULT ;
buf [ len ] = ' \0 ' ;
ret = strict_strtoul ( buf , 0 , & val ) ;
if ( ret )
return - EINVAL ;
if ( val & ~ IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK )
return - ERANGE ;
local - > uapsd_max_sp_len = val ;
return count ;
}
static const struct file_operations uapsd_max_sp_len_ops = {
. read = uapsd_max_sp_len_read ,
. write = uapsd_max_sp_len_write ,
. open = mac80211_open_file_generic
} ;
2010-02-04 22:00:20 +01:00
static ssize_t channel_type_read ( struct file * file , char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct ieee80211_local * local = file - > private_data ;
const char * buf ;
switch ( local - > hw . conf . channel_type ) {
case NL80211_CHAN_NO_HT :
buf = " no ht \n " ;
break ;
case NL80211_CHAN_HT20 :
buf = " ht20 \n " ;
break ;
case NL80211_CHAN_HT40MINUS :
buf = " ht40- \n " ;
break ;
case NL80211_CHAN_HT40PLUS :
buf = " ht40+ \n " ;
break ;
default :
buf = " ??? " ;
break ;
}
return simple_read_from_buffer ( user_buf , count , ppos , buf , strlen ( buf ) ) ;
}
static const struct file_operations channel_type_ops = {
. read = channel_type_read ,
. open = mac80211_open_file_generic
} ;
2009-06-14 17:37:39 +02:00
static ssize_t queues_read ( struct file * file , char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct ieee80211_local * local = file - > private_data ;
unsigned long flags ;
char buf [ IEEE80211_MAX_QUEUES * 20 ] ;
int q , res = 0 ;
spin_lock_irqsave ( & local - > queue_stop_reason_lock , flags ) ;
for ( q = 0 ; q < local - > hw . queues ; q + + )
res + = sprintf ( buf + res , " %02d: %#.8lx/%d \n " , q ,
local - > queue_stop_reasons [ q ] ,
2009-06-17 17:43:56 +02:00
skb_queue_len ( & local - > pending [ q ] ) ) ;
2009-06-14 17:37:39 +02:00
spin_unlock_irqrestore ( & local - > queue_stop_reason_lock , flags ) ;
return simple_read_from_buffer ( user_buf , count , ppos , buf , res ) ;
}
static const struct file_operations queues_ops = {
. read = queues_read ,
. open = mac80211_open_file_generic
} ;
2007-05-05 11:46:38 -07:00
/* statistics stuff */
# define DEBUGFS_STATS_FILE(name, buflen, fmt, value...) \
DEBUGFS_READONLY_FILE ( stats_ # # name , buflen , fmt , # # value )
static ssize_t format_devstat_counter ( struct ieee80211_local * local ,
char __user * userbuf ,
size_t count , loff_t * ppos ,
int ( * printvalue ) ( struct ieee80211_low_level_stats * stats , char * buf ,
int buflen ) )
{
struct ieee80211_low_level_stats stats ;
char buf [ 20 ] ;
int res ;
2008-07-09 14:40:35 +02:00
rtnl_lock ( ) ;
2009-04-23 18:52:52 +02:00
res = drv_get_stats ( local , & stats ) ;
2007-05-05 11:46:38 -07:00
rtnl_unlock ( ) ;
2009-04-23 18:52:52 +02:00
if ( res )
return res ;
res = printvalue ( & stats , buf , sizeof ( buf ) ) ;
2007-05-05 11:46:38 -07:00
return simple_read_from_buffer ( userbuf , count , ppos , buf , res ) ;
}
# define DEBUGFS_DEVSTATS_FILE(name) \
static int print_devstats_ # # name ( struct ieee80211_low_level_stats * stats , \
char * buf , int buflen ) \
{ \
return scnprintf ( buf , buflen , " %u \n " , stats - > name ) ; \
} \
static ssize_t stats_ # # name # # _read ( struct file * file , \
char __user * userbuf , \
size_t count , loff_t * ppos ) \
{ \
return format_devstat_counter ( file - > private_data , \
userbuf , \
count , \
ppos , \
print_devstats_ # # name ) ; \
} \
\
static const struct file_operations stats_ # # name # # _ops = { \
. read = stats_ # # name # # _read , \
. open = mac80211_open_file_generic , \
} ;
# define DEBUGFS_STATS_ADD(name) \
2009-10-27 12:59:03 +01:00
debugfs_create_file ( # name , 0400 , statsd , local , & stats_ # # name # # _ops ) ;
2007-05-05 11:46:38 -07:00
DEBUGFS_STATS_FILE ( transmitted_fragment_count , 20 , " %u " ,
local - > dot11TransmittedFragmentCount ) ;
DEBUGFS_STATS_FILE ( multicast_transmitted_frame_count , 20 , " %u " ,
local - > dot11MulticastTransmittedFrameCount ) ;
DEBUGFS_STATS_FILE ( failed_count , 20 , " %u " ,
local - > dot11FailedCount ) ;
DEBUGFS_STATS_FILE ( retry_count , 20 , " %u " ,
local - > dot11RetryCount ) ;
DEBUGFS_STATS_FILE ( multiple_retry_count , 20 , " %u " ,
local - > dot11MultipleRetryCount ) ;
DEBUGFS_STATS_FILE ( frame_duplicate_count , 20 , " %u " ,
local - > dot11FrameDuplicateCount ) ;
DEBUGFS_STATS_FILE ( received_fragment_count , 20 , " %u " ,
local - > dot11ReceivedFragmentCount ) ;
DEBUGFS_STATS_FILE ( multicast_received_frame_count , 20 , " %u " ,
local - > dot11MulticastReceivedFrameCount ) ;
DEBUGFS_STATS_FILE ( transmitted_frame_count , 20 , " %u " ,
local - > dot11TransmittedFrameCount ) ;
# ifdef CONFIG_MAC80211_DEBUG_COUNTERS
DEBUGFS_STATS_FILE ( tx_handlers_drop , 20 , " %u " ,
local - > tx_handlers_drop ) ;
DEBUGFS_STATS_FILE ( tx_handlers_queued , 20 , " %u " ,
local - > tx_handlers_queued ) ;
DEBUGFS_STATS_FILE ( tx_handlers_drop_unencrypted , 20 , " %u " ,
local - > tx_handlers_drop_unencrypted ) ;
DEBUGFS_STATS_FILE ( tx_handlers_drop_fragment , 20 , " %u " ,
local - > tx_handlers_drop_fragment ) ;
DEBUGFS_STATS_FILE ( tx_handlers_drop_wep , 20 , " %u " ,
local - > tx_handlers_drop_wep ) ;
DEBUGFS_STATS_FILE ( tx_handlers_drop_not_assoc , 20 , " %u " ,
local - > tx_handlers_drop_not_assoc ) ;
DEBUGFS_STATS_FILE ( tx_handlers_drop_unauth_port , 20 , " %u " ,
local - > tx_handlers_drop_unauth_port ) ;
DEBUGFS_STATS_FILE ( rx_handlers_drop , 20 , " %u " ,
local - > rx_handlers_drop ) ;
DEBUGFS_STATS_FILE ( rx_handlers_queued , 20 , " %u " ,
local - > rx_handlers_queued ) ;
DEBUGFS_STATS_FILE ( rx_handlers_drop_nullfunc , 20 , " %u " ,
local - > rx_handlers_drop_nullfunc ) ;
DEBUGFS_STATS_FILE ( rx_handlers_drop_defrag , 20 , " %u " ,
local - > rx_handlers_drop_defrag ) ;
DEBUGFS_STATS_FILE ( rx_handlers_drop_short , 20 , " %u " ,
local - > rx_handlers_drop_short ) ;
DEBUGFS_STATS_FILE ( rx_handlers_drop_passive_scan , 20 , " %u " ,
local - > rx_handlers_drop_passive_scan ) ;
DEBUGFS_STATS_FILE ( tx_expand_skb_head , 20 , " %u " ,
local - > tx_expand_skb_head ) ;
DEBUGFS_STATS_FILE ( tx_expand_skb_head_cloned , 20 , " %u " ,
local - > tx_expand_skb_head_cloned ) ;
DEBUGFS_STATS_FILE ( rx_expand_skb_head , 20 , " %u " ,
local - > rx_expand_skb_head ) ;
DEBUGFS_STATS_FILE ( rx_expand_skb_head2 , 20 , " %u " ,
local - > rx_expand_skb_head2 ) ;
DEBUGFS_STATS_FILE ( rx_handlers_fragments , 20 , " %u " ,
local - > rx_handlers_fragments ) ;
DEBUGFS_STATS_FILE ( tx_status_drop , 20 , " %u " ,
local - > tx_status_drop ) ;
# endif
DEBUGFS_DEVSTATS_FILE ( dot11ACKFailureCount ) ;
DEBUGFS_DEVSTATS_FILE ( dot11RTSFailureCount ) ;
DEBUGFS_DEVSTATS_FILE ( dot11FCSErrorCount ) ;
DEBUGFS_DEVSTATS_FILE ( dot11RTSSuccessCount ) ;
void debugfs_hw_add ( struct ieee80211_local * local )
{
struct dentry * phyd = local - > hw . wiphy - > debugfsdir ;
struct dentry * statsd ;
if ( ! phyd )
return ;
local - > debugfs . stations = debugfs_create_dir ( " stations " , phyd ) ;
local - > debugfs . keys = debugfs_create_dir ( " keys " , phyd ) ;
DEBUGFS_ADD ( frequency ) ;
DEBUGFS_ADD ( total_ps_buffered ) ;
DEBUGFS_ADD ( wep_iv ) ;
2009-01-23 05:33:37 +01:00
DEBUGFS_ADD ( tsf ) ;
2009-06-14 17:37:39 +02:00
DEBUGFS_ADD ( queues ) ;
2009-03-13 11:44:18 +01:00
DEBUGFS_ADD_MODE ( reset , 0200 ) ;
2009-05-12 22:05:40 +02:00
DEBUGFS_ADD ( noack ) ;
2010-01-12 10:42:39 +02:00
DEBUGFS_ADD ( uapsd_queues ) ;
DEBUGFS_ADD ( uapsd_max_sp_len ) ;
2010-02-04 22:00:20 +01:00
DEBUGFS_ADD ( channel_type ) ;
2007-05-05 11:46:38 -07:00
statsd = debugfs_create_dir ( " statistics " , phyd ) ;
/* if the dir failed, don't put all the other things into the root! */
if ( ! statsd )
return ;
DEBUGFS_STATS_ADD ( transmitted_fragment_count ) ;
DEBUGFS_STATS_ADD ( multicast_transmitted_frame_count ) ;
DEBUGFS_STATS_ADD ( failed_count ) ;
DEBUGFS_STATS_ADD ( retry_count ) ;
DEBUGFS_STATS_ADD ( multiple_retry_count ) ;
DEBUGFS_STATS_ADD ( frame_duplicate_count ) ;
DEBUGFS_STATS_ADD ( received_fragment_count ) ;
DEBUGFS_STATS_ADD ( multicast_received_frame_count ) ;
DEBUGFS_STATS_ADD ( transmitted_frame_count ) ;
# ifdef CONFIG_MAC80211_DEBUG_COUNTERS
DEBUGFS_STATS_ADD ( tx_handlers_drop ) ;
DEBUGFS_STATS_ADD ( tx_handlers_queued ) ;
DEBUGFS_STATS_ADD ( tx_handlers_drop_unencrypted ) ;
DEBUGFS_STATS_ADD ( tx_handlers_drop_fragment ) ;
DEBUGFS_STATS_ADD ( tx_handlers_drop_wep ) ;
DEBUGFS_STATS_ADD ( tx_handlers_drop_not_assoc ) ;
DEBUGFS_STATS_ADD ( tx_handlers_drop_unauth_port ) ;
DEBUGFS_STATS_ADD ( rx_handlers_drop ) ;
DEBUGFS_STATS_ADD ( rx_handlers_queued ) ;
DEBUGFS_STATS_ADD ( rx_handlers_drop_nullfunc ) ;
DEBUGFS_STATS_ADD ( rx_handlers_drop_defrag ) ;
DEBUGFS_STATS_ADD ( rx_handlers_drop_short ) ;
DEBUGFS_STATS_ADD ( rx_handlers_drop_passive_scan ) ;
DEBUGFS_STATS_ADD ( tx_expand_skb_head ) ;
DEBUGFS_STATS_ADD ( tx_expand_skb_head_cloned ) ;
DEBUGFS_STATS_ADD ( rx_expand_skb_head ) ;
DEBUGFS_STATS_ADD ( rx_expand_skb_head2 ) ;
DEBUGFS_STATS_ADD ( rx_handlers_fragments ) ;
DEBUGFS_STATS_ADD ( tx_status_drop ) ;
# endif
DEBUGFS_STATS_ADD ( dot11ACKFailureCount ) ;
DEBUGFS_STATS_ADD ( dot11RTSFailureCount ) ;
DEBUGFS_STATS_ADD ( dot11FCSErrorCount ) ;
DEBUGFS_STATS_ADD ( dot11RTSSuccessCount ) ;
}