2007-09-25 17:54:57 -07:00
/******************************************************************************
*
2008-03-11 16:17:17 -07:00
* Copyright ( c ) 2005 - 2008 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 :
* James P . Ketrenos < ipw2100 - admin @ linux . intel . com >
* 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-04-08 15:14:40 -04:00
# include "../net/mac80211/rate.h"
2007-09-25 17:54:57 -07:00
2008-04-24 11:55:38 -07:00
# include "iwl-dev.h"
2008-03-21 13:53:44 -07:00
# include "iwl-core.h"
2007-09-25 17:54:57 -07:00
# include "iwl-helpers.h"
# define RS_NAME "iwl-4965-rs"
2008-04-23 17:14:59 -07:00
# define NUM_TRY_BEFORE_ANT_TOGGLE 1
2007-09-25 17:54:57 -07:00
# define IWL_NUMBER_TRY 1
# define IWL_HT_NUMBER_TRY 3
2007-11-29 11:09:44 +08:00
# define IWL_RATE_MAX_WINDOW 62 /* # tx in history window */
# define IWL_RATE_MIN_FAILURE_TH 6 /* min failures to calc tpt */
# define IWL_RATE_MIN_SUCCESS_TH 8 /* min successes to calc tpt */
/* max time to accum history 2 seconds */
# define IWL_RATE_SCALE_FLUSH_INTVL (2*HZ)
2007-09-25 17:54:57 -07:00
static u8 rs_ht_to_legacy [ ] = {
IWL_RATE_6M_INDEX , IWL_RATE_6M_INDEX ,
IWL_RATE_6M_INDEX , IWL_RATE_6M_INDEX ,
IWL_RATE_6M_INDEX ,
IWL_RATE_6M_INDEX , IWL_RATE_9M_INDEX ,
IWL_RATE_12M_INDEX , IWL_RATE_18M_INDEX ,
IWL_RATE_24M_INDEX , IWL_RATE_36M_INDEX ,
IWL_RATE_48M_INDEX , IWL_RATE_54M_INDEX
} ;
2008-04-23 17:14:59 -07:00
static const u8 ant_toggle_lookup [ ] = {
/*ANT_NONE -> */ ANT_NONE ,
/*ANT_A -> */ ANT_B ,
/*ANT_B -> */ ANT_C ,
/*ANT_AB -> */ ANT_BC ,
/*ANT_C -> */ ANT_A ,
/*ANT_AC -> */ ANT_AB ,
/*ANT_BC -> */ ANT_AC ,
/*ANT_ABC -> */ ANT_ABC ,
} ;
2007-11-29 11:09:44 +08:00
/**
* struct iwl4965_rate_scale_data - - tx success history for one rate
*/
2008-01-27 16:41:47 -08:00
struct iwl4965_rate_scale_data {
2007-11-29 11:09:44 +08:00
u64 data ; /* bitmap of successful frames */
s32 success_counter ; /* number of frames successful */
s32 success_ratio ; /* per-cent * 128 */
s32 counter ; /* number of frames attempted */
s32 average_tpt ; /* success ratio * expected throughput */
2007-09-25 17:54:57 -07:00
unsigned long stamp ;
} ;
2007-11-29 11:09:44 +08:00
/**
* struct iwl4965_scale_tbl_info - - tx params and success history for all rates
*
2008-01-28 14:07:26 +02:00
* There are two of these in struct iwl4965_lq_sta ,
2007-11-29 11:09:44 +08:00
* one for " active " , and one for " search " .
*/
2008-01-27 16:41:47 -08:00
struct iwl4965_scale_tbl_info {
2008-04-21 15:42:01 -07:00
enum iwl_table_type lq_type ;
u8 ant_type ;
2007-11-29 11:09:44 +08:00
u8 is_SGI ; /* 1 = short guard interval */
u8 is_fat ; /* 1 = 40 MHz channel width */
u8 is_dup ; /* 1 = duplicated data streams */
u8 action ; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
s32 * expected_tpt ; /* throughput metrics; expected_tpt_G, etc. */
2008-04-23 17:14:57 -07:00
u32 current_rate ; /* rate_n_flags, uCode API format */
2007-11-29 11:09:44 +08:00
struct iwl4965_rate_scale_data win [ IWL_RATE_COUNT ] ; /* rate histories */
2007-09-25 17:54:57 -07:00
} ;
2008-01-28 14:07:26 +02:00
# ifdef CONFIG_IWL4965_HT
struct iwl4965_traffic_load {
unsigned long time_stamp ; /* age of the oldest statistics */
u32 packet_count [ TID_QUEUE_MAX_SIZE ] ; /* packet count in this time
* slice */
u32 total ; /* total num of packets during the
* last TID_MAX_TIME_DIFF */
u8 queue_count ; /* number of queues that has
* been used since the last cleanup */
u8 head ; /* start of the circular buffer */
} ;
# endif /* CONFIG_IWL4965_HT */
2007-11-29 11:09:44 +08:00
/**
2008-01-28 14:07:26 +02:00
* struct iwl4965_lq_sta - - driver ' s rate scaling private structure
2007-11-29 11:09:44 +08:00
*
* Pointer to this gets passed back and forth between driver and mac80211 .
*/
2008-01-14 17:46:21 -08:00
struct iwl4965_lq_sta {
2007-11-29 11:09:44 +08:00
u8 active_tbl ; /* index of active table, range 0-1 */
u8 enable_counter ; /* indicates HT mode */
u8 stay_in_tbl ; /* 1: disallow, 0: allow search for new mode */
u8 search_better_tbl ; /* 1: currently trying alternate mode */
2007-09-25 17:54:57 -07:00
s32 last_tpt ;
2007-11-29 11:09:44 +08:00
/* The following determine when to search for a new mode */
2007-09-25 17:54:57 -07:00
u32 table_count_limit ;
2007-11-29 11:09:44 +08:00
u32 max_failure_limit ; /* # failed frames before new search */
u32 max_success_limit ; /* # successful frames before new search */
2007-09-25 17:54:57 -07:00
u32 table_count ;
2007-11-29 11:09:44 +08:00
u32 total_failed ; /* total failed frames, any/all rates */
u32 total_success ; /* total successful frames, any/all rates */
u32 flush_timer ; /* time staying in mode before new search */
u8 action_counter ; /* # mode-switch actions tried */
2007-09-25 17:54:57 -07:00
u8 is_green ;
u8 is_dup ;
2008-01-24 19:38:38 +01:00
enum ieee80211_band band ;
2007-09-25 17:54:57 -07:00
u8 ibss_sta_added ;
2007-11-29 11:09:44 +08:00
/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
2007-09-27 11:27:40 +08:00
u32 supp_rates ;
2008-04-23 17:14:57 -07:00
u16 active_legacy_rate ;
2007-09-25 17:54:57 -07:00
u16 active_siso_rate ;
2008-04-21 15:42:01 -07:00
u16 active_mimo2_rate ;
u16 active_mimo3_rate ;
2007-09-25 17:54:57 -07:00
u16 active_rate_basic ;
2007-11-29 11:09:44 +08:00
2008-04-15 16:01:40 -07:00
struct iwl_link_quality_cmd lq ;
2007-11-29 11:09:44 +08:00
struct iwl4965_scale_tbl_info lq_info [ LQ_SIZE ] ; /* "active", "search" */
2008-01-28 14:07:26 +02:00
# ifdef CONFIG_IWL4965_HT
struct iwl4965_traffic_load load [ TID_MAX_LOAD_COUNT ] ;
u8 tx_agg_tid_en ;
# endif
2007-09-27 11:27:38 +08:00
# ifdef CONFIG_MAC80211_DEBUGFS
2007-09-27 11:27:42 +08:00
struct dentry * rs_sta_dbgfs_scale_table_file ;
2007-09-27 11:27:43 +08:00
struct dentry * rs_sta_dbgfs_stats_table_file ;
2008-01-28 14:07:26 +02:00
# ifdef CONFIG_IWL4965_HT
struct dentry * rs_sta_dbgfs_tx_agg_tid_en_file ;
# endif
2008-04-23 17:14:57 -07:00
u32 dbg_fixed_rate ;
2007-09-27 11:27:38 +08:00
# endif
2008-05-05 10:22:46 +08:00
struct iwl_priv * drv ;
2007-09-25 17:54:57 -07:00
} ;
2008-03-12 16:58:50 -07:00
static void rs_rate_scale_perform ( struct iwl_priv * priv ,
2007-09-25 17:54:57 -07:00
struct net_device * dev ,
struct ieee80211_hdr * hdr ,
struct sta_info * sta ) ;
2008-04-21 15:42:01 -07:00
static void rs_fill_link_cmd ( const struct iwl_priv * priv ,
struct iwl4965_lq_sta * lq_sta ,
2008-04-23 17:15:03 -07:00
u32 rate_n_flags ) ;
2007-09-25 17:54:57 -07:00
2007-09-27 11:27:42 +08:00
# ifdef CONFIG_MAC80211_DEBUGFS
2008-01-14 17:46:21 -08:00
static void rs_dbgfs_set_mcs ( struct iwl4965_lq_sta * lq_sta ,
2008-04-23 17:14:57 -07:00
u32 * rate_n_flags , int index ) ;
2007-09-27 11:27:42 +08:00
# else
2008-01-14 17:46:21 -08:00
static void rs_dbgfs_set_mcs ( struct iwl4965_lq_sta * lq_sta ,
2008-04-23 17:14:57 -07:00
u32 * rate_n_flags , int index )
2007-09-27 11:27:42 +08:00
{ }
# endif
2007-11-29 11:09:44 +08:00
/*
* Expected throughput metrics for following rates :
* 1 , 2 , 5.5 , 11 , 6 , 9 , 12 , 18 , 24 , 36 , 48 , 54 , 60 MBits
* " G " is the only table that supports CCK ( the first 4 rates ) .
*/
2008-04-21 15:42:01 -07:00
/*FIXME:RS:need to spearate tables for MIMO2/MIMO3*/
2007-09-25 17:54:57 -07:00
static s32 expected_tpt_A [ IWL_RATE_COUNT ] = {
0 , 0 , 0 , 0 , 40 , 57 , 72 , 98 , 121 , 154 , 177 , 186 , 186
} ;
static s32 expected_tpt_G [ IWL_RATE_COUNT ] = {
7 , 13 , 35 , 58 , 40 , 57 , 72 , 98 , 121 , 154 , 177 , 186 , 186
} ;
static s32 expected_tpt_siso20MHz [ IWL_RATE_COUNT ] = {
0 , 0 , 0 , 0 , 42 , 42 , 76 , 102 , 124 , 159 , 183 , 193 , 202
} ;
static s32 expected_tpt_siso20MHzSGI [ IWL_RATE_COUNT ] = {
0 , 0 , 0 , 0 , 46 , 46 , 82 , 110 , 132 , 168 , 192 , 202 , 211
} ;
static s32 expected_tpt_mimo20MHz [ IWL_RATE_COUNT ] = {
0 , 0 , 0 , 0 , 74 , 74 , 123 , 155 , 179 , 214 , 236 , 244 , 251
} ;
static s32 expected_tpt_mimo20MHzSGI [ IWL_RATE_COUNT ] = {
0 , 0 , 0 , 0 , 81 , 81 , 131 , 164 , 188 , 222 , 243 , 251 , 257
} ;
static s32 expected_tpt_siso40MHz [ IWL_RATE_COUNT ] = {
0 , 0 , 0 , 0 , 77 , 77 , 127 , 160 , 184 , 220 , 242 , 250 , 257
} ;
static s32 expected_tpt_siso40MHzSGI [ IWL_RATE_COUNT ] = {
0 , 0 , 0 , 0 , 83 , 83 , 135 , 169 , 193 , 229 , 250 , 257 , 264
} ;
static s32 expected_tpt_mimo40MHz [ IWL_RATE_COUNT ] = {
0 , 0 , 0 , 0 , 123 , 123 , 182 , 214 , 235 , 264 , 279 , 285 , 289
} ;
static s32 expected_tpt_mimo40MHzSGI [ IWL_RATE_COUNT ] = {
0 , 0 , 0 , 0 , 131 , 131 , 191 , 222 , 242 , 270 , 284 , 289 , 293
} ;
2008-04-23 17:14:57 -07:00
static inline u8 rs_extract_rate ( u32 rate_n_flags )
2007-09-25 17:54:57 -07:00
{
return ( u8 ) ( rate_n_flags & 0xFF ) ;
}
2008-01-27 16:41:47 -08:00
static void rs_rate_scale_clear_window ( struct iwl4965_rate_scale_data * window )
2007-09-25 17:54:57 -07:00
{
window - > data = 0 ;
window - > success_counter = 0 ;
window - > success_ratio = IWL_INVALID_VALUE ;
window - > counter = 0 ;
window - > average_tpt = IWL_INVALID_VALUE ;
window - > stamp = 0 ;
}
2008-04-23 17:14:59 -07:00
static inline u8 rs_is_valid_ant ( u8 valid_antenna , u8 ant_type )
{
return ( ( ant_type & valid_antenna ) = = ant_type ) ;
}
2008-01-28 14:07:26 +02:00
# ifdef CONFIG_IWL4965_HT
/*
* removes the old data from the statistics . All data that is older than
* TID_MAX_TIME_DIFF , will be deleted .
*/
static void rs_tl_rm_old_stats ( struct iwl4965_traffic_load * tl , u32 curr_time )
{
/* The oldest age we want to keep */
u32 oldest_time = curr_time - TID_MAX_TIME_DIFF ;
while ( tl - > queue_count & &
( tl - > time_stamp < oldest_time ) ) {
tl - > total - = tl - > packet_count [ tl - > head ] ;
tl - > packet_count [ tl - > head ] = 0 ;
tl - > time_stamp + = TID_QUEUE_CELL_SPACING ;
tl - > queue_count - - ;
tl - > head + + ;
if ( tl - > head > = TID_QUEUE_MAX_SIZE )
tl - > head = 0 ;
}
}
/*
* increment traffic load value for tid and also remove
* any old values if passed the certain time period
*/
2008-05-15 13:54:06 +08:00
static void rs_tl_add_packet ( struct iwl4965_lq_sta * lq_data ,
struct ieee80211_hdr * hdr )
2008-01-28 14:07:26 +02:00
{
u32 curr_time = jiffies_to_msecs ( jiffies ) ;
u32 time_diff ;
s32 index ;
struct iwl4965_traffic_load * tl = NULL ;
2008-05-15 13:54:06 +08:00
u16 fc = le16_to_cpu ( hdr - > frame_control ) ;
u8 tid ;
2008-01-28 14:07:26 +02:00
2008-05-15 13:54:06 +08:00
if ( ieee80211_is_qos_data ( fc ) ) {
u8 * qc = ieee80211_get_qos_ctrl ( hdr , ieee80211_get_hdrlen ( fc ) ) ;
tid = qc [ 0 ] & 0xf ;
} else
2008-01-28 14:07:26 +02:00
return ;
tl = & lq_data - > load [ tid ] ;
curr_time - = curr_time % TID_ROUND_VALUE ;
/* Happens only for the first packet. Initialize the data */
if ( ! ( tl - > queue_count ) ) {
tl - > total = 1 ;
tl - > time_stamp = curr_time ;
tl - > queue_count = 1 ;
tl - > head = 0 ;
tl - > packet_count [ 0 ] = 1 ;
return ;
}
time_diff = TIME_WRAP_AROUND ( tl - > time_stamp , curr_time ) ;
index = time_diff / TID_QUEUE_CELL_SPACING ;
/* The history is too long: remove data that is older than */
/* TID_MAX_TIME_DIFF */
if ( index > = TID_QUEUE_MAX_SIZE )
rs_tl_rm_old_stats ( tl , curr_time ) ;
index = ( tl - > head + index ) % TID_QUEUE_MAX_SIZE ;
tl - > packet_count [ index ] = tl - > packet_count [ index ] + 1 ;
tl - > total = tl - > total + 1 ;
if ( ( index + 1 ) > tl - > queue_count )
tl - > queue_count = index + 1 ;
}
/*
get the traffic load value for tid
*/
static u32 rs_tl_get_load ( struct iwl4965_lq_sta * lq_data , u8 tid )
{
u32 curr_time = jiffies_to_msecs ( jiffies ) ;
u32 time_diff ;
s32 index ;
struct iwl4965_traffic_load * tl = NULL ;
if ( tid > = TID_MAX_LOAD_COUNT )
return 0 ;
tl = & ( lq_data - > load [ tid ] ) ;
curr_time - = curr_time % TID_ROUND_VALUE ;
if ( ! ( tl - > queue_count ) )
return 0 ;
time_diff = TIME_WRAP_AROUND ( tl - > time_stamp , curr_time ) ;
index = time_diff / TID_QUEUE_CELL_SPACING ;
/* The history is too long: remove data that is older than */
/* TID_MAX_TIME_DIFF */
if ( index > = TID_QUEUE_MAX_SIZE )
rs_tl_rm_old_stats ( tl , curr_time ) ;
return tl - > total ;
}
2008-03-12 16:58:50 -07:00
static void rs_tl_turn_on_agg_for_tid ( struct iwl_priv * priv ,
2008-01-28 14:07:26 +02:00
struct iwl4965_lq_sta * lq_data , u8 tid ,
struct sta_info * sta )
{
unsigned long state ;
DECLARE_MAC_BUF ( mac ) ;
2008-05-03 01:02:02 +02:00
spin_lock_bh ( & sta - > lock ) ;
2008-03-26 20:36:03 +02:00
state = sta - > ampdu_mlme . tid_state_tx [ tid ] ;
2008-05-03 01:02:02 +02:00
spin_unlock_bh ( & sta - > lock ) ;
2008-01-28 14:07:26 +02:00
if ( state = = HT_AGG_STATE_IDLE & &
rs_tl_get_load ( lq_data , tid ) > IWL_AGG_LOAD_THRESHOLD ) {
IWL_DEBUG_HT ( " Starting Tx agg: STA: %s tid: %d \n " ,
print_mac ( mac , sta - > addr ) , tid ) ;
ieee80211_start_tx_ba_session ( priv - > hw , sta - > addr , tid ) ;
}
}
2008-03-12 16:58:50 -07:00
static void rs_tl_turn_on_agg ( struct iwl_priv * priv , u8 tid ,
2008-01-28 14:07:26 +02:00
struct iwl4965_lq_sta * lq_data ,
struct sta_info * sta )
{
if ( ( tid < TID_MAX_LOAD_COUNT ) )
rs_tl_turn_on_agg_for_tid ( priv , lq_data , tid , sta ) ;
else if ( tid = = IWL_AGG_ALL_TID )
for ( tid = 0 ; tid < TID_MAX_LOAD_COUNT ; tid + + )
rs_tl_turn_on_agg_for_tid ( priv , lq_data , tid , sta ) ;
}
# endif /* CONFIG_IWLWIFI_HT */
2008-04-23 17:14:57 -07:00
static inline int get_num_of_ant_from_rate ( u32 rate_n_flags )
2008-04-21 15:42:01 -07:00
{
2008-04-23 17:14:57 -07:00
return ( ! ! ( rate_n_flags & RATE_MCS_ANT_A_MSK ) +
! ! ( rate_n_flags & RATE_MCS_ANT_B_MSK ) +
! ! ( rate_n_flags & RATE_MCS_ANT_C_MSK ) ) ;
2008-04-21 15:42:01 -07:00
}
2007-11-29 11:09:44 +08:00
/**
* rs_collect_tx_data - Update the success / failure sliding window
*
* We keep a sliding window of the last 62 packets transmitted
* at this rate . window - > data contains the bitmask of successful
* packets .
*/
2008-01-27 16:41:47 -08:00
static int rs_collect_tx_data ( struct iwl4965_rate_scale_data * windows ,
2008-01-28 14:07:25 +02:00
int scale_index , s32 tpt , int retries ,
int successes )
2007-09-25 17:54:57 -07:00
{
2008-01-27 16:41:47 -08:00
struct iwl4965_rate_scale_data * window = NULL ;
2008-04-23 17:14:57 -07:00
static const u64 mask = ( ( ( u64 ) 1 ) < < ( IWL_RATE_MAX_WINDOW - 1 ) ) ;
2007-09-25 17:54:57 -07:00
s32 fail_count ;
2007-10-25 17:15:25 +08:00
if ( scale_index < 0 | | scale_index > = IWL_RATE_COUNT )
return - EINVAL ;
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:44 +08:00
/* Select data for current tx bit rate */
2007-09-25 17:54:57 -07:00
window = & ( windows [ scale_index ] ) ;
2007-11-29 11:09:44 +08: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 ! ) .
*/
2008-01-28 14:07:25 +02:00
while ( retries > 0 ) {
2008-04-23 17:14:57 -07:00
if ( window - > counter > = IWL_RATE_MAX_WINDOW ) {
/* remove earliest */
window - > counter = IWL_RATE_MAX_WINDOW - 1 ;
2008-01-28 14:07:25 +02:00
if ( window - > data & mask ) {
window - > data & = ~ mask ;
2008-04-23 17:14:57 -07:00
window - > success_counter - - ;
2008-01-28 14:07:25 +02:00
}
2007-09-25 17:54:57 -07:00
}
2008-01-28 14:07:25 +02:00
/* Increment frames-attempted counter */
window - > counter + + ;
/* Shift bitmap by one frame (throw away oldest history),
* OR in " 1 " , and increment " success " if this
* frame was successful . */
2008-04-23 17:14:57 -07:00
window - > data < < = 1 ; ;
2008-01-28 14:07:25 +02:00
if ( successes > 0 ) {
2008-04-23 17:14:57 -07:00
window - > success_counter + + ;
2008-01-28 14:07:25 +02:00
window - > data | = 0x1 ;
successes - - ;
}
2007-11-29 11:09:44 +08:00
2008-01-28 14:07:25 +02:00
retries - - ;
2007-09-25 17:54:57 -07:00
}
2007-11-29 11:09:44 +08:00
/* Calculate current success ratio, avoid divide-by-0! */
2007-09-25 17:54:57 -07:00
if ( window - > counter > 0 )
window - > success_ratio = 128 * ( 100 * window - > success_counter )
/ window - > counter ;
else
window - > success_ratio = IWL_INVALID_VALUE ;
fail_count = window - > counter - window - > success_counter ;
2007-11-29 11:09:44 +08:00
/* Calculate average throughput, if we have enough history. */
2007-09-25 17:54:57 -07:00
if ( ( fail_count > = IWL_RATE_MIN_FAILURE_TH ) | |
( window - > success_counter > = IWL_RATE_MIN_SUCCESS_TH ) )
window - > average_tpt = ( window - > success_ratio * tpt + 64 ) / 128 ;
else
window - > average_tpt = IWL_INVALID_VALUE ;
2007-11-29 11:09:44 +08:00
/* Tag this window as having been updated */
2007-09-25 17:54:57 -07:00
window - > stamp = jiffies ;
2007-10-25 17:15:25 +08:00
return 0 ;
2007-09-25 17:54:57 -07:00
}
2007-11-29 11:09:44 +08:00
/*
* Fill uCode API rate_n_flags field , based on " search " or " active " table .
*/
2008-04-23 17:14:57 -07:00
/* FIXME:RS:remove this function and put the flags statically in the table */
static u32 rate_n_flags_from_tbl ( struct iwl4965_scale_tbl_info * tbl ,
int index , u8 use_green )
2007-09-25 17:54:57 -07:00
{
2008-04-23 17:14:57 -07:00
u32 rate_n_flags = 0 ;
2007-09-25 17:54:57 -07:00
if ( is_legacy ( tbl - > lq_type ) ) {
2008-05-15 13:54:02 +08:00
rate_n_flags = iwl_rates [ index ] . plcp ;
2007-09-25 17:54:57 -07:00
if ( index > = IWL_FIRST_CCK_RATE & & index < = IWL_LAST_CCK_RATE )
2008-04-23 17:14:57 -07:00
rate_n_flags | = RATE_MCS_CCK_MSK ;
2007-09-25 17:54:57 -07:00
2008-04-21 15:42:01 -07:00
} else if ( is_Ht ( tbl - > lq_type ) ) {
if ( index > IWL_LAST_OFDM_RATE ) {
IWL_ERROR ( " invalid HT rate index %d \n " , index ) ;
2007-09-25 17:54:57 -07:00
index = IWL_LAST_OFDM_RATE ;
2008-04-21 15:42:01 -07:00
}
2008-04-23 17:14:57 -07:00
rate_n_flags = RATE_MCS_HT_MSK ;
2008-04-21 15:42:01 -07:00
if ( is_siso ( tbl - > lq_type ) )
2008-05-15 13:54:02 +08:00
rate_n_flags | = iwl_rates [ index ] . plcp_siso ;
2008-04-21 15:42:01 -07:00
else if ( is_mimo2 ( tbl - > lq_type ) )
2008-05-15 13:54:02 +08:00
rate_n_flags | = iwl_rates [ index ] . plcp_mimo2 ;
2008-04-21 15:42:01 -07:00
else
2008-05-15 13:54:02 +08:00
rate_n_flags | = iwl_rates [ index ] . plcp_mimo3 ;
2007-09-25 17:54:57 -07:00
} else {
2008-04-21 15:42:01 -07:00
IWL_ERROR ( " Invalid tbl->lq_type %d \n " , tbl - > lq_type ) ;
2007-09-25 17:54:57 -07:00
}
2008-04-23 17:14:57 -07:00
rate_n_flags | = ( ( tbl - > ant_type < < RATE_MCS_ANT_POS ) &
2008-04-21 15:42:01 -07:00
RATE_MCS_ANT_ABC_MSK ) ;
2007-09-25 17:54:57 -07:00
2008-04-23 17:14:57 -07:00
if ( is_Ht ( tbl - > lq_type ) ) {
if ( tbl - > is_fat ) {
if ( tbl - > is_dup )
rate_n_flags | = RATE_MCS_DUP_MSK ;
else
rate_n_flags | = RATE_MCS_FAT_MSK ;
}
if ( tbl - > is_SGI )
rate_n_flags | = RATE_MCS_SGI_MSK ;
if ( use_green ) {
rate_n_flags | = RATE_MCS_GF_MSK ;
if ( is_siso ( tbl - > lq_type ) & & tbl - > is_SGI ) {
rate_n_flags & = ~ RATE_MCS_SGI_MSK ;
IWL_ERROR ( " GF was set with SGI:SISO \n " ) ;
}
}
2007-09-25 17:54:57 -07:00
}
2008-04-23 17:14:57 -07:00
return rate_n_flags ;
2007-09-25 17:54:57 -07:00
}
2007-11-29 11:09:44 +08:00
/*
* Interpret uCode API ' s rate_n_flags format ,
* fill " search " or " active " tx mode table .
*/
2008-04-23 17:14:57 -07:00
static int rs_get_tbl_info_from_mcs ( const u32 rate_n_flags ,
2008-01-24 19:38:38 +01:00
enum ieee80211_band band ,
struct iwl4965_scale_tbl_info * tbl ,
2007-09-25 17:54:57 -07:00
int * rate_idx )
{
2008-04-23 17:14:57 -07:00
u32 ant_msk = ( rate_n_flags & RATE_MCS_ANT_ABC_MSK ) ;
u8 num_of_ant = get_num_of_ant_from_rate ( rate_n_flags ) ;
u8 mcs ;
2007-09-25 17:54:57 -07:00
2008-04-23 17:14:57 -07:00
* rate_idx = iwl4965_hwrate_to_plcp_idx ( rate_n_flags ) ;
2007-09-25 17:54:57 -07:00
2008-04-21 15:42:01 -07:00
if ( * rate_idx = = IWL_RATE_INVALID ) {
2007-09-25 17:54:57 -07:00
* rate_idx = - 1 ;
2007-10-25 17:15:25 +08:00
return - EINVAL ;
2007-09-25 17:54:57 -07:00
}
2007-11-29 11:09:44 +08:00
tbl - > is_SGI = 0 ; /* default legacy setup */
2007-09-25 17:54:57 -07:00
tbl - > is_fat = 0 ;
tbl - > is_dup = 0 ;
2008-04-21 15:42:01 -07:00
tbl - > ant_type = ( ant_msk > > RATE_MCS_ANT_POS ) ;
tbl - > lq_type = LQ_NONE ;
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:44 +08:00
/* legacy rate format */
2008-04-23 17:14:57 -07:00
if ( ! ( rate_n_flags & RATE_MCS_HT_MSK ) ) {
2008-04-21 15:42:01 -07:00
if ( num_of_ant = = 1 ) {
2008-01-24 19:38:38 +01:00
if ( band = = IEEE80211_BAND_5GHZ )
2007-09-25 17:54:57 -07:00
tbl - > lq_type = LQ_A ;
else
tbl - > lq_type = LQ_G ;
}
2008-04-21 15:42:01 -07:00
/* HT rate format */
2007-09-25 17:54:57 -07:00
} else {
2008-04-23 17:14:57 -07:00
if ( rate_n_flags & RATE_MCS_SGI_MSK )
2007-09-25 17:54:57 -07:00
tbl - > is_SGI = 1 ;
2008-04-23 17:14:57 -07:00
if ( ( rate_n_flags & RATE_MCS_FAT_MSK ) | |
( rate_n_flags & RATE_MCS_DUP_MSK ) )
2007-09-25 17:54:57 -07:00
tbl - > is_fat = 1 ;
2008-04-23 17:14:57 -07:00
if ( rate_n_flags & RATE_MCS_DUP_MSK )
2007-09-25 17:54:57 -07:00
tbl - > is_dup = 1 ;
2008-04-21 15:42:01 -07:00
2008-04-23 17:14:57 -07:00
mcs = rs_extract_rate ( rate_n_flags ) ;
2008-04-21 15:42:01 -07:00
2008-04-23 17:14:57 -07:00
/* SISO */
if ( mcs < = IWL_RATE_SISO_60M_PLCP ) {
2008-04-21 15:42:01 -07:00
if ( num_of_ant = = 1 )
tbl - > lq_type = LQ_SISO ; /*else NONE*/
/* MIMO2 */
2008-04-23 17:14:57 -07:00
} else if ( mcs < = IWL_RATE_MIMO2_60M_PLCP ) {
2008-04-21 15:42:01 -07:00
if ( num_of_ant = = 2 )
tbl - > lq_type = LQ_MIMO2 ;
/* MIMO3 */
} else {
if ( num_of_ant = = 3 )
tbl - > lq_type = LQ_MIMO3 ;
}
2007-09-25 17:54:57 -07:00
}
return 0 ;
}
2008-04-23 17:14:59 -07:00
/* switch to another antenna/antennas and return 1 */
/* if no other valid antenna found, return 0 */
static int rs_toggle_antenna ( u32 valid_ant , u32 * rate_n_flags ,
struct iwl4965_scale_tbl_info * tbl )
2007-09-25 17:54:57 -07:00
{
2008-04-23 17:14:59 -07:00
u8 new_ant_type ;
if ( ! tbl - > ant_type | | tbl - > ant_type > ANT_ABC )
return 0 ;
if ( ! rs_is_valid_ant ( valid_ant , tbl - > ant_type ) )
return 0 ;
new_ant_type = ant_toggle_lookup [ tbl - > ant_type ] ;
while ( ( new_ant_type ! = tbl - > ant_type ) & &
! rs_is_valid_ant ( valid_ant , new_ant_type ) )
new_ant_type = ant_toggle_lookup [ new_ant_type ] ;
if ( new_ant_type = = tbl - > ant_type )
return 0 ;
tbl - > ant_type = new_ant_type ;
* rate_n_flags & = ~ RATE_MCS_ANT_ABC_MSK ;
* rate_n_flags | = new_ant_type < < RATE_MCS_ANT_POS ;
return 1 ;
2007-09-25 17:54:57 -07:00
}
2008-04-23 17:14:57 -07:00
/* FIXME:RS: in 4965 we don't use greenfield at all */
2008-04-23 17:15:02 -07:00
/* FIXME:RS: don't use greenfield for now in TX */
/* #ifdef CONFIG_IWL4965_HT */
#if 0
static inline u8 rs_use_green ( struct iwl_priv * priv , struct ieee80211_conf * conf )
2007-09-25 17:54:57 -07:00
{
2007-11-26 16:14:41 +02:00
return ( ( conf - > flags & IEEE80211_CONF_SUPPORT_HT_MODE ) & &
priv - > current_ht_config . is_green_field & &
! priv - > current_ht_config . non_GF_STA_present ) ;
2008-04-23 17:15:02 -07:00
}
2008-04-23 17:14:57 -07:00
# else
2008-04-23 17:15:02 -07:00
static inline u8 rs_use_green ( struct iwl_priv * priv , struct ieee80211_conf * conf )
{
2007-10-25 17:15:25 +08:00
return 0 ;
2007-09-25 17:54:57 -07:00
}
2008-04-23 17:15:02 -07:00
# endif /* CONFIG_IWL4965_HT */
2007-09-25 17:54:57 -07:00
/**
* rs_get_supported_rates - get the available rates
*
* if management frame or broadcast frame only return
* basic available rates .
*
*/
2008-04-23 17:14:58 -07:00
static u16 rs_get_supported_rates ( struct iwl4965_lq_sta * lq_sta ,
2007-09-25 17:54:57 -07:00
struct ieee80211_hdr * hdr ,
2008-04-23 17:14:58 -07:00
enum iwl_table_type rate_type )
2007-09-25 17:54:57 -07:00
{
2008-04-23 17:14:58 -07:00
if ( hdr & & is_multicast_ether_addr ( hdr - > addr1 ) & &
lq_sta - > active_rate_basic )
return lq_sta - > active_rate_basic ;
if ( is_legacy ( rate_type ) ) {
return lq_sta - > active_legacy_rate ;
} else {
2007-09-25 17:54:57 -07:00
if ( is_siso ( rate_type ) )
2008-04-23 17:14:58 -07:00
return lq_sta - > active_siso_rate ;
2008-04-21 15:42:01 -07:00
else if ( is_mimo2 ( rate_type ) )
2008-04-23 17:14:58 -07:00
return lq_sta - > active_mimo2_rate ;
2007-09-25 17:54:57 -07:00
else
2008-04-23 17:14:58 -07:00
return lq_sta - > active_mimo3_rate ;
2008-01-14 17:46:21 -08:00
}
2007-09-25 17:54:57 -07:00
}
2008-05-05 10:22:40 +08:00
static u16 rs_get_adjacent_rate ( struct iwl_priv * priv , u8 index , u16 rate_mask ,
int rate_type )
2007-09-25 17:54:57 -07:00
{
u8 high = IWL_RATE_INVALID ;
u8 low = IWL_RATE_INVALID ;
2007-10-25 17:15:22 +08:00
/* 802.11A or ht walks to the next literal adjacent rate in
2007-09-25 17:54:57 -07:00
* the rate table */
if ( is_a_band ( rate_type ) | | ! is_legacy ( rate_type ) ) {
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 ;
for ( mask = ( 1 < < i ) ; i < IWL_RATE_COUNT ; i + + , mask < < = 1 ) {
if ( rate_mask & mask ) {
high = i ;
break ;
}
}
return ( high < < 8 ) | low ;
}
low = index ;
while ( low ! = IWL_RATE_INVALID ) {
2008-05-15 13:54:02 +08:00
low = iwl_rates [ low ] . prev_rs ;
2007-09-25 17:54:57 -07:00
if ( low = = IWL_RATE_INVALID )
break ;
if ( rate_mask & ( 1 < < low ) )
break ;
IWL_DEBUG_RATE ( " Skipping masked lower rate: %d \n " , low ) ;
}
high = index ;
while ( high ! = IWL_RATE_INVALID ) {
2008-05-15 13:54:02 +08:00
high = iwl_rates [ high ] . next_rs ;
2007-09-25 17:54:57 -07:00
if ( high = = IWL_RATE_INVALID )
break ;
if ( rate_mask & ( 1 < < high ) )
break ;
IWL_DEBUG_RATE ( " Skipping masked higher rate: %d \n " , high ) ;
}
return ( high < < 8 ) | low ;
}
2008-04-23 17:14:57 -07:00
static u32 rs_get_lower_rate ( struct iwl4965_lq_sta * lq_sta ,
2008-01-27 16:41:47 -08:00
struct iwl4965_scale_tbl_info * tbl , u8 scale_index ,
2008-04-23 17:14:57 -07:00
u8 ht_possible )
2007-09-25 17:54:57 -07:00
{
s32 low ;
u16 rate_mask ;
u16 high_low ;
u8 switch_to_legacy = 0 ;
2008-01-14 17:46:21 -08:00
u8 is_green = lq_sta - > is_green ;
2007-09-25 17:54:57 -07:00
/* check if we need to switch from HT to legacy rates.
* assumption is that mandatory rates ( 1 Mbps or 6 Mbps )
* are always supported ( spec demand ) */
if ( ! is_legacy ( tbl - > lq_type ) & & ( ! ht_possible | | ! scale_index ) ) {
switch_to_legacy = 1 ;
scale_index = rs_ht_to_legacy [ scale_index ] ;
2008-01-24 19:38:38 +01:00
if ( lq_sta - > band = = IEEE80211_BAND_5GHZ )
2007-09-25 17:54:57 -07:00
tbl - > lq_type = LQ_A ;
else
tbl - > lq_type = LQ_G ;
2008-04-23 17:15:01 -07:00
if ( num_of_ant ( tbl - > ant_type ) > 1 )
2008-04-21 15:42:01 -07:00
tbl - > ant_type = ANT_A ; /*FIXME:RS*/
2007-09-25 17:54:57 -07:00
tbl - > is_fat = 0 ;
tbl - > is_SGI = 0 ;
}
2008-04-23 17:14:58 -07:00
rate_mask = rs_get_supported_rates ( lq_sta , NULL , tbl - > lq_type ) ;
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:44 +08:00
/* Mask with station rate restriction */
2007-09-25 17:54:57 -07:00
if ( is_legacy ( tbl - > lq_type ) ) {
2007-11-29 11:09:44 +08:00
/* supp_rates has no CCK bits in A mode */
2008-01-24 19:38:38 +01:00
if ( lq_sta - > band = = IEEE80211_BAND_5GHZ )
2007-09-25 17:54:57 -07:00
rate_mask = ( u16 ) ( rate_mask &
2008-01-14 17:46:21 -08:00
( lq_sta - > supp_rates < < IWL_FIRST_OFDM_RATE ) ) ;
2007-09-25 17:54:57 -07:00
else
2008-01-14 17:46:21 -08:00
rate_mask = ( u16 ) ( rate_mask & lq_sta - > supp_rates ) ;
2007-09-25 17:54:57 -07:00
}
2007-11-29 11:09:44 +08:00
/* If we switched from HT to legacy, check current rate */
2007-10-25 17:15:25 +08:00
if ( switch_to_legacy & & ( rate_mask & ( 1 < < scale_index ) ) ) {
2008-04-23 17:14:57 -07:00
low = scale_index ;
goto out ;
2007-09-25 17:54:57 -07:00
}
2008-05-05 10:22:40 +08:00
high_low = rs_get_adjacent_rate ( lq_sta - > drv , scale_index , rate_mask ,
tbl - > lq_type ) ;
2007-09-25 17:54:57 -07:00
low = high_low & 0xff ;
2008-04-23 17:14:57 -07:00
if ( low = = IWL_RATE_INVALID )
low = scale_index ;
out :
return rate_n_flags_from_tbl ( tbl , low , is_green ) ;
2007-09-25 17:54:57 -07:00
}
2007-11-29 11:09:44 +08:00
/*
* mac80211 sends us Tx status
*/
2008-01-14 17:46:21 -08:00
static void rs_tx_status ( void * priv_rate , struct net_device * dev ,
2008-05-15 12:55:29 +02:00
struct sk_buff * skb )
2007-09-25 17:54:57 -07:00
{
int status ;
u8 retries ;
int rs_index , index = 0 ;
2008-01-14 17:46:21 -08:00
struct iwl4965_lq_sta * lq_sta ;
2008-04-15 16:01:40 -07:00
struct iwl_link_quality_cmd * table ;
2007-09-25 17:54:57 -07:00
struct sta_info * sta ;
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) skb - > data ;
2008-03-12 16:58:50 -07:00
struct iwl_priv * priv = ( struct iwl_priv * ) priv_rate ;
2007-09-25 17:54:57 -07:00
struct ieee80211_local * local = wdev_priv ( dev - > ieee80211_ptr ) ;
2008-03-04 18:09:27 -08:00
struct ieee80211_hw * hw = local_to_hw ( local ) ;
2008-05-15 12:55:29 +02:00
struct ieee80211_tx_info * info = IEEE80211_SKB_CB ( skb ) ;
2008-01-27 16:41:47 -08:00
struct iwl4965_rate_scale_data * window = NULL ;
struct iwl4965_rate_scale_data * search_win = NULL ;
2008-04-23 17:14:57 -07:00
u32 tx_rate ;
2008-01-27 16:41:47 -08:00
struct iwl4965_scale_tbl_info tbl_type ;
struct iwl4965_scale_tbl_info * curr_tbl , * search_tbl ;
2007-09-25 17:54:57 -07:00
u8 active_index = 0 ;
u16 fc = le16_to_cpu ( hdr - > frame_control ) ;
s32 tpt = 0 ;
2007-09-27 11:27:39 +08:00
IWL_DEBUG_RATE_LIMIT ( " get frame ack response, update rate scale window \n " ) ;
2007-09-25 17:54:57 -07:00
if ( ! ieee80211_is_data ( fc ) | | is_multicast_ether_addr ( hdr - > addr1 ) )
return ;
2008-01-28 14:07:25 +02:00
/* This packet was aggregated but doesn't carry rate scale info */
2008-05-15 12:55:29 +02:00
if ( ( info - > flags & IEEE80211_TX_CTL_AMPDU ) & &
! ( info - > flags & IEEE80211_TX_STAT_AMPDU ) )
2008-01-28 14:07:25 +02:00
return ;
2008-05-15 12:55:29 +02:00
retries = info - > status . retry_count ;
2007-09-25 17:54:57 -07:00
if ( retries > 15 )
retries = 15 ;
2008-02-25 16:27:46 +01:00
rcu_read_lock ( ) ;
2007-09-25 17:54:57 -07:00
sta = sta_info_get ( local , hdr - > addr1 ) ;
2008-03-05 11:31:00 -08:00
if ( ! sta | | ! sta - > rate_ctrl_priv )
goto out ;
2007-09-25 17:54:57 -07:00
2008-01-14 17:46:21 -08:00
lq_sta = ( struct iwl4965_lq_sta * ) sta - > rate_ctrl_priv ;
2007-09-25 17:54:57 -07:00
if ( ! priv - > lq_mngr . lq_ready )
2008-03-05 11:31:00 -08:00
goto out ;
2007-09-25 17:54:57 -07:00
2008-01-14 17:46:21 -08:00
if ( ( priv - > iw_mode = = IEEE80211_IF_TYPE_IBSS ) & &
! lq_sta - > ibss_sta_added )
2008-03-05 11:31:00 -08:00
goto out ;
2007-09-25 17:54:57 -07:00
2008-01-14 17:46:21 -08:00
table = & lq_sta - > lq ;
active_index = lq_sta - > active_tbl ;
2007-09-25 17:54:57 -07:00
2008-01-14 17:46:21 -08:00
curr_tbl = & ( lq_sta - > lq_info [ active_index ] ) ;
search_tbl = & ( lq_sta - > lq_info [ ( 1 - active_index ) ] ) ;
2008-01-27 16:41:47 -08:00
window = ( struct iwl4965_rate_scale_data * )
2007-09-25 17:54:57 -07:00
& ( curr_tbl - > win [ 0 ] ) ;
2008-01-27 16:41:47 -08:00
search_win = ( struct iwl4965_rate_scale_data * )
2007-09-25 17:54:57 -07:00
& ( search_tbl - > win [ 0 ] ) ;
2007-11-29 11:09:44 +08:00
/*
* Ignore this Tx frame response if its initial rate doesn ' t match
* that of latest Link Quality command . There may be stragglers
* from a previous Link Quality command , but we ' re no longer interested
* in those ; they ' re either from the " active " mode while we ' re trying
* to check " search " mode , or a prior " search " mode after we ' ve moved
* to a new " search " mode ( which might become the new " active " mode ) .
*/
2008-04-23 17:14:57 -07:00
tx_rate = le32_to_cpu ( table - > rs_table [ 0 ] . rate_n_flags ) ;
rs_get_tbl_info_from_mcs ( tx_rate , priv - > band , & tbl_type , & rs_index ) ;
2008-03-04 18:09:27 -08:00
if ( priv - > band = = IEEE80211_BAND_5GHZ )
rs_index - = IWL_FIRST_OFDM_RATE ;
2008-05-15 12:55:29 +02:00
if ( ( info - > tx_rate_idx < 0 ) | |
2008-03-04 18:09:27 -08:00
( tbl_type . is_SGI ^
2008-05-15 12:55:29 +02:00
! ! ( info - > flags & IEEE80211_TX_CTL_SHORT_GI ) ) | |
2008-03-04 18:09:27 -08:00
( tbl_type . is_fat ^
2008-05-15 12:55:29 +02:00
! ! ( info - > flags & IEEE80211_TX_CTL_40_MHZ_WIDTH ) ) | |
2008-03-04 18:09:27 -08:00
( tbl_type . is_dup ^
2008-05-15 12:55:29 +02:00
! ! ( info - > flags & IEEE80211_TX_CTL_DUP_DATA ) ) | |
( tbl_type . ant_type ^ info - > antenna_sel_tx ) | |
2008-04-23 17:14:57 -07:00
( ! ! ( tx_rate & RATE_MCS_HT_MSK ) ^
2008-05-15 12:55:29 +02:00
! ! ( info - > flags & IEEE80211_TX_CTL_OFDM_HT ) ) | |
2008-04-23 17:14:57 -07:00
( ! ! ( tx_rate & RATE_MCS_GF_MSK ) ^
2008-05-15 12:55:29 +02:00
! ! ( info - > flags & IEEE80211_TX_CTL_GREEN_FIELD ) ) | |
2008-03-04 18:09:27 -08:00
( hw - > wiphy - > bands [ priv - > band ] - > bitrates [ rs_index ] . bitrate ! =
2008-05-15 12:55:29 +02:00
hw - > wiphy - > bands [ info - > band ] - > bitrates [ info - > tx_rate_idx ] . bitrate ) ) {
2008-04-23 17:14:57 -07:00
IWL_DEBUG_RATE ( " initial rate does not match 0x%x \n " , tx_rate ) ;
2008-03-05 11:31:00 -08:00
goto out ;
2007-09-25 17:54:57 -07:00
}
2007-11-29 11:09:44 +08:00
/* Update frame history window with "failure" for each Tx retry. */
2007-09-25 17:54:57 -07:00
while ( retries ) {
2007-11-29 11:09:44 +08:00
/* Look up the rate and other info used for each tx attempt.
* Each tx attempt steps one entry deeper in the rate table . */
2008-04-23 17:14:57 -07:00
tx_rate = le32_to_cpu ( table - > rs_table [ index ] . rate_n_flags ) ;
rs_get_tbl_info_from_mcs ( tx_rate , priv - > band ,
2007-09-25 17:54:57 -07:00
& tbl_type , & rs_index ) ;
2007-11-29 11:09:44 +08:00
/* If type matches "search" table,
* add failure to " search " history */
2007-09-25 17:54:57 -07:00
if ( ( tbl_type . lq_type = = search_tbl - > lq_type ) & &
2008-04-21 15:42:01 -07:00
( tbl_type . ant_type = = search_tbl - > ant_type ) & &
2007-09-25 17:54:57 -07:00
( tbl_type . is_SGI = = search_tbl - > is_SGI ) ) {
if ( search_tbl - > expected_tpt )
tpt = search_tbl - > expected_tpt [ rs_index ] ;
else
tpt = 0 ;
2008-01-28 14:07:25 +02:00
rs_collect_tx_data ( search_win , rs_index , tpt , 1 , 0 ) ;
2007-11-29 11:09:44 +08:00
/* Else if type matches "current/active" table,
* add failure to " current/active " history */
2007-09-25 17:54:57 -07:00
} else if ( ( tbl_type . lq_type = = curr_tbl - > lq_type ) & &
2008-04-21 15:42:01 -07:00
( tbl_type . ant_type = = curr_tbl - > ant_type ) & &
2007-09-25 17:54:57 -07:00
( tbl_type . is_SGI = = curr_tbl - > is_SGI ) ) {
if ( curr_tbl - > expected_tpt )
tpt = curr_tbl - > expected_tpt [ rs_index ] ;
else
tpt = 0 ;
2008-01-28 14:07:25 +02:00
rs_collect_tx_data ( window , rs_index , tpt , 1 , 0 ) ;
2007-09-25 17:54:57 -07:00
}
2007-11-29 11:09:44 +08:00
/* If not searching for a new mode, increment failed counter
* . . . this helps determine when to start searching again */
2008-01-14 17:46:21 -08:00
if ( lq_sta - > stay_in_tbl )
lq_sta - > total_failed + + ;
2007-09-25 17:54:57 -07:00
- - retries ;
index + + ;
}
2007-11-29 11:09:44 +08:00
/*
* Find ( by rate ) the history window to update with final Tx attempt ;
* if Tx was successful first try , use original rate ,
* else look up the rate that was , finally , successful .
*/
2008-04-23 17:14:57 -07:00
tx_rate = le32_to_cpu ( table - > rs_table [ index ] . rate_n_flags ) ;
rs_get_tbl_info_from_mcs ( tx_rate , priv - > band , & tbl_type , & rs_index ) ;
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:44 +08:00
/* Update frame history window with "success" if Tx got ACKed ... */
2008-05-15 12:55:29 +02:00
status = ! ! ( info - > flags & IEEE80211_TX_STAT_ACK ) ;
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:44 +08:00
/* If type matches "search" table,
* add final tx status to " search " history */
2007-09-25 17:54:57 -07:00
if ( ( tbl_type . lq_type = = search_tbl - > lq_type ) & &
2008-04-21 15:42:01 -07:00
( tbl_type . ant_type = = search_tbl - > ant_type ) & &
2007-09-25 17:54:57 -07:00
( tbl_type . is_SGI = = search_tbl - > is_SGI ) ) {
if ( search_tbl - > expected_tpt )
tpt = search_tbl - > expected_tpt [ rs_index ] ;
else
tpt = 0 ;
2008-05-15 12:55:29 +02:00
if ( info - > flags & IEEE80211_TX_CTL_AMPDU )
2008-01-28 14:07:25 +02:00
rs_collect_tx_data ( search_win , rs_index , tpt ,
2008-05-15 12:55:29 +02:00
info - > status . ampdu_ack_len ,
info - > status . ampdu_ack_map ) ;
2008-01-28 14:07:25 +02:00
else
rs_collect_tx_data ( search_win , rs_index , tpt ,
1 , status ) ;
2007-11-29 11:09:44 +08:00
/* Else if type matches "current/active" table,
* add final tx status to " current/active " history */
2007-09-25 17:54:57 -07:00
} else if ( ( tbl_type . lq_type = = curr_tbl - > lq_type ) & &
2008-04-21 15:42:01 -07:00
( tbl_type . ant_type = = curr_tbl - > ant_type ) & &
2007-09-25 17:54:57 -07:00
( tbl_type . is_SGI = = curr_tbl - > is_SGI ) ) {
if ( curr_tbl - > expected_tpt )
tpt = curr_tbl - > expected_tpt [ rs_index ] ;
else
tpt = 0 ;
2008-05-15 12:55:29 +02:00
if ( info - > flags & IEEE80211_TX_CTL_AMPDU )
2008-01-28 14:07:25 +02:00
rs_collect_tx_data ( window , rs_index , tpt ,
2008-05-15 12:55:29 +02:00
info - > status . ampdu_ack_len ,
info - > status . ampdu_ack_map ) ;
2008-01-28 14:07:25 +02:00
else
rs_collect_tx_data ( window , rs_index , tpt ,
1 , status ) ;
2007-09-25 17:54:57 -07:00
}
2007-11-29 11:09:44 +08:00
/* If not searching for new mode, increment success/failed counter
* . . . these help determine when to start searching again */
2008-01-14 17:46:21 -08:00
if ( lq_sta - > stay_in_tbl ) {
2008-05-15 12:55:29 +02:00
if ( info - > flags & IEEE80211_TX_CTL_AMPDU ) {
lq_sta - > total_success + = info - > status . ampdu_ack_map ;
2008-01-28 14:07:25 +02:00
lq_sta - > total_failed + =
2008-05-15 12:55:29 +02:00
( info - > status . ampdu_ack_len - info - > status . ampdu_ack_map ) ;
2008-01-28 14:07:25 +02:00
} else {
if ( status )
lq_sta - > total_success + + ;
else
lq_sta - > total_failed + + ;
}
2007-09-25 17:54:57 -07:00
}
2007-11-29 11:09:44 +08:00
/* See if there's a better rate or modulation mode to try. */
2007-09-25 17:54:57 -07:00
rs_rate_scale_perform ( priv , dev , hdr , sta ) ;
2008-03-05 11:31:00 -08:00
out :
2008-02-25 16:27:46 +01:00
rcu_read_unlock ( ) ;
2007-09-25 17:54:57 -07:00
return ;
}
2007-11-29 11:09:44 +08:00
/*
* Begin a period of staying with a selected modulation mode .
* Set " stay_in_tbl " flag to prevent any mode switches .
* Set frame tx success limits according to legacy vs . high - throughput ,
* and reset overall ( spanning all rates ) tx success history statistics .
* These control how long we stay using same modulation mode before
* searching for a new mode .
*/
2008-05-05 10:22:40 +08:00
static void rs_set_stay_in_table ( struct iwl_priv * priv , u8 is_legacy ,
2008-01-14 17:46:21 -08:00
struct iwl4965_lq_sta * lq_sta )
2007-09-25 17:54:57 -07:00
{
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " we are staying in the same table \n " ) ;
2008-01-14 17:46:21 -08:00
lq_sta - > stay_in_tbl = 1 ; /* only place this gets set */
2007-09-25 17:54:57 -07:00
if ( is_legacy ) {
2008-01-14 17:46:21 -08:00
lq_sta - > table_count_limit = IWL_LEGACY_TABLE_COUNT ;
lq_sta - > max_failure_limit = IWL_LEGACY_FAILURE_LIMIT ;
lq_sta - > max_success_limit = IWL_LEGACY_SUCCESS_LIMIT ;
2007-09-25 17:54:57 -07:00
} else {
2008-01-14 17:46:21 -08:00
lq_sta - > table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT ;
lq_sta - > max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT ;
lq_sta - > max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT ;
2007-09-25 17:54:57 -07:00
}
2008-01-14 17:46:21 -08:00
lq_sta - > table_count = 0 ;
lq_sta - > total_failed = 0 ;
lq_sta - > total_success = 0 ;
2007-09-25 17:54:57 -07:00
}
2007-11-29 11:09:44 +08:00
/*
* Find correct throughput table for given mode of modulation
*/
2008-04-23 17:14:58 -07:00
static void rs_set_expected_tpt_table ( struct iwl4965_lq_sta * lq_sta ,
2008-01-27 16:41:47 -08:00
struct iwl4965_scale_tbl_info * tbl )
2007-09-25 17:54:57 -07:00
{
if ( is_legacy ( tbl - > lq_type ) ) {
if ( ! is_a_band ( tbl - > lq_type ) )
tbl - > expected_tpt = expected_tpt_G ;
else
tbl - > expected_tpt = expected_tpt_A ;
} else if ( is_siso ( tbl - > lq_type ) ) {
2008-01-14 17:46:21 -08:00
if ( tbl - > is_fat & & ! lq_sta - > is_dup )
2007-09-25 17:54:57 -07:00
if ( tbl - > is_SGI )
tbl - > expected_tpt = expected_tpt_siso40MHzSGI ;
else
tbl - > expected_tpt = expected_tpt_siso40MHz ;
else if ( tbl - > is_SGI )
tbl - > expected_tpt = expected_tpt_siso20MHzSGI ;
else
tbl - > expected_tpt = expected_tpt_siso20MHz ;
2008-04-21 15:42:01 -07:00
} else if ( is_mimo ( tbl - > lq_type ) ) { /* FIXME:need to separate mimo2/3 */
2008-01-14 17:46:21 -08:00
if ( tbl - > is_fat & & ! lq_sta - > is_dup )
2007-09-25 17:54:57 -07:00
if ( tbl - > is_SGI )
tbl - > expected_tpt = expected_tpt_mimo40MHzSGI ;
else
tbl - > expected_tpt = expected_tpt_mimo40MHz ;
else if ( tbl - > is_SGI )
tbl - > expected_tpt = expected_tpt_mimo20MHzSGI ;
else
tbl - > expected_tpt = expected_tpt_mimo20MHz ;
} else
tbl - > expected_tpt = expected_tpt_G ;
}
2007-10-25 17:15:51 +08:00
# ifdef CONFIG_IWL4965_HT
2007-11-29 11:09:44 +08:00
/*
* Find starting rate for new " search " high - throughput mode of modulation .
* Goal is to find lowest expected rate ( under perfect conditions ) that is
* above the current measured throughput of " active " mode , to give new mode
* a fair chance to prove itself without too many challenges .
*
* This gets called when transitioning to more aggressive modulation
* ( i . e . legacy to SISO or MIMO , or SISO to MIMO ) , as well as less aggressive
* ( i . e . MIMO to SISO ) . When moving to MIMO , bit rate will typically need
* to decrease to match " active " throughput . When moving from MIMO to SISO ,
* bit rate will typically need to increase , but not if performance was bad .
*/
2008-03-12 16:58:50 -07:00
static s32 rs_get_best_rate ( struct iwl_priv * priv ,
2008-01-14 17:46:21 -08:00
struct iwl4965_lq_sta * lq_sta ,
2007-11-29 11:09:44 +08:00
struct iwl4965_scale_tbl_info * tbl , /* "search" */
2008-04-23 17:15:02 -07:00
u16 rate_mask , s8 index )
2007-09-25 17:54:57 -07:00
{
2007-11-29 11:09:44 +08:00
/* "active" values */
2008-01-27 16:41:47 -08:00
struct iwl4965_scale_tbl_info * active_tbl =
2008-01-14 17:46:21 -08:00
& ( lq_sta - > lq_info [ lq_sta - > active_tbl ] ) ;
2007-09-25 17:54:57 -07:00
s32 active_sr = active_tbl - > win [ index ] . success_ratio ;
s32 active_tpt = active_tbl - > expected_tpt [ index ] ;
2007-11-29 11:09:44 +08:00
/* expected "search" throughput */
s32 * tpt_tbl = tbl - > expected_tpt ;
s32 new_rate , high , low , start_hi ;
2007-09-25 17:54:57 -07:00
u16 high_low ;
2008-04-23 17:15:02 -07:00
s8 rate = index ;
2007-09-25 17:54:57 -07:00
new_rate = high = low = start_hi = IWL_RATE_INVALID ;
for ( ; ; ) {
2008-05-05 10:22:40 +08:00
high_low = rs_get_adjacent_rate ( priv , rate , rate_mask ,
tbl - > lq_type ) ;
2007-09-25 17:54:57 -07:00
low = high_low & 0xff ;
high = ( high_low > > 8 ) & 0xff ;
2007-11-29 11:09:44 +08:00
/*
* Lower the " search " bit rate , to give new " search " mode
* approximately the same throughput as " active " if :
*
* 1 ) " Active " mode has been working modestly well ( but not
* great ) , and expected " search " throughput ( under perfect
* conditions ) at candidate rate is above the actual
* measured " active " throughput ( but less than expected
* " active " throughput under perfect conditions ) .
* OR
* 2 ) " Active " mode has been working perfectly or very well
* and expected " search " throughput ( under perfect
* conditions ) at candidate rate is above expected
* " active " throughput ( under perfect conditions ) .
*/
2008-01-14 17:46:21 -08:00
if ( ( ( ( 100 * tpt_tbl [ rate ] ) > lq_sta - > last_tpt ) & &
2007-09-25 17:54:57 -07:00
( ( active_sr > IWL_RATE_DECREASE_TH ) & &
( active_sr < = IWL_RATE_HIGH_TH ) & &
( tpt_tbl [ rate ] < = active_tpt ) ) ) | |
( ( active_sr > = IWL_RATE_SCALE_SWITCH ) & &
( tpt_tbl [ rate ] > active_tpt ) ) ) {
2007-11-29 11:09:44 +08:00
/* (2nd or later pass)
* If we ' ve already tried to raise the rate , and are
* now trying to lower it , use the higher rate . */
2007-09-25 17:54:57 -07:00
if ( start_hi ! = IWL_RATE_INVALID ) {
new_rate = start_hi ;
break ;
}
2007-11-29 11:09:44 +08:00
2007-09-25 17:54:57 -07:00
new_rate = rate ;
2007-11-29 11:09:44 +08:00
/* Loop again with lower rate */
2007-09-25 17:54:57 -07:00
if ( low ! = IWL_RATE_INVALID )
rate = low ;
2007-11-29 11:09:44 +08:00
/* Lower rate not available, use the original */
2007-09-25 17:54:57 -07:00
else
break ;
2007-11-29 11:09:44 +08:00
/* Else try to raise the "search" rate to match "active" */
2007-09-25 17:54:57 -07:00
} else {
2007-11-29 11:09:44 +08:00
/* (2nd or later pass)
* If we ' ve already tried to lower the rate , and are
* now trying to raise it , use the lower rate . */
2007-09-25 17:54:57 -07:00
if ( new_rate ! = IWL_RATE_INVALID )
break ;
2007-11-29 11:09:44 +08:00
/* Loop again with higher rate */
2007-09-25 17:54:57 -07:00
else if ( high ! = IWL_RATE_INVALID ) {
start_hi = high ;
rate = high ;
2007-11-29 11:09:44 +08:00
/* Higher rate not available, use the original */
2007-09-25 17:54:57 -07:00
} else {
new_rate = rate ;
break ;
}
}
}
return new_rate ;
}
2007-10-25 17:15:51 +08:00
# endif /* CONFIG_IWL4965_HT */
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:44 +08:00
/*
* Set up search table for MIMO
*/
2008-04-21 15:42:01 -07:00
# ifdef CONFIG_IWL4965_HT
static int rs_switch_to_mimo2 ( struct iwl_priv * priv ,
2008-01-14 17:46:21 -08:00
struct iwl4965_lq_sta * lq_sta ,
2007-11-26 16:14:41 +02:00
struct ieee80211_conf * conf ,
struct sta_info * sta ,
2008-01-27 16:41:47 -08:00
struct iwl4965_scale_tbl_info * tbl , int index )
2007-09-25 17:54:57 -07:00
{
u16 rate_mask ;
s32 rate ;
2008-01-14 17:46:21 -08:00
s8 is_green = lq_sta - > is_green ;
2007-09-25 17:54:57 -07:00
2007-11-26 16:14:41 +02:00
if ( ! ( conf - > flags & IEEE80211_CONF_SUPPORT_HT_MODE ) | |
! sta - > ht_info . ht_supported )
2007-09-25 17:54:57 -07:00
return - 1 ;
2007-11-26 16:14:41 +02:00
if ( priv - > current_ht_config . tx_mimo_ps_mode = = IWL_MIMO_PS_STATIC )
2007-09-25 17:54:57 -07:00
return - 1 ;
2007-11-29 11:09:44 +08:00
/* Need both Tx chains/antennas to support MIMO */
2008-04-23 17:14:59 -07:00
if ( priv - > hw_params . tx_chains_num < 2 )
2007-09-25 17:54:57 -07:00
return - 1 ;
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " LQ: try to switch to MIMO2 \n " ) ;
2008-04-23 17:14:57 -07:00
tbl - > lq_type = LQ_MIMO2 ;
2008-01-14 17:46:21 -08:00
tbl - > is_dup = lq_sta - > is_dup ;
2007-09-25 17:54:57 -07:00
tbl - > action = 0 ;
2008-04-23 17:14:57 -07:00
rate_mask = lq_sta - > active_mimo2_rate ;
2007-11-26 16:14:41 +02:00
if ( priv - > current_ht_config . supported_chan_width
2008-04-23 17:14:57 -07:00
= = IWL_CHANNEL_WIDTH_40MHZ )
2007-09-25 17:54:57 -07:00
tbl - > is_fat = 1 ;
else
tbl - > is_fat = 0 ;
2008-04-23 17:14:57 -07:00
/* FIXME: - don't toggle SGI here
2007-09-25 17:54:57 -07:00
if ( tbl - > is_fat ) {
2007-11-26 16:14:41 +02:00
if ( priv - > current_ht_config . sgf & HT_SHORT_GI_40MHZ_ONLY )
2007-09-25 17:54:57 -07:00
tbl - > is_SGI = 1 ;
else
tbl - > is_SGI = 0 ;
2007-11-26 16:14:41 +02:00
} else if ( priv - > current_ht_config . sgf & HT_SHORT_GI_20MHZ_ONLY )
2007-09-25 17:54:57 -07:00
tbl - > is_SGI = 1 ;
else
tbl - > is_SGI = 0 ;
2008-04-23 17:14:57 -07:00
*/
2007-09-25 17:54:57 -07:00
2008-04-23 17:14:58 -07:00
rs_set_expected_tpt_table ( lq_sta , tbl ) ;
2007-09-25 17:54:57 -07:00
2008-04-23 17:15:02 -07:00
rate = rs_get_best_rate ( priv , lq_sta , tbl , rate_mask , index ) ;
2007-09-25 17:54:57 -07:00
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " LQ: MIMO2 best rate %d mask %X \n " , rate , rate_mask ) ;
2008-04-23 17:14:57 -07:00
if ( ( rate = = IWL_RATE_INVALID ) | | ! ( ( 1 < < rate ) & rate_mask ) ) {
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " Can't switch with index %d rate mask %x \n " ,
2008-04-23 17:14:57 -07:00
rate , rate_mask ) ;
2007-09-25 17:54:57 -07:00
return - 1 ;
2008-04-23 17:14:57 -07:00
}
tbl - > current_rate = rate_n_flags_from_tbl ( tbl , rate , is_green ) ;
2007-09-25 17:54:57 -07:00
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " LQ: Switch to new mcs %X index is green %X \n " ,
2008-04-23 17:14:57 -07:00
tbl - > current_rate , is_green ) ;
2007-10-25 17:15:25 +08:00
return 0 ;
2008-04-21 15:42:01 -07:00
}
2007-11-06 22:06:25 -08:00
# else
2008-04-21 15:42:01 -07:00
static int rs_switch_to_mimo2 ( struct iwl_priv * priv ,
struct iwl4965_lq_sta * lq_sta ,
struct ieee80211_conf * conf ,
struct sta_info * sta ,
struct iwl4965_scale_tbl_info * tbl , int index )
{
2007-11-06 22:06:25 -08:00
return - 1 ;
2007-09-25 17:54:57 -07:00
}
2008-04-21 15:42:01 -07:00
# endif /*CONFIG_IWL4965_HT */
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:44 +08:00
/*
* Set up search table for SISO
*/
2008-03-12 16:58:50 -07:00
static int rs_switch_to_siso ( struct iwl_priv * priv ,
2008-01-14 17:46:21 -08:00
struct iwl4965_lq_sta * lq_sta ,
2007-11-26 16:14:41 +02:00
struct ieee80211_conf * conf ,
struct sta_info * sta ,
2008-01-27 16:41:47 -08:00
struct iwl4965_scale_tbl_info * tbl , int index )
2007-09-25 17:54:57 -07:00
{
2007-10-25 17:15:51 +08:00
# ifdef CONFIG_IWL4965_HT
2007-09-25 17:54:57 -07:00
u16 rate_mask ;
2008-01-14 17:46:21 -08:00
u8 is_green = lq_sta - > is_green ;
2007-09-25 17:54:57 -07:00
s32 rate ;
2007-11-26 16:14:41 +02:00
if ( ! ( conf - > flags & IEEE80211_CONF_SUPPORT_HT_MODE ) | |
! sta - > ht_info . ht_supported )
2007-09-25 17:54:57 -07:00
return - 1 ;
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " LQ: try to switch to SISO \n " ) ;
2008-04-23 17:14:57 -07:00
2008-01-14 17:46:21 -08:00
tbl - > is_dup = lq_sta - > is_dup ;
2007-09-25 17:54:57 -07:00
tbl - > lq_type = LQ_SISO ;
tbl - > action = 0 ;
2008-04-23 17:14:57 -07:00
rate_mask = lq_sta - > active_siso_rate ;
2007-09-25 17:54:57 -07:00
2007-11-26 16:14:41 +02:00
if ( priv - > current_ht_config . supported_chan_width
= = IWL_CHANNEL_WIDTH_40MHZ )
2007-09-25 17:54:57 -07:00
tbl - > is_fat = 1 ;
else
tbl - > is_fat = 0 ;
2008-04-23 17:14:57 -07:00
/* FIXME: - don't toggle SGI here
2007-09-25 17:54:57 -07:00
if ( tbl - > is_fat ) {
2007-11-26 16:14:41 +02:00
if ( priv - > current_ht_config . sgf & HT_SHORT_GI_40MHZ_ONLY )
2007-09-25 17:54:57 -07:00
tbl - > is_SGI = 1 ;
else
tbl - > is_SGI = 0 ;
2007-11-26 16:14:41 +02:00
} else if ( priv - > current_ht_config . sgf & HT_SHORT_GI_20MHZ_ONLY )
2007-09-25 17:54:57 -07:00
tbl - > is_SGI = 1 ;
else
tbl - > is_SGI = 0 ;
2008-04-23 17:14:57 -07:00
*/
2007-09-25 17:54:57 -07:00
if ( is_green )
2008-04-23 17:14:57 -07:00
tbl - > is_SGI = 0 ; /*11n spec: no SGI in SISO+Greenfield*/
2007-09-25 17:54:57 -07:00
2008-04-23 17:14:58 -07:00
rs_set_expected_tpt_table ( lq_sta , tbl ) ;
2008-04-23 17:15:02 -07:00
rate = rs_get_best_rate ( priv , lq_sta , tbl , rate_mask , index ) ;
2007-09-25 17:54:57 -07:00
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " LQ: get best rate %d mask %X \n " , rate , rate_mask ) ;
2007-09-25 17:54:57 -07:00
if ( ( rate = = IWL_RATE_INVALID ) | | ! ( ( 1 < < rate ) & rate_mask ) ) {
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " can not switch with index %d rate mask %x \n " ,
2007-09-25 17:54:57 -07:00
rate , rate_mask ) ;
return - 1 ;
}
2008-04-23 17:14:57 -07:00
tbl - > current_rate = rate_n_flags_from_tbl ( tbl , rate , is_green ) ;
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " LQ: Switch to new mcs %X index is green %X \n " ,
2008-04-23 17:14:57 -07:00
tbl - > current_rate , is_green ) ;
2007-11-06 22:06:25 -08:00
return 0 ;
# else
return - 1 ;
2008-01-28 14:07:26 +02:00
# endif /*CONFIG_IWL4965_HT */
2007-09-25 17:54:57 -07:00
}
2007-11-29 11:09:44 +08:00
/*
* Try to switch to new modulation mode from legacy
*/
2008-03-12 16:58:50 -07:00
static int rs_move_legacy_other ( struct iwl_priv * priv ,
2008-01-14 17:46:21 -08:00
struct iwl4965_lq_sta * lq_sta ,
2007-11-26 16:14:41 +02:00
struct ieee80211_conf * conf ,
struct sta_info * sta ,
2007-09-25 17:54:57 -07:00
int index )
{
2008-01-27 16:41:47 -08:00
struct iwl4965_scale_tbl_info * tbl =
2008-01-14 17:46:21 -08:00
& ( lq_sta - > lq_info [ lq_sta - > active_tbl ] ) ;
2008-01-27 16:41:47 -08:00
struct iwl4965_scale_tbl_info * search_tbl =
2008-01-14 17:46:21 -08:00
& ( lq_sta - > lq_info [ ( 1 - lq_sta - > active_tbl ) ] ) ;
2008-01-27 16:41:47 -08:00
struct iwl4965_rate_scale_data * window = & ( tbl - > win [ index ] ) ;
u32 sz = ( sizeof ( struct iwl4965_scale_tbl_info ) -
( sizeof ( struct iwl4965_rate_scale_data ) * IWL_RATE_COUNT ) ) ;
2007-09-25 17:54:57 -07:00
u8 start_action = tbl - > action ;
2008-04-21 15:42:01 -07:00
u8 valid_tx_ant = priv - > hw_params . valid_tx_ant ;
int ret = 0 ;
2007-09-25 17:54:57 -07:00
for ( ; ; ) {
switch ( tbl - > action ) {
case IWL_LEGACY_SWITCH_ANTENNA :
2008-04-23 17:15:02 -07:00
IWL_DEBUG_RATE ( " LQ: Legacy toggle Antenna \n " ) ;
2007-09-25 17:54:57 -07:00
2008-01-14 17:46:21 -08:00
lq_sta - > action_counter + + ;
2007-11-29 11:09:44 +08:00
/* Don't change antenna if success has been great */
2007-09-25 17:54:57 -07:00
if ( window - > success_ratio > = IWL_RS_GOOD_RATIO )
break ;
2007-11-29 11:09:44 +08:00
/* Set up search table to try other antenna */
2007-09-25 17:54:57 -07:00
memcpy ( search_tbl , tbl , sz ) ;
2008-04-23 17:14:59 -07:00
if ( rs_toggle_antenna ( valid_tx_ant ,
& search_tbl - > current_rate , search_tbl ) ) {
lq_sta - > search_better_tbl = 1 ;
goto out ;
}
2007-09-25 17:54:57 -07:00
case IWL_LEGACY_SWITCH_SISO :
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " LQ: Legacy switch to SISO \n " ) ;
2007-11-29 11:09:44 +08:00
/* Set up search table to try SISO */
2007-09-25 17:54:57 -07:00
memcpy ( search_tbl , tbl , sz ) ;
search_tbl - > is_SGI = 0 ;
2008-01-14 17:46:21 -08:00
ret = rs_switch_to_siso ( priv , lq_sta , conf , sta ,
2007-11-26 16:14:41 +02:00
search_tbl , index ) ;
2007-10-25 17:15:25 +08:00
if ( ! ret ) {
2008-01-14 17:46:21 -08:00
lq_sta - > search_better_tbl = 1 ;
lq_sta - > action_counter = 0 ;
2007-09-25 17:54:57 -07:00
goto out ;
2007-10-25 17:15:25 +08:00
}
2007-09-25 17:54:57 -07:00
break ;
2008-04-21 15:42:01 -07:00
case IWL_LEGACY_SWITCH_MIMO2 :
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " LQ: Legacy switch to MIMO2 \n " ) ;
2007-11-29 11:09:44 +08:00
/* Set up search table to try MIMO */
2007-09-25 17:54:57 -07:00
memcpy ( search_tbl , tbl , sz ) ;
search_tbl - > is_SGI = 0 ;
2008-04-21 15:42:01 -07:00
search_tbl - > ant_type = ANT_AB ; /*FIXME:RS*/
/*FIXME:RS:need to check ant validity*/
ret = rs_switch_to_mimo2 ( priv , lq_sta , conf , sta ,
2007-11-26 16:14:41 +02:00
search_tbl , index ) ;
2007-10-25 17:15:25 +08:00
if ( ! ret ) {
2008-01-14 17:46:21 -08:00
lq_sta - > search_better_tbl = 1 ;
lq_sta - > action_counter = 0 ;
2007-09-25 17:54:57 -07:00
goto out ;
2007-10-25 17:15:25 +08:00
}
2007-09-25 17:54:57 -07:00
break ;
}
tbl - > action + + ;
2008-04-21 15:42:01 -07:00
if ( tbl - > action > IWL_LEGACY_SWITCH_MIMO2 )
2007-09-25 17:54:57 -07:00
tbl - > action = IWL_LEGACY_SWITCH_ANTENNA ;
if ( tbl - > action = = start_action )
break ;
}
return 0 ;
out :
tbl - > action + + ;
2008-04-21 15:42:01 -07:00
if ( tbl - > action > IWL_LEGACY_SWITCH_MIMO2 )
2007-09-25 17:54:57 -07:00
tbl - > action = IWL_LEGACY_SWITCH_ANTENNA ;
return 0 ;
}
2007-11-29 11:09:44 +08:00
/*
* Try to switch to new modulation mode from SISO
*/
2008-03-12 16:58:50 -07:00
static int rs_move_siso_to_other ( struct iwl_priv * priv ,
2008-01-14 17:46:21 -08:00
struct iwl4965_lq_sta * lq_sta ,
2007-11-26 16:14:41 +02:00
struct ieee80211_conf * conf ,
struct sta_info * sta ,
2007-09-25 17:54:57 -07:00
int index )
{
2008-01-14 17:46:21 -08:00
u8 is_green = lq_sta - > is_green ;
2008-01-27 16:41:47 -08:00
struct iwl4965_scale_tbl_info * tbl =
2008-01-14 17:46:21 -08:00
& ( lq_sta - > lq_info [ lq_sta - > active_tbl ] ) ;
2008-01-27 16:41:47 -08:00
struct iwl4965_scale_tbl_info * search_tbl =
2008-01-14 17:46:21 -08:00
& ( lq_sta - > lq_info [ ( 1 - lq_sta - > active_tbl ) ] ) ;
2008-01-27 16:41:47 -08:00
struct iwl4965_rate_scale_data * window = & ( tbl - > win [ index ] ) ;
u32 sz = ( sizeof ( struct iwl4965_scale_tbl_info ) -
( sizeof ( struct iwl4965_rate_scale_data ) * IWL_RATE_COUNT ) ) ;
2007-09-25 17:54:57 -07:00
u8 start_action = tbl - > action ;
2008-04-21 15:42:01 -07:00
u8 valid_tx_ant = priv - > hw_params . valid_tx_ant ;
int ret ;
2007-09-25 17:54:57 -07:00
for ( ; ; ) {
2008-01-14 17:46:21 -08:00
lq_sta - > action_counter + + ;
2007-09-25 17:54:57 -07:00
switch ( tbl - > action ) {
case IWL_SISO_SWITCH_ANTENNA :
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " LQ: SISO toggle Antenna \n " ) ;
2007-09-25 17:54:57 -07:00
if ( window - > success_ratio > = IWL_RS_GOOD_RATIO )
break ;
memcpy ( search_tbl , tbl , sz ) ;
2008-04-23 17:14:59 -07:00
if ( rs_toggle_antenna ( valid_tx_ant ,
& search_tbl - > current_rate , search_tbl ) ) {
lq_sta - > search_better_tbl = 1 ;
goto out ;
}
2007-09-25 17:54:57 -07:00
2008-04-21 15:42:01 -07:00
case IWL_SISO_SWITCH_MIMO2 :
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " LQ: SISO switch to MIMO \n " ) ;
2007-09-25 17:54:57 -07:00
memcpy ( search_tbl , tbl , sz ) ;
search_tbl - > is_SGI = 0 ;
2008-04-21 15:42:01 -07:00
search_tbl - > ant_type = ANT_AB ; /*FIXME:RS*/
ret = rs_switch_to_mimo2 ( priv , lq_sta , conf , sta ,
2007-11-26 16:14:41 +02:00
search_tbl , index ) ;
2007-10-25 17:15:25 +08:00
if ( ! ret ) {
2008-01-14 17:46:21 -08:00
lq_sta - > search_better_tbl = 1 ;
2007-09-25 17:54:57 -07:00
goto out ;
2007-10-25 17:15:25 +08:00
}
2007-09-25 17:54:57 -07:00
break ;
case IWL_SISO_SWITCH_GI :
2008-05-15 13:54:08 +08:00
if ( ! tbl - > is_fat & &
! ( priv - > current_ht_config . sgf &
HT_SHORT_GI_20MHZ ) )
break ;
if ( tbl - > is_fat & &
! ( priv - > current_ht_config . sgf &
HT_SHORT_GI_40MHZ ) )
break ;
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " LQ: SISO toggle SGI/NGI \n " ) ;
2008-01-28 14:07:26 +02:00
2007-09-25 17:54:57 -07:00
memcpy ( search_tbl , tbl , sz ) ;
2008-04-23 17:14:57 -07:00
if ( is_green ) {
if ( ! tbl - > is_SGI )
break ;
else
IWL_ERROR ( " SGI was set in GF+SISO \n " ) ;
2007-09-25 17:54:57 -07:00
}
2008-04-23 17:14:57 -07:00
search_tbl - > is_SGI = ! tbl - > is_SGI ;
2008-04-23 17:14:58 -07:00
rs_set_expected_tpt_table ( lq_sta , search_tbl ) ;
2008-04-23 17:14:57 -07:00
if ( tbl - > is_SGI ) {
s32 tpt = lq_sta - > last_tpt / 100 ;
if ( tpt > = search_tbl - > expected_tpt [ index ] )
break ;
}
search_tbl - > current_rate = rate_n_flags_from_tbl (
search_tbl , index , is_green ) ;
lq_sta - > search_better_tbl = 1 ;
2007-09-25 17:54:57 -07:00
goto out ;
}
tbl - > action + + ;
if ( tbl - > action > IWL_SISO_SWITCH_GI )
tbl - > action = IWL_SISO_SWITCH_ANTENNA ;
if ( tbl - > action = = start_action )
break ;
}
return 0 ;
out :
tbl - > action + + ;
if ( tbl - > action > IWL_SISO_SWITCH_GI )
tbl - > action = IWL_SISO_SWITCH_ANTENNA ;
return 0 ;
}
2007-11-29 11:09:44 +08:00
/*
* Try to switch to new modulation mode from MIMO
*/
2008-03-12 16:58:50 -07:00
static int rs_move_mimo_to_other ( struct iwl_priv * priv ,
2008-01-14 17:46:21 -08:00
struct iwl4965_lq_sta * lq_sta ,
2007-11-26 16:14:41 +02:00
struct ieee80211_conf * conf ,
struct sta_info * sta ,
2007-09-25 17:54:57 -07:00
int index )
{
2008-01-14 17:46:21 -08:00
s8 is_green = lq_sta - > is_green ;
2008-01-27 16:41:47 -08:00
struct iwl4965_scale_tbl_info * tbl =
2008-01-14 17:46:21 -08:00
& ( lq_sta - > lq_info [ lq_sta - > active_tbl ] ) ;
2008-01-27 16:41:47 -08:00
struct iwl4965_scale_tbl_info * search_tbl =
2008-01-14 17:46:21 -08:00
& ( lq_sta - > lq_info [ ( 1 - lq_sta - > active_tbl ) ] ) ;
2008-01-27 16:41:47 -08:00
u32 sz = ( sizeof ( struct iwl4965_scale_tbl_info ) -
( sizeof ( struct iwl4965_rate_scale_data ) * IWL_RATE_COUNT ) ) ;
2007-09-25 17:54:57 -07:00
u8 start_action = tbl - > action ;
2008-04-23 17:14:59 -07:00
/*u8 valid_tx_ant = priv->hw_params.valid_tx_ant;*/
int ret ;
2007-09-25 17:54:57 -07:00
for ( ; ; ) {
2008-01-14 17:46:21 -08:00
lq_sta - > action_counter + + ;
2007-09-25 17:54:57 -07:00
switch ( tbl - > action ) {
case IWL_MIMO_SWITCH_ANTENNA_A :
case IWL_MIMO_SWITCH_ANTENNA_B :
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " LQ: MIMO2 switch to SISO \n " ) ;
2008-01-28 14:07:26 +02:00
2007-11-29 11:09:44 +08:00
/* Set up new search table for SISO */
2007-09-25 17:54:57 -07:00
memcpy ( search_tbl , tbl , sz ) ;
2008-04-23 17:14:57 -07:00
/*FIXME:RS:need to check ant validity + C*/
2007-09-25 17:54:57 -07:00
if ( tbl - > action = = IWL_MIMO_SWITCH_ANTENNA_A )
2008-04-21 15:42:01 -07:00
search_tbl - > ant_type = ANT_A ;
2007-09-25 17:54:57 -07:00
else
2008-04-21 15:42:01 -07:00
search_tbl - > ant_type = ANT_B ;
2007-09-25 17:54:57 -07:00
2008-01-14 17:46:21 -08:00
ret = rs_switch_to_siso ( priv , lq_sta , conf , sta ,
2007-11-26 16:14:41 +02:00
search_tbl , index ) ;
2007-10-25 17:15:25 +08:00
if ( ! ret ) {
2008-01-14 17:46:21 -08:00
lq_sta - > search_better_tbl = 1 ;
2007-09-25 17:54:57 -07:00
goto out ;
}
break ;
case IWL_MIMO_SWITCH_GI :
2008-05-15 13:54:08 +08:00
if ( ! tbl - > is_fat & &
! ( priv - > current_ht_config . sgf &
HT_SHORT_GI_20MHZ ) )
break ;
if ( tbl - > is_fat & &
! ( priv - > current_ht_config . sgf &
HT_SHORT_GI_40MHZ ) )
break ;
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " LQ: MIMO toggle SGI/NGI \n " ) ;
2007-11-29 11:09:44 +08:00
/* Set up new search table for MIMO */
2007-09-25 17:54:57 -07:00
memcpy ( search_tbl , tbl , sz ) ;
2008-04-23 17:14:57 -07:00
search_tbl - > is_SGI = ! tbl - > is_SGI ;
2008-04-23 17:14:58 -07:00
rs_set_expected_tpt_table ( lq_sta , search_tbl ) ;
2007-11-29 11:09:44 +08:00
/*
* If active table already uses the fastest possible
* modulation ( dual stream with short guard interval ) ,
* and it ' s working well , there ' s no need to look
* for a better type of modulation !
*/
2008-04-23 17:14:57 -07:00
if ( tbl - > is_SGI ) {
2008-01-14 17:46:21 -08:00
s32 tpt = lq_sta - > last_tpt / 100 ;
2008-04-23 17:14:57 -07:00
if ( tpt > = search_tbl - > expected_tpt [ index ] )
break ;
2007-09-25 17:54:57 -07:00
}
2008-04-23 17:14:57 -07:00
search_tbl - > current_rate = rate_n_flags_from_tbl (
search_tbl , index , is_green ) ;
lq_sta - > search_better_tbl = 1 ;
2007-09-25 17:54:57 -07:00
goto out ;
}
tbl - > action + + ;
if ( tbl - > action > IWL_MIMO_SWITCH_GI )
tbl - > action = IWL_MIMO_SWITCH_ANTENNA_A ;
if ( tbl - > action = = start_action )
break ;
}
return 0 ;
out :
tbl - > action + + ;
if ( tbl - > action > IWL_MIMO_SWITCH_GI )
tbl - > action = IWL_MIMO_SWITCH_ANTENNA_A ;
return 0 ;
}
2007-11-29 11:09:44 +08:00
/*
* Check whether we should continue using same modulation mode , or
* begin search for a new mode , based on :
* 1 ) # tx successes or failures while using this mode
* 2 ) # times calling this function
* 3 ) elapsed time in this mode ( not used , for now )
*/
2008-01-14 17:46:21 -08:00
static void rs_stay_in_table ( struct iwl4965_lq_sta * lq_sta )
2007-09-25 17:54:57 -07:00
{
2008-01-27 16:41:47 -08:00
struct iwl4965_scale_tbl_info * tbl ;
2007-09-25 17:54:57 -07:00
int i ;
int active_tbl ;
int flush_interval_passed = 0 ;
2008-05-05 10:22:40 +08:00
struct iwl_priv * priv ;
2007-09-25 17:54:57 -07:00
2008-05-05 10:22:40 +08:00
priv = lq_sta - > drv ;
2008-01-14 17:46:21 -08:00
active_tbl = lq_sta - > active_tbl ;
2007-09-25 17:54:57 -07:00
2008-01-14 17:46:21 -08:00
tbl = & ( lq_sta - > lq_info [ active_tbl ] ) ;
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:44 +08:00
/* If we've been disallowing search, see if we should now allow it */
2008-01-14 17:46:21 -08:00
if ( lq_sta - > stay_in_tbl ) {
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:44 +08:00
/* Elapsed time using current modulation mode */
2008-01-14 17:46:21 -08:00
if ( lq_sta - > flush_timer )
2007-09-25 17:54:57 -07:00
flush_interval_passed =
time_after ( jiffies ,
2008-01-14 17:46:21 -08:00
( unsigned long ) ( lq_sta - > flush_timer +
2007-09-25 17:54:57 -07:00
IWL_RATE_SCALE_FLUSH_INTVL ) ) ;
2007-11-29 11:09:44 +08:00
/*
* Check if we should allow search for new modulation mode .
* If many frames have failed or succeeded , or we ' ve used
* this same modulation for a long time , allow search , and
* reset history stats that keep track of whether we should
* allow a new search . Also ( below ) reset all bitmaps and
* stats in active history .
*/
2008-01-14 17:46:21 -08:00
if ( ( lq_sta - > total_failed > lq_sta - > max_failure_limit ) | |
( lq_sta - > total_success > lq_sta - > max_success_limit ) | |
( ( ! lq_sta - > search_better_tbl ) & & ( lq_sta - > flush_timer )
2007-09-25 17:54:57 -07:00
& & ( flush_interval_passed ) ) ) {
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " LQ: stay is expired %d %d %d \n : " ,
2008-01-14 17:46:21 -08:00
lq_sta - > total_failed ,
lq_sta - > total_success ,
2007-09-25 17:54:57 -07:00
flush_interval_passed ) ;
2007-11-29 11:09:44 +08:00
/* Allow search for new mode */
2008-01-14 17:46:21 -08:00
lq_sta - > stay_in_tbl = 0 ; /* only place reset */
lq_sta - > total_failed = 0 ;
lq_sta - > total_success = 0 ;
lq_sta - > flush_timer = 0 ;
2007-11-29 11:09:44 +08:00
/*
* Else if we ' ve used this modulation mode enough repetitions
* ( regardless of elapsed time or success / failure ) , reset
* history bitmaps and rate - specific stats for all rates in
* active table .
*/
2007-11-06 22:06:25 -08:00
} else {
2008-01-14 17:46:21 -08:00
lq_sta - > table_count + + ;
if ( lq_sta - > table_count > =
lq_sta - > table_count_limit ) {
lq_sta - > table_count = 0 ;
2007-09-25 17:54:57 -07:00
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " LQ: stay in table clear win \n " ) ;
2007-09-25 17:54:57 -07:00
for ( i = 0 ; i < IWL_RATE_COUNT ; i + + )
rs_rate_scale_clear_window (
& ( tbl - > win [ i ] ) ) ;
}
}
2007-11-29 11:09:44 +08:00
/* If transitioning to allow "search", reset all history
* bitmaps and stats in active table ( this will become the new
* " search " table ) . */
2008-01-14 17:46:21 -08:00
if ( ! lq_sta - > stay_in_tbl ) {
2007-09-25 17:54:57 -07:00
for ( i = 0 ; i < IWL_RATE_COUNT ; i + + )
rs_rate_scale_clear_window ( & ( tbl - > win [ i ] ) ) ;
}
}
}
2007-11-29 11:09:44 +08:00
/*
* Do rate scaling and search for new modulation mode .
*/
2008-03-12 16:58:50 -07:00
static void rs_rate_scale_perform ( struct iwl_priv * priv ,
2007-09-25 17:54:57 -07:00
struct net_device * dev ,
struct ieee80211_hdr * hdr ,
struct sta_info * sta )
{
2007-11-26 16:14:41 +02:00
struct ieee80211_local * local = wdev_priv ( dev - > ieee80211_ptr ) ;
struct ieee80211_hw * hw = local_to_hw ( local ) ;
struct ieee80211_conf * conf = & hw - > conf ;
2007-09-25 17:54:57 -07:00
int low = IWL_RATE_INVALID ;
int high = IWL_RATE_INVALID ;
int index ;
int i ;
2008-01-27 16:41:47 -08:00
struct iwl4965_rate_scale_data * window = NULL ;
2007-09-25 17:54:57 -07:00
int current_tpt = IWL_INVALID_VALUE ;
int low_tpt = IWL_INVALID_VALUE ;
int high_tpt = IWL_INVALID_VALUE ;
u32 fail_count ;
s8 scale_action = 0 ;
u16 fc , rate_mask ;
u8 update_lq = 0 ;
2008-01-14 17:46:21 -08:00
struct iwl4965_lq_sta * lq_sta ;
2008-01-27 16:41:47 -08:00
struct iwl4965_scale_tbl_info * tbl , * tbl1 ;
2007-09-25 17:54:57 -07:00
u16 rate_scale_index_msk = 0 ;
2008-04-23 17:14:57 -07:00
u32 rate ;
2007-09-25 17:54:57 -07:00
u8 is_green = 0 ;
u8 active_tbl = 0 ;
u8 done_search = 0 ;
u16 high_low ;
2008-01-28 14:07:26 +02:00
# ifdef CONFIG_IWL4965_HT
u8 tid = MAX_TID_COUNT ;
# endif
2007-09-25 17:54:57 -07:00
IWL_DEBUG_RATE ( " rate scale calculate new rate for skb \n " ) ;
fc = le16_to_cpu ( hdr - > frame_control ) ;
if ( ! ieee80211_is_data ( fc ) | | is_multicast_ether_addr ( hdr - > addr1 ) ) {
/* Send management frames and broadcast/multicast data using
* lowest rate . */
/* TODO: this could probably be improved.. */
return ;
}
if ( ! sta | | ! sta - > rate_ctrl_priv )
return ;
if ( ! priv - > lq_mngr . lq_ready ) {
IWL_DEBUG_RATE ( " still rate scaling not ready \n " ) ;
return ;
}
2008-01-14 17:46:21 -08:00
lq_sta = ( struct iwl4965_lq_sta * ) sta - > rate_ctrl_priv ;
2007-09-25 17:54:57 -07:00
2008-01-28 14:07:26 +02:00
# ifdef CONFIG_IWL4965_HT
2008-05-15 13:54:06 +08:00
rs_tl_add_packet ( lq_sta , hdr ) ;
2008-01-28 14:07:26 +02:00
# endif
2007-11-29 11:09:44 +08:00
/*
* Select rate - scale / modulation - mode table to work with in
* the rest of this function : " search " if searching for better
* modulation mode , or " active " if doing rate scaling within a mode .
*/
2008-01-14 17:46:21 -08:00
if ( ! lq_sta - > search_better_tbl )
active_tbl = lq_sta - > active_tbl ;
2007-09-25 17:54:57 -07:00
else
2008-01-14 17:46:21 -08:00
active_tbl = 1 - lq_sta - > active_tbl ;
2007-09-25 17:54:57 -07:00
2008-01-14 17:46:21 -08:00
tbl = & ( lq_sta - > lq_info [ active_tbl ] ) ;
is_green = lq_sta - > is_green ;
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:44 +08:00
/* current tx rate */
2008-01-24 19:38:38 +01:00
index = sta - > last_txrate_idx ;
2007-09-25 17:54:57 -07:00
IWL_DEBUG_RATE ( " Rate scale index %d for type %d \n " , index ,
tbl - > lq_type ) ;
2007-11-29 11:09:44 +08:00
/* rates available for this association, and for modulation mode */
2008-04-23 17:14:58 -07:00
rate_mask = rs_get_supported_rates ( lq_sta , hdr , tbl - > lq_type ) ;
2007-09-25 17:54:57 -07:00
IWL_DEBUG_RATE ( " mask 0x%04X \n " , rate_mask ) ;
/* mask with station rate restriction */
if ( is_legacy ( tbl - > lq_type ) ) {
2008-01-24 19:38:38 +01:00
if ( lq_sta - > band = = IEEE80211_BAND_5GHZ )
2007-11-29 11:09:44 +08:00
/* supp_rates has no CCK bits in A mode */
2007-09-25 17:54:57 -07:00
rate_scale_index_msk = ( u16 ) ( rate_mask &
2008-01-14 17:46:21 -08:00
( lq_sta - > supp_rates < < IWL_FIRST_OFDM_RATE ) ) ;
2007-09-25 17:54:57 -07:00
else
rate_scale_index_msk = ( u16 ) ( rate_mask &
2008-01-14 17:46:21 -08:00
lq_sta - > supp_rates ) ;
2007-09-25 17:54:57 -07:00
} else
rate_scale_index_msk = rate_mask ;
if ( ! rate_scale_index_msk )
rate_scale_index_msk = rate_mask ;
2008-04-23 17:15:03 -07:00
if ( ! ( ( 1 < < index ) & rate_scale_index_msk ) ) {
IWL_ERROR ( " Current Rate is not valid \n " ) ;
return ;
2007-09-25 17:54:57 -07:00
}
2007-11-29 11:09:44 +08:00
/* Get expected throughput table and history window for current rate */
2008-04-23 17:15:03 -07:00
if ( ! tbl - > expected_tpt ) {
IWL_ERROR ( " tbl->expected_tpt is NULL \n " ) ;
return ;
}
2007-09-25 17:54:57 -07:00
window = & ( tbl - > win [ index ] ) ;
2007-11-29 11:09:44 +08:00
/*
* If there is not enough history to calculate actual average
* throughput , keep analyzing results of more tx frames , without
* changing rate or mode ( bypass most of the rest of this function ) .
* Set up new rate table in uCode only if old rate is not supported
* in current association ( use new rate found above ) .
*/
2007-09-25 17:54:57 -07:00
fail_count = window - > counter - window - > success_counter ;
2008-04-23 17:15:03 -07:00
if ( ( fail_count < IWL_RATE_MIN_FAILURE_TH ) & &
( window - > success_counter < IWL_RATE_MIN_SUCCESS_TH ) ) {
IWL_DEBUG_RATE ( " LQ: still below TH. succ=%d total=%d "
2007-09-25 17:54:57 -07:00
" for index %d \n " ,
window - > success_counter , window - > counter , index ) ;
2007-11-29 11:09:44 +08:00
/* Can't calculate this yet; not enough history */
2007-09-25 17:54:57 -07:00
window - > average_tpt = IWL_INVALID_VALUE ;
2007-11-29 11:09:44 +08:00
/* Should we stay with this modulation mode,
* or search for a new one ? */
2008-01-14 17:46:21 -08:00
rs_stay_in_table ( lq_sta ) ;
2007-11-29 11:09:44 +08:00
2007-09-25 17:54:57 -07:00
goto out ;
2007-11-29 11:09:44 +08:00
/* Else we have enough samples; calculate estimate of
* actual average throughput */
2008-04-23 17:15:03 -07:00
} else {
/*FIXME:RS remove this else if we don't get this error*/
if ( window - > average_tpt ! = ( ( window - > success_ratio *
tbl - > expected_tpt [ index ] + 64 ) / 128 ) ) {
IWL_ERROR ( " expected_tpt should have been calculated "
" by now \n " ) ;
window - > average_tpt = ( ( window - > success_ratio *
2007-09-25 17:54:57 -07:00
tbl - > expected_tpt [ index ] + 64 ) / 128 ) ;
2008-04-23 17:15:03 -07:00
}
}
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:44 +08:00
/* If we are searching for better modulation mode, check success. */
2008-01-14 17:46:21 -08:00
if ( lq_sta - > search_better_tbl ) {
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:44 +08:00
/* If good success, continue using the "search" mode;
* no need to send new link quality command , since we ' re
* continuing to use the setup that we ' ve been trying . */
2008-04-23 17:15:03 -07:00
if ( window - > average_tpt > lq_sta - > last_tpt ) {
IWL_DEBUG_RATE ( " LQ: SWITCHING TO CURRENT TABLE "
" suc=%d cur-tpt=%d old-tpt=%d \n " ,
window - > success_ratio ,
window - > average_tpt ,
lq_sta - > last_tpt ) ;
if ( ! is_legacy ( tbl - > lq_type ) )
2008-01-14 17:46:21 -08:00
lq_sta - > enable_counter = 1 ;
2008-04-23 17:15:03 -07:00
2007-11-29 11:09:44 +08:00
/* Swap tables; "search" becomes "active" */
2008-01-14 17:46:21 -08:00
lq_sta - > active_tbl = active_tbl ;
2007-09-25 17:54:57 -07:00
current_tpt = window - > average_tpt ;
2007-11-29 11:09:44 +08:00
/* Else poor success; go back to mode in "active" table */
2007-09-25 17:54:57 -07:00
} else {
2008-04-23 17:15:03 -07:00
IWL_DEBUG_RATE ( " LQ: GOING BACK TO THE OLD TABLE "
" suc=%d cur-tpt=%d old-tpt=%d \n " ,
window - > success_ratio ,
window - > average_tpt ,
lq_sta - > last_tpt ) ;
2007-11-29 11:09:44 +08:00
/* Nullify "search" table */
2007-09-25 17:54:57 -07:00
tbl - > lq_type = LQ_NONE ;
2007-11-29 11:09:44 +08:00
/* Revert to "active" table */
2008-01-14 17:46:21 -08:00
active_tbl = lq_sta - > active_tbl ;
tbl = & ( lq_sta - > lq_info [ active_tbl ] ) ;
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:44 +08:00
/* Revert to "active" rate and throughput info */
2008-03-02 01:52:00 +02:00
index = iwl4965_hwrate_to_plcp_idx (
2008-04-23 17:14:57 -07:00
tbl - > current_rate ) ;
2008-01-14 17:46:21 -08:00
current_tpt = lq_sta - > last_tpt ;
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:44 +08:00
/* Need to set up a new rate table in uCode */
2007-09-25 17:54:57 -07:00
update_lq = 1 ;
}
2007-11-29 11:09:44 +08:00
/* Either way, we've made a decision; modulation mode
* search is done , allow rate adjustment next time . */
2008-01-14 17:46:21 -08:00
lq_sta - > search_better_tbl = 0 ;
2007-11-29 11:09:44 +08:00
done_search = 1 ; /* Don't switch modes below! */
2007-09-25 17:54:57 -07:00
goto lq_update ;
}
2007-11-29 11:09:44 +08:00
/* (Else) not in search of better modulation mode, try for better
* starting rate , while staying in this mode . */
2008-05-05 10:22:40 +08:00
high_low = rs_get_adjacent_rate ( priv , index , rate_scale_index_msk ,
2007-09-25 17:54:57 -07:00
tbl - > lq_type ) ;
low = high_low & 0xff ;
high = ( high_low > > 8 ) & 0xff ;
2007-11-29 11:09:44 +08:00
/* Collect measured throughputs for current and adjacent rates */
2007-09-25 17:54:57 -07:00
current_tpt = window - > average_tpt ;
if ( low ! = IWL_RATE_INVALID )
low_tpt = tbl - > win [ low ] . average_tpt ;
if ( high ! = IWL_RATE_INVALID )
high_tpt = tbl - > win [ high ] . average_tpt ;
2007-11-29 11:09:44 +08:00
/* Assume rate increase */
2007-09-25 17:54:57 -07:00
scale_action = 1 ;
2007-11-29 11:09:44 +08:00
/* Too many failures, decrease rate */
2007-09-25 17:54:57 -07:00
if ( ( window - > success_ratio < = IWL_RATE_DECREASE_TH ) | |
( current_tpt = = 0 ) ) {
IWL_DEBUG_RATE ( " decrease rate because of low success_ratio \n " ) ;
scale_action = - 1 ;
2007-11-29 11:09:44 +08:00
/* No throughput measured yet for adjacent rates; try increase. */
2007-09-25 17:54:57 -07:00
} else if ( ( low_tpt = = IWL_INVALID_VALUE ) & &
( high_tpt = = IWL_INVALID_VALUE ) )
scale_action = 1 ;
2007-11-29 11:09:44 +08:00
/* Both adjacent throughputs are measured, but neither one has better
* throughput ; we ' re using the best rate , don ' t change it ! */
2007-09-25 17:54:57 -07:00
else if ( ( low_tpt ! = IWL_INVALID_VALUE ) & &
( high_tpt ! = IWL_INVALID_VALUE ) & &
( low_tpt < current_tpt ) & &
( high_tpt < current_tpt ) )
scale_action = 0 ;
2007-11-29 11:09:44 +08:00
/* At least one adjacent rate's throughput is measured,
* and may have better performance . */
2007-09-25 17:54:57 -07:00
else {
2007-11-29 11:09:44 +08:00
/* Higher adjacent rate's throughput is measured */
2007-09-25 17:54:57 -07:00
if ( high_tpt ! = IWL_INVALID_VALUE ) {
2007-11-29 11:09:44 +08:00
/* Higher rate has better throughput */
2007-09-25 17:54:57 -07:00
if ( high_tpt > current_tpt )
scale_action = 1 ;
else {
IWL_DEBUG_RATE
( " decrease rate because of high tpt \n " ) ;
scale_action = - 1 ;
}
2007-11-29 11:09:44 +08:00
/* Lower adjacent rate's throughput is measured */
2007-09-25 17:54:57 -07:00
} else if ( low_tpt ! = IWL_INVALID_VALUE ) {
2007-11-29 11:09:44 +08:00
/* Lower rate has better throughput */
2007-09-25 17:54:57 -07:00
if ( low_tpt > current_tpt ) {
IWL_DEBUG_RATE
( " decrease rate because of low tpt \n " ) ;
scale_action = - 1 ;
} else
scale_action = 1 ;
}
}
2007-11-29 11:09:44 +08:00
/* Sanity check; asked for decrease, but success rate or throughput
* has been good at old rate . Don ' t change it . */
2007-09-25 17:54:57 -07:00
if ( scale_action = = - 1 ) {
if ( ( low ! = IWL_RATE_INVALID ) & &
( ( window - > success_ratio > IWL_RATE_HIGH_TH ) | |
( current_tpt > ( 100 * tbl - > expected_tpt [ low ] ) ) ) )
scale_action = 0 ;
2007-11-29 11:09:44 +08:00
/* Sanity check; asked for increase, but success rate has not been great
* even at old rate , higher rate will be worse . Don ' t change it . */
2007-09-25 17:54:57 -07:00
} else if ( ( scale_action = = 1 ) & &
( window - > success_ratio < IWL_RATE_INCREASE_TH ) )
scale_action = 0 ;
switch ( scale_action ) {
case - 1 :
2007-11-29 11:09:44 +08:00
/* Decrease starting rate, update uCode's rate table */
2007-09-25 17:54:57 -07:00
if ( low ! = IWL_RATE_INVALID ) {
update_lq = 1 ;
index = low ;
}
break ;
case 1 :
2007-11-29 11:09:44 +08:00
/* Increase starting rate, update uCode's rate table */
2007-09-25 17:54:57 -07:00
if ( high ! = IWL_RATE_INVALID ) {
update_lq = 1 ;
index = high ;
}
break ;
case 0 :
2007-11-29 11:09:44 +08:00
/* No change */
2007-09-25 17:54:57 -07:00
default :
break ;
}
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " choose rate scale index %d action %d low %d "
2007-09-25 17:54:57 -07:00
" high %d type %d \n " ,
index , scale_action , low , high , tbl - > lq_type ) ;
lq_update :
2007-11-29 11:09:44 +08:00
/* Replace uCode's rate table for the destination station. */
2007-09-25 17:54:57 -07:00
if ( update_lq ) {
2008-04-23 17:14:57 -07:00
rate = rate_n_flags_from_tbl ( tbl , index , is_green ) ;
2008-04-23 17:15:03 -07:00
rs_fill_link_cmd ( priv , lq_sta , rate ) ;
2008-04-15 16:01:40 -07:00
iwl_send_lq_cmd ( priv , & lq_sta - > lq , CMD_ASYNC ) ;
2007-09-25 17:54:57 -07:00
}
2007-11-29 11:09:44 +08:00
/* Should we stay with this modulation mode, or search for a new one? */
2008-01-14 17:46:21 -08:00
rs_stay_in_table ( lq_sta ) ;
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:44 +08:00
/*
* Search for new modulation mode if we ' re :
* 1 ) Not changing rates right now
* 2 ) Not just finishing up a search
* 3 ) Allowing a new search
*/
2008-01-14 17:46:21 -08:00
if ( ! update_lq & & ! done_search & & ! lq_sta - > stay_in_tbl ) {
2007-11-29 11:09:44 +08:00
/* Save current throughput to compare with "search" throughput*/
2008-01-14 17:46:21 -08:00
lq_sta - > last_tpt = current_tpt ;
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:44 +08:00
/* Select a new "search" modulation mode to try.
* If one is found , set up the new " search " table . */
2007-09-25 17:54:57 -07:00
if ( is_legacy ( tbl - > lq_type ) )
2008-01-14 17:46:21 -08:00
rs_move_legacy_other ( priv , lq_sta , conf , sta , index ) ;
2007-09-25 17:54:57 -07:00
else if ( is_siso ( tbl - > lq_type ) )
2008-01-14 17:46:21 -08:00
rs_move_siso_to_other ( priv , lq_sta , conf , sta , index ) ;
2007-09-25 17:54:57 -07:00
else
2008-01-14 17:46:21 -08:00
rs_move_mimo_to_other ( priv , lq_sta , conf , sta , index ) ;
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:44 +08:00
/* If new "search" mode was selected, set up in uCode table */
2008-01-14 17:46:21 -08:00
if ( lq_sta - > search_better_tbl ) {
2007-11-29 11:09:44 +08:00
/* Access the "search" table, clear its history. */
2008-01-14 17:46:21 -08:00
tbl = & ( lq_sta - > lq_info [ ( 1 - lq_sta - > active_tbl ) ] ) ;
2007-09-25 17:54:57 -07:00
for ( i = 0 ; i < IWL_RATE_COUNT ; i + + )
rs_rate_scale_clear_window ( & ( tbl - > win [ i ] ) ) ;
2007-11-29 11:09:44 +08:00
/* Use new "search" start rate */
2008-03-02 01:52:00 +02:00
index = iwl4965_hwrate_to_plcp_idx (
2008-04-23 17:14:57 -07:00
tbl - > current_rate ) ;
2007-09-25 17:54:57 -07:00
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " Switch current mcs: %X index: %d \n " ,
2008-04-23 17:14:57 -07:00
tbl - > current_rate , index ) ;
2008-04-23 17:15:03 -07:00
rs_fill_link_cmd ( priv , lq_sta , tbl - > current_rate ) ;
2008-04-15 16:01:40 -07:00
iwl_send_lq_cmd ( priv , & lq_sta - > lq , CMD_ASYNC ) ;
2007-09-25 17:54:57 -07:00
}
2007-11-29 11:09:44 +08:00
/* If the "active" (non-search) mode was legacy,
* and we ' ve tried switching antennas ,
* but we haven ' t been able to try HT modes ( not available ) ,
* stay with best antenna legacy modulation for a while
* before next round of mode comparisons . */
2008-01-14 17:46:21 -08:00
tbl1 = & ( lq_sta - > lq_info [ lq_sta - > active_tbl ] ) ;
2007-09-25 17:54:57 -07:00
if ( is_legacy ( tbl1 - > lq_type ) & &
2007-10-25 17:15:51 +08:00
# ifdef CONFIG_IWL4965_HT
2007-11-26 16:14:41 +02:00
( ! ( conf - > flags & IEEE80211_CONF_SUPPORT_HT_MODE ) ) & &
2007-09-25 17:54:57 -07:00
# endif
2008-01-14 17:46:21 -08:00
( lq_sta - > action_counter > = 1 ) ) {
lq_sta - > action_counter = 0 ;
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " LQ: STAY in legacy table \n " ) ;
2008-05-05 10:22:40 +08:00
rs_set_stay_in_table ( priv , 1 , lq_sta ) ;
2007-09-25 17:54:57 -07:00
}
2007-11-29 11:09:44 +08:00
/* If we're in an HT mode, and all 3 mode switch actions
* have been tried and compared , stay in this best modulation
* mode for a while before next round of mode comparisons . */
2008-01-14 17:46:21 -08:00
if ( lq_sta - > enable_counter & &
( lq_sta - > action_counter > = IWL_ACTION_LIMIT ) ) {
2008-01-28 14:07:26 +02:00
# ifdef CONFIG_IWL4965_HT
if ( ( lq_sta - > last_tpt > IWL_AGG_TPT_THREHOLD ) & &
( lq_sta - > tx_agg_tid_en & ( 1 < < tid ) ) & &
( tid ! = MAX_TID_COUNT ) ) {
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " try to aggregate tid %d \n " , tid ) ;
2008-01-28 14:07:26 +02:00
rs_tl_turn_on_agg ( priv , tid , lq_sta , sta ) ;
2007-09-25 17:54:57 -07:00
}
2008-01-28 14:07:26 +02:00
# endif /*CONFIG_IWL4965_HT */
2008-01-14 17:46:21 -08:00
lq_sta - > action_counter = 0 ;
2008-05-05 10:22:40 +08:00
rs_set_stay_in_table ( priv , 0 , lq_sta ) ;
2007-09-25 17:54:57 -07:00
}
2007-11-29 11:09:44 +08:00
/*
* Else , don ' t search for a new modulation mode .
* Put new timestamp in stay - in - modulation - mode flush timer if :
* 1 ) Not changing rates right now
* 2 ) Not just finishing up a search
* 3 ) flush timer is empty
*/
2007-09-25 17:54:57 -07:00
} else {
2008-01-14 17:46:21 -08:00
if ( ( ! update_lq ) & & ( ! done_search ) & & ( ! lq_sta - > flush_timer ) )
lq_sta - > flush_timer = jiffies ;
2007-09-25 17:54:57 -07:00
}
out :
2008-04-23 17:14:57 -07:00
tbl - > current_rate = rate_n_flags_from_tbl ( tbl , index , is_green ) ;
2007-09-25 17:54:57 -07:00
i = index ;
2008-01-24 19:38:38 +01:00
sta - > last_txrate_idx = i ;
2007-09-25 17:54:57 -07:00
2008-01-24 19:38:38 +01:00
/* sta->txrate_idx is an index to A mode rates which start
2007-09-25 17:54:57 -07:00
* at IWL_FIRST_OFDM_RATE
*/
2008-01-24 19:38:38 +01:00
if ( lq_sta - > band = = IEEE80211_BAND_5GHZ )
sta - > txrate_idx = i - IWL_FIRST_OFDM_RATE ;
2007-09-25 17:54:57 -07:00
else
2008-01-24 19:38:38 +01:00
sta - > txrate_idx = i ;
2007-09-25 17:54:57 -07:00
return ;
}
2008-03-12 16:58:50 -07:00
static void rs_initialize_lq ( struct iwl_priv * priv ,
2007-11-26 16:14:41 +02:00
struct ieee80211_conf * conf ,
2007-09-25 17:54:57 -07:00
struct sta_info * sta )
{
2008-01-14 17:46:21 -08:00
struct iwl4965_lq_sta * lq_sta ;
2008-01-27 16:41:47 -08:00
struct iwl4965_scale_tbl_info * tbl ;
2007-09-25 17:54:57 -07:00
int rate_idx ;
2008-04-23 17:14:59 -07:00
int i ;
2008-04-23 17:14:57 -07:00
u32 rate ;
2008-04-23 17:14:59 -07:00
u8 use_green = rs_use_green ( priv , conf ) ;
u8 active_tbl = 0 ;
u8 valid_tx_ant ;
2007-09-25 17:54:57 -07:00
if ( ! sta | | ! sta - > rate_ctrl_priv )
goto out ;
2008-01-14 17:46:21 -08:00
lq_sta = ( struct iwl4965_lq_sta * ) sta - > rate_ctrl_priv ;
2008-01-24 19:38:38 +01:00
i = sta - > last_txrate_idx ;
2007-09-25 17:54:57 -07:00
2008-01-14 17:46:21 -08:00
if ( ( lq_sta - > lq . sta_id = = 0xff ) & &
2007-09-25 17:54:57 -07:00
( priv - > iw_mode = = IEEE80211_IF_TYPE_IBSS ) )
goto out ;
2008-04-23 17:14:59 -07:00
valid_tx_ant = priv - > hw_params . valid_tx_ant ;
2008-01-14 17:46:21 -08:00
if ( ! lq_sta - > search_better_tbl )
active_tbl = lq_sta - > active_tbl ;
2007-09-25 17:54:57 -07:00
else
2008-01-14 17:46:21 -08:00
active_tbl = 1 - lq_sta - > active_tbl ;
2007-09-25 17:54:57 -07:00
2008-01-14 17:46:21 -08:00
tbl = & ( lq_sta - > lq_info [ active_tbl ] ) ;
2007-09-25 17:54:57 -07:00
if ( ( i < 0 ) | | ( i > = IWL_RATE_COUNT ) )
i = 0 ;
2008-04-21 15:42:01 -07:00
/* FIXME:RS: This is also wrong in 4965 */
2008-05-15 13:54:02 +08:00
rate = iwl_rates [ i ] . plcp ;
2008-04-23 17:14:57 -07:00
rate | = RATE_MCS_ANT_B_MSK ;
rate & = ~ RATE_MCS_ANT_A_MSK ;
2007-09-25 17:54:57 -07:00
if ( i > = IWL_FIRST_CCK_RATE & & i < = IWL_LAST_CCK_RATE )
2008-04-23 17:14:57 -07:00
rate | = RATE_MCS_CCK_MSK ;
2007-09-25 17:54:57 -07:00
2008-04-21 15:42:01 -07:00
tbl - > ant_type = ANT_B ;
2008-04-23 17:14:57 -07:00
rs_get_tbl_info_from_mcs ( rate , priv - > band , tbl , & rate_idx ) ;
2008-04-23 17:14:59 -07:00
if ( ! rs_is_valid_ant ( valid_tx_ant , tbl - > ant_type ) )
rs_toggle_antenna ( valid_tx_ant , & rate , tbl ) ;
2007-09-25 17:54:57 -07:00
2008-04-23 17:14:57 -07:00
rate = rate_n_flags_from_tbl ( tbl , rate_idx , use_green ) ;
tbl - > current_rate = rate ;
2008-04-23 17:14:58 -07:00
rs_set_expected_tpt_table ( lq_sta , tbl ) ;
2008-04-23 17:15:03 -07:00
rs_fill_link_cmd ( NULL , lq_sta , rate ) ;
2008-04-15 16:01:40 -07:00
iwl_send_lq_cmd ( priv , & lq_sta - > lq , CMD_ASYNC ) ;
2007-09-25 17:54:57 -07:00
out :
return ;
}
2007-12-20 13:50:07 +01:00
static void rs_get_rate ( void * priv_rate , struct net_device * dev ,
2008-01-24 19:38:38 +01:00
struct ieee80211_supported_band * sband ,
struct sk_buff * skb ,
2007-12-20 13:50:07 +01:00
struct rate_selection * sel )
2007-09-25 17:54:57 -07:00
{
int i ;
struct ieee80211_local * local = wdev_priv ( dev - > ieee80211_ptr ) ;
2007-11-26 16:14:41 +02:00
struct ieee80211_conf * conf = & local - > hw . conf ;
2007-09-25 17:54:57 -07:00
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) skb - > data ;
struct sta_info * sta ;
2007-12-25 19:33:16 -05:00
u16 fc ;
2008-03-12 16:58:50 -07:00
struct iwl_priv * priv = ( struct iwl_priv * ) priv_rate ;
2008-01-14 17:46:21 -08:00
struct iwl4965_lq_sta * lq_sta ;
2007-09-25 17:54:57 -07:00
2007-09-27 11:27:39 +08:00
IWL_DEBUG_RATE_LIMIT ( " rate scale calculate new rate for skb \n " ) ;
2007-09-25 17:54:57 -07:00
2008-02-25 16:27:46 +01:00
rcu_read_lock ( ) ;
2007-09-25 17:54:57 -07:00
sta = sta_info_get ( local , hdr - > addr1 ) ;
2007-12-25 19:33:16 -05:00
/* Send management frames and broadcast/multicast data using lowest
* rate . */
fc = le16_to_cpu ( hdr - > frame_control ) ;
if ( ! ieee80211_is_data ( fc ) | | is_multicast_ether_addr ( hdr - > addr1 ) | |
! sta | | ! sta - > rate_ctrl_priv ) {
2008-05-15 12:55:27 +02:00
sel - > rate_idx = rate_lowest_index ( local , sband , sta ) ;
2008-03-05 11:31:00 -08:00
goto out ;
2007-09-25 17:54:57 -07:00
}
2008-01-14 17:46:21 -08:00
lq_sta = ( struct iwl4965_lq_sta * ) sta - > rate_ctrl_priv ;
2008-01-24 19:38:38 +01:00
i = sta - > last_txrate_idx ;
2007-09-25 17:54:57 -07:00
2008-01-14 17:46:21 -08:00
if ( ( priv - > iw_mode = = IEEE80211_IF_TYPE_IBSS ) & &
! lq_sta - > ibss_sta_added ) {
2008-04-16 16:34:48 -07:00
u8 sta_id = iwl_find_station ( priv , hdr - > addr1 ) ;
2007-10-03 17:59:30 -07:00
DECLARE_MAC_BUF ( mac ) ;
2007-09-25 17:54:57 -07:00
if ( sta_id = = IWL_INVALID_STATION ) {
2007-10-03 17:59:30 -07:00
IWL_DEBUG_RATE ( " LQ: ADD station %s \n " ,
print_mac ( mac , hdr - > addr1 ) ) ;
2008-05-15 13:54:04 +08:00
sta_id = iwl_add_station_flags ( priv , hdr - > addr1 ,
2007-11-26 16:14:40 +02:00
0 , CMD_ASYNC , NULL ) ;
2007-09-25 17:54:57 -07:00
}
if ( ( sta_id ! = IWL_INVALID_STATION ) ) {
2008-01-14 17:46:21 -08:00
lq_sta - > lq . sta_id = sta_id ;
lq_sta - > lq . rs_table [ 0 ] . rate_n_flags = 0 ;
lq_sta - > ibss_sta_added = 1 ;
2007-11-26 16:14:41 +02:00
rs_initialize_lq ( priv , conf , sta ) ;
2007-09-25 17:54:57 -07:00
}
2008-01-14 17:46:21 -08:00
if ( ! lq_sta - > ibss_sta_added )
2007-09-25 17:54:57 -07:00
goto done ;
}
2008-03-05 11:31:00 -08:00
done :
2007-12-20 13:50:07 +01:00
if ( ( i < 0 ) | | ( i > IWL_RATE_COUNT ) ) {
2008-05-15 12:55:27 +02:00
sel - > rate_idx = rate_lowest_index ( local , sband , sta ) ;
2008-03-05 11:31:00 -08:00
goto out ;
2007-12-20 13:50:07 +01:00
}
2007-09-25 17:54:57 -07:00
2008-05-15 12:55:27 +02:00
if ( sband - > band = = IEEE80211_BAND_5GHZ )
i - = IWL_FIRST_OFDM_RATE ;
sel - > rate_idx = i ;
2008-03-05 11:31:00 -08:00
out :
rcu_read_unlock ( ) ;
2007-09-25 17:54:57 -07:00
}
2008-05-05 10:22:40 +08:00
static void * rs_alloc_sta ( void * priv_rate , gfp_t gfp )
2007-09-25 17:54:57 -07:00
{
2008-01-14 17:46:21 -08:00
struct iwl4965_lq_sta * lq_sta ;
2008-05-05 10:22:40 +08:00
struct iwl_priv * priv ;
2007-09-25 17:54:57 -07:00
int i , j ;
2008-05-05 10:22:40 +08:00
priv = ( struct iwl_priv * ) priv_rate ;
2007-09-25 17:54:57 -07:00
IWL_DEBUG_RATE ( " create station rate scale window \n " ) ;
2008-01-14 17:46:21 -08:00
lq_sta = kzalloc ( sizeof ( struct iwl4965_lq_sta ) , gfp ) ;
2007-09-25 17:54:57 -07:00
2008-01-14 17:46:21 -08:00
if ( lq_sta = = NULL )
2007-09-25 17:54:57 -07:00
return NULL ;
2008-01-14 17:46:21 -08:00
lq_sta - > lq . sta_id = 0xff ;
2007-09-25 17:54:57 -07:00
2007-09-27 11:27:36 +08:00
2007-09-25 17:54:57 -07:00
for ( j = 0 ; j < LQ_SIZE ; j + + )
for ( i = 0 ; i < IWL_RATE_COUNT ; i + + )
2008-01-14 17:46:21 -08:00
rs_rate_scale_clear_window ( & ( lq_sta - > lq_info [ j ] . win [ i ] ) ) ;
2007-09-25 17:54:57 -07:00
2008-01-14 17:46:21 -08:00
return lq_sta ;
2007-09-25 17:54:57 -07:00
}
static void rs_rate_init ( void * priv_rate , void * priv_sta ,
struct ieee80211_local * local ,
struct sta_info * sta )
{
int i , j ;
2007-11-26 16:14:41 +02:00
struct ieee80211_conf * conf = & local - > hw . conf ;
2008-01-24 19:38:38 +01:00
struct ieee80211_supported_band * sband ;
2008-03-12 16:58:50 -07:00
struct iwl_priv * priv = ( struct iwl_priv * ) priv_rate ;
2008-01-14 17:46:21 -08:00
struct iwl4965_lq_sta * lq_sta = priv_sta ;
2007-09-25 17:54:57 -07:00
2008-01-24 19:38:38 +01:00
sband = local - > hw . wiphy - > bands [ local - > hw . conf . channel - > band ] ;
2008-01-14 17:46:21 -08:00
lq_sta - > flush_timer = 0 ;
2008-01-24 19:38:38 +01:00
lq_sta - > supp_rates = sta - > supp_rates [ sband - > band ] ;
sta - > txrate_idx = 3 ;
2007-09-25 17:54:57 -07:00
for ( j = 0 ; j < LQ_SIZE ; j + + )
for ( i = 0 ; i < IWL_RATE_COUNT ; i + + )
2008-01-14 17:46:21 -08:00
rs_rate_scale_clear_window ( & ( lq_sta - > lq_info [ j ] . win [ i ] ) ) ;
2007-09-25 17:54:57 -07:00
2008-04-23 17:15:03 -07:00
IWL_DEBUG_RATE ( " LQ: *** rate scale global init *** \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-01-14 17:46:21 -08:00
lq_sta - > ibss_sta_added = 0 ;
2007-09-25 17:54:57 -07:00
if ( priv - > iw_mode = = IEEE80211_IF_TYPE_AP ) {
2008-04-16 16:34:48 -07:00
u8 sta_id = iwl_find_station ( priv , sta - > addr ) ;
2007-10-03 17:59:30 -07:00
DECLARE_MAC_BUF ( mac ) ;
2007-09-25 17:54:57 -07:00
/* for IBSS the call are from tasklet */
2008-04-23 17:14:58 -07:00
IWL_DEBUG_RATE ( " LQ: ADD station %s \n " ,
2007-10-03 17:59:30 -07:00
print_mac ( mac , sta - > addr ) ) ;
2007-09-25 17:54:57 -07:00
if ( sta_id = = IWL_INVALID_STATION ) {
2007-10-03 17:59:30 -07:00
IWL_DEBUG_RATE ( " LQ: ADD station %s \n " ,
print_mac ( mac , sta - > addr ) ) ;
2008-05-15 13:54:04 +08:00
sta_id = iwl_add_station_flags ( priv , sta - > addr ,
2007-11-26 16:14:40 +02:00
0 , CMD_ASYNC , NULL ) ;
2007-09-25 17:54:57 -07:00
}
if ( ( sta_id ! = IWL_INVALID_STATION ) ) {
2008-01-14 17:46:21 -08:00
lq_sta - > lq . sta_id = sta_id ;
lq_sta - > lq . rs_table [ 0 ] . rate_n_flags = 0 ;
2007-09-25 17:54:57 -07:00
}
/* FIXME: this is w/a remove it later */
priv - > assoc_station_added = 1 ;
}
2007-11-29 11:09:44 +08:00
/* Find highest tx rate supported by hardware and destination station */
2008-01-24 19:38:38 +01:00
for ( i = 0 ; i < sband - > n_bitrates ; i + + )
if ( sta - > supp_rates [ sband - > band ] & BIT ( i ) )
sta - > txrate_idx = i ;
sta - > last_txrate_idx = sta - > txrate_idx ;
/* WTF is with this bogus comment? A doesn't have cck rates */
2007-11-29 11:09:44 +08:00
/* For MODE_IEEE80211A, cck rates are at end of rate table */
2008-01-24 19:38:38 +01:00
if ( local - > hw . conf . channel - > band = = IEEE80211_BAND_5GHZ )
sta - > last_txrate_idx + = IWL_FIRST_OFDM_RATE ;
2007-09-25 17:54:57 -07:00
2008-01-14 17:46:21 -08:00
lq_sta - > is_dup = 0 ;
lq_sta - > is_green = rs_use_green ( priv , conf ) ;
2008-04-23 17:14:57 -07:00
lq_sta - > active_legacy_rate = priv - > active_rate & ~ ( 0x1000 ) ;
2008-01-14 17:46:21 -08:00
lq_sta - > active_rate_basic = priv - > active_rate_basic ;
2008-01-24 19:38:38 +01:00
lq_sta - > band = priv - > band ;
2007-10-25 17:15:51 +08:00
# ifdef CONFIG_IWL4965_HT
2007-11-29 11:09:44 +08:00
/*
* active_siso_rate mask includes 9 MBits ( bit 5 ) , and CCK ( bits 0 - 3 ) ,
* supp_rates [ ] does not ; shift to convert format , force 9 MBits off .
*/
2008-04-21 15:42:01 -07:00
lq_sta - > active_siso_rate =
priv - > current_ht_config . supp_mcs_set [ 0 ] < < 1 ;
2008-01-14 17:46:21 -08:00
lq_sta - > active_siso_rate | =
2008-04-21 15:42:01 -07:00
priv - > current_ht_config . supp_mcs_set [ 0 ] & 0x1 ;
2008-01-14 17:46:21 -08:00
lq_sta - > active_siso_rate & = ~ ( ( u16 ) 0x2 ) ;
2008-04-21 15:42:01 -07:00
lq_sta - > active_siso_rate < < = IWL_FIRST_OFDM_RATE ;
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:44 +08:00
/* Same here */
2008-04-21 15:42:01 -07:00
lq_sta - > active_mimo2_rate =
priv - > current_ht_config . supp_mcs_set [ 1 ] < < 1 ;
lq_sta - > active_mimo2_rate | =
priv - > current_ht_config . supp_mcs_set [ 1 ] & 0x1 ;
lq_sta - > active_mimo2_rate & = ~ ( ( u16 ) 0x2 ) ;
lq_sta - > active_mimo2_rate < < = IWL_FIRST_OFDM_RATE ;
lq_sta - > active_mimo3_rate =
priv - > current_ht_config . supp_mcs_set [ 2 ] < < 1 ;
lq_sta - > active_mimo3_rate | =
priv - > current_ht_config . supp_mcs_set [ 2 ] & 0x1 ;
lq_sta - > active_mimo3_rate & = ~ ( ( u16 ) 0x2 ) ;
lq_sta - > active_mimo3_rate < < = IWL_FIRST_OFDM_RATE ;
2008-04-23 17:15:03 -07:00
IWL_DEBUG_RATE ( " SISO-RATE=%X MIMO2-RATE=%X MIMO3-RATE=%X \n " ,
2008-01-14 17:46:21 -08:00
lq_sta - > active_siso_rate ,
2008-04-21 15:42:01 -07:00
lq_sta - > active_mimo2_rate ,
lq_sta - > active_mimo3_rate ) ;
2008-04-23 17:15:03 -07:00
/* These values will be overriden later */
lq_sta - > lq . general_params . single_stream_ant_msk = ANT_A ;
lq_sta - > lq . general_params . dual_stream_ant_msk = ANT_AB ;
2008-01-28 14:07:26 +02:00
/* as default allow aggregation for all tids */
lq_sta - > tx_agg_tid_en = IWL_AGG_ALL_TID ;
2007-10-25 17:15:51 +08:00
# endif /*CONFIG_IWL4965_HT*/
2007-09-27 11:27:42 +08:00
# ifdef CONFIG_MAC80211_DEBUGFS
2008-01-14 17:46:21 -08:00
lq_sta - > drv = priv ;
2007-09-27 11:27:42 +08:00
# endif
2007-09-25 17:54:57 -07:00
if ( priv - > assoc_station_added )
priv - > lq_mngr . lq_ready = 1 ;
2007-11-26 16:14:41 +02:00
rs_initialize_lq ( priv , conf , sta ) ;
2007-09-25 17:54:57 -07:00
}
2008-04-21 15:42:01 -07:00
static void rs_fill_link_cmd ( const struct iwl_priv * priv ,
struct iwl4965_lq_sta * lq_sta ,
2008-04-23 17:15:03 -07:00
u32 new_rate )
2007-09-25 17:54:57 -07:00
{
2008-04-23 17:14:59 -07:00
struct iwl4965_scale_tbl_info tbl_type ;
2007-09-25 17:54:57 -07:00
int index = 0 ;
int rate_idx ;
2007-09-27 11:27:41 +08:00
int repeat_rate = 0 ;
2008-04-23 17:14:59 -07:00
u8 ant_toggle_cnt = 0 ;
2007-09-25 17:54:57 -07:00
u8 use_ht_possible = 1 ;
2008-04-23 17:14:59 -07:00
u8 valid_tx_ant = 0 ;
2008-04-23 17:15:03 -07:00
struct iwl_link_quality_cmd * lq_cmd = & lq_sta - > lq ;
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:44 +08:00
/* Override starting rate (index 0) if needed for debug purposes */
2008-04-23 17:14:57 -07:00
rs_dbgfs_set_mcs ( lq_sta , & new_rate , index ) ;
2007-09-27 11:27:42 +08:00
2008-04-23 17:14:57 -07:00
/* Interpret new_rate (rate_n_flags) */
2008-04-23 17:14:59 -07:00
memset ( & tbl_type , 0 , sizeof ( tbl_type ) ) ;
2008-04-23 17:14:57 -07:00
rs_get_tbl_info_from_mcs ( new_rate , lq_sta - > band ,
2007-09-25 17:54:57 -07:00
& tbl_type , & rate_idx ) ;
2007-11-29 11:09:44 +08:00
/* How many times should we repeat the initial rate? */
2007-09-25 17:54:57 -07:00
if ( is_legacy ( tbl_type . lq_type ) ) {
2008-04-23 17:14:59 -07:00
ant_toggle_cnt = 1 ;
2007-09-27 11:27:41 +08:00
repeat_rate = IWL_NUMBER_TRY ;
2008-04-23 17:14:59 -07:00
} else {
2007-09-27 11:27:41 +08:00
repeat_rate = IWL_HT_NUMBER_TRY ;
2008-04-23 17:14:59 -07:00
}
2007-09-25 17:54:57 -07:00
lq_cmd - > general_params . mimo_delimiter =
is_mimo ( tbl_type . lq_type ) ? 1 : 0 ;
2007-11-29 11:09:44 +08:00
/* Fill 1st table entry (index 0) */
2008-04-23 17:14:57 -07:00
lq_cmd - > rs_table [ index ] . rate_n_flags = cpu_to_le32 ( new_rate ) ;
2007-09-25 17:54:57 -07:00
2008-04-23 17:15:03 -07:00
if ( num_of_ant ( tbl_type . ant_type ) = = 1 ) {
lq_cmd - > general_params . single_stream_ant_msk =
tbl_type . ant_type ;
} else if ( num_of_ant ( tbl_type . ant_type ) = = 2 ) {
lq_cmd - > general_params . dual_stream_ant_msk =
tbl_type . ant_type ;
} /* otherwise we don't modify the existing value */
2007-09-25 17:54:57 -07:00
index + + ;
2007-09-27 11:27:41 +08:00
repeat_rate - - ;
2007-09-25 17:54:57 -07:00
2008-04-23 17:14:59 -07:00
if ( priv )
valid_tx_ant = priv - > hw_params . valid_tx_ant ;
2007-11-29 11:09:44 +08:00
/* Fill rest of rate table */
2007-09-25 17:54:57 -07:00
while ( index < LINK_QUAL_MAX_RETRY_NUM ) {
2007-11-29 11:09:44 +08:00
/* Repeat initial/next rate.
* For legacy IWL_NUMBER_TRY = = 1 , this loop will not execute .
* For HT IWL_HT_NUMBER_TRY = = 3 , this executes twice . */
2007-09-27 11:27:41 +08:00
while ( repeat_rate > 0 & & ( index < LINK_QUAL_MAX_RETRY_NUM ) ) {
2007-09-25 17:54:57 -07:00
if ( is_legacy ( tbl_type . lq_type ) ) {
2008-04-23 17:14:59 -07:00
if ( ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE )
ant_toggle_cnt + + ;
else if ( priv & &
rs_toggle_antenna ( valid_tx_ant ,
& new_rate , & tbl_type ) )
ant_toggle_cnt = 1 ;
}
2007-09-27 11:27:42 +08:00
2007-11-29 11:09:44 +08:00
/* Override next rate if needed for debug purposes */
2008-01-14 17:46:21 -08:00
rs_dbgfs_set_mcs ( lq_sta , & new_rate , index ) ;
2007-11-29 11:09:44 +08:00
/* Fill next table entry */
2007-09-25 17:54:57 -07:00
lq_cmd - > rs_table [ index ] . rate_n_flags =
2008-04-23 17:14:57 -07:00
cpu_to_le32 ( new_rate ) ;
2007-09-27 11:27:41 +08:00
repeat_rate - - ;
2007-09-25 17:54:57 -07:00
index + + ;
}
2008-04-23 17:14:57 -07:00
rs_get_tbl_info_from_mcs ( new_rate , lq_sta - > band , & tbl_type ,
2007-09-25 17:54:57 -07:00
& rate_idx ) ;
2007-11-29 11:09:44 +08:00
/* Indicate to uCode which entries might be MIMO.
* If initial rate was MIMO , this will finally end up
* as ( IWL_HT_NUMBER_TRY * 2 ) , after 2 nd pass , otherwise 0. */
2007-09-25 17:54:57 -07:00
if ( is_mimo ( tbl_type . lq_type ) )
lq_cmd - > general_params . mimo_delimiter = index ;
2007-11-29 11:09:44 +08:00
/* Get next rate */
2008-04-23 17:14:57 -07:00
new_rate = rs_get_lower_rate ( lq_sta , & tbl_type , rate_idx ,
use_ht_possible ) ;
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:44 +08:00
/* How many times should we repeat the next rate? */
2007-09-25 17:54:57 -07:00
if ( is_legacy ( tbl_type . lq_type ) ) {
2008-04-23 17:14:59 -07:00
if ( ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE )
ant_toggle_cnt + + ;
else if ( priv & &
rs_toggle_antenna ( valid_tx_ant ,
& new_rate , & tbl_type ) )
ant_toggle_cnt = 1 ;
2007-09-27 11:27:41 +08:00
repeat_rate = IWL_NUMBER_TRY ;
2008-04-23 17:14:59 -07:00
} else {
2007-09-27 11:27:41 +08:00
repeat_rate = IWL_HT_NUMBER_TRY ;
2008-04-23 17:14:59 -07:00
}
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:44 +08:00
/* Don't allow HT rates after next pass.
* rs_get_lower_rate ( ) will change type to LQ_A or LQ_G . */
2007-09-25 17:54:57 -07:00
use_ht_possible = 0 ;
2007-11-29 11:09:44 +08:00
/* Override next rate if needed for debug purposes */
2008-01-14 17:46:21 -08:00
rs_dbgfs_set_mcs ( lq_sta , & new_rate , index ) ;
2007-11-29 11:09:44 +08:00
/* Fill next table entry */
2008-04-23 17:14:57 -07:00
lq_cmd - > rs_table [ index ] . rate_n_flags = cpu_to_le32 ( new_rate ) ;
2007-09-25 17:54:57 -07:00
index + + ;
2007-09-27 11:27:41 +08:00
repeat_rate - - ;
2007-09-25 17:54:57 -07:00
}
lq_cmd - > agg_params . agg_dis_start_th = 3 ;
lq_cmd - > agg_params . agg_time_limit = cpu_to_le16 ( 4000 ) ;
}
static void * rs_alloc ( struct ieee80211_local * local )
{
return local - > hw . priv ;
}
/* rate scale requires free function to be implemented */
static void rs_free ( void * priv_rate )
{
return ;
}
static void rs_clear ( void * priv_rate )
{
2008-03-12 16:58:50 -07:00
struct iwl_priv * priv = ( struct iwl_priv * ) priv_rate ;
2007-09-25 17:54:57 -07:00
IWL_DEBUG_RATE ( " enter \n " ) ;
priv - > lq_mngr . lq_ready = 0 ;
IWL_DEBUG_RATE ( " leave \n " ) ;
}
2008-05-05 10:22:40 +08:00
static void rs_free_sta ( void * priv_rate , void * priv_sta )
2007-09-25 17:54:57 -07:00
{
2008-01-14 17:46:21 -08:00
struct iwl4965_lq_sta * lq_sta = priv_sta ;
2008-05-05 10:22:40 +08:00
struct iwl_priv * priv ;
2007-09-25 17:54:57 -07:00
2008-05-05 10:22:40 +08:00
priv = ( struct iwl_priv * ) priv_rate ;
2007-09-25 17:54:57 -07:00
IWL_DEBUG_RATE ( " enter \n " ) ;
2008-01-14 17:46:21 -08:00
kfree ( lq_sta ) ;
2007-09-25 17:54:57 -07:00
IWL_DEBUG_RATE ( " leave \n " ) ;
}
2007-09-27 11:27:37 +08:00
# ifdef CONFIG_MAC80211_DEBUGFS
2007-09-27 11:27:38 +08:00
static int open_file_generic ( struct inode * inode , struct file * file )
{
file - > private_data = inode - > i_private ;
return 0 ;
}
2008-01-14 17:46:21 -08:00
static void rs_dbgfs_set_mcs ( struct iwl4965_lq_sta * lq_sta ,
2008-04-23 17:14:57 -07:00
u32 * rate_n_flags , int index )
2007-09-27 11:27:42 +08:00
{
2008-05-05 10:22:40 +08:00
struct iwl_priv * priv ;
priv = lq_sta - > drv ;
2008-04-23 17:14:57 -07:00
if ( lq_sta - > dbg_fixed_rate ) {
if ( index < 12 ) {
* rate_n_flags = lq_sta - > dbg_fixed_rate ;
} else {
if ( lq_sta - > band = = IEEE80211_BAND_5GHZ )
* rate_n_flags = 0x800D ;
else
* rate_n_flags = 0x820A ;
}
2007-09-27 11:27:42 +08:00
IWL_DEBUG_RATE ( " Fixed rate ON \n " ) ;
2008-04-23 17:14:57 -07:00
} else {
IWL_DEBUG_RATE ( " Fixed rate OFF \n " ) ;
2007-09-27 11:27:42 +08:00
}
}
2007-09-27 11:27:38 +08:00
2007-09-27 11:27:42 +08:00
static ssize_t rs_sta_dbgfs_scale_table_write ( struct file * file ,
const char __user * user_buf , size_t count , loff_t * ppos )
{
2008-01-14 17:46:21 -08:00
struct iwl4965_lq_sta * lq_sta = file - > private_data ;
2008-05-05 10:22:40 +08:00
struct iwl_priv * priv ;
2007-09-27 11:27:42 +08:00
char buf [ 64 ] ;
int buf_size ;
u32 parsed_rate ;
2008-05-05 10:22:40 +08:00
priv = lq_sta - > drv ;
2007-09-27 11:27:42 +08:00
memset ( buf , 0 , sizeof ( buf ) ) ;
buf_size = min ( count , sizeof ( buf ) - 1 ) ;
if ( copy_from_user ( buf , user_buf , buf_size ) )
return - EFAULT ;
if ( sscanf ( buf , " %x " , & parsed_rate ) = = 1 )
2008-04-23 17:14:57 -07:00
lq_sta - > dbg_fixed_rate = parsed_rate ;
2007-09-27 11:27:42 +08:00
else
2008-04-23 17:14:57 -07:00
lq_sta - > dbg_fixed_rate = 0 ;
2007-09-27 11:27:42 +08:00
2008-04-23 17:14:57 -07:00
lq_sta - > active_legacy_rate = 0x0FFF ; /* 1 - 54 MBits, includes CCK */
lq_sta - > active_siso_rate = 0x1FD0 ; /* 6 - 60 MBits, no 9, no CCK */
lq_sta - > active_mimo2_rate = 0x1FD0 ; /* 6 - 60 MBits, no 9, no CCK */
lq_sta - > active_mimo3_rate = 0x1FD0 ; /* 6 - 60 MBits, no 9, no CCK */
2007-09-27 11:27:42 +08:00
IWL_DEBUG_RATE ( " sta_id %d rate 0x%X \n " ,
2008-04-23 17:14:57 -07:00
lq_sta - > lq . sta_id , lq_sta - > dbg_fixed_rate ) ;
2007-09-27 11:27:42 +08:00
2008-04-23 17:14:57 -07:00
if ( lq_sta - > dbg_fixed_rate ) {
2008-04-23 17:15:03 -07:00
rs_fill_link_cmd ( NULL , lq_sta , lq_sta - > dbg_fixed_rate ) ;
2008-04-15 16:01:40 -07:00
iwl_send_lq_cmd ( lq_sta - > drv , & lq_sta - > lq , CMD_ASYNC ) ;
2007-09-27 11:27:42 +08:00
}
return count ;
}
2007-09-27 11:27:43 +08:00
2007-09-27 11:27:38 +08:00
static ssize_t rs_sta_dbgfs_scale_table_read ( struct file * file ,
char __user * user_buf , size_t count , loff_t * ppos )
{
char buff [ 1024 ] ;
int desc = 0 ;
int i = 0 ;
2008-01-14 17:46:21 -08:00
struct iwl4965_lq_sta * lq_sta = file - > private_data ;
2007-09-27 11:27:38 +08:00
2008-01-14 17:46:21 -08:00
desc + = sprintf ( buff + desc , " sta_id %d \n " , lq_sta - > lq . sta_id ) ;
2007-09-27 11:27:42 +08:00
desc + = sprintf ( buff + desc , " failed=%d success=%d rate=0%X \n " ,
2008-01-14 17:46:21 -08:00
lq_sta - > total_failed , lq_sta - > total_success ,
2008-04-23 17:14:57 -07:00
lq_sta - > active_legacy_rate ) ;
2007-09-27 11:27:42 +08:00
desc + = sprintf ( buff + desc , " fixed rate 0x%X \n " ,
2008-04-23 17:14:57 -07:00
lq_sta - > dbg_fixed_rate ) ;
2007-09-27 11:27:38 +08:00
desc + = sprintf ( buff + desc , " general: "
" flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x \n " ,
2008-01-14 17:46:21 -08:00
lq_sta - > lq . general_params . flags ,
lq_sta - > lq . general_params . mimo_delimiter ,
lq_sta - > lq . general_params . single_stream_ant_msk ,
lq_sta - > lq . general_params . dual_stream_ant_msk ) ;
2007-09-27 11:27:38 +08:00
desc + = sprintf ( buff + desc , " agg: "
" time_limit=%d dist_start_th=%d frame_cnt_limit=%d \n " ,
2008-01-14 17:46:21 -08:00
le16_to_cpu ( lq_sta - > lq . agg_params . agg_time_limit ) ,
lq_sta - > lq . agg_params . agg_dis_start_th ,
lq_sta - > lq . agg_params . agg_frame_cnt_limit ) ;
2007-09-27 11:27:38 +08:00
desc + = sprintf ( buff + desc ,
" Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x \n " ,
2008-01-14 17:46:21 -08:00
lq_sta - > lq . general_params . start_rate_index [ 0 ] ,
lq_sta - > lq . general_params . start_rate_index [ 1 ] ,
lq_sta - > lq . general_params . start_rate_index [ 2 ] ,
lq_sta - > lq . general_params . start_rate_index [ 3 ] ) ;
2007-09-27 11:27:38 +08:00
for ( i = 0 ; i < LINK_QUAL_MAX_RETRY_NUM ; i + + )
desc + = sprintf ( buff + desc , " rate[%d] 0x%X \n " ,
2008-01-14 17:46:21 -08:00
i , le32_to_cpu ( lq_sta - > lq . rs_table [ i ] . rate_n_flags ) ) ;
2007-09-27 11:27:38 +08:00
return simple_read_from_buffer ( user_buf , count , ppos , buff , desc ) ;
}
static const struct file_operations rs_sta_dbgfs_scale_table_ops = {
2007-09-27 11:27:42 +08:00
. write = rs_sta_dbgfs_scale_table_write ,
2007-09-27 11:27:38 +08:00
. read = rs_sta_dbgfs_scale_table_read ,
. open = open_file_generic ,
} ;
2007-09-27 11:27:43 +08:00
static ssize_t rs_sta_dbgfs_stats_table_read ( struct file * file ,
char __user * user_buf , size_t count , loff_t * ppos )
{
char buff [ 1024 ] ;
int desc = 0 ;
int i , j ;
2008-01-14 17:46:21 -08:00
struct iwl4965_lq_sta * lq_sta = file - > private_data ;
2007-09-27 11:27:43 +08:00
for ( i = 0 ; i < LQ_SIZE ; i + + ) {
desc + = sprintf ( buff + desc , " %s type=%d SGI=%d FAT=%d DUP=%d \n "
" rate=0x%X \n " ,
2008-01-14 17:46:21 -08:00
lq_sta - > active_tbl = = i ? " * " : " x " ,
lq_sta - > lq_info [ i ] . lq_type ,
lq_sta - > lq_info [ i ] . is_SGI ,
lq_sta - > lq_info [ i ] . is_fat ,
lq_sta - > lq_info [ i ] . is_dup ,
2008-04-23 17:14:57 -07:00
lq_sta - > lq_info [ i ] . current_rate ) ;
2007-09-27 11:27:43 +08:00
for ( j = 0 ; j < IWL_RATE_COUNT ; j + + ) {
desc + = sprintf ( buff + desc ,
2008-01-14 17:46:21 -08:00
" counter=%d success=%d %%=%d \n " ,
lq_sta - > lq_info [ i ] . win [ j ] . counter ,
lq_sta - > lq_info [ i ] . win [ j ] . success_counter ,
lq_sta - > lq_info [ i ] . win [ j ] . success_ratio ) ;
2007-09-27 11:27:43 +08:00
}
}
return simple_read_from_buffer ( user_buf , count , ppos , buff , desc ) ;
}
static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
. read = rs_sta_dbgfs_stats_table_read ,
. open = open_file_generic ,
} ;
2007-09-27 11:27:38 +08:00
2007-09-27 11:27:37 +08:00
static void rs_add_debugfs ( void * priv , void * priv_sta ,
struct dentry * dir )
{
2008-01-14 17:46:21 -08:00
struct iwl4965_lq_sta * lq_sta = priv_sta ;
lq_sta - > rs_sta_dbgfs_scale_table_file =
2007-09-27 11:27:43 +08:00
debugfs_create_file ( " rate_scale_table " , 0600 , dir ,
2008-01-14 17:46:21 -08:00
lq_sta , & rs_sta_dbgfs_scale_table_ops ) ;
lq_sta - > rs_sta_dbgfs_stats_table_file =
2007-09-27 11:27:43 +08:00
debugfs_create_file ( " rate_stats_table " , 0600 , dir ,
2008-01-14 17:46:21 -08:00
lq_sta , & rs_sta_dbgfs_stats_table_ops ) ;
2008-01-28 14:07:26 +02:00
# ifdef CONFIG_IWL4965_HT
lq_sta - > rs_sta_dbgfs_tx_agg_tid_en_file =
debugfs_create_u8 ( " tx_agg_tid_enable " , 0600 , dir ,
& lq_sta - > tx_agg_tid_en ) ;
# endif
2007-09-27 11:27:37 +08:00
}
static void rs_remove_debugfs ( void * priv , void * priv_sta )
{
2008-01-14 17:46:21 -08:00
struct iwl4965_lq_sta * lq_sta = priv_sta ;
debugfs_remove ( lq_sta - > rs_sta_dbgfs_scale_table_file ) ;
debugfs_remove ( lq_sta - > rs_sta_dbgfs_stats_table_file ) ;
2008-01-28 14:07:26 +02:00
# ifdef CONFIG_IWL4965_HT
debugfs_remove ( lq_sta - > rs_sta_dbgfs_tx_agg_tid_en_file ) ;
# endif
2007-09-27 11:27:37 +08:00
}
# 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 ,
. clear = rs_clear ,
. alloc = rs_alloc ,
. free = rs_free ,
. alloc_sta = rs_alloc_sta ,
. free_sta = rs_free_sta ,
2007-09-27 11:27:37 +08:00
# ifdef CONFIG_MAC80211_DEBUGFS
. add_sta_debugfs = rs_add_debugfs ,
. remove_sta_debugfs = rs_remove_debugfs ,
# endif
2007-09-25 17:54:57 -07:00
} ;
2008-01-27 16:41:47 -08:00
int iwl4965_fill_rs_info ( struct ieee80211_hw * hw , char * buf , u8 sta_id )
2007-09-25 17:54:57 -07:00
{
struct ieee80211_local * local = hw_to_local ( hw ) ;
2008-03-12 16:58:50 -07:00
struct iwl_priv * priv = hw - > priv ;
2008-01-14 17:46:21 -08:00
struct iwl4965_lq_sta * lq_sta ;
2007-09-25 17:54:57 -07:00
struct sta_info * sta ;
2008-01-14 17:46:21 -08:00
int cnt = 0 , i ;
2007-09-25 17:54:57 -07:00
u32 samples = 0 , success = 0 , good = 0 ;
unsigned long now = jiffies ;
u32 max_time = 0 ;
u8 lq_type , antenna ;
2008-02-25 16:27:46 +01:00
rcu_read_lock ( ) ;
2007-09-25 17:54:57 -07:00
sta = sta_info_get ( local , priv - > stations [ sta_id ] . sta . sta . addr ) ;
if ( ! sta | | ! sta - > rate_ctrl_priv ) {
2008-02-25 16:27:46 +01:00
if ( sta )
2007-09-25 17:54:57 -07:00
IWL_DEBUG_RATE ( " leave - no private rate data! \n " ) ;
2008-02-25 16:27:46 +01:00
else
2007-09-25 17:54:57 -07:00
IWL_DEBUG_RATE ( " leave - no station! \n " ) ;
2008-02-25 16:27:46 +01:00
rcu_read_unlock ( ) ;
2007-09-25 17:54:57 -07:00
return sprintf ( buf , " station %d not found \n " , sta_id ) ;
}
2008-01-14 17:46:21 -08:00
lq_sta = ( void * ) sta - > rate_ctrl_priv ;
2007-09-25 17:54:57 -07:00
2008-01-14 17:46:21 -08:00
lq_type = lq_sta - > lq_info [ lq_sta - > active_tbl ] . lq_type ;
2008-04-21 15:42:01 -07:00
antenna = lq_sta - > lq_info [ lq_sta - > active_tbl ] . ant_type ;
2007-09-25 17:54:57 -07:00
if ( is_legacy ( lq_type ) )
i = IWL_RATE_54M_INDEX ;
else
i = IWL_RATE_60M_INDEX ;
while ( 1 ) {
u64 mask ;
int j ;
2008-01-14 17:46:21 -08:00
int active = lq_sta - > active_tbl ;
2007-09-25 17:54:57 -07:00
2008-01-14 17:46:21 -08:00
cnt + =
2008-05-15 13:54:02 +08:00
sprintf ( & buf [ cnt ] , " %2dMbs: " , iwl_rates [ i ] . ieee / 2 ) ;
2007-09-25 17:54:57 -07:00
mask = ( 1ULL < < ( IWL_RATE_MAX_WINDOW - 1 ) ) ;
for ( j = 0 ; j < IWL_RATE_MAX_WINDOW ; j + + , mask > > = 1 )
2008-01-14 17:46:21 -08:00
buf [ cnt + + ] =
( lq_sta - > lq_info [ active ] . win [ i ] . data & mask )
2007-09-25 17:54:57 -07:00
? ' 1 ' : ' 0 ' ;
2008-01-14 17:46:21 -08:00
samples + = lq_sta - > lq_info [ active ] . win [ i ] . counter ;
good + = lq_sta - > lq_info [ active ] . win [ i ] . success_counter ;
success + = lq_sta - > lq_info [ active ] . win [ i ] . success_counter *
2008-05-15 13:54:02 +08:00
iwl_rates [ i ] . ieee ;
2007-09-25 17:54:57 -07:00
2008-01-14 17:46:21 -08:00
if ( lq_sta - > lq_info [ active ] . win [ i ] . stamp ) {
2007-09-25 17:54:57 -07:00
int delta =
jiffies_to_msecs ( now -
2008-01-14 17:46:21 -08:00
lq_sta - > lq_info [ active ] . win [ i ] . stamp ) ;
2007-09-25 17:54:57 -07:00
if ( delta > max_time )
max_time = delta ;
2008-01-14 17:46:21 -08:00
cnt + = sprintf ( & buf [ cnt ] , " %5dms \n " , delta ) ;
2007-09-25 17:54:57 -07:00
} else
2008-01-14 17:46:21 -08:00
buf [ cnt + + ] = ' \n ' ;
2007-09-25 17:54:57 -07:00
2008-01-27 16:41:47 -08:00
j = iwl4965_get_prev_ieee_rate ( i ) ;
2007-09-25 17:54:57 -07:00
if ( j = = i )
break ;
i = j ;
}
2008-05-15 13:54:02 +08:00
/*
* Display the average rate of all samples taken .
* NOTE : We multiply # of samples by 2 since the IEEE measurement
* added from iwl_rates is actually 2 X the rate .
*/
2007-09-25 17:54:57 -07:00
if ( samples )
2008-01-14 17:46:21 -08:00
cnt + = sprintf ( & buf [ cnt ] ,
2007-09-25 17:54:57 -07:00
" \n Average rate is %3d.%02dMbs over last %4dms \n "
" %3d%% success (%d good packets over %d tries) \n " ,
success / ( 2 * samples ) , ( success * 5 / samples ) % 10 ,
max_time , good * 100 / samples , good , samples ) ;
else
2008-01-14 17:46:21 -08:00
cnt + = sprintf ( & buf [ cnt ] , " \n Average rate: 0Mbs \n " ) ;
cnt + = sprintf ( & buf [ cnt ] , " \n rate scale type %d antenna %d "
2007-09-25 17:54:57 -07:00
" active_search %d rate index %d \n " , lq_type , antenna ,
2008-01-24 19:38:38 +01:00
lq_sta - > search_better_tbl , sta - > last_txrate_idx ) ;
2007-09-25 17:54:57 -07:00
2008-02-25 16:27:46 +01:00
rcu_read_unlock ( ) ;
2008-01-14 17:46:21 -08:00
return cnt ;
2007-09-25 17:54:57 -07:00
}
2008-01-27 16:41:47 -08:00
void iwl4965_rate_scale_init ( struct ieee80211_hw * hw , s32 sta_id )
2007-09-25 17:54:57 -07:00
{
2008-03-12 16:58:50 -07:00
struct iwl_priv * priv = hw - > priv ;
2007-09-25 17:54:57 -07:00
priv - > lq_mngr . lq_ready = 1 ;
}
2008-03-28 16:21:09 -07:00
int iwl4965_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 iwl4965_rate_control_unregister ( void )
2007-09-25 17:54:57 -07:00
{
ieee80211_rate_control_unregister ( & rs_ops ) ;
}