2010-05-13 18:48:03 +04:00
/*
* Copyright ( C ) 2010 Felix Fietkau < nbd @ openwrt . org >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/netdevice.h>
# include <linux/types.h>
# include <linux/skbuff.h>
# include <linux/debugfs.h>
# include <linux/ieee80211.h>
2011-07-15 19:47:34 +04:00
# include <linux/export.h>
2010-05-13 18:48:03 +04:00
# include <net/mac80211.h>
# include "rc80211_minstrel.h"
# include "rc80211_minstrel_ht.h"
2013-02-13 13:51:08 +04:00
static char *
minstrel_ht_stats_dump ( struct minstrel_ht_sta * mi , int i , char * p )
{
unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS ;
const struct mcs_group * mg ;
unsigned int j , tp , prob , eprob ;
char htmode = ' 2 ' ;
char gimode = ' L ' ;
if ( ! mi - > groups [ i ] . supported )
return p ;
mg = & minstrel_mcs_groups [ i ] ;
if ( mg - > flags & IEEE80211_TX_RC_40_MHZ_WIDTH )
htmode = ' 4 ' ;
if ( mg - > flags & IEEE80211_TX_RC_SHORT_GI )
gimode = ' S ' ;
for ( j = 0 ; j < MCS_GROUP_RATES ; j + + ) {
struct minstrel_rate_stats * mr = & mi - > groups [ i ] . rates [ j ] ;
static const int bitrates [ 4 ] = { 10 , 20 , 55 , 110 } ;
int idx = i * MCS_GROUP_RATES + j ;
if ( ! ( mi - > groups [ i ] . supported & BIT ( j ) ) )
continue ;
if ( i = = max_mcs )
p + = sprintf ( p , " CCK/%cP " , j < 4 ? ' L ' : ' S ' ) ;
else
p + = sprintf ( p , " HT%c0/%cGI " , htmode , gimode ) ;
* ( p + + ) = ( idx = = mi - > max_tp_rate ) ? ' T ' : ' ' ;
* ( p + + ) = ( idx = = mi - > max_tp_rate2 ) ? ' t ' : ' ' ;
* ( p + + ) = ( idx = = mi - > max_prob_rate ) ? ' P ' : ' ' ;
if ( i = = max_mcs ) {
int r = bitrates [ j % 4 ] ;
p + = sprintf ( p , " %2u.%1uM " , r / 10 , r % 10 ) ;
} else {
2013-11-11 16:12:55 +04:00
p + = sprintf ( p , " MCS%-2u " , ( mg - > streams - 1 ) * 8 + j ) ;
2013-02-13 13:51:08 +04:00
}
tp = mr - > cur_tp / 10 ;
prob = MINSTREL_TRUNC ( mr - > cur_prob * 1000 ) ;
eprob = MINSTREL_TRUNC ( mr - > probability * 1000 ) ;
p + = sprintf ( p , " %6u.%1u %6u.%1u %6u.%1u "
" %3u %3u(%3u) %8llu %8llu \n " ,
tp / 10 , tp % 10 ,
eprob / 10 , eprob % 10 ,
prob / 10 , prob % 10 ,
mr - > retry_count ,
mr - > last_success ,
mr - > last_attempts ,
( unsigned long long ) mr - > succ_hist ,
( unsigned long long ) mr - > att_hist ) ;
}
return p ;
}
2010-05-13 18:48:03 +04:00
static int
minstrel_ht_stats_open ( struct inode * inode , struct file * file )
{
struct minstrel_ht_sta_priv * msp = inode - > i_private ;
struct minstrel_ht_sta * mi = & msp - > ht ;
struct minstrel_debugfs_info * ms ;
2013-02-13 13:51:08 +04:00
unsigned int i ;
unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS ;
2010-05-13 18:48:03 +04:00
char * p ;
int ret ;
if ( ! msp - > is_ht ) {
inode - > i_private = & msp - > legacy ;
ret = minstrel_stats_open ( inode , file ) ;
inode - > i_private = msp ;
return ret ;
}
ms = kmalloc ( sizeof ( * ms ) + 8192 , GFP_KERNEL ) ;
if ( ! ms )
return - ENOMEM ;
file - > private_data = ms ;
p = ms - > buf ;
2013-02-11 17:36:03 +04:00
p + = sprintf ( p , " type rate throughput ewma prob this prob "
" retry this succ/attempt success attempts \n " ) ;
2010-05-13 18:48:03 +04:00
2013-02-13 13:51:08 +04:00
p = minstrel_ht_stats_dump ( mi , max_mcs , p ) ;
for ( i = 0 ; i < max_mcs ; i + + )
p = minstrel_ht_stats_dump ( mi , i , p ) ;
2010-05-13 18:48:03 +04:00
p + = sprintf ( p , " \n Total packet count:: ideal %d "
" lookaround %d \n " ,
max ( 0 , ( int ) mi - > total_packets - ( int ) mi - > sample_packets ) ,
mi - > sample_packets ) ;
p + = sprintf ( p , " Average A-MPDU length: %d.%d \n " ,
MINSTREL_TRUNC ( mi - > avg_ampdu_len ) ,
MINSTREL_TRUNC ( mi - > avg_ampdu_len * 10 ) % 10 ) ;
ms - > len = p - ms - > buf ;
2010-08-15 20:32:42 +04:00
return nonseekable_open ( inode , file ) ;
2010-05-13 18:48:03 +04:00
}
static const struct file_operations minstrel_ht_stat_fops = {
. owner = THIS_MODULE ,
. open = minstrel_ht_stats_open ,
. read = minstrel_stats_read ,
. release = minstrel_stats_release ,
2010-08-15 20:32:42 +04:00
. llseek = no_llseek ,
2010-05-13 18:48:03 +04:00
} ;
void
minstrel_ht_add_sta_debugfs ( void * priv , void * priv_sta , struct dentry * dir )
{
struct minstrel_ht_sta_priv * msp = priv_sta ;
msp - > dbg_stats = debugfs_create_file ( " rc_stats " , S_IRUGO , dir , msp ,
& minstrel_ht_stat_fops ) ;
}
void
minstrel_ht_remove_sta_debugfs ( void * priv , void * priv_sta )
{
struct minstrel_ht_sta_priv * msp = priv_sta ;
debugfs_remove ( msp - > dbg_stats ) ;
}