ath5k: Extend rate_duration
* Extend ieee80211_generic_frame_duration to support the various bwmodes. * Better document what's going on with ack bitrates and update write_rate_duration to support the standard ack bitrates (when we don't set the high bit). * Get rid of set_ack_bitrate_high and introduce a flag on ath5k_hw for this (we only called the function on init anyway so there is no difference). Signed-off-by: Nick Kossifidis <mickflemm@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
committed by
John W. Linville
parent
3017fcab41
commit
61cde03723
@@ -267,6 +267,15 @@
|
|||||||
#define AR5K_INIT_SIFS_HALF_RATE 32
|
#define AR5K_INIT_SIFS_HALF_RATE 32
|
||||||
#define AR5K_INIT_SIFS_QUARTER_RATE 64
|
#define AR5K_INIT_SIFS_QUARTER_RATE 64
|
||||||
|
|
||||||
|
/* Used to calculate tx time for non 5/10/40MHz
|
||||||
|
* operation */
|
||||||
|
/* It's preamble time + signal time (16 + 4) */
|
||||||
|
#define AR5K_INIT_OFDM_PREAMPLE_TIME 20
|
||||||
|
/* Preamble time for 40MHz (turbo) operation (min ?) */
|
||||||
|
#define AR5K_INIT_OFDM_PREAMBLE_TIME_MIN 14
|
||||||
|
#define AR5K_INIT_OFDM_SYMBOL_TIME 4
|
||||||
|
#define AR5K_INIT_OFDM_PLCP_BITS 22
|
||||||
|
|
||||||
/* Rx latency for 5 and 10MHz operation (max ?) */
|
/* Rx latency for 5 and 10MHz operation (max ?) */
|
||||||
#define AR5K_INIT_RX_LAT_MAX 63
|
#define AR5K_INIT_RX_LAT_MAX 63
|
||||||
/* Tx latencies from initvals (5212 only but no problem
|
/* Tx latencies from initvals (5212 only but no problem
|
||||||
@@ -1083,6 +1092,7 @@ struct ath5k_hw {
|
|||||||
|
|
||||||
u32 ah_limit_tx_retries;
|
u32 ah_limit_tx_retries;
|
||||||
u8 ah_coverage_class;
|
u8 ah_coverage_class;
|
||||||
|
bool ah_ack_bitrate_high;
|
||||||
u8 ah_bwmode;
|
u8 ah_bwmode;
|
||||||
|
|
||||||
/* Antenna Control */
|
/* Antenna Control */
|
||||||
@@ -1248,8 +1258,6 @@ void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64);
|
|||||||
void ath5k_hw_reset_tsf(struct ath5k_hw *ah);
|
void ath5k_hw_reset_tsf(struct ath5k_hw *ah);
|
||||||
void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval);
|
void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval);
|
||||||
bool ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval);
|
bool ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval);
|
||||||
/* ACK bit rate */
|
|
||||||
void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high);
|
|
||||||
/* Init function */
|
/* Init function */
|
||||||
void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
|
void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
|
||||||
u8 mode);
|
u8 mode);
|
||||||
|
@@ -2420,7 +2420,9 @@ ath5k_init(struct ath5k_softc *sc)
|
|||||||
for (i = 0; i < common->keymax; i++)
|
for (i = 0; i < common->keymax; i++)
|
||||||
ath_hw_keyreset(common, (u16) i);
|
ath_hw_keyreset(common, (u16) i);
|
||||||
|
|
||||||
ath5k_hw_set_ack_bitrate_high(ah, true);
|
/* Use higher rates for acks instead of base
|
||||||
|
* rate */
|
||||||
|
ah->ah_ack_bitrate_high = true;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(sc->bslot); i++)
|
for (i = 0; i < ARRAY_SIZE(sc->bslot); i++)
|
||||||
sc->bslot[i] = NULL;
|
sc->bslot[i] = NULL;
|
||||||
|
@@ -31,10 +31,99 @@
|
|||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AR5212+ can use higher rates for ack transmition
|
||||||
|
* based on current tx rate instead of the base rate.
|
||||||
|
* It does this to better utilize channel usage.
|
||||||
|
* This is a mapping between G rates (that cover both
|
||||||
|
* CCK and OFDM) and ack rates that we use when setting
|
||||||
|
* rate -> duration table. This mapping is hw-based so
|
||||||
|
* don't change anything.
|
||||||
|
*
|
||||||
|
* To enable this functionality we must set
|
||||||
|
* ah->ah_ack_bitrate_high to true else base rate is
|
||||||
|
* used (1Mb for CCK, 6Mb for OFDM).
|
||||||
|
*/
|
||||||
|
static const unsigned int ack_rates_high[] =
|
||||||
|
/* Tx -> ACK */
|
||||||
|
/* 1Mb -> 1Mb */ { 0,
|
||||||
|
/* 2MB -> 2Mb */ 1,
|
||||||
|
/* 5.5Mb -> 2Mb */ 1,
|
||||||
|
/* 11Mb -> 2Mb */ 1,
|
||||||
|
/* 6Mb -> 6Mb */ 4,
|
||||||
|
/* 9Mb -> 6Mb */ 4,
|
||||||
|
/* 12Mb -> 12Mb */ 6,
|
||||||
|
/* 18Mb -> 12Mb */ 6,
|
||||||
|
/* 24Mb -> 24Mb */ 8,
|
||||||
|
/* 36Mb -> 24Mb */ 8,
|
||||||
|
/* 48Mb -> 24Mb */ 8,
|
||||||
|
/* 54Mb -> 24Mb */ 8 };
|
||||||
|
|
||||||
/*******************\
|
/*******************\
|
||||||
* Helper functions *
|
* Helper functions *
|
||||||
\*******************/
|
\*******************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ath5k_hw_get_frame_duration - Get tx time of a frame
|
||||||
|
*
|
||||||
|
* @ah: The &struct ath5k_hw
|
||||||
|
* @len: Frame's length in bytes
|
||||||
|
* @rate: The @struct ieee80211_rate
|
||||||
|
*
|
||||||
|
* Calculate tx duration of a frame given it's rate and length
|
||||||
|
* It extends ieee80211_generic_frame_duration for non standard
|
||||||
|
* bwmodes.
|
||||||
|
*/
|
||||||
|
int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
|
||||||
|
int len, struct ieee80211_rate *rate)
|
||||||
|
{
|
||||||
|
struct ath5k_softc *sc = ah->ah_sc;
|
||||||
|
int sifs, preamble, plcp_bits, sym_time;
|
||||||
|
int bitrate, bits, symbols, symbol_bits;
|
||||||
|
int dur;
|
||||||
|
|
||||||
|
/* Fallback */
|
||||||
|
if (!ah->ah_bwmode) {
|
||||||
|
dur = ieee80211_generic_frame_duration(sc->hw,
|
||||||
|
NULL, len, rate);
|
||||||
|
return dur;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitrate = rate->bitrate;
|
||||||
|
preamble = AR5K_INIT_OFDM_PREAMPLE_TIME;
|
||||||
|
plcp_bits = AR5K_INIT_OFDM_PLCP_BITS;
|
||||||
|
sym_time = AR5K_INIT_OFDM_SYMBOL_TIME;
|
||||||
|
|
||||||
|
switch (ah->ah_bwmode) {
|
||||||
|
case AR5K_BWMODE_40MHZ:
|
||||||
|
sifs = AR5K_INIT_SIFS_TURBO;
|
||||||
|
preamble = AR5K_INIT_OFDM_PREAMBLE_TIME_MIN;
|
||||||
|
break;
|
||||||
|
case AR5K_BWMODE_10MHZ:
|
||||||
|
sifs = AR5K_INIT_SIFS_HALF_RATE;
|
||||||
|
preamble *= 2;
|
||||||
|
sym_time *= 2;
|
||||||
|
break;
|
||||||
|
case AR5K_BWMODE_5MHZ:
|
||||||
|
sifs = AR5K_INIT_SIFS_QUARTER_RATE;
|
||||||
|
preamble *= 4;
|
||||||
|
sym_time *= 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sifs = AR5K_INIT_SIFS_DEFAULT_BG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bits = plcp_bits + (len << 3);
|
||||||
|
/* Bit rate is in 100Kbits */
|
||||||
|
symbol_bits = bitrate * sym_time;
|
||||||
|
symbols = DIV_ROUND_UP(bits * 10, symbol_bits);
|
||||||
|
|
||||||
|
dur = sifs + preamble + (sym_time * symbols);
|
||||||
|
|
||||||
|
return dur;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ath5k_hw_get_default_slottime - Get the default slot time for current mode
|
* ath5k_hw_get_default_slottime - Get the default slot time for current mode
|
||||||
*
|
*
|
||||||
@@ -120,43 +209,11 @@ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah)
|
|||||||
stats->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);
|
stats->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* ath5k_hw_set_ack_bitrate - set bitrate for ACKs
|
|
||||||
*
|
|
||||||
* @ah: The &struct ath5k_hw
|
|
||||||
* @high: Flag to determine if we want to use high transmission rate
|
|
||||||
* for ACKs or not
|
|
||||||
*
|
|
||||||
* If high flag is set, we tell hw to use a set of control rates based on
|
|
||||||
* the current transmission rate (check out control_rates array inside reset.c).
|
|
||||||
* If not hw just uses the lowest rate available for the current modulation
|
|
||||||
* scheme being used (1Mbit for CCK and 6Mbits for OFDM).
|
|
||||||
*/
|
|
||||||
void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high)
|
|
||||||
{
|
|
||||||
if (ah->ah_version != AR5K_AR5212)
|
|
||||||
return;
|
|
||||||
else {
|
|
||||||
u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
|
|
||||||
if (high)
|
|
||||||
AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
|
|
||||||
else
|
|
||||||
AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/******************\
|
/******************\
|
||||||
* ACK/CTS Timeouts *
|
* ACK/CTS Timeouts *
|
||||||
\******************/
|
\******************/
|
||||||
|
|
||||||
/*
|
|
||||||
* index into rates for control rates, we can set it up like this because
|
|
||||||
* this is only used for AR5212 and we know it supports G mode
|
|
||||||
*/
|
|
||||||
static const unsigned int control_rates[] =
|
|
||||||
{ 0, 1, 1, 1, 4, 4, 6, 6, 8, 8, 8, 8 };
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ath5k_hw_write_rate_duration - fill rate code to duration table
|
* ath5k_hw_write_rate_duration - fill rate code to duration table
|
||||||
*
|
*
|
||||||
@@ -164,7 +221,7 @@ static const unsigned int control_rates[] =
|
|||||||
* @mode: one of enum ath5k_driver_mode
|
* @mode: one of enum ath5k_driver_mode
|
||||||
*
|
*
|
||||||
* Write the rate code to duration table upon hw reset. This is a helper for
|
* Write the rate code to duration table upon hw reset. This is a helper for
|
||||||
* ath5k_hw_reset(). It seems all this is doing is setting an ACK timeout on
|
* ath5k_hw_pcu_init(). It seems all this is doing is setting an ACK timeout on
|
||||||
* the hardware, based on current mode, for each rate. The rates which are
|
* the hardware, based on current mode, for each rate. The rates which are
|
||||||
* capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have
|
* capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have
|
||||||
* different rate code so we write their value twice (one for long preamble
|
* different rate code so we write their value twice (one for long preamble
|
||||||
@@ -172,23 +229,30 @@ static const unsigned int control_rates[] =
|
|||||||
*
|
*
|
||||||
* Note: Band doesn't matter here, if we set the values for OFDM it works
|
* Note: Band doesn't matter here, if we set the values for OFDM it works
|
||||||
* on both a and g modes. So all we have to do is set values for all g rates
|
* on both a and g modes. So all we have to do is set values for all g rates
|
||||||
* that include all OFDM and CCK rates. If we operate in turbo or xr/half/
|
* that include all OFDM and CCK rates.
|
||||||
* quarter rate mode, we need to use another set of bitrates (that's why we
|
*
|
||||||
* need the mode parameter) but we don't handle these proprietary modes yet.
|
|
||||||
*/
|
*/
|
||||||
static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah,
|
static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah)
|
||||||
unsigned int mode)
|
|
||||||
{
|
{
|
||||||
struct ath5k_softc *sc = ah->ah_sc;
|
struct ath5k_softc *sc = ah->ah_sc;
|
||||||
struct ieee80211_rate *rate;
|
struct ieee80211_rate *rate;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
/* 802.11g covers both OFDM and CCK */
|
||||||
|
u8 band = IEEE80211_BAND_2GHZ;
|
||||||
|
|
||||||
/* Write rate duration table */
|
/* Write rate duration table */
|
||||||
for (i = 0; i < sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates; i++) {
|
for (i = 0; i < sc->sbands[band].n_bitrates; i++) {
|
||||||
u32 reg;
|
u32 reg;
|
||||||
u16 tx_time;
|
u16 tx_time;
|
||||||
|
|
||||||
rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[control_rates[i]];
|
if (ah->ah_ack_bitrate_high)
|
||||||
|
rate = &sc->sbands[band].bitrates[ack_rates_high[i]];
|
||||||
|
/* CCK -> 1Mb */
|
||||||
|
else if (i < 4)
|
||||||
|
rate = &sc->sbands[band].bitrates[0];
|
||||||
|
/* OFDM -> 6Mb */
|
||||||
|
else
|
||||||
|
rate = &sc->sbands[band].bitrates[4];
|
||||||
|
|
||||||
/* Set ACK timeout */
|
/* Set ACK timeout */
|
||||||
reg = AR5K_RATE_DUR(rate->hw_value);
|
reg = AR5K_RATE_DUR(rate->hw_value);
|
||||||
@@ -199,8 +263,9 @@ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah,
|
|||||||
* actual rate for this rate. See mac80211 tx.c
|
* actual rate for this rate. See mac80211 tx.c
|
||||||
* ieee80211_duration() for a brief description of
|
* ieee80211_duration() for a brief description of
|
||||||
* what rate we should choose to TX ACKs. */
|
* what rate we should choose to TX ACKs. */
|
||||||
tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw,
|
tx_time = ath5k_hw_get_frame_duration(ah, 10, rate);
|
||||||
NULL, 10, rate));
|
|
||||||
|
tx_time = le16_to_cpu(tx_time);
|
||||||
|
|
||||||
ath5k_hw_reg_write(ah, tx_time, reg);
|
ath5k_hw_reg_write(ah, tx_time, reg);
|
||||||
|
|
||||||
@@ -835,7 +900,7 @@ void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
|
|||||||
* mac80211 are integrated */
|
* mac80211 are integrated */
|
||||||
if (ah->ah_version == AR5K_AR5212 &&
|
if (ah->ah_version == AR5K_AR5212 &&
|
||||||
ah->ah_sc->nvifs)
|
ah->ah_sc->nvifs)
|
||||||
ath5k_hw_write_rate_duration(ah, mode);
|
ath5k_hw_write_rate_duration(ah);
|
||||||
|
|
||||||
/* Set RSSI/BRSSI thresholds
|
/* Set RSSI/BRSSI thresholds
|
||||||
*
|
*
|
||||||
@@ -869,5 +934,13 @@ void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
|
|||||||
if (ah->ah_coverage_class > 0)
|
if (ah->ah_coverage_class > 0)
|
||||||
ath5k_hw_set_coverage_class(ah, ah->ah_coverage_class);
|
ath5k_hw_set_coverage_class(ah, ah->ah_coverage_class);
|
||||||
|
|
||||||
|
/* Set ACK bitrate mode (see ack_rates_high) */
|
||||||
|
if (ah->ah_version == AR5K_AR5212) {
|
||||||
|
u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
|
||||||
|
if (ah->ah_ack_bitrate_high)
|
||||||
|
AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
|
||||||
|
else
|
||||||
|
AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user