Commit f078f209 authored by Luis R. Rodriguez's avatar Luis R. Rodriguez Committed by John W. Linville
Browse files

ath9k: Add new Atheros IEEE 802.11n driver


This adds the new mac80211 11n ath9k Atheros driver. Only STA support
is currently enabled and tested.
Signed-off-by: default avatarSenthil Balasubramanian <senthilkumar@atheros.com>
Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarJack Howarth <howarth@bromo.msbb.uc.edu>
Signed-off-by: default avatarJouni Malinen <jouni.malinen@atheros.com>
Signed-off-by: default avatarSujith Manoharan <Sujith.Manoharan@atheros.com>
Signed-off-by: default avatarLuis R. Rodriguez <lrodriguez@atheros.com>
Signed-off-by: default avatarPavel Roskin <proski@gnu.org>
Signed-off-by: default avatarVasanthakumar Thiagarajan <vasanth@atheros.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent b1a52150
......@@ -720,6 +720,15 @@ L: linux-wireless@vger.kernel.org
L: ath5k-devel@lists.ath5k.org
S: Maintained
ATHEROS ATH9K WIRELESS DRIVER
P: Luis R. Rodriguez
M: lrodriguez@atheros.com
P: Jouni Malinen
M: jmalinen@atheros.com
L: linux-wireless@vger.kernel.org
L: ath9k-devel@lists.ath9k.org
S: Supported
ATI_REMOTE2 DRIVER
P: Ville Syrjala
M: syrjala@sci.fi
......
......@@ -695,6 +695,7 @@ config MAC80211_HWSIM
source "drivers/net/wireless/p54/Kconfig"
source "drivers/net/wireless/ath5k/Kconfig"
source "drivers/net/wireless/ath9k/Kconfig"
source "drivers/net/wireless/iwlwifi/Kconfig"
source "drivers/net/wireless/hostap/Kconfig"
source "drivers/net/wireless/b43/Kconfig"
......
......@@ -62,5 +62,6 @@ obj-$(CONFIG_RT2X00) += rt2x00/
obj-$(CONFIG_P54_COMMON) += p54/
obj-$(CONFIG_ATH5K) += ath5k/
obj-$(CONFIG_ATH9K) += ath9k/
obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
config ATH9K
tristate "Atheros 802.11n wireless cards support"
depends on PCI && MAC80211 && WLAN_80211
---help---
This module adds support for wireless adapters based on
Atheros IEEE 802.11n AR5008 and AR9001 family of chipsets.
If you choose to build a module, it'll be called ath9k.
ath9k-y += hw.o \
phy.o \
regd.o \
beacon.o \
main.o \
recv.o \
xmit.o \
rc.o \
core.o
obj-$(CONFIG_ATH9K) += ath9k.o
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* Copyright (c) 2008 Atheros Communications Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "core.h"
#include "hw.h"
#include "reg.h"
#include "phy.h"
void
ath9k_hw_write_regs(struct ath_hal *ah, u32 modesIndex, u32 freqIndex,
int regWrites)
{
struct ath_hal_5416 *ahp = AH5416(ah);
REG_WRITE_ARRAY(&ahp->ah_iniBB_RfGain, freqIndex, regWrites);
}
bool
ath9k_hw_set_channel(struct ath_hal *ah, struct ath9k_channel *chan)
{
u32 channelSel = 0;
u32 bModeSynth = 0;
u32 aModeRefSel = 0;
u32 reg32 = 0;
u16 freq;
struct chan_centers centers;
ath9k_hw_get_channel_centers(ah, chan, &centers);
freq = centers.synth_center;
if (freq < 4800) {
u32 txctl;
if (((freq - 2192) % 5) == 0) {
channelSel = ((freq - 672) * 2 - 3040) / 10;
bModeSynth = 0;
} else if (((freq - 2224) % 5) == 0) {
channelSel = ((freq - 704) * 2 - 3040) / 10;
bModeSynth = 1;
} else {
DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
"%s: invalid channel %u MHz\n", __func__,
freq);
return false;
}
channelSel = (channelSel << 2) & 0xff;
channelSel = ath9k_hw_reverse_bits(channelSel, 8);
txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL);
if (freq == 2484) {
REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
} else {
REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN);
}
} else if ((freq % 20) == 0 && freq >= 5120) {
channelSel =
ath9k_hw_reverse_bits(((freq - 4800) / 20 << 2), 8);
aModeRefSel = ath9k_hw_reverse_bits(1, 2);
} else if ((freq % 10) == 0) {
channelSel =
ath9k_hw_reverse_bits(((freq - 4800) / 10 << 1), 8);
if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah))
aModeRefSel = ath9k_hw_reverse_bits(2, 2);
else
aModeRefSel = ath9k_hw_reverse_bits(1, 2);
} else if ((freq % 5) == 0) {
channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8);
aModeRefSel = ath9k_hw_reverse_bits(1, 2);
} else {
DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
"%s: invalid channel %u MHz\n", __func__, freq);
return false;
}
reg32 =
(channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) |
(1 << 5) | 0x1;
REG_WRITE(ah, AR_PHY(0x37), reg32);
ah->ah_curchan = chan;
AH5416(ah)->ah_curchanRadIndex = -1;
return true;
}
bool
ath9k_hw_ar9280_set_channel(struct ath_hal *ah,
struct ath9k_channel *chan)
{
u16 bMode, fracMode, aModeRefSel = 0;
u32 freq, ndiv, channelSel = 0, channelFrac = 0, reg32 = 0;
struct chan_centers centers;
u32 refDivA = 24;
ath9k_hw_get_channel_centers(ah, chan, &centers);
freq = centers.synth_center;
reg32 = REG_READ(ah, AR_PHY_SYNTH_CONTROL);
reg32 &= 0xc0000000;
if (freq < 4800) {
u32 txctl;
bMode = 1;
fracMode = 1;
aModeRefSel = 0;
channelSel = (freq * 0x10000) / 15;
txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL);
if (freq == 2484) {
REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
} else {
REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN);
}
} else {
bMode = 0;
fracMode = 0;
if ((freq % 20) == 0) {
aModeRefSel = 3;
} else if ((freq % 10) == 0) {
aModeRefSel = 2;
} else {
aModeRefSel = 0;
fracMode = 1;
refDivA = 1;
channelSel = (freq * 0x8000) / 15;
REG_RMW_FIELD(ah, AR_AN_SYNTH9,
AR_AN_SYNTH9_REFDIVA, refDivA);
}
if (!fracMode) {
ndiv = (freq * (refDivA >> aModeRefSel)) / 60;
channelSel = ndiv & 0x1ff;
channelFrac = (ndiv & 0xfffffe00) * 2;
channelSel = (channelSel << 17) | channelFrac;
}
}
reg32 = reg32 |
(bMode << 29) |
(fracMode << 28) | (aModeRefSel << 26) | (channelSel);
REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32);
ah->ah_curchan = chan;
AH5416(ah)->ah_curchanRadIndex = -1;
return true;
}
static void
ath9k_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32,
u32 numBits, u32 firstBit,
u32 column)
{
u32 tmp32, mask, arrayEntry, lastBit;
int32_t bitPosition, bitsLeft;
tmp32 = ath9k_hw_reverse_bits(reg32, numBits);
arrayEntry = (firstBit - 1) / 8;
bitPosition = (firstBit - 1) % 8;
bitsLeft = numBits;
while (bitsLeft > 0) {
lastBit = (bitPosition + bitsLeft > 8) ?
8 : bitPosition + bitsLeft;
mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) <<
(column * 8);
rfBuf[arrayEntry] &= ~mask;
rfBuf[arrayEntry] |= ((tmp32 << bitPosition) <<
(column * 8)) & mask;
bitsLeft -= 8 - bitPosition;
tmp32 = tmp32 >> (8 - bitPosition);
bitPosition = 0;
arrayEntry++;
}
}
bool
ath9k_hw_set_rf_regs(struct ath_hal *ah, struct ath9k_channel *chan,
u16 modesIndex)
{
struct ath_hal_5416 *ahp = AH5416(ah);
u32 eepMinorRev;
u32 ob5GHz = 0, db5GHz = 0;
u32 ob2GHz = 0, db2GHz = 0;
int regWrites = 0;
if (AR_SREV_9280_10_OR_LATER(ah))
return true;
eepMinorRev = ath9k_hw_get_eeprom(ahp, EEP_MINOR_REV);
RF_BANK_SETUP(ahp->ah_analogBank0Data, &ahp->ah_iniBank0, 1);
RF_BANK_SETUP(ahp->ah_analogBank1Data, &ahp->ah_iniBank1, 1);
RF_BANK_SETUP(ahp->ah_analogBank2Data, &ahp->ah_iniBank2, 1);
RF_BANK_SETUP(ahp->ah_analogBank3Data, &ahp->ah_iniBank3,
modesIndex);
{
int i;
for (i = 0; i < ahp->ah_iniBank6TPC.ia_rows; i++) {
ahp->ah_analogBank6Data[i] =
INI_RA(&ahp->ah_iniBank6TPC, i, modesIndex);
}
}
if (eepMinorRev >= 2) {
if (IS_CHAN_2GHZ(chan)) {
ob2GHz = ath9k_hw_get_eeprom(ahp, EEP_OB_2);
db2GHz = ath9k_hw_get_eeprom(ahp, EEP_DB_2);
ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
ob2GHz, 3, 197, 0);
ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
db2GHz, 3, 194, 0);
} else {
ob5GHz = ath9k_hw_get_eeprom(ahp, EEP_OB_5);
db5GHz = ath9k_hw_get_eeprom(ahp, EEP_DB_5);
ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
ob5GHz, 3, 203, 0);
ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
db5GHz, 3, 200, 0);
}
}
RF_BANK_SETUP(ahp->ah_analogBank7Data, &ahp->ah_iniBank7, 1);
REG_WRITE_RF_ARRAY(&ahp->ah_iniBank0, ahp->ah_analogBank0Data,
regWrites);
REG_WRITE_RF_ARRAY(&ahp->ah_iniBank1, ahp->ah_analogBank1Data,
regWrites);
REG_WRITE_RF_ARRAY(&ahp->ah_iniBank2, ahp->ah_analogBank2Data,
regWrites);
REG_WRITE_RF_ARRAY(&ahp->ah_iniBank3, ahp->ah_analogBank3Data,
regWrites);
REG_WRITE_RF_ARRAY(&ahp->ah_iniBank6TPC, ahp->ah_analogBank6Data,
regWrites);
REG_WRITE_RF_ARRAY(&ahp->ah_iniBank7, ahp->ah_analogBank7Data,
regWrites);
return true;
}
void
ath9k_hw_rfdetach(struct ath_hal *ah)
{
struct ath_hal_5416 *ahp = AH5416(ah);
if (ahp->ah_analogBank0Data != NULL) {
kfree(ahp->ah_analogBank0Data);
ahp->ah_analogBank0Data = NULL;
}
if (ahp->ah_analogBank1Data != NULL) {
kfree(ahp->ah_analogBank1Data);
ahp->ah_analogBank1Data = NULL;
}
if (ahp->ah_analogBank2Data != NULL) {
kfree(ahp->ah_analogBank2Data);
ahp->ah_analogBank2Data = NULL;
}
if (ahp->ah_analogBank3Data != NULL) {
kfree(ahp->ah_analogBank3Data);
ahp->ah_analogBank3Data = NULL;
}
if (ahp->ah_analogBank6Data != NULL) {
kfree(ahp->ah_analogBank6Data);
ahp->ah_analogBank6Data = NULL;
}
if (ahp->ah_analogBank6TPCData != NULL) {
kfree(ahp->ah_analogBank6TPCData);
ahp->ah_analogBank6TPCData = NULL;
}
if (ahp->ah_analogBank7Data != NULL) {
kfree(ahp->ah_analogBank7Data);
ahp->ah_analogBank7Data = NULL;
}
if (ahp->ah_addac5416_21 != NULL) {
kfree(ahp->ah_addac5416_21);
ahp->ah_addac5416_21 = NULL;
}
if (ahp->ah_bank6Temp != NULL) {
kfree(ahp->ah_bank6Temp);
ahp->ah_bank6Temp = NULL;
}
}
bool ath9k_hw_init_rf(struct ath_hal *ah, int *status)
{
struct ath_hal_5416 *ahp = AH5416(ah);
if (!AR_SREV_9280_10_OR_LATER(ah)) {
ahp->ah_analogBank0Data =
kzalloc((sizeof(u32) *
ahp->ah_iniBank0.ia_rows), GFP_KERNEL);
ahp->ah_analogBank1Data =
kzalloc((sizeof(u32) *
ahp->ah_iniBank1.ia_rows), GFP_KERNEL);
ahp->ah_analogBank2Data =
kzalloc((sizeof(u32) *
ahp->ah_iniBank2.ia_rows), GFP_KERNEL);
ahp->ah_analogBank3Data =
kzalloc((sizeof(u32) *
ahp->ah_iniBank3.ia_rows), GFP_KERNEL);
ahp->ah_analogBank6Data =
kzalloc((sizeof(u32) *
ahp->ah_iniBank6.ia_rows), GFP_KERNEL);
ahp->ah_analogBank6TPCData =
kzalloc((sizeof(u32) *
ahp->ah_iniBank6TPC.ia_rows), GFP_KERNEL);
ahp->ah_analogBank7Data =
kzalloc((sizeof(u32) *
ahp->ah_iniBank7.ia_rows), GFP_KERNEL);
if (ahp->ah_analogBank0Data == NULL
|| ahp->ah_analogBank1Data == NULL
|| ahp->ah_analogBank2Data == NULL
|| ahp->ah_analogBank3Data == NULL
|| ahp->ah_analogBank6Data == NULL
|| ahp->ah_analogBank6TPCData == NULL
|| ahp->ah_analogBank7Data == NULL) {
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
"%s: cannot allocate RF banks\n",
__func__);
*status = -ENOMEM;
return false;
}
ahp->ah_addac5416_21 =
kzalloc((sizeof(u32) *
ahp->ah_iniAddac.ia_rows *
ahp->ah_iniAddac.ia_columns), GFP_KERNEL);
if (ahp->ah_addac5416_21 == NULL) {
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
"%s: cannot allocate ah_addac5416_21\n",
__func__);
*status = -ENOMEM;
return false;
}
ahp->ah_bank6Temp =
kzalloc((sizeof(u32) *
ahp->ah_iniBank6.ia_rows), GFP_KERNEL);
if (ahp->ah_bank6Temp == NULL) {
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
"%s: cannot allocate ah_bank6Temp\n",
__func__);
*status = -ENOMEM;
return false;
}
}
return true;
}
void
ath9k_hw_decrease_chain_power(struct ath_hal *ah, struct ath9k_channel *chan)
{
int i, regWrites = 0;
struct ath_hal_5416 *ahp = AH5416(ah);
u32 bank6SelMask;
u32 *bank6Temp = ahp->ah_bank6Temp;
switch (ahp->ah_diversityControl) {
case ATH9K_ANT_FIXED_A:
bank6SelMask =
(ahp->
ah_antennaSwitchSwap & ANTSWAP_AB) ? REDUCE_CHAIN_0 :
REDUCE_CHAIN_1;
break;
case ATH9K_ANT_FIXED_B:
bank6SelMask =
(ahp->
ah_antennaSwitchSwap & ANTSWAP_AB) ? REDUCE_CHAIN_1 :
REDUCE_CHAIN_0;
break;
case ATH9K_ANT_VARIABLE:
return;
break;
default:
return;
break;
}
for (i = 0; i < ahp->ah_iniBank6.ia_rows; i++)
bank6Temp[i] = ahp->ah_analogBank6Data[i];
REG_WRITE(ah, AR_PHY_BASE + 0xD8, bank6SelMask);
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 189, 0);
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 190, 0);
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 191, 0);
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 192, 0);
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 193, 0);
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 222, 0);
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 245, 0);
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 246, 0);
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 247, 0);
REG_WRITE_RF_ARRAY(&ahp->ah_iniBank6, bank6Temp, regWrites);
REG_WRITE(ah, AR_PHY_BASE + 0xD8, 0x00000053);
#ifdef ALTER_SWITCH
REG_WRITE(ah, PHY_SWITCH_CHAIN_0,
(REG_READ(ah, PHY_SWITCH_CHAIN_0) & ~0x38)
| ((REG_READ(ah, PHY_SWITCH_CHAIN_0) >> 3) & 0x38));
#endif
}
This diff is collapsed.
This diff is collapsed.
/*
* Copyright (c) 2004 Sam Leffler, Errno Consulting
* Copyright (c) 2004 Video54 Technologies, Inc.
* Copyright (c) 2008 Atheros Communications Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef RC_H
#define RC_H
#include "ath9k.h"
/*
* Interface definitions for transmit rate control modules for the
* Atheros driver.
*
* A rate control module is responsible for choosing the transmit rate
* for each data frame. Management+control frames are always sent at
* a fixed rate.
*
* Only one module may be present at a time; the driver references
* rate control interfaces by symbol name. If multiple modules are
* to be supported we'll need to switch to a registration-based scheme
* as is currently done, for example, for authentication modules.
*
* An instance of the rate control module is attached to each device
* at attach time and detached when the device is destroyed. The module
* may associate data with each device and each node (station). Both
* sets of storage are opaque except for the size of the per-node storage
* which must be provided when the module is attached.
*
* The rate control module is notified for each state transition and
* station association/reassociation. Otherwise it is queried for a
* rate for each outgoing frame and provided status from each transmitted
* frame. Any ancillary processing is the responsibility of the module
* (e.g. if periodic processing is required then the module should setup
* it's own timer).
*
* In addition to the transmit rate for each frame the module must also
* indicate the number of attempts to make at the specified rate. If this
* number is != ATH_TXMAXTRY then an additional callback is made to setup
* additional transmit state. The rate control code is assumed to write
* this additional data directly to the transmit descriptor.
*/
struct ath_softc;
#define TRUE 1
#define FALSE 0
#define ATH_RATE_MAX 30
#define MCS_SET_SIZE 128
enum ieee80211_fixed_rate_mode {
IEEE80211_FIXED_RATE_NONE = 0,
IEEE80211_FIXED_RATE_MCS = 1 /* HT rates */
};
/*
* Use the hal os glue code to get ms time
*/
#define IEEE80211_RATE_IDX_ENTRY(val, idx) (((val&(0xff<<(idx*8)))>>(idx*8)))
#define SHORT_PRE 1
#define LONG_PRE 0
#define WLAN_PHY_HT_20_SS WLAN_RC_PHY_HT_20_SS
#define WLAN_PHY_HT_20_DS WLAN_RC_PHY_HT_20_DS
#define WLAN_PHY_HT_20_DS_HGI WLAN_RC_PHY_HT_20_DS_HGI
#define WLAN_PHY_HT_40_SS WLAN_RC_PHY_HT_40_SS
#define WLAN_PHY_HT_40_SS_HGI WLAN_RC_PHY_HT_40_SS_HGI
#define WLAN_PHY_HT_40_DS WLAN_RC_PHY_HT_40_DS
#define WLAN_PHY_HT_40_DS_HGI WLAN_RC_PHY_HT_40_DS_HGI
#define WLAN_PHY_OFDM PHY_OFDM
#define WLAN_PHY_CCK PHY_CCK
#define TRUE_20 0x2
#define TRUE_40 0x4
#define TRUE_2040 (TRUE_20|TRUE_40)
#define TRUE_ALL (TRUE_2040|TRUE)
enum {
WLAN_RC_PHY_HT_20_SS = 4,
WLAN_RC_PHY_HT_20_DS,
WLAN_RC_PHY_HT_40_SS,
WLAN_RC_PHY_HT_40_DS,
WLAN_RC_PHY_HT_20_SS_HGI,
WLAN_RC_PHY_HT_20_DS_HGI,
WLAN_RC_PHY_HT_40_SS_HGI,
WLAN_RC_PHY_HT_40_DS_HGI,
WLAN_RC_PHY_MAX
};
#define WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \
|| (_phy == WLAN_RC_PHY_HT_40_DS) \
|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \
|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
#define WLAN_RC_PHY_40(_phy) ((_phy == WLAN_RC_PHY_HT_40_SS) \
|| (_phy == WLAN_RC_PHY_HT_40_DS) \
|| (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \
|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
#define WLAN_RC_PHY_SGI(_phy) ((_phy == WLAN_RC_PHY_HT_20_SS_HGI) \
|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \
|| (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \
|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
#define WLAN_RC_PHY_HT(_phy) (_phy >= WLAN_RC_PHY_HT_20_SS)
/* Returns the capflag mode */
#define WLAN_RC_CAP_MODE(capflag) (((capflag & WLAN_RC_HT_FLAG) ? \
(capflag & WLAN_RC_40_FLAG) ? TRUE_40 : TRUE_20 : TRUE))
/* Return TRUE if flag supports HT20 && client supports HT20 or
* return TRUE if flag supports HT40 && client supports HT40.
* This is used becos some rates overlap between HT20/HT40.
*/
#define WLAN_RC_PHY_HT_VALID(flag, capflag) (((flag & TRUE_20) && !(capflag \
& WLAN_RC_40_FLAG)) || ((flag & TRUE_40) && \
(capflag & WLAN_RC_40_FLAG)))
#define WLAN_RC_DS_FLAG (0x01)
#define WLAN_RC_40_FLAG (0x02)
#define WLAN_RC_SGI_FLAG (0x04)
#define WLAN_RC_HT_FLAG (0x08)
/* Index into the rate table */
#define INIT_RATE_MAX_20 23
#define INIT_RATE_MAX_40 40
#define RATE_TABLE_SIZE 64
/* XXX: Convert to kdoc */
struct ath_rate_table {
int rate_cnt;
struct {
int valid; /* Valid for use in rate control */
int valid_single_stream;/* Valid for use in rate control
for single stream operation */
u8 phy; /* CCK/OFDM/TURBO/XR */
u32 ratekbps; /* Rate in Kbits per second */
u32 user_ratekbps; /* User rate in KBits per second */
u8 ratecode; /* rate that goes into
hw descriptors */
u8 short_preamble; /* Mask for enabling short preamble
in rate code for CCK */
u8 dot11rate; /* Value that goes into supported
rates info element of MLME */
u8 ctrl_rate; /* Index of next lower basic rate,
used for duration computation */
int8_t rssi_ack_validmin; /* Rate control related */
int8_t rssi_ack_deltamin; /* Rate control related */
u8 base_index; /* base rate index */
u8 cw40index; /* 40cap rate index */
u8 sgi_index; /* shortgi rate index */
u8 ht_index; /* shortgi rate index */
u32 max_4ms_framelen; /* Maximum frame length(bytes)
for 4ms tx duration */
} info[RATE_TABLE_SIZE];
u32 probe_interval; /* interval for ratectrl to
probe for other rates */
u32 rssi_reduce_interval; /* interval for ratectrl
to reduce RSSI */
u8 initial_ratemax; /* the initial ratemax value used
in ath_rc_sib_update() */
};
#define ATH_RC_PROBE_ALLOWED 0x00000001
#define ATH_RC_MINRATE_LASTRATE 0x00000002
#define ATH_RC_SHORT_PREAMBLE 0x00000004
struct ath_rc_series {
u8 rix;
u8 tries;
u8 flags;
u32 max_4ms_framelen;
};
/* rcs_flags definition */
#define ATH_RC_DS_FLAG 0x01
#define ATH_RC_CW40_FLAG 0x02 /* CW 40 */
#define ATH_RC_SGI_FLAG 0x04 /* Short Guard Interval */
#define ATH_RC_HT_FLAG 0x08 /* HT */
#define ATH_RC_RTSCTS_FLAG 0x10 /* RTS-CTS */
/*
* State structures for new rate adaptation code
*/
#define MAX_TX_RATE_TBL 64
#define MAX_TX_RATE_PHY 48
struct ath_tx_ratectrl_state {
int8_t rssi_thres; /* required rssi for this rate (dB) */
u8 per; /* recent estimate of packet error rate (%) */
};
struct ath_tx_ratectrl {
struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL]; /* state */
int8_t rssi_last; /* last ack rssi */
int8_t rssi_last_lookup; /* last ack rssi used for lookup */
int8_t rssi_last_prev; /* previous last ack rssi */
int8_t rssi_last_prev2; /* 2nd previous last ack rssi */
int32_t rssi_sum_cnt; /* count of rssi_sum for averaging */
int32_t rssi_sum_rate; /* rate that we are averaging */
int32_t rssi_sum; /* running sum of rssi for averaging */
u32 valid_txrate_mask; /* mask of valid rates */
u8 rate_table_size; /* rate table size */
u8 rate_max; /* max rate that has recently worked */
u8 probe_rate; /* rate we are probing at */
u32 rssi_time; /* msec timestamp for last ack rssi */
u32 rssi_down_time; /* msec timestamp for last down step */
u32 probe_time; /* msec timestamp for last probe */
u8 hw_maxretry_pktcnt; /* num packets since we got
HW max retry error */
u8 max_valid_rate; /* maximum number of valid rate */
u8 valid_rate_index[MAX_TX_RATE_TBL]; /* valid rate index */
u32 per_down_time; /* msec timstamp for last
PER down step */
/* 11n state */
u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; /* valid rate count */
u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][MAX_TX_RATE_TBL];
u8 rc_phy_mode;
u8 rate_max_phy; /* Phy index for the max rate */
u32 rate_max_lastused; /* msec timstamp of when we
last used rateMaxPhy */
u32 probe_interval; /* interval for ratectrl to probe
for other rates */
};
struct ath_rateset {
u8 rs_nrates;
u8 rs_rates[ATH_RATE_MAX];
};
/* per-device state */
struct ath_rate_softc {
/* phy tables that contain rate control data */
const void *hw_rate_table[WIRELESS_MODE_MAX];
int fixedrix; /* -1 or index of fixed rate */
};
/* per-node state */
struct ath_rate_node {
struct ath_tx_ratectrl tx_ratectrl; /* rate control state proper */
u32 prev_data_rix; /* rate idx of last data frame */
/* map of rate ix -> negotiated rate set ix */
u8 rixmap[MAX_TX_RATE_TBL];
/* map of ht rate ix -> negotiated rate set ix */
u8 ht_rixmap[MAX_TX_RATE_TBL];
u8 ht_cap; /* ht capabilities */
u8 ant_tx; /* current transmit antenna */
u8 single_stream; /* When TRUE, only single
stream Tx possible */
struct ath_rateset neg_rates; /* Negotiated rates */
struct ath_rateset neg_ht_rates; /* Negotiated HT rates */
struct ath_rate_softc *asc; /* back pointer to atheros softc */
struct ath_vap *avp; /* back pointer to vap */
};
/* Driver data of ieee80211_tx_info */
struct ath_tx_info_priv {
struct ath_rc_series rcs[4];
struct ath_tx_status tx;
int n_frames;
int n_bad_frames;
u8 min_rate;
};
/*
* Attach/detach a rate control module.
*/
struct ath_rate_softc *ath_rate_attach(struct ath_hal *ah);
void ath_rate_detach(struct ath_rate_softc *asc);
/*
* Update/reset rate control state for 802.11 state transitions.
* Important mostly as the analog to ath_rate_newassoc when operating
* in station mode.
*/
void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv);
void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp);
/*
* Return the tx rate series.
*/
void ath_rate_findrate(struct ath_softc *sc, struct ath_rate_node *ath_rc_priv,
int num_tries, int num_rates,
unsigned int rcflag, struct ath_rc_series[],
int *is_probe, int isretry);
/*
* Return rate index for given Dot11 Rate.
*/
u8 ath_rate_findrateix(struct ath_softc *sc,
u8 dot11_rate);
/* Routines to register/unregister rate control algorithm */
int ath_rate_control_register(void);
void ath_rate_control_unregister(void);
#endif /* RC_H */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment