2007-12-19 03:25:57 +03:00
/*
* Copyright 2002 - 2005 , Instant802 Networks , Inc .
* Copyright 2005 , Devicescape Software , Inc .
* Copyright 2007 , Mattias Nissler < mattias . nissler @ gmx . de >
2008-01-29 22:29:16 +03:00
* Copyright 2007 - 2008 , Stefano Brivio < stefano . brivio @ polimi . it >
2007-12-19 03:25:57 +03:00
*
* 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>
2008-01-02 17:17:03 +03:00
# include <linux/debugfs.h>
2007-12-19 03:25:57 +03:00
# include <net/mac80211.h>
2008-04-08 23:14:40 +04:00
# include "rate.h"
2008-02-23 17:17:11 +03:00
# include "mesh.h"
2007-12-19 03:27:18 +03:00
# include "rc80211_pid.h"
2007-12-19 03:25:57 +03:00
/* This is an implementation of a TX rate control algorithm that uses a PID
* controller . Given a target failed frames rate , the controller decides about
* TX rate changes to meet the target failed frames rate .
*
* The controller basically computes the following :
*
2007-12-19 03:26:52 +03:00
* adj = CP * err + CI * err_avg + CD * ( err - last_err ) * ( 1 + sharpening )
2007-12-19 03:25:57 +03:00
*
* where
* adj adjustment value that is used to switch TX rate ( see below )
* err current error : target vs . current failed frames percentage
* last_err last error
* err_avg average ( i . e . poor man ' s integral ) of recent errors
2007-12-19 03:26:52 +03:00
* sharpening non - zero when fast response is needed ( i . e . right after
* association or no frames sent for a long time ) , heading
* to zero over time
2007-12-19 03:25:57 +03:00
* CP Proportional coefficient
* CI Integral coefficient
* CD Derivative coefficient
*
* CP , CI , CD are subject to careful tuning .
*
* The integral component uses a exponential moving average approach instead of
* an actual sliding window . The advantage is that we don ' t need to keep an
* array of the last N error values and computation is easier .
*
2007-12-19 03:26:34 +03:00
* Once we have the adj value , we map it to a rate by means of a learning
* algorithm . This algorithm keeps the state of the percentual failed frames
* difference between rates . The behaviour of the lowest available rate is kept
* as a reference value , and every time we switch between two rates , we compute
* the difference between the failed frames each rate exhibited . By doing so ,
* we compare behaviours which different rates exhibited in adjacent timeslices ,
* thus the comparison is minimally affected by external conditions . This
* difference gets propagated to the whole set of measurements , so that the
* reference is always the same . Periodically , we normalize this set so that
* recent events weigh the most . By comparing the adj value with this set , we
* avoid pejorative switches to lower rates and allow for switches to higher
* rates if they behaved well .
2007-12-19 03:25:57 +03:00
*
* Note that for the computations we use a fixed - point representation to avoid
* floating point arithmetic . Hence , all values are shifted left by
* RC_PID_ARITH_SHIFT .
*/
2008-01-29 22:29:16 +03:00
/* Adjust the rate while ensuring that we won't switch to a lower rate if it
* exhibited a worse failed frames behaviour and we ' ll choose the highest rate
* whose failed frames behaviour is not worse than the one of the original rate
* target . While at it , check that the new rate is valid . */
2008-09-18 20:14:18 +04:00
static void rate_control_pid_adjust_rate ( struct ieee80211_supported_band * sband ,
struct ieee80211_sta * sta ,
struct rc_pid_sta_info * spinfo , int adj ,
2007-12-19 03:26:34 +03:00
struct rc_pid_rateinfo * rinfo )
2007-12-19 03:25:57 +03:00
{
2008-01-29 22:29:16 +03:00
int cur_sorted , new_sorted , probe , tmp , n_bitrates , band ;
2008-09-11 05:04:36 +04:00
int cur = spinfo - > txrate_idx ;
2007-12-19 03:25:57 +03:00
2008-01-29 22:29:16 +03:00
band = sband - > band ;
n_bitrates = sband - > n_bitrates ;
2007-12-19 03:25:57 +03:00
2008-01-29 22:29:16 +03:00
/* Map passed arguments to sorted values. */
cur_sorted = rinfo [ cur ] . rev_index ;
new_sorted = cur_sorted + adj ;
2007-12-19 03:25:57 +03:00
2008-01-29 22:29:16 +03:00
/* Check limits. */
if ( new_sorted < 0 )
new_sorted = rinfo [ 0 ] . rev_index ;
else if ( new_sorted > = n_bitrates )
new_sorted = rinfo [ n_bitrates - 1 ] . rev_index ;
tmp = new_sorted ;
2007-12-19 03:25:57 +03:00
2008-01-29 22:29:16 +03:00
if ( adj < 0 ) {
/* Ensure that the rate decrease isn't disadvantageous. */
for ( probe = cur_sorted ; probe > = new_sorted ; probe - - )
if ( rinfo [ probe ] . diff < = rinfo [ cur_sorted ] . diff & &
rate_supported ( sta , band , rinfo [ probe ] . index ) )
tmp = probe ;
} else {
/* Look for rate increase with zero (or below) cost. */
for ( probe = new_sorted + 1 ; probe < n_bitrates ; probe + + )
if ( rinfo [ probe ] . diff < = rinfo [ new_sorted ] . diff & &
rate_supported ( sta , band , rinfo [ probe ] . index ) )
tmp = probe ;
2007-12-19 03:25:57 +03:00
}
2007-12-19 03:27:18 +03:00
2008-01-29 22:29:16 +03:00
/* Fit the rate found to the nearest supported rate. */
do {
if ( rate_supported ( sta , band , rinfo [ tmp ] . index ) ) {
2008-09-11 05:04:36 +04:00
spinfo - > txrate_idx = rinfo [ tmp ] . index ;
2008-01-29 22:29:16 +03:00
break ;
}
if ( adj < 0 )
tmp - - ;
else
tmp + + ;
} while ( tmp < n_bitrates & & tmp > = 0 ) ;
2007-12-19 03:27:18 +03:00
# ifdef CONFIG_MAC80211_DEBUGFS
2008-09-11 05:04:36 +04:00
rate_control_pid_event_rate_change ( & spinfo - > events ,
spinfo - > txrate_idx ,
sband - > bitrates [ spinfo - > txrate_idx ] . bitrate ) ;
2007-12-19 03:27:18 +03:00
# endif
2007-12-19 03:25:57 +03:00
}
2007-12-19 03:26:34 +03:00
/* Normalize the failed frames per-rate differences. */
2007-12-20 15:27:26 +03:00
static void rate_control_pid_normalize ( struct rc_pid_info * pinfo , int l )
2007-12-19 03:26:34 +03:00
{
2007-12-20 15:27:26 +03:00
int i , norm_offset = pinfo - > norm_offset ;
struct rc_pid_rateinfo * r = pinfo - > rinfo ;
2007-12-19 03:26:34 +03:00
2007-12-20 15:27:26 +03:00
if ( r [ 0 ] . diff > norm_offset )
r [ 0 ] . diff - = norm_offset ;
else if ( r [ 0 ] . diff < - norm_offset )
r [ 0 ] . diff + = norm_offset ;
2007-12-19 03:26:34 +03:00
for ( i = 0 ; i < l - 1 ; i + + )
2007-12-20 15:27:26 +03:00
if ( r [ i + 1 ] . diff > r [ i ] . diff + norm_offset )
r [ i + 1 ] . diff - = norm_offset ;
2007-12-19 03:26:34 +03:00
else if ( r [ i + 1 ] . diff < = r [ i ] . diff )
2007-12-20 15:27:26 +03:00
r [ i + 1 ] . diff + = norm_offset ;
2007-12-19 03:26:34 +03:00
}
2007-12-19 03:25:57 +03:00
static void rate_control_pid_sample ( struct rc_pid_info * pinfo ,
2008-09-18 20:14:18 +04:00
struct ieee80211_supported_band * sband ,
struct ieee80211_sta * sta ,
struct rc_pid_sta_info * spinfo )
2007-12-19 03:25:57 +03:00
{
2007-12-19 03:26:34 +03:00
struct rc_pid_rateinfo * rinfo = pinfo - > rinfo ;
2007-12-19 03:25:57 +03:00
u32 pf ;
s32 err_avg ;
2007-12-20 15:27:26 +03:00
u32 err_prop ;
u32 err_int ;
u32 err_der ;
2007-12-19 03:26:34 +03:00
int adj , i , j , tmp ;
2007-12-20 15:27:26 +03:00
unsigned long period ;
2007-12-19 03:25:57 +03:00
2007-12-19 03:26:52 +03:00
/* In case nothing happened during the previous control interval, turn
* the sharpening factor on . */
2007-12-20 15:27:26 +03:00
period = ( HZ * pinfo - > sampling_period + 500 ) / 1000 ;
if ( ! period )
period = 1 ;
if ( jiffies - spinfo - > last_sample > 2 * period )
spinfo - > sharp_cnt = pinfo - > sharpen_duration ;
2007-12-19 03:26:52 +03:00
2007-12-19 03:25:57 +03:00
spinfo - > last_sample = jiffies ;
2007-12-19 03:26:52 +03:00
/* This should never happen, but in case, we assume the old sample is
2007-12-19 03:25:57 +03:00
* still a good measurement and copy it . */
2007-12-19 03:26:52 +03:00
if ( unlikely ( spinfo - > tx_num_xmit = = 0 ) )
2007-12-19 03:25:57 +03:00
pf = spinfo - > last_pf ;
else {
2008-09-18 20:14:18 +04:00
/* XXX: BAD HACK!!! */
struct sta_info * si = container_of ( sta , struct sta_info , sta ) ;
2007-12-19 03:25:57 +03:00
pf = spinfo - > tx_num_failed * 100 / spinfo - > tx_num_xmit ;
2008-09-18 20:14:18 +04:00
if ( ieee80211_vif_is_mesh ( & si - > sdata - > vif ) & & pf = = 100 )
mesh_plink_broken ( si ) ;
2007-12-19 03:25:57 +03:00
pf < < = RC_PID_ARITH_SHIFT ;
2008-09-18 20:14:18 +04:00
si - > fail_avg = ( ( pf + ( spinfo - > last_pf < < 3 ) ) / 9 )
2008-02-23 17:17:11 +03:00
> > RC_PID_ARITH_SHIFT ;
2007-12-19 03:25:57 +03:00
}
2007-12-19 03:26:52 +03:00
spinfo - > tx_num_xmit = 0 ;
spinfo - > tx_num_failed = 0 ;
2007-12-19 03:26:34 +03:00
/* If we just switched rate, update the rate behaviour info. */
2008-09-11 05:04:36 +04:00
if ( pinfo - > oldrate ! = spinfo - > txrate_idx ) {
2007-12-19 03:26:34 +03:00
i = rinfo [ pinfo - > oldrate ] . rev_index ;
2008-09-11 05:04:36 +04:00
j = rinfo [ spinfo - > txrate_idx ] . rev_index ;
2007-12-19 03:26:34 +03:00
tmp = ( pf - spinfo - > last_pf ) ;
tmp = RC_PID_DO_ARITH_RIGHT_SHIFT ( tmp , RC_PID_ARITH_SHIFT ) ;
rinfo [ j ] . diff = rinfo [ i ] . diff + tmp ;
2008-09-11 05:04:36 +04:00
pinfo - > oldrate = spinfo - > txrate_idx ;
2007-12-19 03:26:34 +03:00
}
2008-01-24 21:38:38 +03:00
rate_control_pid_normalize ( pinfo , sband - > n_bitrates ) ;
2007-12-19 03:26:34 +03:00
2007-12-19 03:25:57 +03:00
/* Compute the proportional, integral and derivative errors. */
2007-12-23 06:39:17 +03:00
err_prop = ( pinfo - > target < < RC_PID_ARITH_SHIFT ) - pf ;
2007-12-19 03:25:57 +03:00
2007-12-20 15:27:26 +03:00
err_avg = spinfo - > err_avg_sc > > pinfo - > smoothing_shift ;
2007-12-19 03:25:57 +03:00
spinfo - > err_avg_sc = spinfo - > err_avg_sc - err_avg + err_prop ;
2007-12-20 15:27:26 +03:00
err_int = spinfo - > err_avg_sc > > pinfo - > smoothing_shift ;
2007-12-19 03:25:57 +03:00
2007-12-20 15:27:26 +03:00
err_der = ( pf - spinfo - > last_pf ) *
( 1 + pinfo - > sharpen_factor * spinfo - > sharp_cnt ) ;
2007-12-19 03:25:57 +03:00
spinfo - > last_pf = pf ;
2007-12-19 03:26:52 +03:00
if ( spinfo - > sharp_cnt )
spinfo - > sharp_cnt - - ;
2007-12-19 03:25:57 +03:00
2007-12-19 03:27:18 +03:00
# ifdef CONFIG_MAC80211_DEBUGFS
rate_control_pid_event_pf_sample ( & spinfo - > events , pf , err_prop , err_int ,
err_der ) ;
# endif
2007-12-19 03:25:57 +03:00
/* Compute the controller output. */
adj = ( err_prop * pinfo - > coeff_p + err_int * pinfo - > coeff_i
+ err_der * pinfo - > coeff_d ) ;
2007-12-19 03:26:34 +03:00
adj = RC_PID_DO_ARITH_RIGHT_SHIFT ( adj , 2 * RC_PID_ARITH_SHIFT ) ;
2007-12-19 03:25:57 +03:00
/* Change rate. */
if ( adj )
2008-09-18 20:14:18 +04:00
rate_control_pid_adjust_rate ( sband , sta , spinfo , adj , rinfo ) ;
2007-12-19 03:25:57 +03:00
}
2008-09-18 20:14:18 +04:00
static void rate_control_pid_tx_status ( void * priv , struct ieee80211_supported_band * sband ,
struct ieee80211_sta * sta , void * priv_sta ,
2008-05-15 14:55:29 +04:00
struct sk_buff * skb )
2007-12-19 03:25:57 +03:00
{
struct rc_pid_info * pinfo = priv ;
2008-09-18 20:14:18 +04:00
struct rc_pid_sta_info * spinfo = priv_sta ;
2007-12-20 15:27:26 +03:00
unsigned long period ;
2008-05-15 14:55:29 +04:00
struct ieee80211_tx_info * info = IEEE80211_SKB_CB ( skb ) ;
2007-12-19 03:25:57 +03:00
2008-09-18 20:14:18 +04:00
if ( ! spinfo )
return ;
2008-01-04 08:05:37 +03:00
2007-12-19 03:25:57 +03:00
/* Ignore all frames that were sent with a different rate than the rate
* we currently advise mac80211 to use . */
2008-10-21 14:40:02 +04:00
if ( info - > status . rates [ 0 ] . idx ! = spinfo - > txrate_idx )
2008-09-18 20:14:18 +04:00
return ;
2007-12-19 03:25:57 +03:00
spinfo - > tx_num_xmit + + ;
2007-12-19 03:27:18 +03:00
# ifdef CONFIG_MAC80211_DEBUGFS
2008-05-15 14:55:29 +04:00
rate_control_pid_event_tx_status ( & spinfo - > events , info ) ;
2007-12-19 03:27:18 +03:00
# endif
2007-12-19 03:25:57 +03:00
/* We count frames that totally failed to be transmitted as two bad
* frames , those that made it out but had some retries as one good and
* one bad frame . */
2008-10-21 14:40:02 +04:00
if ( ! ( info - > flags & IEEE80211_TX_STAT_ACK ) ) {
2007-12-19 03:25:57 +03:00
spinfo - > tx_num_failed + = 2 ;
spinfo - > tx_num_xmit + + ;
2008-11-17 02:09:25 +03:00
} else if ( info - > status . rates [ 0 ] . count > 1 ) {
2007-12-19 03:25:57 +03:00
spinfo - > tx_num_failed + + ;
spinfo - > tx_num_xmit + + ;
}
/* Update PID controller state. */
2007-12-20 15:27:26 +03:00
period = ( HZ * pinfo - > sampling_period + 500 ) / 1000 ;
if ( ! period )
period = 1 ;
if ( time_after ( jiffies , spinfo - > last_sample + period ) )
2008-09-18 20:14:18 +04:00
rate_control_pid_sample ( pinfo , sband , sta , spinfo ) ;
2007-12-19 03:25:57 +03:00
}
2008-09-18 20:14:18 +04:00
static void
2008-10-21 14:40:02 +04:00
rate_control_pid_get_rate ( void * priv , struct ieee80211_sta * sta ,
void * priv_sta ,
struct ieee80211_tx_rate_control * txrc )
2007-12-19 03:25:57 +03:00
{
2008-10-21 14:40:02 +04:00
struct sk_buff * skb = txrc - > skb ;
struct ieee80211_supported_band * sband = txrc - > sband ;
2007-12-19 03:25:57 +03:00
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) skb - > data ;
2008-10-21 14:40:02 +04:00
struct ieee80211_tx_info * info = IEEE80211_SKB_CB ( skb ) ;
2008-09-18 20:14:18 +04:00
struct rc_pid_sta_info * spinfo = priv_sta ;
2007-12-19 03:25:57 +03:00
int rateidx ;
2007-12-26 03:33:16 +03:00
u16 fc ;
2007-12-19 03:25:57 +03:00
2008-10-21 14:40:02 +04:00
if ( txrc - > rts )
info - > control . rates [ 0 ] . count =
txrc - > hw - > conf . long_frame_max_tx_count ;
else
info - > control . rates [ 0 ] . count =
txrc - > hw - > conf . short_frame_max_tx_count ;
2007-12-26 03:33:16 +03:00
/* Send management frames and broadcast/multicast data using lowest
* rate . */
fc = le16_to_cpu ( hdr - > frame_control ) ;
2008-09-18 20:14:18 +04:00
if ( ! sta | | ! spinfo | |
( fc & IEEE80211_FCTL_FTYPE ) ! = IEEE80211_FTYPE_DATA | |
is_multicast_ether_addr ( hdr - > addr1 ) ) {
2008-10-21 14:40:02 +04:00
info - > control . rates [ 0 ] . idx = rate_lowest_index ( sband , sta ) ;
2007-12-19 03:25:57 +03:00
return ;
}
2008-09-11 05:04:36 +04:00
rateidx = spinfo - > txrate_idx ;
2007-12-19 03:25:57 +03:00
2008-01-24 21:38:38 +03:00
if ( rateidx > = sband - > n_bitrates )
rateidx = sband - > n_bitrates - 1 ;
2007-12-19 03:25:57 +03:00
2008-10-21 14:40:02 +04:00
info - > control . rates [ 0 ] . idx = rateidx ;
2007-12-19 03:27:18 +03:00
# ifdef CONFIG_MAC80211_DEBUGFS
2008-09-18 20:14:18 +04:00
rate_control_pid_event_tx_rate ( & spinfo - > events ,
2008-01-24 21:38:38 +03:00
rateidx , sband - > bitrates [ rateidx ] . bitrate ) ;
2007-12-19 03:27:18 +03:00
# endif
2007-12-19 03:25:57 +03:00
}
2008-09-18 20:14:18 +04:00
static void
rate_control_pid_rate_init ( void * priv , struct ieee80211_supported_band * sband ,
struct ieee80211_sta * sta , void * priv_sta )
2007-12-19 03:25:57 +03:00
{
2008-09-18 20:14:18 +04:00
struct rc_pid_sta_info * spinfo = priv_sta ;
struct sta_info * si ;
2007-12-19 03:25:57 +03:00
/* TODO: This routine should consider using RSSI from previous packets
* as we need to have IEEE 802.1 X auth succeed immediately after assoc . .
* Until that method is implemented , we will use the lowest supported
* rate as a workaround . */
2008-01-24 21:38:38 +03:00
2008-09-18 20:14:18 +04:00
spinfo - > txrate_idx = rate_lowest_index ( sband , sta ) ;
/* HACK */
si = container_of ( sta , struct sta_info , sta ) ;
si - > fail_avg = 0 ;
2007-12-19 03:25:57 +03:00
}
2008-09-18 20:14:18 +04:00
static void * rate_control_pid_alloc ( struct ieee80211_hw * hw ,
struct dentry * debugfsdir )
2007-12-19 03:25:57 +03:00
{
struct rc_pid_info * pinfo ;
2007-12-19 03:26:34 +03:00
struct rc_pid_rateinfo * rinfo ;
2008-01-24 21:38:38 +03:00
struct ieee80211_supported_band * sband ;
2007-12-19 03:26:34 +03:00
int i , j , tmp ;
bool s ;
2007-12-20 15:27:26 +03:00
# ifdef CONFIG_MAC80211_DEBUGFS
struct rc_pid_debugfs_entries * de ;
# endif
2007-12-19 03:25:57 +03:00
2008-09-18 20:14:18 +04:00
sband = hw - > wiphy - > bands [ hw - > conf . channel - > band ] ;
2008-01-24 21:38:38 +03:00
2007-12-19 03:25:57 +03:00
pinfo = kmalloc ( sizeof ( * pinfo ) , GFP_ATOMIC ) ;
2007-12-19 03:26:34 +03:00
if ( ! pinfo )
return NULL ;
2008-01-24 21:38:38 +03:00
/* We can safely assume that sband won't change unless we get
2007-12-19 03:26:34 +03:00
* reinitialized . */
2008-01-24 21:38:38 +03:00
rinfo = kmalloc ( sizeof ( * rinfo ) * sband - > n_bitrates , GFP_ATOMIC ) ;
2007-12-19 03:26:34 +03:00
if ( ! rinfo ) {
kfree ( pinfo ) ;
return NULL ;
}
2008-07-08 01:08:19 +04:00
pinfo - > target = RC_PID_TARGET_PF ;
pinfo - > sampling_period = RC_PID_INTERVAL ;
pinfo - > coeff_p = RC_PID_COEFF_P ;
pinfo - > coeff_i = RC_PID_COEFF_I ;
pinfo - > coeff_d = RC_PID_COEFF_D ;
pinfo - > smoothing_shift = RC_PID_SMOOTHING_SHIFT ;
pinfo - > sharpen_factor = RC_PID_SHARPENING_FACTOR ;
pinfo - > sharpen_duration = RC_PID_SHARPENING_DURATION ;
pinfo - > norm_offset = RC_PID_NORM_OFFSET ;
pinfo - > rinfo = rinfo ;
pinfo - > oldrate = 0 ;
2007-12-19 03:26:34 +03:00
/* Sort the rates. This is optimized for the most common case (i.e.
* almost - sorted CCK + OFDM rates ) . Kind of bubble - sort with reversed
* mapping too . */
2008-01-24 21:38:38 +03:00
for ( i = 0 ; i < sband - > n_bitrates ; i + + ) {
2007-12-19 03:26:34 +03:00
rinfo [ i ] . index = i ;
rinfo [ i ] . rev_index = i ;
2008-07-08 01:08:19 +04:00
if ( RC_PID_FAST_START )
2007-12-19 03:26:34 +03:00
rinfo [ i ] . diff = 0 ;
else
2007-12-20 15:27:26 +03:00
rinfo [ i ] . diff = i * pinfo - > norm_offset ;
2007-12-19 03:26:34 +03:00
}
2008-01-24 21:38:38 +03:00
for ( i = 1 ; i < sband - > n_bitrates ; i + + ) {
2007-12-19 03:26:34 +03:00
s = 0 ;
2008-01-24 21:38:38 +03:00
for ( j = 0 ; j < sband - > n_bitrates - i ; j + + )
if ( unlikely ( sband - > bitrates [ rinfo [ j ] . index ] . bitrate >
sband - > bitrates [ rinfo [ j + 1 ] . index ] . bitrate ) ) {
2007-12-19 03:26:34 +03:00
tmp = rinfo [ j ] . index ;
rinfo [ j ] . index = rinfo [ j + 1 ] . index ;
rinfo [ j + 1 ] . index = tmp ;
rinfo [ rinfo [ j ] . index ] . rev_index = j ;
rinfo [ rinfo [ j + 1 ] . index ] . rev_index = j + 1 ;
s = 1 ;
}
if ( ! s )
break ;
}
2007-12-19 03:25:57 +03:00
2007-12-20 15:27:26 +03:00
# ifdef CONFIG_MAC80211_DEBUGFS
de = & pinfo - > dentries ;
de - > target = debugfs_create_u32 ( " target_pf " , S_IRUSR | S_IWUSR ,
2008-09-18 20:14:18 +04:00
debugfsdir , & pinfo - > target ) ;
2007-12-20 15:27:26 +03:00
de - > sampling_period = debugfs_create_u32 ( " sampling_period " ,
2008-09-18 20:14:18 +04:00
S_IRUSR | S_IWUSR , debugfsdir ,
2007-12-20 15:27:26 +03:00
& pinfo - > sampling_period ) ;
de - > coeff_p = debugfs_create_u32 ( " coeff_p " , S_IRUSR | S_IWUSR ,
2008-11-09 00:50:55 +03:00
debugfsdir , ( u32 * ) & pinfo - > coeff_p ) ;
2007-12-20 15:27:26 +03:00
de - > coeff_i = debugfs_create_u32 ( " coeff_i " , S_IRUSR | S_IWUSR ,
2008-11-09 00:50:55 +03:00
debugfsdir , ( u32 * ) & pinfo - > coeff_i ) ;
2007-12-20 15:27:26 +03:00
de - > coeff_d = debugfs_create_u32 ( " coeff_d " , S_IRUSR | S_IWUSR ,
2008-11-09 00:50:55 +03:00
debugfsdir , ( u32 * ) & pinfo - > coeff_d ) ;
2007-12-20 15:27:26 +03:00
de - > smoothing_shift = debugfs_create_u32 ( " smoothing_shift " ,
2008-09-18 20:14:18 +04:00
S_IRUSR | S_IWUSR , debugfsdir ,
2007-12-20 15:27:26 +03:00
& pinfo - > smoothing_shift ) ;
de - > sharpen_factor = debugfs_create_u32 ( " sharpen_factor " ,
2008-09-18 20:14:18 +04:00
S_IRUSR | S_IWUSR , debugfsdir ,
2007-12-20 15:27:26 +03:00
& pinfo - > sharpen_factor ) ;
de - > sharpen_duration = debugfs_create_u32 ( " sharpen_duration " ,
2008-09-18 20:14:18 +04:00
S_IRUSR | S_IWUSR , debugfsdir ,
2007-12-20 15:27:26 +03:00
& pinfo - > sharpen_duration ) ;
de - > norm_offset = debugfs_create_u32 ( " norm_offset " ,
2008-09-18 20:14:18 +04:00
S_IRUSR | S_IWUSR , debugfsdir ,
2007-12-20 15:27:26 +03:00
& pinfo - > norm_offset ) ;
# endif
2007-12-19 03:25:57 +03:00
return pinfo ;
}
static void rate_control_pid_free ( void * priv )
{
struct rc_pid_info * pinfo = priv ;
2007-12-20 15:27:26 +03:00
# ifdef CONFIG_MAC80211_DEBUGFS
struct rc_pid_debugfs_entries * de = & pinfo - > dentries ;
debugfs_remove ( de - > norm_offset ) ;
debugfs_remove ( de - > sharpen_duration ) ;
debugfs_remove ( de - > sharpen_factor ) ;
debugfs_remove ( de - > smoothing_shift ) ;
debugfs_remove ( de - > coeff_d ) ;
debugfs_remove ( de - > coeff_i ) ;
debugfs_remove ( de - > coeff_p ) ;
debugfs_remove ( de - > sampling_period ) ;
debugfs_remove ( de - > target ) ;
# endif
2007-12-19 03:26:34 +03:00
kfree ( pinfo - > rinfo ) ;
2007-12-19 03:25:57 +03:00
kfree ( pinfo ) ;
}
2008-09-18 20:14:18 +04:00
static void * rate_control_pid_alloc_sta ( void * priv , struct ieee80211_sta * sta ,
gfp_t gfp )
2007-12-19 03:25:57 +03:00
{
struct rc_pid_sta_info * spinfo ;
spinfo = kzalloc ( sizeof ( * spinfo ) , gfp ) ;
2007-12-19 03:27:18 +03:00
if ( spinfo = = NULL )
return NULL ;
2008-01-17 02:38:29 +03:00
spinfo - > last_sample = jiffies ;
2007-12-19 03:27:18 +03:00
# ifdef CONFIG_MAC80211_DEBUGFS
spin_lock_init ( & spinfo - > events . lock ) ;
init_waitqueue_head ( & spinfo - > events . waitqueue ) ;
# endif
2007-12-19 03:25:57 +03:00
return spinfo ;
}
2008-09-18 20:14:18 +04:00
static void rate_control_pid_free_sta ( void * priv , struct ieee80211_sta * sta ,
void * priv_sta )
2007-12-19 03:25:57 +03:00
{
2008-09-18 20:14:18 +04:00
kfree ( priv_sta ) ;
2007-12-19 03:25:57 +03:00
}
2008-01-02 17:17:03 +03:00
static struct rate_control_ops mac80211_rcpid = {
2007-12-19 03:25:57 +03:00
. name = " pid " ,
. tx_status = rate_control_pid_tx_status ,
. get_rate = rate_control_pid_get_rate ,
. rate_init = rate_control_pid_rate_init ,
. alloc = rate_control_pid_alloc ,
. free = rate_control_pid_free ,
. alloc_sta = rate_control_pid_alloc_sta ,
. free_sta = rate_control_pid_free_sta ,
2007-12-19 03:27:18 +03:00
# ifdef CONFIG_MAC80211_DEBUGFS
. add_sta_debugfs = rate_control_pid_add_sta_debugfs ,
. remove_sta_debugfs = rate_control_pid_remove_sta_debugfs ,
# endif
2007-12-19 03:25:57 +03:00
} ;
2008-01-02 17:17:03 +03:00
int __init rc80211_pid_init ( void )
{
return ieee80211_rate_control_register ( & mac80211_rcpid ) ;
}
2008-01-31 21:31:57 +03:00
void rc80211_pid_exit ( void )
2008-01-02 17:17:03 +03:00
{
ieee80211_rate_control_unregister ( & mac80211_rcpid ) ;
}