2007-09-25 17:54:57 -07:00
/******************************************************************************
*
2009-01-08 10:20:02 -08:00
* Copyright ( c ) 2005 - 2009 Intel Corporation . All rights reserved .
2007-09-25 17:54:57 -07:00
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation .
*
* 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 ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 , USA
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE .
*
* Contact Information :
2008-12-09 11:28:58 -08:00
* Intel Linux Wireless < ilw @ linux . intel . com >
2007-09-25 17:54:57 -07:00
* Intel Corporation , 5200 N . E . Elam Young Parkway , Hillsboro , OR 97124 - 6497
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/skbuff.h>
# include <linux/wireless.h>
# include <net/mac80211.h>
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/delay.h>
# include <linux/workqueue.h>
2008-12-19 10:37:04 +08:00
# include "iwl-commands.h"
2007-10-25 17:15:50 +08:00
# include "iwl-3945.h"
2009-06-03 11:44:07 -07:00
# include "iwl-sta.h"
2007-09-25 17:54:57 -07:00
# define RS_NAME "iwl-3945-rs"
2008-01-27 16:41:47 -08:00
struct iwl3945_rate_scale_data {
2007-09-25 17:54:57 -07:00
u64 data ;
s32 success_counter ;
s32 success_ratio ;
s32 counter ;
s32 average_tpt ;
unsigned long stamp ;
} ;
2008-01-27 20:41:38 -08:00
struct iwl3945_rs_sta {
2007-09-25 17:54:57 -07:00
spinlock_t lock ;
2008-12-19 10:37:28 +08:00
struct iwl_priv * priv ;
2007-09-25 17:54:57 -07:00
s32 * expected_tpt ;
unsigned long last_partial_flush ;
unsigned long last_flush ;
u32 flush_time ;
u32 last_tx_packets ;
u32 tx_packets ;
u8 tgg ;
u8 flush_pending ;
u8 start_rate ;
u8 ibss_sta_added ;
struct timer_list rate_scale_flush ;
2008-12-19 10:37:12 +08:00
struct iwl3945_rate_scale_data win [ IWL_RATE_COUNT_3945 ] ;
2008-12-02 12:14:02 -08:00
# ifdef CONFIG_MAC80211_DEBUGFS
struct dentry * rs_sta_dbgfs_stats_table_file ;
# endif
2008-09-11 02:22:58 +02:00
/* used to be in sta_info */
int last_txrate_idx ;
2007-09-25 17:54:57 -07:00
} ;
2008-12-19 10:37:12 +08:00
static s32 iwl3945_expected_tpt_g [ IWL_RATE_COUNT_3945 ] = {
2007-11-12 11:37:42 +08:00
7 , 13 , 35 , 58 , 0 , 0 , 76 , 104 , 130 , 168 , 191 , 202
2007-09-25 17:54:57 -07:00
} ;
2008-12-19 10:37:12 +08:00
static s32 iwl3945_expected_tpt_g_prot [ IWL_RATE_COUNT_3945 ] = {
2007-11-12 11:37:42 +08:00
7 , 13 , 35 , 58 , 0 , 0 , 0 , 80 , 93 , 113 , 123 , 125
2007-09-25 17:54:57 -07:00
} ;
2008-12-19 10:37:12 +08:00
static s32 iwl3945_expected_tpt_a [ IWL_RATE_COUNT_3945 ] = {
2007-11-12 11:37:42 +08:00
0 , 0 , 0 , 0 , 40 , 57 , 72 , 98 , 121 , 154 , 177 , 186
2007-09-25 17:54:57 -07:00
} ;
2008-12-19 10:37:12 +08:00
static s32 iwl3945_expected_tpt_b [ IWL_RATE_COUNT_3945 ] = {
2007-11-12 11:37:42 +08:00
7 , 13 , 35 , 58 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
2007-09-25 17:54:57 -07:00
} ;
2008-01-27 16:41:47 -08:00
struct iwl3945_tpt_entry {
2007-09-25 17:54:57 -07:00
s8 min_rssi ;
u8 index ;
} ;
2008-01-27 16:41:47 -08:00
static struct iwl3945_tpt_entry iwl3945_tpt_table_a [ ] = {
2007-09-25 17:54:57 -07:00
{ - 60 , IWL_RATE_54M_INDEX } ,
{ - 64 , IWL_RATE_48M_INDEX } ,
{ - 72 , IWL_RATE_36M_INDEX } ,
{ - 80 , IWL_RATE_24M_INDEX } ,
{ - 84 , IWL_RATE_18M_INDEX } ,
{ - 85 , IWL_RATE_12M_INDEX } ,
{ - 87 , IWL_RATE_9M_INDEX } ,
{ - 89 , IWL_RATE_6M_INDEX }
} ;
2008-01-27 16:41:47 -08:00
static struct iwl3945_tpt_entry iwl3945_tpt_table_g [ ] = {
2007-09-25 17:54:57 -07:00
{ - 60 , IWL_RATE_54M_INDEX } ,
{ - 64 , IWL_RATE_48M_INDEX } ,
{ - 68 , IWL_RATE_36M_INDEX } ,
{ - 80 , IWL_RATE_24M_INDEX } ,
{ - 84 , IWL_RATE_18M_INDEX } ,
{ - 85 , IWL_RATE_12M_INDEX } ,
{ - 86 , IWL_RATE_11M_INDEX } ,
{ - 88 , IWL_RATE_5M_INDEX } ,
{ - 90 , IWL_RATE_2M_INDEX } ,
{ - 92 , IWL_RATE_1M_INDEX }
} ;
# define IWL_RATE_MAX_WINDOW 62
2008-12-02 12:14:03 -08:00
# define IWL_RATE_FLUSH (3*HZ)
2007-09-25 17:54:57 -07:00
# define IWL_RATE_WIN_FLUSH (HZ / 2)
2008-12-19 10:37:12 +08:00
# define IWL39_RATE_HIGH_TH 11520
2008-12-02 12:14:03 -08:00
# define IWL_SUCCESS_UP_TH 8960
# define IWL_SUCCESS_DOWN_TH 10880
2009-03-17 21:51:51 -07:00
# define IWL_RATE_MIN_FAILURE_TH 6
2007-09-25 17:54:57 -07:00
# define IWL_RATE_MIN_SUCCESS_TH 8
# define IWL_RATE_DECREASE_TH 1920
2009-03-11 11:17:56 -07:00
# define IWL_RATE_RETRY_TH 15
2007-09-25 17:54:57 -07:00
2008-01-24 19:38:38 +01:00
static u8 iwl3945_get_rate_index_by_rssi ( s32 rssi , enum ieee80211_band band )
2007-09-25 17:54:57 -07:00
{
u32 index = 0 ;
u32 table_size = 0 ;
2008-01-27 16:41:47 -08:00
struct iwl3945_tpt_entry * tpt_table = NULL ;
2007-09-25 17:54:57 -07:00
if ( ( rssi < IWL_MIN_RSSI_VAL ) | | ( rssi > IWL_MAX_RSSI_VAL ) )
rssi = IWL_MIN_RSSI_VAL ;
2008-01-24 19:38:38 +01:00
switch ( band ) {
case IEEE80211_BAND_2GHZ :
2008-01-27 16:41:47 -08:00
tpt_table = iwl3945_tpt_table_g ;
table_size = ARRAY_SIZE ( iwl3945_tpt_table_g ) ;
2007-09-25 17:54:57 -07:00
break ;
2008-01-24 19:38:38 +01:00
case IEEE80211_BAND_5GHZ :
2008-01-27 16:41:47 -08:00
tpt_table = iwl3945_tpt_table_a ;
table_size = ARRAY_SIZE ( iwl3945_tpt_table_a ) ;
2007-09-25 17:54:57 -07:00
break ;
default :
2008-01-24 19:38:38 +01:00
BUG ( ) ;
2007-09-25 17:54:57 -07:00
break ;
}
while ( ( index < table_size ) & & ( rssi < tpt_table [ index ] . min_rssi ) )
index + + ;
index = min ( index , ( table_size - 1 ) ) ;
return tpt_table [ index ] . index ;
}
2008-01-27 16:41:47 -08:00
static void iwl3945_clear_window ( struct iwl3945_rate_scale_data * window )
2007-09-25 17:54:57 -07:00
{
window - > data = 0 ;
window - > success_counter = 0 ;
2008-03-06 17:36:54 -08:00
window - > success_ratio = - 1 ;
2007-09-25 17:54:57 -07:00
window - > counter = 0 ;
2008-12-19 10:37:12 +08:00
window - > average_tpt = IWL_INVALID_VALUE ;
2007-09-25 17:54:57 -07:00
window - > stamp = 0 ;
}
/**
2008-01-27 16:41:47 -08:00
* iwl3945_rate_scale_flush_windows - flush out the rate scale windows
2007-09-25 17:54:57 -07:00
*
* Returns the number of windows that have gathered data but were
* not flushed . If there were any that were not flushed , then
* reschedule the rate flushing routine .
*/
2008-01-27 20:41:38 -08:00
static int iwl3945_rate_scale_flush_windows ( struct iwl3945_rs_sta * rs_sta )
2007-09-25 17:54:57 -07:00
{
int unflushed = 0 ;
int i ;
unsigned long flags ;
2009-01-27 14:27:53 -08:00
struct iwl_priv * priv __maybe_unused = rs_sta - > priv ;
2007-09-25 17:54:57 -07:00
/*
* For each rate , if we have collected data on that rate
* and it has been more than IWL_RATE_WIN_FLUSH
* since we flushed , clear out the gathered statistics
*/
2008-12-19 10:37:12 +08:00
for ( i = 0 ; i < IWL_RATE_COUNT_3945 ; i + + ) {
2008-01-27 20:41:38 -08:00
if ( ! rs_sta - > win [ i ] . counter )
2007-09-25 17:54:57 -07:00
continue ;
2008-01-27 20:41:38 -08:00
spin_lock_irqsave ( & rs_sta - > lock , flags ) ;
if ( time_after ( jiffies , rs_sta - > win [ i ] . stamp +
2007-09-25 17:54:57 -07:00
IWL_RATE_WIN_FLUSH ) ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " flushing %d samples of rate "
2007-09-25 17:54:57 -07:00
" index %d \n " ,
2008-01-27 20:41:38 -08:00
rs_sta - > win [ i ] . counter , i ) ;
iwl3945_clear_window ( & rs_sta - > win [ i ] ) ;
2007-09-25 17:54:57 -07:00
} else
unflushed + + ;
2008-01-27 20:41:38 -08:00
spin_unlock_irqrestore ( & rs_sta - > lock , flags ) ;
2007-09-25 17:54:57 -07:00
}
return unflushed ;
}
# define IWL_RATE_FLUSH_MAX 5000 /* msec */
# define IWL_RATE_FLUSH_MIN 50 /* msec */
2008-12-02 12:14:03 -08:00
# define IWL_AVERAGE_PACKETS 1500
2007-09-25 17:54:57 -07:00
2008-01-27 16:41:47 -08:00
static void iwl3945_bg_rate_scale_flush ( unsigned long data )
2007-09-25 17:54:57 -07:00
{
2008-01-27 20:41:38 -08:00
struct iwl3945_rs_sta * rs_sta = ( void * ) data ;
2009-01-27 14:27:53 -08:00
struct iwl_priv * priv __maybe_unused = rs_sta - > priv ;
2007-09-25 17:54:57 -07:00
int unflushed = 0 ;
unsigned long flags ;
u32 packet_count , duration , pps ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " enter \n " ) ;
2007-09-25 17:54:57 -07:00
2008-01-27 20:41:38 -08:00
unflushed = iwl3945_rate_scale_flush_windows ( rs_sta ) ;
2007-09-25 17:54:57 -07:00
2008-01-27 20:41:38 -08:00
spin_lock_irqsave ( & rs_sta - > lock , flags ) ;
2007-09-25 17:54:57 -07:00
/* Number of packets Rx'd since last time this timer ran */
2008-01-27 20:41:38 -08:00
packet_count = ( rs_sta - > tx_packets - rs_sta - > last_tx_packets ) + 1 ;
2007-09-25 17:54:57 -07:00
2008-01-27 20:41:38 -08:00
rs_sta - > last_tx_packets = rs_sta - > tx_packets + 1 ;
2007-09-25 17:54:57 -07:00
if ( unflushed ) {
duration =
2008-01-27 20:41:38 -08:00
jiffies_to_msecs ( jiffies - rs_sta - > last_partial_flush ) ;
2007-09-25 17:54:57 -07:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " Tx'd %d packets in %dms \n " ,
2007-09-25 17:54:57 -07:00
packet_count , duration ) ;
/* Determine packets per second */
if ( duration )
pps = ( packet_count * 1000 ) / duration ;
else
pps = 0 ;
if ( pps ) {
2008-12-02 12:14:03 -08:00
duration = ( IWL_AVERAGE_PACKETS * 1000 ) / pps ;
2007-09-25 17:54:57 -07:00
if ( duration < IWL_RATE_FLUSH_MIN )
duration = IWL_RATE_FLUSH_MIN ;
2008-12-02 12:14:03 -08:00
else if ( duration > IWL_RATE_FLUSH_MAX )
duration = IWL_RATE_FLUSH_MAX ;
2007-09-25 17:54:57 -07:00
} else
duration = IWL_RATE_FLUSH_MAX ;
2008-01-27 20:41:38 -08:00
rs_sta - > flush_time = msecs_to_jiffies ( duration ) ;
2007-09-25 17:54:57 -07:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " new flush period: %d msec ave %d \n " ,
2007-09-25 17:54:57 -07:00
duration , packet_count ) ;
2008-01-27 20:41:38 -08:00
mod_timer ( & rs_sta - > rate_scale_flush , jiffies +
rs_sta - > flush_time ) ;
2007-09-25 17:54:57 -07:00
2008-01-27 20:41:38 -08:00
rs_sta - > last_partial_flush = jiffies ;
2008-12-02 12:14:03 -08:00
} else {
rs_sta - > flush_time = IWL_RATE_FLUSH ;
rs_sta - > flush_pending = 0 ;
2007-09-25 17:54:57 -07:00
}
/* If there weren't any unflushed entries, we don't schedule the timer
* to run again */
2008-01-27 20:41:38 -08:00
rs_sta - > last_flush = jiffies ;
2007-09-25 17:54:57 -07:00
2008-01-27 20:41:38 -08:00
spin_unlock_irqrestore ( & rs_sta - > lock , flags ) ;
2007-09-25 17:54:57 -07:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " leave \n " ) ;
2007-09-25 17:54:57 -07:00
}
/**
2008-01-27 16:41:47 -08:00
* iwl3945_collect_tx_data - Update the success / failure sliding window
2007-09-25 17:54:57 -07:00
*
* We keep a sliding window of the last 64 packets transmitted
* at this rate . window - > data contains the bitmask of successful
* packets .
*/
2008-01-27 20:41:38 -08:00
static void iwl3945_collect_tx_data ( struct iwl3945_rs_sta * rs_sta ,
2008-01-27 16:41:47 -08:00
struct iwl3945_rate_scale_data * window ,
2008-12-02 12:14:03 -08:00
int success , int retries , int index )
2007-09-25 17:54:57 -07:00
{
unsigned long flags ;
2008-12-02 12:14:03 -08:00
s32 fail_count ;
2009-01-27 14:27:53 -08:00
struct iwl_priv * priv __maybe_unused = rs_sta - > priv ;
2007-09-25 17:54:57 -07:00
if ( ! retries ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " leave: retries == 0 -- should be at least 1 \n " ) ;
2007-09-25 17:54:57 -07:00
return ;
}
2008-12-02 12:14:03 -08:00
spin_lock_irqsave ( & rs_sta - > lock , flags ) ;
2007-09-25 17:54:57 -07:00
2009-03-11 11:17:56 -07:00
/*
* Keep track of only the latest 62 tx frame attempts in this rate ' s
* history window ; anything older isn ' t really relevant any more .
* If we have filled up the sliding window , drop the oldest attempt ;
* if the oldest attempt ( highest bit in bitmap ) shows " success " ,
* subtract " 1 " from the success counter ( this is the main reason
* we keep these bitmaps ! ) .
* */
while ( retries > 0 ) {
if ( window - > counter > = IWL_RATE_MAX_WINDOW ) {
/* remove earliest */
window - > counter = IWL_RATE_MAX_WINDOW - 1 ;
if ( window - > data & ( 1ULL < < ( IWL_RATE_MAX_WINDOW - 1 ) ) ) {
window - > data & = ~ ( 1ULL < < ( IWL_RATE_MAX_WINDOW - 1 ) ) ;
2007-09-25 17:54:57 -07:00
window - > success_counter - - ;
2009-03-11 11:17:56 -07:00
}
}
2007-09-25 17:54:57 -07:00
2009-03-11 11:17:56 -07:00
/* Increment frames-attempted counter */
window - > counter + + ;
2007-09-25 17:54:57 -07:00
2009-03-11 11:17:56 -07:00
/* Shift bitmap by one frame (throw away oldest history),
* OR in " 1 " , and increment " success " if this
* frame was successful . */
window - > data < < = 1 ;
if ( success > 0 ) {
2007-09-25 17:54:57 -07:00
window - > success_counter + + ;
2009-03-11 11:17:56 -07:00
window - > data | = 0x1 ;
success - - ;
2007-09-25 17:54:57 -07:00
}
2009-03-11 11:17:56 -07:00
retries - - ;
2007-09-25 17:54:57 -07:00
}
2008-12-02 12:14:03 -08:00
2009-03-11 11:17:56 -07:00
/* Calculate current success ratio, avoid divide-by-0! */
if ( window - > counter > 0 )
window - > success_ratio = 128 * ( 100 * window - > success_counter )
/ window - > counter ;
else
window - > success_ratio = IWL_INVALID_VALUE ;
2008-12-02 12:14:03 -08:00
fail_count = window - > counter - window - > success_counter ;
2009-03-11 11:17:56 -07:00
/* Calculate average throughput, if we have enough history. */
2008-12-02 12:14:03 -08:00
if ( ( fail_count > = IWL_RATE_MIN_FAILURE_TH ) | |
( window - > success_counter > = IWL_RATE_MIN_SUCCESS_TH ) )
window - > average_tpt = ( ( window - > success_ratio *
rs_sta - > expected_tpt [ index ] + 64 ) / 128 ) ;
else
2008-12-19 10:37:12 +08:00
window - > average_tpt = IWL_INVALID_VALUE ;
2008-12-02 12:14:03 -08:00
2009-03-11 11:17:56 -07:00
/* Tag this window as having been updated */
window - > stamp = jiffies ;
2008-12-02 12:14:03 -08:00
spin_unlock_irqrestore ( & rs_sta - > lock , flags ) ;
2007-09-25 17:54:57 -07:00
}
2008-12-05 07:58:37 -08:00
static void rs_rate_init ( void * priv_r , struct ieee80211_supported_band * sband ,
2008-09-18 18:14:18 +02:00
struct ieee80211_sta * sta , void * priv_sta )
2007-09-25 17:54:57 -07:00
{
2008-09-18 18:14:18 +02:00
struct iwl3945_rs_sta * rs_sta = priv_sta ;
2008-12-19 10:37:28 +08:00
struct iwl_priv * priv = ( struct iwl_priv * ) priv_r ;
2007-09-25 17:54:57 -07:00
int i ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " enter \n " ) ;
2007-09-25 17:54:57 -07:00
/* TODO: what is a good starting rate for STA? About middle? Maybe not
* the lowest or the highest rate . . Could consider using RSSI from
* previous packets ? Need to have IEEE 802.1 X auth succeed immediately
* after assoc . . */
2008-12-05 07:58:37 -08:00
for ( i = sband - > n_bitrates - 1 ; i > = 0 ; i - - ) {
2008-09-18 18:14:18 +02:00
if ( sta - > supp_rates [ sband - > band ] & ( 1 < < i ) ) {
2008-09-11 03:04:36 +02:00
rs_sta - > last_txrate_idx = i ;
2007-09-25 17:54:57 -07:00
break ;
}
}
2008-12-05 07:58:37 -08:00
priv - > sta_supp_rates = sta - > supp_rates [ sband - > band ] ;
2008-01-24 19:38:38 +01:00
/* For 5 GHz band it start at IWL_FIRST_OFDM_RATE */
2008-12-05 07:58:37 -08:00
if ( sband - > band = = IEEE80211_BAND_5GHZ ) {
2008-09-11 02:22:58 +02:00
rs_sta - > last_txrate_idx + = IWL_FIRST_OFDM_RATE ;
2008-12-05 07:58:37 -08:00
priv - > sta_supp_rates = priv - > sta_supp_rates < <
IWL_FIRST_OFDM_RATE ;
}
2007-11-12 11:37:42 +08:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " leave \n " ) ;
2007-09-25 17:54:57 -07:00
}
2008-09-18 18:14:18 +02:00
static void * rs_alloc ( struct ieee80211_hw * hw , struct dentry * debugfsdir )
2007-09-25 17:54:57 -07:00
{
2008-09-18 18:14:18 +02:00
return hw - > priv ;
2007-09-25 17:54:57 -07:00
}
2007-10-25 17:15:22 +08:00
/* rate scale requires free function to be implemented */
2007-09-25 17:54:57 -07:00
static void rs_free ( void * priv )
{
return ;
}
2008-09-18 18:14:18 +02:00
2008-12-19 10:37:08 +08:00
static void * rs_alloc_sta ( void * iwl_priv , struct ieee80211_sta * sta , gfp_t gfp )
2007-09-25 17:54:57 -07:00
{
2008-01-27 20:41:38 -08:00
struct iwl3945_rs_sta * rs_sta ;
2008-09-18 18:14:18 +02:00
struct iwl3945_sta_priv * psta = ( void * ) sta - > drv_priv ;
2008-12-19 10:37:28 +08:00
struct iwl_priv * priv = iwl_priv ;
2007-09-25 17:54:57 -07:00
int i ;
2008-09-18 18:14:18 +02:00
/*
* XXX : If it ' s using sta - > drv_priv anyway , it might
* as well just put all the information there .
*/
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " enter \n " ) ;
2007-09-25 17:54:57 -07:00
2008-01-27 20:41:38 -08:00
rs_sta = kzalloc ( sizeof ( struct iwl3945_rs_sta ) , gfp ) ;
if ( ! rs_sta ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " leave: ENOMEM \n " ) ;
2007-09-25 17:54:57 -07:00
return NULL ;
}
2008-09-18 18:14:18 +02:00
psta - > rs_sta = rs_sta ;
2008-01-27 20:41:38 -08:00
spin_lock_init ( & rs_sta - > lock ) ;
2007-09-25 17:54:57 -07:00
2008-12-19 10:37:08 +08:00
rs_sta - > priv = priv ;
2008-01-27 20:41:38 -08:00
rs_sta - > start_rate = IWL_RATE_INVALID ;
2007-09-25 17:54:57 -07:00
/* default to just 802.11b */
2008-01-27 20:41:38 -08:00
rs_sta - > expected_tpt = iwl3945_expected_tpt_b ;
2007-09-25 17:54:57 -07:00
2008-01-27 20:41:38 -08:00
rs_sta - > last_partial_flush = jiffies ;
rs_sta - > last_flush = jiffies ;
rs_sta - > flush_time = IWL_RATE_FLUSH ;
rs_sta - > last_tx_packets = 0 ;
rs_sta - > ibss_sta_added = 0 ;
2007-09-25 17:54:57 -07:00
2008-01-27 20:41:38 -08:00
init_timer ( & rs_sta - > rate_scale_flush ) ;
rs_sta - > rate_scale_flush . data = ( unsigned long ) rs_sta ;
rs_sta - > rate_scale_flush . function = & iwl3945_bg_rate_scale_flush ;
2007-09-25 17:54:57 -07:00
2008-12-19 10:37:12 +08:00
for ( i = 0 ; i < IWL_RATE_COUNT_3945 ; i + + )
2008-01-27 20:41:38 -08:00
iwl3945_clear_window ( & rs_sta - > win [ i ] ) ;
2007-09-25 17:54:57 -07:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " leave \n " ) ;
2007-09-25 17:54:57 -07:00
2008-01-27 20:41:38 -08:00
return rs_sta ;
2007-09-25 17:54:57 -07:00
}
2008-12-19 10:37:08 +08:00
static void rs_free_sta ( void * iwl_priv , struct ieee80211_sta * sta ,
2008-09-18 18:14:18 +02:00
void * priv_sta )
2007-09-25 17:54:57 -07:00
{
2008-09-18 18:14:18 +02:00
struct iwl3945_sta_priv * psta = ( void * ) sta - > drv_priv ;
2008-01-27 20:41:38 -08:00
struct iwl3945_rs_sta * rs_sta = priv_sta ;
2009-01-27 14:27:53 -08:00
struct iwl_priv * priv __maybe_unused = rs_sta - > priv ;
2007-09-25 17:54:57 -07:00
2008-09-18 18:14:18 +02:00
psta - > rs_sta = NULL ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " enter \n " ) ;
2008-01-27 20:41:38 -08:00
del_timer_sync ( & rs_sta - > rate_scale_flush ) ;
kfree ( rs_sta ) ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " leave \n " ) ;
2007-09-25 17:54:57 -07:00
}
2007-11-12 11:37:42 +08:00
2007-09-25 17:54:57 -07:00
/**
* rs_tx_status - Update rate control values based on Tx results
*
2008-12-19 10:37:28 +08:00
* NOTE : Uses iwl_priv - > retry_rate for the # of retries attempted by
2007-09-25 17:54:57 -07:00
* the hardware for each rate .
*/
2008-09-18 18:14:18 +02:00
static void rs_tx_status ( void * priv_rate , struct ieee80211_supported_band * sband ,
struct ieee80211_sta * sta , void * priv_sta ,
2008-05-15 12:55:29 +02:00
struct sk_buff * skb )
2007-09-25 17:54:57 -07:00
{
2008-12-02 12:14:03 -08:00
s8 retries = 0 , current_count ;
2007-09-25 17:54:57 -07:00
int scale_rate_index , first_index , last_index ;
unsigned long flags ;
2008-12-19 10:37:28 +08:00
struct iwl_priv * priv = ( struct iwl_priv * ) priv_rate ;
2008-09-18 18:14:18 +02:00
struct iwl3945_rs_sta * rs_sta = priv_sta ;
2008-05-15 12:55:29 +02:00
struct ieee80211_tx_info * info = IEEE80211_SKB_CB ( skb ) ;
2008-01-24 19:38:38 +01:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " enter \n " ) ;
2008-03-06 17:36:54 -08:00
2009-03-17 21:51:51 -07:00
retries = info - > status . rates [ 0 ] . count ;
2009-03-11 11:17:56 -07:00
/* Sanity Check for retries */
if ( retries > IWL_RATE_RETRY_TH )
retries = IWL_RATE_RETRY_TH ;
2008-10-21 12:40:02 +02:00
first_index = sband - > bitrates [ info - > status . rates [ 0 ] . idx ] . hw_value ;
2008-12-19 10:37:12 +08:00
if ( ( first_index < 0 ) | | ( first_index > = IWL_RATE_COUNT_3945 ) ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " leave: Rate out of bounds: %d \n " , first_index ) ;
2007-09-25 17:54:57 -07:00
return ;
}
2008-09-18 18:14:18 +02:00
if ( ! priv_sta ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " leave: No STA priv data to update! \n " ) ;
2007-09-25 17:54:57 -07:00
return ;
}
2008-01-27 20:41:38 -08:00
rs_sta - > tx_packets + + ;
2007-09-25 17:54:57 -07:00
scale_rate_index = first_index ;
last_index = first_index ;
/*
* Update the window for each rate . We determine which rates
* were Tx ' d based on the total number of retries vs . the number
* of retries configured for each rate - - currently set to the
* priv value ' retry_rate ' vs . rate specific
*
* On exit from this while loop last_index indicates the rate
* at which the frame was finally transmitted ( or failed if no
* ACK )
*/
2008-12-02 12:14:03 -08:00
while ( retries > 1 ) {
if ( ( retries - 1 ) < priv - > retry_rate ) {
current_count = ( retries - 1 ) ;
2007-09-25 17:54:57 -07:00
last_index = scale_rate_index ;
} else {
current_count = priv - > retry_rate ;
2008-10-21 12:40:02 +02:00
last_index = iwl3945_rs_next_rate ( priv ,
2007-11-12 11:37:42 +08:00
scale_rate_index ) ;
2007-09-25 17:54:57 -07:00
}
/* Update this rate accounting for as many retries
* as was used for it ( per current_count ) */
2008-01-27 20:41:38 -08:00
iwl3945_collect_tx_data ( rs_sta ,
& rs_sta - > win [ scale_rate_index ] ,
2008-12-02 12:14:03 -08:00
0 , current_count , scale_rate_index ) ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " Update rate %d for %d retries. \n " ,
2007-09-25 17:54:57 -07:00
scale_rate_index , current_count ) ;
retries - = current_count ;
2008-12-02 12:14:03 -08:00
scale_rate_index = last_index ;
2007-09-25 17:54:57 -07:00
}
2007-11-12 11:37:42 +08:00
2007-09-25 17:54:57 -07:00
/* Update the last index window with success/failure based on ACK */
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " Update rate %d with %s. \n " ,
2007-09-25 17:54:57 -07:00
last_index ,
2008-05-15 12:55:29 +02:00
( info - > flags & IEEE80211_TX_STAT_ACK ) ?
2007-09-25 17:54:57 -07:00
" success " : " failure " ) ;
2008-01-27 20:41:38 -08:00
iwl3945_collect_tx_data ( rs_sta ,
& rs_sta - > win [ last_index ] ,
2008-12-02 12:14:03 -08:00
info - > flags & IEEE80211_TX_STAT_ACK , 1 , last_index ) ;
2007-09-25 17:54:57 -07:00
/* We updated the rate scale window -- if its been more than
* flush_time since the last run , schedule the flush
* again */
2008-01-27 20:41:38 -08:00
spin_lock_irqsave ( & rs_sta - > lock , flags ) ;
2007-09-25 17:54:57 -07:00
2008-01-27 20:41:38 -08:00
if ( ! rs_sta - > flush_pending & &
2008-12-02 12:14:03 -08:00
time_after ( jiffies , rs_sta - > last_flush +
2008-01-27 20:41:38 -08:00
rs_sta - > flush_time ) ) {
2007-09-25 17:54:57 -07:00
2008-12-02 12:14:03 -08:00
rs_sta - > last_partial_flush = jiffies ;
2008-01-27 20:41:38 -08:00
rs_sta - > flush_pending = 1 ;
mod_timer ( & rs_sta - > rate_scale_flush ,
jiffies + rs_sta - > flush_time ) ;
2007-09-25 17:54:57 -07:00
}
2008-01-27 20:41:38 -08:00
spin_unlock_irqrestore ( & rs_sta - > lock , flags ) ;
2007-09-25 17:54:57 -07:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " leave \n " ) ;
2007-09-25 17:54:57 -07:00
return ;
}
2008-01-27 20:41:38 -08:00
static u16 iwl3945_get_adjacent_rate ( struct iwl3945_rs_sta * rs_sta ,
2008-01-24 19:38:38 +01:00
u8 index , u16 rate_mask , enum ieee80211_band band )
2007-09-25 17:54:57 -07:00
{
u8 high = IWL_RATE_INVALID ;
u8 low = IWL_RATE_INVALID ;
2009-01-27 14:27:53 -08:00
struct iwl_priv * priv __maybe_unused = rs_sta - > priv ;
2007-09-25 17:54:57 -07:00
2007-10-25 17:15:22 +08:00
/* 802.11A walks to the next literal adjacent rate in
2007-09-25 17:54:57 -07:00
* the rate table */
2008-01-24 19:38:38 +01:00
if ( unlikely ( band = = IEEE80211_BAND_5GHZ ) ) {
2007-09-25 17:54:57 -07:00
int i ;
u32 mask ;
/* Find the previous rate that is in the rate mask */
i = index - 1 ;
for ( mask = ( 1 < < i ) ; i > = 0 ; i - - , mask > > = 1 ) {
if ( rate_mask & mask ) {
low = i ;
break ;
}
}
/* Find the next rate that is in the rate mask */
i = index + 1 ;
2008-12-19 10:37:12 +08:00
for ( mask = ( 1 < < i ) ; i < IWL_RATE_COUNT_3945 ;
i + + , mask < < = 1 ) {
2007-09-25 17:54:57 -07:00
if ( rate_mask & mask ) {
high = i ;
break ;
}
}
return ( high < < 8 ) | low ;
}
low = index ;
while ( low ! = IWL_RATE_INVALID ) {
2008-01-27 20:41:38 -08:00
if ( rs_sta - > tgg )
2008-01-27 16:41:47 -08:00
low = iwl3945_rates [ low ] . prev_rs_tgg ;
2007-09-25 17:54:57 -07:00
else
2008-01-27 16:41:47 -08:00
low = iwl3945_rates [ low ] . prev_rs ;
2007-09-25 17:54:57 -07:00
if ( low = = IWL_RATE_INVALID )
break ;
if ( rate_mask & ( 1 < < low ) )
break ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " Skipping masked lower rate: %d \n " , low ) ;
2007-09-25 17:54:57 -07:00
}
high = index ;
while ( high ! = IWL_RATE_INVALID ) {
2008-01-27 20:41:38 -08:00
if ( rs_sta - > tgg )
2008-01-27 16:41:47 -08:00
high = iwl3945_rates [ high ] . next_rs_tgg ;
2007-09-25 17:54:57 -07:00
else
2008-01-27 16:41:47 -08:00
high = iwl3945_rates [ high ] . next_rs ;
2007-09-25 17:54:57 -07:00
if ( high = = IWL_RATE_INVALID )
break ;
if ( rate_mask & ( 1 < < high ) )
break ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " Skipping masked higher rate: %d \n " , high ) ;
2007-09-25 17:54:57 -07:00
}
return ( high < < 8 ) | low ;
}
/**
* rs_get_rate - find the rate for the requested packet
*
* Returns the ieee80211_rate structure allocated by the driver .
*
* The rate control algorithm has no internal mapping between hw_mode ' s
* rate ordering and the rate ordering used by the rate control algorithm .
*
* The rate control algorithm uses a single table of rates that goes across
* the entire A / B / G spectrum vs . being limited to just one particular
* hw_mode .
*
* As such , we can ' t convert the index obtained below into the hw_mode ' s
* rate table and must reference the driver allocated rate table
*
*/
2008-10-21 12:40:02 +02:00
static void rs_get_rate ( void * priv_r , struct ieee80211_sta * sta ,
void * priv_sta , struct ieee80211_tx_rate_control * txrc )
2007-09-25 17:54:57 -07:00
{
2008-10-21 12:40:02 +02:00
struct ieee80211_supported_band * sband = txrc - > sband ;
struct sk_buff * skb = txrc - > skb ;
2007-09-25 17:54:57 -07:00
u8 low = IWL_RATE_INVALID ;
u8 high = IWL_RATE_INVALID ;
u16 high_low ;
int index ;
2008-09-18 18:14:18 +02:00
struct iwl3945_rs_sta * rs_sta = priv_sta ;
2008-01-27 16:41:47 -08:00
struct iwl3945_rate_scale_data * window = NULL ;
2008-12-19 10:37:12 +08:00
int current_tpt = IWL_INVALID_VALUE ;
int low_tpt = IWL_INVALID_VALUE ;
int high_tpt = IWL_INVALID_VALUE ;
2007-09-25 17:54:57 -07:00
u32 fail_count ;
s8 scale_action = 0 ;
unsigned long flags ;
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) skb - > data ;
2009-01-21 10:58:02 -08:00
u16 fc ;
u16 rate_mask = 0 ;
2009-01-20 21:33:52 -08:00
s8 max_rate_idx = - 1 ;
2008-12-19 10:37:28 +08:00
struct iwl_priv * priv = ( struct iwl_priv * ) priv_r ;
2008-10-21 12:40:02 +02:00
struct ieee80211_tx_info * info = IEEE80211_SKB_CB ( skb ) ;
2007-09-25 17:54:57 -07:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " enter \n " ) ;
2007-09-25 17:54:57 -07:00
2009-01-21 10:58:02 -08:00
if ( sta )
rate_mask = sta - > supp_rates [ sband - > band ] ;
2009-04-23 19:36:08 +02:00
/* Send management frames and NO_ACK data using lowest rate. */
2007-12-25 19:33:16 -05:00
fc = le16_to_cpu ( hdr - > frame_control ) ;
if ( ( fc & IEEE80211_FCTL_FTYPE ) ! = IEEE80211_FTYPE_DATA | |
2009-04-23 19:36:08 +02:00
info - > flags & IEEE80211_TX_CTL_NO_ACK | |
2008-09-18 18:14:18 +02:00
! sta | | ! priv_sta ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " leave: No STA priv data to update! \n " ) ;
2009-01-21 10:58:02 -08:00
if ( ! rate_mask )
info - > control . rates [ 0 ] . idx =
rate_lowest_index ( sband , NULL ) ;
else
info - > control . rates [ 0 ] . idx =
rate_lowest_index ( sband , sta ) ;
2009-04-23 19:36:08 +02:00
if ( info - > flags & IEEE80211_TX_CTL_NO_ACK )
info - > control . rates [ 0 ] . count = 1 ;
2007-12-20 13:50:07 +01:00
return ;
2007-09-25 17:54:57 -07:00
}
2009-01-20 21:33:52 -08:00
/* get user max rate if set */
max_rate_idx = txrc - > max_rate_idx ;
if ( ( sband - > band = = IEEE80211_BAND_5GHZ ) & & ( max_rate_idx ! = - 1 ) )
max_rate_idx + = IWL_FIRST_OFDM_RATE ;
if ( ( max_rate_idx < 0 ) | | ( max_rate_idx > = IWL_RATE_COUNT ) )
max_rate_idx = - 1 ;
2008-12-19 10:37:12 +08:00
index = min ( rs_sta - > last_txrate_idx & 0xffff , IWL_RATE_COUNT_3945 - 1 ) ;
2007-11-12 11:37:42 +08:00
2008-03-06 17:36:54 -08:00
if ( sband - > band = = IEEE80211_BAND_5GHZ )
2007-11-12 11:37:42 +08:00
rate_mask = rate_mask < < IWL_FIRST_OFDM_RATE ;
2007-09-25 17:54:57 -07:00
2008-09-11 00:01:58 +02:00
if ( ( priv - > iw_mode = = NL80211_IFTYPE_ADHOC ) & &
2008-01-27 20:41:38 -08:00
! rs_sta - > ibss_sta_added ) {
2009-06-03 11:44:07 -07:00
u8 sta_id = iwl_find_station ( priv , hdr - > addr1 ) ;
2007-09-25 17:54:57 -07:00
if ( sta_id = = IWL_INVALID_STATION ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " LQ: ADD station %pm \n " ,
2008-10-27 15:59:26 -07:00
hdr - > addr1 ) ;
2009-06-03 11:44:07 -07:00
sta_id = iwl_add_station ( priv , hdr - > addr1 , false ,
CMD_ASYNC , NULL ) ;
2007-09-25 17:54:57 -07:00
}
if ( sta_id ! = IWL_INVALID_STATION )
2008-01-27 20:41:38 -08:00
rs_sta - > ibss_sta_added = 1 ;
2007-09-25 17:54:57 -07:00
}
2008-01-27 20:41:38 -08:00
spin_lock_irqsave ( & rs_sta - > lock , flags ) ;
2007-09-25 17:54:57 -07:00
2008-12-02 12:14:03 -08:00
/* for recent assoc, choose best rate regarding
* to rssi value
*/
2008-01-27 20:41:38 -08:00
if ( rs_sta - > start_rate ! = IWL_RATE_INVALID ) {
2008-12-02 12:14:03 -08:00
if ( rs_sta - > start_rate < index & &
( rate_mask & ( 1 < < rs_sta - > start_rate ) ) )
index = rs_sta - > start_rate ;
2008-01-27 20:41:38 -08:00
rs_sta - > start_rate = IWL_RATE_INVALID ;
2007-09-25 17:54:57 -07:00
}
2009-01-20 21:33:52 -08:00
/* force user max rate if set by user */
if ( ( max_rate_idx ! = - 1 ) & & ( max_rate_idx < index ) ) {
if ( rate_mask & ( 1 < < max_rate_idx ) )
index = max_rate_idx ;
}
2008-01-27 20:41:38 -08:00
window = & ( rs_sta - > win [ index ] ) ;
2007-09-25 17:54:57 -07:00
fail_count = window - > counter - window - > success_counter ;
2009-03-11 11:17:56 -07:00
if ( ( ( fail_count < IWL_RATE_MIN_FAILURE_TH ) & &
2007-09-25 17:54:57 -07:00
( window - > success_counter < IWL_RATE_MIN_SUCCESS_TH ) ) ) {
2008-01-27 20:41:38 -08:00
spin_unlock_irqrestore ( & rs_sta - > lock , flags ) ;
2007-09-25 17:54:57 -07:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " Invalid average_tpt on rate %d: "
2007-09-25 17:54:57 -07:00
" counter: %d, success_counter: %d, "
" expected_tpt is %sNULL \n " ,
index ,
window - > counter ,
window - > success_counter ,
2008-01-27 20:41:38 -08:00
rs_sta - > expected_tpt ? " not " : " " ) ;
2009-03-11 11:17:56 -07:00
/* Can't calculate this yet; not enough history */
window - > average_tpt = IWL_INVALID_VALUE ;
2007-09-25 17:54:57 -07:00
goto out ;
}
current_tpt = window - > average_tpt ;
2008-01-27 20:41:38 -08:00
high_low = iwl3945_get_adjacent_rate ( rs_sta , index , rate_mask ,
2008-03-06 17:36:54 -08:00
sband - > band ) ;
2007-09-25 17:54:57 -07:00
low = high_low & 0xff ;
high = ( high_low > > 8 ) & 0xff ;
2009-01-20 21:33:52 -08:00
/* If user set max rate, dont allow higher than user constrain */
if ( ( max_rate_idx ! = - 1 ) & & ( max_rate_idx < high ) )
high = IWL_RATE_INVALID ;
2009-03-11 11:17:56 -07:00
/* Collect Measured throughputs of adjacent rates */
2007-09-25 17:54:57 -07:00
if ( low ! = IWL_RATE_INVALID )
2008-01-27 20:41:38 -08:00
low_tpt = rs_sta - > win [ low ] . average_tpt ;
2007-09-25 17:54:57 -07:00
if ( high ! = IWL_RATE_INVALID )
2008-01-27 20:41:38 -08:00
high_tpt = rs_sta - > win [ high ] . average_tpt ;
2007-09-25 17:54:57 -07:00
2008-01-27 20:41:38 -08:00
spin_unlock_irqrestore ( & rs_sta - > lock , flags ) ;
2007-09-25 17:54:57 -07:00
2009-03-11 11:17:56 -07:00
scale_action = 0 ;
2007-09-25 17:54:57 -07:00
2009-03-11 11:17:56 -07:00
/* Low success ratio , need to drop the rate */
2007-09-25 17:54:57 -07:00
if ( ( window - > success_ratio < IWL_RATE_DECREASE_TH ) | | ! current_tpt ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " decrease rate because of low success_ratio \n " ) ;
2007-09-25 17:54:57 -07:00
scale_action = - 1 ;
2009-03-11 11:17:56 -07:00
/* No throughput measured yet for adjacent rates,
* try increase */
2008-12-19 10:37:12 +08:00
} else if ( ( low_tpt = = IWL_INVALID_VALUE ) & &
2009-03-11 11:17:56 -07:00
( high_tpt = = IWL_INVALID_VALUE ) ) {
2009-03-17 21:51:51 -07:00
if ( high ! = IWL_RATE_INVALID & & window - > success_ratio > = IWL_RATE_INCREASE_TH )
2009-03-11 11:17:56 -07:00
scale_action = 1 ;
else if ( low ! = IWL_RATE_INVALID )
2009-03-17 21:51:51 -07:00
scale_action = 0 ;
2009-03-11 11:17:56 -07:00
/* Both adjacent throughputs are measured, but neither one has
* better throughput ; we ' re using the best rate , don ' t change
* it ! */
} else if ( ( low_tpt ! = IWL_INVALID_VALUE ) & &
2008-12-19 10:37:12 +08:00
( high_tpt ! = IWL_INVALID_VALUE ) & &
2008-03-06 17:36:54 -08:00
( low_tpt < current_tpt ) & & ( high_tpt < current_tpt ) ) {
2009-03-11 11:17:56 -07:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " No action -- low [%d] & high [%d] < "
2007-09-25 17:54:57 -07:00
" current_tpt [%d] \n " ,
low_tpt , high_tpt , current_tpt ) ;
scale_action = 0 ;
2009-03-11 11:17:56 -07:00
/* At least one of the rates has better throughput */
2007-09-25 17:54:57 -07:00
} else {
2008-12-19 10:37:12 +08:00
if ( high_tpt ! = IWL_INVALID_VALUE ) {
2009-03-11 11:17:56 -07:00
/* High rate has better throughput, Increase
* rate */
if ( high_tpt > current_tpt & &
window - > success_ratio > = IWL_RATE_INCREASE_TH )
2007-09-25 17:54:57 -07:00
scale_action = 1 ;
else {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv ,
" decrease rate because of high tpt \n " ) ;
2009-03-17 21:51:51 -07:00
scale_action = 0 ;
2007-09-25 17:54:57 -07:00
}
2008-12-19 10:37:12 +08:00
} else if ( low_tpt ! = IWL_INVALID_VALUE ) {
2007-09-25 17:54:57 -07:00
if ( low_tpt > current_tpt ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv ,
" decrease rate because of low tpt \n " ) ;
2007-09-25 17:54:57 -07:00
scale_action = - 1 ;
2009-03-17 21:51:51 -07:00
} else if ( window - > success_ratio > = IWL_RATE_INCREASE_TH ) {
2009-03-11 11:17:56 -07:00
/* Lower rate has better
* throughput , decrease rate */
2007-09-25 17:54:57 -07:00
scale_action = 1 ;
2009-03-11 11:17:56 -07:00
}
2007-09-25 17:54:57 -07:00
}
}
2009-03-11 11:17:56 -07:00
/* Sanity check; asked for decrease, but success rate or throughput
* has been good at old rate . Don ' t change it . */
if ( ( scale_action = = - 1 ) & & ( low ! = IWL_RATE_INVALID ) & &
( ( window - > success_ratio > IWL_RATE_HIGH_TH ) | |
( current_tpt > ( 100 * rs_sta - > expected_tpt [ low ] ) ) ) )
scale_action = 0 ;
2007-09-25 17:54:57 -07:00
switch ( scale_action ) {
case - 1 :
2009-03-11 11:17:56 -07:00
/* Decrese rate */
2007-09-25 17:54:57 -07:00
if ( low ! = IWL_RATE_INVALID )
index = low ;
break ;
case 1 :
2009-03-11 11:17:56 -07:00
/* Increase rate */
2007-09-25 17:54:57 -07:00
if ( high ! = IWL_RATE_INVALID )
index = high ;
break ;
case 0 :
default :
2009-03-11 11:17:56 -07:00
/* No change */
2007-09-25 17:54:57 -07:00
break ;
}
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " Selected %d (action %d) - low %d high %d \n " ,
2007-09-25 17:54:57 -07:00
index , scale_action , low , high ) ;
out :
2008-09-11 02:22:58 +02:00
rs_sta - > last_txrate_idx = index ;
2008-03-06 17:36:54 -08:00
if ( sband - > band = = IEEE80211_BAND_5GHZ )
2008-10-21 12:40:02 +02:00
info - > control . rates [ 0 ] . idx = rs_sta - > last_txrate_idx -
IWL_FIRST_OFDM_RATE ;
2007-11-12 11:37:42 +08:00
else
2008-10-21 12:40:02 +02:00
info - > control . rates [ 0 ] . idx = rs_sta - > last_txrate_idx ;
2007-11-12 11:37:42 +08:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " leave: %d \n " , index ) ;
2007-09-25 17:54:57 -07:00
}
2008-12-02 12:14:02 -08:00
# ifdef CONFIG_MAC80211_DEBUGFS
static int iwl3945_open_file_generic ( struct inode * inode , struct file * file )
{
file - > private_data = inode - > i_private ;
return 0 ;
}
static ssize_t iwl3945_sta_dbgfs_stats_table_read ( struct file * file ,
char __user * user_buf ,
size_t count , loff_t * ppos )
{
2009-03-01 20:25:38 +01:00
char * buff ;
2008-12-02 12:14:02 -08:00
int desc = 0 ;
int j ;
2009-03-01 20:25:38 +01:00
ssize_t ret ;
2008-12-02 12:14:02 -08:00
struct iwl3945_rs_sta * lq_sta = file - > private_data ;
2009-03-01 20:25:38 +01:00
buff = kmalloc ( 1024 , GFP_KERNEL ) ;
if ( ! buff )
return - ENOMEM ;
2008-12-02 12:14:02 -08:00
desc + = sprintf ( buff + desc , " tx packets=%d last rate index=%d \n "
" rate=0x%X flush time %d \n " ,
lq_sta - > tx_packets ,
lq_sta - > last_txrate_idx ,
lq_sta - > start_rate , jiffies_to_msecs ( lq_sta - > flush_time ) ) ;
2008-12-19 10:37:12 +08:00
for ( j = 0 ; j < IWL_RATE_COUNT_3945 ; j + + ) {
2008-12-02 12:14:02 -08:00
desc + = sprintf ( buff + desc ,
" counter=%d success=%d %%=%d \n " ,
lq_sta - > win [ j ] . counter ,
lq_sta - > win [ j ] . success_counter ,
lq_sta - > win [ j ] . success_ratio ) ;
}
2009-03-01 20:25:38 +01:00
ret = simple_read_from_buffer ( user_buf , count , ppos , buff , desc ) ;
kfree ( buff ) ;
return ret ;
2008-12-02 12:14:02 -08:00
}
static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
. read = iwl3945_sta_dbgfs_stats_table_read ,
. open = iwl3945_open_file_generic ,
} ;
static void iwl3945_add_debugfs ( void * priv , void * priv_sta ,
struct dentry * dir )
{
struct iwl3945_rs_sta * lq_sta = priv_sta ;
lq_sta - > rs_sta_dbgfs_stats_table_file =
debugfs_create_file ( " rate_stats_table " , 0600 , dir ,
lq_sta , & rs_sta_dbgfs_stats_table_ops ) ;
}
static void iwl3945_remove_debugfs ( void * priv , void * priv_sta )
{
struct iwl3945_rs_sta * lq_sta = priv_sta ;
debugfs_remove ( lq_sta - > rs_sta_dbgfs_stats_table_file ) ;
}
# endif
2007-09-25 17:54:57 -07:00
static struct rate_control_ops rs_ops = {
. module = NULL ,
. name = RS_NAME ,
. tx_status = rs_tx_status ,
. get_rate = rs_get_rate ,
. rate_init = rs_rate_init ,
. alloc = rs_alloc ,
. free = rs_free ,
. alloc_sta = rs_alloc_sta ,
. free_sta = rs_free_sta ,
2008-12-02 12:14:02 -08:00
# ifdef CONFIG_MAC80211_DEBUGFS
. add_sta_debugfs = iwl3945_add_debugfs ,
. remove_sta_debugfs = iwl3945_remove_debugfs ,
# endif
2007-09-25 17:54:57 -07:00
} ;
2008-01-27 16:41:47 -08:00
void iwl3945_rate_scale_init ( struct ieee80211_hw * hw , s32 sta_id )
2007-09-25 17:54:57 -07:00
{
2008-12-19 10:37:28 +08:00
struct iwl_priv * priv = hw - > priv ;
2007-09-25 17:54:57 -07:00
s32 rssi = 0 ;
unsigned long flags ;
2008-01-27 20:41:38 -08:00
struct iwl3945_rs_sta * rs_sta ;
2008-09-18 18:14:18 +02:00
struct ieee80211_sta * sta ;
struct iwl3945_sta_priv * psta ;
2007-09-25 17:54:57 -07:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " enter \n " ) ;
2007-09-25 17:54:57 -07:00
2008-02-25 16:27:46 +01:00
rcu_read_lock ( ) ;
2009-06-03 11:44:07 -07:00
sta = ieee80211_find_sta ( hw , priv - > stations [ sta_id ] . sta . sta . addr ) ;
2008-10-11 01:46:25 +02:00
if ( ! sta ) {
2008-02-25 16:27:46 +01:00
rcu_read_unlock ( ) ;
2007-09-25 17:54:57 -07:00
return ;
}
2008-10-11 01:46:25 +02:00
psta = ( void * ) sta - > drv_priv ;
2008-09-18 18:14:18 +02:00
rs_sta = psta - > rs_sta ;
2007-09-25 17:54:57 -07:00
2008-01-27 20:41:38 -08:00
spin_lock_irqsave ( & rs_sta - > lock , flags ) ;
2007-09-25 17:54:57 -07:00
2008-01-27 20:41:38 -08:00
rs_sta - > tgg = 0 ;
2008-01-24 19:38:38 +01:00
switch ( priv - > band ) {
case IEEE80211_BAND_2GHZ :
/* TODO: this always does G, not a regression */
2009-01-27 14:27:52 -08:00
if ( priv - > active_rxon . flags & RXON_FLG_TGG_PROTECT_MSK ) {
2008-01-27 20:41:38 -08:00
rs_sta - > tgg = 1 ;
rs_sta - > expected_tpt = iwl3945_expected_tpt_g_prot ;
2007-09-25 17:54:57 -07:00
} else
2008-01-27 20:41:38 -08:00
rs_sta - > expected_tpt = iwl3945_expected_tpt_g ;
2007-09-25 17:54:57 -07:00
break ;
2008-01-24 19:38:38 +01:00
case IEEE80211_BAND_5GHZ :
2008-01-27 20:41:38 -08:00
rs_sta - > expected_tpt = iwl3945_expected_tpt_a ;
2007-09-25 17:54:57 -07:00
break ;
2008-01-24 19:38:38 +01:00
case IEEE80211_NUM_BANDS :
BUG ( ) ;
2007-09-25 17:54:57 -07:00
break ;
}
2008-01-27 20:41:38 -08:00
spin_unlock_irqrestore ( & rs_sta - > lock , flags ) ;
2007-09-25 17:54:57 -07:00
rssi = priv - > last_rx_rssi ;
if ( rssi = = 0 )
rssi = IWL_MIN_RSSI_VAL ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " Network RSSI: %d \n " , rssi ) ;
2007-09-25 17:54:57 -07:00
2008-01-24 19:38:38 +01:00
rs_sta - > start_rate = iwl3945_get_rate_index_by_rssi ( rssi , priv - > band ) ;
2007-09-25 17:54:57 -07:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RATE ( priv , " leave: rssi %d assign rate index: "
2008-01-27 20:41:38 -08:00
" %d (plcp 0x%x) \n " , rssi , rs_sta - > start_rate ,
iwl3945_rates [ rs_sta - > start_rate ] . plcp ) ;
2008-10-11 01:46:25 +02:00
rcu_read_unlock ( ) ;
2007-09-25 17:54:57 -07:00
}
2008-03-28 16:21:09 -07:00
int iwl3945_rate_control_register ( void )
2007-09-25 17:54:57 -07:00
{
2008-03-28 16:21:09 -07:00
return ieee80211_rate_control_register ( & rs_ops ) ;
2007-09-25 17:54:57 -07:00
}
2008-03-28 16:21:09 -07:00
void iwl3945_rate_control_unregister ( void )
2007-09-25 17:54:57 -07:00
{
ieee80211_rate_control_unregister ( & rs_ops ) ;
}