Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
commit
ac178ef0ae
@ -165,9 +165,6 @@
|
||||
#define AR5K_INI_VAL_XR 0
|
||||
#define AR5K_INI_VAL_MAX 5
|
||||
|
||||
#define AR5K_RF5111_INI_RF_MAX_BANKS AR5K_MAX_RF_BANKS
|
||||
#define AR5K_RF5112_INI_RF_MAX_BANKS AR5K_MAX_RF_BANKS
|
||||
|
||||
/* Used for BSSID etc manipulation */
|
||||
#define AR5K_LOW_ID(_a)( \
|
||||
(_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24 \
|
||||
@ -225,6 +222,7 @@
|
||||
#endif
|
||||
|
||||
/* Initial values */
|
||||
#define AR5K_INIT_CYCRSSI_THR1 2
|
||||
#define AR5K_INIT_TX_LATENCY 502
|
||||
#define AR5K_INIT_USEC 39
|
||||
#define AR5K_INIT_USEC_TURBO 79
|
||||
@ -316,7 +314,7 @@ struct ath5k_srev_name {
|
||||
#define AR5K_SREV_AR5424 0x90 /* Condor */
|
||||
#define AR5K_SREV_AR5413 0xa4 /* Eagle lite */
|
||||
#define AR5K_SREV_AR5414 0xa0 /* Eagle */
|
||||
#define AR5K_SREV_AR2415 0xb0 /* Cobra */
|
||||
#define AR5K_SREV_AR2415 0xb0 /* Talon */
|
||||
#define AR5K_SREV_AR5416 0xc0 /* PCI-E */
|
||||
#define AR5K_SREV_AR5418 0xca /* PCI-E */
|
||||
#define AR5K_SREV_AR2425 0xe0 /* Swan */
|
||||
@ -334,7 +332,7 @@ struct ath5k_srev_name {
|
||||
#define AR5K_SREV_RAD_2112B 0x46
|
||||
#define AR5K_SREV_RAD_2413 0x50
|
||||
#define AR5K_SREV_RAD_5413 0x60
|
||||
#define AR5K_SREV_RAD_2316 0x70
|
||||
#define AR5K_SREV_RAD_2316 0x70 /* Cobra SoC */
|
||||
#define AR5K_SREV_RAD_2317 0x80
|
||||
#define AR5K_SREV_RAD_5424 0xa0 /* Mostly same as 5413 */
|
||||
#define AR5K_SREV_RAD_2425 0xa2
|
||||
@ -342,7 +340,8 @@ struct ath5k_srev_name {
|
||||
|
||||
#define AR5K_SREV_PHY_5211 0x30
|
||||
#define AR5K_SREV_PHY_5212 0x41
|
||||
#define AR5K_SREV_PHY_2112B 0x43
|
||||
#define AR5K_SREV_PHY_5212A 0x42
|
||||
#define AR5K_SREV_PHY_5212B 0x43
|
||||
#define AR5K_SREV_PHY_2413 0x45
|
||||
#define AR5K_SREV_PHY_5413 0x61
|
||||
#define AR5K_SREV_PHY_2425 0x70
|
||||
@ -649,49 +648,21 @@ struct ath5k_beacon_state {
|
||||
|
||||
enum ath5k_rfgain {
|
||||
AR5K_RFGAIN_INACTIVE = 0,
|
||||
AR5K_RFGAIN_ACTIVE,
|
||||
AR5K_RFGAIN_READ_REQUESTED,
|
||||
AR5K_RFGAIN_NEED_CHANGE,
|
||||
};
|
||||
|
||||
#define AR5K_GAIN_CRN_FIX_BITS_5111 4
|
||||
#define AR5K_GAIN_CRN_FIX_BITS_5112 7
|
||||
#define AR5K_GAIN_CRN_MAX_FIX_BITS AR5K_GAIN_CRN_FIX_BITS_5112
|
||||
#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN 15
|
||||
#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN 20
|
||||
#define AR5K_GAIN_CCK_PROBE_CORR 5
|
||||
#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA 15
|
||||
#define AR5K_GAIN_STEP_COUNT 10
|
||||
#define AR5K_GAIN_PARAM_TX_CLIP 0
|
||||
#define AR5K_GAIN_PARAM_PD_90 1
|
||||
#define AR5K_GAIN_PARAM_PD_84 2
|
||||
#define AR5K_GAIN_PARAM_GAIN_SEL 3
|
||||
#define AR5K_GAIN_PARAM_MIX_ORN 0
|
||||
#define AR5K_GAIN_PARAM_PD_138 1
|
||||
#define AR5K_GAIN_PARAM_PD_137 2
|
||||
#define AR5K_GAIN_PARAM_PD_136 3
|
||||
#define AR5K_GAIN_PARAM_PD_132 4
|
||||
#define AR5K_GAIN_PARAM_PD_131 5
|
||||
#define AR5K_GAIN_PARAM_PD_130 6
|
||||
#define AR5K_GAIN_CHECK_ADJUST(_g) \
|
||||
((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
|
||||
|
||||
struct ath5k_gain_opt_step {
|
||||
s16 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
|
||||
s32 gos_gain;
|
||||
};
|
||||
|
||||
struct ath5k_gain {
|
||||
u32 g_step_idx;
|
||||
u32 g_current;
|
||||
u32 g_target;
|
||||
u32 g_low;
|
||||
u32 g_high;
|
||||
u32 g_f_corr;
|
||||
u32 g_active;
|
||||
const struct ath5k_gain_opt_step *g_step;
|
||||
u8 g_step_idx;
|
||||
u8 g_current;
|
||||
u8 g_target;
|
||||
u8 g_low;
|
||||
u8 g_high;
|
||||
u8 g_f_corr;
|
||||
u8 g_state;
|
||||
};
|
||||
|
||||
|
||||
/********************\
|
||||
COMMON DEFINITIONS
|
||||
\********************/
|
||||
@ -1053,7 +1024,6 @@ struct ath5k_hw {
|
||||
bool ah_running;
|
||||
bool ah_single_chip;
|
||||
bool ah_combined_mic;
|
||||
enum ath5k_rfgain ah_rf_gain;
|
||||
|
||||
u32 ah_mac_srev;
|
||||
u16 ah_mac_version;
|
||||
@ -1061,7 +1031,6 @@ struct ath5k_hw {
|
||||
u16 ah_phy_revision;
|
||||
u16 ah_radio_5ghz_revision;
|
||||
u16 ah_radio_2ghz_revision;
|
||||
u32 ah_phy_spending;
|
||||
|
||||
enum ath5k_version ah_version;
|
||||
enum ath5k_radio ah_radio;
|
||||
@ -1112,8 +1081,9 @@ struct ath5k_hw {
|
||||
u32 ah_txq_isr;
|
||||
u32 *ah_rf_banks;
|
||||
size_t ah_rf_banks_size;
|
||||
size_t ah_rf_regs_count;
|
||||
struct ath5k_gain ah_gain;
|
||||
u32 ah_offset[AR5K_MAX_RF_BANKS];
|
||||
u8 ah_offset[AR5K_MAX_RF_BANKS];
|
||||
|
||||
struct {
|
||||
u16 txp_pcdac[AR5K_EEPROM_POWER_TABLE_SIZE];
|
||||
@ -1186,6 +1156,7 @@ extern void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, struct ieee80211_l
|
||||
/* EEPROM access functions */
|
||||
extern int ath5k_eeprom_init(struct ath5k_hw *ah);
|
||||
extern int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac);
|
||||
extern bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah);
|
||||
|
||||
/* Protocol Control Unit Functions */
|
||||
extern int ath5k_hw_set_opmode(struct ath5k_hw *ah);
|
||||
@ -1261,10 +1232,12 @@ extern int ath5k_hw_disable_pspoll(struct ath5k_hw *ah);
|
||||
extern int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel);
|
||||
|
||||
/* Initialize RF */
|
||||
extern int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int mode);
|
||||
extern int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq);
|
||||
extern enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah);
|
||||
extern int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah);
|
||||
extern int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
|
||||
struct ieee80211_channel *channel,
|
||||
unsigned int mode);
|
||||
extern int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq);
|
||||
extern enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah);
|
||||
extern int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah);
|
||||
/* PHY/RF channel functions */
|
||||
extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
|
||||
extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel);
|
||||
@ -1286,6 +1259,7 @@ extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, unsigned int power);
|
||||
|
||||
/*
|
||||
* Translate usec to hw clock units
|
||||
* TODO: Half/quarter rate
|
||||
*/
|
||||
static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo)
|
||||
{
|
||||
@ -1294,6 +1268,7 @@ static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo)
|
||||
|
||||
/*
|
||||
* Translate hw clock units to usec
|
||||
* TODO: Half/quarter rate
|
||||
*/
|
||||
static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo)
|
||||
{
|
||||
|
@ -169,7 +169,6 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
|
||||
ah->ah_single_chip = false;
|
||||
ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
|
||||
CHANNEL_2GHZ);
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5111;
|
||||
break;
|
||||
case AR5K_SREV_RAD_5112:
|
||||
case AR5K_SREV_RAD_2112:
|
||||
@ -177,38 +176,31 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
|
||||
ah->ah_single_chip = false;
|
||||
ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
|
||||
CHANNEL_2GHZ);
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112;
|
||||
break;
|
||||
case AR5K_SREV_RAD_2413:
|
||||
ah->ah_radio = AR5K_RF2413;
|
||||
ah->ah_single_chip = true;
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413;
|
||||
break;
|
||||
case AR5K_SREV_RAD_5413:
|
||||
ah->ah_radio = AR5K_RF5413;
|
||||
ah->ah_single_chip = true;
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413;
|
||||
break;
|
||||
case AR5K_SREV_RAD_2316:
|
||||
ah->ah_radio = AR5K_RF2316;
|
||||
ah->ah_single_chip = true;
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2316;
|
||||
break;
|
||||
case AR5K_SREV_RAD_2317:
|
||||
ah->ah_radio = AR5K_RF2317;
|
||||
ah->ah_single_chip = true;
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2317;
|
||||
break;
|
||||
case AR5K_SREV_RAD_5424:
|
||||
if (ah->ah_mac_version == AR5K_SREV_AR2425 ||
|
||||
ah->ah_mac_version == AR5K_SREV_AR2417){
|
||||
ah->ah_radio = AR5K_RF2425;
|
||||
ah->ah_single_chip = true;
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425;
|
||||
} else {
|
||||
ah->ah_radio = AR5K_RF5413;
|
||||
ah->ah_single_chip = true;
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -227,29 +219,25 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
|
||||
ah->ah_radio = AR5K_RF2425;
|
||||
ah->ah_single_chip = true;
|
||||
ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2425;
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425;
|
||||
} else if (srev == AR5K_SREV_AR5213A &&
|
||||
ah->ah_phy_revision == AR5K_SREV_PHY_2112B) {
|
||||
ah->ah_phy_revision == AR5K_SREV_PHY_5212B) {
|
||||
ah->ah_radio = AR5K_RF5112;
|
||||
ah->ah_single_chip = false;
|
||||
ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2112B;
|
||||
ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5112B;
|
||||
} else if (ah->ah_mac_version == (AR5K_SREV_AR2415 >> 4)) {
|
||||
ah->ah_radio = AR5K_RF2316;
|
||||
ah->ah_single_chip = true;
|
||||
ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2316;
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2316;
|
||||
} else if (ah->ah_mac_version == (AR5K_SREV_AR5414 >> 4) ||
|
||||
ah->ah_phy_revision == AR5K_SREV_PHY_5413) {
|
||||
ah->ah_radio = AR5K_RF5413;
|
||||
ah->ah_single_chip = true;
|
||||
ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5413;
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413;
|
||||
} else if (ah->ah_mac_version == (AR5K_SREV_AR2414 >> 4) ||
|
||||
ah->ah_phy_revision == AR5K_SREV_PHY_2413) {
|
||||
ah->ah_radio = AR5K_RF2413;
|
||||
ah->ah_single_chip = true;
|
||||
ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2413;
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413;
|
||||
} else {
|
||||
ATH5K_ERR(sc, "Couldn't identify radio revision.\n");
|
||||
ret = -ENODEV;
|
||||
@ -331,7 +319,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
|
||||
ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
|
||||
ath5k_hw_set_opmode(ah);
|
||||
|
||||
ath5k_hw_set_rfgain_opt(ah);
|
||||
ath5k_hw_rfgain_opt_init(ah);
|
||||
|
||||
return ah;
|
||||
err_free:
|
||||
|
@ -2209,10 +2209,6 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf)
|
||||
*
|
||||
* @sc: struct ath5k_softc pointer we are operating on
|
||||
*
|
||||
* When operating in station mode we want to receive a BMISS interrupt when we
|
||||
* stop seeing beacons from the AP we've associated with so we can look for
|
||||
* another AP to associate with.
|
||||
*
|
||||
* In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA
|
||||
* interrupts to detect TSF updates only.
|
||||
*/
|
||||
@ -2225,9 +2221,7 @@ ath5k_beacon_config(struct ath5k_softc *sc)
|
||||
sc->bmisscount = 0;
|
||||
sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA);
|
||||
|
||||
if (sc->opmode == NL80211_IFTYPE_STATION) {
|
||||
sc->imask |= AR5K_INT_BMISS;
|
||||
} else if (sc->opmode == NL80211_IFTYPE_ADHOC ||
|
||||
if (sc->opmode == NL80211_IFTYPE_ADHOC ||
|
||||
sc->opmode == NL80211_IFTYPE_MESH_POINT ||
|
||||
sc->opmode == NL80211_IFTYPE_AP) {
|
||||
/*
|
||||
@ -2479,6 +2473,7 @@ ath5k_intr(int irq, void *dev_id)
|
||||
| AR5K_INT_TXERR | AR5K_INT_TXEOL))
|
||||
tasklet_schedule(&sc->txtq);
|
||||
if (status & AR5K_INT_BMISS) {
|
||||
/* TODO */
|
||||
}
|
||||
if (status & AR5K_INT_MIB) {
|
||||
/*
|
||||
@ -2518,7 +2513,7 @@ ath5k_calibrate(unsigned long data)
|
||||
ieee80211_frequency_to_channel(sc->curchan->center_freq),
|
||||
sc->curchan->hw_value);
|
||||
|
||||
if (ath5k_hw_get_rf_gain(ah) == AR5K_RFGAIN_NEED_CHANGE) {
|
||||
if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) {
|
||||
/*
|
||||
* Rfgain is out of bounds, reset the chip
|
||||
* to load new gain values.
|
||||
@ -2889,7 +2884,7 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
{
|
||||
struct ath5k_softc *sc = hw->priv;
|
||||
struct ath5k_hw *ah = sc->ah;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&sc->lock);
|
||||
if (sc->vif != vif) {
|
||||
@ -2915,9 +2910,7 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
}
|
||||
ath5k_beacon_update(sc, beacon);
|
||||
}
|
||||
mutex_unlock(&sc->lock);
|
||||
|
||||
return ath5k_reset_wake(sc);
|
||||
unlock:
|
||||
mutex_unlock(&sc->lock);
|
||||
return ret;
|
||||
|
@ -204,7 +204,7 @@ static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
|
||||
|
||||
/* Get antenna modes */
|
||||
ah->ah_antenna[mode][0] =
|
||||
(ee->ee_ant_control[mode][0] << 4) | 0x1;
|
||||
(ee->ee_ant_control[mode][0] << 4);
|
||||
ah->ah_antenna[mode][AR5K_ANT_FIXED_A] =
|
||||
ee->ee_ant_control[mode][1] |
|
||||
(ee->ee_ant_control[mode][2] << 6) |
|
||||
@ -517,9 +517,9 @@ ath5k_eeprom_init_modes(struct ath5k_hw *ah)
|
||||
static inline void
|
||||
ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp)
|
||||
{
|
||||
const static u16 intercepts3[] =
|
||||
static const u16 intercepts3[] =
|
||||
{ 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 };
|
||||
const static u16 intercepts3_2[] =
|
||||
static const u16 intercepts3_2[] =
|
||||
{ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
|
||||
const u16 *ip;
|
||||
int i;
|
||||
@ -1412,6 +1412,7 @@ ath5k_eeprom_init(struct ath5k_hw *ah)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the MAC address from eeprom
|
||||
*/
|
||||
@ -1448,3 +1449,14 @@ int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah)
|
||||
{
|
||||
u16 data;
|
||||
|
||||
ath5k_hw_eeprom_read(ah, AR5K_EEPROM_IS_HB63, &data);
|
||||
|
||||
if ((ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4)) && data)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
#define AR5K_EEPROM_MAGIC_5211 0x0000145b /* 5211 */
|
||||
#define AR5K_EEPROM_MAGIC_5210 0x0000145a /* 5210 */
|
||||
|
||||
#define AR5K_EEPROM_IS_HB63 0x000b /* Talon detect */
|
||||
#define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */
|
||||
#define AR5K_EEPROM_CHECKSUM 0x00c0 /* EEPROM checksum */
|
||||
#define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -187,6 +187,7 @@
|
||||
#define AR5K_TXCFG_FRMPAD_DIS 0x00002000 /* [5211+] */
|
||||
#define AR5K_TXCFG_RDY_CBR_DIS 0x00004000 /* Ready time CBR disable [5211+] */
|
||||
#define AR5K_TXCFG_JUMBO_FRM_MODE 0x00008000 /* Jumbo frame mode [5211+] */
|
||||
#define AR5K_TXCFG_DCU_DBL_BUF_DIS 0x00008000 /* Disable double buffering on DCU */
|
||||
#define AR5K_TXCFG_DCU_CACHING_DIS 0x00010000 /* Disable DCU caching */
|
||||
|
||||
/*
|
||||
@ -753,7 +754,7 @@
|
||||
*/
|
||||
#define AR5K_DCU_SEQNUM_BASE 0x1140
|
||||
#define AR5K_DCU_SEQNUM_M 0x00000fff
|
||||
#define AR5K_QUEUE_DFS_SEQNUM(_q) AR5K_QUEUE_REG(AR5K_DCU_SEQNUM_BASE, _q)
|
||||
#define AR5K_QUEUE_DCU_SEQNUM(_q) AR5K_QUEUE_REG(AR5K_DCU_SEQNUM_BASE, _q)
|
||||
|
||||
/*
|
||||
* DCU global IFS SIFS register
|
||||
@ -811,6 +812,8 @@
|
||||
|
||||
/*
|
||||
* DCU transmit filter table 0 (32 entries)
|
||||
* each entry contains a 32bit slice of the
|
||||
* 128bit tx filter for each DCU (4 slices per DCU)
|
||||
*/
|
||||
#define AR5K_DCU_TX_FILTER_0_BASE 0x1038
|
||||
#define AR5K_DCU_TX_FILTER_0(_n) (AR5K_DCU_TX_FILTER_0_BASE + (_n * 64))
|
||||
@ -819,7 +822,7 @@
|
||||
* DCU transmit filter table 1 (16 entries)
|
||||
*/
|
||||
#define AR5K_DCU_TX_FILTER_1_BASE 0x103c
|
||||
#define AR5K_DCU_TX_FILTER_1(_n) (AR5K_DCU_TX_FILTER_1_BASE + ((_n - 32) * 64))
|
||||
#define AR5K_DCU_TX_FILTER_1(_n) (AR5K_DCU_TX_FILTER_1_BASE + (_n * 64))
|
||||
|
||||
/*
|
||||
* DCU clear transmit filter register
|
||||
@ -1447,7 +1450,7 @@
|
||||
AR5K_TSF_U32_5210 : AR5K_TSF_U32_5211)
|
||||
|
||||
/*
|
||||
* Last beacon timestamp register
|
||||
* Last beacon timestamp register (Read Only)
|
||||
*/
|
||||
#define AR5K_LAST_TSTP 0x8080
|
||||
|
||||
@ -1465,7 +1468,7 @@
|
||||
#define AR5K_ADDAC_TEST_TRIG_PTY 0x00020000 /* Trigger polarity */
|
||||
#define AR5K_ADDAC_TEST_RXCONT 0x00040000 /* Continuous capture */
|
||||
#define AR5K_ADDAC_TEST_CAPTURE 0x00080000 /* Begin capture */
|
||||
#define AR5K_ADDAC_TEST_TST_ARM 0x00100000 /* Test ARM (Adaptive Radio Mode ?) */
|
||||
#define AR5K_ADDAC_TEST_TST_ARM 0x00100000 /* ARM rx buffer for capture */
|
||||
|
||||
/*
|
||||
* Default antenna register [5211+]
|
||||
@ -1677,7 +1680,7 @@
|
||||
* TSF parameter register
|
||||
*/
|
||||
#define AR5K_TSF_PARM 0x8104 /* Register Address */
|
||||
#define AR5K_TSF_PARM_INC_M 0x000000ff /* Mask for TSF increment */
|
||||
#define AR5K_TSF_PARM_INC 0x000000ff /* Mask for TSF increment */
|
||||
#define AR5K_TSF_PARM_INC_S 0
|
||||
|
||||
/*
|
||||
@ -1689,7 +1692,7 @@
|
||||
#define AR5K_QOS_NOACK_BIT_OFFSET 0x00000070 /* ??? */
|
||||
#define AR5K_QOS_NOACK_BIT_OFFSET_S 4
|
||||
#define AR5K_QOS_NOACK_BYTE_OFFSET 0x00000180 /* ??? */
|
||||
#define AR5K_QOS_NOACK_BYTE_OFFSET_S 8
|
||||
#define AR5K_QOS_NOACK_BYTE_OFFSET_S 7
|
||||
|
||||
/*
|
||||
* PHY error filter register
|
||||
@ -1848,15 +1851,14 @@
|
||||
* TST_2 (Misc config parameters)
|
||||
*/
|
||||
#define AR5K_PHY_TST2 0x9800 /* Register Address */
|
||||
#define AR5K_PHY_TST2_TRIG_SEL 0x00000001 /* Trigger select (?) (field ?) */
|
||||
#define AR5K_PHY_TST2_TRIG 0x00000010 /* Trigger (?) (field ?) */
|
||||
#define AR5K_PHY_TST2_CBUS_MODE 0x00000100 /* Cardbus mode (?) */
|
||||
/* bit reserved */
|
||||
#define AR5K_PHY_TST2_TRIG_SEL 0x00000007 /* Trigger select (?)*/
|
||||
#define AR5K_PHY_TST2_TRIG 0x00000010 /* Trigger (?) */
|
||||
#define AR5K_PHY_TST2_CBUS_MODE 0x00000060 /* Cardbus mode (?) */
|
||||
#define AR5K_PHY_TST2_CLK32 0x00000400 /* CLK_OUT is CLK32 (32Khz external) */
|
||||
#define AR5K_PHY_TST2_CHANCOR_DUMP_EN 0x00000800 /* Enable Chancor dump (?) */
|
||||
#define AR5K_PHY_TST2_EVEN_CHANCOR_DUMP 0x00001000 /* Even Chancor dump (?) */
|
||||
#define AR5K_PHY_TST2_RFSILENT_EN 0x00002000 /* Enable RFSILENT */
|
||||
#define AR5K_PHY_TST2_ALT_RFDATA 0x00004000 /* Alternate RFDATA (5-2GHz switch) */
|
||||
#define AR5K_PHY_TST2_ALT_RFDATA 0x00004000 /* Alternate RFDATA (5-2GHz switch ?) */
|
||||
#define AR5K_PHY_TST2_MINI_OBS_EN 0x00008000 /* Enable mini OBS (?) */
|
||||
#define AR5K_PHY_TST2_RX2_IS_RX5_INV 0x00010000 /* 2GHz rx path is the 5GHz path inverted (?) */
|
||||
#define AR5K_PHY_TST2_SLOW_CLK160 0x00020000 /* Slow CLK160 (?) */
|
||||
@ -1926,8 +1928,8 @@
|
||||
#define AR5K_PHY_RF_CTL2_TXF2TXD_START_S 0
|
||||
|
||||
#define AR5K_PHY_RF_CTL3 0x9828 /* Register Address */
|
||||
#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON 0x0000000f /* TX end to XLNA on */
|
||||
#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON_S 0
|
||||
#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON 0x0000ff00 /* TX end to XLNA on */
|
||||
#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON_S 8
|
||||
|
||||
#define AR5K_PHY_ADC_CTL 0x982c
|
||||
#define AR5K_PHY_ADC_CTL_INBUFGAIN_OFF 0x00000003
|
||||
@ -1961,7 +1963,7 @@
|
||||
#define AR5K_PHY_SETTLING_AGC 0x0000007f /* AGC settling time */
|
||||
#define AR5K_PHY_SETTLING_AGC_S 0
|
||||
#define AR5K_PHY_SETTLING_SWITCH 0x00003f80 /* Switch settlig time */
|
||||
#define AR5K_PHY_SETTLINK_SWITCH_S 7
|
||||
#define AR5K_PHY_SETTLING_SWITCH_S 7
|
||||
|
||||
/*
|
||||
* PHY Gain registers
|
||||
@ -2067,14 +2069,14 @@
|
||||
* PHY sleep registers [5112+]
|
||||
*/
|
||||
#define AR5K_PHY_SCR 0x9870
|
||||
#define AR5K_PHY_SCR_32MHZ 0x0000001f
|
||||
|
||||
#define AR5K_PHY_SLMT 0x9874
|
||||
#define AR5K_PHY_SLMT_32MHZ 0x0000007f
|
||||
|
||||
#define AR5K_PHY_SCAL 0x9878
|
||||
#define AR5K_PHY_SCAL_32MHZ 0x0000000e
|
||||
|
||||
#define AR5K_PHY_SCAL_32MHZ_2417 0x0000000a
|
||||
#define AR5K_PHY_SCAL_32MHZ_HB63 0x00000032
|
||||
|
||||
/*
|
||||
* PHY PLL (Phase Locked Loop) control register
|
||||
@ -2101,34 +2103,10 @@
|
||||
/*
|
||||
* RF Buffer register
|
||||
*
|
||||
* There are some special control registers on the RF chip
|
||||
* that hold various operation settings related mostly to
|
||||
* the analog parts (channel, gain adjustment etc).
|
||||
*
|
||||
* We don't write on those registers directly but
|
||||
* we send a data packet on the buffer register and
|
||||
* then write on another special register to notify hw
|
||||
* to apply the settings. This is done so that control registers
|
||||
* can be dynamicaly programmed during operation and the settings
|
||||
* are applied faster on the hw.
|
||||
*
|
||||
* We sent such data packets during rf initialization and channel change
|
||||
* through ath5k_hw_rf*_rfregs and ath5k_hw_rf*_channel functions.
|
||||
*
|
||||
* The data packets we send during initializadion are inside ath5k_ini_rf
|
||||
* struct (see ath5k_hw.h) and each one is related to an "rf register bank".
|
||||
* We use *rfregs functions to modify them acording to current operation
|
||||
* mode and eeprom values and pass them all together to the chip.
|
||||
*
|
||||
* It's obvious from the code that 0x989c is the buffer register but
|
||||
* for the other special registers that we write to after sending each
|
||||
* packet, i have no idea. So i'll name them BUFFER_CONTROL_X registers
|
||||
* for now. It's interesting that they are also used for some other operations.
|
||||
*
|
||||
* Also check out hw.h and U.S. Patent 6677779 B1 (about buffer
|
||||
* registers and control registers):
|
||||
*
|
||||
* http://www.google.com/patents?id=qNURAAAAEBAJ
|
||||
*/
|
||||
|
||||
#define AR5K_RF_BUFFER 0x989c
|
||||
@ -2178,7 +2156,8 @@
|
||||
#define AR5K_PHY_ANT_CTL_TXRX_EN 0x00000001 /* Enable TX/RX (?) */
|
||||
#define AR5K_PHY_ANT_CTL_SECTORED_ANT 0x00000004 /* Sectored Antenna */
|
||||
#define AR5K_PHY_ANT_CTL_HITUNE5 0x00000008 /* Hitune5 (?) */
|
||||
#define AR5K_PHY_ANT_CTL_SWTABLE_IDLE 0x00000010 /* Switch table idle (?) */
|
||||
#define AR5K_PHY_ANT_CTL_SWTABLE_IDLE 0x000003f0 /* Switch table idle (?) */
|
||||
#define AR5K_PHY_ANT_CTL_SWTABLE_IDLE_S 4
|
||||
|
||||
/*
|
||||
* PHY receiver delay register [5111+]
|
||||
@ -2218,7 +2197,7 @@
|
||||
#define AR5K_PHY_OFDM_SELFCORR 0x9924 /* Register Address */
|
||||
#define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_EN 0x00000001 /* Enable cyclic RSSI thr 1 */
|
||||
#define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1 0x000000fe /* Mask for Cyclic RSSI threshold 1 */
|
||||
#define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_S 0
|
||||
#define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_S 1
|
||||
#define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR3 0x00000100 /* Cyclic RSSI threshold 3 (field) (?) */
|
||||
#define AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR_EN 0x00008000 /* Enable 1A RSSI threshold (?) */
|
||||
#define AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR 0x00010000 /* 1A RSSI threshold (field) (?) */
|
||||
@ -2243,9 +2222,7 @@
|
||||
#define AR5K_PHY_CTL_LOW_FREQ_SLE_EN 0x00000080 /* Enable low freq sleep */
|
||||
|
||||
/*
|
||||
* PHY PAPD probe register [5111+ (?)]
|
||||
* Is this only present in 5212 ?
|
||||
* Because it's always 0 in 5211 initialization code
|
||||
* PHY PAPD probe register [5111+]
|
||||
*/
|
||||
#define AR5K_PHY_PAPD_PROBE 0x9930
|
||||
#define AR5K_PHY_PAPD_PROBE_SH_HI_PAR 0x00000001
|
||||
@ -2302,6 +2279,15 @@
|
||||
AR5K_PHY_FRAME_CTL_PARITY_ERR | \
|
||||
AR5K_PHY_FRAME_CTL_TIMING_ERR
|
||||
|
||||
/*
|
||||
* PHY Tx Power adjustment register [5212A+]
|
||||
*/
|
||||
#define AR5K_PHY_TX_PWR_ADJ 0x994c
|
||||
#define AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA 0x00000fc0
|
||||
#define AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA_S 6
|
||||
#define AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX 0x00fc0000
|
||||
#define AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX_S 18
|
||||
|
||||
/*
|
||||
* PHY radar detection register [5111+]
|
||||
*/
|
||||
@ -2355,7 +2341,7 @@
|
||||
#define AR5K_PHY_SIGMA_DELTA_FILT2_S 3
|
||||
#define AR5K_PHY_SIGMA_DELTA_FILT1 0x00001f00
|
||||
#define AR5K_PHY_SIGMA_DELTA_FILT1_S 8
|
||||
#define AR5K_PHY_SIGMA_DELTA_ADC_CLIP 0x01ff3000
|
||||
#define AR5K_PHY_SIGMA_DELTA_ADC_CLIP 0x01ffe000
|
||||
#define AR5K_PHY_SIGMA_DELTA_ADC_CLIP_S 13
|
||||
|
||||
/*
|
||||
@ -2387,21 +2373,21 @@
|
||||
#define AR5K_PHY_BIN_MASK2_4_MASK_4 0x00003fff
|
||||
#define AR5K_PHY_BIN_MASK2_4_MASK_4_S 0
|
||||
|
||||
#define AR_PHY_TIMING_9 0x9998
|
||||
#define AR_PHY_TIMING_10 0x999c
|
||||
#define AR_PHY_TIMING_10_PILOT_MASK_2 0x000fffff
|
||||
#define AR_PHY_TIMING_10_PILOT_MASK_2_S 0
|
||||
#define AR5K_PHY_TIMING_9 0x9998
|
||||
#define AR5K_PHY_TIMING_10 0x999c
|
||||
#define AR5K_PHY_TIMING_10_PILOT_MASK_2 0x000fffff
|
||||
#define AR5K_PHY_TIMING_10_PILOT_MASK_2_S 0
|
||||
|
||||
/*
|
||||
* Spur mitigation control
|
||||
*/
|
||||
#define AR_PHY_TIMING_11 0x99a0 /* Register address */
|
||||
#define AR_PHY_TIMING_11_SPUR_DELTA_PHASE 0x000fffff /* Spur delta phase */
|
||||
#define AR_PHY_TIMING_11_SPUR_DELTA_PHASE_S 0
|
||||
#define AR_PHY_TIMING_11_SPUR_FREQ_SD 0x3ff00000 /* Freq sigma delta */
|
||||
#define AR_PHY_TIMING_11_SPUR_FREQ_SD_S 20
|
||||
#define AR_PHY_TIMING_11_USE_SPUR_IN_AGC 0x40000000 /* Spur filter in AGC detector */
|
||||
#define AR_PHY_TIMING_11_USE_SPUR_IN_SELFCOR 0x80000000 /* Spur filter in OFDM self correlator */
|
||||
#define AR5K_PHY_TIMING_11 0x99a0 /* Register address */
|
||||
#define AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE 0x000fffff /* Spur delta phase */
|
||||
#define AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE_S 0
|
||||
#define AR5K_PHY_TIMING_11_SPUR_FREQ_SD 0x3ff00000 /* Freq sigma delta */
|
||||
#define AR5K_PHY_TIMING_11_SPUR_FREQ_SD_S 20
|
||||
#define AR5K_PHY_TIMING_11_USE_SPUR_IN_AGC 0x40000000 /* Spur filter in AGC detector */
|
||||
#define AR5K_PHY_TIMING_11_USE_SPUR_IN_SELFCOR 0x80000000 /* Spur filter in OFDM self correlator */
|
||||
|
||||
/*
|
||||
* Gain tables
|
||||
@ -2483,17 +2469,7 @@
|
||||
#define AR5K_PHY_SDELAY 0x99f4
|
||||
#define AR5K_PHY_SDELAY_32MHZ 0x000000ff
|
||||
#define AR5K_PHY_SPENDING 0x99f8
|
||||
#define AR5K_PHY_SPENDING_14 0x00000014
|
||||
#define AR5K_PHY_SPENDING_18 0x00000018
|
||||
#define AR5K_PHY_SPENDING_RF5111 0x00000018
|
||||
#define AR5K_PHY_SPENDING_RF5112 0x00000014
|
||||
/* #define AR5K_PHY_SPENDING_RF5112A 0x0000000e */
|
||||
/* #define AR5K_PHY_SPENDING_RF5424 0x00000012 */
|
||||
#define AR5K_PHY_SPENDING_RF5413 0x00000018
|
||||
#define AR5K_PHY_SPENDING_RF2413 0x00000018
|
||||
#define AR5K_PHY_SPENDING_RF2316 0x00000018
|
||||
#define AR5K_PHY_SPENDING_RF2317 0x00000018
|
||||
#define AR5K_PHY_SPENDING_RF2425 0x00000014
|
||||
|
||||
|
||||
/*
|
||||
* PHY PAPD I (power?) table (?)
|
||||
@ -2505,11 +2481,7 @@
|
||||
/*
|
||||
* PHY PCDAC TX power table
|
||||
*/
|
||||
#define AR5K_PHY_PCDAC_TXPOWER_BASE_5211 0xa180
|
||||
#define AR5K_PHY_PCDAC_TXPOWER_BASE_2413 0xa280
|
||||
#define AR5K_PHY_PCDAC_TXPOWER_BASE (ah->ah_radio >= AR5K_RF2413 ? \
|
||||
AR5K_PHY_PCDAC_TXPOWER_BASE_2413 :\
|
||||
AR5K_PHY_PCDAC_TXPOWER_BASE_5211)
|
||||
#define AR5K_PHY_PCDAC_TXPOWER_BASE 0xa180
|
||||
#define AR5K_PHY_PCDAC_TXPOWER(_n) (AR5K_PHY_PCDAC_TXPOWER_BASE + ((_n) << 2))
|
||||
|
||||
/*
|
||||
@ -2590,3 +2562,9 @@
|
||||
#define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3_S 16
|
||||
#define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4 0x0FC00000
|
||||
#define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4_S 22
|
||||
|
||||
/*
|
||||
* PHY PDADC Tx power table
|
||||
*/
|
||||
#define AR5K_PHY_PDADC_TXPOWER_BASE 0xa280
|
||||
#define AR5K_PHY_PDADC_TXPOWER(_n) (AR5K_PHY_PDADC_TXPOWER_BASE + ((_n) << 2))
|
||||
|
File diff suppressed because it is too large
Load Diff
1181
drivers/net/wireless/ath5k/rfbuffer.h
Normal file
1181
drivers/net/wireless/ath5k/rfbuffer.h
Normal file
File diff suppressed because it is too large
Load Diff
516
drivers/net/wireless/ath5k/rfgain.h
Normal file
516
drivers/net/wireless/ath5k/rfgain.h
Normal file
@ -0,0 +1,516 @@
|
||||
/*
|
||||
* RF Gain optimization
|
||||
*
|
||||
* Copyright (c) 2004-2009 Reyk Floeter <reyk@openbsd.org>
|
||||
* Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Mode-specific RF Gain table (64bytes) for RF5111/5112
|
||||
* (RF5110 only comes with AR5210 and only supports a/turbo a mode so initial
|
||||
* RF Gain values are included in AR5K_AR5210_INI)
|
||||
*/
|
||||
struct ath5k_ini_rfgain {
|
||||
u16 rfg_register; /* RF Gain register address */
|
||||
u32 rfg_value[2]; /* [freq (see below)] */
|
||||
};
|
||||
|
||||
/* Initial RF Gain settings for RF5111 */
|
||||
static const struct ath5k_ini_rfgain rfgain_5111[] = {
|
||||
/* 5Ghz 2Ghz */
|
||||
{ AR5K_RF_GAIN(0), { 0x000001a9, 0x00000000 } },
|
||||
{ AR5K_RF_GAIN(1), { 0x000001e9, 0x00000040 } },
|
||||
{ AR5K_RF_GAIN(2), { 0x00000029, 0x00000080 } },
|
||||
{ AR5K_RF_GAIN(3), { 0x00000069, 0x00000150 } },
|
||||
{ AR5K_RF_GAIN(4), { 0x00000199, 0x00000190 } },
|
||||
{ AR5K_RF_GAIN(5), { 0x000001d9, 0x000001d0 } },
|
||||
{ AR5K_RF_GAIN(6), { 0x00000019, 0x00000010 } },
|
||||
{ AR5K_RF_GAIN(7), { 0x00000059, 0x00000044 } },
|
||||
{ AR5K_RF_GAIN(8), { 0x00000099, 0x00000084 } },
|
||||
{ AR5K_RF_GAIN(9), { 0x000001a5, 0x00000148 } },
|
||||
{ AR5K_RF_GAIN(10), { 0x000001e5, 0x00000188 } },
|
||||
{ AR5K_RF_GAIN(11), { 0x00000025, 0x000001c8 } },
|
||||
{ AR5K_RF_GAIN(12), { 0x000001c8, 0x00000014 } },
|
||||
{ AR5K_RF_GAIN(13), { 0x00000008, 0x00000042 } },
|
||||
{ AR5K_RF_GAIN(14), { 0x00000048, 0x00000082 } },
|
||||
{ AR5K_RF_GAIN(15), { 0x00000088, 0x00000178 } },
|
||||
{ AR5K_RF_GAIN(16), { 0x00000198, 0x000001b8 } },
|
||||
{ AR5K_RF_GAIN(17), { 0x000001d8, 0x000001f8 } },
|
||||
{ AR5K_RF_GAIN(18), { 0x00000018, 0x00000012 } },
|
||||
{ AR5K_RF_GAIN(19), { 0x00000058, 0x00000052 } },
|
||||
{ AR5K_RF_GAIN(20), { 0x00000098, 0x00000092 } },
|
||||
{ AR5K_RF_GAIN(21), { 0x000001a4, 0x0000017c } },
|
||||
{ AR5K_RF_GAIN(22), { 0x000001e4, 0x000001bc } },
|
||||
{ AR5K_RF_GAIN(23), { 0x00000024, 0x000001fc } },
|
||||
{ AR5K_RF_GAIN(24), { 0x00000064, 0x0000000a } },
|
||||
{ AR5K_RF_GAIN(25), { 0x000000a4, 0x0000004a } },
|
||||
{ AR5K_RF_GAIN(26), { 0x000000e4, 0x0000008a } },
|
||||
{ AR5K_RF_GAIN(27), { 0x0000010a, 0x0000015a } },
|
||||
{ AR5K_RF_GAIN(28), { 0x0000014a, 0x0000019a } },
|
||||
{ AR5K_RF_GAIN(29), { 0x0000018a, 0x000001da } },
|
||||
{ AR5K_RF_GAIN(30), { 0x000001ca, 0x0000000e } },
|
||||
{ AR5K_RF_GAIN(31), { 0x0000000a, 0x0000004e } },
|
||||
{ AR5K_RF_GAIN(32), { 0x0000004a, 0x0000008e } },
|
||||
{ AR5K_RF_GAIN(33), { 0x0000008a, 0x0000015e } },
|
||||
{ AR5K_RF_GAIN(34), { 0x000001ba, 0x0000019e } },
|
||||
{ AR5K_RF_GAIN(35), { 0x000001fa, 0x000001de } },
|
||||
{ AR5K_RF_GAIN(36), { 0x0000003a, 0x00000009 } },
|
||||
{ AR5K_RF_GAIN(37), { 0x0000007a, 0x00000049 } },
|
||||
{ AR5K_RF_GAIN(38), { 0x00000186, 0x00000089 } },
|
||||
{ AR5K_RF_GAIN(39), { 0x000001c6, 0x00000179 } },
|
||||
{ AR5K_RF_GAIN(40), { 0x00000006, 0x000001b9 } },
|
||||
{ AR5K_RF_GAIN(41), { 0x00000046, 0x000001f9 } },
|
||||
{ AR5K_RF_GAIN(42), { 0x00000086, 0x00000039 } },
|
||||
{ AR5K_RF_GAIN(43), { 0x000000c6, 0x00000079 } },
|
||||
{ AR5K_RF_GAIN(44), { 0x000000c6, 0x000000b9 } },
|
||||
{ AR5K_RF_GAIN(45), { 0x000000c6, 0x000001bd } },
|
||||
{ AR5K_RF_GAIN(46), { 0x000000c6, 0x000001fd } },
|
||||
{ AR5K_RF_GAIN(47), { 0x000000c6, 0x0000003d } },
|
||||
{ AR5K_RF_GAIN(48), { 0x000000c6, 0x0000007d } },
|
||||
{ AR5K_RF_GAIN(49), { 0x000000c6, 0x000000bd } },
|
||||
{ AR5K_RF_GAIN(50), { 0x000000c6, 0x000000fd } },
|
||||
{ AR5K_RF_GAIN(51), { 0x000000c6, 0x000000fd } },
|
||||
{ AR5K_RF_GAIN(52), { 0x000000c6, 0x000000fd } },
|
||||
{ AR5K_RF_GAIN(53), { 0x000000c6, 0x000000fd } },
|
||||
{ AR5K_RF_GAIN(54), { 0x000000c6, 0x000000fd } },
|
||||
{ AR5K_RF_GAIN(55), { 0x000000c6, 0x000000fd } },
|
||||
{ AR5K_RF_GAIN(56), { 0x000000c6, 0x000000fd } },
|
||||
{ AR5K_RF_GAIN(57), { 0x000000c6, 0x000000fd } },
|
||||
{ AR5K_RF_GAIN(58), { 0x000000c6, 0x000000fd } },
|
||||
{ AR5K_RF_GAIN(59), { 0x000000c6, 0x000000fd } },
|
||||
{ AR5K_RF_GAIN(60), { 0x000000c6, 0x000000fd } },
|
||||
{ AR5K_RF_GAIN(61), { 0x000000c6, 0x000000fd } },
|
||||
{ AR5K_RF_GAIN(62), { 0x000000c6, 0x000000fd } },
|
||||
{ AR5K_RF_GAIN(63), { 0x000000c6, 0x000000fd } },
|
||||
};
|
||||
|
||||
/* Initial RF Gain settings for RF5112 */
|
||||
static const struct ath5k_ini_rfgain rfgain_5112[] = {
|
||||
/* 5Ghz 2Ghz */
|
||||
{ AR5K_RF_GAIN(0), { 0x00000007, 0x00000007 } },
|
||||
{ AR5K_RF_GAIN(1), { 0x00000047, 0x00000047 } },
|
||||
{ AR5K_RF_GAIN(2), { 0x00000087, 0x00000087 } },
|
||||
{ AR5K_RF_GAIN(3), { 0x000001a0, 0x000001a0 } },
|
||||
{ AR5K_RF_GAIN(4), { 0x000001e0, 0x000001e0 } },
|
||||
{ AR5K_RF_GAIN(5), { 0x00000020, 0x00000020 } },
|
||||
{ AR5K_RF_GAIN(6), { 0x00000060, 0x00000060 } },
|
||||
{ AR5K_RF_GAIN(7), { 0x000001a1, 0x000001a1 } },
|
||||
{ AR5K_RF_GAIN(8), { 0x000001e1, 0x000001e1 } },
|
||||
{ AR5K_RF_GAIN(9), { 0x00000021, 0x00000021 } },
|
||||
{ AR5K_RF_GAIN(10), { 0x00000061, 0x00000061 } },
|
||||
{ AR5K_RF_GAIN(11), { 0x00000162, 0x00000162 } },
|
||||
{ AR5K_RF_GAIN(12), { 0x000001a2, 0x000001a2 } },
|
||||
{ AR5K_RF_GAIN(13), { 0x000001e2, 0x000001e2 } },
|
||||
{ AR5K_RF_GAIN(14), { 0x00000022, 0x00000022 } },
|
||||
{ AR5K_RF_GAIN(15), { 0x00000062, 0x00000062 } },
|
||||
{ AR5K_RF_GAIN(16), { 0x00000163, 0x00000163 } },
|
||||
{ AR5K_RF_GAIN(17), { 0x000001a3, 0x000001a3 } },
|
||||
{ AR5K_RF_GAIN(18), { 0x000001e3, 0x000001e3 } },
|
||||
{ AR5K_RF_GAIN(19), { 0x00000023, 0x00000023 } },
|
||||
{ AR5K_RF_GAIN(20), { 0x00000063, 0x00000063 } },
|
||||
{ AR5K_RF_GAIN(21), { 0x00000184, 0x00000184 } },
|
||||
{ AR5K_RF_GAIN(22), { 0x000001c4, 0x000001c4 } },
|
||||
{ AR5K_RF_GAIN(23), { 0x00000004, 0x00000004 } },
|
||||
{ AR5K_RF_GAIN(24), { 0x000001ea, 0x0000000b } },
|
||||
{ AR5K_RF_GAIN(25), { 0x0000002a, 0x0000004b } },
|
||||
{ AR5K_RF_GAIN(26), { 0x0000006a, 0x0000008b } },
|
||||
{ AR5K_RF_GAIN(27), { 0x000000aa, 0x000001ac } },
|
||||
{ AR5K_RF_GAIN(28), { 0x000001ab, 0x000001ec } },
|
||||
{ AR5K_RF_GAIN(29), { 0x000001eb, 0x0000002c } },
|
||||
{ AR5K_RF_GAIN(30), { 0x0000002b, 0x00000012 } },
|
||||
{ AR5K_RF_GAIN(31), { 0x0000006b, 0x00000052 } },
|
||||
{ AR5K_RF_GAIN(32), { 0x000000ab, 0x00000092 } },
|
||||
{ AR5K_RF_GAIN(33), { 0x000001ac, 0x00000193 } },
|
||||
{ AR5K_RF_GAIN(34), { 0x000001ec, 0x000001d3 } },
|
||||
{ AR5K_RF_GAIN(35), { 0x0000002c, 0x00000013 } },
|
||||
{ AR5K_RF_GAIN(36), { 0x0000003a, 0x00000053 } },
|
||||
{ AR5K_RF_GAIN(37), { 0x0000007a, 0x00000093 } },
|
||||
{ AR5K_RF_GAIN(38), { 0x000000ba, 0x00000194 } },
|
||||
{ AR5K_RF_GAIN(39), { 0x000001bb, 0x000001d4 } },
|
||||
{ AR5K_RF_GAIN(40), { 0x000001fb, 0x00000014 } },
|
||||
{ AR5K_RF_GAIN(41), { 0x0000003b, 0x0000003a } },
|
||||
{ AR5K_RF_GAIN(42), { 0x0000007b, 0x0000007a } },
|
||||
{ AR5K_RF_GAIN(43), { 0x000000bb, 0x000000ba } },
|
||||
{ AR5K_RF_GAIN(44), { 0x000001bc, 0x000001bb } },
|
||||
{ AR5K_RF_GAIN(45), { 0x000001fc, 0x000001fb } },
|
||||
{ AR5K_RF_GAIN(46), { 0x0000003c, 0x0000003b } },
|
||||
{ AR5K_RF_GAIN(47), { 0x0000007c, 0x0000007b } },
|
||||
{ AR5K_RF_GAIN(48), { 0x000000bc, 0x000000bb } },
|
||||
{ AR5K_RF_GAIN(49), { 0x000000fc, 0x000001bc } },
|
||||
{ AR5K_RF_GAIN(50), { 0x000000fc, 0x000001fc } },
|
||||
{ AR5K_RF_GAIN(51), { 0x000000fc, 0x0000003c } },
|
||||
{ AR5K_RF_GAIN(52), { 0x000000fc, 0x0000007c } },
|
||||
{ AR5K_RF_GAIN(53), { 0x000000fc, 0x000000bc } },
|
||||
{ AR5K_RF_GAIN(54), { 0x000000fc, 0x000000fc } },
|
||||
{ AR5K_RF_GAIN(55), { 0x000000fc, 0x000000fc } },
|
||||
{ AR5K_RF_GAIN(56), { 0x000000fc, 0x000000fc } },
|
||||
{ AR5K_RF_GAIN(57), { 0x000000fc, 0x000000fc } },
|
||||
{ AR5K_RF_GAIN(58), { 0x000000fc, 0x000000fc } },
|
||||
{ AR5K_RF_GAIN(59), { 0x000000fc, 0x000000fc } },
|
||||
{ AR5K_RF_GAIN(60), { 0x000000fc, 0x000000fc } },
|
||||
{ AR5K_RF_GAIN(61), { 0x000000fc, 0x000000fc } },
|
||||
{ AR5K_RF_GAIN(62), { 0x000000fc, 0x000000fc } },
|
||||
{ AR5K_RF_GAIN(63), { 0x000000fc, 0x000000fc } },
|
||||
};
|
||||
|
||||
/* Initial RF Gain settings for RF2413 */
|
||||
static const struct ath5k_ini_rfgain rfgain_2413[] = {
|
||||
{ AR5K_RF_GAIN(0), { 0x00000000, 0x00000000 } },
|
||||
{ AR5K_RF_GAIN(1), { 0x00000000, 0x00000040 } },
|
||||
{ AR5K_RF_GAIN(2), { 0x00000000, 0x00000080 } },
|
||||
{ AR5K_RF_GAIN(3), { 0x00000000, 0x00000181 } },
|
||||
{ AR5K_RF_GAIN(4), { 0x00000000, 0x000001c1 } },
|
||||
{ AR5K_RF_GAIN(5), { 0x00000000, 0x00000001 } },
|
||||
{ AR5K_RF_GAIN(6), { 0x00000000, 0x00000041 } },
|
||||
{ AR5K_RF_GAIN(7), { 0x00000000, 0x00000081 } },
|
||||
{ AR5K_RF_GAIN(8), { 0x00000000, 0x00000168 } },
|
||||
{ AR5K_RF_GAIN(9), { 0x00000000, 0x000001a8 } },
|
||||
{ AR5K_RF_GAIN(10), { 0x00000000, 0x000001e8 } },
|
||||
{ AR5K_RF_GAIN(11), { 0x00000000, 0x00000028 } },
|
||||
{ AR5K_RF_GAIN(12), { 0x00000000, 0x00000068 } },
|
||||
{ AR5K_RF_GAIN(13), { 0x00000000, 0x00000189 } },
|
||||
{ AR5K_RF_GAIN(14), { 0x00000000, 0x000001c9 } },
|
||||
{ AR5K_RF_GAIN(15), { 0x00000000, 0x00000009 } },
|
||||
{ AR5K_RF_GAIN(16), { 0x00000000, 0x00000049 } },
|
||||
{ AR5K_RF_GAIN(17), { 0x00000000, 0x00000089 } },
|
||||
{ AR5K_RF_GAIN(18), { 0x00000000, 0x00000190 } },
|
||||
{ AR5K_RF_GAIN(19), { 0x00000000, 0x000001d0 } },
|
||||
{ AR5K_RF_GAIN(20), { 0x00000000, 0x00000010 } },
|
||||
{ AR5K_RF_GAIN(21), { 0x00000000, 0x00000050 } },
|
||||
{ AR5K_RF_GAIN(22), { 0x00000000, 0x00000090 } },
|
||||
{ AR5K_RF_GAIN(23), { 0x00000000, 0x00000191 } },
|
||||
{ AR5K_RF_GAIN(24), { 0x00000000, 0x000001d1 } },
|
||||
{ AR5K_RF_GAIN(25), { 0x00000000, 0x00000011 } },
|
||||
{ AR5K_RF_GAIN(26), { 0x00000000, 0x00000051 } },
|
||||
{ AR5K_RF_GAIN(27), { 0x00000000, 0x00000091 } },
|
||||
{ AR5K_RF_GAIN(28), { 0x00000000, 0x00000178 } },
|
||||
{ AR5K_RF_GAIN(29), { 0x00000000, 0x000001b8 } },
|
||||
{ AR5K_RF_GAIN(30), { 0x00000000, 0x000001f8 } },
|
||||
{ AR5K_RF_GAIN(31), { 0x00000000, 0x00000038 } },
|
||||
{ AR5K_RF_GAIN(32), { 0x00000000, 0x00000078 } },
|
||||
{ AR5K_RF_GAIN(33), { 0x00000000, 0x00000199 } },
|
||||
{ AR5K_RF_GAIN(34), { 0x00000000, 0x000001d9 } },
|
||||
{ AR5K_RF_GAIN(35), { 0x00000000, 0x00000019 } },
|
||||
{ AR5K_RF_GAIN(36), { 0x00000000, 0x00000059 } },
|
||||
{ AR5K_RF_GAIN(37), { 0x00000000, 0x00000099 } },
|
||||
{ AR5K_RF_GAIN(38), { 0x00000000, 0x000000d9 } },
|
||||
{ AR5K_RF_GAIN(39), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(40), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(41), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(42), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(43), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(44), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(45), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(46), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(47), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(48), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(49), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(50), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(51), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(52), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(53), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(54), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(55), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(56), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(57), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(58), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(59), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(60), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(61), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(62), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(63), { 0x00000000, 0x000000f9 } },
|
||||
};
|
||||
|
||||
/* Initial RF Gain settings for AR2316 */
|
||||
static const struct ath5k_ini_rfgain rfgain_2316[] = {
|
||||
{ AR5K_RF_GAIN(0), { 0x00000000, 0x00000000 } },
|
||||
{ AR5K_RF_GAIN(1), { 0x00000000, 0x00000040 } },
|
||||
{ AR5K_RF_GAIN(2), { 0x00000000, 0x00000080 } },
|
||||
{ AR5K_RF_GAIN(3), { 0x00000000, 0x000000c0 } },
|
||||
{ AR5K_RF_GAIN(4), { 0x00000000, 0x000000e0 } },
|
||||
{ AR5K_RF_GAIN(5), { 0x00000000, 0x000000e0 } },
|
||||
{ AR5K_RF_GAIN(6), { 0x00000000, 0x00000128 } },
|
||||
{ AR5K_RF_GAIN(7), { 0x00000000, 0x00000128 } },
|
||||
{ AR5K_RF_GAIN(8), { 0x00000000, 0x00000128 } },
|
||||
{ AR5K_RF_GAIN(9), { 0x00000000, 0x00000168 } },
|
||||
{ AR5K_RF_GAIN(10), { 0x00000000, 0x000001a8 } },
|
||||
{ AR5K_RF_GAIN(11), { 0x00000000, 0x000001e8 } },
|
||||
{ AR5K_RF_GAIN(12), { 0x00000000, 0x00000028 } },
|
||||
{ AR5K_RF_GAIN(13), { 0x00000000, 0x00000068 } },
|
||||
{ AR5K_RF_GAIN(14), { 0x00000000, 0x000000a8 } },
|
||||
{ AR5K_RF_GAIN(15), { 0x00000000, 0x000000e8 } },
|
||||
{ AR5K_RF_GAIN(16), { 0x00000000, 0x000000e8 } },
|
||||
{ AR5K_RF_GAIN(17), { 0x00000000, 0x00000130 } },
|
||||
{ AR5K_RF_GAIN(18), { 0x00000000, 0x00000130 } },
|
||||
{ AR5K_RF_GAIN(19), { 0x00000000, 0x00000170 } },
|
||||
{ AR5K_RF_GAIN(20), { 0x00000000, 0x000001b0 } },
|
||||
{ AR5K_RF_GAIN(21), { 0x00000000, 0x000001f0 } },
|
||||
{ AR5K_RF_GAIN(22), { 0x00000000, 0x00000030 } },
|
||||
{ AR5K_RF_GAIN(23), { 0x00000000, 0x00000070 } },
|
||||
{ AR5K_RF_GAIN(24), { 0x00000000, 0x000000b0 } },
|
||||
{ AR5K_RF_GAIN(25), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(26), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(27), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(28), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(29), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(30), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(31), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(32), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(33), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(34), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(35), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(36), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(37), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(38), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(39), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(40), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(41), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(42), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(43), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(44), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(45), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(46), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(47), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(48), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(49), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(50), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(51), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(52), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(53), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(54), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(55), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(56), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(57), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(58), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(59), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(60), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(61), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(62), { 0x00000000, 0x000000f0 } },
|
||||
{ AR5K_RF_GAIN(63), { 0x00000000, 0x000000f0 } },
|
||||
};
|
||||
|
||||
|
||||
/* Initial RF Gain settings for RF5413 */
|
||||
static const struct ath5k_ini_rfgain rfgain_5413[] = {
|
||||
/* 5Ghz 2Ghz */
|
||||
{ AR5K_RF_GAIN(0), { 0x00000000, 0x00000000 } },
|
||||
{ AR5K_RF_GAIN(1), { 0x00000040, 0x00000040 } },
|
||||
{ AR5K_RF_GAIN(2), { 0x00000080, 0x00000080 } },
|
||||
{ AR5K_RF_GAIN(3), { 0x000001a1, 0x00000161 } },
|
||||
{ AR5K_RF_GAIN(4), { 0x000001e1, 0x000001a1 } },
|
||||
{ AR5K_RF_GAIN(5), { 0x00000021, 0x000001e1 } },
|
||||
{ AR5K_RF_GAIN(6), { 0x00000061, 0x00000021 } },
|
||||
{ AR5K_RF_GAIN(7), { 0x00000188, 0x00000061 } },
|
||||
{ AR5K_RF_GAIN(8), { 0x000001c8, 0x00000188 } },
|
||||
{ AR5K_RF_GAIN(9), { 0x00000008, 0x000001c8 } },
|
||||
{ AR5K_RF_GAIN(10), { 0x00000048, 0x00000008 } },
|
||||
{ AR5K_RF_GAIN(11), { 0x00000088, 0x00000048 } },
|
||||
{ AR5K_RF_GAIN(12), { 0x000001a9, 0x00000088 } },
|
||||
{ AR5K_RF_GAIN(13), { 0x000001e9, 0x00000169 } },
|
||||
{ AR5K_RF_GAIN(14), { 0x00000029, 0x000001a9 } },
|
||||
{ AR5K_RF_GAIN(15), { 0x00000069, 0x000001e9 } },
|
||||
{ AR5K_RF_GAIN(16), { 0x000001d0, 0x00000029 } },
|
||||
{ AR5K_RF_GAIN(17), { 0x00000010, 0x00000069 } },
|
||||
{ AR5K_RF_GAIN(18), { 0x00000050, 0x00000190 } },
|
||||
{ AR5K_RF_GAIN(19), { 0x00000090, 0x000001d0 } },
|
||||
{ AR5K_RF_GAIN(20), { 0x000001b1, 0x00000010 } },
|
||||
{ AR5K_RF_GAIN(21), { 0x000001f1, 0x00000050 } },
|
||||
{ AR5K_RF_GAIN(22), { 0x00000031, 0x00000090 } },
|
||||
{ AR5K_RF_GAIN(23), { 0x00000071, 0x00000171 } },
|
||||
{ AR5K_RF_GAIN(24), { 0x000001b8, 0x000001b1 } },
|
||||
{ AR5K_RF_GAIN(25), { 0x000001f8, 0x000001f1 } },
|
||||
{ AR5K_RF_GAIN(26), { 0x00000038, 0x00000031 } },
|
||||
{ AR5K_RF_GAIN(27), { 0x00000078, 0x00000071 } },
|
||||
{ AR5K_RF_GAIN(28), { 0x00000199, 0x00000198 } },
|
||||
{ AR5K_RF_GAIN(29), { 0x000001d9, 0x000001d8 } },
|
||||
{ AR5K_RF_GAIN(30), { 0x00000019, 0x00000018 } },
|
||||
{ AR5K_RF_GAIN(31), { 0x00000059, 0x00000058 } },
|
||||
{ AR5K_RF_GAIN(32), { 0x00000099, 0x00000098 } },
|
||||
{ AR5K_RF_GAIN(33), { 0x000000d9, 0x00000179 } },
|
||||
{ AR5K_RF_GAIN(34), { 0x000000f9, 0x000001b9 } },
|
||||
{ AR5K_RF_GAIN(35), { 0x000000f9, 0x000001f9 } },
|
||||
{ AR5K_RF_GAIN(36), { 0x000000f9, 0x00000039 } },
|
||||
{ AR5K_RF_GAIN(37), { 0x000000f9, 0x00000079 } },
|
||||
{ AR5K_RF_GAIN(38), { 0x000000f9, 0x000000b9 } },
|
||||
{ AR5K_RF_GAIN(39), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(40), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(41), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(42), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(43), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(44), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(45), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(46), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(47), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(48), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(49), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(50), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(51), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(52), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(53), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(54), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(55), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(56), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(57), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(58), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(59), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(60), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(61), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(62), { 0x000000f9, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(63), { 0x000000f9, 0x000000f9 } },
|
||||
};
|
||||
|
||||
|
||||
/* Initial RF Gain settings for RF2425 */
|
||||
static const struct ath5k_ini_rfgain rfgain_2425[] = {
|
||||
{ AR5K_RF_GAIN(0), { 0x00000000, 0x00000000 } },
|
||||
{ AR5K_RF_GAIN(1), { 0x00000000, 0x00000040 } },
|
||||
{ AR5K_RF_GAIN(2), { 0x00000000, 0x00000080 } },
|
||||
{ AR5K_RF_GAIN(3), { 0x00000000, 0x00000181 } },
|
||||
{ AR5K_RF_GAIN(4), { 0x00000000, 0x000001c1 } },
|
||||
{ AR5K_RF_GAIN(5), { 0x00000000, 0x00000001 } },
|
||||
{ AR5K_RF_GAIN(6), { 0x00000000, 0x00000041 } },
|
||||
{ AR5K_RF_GAIN(7), { 0x00000000, 0x00000081 } },
|
||||
{ AR5K_RF_GAIN(8), { 0x00000000, 0x00000188 } },
|
||||
{ AR5K_RF_GAIN(9), { 0x00000000, 0x000001c8 } },
|
||||
{ AR5K_RF_GAIN(10), { 0x00000000, 0x00000008 } },
|
||||
{ AR5K_RF_GAIN(11), { 0x00000000, 0x00000048 } },
|
||||
{ AR5K_RF_GAIN(12), { 0x00000000, 0x00000088 } },
|
||||
{ AR5K_RF_GAIN(13), { 0x00000000, 0x00000189 } },
|
||||
{ AR5K_RF_GAIN(14), { 0x00000000, 0x000001c9 } },
|
||||
{ AR5K_RF_GAIN(15), { 0x00000000, 0x00000009 } },
|
||||
{ AR5K_RF_GAIN(16), { 0x00000000, 0x00000049 } },
|
||||
{ AR5K_RF_GAIN(17), { 0x00000000, 0x00000089 } },
|
||||
{ AR5K_RF_GAIN(18), { 0x00000000, 0x000001b0 } },
|
||||
{ AR5K_RF_GAIN(19), { 0x00000000, 0x000001f0 } },
|
||||
{ AR5K_RF_GAIN(20), { 0x00000000, 0x00000030 } },
|
||||
{ AR5K_RF_GAIN(21), { 0x00000000, 0x00000070 } },
|
||||
{ AR5K_RF_GAIN(22), { 0x00000000, 0x00000171 } },
|
||||
{ AR5K_RF_GAIN(23), { 0x00000000, 0x000001b1 } },
|
||||
{ AR5K_RF_GAIN(24), { 0x00000000, 0x000001f1 } },
|
||||
{ AR5K_RF_GAIN(25), { 0x00000000, 0x00000031 } },
|
||||
{ AR5K_RF_GAIN(26), { 0x00000000, 0x00000071 } },
|
||||
{ AR5K_RF_GAIN(27), { 0x00000000, 0x000001b8 } },
|
||||
{ AR5K_RF_GAIN(28), { 0x00000000, 0x000001f8 } },
|
||||
{ AR5K_RF_GAIN(29), { 0x00000000, 0x00000038 } },
|
||||
{ AR5K_RF_GAIN(30), { 0x00000000, 0x00000078 } },
|
||||
{ AR5K_RF_GAIN(31), { 0x00000000, 0x000000b8 } },
|
||||
{ AR5K_RF_GAIN(32), { 0x00000000, 0x000001b9 } },
|
||||
{ AR5K_RF_GAIN(33), { 0x00000000, 0x000001f9 } },
|
||||
{ AR5K_RF_GAIN(34), { 0x00000000, 0x00000039 } },
|
||||
{ AR5K_RF_GAIN(35), { 0x00000000, 0x00000079 } },
|
||||
{ AR5K_RF_GAIN(36), { 0x00000000, 0x000000b9 } },
|
||||
{ AR5K_RF_GAIN(37), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(38), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(39), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(40), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(41), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(42), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(43), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(44), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(45), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(46), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(47), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(48), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(49), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(50), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(51), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(52), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(53), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(54), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(55), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(56), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(57), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(58), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(59), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(60), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(61), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(62), { 0x00000000, 0x000000f9 } },
|
||||
{ AR5K_RF_GAIN(63), { 0x00000000, 0x000000f9 } },
|
||||
};
|
||||
|
||||
#define AR5K_GAIN_CRN_FIX_BITS_5111 4
|
||||
#define AR5K_GAIN_CRN_FIX_BITS_5112 7
|
||||
#define AR5K_GAIN_CRN_MAX_FIX_BITS AR5K_GAIN_CRN_FIX_BITS_5112
|
||||
#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN 15
|
||||
#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN 20
|
||||
#define AR5K_GAIN_CCK_PROBE_CORR 5
|
||||
#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA 15
|
||||
#define AR5K_GAIN_STEP_COUNT 10
|
||||
|
||||
/* Check if our current measurement is inside our
|
||||
* current variable attenuation window */
|
||||
#define AR5K_GAIN_CHECK_ADJUST(_g) \
|
||||
((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
|
||||
|
||||
struct ath5k_gain_opt_step {
|
||||
s8 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
|
||||
s8 gos_gain;
|
||||
};
|
||||
|
||||
struct ath5k_gain_opt {
|
||||
u8 go_default;
|
||||
u8 go_steps_count;
|
||||
const struct ath5k_gain_opt_step go_step[AR5K_GAIN_STEP_COUNT];
|
||||
};
|
||||
|
||||
/*
|
||||
* Parameters on gos_param:
|
||||
* 1) Tx clip PHY register
|
||||
* 2) PWD 90 RF register
|
||||
* 3) PWD 84 RF register
|
||||
* 4) RFGainSel RF register
|
||||
*/
|
||||
static const struct ath5k_gain_opt rfgain_opt_5111 = {
|
||||
4,
|
||||
9,
|
||||
{
|
||||
{ { 4, 1, 1, 1 }, 6 },
|
||||
{ { 4, 0, 1, 1 }, 4 },
|
||||
{ { 3, 1, 1, 1 }, 3 },
|
||||
{ { 4, 0, 0, 1 }, 1 },
|
||||
{ { 4, 1, 1, 0 }, 0 },
|
||||
{ { 4, 0, 1, 0 }, -2 },
|
||||
{ { 3, 1, 1, 0 }, -3 },
|
||||
{ { 4, 0, 0, 0 }, -4 },
|
||||
{ { 2, 1, 1, 0 }, -6 }
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Parameters on gos_param:
|
||||
* 1) Mixgain ovr RF register
|
||||
* 2) PWD 138 RF register
|
||||
* 3) PWD 137 RF register
|
||||
* 4) PWD 136 RF register
|
||||
* 5) PWD 132 RF register
|
||||
* 6) PWD 131 RF register
|
||||
* 7) PWD 130 RF register
|
||||
*/
|
||||
static const struct ath5k_gain_opt rfgain_opt_5112 = {
|
||||
1,
|
||||
8,
|
||||
{
|
||||
{ { 3, 0, 0, 0, 0, 0, 0 }, 6 },
|
||||
{ { 2, 0, 0, 0, 0, 0, 0 }, 0 },
|
||||
{ { 1, 0, 0, 0, 0, 0, 0 }, -3 },
|
||||
{ { 0, 0, 0, 0, 0, 0, 0 }, -6 },
|
||||
{ { 0, 1, 1, 0, 0, 0, 0 }, -8 },
|
||||
{ { 0, 1, 1, 0, 1, 1, 0 }, -10 },
|
||||
{ { 0, 1, 0, 1, 1, 1, 0 }, -13 },
|
||||
{ { 0, 1, 0, 1, 1, 0, 1 }, -16 },
|
||||
}
|
||||
};
|
||||
|
@ -19,9 +19,7 @@
|
||||
#include <linux/nl80211.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/ath9k_platform.h>
|
||||
#include "core.h"
|
||||
#include "reg.h"
|
||||
#include "hw.h"
|
||||
#include "ath9k.h"
|
||||
|
||||
/* return bus cachesize in 4B word units */
|
||||
static void ath_ahb_read_cachesize(struct ath_softc *sc, int *csz)
|
||||
@ -34,7 +32,7 @@ static void ath_ahb_cleanup(struct ath_softc *sc)
|
||||
iounmap(sc->mem);
|
||||
}
|
||||
|
||||
static bool ath_ahb_eeprom_read(struct ath_hal *ah, u32 off, u16 *data)
|
||||
static bool ath_ahb_eeprom_read(struct ath_hw *ah, u32 off, u16 *data)
|
||||
{
|
||||
struct ath_softc *sc = ah->ah_sc;
|
||||
struct platform_device *pdev = to_platform_device(sc->dev);
|
||||
@ -67,7 +65,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
int irq;
|
||||
int ret = 0;
|
||||
struct ath_hal *ah;
|
||||
struct ath_hw *ah;
|
||||
|
||||
if (!pdev->dev.platform_data) {
|
||||
dev_err(&pdev->dev, "no platform data specified\n");
|
||||
@ -134,10 +132,10 @@ static int ath_ahb_probe(struct platform_device *pdev)
|
||||
"%s: Atheros AR%s MAC/BB Rev:%x, "
|
||||
"AR%s RF Rev:%x, mem=0x%lx, irq=%d\n",
|
||||
wiphy_name(hw->wiphy),
|
||||
ath_mac_bb_name(ah->ah_macVersion),
|
||||
ah->ah_macRev,
|
||||
ath_rf_name((ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)),
|
||||
ah->ah_phyRev,
|
||||
ath_mac_bb_name(ah->hw_version.macVersion),
|
||||
ah->hw_version.macRev,
|
||||
ath_rf_name((ah->hw_version.analog5GhzRev & AR_RADIO_SREV_MAJOR)),
|
||||
ah->hw_version.phyRev,
|
||||
(unsigned long)mem, irq);
|
||||
|
||||
return 0;
|
||||
|
@ -14,23 +14,19 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
#include "hw.h"
|
||||
#include "reg.h"
|
||||
#include "phy.h"
|
||||
#include "ath9k.h"
|
||||
|
||||
static int ath9k_hw_get_ani_channel_idx(struct ath_hal *ah,
|
||||
static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
|
||||
if (ahp->ah_ani[i].c.channel == chan->channel)
|
||||
for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
|
||||
if (ah->ani[i].c &&
|
||||
ah->ani[i].c->channel == chan->channel)
|
||||
return i;
|
||||
if (ahp->ah_ani[i].c.channel == 0) {
|
||||
ahp->ah_ani[i].c.channel = chan->channel;
|
||||
ahp->ah_ani[i].c.channelFlags = chan->channelFlags;
|
||||
if (ah->ani[i].c == NULL) {
|
||||
ah->ani[i].c = chan;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@ -41,41 +37,40 @@ static int ath9k_hw_get_ani_channel_idx(struct ath_hal *ah,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ath9k_hw_ani_control(struct ath_hal *ah,
|
||||
static bool ath9k_hw_ani_control(struct ath_hw *ah,
|
||||
enum ath9k_ani_cmd cmd, int param)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
struct ar5416AniState *aniState = ahp->ah_curani;
|
||||
struct ar5416AniState *aniState = ah->curani;
|
||||
|
||||
switch (cmd & ahp->ah_ani_function) {
|
||||
switch (cmd & ah->ani_function) {
|
||||
case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
|
||||
u32 level = param;
|
||||
|
||||
if (level >= ARRAY_SIZE(ahp->ah_totalSizeDesired)) {
|
||||
if (level >= ARRAY_SIZE(ah->totalSizeDesired)) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
|
||||
"level out of range (%u > %u)\n",
|
||||
level,
|
||||
(unsigned)ARRAY_SIZE(ahp->ah_totalSizeDesired));
|
||||
(unsigned)ARRAY_SIZE(ah->totalSizeDesired));
|
||||
return false;
|
||||
}
|
||||
|
||||
REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
|
||||
AR_PHY_DESIRED_SZ_TOT_DES,
|
||||
ahp->ah_totalSizeDesired[level]);
|
||||
ah->totalSizeDesired[level]);
|
||||
REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
|
||||
AR_PHY_AGC_CTL1_COARSE_LOW,
|
||||
ahp->ah_coarseLow[level]);
|
||||
ah->coarse_low[level]);
|
||||
REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
|
||||
AR_PHY_AGC_CTL1_COARSE_HIGH,
|
||||
ahp->ah_coarseHigh[level]);
|
||||
ah->coarse_high[level]);
|
||||
REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
|
||||
AR_PHY_FIND_SIG_FIRPWR,
|
||||
ahp->ah_firpwr[level]);
|
||||
ah->firpwr[level]);
|
||||
|
||||
if (level > aniState->noiseImmunityLevel)
|
||||
ahp->ah_stats.ast_ani_niup++;
|
||||
ah->stats.ast_ani_niup++;
|
||||
else if (level < aniState->noiseImmunityLevel)
|
||||
ahp->ah_stats.ast_ani_nidown++;
|
||||
ah->stats.ast_ani_nidown++;
|
||||
aniState->noiseImmunityLevel = level;
|
||||
break;
|
||||
}
|
||||
@ -129,9 +124,9 @@ static bool ath9k_hw_ani_control(struct ath_hal *ah,
|
||||
|
||||
if (!on != aniState->ofdmWeakSigDetectOff) {
|
||||
if (on)
|
||||
ahp->ah_stats.ast_ani_ofdmon++;
|
||||
ah->stats.ast_ani_ofdmon++;
|
||||
else
|
||||
ahp->ah_stats.ast_ani_ofdmoff++;
|
||||
ah->stats.ast_ani_ofdmoff++;
|
||||
aniState->ofdmWeakSigDetectOff = !on;
|
||||
}
|
||||
break;
|
||||
@ -145,9 +140,9 @@ static bool ath9k_hw_ani_control(struct ath_hal *ah,
|
||||
weakSigThrCck[high]);
|
||||
if (high != aniState->cckWeakSigThreshold) {
|
||||
if (high)
|
||||
ahp->ah_stats.ast_ani_cckhigh++;
|
||||
ah->stats.ast_ani_cckhigh++;
|
||||
else
|
||||
ahp->ah_stats.ast_ani_ccklow++;
|
||||
ah->stats.ast_ani_ccklow++;
|
||||
aniState->cckWeakSigThreshold = high;
|
||||
}
|
||||
break;
|
||||
@ -167,9 +162,9 @@ static bool ath9k_hw_ani_control(struct ath_hal *ah,
|
||||
AR_PHY_FIND_SIG_FIRSTEP,
|
||||
firstep[level]);
|
||||
if (level > aniState->firstepLevel)
|
||||
ahp->ah_stats.ast_ani_stepup++;
|
||||
ah->stats.ast_ani_stepup++;
|
||||
else if (level < aniState->firstepLevel)
|
||||
ahp->ah_stats.ast_ani_stepdown++;
|
||||
ah->stats.ast_ani_stepdown++;
|
||||
aniState->firstepLevel = level;
|
||||
break;
|
||||
}
|
||||
@ -190,9 +185,9 @@ static bool ath9k_hw_ani_control(struct ath_hal *ah,
|
||||
AR_PHY_TIMING5_CYCPWR_THR1,
|
||||
cycpwrThr1[level]);
|
||||
if (level > aniState->spurImmunityLevel)
|
||||
ahp->ah_stats.ast_ani_spurup++;
|
||||
ah->stats.ast_ani_spurup++;
|
||||
else if (level < aniState->spurImmunityLevel)
|
||||
ahp->ah_stats.ast_ani_spurdown++;
|
||||
ah->stats.ast_ani_spurdown++;
|
||||
aniState->spurImmunityLevel = level;
|
||||
break;
|
||||
}
|
||||
@ -223,7 +218,7 @@ static bool ath9k_hw_ani_control(struct ath_hal *ah,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ath9k_hw_update_mibstats(struct ath_hal *ah,
|
||||
static void ath9k_hw_update_mibstats(struct ath_hw *ah,
|
||||
struct ath9k_mib_stats *stats)
|
||||
{
|
||||
stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
|
||||
@ -233,18 +228,17 @@ static void ath9k_hw_update_mibstats(struct ath_hal *ah,
|
||||
stats->beacons += REG_READ(ah, AR_BEACON_CNT);
|
||||
}
|
||||
|
||||
static void ath9k_ani_restart(struct ath_hal *ah)
|
||||
static void ath9k_ani_restart(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
struct ar5416AniState *aniState;
|
||||
|
||||
if (!DO_ANI(ah))
|
||||
return;
|
||||
|
||||
aniState = ahp->ah_curani;
|
||||
aniState = ah->curani;
|
||||
|
||||
aniState->listenTime = 0;
|
||||
if (ahp->ah_hasHwPhyCounters) {
|
||||
if (ah->has_hw_phycounters) {
|
||||
if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
|
||||
aniState->ofdmPhyErrBase = 0;
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
|
||||
@ -270,15 +264,14 @@ static void ath9k_ani_restart(struct ath_hal *ah)
|
||||
REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
|
||||
REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
|
||||
|
||||
ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
|
||||
ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
|
||||
}
|
||||
aniState->ofdmPhyErrCount = 0;
|
||||
aniState->cckPhyErrCount = 0;
|
||||
}
|
||||
|
||||
static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah)
|
||||
static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
|
||||
struct ar5416AniState *aniState;
|
||||
int32_t rssi;
|
||||
@ -286,7 +279,7 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah)
|
||||
if (!DO_ANI(ah))
|
||||
return;
|
||||
|
||||
aniState = ahp->ah_curani;
|
||||
aniState = ah->curani;
|
||||
|
||||
if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
|
||||
if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
|
||||
@ -302,14 +295,14 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah)
|
||||
}
|
||||
}
|
||||
|
||||
if (ah->ah_opmode == NL80211_IFTYPE_AP) {
|
||||
if (ah->opmode == NL80211_IFTYPE_AP) {
|
||||
if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
|
||||
ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
|
||||
aniState->firstepLevel + 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
rssi = BEACON_RSSI(ahp);
|
||||
rssi = BEACON_RSSI(ah);
|
||||
if (rssi > aniState->rssiThrHigh) {
|
||||
if (!aniState->ofdmWeakSigDetectOff) {
|
||||
if (ath9k_hw_ani_control(ah,
|
||||
@ -348,9 +341,8 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah)
|
||||
}
|
||||
}
|
||||
|
||||
static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah)
|
||||
static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
|
||||
struct ar5416AniState *aniState;
|
||||
int32_t rssi;
|
||||
@ -358,21 +350,21 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah)
|
||||
if (!DO_ANI(ah))
|
||||
return;
|
||||
|
||||
aniState = ahp->ah_curani;
|
||||
aniState = ah->curani;
|
||||
if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
|
||||
if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
|
||||
aniState->noiseImmunityLevel + 1)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (ah->ah_opmode == NL80211_IFTYPE_AP) {
|
||||
if (ah->opmode == NL80211_IFTYPE_AP) {
|
||||
if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
|
||||
ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
|
||||
aniState->firstepLevel + 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
rssi = BEACON_RSSI(ahp);
|
||||
rssi = BEACON_RSSI(ah);
|
||||
if (rssi > aniState->rssiThrLow) {
|
||||
if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
|
||||
ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
|
||||
@ -386,22 +378,21 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah)
|
||||
}
|
||||
}
|
||||
|
||||
static void ath9k_hw_ani_lower_immunity(struct ath_hal *ah)
|
||||
static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
struct ar5416AniState *aniState;
|
||||
int32_t rssi;
|
||||
|
||||
aniState = ahp->ah_curani;
|
||||
aniState = ah->curani;
|
||||
|
||||
if (ah->ah_opmode == NL80211_IFTYPE_AP) {
|
||||
if (ah->opmode == NL80211_IFTYPE_AP) {
|
||||
if (aniState->firstepLevel > 0) {
|
||||
if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
|
||||
aniState->firstepLevel - 1))
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
rssi = BEACON_RSSI(ahp);
|
||||
rssi = BEACON_RSSI(ah);
|
||||
if (rssi > aniState->rssiThrHigh) {
|
||||
/* XXX: Handle me */
|
||||
} else if (rssi > aniState->rssiThrLow) {
|
||||
@ -440,9 +431,8 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hal *ah)
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah)
|
||||
static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
struct ar5416AniState *aniState;
|
||||
u32 txFrameCount, rxFrameCount, cycleCount;
|
||||
int32_t listenTime;
|
||||
@ -451,11 +441,11 @@ static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah)
|
||||
rxFrameCount = REG_READ(ah, AR_RFCNT);
|
||||
cycleCount = REG_READ(ah, AR_CCCNT);
|
||||
|
||||
aniState = ahp->ah_curani;
|
||||
aniState = ah->curani;
|
||||
if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
|
||||
|
||||
listenTime = 0;
|
||||
ahp->ah_stats.ast_ani_lzero++;
|
||||
ah->stats.ast_ani_lzero++;
|
||||
} else {
|
||||
int32_t ccdelta = cycleCount - aniState->cycleCount;
|
||||
int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
|
||||
@ -469,25 +459,24 @@ static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah)
|
||||
return listenTime;
|
||||
}
|
||||
|
||||
void ath9k_ani_reset(struct ath_hal *ah)
|
||||
void ath9k_ani_reset(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
struct ar5416AniState *aniState;
|
||||
struct ath9k_channel *chan = ah->ah_curchan;
|
||||
struct ath9k_channel *chan = ah->curchan;
|
||||
int index;
|
||||
|
||||
if (!DO_ANI(ah))
|
||||
return;
|
||||
|
||||
index = ath9k_hw_get_ani_channel_idx(ah, chan);
|
||||
aniState = &ahp->ah_ani[index];
|
||||
ahp->ah_curani = aniState;
|
||||
aniState = &ah->ani[index];
|
||||
ah->curani = aniState;
|
||||
|
||||
if (DO_ANI(ah) && ah->ah_opmode != NL80211_IFTYPE_STATION
|
||||
&& ah->ah_opmode != NL80211_IFTYPE_ADHOC) {
|
||||
if (DO_ANI(ah) && ah->opmode != NL80211_IFTYPE_STATION
|
||||
&& ah->opmode != NL80211_IFTYPE_ADHOC) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
|
||||
"Reset ANI state opmode %u\n", ah->ah_opmode);
|
||||
ahp->ah_stats.ast_ani_reset++;
|
||||
"Reset ANI state opmode %u\n", ah->opmode);
|
||||
ah->stats.ast_ani_reset++;
|
||||
|
||||
ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
|
||||
ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
|
||||
@ -500,15 +489,15 @@ void ath9k_ani_reset(struct ath_hal *ah)
|
||||
ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
|
||||
ATH9K_RX_FILTER_PHYERR);
|
||||
|
||||
if (ah->ah_opmode == NL80211_IFTYPE_AP) {
|
||||
ahp->ah_curani->ofdmTrigHigh =
|
||||
ah->ah_config.ofdm_trig_high;
|
||||
ahp->ah_curani->ofdmTrigLow =
|
||||
ah->ah_config.ofdm_trig_low;
|
||||
ahp->ah_curani->cckTrigHigh =
|
||||
ah->ah_config.cck_trig_high;
|
||||
ahp->ah_curani->cckTrigLow =
|
||||
ah->ah_config.cck_trig_low;
|
||||
if (ah->opmode == NL80211_IFTYPE_AP) {
|
||||
ah->curani->ofdmTrigHigh =
|
||||
ah->config.ofdm_trig_high;
|
||||
ah->curani->ofdmTrigLow =
|
||||
ah->config.ofdm_trig_low;
|
||||
ah->curani->cckTrigHigh =
|
||||
ah->config.cck_trig_high;
|
||||
ah->curani->cckTrigLow =
|
||||
ah->config.cck_trig_low;
|
||||
}
|
||||
ath9k_ani_restart(ah);
|
||||
return;
|
||||
@ -529,7 +518,7 @@ void ath9k_ani_reset(struct ath_hal *ah)
|
||||
if (aniState->firstepLevel != 0)
|
||||
ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
|
||||
aniState->firstepLevel);
|
||||
if (ahp->ah_hasHwPhyCounters) {
|
||||
if (ah->has_hw_phycounters) {
|
||||
ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
|
||||
~ATH9K_RX_FILTER_PHYERR);
|
||||
ath9k_ani_restart(ah);
|
||||
@ -543,34 +532,33 @@ void ath9k_ani_reset(struct ath_hal *ah)
|
||||
}
|
||||
}
|
||||
|
||||
void ath9k_hw_ani_monitor(struct ath_hal *ah,
|
||||
void ath9k_hw_ani_monitor(struct ath_hw *ah,
|
||||
const struct ath9k_node_stats *stats,
|
||||
struct ath9k_channel *chan)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
struct ar5416AniState *aniState;
|
||||
int32_t listenTime;
|
||||
|
||||
if (!DO_ANI(ah))
|
||||
return;
|
||||
|
||||
aniState = ahp->ah_curani;
|
||||
ahp->ah_stats.ast_nodestats = *stats;
|
||||
aniState = ah->curani;
|
||||
ah->stats.ast_nodestats = *stats;
|
||||
|
||||
listenTime = ath9k_hw_ani_get_listen_time(ah);
|
||||
if (listenTime < 0) {
|
||||
ahp->ah_stats.ast_ani_lneg++;
|
||||
ah->stats.ast_ani_lneg++;
|
||||
ath9k_ani_restart(ah);
|
||||
return;
|
||||
}
|
||||
|
||||
aniState->listenTime += listenTime;
|
||||
|
||||
if (ahp->ah_hasHwPhyCounters) {
|
||||
if (ah->has_hw_phycounters) {
|
||||
u32 phyCnt1, phyCnt2;
|
||||
u32 ofdmPhyErrCnt, cckPhyErrCnt;
|
||||
|
||||
ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
|
||||
ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
|
||||
|
||||
phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
|
||||
phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
|
||||
@ -603,24 +591,24 @@ void ath9k_hw_ani_monitor(struct ath_hal *ah,
|
||||
}
|
||||
|
||||
ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
|
||||
ahp->ah_stats.ast_ani_ofdmerrs +=
|
||||
ah->stats.ast_ani_ofdmerrs +=
|
||||
ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
|
||||
aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
|
||||
|
||||
cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
|
||||
ahp->ah_stats.ast_ani_cckerrs +=
|
||||
ah->stats.ast_ani_cckerrs +=
|
||||
cckPhyErrCnt - aniState->cckPhyErrCount;
|
||||
aniState->cckPhyErrCount = cckPhyErrCnt;
|
||||
}
|
||||
|
||||
if (aniState->listenTime > 5 * ahp->ah_aniPeriod) {
|
||||
if (aniState->listenTime > 5 * ah->aniperiod) {
|
||||
if (aniState->ofdmPhyErrCount <= aniState->listenTime *
|
||||
aniState->ofdmTrigLow / 1000 &&
|
||||
aniState->cckPhyErrCount <= aniState->listenTime *
|
||||
aniState->cckTrigLow / 1000)
|
||||
ath9k_hw_ani_lower_immunity(ah);
|
||||
ath9k_ani_restart(ah);
|
||||
} else if (aniState->listenTime > ahp->ah_aniPeriod) {
|
||||
} else if (aniState->listenTime > ah->aniperiod) {
|
||||
if (aniState->ofdmPhyErrCount > aniState->listenTime *
|
||||
aniState->ofdmTrigHigh / 1000) {
|
||||
ath9k_hw_ani_ofdm_err_trigger(ah);
|
||||
@ -634,20 +622,16 @@ void ath9k_hw_ani_monitor(struct ath_hal *ah,
|
||||
}
|
||||
}
|
||||
|
||||
bool ath9k_hw_phycounters(struct ath_hal *ah)
|
||||
bool ath9k_hw_phycounters(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
|
||||
return ahp->ah_hasHwPhyCounters ? true : false;
|
||||
return ah->has_hw_phycounters ? true : false;
|
||||
}
|
||||
|
||||
void ath9k_enable_mib_counters(struct ath_hal *ah)
|
||||
void ath9k_enable_mib_counters(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n");
|
||||
|
||||
ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
|
||||
ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
|
||||
|
||||
REG_WRITE(ah, AR_FILT_OFDM, 0);
|
||||
REG_WRITE(ah, AR_FILT_CCK, 0);
|
||||
@ -658,21 +642,19 @@ void ath9k_enable_mib_counters(struct ath_hal *ah)
|
||||
REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
|
||||
}
|
||||
|
||||
void ath9k_hw_disable_mib_counters(struct ath_hal *ah)
|
||||
void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n");
|
||||
|
||||
REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC);
|
||||
|
||||
ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
|
||||
ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
|
||||
|
||||
REG_WRITE(ah, AR_FILT_OFDM, 0);
|
||||
REG_WRITE(ah, AR_FILT_CCK, 0);
|
||||
}
|
||||
|
||||
u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
|
||||
u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
|
||||
u32 *rxc_pcnt,
|
||||
u32 *rxf_pcnt,
|
||||
u32 *txf_pcnt)
|
||||
@ -717,10 +699,9 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
|
||||
* any of the MIB counters overflow/trigger so don't assume we're
|
||||
* here because a PHY error counter triggered.
|
||||
*/
|
||||
void ath9k_hw_procmibevent(struct ath_hal *ah,
|
||||
void ath9k_hw_procmibevent(struct ath_hw *ah,
|
||||
const struct ath9k_node_stats *stats)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
u32 phyCnt1, phyCnt2;
|
||||
|
||||
/* Reset these counters regardless */
|
||||
@ -730,8 +711,8 @@ void ath9k_hw_procmibevent(struct ath_hal *ah,
|
||||
REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
|
||||
|
||||
/* Clear the mib counters and save them in the stats */
|
||||
ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
|
||||
ahp->ah_stats.ast_nodestats = *stats;
|
||||
ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
|
||||
ah->stats.ast_nodestats = *stats;
|
||||
|
||||
if (!DO_ANI(ah))
|
||||
return;
|
||||
@ -741,17 +722,17 @@ void ath9k_hw_procmibevent(struct ath_hal *ah,
|
||||
phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
|
||||
if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
|
||||
((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
|
||||
struct ar5416AniState *aniState = ahp->ah_curani;
|
||||
struct ar5416AniState *aniState = ah->curani;
|
||||
u32 ofdmPhyErrCnt, cckPhyErrCnt;
|
||||
|
||||
/* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
|
||||
ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
|
||||
ahp->ah_stats.ast_ani_ofdmerrs +=
|
||||
ah->stats.ast_ani_ofdmerrs +=
|
||||
ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
|
||||
aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
|
||||
|
||||
cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
|
||||
ahp->ah_stats.ast_ani_cckerrs +=
|
||||
ah->stats.ast_ani_cckerrs +=
|
||||
cckPhyErrCnt - aniState->cckPhyErrCount;
|
||||
aniState->cckPhyErrCount = cckPhyErrCnt;
|
||||
|
||||
@ -770,9 +751,8 @@ void ath9k_hw_procmibevent(struct ath_hal *ah,
|
||||
}
|
||||
}
|
||||
|
||||
void ath9k_hw_ani_setup(struct ath_hal *ah)
|
||||
void ath9k_hw_ani_setup(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
int i;
|
||||
|
||||
const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
|
||||
@ -781,66 +761,63 @@ void ath9k_hw_ani_setup(struct ath_hal *ah)
|
||||
const int firpwr[] = { -78, -78, -78, -78, -80 };
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
ahp->ah_totalSizeDesired[i] = totalSizeDesired[i];
|
||||
ahp->ah_coarseHigh[i] = coarseHigh[i];
|
||||
ahp->ah_coarseLow[i] = coarseLow[i];
|
||||
ahp->ah_firpwr[i] = firpwr[i];
|
||||
ah->totalSizeDesired[i] = totalSizeDesired[i];
|
||||
ah->coarse_high[i] = coarseHigh[i];
|
||||
ah->coarse_low[i] = coarseLow[i];
|
||||
ah->firpwr[i] = firpwr[i];
|
||||
}
|
||||
}
|
||||
|
||||
void ath9k_hw_ani_attach(struct ath_hal *ah)
|
||||
void ath9k_hw_ani_attach(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
int i;
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n");
|
||||
|
||||
ahp->ah_hasHwPhyCounters = 1;
|
||||
ah->has_hw_phycounters = 1;
|
||||
|
||||
memset(ahp->ah_ani, 0, sizeof(ahp->ah_ani));
|
||||
for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
|
||||
ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
|
||||
ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
|
||||
ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
|
||||
ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
|
||||
ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
|
||||
ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
|
||||
ahp->ah_ani[i].ofdmWeakSigDetectOff =
|
||||
memset(ah->ani, 0, sizeof(ah->ani));
|
||||
for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
|
||||
ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
|
||||
ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
|
||||
ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
|
||||
ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
|
||||
ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
|
||||
ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
|
||||
ah->ani[i].ofdmWeakSigDetectOff =
|
||||
!ATH9K_ANI_USE_OFDM_WEAK_SIG;
|
||||
ahp->ah_ani[i].cckWeakSigThreshold =
|
||||
ah->ani[i].cckWeakSigThreshold =
|
||||
ATH9K_ANI_CCK_WEAK_SIG_THR;
|
||||
ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
|
||||
ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
|
||||
if (ahp->ah_hasHwPhyCounters) {
|
||||
ahp->ah_ani[i].ofdmPhyErrBase =
|
||||
ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
|
||||
ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
|
||||
if (ah->has_hw_phycounters) {
|
||||
ah->ani[i].ofdmPhyErrBase =
|
||||
AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
|
||||
ahp->ah_ani[i].cckPhyErrBase =
|
||||
ah->ani[i].cckPhyErrBase =
|
||||
AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
|
||||
}
|
||||
}
|
||||
if (ahp->ah_hasHwPhyCounters) {
|
||||
if (ah->has_hw_phycounters) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
|
||||
"Setting OfdmErrBase = 0x%08x\n",
|
||||
ahp->ah_ani[0].ofdmPhyErrBase);
|
||||
ah->ani[0].ofdmPhyErrBase);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
|
||||
ahp->ah_ani[0].cckPhyErrBase);
|
||||
ah->ani[0].cckPhyErrBase);
|
||||
|
||||
REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase);
|
||||
ath9k_enable_mib_counters(ah);
|
||||
}
|
||||
ahp->ah_aniPeriod = ATH9K_ANI_PERIOD;
|
||||
if (ah->ah_config.enable_ani)
|
||||
ahp->ah_procPhyErr |= HAL_PROCESS_ANI;
|
||||
ah->aniperiod = ATH9K_ANI_PERIOD;
|
||||
if (ah->config.enable_ani)
|
||||
ah->proc_phyerr |= HAL_PROCESS_ANI;
|
||||
}
|
||||
|
||||
void ath9k_hw_ani_detach(struct ath_hal *ah)
|
||||
void ath9k_hw_ani_detach(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n");
|
||||
|
||||
if (ahp->ah_hasHwPhyCounters) {
|
||||
if (ah->has_hw_phycounters) {
|
||||
ath9k_hw_disable_mib_counters(ah);
|
||||
REG_WRITE(ah, AR_PHY_ERR_1, 0);
|
||||
REG_WRITE(ah, AR_PHY_ERR_2, 0);
|
||||
|
138
drivers/net/wireless/ath9k/ani.h
Normal file
138
drivers/net/wireless/ath9k/ani.h
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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 ANI_H
|
||||
#define ANI_H
|
||||
|
||||
#define HAL_PROCESS_ANI 0x00000001
|
||||
#define ATH9K_RSSI_EP_MULTIPLIER (1<<7)
|
||||
|
||||
#define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI))
|
||||
|
||||
#define HAL_EP_RND(x, mul) \
|
||||
((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
|
||||
#define BEACON_RSSI(ahp) \
|
||||
HAL_EP_RND(ahp->stats.ast_nodestats.ns_avgbrssi, \
|
||||
ATH9K_RSSI_EP_MULTIPLIER)
|
||||
|
||||
#define ATH9K_ANI_OFDM_TRIG_HIGH 500
|
||||
#define ATH9K_ANI_OFDM_TRIG_LOW 200
|
||||
#define ATH9K_ANI_CCK_TRIG_HIGH 200
|
||||
#define ATH9K_ANI_CCK_TRIG_LOW 100
|
||||
#define ATH9K_ANI_NOISE_IMMUNE_LVL 4
|
||||
#define ATH9K_ANI_USE_OFDM_WEAK_SIG true
|
||||
#define ATH9K_ANI_CCK_WEAK_SIG_THR false
|
||||
#define ATH9K_ANI_SPUR_IMMUNE_LVL 7
|
||||
#define ATH9K_ANI_FIRSTEP_LVL 0
|
||||
#define ATH9K_ANI_RSSI_THR_HIGH 40
|
||||
#define ATH9K_ANI_RSSI_THR_LOW 7
|
||||
#define ATH9K_ANI_PERIOD 100
|
||||
|
||||
#define HAL_NOISE_IMMUNE_MAX 4
|
||||
#define HAL_SPUR_IMMUNE_MAX 7
|
||||
#define HAL_FIRST_STEP_MAX 2
|
||||
|
||||
enum ath9k_ani_cmd {
|
||||
ATH9K_ANI_PRESENT = 0x1,
|
||||
ATH9K_ANI_NOISE_IMMUNITY_LEVEL = 0x2,
|
||||
ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION = 0x4,
|
||||
ATH9K_ANI_CCK_WEAK_SIGNAL_THR = 0x8,
|
||||
ATH9K_ANI_FIRSTEP_LEVEL = 0x10,
|
||||
ATH9K_ANI_SPUR_IMMUNITY_LEVEL = 0x20,
|
||||
ATH9K_ANI_MODE = 0x40,
|
||||
ATH9K_ANI_PHYERR_RESET = 0x80,
|
||||
ATH9K_ANI_ALL = 0xff
|
||||
};
|
||||
|
||||
struct ath9k_mib_stats {
|
||||
u32 ackrcv_bad;
|
||||
u32 rts_bad;
|
||||
u32 rts_good;
|
||||
u32 fcs_bad;
|
||||
u32 beacons;
|
||||
};
|
||||
|
||||
struct ath9k_node_stats {
|
||||
u32 ns_avgbrssi;
|
||||
u32 ns_avgrssi;
|
||||
u32 ns_avgtxrssi;
|
||||
u32 ns_avgtxrate;
|
||||
};
|
||||
|
||||
struct ar5416AniState {
|
||||
struct ath9k_channel *c;
|
||||
u8 noiseImmunityLevel;
|
||||
u8 spurImmunityLevel;
|
||||
u8 firstepLevel;
|
||||
u8 ofdmWeakSigDetectOff;
|
||||
u8 cckWeakSigThreshold;
|
||||
u32 listenTime;
|
||||
u32 ofdmTrigHigh;
|
||||
u32 ofdmTrigLow;
|
||||
int32_t cckTrigHigh;
|
||||
int32_t cckTrigLow;
|
||||
int32_t rssiThrLow;
|
||||
int32_t rssiThrHigh;
|
||||
u32 noiseFloor;
|
||||
u32 txFrameCount;
|
||||
u32 rxFrameCount;
|
||||
u32 cycleCount;
|
||||
u32 ofdmPhyErrCount;
|
||||
u32 cckPhyErrCount;
|
||||
u32 ofdmPhyErrBase;
|
||||
u32 cckPhyErrBase;
|
||||
int16_t pktRssi[2];
|
||||
int16_t ofdmErrRssi[2];
|
||||
int16_t cckErrRssi[2];
|
||||
};
|
||||
|
||||
struct ar5416Stats {
|
||||
u32 ast_ani_niup;
|
||||
u32 ast_ani_nidown;
|
||||
u32 ast_ani_spurup;
|
||||
u32 ast_ani_spurdown;
|
||||
u32 ast_ani_ofdmon;
|
||||
u32 ast_ani_ofdmoff;
|
||||
u32 ast_ani_cckhigh;
|
||||
u32 ast_ani_ccklow;
|
||||
u32 ast_ani_stepup;
|
||||
u32 ast_ani_stepdown;
|
||||
u32 ast_ani_ofdmerrs;
|
||||
u32 ast_ani_cckerrs;
|
||||
u32 ast_ani_reset;
|
||||
u32 ast_ani_lzero;
|
||||
u32 ast_ani_lneg;
|
||||
struct ath9k_mib_stats ast_mibstats;
|
||||
struct ath9k_node_stats ast_nodestats;
|
||||
};
|
||||
#define ah_mibStats stats.ast_mibstats
|
||||
|
||||
void ath9k_ani_reset(struct ath_hw *ah);
|
||||
void ath9k_hw_ani_monitor(struct ath_hw *ah,
|
||||
const struct ath9k_node_stats *stats,
|
||||
struct ath9k_channel *chan);
|
||||
bool ath9k_hw_phycounters(struct ath_hw *ah);
|
||||
void ath9k_enable_mib_counters(struct ath_hw *ah);
|
||||
void ath9k_hw_disable_mib_counters(struct ath_hw *ah);
|
||||
u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt,
|
||||
u32 *rxf_pcnt, u32 *txf_pcnt);
|
||||
void ath9k_hw_procmibevent(struct ath_hw *ah,
|
||||
const struct ath9k_node_stats *stats);
|
||||
void ath9k_hw_ani_setup(struct ath_hw *ah);
|
||||
void ath9k_hw_ani_attach(struct ath_hw *ah);
|
||||
void ath9k_hw_ani_detach(struct ath_hw *ah);
|
||||
|
||||
#endif /* ANI_H */
|
File diff suppressed because it is too large
Load Diff
@ -14,7 +14,7 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
#include "ath9k.h"
|
||||
|
||||
/*
|
||||
* This function will modify certain transmit queue properties depending on
|
||||
@ -23,11 +23,11 @@
|
||||
*/
|
||||
static int ath_beaconq_config(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath9k_tx_queue_info qi;
|
||||
|
||||
ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi);
|
||||
if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) {
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
|
||||
/* Always burst out beacon and CAB traffic. */
|
||||
qi.tqi_aifs = 1;
|
||||
qi.tqi_cwmin = 0;
|
||||
@ -63,10 +63,10 @@ static void ath_bstuck_process(struct ath_softc *sc)
|
||||
* Beacons are always sent out at the lowest rate, and are not retried.
|
||||
*/
|
||||
static void ath_beacon_setup(struct ath_softc *sc,
|
||||
struct ath_vap *avp, struct ath_buf *bf)
|
||||
struct ath_vif *avp, struct ath_buf *bf)
|
||||
{
|
||||
struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_desc *ds;
|
||||
struct ath9k_11n_rate_series series[4];
|
||||
struct ath_rate_table *rt;
|
||||
@ -82,8 +82,8 @@ static void ath_beacon_setup(struct ath_softc *sc,
|
||||
|
||||
flags = ATH9K_TXDESC_NOACK;
|
||||
|
||||
if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC &&
|
||||
(ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC &&
|
||||
(ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
|
||||
ds->ds_link = bf->bf_daddr; /* self-linked */
|
||||
flags |= ATH9K_TXDESC_VEOL;
|
||||
/* Let hardware handle antenna switching. */
|
||||
@ -96,7 +96,7 @@ static void ath_beacon_setup(struct ath_softc *sc,
|
||||
* SWBA's
|
||||
* XXX assumes two antenna
|
||||
*/
|
||||
antenna = ((sc->beacon.ast_be_xmit / sc->sc_nbcnvaps) & 1 ? 2 : 1);
|
||||
antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1);
|
||||
}
|
||||
|
||||
ds->ds_data = bf->bf_buf_addr;
|
||||
@ -132,24 +132,24 @@ static void ath_beacon_setup(struct ath_softc *sc,
|
||||
memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
|
||||
series[0].Tries = 1;
|
||||
series[0].Rate = rate;
|
||||
series[0].ChSel = sc->sc_tx_chainmask;
|
||||
series[0].ChSel = sc->tx_chainmask;
|
||||
series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0;
|
||||
ath9k_hw_set11n_ratescenario(ah, ds, ds, 0,
|
||||
ctsrate, ctsduration, series, 4, 0);
|
||||
}
|
||||
|
||||
/* Generate beacon frame and queue cab data for a vap */
|
||||
/* Generate beacon frame and queue cab data for a VIF */
|
||||
static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
|
||||
{
|
||||
struct ath_buf *bf;
|
||||
struct ath_vap *avp;
|
||||
struct ath_vif *avp;
|
||||
struct sk_buff *skb;
|
||||
struct ath_txq *cabq;
|
||||
struct ieee80211_vif *vif;
|
||||
struct ieee80211_tx_info *info;
|
||||
int cabq_depth;
|
||||
|
||||
vif = sc->sc_vaps[if_id];
|
||||
vif = sc->vifs[if_id];
|
||||
ASSERT(vif);
|
||||
|
||||
avp = (void *)vif->drv_priv;
|
||||
@ -204,10 +204,10 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
|
||||
/*
|
||||
* if the CABQ traffic from previous DTIM is pending and the current
|
||||
* beacon is also a DTIM.
|
||||
* 1) if there is only one vap let the cab traffic continue.
|
||||
* 2) if there are more than one vap and we are using staggered
|
||||
* 1) if there is only one vif let the cab traffic continue.
|
||||
* 2) if there are more than one vif and we are using staggered
|
||||
* beacons, then drain the cabq by dropping all the frames in
|
||||
* the cabq so that the current vaps cab traffic can be scheduled.
|
||||
* the cabq so that the current vifs cab traffic can be scheduled.
|
||||
*/
|
||||
spin_lock_bh(&cabq->axq_lock);
|
||||
cabq_depth = cabq->axq_depth;
|
||||
@ -219,7 +219,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
|
||||
* the lock again which is a common function and that
|
||||
* acquires txq lock inside.
|
||||
*/
|
||||
if (sc->sc_nvaps > 1) {
|
||||
if (sc->nvifs > 1) {
|
||||
ath_draintxq(sc, cabq, false);
|
||||
DPRINTF(sc, ATH_DBG_BEACON,
|
||||
"flush previous cabq traffic\n");
|
||||
@ -248,12 +248,12 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
|
||||
static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id)
|
||||
{
|
||||
struct ieee80211_vif *vif;
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_buf *bf;
|
||||
struct ath_vap *avp;
|
||||
struct ath_vif *avp;
|
||||
struct sk_buff *skb;
|
||||
|
||||
vif = sc->sc_vaps[if_id];
|
||||
vif = sc->vifs[if_id];
|
||||
ASSERT(vif);
|
||||
|
||||
avp = (void *)vif->drv_priv;
|
||||
@ -276,7 +276,7 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id)
|
||||
sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc);
|
||||
}
|
||||
|
||||
int ath_beaconq_setup(struct ath_hal *ah)
|
||||
int ath_beaconq_setup(struct ath_hw *ah)
|
||||
{
|
||||
struct ath9k_tx_queue_info qi;
|
||||
|
||||
@ -291,13 +291,13 @@ int ath_beaconq_setup(struct ath_hal *ah)
|
||||
int ath_beacon_alloc(struct ath_softc *sc, int if_id)
|
||||
{
|
||||
struct ieee80211_vif *vif;
|
||||
struct ath_vap *avp;
|
||||
struct ath_vif *avp;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct ath_buf *bf;
|
||||
struct sk_buff *skb;
|
||||
__le64 tstamp;
|
||||
|
||||
vif = sc->sc_vaps[if_id];
|
||||
vif = sc->vifs[if_id];
|
||||
ASSERT(vif);
|
||||
|
||||
avp = (void *)vif->drv_priv;
|
||||
@ -310,11 +310,11 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
|
||||
struct ath_buf, list);
|
||||
list_del(&avp->av_bcbuf->list);
|
||||
|
||||
if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP ||
|
||||
!(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP ||
|
||||
!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
|
||||
int slot;
|
||||
/*
|
||||
* Assign the vap to a beacon xmit slot. As
|
||||
* Assign the vif to a beacon xmit slot. As
|
||||
* above, this cannot fail to find one.
|
||||
*/
|
||||
avp->av_bslot = 0;
|
||||
@ -335,7 +335,7 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
|
||||
}
|
||||
BUG_ON(sc->beacon.bslot[avp->av_bslot] != ATH_IF_ID_ANY);
|
||||
sc->beacon.bslot[avp->av_bslot] = if_id;
|
||||
sc->sc_nbcnvaps++;
|
||||
sc->nbcnvifs++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -384,8 +384,8 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
|
||||
* timestamp then convert to TSF units and handle
|
||||
* byte swapping before writing it in the frame.
|
||||
* The hardware will then add this each time a beacon
|
||||
* frame is sent. Note that we align vap's 1..N
|
||||
* and leave vap 0 untouched. This means vap 0
|
||||
* frame is sent. Note that we align vif's 1..N
|
||||
* and leave vif 0 untouched. This means vap 0
|
||||
* has a timestamp in one beacon interval while the
|
||||
* others get a timestamp aligned to the next interval.
|
||||
*/
|
||||
@ -416,14 +416,14 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp)
|
||||
void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp)
|
||||
{
|
||||
if (avp->av_bcbuf != NULL) {
|
||||
struct ath_buf *bf;
|
||||
|
||||
if (avp->av_bslot != -1) {
|
||||
sc->beacon.bslot[avp->av_bslot] = ATH_IF_ID_ANY;
|
||||
sc->sc_nbcnvaps--;
|
||||
sc->nbcnvifs--;
|
||||
}
|
||||
|
||||
bf = avp->av_bcbuf;
|
||||
@ -444,7 +444,7 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp)
|
||||
void ath9k_beacon_tasklet(unsigned long data)
|
||||
{
|
||||
struct ath_softc *sc = (struct ath_softc *)data;
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_buf *bf = NULL;
|
||||
int slot, if_id;
|
||||
u32 bfaddr;
|
||||
@ -597,7 +597,7 @@ void ath9k_beacon_tasklet(unsigned long data)
|
||||
ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr);
|
||||
ath9k_hw_txstart(ah, sc->beacon.beaconq);
|
||||
|
||||
sc->beacon.ast_be_xmit += bc; /* XXX per-vap? */
|
||||
sc->beacon.ast_be_xmit += bc; /* XXX per-vif? */
|
||||
}
|
||||
}
|
||||
|
||||
@ -619,19 +619,19 @@ void ath9k_beacon_tasklet(unsigned long data)
|
||||
void ath_beacon_config(struct ath_softc *sc, int if_id)
|
||||
{
|
||||
struct ieee80211_vif *vif;
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_beacon_config conf;
|
||||
struct ath_vap *avp;
|
||||
struct ath_vif *avp;
|
||||
enum nl80211_iftype opmode;
|
||||
u32 nexttbtt, intval;
|
||||
|
||||
if (if_id != ATH_IF_ID_ANY) {
|
||||
vif = sc->sc_vaps[if_id];
|
||||
vif = sc->vifs[if_id];
|
||||
ASSERT(vif);
|
||||
avp = (void *)vif->drv_priv;
|
||||
opmode = avp->av_opmode;
|
||||
} else {
|
||||
opmode = sc->sc_ah->ah_opmode;
|
||||
opmode = sc->sc_ah->opmode;
|
||||
}
|
||||
|
||||
memset(&conf, 0, sizeof(struct ath_beacon_config));
|
||||
@ -647,7 +647,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
|
||||
nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp);
|
||||
|
||||
/* XXX conditionalize multi-bss support? */
|
||||
if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) {
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
|
||||
/*
|
||||
* For multi-bss ap support beacons are either staggered
|
||||
* evenly over N slots or burst together. For the former
|
||||
@ -670,7 +670,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
|
||||
nexttbtt, intval, conf.beacon_interval);
|
||||
|
||||
/* Check for NL80211_IFTYPE_AP and sc_nostabeacons for WDS client */
|
||||
if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) {
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
|
||||
struct ath9k_beacon_state bs;
|
||||
u64 tsf;
|
||||
u32 tsftu;
|
||||
@ -781,15 +781,15 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
|
||||
|
||||
ath9k_hw_set_interrupts(ah, 0);
|
||||
ath9k_hw_set_sta_beacon_timers(ah, &bs);
|
||||
sc->sc_imask |= ATH9K_INT_BMISS;
|
||||
ath9k_hw_set_interrupts(ah, sc->sc_imask);
|
||||
sc->imask |= ATH9K_INT_BMISS;
|
||||
ath9k_hw_set_interrupts(ah, sc->imask);
|
||||
} else {
|
||||
u64 tsf;
|
||||
u32 tsftu;
|
||||
ath9k_hw_set_interrupts(ah, 0);
|
||||
if (nexttbtt == intval)
|
||||
intval |= ATH9K_BEACON_RESET_TSF;
|
||||
if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) {
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) {
|
||||
/*
|
||||
* Pull nexttbtt forward to reflect the current
|
||||
* TSF
|
||||
@ -818,27 +818,27 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
|
||||
* deal with things.
|
||||
*/
|
||||
intval |= ATH9K_BEACON_ENA;
|
||||
if (!(ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL))
|
||||
sc->sc_imask |= ATH9K_INT_SWBA;
|
||||
if (!(ah->caps.hw_caps & ATH9K_HW_CAP_VEOL))
|
||||
sc->imask |= ATH9K_INT_SWBA;
|
||||
ath_beaconq_config(sc);
|
||||
} else if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) {
|
||||
} else if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
|
||||
/*
|
||||
* In AP mode we enable the beacon timers and
|
||||
* SWBA interrupts to prepare beacon frames.
|
||||
*/
|
||||
intval |= ATH9K_BEACON_ENA;
|
||||
sc->sc_imask |= ATH9K_INT_SWBA; /* beacon prepare */
|
||||
sc->imask |= ATH9K_INT_SWBA; /* beacon prepare */
|
||||
ath_beaconq_config(sc);
|
||||
}
|
||||
ath9k_hw_beaconinit(ah, nexttbtt, intval);
|
||||
sc->beacon.bmisscnt = 0;
|
||||
ath9k_hw_set_interrupts(ah, sc->sc_imask);
|
||||
ath9k_hw_set_interrupts(ah, sc->imask);
|
||||
/*
|
||||
* When using a self-linked beacon descriptor in
|
||||
* ibss mode load it once here.
|
||||
*/
|
||||
if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC &&
|
||||
(ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL))
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC &&
|
||||
(ah->caps.hw_caps & ATH9K_HW_CAP_VEOL))
|
||||
ath_beacon_start_adhoc(sc, 0);
|
||||
}
|
||||
}
|
||||
|
@ -14,10 +14,7 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
#include "hw.h"
|
||||
#include "reg.h"
|
||||
#include "phy.h"
|
||||
#include "ath9k.h"
|
||||
|
||||
/* We can tune this as we go by monitoring really low values */
|
||||
#define ATH9K_NF_TOO_LOW -60
|
||||
@ -26,7 +23,7 @@
|
||||
* is incorrect and we should use the static NF value. Later we can try to
|
||||
* find out why they are reporting these values */
|
||||
|
||||
static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf)
|
||||
static bool ath9k_hw_nf_in_range(struct ath_hw *ah, s16 nf)
|
||||
{
|
||||
if (nf > ATH9K_NF_TOO_LOW) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
|
||||
@ -89,7 +86,7 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
|
||||
return;
|
||||
}
|
||||
|
||||
static void ath9k_hw_do_getnf(struct ath_hal *ah,
|
||||
static void ath9k_hw_do_getnf(struct ath_hw *ah,
|
||||
int16_t nfarray[NUM_NF_READINGS])
|
||||
{
|
||||
int16_t nf;
|
||||
@ -169,16 +166,16 @@ static void ath9k_hw_do_getnf(struct ath_hal *ah,
|
||||
}
|
||||
}
|
||||
|
||||
static bool getNoiseFloorThresh(struct ath_hal *ah,
|
||||
static bool getNoiseFloorThresh(struct ath_hw *ah,
|
||||
enum ieee80211_band band,
|
||||
int16_t *nft)
|
||||
{
|
||||
switch (band) {
|
||||
case IEEE80211_BAND_5GHZ:
|
||||
*nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_5);
|
||||
*nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_5);
|
||||
break;
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
*nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2);
|
||||
*nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_2);
|
||||
break;
|
||||
default:
|
||||
BUG_ON(1);
|
||||
@ -188,7 +185,7 @@ static bool getNoiseFloorThresh(struct ath_hal *ah,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ath9k_hw_setup_calibration(struct ath_hal *ah,
|
||||
static void ath9k_hw_setup_calibration(struct ath_hw *ah,
|
||||
struct hal_cal_list *currCal)
|
||||
{
|
||||
REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
|
||||
@ -222,10 +219,9 @@ static void ath9k_hw_setup_calibration(struct ath_hal *ah,
|
||||
AR_PHY_TIMING_CTRL4_DO_CAL);
|
||||
}
|
||||
|
||||
static void ath9k_hw_reset_calibration(struct ath_hal *ah,
|
||||
static void ath9k_hw_reset_calibration(struct ath_hw *ah,
|
||||
struct hal_cal_list *currCal)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
int i;
|
||||
|
||||
ath9k_hw_setup_calibration(ah, currCal);
|
||||
@ -233,23 +229,21 @@ static void ath9k_hw_reset_calibration(struct ath_hal *ah,
|
||||
currCal->calState = CAL_RUNNING;
|
||||
|
||||
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
|
||||
ahp->ah_Meas0.sign[i] = 0;
|
||||
ahp->ah_Meas1.sign[i] = 0;
|
||||
ahp->ah_Meas2.sign[i] = 0;
|
||||
ahp->ah_Meas3.sign[i] = 0;
|
||||
ah->meas0.sign[i] = 0;
|
||||
ah->meas1.sign[i] = 0;
|
||||
ah->meas2.sign[i] = 0;
|
||||
ah->meas3.sign[i] = 0;
|
||||
}
|
||||
|
||||
ahp->ah_CalSamples = 0;
|
||||
ah->cal_samples = 0;
|
||||
}
|
||||
|
||||
static void ath9k_hw_per_calibration(struct ath_hal *ah,
|
||||
static void ath9k_hw_per_calibration(struct ath_hw *ah,
|
||||
struct ath9k_channel *ichan,
|
||||
u8 rxchainmask,
|
||||
struct hal_cal_list *currCal,
|
||||
bool *isCalDone)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
|
||||
*isCalDone = false;
|
||||
|
||||
if (currCal->calState == CAL_RUNNING) {
|
||||
@ -257,9 +251,9 @@ static void ath9k_hw_per_calibration(struct ath_hal *ah,
|
||||
AR_PHY_TIMING_CTRL4_DO_CAL)) {
|
||||
|
||||
currCal->calData->calCollect(ah);
|
||||
ahp->ah_CalSamples++;
|
||||
ah->cal_samples++;
|
||||
|
||||
if (ahp->ah_CalSamples >= currCal->calData->calNumSamples) {
|
||||
if (ah->cal_samples >= currCal->calData->calNumSamples) {
|
||||
int i, numChains = 0;
|
||||
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
|
||||
if (rxchainmask & (1 << i))
|
||||
@ -280,13 +274,12 @@ static void ath9k_hw_per_calibration(struct ath_hal *ah,
|
||||
}
|
||||
|
||||
/* Assumes you are talking about the currently configured channel */
|
||||
static bool ath9k_hw_iscal_supported(struct ath_hal *ah,
|
||||
static bool ath9k_hw_iscal_supported(struct ath_hw *ah,
|
||||
enum hal_cal_types calType)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
|
||||
|
||||
switch (calType & ahp->ah_suppCals) {
|
||||
switch (calType & ah->supp_cals) {
|
||||
case IQ_MISMATCH_CAL: /* Both 2 GHz and 5 GHz support OFDM */
|
||||
return true;
|
||||
case ADC_GAIN_CAL:
|
||||
@ -299,90 +292,86 @@ static bool ath9k_hw_iscal_supported(struct ath_hal *ah,
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ath9k_hw_iqcal_collect(struct ath_hal *ah)
|
||||
static void ath9k_hw_iqcal_collect(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
|
||||
ahp->ah_totalPowerMeasI[i] +=
|
||||
ah->totalPowerMeasI[i] +=
|
||||
REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
|
||||
ahp->ah_totalPowerMeasQ[i] +=
|
||||
ah->totalPowerMeasQ[i] +=
|
||||
REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
|
||||
ahp->ah_totalIqCorrMeas[i] +=
|
||||
ah->totalIqCorrMeas[i] +=
|
||||
(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
|
||||
"%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
|
||||
ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i],
|
||||
ahp->ah_totalPowerMeasQ[i],
|
||||
ahp->ah_totalIqCorrMeas[i]);
|
||||
ah->cal_samples, i, ah->totalPowerMeasI[i],
|
||||
ah->totalPowerMeasQ[i],
|
||||
ah->totalIqCorrMeas[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah)
|
||||
static void ath9k_hw_adc_gaincal_collect(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
|
||||
ahp->ah_totalAdcIOddPhase[i] +=
|
||||
ah->totalAdcIOddPhase[i] +=
|
||||
REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
|
||||
ahp->ah_totalAdcIEvenPhase[i] +=
|
||||
ah->totalAdcIEvenPhase[i] +=
|
||||
REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
|
||||
ahp->ah_totalAdcQOddPhase[i] +=
|
||||
ah->totalAdcQOddPhase[i] +=
|
||||
REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
|
||||
ahp->ah_totalAdcQEvenPhase[i] +=
|
||||
ah->totalAdcQEvenPhase[i] +=
|
||||
REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
|
||||
"%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
|
||||
"oddq=0x%08x; evenq=0x%08x;\n",
|
||||
ahp->ah_CalSamples, i,
|
||||
ahp->ah_totalAdcIOddPhase[i],
|
||||
ahp->ah_totalAdcIEvenPhase[i],
|
||||
ahp->ah_totalAdcQOddPhase[i],
|
||||
ahp->ah_totalAdcQEvenPhase[i]);
|
||||
ah->cal_samples, i,
|
||||
ah->totalAdcIOddPhase[i],
|
||||
ah->totalAdcIEvenPhase[i],
|
||||
ah->totalAdcQOddPhase[i],
|
||||
ah->totalAdcQEvenPhase[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah)
|
||||
static void ath9k_hw_adc_dccal_collect(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
|
||||
ahp->ah_totalAdcDcOffsetIOddPhase[i] +=
|
||||
ah->totalAdcDcOffsetIOddPhase[i] +=
|
||||
(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
|
||||
ahp->ah_totalAdcDcOffsetIEvenPhase[i] +=
|
||||
ah->totalAdcDcOffsetIEvenPhase[i] +=
|
||||
(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
|
||||
ahp->ah_totalAdcDcOffsetQOddPhase[i] +=
|
||||
ah->totalAdcDcOffsetQOddPhase[i] +=
|
||||
(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
|
||||
ahp->ah_totalAdcDcOffsetQEvenPhase[i] +=
|
||||
ah->totalAdcDcOffsetQEvenPhase[i] +=
|
||||
(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
|
||||
"%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
|
||||
"oddq=0x%08x; evenq=0x%08x;\n",
|
||||
ahp->ah_CalSamples, i,
|
||||
ahp->ah_totalAdcDcOffsetIOddPhase[i],
|
||||
ahp->ah_totalAdcDcOffsetIEvenPhase[i],
|
||||
ahp->ah_totalAdcDcOffsetQOddPhase[i],
|
||||
ahp->ah_totalAdcDcOffsetQEvenPhase[i]);
|
||||
ah->cal_samples, i,
|
||||
ah->totalAdcDcOffsetIOddPhase[i],
|
||||
ah->totalAdcDcOffsetIEvenPhase[i],
|
||||
ah->totalAdcDcOffsetQOddPhase[i],
|
||||
ah->totalAdcDcOffsetQEvenPhase[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains)
|
||||
static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
u32 powerMeasQ, powerMeasI, iqCorrMeas;
|
||||
u32 qCoffDenom, iCoffDenom;
|
||||
int32_t qCoff, iCoff;
|
||||
int iqCorrNeg, i;
|
||||
|
||||
for (i = 0; i < numChains; i++) {
|
||||
powerMeasI = ahp->ah_totalPowerMeasI[i];
|
||||
powerMeasQ = ahp->ah_totalPowerMeasQ[i];
|
||||
iqCorrMeas = ahp->ah_totalIqCorrMeas[i];
|
||||
powerMeasI = ah->totalPowerMeasI[i];
|
||||
powerMeasQ = ah->totalPowerMeasQ[i];
|
||||
iqCorrMeas = ah->totalIqCorrMeas[i];
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
|
||||
"Starting IQ Cal and Correction for Chain %d\n",
|
||||
@ -390,7 +379,7 @@ static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains)
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
|
||||
"Orignal: Chn %diq_corr_meas = 0x%08x\n",
|
||||
i, ahp->ah_totalIqCorrMeas[i]);
|
||||
i, ah->totalIqCorrMeas[i]);
|
||||
|
||||
iqCorrNeg = 0;
|
||||
|
||||
@ -448,17 +437,16 @@ static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains)
|
||||
AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
|
||||
}
|
||||
|
||||
static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains)
|
||||
static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset;
|
||||
u32 qGainMismatch, iGainMismatch, val, i;
|
||||
|
||||
for (i = 0; i < numChains; i++) {
|
||||
iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i];
|
||||
iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i];
|
||||
qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i];
|
||||
qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i];
|
||||
iOddMeasOffset = ah->totalAdcIOddPhase[i];
|
||||
iEvenMeasOffset = ah->totalAdcIEvenPhase[i];
|
||||
qOddMeasOffset = ah->totalAdcQOddPhase[i];
|
||||
qEvenMeasOffset = ah->totalAdcQEvenPhase[i];
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
|
||||
"Starting ADC Gain Cal for Chain %d\n", i);
|
||||
@ -506,21 +494,20 @@ static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains)
|
||||
AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
|
||||
}
|
||||
|
||||
static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains)
|
||||
static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
u32 iOddMeasOffset, iEvenMeasOffset, val, i;
|
||||
int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
|
||||
const struct hal_percal_data *calData =
|
||||
ahp->ah_cal_list_curr->calData;
|
||||
ah->cal_list_curr->calData;
|
||||
u32 numSamples =
|
||||
(1 << (calData->calCountMax + 5)) * calData->calNumSamples;
|
||||
|
||||
for (i = 0; i < numChains; i++) {
|
||||
iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i];
|
||||
iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i];
|
||||
qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i];
|
||||
qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i];
|
||||
iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i];
|
||||
iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i];
|
||||
qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i];
|
||||
qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i];
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
|
||||
"Starting ADC DC Offset Cal for Chain %d\n", i);
|
||||
@ -565,13 +552,12 @@ static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains)
|
||||
}
|
||||
|
||||
/* This is done for the currently configured channel */
|
||||
bool ath9k_hw_reset_calvalid(struct ath_hal *ah)
|
||||
bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
|
||||
struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
|
||||
struct hal_cal_list *currCal = ah->cal_list_curr;
|
||||
|
||||
if (!ah->ah_curchan)
|
||||
if (!ah->curchan)
|
||||
return true;
|
||||
|
||||
if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
|
||||
@ -594,13 +580,13 @@ bool ath9k_hw_reset_calvalid(struct ath_hal *ah)
|
||||
"Resetting Cal %d state for channel %u\n",
|
||||
currCal->calData->calType, conf->channel->center_freq);
|
||||
|
||||
ah->ah_curchan->CalValid &= ~currCal->calData->calType;
|
||||
ah->curchan->CalValid &= ~currCal->calData->calType;
|
||||
currCal->calState = CAL_WAITING;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ath9k_hw_start_nfcal(struct ath_hal *ah)
|
||||
void ath9k_hw_start_nfcal(struct ath_hw *ah)
|
||||
{
|
||||
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
|
||||
AR_PHY_AGC_CONTROL_ENABLE_NF);
|
||||
@ -609,7 +595,7 @@ void ath9k_hw_start_nfcal(struct ath_hal *ah)
|
||||
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
|
||||
}
|
||||
|
||||
void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan)
|
||||
void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||
{
|
||||
struct ath9k_nfcal_hist *h;
|
||||
int i, j;
|
||||
@ -665,7 +651,7 @@ void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan)
|
||||
}
|
||||
}
|
||||
|
||||
int16_t ath9k_hw_getnf(struct ath_hal *ah,
|
||||
int16_t ath9k_hw_getnf(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan)
|
||||
{
|
||||
int16_t nf, nfThresh;
|
||||
@ -701,7 +687,7 @@ int16_t ath9k_hw_getnf(struct ath_hal *ah,
|
||||
return chan->rawNoiseFloor;
|
||||
}
|
||||
|
||||
void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah)
|
||||
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
@ -715,10 +701,9 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah)
|
||||
AR_PHY_CCA_MAX_GOOD_VALUE;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan)
|
||||
s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||
{
|
||||
s16 nf;
|
||||
|
||||
@ -733,12 +718,11 @@ s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan)
|
||||
return nf;
|
||||
}
|
||||
|
||||
bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
|
||||
bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||
u8 rxchainmask, bool longcal,
|
||||
bool *isCalDone)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
|
||||
struct hal_cal_list *currCal = ah->cal_list_curr;
|
||||
|
||||
*isCalDone = true;
|
||||
|
||||
@ -748,7 +732,7 @@ bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
|
||||
ath9k_hw_per_calibration(ah, chan, rxchainmask, currCal,
|
||||
isCalDone);
|
||||
if (*isCalDone) {
|
||||
ahp->ah_cal_list_curr = currCal = currCal->calNext;
|
||||
ah->cal_list_curr = currCal = currCal->calNext;
|
||||
|
||||
if (currCal->calState == CAL_WAITING) {
|
||||
*isCalDone = false;
|
||||
@ -759,7 +743,7 @@ bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
|
||||
|
||||
if (longcal) {
|
||||
ath9k_hw_getnf(ah, chan);
|
||||
ath9k_hw_loadnf(ah, ah->ah_curchan);
|
||||
ath9k_hw_loadnf(ah, ah->curchan);
|
||||
ath9k_hw_start_nfcal(ah);
|
||||
|
||||
if (chan->channelFlags & CHANNEL_CW_INT)
|
||||
@ -769,7 +753,7 @@ bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void ath9k_hw_9285_pa_cal(struct ath_hal *ah)
|
||||
static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
|
||||
{
|
||||
|
||||
u32 regVal;
|
||||
@ -864,11 +848,9 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hal *ah)
|
||||
|
||||
}
|
||||
|
||||
bool ath9k_hw_init_cal(struct ath_hal *ah,
|
||||
bool ath9k_hw_init_cal(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
|
||||
REG_WRITE(ah, AR_PHY_AGC_CONTROL,
|
||||
REG_READ(ah, AR_PHY_AGC_CONTROL) |
|
||||
AR_PHY_AGC_CONTROL_CAL);
|
||||
@ -887,32 +869,32 @@ bool ath9k_hw_init_cal(struct ath_hal *ah,
|
||||
REG_READ(ah, AR_PHY_AGC_CONTROL) |
|
||||
AR_PHY_AGC_CONTROL_NF);
|
||||
|
||||
ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL;
|
||||
ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
|
||||
|
||||
if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
|
||||
if (ath9k_hw_iscal_supported(ah, ADC_GAIN_CAL)) {
|
||||
INIT_CAL(&ahp->ah_adcGainCalData);
|
||||
INSERT_CAL(ahp, &ahp->ah_adcGainCalData);
|
||||
INIT_CAL(&ah->adcgain_caldata);
|
||||
INSERT_CAL(ah, &ah->adcgain_caldata);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
|
||||
"enabling ADC Gain Calibration.\n");
|
||||
}
|
||||
if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) {
|
||||
INIT_CAL(&ahp->ah_adcDcCalData);
|
||||
INSERT_CAL(ahp, &ahp->ah_adcDcCalData);
|
||||
INIT_CAL(&ah->adcdc_caldata);
|
||||
INSERT_CAL(ah, &ah->adcdc_caldata);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
|
||||
"enabling ADC DC Calibration.\n");
|
||||
}
|
||||
if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) {
|
||||
INIT_CAL(&ahp->ah_iqCalData);
|
||||
INSERT_CAL(ahp, &ahp->ah_iqCalData);
|
||||
INIT_CAL(&ah->iq_caldata);
|
||||
INSERT_CAL(ah, &ah->iq_caldata);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
|
||||
"enabling IQ Calibration.\n");
|
||||
}
|
||||
|
||||
ahp->ah_cal_list_curr = ahp->ah_cal_list;
|
||||
ah->cal_list_curr = ah->cal_list;
|
||||
|
||||
if (ahp->ah_cal_list_curr)
|
||||
ath9k_hw_reset_calibration(ah, ahp->ah_cal_list_curr);
|
||||
if (ah->cal_list_curr)
|
||||
ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
|
||||
}
|
||||
|
||||
chan->CalValid = 0;
|
||||
|
124
drivers/net/wireless/ath9k/calib.h
Normal file
124
drivers/net/wireless/ath9k/calib.h
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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 CALIB_H
|
||||
#define CALIB_H
|
||||
|
||||
extern const struct hal_percal_data iq_cal_multi_sample;
|
||||
extern const struct hal_percal_data iq_cal_single_sample;
|
||||
extern const struct hal_percal_data adc_gain_cal_multi_sample;
|
||||
extern const struct hal_percal_data adc_gain_cal_single_sample;
|
||||
extern const struct hal_percal_data adc_dc_cal_multi_sample;
|
||||
extern const struct hal_percal_data adc_dc_cal_single_sample;
|
||||
extern const struct hal_percal_data adc_init_dc_cal;
|
||||
|
||||
#define AR_PHY_CCA_MAX_GOOD_VALUE -85
|
||||
#define AR_PHY_CCA_MAX_HIGH_VALUE -62
|
||||
#define AR_PHY_CCA_MIN_BAD_VALUE -121
|
||||
#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3
|
||||
#define AR_PHY_CCA_FILTERWINDOW_LENGTH 5
|
||||
|
||||
#define NUM_NF_READINGS 6
|
||||
#define ATH9K_NF_CAL_HIST_MAX 5
|
||||
|
||||
struct ar5416IniArray {
|
||||
u32 *ia_array;
|
||||
u32 ia_rows;
|
||||
u32 ia_columns;
|
||||
};
|
||||
|
||||
#define INIT_INI_ARRAY(iniarray, array, rows, columns) do { \
|
||||
(iniarray)->ia_array = (u32 *)(array); \
|
||||
(iniarray)->ia_rows = (rows); \
|
||||
(iniarray)->ia_columns = (columns); \
|
||||
} while (0)
|
||||
|
||||
#define INI_RA(iniarray, row, column) \
|
||||
(((iniarray)->ia_array)[(row) * ((iniarray)->ia_columns) + (column)])
|
||||
|
||||
#define INIT_CAL(_perCal) do { \
|
||||
(_perCal)->calState = CAL_WAITING; \
|
||||
(_perCal)->calNext = NULL; \
|
||||
} while (0)
|
||||
|
||||
#define INSERT_CAL(_ahp, _perCal) \
|
||||
do { \
|
||||
if ((_ahp)->cal_list_last == NULL) { \
|
||||
(_ahp)->cal_list = \
|
||||
(_ahp)->cal_list_last = (_perCal); \
|
||||
((_ahp)->cal_list_last)->calNext = (_perCal); \
|
||||
} else { \
|
||||
((_ahp)->cal_list_last)->calNext = (_perCal); \
|
||||
(_ahp)->cal_list_last = (_perCal); \
|
||||
(_perCal)->calNext = (_ahp)->cal_list; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
enum hal_cal_types {
|
||||
ADC_DC_INIT_CAL = 0x1,
|
||||
ADC_GAIN_CAL = 0x2,
|
||||
ADC_DC_CAL = 0x4,
|
||||
IQ_MISMATCH_CAL = 0x8
|
||||
};
|
||||
|
||||
enum hal_cal_state {
|
||||
CAL_INACTIVE,
|
||||
CAL_WAITING,
|
||||
CAL_RUNNING,
|
||||
CAL_DONE
|
||||
};
|
||||
|
||||
#define MIN_CAL_SAMPLES 1
|
||||
#define MAX_CAL_SAMPLES 64
|
||||
#define INIT_LOG_COUNT 5
|
||||
#define PER_MIN_LOG_COUNT 2
|
||||
#define PER_MAX_LOG_COUNT 10
|
||||
|
||||
struct hal_percal_data {
|
||||
enum hal_cal_types calType;
|
||||
u32 calNumSamples;
|
||||
u32 calCountMax;
|
||||
void (*calCollect) (struct ath_hw *);
|
||||
void (*calPostProc) (struct ath_hw *, u8);
|
||||
};
|
||||
|
||||
struct hal_cal_list {
|
||||
const struct hal_percal_data *calData;
|
||||
enum hal_cal_state calState;
|
||||
struct hal_cal_list *calNext;
|
||||
};
|
||||
|
||||
struct ath9k_nfcal_hist {
|
||||
int16_t nfCalBuffer[ATH9K_NF_CAL_HIST_MAX];
|
||||
u8 currIndex;
|
||||
int16_t privNF;
|
||||
u8 invalidNFcount;
|
||||
};
|
||||
|
||||
bool ath9k_hw_reset_calvalid(struct ath_hw *ah);
|
||||
void ath9k_hw_start_nfcal(struct ath_hw *ah);
|
||||
void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
|
||||
int16_t ath9k_hw_getnf(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan);
|
||||
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah);
|
||||
s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan);
|
||||
bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||
u8 rxchainmask, bool longcal,
|
||||
bool *isCalDone);
|
||||
bool ath9k_hw_init_cal(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan);
|
||||
|
||||
#endif /* CALIB_H */
|
@ -1,816 +0,0 @@
|
||||
/*
|
||||
* 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 CORE_H
|
||||
#define CORE_H
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/device.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/rfkill.h>
|
||||
|
||||
#include "ath9k.h"
|
||||
#include "rc.h"
|
||||
|
||||
struct ath_node;
|
||||
|
||||
/* Macro to expand scalars to 64-bit objects */
|
||||
|
||||
#define ito64(x) (sizeof(x) == 8) ? \
|
||||
(((unsigned long long int)(x)) & (0xff)) : \
|
||||
(sizeof(x) == 16) ? \
|
||||
(((unsigned long long int)(x)) & 0xffff) : \
|
||||
((sizeof(x) == 32) ? \
|
||||
(((unsigned long long int)(x)) & 0xffffffff) : \
|
||||
(unsigned long long int)(x))
|
||||
|
||||
/* increment with wrap-around */
|
||||
#define INCR(_l, _sz) do { \
|
||||
(_l)++; \
|
||||
(_l) &= ((_sz) - 1); \
|
||||
} while (0)
|
||||
|
||||
/* decrement with wrap-around */
|
||||
#define DECR(_l, _sz) do { \
|
||||
(_l)--; \
|
||||
(_l) &= ((_sz) - 1); \
|
||||
} while (0)
|
||||
|
||||
#define A_MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
#define ASSERT(exp) do { \
|
||||
if (unlikely(!(exp))) { \
|
||||
BUG(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TSF_TO_TU(_h,_l) \
|
||||
((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
|
||||
|
||||
#define ATH_TXQ_SETUP(sc, i) ((sc)->tx.txqsetup & (1<<i))
|
||||
|
||||
static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
|
||||
enum ATH_DEBUG {
|
||||
ATH_DBG_RESET = 0x00000001,
|
||||
ATH_DBG_REG_IO = 0x00000002,
|
||||
ATH_DBG_QUEUE = 0x00000004,
|
||||
ATH_DBG_EEPROM = 0x00000008,
|
||||
ATH_DBG_CALIBRATE = 0x00000010,
|
||||
ATH_DBG_CHANNEL = 0x00000020,
|
||||
ATH_DBG_INTERRUPT = 0x00000040,
|
||||
ATH_DBG_REGULATORY = 0x00000080,
|
||||
ATH_DBG_ANI = 0x00000100,
|
||||
ATH_DBG_POWER_MGMT = 0x00000200,
|
||||
ATH_DBG_XMIT = 0x00000400,
|
||||
ATH_DBG_BEACON = 0x00001000,
|
||||
ATH_DBG_CONFIG = 0x00002000,
|
||||
ATH_DBG_KEYCACHE = 0x00004000,
|
||||
ATH_DBG_FATAL = 0x00008000,
|
||||
ATH_DBG_ANY = 0xffffffff
|
||||
};
|
||||
|
||||
#define DBG_DEFAULT (ATH_DBG_FATAL)
|
||||
|
||||
#ifdef CONFIG_ATH9K_DEBUG
|
||||
|
||||
/**
|
||||
* struct ath_interrupt_stats - Contains statistics about interrupts
|
||||
* @total: Total no. of interrupts generated so far
|
||||
* @rxok: RX with no errors
|
||||
* @rxeol: RX with no more RXDESC available
|
||||
* @rxorn: RX FIFO overrun
|
||||
* @txok: TX completed at the requested rate
|
||||
* @txurn: TX FIFO underrun
|
||||
* @mib: MIB regs reaching its threshold
|
||||
* @rxphyerr: RX with phy errors
|
||||
* @rx_keycache_miss: RX with key cache misses
|
||||
* @swba: Software Beacon Alert
|
||||
* @bmiss: Beacon Miss
|
||||
* @bnr: Beacon Not Ready
|
||||
* @cst: Carrier Sense TImeout
|
||||
* @gtt: Global TX Timeout
|
||||
* @tim: RX beacon TIM occurrence
|
||||
* @cabend: RX End of CAB traffic
|
||||
* @dtimsync: DTIM sync lossage
|
||||
* @dtim: RX Beacon with DTIM
|
||||
*/
|
||||
struct ath_interrupt_stats {
|
||||
u32 total;
|
||||
u32 rxok;
|
||||
u32 rxeol;
|
||||
u32 rxorn;
|
||||
u32 txok;
|
||||
u32 txeol;
|
||||
u32 txurn;
|
||||
u32 mib;
|
||||
u32 rxphyerr;
|
||||
u32 rx_keycache_miss;
|
||||
u32 swba;
|
||||
u32 bmiss;
|
||||
u32 bnr;
|
||||
u32 cst;
|
||||
u32 gtt;
|
||||
u32 tim;
|
||||
u32 cabend;
|
||||
u32 dtimsync;
|
||||
u32 dtim;
|
||||
};
|
||||
|
||||
struct ath_legacy_rc_stats {
|
||||
u32 success;
|
||||
};
|
||||
|
||||
struct ath_11n_rc_stats {
|
||||
u32 success;
|
||||
};
|
||||
|
||||
struct ath_stats {
|
||||
struct ath_interrupt_stats istats;
|
||||
struct ath_legacy_rc_stats legacy_rcstats[12]; /* max(11a,11b,11g) */
|
||||
struct ath_11n_rc_stats n_rcstats[16]; /* 0..15 MCS rates */
|
||||
};
|
||||
|
||||
struct ath9k_debug {
|
||||
int debug_mask;
|
||||
struct dentry *debugfs_root;
|
||||
struct dentry *debugfs_phy;
|
||||
struct dentry *debugfs_dma;
|
||||
struct dentry *debugfs_interrupt;
|
||||
struct dentry *debugfs_rcstat;
|
||||
struct ath_stats stats;
|
||||
};
|
||||
|
||||
void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...);
|
||||
int ath9k_init_debug(struct ath_softc *sc);
|
||||
void ath9k_exit_debug(struct ath_softc *sc);
|
||||
void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
|
||||
void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb);
|
||||
|
||||
#else
|
||||
|
||||
static inline void DPRINTF(struct ath_softc *sc, int dbg_mask,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int ath9k_init_debug(struct ath_softc *sc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ath9k_exit_debug(struct ath_softc *sc)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath_debug_stat_interrupt(struct ath_softc *sc,
|
||||
enum ath9k_int status)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath_debug_stat_rc(struct ath_softc *sc,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ATH9K_DEBUG */
|
||||
|
||||
struct ath_config {
|
||||
u32 ath_aggr_prot;
|
||||
u16 txpowlimit;
|
||||
u16 txpowlimit_override;
|
||||
u8 cabqReadytime;
|
||||
u8 swBeaconProcess;
|
||||
};
|
||||
|
||||
/*************************/
|
||||
/* Descriptor Management */
|
||||
/*************************/
|
||||
|
||||
#define ATH_TXBUF_RESET(_bf) do { \
|
||||
(_bf)->bf_status = 0; \
|
||||
(_bf)->bf_lastbf = NULL; \
|
||||
(_bf)->bf_next = NULL; \
|
||||
memset(&((_bf)->bf_state), 0, \
|
||||
sizeof(struct ath_buf_state)); \
|
||||
} while (0)
|
||||
|
||||
enum buffer_type {
|
||||
BUF_DATA = BIT(0),
|
||||
BUF_AGGR = BIT(1),
|
||||
BUF_AMPDU = BIT(2),
|
||||
BUF_HT = BIT(3),
|
||||
BUF_RETRY = BIT(4),
|
||||
BUF_XRETRY = BIT(5),
|
||||
BUF_SHORT_PREAMBLE = BIT(6),
|
||||
BUF_BAR = BIT(7),
|
||||
BUF_PSPOLL = BIT(8),
|
||||
BUF_AGGR_BURST = BIT(9),
|
||||
BUF_CALC_AIRTIME = BIT(10),
|
||||
};
|
||||
|
||||
struct ath_buf_state {
|
||||
int bfs_nframes; /* # frames in aggregate */
|
||||
u16 bfs_al; /* length of aggregate */
|
||||
u16 bfs_frmlen; /* length of frame */
|
||||
int bfs_seqno; /* sequence number */
|
||||
int bfs_tidno; /* tid of this frame */
|
||||
int bfs_retries; /* current retries */
|
||||
u32 bf_type; /* BUF_* (enum buffer_type) */
|
||||
u32 bfs_keyix;
|
||||
enum ath9k_key_type bfs_keytype;
|
||||
};
|
||||
|
||||
#define bf_nframes bf_state.bfs_nframes
|
||||
#define bf_al bf_state.bfs_al
|
||||
#define bf_frmlen bf_state.bfs_frmlen
|
||||
#define bf_retries bf_state.bfs_retries
|
||||
#define bf_seqno bf_state.bfs_seqno
|
||||
#define bf_tidno bf_state.bfs_tidno
|
||||
#define bf_rcs bf_state.bfs_rcs
|
||||
#define bf_keyix bf_state.bfs_keyix
|
||||
#define bf_keytype bf_state.bfs_keytype
|
||||
#define bf_isdata(bf) (bf->bf_state.bf_type & BUF_DATA)
|
||||
#define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR)
|
||||
#define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU)
|
||||
#define bf_isht(bf) (bf->bf_state.bf_type & BUF_HT)
|
||||
#define bf_isretried(bf) (bf->bf_state.bf_type & BUF_RETRY)
|
||||
#define bf_isxretried(bf) (bf->bf_state.bf_type & BUF_XRETRY)
|
||||
#define bf_isbar(bf) (bf->bf_state.bf_type & BUF_BAR)
|
||||
#define bf_ispspoll(bf) (bf->bf_state.bf_type & BUF_PSPOLL)
|
||||
#define bf_isaggrburst(bf) (bf->bf_state.bf_type & BUF_AGGR_BURST)
|
||||
|
||||
/*
|
||||
* Abstraction of a contiguous buffer to transmit/receive. There is only
|
||||
* a single hw descriptor encapsulated here.
|
||||
*/
|
||||
struct ath_buf {
|
||||
struct list_head list;
|
||||
struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or
|
||||
an aggregate) */
|
||||
struct ath_buf *bf_next; /* next subframe in the aggregate */
|
||||
void *bf_mpdu; /* enclosing frame structure */
|
||||
struct ath_desc *bf_desc; /* virtual addr of desc */
|
||||
dma_addr_t bf_daddr; /* physical addr of desc */
|
||||
dma_addr_t bf_buf_addr; /* physical addr of data buffer */
|
||||
u32 bf_status;
|
||||
u16 bf_flags; /* tx descriptor flags */
|
||||
struct ath_buf_state bf_state; /* buffer state */
|
||||
dma_addr_t bf_dmacontext;
|
||||
};
|
||||
|
||||
#define ATH_RXBUF_RESET(_bf) ((_bf)->bf_status = 0)
|
||||
#define ATH_BUFSTATUS_STALE 0x00000002
|
||||
|
||||
/* DMA state for tx/rx descriptors */
|
||||
|
||||
struct ath_descdma {
|
||||
const char *dd_name;
|
||||
struct ath_desc *dd_desc; /* descriptors */
|
||||
dma_addr_t dd_desc_paddr; /* physical addr of dd_desc */
|
||||
u32 dd_desc_len; /* size of dd_desc */
|
||||
struct ath_buf *dd_bufptr; /* associated buffers */
|
||||
dma_addr_t dd_dmacontext;
|
||||
};
|
||||
|
||||
int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
|
||||
struct list_head *head, const char *name,
|
||||
int nbuf, int ndesc);
|
||||
void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
|
||||
struct list_head *head);
|
||||
|
||||
/***********/
|
||||
/* RX / TX */
|
||||
/***********/
|
||||
|
||||
#define ATH_MAX_ANTENNA 3
|
||||
#define ATH_RXBUF 512
|
||||
#define WME_NUM_TID 16
|
||||
#define ATH_TXBUF 512
|
||||
#define ATH_TXMAXTRY 13
|
||||
#define ATH_11N_TXMAXTRY 10
|
||||
#define ATH_MGT_TXMAXTRY 4
|
||||
#define WME_BA_BMP_SIZE 64
|
||||
#define WME_MAX_BA WME_BA_BMP_SIZE
|
||||
#define ATH_TID_MAX_BUFS (2 * WME_MAX_BA)
|
||||
|
||||
#define TID_TO_WME_AC(_tid) \
|
||||
((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \
|
||||
(((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \
|
||||
(((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \
|
||||
WME_AC_VO)
|
||||
|
||||
#define WME_AC_BE 0
|
||||
#define WME_AC_BK 1
|
||||
#define WME_AC_VI 2
|
||||
#define WME_AC_VO 3
|
||||
#define WME_NUM_AC 4
|
||||
|
||||
#define ADDBA_EXCHANGE_ATTEMPTS 10
|
||||
#define ATH_AGGR_DELIM_SZ 4
|
||||
#define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */
|
||||
/* number of delimiters for encryption padding */
|
||||
#define ATH_AGGR_ENCRYPTDELIM 10
|
||||
/* minimum h/w qdepth to be sustained to maximize aggregation */
|
||||
#define ATH_AGGR_MIN_QDEPTH 2
|
||||
#define ATH_AMPDU_SUBFRAME_DEFAULT 32
|
||||
#define IEEE80211_SEQ_SEQ_SHIFT 4
|
||||
#define IEEE80211_SEQ_MAX 4096
|
||||
#define IEEE80211_MIN_AMPDU_BUF 0x8
|
||||
#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13
|
||||
|
||||
/* return whether a bit at index _n in bitmap _bm is set
|
||||
* _sz is the size of the bitmap */
|
||||
#define ATH_BA_ISSET(_bm, _n) (((_n) < (WME_BA_BMP_SIZE)) && \
|
||||
((_bm)[(_n) >> 5] & (1 << ((_n) & 31))))
|
||||
|
||||
/* return block-ack bitmap index given sequence and starting sequence */
|
||||
#define ATH_BA_INDEX(_st, _seq) (((_seq) - (_st)) & (IEEE80211_SEQ_MAX - 1))
|
||||
|
||||
/* returns delimiter padding required given the packet length */
|
||||
#define ATH_AGGR_GET_NDELIM(_len) \
|
||||
(((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ? \
|
||||
(ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2)
|
||||
|
||||
#define BAW_WITHIN(_start, _bawsz, _seqno) \
|
||||
((((_seqno) - (_start)) & 4095) < (_bawsz))
|
||||
|
||||
#define ATH_DS_BA_SEQ(_ds) ((_ds)->ds_us.tx.ts_seqnum)
|
||||
#define ATH_DS_BA_BITMAP(_ds) (&(_ds)->ds_us.tx.ba_low)
|
||||
#define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA)
|
||||
#define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)])
|
||||
|
||||
enum ATH_AGGR_STATUS {
|
||||
ATH_AGGR_DONE,
|
||||
ATH_AGGR_BAW_CLOSED,
|
||||
ATH_AGGR_LIMITED,
|
||||
ATH_AGGR_SHORTPKT,
|
||||
ATH_AGGR_8K_LIMITED,
|
||||
};
|
||||
|
||||
struct ath_txq {
|
||||
u32 axq_qnum; /* hardware q number */
|
||||
u32 *axq_link; /* link ptr in last TX desc */
|
||||
struct list_head axq_q; /* transmit queue */
|
||||
spinlock_t axq_lock;
|
||||
u32 axq_depth; /* queue depth */
|
||||
u8 axq_aggr_depth; /* aggregates queued */
|
||||
u32 axq_totalqueued; /* total ever queued */
|
||||
bool stopped; /* Is mac80211 queue stopped ? */
|
||||
struct ath_buf *axq_linkbuf; /* virtual addr of last buffer*/
|
||||
|
||||
/* first desc of the last descriptor that contains CTS */
|
||||
struct ath_desc *axq_lastdsWithCTS;
|
||||
|
||||
/* final desc of the gating desc that determines whether
|
||||
lastdsWithCTS has been DMA'ed or not */
|
||||
struct ath_desc *axq_gatingds;
|
||||
|
||||
struct list_head axq_acq;
|
||||
};
|
||||
|
||||
#define AGGR_CLEANUP BIT(1)
|
||||
#define AGGR_ADDBA_COMPLETE BIT(2)
|
||||
#define AGGR_ADDBA_PROGRESS BIT(3)
|
||||
|
||||
/* per TID aggregate tx state for a destination */
|
||||
struct ath_atx_tid {
|
||||
struct list_head list; /* round-robin tid entry */
|
||||
struct list_head buf_q; /* pending buffers */
|
||||
struct ath_node *an;
|
||||
struct ath_atx_ac *ac;
|
||||
struct ath_buf *tx_buf[ATH_TID_MAX_BUFS]; /* active tx frames */
|
||||
u16 seq_start;
|
||||
u16 seq_next;
|
||||
u16 baw_size;
|
||||
int tidno;
|
||||
int baw_head; /* first un-acked tx buffer */
|
||||
int baw_tail; /* next unused tx buffer slot */
|
||||
int sched;
|
||||
int paused;
|
||||
u8 state;
|
||||
int addba_exchangeattempts;
|
||||
};
|
||||
|
||||
/* per access-category aggregate tx state for a destination */
|
||||
struct ath_atx_ac {
|
||||
int sched; /* dest-ac is scheduled */
|
||||
int qnum; /* H/W queue number associated
|
||||
with this AC */
|
||||
struct list_head list; /* round-robin txq entry */
|
||||
struct list_head tid_q; /* queue of TIDs with buffers */
|
||||
};
|
||||
|
||||
/* per-frame tx control block */
|
||||
struct ath_tx_control {
|
||||
struct ath_txq *txq;
|
||||
int if_id;
|
||||
};
|
||||
|
||||
/* per frame tx status block */
|
||||
struct ath_xmit_status {
|
||||
int retries; /* number of retries to successufully
|
||||
transmit this frame */
|
||||
int flags; /* status of transmit */
|
||||
#define ATH_TX_ERROR 0x01
|
||||
#define ATH_TX_XRETRY 0x02
|
||||
#define ATH_TX_BAR 0x04
|
||||
};
|
||||
|
||||
/* All RSSI values are noise floor adjusted */
|
||||
struct ath_tx_stat {
|
||||
int rssi;
|
||||
int rssictl[ATH_MAX_ANTENNA];
|
||||
int rssiextn[ATH_MAX_ANTENNA];
|
||||
int rateieee;
|
||||
int rateKbps;
|
||||
int ratecode;
|
||||
int flags;
|
||||
u32 airtime; /* time on air per final tx rate */
|
||||
};
|
||||
|
||||
struct aggr_rifs_param {
|
||||
int param_max_frames;
|
||||
int param_max_len;
|
||||
int param_rl;
|
||||
int param_al;
|
||||
struct ath_rc_series *param_rcs;
|
||||
};
|
||||
|
||||
struct ath_node {
|
||||
struct ath_softc *an_sc;
|
||||
struct ath_atx_tid tid[WME_NUM_TID];
|
||||
struct ath_atx_ac ac[WME_NUM_AC];
|
||||
u16 maxampdu;
|
||||
u8 mpdudensity;
|
||||
};
|
||||
|
||||
struct ath_tx {
|
||||
u16 seq_no;
|
||||
u32 txqsetup;
|
||||
int hwq_map[ATH9K_WME_AC_VO+1];
|
||||
spinlock_t txbuflock;
|
||||
struct list_head txbuf;
|
||||
struct ath_txq txq[ATH9K_NUM_TX_QUEUES];
|
||||
struct ath_descdma txdma;
|
||||
};
|
||||
|
||||
struct ath_rx {
|
||||
u8 defant;
|
||||
u8 rxotherant;
|
||||
u32 *rxlink;
|
||||
int bufsize;
|
||||
unsigned int rxfilter;
|
||||
spinlock_t rxflushlock;
|
||||
spinlock_t rxbuflock;
|
||||
struct list_head rxbuf;
|
||||
struct ath_descdma rxdma;
|
||||
};
|
||||
|
||||
int ath_startrecv(struct ath_softc *sc);
|
||||
bool ath_stoprecv(struct ath_softc *sc);
|
||||
void ath_flushrecv(struct ath_softc *sc);
|
||||
u32 ath_calcrxfilter(struct ath_softc *sc);
|
||||
int ath_rx_init(struct ath_softc *sc, int nbufs);
|
||||
void ath_rx_cleanup(struct ath_softc *sc);
|
||||
int ath_rx_tasklet(struct ath_softc *sc, int flush);
|
||||
struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype);
|
||||
void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
|
||||
int ath_tx_setup(struct ath_softc *sc, int haltype);
|
||||
void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx);
|
||||
void ath_draintxq(struct ath_softc *sc,
|
||||
struct ath_txq *txq, bool retry_tx);
|
||||
void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
|
||||
void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
|
||||
void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
|
||||
int ath_tx_init(struct ath_softc *sc, int nbufs);
|
||||
int ath_tx_cleanup(struct ath_softc *sc);
|
||||
struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb);
|
||||
int ath_txq_update(struct ath_softc *sc, int qnum,
|
||||
struct ath9k_tx_queue_info *q);
|
||||
int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
|
||||
struct ath_tx_control *txctl);
|
||||
void ath_tx_tasklet(struct ath_softc *sc);
|
||||
void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb);
|
||||
bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno);
|
||||
int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn);
|
||||
int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
|
||||
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
|
||||
|
||||
/********/
|
||||
/* VAPs */
|
||||
/********/
|
||||
|
||||
/*
|
||||
* Define the scheme that we select MAC address for multiple
|
||||
* BSS on the same radio. The very first VAP will just use the MAC
|
||||
* address from the EEPROM. For the next 3 VAPs, we set the
|
||||
* U/L bit (bit 1) in MAC address, and use the next two bits as the
|
||||
* index of the VAP.
|
||||
*/
|
||||
|
||||
#define ATH_SET_VAP_BSSID_MASK(bssid_mask) \
|
||||
((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02))
|
||||
|
||||
struct ath_vap {
|
||||
int av_bslot;
|
||||
enum nl80211_iftype av_opmode;
|
||||
struct ath_buf *av_bcbuf;
|
||||
struct ath_tx_control av_btxctl;
|
||||
};
|
||||
|
||||
/*******************/
|
||||
/* Beacon Handling */
|
||||
/*******************/
|
||||
|
||||
/*
|
||||
* Regardless of the number of beacons we stagger, (i.e. regardless of the
|
||||
* number of BSSIDs) if a given beacon does not go out even after waiting this
|
||||
* number of beacon intervals, the game's up.
|
||||
*/
|
||||
#define BSTUCK_THRESH (9 * ATH_BCBUF)
|
||||
#define ATH_BCBUF 1
|
||||
#define ATH_DEFAULT_BINTVAL 100 /* TU */
|
||||
#define ATH_DEFAULT_BMISS_LIMIT 10
|
||||
#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024)
|
||||
|
||||
struct ath_beacon_config {
|
||||
u16 beacon_interval;
|
||||
u16 listen_interval;
|
||||
u16 dtim_period;
|
||||
u16 bmiss_timeout;
|
||||
u8 dtim_count;
|
||||
u8 tim_offset;
|
||||
union {
|
||||
u64 last_tsf;
|
||||
u8 last_tstamp[8];
|
||||
} u; /* last received beacon/probe response timestamp of this BSS. */
|
||||
};
|
||||
|
||||
struct ath_beacon {
|
||||
enum {
|
||||
OK, /* no change needed */
|
||||
UPDATE, /* update pending */
|
||||
COMMIT /* beacon sent, commit change */
|
||||
} updateslot; /* slot time update fsm */
|
||||
|
||||
u32 beaconq;
|
||||
u32 bmisscnt;
|
||||
u32 ast_be_xmit;
|
||||
u64 bc_tstamp;
|
||||
int bslot[ATH_BCBUF];
|
||||
int slottime;
|
||||
int slotupdate;
|
||||
struct ath9k_tx_queue_info beacon_qi;
|
||||
struct ath_descdma bdma;
|
||||
struct ath_txq *cabq;
|
||||
struct list_head bbuf;
|
||||
};
|
||||
|
||||
void ath9k_beacon_tasklet(unsigned long data);
|
||||
void ath_beacon_config(struct ath_softc *sc, int if_id);
|
||||
int ath_beaconq_setup(struct ath_hal *ah);
|
||||
int ath_beacon_alloc(struct ath_softc *sc, int if_id);
|
||||
void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp);
|
||||
void ath_beacon_sync(struct ath_softc *sc, int if_id);
|
||||
|
||||
/*******/
|
||||
/* ANI */
|
||||
/*******/
|
||||
|
||||
/* ANI values for STA only.
|
||||
FIXME: Add appropriate values for AP later */
|
||||
|
||||
#define ATH_ANI_POLLINTERVAL 100 /* 100 milliseconds between ANI poll */
|
||||
#define ATH_SHORT_CALINTERVAL 1000 /* 1 second between calibrations */
|
||||
#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds between calibrations */
|
||||
#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes between calibrations */
|
||||
|
||||
struct ath_ani {
|
||||
bool sc_caldone;
|
||||
int16_t sc_noise_floor;
|
||||
unsigned int sc_longcal_timer;
|
||||
unsigned int sc_shortcal_timer;
|
||||
unsigned int sc_resetcal_timer;
|
||||
unsigned int sc_checkani_timer;
|
||||
struct timer_list timer;
|
||||
};
|
||||
|
||||
/********************/
|
||||
/* LED Control */
|
||||
/********************/
|
||||
|
||||
#define ATH_LED_PIN 1
|
||||
#define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */
|
||||
#define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */
|
||||
|
||||
enum ath_led_type {
|
||||
ATH_LED_RADIO,
|
||||
ATH_LED_ASSOC,
|
||||
ATH_LED_TX,
|
||||
ATH_LED_RX
|
||||
};
|
||||
|
||||
struct ath_led {
|
||||
struct ath_softc *sc;
|
||||
struct led_classdev led_cdev;
|
||||
enum ath_led_type led_type;
|
||||
char name[32];
|
||||
bool registered;
|
||||
};
|
||||
|
||||
/* Rfkill */
|
||||
#define ATH_RFKILL_POLL_INTERVAL 2000 /* msecs */
|
||||
|
||||
struct ath_rfkill {
|
||||
struct rfkill *rfkill;
|
||||
struct delayed_work rfkill_poll;
|
||||
char rfkill_name[32];
|
||||
};
|
||||
|
||||
/********************/
|
||||
/* Main driver core */
|
||||
/********************/
|
||||
|
||||
/*
|
||||
* Default cache line size, in bytes.
|
||||
* Used when PCI device not fully initialized by bootrom/BIOS
|
||||
*/
|
||||
#define DEFAULT_CACHELINE 32
|
||||
#define ATH_DEFAULT_NOISE_FLOOR -95
|
||||
#define ATH_REGCLASSIDS_MAX 10
|
||||
#define ATH_CABQ_READY_TIME 80 /* % of beacon interval */
|
||||
#define ATH_MAX_SW_RETRIES 10
|
||||
#define ATH_CHAN_MAX 255
|
||||
#define IEEE80211_WEP_NKID 4 /* number of key ids */
|
||||
#define IEEE80211_RATE_VAL 0x7f
|
||||
/*
|
||||
* The key cache is used for h/w cipher state and also for
|
||||
* tracking station state such as the current tx antenna.
|
||||
* We also setup a mapping table between key cache slot indices
|
||||
* and station state to short-circuit node lookups on rx.
|
||||
* Different parts have different size key caches. We handle
|
||||
* up to ATH_KEYMAX entries (could dynamically allocate state).
|
||||
*/
|
||||
#define ATH_KEYMAX 128 /* max key cache size we handle */
|
||||
|
||||
#define ATH_IF_ID_ANY 0xff
|
||||
#define ATH_TXPOWER_MAX 100 /* .5 dBm units */
|
||||
#define ATH_RSSI_DUMMY_MARKER 0x127
|
||||
#define ATH_RATE_DUMMY_MARKER 0
|
||||
|
||||
#define SC_OP_INVALID BIT(0)
|
||||
#define SC_OP_BEACONS BIT(1)
|
||||
#define SC_OP_RXAGGR BIT(2)
|
||||
#define SC_OP_TXAGGR BIT(3)
|
||||
#define SC_OP_CHAINMASK_UPDATE BIT(4)
|
||||
#define SC_OP_FULL_RESET BIT(5)
|
||||
#define SC_OP_NO_RESET BIT(6)
|
||||
#define SC_OP_PREAMBLE_SHORT BIT(7)
|
||||
#define SC_OP_PROTECT_ENABLE BIT(8)
|
||||
#define SC_OP_RXFLUSH BIT(9)
|
||||
#define SC_OP_LED_ASSOCIATED BIT(10)
|
||||
#define SC_OP_RFKILL_REGISTERED BIT(11)
|
||||
#define SC_OP_RFKILL_SW_BLOCKED BIT(12)
|
||||
#define SC_OP_RFKILL_HW_BLOCKED BIT(13)
|
||||
#define SC_OP_WAIT_FOR_BEACON BIT(14)
|
||||
#define SC_OP_LED_ON BIT(15)
|
||||
|
||||
struct ath_bus_ops {
|
||||
void (*read_cachesize)(struct ath_softc *sc, int *csz);
|
||||
void (*cleanup)(struct ath_softc *sc);
|
||||
bool (*eeprom_read)(struct ath_hal *ah, u32 off, u16 *data);
|
||||
};
|
||||
|
||||
struct ath_softc {
|
||||
struct ieee80211_hw *hw;
|
||||
struct device *dev;
|
||||
struct tasklet_struct intr_tq;
|
||||
struct tasklet_struct bcon_tasklet;
|
||||
struct ath_hal *sc_ah;
|
||||
void __iomem *mem;
|
||||
int irq;
|
||||
spinlock_t sc_resetlock;
|
||||
struct mutex mutex;
|
||||
|
||||
u8 sc_curbssid[ETH_ALEN];
|
||||
u8 sc_myaddr[ETH_ALEN];
|
||||
u8 sc_bssidmask[ETH_ALEN];
|
||||
u32 sc_intrstatus;
|
||||
u32 sc_flags; /* SC_OP_* */
|
||||
u16 sc_curtxpow;
|
||||
u16 sc_curaid;
|
||||
u16 sc_cachelsz;
|
||||
u8 sc_nbcnvaps;
|
||||
u16 sc_nvaps;
|
||||
u8 sc_tx_chainmask;
|
||||
u8 sc_rx_chainmask;
|
||||
u32 sc_keymax;
|
||||
DECLARE_BITMAP(sc_keymap, ATH_KEYMAX);
|
||||
u8 sc_splitmic;
|
||||
atomic_t ps_usecount;
|
||||
enum ath9k_int sc_imask;
|
||||
enum ath9k_ht_extprotspacing sc_ht_extprotspacing;
|
||||
enum ath9k_ht_macmode tx_chan_width;
|
||||
|
||||
struct ath_config sc_config;
|
||||
struct ath_rx rx;
|
||||
struct ath_tx tx;
|
||||
struct ath_beacon beacon;
|
||||
struct ieee80211_vif *sc_vaps[ATH_BCBUF];
|
||||
struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX];
|
||||
struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX];
|
||||
struct ath_rate_table *cur_rate_table;
|
||||
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
|
||||
|
||||
struct ath_led radio_led;
|
||||
struct ath_led assoc_led;
|
||||
struct ath_led tx_led;
|
||||
struct ath_led rx_led;
|
||||
struct delayed_work ath_led_blink_work;
|
||||
int led_on_duration;
|
||||
int led_off_duration;
|
||||
int led_on_cnt;
|
||||
int led_off_cnt;
|
||||
|
||||
struct ath_rfkill rf_kill;
|
||||
struct ath_ani sc_ani;
|
||||
struct ath9k_node_stats sc_halstats;
|
||||
#ifdef CONFIG_ATH9K_DEBUG
|
||||
struct ath9k_debug sc_debug;
|
||||
#endif
|
||||
struct ath_bus_ops *bus_ops;
|
||||
};
|
||||
|
||||
int ath_reset(struct ath_softc *sc, bool retry_tx);
|
||||
int ath_get_hal_qnum(u16 queue, struct ath_softc *sc);
|
||||
int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
|
||||
int ath_cabq_update(struct ath_softc *);
|
||||
|
||||
static inline void ath_read_cachesize(struct ath_softc *sc, int *csz)
|
||||
{
|
||||
sc->bus_ops->read_cachesize(sc, csz);
|
||||
}
|
||||
|
||||
static inline void ath_bus_cleanup(struct ath_softc *sc)
|
||||
{
|
||||
sc->bus_ops->cleanup(sc);
|
||||
}
|
||||
|
||||
extern struct ieee80211_ops ath9k_ops;
|
||||
|
||||
irqreturn_t ath_isr(int irq, void *dev);
|
||||
void ath_cleanup(struct ath_softc *sc);
|
||||
int ath_attach(u16 devid, struct ath_softc *sc);
|
||||
void ath_detach(struct ath_softc *sc);
|
||||
const char *ath_mac_bb_name(u32 mac_bb_version);
|
||||
const char *ath_rf_name(u16 rf_version);
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
int ath_pci_init(void);
|
||||
void ath_pci_exit(void);
|
||||
#else
|
||||
static inline int ath_pci_init(void) { return 0; };
|
||||
static inline void ath_pci_exit(void) {};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ATHEROS_AR71XX
|
||||
int ath_ahb_init(void);
|
||||
void ath_ahb_exit(void);
|
||||
#else
|
||||
static inline int ath_ahb_init(void) { return 0; };
|
||||
static inline void ath_ahb_exit(void) {};
|
||||
#endif
|
||||
|
||||
static inline void ath9k_ps_wakeup(struct ath_softc *sc)
|
||||
{
|
||||
if (atomic_inc_return(&sc->ps_usecount) == 1)
|
||||
if (sc->sc_ah->ah_power_mode != ATH9K_PM_AWAKE) {
|
||||
sc->sc_ah->ah_restore_mode = sc->sc_ah->ah_power_mode;
|
||||
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ath9k_ps_restore(struct ath_softc *sc)
|
||||
{
|
||||
if (atomic_dec_and_test(&sc->ps_usecount))
|
||||
if (sc->hw->conf.flags & IEEE80211_CONF_PS)
|
||||
ath9k_hw_setpower(sc->sc_ah,
|
||||
sc->sc_ah->ah_restore_mode);
|
||||
}
|
||||
#endif /* CORE_H */
|
@ -14,9 +14,7 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
#include "reg.h"
|
||||
#include "hw.h"
|
||||
#include "ath9k.h"
|
||||
|
||||
static unsigned int ath9k_debug = DBG_DEFAULT;
|
||||
module_param_named(debug, ath9k_debug, uint, 0);
|
||||
@ -26,7 +24,7 @@ void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...)
|
||||
if (!sc)
|
||||
return;
|
||||
|
||||
if (sc->sc_debug.debug_mask & dbg_mask) {
|
||||
if (sc->debug.debug_mask & dbg_mask) {
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
@ -46,7 +44,7 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath_softc *sc = file->private_data;
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
char buf[1024];
|
||||
unsigned int len = 0;
|
||||
u32 val[ATH9K_NUM_DMA_DEBUG_REGS];
|
||||
@ -132,41 +130,41 @@ static const struct file_operations fops_dma = {
|
||||
void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
|
||||
{
|
||||
if (status)
|
||||
sc->sc_debug.stats.istats.total++;
|
||||
sc->debug.stats.istats.total++;
|
||||
if (status & ATH9K_INT_RX)
|
||||
sc->sc_debug.stats.istats.rxok++;
|
||||
sc->debug.stats.istats.rxok++;
|
||||
if (status & ATH9K_INT_RXEOL)
|
||||
sc->sc_debug.stats.istats.rxeol++;
|
||||
sc->debug.stats.istats.rxeol++;
|
||||
if (status & ATH9K_INT_RXORN)
|
||||
sc->sc_debug.stats.istats.rxorn++;
|
||||
sc->debug.stats.istats.rxorn++;
|
||||
if (status & ATH9K_INT_TX)
|
||||
sc->sc_debug.stats.istats.txok++;
|
||||
sc->debug.stats.istats.txok++;
|
||||
if (status & ATH9K_INT_TXURN)
|
||||
sc->sc_debug.stats.istats.txurn++;
|
||||
sc->debug.stats.istats.txurn++;
|
||||
if (status & ATH9K_INT_MIB)
|
||||
sc->sc_debug.stats.istats.mib++;
|
||||
sc->debug.stats.istats.mib++;
|
||||
if (status & ATH9K_INT_RXPHY)
|
||||
sc->sc_debug.stats.istats.rxphyerr++;
|
||||
sc->debug.stats.istats.rxphyerr++;
|
||||
if (status & ATH9K_INT_RXKCM)
|
||||
sc->sc_debug.stats.istats.rx_keycache_miss++;
|
||||
sc->debug.stats.istats.rx_keycache_miss++;
|
||||
if (status & ATH9K_INT_SWBA)
|
||||
sc->sc_debug.stats.istats.swba++;
|
||||
sc->debug.stats.istats.swba++;
|
||||
if (status & ATH9K_INT_BMISS)
|
||||
sc->sc_debug.stats.istats.bmiss++;
|
||||
sc->debug.stats.istats.bmiss++;
|
||||
if (status & ATH9K_INT_BNR)
|
||||
sc->sc_debug.stats.istats.bnr++;
|
||||
sc->debug.stats.istats.bnr++;
|
||||
if (status & ATH9K_INT_CST)
|
||||
sc->sc_debug.stats.istats.cst++;
|
||||
sc->debug.stats.istats.cst++;
|
||||
if (status & ATH9K_INT_GTT)
|
||||
sc->sc_debug.stats.istats.gtt++;
|
||||
sc->debug.stats.istats.gtt++;
|
||||
if (status & ATH9K_INT_TIM)
|
||||
sc->sc_debug.stats.istats.tim++;
|
||||
sc->debug.stats.istats.tim++;
|
||||
if (status & ATH9K_INT_CABEND)
|
||||
sc->sc_debug.stats.istats.cabend++;
|
||||
sc->debug.stats.istats.cabend++;
|
||||
if (status & ATH9K_INT_DTIMSYNC)
|
||||
sc->sc_debug.stats.istats.dtimsync++;
|
||||
sc->debug.stats.istats.dtimsync++;
|
||||
if (status & ATH9K_INT_DTIM)
|
||||
sc->sc_debug.stats.istats.dtim++;
|
||||
sc->debug.stats.istats.dtim++;
|
||||
}
|
||||
|
||||
static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
|
||||
@ -177,41 +175,41 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
|
||||
unsigned int len = 0;
|
||||
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "RX", sc->sc_debug.stats.istats.rxok);
|
||||
"%8s: %10u\n", "RX", sc->debug.stats.istats.rxok);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "RXEOL", sc->sc_debug.stats.istats.rxeol);
|
||||
"%8s: %10u\n", "RXEOL", sc->debug.stats.istats.rxeol);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "RXORN", sc->sc_debug.stats.istats.rxorn);
|
||||
"%8s: %10u\n", "RXORN", sc->debug.stats.istats.rxorn);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "TX", sc->sc_debug.stats.istats.txok);
|
||||
"%8s: %10u\n", "TX", sc->debug.stats.istats.txok);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "TXURN", sc->sc_debug.stats.istats.txurn);
|
||||
"%8s: %10u\n", "TXURN", sc->debug.stats.istats.txurn);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "MIB", sc->sc_debug.stats.istats.mib);
|
||||
"%8s: %10u\n", "MIB", sc->debug.stats.istats.mib);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "RXPHY", sc->sc_debug.stats.istats.rxphyerr);
|
||||
"%8s: %10u\n", "RXPHY", sc->debug.stats.istats.rxphyerr);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "RXKCM", sc->sc_debug.stats.istats.rx_keycache_miss);
|
||||
"%8s: %10u\n", "RXKCM", sc->debug.stats.istats.rx_keycache_miss);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "SWBA", sc->sc_debug.stats.istats.swba);
|
||||
"%8s: %10u\n", "SWBA", sc->debug.stats.istats.swba);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "BMISS", sc->sc_debug.stats.istats.bmiss);
|
||||
"%8s: %10u\n", "BMISS", sc->debug.stats.istats.bmiss);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "BNR", sc->sc_debug.stats.istats.bnr);
|
||||
"%8s: %10u\n", "BNR", sc->debug.stats.istats.bnr);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "CST", sc->sc_debug.stats.istats.cst);
|
||||
"%8s: %10u\n", "CST", sc->debug.stats.istats.cst);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "GTT", sc->sc_debug.stats.istats.gtt);
|
||||
"%8s: %10u\n", "GTT", sc->debug.stats.istats.gtt);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "TIM", sc->sc_debug.stats.istats.tim);
|
||||
"%8s: %10u\n", "TIM", sc->debug.stats.istats.tim);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "CABEND", sc->sc_debug.stats.istats.cabend);
|
||||
"%8s: %10u\n", "CABEND", sc->debug.stats.istats.cabend);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "DTIMSYNC", sc->sc_debug.stats.istats.dtimsync);
|
||||
"%8s: %10u\n", "DTIMSYNC", sc->debug.stats.istats.dtimsync);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "DTIM", sc->sc_debug.stats.istats.dtim);
|
||||
"%8s: %10u\n", "DTIM", sc->debug.stats.istats.dtim);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "TOTAL", sc->sc_debug.stats.istats.total);
|
||||
"%8s: %10u\n", "TOTAL", sc->debug.stats.istats.total);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
}
|
||||
@ -233,7 +231,7 @@ static void ath_debug_stat_11n_rc(struct ath_softc *sc, struct sk_buff *skb)
|
||||
final_ts_idx = tx_info_priv->tx.ts_rateindex;
|
||||
idx = sc->cur_rate_table->info[rates[final_ts_idx].idx].dot11rate;
|
||||
|
||||
sc->sc_debug.stats.n_rcstats[idx].success++;
|
||||
sc->debug.stats.n_rcstats[idx].success++;
|
||||
}
|
||||
|
||||
static void ath_debug_stat_legacy_rc(struct ath_softc *sc, struct sk_buff *skb)
|
||||
@ -247,7 +245,7 @@ static void ath_debug_stat_legacy_rc(struct ath_softc *sc, struct sk_buff *skb)
|
||||
final_ts_idx = tx_info_priv->tx.ts_rateindex;
|
||||
idx = rates[final_ts_idx].idx;
|
||||
|
||||
sc->sc_debug.stats.legacy_rcstats[idx].success++;
|
||||
sc->debug.stats.legacy_rcstats[idx].success++;
|
||||
}
|
||||
|
||||
void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb)
|
||||
@ -258,21 +256,36 @@ void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb)
|
||||
ath_debug_stat_legacy_rc(sc, skb);
|
||||
}
|
||||
|
||||
/* FIXME: legacy rates, later on .. */
|
||||
void ath_debug_stat_retries(struct ath_softc *sc, int rix,
|
||||
int xretries, int retries)
|
||||
{
|
||||
if (conf_is_ht(&sc->hw->conf)) {
|
||||
int idx = sc->cur_rate_table->info[rix].dot11rate;
|
||||
|
||||
sc->debug.stats.n_rcstats[idx].xretries += xretries;
|
||||
sc->debug.stats.n_rcstats[idx].retries += retries;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t ath_read_file_stat_11n_rc(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath_softc *sc = file->private_data;
|
||||
char buf[512];
|
||||
char buf[1024];
|
||||
unsigned int len = 0;
|
||||
int i = 0;
|
||||
|
||||
len += sprintf(buf, "%7s %13s\n\n", "Rate", "Success");
|
||||
len += sprintf(buf, "%7s %13s %8s %8s\n\n", "Rate", "Success",
|
||||
"Retries", "XRetries");
|
||||
|
||||
for (i = 0; i <= 15; i++) {
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%5s%3d: %8u\n", "MCS", i,
|
||||
sc->sc_debug.stats.n_rcstats[i].success);
|
||||
"%5s%3d: %8u %8u %8u\n", "MCS", i,
|
||||
sc->debug.stats.n_rcstats[i].success,
|
||||
sc->debug.stats.n_rcstats[i].retries,
|
||||
sc->debug.stats.n_rcstats[i].xretries);
|
||||
}
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
@ -292,7 +305,7 @@ static ssize_t ath_read_file_stat_legacy_rc(struct file *file,
|
||||
for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) {
|
||||
len += snprintf(buf + len, sizeof(buf) - len, "%5u: %12u\n",
|
||||
sc->cur_rate_table->info[i].ratekbps / 1000,
|
||||
sc->sc_debug.stats.legacy_rcstats[i].success);
|
||||
sc->debug.stats.legacy_rcstats[i].success);
|
||||
}
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
@ -317,34 +330,34 @@ static const struct file_operations fops_rcstat = {
|
||||
|
||||
int ath9k_init_debug(struct ath_softc *sc)
|
||||
{
|
||||
sc->sc_debug.debug_mask = ath9k_debug;
|
||||
sc->debug.debug_mask = ath9k_debug;
|
||||
|
||||
sc->sc_debug.debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
|
||||
if (!sc->sc_debug.debugfs_root)
|
||||
sc->debug.debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
|
||||
if (!sc->debug.debugfs_root)
|
||||
goto err;
|
||||
|
||||
sc->sc_debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
|
||||
sc->sc_debug.debugfs_root);
|
||||
if (!sc->sc_debug.debugfs_phy)
|
||||
sc->debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
|
||||
sc->debug.debugfs_root);
|
||||
if (!sc->debug.debugfs_phy)
|
||||
goto err;
|
||||
|
||||
sc->sc_debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO,
|
||||
sc->sc_debug.debugfs_phy, sc, &fops_dma);
|
||||
if (!sc->sc_debug.debugfs_dma)
|
||||
sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO,
|
||||
sc->debug.debugfs_phy, sc, &fops_dma);
|
||||
if (!sc->debug.debugfs_dma)
|
||||
goto err;
|
||||
|
||||
sc->sc_debug.debugfs_interrupt = debugfs_create_file("interrupt",
|
||||
sc->debug.debugfs_interrupt = debugfs_create_file("interrupt",
|
||||
S_IRUGO,
|
||||
sc->sc_debug.debugfs_phy,
|
||||
sc->debug.debugfs_phy,
|
||||
sc, &fops_interrupt);
|
||||
if (!sc->sc_debug.debugfs_interrupt)
|
||||
if (!sc->debug.debugfs_interrupt)
|
||||
goto err;
|
||||
|
||||
sc->sc_debug.debugfs_rcstat = debugfs_create_file("rcstat",
|
||||
sc->debug.debugfs_rcstat = debugfs_create_file("rcstat",
|
||||
S_IRUGO,
|
||||
sc->sc_debug.debugfs_phy,
|
||||
sc->debug.debugfs_phy,
|
||||
sc, &fops_rcstat);
|
||||
if (!sc->sc_debug.debugfs_rcstat)
|
||||
if (!sc->debug.debugfs_rcstat)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
@ -355,9 +368,9 @@ int ath9k_init_debug(struct ath_softc *sc)
|
||||
|
||||
void ath9k_exit_debug(struct ath_softc *sc)
|
||||
{
|
||||
debugfs_remove(sc->sc_debug.debugfs_rcstat);
|
||||
debugfs_remove(sc->sc_debug.debugfs_interrupt);
|
||||
debugfs_remove(sc->sc_debug.debugfs_dma);
|
||||
debugfs_remove(sc->sc_debug.debugfs_phy);
|
||||
debugfs_remove(sc->sc_debug.debugfs_root);
|
||||
debugfs_remove(sc->debug.debugfs_rcstat);
|
||||
debugfs_remove(sc->debug.debugfs_interrupt);
|
||||
debugfs_remove(sc->debug.debugfs_dma);
|
||||
debugfs_remove(sc->debug.debugfs_phy);
|
||||
debugfs_remove(sc->debug.debugfs_root);
|
||||
}
|
||||
|
153
drivers/net/wireless/ath9k/debug.h
Normal file
153
drivers/net/wireless/ath9k/debug.h
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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 DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
enum ATH_DEBUG {
|
||||
ATH_DBG_RESET = 0x00000001,
|
||||
ATH_DBG_REG_IO = 0x00000002,
|
||||
ATH_DBG_QUEUE = 0x00000004,
|
||||
ATH_DBG_EEPROM = 0x00000008,
|
||||
ATH_DBG_CALIBRATE = 0x00000010,
|
||||
ATH_DBG_CHANNEL = 0x00000020,
|
||||
ATH_DBG_INTERRUPT = 0x00000040,
|
||||
ATH_DBG_REGULATORY = 0x00000080,
|
||||
ATH_DBG_ANI = 0x00000100,
|
||||
ATH_DBG_POWER_MGMT = 0x00000200,
|
||||
ATH_DBG_XMIT = 0x00000400,
|
||||
ATH_DBG_BEACON = 0x00001000,
|
||||
ATH_DBG_CONFIG = 0x00002000,
|
||||
ATH_DBG_KEYCACHE = 0x00004000,
|
||||
ATH_DBG_FATAL = 0x00008000,
|
||||
ATH_DBG_ANY = 0xffffffff
|
||||
};
|
||||
|
||||
#define DBG_DEFAULT (ATH_DBG_FATAL)
|
||||
|
||||
#ifdef CONFIG_ATH9K_DEBUG
|
||||
|
||||
/**
|
||||
* struct ath_interrupt_stats - Contains statistics about interrupts
|
||||
* @total: Total no. of interrupts generated so far
|
||||
* @rxok: RX with no errors
|
||||
* @rxeol: RX with no more RXDESC available
|
||||
* @rxorn: RX FIFO overrun
|
||||
* @txok: TX completed at the requested rate
|
||||
* @txurn: TX FIFO underrun
|
||||
* @mib: MIB regs reaching its threshold
|
||||
* @rxphyerr: RX with phy errors
|
||||
* @rx_keycache_miss: RX with key cache misses
|
||||
* @swba: Software Beacon Alert
|
||||
* @bmiss: Beacon Miss
|
||||
* @bnr: Beacon Not Ready
|
||||
* @cst: Carrier Sense TImeout
|
||||
* @gtt: Global TX Timeout
|
||||
* @tim: RX beacon TIM occurrence
|
||||
* @cabend: RX End of CAB traffic
|
||||
* @dtimsync: DTIM sync lossage
|
||||
* @dtim: RX Beacon with DTIM
|
||||
*/
|
||||
struct ath_interrupt_stats {
|
||||
u32 total;
|
||||
u32 rxok;
|
||||
u32 rxeol;
|
||||
u32 rxorn;
|
||||
u32 txok;
|
||||
u32 txeol;
|
||||
u32 txurn;
|
||||
u32 mib;
|
||||
u32 rxphyerr;
|
||||
u32 rx_keycache_miss;
|
||||
u32 swba;
|
||||
u32 bmiss;
|
||||
u32 bnr;
|
||||
u32 cst;
|
||||
u32 gtt;
|
||||
u32 tim;
|
||||
u32 cabend;
|
||||
u32 dtimsync;
|
||||
u32 dtim;
|
||||
};
|
||||
|
||||
struct ath_legacy_rc_stats {
|
||||
u32 success;
|
||||
};
|
||||
|
||||
struct ath_11n_rc_stats {
|
||||
u32 success;
|
||||
u32 retries;
|
||||
u32 xretries;
|
||||
};
|
||||
|
||||
struct ath_stats {
|
||||
struct ath_interrupt_stats istats;
|
||||
struct ath_legacy_rc_stats legacy_rcstats[12]; /* max(11a,11b,11g) */
|
||||
struct ath_11n_rc_stats n_rcstats[16]; /* 0..15 MCS rates */
|
||||
};
|
||||
|
||||
struct ath9k_debug {
|
||||
int debug_mask;
|
||||
struct dentry *debugfs_root;
|
||||
struct dentry *debugfs_phy;
|
||||
struct dentry *debugfs_dma;
|
||||
struct dentry *debugfs_interrupt;
|
||||
struct dentry *debugfs_rcstat;
|
||||
struct ath_stats stats;
|
||||
};
|
||||
|
||||
void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...);
|
||||
int ath9k_init_debug(struct ath_softc *sc);
|
||||
void ath9k_exit_debug(struct ath_softc *sc);
|
||||
void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
|
||||
void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb);
|
||||
void ath_debug_stat_retries(struct ath_softc *sc, int rix,
|
||||
int xretries, int retries);
|
||||
|
||||
#else
|
||||
|
||||
static inline void DPRINTF(struct ath_softc *sc, int dbg_mask,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int ath9k_init_debug(struct ath_softc *sc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ath9k_exit_debug(struct ath_softc *sc)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath_debug_stat_interrupt(struct ath_softc *sc,
|
||||
enum ath9k_int status)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath_debug_stat_rc(struct ath_softc *sc,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix,
|
||||
int xretries, int retries)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ATH9K_DEBUG */
|
||||
|
||||
#endif /* DEBUG_H */
|
File diff suppressed because it is too large
Load Diff
473
drivers/net/wireless/ath9k/eeprom.h
Normal file
473
drivers/net/wireless/ath9k/eeprom.h
Normal file
@ -0,0 +1,473 @@
|
||||
/*
|
||||
* 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 EEPROM_H
|
||||
#define EEPROM_H
|
||||
|
||||
#define AH_USE_EEPROM 0x1
|
||||
|
||||
#ifdef __BIG_ENDIAN
|
||||
#define AR5416_EEPROM_MAGIC 0x5aa5
|
||||
#else
|
||||
#define AR5416_EEPROM_MAGIC 0xa55a
|
||||
#endif
|
||||
|
||||
#define CTRY_DEBUG 0x1ff
|
||||
#define CTRY_DEFAULT 0
|
||||
|
||||
#define AR_EEPROM_EEPCAP_COMPRESS_DIS 0x0001
|
||||
#define AR_EEPROM_EEPCAP_AES_DIS 0x0002
|
||||
#define AR_EEPROM_EEPCAP_FASTFRAME_DIS 0x0004
|
||||
#define AR_EEPROM_EEPCAP_BURST_DIS 0x0008
|
||||
#define AR_EEPROM_EEPCAP_MAXQCU 0x01F0
|
||||
#define AR_EEPROM_EEPCAP_MAXQCU_S 4
|
||||
#define AR_EEPROM_EEPCAP_HEAVY_CLIP_EN 0x0200
|
||||
#define AR_EEPROM_EEPCAP_KC_ENTRIES 0xF000
|
||||
#define AR_EEPROM_EEPCAP_KC_ENTRIES_S 12
|
||||
|
||||
#define AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND 0x0040
|
||||
#define AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN 0x0080
|
||||
#define AR_EEPROM_EEREGCAP_EN_KK_U2 0x0100
|
||||
#define AR_EEPROM_EEREGCAP_EN_KK_MIDBAND 0x0200
|
||||
#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD 0x0400
|
||||
#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A 0x0800
|
||||
|
||||
#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD_PRE4_0 0x4000
|
||||
#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A_PRE4_0 0x8000
|
||||
|
||||
#define AR5416_EEPROM_MAGIC_OFFSET 0x0
|
||||
#define AR5416_EEPROM_S 2
|
||||
#define AR5416_EEPROM_OFFSET 0x2000
|
||||
#define AR5416_EEPROM_MAX 0xae0
|
||||
|
||||
#define AR5416_EEPROM_START_ADDR \
|
||||
(AR_SREV_9100(ah)) ? 0x1fff1000 : 0x503f1200
|
||||
|
||||
#define SD_NO_CTL 0xE0
|
||||
#define NO_CTL 0xff
|
||||
#define CTL_MODE_M 7
|
||||
#define CTL_11A 0
|
||||
#define CTL_11B 1
|
||||
#define CTL_11G 2
|
||||
#define CTL_2GHT20 5
|
||||
#define CTL_5GHT20 6
|
||||
#define CTL_2GHT40 7
|
||||
#define CTL_5GHT40 8
|
||||
|
||||
#define EXT_ADDITIVE (0x8000)
|
||||
#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE)
|
||||
#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE)
|
||||
#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE)
|
||||
|
||||
#define SUB_NUM_CTL_MODES_AT_5G_40 2
|
||||
#define SUB_NUM_CTL_MODES_AT_2G_40 3
|
||||
|
||||
#define AR_EEPROM_MAC(i) (0x1d+(i))
|
||||
#define ATH9K_POW_SM(_r, _s) (((_r) & 0x3f) << (_s))
|
||||
#define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5))
|
||||
#define ath9k_hw_use_flash(_ah) (!(_ah->ah_flags & AH_USE_EEPROM))
|
||||
|
||||
#define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c
|
||||
#define AR_EEPROM_RFSILENT_GPIO_SEL_S 2
|
||||
#define AR_EEPROM_RFSILENT_POLARITY 0x0002
|
||||
#define AR_EEPROM_RFSILENT_POLARITY_S 1
|
||||
|
||||
#define EEP_RFSILENT_ENABLED 0x0001
|
||||
#define EEP_RFSILENT_ENABLED_S 0
|
||||
#define EEP_RFSILENT_POLARITY 0x0002
|
||||
#define EEP_RFSILENT_POLARITY_S 1
|
||||
#define EEP_RFSILENT_GPIO_SEL 0x001c
|
||||
#define EEP_RFSILENT_GPIO_SEL_S 2
|
||||
|
||||
#define AR5416_OPFLAGS_11A 0x01
|
||||
#define AR5416_OPFLAGS_11G 0x02
|
||||
#define AR5416_OPFLAGS_N_5G_HT40 0x04
|
||||
#define AR5416_OPFLAGS_N_2G_HT40 0x08
|
||||
#define AR5416_OPFLAGS_N_5G_HT20 0x10
|
||||
#define AR5416_OPFLAGS_N_2G_HT20 0x20
|
||||
|
||||
#define AR5416_EEP_NO_BACK_VER 0x1
|
||||
#define AR5416_EEP_VER 0xE
|
||||
#define AR5416_EEP_VER_MINOR_MASK 0x0FFF
|
||||
#define AR5416_EEP_MINOR_VER_2 0x2
|
||||
#define AR5416_EEP_MINOR_VER_3 0x3
|
||||
#define AR5416_EEP_MINOR_VER_7 0x7
|
||||
#define AR5416_EEP_MINOR_VER_9 0x9
|
||||
#define AR5416_EEP_MINOR_VER_16 0x10
|
||||
#define AR5416_EEP_MINOR_VER_17 0x11
|
||||
#define AR5416_EEP_MINOR_VER_19 0x13
|
||||
#define AR5416_EEP_MINOR_VER_20 0x14
|
||||
|
||||
#define AR5416_NUM_5G_CAL_PIERS 8
|
||||
#define AR5416_NUM_2G_CAL_PIERS 4
|
||||
#define AR5416_NUM_5G_20_TARGET_POWERS 8
|
||||
#define AR5416_NUM_5G_40_TARGET_POWERS 8
|
||||
#define AR5416_NUM_2G_CCK_TARGET_POWERS 3
|
||||
#define AR5416_NUM_2G_20_TARGET_POWERS 4
|
||||
#define AR5416_NUM_2G_40_TARGET_POWERS 4
|
||||
#define AR5416_NUM_CTLS 24
|
||||
#define AR5416_NUM_BAND_EDGES 8
|
||||
#define AR5416_NUM_PD_GAINS 4
|
||||
#define AR5416_PD_GAINS_IN_MASK 4
|
||||
#define AR5416_PD_GAIN_ICEPTS 5
|
||||
#define AR5416_EEPROM_MODAL_SPURS 5
|
||||
#define AR5416_MAX_RATE_POWER 63
|
||||
#define AR5416_NUM_PDADC_VALUES 128
|
||||
#define AR5416_BCHAN_UNUSED 0xFF
|
||||
#define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64
|
||||
#define AR5416_MAX_CHAINS 3
|
||||
#define AR5416_PWR_TABLE_OFFSET -5
|
||||
|
||||
/* Rx gain type values */
|
||||
#define AR5416_EEP_RXGAIN_23DB_BACKOFF 0
|
||||
#define AR5416_EEP_RXGAIN_13DB_BACKOFF 1
|
||||
#define AR5416_EEP_RXGAIN_ORIG 2
|
||||
|
||||
/* Tx gain type values */
|
||||
#define AR5416_EEP_TXGAIN_ORIGINAL 0
|
||||
#define AR5416_EEP_TXGAIN_HIGH_POWER 1
|
||||
|
||||
#define AR5416_EEP4K_START_LOC 64
|
||||
#define AR5416_EEP4K_NUM_2G_CAL_PIERS 3
|
||||
#define AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS 3
|
||||
#define AR5416_EEP4K_NUM_2G_20_TARGET_POWERS 3
|
||||
#define AR5416_EEP4K_NUM_2G_40_TARGET_POWERS 3
|
||||
#define AR5416_EEP4K_NUM_CTLS 12
|
||||
#define AR5416_EEP4K_NUM_BAND_EDGES 4
|
||||
#define AR5416_EEP4K_NUM_PD_GAINS 2
|
||||
#define AR5416_EEP4K_PD_GAINS_IN_MASK 4
|
||||
#define AR5416_EEP4K_PD_GAIN_ICEPTS 5
|
||||
#define AR5416_EEP4K_MAX_CHAINS 1
|
||||
|
||||
enum eeprom_param {
|
||||
EEP_NFTHRESH_5,
|
||||
EEP_NFTHRESH_2,
|
||||
EEP_MAC_MSW,
|
||||
EEP_MAC_MID,
|
||||
EEP_MAC_LSW,
|
||||
EEP_REG_0,
|
||||
EEP_REG_1,
|
||||
EEP_OP_CAP,
|
||||
EEP_OP_MODE,
|
||||
EEP_RF_SILENT,
|
||||
EEP_OB_5,
|
||||
EEP_DB_5,
|
||||
EEP_OB_2,
|
||||
EEP_DB_2,
|
||||
EEP_MINOR_REV,
|
||||
EEP_TX_MASK,
|
||||
EEP_RX_MASK,
|
||||
EEP_RXGAIN_TYPE,
|
||||
EEP_TXGAIN_TYPE,
|
||||
EEP_DAC_HPWR_5G,
|
||||
};
|
||||
|
||||
enum ar5416_rates {
|
||||
rate6mb, rate9mb, rate12mb, rate18mb,
|
||||
rate24mb, rate36mb, rate48mb, rate54mb,
|
||||
rate1l, rate2l, rate2s, rate5_5l,
|
||||
rate5_5s, rate11l, rate11s, rateXr,
|
||||
rateHt20_0, rateHt20_1, rateHt20_2, rateHt20_3,
|
||||
rateHt20_4, rateHt20_5, rateHt20_6, rateHt20_7,
|
||||
rateHt40_0, rateHt40_1, rateHt40_2, rateHt40_3,
|
||||
rateHt40_4, rateHt40_5, rateHt40_6, rateHt40_7,
|
||||
rateDupCck, rateDupOfdm, rateExtCck, rateExtOfdm,
|
||||
Ar5416RateSize
|
||||
};
|
||||
|
||||
enum ath9k_hal_freq_band {
|
||||
ATH9K_HAL_FREQ_BAND_5GHZ = 0,
|
||||
ATH9K_HAL_FREQ_BAND_2GHZ = 1
|
||||
};
|
||||
|
||||
struct base_eep_header {
|
||||
u16 length;
|
||||
u16 checksum;
|
||||
u16 version;
|
||||
u8 opCapFlags;
|
||||
u8 eepMisc;
|
||||
u16 regDmn[2];
|
||||
u8 macAddr[6];
|
||||
u8 rxMask;
|
||||
u8 txMask;
|
||||
u16 rfSilent;
|
||||
u16 blueToothOptions;
|
||||
u16 deviceCap;
|
||||
u32 binBuildNumber;
|
||||
u8 deviceType;
|
||||
u8 pwdclkind;
|
||||
u8 futureBase_1[2];
|
||||
u8 rxGainType;
|
||||
u8 dacHiPwrMode_5G;
|
||||
u8 futureBase_2;
|
||||
u8 dacLpMode;
|
||||
u8 txGainType;
|
||||
u8 rcChainMask;
|
||||
u8 desiredScaleCCK;
|
||||
u8 futureBase_3[23];
|
||||
} __packed;
|
||||
|
||||
struct base_eep_header_4k {
|
||||
u16 length;
|
||||
u16 checksum;
|
||||
u16 version;
|
||||
u8 opCapFlags;
|
||||
u8 eepMisc;
|
||||
u16 regDmn[2];
|
||||
u8 macAddr[6];
|
||||
u8 rxMask;
|
||||
u8 txMask;
|
||||
u16 rfSilent;
|
||||
u16 blueToothOptions;
|
||||
u16 deviceCap;
|
||||
u32 binBuildNumber;
|
||||
u8 deviceType;
|
||||
u8 futureBase[1];
|
||||
} __packed;
|
||||
|
||||
|
||||
struct spur_chan {
|
||||
u16 spurChan;
|
||||
u8 spurRangeLow;
|
||||
u8 spurRangeHigh;
|
||||
} __packed;
|
||||
|
||||
struct modal_eep_header {
|
||||
u32 antCtrlChain[AR5416_MAX_CHAINS];
|
||||
u32 antCtrlCommon;
|
||||
u8 antennaGainCh[AR5416_MAX_CHAINS];
|
||||
u8 switchSettling;
|
||||
u8 txRxAttenCh[AR5416_MAX_CHAINS];
|
||||
u8 rxTxMarginCh[AR5416_MAX_CHAINS];
|
||||
u8 adcDesiredSize;
|
||||
u8 pgaDesiredSize;
|
||||
u8 xlnaGainCh[AR5416_MAX_CHAINS];
|
||||
u8 txEndToXpaOff;
|
||||
u8 txEndToRxOn;
|
||||
u8 txFrameToXpaOn;
|
||||
u8 thresh62;
|
||||
u8 noiseFloorThreshCh[AR5416_MAX_CHAINS];
|
||||
u8 xpdGain;
|
||||
u8 xpd;
|
||||
u8 iqCalICh[AR5416_MAX_CHAINS];
|
||||
u8 iqCalQCh[AR5416_MAX_CHAINS];
|
||||
u8 pdGainOverlap;
|
||||
u8 ob;
|
||||
u8 db;
|
||||
u8 xpaBiasLvl;
|
||||
u8 pwrDecreaseFor2Chain;
|
||||
u8 pwrDecreaseFor3Chain;
|
||||
u8 txFrameToDataStart;
|
||||
u8 txFrameToPaOn;
|
||||
u8 ht40PowerIncForPdadc;
|
||||
u8 bswAtten[AR5416_MAX_CHAINS];
|
||||
u8 bswMargin[AR5416_MAX_CHAINS];
|
||||
u8 swSettleHt40;
|
||||
u8 xatten2Db[AR5416_MAX_CHAINS];
|
||||
u8 xatten2Margin[AR5416_MAX_CHAINS];
|
||||
u8 ob_ch1;
|
||||
u8 db_ch1;
|
||||
u8 useAnt1:1,
|
||||
force_xpaon:1,
|
||||
local_bias:1,
|
||||
femBandSelectUsed:1, xlnabufin:1, xlnaisel:2, xlnabufmode:1;
|
||||
u8 miscBits;
|
||||
u16 xpaBiasLvlFreq[3];
|
||||
u8 futureModal[6];
|
||||
|
||||
struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS];
|
||||
} __packed;
|
||||
|
||||
struct modal_eep_4k_header {
|
||||
u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS];
|
||||
u32 antCtrlCommon;
|
||||
u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 switchSettling;
|
||||
u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 adcDesiredSize;
|
||||
u8 pgaDesiredSize;
|
||||
u8 xlnaGainCh[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 txEndToXpaOff;
|
||||
u8 txEndToRxOn;
|
||||
u8 txFrameToXpaOn;
|
||||
u8 thresh62;
|
||||
u8 noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 xpdGain;
|
||||
u8 xpd;
|
||||
u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 pdGainOverlap;
|
||||
u8 ob_01;
|
||||
u8 db1_01;
|
||||
u8 xpaBiasLvl;
|
||||
u8 txFrameToDataStart;
|
||||
u8 txFrameToPaOn;
|
||||
u8 ht40PowerIncForPdadc;
|
||||
u8 bswAtten[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 bswMargin[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 swSettleHt40;
|
||||
u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 db2_01;
|
||||
u8 version;
|
||||
u16 ob_234;
|
||||
u16 db1_234;
|
||||
u16 db2_234;
|
||||
u8 futureModal[4];
|
||||
|
||||
struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS];
|
||||
} __packed;
|
||||
|
||||
|
||||
struct cal_data_per_freq {
|
||||
u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
|
||||
u8 vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
|
||||
} __packed;
|
||||
|
||||
struct cal_data_per_freq_4k {
|
||||
u8 pwrPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS];
|
||||
u8 vpdPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS];
|
||||
} __packed;
|
||||
|
||||
struct cal_target_power_leg {
|
||||
u8 bChannel;
|
||||
u8 tPow2x[4];
|
||||
} __packed;
|
||||
|
||||
struct cal_target_power_ht {
|
||||
u8 bChannel;
|
||||
u8 tPow2x[8];
|
||||
} __packed;
|
||||
|
||||
|
||||
#ifdef __BIG_ENDIAN_BITFIELD
|
||||
struct cal_ctl_edges {
|
||||
u8 bChannel;
|
||||
u8 flag:2, tPower:6;
|
||||
} __packed;
|
||||
#else
|
||||
struct cal_ctl_edges {
|
||||
u8 bChannel;
|
||||
u8 tPower:6, flag:2;
|
||||
} __packed;
|
||||
#endif
|
||||
|
||||
struct cal_ctl_data {
|
||||
struct cal_ctl_edges
|
||||
ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES];
|
||||
} __packed;
|
||||
|
||||
struct cal_ctl_data_4k {
|
||||
struct cal_ctl_edges
|
||||
ctlEdges[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_BAND_EDGES];
|
||||
} __packed;
|
||||
|
||||
struct ar5416_eeprom_def {
|
||||
struct base_eep_header baseEepHeader;
|
||||
u8 custData[64];
|
||||
struct modal_eep_header modalHeader[2];
|
||||
u8 calFreqPier5G[AR5416_NUM_5G_CAL_PIERS];
|
||||
u8 calFreqPier2G[AR5416_NUM_2G_CAL_PIERS];
|
||||
struct cal_data_per_freq
|
||||
calPierData5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS];
|
||||
struct cal_data_per_freq
|
||||
calPierData2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS];
|
||||
struct cal_target_power_leg
|
||||
calTargetPower5G[AR5416_NUM_5G_20_TARGET_POWERS];
|
||||
struct cal_target_power_ht
|
||||
calTargetPower5GHT20[AR5416_NUM_5G_20_TARGET_POWERS];
|
||||
struct cal_target_power_ht
|
||||
calTargetPower5GHT40[AR5416_NUM_5G_40_TARGET_POWERS];
|
||||
struct cal_target_power_leg
|
||||
calTargetPowerCck[AR5416_NUM_2G_CCK_TARGET_POWERS];
|
||||
struct cal_target_power_leg
|
||||
calTargetPower2G[AR5416_NUM_2G_20_TARGET_POWERS];
|
||||
struct cal_target_power_ht
|
||||
calTargetPower2GHT20[AR5416_NUM_2G_20_TARGET_POWERS];
|
||||
struct cal_target_power_ht
|
||||
calTargetPower2GHT40[AR5416_NUM_2G_40_TARGET_POWERS];
|
||||
u8 ctlIndex[AR5416_NUM_CTLS];
|
||||
struct cal_ctl_data ctlData[AR5416_NUM_CTLS];
|
||||
u8 padding;
|
||||
} __packed;
|
||||
|
||||
struct ar5416_eeprom_4k {
|
||||
struct base_eep_header_4k baseEepHeader;
|
||||
u8 custData[20];
|
||||
struct modal_eep_4k_header modalHeader;
|
||||
u8 calFreqPier2G[AR5416_EEP4K_NUM_2G_CAL_PIERS];
|
||||
struct cal_data_per_freq_4k
|
||||
calPierData2G[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_2G_CAL_PIERS];
|
||||
struct cal_target_power_leg
|
||||
calTargetPowerCck[AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS];
|
||||
struct cal_target_power_leg
|
||||
calTargetPower2G[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS];
|
||||
struct cal_target_power_ht
|
||||
calTargetPower2GHT20[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS];
|
||||
struct cal_target_power_ht
|
||||
calTargetPower2GHT40[AR5416_EEP4K_NUM_2G_40_TARGET_POWERS];
|
||||
u8 ctlIndex[AR5416_EEP4K_NUM_CTLS];
|
||||
struct cal_ctl_data_4k ctlData[AR5416_EEP4K_NUM_CTLS];
|
||||
u8 padding;
|
||||
} __packed;
|
||||
|
||||
enum reg_ext_bitmap {
|
||||
REG_EXT_JAPAN_MIDBAND = 1,
|
||||
REG_EXT_FCC_DFS_HT40 = 2,
|
||||
REG_EXT_JAPAN_NONDFS_HT40 = 3,
|
||||
REG_EXT_JAPAN_DFS_HT40 = 4
|
||||
};
|
||||
|
||||
struct ath9k_country_entry {
|
||||
u16 countryCode;
|
||||
u16 regDmnEnum;
|
||||
u16 regDmn5G;
|
||||
u16 regDmn2G;
|
||||
u8 isMultidomain;
|
||||
u8 iso[3];
|
||||
};
|
||||
|
||||
enum ath9k_eep_map {
|
||||
EEP_MAP_DEFAULT = 0x0,
|
||||
EEP_MAP_4KBITS,
|
||||
EEP_MAP_MAX
|
||||
};
|
||||
|
||||
struct eeprom_ops {
|
||||
int (*check_eeprom)(struct ath_hw *hw);
|
||||
u32 (*get_eeprom)(struct ath_hw *hw, enum eeprom_param param);
|
||||
bool (*fill_eeprom)(struct ath_hw *hw);
|
||||
int (*get_eeprom_ver)(struct ath_hw *hw);
|
||||
int (*get_eeprom_rev)(struct ath_hw *hw);
|
||||
u8 (*get_num_ant_config)(struct ath_hw *hw, enum ieee80211_band band);
|
||||
u16 (*get_eeprom_antenna_cfg)(struct ath_hw *hw,
|
||||
struct ath9k_channel *chan);
|
||||
bool (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan);
|
||||
void (*set_addac)(struct ath_hw *hw, struct ath9k_channel *chan);
|
||||
int (*set_txpower)(struct ath_hw *hw, struct ath9k_channel *chan,
|
||||
u16 cfgCtl, u8 twiceAntennaReduction,
|
||||
u8 twiceMaxRegulatoryPower, u8 powerLimit);
|
||||
u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz);
|
||||
};
|
||||
|
||||
#define ar5416_get_ntxchains(_txchainmask) \
|
||||
(((_txchainmask >> 2) & 1) + \
|
||||
((_txchainmask >> 1) & 1) + (_txchainmask & 1))
|
||||
|
||||
int ath9k_hw_eeprom_attach(struct ath_hw *ah);
|
||||
|
||||
#endif /* EEPROM_H */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -14,45 +14,40 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
#include "hw.h"
|
||||
#include "reg.h"
|
||||
#include "phy.h"
|
||||
#include "ath9k.h"
|
||||
|
||||
static void ath9k_hw_set_txq_interrupts(struct ath_hal *ah,
|
||||
static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
|
||||
struct ath9k_tx_queue_info *qi)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
|
||||
"tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
|
||||
ahp->ah_txOkInterruptMask, ahp->ah_txErrInterruptMask,
|
||||
ahp->ah_txDescInterruptMask, ahp->ah_txEolInterruptMask,
|
||||
ahp->ah_txUrnInterruptMask);
|
||||
ah->txok_interrupt_mask, ah->txerr_interrupt_mask,
|
||||
ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask,
|
||||
ah->txurn_interrupt_mask);
|
||||
|
||||
REG_WRITE(ah, AR_IMR_S0,
|
||||
SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK)
|
||||
| SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC));
|
||||
SM(ah->txok_interrupt_mask, AR_IMR_S0_QCU_TXOK)
|
||||
| SM(ah->txdesc_interrupt_mask, AR_IMR_S0_QCU_TXDESC));
|
||||
REG_WRITE(ah, AR_IMR_S1,
|
||||
SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR)
|
||||
| SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL));
|
||||
SM(ah->txerr_interrupt_mask, AR_IMR_S1_QCU_TXERR)
|
||||
| SM(ah->txeol_interrupt_mask, AR_IMR_S1_QCU_TXEOL));
|
||||
REG_RMW_FIELD(ah, AR_IMR_S2,
|
||||
AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask);
|
||||
AR_IMR_S2_QCU_TXURN, ah->txurn_interrupt_mask);
|
||||
}
|
||||
|
||||
u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q)
|
||||
u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q)
|
||||
{
|
||||
return REG_READ(ah, AR_QTXDP(q));
|
||||
}
|
||||
|
||||
bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp)
|
||||
bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp)
|
||||
{
|
||||
REG_WRITE(ah, AR_QTXDP(q), txdp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ath9k_hw_txstart(struct ath_hal *ah, u32 q)
|
||||
bool ath9k_hw_txstart(struct ath_hw *ah, u32 q)
|
||||
{
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q);
|
||||
|
||||
@ -61,7 +56,7 @@ bool ath9k_hw_txstart(struct ath_hal *ah, u32 q)
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q)
|
||||
u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q)
|
||||
{
|
||||
u32 npend;
|
||||
|
||||
@ -75,16 +70,15 @@ u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q)
|
||||
return npend;
|
||||
}
|
||||
|
||||
bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel)
|
||||
bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
u32 txcfg, curLevel, newLevel;
|
||||
enum ath9k_int omask;
|
||||
|
||||
if (ah->ah_txTrigLevel >= MAX_TX_FIFO_THRESHOLD)
|
||||
if (ah->tx_trig_level >= MAX_TX_FIFO_THRESHOLD)
|
||||
return false;
|
||||
|
||||
omask = ath9k_hw_set_interrupts(ah, ahp->ah_maskReg & ~ATH9K_INT_GLOBAL);
|
||||
omask = ath9k_hw_set_interrupts(ah, ah->mask_reg & ~ATH9K_INT_GLOBAL);
|
||||
|
||||
txcfg = REG_READ(ah, AR_TXCFG);
|
||||
curLevel = MS(txcfg, AR_FTRIG);
|
||||
@ -100,18 +94,17 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel)
|
||||
|
||||
ath9k_hw_set_interrupts(ah, omask);
|
||||
|
||||
ah->ah_txTrigLevel = newLevel;
|
||||
ah->tx_trig_level = newLevel;
|
||||
|
||||
return newLevel != curLevel;
|
||||
}
|
||||
|
||||
bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q)
|
||||
bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
|
||||
{
|
||||
#define ATH9K_TX_STOP_DMA_TIMEOUT 4000 /* usec */
|
||||
#define ATH9K_TIME_QUANTUM 100 /* usec */
|
||||
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
|
||||
struct ath9k_hw_capabilities *pCap = &ah->caps;
|
||||
struct ath9k_tx_queue_info *qi;
|
||||
u32 tsfLow, j, wait;
|
||||
u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
|
||||
@ -121,7 +114,7 @@ bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q)
|
||||
return false;
|
||||
}
|
||||
|
||||
qi = &ahp->ah_txq[q];
|
||||
qi = &ah->txq[q];
|
||||
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n");
|
||||
return false;
|
||||
@ -183,7 +176,7 @@ bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q)
|
||||
#undef ATH9K_TIME_QUANTUM
|
||||
}
|
||||
|
||||
bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
|
||||
bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
|
||||
u32 segLen, bool firstSeg,
|
||||
bool lastSeg, const struct ath_desc *ds0)
|
||||
{
|
||||
@ -211,7 +204,7 @@ bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
|
||||
return true;
|
||||
}
|
||||
|
||||
void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds)
|
||||
void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds)
|
||||
{
|
||||
struct ar5416_desc *ads = AR5416DESC(ds);
|
||||
|
||||
@ -222,7 +215,7 @@ void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds)
|
||||
ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
|
||||
}
|
||||
|
||||
int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds)
|
||||
int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds)
|
||||
{
|
||||
struct ar5416_desc *ads = AR5416DESC(ds);
|
||||
|
||||
@ -297,14 +290,13 @@ int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
|
||||
void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds,
|
||||
u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
|
||||
u32 keyIx, enum ath9k_key_type keyType, u32 flags)
|
||||
{
|
||||
struct ar5416_desc *ads = AR5416DESC(ds);
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
|
||||
txPower += ahp->ah_txPowerIndexOffset;
|
||||
txPower += ah->txpower_indexoffset;
|
||||
if (txPower > 63)
|
||||
txPower = 63;
|
||||
|
||||
@ -333,7 +325,7 @@ void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
|
||||
}
|
||||
}
|
||||
|
||||
void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds,
|
||||
void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds,
|
||||
struct ath_desc *lastds,
|
||||
u32 durUpdateEn, u32 rtsctsRate,
|
||||
u32 rtsctsDuration,
|
||||
@ -388,7 +380,7 @@ void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds,
|
||||
last_ads->ds_ctl3 = ads->ds_ctl3;
|
||||
}
|
||||
|
||||
void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
|
||||
void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds,
|
||||
u32 aggrLen)
|
||||
{
|
||||
struct ar5416_desc *ads = AR5416DESC(ds);
|
||||
@ -398,7 +390,7 @@ void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
|
||||
ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
|
||||
}
|
||||
|
||||
void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
|
||||
void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds,
|
||||
u32 numDelims)
|
||||
{
|
||||
struct ar5416_desc *ads = AR5416DESC(ds);
|
||||
@ -412,7 +404,7 @@ void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
|
||||
ads->ds_ctl6 = ctl6;
|
||||
}
|
||||
|
||||
void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds)
|
||||
void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds)
|
||||
{
|
||||
struct ar5416_desc *ads = AR5416DESC(ds);
|
||||
|
||||
@ -421,14 +413,14 @@ void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds)
|
||||
ads->ds_ctl6 &= ~AR_PadDelim;
|
||||
}
|
||||
|
||||
void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds)
|
||||
void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds)
|
||||
{
|
||||
struct ar5416_desc *ads = AR5416DESC(ds);
|
||||
|
||||
ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
|
||||
}
|
||||
|
||||
void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds,
|
||||
void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds,
|
||||
u32 burstDuration)
|
||||
{
|
||||
struct ar5416_desc *ads = AR5416DESC(ds);
|
||||
@ -437,7 +429,7 @@ void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds,
|
||||
ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
|
||||
}
|
||||
|
||||
void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds,
|
||||
void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds,
|
||||
u32 vmf)
|
||||
{
|
||||
struct ar5416_desc *ads = AR5416DESC(ds);
|
||||
@ -448,20 +440,17 @@ void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds,
|
||||
ads->ds_ctl0 &= ~AR_VirtMoreFrag;
|
||||
}
|
||||
|
||||
void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs)
|
||||
void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
|
||||
*txqs &= ahp->ah_intrTxqs;
|
||||
ahp->ah_intrTxqs &= ~(*txqs);
|
||||
*txqs &= ah->intr_txqs;
|
||||
ah->intr_txqs &= ~(*txqs);
|
||||
}
|
||||
|
||||
bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q,
|
||||
bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
|
||||
const struct ath9k_tx_queue_info *qinfo)
|
||||
{
|
||||
u32 cw;
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
|
||||
struct ath9k_hw_capabilities *pCap = &ah->caps;
|
||||
struct ath9k_tx_queue_info *qi;
|
||||
|
||||
if (q >= pCap->total_queues) {
|
||||
@ -469,7 +458,7 @@ bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q,
|
||||
return false;
|
||||
}
|
||||
|
||||
qi = &ahp->ah_txq[q];
|
||||
qi = &ah->txq[q];
|
||||
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n");
|
||||
return false;
|
||||
@ -525,11 +514,10 @@ bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
|
||||
bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q,
|
||||
struct ath9k_tx_queue_info *qinfo)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
|
||||
struct ath9k_hw_capabilities *pCap = &ah->caps;
|
||||
struct ath9k_tx_queue_info *qi;
|
||||
|
||||
if (q >= pCap->total_queues) {
|
||||
@ -537,7 +525,7 @@ bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
|
||||
return false;
|
||||
}
|
||||
|
||||
qi = &ahp->ah_txq[q];
|
||||
qi = &ah->txq[q];
|
||||
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n");
|
||||
return false;
|
||||
@ -561,12 +549,11 @@ bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
|
||||
return true;
|
||||
}
|
||||
|
||||
int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
|
||||
int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
|
||||
const struct ath9k_tx_queue_info *qinfo)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
struct ath9k_tx_queue_info *qi;
|
||||
struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
|
||||
struct ath9k_hw_capabilities *pCap = &ah->caps;
|
||||
int q;
|
||||
|
||||
switch (type) {
|
||||
@ -584,7 +571,7 @@ int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
|
||||
break;
|
||||
case ATH9K_TX_QUEUE_DATA:
|
||||
for (q = 0; q < pCap->total_queues; q++)
|
||||
if (ahp->ah_txq[q].tqi_type ==
|
||||
if (ah->txq[q].tqi_type ==
|
||||
ATH9K_TX_QUEUE_INACTIVE)
|
||||
break;
|
||||
if (q == pCap->total_queues) {
|
||||
@ -600,7 +587,7 @@ int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q);
|
||||
|
||||
qi = &ahp->ah_txq[q];
|
||||
qi = &ah->txq[q];
|
||||
if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
|
||||
"tx queue %u already active\n", q);
|
||||
@ -627,17 +614,16 @@ int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
|
||||
return q;
|
||||
}
|
||||
|
||||
bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q)
|
||||
bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
|
||||
struct ath9k_hw_capabilities *pCap = &ah->caps;
|
||||
struct ath9k_tx_queue_info *qi;
|
||||
|
||||
if (q >= pCap->total_queues) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
|
||||
return false;
|
||||
}
|
||||
qi = &ahp->ah_txq[q];
|
||||
qi = &ah->txq[q];
|
||||
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q);
|
||||
return false;
|
||||
@ -646,21 +632,20 @@ bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q)
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "release queue %u\n", q);
|
||||
|
||||
qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
|
||||
ahp->ah_txOkInterruptMask &= ~(1 << q);
|
||||
ahp->ah_txErrInterruptMask &= ~(1 << q);
|
||||
ahp->ah_txDescInterruptMask &= ~(1 << q);
|
||||
ahp->ah_txEolInterruptMask &= ~(1 << q);
|
||||
ahp->ah_txUrnInterruptMask &= ~(1 << q);
|
||||
ah->txok_interrupt_mask &= ~(1 << q);
|
||||
ah->txerr_interrupt_mask &= ~(1 << q);
|
||||
ah->txdesc_interrupt_mask &= ~(1 << q);
|
||||
ah->txeol_interrupt_mask &= ~(1 << q);
|
||||
ah->txurn_interrupt_mask &= ~(1 << q);
|
||||
ath9k_hw_set_txq_interrupts(ah, qi);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q)
|
||||
bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
|
||||
struct ath9k_channel *chan = ah->ah_curchan;
|
||||
struct ath9k_hw_capabilities *pCap = &ah->caps;
|
||||
struct ath9k_channel *chan = ah->curchan;
|
||||
struct ath9k_tx_queue_info *qi;
|
||||
u32 cwMin, chanCwMin, value;
|
||||
|
||||
@ -669,7 +654,7 @@ bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q)
|
||||
return false;
|
||||
}
|
||||
|
||||
qi = &ahp->ah_txq[q];
|
||||
qi = &ah->txq[q];
|
||||
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q);
|
||||
return true;
|
||||
@ -757,9 +742,9 @@ bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q)
|
||||
| AR_Q_MISC_CBR_INCR_DIS1
|
||||
| AR_Q_MISC_CBR_INCR_DIS0);
|
||||
value = (qi->tqi_readyTime -
|
||||
(ah->ah_config.sw_beacon_response_time -
|
||||
ah->ah_config.dma_beacon_response_time) -
|
||||
ah->ah_config.additional_swba_backoff) * 1024;
|
||||
(ah->config.sw_beacon_response_time -
|
||||
ah->config.dma_beacon_response_time) -
|
||||
ah->config.additional_swba_backoff) * 1024;
|
||||
REG_WRITE(ah, AR_QRDYTIMECFG(q),
|
||||
value | AR_Q_RDYTIMECFG_EN);
|
||||
REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
|
||||
@ -787,31 +772,31 @@ bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q)
|
||||
}
|
||||
|
||||
if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE)
|
||||
ahp->ah_txOkInterruptMask |= 1 << q;
|
||||
ah->txok_interrupt_mask |= 1 << q;
|
||||
else
|
||||
ahp->ah_txOkInterruptMask &= ~(1 << q);
|
||||
ah->txok_interrupt_mask &= ~(1 << q);
|
||||
if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE)
|
||||
ahp->ah_txErrInterruptMask |= 1 << q;
|
||||
ah->txerr_interrupt_mask |= 1 << q;
|
||||
else
|
||||
ahp->ah_txErrInterruptMask &= ~(1 << q);
|
||||
ah->txerr_interrupt_mask &= ~(1 << q);
|
||||
if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE)
|
||||
ahp->ah_txDescInterruptMask |= 1 << q;
|
||||
ah->txdesc_interrupt_mask |= 1 << q;
|
||||
else
|
||||
ahp->ah_txDescInterruptMask &= ~(1 << q);
|
||||
ah->txdesc_interrupt_mask &= ~(1 << q);
|
||||
if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE)
|
||||
ahp->ah_txEolInterruptMask |= 1 << q;
|
||||
ah->txeol_interrupt_mask |= 1 << q;
|
||||
else
|
||||
ahp->ah_txEolInterruptMask &= ~(1 << q);
|
||||
ah->txeol_interrupt_mask &= ~(1 << q);
|
||||
if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE)
|
||||
ahp->ah_txUrnInterruptMask |= 1 << q;
|
||||
ah->txurn_interrupt_mask |= 1 << q;
|
||||
else
|
||||
ahp->ah_txUrnInterruptMask &= ~(1 << q);
|
||||
ah->txurn_interrupt_mask &= ~(1 << q);
|
||||
ath9k_hw_set_txq_interrupts(ah, qi);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds,
|
||||
int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
|
||||
u32 pa, struct ath_desc *nds, u64 tsf)
|
||||
{
|
||||
struct ar5416_desc ads;
|
||||
@ -876,11 +861,11 @@ int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds,
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds,
|
||||
bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
|
||||
u32 size, u32 flags)
|
||||
{
|
||||
struct ar5416_desc *ads = AR5416DESC(ds);
|
||||
struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
|
||||
struct ath9k_hw_capabilities *pCap = &ah->caps;
|
||||
|
||||
ads->ds_ctl1 = size & AR_BufLen;
|
||||
if (flags & ATH9K_RXDESC_INTREQ)
|
||||
@ -893,7 +878,7 @@ bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set)
|
||||
bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
@ -920,17 +905,17 @@ bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set)
|
||||
return true;
|
||||
}
|
||||
|
||||
void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp)
|
||||
void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp)
|
||||
{
|
||||
REG_WRITE(ah, AR_RXDP, rxdp);
|
||||
}
|
||||
|
||||
void ath9k_hw_rxena(struct ath_hal *ah)
|
||||
void ath9k_hw_rxena(struct ath_hw *ah)
|
||||
{
|
||||
REG_WRITE(ah, AR_CR, AR_CR_RXE);
|
||||
}
|
||||
|
||||
void ath9k_hw_startpcureceive(struct ath_hal *ah)
|
||||
void ath9k_hw_startpcureceive(struct ath_hw *ah)
|
||||
{
|
||||
ath9k_enable_mib_counters(ah);
|
||||
|
||||
@ -939,14 +924,14 @@ void ath9k_hw_startpcureceive(struct ath_hal *ah)
|
||||
REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
|
||||
}
|
||||
|
||||
void ath9k_hw_stoppcurecv(struct ath_hal *ah)
|
||||
void ath9k_hw_stoppcurecv(struct ath_hw *ah)
|
||||
{
|
||||
REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
|
||||
|
||||
ath9k_hw_disable_mib_counters(ah);
|
||||
}
|
||||
|
||||
bool ath9k_hw_stopdmarecv(struct ath_hal *ah)
|
||||
bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
|
||||
{
|
||||
REG_WRITE(ah, AR_CR, AR_CR_RXD);
|
||||
|
||||
|
676
drivers/net/wireless/ath9k/mac.h
Normal file
676
drivers/net/wireless/ath9k/mac.h
Normal file
@ -0,0 +1,676 @@
|
||||
/*
|
||||
* 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 MAC_H
|
||||
#define MAC_H
|
||||
|
||||
#define RXSTATUS_RATE(ah, ads) (AR_SREV_5416_V20_OR_LATER(ah) ? \
|
||||
MS(ads->ds_rxstatus0, AR_RxRate) : \
|
||||
(ads->ds_rxstatus3 >> 2) & 0xFF)
|
||||
|
||||
#define set11nTries(_series, _index) \
|
||||
(SM((_series)[_index].Tries, AR_XmitDataTries##_index))
|
||||
|
||||
#define set11nRate(_series, _index) \
|
||||
(SM((_series)[_index].Rate, AR_XmitRate##_index))
|
||||
|
||||
#define set11nPktDurRTSCTS(_series, _index) \
|
||||
(SM((_series)[_index].PktDuration, AR_PacketDur##_index) | \
|
||||
((_series)[_index].RateFlags & ATH9K_RATESERIES_RTS_CTS ? \
|
||||
AR_RTSCTSQual##_index : 0))
|
||||
|
||||
#define set11nRateFlags(_series, _index) \
|
||||
(((_series)[_index].RateFlags & ATH9K_RATESERIES_2040 ? \
|
||||
AR_2040_##_index : 0) \
|
||||
|((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ? \
|
||||
AR_GI##_index : 0) \
|
||||
|SM((_series)[_index].ChSel, AR_ChainSel##_index))
|
||||
|
||||
#define CCK_SIFS_TIME 10
|
||||
#define CCK_PREAMBLE_BITS 144
|
||||
#define CCK_PLCP_BITS 48
|
||||
|
||||
#define OFDM_SIFS_TIME 16
|
||||
#define OFDM_PREAMBLE_TIME 20
|
||||
#define OFDM_PLCP_BITS 22
|
||||
#define OFDM_SYMBOL_TIME 4
|
||||
|
||||
#define OFDM_SIFS_TIME_HALF 32
|
||||
#define OFDM_PREAMBLE_TIME_HALF 40
|
||||
#define OFDM_PLCP_BITS_HALF 22
|
||||
#define OFDM_SYMBOL_TIME_HALF 8
|
||||
|
||||
#define OFDM_SIFS_TIME_QUARTER 64
|
||||
#define OFDM_PREAMBLE_TIME_QUARTER 80
|
||||
#define OFDM_PLCP_BITS_QUARTER 22
|
||||
#define OFDM_SYMBOL_TIME_QUARTER 16
|
||||
|
||||
#define INIT_AIFS 2
|
||||
#define INIT_CWMIN 15
|
||||
#define INIT_CWMIN_11B 31
|
||||
#define INIT_CWMAX 1023
|
||||
#define INIT_SH_RETRY 10
|
||||
#define INIT_LG_RETRY 10
|
||||
#define INIT_SSH_RETRY 32
|
||||
#define INIT_SLG_RETRY 32
|
||||
|
||||
#define ATH9K_SLOT_TIME_6 6
|
||||
#define ATH9K_SLOT_TIME_9 9
|
||||
#define ATH9K_SLOT_TIME_20 20
|
||||
|
||||
#define ATH9K_TXERR_XRETRY 0x01
|
||||
#define ATH9K_TXERR_FILT 0x02
|
||||
#define ATH9K_TXERR_FIFO 0x04
|
||||
#define ATH9K_TXERR_XTXOP 0x08
|
||||
#define ATH9K_TXERR_TIMER_EXPIRED 0x10
|
||||
|
||||
#define ATH9K_TX_BA 0x01
|
||||
#define ATH9K_TX_PWRMGMT 0x02
|
||||
#define ATH9K_TX_DESC_CFG_ERR 0x04
|
||||
#define ATH9K_TX_DATA_UNDERRUN 0x08
|
||||
#define ATH9K_TX_DELIM_UNDERRUN 0x10
|
||||
#define ATH9K_TX_SW_ABORTED 0x40
|
||||
#define ATH9K_TX_SW_FILTERED 0x80
|
||||
|
||||
#define MIN_TX_FIFO_THRESHOLD 0x1
|
||||
#define MAX_TX_FIFO_THRESHOLD ((4096 / 64) - 1)
|
||||
#define INIT_TX_FIFO_THRESHOLD MIN_TX_FIFO_THRESHOLD
|
||||
|
||||
struct ath_tx_status {
|
||||
u32 ts_tstamp;
|
||||
u16 ts_seqnum;
|
||||
u8 ts_status;
|
||||
u8 ts_ratecode;
|
||||
u8 ts_rateindex;
|
||||
int8_t ts_rssi;
|
||||
u8 ts_shortretry;
|
||||
u8 ts_longretry;
|
||||
u8 ts_virtcol;
|
||||
u8 ts_antenna;
|
||||
u8 ts_flags;
|
||||
int8_t ts_rssi_ctl0;
|
||||
int8_t ts_rssi_ctl1;
|
||||
int8_t ts_rssi_ctl2;
|
||||
int8_t ts_rssi_ext0;
|
||||
int8_t ts_rssi_ext1;
|
||||
int8_t ts_rssi_ext2;
|
||||
u8 pad[3];
|
||||
u32 ba_low;
|
||||
u32 ba_high;
|
||||
u32 evm0;
|
||||
u32 evm1;
|
||||
u32 evm2;
|
||||
};
|
||||
|
||||
struct ath_rx_status {
|
||||
u32 rs_tstamp;
|
||||
u16 rs_datalen;
|
||||
u8 rs_status;
|
||||
u8 rs_phyerr;
|
||||
int8_t rs_rssi;
|
||||
u8 rs_keyix;
|
||||
u8 rs_rate;
|
||||
u8 rs_antenna;
|
||||
u8 rs_more;
|
||||
int8_t rs_rssi_ctl0;
|
||||
int8_t rs_rssi_ctl1;
|
||||
int8_t rs_rssi_ctl2;
|
||||
int8_t rs_rssi_ext0;
|
||||
int8_t rs_rssi_ext1;
|
||||
int8_t rs_rssi_ext2;
|
||||
u8 rs_isaggr;
|
||||
u8 rs_moreaggr;
|
||||
u8 rs_num_delims;
|
||||
u8 rs_flags;
|
||||
u32 evm0;
|
||||
u32 evm1;
|
||||
u32 evm2;
|
||||
};
|
||||
|
||||
#define ATH9K_RXERR_CRC 0x01
|
||||
#define ATH9K_RXERR_PHY 0x02
|
||||
#define ATH9K_RXERR_FIFO 0x04
|
||||
#define ATH9K_RXERR_DECRYPT 0x08
|
||||
#define ATH9K_RXERR_MIC 0x10
|
||||
|
||||
#define ATH9K_RX_MORE 0x01
|
||||
#define ATH9K_RX_MORE_AGGR 0x02
|
||||
#define ATH9K_RX_GI 0x04
|
||||
#define ATH9K_RX_2040 0x08
|
||||
#define ATH9K_RX_DELIM_CRC_PRE 0x10
|
||||
#define ATH9K_RX_DELIM_CRC_POST 0x20
|
||||
#define ATH9K_RX_DECRYPT_BUSY 0x40
|
||||
|
||||
#define ATH9K_RXKEYIX_INVALID ((u8)-1)
|
||||
#define ATH9K_TXKEYIX_INVALID ((u32)-1)
|
||||
|
||||
struct ath_desc {
|
||||
u32 ds_link;
|
||||
u32 ds_data;
|
||||
u32 ds_ctl0;
|
||||
u32 ds_ctl1;
|
||||
u32 ds_hw[20];
|
||||
union {
|
||||
struct ath_tx_status tx;
|
||||
struct ath_rx_status rx;
|
||||
void *stats;
|
||||
} ds_us;
|
||||
void *ds_vdata;
|
||||
} __packed;
|
||||
|
||||
#define ds_txstat ds_us.tx
|
||||
#define ds_rxstat ds_us.rx
|
||||
#define ds_stat ds_us.stats
|
||||
|
||||
#define ATH9K_TXDESC_CLRDMASK 0x0001
|
||||
#define ATH9K_TXDESC_NOACK 0x0002
|
||||
#define ATH9K_TXDESC_RTSENA 0x0004
|
||||
#define ATH9K_TXDESC_CTSENA 0x0008
|
||||
/* ATH9K_TXDESC_INTREQ forces a tx interrupt to be generated for
|
||||
* the descriptor its marked on. We take a tx interrupt to reap
|
||||
* descriptors when the h/w hits an EOL condition or
|
||||
* when the descriptor is specifically marked to generate
|
||||
* an interrupt with this flag. Descriptors should be
|
||||
* marked periodically to insure timely replenishing of the
|
||||
* supply needed for sending frames. Defering interrupts
|
||||
* reduces system load and potentially allows more concurrent
|
||||
* work to be done but if done to aggressively can cause
|
||||
* senders to backup. When the hardware queue is left too
|
||||
* large rate control information may also be too out of
|
||||
* date. An Alternative for this is TX interrupt mitigation
|
||||
* but this needs more testing. */
|
||||
#define ATH9K_TXDESC_INTREQ 0x0010
|
||||
#define ATH9K_TXDESC_VEOL 0x0020
|
||||
#define ATH9K_TXDESC_EXT_ONLY 0x0040
|
||||
#define ATH9K_TXDESC_EXT_AND_CTL 0x0080
|
||||
#define ATH9K_TXDESC_VMF 0x0100
|
||||
#define ATH9K_TXDESC_FRAG_IS_ON 0x0200
|
||||
#define ATH9K_TXDESC_CAB 0x0400
|
||||
|
||||
#define ATH9K_RXDESC_INTREQ 0x0020
|
||||
|
||||
struct ar5416_desc {
|
||||
u32 ds_link;
|
||||
u32 ds_data;
|
||||
u32 ds_ctl0;
|
||||
u32 ds_ctl1;
|
||||
union {
|
||||
struct {
|
||||
u32 ctl2;
|
||||
u32 ctl3;
|
||||
u32 ctl4;
|
||||
u32 ctl5;
|
||||
u32 ctl6;
|
||||
u32 ctl7;
|
||||
u32 ctl8;
|
||||
u32 ctl9;
|
||||
u32 ctl10;
|
||||
u32 ctl11;
|
||||
u32 status0;
|
||||
u32 status1;
|
||||
u32 status2;
|
||||
u32 status3;
|
||||
u32 status4;
|
||||
u32 status5;
|
||||
u32 status6;
|
||||
u32 status7;
|
||||
u32 status8;
|
||||
u32 status9;
|
||||
} tx;
|
||||
struct {
|
||||
u32 status0;
|
||||
u32 status1;
|
||||
u32 status2;
|
||||
u32 status3;
|
||||
u32 status4;
|
||||
u32 status5;
|
||||
u32 status6;
|
||||
u32 status7;
|
||||
u32 status8;
|
||||
} rx;
|
||||
} u;
|
||||
} __packed;
|
||||
|
||||
#define AR5416DESC(_ds) ((struct ar5416_desc *)(_ds))
|
||||
#define AR5416DESC_CONST(_ds) ((const struct ar5416_desc *)(_ds))
|
||||
|
||||
#define ds_ctl2 u.tx.ctl2
|
||||
#define ds_ctl3 u.tx.ctl3
|
||||
#define ds_ctl4 u.tx.ctl4
|
||||
#define ds_ctl5 u.tx.ctl5
|
||||
#define ds_ctl6 u.tx.ctl6
|
||||
#define ds_ctl7 u.tx.ctl7
|
||||
#define ds_ctl8 u.tx.ctl8
|
||||
#define ds_ctl9 u.tx.ctl9
|
||||
#define ds_ctl10 u.tx.ctl10
|
||||
#define ds_ctl11 u.tx.ctl11
|
||||
|
||||
#define ds_txstatus0 u.tx.status0
|
||||
#define ds_txstatus1 u.tx.status1
|
||||
#define ds_txstatus2 u.tx.status2
|
||||
#define ds_txstatus3 u.tx.status3
|
||||
#define ds_txstatus4 u.tx.status4
|
||||
#define ds_txstatus5 u.tx.status5
|
||||
#define ds_txstatus6 u.tx.status6
|
||||
#define ds_txstatus7 u.tx.status7
|
||||
#define ds_txstatus8 u.tx.status8
|
||||
#define ds_txstatus9 u.tx.status9
|
||||
|
||||
#define ds_rxstatus0 u.rx.status0
|
||||
#define ds_rxstatus1 u.rx.status1
|
||||
#define ds_rxstatus2 u.rx.status2
|
||||
#define ds_rxstatus3 u.rx.status3
|
||||
#define ds_rxstatus4 u.rx.status4
|
||||
#define ds_rxstatus5 u.rx.status5
|
||||
#define ds_rxstatus6 u.rx.status6
|
||||
#define ds_rxstatus7 u.rx.status7
|
||||
#define ds_rxstatus8 u.rx.status8
|
||||
|
||||
#define AR_FrameLen 0x00000fff
|
||||
#define AR_VirtMoreFrag 0x00001000
|
||||
#define AR_TxCtlRsvd00 0x0000e000
|
||||
#define AR_XmitPower 0x003f0000
|
||||
#define AR_XmitPower_S 16
|
||||
#define AR_RTSEnable 0x00400000
|
||||
#define AR_VEOL 0x00800000
|
||||
#define AR_ClrDestMask 0x01000000
|
||||
#define AR_TxCtlRsvd01 0x1e000000
|
||||
#define AR_TxIntrReq 0x20000000
|
||||
#define AR_DestIdxValid 0x40000000
|
||||
#define AR_CTSEnable 0x80000000
|
||||
|
||||
#define AR_BufLen 0x00000fff
|
||||
#define AR_TxMore 0x00001000
|
||||
#define AR_DestIdx 0x000fe000
|
||||
#define AR_DestIdx_S 13
|
||||
#define AR_FrameType 0x00f00000
|
||||
#define AR_FrameType_S 20
|
||||
#define AR_NoAck 0x01000000
|
||||
#define AR_InsertTS 0x02000000
|
||||
#define AR_CorruptFCS 0x04000000
|
||||
#define AR_ExtOnly 0x08000000
|
||||
#define AR_ExtAndCtl 0x10000000
|
||||
#define AR_MoreAggr 0x20000000
|
||||
#define AR_IsAggr 0x40000000
|
||||
|
||||
#define AR_BurstDur 0x00007fff
|
||||
#define AR_BurstDur_S 0
|
||||
#define AR_DurUpdateEna 0x00008000
|
||||
#define AR_XmitDataTries0 0x000f0000
|
||||
#define AR_XmitDataTries0_S 16
|
||||
#define AR_XmitDataTries1 0x00f00000
|
||||
#define AR_XmitDataTries1_S 20
|
||||
#define AR_XmitDataTries2 0x0f000000
|
||||
#define AR_XmitDataTries2_S 24
|
||||
#define AR_XmitDataTries3 0xf0000000
|
||||
#define AR_XmitDataTries3_S 28
|
||||
|
||||
#define AR_XmitRate0 0x000000ff
|
||||
#define AR_XmitRate0_S 0
|
||||
#define AR_XmitRate1 0x0000ff00
|
||||
#define AR_XmitRate1_S 8
|
||||
#define AR_XmitRate2 0x00ff0000
|
||||
#define AR_XmitRate2_S 16
|
||||
#define AR_XmitRate3 0xff000000
|
||||
#define AR_XmitRate3_S 24
|
||||
|
||||
#define AR_PacketDur0 0x00007fff
|
||||
#define AR_PacketDur0_S 0
|
||||
#define AR_RTSCTSQual0 0x00008000
|
||||
#define AR_PacketDur1 0x7fff0000
|
||||
#define AR_PacketDur1_S 16
|
||||
#define AR_RTSCTSQual1 0x80000000
|
||||
|
||||
#define AR_PacketDur2 0x00007fff
|
||||
#define AR_PacketDur2_S 0
|
||||
#define AR_RTSCTSQual2 0x00008000
|
||||
#define AR_PacketDur3 0x7fff0000
|
||||
#define AR_PacketDur3_S 16
|
||||
#define AR_RTSCTSQual3 0x80000000
|
||||
|
||||
#define AR_AggrLen 0x0000ffff
|
||||
#define AR_AggrLen_S 0
|
||||
#define AR_TxCtlRsvd60 0x00030000
|
||||
#define AR_PadDelim 0x03fc0000
|
||||
#define AR_PadDelim_S 18
|
||||
#define AR_EncrType 0x0c000000
|
||||
#define AR_EncrType_S 26
|
||||
#define AR_TxCtlRsvd61 0xf0000000
|
||||
|
||||
#define AR_2040_0 0x00000001
|
||||
#define AR_GI0 0x00000002
|
||||
#define AR_ChainSel0 0x0000001c
|
||||
#define AR_ChainSel0_S 2
|
||||
#define AR_2040_1 0x00000020
|
||||
#define AR_GI1 0x00000040
|
||||
#define AR_ChainSel1 0x00000380
|
||||
#define AR_ChainSel1_S 7
|
||||
#define AR_2040_2 0x00000400
|
||||
#define AR_GI2 0x00000800
|
||||
#define AR_ChainSel2 0x00007000
|
||||
#define AR_ChainSel2_S 12
|
||||
#define AR_2040_3 0x00008000
|
||||
#define AR_GI3 0x00010000
|
||||
#define AR_ChainSel3 0x000e0000
|
||||
#define AR_ChainSel3_S 17
|
||||
#define AR_RTSCTSRate 0x0ff00000
|
||||
#define AR_RTSCTSRate_S 20
|
||||
#define AR_TxCtlRsvd70 0xf0000000
|
||||
|
||||
#define AR_TxRSSIAnt00 0x000000ff
|
||||
#define AR_TxRSSIAnt00_S 0
|
||||
#define AR_TxRSSIAnt01 0x0000ff00
|
||||
#define AR_TxRSSIAnt01_S 8
|
||||
#define AR_TxRSSIAnt02 0x00ff0000
|
||||
#define AR_TxRSSIAnt02_S 16
|
||||
#define AR_TxStatusRsvd00 0x3f000000
|
||||
#define AR_TxBaStatus 0x40000000
|
||||
#define AR_TxStatusRsvd01 0x80000000
|
||||
|
||||
#define AR_FrmXmitOK 0x00000001
|
||||
#define AR_ExcessiveRetries 0x00000002
|
||||
#define AR_FIFOUnderrun 0x00000004
|
||||
#define AR_Filtered 0x00000008
|
||||
#define AR_RTSFailCnt 0x000000f0
|
||||
#define AR_RTSFailCnt_S 4
|
||||
#define AR_DataFailCnt 0x00000f00
|
||||
#define AR_DataFailCnt_S 8
|
||||
#define AR_VirtRetryCnt 0x0000f000
|
||||
#define AR_VirtRetryCnt_S 12
|
||||
#define AR_TxDelimUnderrun 0x00010000
|
||||
#define AR_TxDataUnderrun 0x00020000
|
||||
#define AR_DescCfgErr 0x00040000
|
||||
#define AR_TxTimerExpired 0x00080000
|
||||
#define AR_TxStatusRsvd10 0xfff00000
|
||||
|
||||
#define AR_SendTimestamp ds_txstatus2
|
||||
#define AR_BaBitmapLow ds_txstatus3
|
||||
#define AR_BaBitmapHigh ds_txstatus4
|
||||
|
||||
#define AR_TxRSSIAnt10 0x000000ff
|
||||
#define AR_TxRSSIAnt10_S 0
|
||||
#define AR_TxRSSIAnt11 0x0000ff00
|
||||
#define AR_TxRSSIAnt11_S 8
|
||||
#define AR_TxRSSIAnt12 0x00ff0000
|
||||
#define AR_TxRSSIAnt12_S 16
|
||||
#define AR_TxRSSICombined 0xff000000
|
||||
#define AR_TxRSSICombined_S 24
|
||||
|
||||
#define AR_TxEVM0 ds_txstatus5
|
||||
#define AR_TxEVM1 ds_txstatus6
|
||||
#define AR_TxEVM2 ds_txstatus7
|
||||
|
||||
#define AR_TxDone 0x00000001
|
||||
#define AR_SeqNum 0x00001ffe
|
||||
#define AR_SeqNum_S 1
|
||||
#define AR_TxStatusRsvd80 0x0001e000
|
||||
#define AR_TxOpExceeded 0x00020000
|
||||
#define AR_TxStatusRsvd81 0x001c0000
|
||||
#define AR_FinalTxIdx 0x00600000
|
||||
#define AR_FinalTxIdx_S 21
|
||||
#define AR_TxStatusRsvd82 0x01800000
|
||||
#define AR_PowerMgmt 0x02000000
|
||||
#define AR_TxStatusRsvd83 0xfc000000
|
||||
|
||||
#define AR_RxCTLRsvd00 0xffffffff
|
||||
|
||||
#define AR_BufLen 0x00000fff
|
||||
#define AR_RxCtlRsvd00 0x00001000
|
||||
#define AR_RxIntrReq 0x00002000
|
||||
#define AR_RxCtlRsvd01 0xffffc000
|
||||
|
||||
#define AR_RxRSSIAnt00 0x000000ff
|
||||
#define AR_RxRSSIAnt00_S 0
|
||||
#define AR_RxRSSIAnt01 0x0000ff00
|
||||
#define AR_RxRSSIAnt01_S 8
|
||||
#define AR_RxRSSIAnt02 0x00ff0000
|
||||
#define AR_RxRSSIAnt02_S 16
|
||||
#define AR_RxRate 0xff000000
|
||||
#define AR_RxRate_S 24
|
||||
#define AR_RxStatusRsvd00 0xff000000
|
||||
|
||||
#define AR_DataLen 0x00000fff
|
||||
#define AR_RxMore 0x00001000
|
||||
#define AR_NumDelim 0x003fc000
|
||||
#define AR_NumDelim_S 14
|
||||
#define AR_RxStatusRsvd10 0xff800000
|
||||
|
||||
#define AR_RcvTimestamp ds_rxstatus2
|
||||
|
||||
#define AR_GI 0x00000001
|
||||
#define AR_2040 0x00000002
|
||||
#define AR_Parallel40 0x00000004
|
||||
#define AR_Parallel40_S 2
|
||||
#define AR_RxStatusRsvd30 0x000000f8
|
||||
#define AR_RxAntenna 0xffffff00
|
||||
#define AR_RxAntenna_S 8
|
||||
|
||||
#define AR_RxRSSIAnt10 0x000000ff
|
||||
#define AR_RxRSSIAnt10_S 0
|
||||
#define AR_RxRSSIAnt11 0x0000ff00
|
||||
#define AR_RxRSSIAnt11_S 8
|
||||
#define AR_RxRSSIAnt12 0x00ff0000
|
||||
#define AR_RxRSSIAnt12_S 16
|
||||
#define AR_RxRSSICombined 0xff000000
|
||||
#define AR_RxRSSICombined_S 24
|
||||
|
||||
#define AR_RxEVM0 ds_rxstatus4
|
||||
#define AR_RxEVM1 ds_rxstatus5
|
||||
#define AR_RxEVM2 ds_rxstatus6
|
||||
|
||||
#define AR_RxDone 0x00000001
|
||||
#define AR_RxFrameOK 0x00000002
|
||||
#define AR_CRCErr 0x00000004
|
||||
#define AR_DecryptCRCErr 0x00000008
|
||||
#define AR_PHYErr 0x00000010
|
||||
#define AR_MichaelErr 0x00000020
|
||||
#define AR_PreDelimCRCErr 0x00000040
|
||||
#define AR_RxStatusRsvd70 0x00000080
|
||||
#define AR_RxKeyIdxValid 0x00000100
|
||||
#define AR_KeyIdx 0x0000fe00
|
||||
#define AR_KeyIdx_S 9
|
||||
#define AR_PHYErrCode 0x0000ff00
|
||||
#define AR_PHYErrCode_S 8
|
||||
#define AR_RxMoreAggr 0x00010000
|
||||
#define AR_RxAggr 0x00020000
|
||||
#define AR_PostDelimCRCErr 0x00040000
|
||||
#define AR_RxStatusRsvd71 0x3ff80000
|
||||
#define AR_DecryptBusyErr 0x40000000
|
||||
#define AR_KeyMiss 0x80000000
|
||||
|
||||
enum ath9k_tx_queue {
|
||||
ATH9K_TX_QUEUE_INACTIVE = 0,
|
||||
ATH9K_TX_QUEUE_DATA,
|
||||
ATH9K_TX_QUEUE_BEACON,
|
||||
ATH9K_TX_QUEUE_CAB,
|
||||
ATH9K_TX_QUEUE_UAPSD,
|
||||
ATH9K_TX_QUEUE_PSPOLL
|
||||
};
|
||||
|
||||
#define ATH9K_NUM_TX_QUEUES 10
|
||||
|
||||
enum ath9k_tx_queue_subtype {
|
||||
ATH9K_WME_AC_BK = 0,
|
||||
ATH9K_WME_AC_BE,
|
||||
ATH9K_WME_AC_VI,
|
||||
ATH9K_WME_AC_VO,
|
||||
ATH9K_WME_UPSD
|
||||
};
|
||||
|
||||
enum ath9k_tx_queue_flags {
|
||||
TXQ_FLAG_TXOKINT_ENABLE = 0x0001,
|
||||
TXQ_FLAG_TXERRINT_ENABLE = 0x0001,
|
||||
TXQ_FLAG_TXDESCINT_ENABLE = 0x0002,
|
||||
TXQ_FLAG_TXEOLINT_ENABLE = 0x0004,
|
||||
TXQ_FLAG_TXURNINT_ENABLE = 0x0008,
|
||||
TXQ_FLAG_BACKOFF_DISABLE = 0x0010,
|
||||
TXQ_FLAG_COMPRESSION_ENABLE = 0x0020,
|
||||
TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE = 0x0040,
|
||||
TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE = 0x0080,
|
||||
};
|
||||
|
||||
#define ATH9K_TXQ_USEDEFAULT ((u32) -1)
|
||||
#define ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS 0x00000001
|
||||
|
||||
#define ATH9K_DECOMP_MASK_SIZE 128
|
||||
#define ATH9K_READY_TIME_LO_BOUND 50
|
||||
#define ATH9K_READY_TIME_HI_BOUND 96
|
||||
|
||||
enum ath9k_pkt_type {
|
||||
ATH9K_PKT_TYPE_NORMAL = 0,
|
||||
ATH9K_PKT_TYPE_ATIM,
|
||||
ATH9K_PKT_TYPE_PSPOLL,
|
||||
ATH9K_PKT_TYPE_BEACON,
|
||||
ATH9K_PKT_TYPE_PROBE_RESP,
|
||||
ATH9K_PKT_TYPE_CHIRP,
|
||||
ATH9K_PKT_TYPE_GRP_POLL,
|
||||
};
|
||||
|
||||
struct ath9k_tx_queue_info {
|
||||
u32 tqi_ver;
|
||||
enum ath9k_tx_queue tqi_type;
|
||||
enum ath9k_tx_queue_subtype tqi_subtype;
|
||||
enum ath9k_tx_queue_flags tqi_qflags;
|
||||
u32 tqi_priority;
|
||||
u32 tqi_aifs;
|
||||
u32 tqi_cwmin;
|
||||
u32 tqi_cwmax;
|
||||
u16 tqi_shretry;
|
||||
u16 tqi_lgretry;
|
||||
u32 tqi_cbrPeriod;
|
||||
u32 tqi_cbrOverflowLimit;
|
||||
u32 tqi_burstTime;
|
||||
u32 tqi_readyTime;
|
||||
u32 tqi_physCompBuf;
|
||||
u32 tqi_intFlags;
|
||||
};
|
||||
|
||||
enum ath9k_rx_filter {
|
||||
ATH9K_RX_FILTER_UCAST = 0x00000001,
|
||||
ATH9K_RX_FILTER_MCAST = 0x00000002,
|
||||
ATH9K_RX_FILTER_BCAST = 0x00000004,
|
||||
ATH9K_RX_FILTER_CONTROL = 0x00000008,
|
||||
ATH9K_RX_FILTER_BEACON = 0x00000010,
|
||||
ATH9K_RX_FILTER_PROM = 0x00000020,
|
||||
ATH9K_RX_FILTER_PROBEREQ = 0x00000080,
|
||||
ATH9K_RX_FILTER_PSPOLL = 0x00004000,
|
||||
ATH9K_RX_FILTER_PHYERR = 0x00000100,
|
||||
ATH9K_RX_FILTER_PHYRADAR = 0x00002000,
|
||||
};
|
||||
|
||||
#define ATH9K_RATESERIES_RTS_CTS 0x0001
|
||||
#define ATH9K_RATESERIES_2040 0x0002
|
||||
#define ATH9K_RATESERIES_HALFGI 0x0004
|
||||
|
||||
struct ath9k_11n_rate_series {
|
||||
u32 Tries;
|
||||
u32 Rate;
|
||||
u32 PktDuration;
|
||||
u32 ChSel;
|
||||
u32 RateFlags;
|
||||
};
|
||||
|
||||
struct ath9k_keyval {
|
||||
u8 kv_type;
|
||||
u8 kv_pad;
|
||||
u16 kv_len;
|
||||
u8 kv_val[16];
|
||||
u8 kv_mic[8];
|
||||
u8 kv_txmic[8];
|
||||
};
|
||||
|
||||
enum ath9k_key_type {
|
||||
ATH9K_KEY_TYPE_CLEAR,
|
||||
ATH9K_KEY_TYPE_WEP,
|
||||
ATH9K_KEY_TYPE_AES,
|
||||
ATH9K_KEY_TYPE_TKIP,
|
||||
};
|
||||
|
||||
enum ath9k_cipher {
|
||||
ATH9K_CIPHER_WEP = 0,
|
||||
ATH9K_CIPHER_AES_OCB = 1,
|
||||
ATH9K_CIPHER_AES_CCM = 2,
|
||||
ATH9K_CIPHER_CKIP = 3,
|
||||
ATH9K_CIPHER_TKIP = 4,
|
||||
ATH9K_CIPHER_CLR = 5,
|
||||
ATH9K_CIPHER_MIC = 127
|
||||
};
|
||||
|
||||
enum ath9k_ht_macmode {
|
||||
ATH9K_HT_MACMODE_20 = 0,
|
||||
ATH9K_HT_MACMODE_2040 = 1,
|
||||
};
|
||||
|
||||
enum ath9k_ht_extprotspacing {
|
||||
ATH9K_HT_EXTPROTSPACING_20 = 0,
|
||||
ATH9K_HT_EXTPROTSPACING_25 = 1,
|
||||
};
|
||||
|
||||
struct ath_hw;
|
||||
struct ath9k_channel;
|
||||
struct ath_rate_table;
|
||||
|
||||
u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q);
|
||||
bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp);
|
||||
bool ath9k_hw_txstart(struct ath_hw *ah, u32 q);
|
||||
u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q);
|
||||
bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel);
|
||||
bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q);
|
||||
bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
|
||||
u32 segLen, bool firstSeg,
|
||||
bool lastSeg, const struct ath_desc *ds0);
|
||||
void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds);
|
||||
int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds);
|
||||
void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds,
|
||||
u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
|
||||
u32 keyIx, enum ath9k_key_type keyType, u32 flags);
|
||||
void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds,
|
||||
struct ath_desc *lastds,
|
||||
u32 durUpdateEn, u32 rtsctsRate,
|
||||
u32 rtsctsDuration,
|
||||
struct ath9k_11n_rate_series series[],
|
||||
u32 nseries, u32 flags);
|
||||
void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds,
|
||||
u32 aggrLen);
|
||||
void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds,
|
||||
u32 numDelims);
|
||||
void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds);
|
||||
void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds);
|
||||
void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds,
|
||||
u32 burstDuration);
|
||||
void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds,
|
||||
u32 vmf);
|
||||
void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs);
|
||||
bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
|
||||
const struct ath9k_tx_queue_info *qinfo);
|
||||
bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q,
|
||||
struct ath9k_tx_queue_info *qinfo);
|
||||
int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
|
||||
const struct ath9k_tx_queue_info *qinfo);
|
||||
bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q);
|
||||
bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q);
|
||||
int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
|
||||
u32 pa, struct ath_desc *nds, u64 tsf);
|
||||
bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
|
||||
u32 size, u32 flags);
|
||||
bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set);
|
||||
void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp);
|
||||
void ath9k_hw_rxena(struct ath_hw *ah);
|
||||
void ath9k_hw_startpcureceive(struct ath_hw *ah);
|
||||
void ath9k_hw_stoppcurecv(struct ath_hw *ah);
|
||||
bool ath9k_hw_stopdmarecv(struct ath_hw *ah);
|
||||
|
||||
#endif /* MAC_H */
|
File diff suppressed because it is too large
Load Diff
@ -16,9 +16,7 @@
|
||||
|
||||
#include <linux/nl80211.h>
|
||||
#include <linux/pci.h>
|
||||
#include "core.h"
|
||||
#include "reg.h"
|
||||
#include "hw.h"
|
||||
#include "ath9k.h"
|
||||
|
||||
static struct pci_device_id ath_pci_id_table[] __devinitdata = {
|
||||
{ PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI */
|
||||
@ -58,7 +56,7 @@ static void ath_pci_cleanup(struct ath_softc *sc)
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
static bool ath_pci_eeprom_read(struct ath_hal *ah, u32 off, u16 *data)
|
||||
static bool ath_pci_eeprom_read(struct ath_hw *ah, u32 off, u16 *data)
|
||||
{
|
||||
(void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
|
||||
|
||||
@ -89,7 +87,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
u8 csz;
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
struct ath_hal *ah;
|
||||
struct ath_hw *ah;
|
||||
|
||||
if (pci_enable_device(pdev))
|
||||
return -EIO;
|
||||
@ -192,10 +190,10 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
"%s: Atheros AR%s MAC/BB Rev:%x "
|
||||
"AR%s RF Rev:%x: mem=0x%lx, irq=%d\n",
|
||||
wiphy_name(hw->wiphy),
|
||||
ath_mac_bb_name(ah->ah_macVersion),
|
||||
ah->ah_macRev,
|
||||
ath_rf_name((ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)),
|
||||
ah->ah_phyRev,
|
||||
ath_mac_bb_name(ah->hw_version.macVersion),
|
||||
ah->hw_version.macRev,
|
||||
ath_rf_name((ah->hw_version.analog5GhzRev & AR_RADIO_SREV_MAJOR)),
|
||||
ah->hw_version.phyRev,
|
||||
(unsigned long)mem, pdev->irq);
|
||||
|
||||
return 0;
|
||||
@ -230,7 +228,7 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
|
||||
|
||||
#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
|
||||
if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
|
||||
cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
|
||||
#endif
|
||||
|
||||
@ -271,7 +269,7 @@ static int ath_pci_resume(struct pci_dev *pdev)
|
||||
* check the h/w rfkill state on resume
|
||||
* and start the rfkill poll timer
|
||||
*/
|
||||
if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
|
||||
queue_delayed_work(sc->hw->workqueue,
|
||||
&sc->rf_kill.rfkill_poll, 0);
|
||||
#endif
|
||||
|
@ -14,22 +14,17 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
#include "hw.h"
|
||||
#include "reg.h"
|
||||
#include "phy.h"
|
||||
#include "ath9k.h"
|
||||
|
||||
void
|
||||
ath9k_hw_write_regs(struct ath_hal *ah, u32 modesIndex, u32 freqIndex,
|
||||
ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, u32 freqIndex,
|
||||
int regWrites)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
|
||||
REG_WRITE_ARRAY(&ahp->ah_iniBB_RfGain, freqIndex, regWrites);
|
||||
REG_WRITE_ARRAY(&ah->iniBB_RfGain, freqIndex, regWrites);
|
||||
}
|
||||
|
||||
bool
|
||||
ath9k_hw_set_channel(struct ath_hal *ah, struct ath9k_channel *chan)
|
||||
ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||
{
|
||||
u32 channelSel = 0;
|
||||
u32 bModeSynth = 0;
|
||||
@ -95,15 +90,14 @@ ath9k_hw_set_channel(struct ath_hal *ah, struct ath9k_channel *chan)
|
||||
|
||||
REG_WRITE(ah, AR_PHY(0x37), reg32);
|
||||
|
||||
ah->ah_curchan = chan;
|
||||
|
||||
AH5416(ah)->ah_curchanRadIndex = -1;
|
||||
ah->curchan = chan;
|
||||
ah->curchan_rad_index = -1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ath9k_hw_ar9280_set_channel(struct ath_hal *ah,
|
||||
ath9k_hw_ar9280_set_channel(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan)
|
||||
{
|
||||
u16 bMode, fracMode, aModeRefSel = 0;
|
||||
@ -166,9 +160,8 @@ ath9k_hw_ar9280_set_channel(struct ath_hal *ah,
|
||||
|
||||
REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32);
|
||||
|
||||
ah->ah_curchan = chan;
|
||||
|
||||
AH5416(ah)->ah_curchanRadIndex = -1;
|
||||
ah->curchan = chan;
|
||||
ah->curchan_rad_index = -1;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -201,11 +194,9 @@ ath9k_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32,
|
||||
}
|
||||
|
||||
bool
|
||||
ath9k_hw_set_rf_regs(struct ath_hal *ah, struct ath9k_channel *chan,
|
||||
ath9k_hw_set_rf_regs(struct ath_hw *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;
|
||||
@ -214,161 +205,156 @@ ath9k_hw_set_rf_regs(struct ath_hal *ah, struct ath9k_channel *chan,
|
||||
if (AR_SREV_9280_10_OR_LATER(ah))
|
||||
return true;
|
||||
|
||||
eepMinorRev = ath9k_hw_get_eeprom(ah, EEP_MINOR_REV);
|
||||
eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV);
|
||||
|
||||
RF_BANK_SETUP(ahp->ah_analogBank0Data, &ahp->ah_iniBank0, 1);
|
||||
RF_BANK_SETUP(ah->analogBank0Data, &ah->iniBank0, 1);
|
||||
|
||||
RF_BANK_SETUP(ahp->ah_analogBank1Data, &ahp->ah_iniBank1, 1);
|
||||
RF_BANK_SETUP(ah->analogBank1Data, &ah->iniBank1, 1);
|
||||
|
||||
RF_BANK_SETUP(ahp->ah_analogBank2Data, &ahp->ah_iniBank2, 1);
|
||||
RF_BANK_SETUP(ah->analogBank2Data, &ah->iniBank2, 1);
|
||||
|
||||
RF_BANK_SETUP(ahp->ah_analogBank3Data, &ahp->ah_iniBank3,
|
||||
RF_BANK_SETUP(ah->analogBank3Data, &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);
|
||||
for (i = 0; i < ah->iniBank6TPC.ia_rows; i++) {
|
||||
ah->analogBank6Data[i] =
|
||||
INI_RA(&ah->iniBank6TPC, i, modesIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (eepMinorRev >= 2) {
|
||||
if (IS_CHAN_2GHZ(chan)) {
|
||||
ob2GHz = ath9k_hw_get_eeprom(ah, EEP_OB_2);
|
||||
db2GHz = ath9k_hw_get_eeprom(ah, EEP_DB_2);
|
||||
ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
|
||||
ob2GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_2);
|
||||
db2GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_2);
|
||||
ath9k_phy_modify_rx_buffer(ah->analogBank6Data,
|
||||
ob2GHz, 3, 197, 0);
|
||||
ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
|
||||
ath9k_phy_modify_rx_buffer(ah->analogBank6Data,
|
||||
db2GHz, 3, 194, 0);
|
||||
} else {
|
||||
ob5GHz = ath9k_hw_get_eeprom(ah, EEP_OB_5);
|
||||
db5GHz = ath9k_hw_get_eeprom(ah, EEP_DB_5);
|
||||
ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
|
||||
ob5GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_5);
|
||||
db5GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_5);
|
||||
ath9k_phy_modify_rx_buffer(ah->analogBank6Data,
|
||||
ob5GHz, 3, 203, 0);
|
||||
ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
|
||||
ath9k_phy_modify_rx_buffer(ah->analogBank6Data,
|
||||
db5GHz, 3, 200, 0);
|
||||
}
|
||||
}
|
||||
|
||||
RF_BANK_SETUP(ahp->ah_analogBank7Data, &ahp->ah_iniBank7, 1);
|
||||
RF_BANK_SETUP(ah->analogBank7Data, &ah->iniBank7, 1);
|
||||
|
||||
REG_WRITE_RF_ARRAY(&ahp->ah_iniBank0, ahp->ah_analogBank0Data,
|
||||
REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data,
|
||||
regWrites);
|
||||
REG_WRITE_RF_ARRAY(&ahp->ah_iniBank1, ahp->ah_analogBank1Data,
|
||||
REG_WRITE_RF_ARRAY(&ah->iniBank1, ah->analogBank1Data,
|
||||
regWrites);
|
||||
REG_WRITE_RF_ARRAY(&ahp->ah_iniBank2, ahp->ah_analogBank2Data,
|
||||
REG_WRITE_RF_ARRAY(&ah->iniBank2, ah->analogBank2Data,
|
||||
regWrites);
|
||||
REG_WRITE_RF_ARRAY(&ahp->ah_iniBank3, ahp->ah_analogBank3Data,
|
||||
REG_WRITE_RF_ARRAY(&ah->iniBank3, ah->analogBank3Data,
|
||||
regWrites);
|
||||
REG_WRITE_RF_ARRAY(&ahp->ah_iniBank6TPC, ahp->ah_analogBank6Data,
|
||||
REG_WRITE_RF_ARRAY(&ah->iniBank6TPC, ah->analogBank6Data,
|
||||
regWrites);
|
||||
REG_WRITE_RF_ARRAY(&ahp->ah_iniBank7, ahp->ah_analogBank7Data,
|
||||
REG_WRITE_RF_ARRAY(&ah->iniBank7, ah->analogBank7Data,
|
||||
regWrites);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ath9k_hw_rfdetach(struct ath_hal *ah)
|
||||
ath9k_hw_rfdetach(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
|
||||
if (ahp->ah_analogBank0Data != NULL) {
|
||||
kfree(ahp->ah_analogBank0Data);
|
||||
ahp->ah_analogBank0Data = NULL;
|
||||
if (ah->analogBank0Data != NULL) {
|
||||
kfree(ah->analogBank0Data);
|
||||
ah->analogBank0Data = NULL;
|
||||
}
|
||||
if (ahp->ah_analogBank1Data != NULL) {
|
||||
kfree(ahp->ah_analogBank1Data);
|
||||
ahp->ah_analogBank1Data = NULL;
|
||||
if (ah->analogBank1Data != NULL) {
|
||||
kfree(ah->analogBank1Data);
|
||||
ah->analogBank1Data = NULL;
|
||||
}
|
||||
if (ahp->ah_analogBank2Data != NULL) {
|
||||
kfree(ahp->ah_analogBank2Data);
|
||||
ahp->ah_analogBank2Data = NULL;
|
||||
if (ah->analogBank2Data != NULL) {
|
||||
kfree(ah->analogBank2Data);
|
||||
ah->analogBank2Data = NULL;
|
||||
}
|
||||
if (ahp->ah_analogBank3Data != NULL) {
|
||||
kfree(ahp->ah_analogBank3Data);
|
||||
ahp->ah_analogBank3Data = NULL;
|
||||
if (ah->analogBank3Data != NULL) {
|
||||
kfree(ah->analogBank3Data);
|
||||
ah->analogBank3Data = NULL;
|
||||
}
|
||||
if (ahp->ah_analogBank6Data != NULL) {
|
||||
kfree(ahp->ah_analogBank6Data);
|
||||
ahp->ah_analogBank6Data = NULL;
|
||||
if (ah->analogBank6Data != NULL) {
|
||||
kfree(ah->analogBank6Data);
|
||||
ah->analogBank6Data = NULL;
|
||||
}
|
||||
if (ahp->ah_analogBank6TPCData != NULL) {
|
||||
kfree(ahp->ah_analogBank6TPCData);
|
||||
ahp->ah_analogBank6TPCData = NULL;
|
||||
if (ah->analogBank6TPCData != NULL) {
|
||||
kfree(ah->analogBank6TPCData);
|
||||
ah->analogBank6TPCData = NULL;
|
||||
}
|
||||
if (ahp->ah_analogBank7Data != NULL) {
|
||||
kfree(ahp->ah_analogBank7Data);
|
||||
ahp->ah_analogBank7Data = NULL;
|
||||
if (ah->analogBank7Data != NULL) {
|
||||
kfree(ah->analogBank7Data);
|
||||
ah->analogBank7Data = NULL;
|
||||
}
|
||||
if (ahp->ah_addac5416_21 != NULL) {
|
||||
kfree(ahp->ah_addac5416_21);
|
||||
ahp->ah_addac5416_21 = NULL;
|
||||
if (ah->addac5416_21 != NULL) {
|
||||
kfree(ah->addac5416_21);
|
||||
ah->addac5416_21 = NULL;
|
||||
}
|
||||
if (ahp->ah_bank6Temp != NULL) {
|
||||
kfree(ahp->ah_bank6Temp);
|
||||
ahp->ah_bank6Temp = NULL;
|
||||
if (ah->bank6Temp != NULL) {
|
||||
kfree(ah->bank6Temp);
|
||||
ah->bank6Temp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool ath9k_hw_init_rf(struct ath_hal *ah, int *status)
|
||||
bool ath9k_hw_init_rf(struct ath_hw *ah, int *status)
|
||||
{
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
|
||||
if (!AR_SREV_9280_10_OR_LATER(ah)) {
|
||||
ah->analogBank0Data =
|
||||
kzalloc((sizeof(u32) *
|
||||
ah->iniBank0.ia_rows), GFP_KERNEL);
|
||||
ah->analogBank1Data =
|
||||
kzalloc((sizeof(u32) *
|
||||
ah->iniBank1.ia_rows), GFP_KERNEL);
|
||||
ah->analogBank2Data =
|
||||
kzalloc((sizeof(u32) *
|
||||
ah->iniBank2.ia_rows), GFP_KERNEL);
|
||||
ah->analogBank3Data =
|
||||
kzalloc((sizeof(u32) *
|
||||
ah->iniBank3.ia_rows), GFP_KERNEL);
|
||||
ah->analogBank6Data =
|
||||
kzalloc((sizeof(u32) *
|
||||
ah->iniBank6.ia_rows), GFP_KERNEL);
|
||||
ah->analogBank6TPCData =
|
||||
kzalloc((sizeof(u32) *
|
||||
ah->iniBank6TPC.ia_rows), GFP_KERNEL);
|
||||
ah->analogBank7Data =
|
||||
kzalloc((sizeof(u32) *
|
||||
ah->iniBank7.ia_rows), GFP_KERNEL);
|
||||
|
||||
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) {
|
||||
if (ah->analogBank0Data == NULL
|
||||
|| ah->analogBank1Data == NULL
|
||||
|| ah->analogBank2Data == NULL
|
||||
|| ah->analogBank3Data == NULL
|
||||
|| ah->analogBank6Data == NULL
|
||||
|| ah->analogBank6TPCData == NULL
|
||||
|| ah->analogBank7Data == NULL) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"Cannot allocate RF banks\n");
|
||||
*status = -ENOMEM;
|
||||
return false;
|
||||
}
|
||||
|
||||
ahp->ah_addac5416_21 =
|
||||
ah->addac5416_21 =
|
||||
kzalloc((sizeof(u32) *
|
||||
ahp->ah_iniAddac.ia_rows *
|
||||
ahp->ah_iniAddac.ia_columns), GFP_KERNEL);
|
||||
if (ahp->ah_addac5416_21 == NULL) {
|
||||
ah->iniAddac.ia_rows *
|
||||
ah->iniAddac.ia_columns), GFP_KERNEL);
|
||||
if (ah->addac5416_21 == NULL) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"Cannot allocate ah_addac5416_21\n");
|
||||
"Cannot allocate addac5416_21\n");
|
||||
*status = -ENOMEM;
|
||||
return false;
|
||||
}
|
||||
|
||||
ahp->ah_bank6Temp =
|
||||
ah->bank6Temp =
|
||||
kzalloc((sizeof(u32) *
|
||||
ahp->ah_iniBank6.ia_rows), GFP_KERNEL);
|
||||
if (ahp->ah_bank6Temp == NULL) {
|
||||
ah->iniBank6.ia_rows), GFP_KERNEL);
|
||||
if (ah->bank6Temp == NULL) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"Cannot allocate ah_bank6Temp\n");
|
||||
"Cannot allocate bank6Temp\n");
|
||||
*status = -ENOMEM;
|
||||
return false;
|
||||
}
|
||||
@ -378,24 +364,23 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, int *status)
|
||||
}
|
||||
|
||||
void
|
||||
ath9k_hw_decrease_chain_power(struct ath_hal *ah, struct ath9k_channel *chan)
|
||||
ath9k_hw_decrease_chain_power(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||
{
|
||||
int i, regWrites = 0;
|
||||
struct ath_hal_5416 *ahp = AH5416(ah);
|
||||
u32 bank6SelMask;
|
||||
u32 *bank6Temp = ahp->ah_bank6Temp;
|
||||
u32 *bank6Temp = ah->bank6Temp;
|
||||
|
||||
switch (ahp->ah_diversityControl) {
|
||||
switch (ah->diversity_control) {
|
||||
case ATH9K_ANT_FIXED_A:
|
||||
bank6SelMask =
|
||||
(ahp->
|
||||
ah_antennaSwitchSwap & ANTSWAP_AB) ? REDUCE_CHAIN_0 :
|
||||
(ah->
|
||||
antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_0 :
|
||||
REDUCE_CHAIN_1;
|
||||
break;
|
||||
case ATH9K_ANT_FIXED_B:
|
||||
bank6SelMask =
|
||||
(ahp->
|
||||
ah_antennaSwitchSwap & ANTSWAP_AB) ? REDUCE_CHAIN_1 :
|
||||
(ah->
|
||||
antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_1 :
|
||||
REDUCE_CHAIN_0;
|
||||
break;
|
||||
case ATH9K_ANT_VARIABLE:
|
||||
@ -406,8 +391,8 @@ ath9k_hw_decrease_chain_power(struct ath_hal *ah, struct ath9k_channel *chan)
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < ahp->ah_iniBank6.ia_rows; i++)
|
||||
bank6Temp[i] = ahp->ah_analogBank6Data[i];
|
||||
for (i = 0; i < ah->iniBank6.ia_rows; i++)
|
||||
bank6Temp[i] = ah->analogBank6Data[i];
|
||||
|
||||
REG_WRITE(ah, AR_PHY_BASE + 0xD8, bank6SelMask);
|
||||
|
||||
@ -421,7 +406,7 @@ ath9k_hw_decrease_chain_power(struct ath_hal *ah, struct ath9k_channel *chan)
|
||||
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_RF_ARRAY(&ah->iniBank6, bank6Temp, regWrites);
|
||||
|
||||
REG_WRITE(ah, AR_PHY_BASE + 0xD8, 0x00000053);
|
||||
#ifdef ALTER_SWITCH
|
||||
|
@ -17,19 +17,19 @@
|
||||
#ifndef PHY_H
|
||||
#define PHY_H
|
||||
|
||||
bool ath9k_hw_ar9280_set_channel(struct ath_hal *ah,
|
||||
bool ath9k_hw_ar9280_set_channel(struct ath_hw *ah,
|
||||
struct ath9k_channel
|
||||
*chan);
|
||||
bool ath9k_hw_set_channel(struct ath_hal *ah,
|
||||
bool ath9k_hw_set_channel(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan);
|
||||
void ath9k_hw_write_regs(struct ath_hal *ah, u32 modesIndex,
|
||||
void ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex,
|
||||
u32 freqIndex, int regWrites);
|
||||
bool ath9k_hw_set_rf_regs(struct ath_hal *ah,
|
||||
bool ath9k_hw_set_rf_regs(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan,
|
||||
u16 modesIndex);
|
||||
void ath9k_hw_decrease_chain_power(struct ath_hal *ah,
|
||||
void ath9k_hw_decrease_chain_power(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan);
|
||||
bool ath9k_hw_init_rf(struct ath_hal *ah,
|
||||
bool ath9k_hw_init_rf(struct ath_hw *ah,
|
||||
int *status);
|
||||
|
||||
#define AR_PHY_BASE 0x9800
|
||||
@ -533,7 +533,7 @@ bool ath9k_hw_init_rf(struct ath_hal *ah,
|
||||
#define ATH9K_KEY_XOR 0xaa
|
||||
|
||||
#define ATH9K_IS_MIC_ENABLED(ah) \
|
||||
(AH5416(ah)->ah_staId1Defaults & AR_STA_ID1_CRPT_MIC_ENABLE)
|
||||
((ah)->sta_id1_defaults & AR_STA_ID1_CRPT_MIC_ENABLE)
|
||||
|
||||
#define ANTSWAP_AB 0x0001
|
||||
#define REDUCE_CHAIN_0 0x00000050
|
||||
|
@ -15,7 +15,7 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
#include "ath9k.h"
|
||||
|
||||
static struct ath_rate_table ar5416_11na_ratetable = {
|
||||
42,
|
||||
@ -1267,6 +1267,8 @@ static void ath_rc_update_ht(struct ath_softc *sc,
|
||||
ath_rc_priv->per_down_time = now_msec;
|
||||
}
|
||||
|
||||
ath_debug_stat_retries(sc, tx_rate, xretries, retries);
|
||||
|
||||
#undef CHK_RSSI
|
||||
}
|
||||
|
||||
@ -1392,13 +1394,13 @@ static void ath_rc_init(struct ath_softc *sc,
|
||||
u8 i, j, k, hi = 0, hthi = 0;
|
||||
|
||||
/* FIXME: Adhoc */
|
||||
if ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) ||
|
||||
(sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC)) {
|
||||
if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) ||
|
||||
(sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)) {
|
||||
bool is_cw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
|
||||
rate_table = ath_choose_rate_table(sc, sband->band,
|
||||
sta->ht_cap.ht_supported,
|
||||
is_cw_40);
|
||||
} else if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) {
|
||||
} else if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
|
||||
/* cur_rate_table would be set on init through config() */
|
||||
rate_table = sc->cur_rate_table;
|
||||
}
|
||||
@ -1410,7 +1412,7 @@ static void ath_rc_init(struct ath_softc *sc,
|
||||
|
||||
if (sta->ht_cap.ht_supported) {
|
||||
ath_rc_priv->ht_cap = WLAN_RC_HT_FLAG;
|
||||
if (sc->sc_ah->ah_caps.tx_chainmask != 1)
|
||||
if (sc->sc_ah->caps.tx_chainmask != 1)
|
||||
ath_rc_priv->ht_cap |= WLAN_RC_DS_FLAG;
|
||||
if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
|
||||
ath_rc_priv->ht_cap |= WLAN_RC_40_FLAG;
|
||||
@ -1517,7 +1519,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
||||
*/
|
||||
if (tx_info_priv->tx.ts_flags &
|
||||
(ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) &&
|
||||
((sc->sc_ah->ah_txTrigLevel) >= ath_rc_priv->tx_triglevel_max)) {
|
||||
((sc->sc_ah->tx_trig_level) >= ath_rc_priv->tx_triglevel_max)) {
|
||||
tx_status = 1;
|
||||
is_underrun = 1;
|
||||
}
|
||||
@ -1626,7 +1628,7 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp
|
||||
}
|
||||
|
||||
rate_priv->rssi_down_time = jiffies_to_msecs(jiffies);
|
||||
rate_priv->tx_triglevel_max = sc->sc_ah->ah_caps.tx_triglevel_max;
|
||||
rate_priv->tx_triglevel_max = sc->sc_ah->caps.tx_triglevel_max;
|
||||
|
||||
return rate_priv;
|
||||
}
|
||||
|
@ -19,13 +19,12 @@
|
||||
#ifndef RC_H
|
||||
#define RC_H
|
||||
|
||||
#include "ath9k.h"
|
||||
|
||||
struct ath_softc;
|
||||
|
||||
#define ATH_RATE_MAX 30
|
||||
#define RATE_TABLE_SIZE 64
|
||||
#define MAX_TX_RATE_PHY 48
|
||||
#define WLAN_CTRL_FRAME_SIZE (2+2+6+4)
|
||||
|
||||
/* VALID_ALL - valid for 20/40/Legacy,
|
||||
* VALID - Legacy only,
|
||||
@ -39,6 +38,20 @@ struct ath_softc;
|
||||
#define VALID_2040 (VALID_20|VALID_40)
|
||||
#define VALID_ALL (VALID_2040|VALID)
|
||||
|
||||
enum {
|
||||
WLAN_RC_PHY_OFDM,
|
||||
WLAN_RC_PHY_CCK,
|
||||
WLAN_RC_PHY_HT_20_SS,
|
||||
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) \
|
||||
|
@ -14,7 +14,7 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
#include "ath9k.h"
|
||||
|
||||
/*
|
||||
* Setup and link descriptors.
|
||||
@ -26,7 +26,7 @@
|
||||
*/
|
||||
static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
|
||||
{
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_desc *ds;
|
||||
struct sk_buff *skb;
|
||||
|
||||
@ -97,11 +97,11 @@ static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len)
|
||||
* Unfortunately this means we may get 8 KB here from the
|
||||
* kernel... and that is actually what is observed on some
|
||||
* systems :( */
|
||||
skb = dev_alloc_skb(len + sc->sc_cachelsz - 1);
|
||||
skb = dev_alloc_skb(len + sc->cachelsz - 1);
|
||||
if (skb != NULL) {
|
||||
off = ((unsigned long) skb->data) % sc->sc_cachelsz;
|
||||
off = ((unsigned long) skb->data) % sc->cachelsz;
|
||||
if (off != 0)
|
||||
skb_reserve(skb, sc->sc_cachelsz - off);
|
||||
skb_reserve(skb, sc->cachelsz - off);
|
||||
} else {
|
||||
DPRINTF(sc, ATH_DBG_FATAL,
|
||||
"skbuff alloc of size %u failed\n", len);
|
||||
@ -135,7 +135,7 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
|
||||
* discard the frame. Enable this if you want to see
|
||||
* error frames in Monitor mode.
|
||||
*/
|
||||
if (sc->sc_ah->ah_opmode != NL80211_IFTYPE_MONITOR)
|
||||
if (sc->sc_ah->opmode != NL80211_IFTYPE_MONITOR)
|
||||
goto rx_next;
|
||||
} else if (ds->ds_rxstat.rs_status != 0) {
|
||||
if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC)
|
||||
@ -161,7 +161,7 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
|
||||
* decryption and MIC failures. For monitor mode,
|
||||
* we also ignore the CRC error.
|
||||
*/
|
||||
if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_MONITOR) {
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_MONITOR) {
|
||||
if (ds->ds_rxstat.rs_status &
|
||||
~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
|
||||
ATH9K_RXERR_CRC))
|
||||
@ -210,7 +210,7 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
|
||||
rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
|
||||
rx_status->band = sc->hw->conf.channel->band;
|
||||
rx_status->freq = sc->hw->conf.channel->center_freq;
|
||||
rx_status->noise = sc->sc_ani.sc_noise_floor;
|
||||
rx_status->noise = sc->ani.noise_floor;
|
||||
rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi;
|
||||
rx_status->antenna = ds->ds_rxstat.rs_antenna;
|
||||
|
||||
@ -233,7 +233,7 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
|
||||
|
||||
static void ath_opmode_init(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
u32 rfilt, mfilt[2];
|
||||
|
||||
/* configure rx filter */
|
||||
@ -241,14 +241,14 @@ static void ath_opmode_init(struct ath_softc *sc)
|
||||
ath9k_hw_setrxfilter(ah, rfilt);
|
||||
|
||||
/* configure bssid mask */
|
||||
if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
|
||||
ath9k_hw_setbssidmask(ah, sc->sc_bssidmask);
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
|
||||
ath9k_hw_setbssidmask(sc);
|
||||
|
||||
/* configure operational mode */
|
||||
ath9k_hw_setopmode(ah);
|
||||
|
||||
/* Handle any link-level address change. */
|
||||
ath9k_hw_setmac(ah, sc->sc_myaddr);
|
||||
ath9k_hw_setmac(ah, sc->sc_ah->macaddr);
|
||||
|
||||
/* calculate and install multicast filter */
|
||||
mfilt[0] = mfilt[1] = ~0;
|
||||
@ -267,11 +267,11 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
|
||||
spin_lock_init(&sc->rx.rxbuflock);
|
||||
|
||||
sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
|
||||
min(sc->sc_cachelsz,
|
||||
min(sc->cachelsz,
|
||||
(u16)64));
|
||||
|
||||
DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
|
||||
sc->sc_cachelsz, sc->rx.bufsize);
|
||||
sc->cachelsz, sc->rx.bufsize);
|
||||
|
||||
/* Initialize rx descriptors */
|
||||
|
||||
@ -360,25 +360,28 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
|
||||
| ATH9K_RX_FILTER_MCAST;
|
||||
|
||||
/* If not a STA, enable processing of Probe Requests */
|
||||
if (sc->sc_ah->ah_opmode != NL80211_IFTYPE_STATION)
|
||||
if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION)
|
||||
rfilt |= ATH9K_RX_FILTER_PROBEREQ;
|
||||
|
||||
/* Can't set HOSTAP into promiscous mode */
|
||||
if (((sc->sc_ah->ah_opmode != NL80211_IFTYPE_AP) &&
|
||||
if (((sc->sc_ah->opmode != NL80211_IFTYPE_AP) &&
|
||||
(sc->rx.rxfilter & FIF_PROMISC_IN_BSS)) ||
|
||||
(sc->sc_ah->ah_opmode == NL80211_IFTYPE_MONITOR)) {
|
||||
(sc->sc_ah->opmode == NL80211_IFTYPE_MONITOR)) {
|
||||
rfilt |= ATH9K_RX_FILTER_PROM;
|
||||
/* ??? To prevent from sending ACK */
|
||||
rfilt &= ~ATH9K_RX_FILTER_UCAST;
|
||||
}
|
||||
|
||||
if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION ||
|
||||
sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC)
|
||||
if (sc->rx.rxfilter & FIF_CONTROL)
|
||||
rfilt |= ATH9K_RX_FILTER_CONTROL;
|
||||
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION ||
|
||||
sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)
|
||||
rfilt |= ATH9K_RX_FILTER_BEACON;
|
||||
|
||||
/* If in HOSTAP mode, want to enable reception of PSPOLL frames
|
||||
& beacon frames */
|
||||
if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP)
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP)
|
||||
rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL);
|
||||
|
||||
return rfilt;
|
||||
@ -388,7 +391,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
|
||||
|
||||
int ath_startrecv(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_buf *bf, *tbf;
|
||||
|
||||
spin_lock_bh(&sc->rx.rxbuflock);
|
||||
@ -418,7 +421,7 @@ int ath_startrecv(struct ath_softc *sc)
|
||||
|
||||
bool ath_stoprecv(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
bool stopped;
|
||||
|
||||
ath9k_hw_stoppcurecv(ah);
|
||||
@ -449,7 +452,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
|
||||
struct ath_desc *ds;
|
||||
struct sk_buff *skb = NULL, *requeue_skb;
|
||||
struct ieee80211_rx_status rx_status;
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ieee80211_hdr *hdr;
|
||||
int hdrlen, padsize, retval;
|
||||
bool decrypt_error = false;
|
||||
@ -590,7 +593,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
|
||||
&& !decrypt_error && skb->len >= hdrlen + 4) {
|
||||
keyix = skb->data[hdrlen + 3] >> 6;
|
||||
|
||||
if (test_bit(keyix, sc->sc_keymap))
|
||||
if (test_bit(keyix, sc->keymap))
|
||||
rx_status.flag |= RX_FLAG_DECRYPTED;
|
||||
}
|
||||
if (ah->sw_mgmt_crypto &&
|
||||
|
@ -160,6 +160,7 @@
|
||||
|
||||
#define AR_SREV_VERSION_9100 0x014
|
||||
|
||||
#define AR_SREV_9100(ah) ((ah->hw_version.macVersion) == AR_SREV_VERSION_9100)
|
||||
#define AR_SREV_5416_V20_OR_LATER(_ah) \
|
||||
(AR_SREV_9100((_ah)) || AR_SREV_5416_20_OR_LATER(_ah))
|
||||
#define AR_SREV_5416_V22_OR_LATER(_ah) \
|
||||
@ -746,44 +747,50 @@
|
||||
#define AR_SREV_REVISION_9285_12 2
|
||||
|
||||
#define AR_SREV_9100_OR_LATER(_ah) \
|
||||
(((_ah)->ah_macVersion >= AR_SREV_VERSION_5416_PCIE))
|
||||
(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_5416_PCIE))
|
||||
#define AR_SREV_5416_20_OR_LATER(_ah) \
|
||||
(((_ah)->ah_macVersion >= AR_SREV_VERSION_9160) || \
|
||||
((_ah)->ah_macRev >= AR_SREV_REVISION_5416_20))
|
||||
(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9160) || \
|
||||
((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_20))
|
||||
#define AR_SREV_5416_22_OR_LATER(_ah) \
|
||||
(((_ah)->ah_macVersion >= AR_SREV_VERSION_9160) || \
|
||||
((_ah)->ah_macRev >= AR_SREV_REVISION_5416_22))
|
||||
(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9160) || \
|
||||
((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_22))
|
||||
#define AR_SREV_9160(_ah) \
|
||||
(((_ah)->ah_macVersion == AR_SREV_VERSION_9160))
|
||||
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9160))
|
||||
#define AR_SREV_9160_10_OR_LATER(_ah) \
|
||||
(((_ah)->ah_macVersion >= AR_SREV_VERSION_9160))
|
||||
(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9160))
|
||||
#define AR_SREV_9160_11(_ah) \
|
||||
(AR_SREV_9160(_ah) && ((_ah)->ah_macRev == AR_SREV_REVISION_9160_11))
|
||||
(AR_SREV_9160(_ah) && \
|
||||
((_ah)->hw_version.macRev == AR_SREV_REVISION_9160_11))
|
||||
#define AR_SREV_9280(_ah) \
|
||||
(((_ah)->ah_macVersion == AR_SREV_VERSION_9280))
|
||||
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280))
|
||||
#define AR_SREV_9280_10_OR_LATER(_ah) \
|
||||
(((_ah)->ah_macVersion >= AR_SREV_VERSION_9280))
|
||||
(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9280))
|
||||
#define AR_SREV_9280_20(_ah) \
|
||||
(((_ah)->ah_macVersion == AR_SREV_VERSION_9280) && \
|
||||
((_ah)->ah_macRev >= AR_SREV_REVISION_9280_20))
|
||||
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280) && \
|
||||
((_ah)->hw_version.macRev >= AR_SREV_REVISION_9280_20))
|
||||
#define AR_SREV_9280_20_OR_LATER(_ah) \
|
||||
(((_ah)->ah_macVersion > AR_SREV_VERSION_9280) || \
|
||||
(((_ah)->ah_macVersion == AR_SREV_VERSION_9280) && \
|
||||
((_ah)->ah_macRev >= AR_SREV_REVISION_9280_20)))
|
||||
(((_ah)->hw_version.macVersion > AR_SREV_VERSION_9280) || \
|
||||
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280) && \
|
||||
((_ah)->hw_version.macRev >= AR_SREV_REVISION_9280_20)))
|
||||
|
||||
#define AR_SREV_9285(_ah) (((_ah)->ah_macVersion == AR_SREV_VERSION_9285))
|
||||
#define AR_SREV_9285(_ah) \
|
||||
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9285))
|
||||
#define AR_SREV_9285_10_OR_LATER(_ah) \
|
||||
(((_ah)->ah_macVersion >= AR_SREV_VERSION_9285))
|
||||
(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9285))
|
||||
#define AR_SREV_9285_11(_ah) \
|
||||
(AR_SREV_9280(ah) && ((_ah)->ah_macRev == AR_SREV_REVISION_9285_11))
|
||||
(AR_SREV_9280(ah) && \
|
||||
((_ah)->hw_version.macRev == AR_SREV_REVISION_9285_11))
|
||||
#define AR_SREV_9285_11_OR_LATER(_ah) \
|
||||
(((_ah)->ah_macVersion > AR_SREV_VERSION_9285) || \
|
||||
(AR_SREV_9285(ah) && ((_ah)->ah_macRev >= AR_SREV_REVISION_9285_11)))
|
||||
(((_ah)->hw_version.macVersion > AR_SREV_VERSION_9285) || \
|
||||
(AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \
|
||||
AR_SREV_REVISION_9285_11)))
|
||||
#define AR_SREV_9285_12(_ah) \
|
||||
(AR_SREV_9280(ah) && ((_ah)->ah_macRev == AR_SREV_REVISION_9285_12))
|
||||
(AR_SREV_9280(ah) && \
|
||||
((_ah)->hw_version.macRev == AR_SREV_REVISION_9285_12))
|
||||
#define AR_SREV_9285_12_OR_LATER(_ah) \
|
||||
(((_ah)->ah_macVersion > AR_SREV_VERSION_9285) || \
|
||||
(AR_SREV_9285(ah) && ((_ah)->ah_macRev >= AR_SREV_REVISION_9285_12)))
|
||||
(((_ah)->hw_version.macVersion > AR_SREV_VERSION_9285) || \
|
||||
(AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \
|
||||
AR_SREV_REVISION_9285_12)))
|
||||
|
||||
#define AR_RADIO_SREV_MAJOR 0xf0
|
||||
#define AR_RAD5133_SREV_MAJOR 0xc0
|
||||
|
@ -16,9 +16,7 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include "core.h"
|
||||
#include "hw.h"
|
||||
#include "regd.h"
|
||||
#include "ath9k.h"
|
||||
#include "regd_common.h"
|
||||
|
||||
/*
|
||||
@ -108,17 +106,17 @@ static const struct ieee80211_regdomain ath9k_world_regdom_67_68_6A = {
|
||||
}
|
||||
};
|
||||
|
||||
static u16 ath9k_regd_get_eepromRD(struct ath_hal *ah)
|
||||
static u16 ath9k_regd_get_eepromRD(struct ath_hw *ah)
|
||||
{
|
||||
return ah->ah_currentRD & ~WORLDWIDE_ROAMING_FLAG;
|
||||
return ah->regulatory.current_rd & ~WORLDWIDE_ROAMING_FLAG;
|
||||
}
|
||||
|
||||
u16 ath9k_regd_get_rd(struct ath_hal *ah)
|
||||
u16 ath9k_regd_get_rd(struct ath_hw *ah)
|
||||
{
|
||||
return ath9k_regd_get_eepromRD(ah);
|
||||
}
|
||||
|
||||
bool ath9k_is_world_regd(struct ath_hal *ah)
|
||||
bool ath9k_is_world_regd(struct ath_hw *ah)
|
||||
{
|
||||
return isWwrSKU(ah);
|
||||
}
|
||||
@ -129,9 +127,9 @@ const struct ieee80211_regdomain *ath9k_default_world_regdomain(void)
|
||||
return &ath9k_world_regdom_64;
|
||||
}
|
||||
|
||||
const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hal *ah)
|
||||
const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hw *ah)
|
||||
{
|
||||
switch (ah->regpair->regDmnEnum) {
|
||||
switch (ah->regulatory.regpair->regDmnEnum) {
|
||||
case 0x60:
|
||||
case 0x61:
|
||||
case 0x62:
|
||||
@ -284,9 +282,9 @@ void ath9k_reg_apply_world_flags(struct wiphy *wiphy, enum reg_set_by setby)
|
||||
{
|
||||
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
switch (ah->regpair->regDmnEnum) {
|
||||
switch (ah->regulatory.regpair->regDmnEnum) {
|
||||
case 0x60:
|
||||
case 0x63:
|
||||
case 0x66:
|
||||
@ -324,7 +322,7 @@ int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ath9k_regd_is_eeprom_valid(struct ath_hal *ah)
|
||||
bool ath9k_regd_is_eeprom_valid(struct ath_hw *ah)
|
||||
{
|
||||
u16 rd = ath9k_regd_get_eepromRD(ah);
|
||||
int i;
|
||||
@ -373,7 +371,7 @@ ath9k_regd_find_country_by_rd(int regdmn)
|
||||
}
|
||||
|
||||
/* Returns the map of the EEPROM set RD to a country code */
|
||||
static u16 ath9k_regd_get_default_country(struct ath_hal *ah)
|
||||
static u16 ath9k_regd_get_default_country(struct ath_hw *ah)
|
||||
{
|
||||
u16 rd;
|
||||
|
||||
@ -404,7 +402,7 @@ ath9k_get_regpair(int regdmn)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ath9k_regd_init(struct ath_hal *ah)
|
||||
int ath9k_regd_init(struct ath_hw *ah)
|
||||
{
|
||||
struct country_code_to_enum_rd *country = NULL;
|
||||
int regdmn;
|
||||
@ -415,30 +413,30 @@ int ath9k_regd_init(struct ath_hal *ah)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ah->ah_countryCode = ath9k_regd_get_default_country(ah);
|
||||
ah->regulatory.country_code = ath9k_regd_get_default_country(ah);
|
||||
|
||||
if (ah->ah_countryCode == CTRY_DEFAULT &&
|
||||
if (ah->regulatory.country_code == CTRY_DEFAULT &&
|
||||
ath9k_regd_get_eepromRD(ah) == CTRY_DEFAULT)
|
||||
ah->ah_countryCode = CTRY_UNITED_STATES;
|
||||
ah->regulatory.country_code = CTRY_UNITED_STATES;
|
||||
|
||||
if (ah->ah_countryCode == CTRY_DEFAULT) {
|
||||
if (ah->regulatory.country_code == CTRY_DEFAULT) {
|
||||
regdmn = ath9k_regd_get_eepromRD(ah);
|
||||
country = NULL;
|
||||
} else {
|
||||
country = ath9k_regd_find_country(ah->ah_countryCode);
|
||||
country = ath9k_regd_find_country(ah->regulatory.country_code);
|
||||
if (country == NULL) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
|
||||
"Country is NULL!!!!, cc= %d\n",
|
||||
ah->ah_countryCode);
|
||||
ah->regulatory.country_code);
|
||||
return -EINVAL;
|
||||
} else
|
||||
regdmn = country->regDmnEnum;
|
||||
}
|
||||
|
||||
ah->ah_currentRDInUse = regdmn;
|
||||
ah->regpair = ath9k_get_regpair(regdmn);
|
||||
ah->regulatory.current_rd_inuse = regdmn;
|
||||
ah->regulatory.regpair = ath9k_get_regpair(regdmn);
|
||||
|
||||
if (!ah->regpair) {
|
||||
if (!ah->regulatory.regpair) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
|
||||
"No regulatory domain pair found, cannot continue\n");
|
||||
return -EINVAL;
|
||||
@ -448,28 +446,28 @@ int ath9k_regd_init(struct ath_hal *ah)
|
||||
country = ath9k_regd_find_country_by_rd(regdmn);
|
||||
|
||||
if (country) {
|
||||
ah->alpha2[0] = country->isoName[0];
|
||||
ah->alpha2[1] = country->isoName[1];
|
||||
ah->regulatory.alpha2[0] = country->isoName[0];
|
||||
ah->regulatory.alpha2[1] = country->isoName[1];
|
||||
} else {
|
||||
ah->alpha2[0] = '0';
|
||||
ah->alpha2[1] = '0';
|
||||
ah->regulatory.alpha2[0] = '0';
|
||||
ah->regulatory.alpha2[1] = '0';
|
||||
}
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
|
||||
"Country alpha2 being used: %c%c\n"
|
||||
"Regpair detected: 0x%0x\n",
|
||||
ah->alpha2[0], ah->alpha2[1],
|
||||
ah->regpair->regDmnEnum);
|
||||
"Regulatory.Regpair detected: 0x%0x\n",
|
||||
ah->regulatory.alpha2[0], ah->regulatory.alpha2[1],
|
||||
ah->regulatory.regpair->regDmnEnum);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan)
|
||||
u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||
{
|
||||
u32 ctl = NO_CTL;
|
||||
|
||||
if (!ah->regpair ||
|
||||
(ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah))) {
|
||||
if (!ah->regulatory.regpair ||
|
||||
(ah->regulatory.country_code == CTRY_DEFAULT && isWwrSKU(ah))) {
|
||||
if (IS_CHAN_B(chan))
|
||||
ctl = SD_NO_CTL | CTL_11B;
|
||||
else if (IS_CHAN_G(chan))
|
||||
@ -480,11 +478,11 @@ u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan)
|
||||
}
|
||||
|
||||
if (IS_CHAN_B(chan))
|
||||
ctl = ah->regpair->reg_2ghz_ctl | CTL_11B;
|
||||
ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11B;
|
||||
else if (IS_CHAN_G(chan))
|
||||
ctl = ah->regpair->reg_5ghz_ctl | CTL_11G;
|
||||
ctl = ah->regulatory.regpair->reg_5ghz_ctl | CTL_11G;
|
||||
else
|
||||
ctl = ah->regpair->reg_5ghz_ctl | CTL_11A;
|
||||
ctl = ah->regulatory.regpair->reg_5ghz_ctl | CTL_11A;
|
||||
|
||||
return ctl;
|
||||
}
|
||||
|
@ -17,8 +17,6 @@
|
||||
#ifndef REGD_H
|
||||
#define REGD_H
|
||||
|
||||
#include "ath9k.h"
|
||||
|
||||
#define COUNTRY_ERD_FLAG 0x8000
|
||||
#define WORLDWIDE_ROAMING_FLAG 0x4000
|
||||
|
||||
@ -47,6 +45,18 @@ struct country_code_to_enum_rd {
|
||||
const char *isoName;
|
||||
};
|
||||
|
||||
struct ath9k_regulatory {
|
||||
char alpha2[2];
|
||||
u16 country_code;
|
||||
u16 max_power_level;
|
||||
u32 tp_scale;
|
||||
u16 current_rd;
|
||||
u16 current_rd_ext;
|
||||
u16 current_rd_inuse;
|
||||
int16_t power_limit;
|
||||
struct reg_dmn_pair_mapping *regpair;
|
||||
};
|
||||
|
||||
enum CountryCode {
|
||||
CTRY_ALBANIA = 8,
|
||||
CTRY_ALGERIA = 12,
|
||||
@ -229,7 +239,17 @@ enum CountryCode {
|
||||
CTRY_BELGIUM2 = 5002
|
||||
};
|
||||
|
||||
void ath9k_regd_get_current_country(struct ath_hal *ah,
|
||||
u16 ath9k_regd_get_rd(struct ath_hw *ah);
|
||||
bool ath9k_is_world_regd(struct ath_hw *ah);
|
||||
const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hw *ah);
|
||||
const struct ieee80211_regdomain *ath9k_default_world_regdomain(void);
|
||||
void ath9k_reg_apply_world_flags(struct wiphy *wiphy, enum reg_set_by setby);
|
||||
void ath9k_reg_apply_radar_flags(struct wiphy *wiphy);
|
||||
int ath9k_regd_init(struct ath_hw *ah);
|
||||
bool ath9k_regd_is_eeprom_valid(struct ath_hw *ah);
|
||||
u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan);
|
||||
int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
|
||||
void ath9k_regd_get_current_country(struct ath_hw *ah,
|
||||
struct ath9k_country_entry *ctry);
|
||||
|
||||
#endif
|
||||
|
@ -14,7 +14,7 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
#include "ath9k.h"
|
||||
|
||||
#define BITS_PER_BYTE 8
|
||||
#define OFDM_PLCP_BITS 22
|
||||
@ -308,7 +308,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
||||
* when perform internal reset in this routine.
|
||||
* Only enable reset in STA mode for now.
|
||||
*/
|
||||
if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION)
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION)
|
||||
needreset = 1;
|
||||
}
|
||||
}
|
||||
@ -809,7 +809,7 @@ static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
|
||||
|
||||
struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
|
||||
{
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath9k_tx_queue_info qi;
|
||||
int qnum;
|
||||
|
||||
@ -926,7 +926,7 @@ struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb)
|
||||
int ath_txq_update(struct ath_softc *sc, int qnum,
|
||||
struct ath9k_tx_queue_info *qinfo)
|
||||
{
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
int error = 0;
|
||||
struct ath9k_tx_queue_info qi;
|
||||
|
||||
@ -970,14 +970,14 @@ int ath_cabq_update(struct ath_softc *sc)
|
||||
/*
|
||||
* Ensure the readytime % is within the bounds.
|
||||
*/
|
||||
if (sc->sc_config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
|
||||
sc->sc_config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
|
||||
else if (sc->sc_config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
|
||||
sc->sc_config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
|
||||
if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
|
||||
sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
|
||||
else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
|
||||
sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
|
||||
|
||||
ath_get_beaconconfig(sc, ATH_IF_ID_ANY, &conf);
|
||||
qi.tqi_readyTime =
|
||||
(conf.beacon_interval * sc->sc_config.cabqReadytime) / 100;
|
||||
(conf.beacon_interval * sc->config.cabqReadytime) / 100;
|
||||
ath_txq_update(sc, qnum, &qi);
|
||||
|
||||
return 0;
|
||||
@ -1047,7 +1047,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
|
||||
|
||||
void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
|
||||
{
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_txq *txq;
|
||||
int i, npend = 0;
|
||||
|
||||
@ -1072,7 +1072,7 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
|
||||
DPRINTF(sc, ATH_DBG_XMIT, "Unable to stop TxDMA. Reset HAL!\n");
|
||||
|
||||
spin_lock_bh(&sc->sc_resetlock);
|
||||
r = ath9k_hw_reset(ah, sc->sc_ah->ah_curchan, true);
|
||||
r = ath9k_hw_reset(ah, sc->sc_ah->curchan, true);
|
||||
if (r)
|
||||
DPRINTF(sc, ATH_DBG_FATAL,
|
||||
"Unable to reset hardware; reset status %u\n",
|
||||
@ -1165,7 +1165,7 @@ int ath_tx_setup(struct ath_softc *sc, int haltype)
|
||||
static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_buf *bf;
|
||||
|
||||
/*
|
||||
@ -1436,14 +1436,18 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_tx_info *tx_info;
|
||||
struct ieee80211_tx_rate *rates;
|
||||
struct ieee80211_hdr *hdr;
|
||||
int i, flags = 0;
|
||||
u8 rix = 0, ctsrate = 0;
|
||||
bool is_pspoll;
|
||||
|
||||
memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
|
||||
|
||||
skb = (struct sk_buff *)bf->bf_mpdu;
|
||||
tx_info = IEEE80211_SKB_CB(skb);
|
||||
rates = tx_info->control.rates;
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
|
||||
|
||||
/*
|
||||
* We check if Short Preamble is needed for the CTS rate by
|
||||
@ -1467,13 +1471,13 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
|
||||
flags = ATH9K_TXDESC_RTSENA;
|
||||
|
||||
/* FIXME: Handle aggregation protection */
|
||||
if (sc->sc_config.ath_aggr_prot &&
|
||||
if (sc->config.ath_aggr_prot &&
|
||||
(!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) {
|
||||
flags = ATH9K_TXDESC_RTSENA;
|
||||
}
|
||||
|
||||
/* For AR5416 - RTS cannot be followed by a frame larger than 8K */
|
||||
if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->ah_caps.rts_aggr_limit))
|
||||
if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
|
||||
flags &= ~(ATH9K_TXDESC_RTSENA);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
@ -1482,7 +1486,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
|
||||
|
||||
rix = rates[i].idx;
|
||||
series[i].Tries = rates[i].count;
|
||||
series[i].ChSel = sc->sc_tx_chainmask;
|
||||
series[i].ChSel = sc->tx_chainmask;
|
||||
|
||||
if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
|
||||
series[i].Rate = rt->info[rix].ratecode |
|
||||
@ -1506,10 +1510,10 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
|
||||
/* set dur_update_en for l-sig computation except for PS-Poll frames */
|
||||
ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
|
||||
bf->bf_lastbf->bf_desc,
|
||||
!bf_ispspoll(bf), ctsrate,
|
||||
!is_pspoll, ctsrate,
|
||||
0, series, 4, flags);
|
||||
|
||||
if (sc->sc_config.ath_aggr_prot && flags)
|
||||
if (sc->config.ath_aggr_prot && flags)
|
||||
ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
|
||||
}
|
||||
|
||||
@ -1534,12 +1538,6 @@ static int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
|
||||
|
||||
bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3);
|
||||
|
||||
if (ieee80211_is_data(fc))
|
||||
bf->bf_state.bf_type |= BUF_DATA;
|
||||
if (ieee80211_is_back_req(fc))
|
||||
bf->bf_state.bf_type |= BUF_BAR;
|
||||
if (ieee80211_is_pspoll(fc))
|
||||
bf->bf_state.bf_type |= BUF_PSPOLL;
|
||||
if ((conf_is_ht(&sc->hw->conf) && !is_pae(skb) &&
|
||||
(tx_info->flags & IEEE80211_TX_CTL_AMPDU)))
|
||||
bf->bf_state.bf_type |= BUF_HT;
|
||||
@ -1582,7 +1580,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
|
||||
struct list_head bf_head;
|
||||
struct ath_desc *ds;
|
||||
struct ath_atx_tid *tid;
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
int frm_type;
|
||||
|
||||
frm_type = get_hw_packet_type(skb);
|
||||
@ -1843,6 +1841,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
|
||||
static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, int nbad)
|
||||
{
|
||||
struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
|
||||
|
||||
@ -1852,7 +1851,7 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, int nbad)
|
||||
|
||||
if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
|
||||
(bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) {
|
||||
if (bf_isdata(bf)) {
|
||||
if (ieee80211_is_data(hdr->frame_control)) {
|
||||
memcpy(&tx_info_priv->tx, &ds->ds_txstat,
|
||||
sizeof(tx_info_priv->tx));
|
||||
tx_info_priv->n_frames = bf->bf_nframes;
|
||||
@ -1880,7 +1879,7 @@ static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
|
||||
|
||||
static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
||||
{
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_buf *bf, *lastbf, *bf_held = NULL;
|
||||
struct list_head bf_head;
|
||||
struct ath_desc *ds;
|
||||
|
@ -120,6 +120,9 @@
|
||||
#define B43_MMIO_IFSCTL 0x688 /* Interframe space control */
|
||||
#define B43_MMIO_IFSCTL_USE_EDCF 0x0004
|
||||
#define B43_MMIO_POWERUP_DELAY 0x6A8
|
||||
#define B43_MMIO_BTCOEX_CTL 0x6B4 /* Bluetooth Coexistence Control */
|
||||
#define B43_MMIO_BTCOEX_STAT 0x6B6 /* Bluetooth Coexistence Status */
|
||||
#define B43_MMIO_BTCOEX_TXCTL 0x6B8 /* Bluetooth Coexistence Transmit Control */
|
||||
|
||||
/* SPROM boardflags_lo values */
|
||||
#define B43_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */
|
||||
|
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "b43.h"
|
||||
#include "main.h"
|
||||
#include "phy_lp.h"
|
||||
#include "phy_common.h"
|
||||
#include "tables_lpphy.h"
|
||||
@ -267,13 +268,185 @@ static void lpphy_radio_init(struct b43_wldev *dev)
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the TX power control mode from hardware. */
|
||||
static void lpphy_read_tx_pctl_mode_from_hardware(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_lp *lpphy = dev->phy.lp;
|
||||
u16 ctl;
|
||||
|
||||
ctl = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_CMD);
|
||||
switch (ctl & B43_LPPHY_TX_PWR_CTL_CMD_MODE) {
|
||||
case B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF:
|
||||
lpphy->txpctl_mode = B43_LPPHY_TXPCTL_OFF;
|
||||
break;
|
||||
case B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW:
|
||||
lpphy->txpctl_mode = B43_LPPHY_TXPCTL_SW;
|
||||
break;
|
||||
case B43_LPPHY_TX_PWR_CTL_CMD_MODE_HW:
|
||||
lpphy->txpctl_mode = B43_LPPHY_TXPCTL_HW;
|
||||
break;
|
||||
default:
|
||||
lpphy->txpctl_mode = B43_LPPHY_TXPCTL_UNKNOWN;
|
||||
B43_WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the TX power control mode in hardware. */
|
||||
static void lpphy_write_tx_pctl_mode_to_hardware(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_lp *lpphy = dev->phy.lp;
|
||||
u16 ctl;
|
||||
|
||||
switch (lpphy->txpctl_mode) {
|
||||
case B43_LPPHY_TXPCTL_OFF:
|
||||
ctl = B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF;
|
||||
break;
|
||||
case B43_LPPHY_TXPCTL_HW:
|
||||
ctl = B43_LPPHY_TX_PWR_CTL_CMD_MODE_HW;
|
||||
break;
|
||||
case B43_LPPHY_TXPCTL_SW:
|
||||
ctl = B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW;
|
||||
break;
|
||||
default:
|
||||
ctl = 0;
|
||||
B43_WARN_ON(1);
|
||||
}
|
||||
b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
|
||||
(u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE, ctl);
|
||||
}
|
||||
|
||||
static void lpphy_set_tx_power_control(struct b43_wldev *dev,
|
||||
enum b43_lpphy_txpctl_mode mode)
|
||||
{
|
||||
struct b43_phy_lp *lpphy = dev->phy.lp;
|
||||
enum b43_lpphy_txpctl_mode oldmode;
|
||||
|
||||
oldmode = lpphy->txpctl_mode;
|
||||
lpphy_read_tx_pctl_mode_from_hardware(dev);
|
||||
if (lpphy->txpctl_mode == mode)
|
||||
return;
|
||||
lpphy->txpctl_mode = mode;
|
||||
|
||||
if (oldmode == B43_LPPHY_TXPCTL_HW) {
|
||||
//TODO Update TX Power NPT
|
||||
//TODO Clear all TX Power offsets
|
||||
} else {
|
||||
if (mode == B43_LPPHY_TXPCTL_HW) {
|
||||
//TODO Recalculate target TX power
|
||||
b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
|
||||
0xFF80, lpphy->tssi_idx);
|
||||
b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM,
|
||||
0x8FFF, ((u16)lpphy->tssi_npt << 16));
|
||||
//TODO Set "TSSI Transmit Count" variable to total transmitted frame count
|
||||
//TODO Disable TX gain override
|
||||
lpphy->tx_pwr_idx_over = -1;
|
||||
}
|
||||
}
|
||||
if (dev->phy.rev >= 2) {
|
||||
if (mode == B43_LPPHY_TXPCTL_HW)
|
||||
b43_phy_maskset(dev, B43_PHY_OFDM(0xD0), 0xFD, 0x2);
|
||||
else
|
||||
b43_phy_maskset(dev, B43_PHY_OFDM(0xD0), 0xFD, 0);
|
||||
}
|
||||
lpphy_write_tx_pctl_mode_to_hardware(dev);
|
||||
}
|
||||
|
||||
static void lpphy_set_tx_power_by_index(struct b43_wldev *dev, u8 index)
|
||||
{
|
||||
struct b43_phy_lp *lpphy = dev->phy.lp;
|
||||
|
||||
lpphy->tx_pwr_idx_over = index;
|
||||
if (lpphy->txpctl_mode != B43_LPPHY_TXPCTL_OFF)
|
||||
lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_SW);
|
||||
|
||||
//TODO
|
||||
}
|
||||
|
||||
static void lpphy_btcoex_override(struct b43_wldev *dev)
|
||||
{
|
||||
b43_write16(dev, B43_MMIO_BTCOEX_CTL, 0x3);
|
||||
b43_write16(dev, B43_MMIO_BTCOEX_TXCTL, 0xFF);
|
||||
}
|
||||
|
||||
static void lpphy_pr41573_workaround(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_lp *lpphy = dev->phy.lp;
|
||||
u32 *saved_tab;
|
||||
const unsigned int saved_tab_size = 256;
|
||||
enum b43_lpphy_txpctl_mode txpctl_mode;
|
||||
s8 tx_pwr_idx_over;
|
||||
u16 tssi_npt, tssi_idx;
|
||||
|
||||
saved_tab = kcalloc(saved_tab_size, sizeof(saved_tab[0]), GFP_KERNEL);
|
||||
if (!saved_tab) {
|
||||
b43err(dev->wl, "PR41573 failed. Out of memory!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
lpphy_read_tx_pctl_mode_from_hardware(dev);
|
||||
txpctl_mode = lpphy->txpctl_mode;
|
||||
tx_pwr_idx_over = lpphy->tx_pwr_idx_over;
|
||||
tssi_npt = lpphy->tssi_npt;
|
||||
tssi_idx = lpphy->tssi_idx;
|
||||
|
||||
if (dev->phy.rev < 2) {
|
||||
b43_lptab_read_bulk(dev, B43_LPTAB32(10, 0x140),
|
||||
saved_tab_size, saved_tab);
|
||||
} else {
|
||||
b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140),
|
||||
saved_tab_size, saved_tab);
|
||||
}
|
||||
//TODO
|
||||
|
||||
kfree(saved_tab);
|
||||
}
|
||||
|
||||
static void lpphy_calibration(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_lp *lpphy = dev->phy.lp;
|
||||
enum b43_lpphy_txpctl_mode saved_pctl_mode;
|
||||
|
||||
b43_mac_suspend(dev);
|
||||
|
||||
lpphy_btcoex_override(dev);
|
||||
lpphy_read_tx_pctl_mode_from_hardware(dev);
|
||||
saved_pctl_mode = lpphy->txpctl_mode;
|
||||
lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
|
||||
//TODO Perform transmit power table I/Q LO calibration
|
||||
if ((dev->phy.rev == 0) && (saved_pctl_mode != B43_LPPHY_TXPCTL_OFF))
|
||||
lpphy_pr41573_workaround(dev);
|
||||
//TODO If a full calibration has not been performed on this channel yet, perform PAPD TX-power calibration
|
||||
lpphy_set_tx_power_control(dev, saved_pctl_mode);
|
||||
//TODO Perform I/Q calibration with a single control value set
|
||||
|
||||
b43_mac_enable(dev);
|
||||
}
|
||||
|
||||
/* Initialize TX power control */
|
||||
static void lpphy_tx_pctl_init(struct b43_wldev *dev)
|
||||
{
|
||||
if (0/*FIXME HWPCTL capable */) {
|
||||
//TODO
|
||||
} else { /* This device is only software TX power control capable. */
|
||||
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
|
||||
//TODO
|
||||
} else {
|
||||
//TODO
|
||||
}
|
||||
//TODO set BB multiplier to 0x0096
|
||||
}
|
||||
}
|
||||
|
||||
static int b43_lpphy_op_init(struct b43_wldev *dev)
|
||||
{
|
||||
/* TODO: band SPROM */
|
||||
lpphy_baseband_init(dev);
|
||||
lpphy_radio_init(dev);
|
||||
|
||||
//TODO
|
||||
//TODO calibrate RC
|
||||
//TODO set channel
|
||||
lpphy_tx_pctl_init(dev);
|
||||
//TODO full calib
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -247,6 +247,10 @@
|
||||
#define B43_LPPHY_FOURWIRE_CTL B43_PHY_OFDM(0xA2) /* fourwire Control */
|
||||
#define B43_LPPHY_CPA_TAILCOUNT_VAL B43_PHY_OFDM(0xA3) /* CPA TailCount Value */
|
||||
#define B43_LPPHY_TX_PWR_CTL_CMD B43_PHY_OFDM(0xA4) /* TX Power Control Cmd */
|
||||
#define B43_LPPHY_TX_PWR_CTL_CMD_MODE 0xE000 /* TX power control mode mask */
|
||||
#define B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF 0x0000 /* TX power control is OFF */
|
||||
#define B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW 0x8000 /* TX power control is SOFTWARE */
|
||||
#define B43_LPPHY_TX_PWR_CTL_CMD_MODE_HW 0xE000 /* TX power control is HARDWARE */
|
||||
#define B43_LPPHY_TX_PWR_CTL_NNUM B43_PHY_OFDM(0xA5) /* TX Power Control Nnum */
|
||||
#define B43_LPPHY_TX_PWR_CTL_IDLETSSI B43_PHY_OFDM(0xA6) /* TX Power Control IdleTssi */
|
||||
#define B43_LPPHY_TX_PWR_CTL_TARGETPWR B43_PHY_OFDM(0xA7) /* TX Power Control TargetPower */
|
||||
@ -802,7 +806,17 @@
|
||||
|
||||
|
||||
|
||||
enum b43_lpphy_txpctl_mode {
|
||||
B43_LPPHY_TXPCTL_UNKNOWN = 0,
|
||||
B43_LPPHY_TXPCTL_OFF, /* TX power control is OFF */
|
||||
B43_LPPHY_TXPCTL_SW, /* TX power control is set to Software */
|
||||
B43_LPPHY_TXPCTL_HW, /* TX power control is set to Hardware */
|
||||
};
|
||||
|
||||
struct b43_phy_lp {
|
||||
/* Current TX power control mode. */
|
||||
enum b43_lpphy_txpctl_mode txpctl_mode;
|
||||
|
||||
/* Transmit isolation medium band */
|
||||
u8 tx_isolation_med_band; /* FIXME initial value? */
|
||||
/* Transmit isolation low band */
|
||||
@ -814,7 +828,7 @@ struct b43_phy_lp {
|
||||
u8 rx_pwr_offset; /* FIXME initial value? */
|
||||
|
||||
/* TSSI transmit count */
|
||||
u16 tssi_tx_count; /* FIXME initial value? */
|
||||
u16 tssi_tx_count;
|
||||
/* TSSI index */
|
||||
u16 tssi_idx; /* FIXME initial value? */
|
||||
/* TSSI npt */
|
||||
|
@ -303,6 +303,36 @@ u32 b43_lptab_read(struct b43_wldev *dev, u32 offset)
|
||||
return value;
|
||||
}
|
||||
|
||||
void b43_lptab_read_bulk(struct b43_wldev *dev, u32 offset,
|
||||
unsigned int nr_elements, void *_data)
|
||||
{
|
||||
u32 type, value;
|
||||
u8 *data = _data;
|
||||
unsigned int i;
|
||||
|
||||
type = offset & B43_LPTAB_TYPEMASK;
|
||||
for (i = 0; i < nr_elements; i++) {
|
||||
value = b43_lptab_read(dev, offset);
|
||||
switch (type) {
|
||||
case B43_LPTAB_8BIT:
|
||||
*data = value;
|
||||
data++;
|
||||
break;
|
||||
case B43_LPTAB_16BIT:
|
||||
*((u16 *)data) = value;
|
||||
data += 2;
|
||||
break;
|
||||
case B43_LPTAB_32BIT:
|
||||
*((u32 *)data) = value;
|
||||
data += 4;
|
||||
break;
|
||||
default:
|
||||
B43_WARN_ON(1);
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
|
||||
void b43_lptab_write(struct b43_wldev *dev, u32 offset, u32 value)
|
||||
{
|
||||
u32 type;
|
||||
@ -331,3 +361,34 @@ void b43_lptab_write(struct b43_wldev *dev, u32 offset, u32 value)
|
||||
B43_WARN_ON(1);
|
||||
}
|
||||
}
|
||||
|
||||
void b43_lptab_write_bulk(struct b43_wldev *dev, u32 offset,
|
||||
unsigned int nr_elements, const void *_data)
|
||||
{
|
||||
u32 type, value;
|
||||
const u8 *data = _data;
|
||||
unsigned int i;
|
||||
|
||||
type = offset & B43_LPTAB_TYPEMASK;
|
||||
for (i = 0; i < nr_elements; i++) {
|
||||
switch (type) {
|
||||
case B43_LPTAB_8BIT:
|
||||
value = *data;
|
||||
data++;
|
||||
break;
|
||||
case B43_LPTAB_16BIT:
|
||||
value = *((u16 *)data);
|
||||
data += 2;
|
||||
break;
|
||||
case B43_LPTAB_32BIT:
|
||||
value = *((u32 *)data);
|
||||
data += 4;
|
||||
break;
|
||||
default:
|
||||
B43_WARN_ON(1);
|
||||
value = 0;
|
||||
}
|
||||
b43_lptab_write(dev, offset, value);
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,14 @@
|
||||
u32 b43_lptab_read(struct b43_wldev *dev, u32 offset);
|
||||
void b43_lptab_write(struct b43_wldev *dev, u32 offset, u32 value);
|
||||
|
||||
/* Bulk table access. Note that these functions return the bulk data in
|
||||
* host endianness! The returned data is _not_ a bytearray, but an array
|
||||
* consisting of nr_elements of the data type. */
|
||||
void b43_lptab_read_bulk(struct b43_wldev *dev, u32 offset,
|
||||
unsigned int nr_elements, void *data);
|
||||
void b43_lptab_write_bulk(struct b43_wldev *dev, u32 offset,
|
||||
unsigned int nr_elements, const void *data);
|
||||
|
||||
void b2062_upload_init_table(struct b43_wldev *dev);
|
||||
|
||||
|
||||
|
@ -229,12 +229,6 @@ struct iwl3945_eeprom {
|
||||
|
||||
/* End of EEPROM */
|
||||
|
||||
|
||||
#define PCI_LINK_CTRL 0x0F0
|
||||
#define PCI_POWER_SOURCE 0x0C8
|
||||
#define PCI_REG_WUM8 0x0E8
|
||||
#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000)
|
||||
|
||||
#define PCI_CFG_REV_ID_BIT_BASIC_SKU (0x40) /* bit 6 */
|
||||
#define PCI_CFG_REV_ID_BIT_RTP (0x80) /* bit 7 */
|
||||
|
||||
|
@ -905,22 +905,18 @@ u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags)
|
||||
|
||||
static int iwl3945_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
|
||||
{
|
||||
int rc;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
rc = iwl_grab_nic_access(priv);
|
||||
if (rc) {
|
||||
ret = iwl_grab_nic_access(priv);
|
||||
if (ret) {
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
return rc;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (src == IWL_PWR_SRC_VAUX) {
|
||||
u32 val;
|
||||
|
||||
rc = pci_read_config_dword(priv->pci_dev,
|
||||
PCI_POWER_SOURCE, &val);
|
||||
if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) {
|
||||
if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) {
|
||||
iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
|
||||
APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
|
||||
~APMG_PS_CTRL_MSK_PWR_SRC);
|
||||
@ -929,8 +925,9 @@ static int iwl3945_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
|
||||
iwl_poll_bit(priv, CSR_GPIO_IN,
|
||||
CSR_GPIO_IN_VAL_VAUX_PWR_SRC,
|
||||
CSR_GPIO_IN_BIT_AUX_POWER, 5000);
|
||||
} else
|
||||
} else {
|
||||
iwl_release_nic_access(priv);
|
||||
}
|
||||
} else {
|
||||
iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
|
||||
APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
|
||||
@ -942,7 +939,7 @@ static int iwl3945_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return rc;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
|
||||
@ -2741,8 +2738,8 @@ static struct iwl_lib_ops iwl3945_lib = {
|
||||
EEPROM_REGULATORY_BAND_3_CHANNELS,
|
||||
EEPROM_REGULATORY_BAND_4_CHANNELS,
|
||||
EEPROM_REGULATORY_BAND_5_CHANNELS,
|
||||
IWL3945_EEPROM_IMG_SIZE,
|
||||
IWL3945_EEPROM_IMG_SIZE,
|
||||
EEPROM_REGULATORY_BAND_NO_FAT,
|
||||
EEPROM_REGULATORY_BAND_NO_FAT,
|
||||
},
|
||||
.verify_signature = iwlcore_eeprom_verify_signature,
|
||||
.acquire_semaphore = iwl3945_eeprom_acquire_semaphore,
|
||||
|
@ -92,19 +92,12 @@
|
||||
#define IWL49_RSSI_OFFSET 44
|
||||
|
||||
|
||||
|
||||
/* PCI registers */
|
||||
#define PCI_CFG_RETRY_TIMEOUT 0x041
|
||||
#define PCI_CFG_POWER_SOURCE 0x0C8
|
||||
#define PCI_REG_WUM8 0x0E8
|
||||
#define PCI_CFG_LINK_CTRL 0x0F0
|
||||
|
||||
/* PCI register values */
|
||||
#define PCI_CFG_LINK_CTRL_VAL_L0S_EN 0x01
|
||||
#define PCI_CFG_LINK_CTRL_VAL_L1_EN 0x02
|
||||
#define PCI_CFG_CMD_REG_INT_DIS_MSK 0x04
|
||||
#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000)
|
||||
|
||||
|
||||
#define IWL_NUM_SCAN_RATES (2)
|
||||
|
||||
|
@ -381,27 +381,20 @@ static int iwl4965_apm_init(struct iwl_priv *priv)
|
||||
static void iwl4965_nic_config(struct iwl_priv *priv)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
u16 radio_cfg;
|
||||
u16 link;
|
||||
u16 lctl;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
if ((priv->rev_id & 0x80) == 0x80 && (priv->rev_id & 0x7f) < 8) {
|
||||
pci_read_config_dword(priv->pci_dev, PCI_REG_WUM8, &val);
|
||||
/* Enable No Snoop field */
|
||||
pci_write_config_dword(priv->pci_dev, PCI_REG_WUM8,
|
||||
val & ~(1 << 11));
|
||||
}
|
||||
lctl = iwl_pcie_link_ctl(priv);
|
||||
|
||||
pci_read_config_word(priv->pci_dev, PCI_CFG_LINK_CTRL, &link);
|
||||
|
||||
/* L1 is enabled by BIOS */
|
||||
if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
|
||||
/* disable L0S disabled L1A enabled */
|
||||
/* HW bug W/A - negligible power consumption */
|
||||
/* L1-ASPM is enabled by BIOS */
|
||||
if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
|
||||
/* L1-ASPM enabled: disable L0S */
|
||||
iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
|
||||
else
|
||||
/* L0S enabled L1A disabled */
|
||||
/* L1-ASPM disabled: enable L0S */
|
||||
iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
|
||||
|
||||
radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
|
||||
|
@ -219,18 +219,19 @@ static void iwl5000_nic_config(struct iwl_priv *priv)
|
||||
{
|
||||
unsigned long flags;
|
||||
u16 radio_cfg;
|
||||
u16 link;
|
||||
u16 lctl;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
pci_read_config_word(priv->pci_dev, PCI_CFG_LINK_CTRL, &link);
|
||||
lctl = iwl_pcie_link_ctl(priv);
|
||||
|
||||
/* L1 is enabled by BIOS */
|
||||
if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
|
||||
/* disable L0S disabled L1A enabled */
|
||||
/* HW bug W/A */
|
||||
/* L1-ASPM is enabled by BIOS */
|
||||
if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
|
||||
/* L1-APSM enabled: disable L0S */
|
||||
iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
|
||||
else
|
||||
/* L0S enabled L1A disabled */
|
||||
/* L1-ASPM disabled: enable L0S */
|
||||
iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
|
||||
|
||||
radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
|
||||
|
@ -940,11 +940,7 @@ int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
|
||||
goto err;
|
||||
|
||||
if (src == IWL_PWR_SRC_VAUX) {
|
||||
u32 val;
|
||||
ret = pci_read_config_dword(priv->pci_dev, PCI_CFG_POWER_SOURCE,
|
||||
&val);
|
||||
|
||||
if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT)
|
||||
if (pci_pme_capable(priv->pci_dev, PCI_D3cold))
|
||||
iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
|
||||
APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
|
||||
~APMG_PS_CTRL_MSK_PWR_SRC);
|
||||
@ -2678,11 +2674,19 @@ static void iwl_bss_info_changed(struct ieee80211_hw *hw,
|
||||
|
||||
}
|
||||
|
||||
static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len)
|
||||
static int iwl_mac_hw_scan(struct ieee80211_hw *hw,
|
||||
struct cfg80211_scan_request *req)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct iwl_priv *priv = hw->priv;
|
||||
int ret;
|
||||
u8 *ssid = NULL;
|
||||
size_t ssid_len = 0;
|
||||
|
||||
if (req->n_ssids) {
|
||||
ssid = req->ssids[0].ssid;
|
||||
ssid_len = req->ssids[0].ssid_len;
|
||||
}
|
||||
|
||||
IWL_DEBUG_MAC80211(priv, "enter\n");
|
||||
|
||||
@ -2718,7 +2722,7 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len)
|
||||
|
||||
if (ssid_len) {
|
||||
priv->one_direct_scan = 1;
|
||||
priv->direct_ssid_len = min_t(u8, ssid_len, IW_ESSID_MAX_SIZE);
|
||||
priv->direct_ssid_len = ssid_len;
|
||||
memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
|
||||
} else {
|
||||
priv->one_direct_scan = 0;
|
||||
|
@ -1271,6 +1271,7 @@ int iwl_setup_mac(struct iwl_priv *priv)
|
||||
BIT(NL80211_IFTYPE_ADHOC);
|
||||
|
||||
hw->wiphy->custom_regulatory = true;
|
||||
hw->wiphy->max_scan_ssids = 1;
|
||||
|
||||
/* Default value; 4 EDCA QOS priorities */
|
||||
hw->queues = 4;
|
||||
|
@ -410,6 +410,14 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags,
|
||||
*****************************************************/
|
||||
void iwl_disable_interrupts(struct iwl_priv *priv);
|
||||
void iwl_enable_interrupts(struct iwl_priv *priv);
|
||||
static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv)
|
||||
{
|
||||
int pos;
|
||||
u16 pci_lnk_ctl;
|
||||
pos = pci_find_capability(priv->pci_dev, PCI_CAP_ID_EXP);
|
||||
pci_read_config_word(priv->pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl);
|
||||
return pci_lnk_ctl;
|
||||
}
|
||||
|
||||
/*****************************************************
|
||||
* Error Handling Debugging
|
||||
|
@ -532,10 +532,10 @@ int iwl_init_channel_map(struct iwl_priv *priv)
|
||||
}
|
||||
|
||||
/* Check if we do have FAT channels */
|
||||
if (priv->cfg->ops->lib->eeprom_ops.regulatory_bands[5] >=
|
||||
priv->cfg->eeprom_size &&
|
||||
priv->cfg->ops->lib->eeprom_ops.regulatory_bands[6] >=
|
||||
priv->cfg->eeprom_size)
|
||||
if (priv->cfg->ops->lib->eeprom_ops.regulatory_bands[5] ==
|
||||
EEPROM_REGULATORY_BAND_NO_FAT &&
|
||||
priv->cfg->ops->lib->eeprom_ops.regulatory_bands[6] ==
|
||||
EEPROM_REGULATORY_BAND_NO_FAT)
|
||||
return 0;
|
||||
|
||||
/* Two additional EEPROM bands for 2.4 and 5 GHz FAT channels */
|
||||
|
@ -370,6 +370,8 @@ struct iwl_eeprom_calib_info {
|
||||
*/
|
||||
#define EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8) /* 22 bytes */
|
||||
|
||||
#define EEPROM_REGULATORY_BAND_NO_FAT (0)
|
||||
|
||||
struct iwl_eeprom_ops {
|
||||
const u32 regulatory_bands[7];
|
||||
int (*verify_signature) (struct iwl_priv *priv);
|
||||
|
@ -141,7 +141,7 @@ static void iwl_power_init_handle(struct iwl_priv *priv)
|
||||
int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_MAX;
|
||||
struct iwl_powertable_cmd *cmd;
|
||||
int i;
|
||||
u16 pci_pm;
|
||||
u16 lctl;
|
||||
|
||||
IWL_DEBUG_POWER(priv, "Initialize power \n");
|
||||
|
||||
@ -153,14 +153,14 @@ static void iwl_power_init_handle(struct iwl_priv *priv)
|
||||
memcpy(&pow_data->pwr_range_1[0], &range_1[0], size);
|
||||
memcpy(&pow_data->pwr_range_2[0], &range_2[0], size);
|
||||
|
||||
pci_read_config_word(priv->pci_dev, PCI_CFG_LINK_CTRL, &pci_pm);
|
||||
lctl = iwl_pcie_link_ctl(priv);
|
||||
|
||||
IWL_DEBUG_POWER(priv, "adjust power command flags\n");
|
||||
|
||||
for (i = 0; i < IWL_POWER_MAX; i++) {
|
||||
cmd = &pow_data->pwr_range_0[i].cmd;
|
||||
|
||||
if (pci_pm & PCI_CFG_LINK_CTRL_VAL_L0S_EN)
|
||||
if (lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN)
|
||||
cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
|
||||
else
|
||||
cmd->flags |= IWL_POWER_PCI_PM_MSK;
|
||||
|
@ -860,7 +860,7 @@ void iwl_bg_scan_completed(struct work_struct *work)
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
|
||||
ieee80211_scan_completed(priv->hw);
|
||||
ieee80211_scan_completed(priv->hw, false);
|
||||
|
||||
/* Since setting the TXPOWER may have been deferred while
|
||||
* performing the scan, fire one off */
|
||||
|
@ -4442,15 +4442,23 @@ static void iwl3945_bss_info_changed(struct ieee80211_hw *hw,
|
||||
|
||||
}
|
||||
|
||||
static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
|
||||
static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw,
|
||||
struct cfg80211_scan_request *req)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned long flags;
|
||||
struct iwl_priv *priv = hw->priv;
|
||||
size_t len = 0;
|
||||
u8 *ssid = NULL;
|
||||
DECLARE_SSID_BUF(ssid_buf);
|
||||
|
||||
IWL_DEBUG_MAC80211(priv, "enter\n");
|
||||
|
||||
if (req->n_ssids) {
|
||||
ssid = req->ssids[0].ssid;
|
||||
len = req->ssids[0].ssid_len;
|
||||
}
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
@ -4478,9 +4486,8 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
|
||||
print_ssid(ssid_buf, ssid, len), len);
|
||||
|
||||
priv->one_direct_scan = 1;
|
||||
priv->direct_ssid_len = (u8)
|
||||
min((u8) len, (u8) IW_ESSID_MAX_SIZE);
|
||||
memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
|
||||
priv->direct_ssid_len = len;
|
||||
memcpy(priv->direct_ssid, ssid, len);
|
||||
} else
|
||||
priv->one_direct_scan = 0;
|
||||
|
||||
@ -5412,6 +5419,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
|
||||
|
||||
hw->wiphy->custom_regulatory = true;
|
||||
|
||||
hw->wiphy->max_scan_ssids = 1;
|
||||
|
||||
/* 4 EDCA QOS priorities */
|
||||
hw->queues = 4;
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
#
|
||||
# Makefile for the orinoco wireless device drivers.
|
||||
#
|
||||
orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o
|
||||
|
||||
obj-$(CONFIG_HERMES) += orinoco.o hermes.o hermes_dld.o
|
||||
obj-$(CONFIG_HERMES) += orinoco.o
|
||||
obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o
|
||||
obj-$(CONFIG_APPLE_AIRPORT) += airport.o
|
||||
obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o
|
||||
|
@ -3,7 +3,7 @@
|
||||
* A driver for "Hermes" chipset based Apple Airport wireless
|
||||
* card.
|
||||
*
|
||||
* Copyright notice & release notes in file orinoco.c
|
||||
* Copyright notice & release notes in file main.c
|
||||
*
|
||||
* Note specific to airport stub:
|
||||
*
|
||||
|
340
drivers/net/wireless/orinoco/fw.c
Normal file
340
drivers/net/wireless/orinoco/fw.c
Normal file
@ -0,0 +1,340 @@
|
||||
/* Firmware file reading and download helpers
|
||||
*
|
||||
* See copyright notice in main.c
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/firmware.h>
|
||||
|
||||
#include "hermes.h"
|
||||
#include "hermes_dld.h"
|
||||
#include "orinoco.h"
|
||||
|
||||
#include "fw.h"
|
||||
|
||||
/* End markers (for Symbol firmware only) */
|
||||
#define TEXT_END 0x1A /* End of text header */
|
||||
|
||||
struct fw_info {
|
||||
char *pri_fw;
|
||||
char *sta_fw;
|
||||
char *ap_fw;
|
||||
u32 pda_addr;
|
||||
u16 pda_size;
|
||||
};
|
||||
|
||||
static const struct fw_info orinoco_fw[] = {
|
||||
{ NULL, "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
|
||||
{ NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
|
||||
{ "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 }
|
||||
};
|
||||
|
||||
/* Structure used to access fields in FW
|
||||
* Make sure LE decoding macros are used
|
||||
*/
|
||||
struct orinoco_fw_header {
|
||||
char hdr_vers[6]; /* ASCII string for header version */
|
||||
__le16 headersize; /* Total length of header */
|
||||
__le32 entry_point; /* NIC entry point */
|
||||
__le32 blocks; /* Number of blocks to program */
|
||||
__le32 block_offset; /* Offset of block data from eof header */
|
||||
__le32 pdr_offset; /* Offset to PDR data from eof header */
|
||||
__le32 pri_offset; /* Offset to primary plug data */
|
||||
__le32 compat_offset; /* Offset to compatibility data*/
|
||||
char signature[0]; /* FW signature length headersize-20 */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Download either STA or AP firmware into the card. */
|
||||
static int
|
||||
orinoco_dl_firmware(struct orinoco_private *priv,
|
||||
const struct fw_info *fw,
|
||||
int ap)
|
||||
{
|
||||
/* Plug Data Area (PDA) */
|
||||
__le16 *pda;
|
||||
|
||||
hermes_t *hw = &priv->hw;
|
||||
const struct firmware *fw_entry;
|
||||
const struct orinoco_fw_header *hdr;
|
||||
const unsigned char *first_block;
|
||||
const unsigned char *end;
|
||||
const char *firmware;
|
||||
struct net_device *dev = priv->ndev;
|
||||
int err = 0;
|
||||
|
||||
pda = kzalloc(fw->pda_size, GFP_KERNEL);
|
||||
if (!pda)
|
||||
return -ENOMEM;
|
||||
|
||||
if (ap)
|
||||
firmware = fw->ap_fw;
|
||||
else
|
||||
firmware = fw->sta_fw;
|
||||
|
||||
printk(KERN_DEBUG "%s: Attempting to download firmware %s\n",
|
||||
dev->name, firmware);
|
||||
|
||||
/* Read current plug data */
|
||||
err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0);
|
||||
printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err);
|
||||
if (err)
|
||||
goto free;
|
||||
|
||||
if (!priv->cached_fw) {
|
||||
err = request_firmware(&fw_entry, firmware, priv->dev);
|
||||
|
||||
if (err) {
|
||||
printk(KERN_ERR "%s: Cannot find firmware %s\n",
|
||||
dev->name, firmware);
|
||||
err = -ENOENT;
|
||||
goto free;
|
||||
}
|
||||
} else
|
||||
fw_entry = priv->cached_fw;
|
||||
|
||||
hdr = (const struct orinoco_fw_header *) fw_entry->data;
|
||||
|
||||
/* Enable aux port to allow programming */
|
||||
err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point));
|
||||
printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err);
|
||||
if (err != 0)
|
||||
goto abort;
|
||||
|
||||
/* Program data */
|
||||
first_block = (fw_entry->data +
|
||||
le16_to_cpu(hdr->headersize) +
|
||||
le32_to_cpu(hdr->block_offset));
|
||||
end = fw_entry->data + fw_entry->size;
|
||||
|
||||
err = hermes_program(hw, first_block, end);
|
||||
printk(KERN_DEBUG "%s: Program returned %d\n", dev->name, err);
|
||||
if (err != 0)
|
||||
goto abort;
|
||||
|
||||
/* Update production data */
|
||||
first_block = (fw_entry->data +
|
||||
le16_to_cpu(hdr->headersize) +
|
||||
le32_to_cpu(hdr->pdr_offset));
|
||||
|
||||
err = hermes_apply_pda_with_defaults(hw, first_block, pda);
|
||||
printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err);
|
||||
if (err)
|
||||
goto abort;
|
||||
|
||||
/* Tell card we've finished */
|
||||
err = hermesi_program_end(hw);
|
||||
printk(KERN_DEBUG "%s: Program end returned %d\n", dev->name, err);
|
||||
if (err != 0)
|
||||
goto abort;
|
||||
|
||||
/* Check if we're running */
|
||||
printk(KERN_DEBUG "%s: hermes_present returned %d\n",
|
||||
dev->name, hermes_present(hw));
|
||||
|
||||
abort:
|
||||
/* If we requested the firmware, release it. */
|
||||
if (!priv->cached_fw)
|
||||
release_firmware(fw_entry);
|
||||
|
||||
free:
|
||||
kfree(pda);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a firmware image - stop the card, load the firmware, reset
|
||||
* the card and make sure it responds. For the secondary firmware take
|
||||
* care of the PDA - read it and then write it on top of the firmware.
|
||||
*/
|
||||
static int
|
||||
symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
|
||||
const unsigned char *image, const unsigned char *end,
|
||||
int secondary)
|
||||
{
|
||||
hermes_t *hw = &priv->hw;
|
||||
int ret = 0;
|
||||
const unsigned char *ptr;
|
||||
const unsigned char *first_block;
|
||||
|
||||
/* Plug Data Area (PDA) */
|
||||
__le16 *pda = NULL;
|
||||
|
||||
/* Binary block begins after the 0x1A marker */
|
||||
ptr = image;
|
||||
while (*ptr++ != TEXT_END);
|
||||
first_block = ptr;
|
||||
|
||||
/* Read the PDA from EEPROM */
|
||||
if (secondary) {
|
||||
pda = kzalloc(fw->pda_size, GFP_KERNEL);
|
||||
if (!pda)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 1);
|
||||
if (ret)
|
||||
goto free;
|
||||
}
|
||||
|
||||
/* Stop the firmware, so that it can be safely rewritten */
|
||||
if (priv->stop_fw) {
|
||||
ret = priv->stop_fw(priv, 1);
|
||||
if (ret)
|
||||
goto free;
|
||||
}
|
||||
|
||||
/* Program the adapter with new firmware */
|
||||
ret = hermes_program(hw, first_block, end);
|
||||
if (ret)
|
||||
goto free;
|
||||
|
||||
/* Write the PDA to the adapter */
|
||||
if (secondary) {
|
||||
size_t len = hermes_blocks_length(first_block);
|
||||
ptr = first_block + len;
|
||||
ret = hermes_apply_pda(hw, ptr, pda);
|
||||
kfree(pda);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Run the firmware */
|
||||
if (priv->stop_fw) {
|
||||
ret = priv->stop_fw(priv, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Reset hermes chip and make sure it responds */
|
||||
ret = hermes_init(hw);
|
||||
|
||||
/* hermes_reset() should return 0 with the secondary firmware */
|
||||
if (secondary && ret != 0)
|
||||
return -ENODEV;
|
||||
|
||||
/* And this should work with any firmware */
|
||||
if (!hermes_present(hw))
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
|
||||
free:
|
||||
kfree(pda);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Download the firmware into the card, this also does a PCMCIA soft
|
||||
* reset on the card, to make sure it's in a sane state.
|
||||
*/
|
||||
static int
|
||||
symbol_dl_firmware(struct orinoco_private *priv,
|
||||
const struct fw_info *fw)
|
||||
{
|
||||
struct net_device *dev = priv->ndev;
|
||||
int ret;
|
||||
const struct firmware *fw_entry;
|
||||
|
||||
if (!priv->cached_pri_fw) {
|
||||
if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) {
|
||||
printk(KERN_ERR "%s: Cannot find firmware: %s\n",
|
||||
dev->name, fw->pri_fw);
|
||||
return -ENOENT;
|
||||
}
|
||||
} else
|
||||
fw_entry = priv->cached_pri_fw;
|
||||
|
||||
/* Load primary firmware */
|
||||
ret = symbol_dl_image(priv, fw, fw_entry->data,
|
||||
fw_entry->data + fw_entry->size, 0);
|
||||
|
||||
if (!priv->cached_pri_fw)
|
||||
release_firmware(fw_entry);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "%s: Primary firmware download failed\n",
|
||||
dev->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!priv->cached_fw) {
|
||||
if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) {
|
||||
printk(KERN_ERR "%s: Cannot find firmware: %s\n",
|
||||
dev->name, fw->sta_fw);
|
||||
return -ENOENT;
|
||||
}
|
||||
} else
|
||||
fw_entry = priv->cached_fw;
|
||||
|
||||
/* Load secondary firmware */
|
||||
ret = symbol_dl_image(priv, fw, fw_entry->data,
|
||||
fw_entry->data + fw_entry->size, 1);
|
||||
if (!priv->cached_fw)
|
||||
release_firmware(fw_entry);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "%s: Secondary firmware download failed\n",
|
||||
dev->name);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int orinoco_download(struct orinoco_private *priv)
|
||||
{
|
||||
int err = 0;
|
||||
/* Reload firmware */
|
||||
switch (priv->firmware_type) {
|
||||
case FIRMWARE_TYPE_AGERE:
|
||||
/* case FIRMWARE_TYPE_INTERSIL: */
|
||||
err = orinoco_dl_firmware(priv,
|
||||
&orinoco_fw[priv->firmware_type], 0);
|
||||
break;
|
||||
|
||||
case FIRMWARE_TYPE_SYMBOL:
|
||||
err = symbol_dl_firmware(priv,
|
||||
&orinoco_fw[priv->firmware_type]);
|
||||
break;
|
||||
case FIRMWARE_TYPE_INTERSIL:
|
||||
break;
|
||||
}
|
||||
/* TODO: if we fail we probably need to reinitialise
|
||||
* the driver */
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void orinoco_cache_fw(struct orinoco_private *priv, int ap)
|
||||
{
|
||||
#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
|
||||
const struct firmware *fw_entry = NULL;
|
||||
const char *pri_fw;
|
||||
const char *fw;
|
||||
|
||||
pri_fw = orinoco_fw[priv->firmware_type].pri_fw;
|
||||
if (ap)
|
||||
fw = orinoco_fw[priv->firmware_type].ap_fw;
|
||||
else
|
||||
fw = orinoco_fw[priv->firmware_type].sta_fw;
|
||||
|
||||
if (pri_fw) {
|
||||
if (request_firmware(&fw_entry, pri_fw, priv->dev) == 0)
|
||||
priv->cached_pri_fw = fw_entry;
|
||||
}
|
||||
|
||||
if (fw) {
|
||||
if (request_firmware(&fw_entry, fw, priv->dev) == 0)
|
||||
priv->cached_fw = fw_entry;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void orinoco_uncache_fw(struct orinoco_private *priv)
|
||||
{
|
||||
#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
|
||||
if (priv->cached_pri_fw)
|
||||
release_firmware(priv->cached_pri_fw);
|
||||
if (priv->cached_fw)
|
||||
release_firmware(priv->cached_fw);
|
||||
|
||||
priv->cached_pri_fw = NULL;
|
||||
priv->cached_fw = NULL;
|
||||
#endif
|
||||
}
|
16
drivers/net/wireless/orinoco/fw.h
Normal file
16
drivers/net/wireless/orinoco/fw.h
Normal file
@ -0,0 +1,16 @@
|
||||
/* Firmware file reading and download helpers
|
||||
*
|
||||
* See copyright notice in main.c
|
||||
*/
|
||||
#ifndef _ORINOCO_FW_H_
|
||||
#define _ORINOCO_FW_H_
|
||||
|
||||
/* Forward declations */
|
||||
struct orinoco_private;
|
||||
|
||||
int orinoco_download(struct orinoco_private *priv);
|
||||
|
||||
void orinoco_cache_fw(struct orinoco_private *priv, int ap);
|
||||
void orinoco_uncache_fw(struct orinoco_private *priv);
|
||||
|
||||
#endif /* _ORINOCO_FW_H_ */
|
@ -45,12 +45,6 @@
|
||||
|
||||
#include "hermes.h"
|
||||
|
||||
MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset"
|
||||
" and Prism II HFA384x wireless MAC controller");
|
||||
MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>"
|
||||
" & David Gibson <hermes@gibson.dropbear.id.au>");
|
||||
MODULE_LICENSE("Dual MPL/GPL");
|
||||
|
||||
/* These are maximum timeouts. Most often, card wil react much faster */
|
||||
#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
|
||||
#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */
|
||||
@ -540,15 +534,3 @@ int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(hermes_write_ltv);
|
||||
|
||||
static int __init init_hermes(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit exit_hermes(void)
|
||||
{
|
||||
}
|
||||
|
||||
module_init(init_hermes);
|
||||
module_exit(exit_hermes);
|
||||
|
@ -1,13 +1,7 @@
|
||||
/*
|
||||
* Hermes download helper driver.
|
||||
* Hermes download helper.
|
||||
*
|
||||
* This could be entirely merged into hermes.c.
|
||||
*
|
||||
* I'm keeping it separate to minimise the amount of merging between
|
||||
* kernel upgrades. It also means the memory overhead for drivers that
|
||||
* don't need firmware download low.
|
||||
*
|
||||
* This driver:
|
||||
* This helper:
|
||||
* - is capable of writing to the volatile area of the hermes device
|
||||
* - is currently not capable of writing to non-volatile areas
|
||||
* - provide helpers to identify and update plugin data
|
||||
@ -50,10 +44,6 @@
|
||||
#include "hermes.h"
|
||||
#include "hermes_dld.h"
|
||||
|
||||
MODULE_DESCRIPTION("Download helper for Lucent Hermes chipset");
|
||||
MODULE_AUTHOR("David Kilroy <kilroyd@gmail.com>");
|
||||
MODULE_LICENSE("Dual MPL/GPL");
|
||||
|
||||
#define PFX "hermes_dld: "
|
||||
|
||||
/*
|
||||
@ -347,7 +337,6 @@ int hermes_read_pda(hermes_t *hw,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hermes_read_pda);
|
||||
|
||||
/* Parse PDA and write the records into the adapter
|
||||
*
|
||||
@ -376,7 +365,6 @@ int hermes_apply_pda(hermes_t *hw,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hermes_apply_pda);
|
||||
|
||||
/* Identify the total number of bytes in all blocks
|
||||
* including the header data.
|
||||
@ -398,7 +386,6 @@ hermes_blocks_length(const char *first_block)
|
||||
|
||||
return total_len;
|
||||
}
|
||||
EXPORT_SYMBOL(hermes_blocks_length);
|
||||
|
||||
/*** Hermes programming ***/
|
||||
|
||||
@ -452,7 +439,6 @@ int hermesi_program_init(hermes_t *hw, u32 offset)
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(hermesi_program_init);
|
||||
|
||||
/* Done programming data (Hermes I)
|
||||
*
|
||||
@ -488,7 +474,6 @@ int hermesi_program_end(hermes_t *hw)
|
||||
|
||||
return rc ? rc : err;
|
||||
}
|
||||
EXPORT_SYMBOL(hermesi_program_end);
|
||||
|
||||
/* Program the data blocks */
|
||||
int hermes_program(hermes_t *hw, const char *first_block, const char *end)
|
||||
@ -550,19 +535,6 @@ int hermes_program(hermes_t *hw, const char *first_block, const char *end)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hermes_program);
|
||||
|
||||
static int __init init_hermes_dld(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit exit_hermes_dld(void)
|
||||
{
|
||||
}
|
||||
|
||||
module_init(init_hermes_dld);
|
||||
module_exit(exit_hermes_dld);
|
||||
|
||||
/*** Default plugging data for Hermes I ***/
|
||||
/* Values from wl_lkm_718/hcf/dhf.c */
|
||||
@ -727,4 +699,3 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hermes_apply_pda_with_defaults);
|
||||
|
586
drivers/net/wireless/orinoco/hw.c
Normal file
586
drivers/net/wireless/orinoco/hw.c
Normal file
@ -0,0 +1,586 @@
|
||||
/* Encapsulate basic setting changes and retrieval on Hermes hardware
|
||||
*
|
||||
* See copyright notice in main.c
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/ieee80211.h>
|
||||
#include <linux/wireless.h>
|
||||
|
||||
#include "hermes.h"
|
||||
#include "hermes_rid.h"
|
||||
#include "orinoco.h"
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
/********************************************************************/
|
||||
/* Data tables */
|
||||
/********************************************************************/
|
||||
|
||||
/* This tables gives the actual meanings of the bitrate IDs returned
|
||||
* by the firmware. */
|
||||
static const struct {
|
||||
int bitrate; /* in 100s of kilobits */
|
||||
int automatic;
|
||||
u16 agere_txratectrl;
|
||||
u16 intersil_txratectrl;
|
||||
} bitrate_table[] = {
|
||||
{110, 1, 3, 15}, /* Entry 0 is the default */
|
||||
{10, 0, 1, 1},
|
||||
{10, 1, 1, 1},
|
||||
{20, 0, 2, 2},
|
||||
{20, 1, 6, 3},
|
||||
{55, 0, 4, 4},
|
||||
{55, 1, 7, 7},
|
||||
{110, 0, 5, 8},
|
||||
};
|
||||
#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table)
|
||||
|
||||
int orinoco_get_bitratemode(int bitrate, int automatic)
|
||||
{
|
||||
int ratemode = -1;
|
||||
int i;
|
||||
|
||||
if ((bitrate != 10) && (bitrate != 20) &&
|
||||
(bitrate != 55) && (bitrate != 110))
|
||||
return ratemode;
|
||||
|
||||
for (i = 0; i < BITRATE_TABLE_SIZE; i++) {
|
||||
if ((bitrate_table[i].bitrate == bitrate) &&
|
||||
(bitrate_table[i].automatic == automatic)) {
|
||||
ratemode = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ratemode;
|
||||
}
|
||||
|
||||
void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic)
|
||||
{
|
||||
BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE));
|
||||
|
||||
*bitrate = bitrate_table[ratemode].bitrate * 100000;
|
||||
*automatic = bitrate_table[ratemode].automatic;
|
||||
}
|
||||
|
||||
/* Get tsc from the firmware */
|
||||
int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc)
|
||||
{
|
||||
hermes_t *hw = &priv->hw;
|
||||
int err = 0;
|
||||
u8 tsc_arr[4][IW_ENCODE_SEQ_MAX_SIZE];
|
||||
|
||||
if ((key < 0) || (key > 4))
|
||||
return -EINVAL;
|
||||
|
||||
err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV,
|
||||
sizeof(tsc_arr), NULL, &tsc_arr);
|
||||
if (!err)
|
||||
memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0]));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
|
||||
{
|
||||
hermes_t *hw = &priv->hw;
|
||||
int ratemode = priv->bitratemode;
|
||||
int err = 0;
|
||||
|
||||
if (ratemode >= BITRATE_TABLE_SIZE) {
|
||||
printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n",
|
||||
priv->ndev->name, ratemode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (priv->firmware_type) {
|
||||
case FIRMWARE_TYPE_AGERE:
|
||||
err = hermes_write_wordrec(hw, USER_BAP,
|
||||
HERMES_RID_CNFTXRATECONTROL,
|
||||
bitrate_table[ratemode].agere_txratectrl);
|
||||
break;
|
||||
case FIRMWARE_TYPE_INTERSIL:
|
||||
case FIRMWARE_TYPE_SYMBOL:
|
||||
err = hermes_write_wordrec(hw, USER_BAP,
|
||||
HERMES_RID_CNFTXRATECONTROL,
|
||||
bitrate_table[ratemode].intersil_txratectrl);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate)
|
||||
{
|
||||
hermes_t *hw = &priv->hw;
|
||||
int i;
|
||||
int err = 0;
|
||||
u16 val;
|
||||
|
||||
err = hermes_read_wordrec(hw, USER_BAP,
|
||||
HERMES_RID_CURRENTTXRATE, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (priv->firmware_type) {
|
||||
case FIRMWARE_TYPE_AGERE: /* Lucent style rate */
|
||||
/* Note : in Lucent firmware, the return value of
|
||||
* HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s,
|
||||
* and therefore is totally different from the
|
||||
* encoding of HERMES_RID_CNFTXRATECONTROL.
|
||||
* Don't forget that 6Mb/s is really 5.5Mb/s */
|
||||
if (val == 6)
|
||||
*bitrate = 5500000;
|
||||
else
|
||||
*bitrate = val * 1000000;
|
||||
break;
|
||||
case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
|
||||
case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
|
||||
for (i = 0; i < BITRATE_TABLE_SIZE; i++)
|
||||
if (bitrate_table[i].intersil_txratectrl == val)
|
||||
break;
|
||||
|
||||
if (i >= BITRATE_TABLE_SIZE)
|
||||
printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n",
|
||||
priv->ndev->name, val);
|
||||
|
||||
*bitrate = bitrate_table[i].bitrate * 100000;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Set fixed AP address */
|
||||
int __orinoco_hw_set_wap(struct orinoco_private *priv)
|
||||
{
|
||||
int roaming_flag;
|
||||
int err = 0;
|
||||
hermes_t *hw = &priv->hw;
|
||||
|
||||
switch (priv->firmware_type) {
|
||||
case FIRMWARE_TYPE_AGERE:
|
||||
/* not supported */
|
||||
break;
|
||||
case FIRMWARE_TYPE_INTERSIL:
|
||||
if (priv->bssid_fixed)
|
||||
roaming_flag = 2;
|
||||
else
|
||||
roaming_flag = 1;
|
||||
|
||||
err = hermes_write_wordrec(hw, USER_BAP,
|
||||
HERMES_RID_CNFROAMINGMODE,
|
||||
roaming_flag);
|
||||
break;
|
||||
case FIRMWARE_TYPE_SYMBOL:
|
||||
err = HERMES_WRITE_RECORD(hw, USER_BAP,
|
||||
HERMES_RID_CNFMANDATORYBSSID_SYMBOL,
|
||||
&priv->desired_bssid);
|
||||
break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Change the WEP keys and/or the current keys. Can be called
|
||||
* either from __orinoco_hw_setup_enc() or directly from
|
||||
* orinoco_ioctl_setiwencode(). In the later case the association
|
||||
* with the AP is not broken (if the firmware can handle it),
|
||||
* which is needed for 802.1x implementations. */
|
||||
int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
|
||||
{
|
||||
hermes_t *hw = &priv->hw;
|
||||
int err = 0;
|
||||
|
||||
switch (priv->firmware_type) {
|
||||
case FIRMWARE_TYPE_AGERE:
|
||||
err = HERMES_WRITE_RECORD(hw, USER_BAP,
|
||||
HERMES_RID_CNFWEPKEYS_AGERE,
|
||||
&priv->keys);
|
||||
if (err)
|
||||
return err;
|
||||
err = hermes_write_wordrec(hw, USER_BAP,
|
||||
HERMES_RID_CNFTXKEY_AGERE,
|
||||
priv->tx_key);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
case FIRMWARE_TYPE_INTERSIL:
|
||||
case FIRMWARE_TYPE_SYMBOL:
|
||||
{
|
||||
int keylen;
|
||||
int i;
|
||||
|
||||
/* Force uniform key length to work around
|
||||
* firmware bugs */
|
||||
keylen = le16_to_cpu(priv->keys[priv->tx_key].len);
|
||||
|
||||
if (keylen > LARGE_KEY_SIZE) {
|
||||
printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n",
|
||||
priv->ndev->name, priv->tx_key, keylen);
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
/* Write all 4 keys */
|
||||
for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
|
||||
err = hermes_write_ltv(hw, USER_BAP,
|
||||
HERMES_RID_CNFDEFAULTKEY0 + i,
|
||||
HERMES_BYTES_TO_RECLEN(keylen),
|
||||
priv->keys[i].data);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Write the index of the key used in transmission */
|
||||
err = hermes_write_wordrec(hw, USER_BAP,
|
||||
HERMES_RID_CNFWEPDEFAULTKEYID,
|
||||
priv->tx_key);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __orinoco_hw_setup_enc(struct orinoco_private *priv)
|
||||
{
|
||||
hermes_t *hw = &priv->hw;
|
||||
int err = 0;
|
||||
int master_wep_flag;
|
||||
int auth_flag;
|
||||
int enc_flag;
|
||||
|
||||
/* Setup WEP keys for WEP and WPA */
|
||||
if (priv->encode_alg)
|
||||
__orinoco_hw_setup_wepkeys(priv);
|
||||
|
||||
if (priv->wep_restrict)
|
||||
auth_flag = HERMES_AUTH_SHARED_KEY;
|
||||
else
|
||||
auth_flag = HERMES_AUTH_OPEN;
|
||||
|
||||
if (priv->wpa_enabled)
|
||||
enc_flag = 2;
|
||||
else if (priv->encode_alg == IW_ENCODE_ALG_WEP)
|
||||
enc_flag = 1;
|
||||
else
|
||||
enc_flag = 0;
|
||||
|
||||
switch (priv->firmware_type) {
|
||||
case FIRMWARE_TYPE_AGERE: /* Agere style WEP */
|
||||
if (priv->encode_alg == IW_ENCODE_ALG_WEP) {
|
||||
/* Enable the shared-key authentication. */
|
||||
err = hermes_write_wordrec(hw, USER_BAP,
|
||||
HERMES_RID_CNFAUTHENTICATION_AGERE,
|
||||
auth_flag);
|
||||
}
|
||||
err = hermes_write_wordrec(hw, USER_BAP,
|
||||
HERMES_RID_CNFWEPENABLED_AGERE,
|
||||
enc_flag);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (priv->has_wpa) {
|
||||
/* Set WPA key management */
|
||||
err = hermes_write_wordrec(hw, USER_BAP,
|
||||
HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE,
|
||||
priv->key_mgmt);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */
|
||||
case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
|
||||
if (priv->encode_alg == IW_ENCODE_ALG_WEP) {
|
||||
if (priv->wep_restrict ||
|
||||
(priv->firmware_type == FIRMWARE_TYPE_SYMBOL))
|
||||
master_wep_flag = HERMES_WEP_PRIVACY_INVOKED |
|
||||
HERMES_WEP_EXCL_UNENCRYPTED;
|
||||
else
|
||||
master_wep_flag = HERMES_WEP_PRIVACY_INVOKED;
|
||||
|
||||
err = hermes_write_wordrec(hw, USER_BAP,
|
||||
HERMES_RID_CNFAUTHENTICATION,
|
||||
auth_flag);
|
||||
if (err)
|
||||
return err;
|
||||
} else
|
||||
master_wep_flag = 0;
|
||||
|
||||
if (priv->iw_mode == IW_MODE_MONITOR)
|
||||
master_wep_flag |= HERMES_WEP_HOST_DECRYPT;
|
||||
|
||||
/* Master WEP setting : on/off */
|
||||
err = hermes_write_wordrec(hw, USER_BAP,
|
||||
HERMES_RID_CNFWEPFLAGS_INTERSIL,
|
||||
master_wep_flag);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* key must be 32 bytes, including the tx and rx MIC keys.
|
||||
* rsc must be 8 bytes
|
||||
* tsc must be 8 bytes or NULL
|
||||
*/
|
||||
int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
|
||||
u8 *key, u8 *rsc, u8 *tsc)
|
||||
{
|
||||
struct {
|
||||
__le16 idx;
|
||||
u8 rsc[IW_ENCODE_SEQ_MAX_SIZE];
|
||||
u8 key[TKIP_KEYLEN];
|
||||
u8 tx_mic[MIC_KEYLEN];
|
||||
u8 rx_mic[MIC_KEYLEN];
|
||||
u8 tsc[IW_ENCODE_SEQ_MAX_SIZE];
|
||||
} __attribute__ ((packed)) buf;
|
||||
int ret;
|
||||
int err;
|
||||
int k;
|
||||
u16 xmitting;
|
||||
|
||||
key_idx &= 0x3;
|
||||
|
||||
if (set_tx)
|
||||
key_idx |= 0x8000;
|
||||
|
||||
buf.idx = cpu_to_le16(key_idx);
|
||||
memcpy(buf.key, key,
|
||||
sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic));
|
||||
|
||||
if (rsc == NULL)
|
||||
memset(buf.rsc, 0, sizeof(buf.rsc));
|
||||
else
|
||||
memcpy(buf.rsc, rsc, sizeof(buf.rsc));
|
||||
|
||||
if (tsc == NULL) {
|
||||
memset(buf.tsc, 0, sizeof(buf.tsc));
|
||||
buf.tsc[4] = 0x10;
|
||||
} else {
|
||||
memcpy(buf.tsc, tsc, sizeof(buf.tsc));
|
||||
}
|
||||
|
||||
/* Wait upto 100ms for tx queue to empty */
|
||||
k = 100;
|
||||
do {
|
||||
k--;
|
||||
udelay(1000);
|
||||
ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY,
|
||||
&xmitting);
|
||||
if (ret)
|
||||
break;
|
||||
} while ((k > 0) && xmitting);
|
||||
|
||||
if (k == 0)
|
||||
ret = -ETIMEDOUT;
|
||||
|
||||
err = HERMES_WRITE_RECORD(hw, USER_BAP,
|
||||
HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE,
|
||||
&buf);
|
||||
|
||||
return ret ? ret : err;
|
||||
}
|
||||
|
||||
int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx)
|
||||
{
|
||||
hermes_t *hw = &priv->hw;
|
||||
int err;
|
||||
|
||||
memset(&priv->tkip_key[key_idx], 0, sizeof(priv->tkip_key[key_idx]));
|
||||
err = hermes_write_wordrec(hw, USER_BAP,
|
||||
HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE,
|
||||
key_idx);
|
||||
if (err)
|
||||
printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n",
|
||||
priv->ndev->name, err, key_idx);
|
||||
return err;
|
||||
}
|
||||
|
||||
int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
|
||||
struct dev_addr_list *mc_list,
|
||||
int mc_count, int promisc)
|
||||
{
|
||||
hermes_t *hw = &priv->hw;
|
||||
int err = 0;
|
||||
|
||||
if (promisc != priv->promiscuous) {
|
||||
err = hermes_write_wordrec(hw, USER_BAP,
|
||||
HERMES_RID_CNFPROMISCUOUSMODE,
|
||||
promisc);
|
||||
if (err) {
|
||||
printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n",
|
||||
priv->ndev->name, err);
|
||||
} else
|
||||
priv->promiscuous = promisc;
|
||||
}
|
||||
|
||||
/* If we're not in promiscuous mode, then we need to set the
|
||||
* group address if either we want to multicast, or if we were
|
||||
* multicasting and want to stop */
|
||||
if (!promisc && (mc_count || priv->mc_count)) {
|
||||
struct dev_mc_list *p = mc_list;
|
||||
struct hermes_multicast mclist;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < mc_count; i++) {
|
||||
/* paranoia: is list shorter than mc_count? */
|
||||
BUG_ON(!p);
|
||||
/* paranoia: bad address size in list? */
|
||||
BUG_ON(p->dmi_addrlen != ETH_ALEN);
|
||||
|
||||
memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN);
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
if (p)
|
||||
printk(KERN_WARNING "%s: Multicast list is "
|
||||
"longer than mc_count\n", priv->ndev->name);
|
||||
|
||||
err = hermes_write_ltv(hw, USER_BAP,
|
||||
HERMES_RID_CNFGROUPADDRESSES,
|
||||
HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN),
|
||||
&mclist);
|
||||
if (err)
|
||||
printk(KERN_ERR "%s: Error %d setting multicast list.\n",
|
||||
priv->ndev->name, err);
|
||||
else
|
||||
priv->mc_count = mc_count;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Return : < 0 -> error code ; >= 0 -> length */
|
||||
int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
|
||||
char buf[IW_ESSID_MAX_SIZE+1])
|
||||
{
|
||||
hermes_t *hw = &priv->hw;
|
||||
int err = 0;
|
||||
struct hermes_idstring essidbuf;
|
||||
char *p = (char *)(&essidbuf.val);
|
||||
int len;
|
||||
unsigned long flags;
|
||||
|
||||
if (orinoco_lock(priv, &flags) != 0)
|
||||
return -EBUSY;
|
||||
|
||||
if (strlen(priv->desired_essid) > 0) {
|
||||
/* We read the desired SSID from the hardware rather
|
||||
than from priv->desired_essid, just in case the
|
||||
firmware is allowed to change it on us. I'm not
|
||||
sure about this */
|
||||
/* My guess is that the OWNSSID should always be whatever
|
||||
* we set to the card, whereas CURRENT_SSID is the one that
|
||||
* may change... - Jean II */
|
||||
u16 rid;
|
||||
|
||||
*active = 1;
|
||||
|
||||
rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID :
|
||||
HERMES_RID_CNFDESIREDSSID;
|
||||
|
||||
err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
|
||||
NULL, &essidbuf);
|
||||
if (err)
|
||||
goto fail_unlock;
|
||||
} else {
|
||||
*active = 0;
|
||||
|
||||
err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID,
|
||||
sizeof(essidbuf), NULL, &essidbuf);
|
||||
if (err)
|
||||
goto fail_unlock;
|
||||
}
|
||||
|
||||
len = le16_to_cpu(essidbuf.len);
|
||||
BUG_ON(len > IW_ESSID_MAX_SIZE);
|
||||
|
||||
memset(buf, 0, IW_ESSID_MAX_SIZE);
|
||||
memcpy(buf, p, len);
|
||||
err = len;
|
||||
|
||||
fail_unlock:
|
||||
orinoco_unlock(priv, &flags);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int orinoco_hw_get_freq(struct orinoco_private *priv)
|
||||
{
|
||||
hermes_t *hw = &priv->hw;
|
||||
int err = 0;
|
||||
u16 channel;
|
||||
int freq = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (orinoco_lock(priv, &flags) != 0)
|
||||
return -EBUSY;
|
||||
|
||||
err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL,
|
||||
&channel);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Intersil firmware 1.3.5 returns 0 when the interface is down */
|
||||
if (channel == 0) {
|
||||
err = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((channel < 1) || (channel > NUM_CHANNELS)) {
|
||||
printk(KERN_WARNING "%s: Channel out of range (%d)!\n",
|
||||
priv->ndev->name, channel);
|
||||
err = -EBUSY;
|
||||
goto out;
|
||||
|
||||
}
|
||||
freq = ieee80211_dsss_chan_to_freq(channel);
|
||||
|
||||
out:
|
||||
orinoco_unlock(priv, &flags);
|
||||
|
||||
if (err > 0)
|
||||
err = -EBUSY;
|
||||
return err ? err : freq;
|
||||
}
|
||||
|
||||
int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
|
||||
int *numrates, s32 *rates, int max)
|
||||
{
|
||||
hermes_t *hw = &priv->hw;
|
||||
struct hermes_idstring list;
|
||||
unsigned char *p = (unsigned char *)&list.val;
|
||||
int err = 0;
|
||||
int num;
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
if (orinoco_lock(priv, &flags) != 0)
|
||||
return -EBUSY;
|
||||
|
||||
err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES,
|
||||
sizeof(list), NULL, &list);
|
||||
orinoco_unlock(priv, &flags);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
num = le16_to_cpu(list.len);
|
||||
*numrates = num;
|
||||
num = min(num, max);
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */
|
||||
|
||||
return 0;
|
||||
}
|
47
drivers/net/wireless/orinoco/hw.h
Normal file
47
drivers/net/wireless/orinoco/hw.h
Normal file
@ -0,0 +1,47 @@
|
||||
/* Encapsulate basic setting changes on Hermes hardware
|
||||
*
|
||||
* See copyright notice in main.c
|
||||
*/
|
||||
#ifndef _ORINOCO_HW_H_
|
||||
#define _ORINOCO_HW_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/wireless.h>
|
||||
|
||||
/* Hardware BAPs */
|
||||
#define USER_BAP 0
|
||||
#define IRQ_BAP 1
|
||||
|
||||
/* WEP key sizes */
|
||||
#define SMALL_KEY_SIZE 5
|
||||
#define LARGE_KEY_SIZE 13
|
||||
|
||||
/* Number of supported channels */
|
||||
#define NUM_CHANNELS 14
|
||||
|
||||
/* Forward declarations */
|
||||
struct orinoco_private;
|
||||
struct dev_addr_list;
|
||||
|
||||
int orinoco_get_bitratemode(int bitrate, int automatic);
|
||||
void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic);
|
||||
|
||||
int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc);
|
||||
int __orinoco_hw_set_bitrate(struct orinoco_private *priv);
|
||||
int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate);
|
||||
int __orinoco_hw_set_wap(struct orinoco_private *priv);
|
||||
int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv);
|
||||
int __orinoco_hw_setup_enc(struct orinoco_private *priv);
|
||||
int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
|
||||
u8 *key, u8 *rsc, u8 *tsc);
|
||||
int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx);
|
||||
int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
|
||||
struct dev_addr_list *mc_list,
|
||||
int mc_count, int promisc);
|
||||
int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
|
||||
char buf[IW_ESSID_MAX_SIZE+1]);
|
||||
int orinoco_hw_get_freq(struct orinoco_private *priv);
|
||||
int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
|
||||
int *numrates, s32 *rates, int max);
|
||||
|
||||
#endif /* _ORINOCO_HW_H_ */
|
2654
drivers/net/wireless/orinoco/main.c
Normal file
2654
drivers/net/wireless/orinoco/main.c
Normal file
File diff suppressed because it is too large
Load Diff
63
drivers/net/wireless/orinoco/main.h
Normal file
63
drivers/net/wireless/orinoco/main.h
Normal file
@ -0,0 +1,63 @@
|
||||
/* Exports from main to helper modules
|
||||
*
|
||||
* See copyright notice in main.c
|
||||
*/
|
||||
#ifndef _ORINOCO_MAIN_H_
|
||||
#define _ORINOCO_MAIN_H_
|
||||
|
||||
#include <linux/ieee80211.h>
|
||||
#include "orinoco.h"
|
||||
|
||||
/********************************************************************/
|
||||
/* Compile time configuration and compatibility stuff */
|
||||
/********************************************************************/
|
||||
|
||||
/* We do this this way to avoid ifdefs in the actual code */
|
||||
#ifdef WIRELESS_SPY
|
||||
#define SPY_NUMBER(priv) (priv->spy_data.spy_number)
|
||||
#else
|
||||
#define SPY_NUMBER(priv) 0
|
||||
#endif /* WIRELESS_SPY */
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
/* Export module parameter */
|
||||
extern int force_monitor;
|
||||
|
||||
/* Forward declarations */
|
||||
struct net_device;
|
||||
struct work_struct;
|
||||
|
||||
void set_port_type(struct orinoco_private *priv);
|
||||
int __orinoco_program_rids(struct net_device *dev);
|
||||
void orinoco_reset(struct work_struct *work);
|
||||
|
||||
|
||||
/* Information element helpers - find a home for these... */
|
||||
static inline u8 *orinoco_get_ie(u8 *data, size_t len,
|
||||
enum ieee80211_eid eid)
|
||||
{
|
||||
u8 *p = data;
|
||||
while ((p + 2) < (data + len)) {
|
||||
if (p[0] == eid)
|
||||
return p;
|
||||
p += p[1] + 2;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define WPA_OUI_TYPE "\x00\x50\xF2\x01"
|
||||
#define WPA_SELECTOR_LEN 4
|
||||
static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len)
|
||||
{
|
||||
u8 *p = data;
|
||||
while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) {
|
||||
if ((p[0] == WLAN_EID_GENERIC) &&
|
||||
(memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0))
|
||||
return p;
|
||||
p += p[1] + 2;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _ORINOCO_MAIN_H_ */
|
79
drivers/net/wireless/orinoco/mic.c
Normal file
79
drivers/net/wireless/orinoco/mic.c
Normal file
@ -0,0 +1,79 @@
|
||||
/* Orinoco MIC helpers
|
||||
*
|
||||
* See copyright notice in main.c
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/crypto.h>
|
||||
|
||||
#include "orinoco.h"
|
||||
#include "mic.h"
|
||||
|
||||
/********************************************************************/
|
||||
/* Michael MIC crypto setup */
|
||||
/********************************************************************/
|
||||
int orinoco_mic_init(struct orinoco_private *priv)
|
||||
{
|
||||
priv->tx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0);
|
||||
if (IS_ERR(priv->tx_tfm_mic)) {
|
||||
printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
|
||||
"crypto API michael_mic\n");
|
||||
priv->tx_tfm_mic = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
priv->rx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0);
|
||||
if (IS_ERR(priv->rx_tfm_mic)) {
|
||||
printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
|
||||
"crypto API michael_mic\n");
|
||||
priv->rx_tfm_mic = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void orinoco_mic_free(struct orinoco_private *priv)
|
||||
{
|
||||
if (priv->tx_tfm_mic)
|
||||
crypto_free_hash(priv->tx_tfm_mic);
|
||||
if (priv->rx_tfm_mic)
|
||||
crypto_free_hash(priv->rx_tfm_mic);
|
||||
}
|
||||
|
||||
int orinoco_mic(struct crypto_hash *tfm_michael, u8 *key,
|
||||
u8 *da, u8 *sa, u8 priority,
|
||||
u8 *data, size_t data_len, u8 *mic)
|
||||
{
|
||||
struct hash_desc desc;
|
||||
struct scatterlist sg[2];
|
||||
u8 hdr[ETH_HLEN + 2]; /* size of header + padding */
|
||||
|
||||
if (tfm_michael == NULL) {
|
||||
printk(KERN_WARNING "orinoco_mic: tfm_michael == NULL\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Copy header into buffer. We need the padding on the end zeroed */
|
||||
memcpy(&hdr[0], da, ETH_ALEN);
|
||||
memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN);
|
||||
hdr[ETH_ALEN*2] = priority;
|
||||
hdr[ETH_ALEN*2+1] = 0;
|
||||
hdr[ETH_ALEN*2+2] = 0;
|
||||
hdr[ETH_ALEN*2+3] = 0;
|
||||
|
||||
/* Use scatter gather to MIC header and data in one go */
|
||||
sg_init_table(sg, 2);
|
||||
sg_set_buf(&sg[0], hdr, sizeof(hdr));
|
||||
sg_set_buf(&sg[1], data, data_len);
|
||||
|
||||
if (crypto_hash_setkey(tfm_michael, key, MIC_KEYLEN))
|
||||
return -1;
|
||||
|
||||
desc.tfm = tfm_michael;
|
||||
desc.flags = 0;
|
||||
return crypto_hash_digest(&desc, sg, data_len + sizeof(hdr),
|
||||
mic);
|
||||
}
|
22
drivers/net/wireless/orinoco/mic.h
Normal file
22
drivers/net/wireless/orinoco/mic.h
Normal file
@ -0,0 +1,22 @@
|
||||
/* Orinoco MIC helpers
|
||||
*
|
||||
* See copyright notice in main.c
|
||||
*/
|
||||
#ifndef _ORINOCO_MIC_H_
|
||||
#define _ORINOCO_MIC_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#define MICHAEL_MIC_LEN 8
|
||||
|
||||
/* Forward declarations */
|
||||
struct orinoco_private;
|
||||
struct crypto_hash;
|
||||
|
||||
int orinoco_mic_init(struct orinoco_private *priv);
|
||||
void orinoco_mic_free(struct orinoco_private *priv);
|
||||
int orinoco_mic(struct crypto_hash *tfm_michael, u8 *key,
|
||||
u8 *da, u8 *sa, u8 priority,
|
||||
u8 *data, size_t data_len, u8 *mic);
|
||||
|
||||
#endif /* ORINOCO_MIC_H */
|
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@
|
||||
* Linksys, D-Link and Farallon Skyline. It should also work on Symbol
|
||||
* cards such as the 3Com AirConnect and Ericsson WLAN.
|
||||
*
|
||||
* Copyright notice & release notes in file orinoco.c
|
||||
* Copyright notice & release notes in file main.c
|
||||
*/
|
||||
|
||||
#define DRIVER_NAME "orinoco_cs"
|
||||
|
@ -4,7 +4,7 @@
|
||||
* both native PCI and PCMCIA-to-PCI bridges.
|
||||
*
|
||||
* Copyright (C) 2005, Pavel Roskin.
|
||||
* See orinoco.c for license.
|
||||
* See main.c for license.
|
||||
*/
|
||||
|
||||
#ifndef _ORINOCO_PCI_H
|
||||
|
@ -27,7 +27,7 @@
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the MPL or the GPL.
|
||||
*
|
||||
* The actual driving is done by orinoco.c, this is just resource
|
||||
* The actual driving is done by main.c, this is just resource
|
||||
* allocation stuff.
|
||||
*
|
||||
* This driver is modeled after the orinoco_plx driver. The main
|
||||
|
233
drivers/net/wireless/orinoco/scan.c
Normal file
233
drivers/net/wireless/orinoco/scan.c
Normal file
@ -0,0 +1,233 @@
|
||||
/* Helpers for managing scan queues
|
||||
*
|
||||
* See copyright notice in main.c
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include "hermes.h"
|
||||
#include "orinoco.h"
|
||||
|
||||
#include "scan.h"
|
||||
|
||||
#define ORINOCO_MAX_BSS_COUNT 64
|
||||
|
||||
#define PRIV_BSS ((struct bss_element *)priv->bss_xbss_data)
|
||||
#define PRIV_XBSS ((struct xbss_element *)priv->bss_xbss_data)
|
||||
|
||||
int orinoco_bss_data_allocate(struct orinoco_private *priv)
|
||||
{
|
||||
if (priv->bss_xbss_data)
|
||||
return 0;
|
||||
|
||||
if (priv->has_ext_scan)
|
||||
priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
|
||||
sizeof(struct xbss_element),
|
||||
GFP_KERNEL);
|
||||
else
|
||||
priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
|
||||
sizeof(struct bss_element),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!priv->bss_xbss_data) {
|
||||
printk(KERN_WARNING "Out of memory allocating beacons");
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void orinoco_bss_data_free(struct orinoco_private *priv)
|
||||
{
|
||||
kfree(priv->bss_xbss_data);
|
||||
priv->bss_xbss_data = NULL;
|
||||
}
|
||||
|
||||
void orinoco_bss_data_init(struct orinoco_private *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
INIT_LIST_HEAD(&priv->bss_free_list);
|
||||
INIT_LIST_HEAD(&priv->bss_list);
|
||||
if (priv->has_ext_scan)
|
||||
for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
|
||||
list_add_tail(&(PRIV_XBSS[i].list),
|
||||
&priv->bss_free_list);
|
||||
else
|
||||
for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
|
||||
list_add_tail(&(PRIV_BSS[i].list),
|
||||
&priv->bss_free_list);
|
||||
|
||||
}
|
||||
|
||||
void orinoco_clear_scan_results(struct orinoco_private *priv,
|
||||
unsigned long scan_age)
|
||||
{
|
||||
if (priv->has_ext_scan) {
|
||||
struct xbss_element *bss;
|
||||
struct xbss_element *tmp_bss;
|
||||
|
||||
/* Blow away current list of scan results */
|
||||
list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
|
||||
if (!scan_age ||
|
||||
time_after(jiffies, bss->last_scanned + scan_age)) {
|
||||
list_move_tail(&bss->list,
|
||||
&priv->bss_free_list);
|
||||
/* Don't blow away ->list, just BSS data */
|
||||
memset(&bss->bss, 0, sizeof(bss->bss));
|
||||
bss->last_scanned = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
struct bss_element *bss;
|
||||
struct bss_element *tmp_bss;
|
||||
|
||||
/* Blow away current list of scan results */
|
||||
list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
|
||||
if (!scan_age ||
|
||||
time_after(jiffies, bss->last_scanned + scan_age)) {
|
||||
list_move_tail(&bss->list,
|
||||
&priv->bss_free_list);
|
||||
/* Don't blow away ->list, just BSS data */
|
||||
memset(&bss->bss, 0, sizeof(bss->bss));
|
||||
bss->last_scanned = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void orinoco_add_ext_scan_result(struct orinoco_private *priv,
|
||||
struct agere_ext_scan_info *atom)
|
||||
{
|
||||
struct xbss_element *bss = NULL;
|
||||
int found = 0;
|
||||
|
||||
/* Try to update an existing bss first */
|
||||
list_for_each_entry(bss, &priv->bss_list, list) {
|
||||
if (compare_ether_addr(bss->bss.bssid, atom->bssid))
|
||||
continue;
|
||||
/* ESSID lengths */
|
||||
if (bss->bss.data[1] != atom->data[1])
|
||||
continue;
|
||||
if (memcmp(&bss->bss.data[2], &atom->data[2],
|
||||
atom->data[1]))
|
||||
continue;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Grab a bss off the free list */
|
||||
if (!found && !list_empty(&priv->bss_free_list)) {
|
||||
bss = list_entry(priv->bss_free_list.next,
|
||||
struct xbss_element, list);
|
||||
list_del(priv->bss_free_list.next);
|
||||
|
||||
list_add_tail(&bss->list, &priv->bss_list);
|
||||
}
|
||||
|
||||
if (bss) {
|
||||
/* Always update the BSS to get latest beacon info */
|
||||
memcpy(&bss->bss, atom, sizeof(bss->bss));
|
||||
bss->last_scanned = jiffies;
|
||||
}
|
||||
}
|
||||
|
||||
int orinoco_process_scan_results(struct orinoco_private *priv,
|
||||
unsigned char *buf,
|
||||
int len)
|
||||
{
|
||||
int offset; /* In the scan data */
|
||||
union hermes_scan_info *atom;
|
||||
int atom_len;
|
||||
|
||||
switch (priv->firmware_type) {
|
||||
case FIRMWARE_TYPE_AGERE:
|
||||
atom_len = sizeof(struct agere_scan_apinfo);
|
||||
offset = 0;
|
||||
break;
|
||||
case FIRMWARE_TYPE_SYMBOL:
|
||||
/* Lack of documentation necessitates this hack.
|
||||
* Different firmwares have 68 or 76 byte long atoms.
|
||||
* We try modulo first. If the length divides by both,
|
||||
* we check what would be the channel in the second
|
||||
* frame for a 68-byte atom. 76-byte atoms have 0 there.
|
||||
* Valid channel cannot be 0. */
|
||||
if (len % 76)
|
||||
atom_len = 68;
|
||||
else if (len % 68)
|
||||
atom_len = 76;
|
||||
else if (len >= 1292 && buf[68] == 0)
|
||||
atom_len = 76;
|
||||
else
|
||||
atom_len = 68;
|
||||
offset = 0;
|
||||
break;
|
||||
case FIRMWARE_TYPE_INTERSIL:
|
||||
offset = 4;
|
||||
if (priv->has_hostscan) {
|
||||
atom_len = le16_to_cpup((__le16 *)buf);
|
||||
/* Sanity check for atom_len */
|
||||
if (atom_len < sizeof(struct prism2_scan_apinfo)) {
|
||||
printk(KERN_ERR "%s: Invalid atom_len in scan "
|
||||
"data: %d\n", priv->ndev->name,
|
||||
atom_len);
|
||||
return -EIO;
|
||||
}
|
||||
} else
|
||||
atom_len = offsetof(struct prism2_scan_apinfo, atim);
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Check that we got an whole number of atoms */
|
||||
if ((len - offset) % atom_len) {
|
||||
printk(KERN_ERR "%s: Unexpected scan data length %d, "
|
||||
"atom_len %d, offset %d\n", priv->ndev->name, len,
|
||||
atom_len, offset);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
orinoco_clear_scan_results(priv, msecs_to_jiffies(15000));
|
||||
|
||||
/* Read the entries one by one */
|
||||
for (; offset + atom_len <= len; offset += atom_len) {
|
||||
int found = 0;
|
||||
struct bss_element *bss = NULL;
|
||||
|
||||
/* Get next atom */
|
||||
atom = (union hermes_scan_info *) (buf + offset);
|
||||
|
||||
/* Try to update an existing bss first */
|
||||
list_for_each_entry(bss, &priv->bss_list, list) {
|
||||
if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid))
|
||||
continue;
|
||||
if (le16_to_cpu(bss->bss.a.essid_len) !=
|
||||
le16_to_cpu(atom->a.essid_len))
|
||||
continue;
|
||||
if (memcmp(bss->bss.a.essid, atom->a.essid,
|
||||
le16_to_cpu(atom->a.essid_len)))
|
||||
continue;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Grab a bss off the free list */
|
||||
if (!found && !list_empty(&priv->bss_free_list)) {
|
||||
bss = list_entry(priv->bss_free_list.next,
|
||||
struct bss_element, list);
|
||||
list_del(priv->bss_free_list.next);
|
||||
|
||||
list_add_tail(&bss->list, &priv->bss_list);
|
||||
}
|
||||
|
||||
if (bss) {
|
||||
/* Always update the BSS to get latest beacon info */
|
||||
memcpy(&bss->bss, atom, sizeof(bss->bss));
|
||||
bss->last_scanned = jiffies;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
29
drivers/net/wireless/orinoco/scan.h
Normal file
29
drivers/net/wireless/orinoco/scan.h
Normal file
@ -0,0 +1,29 @@
|
||||
/* Helpers for managing scan queues
|
||||
*
|
||||
* See copyright notice in main.c
|
||||
*/
|
||||
#ifndef _ORINOCO_SCAN_H_
|
||||
#define _ORINOCO_SCAN_H_
|
||||
|
||||
/* Forward declarations */
|
||||
struct orinoco_private;
|
||||
struct agere_ext_scan_info;
|
||||
|
||||
/* Setup and free memory for scan results */
|
||||
int orinoco_bss_data_allocate(struct orinoco_private *priv);
|
||||
void orinoco_bss_data_free(struct orinoco_private *priv);
|
||||
void orinoco_bss_data_init(struct orinoco_private *priv);
|
||||
|
||||
/* Add scan results */
|
||||
void orinoco_add_ext_scan_result(struct orinoco_private *priv,
|
||||
struct agere_ext_scan_info *atom);
|
||||
int orinoco_process_scan_results(struct orinoco_private *dev,
|
||||
unsigned char *buf,
|
||||
int len);
|
||||
|
||||
/* Clear scan results */
|
||||
void orinoco_clear_scan_results(struct orinoco_private *priv,
|
||||
unsigned long scan_age);
|
||||
|
||||
|
||||
#endif /* _ORINOCO_SCAN_H_ */
|
@ -4,7 +4,7 @@
|
||||
* Communications and Intel PRO/Wireless 2011B.
|
||||
*
|
||||
* The driver implements Symbol firmware download. The rest is handled
|
||||
* in hermes.c and orinoco.c.
|
||||
* in hermes.c and main.c.
|
||||
*
|
||||
* Utilities for downloading the Symbol firmware are available at
|
||||
* http://sourceforge.net/projects/orinoco/
|
||||
@ -15,7 +15,7 @@
|
||||
* Portions based on Spectrum24tDnld.c from original spectrum24 driver:
|
||||
* Copyright (C) Symbol Technologies.
|
||||
*
|
||||
* See copyright notice in file orinoco.c.
|
||||
* See copyright notice in file main.c.
|
||||
*/
|
||||
|
||||
#define DRIVER_NAME "spectrum_cs"
|
||||
|
2325
drivers/net/wireless/orinoco/wext.c
Normal file
2325
drivers/net/wireless/orinoco/wext.c
Normal file
File diff suppressed because it is too large
Load Diff
13
drivers/net/wireless/orinoco/wext.h
Normal file
13
drivers/net/wireless/orinoco/wext.h
Normal file
@ -0,0 +1,13 @@
|
||||
/* Wireless extensions support.
|
||||
*
|
||||
* See copyright notice in main.c
|
||||
*/
|
||||
#ifndef _ORINOCO_WEXT_H_
|
||||
#define _ORINOCO_WEXT_H_
|
||||
|
||||
#include <net/iw_handler.h>
|
||||
|
||||
/* Structure defining all our WEXT handlers */
|
||||
extern const struct iw_handler_def orinoco_handler_def;
|
||||
|
||||
#endif /* _ORINOCO_WEXT_H_ */
|
@ -33,8 +33,13 @@ typedef u16 __nocast zd_addr_t;
|
||||
#ifdef DEBUG
|
||||
# define dev_dbg_f(dev, fmt, args...) \
|
||||
dev_printk_f(KERN_DEBUG, dev, fmt, ## args)
|
||||
# define dev_dbg_f_limit(dev, fmt, args...) do { \
|
||||
if (net_ratelimit()) \
|
||||
dev_printk_f(KERN_DEBUG, dev, fmt, ## args); \
|
||||
} while (0)
|
||||
#else
|
||||
# define dev_dbg_f(dev, fmt, args...) do { (void)(dev); } while (0)
|
||||
# define dev_dbg_f_limit(dev, fmt, args...) do { (void)(dev); } while (0)
|
||||
#endif /* DEBUG */
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -768,13 +768,23 @@ static int zd_op_config_interface(struct ieee80211_hw *hw,
|
||||
if (!beacon)
|
||||
return -ENOMEM;
|
||||
r = zd_mac_config_beacon(hw, beacon);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS |
|
||||
hw->conf.beacon_int);
|
||||
if (r < 0)
|
||||
return r;
|
||||
kfree_skb(beacon);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (conf->changed & IEEE80211_IFCC_BEACON_ENABLED) {
|
||||
u32 interval;
|
||||
|
||||
if (conf->enable_beacon)
|
||||
interval = BCN_MODE_IBSS | hw->conf.beacon_int;
|
||||
else
|
||||
interval = 0;
|
||||
|
||||
r = zd_set_beacon_interval(&mac->chip, interval);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
} else
|
||||
associated = is_valid_ether_addr(conf->bssid);
|
||||
@ -793,10 +803,9 @@ static void zd_process_intr(struct work_struct *work)
|
||||
struct zd_mac *mac = container_of(work, struct zd_mac, process_intr);
|
||||
|
||||
int_status = le16_to_cpu(*(__le16 *)(mac->intr_buffer+4));
|
||||
if (int_status & INT_CFG_NEXT_BCN) {
|
||||
if (net_ratelimit())
|
||||
dev_dbg_f(zd_mac_dev(mac), "INT_CFG_NEXT_BCN\n");
|
||||
} else
|
||||
if (int_status & INT_CFG_NEXT_BCN)
|
||||
dev_dbg_f_limit(zd_mac_dev(mac), "INT_CFG_NEXT_BCN\n");
|
||||
else
|
||||
dev_dbg_f(zd_mac_dev(mac), "Unsupported interrupt\n");
|
||||
|
||||
zd_chip_enable_hwint(&mac->chip);
|
||||
|
@ -143,6 +143,13 @@
|
||||
* added to all specified management frames generated by
|
||||
* kernel/firmware/driver.
|
||||
*
|
||||
* @NL80211_CMD_GET_SCAN: get scan results
|
||||
* @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
|
||||
* @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to
|
||||
* NL80211_CMD_GET_SCAN and on the "scan" multicast group)
|
||||
* @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
|
||||
* partial scan results may be available
|
||||
*
|
||||
* @NL80211_CMD_MAX: highest used command number
|
||||
* @__NL80211_CMD_AFTER_LAST: internal use
|
||||
*/
|
||||
@ -192,6 +199,11 @@ enum nl80211_commands {
|
||||
|
||||
NL80211_CMD_GET_REG,
|
||||
|
||||
NL80211_CMD_GET_SCAN,
|
||||
NL80211_CMD_TRIGGER_SCAN,
|
||||
NL80211_CMD_NEW_SCAN_RESULTS,
|
||||
NL80211_CMD_SCAN_ABORTED,
|
||||
|
||||
/* add new commands above here */
|
||||
|
||||
/* used to define NL80211_CMD_MAX below */
|
||||
@ -305,6 +317,18 @@ enum nl80211_commands {
|
||||
* @NL80211_ATTR_IE: Information element(s) data (used, e.g., with
|
||||
* %NL80211_CMD_SET_MGMT_EXTRA_IE).
|
||||
*
|
||||
* @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with
|
||||
* a single scan request, a wiphy attribute.
|
||||
*
|
||||
* @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
|
||||
* @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
|
||||
* scanning and include a zero-length SSID (wildcard) for wildcard scan
|
||||
* @NL80211_ATTR_SCAN_GENERATION: the scan generation increases whenever the
|
||||
* scan result list changes (BSS expired or added) so that applications
|
||||
* can verify that they got a single, consistent snapshot (when all dump
|
||||
* messages carried the same generation number)
|
||||
* @NL80211_ATTR_BSS: scan result BSS
|
||||
*
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
*/
|
||||
@ -372,6 +396,13 @@ enum nl80211_attrs {
|
||||
NL80211_ATTR_MGMT_SUBTYPE,
|
||||
NL80211_ATTR_IE,
|
||||
|
||||
NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
|
||||
|
||||
NL80211_ATTR_SCAN_FREQUENCIES,
|
||||
NL80211_ATTR_SCAN_SSIDS,
|
||||
NL80211_ATTR_SCAN_GENERATION,
|
||||
NL80211_ATTR_BSS,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
@ -841,4 +872,38 @@ enum nl80211_channel_type {
|
||||
NL80211_CHAN_HT40MINUS,
|
||||
NL80211_CHAN_HT40PLUS
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_bss - netlink attributes for a BSS
|
||||
*
|
||||
* @__NL80211_BSS_INVALID: invalid
|
||||
* @NL80211_BSS_FREQUENCY: frequency in MHz (u32)
|
||||
* @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64)
|
||||
* @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
|
||||
* @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
|
||||
* @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
|
||||
* raw information elements from the probe response/beacon (bin)
|
||||
* @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
|
||||
* in mBm (100 * dBm) (s32)
|
||||
* @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
|
||||
* in unspecified units, scaled to 0..100 (u8)
|
||||
* @__NL80211_BSS_AFTER_LAST: internal
|
||||
* @NL80211_BSS_MAX: highest BSS attribute
|
||||
*/
|
||||
enum nl80211_bss {
|
||||
__NL80211_BSS_INVALID,
|
||||
NL80211_BSS_BSSID,
|
||||
NL80211_BSS_FREQUENCY,
|
||||
NL80211_BSS_TSF,
|
||||
NL80211_BSS_BEACON_INTERVAL,
|
||||
NL80211_BSS_CAPABILITY,
|
||||
NL80211_BSS_INFORMATION_ELEMENTS,
|
||||
NL80211_BSS_SIGNAL_MBM,
|
||||
NL80211_BSS_SIGNAL_UNSPEC,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_BSS_AFTER_LAST,
|
||||
NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
#endif /* __LINUX_NL80211_H */
|
||||
|
@ -4,6 +4,10 @@
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/nl80211.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/ieee80211.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <net/iw_handler.h>
|
||||
#include <net/genetlink.h>
|
||||
/* remove once we remove the wext stuff */
|
||||
#include <net/iw_handler.h>
|
||||
@ -504,6 +508,85 @@ struct wiphy;
|
||||
/* from net/ieee80211.h */
|
||||
struct ieee80211_channel;
|
||||
|
||||
/**
|
||||
* struct cfg80211_ssid - SSID description
|
||||
* @ssid: the SSID
|
||||
* @ssid_len: length of the ssid
|
||||
*/
|
||||
struct cfg80211_ssid {
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
u8 ssid_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_scan_request - scan request description
|
||||
*
|
||||
* @ssids: SSIDs to scan for (active scan only)
|
||||
* @n_ssids: number of SSIDs
|
||||
* @channels: channels to scan on.
|
||||
* @n_channels: number of channels for each band
|
||||
* @wiphy: the wiphy this was for
|
||||
* @ifidx: the interface index
|
||||
*/
|
||||
struct cfg80211_scan_request {
|
||||
struct cfg80211_ssid *ssids;
|
||||
int n_ssids;
|
||||
struct ieee80211_channel **channels;
|
||||
u32 n_channels;
|
||||
|
||||
/* internal */
|
||||
struct wiphy *wiphy;
|
||||
int ifidx;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum cfg80211_signal_type - signal type
|
||||
*
|
||||
* @CFG80211_SIGNAL_TYPE_NONE: no signal strength information available
|
||||
* @CFG80211_SIGNAL_TYPE_MBM: signal strength in mBm (100*dBm)
|
||||
* @CFG80211_SIGNAL_TYPE_UNSPEC: signal strength, increasing from 0 through 100
|
||||
*/
|
||||
enum cfg80211_signal_type {
|
||||
CFG80211_SIGNAL_TYPE_NONE,
|
||||
CFG80211_SIGNAL_TYPE_MBM,
|
||||
CFG80211_SIGNAL_TYPE_UNSPEC,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_bss - BSS description
|
||||
*
|
||||
* This structure describes a BSS (which may also be a mesh network)
|
||||
* for use in scan results and similar.
|
||||
*
|
||||
* @bssid: BSSID of the BSS
|
||||
* @tsf: timestamp of last received update
|
||||
* @beacon_interval: the beacon interval as from the frame
|
||||
* @capability: the capability field in host byte order
|
||||
* @information_elements: the information elements (Note that there
|
||||
* is no guarantee that these are well-formed!)
|
||||
* @len_information_elements: total length of the information elements
|
||||
* @signal: signal strength value
|
||||
* @signal_type: signal type
|
||||
* @free_priv: function pointer to free private data
|
||||
* @priv: private area for driver use, has at least wiphy->bss_priv_size bytes
|
||||
*/
|
||||
struct cfg80211_bss {
|
||||
struct ieee80211_channel *channel;
|
||||
|
||||
u8 bssid[ETH_ALEN];
|
||||
u64 tsf;
|
||||
u16 beacon_interval;
|
||||
u16 capability;
|
||||
u8 *information_elements;
|
||||
size_t len_information_elements;
|
||||
|
||||
s32 signal;
|
||||
enum cfg80211_signal_type signal_type;
|
||||
|
||||
void (*free_priv)(struct cfg80211_bss *bss);
|
||||
u8 priv[0] __attribute__((__aligned__(sizeof(void *))));
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_ops - backend description for wireless configuration
|
||||
*
|
||||
@ -571,6 +654,11 @@ struct ieee80211_channel;
|
||||
* @set_channel: Set channel
|
||||
*
|
||||
* @set_mgmt_extra_ie: Set extra IE data for management frames
|
||||
*
|
||||
* @scan: Request to do a scan. If returning zero, the scan request is given
|
||||
* the driver, and will be valid until passed to cfg80211_scan_done().
|
||||
* For scan results, call cfg80211_inform_bss(); you can call this outside
|
||||
* the scan/scan_done bracket too.
|
||||
*/
|
||||
struct cfg80211_ops {
|
||||
int (*suspend)(struct wiphy *wiphy);
|
||||
@ -648,6 +736,9 @@ struct cfg80211_ops {
|
||||
int (*set_mgmt_extra_ie)(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
struct mgmt_extra_ie_params *params);
|
||||
|
||||
int (*scan)(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct cfg80211_scan_request *request);
|
||||
};
|
||||
|
||||
/* temporary wext handlers */
|
||||
@ -658,5 +749,68 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
|
||||
u32 *mode, char *extra);
|
||||
int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
|
||||
u32 *mode, char *extra);
|
||||
int cfg80211_wext_siwscan(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
union iwreq_data *wrqu, char *extra);
|
||||
int cfg80211_wext_giwscan(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct iw_point *data, char *extra);
|
||||
|
||||
/**
|
||||
* cfg80211_scan_done - notify that scan finished
|
||||
*
|
||||
* @request: the corresponding scan request
|
||||
* @aborted: set to true if the scan was aborted for any reason,
|
||||
* userspace will be notified of that
|
||||
*/
|
||||
void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted);
|
||||
|
||||
/**
|
||||
* cfg80211_inform_bss - inform cfg80211 of a new BSS
|
||||
*
|
||||
* @wiphy: the wiphy reporting the BSS
|
||||
* @bss: the found BSS
|
||||
* @gfp: context flags
|
||||
*
|
||||
* This informs cfg80211 that BSS information was found and
|
||||
* the BSS should be updated/added.
|
||||
*/
|
||||
struct cfg80211_bss*
|
||||
cfg80211_inform_bss_frame(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *channel,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
s32 signal, enum cfg80211_signal_type sigtype,
|
||||
gfp_t gfp);
|
||||
|
||||
struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *channel,
|
||||
const u8 *bssid,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
u16 capa_mask, u16 capa_val);
|
||||
static inline struct cfg80211_bss *
|
||||
cfg80211_get_ibss(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *channel,
|
||||
const u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
return cfg80211_get_bss(wiphy, channel, NULL, ssid, ssid_len,
|
||||
WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
|
||||
}
|
||||
|
||||
struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *channel,
|
||||
const u8 *meshid, size_t meshidlen,
|
||||
const u8 *meshcfg);
|
||||
void cfg80211_put_bss(struct cfg80211_bss *bss);
|
||||
/**
|
||||
* cfg80211_unlink_bss - unlink BSS from internal data structures
|
||||
* @wiphy: the wiphy
|
||||
* @bss: the bss to remove
|
||||
*
|
||||
* This function removes the given BSS from the internal data structures
|
||||
* thereby making it no longer show up in scan results etc. Use this
|
||||
* function when you detect a BSS is gone. Normally BSSes will also time
|
||||
* out, so it is not necessary to use this function at all.
|
||||
*/
|
||||
void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *bss);
|
||||
|
||||
#endif /* __NET_CFG80211_H */
|
||||
|
@ -1354,11 +1354,11 @@ enum ieee80211_ampdu_mlme_action {
|
||||
*
|
||||
* @get_tsf: Get the current TSF timer value from firmware/hardware. Currently,
|
||||
* this is only used for IBSS mode BSSID merging and debugging. Is not a
|
||||
* required function. Must be atomic.
|
||||
* required function.
|
||||
*
|
||||
* @set_tsf: Set the TSF timer to the specified value in the firmware/hardware.
|
||||
* Currently, this is only used for IBSS mode debugging. Is not a
|
||||
* required function. Must be atomic.
|
||||
* required function.
|
||||
*
|
||||
* @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize
|
||||
* with other STAs in the IBSS. This is only used in IBSS mode. This
|
||||
@ -1406,7 +1406,8 @@ struct ieee80211_ops {
|
||||
void (*update_tkip_key)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_key_conf *conf, const u8 *address,
|
||||
u32 iv32, u16 *phase1key);
|
||||
int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len);
|
||||
int (*hw_scan)(struct ieee80211_hw *hw,
|
||||
struct cfg80211_scan_request *req);
|
||||
int (*get_stats)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_low_level_stats *stats);
|
||||
void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,
|
||||
@ -1844,8 +1845,9 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw);
|
||||
* mac80211 that the scan finished.
|
||||
*
|
||||
* @hw: the hardware that finished the scan
|
||||
* @aborted: set to true if scan was aborted
|
||||
*/
|
||||
void ieee80211_scan_completed(struct ieee80211_hw *hw);
|
||||
void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted);
|
||||
|
||||
/**
|
||||
* ieee80211_iterate_active_interfaces - iterate active interfaces
|
||||
|
@ -213,6 +213,9 @@ struct wiphy {
|
||||
bool custom_regulatory;
|
||||
bool strict_regulatory;
|
||||
|
||||
int bss_priv_size;
|
||||
u8 max_scan_ssids;
|
||||
|
||||
/* If multiple wiphys are registered and you're handed e.g.
|
||||
* a regular netdev with assigned ieee80211_ptr, you won't
|
||||
* know whether it points to a wiphy your driver has registered
|
||||
|
@ -8,7 +8,7 @@ mac80211-y := \
|
||||
wep.o \
|
||||
wpa.o \
|
||||
scan.o \
|
||||
ht.o \
|
||||
ht.o agg-tx.o agg-rx.o \
|
||||
mlme.o \
|
||||
iface.o \
|
||||
rate.o \
|
||||
|
302
net/mac80211/agg-rx.c
Normal file
302
net/mac80211/agg-rx.c
Normal file
@ -0,0 +1,302 @@
|
||||
/*
|
||||
* HT handling
|
||||
*
|
||||
* Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
|
||||
* Copyright 2002-2005, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
||||
* Copyright 2007-2008, Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/ieee80211.h>
|
||||
#include <net/mac80211.h>
|
||||
#include "ieee80211_i.h"
|
||||
|
||||
void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
||||
u16 initiator, u16 reason)
|
||||
{
|
||||
struct ieee80211_local *local = sta->local;
|
||||
struct ieee80211_hw *hw = &local->hw;
|
||||
int i;
|
||||
|
||||
/* check if TID is in operational state */
|
||||
spin_lock_bh(&sta->lock);
|
||||
if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) {
|
||||
spin_unlock_bh(&sta->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
sta->ampdu_mlme.tid_state_rx[tid] =
|
||||
HT_AGG_STATE_REQ_STOP_BA_MSK |
|
||||
(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
|
||||
spin_unlock_bh(&sta->lock);
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n",
|
||||
sta->sta.addr, tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
|
||||
if (local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP,
|
||||
&sta->sta, tid, NULL))
|
||||
printk(KERN_DEBUG "HW problem - can not stop rx "
|
||||
"aggregation for tid %d\n", tid);
|
||||
|
||||
/* shutdown timer has not expired */
|
||||
if (initiator != WLAN_BACK_TIMER)
|
||||
del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
|
||||
|
||||
/* check if this is a self generated aggregation halt */
|
||||
if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER)
|
||||
ieee80211_send_delba(sta->sdata, sta->sta.addr,
|
||||
tid, 0, reason);
|
||||
|
||||
/* free the reordering buffer */
|
||||
for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) {
|
||||
if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) {
|
||||
/* release the reordered frames */
|
||||
dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]);
|
||||
sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--;
|
||||
sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
/* free resources */
|
||||
kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf);
|
||||
|
||||
if (!sta->ampdu_mlme.tid_rx[tid]->shutdown) {
|
||||
kfree(sta->ampdu_mlme.tid_rx[tid]);
|
||||
sta->ampdu_mlme.tid_rx[tid] = NULL;
|
||||
}
|
||||
|
||||
sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE;
|
||||
spin_unlock_bh(&sta->lock);
|
||||
}
|
||||
|
||||
void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid,
|
||||
u16 initiator, u16 reason)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta;
|
||||
|
||||
/* stop HW Rx aggregation. ampdu_action existence
|
||||
* already verified in session init so we add the BUG_ON */
|
||||
BUG_ON(!local->ops->ampdu_action);
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(local, ra);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
__ieee80211_stop_rx_ba_session(sta, tid, initiator, reason);
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
* After accepting the AddBA Request we activated a timer,
|
||||
* resetting it after each frame that arrives from the originator.
|
||||
* if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
|
||||
*/
|
||||
static void sta_rx_agg_session_timer_expired(unsigned long data)
|
||||
{
|
||||
/* not an elegant detour, but there is no choice as the timer passes
|
||||
* only one argument, and various sta_info are needed here, so init
|
||||
* flow in sta_info_create gives the TID as data, while the timer_to_id
|
||||
* array gives the sta through container_of */
|
||||
u8 *ptid = (u8 *)data;
|
||||
u8 *timer_to_id = ptid - *ptid;
|
||||
struct sta_info *sta = container_of(timer_to_id, struct sta_info,
|
||||
timer_to_tid[0]);
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
|
||||
#endif
|
||||
ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
|
||||
(u16)*ptid, WLAN_BACK_TIMER,
|
||||
WLAN_REASON_QSTA_TIMEOUT);
|
||||
}
|
||||
|
||||
static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
|
||||
u8 dialog_token, u16 status, u16 policy,
|
||||
u16 buf_size, u16 timeout)
|
||||
{
|
||||
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
u16 capab;
|
||||
|
||||
skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
|
||||
|
||||
if (!skb) {
|
||||
printk(KERN_DEBUG "%s: failed to allocate buffer "
|
||||
"for addba resp frame\n", sdata->dev->name);
|
||||
return;
|
||||
}
|
||||
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
|
||||
memset(mgmt, 0, 24);
|
||||
memcpy(mgmt->da, da, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
|
||||
else
|
||||
memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
|
||||
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_ACTION);
|
||||
|
||||
skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
|
||||
mgmt->u.action.category = WLAN_CATEGORY_BACK;
|
||||
mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
|
||||
mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
|
||||
|
||||
capab = (u16)(policy << 1); /* bit 1 aggregation policy */
|
||||
capab |= (u16)(tid << 2); /* bit 5:2 TID number */
|
||||
capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */
|
||||
|
||||
mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
|
||||
mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
|
||||
mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
|
||||
|
||||
ieee80211_tx_skb(sdata, skb, 1);
|
||||
}
|
||||
|
||||
void ieee80211_process_addba_request(struct ieee80211_local *local,
|
||||
struct sta_info *sta,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
size_t len)
|
||||
{
|
||||
struct ieee80211_hw *hw = &local->hw;
|
||||
struct ieee80211_conf *conf = &hw->conf;
|
||||
struct tid_ampdu_rx *tid_agg_rx;
|
||||
u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status;
|
||||
u8 dialog_token;
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
/* extract session parameters from addba request frame */
|
||||
dialog_token = mgmt->u.action.u.addba_req.dialog_token;
|
||||
timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
|
||||
start_seq_num =
|
||||
le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
|
||||
|
||||
capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
|
||||
ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
|
||||
tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
|
||||
buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
|
||||
|
||||
status = WLAN_STATUS_REQUEST_DECLINED;
|
||||
|
||||
/* sanity check for incoming parameters:
|
||||
* check if configuration can support the BA policy
|
||||
* and if buffer size does not exceeds max value */
|
||||
/* XXX: check own ht delayed BA capability?? */
|
||||
if (((ba_policy != 1)
|
||||
&& (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA)))
|
||||
|| (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
|
||||
status = WLAN_STATUS_INVALID_QOS_PARAM;
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_DEBUG "AddBA Req with bad params from "
|
||||
"%pM on tid %u. policy %d, buffer size %d\n",
|
||||
mgmt->sa, tid, ba_policy,
|
||||
buf_size);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
goto end_no_lock;
|
||||
}
|
||||
/* determine default buffer size */
|
||||
if (buf_size == 0) {
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
sband = local->hw.wiphy->bands[conf->channel->band];
|
||||
buf_size = IEEE80211_MIN_AMPDU_BUF;
|
||||
buf_size = buf_size << sband->ht_cap.ampdu_factor;
|
||||
}
|
||||
|
||||
|
||||
/* examine state machine */
|
||||
spin_lock_bh(&sta->lock);
|
||||
|
||||
if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_DEBUG "unexpected AddBA Req from "
|
||||
"%pM on tid %u\n",
|
||||
mgmt->sa, tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* prepare A-MPDU MLME for Rx aggregation */
|
||||
sta->ampdu_mlme.tid_rx[tid] =
|
||||
kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
|
||||
if (!sta->ampdu_mlme.tid_rx[tid]) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_ERR "allocate rx mlme to tid %d failed\n",
|
||||
tid);
|
||||
#endif
|
||||
goto end;
|
||||
}
|
||||
/* rx timer */
|
||||
sta->ampdu_mlme.tid_rx[tid]->session_timer.function =
|
||||
sta_rx_agg_session_timer_expired;
|
||||
sta->ampdu_mlme.tid_rx[tid]->session_timer.data =
|
||||
(unsigned long)&sta->timer_to_tid[tid];
|
||||
init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
|
||||
|
||||
tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
|
||||
|
||||
/* prepare reordering buffer */
|
||||
tid_agg_rx->reorder_buf =
|
||||
kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC);
|
||||
if (!tid_agg_rx->reorder_buf) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_ERR "can not allocate reordering buffer "
|
||||
"to tid %d\n", tid);
|
||||
#endif
|
||||
kfree(sta->ampdu_mlme.tid_rx[tid]);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (local->ops->ampdu_action)
|
||||
ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START,
|
||||
&sta->sta, tid, &start_seq_num);
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
|
||||
if (ret) {
|
||||
kfree(tid_agg_rx->reorder_buf);
|
||||
kfree(tid_agg_rx);
|
||||
sta->ampdu_mlme.tid_rx[tid] = NULL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* change state and send addba resp */
|
||||
sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL;
|
||||
tid_agg_rx->dialog_token = dialog_token;
|
||||
tid_agg_rx->ssn = start_seq_num;
|
||||
tid_agg_rx->head_seq_num = start_seq_num;
|
||||
tid_agg_rx->buf_size = buf_size;
|
||||
tid_agg_rx->timeout = timeout;
|
||||
tid_agg_rx->stored_mpdu_num = 0;
|
||||
status = WLAN_STATUS_SUCCESS;
|
||||
end:
|
||||
spin_unlock_bh(&sta->lock);
|
||||
|
||||
end_no_lock:
|
||||
ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
|
||||
dialog_token, status, 1, buf_size, timeout);
|
||||
}
|
636
net/mac80211/agg-tx.c
Normal file
636
net/mac80211/agg-tx.c
Normal file
@ -0,0 +1,636 @@
|
||||
/*
|
||||
* HT handling
|
||||
*
|
||||
* Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
|
||||
* Copyright 2002-2005, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
||||
* Copyright 2007-2009, Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/ieee80211.h>
|
||||
#include <net/mac80211.h>
|
||||
#include "ieee80211_i.h"
|
||||
#include "wme.h"
|
||||
|
||||
/**
|
||||
* DOC: TX aggregation
|
||||
*
|
||||
* Aggregation on the TX side requires setting the hardware flag
|
||||
* %IEEE80211_HW_AMPDU_AGGREGATION as well as, if present, the @ampdu_queues
|
||||
* hardware parameter to the number of hardware AMPDU queues. If there are no
|
||||
* hardware queues then the driver will (currently) have to do all frame
|
||||
* buffering.
|
||||
*
|
||||
* When TX aggregation is started by some subsystem (usually the rate control
|
||||
* algorithm would be appropriate) by calling the
|
||||
* ieee80211_start_tx_ba_session() function, the driver will be notified via
|
||||
* its @ampdu_action function, with the %IEEE80211_AMPDU_TX_START action.
|
||||
*
|
||||
* In response to that, the driver is later required to call the
|
||||
* ieee80211_start_tx_ba_cb() (or ieee80211_start_tx_ba_cb_irqsafe())
|
||||
* function, which will start the aggregation session.
|
||||
*
|
||||
* Similarly, when the aggregation session is stopped by
|
||||
* ieee80211_stop_tx_ba_session(), the driver's @ampdu_action function will
|
||||
* be called with the action %IEEE80211_AMPDU_TX_STOP. In this case, the
|
||||
* call must not fail, and the driver must later call ieee80211_stop_tx_ba_cb()
|
||||
* (or ieee80211_stop_tx_ba_cb_irqsafe()).
|
||||
*/
|
||||
|
||||
static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *da, u16 tid,
|
||||
u8 dialog_token, u16 start_seq_num,
|
||||
u16 agg_size, u16 timeout)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
u16 capab;
|
||||
|
||||
skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
|
||||
|
||||
if (!skb) {
|
||||
printk(KERN_ERR "%s: failed to allocate buffer "
|
||||
"for addba request frame\n", sdata->dev->name);
|
||||
return;
|
||||
}
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
|
||||
memset(mgmt, 0, 24);
|
||||
memcpy(mgmt->da, da, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
|
||||
else
|
||||
memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
|
||||
|
||||
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_ACTION);
|
||||
|
||||
skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
|
||||
|
||||
mgmt->u.action.category = WLAN_CATEGORY_BACK;
|
||||
mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
|
||||
|
||||
mgmt->u.action.u.addba_req.dialog_token = dialog_token;
|
||||
capab = (u16)(1 << 1); /* bit 1 aggregation policy */
|
||||
capab |= (u16)(tid << 2); /* bit 5:2 TID number */
|
||||
capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */
|
||||
|
||||
mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
|
||||
|
||||
mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout);
|
||||
mgmt->u.action.u.addba_req.start_seq_num =
|
||||
cpu_to_le16(start_seq_num << 4);
|
||||
|
||||
ieee80211_tx_skb(sdata, skb, 1);
|
||||
}
|
||||
|
||||
void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_bar *bar;
|
||||
u16 bar_control = 0;
|
||||
|
||||
skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom);
|
||||
if (!skb) {
|
||||
printk(KERN_ERR "%s: failed to allocate buffer for "
|
||||
"bar frame\n", sdata->dev->name);
|
||||
return;
|
||||
}
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar));
|
||||
memset(bar, 0, sizeof(*bar));
|
||||
bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
|
||||
IEEE80211_STYPE_BACK_REQ);
|
||||
memcpy(bar->ra, ra, ETH_ALEN);
|
||||
memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN);
|
||||
bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
|
||||
bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
|
||||
bar_control |= (u16)(tid << 12);
|
||||
bar->control = cpu_to_le16(bar_control);
|
||||
bar->start_seq_num = cpu_to_le16(ssn);
|
||||
|
||||
ieee80211_tx_skb(sdata, skb, 0);
|
||||
}
|
||||
|
||||
static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
||||
enum ieee80211_back_parties initiator)
|
||||
{
|
||||
struct ieee80211_local *local = sta->local;
|
||||
int ret;
|
||||
u8 *state;
|
||||
|
||||
state = &sta->ampdu_mlme.tid_state_tx[tid];
|
||||
|
||||
if (local->hw.ampdu_queues)
|
||||
ieee80211_stop_queue(&local->hw, sta->tid_to_tx_q[tid]);
|
||||
|
||||
*state = HT_AGG_STATE_REQ_STOP_BA_MSK |
|
||||
(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
|
||||
|
||||
ret = local->ops->ampdu_action(&local->hw, IEEE80211_AMPDU_TX_STOP,
|
||||
&sta->sta, tid, NULL);
|
||||
|
||||
/* HW shall not deny going back to legacy */
|
||||
if (WARN_ON(ret)) {
|
||||
*state = HT_AGG_STATE_OPERATIONAL;
|
||||
if (local->hw.ampdu_queues)
|
||||
ieee80211_wake_queue(&local->hw, sta->tid_to_tx_q[tid]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* After sending add Block Ack request we activated a timer until
|
||||
* add Block Ack response will arrive from the recipient.
|
||||
* If this timer expires sta_addba_resp_timer_expired will be executed.
|
||||
*/
|
||||
static void sta_addba_resp_timer_expired(unsigned long data)
|
||||
{
|
||||
/* not an elegant detour, but there is no choice as the timer passes
|
||||
* only one argument, and both sta_info and TID are needed, so init
|
||||
* flow in sta_info_create gives the TID as data, while the timer_to_id
|
||||
* array gives the sta through container_of */
|
||||
u16 tid = *(u8 *)data;
|
||||
struct sta_info *sta = container_of((void *)data,
|
||||
struct sta_info, timer_to_tid[tid]);
|
||||
u8 *state;
|
||||
|
||||
state = &sta->ampdu_mlme.tid_state_tx[tid];
|
||||
|
||||
/* check if the TID waits for addBA response */
|
||||
spin_lock_bh(&sta->lock);
|
||||
if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
|
||||
spin_unlock_bh(&sta->lock);
|
||||
*state = HT_AGG_STATE_IDLE;
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "timer expired on tid %d but we are not "
|
||||
"expecting addBA response there", tid);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
|
||||
#endif
|
||||
|
||||
___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR);
|
||||
spin_unlock_bh(&sta->lock);
|
||||
}
|
||||
|
||||
int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
u16 start_seq_num;
|
||||
u8 *state;
|
||||
int ret = 0;
|
||||
|
||||
if (WARN_ON(!local->ops->ampdu_action))
|
||||
return -EINVAL;
|
||||
|
||||
if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
|
||||
return -EINVAL;
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
|
||||
ra, tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(local, ra);
|
||||
if (!sta) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Could not find the station\n");
|
||||
#endif
|
||||
ret = -ENOENT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* The aggregation code is not prepared to handle
|
||||
* anything but STA/AP due to the BSSID handling.
|
||||
* IBSS could work in the code but isn't supported
|
||||
* by drivers or the standard.
|
||||
*/
|
||||
if (sta->sdata->vif.type != NL80211_IFTYPE_STATION &&
|
||||
sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
||||
sta->sdata->vif.type != NL80211_IFTYPE_AP) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
|
||||
/* we have tried too many times, receiver does not want A-MPDU */
|
||||
if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
|
||||
ret = -EBUSY;
|
||||
goto err_unlock_sta;
|
||||
}
|
||||
|
||||
state = &sta->ampdu_mlme.tid_state_tx[tid];
|
||||
/* check if the TID is not in aggregation flow already */
|
||||
if (*state != HT_AGG_STATE_IDLE) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "BA request denied - session is not "
|
||||
"idle on tid %u\n", tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
ret = -EAGAIN;
|
||||
goto err_unlock_sta;
|
||||
}
|
||||
|
||||
/* prepare A-MPDU MLME for Tx aggregation */
|
||||
sta->ampdu_mlme.tid_tx[tid] =
|
||||
kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
|
||||
if (!sta->ampdu_mlme.tid_tx[tid]) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
|
||||
tid);
|
||||
#endif
|
||||
ret = -ENOMEM;
|
||||
goto err_unlock_sta;
|
||||
}
|
||||
/* Tx timer */
|
||||
sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
|
||||
sta_addba_resp_timer_expired;
|
||||
sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data =
|
||||
(unsigned long)&sta->timer_to_tid[tid];
|
||||
init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
|
||||
|
||||
if (hw->ampdu_queues) {
|
||||
/* create a new queue for this aggregation */
|
||||
ret = ieee80211_ht_agg_queue_add(local, sta, tid);
|
||||
|
||||
/* case no queue is available to aggregation
|
||||
* don't switch to aggregation */
|
||||
if (ret) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "BA request denied - "
|
||||
"queue unavailable for tid %d\n", tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
goto err_unlock_queue;
|
||||
}
|
||||
}
|
||||
sdata = sta->sdata;
|
||||
|
||||
/* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
|
||||
* call back right away, it must see that the flow has begun */
|
||||
*state |= HT_ADDBA_REQUESTED_MSK;
|
||||
|
||||
/* This is slightly racy because the queue isn't stopped */
|
||||
start_seq_num = sta->tid_seq[tid];
|
||||
|
||||
ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
|
||||
&sta->sta, tid, &start_seq_num);
|
||||
|
||||
if (ret) {
|
||||
/* No need to requeue the packets in the agg queue, since we
|
||||
* held the tx lock: no packet could be enqueued to the newly
|
||||
* allocated queue */
|
||||
if (hw->ampdu_queues)
|
||||
ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "BA request denied - HW unavailable for"
|
||||
" tid %d\n", tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
*state = HT_AGG_STATE_IDLE;
|
||||
goto err_unlock_queue;
|
||||
}
|
||||
|
||||
/* Will put all the packets in the new SW queue */
|
||||
if (hw->ampdu_queues)
|
||||
ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
|
||||
spin_unlock_bh(&sta->lock);
|
||||
|
||||
/* send an addBA request */
|
||||
sta->ampdu_mlme.dialog_token_allocator++;
|
||||
sta->ampdu_mlme.tid_tx[tid]->dialog_token =
|
||||
sta->ampdu_mlme.dialog_token_allocator;
|
||||
sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
|
||||
|
||||
|
||||
ieee80211_send_addba_request(sta->sdata, ra, tid,
|
||||
sta->ampdu_mlme.tid_tx[tid]->dialog_token,
|
||||
sta->ampdu_mlme.tid_tx[tid]->ssn,
|
||||
0x40, 5000);
|
||||
/* activate the timer for the recipient's addBA response */
|
||||
sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
|
||||
jiffies + ADDBA_RESP_INTERVAL;
|
||||
add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
|
||||
#endif
|
||||
goto exit;
|
||||
|
||||
err_unlock_queue:
|
||||
kfree(sta->ampdu_mlme.tid_tx[tid]);
|
||||
sta->ampdu_mlme.tid_tx[tid] = NULL;
|
||||
ret = -EBUSY;
|
||||
err_unlock_sta:
|
||||
spin_unlock_bh(&sta->lock);
|
||||
exit:
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
|
||||
|
||||
void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct sta_info *sta;
|
||||
u8 *state;
|
||||
|
||||
if (tid >= STA_TID_NUM) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
|
||||
tid, STA_TID_NUM);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(local, ra);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Could not find station: %pM\n", ra);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
state = &sta->ampdu_mlme.tid_state_tx[tid];
|
||||
spin_lock_bh(&sta->lock);
|
||||
|
||||
if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
|
||||
*state);
|
||||
#endif
|
||||
spin_unlock_bh(&sta->lock);
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK);
|
||||
|
||||
*state |= HT_ADDBA_DRV_READY_MSK;
|
||||
|
||||
if (*state == HT_AGG_STATE_OPERATIONAL) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
|
||||
#endif
|
||||
if (hw->ampdu_queues)
|
||||
ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
|
||||
}
|
||||
spin_unlock_bh(&sta->lock);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
|
||||
|
||||
void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
|
||||
const u8 *ra, u16 tid)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_ra_tid *ra_tid;
|
||||
struct sk_buff *skb = dev_alloc_skb(0);
|
||||
|
||||
if (unlikely(!skb)) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_WARNING "%s: Not enough memory, "
|
||||
"dropping start BA session", skb->dev->name);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
|
||||
memcpy(&ra_tid->ra, ra, ETH_ALEN);
|
||||
ra_tid->tid = tid;
|
||||
|
||||
skb->pkt_type = IEEE80211_ADDBA_MSG;
|
||||
skb_queue_tail(&local->skb_queue, skb);
|
||||
tasklet_schedule(&local->tasklet);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
|
||||
|
||||
int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
||||
enum ieee80211_back_parties initiator)
|
||||
{
|
||||
u8 *state;
|
||||
int ret;
|
||||
|
||||
/* check if the TID is in aggregation */
|
||||
state = &sta->ampdu_mlme.tid_state_tx[tid];
|
||||
spin_lock_bh(&sta->lock);
|
||||
|
||||
if (*state != HT_AGG_STATE_OPERATIONAL) {
|
||||
ret = -ENOENT;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
|
||||
sta->sta.addr, tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
|
||||
ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator);
|
||||
|
||||
unlock:
|
||||
spin_unlock_bh(&sta->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
|
||||
u8 *ra, u16 tid,
|
||||
enum ieee80211_back_parties initiator)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct sta_info *sta;
|
||||
int ret = 0;
|
||||
|
||||
if (WARN_ON(!local->ops->ampdu_action))
|
||||
return -EINVAL;
|
||||
|
||||
if (tid >= STA_TID_NUM)
|
||||
return -EINVAL;
|
||||
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(local, ra);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = __ieee80211_stop_tx_ba_session(sta, tid, initiator);
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
|
||||
|
||||
void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct sta_info *sta;
|
||||
u8 *state;
|
||||
int agg_queue;
|
||||
|
||||
if (tid >= STA_TID_NUM) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
|
||||
tid, STA_TID_NUM);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n",
|
||||
ra, tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(local, ra);
|
||||
if (!sta) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Could not find station: %pM\n", ra);
|
||||
#endif
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
state = &sta->ampdu_mlme.tid_state_tx[tid];
|
||||
|
||||
/* NOTE: no need to use sta->lock in this state check, as
|
||||
* ieee80211_stop_tx_ba_session will let only one stop call to
|
||||
* pass through per sta/tid
|
||||
*/
|
||||
if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
|
||||
#endif
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
if (*state & HT_AGG_STATE_INITIATOR_MSK)
|
||||
ieee80211_send_delba(sta->sdata, ra, tid,
|
||||
WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
|
||||
|
||||
if (hw->ampdu_queues) {
|
||||
agg_queue = sta->tid_to_tx_q[tid];
|
||||
ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
|
||||
|
||||
/* We just requeued the all the frames that were in the
|
||||
* removed queue, and since we might miss a softirq we do
|
||||
* netif_schedule_queue. ieee80211_wake_queue is not used
|
||||
* here as this queue is not necessarily stopped
|
||||
*/
|
||||
netif_schedule_queue(netdev_get_tx_queue(local->mdev,
|
||||
agg_queue));
|
||||
}
|
||||
spin_lock_bh(&sta->lock);
|
||||
*state = HT_AGG_STATE_IDLE;
|
||||
sta->ampdu_mlme.addba_req_num[tid] = 0;
|
||||
kfree(sta->ampdu_mlme.tid_tx[tid]);
|
||||
sta->ampdu_mlme.tid_tx[tid] = NULL;
|
||||
spin_unlock_bh(&sta->lock);
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
|
||||
|
||||
void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
|
||||
const u8 *ra, u16 tid)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_ra_tid *ra_tid;
|
||||
struct sk_buff *skb = dev_alloc_skb(0);
|
||||
|
||||
if (unlikely(!skb)) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_WARNING "%s: Not enough memory, "
|
||||
"dropping stop BA session", skb->dev->name);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
|
||||
memcpy(&ra_tid->ra, ra, ETH_ALEN);
|
||||
ra_tid->tid = tid;
|
||||
|
||||
skb->pkt_type = IEEE80211_DELBA_MSG;
|
||||
skb_queue_tail(&local->skb_queue, skb);
|
||||
tasklet_schedule(&local->tasklet);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
|
||||
|
||||
|
||||
void ieee80211_process_addba_resp(struct ieee80211_local *local,
|
||||
struct sta_info *sta,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
size_t len)
|
||||
{
|
||||
struct ieee80211_hw *hw = &local->hw;
|
||||
u16 capab;
|
||||
u16 tid, start_seq_num;
|
||||
u8 *state;
|
||||
|
||||
capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
|
||||
tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
|
||||
|
||||
state = &sta->ampdu_mlme.tid_state_tx[tid];
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
|
||||
if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
|
||||
spin_unlock_bh(&sta->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mgmt->u.action.u.addba_resp.dialog_token !=
|
||||
sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
|
||||
spin_unlock_bh(&sta->lock);
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
return;
|
||||
}
|
||||
|
||||
del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
|
||||
== WLAN_STATUS_SUCCESS) {
|
||||
*state |= HT_ADDBA_RECEIVED_MSK;
|
||||
sta->ampdu_mlme.addba_req_num[tid] = 0;
|
||||
|
||||
if (*state == HT_AGG_STATE_OPERATIONAL &&
|
||||
local->hw.ampdu_queues)
|
||||
ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
|
||||
|
||||
if (local->ops->ampdu_action) {
|
||||
(void)local->ops->ampdu_action(hw,
|
||||
IEEE80211_AMPDU_TX_RESUME,
|
||||
&sta->sta, tid, &start_seq_num);
|
||||
}
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
} else {
|
||||
sta->ampdu_mlme.addba_req_num[tid]++;
|
||||
___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR);
|
||||
}
|
||||
spin_unlock_bh(&sta->lock);
|
||||
}
|
@ -1176,11 +1176,16 @@ static int ieee80211_set_channel(struct wiphy *wiphy,
|
||||
return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
|
||||
}
|
||||
|
||||
static int set_mgmt_extra_ie_sta(struct ieee80211_if_sta *ifsta, u8 subtype,
|
||||
u8 *ies, size_t ies_len)
|
||||
static int set_mgmt_extra_ie_sta(struct ieee80211_sub_if_data *sdata,
|
||||
u8 subtype, u8 *ies, size_t ies_len)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
|
||||
|
||||
switch (subtype) {
|
||||
case IEEE80211_STYPE_PROBE_REQ >> 4:
|
||||
if (local->ops->hw_scan)
|
||||
break;
|
||||
kfree(ifsta->ie_probereq);
|
||||
ifsta->ie_probereq = ies;
|
||||
ifsta->ie_probereq_len = ies_len;
|
||||
@ -1244,7 +1249,7 @@ static int ieee80211_set_mgmt_extra_ie(struct wiphy *wiphy,
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
ret = set_mgmt_extra_ie_sta(&sdata->u.sta, params->subtype,
|
||||
ret = set_mgmt_extra_ie_sta(sdata, params->subtype,
|
||||
ies, ies_len);
|
||||
break;
|
||||
default:
|
||||
@ -1272,6 +1277,25 @@ static int ieee80211_resume(struct wiphy *wiphy)
|
||||
#define ieee80211_resume NULL
|
||||
#endif
|
||||
|
||||
static int ieee80211_scan(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_scan_request *req)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
if (!netif_running(dev))
|
||||
return -ENETDOWN;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
|
||||
sdata->vif.type != NL80211_IFTYPE_ADHOC &&
|
||||
sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return ieee80211_request_scan(sdata, req);
|
||||
}
|
||||
|
||||
struct cfg80211_ops mac80211_config_ops = {
|
||||
.add_virtual_intf = ieee80211_add_iface,
|
||||
.del_virtual_intf = ieee80211_del_iface,
|
||||
@ -1304,4 +1328,5 @@ struct cfg80211_ops mac80211_config_ops = {
|
||||
.set_mgmt_extra_ie = ieee80211_set_mgmt_extra_ie,
|
||||
.suspend = ieee80211_suspend,
|
||||
.resume = ieee80211_resume,
|
||||
.scan = ieee80211_scan,
|
||||
};
|
||||
|
@ -17,8 +17,6 @@
|
||||
#include <net/wireless.h>
|
||||
#include <net/mac80211.h>
|
||||
#include "ieee80211_i.h"
|
||||
#include "sta_info.h"
|
||||
#include "wme.h"
|
||||
|
||||
void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
|
||||
struct ieee80211_ht_cap *ht_cap_ie,
|
||||
@ -155,105 +153,20 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
|
||||
return changed;
|
||||
}
|
||||
|
||||
static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *da, u16 tid,
|
||||
u8 dialog_token, u16 start_seq_num,
|
||||
u16 agg_size, u16 timeout)
|
||||
void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
u16 capab;
|
||||
int i;
|
||||
|
||||
skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
|
||||
|
||||
if (!skb) {
|
||||
printk(KERN_ERR "%s: failed to allocate buffer "
|
||||
"for addba request frame\n", sdata->dev->name);
|
||||
return;
|
||||
for (i = 0; i < STA_TID_NUM; i++) {
|
||||
__ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR);
|
||||
__ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT,
|
||||
WLAN_REASON_QSTA_LEAVE_QBSS);
|
||||
}
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
|
||||
memset(mgmt, 0, 24);
|
||||
memcpy(mgmt->da, da, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP)
|
||||
memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
|
||||
else
|
||||
memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
|
||||
|
||||
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_ACTION);
|
||||
|
||||
skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
|
||||
|
||||
mgmt->u.action.category = WLAN_CATEGORY_BACK;
|
||||
mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
|
||||
|
||||
mgmt->u.action.u.addba_req.dialog_token = dialog_token;
|
||||
capab = (u16)(1 << 1); /* bit 1 aggregation policy */
|
||||
capab |= (u16)(tid << 2); /* bit 5:2 TID number */
|
||||
capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */
|
||||
|
||||
mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
|
||||
|
||||
mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout);
|
||||
mgmt->u.action.u.addba_req.start_seq_num =
|
||||
cpu_to_le16(start_seq_num << 4);
|
||||
|
||||
ieee80211_tx_skb(sdata, skb, 1);
|
||||
}
|
||||
|
||||
static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
|
||||
u8 dialog_token, u16 status, u16 policy,
|
||||
u16 buf_size, u16 timeout)
|
||||
{
|
||||
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
u16 capab;
|
||||
|
||||
skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
|
||||
|
||||
if (!skb) {
|
||||
printk(KERN_DEBUG "%s: failed to allocate buffer "
|
||||
"for addba resp frame\n", sdata->dev->name);
|
||||
return;
|
||||
}
|
||||
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
|
||||
memset(mgmt, 0, 24);
|
||||
memcpy(mgmt->da, da, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP)
|
||||
memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
|
||||
else
|
||||
memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
|
||||
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_ACTION);
|
||||
|
||||
skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
|
||||
mgmt->u.action.category = WLAN_CATEGORY_BACK;
|
||||
mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
|
||||
mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
|
||||
|
||||
capab = (u16)(policy << 1); /* bit 1 aggregation policy */
|
||||
capab |= (u16)(tid << 2); /* bit 5:2 TID number */
|
||||
capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */
|
||||
|
||||
mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
|
||||
mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
|
||||
mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
|
||||
|
||||
ieee80211_tx_skb(sdata, skb, 1);
|
||||
}
|
||||
|
||||
static void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *da, u16 tid,
|
||||
u16 initiator, u16 reason_code)
|
||||
void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *da, u16 tid,
|
||||
u16 initiator, u16 reason_code)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
|
||||
@ -274,7 +187,8 @@ static void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
|
||||
memset(mgmt, 0, 24);
|
||||
memcpy(mgmt->da, da, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP)
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
|
||||
else
|
||||
memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
|
||||
@ -294,767 +208,6 @@ static void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_tx_skb(sdata, skb, 1);
|
||||
}
|
||||
|
||||
void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_bar *bar;
|
||||
u16 bar_control = 0;
|
||||
|
||||
skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom);
|
||||
if (!skb) {
|
||||
printk(KERN_ERR "%s: failed to allocate buffer for "
|
||||
"bar frame\n", sdata->dev->name);
|
||||
return;
|
||||
}
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar));
|
||||
memset(bar, 0, sizeof(*bar));
|
||||
bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
|
||||
IEEE80211_STYPE_BACK_REQ);
|
||||
memcpy(bar->ra, ra, ETH_ALEN);
|
||||
memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN);
|
||||
bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
|
||||
bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
|
||||
bar_control |= (u16)(tid << 12);
|
||||
bar->control = cpu_to_le16(bar_control);
|
||||
bar->start_seq_num = cpu_to_le16(ssn);
|
||||
|
||||
ieee80211_tx_skb(sdata, skb, 0);
|
||||
}
|
||||
|
||||
void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid,
|
||||
u16 initiator, u16 reason)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_hw *hw = &local->hw;
|
||||
struct sta_info *sta;
|
||||
int ret, i;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(local, ra);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
/* check if TID is in operational state */
|
||||
spin_lock_bh(&sta->lock);
|
||||
if (sta->ampdu_mlme.tid_state_rx[tid]
|
||||
!= HT_AGG_STATE_OPERATIONAL) {
|
||||
spin_unlock_bh(&sta->lock);
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
sta->ampdu_mlme.tid_state_rx[tid] =
|
||||
HT_AGG_STATE_REQ_STOP_BA_MSK |
|
||||
(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
|
||||
spin_unlock_bh(&sta->lock);
|
||||
|
||||
/* stop HW Rx aggregation. ampdu_action existence
|
||||
* already verified in session init so we add the BUG_ON */
|
||||
BUG_ON(!local->ops->ampdu_action);
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n",
|
||||
ra, tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
|
||||
ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP,
|
||||
&sta->sta, tid, NULL);
|
||||
if (ret)
|
||||
printk(KERN_DEBUG "HW problem - can not stop rx "
|
||||
"aggregation for tid %d\n", tid);
|
||||
|
||||
/* shutdown timer has not expired */
|
||||
if (initiator != WLAN_BACK_TIMER)
|
||||
del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
|
||||
|
||||
/* check if this is a self generated aggregation halt */
|
||||
if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER)
|
||||
ieee80211_send_delba(sdata, ra, tid, 0, reason);
|
||||
|
||||
/* free the reordering buffer */
|
||||
for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) {
|
||||
if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) {
|
||||
/* release the reordered frames */
|
||||
dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]);
|
||||
sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--;
|
||||
sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL;
|
||||
}
|
||||
}
|
||||
/* free resources */
|
||||
kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf);
|
||||
kfree(sta->ampdu_mlme.tid_rx[tid]);
|
||||
sta->ampdu_mlme.tid_rx[tid] = NULL;
|
||||
sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE;
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* After sending add Block Ack request we activated a timer until
|
||||
* add Block Ack response will arrive from the recipient.
|
||||
* If this timer expires sta_addba_resp_timer_expired will be executed.
|
||||
*/
|
||||
static void sta_addba_resp_timer_expired(unsigned long data)
|
||||
{
|
||||
/* not an elegant detour, but there is no choice as the timer passes
|
||||
* only one argument, and both sta_info and TID are needed, so init
|
||||
* flow in sta_info_create gives the TID as data, while the timer_to_id
|
||||
* array gives the sta through container_of */
|
||||
u16 tid = *(u8 *)data;
|
||||
struct sta_info *temp_sta = container_of((void *)data,
|
||||
struct sta_info, timer_to_tid[tid]);
|
||||
|
||||
struct ieee80211_local *local = temp_sta->local;
|
||||
struct ieee80211_hw *hw = &local->hw;
|
||||
struct sta_info *sta;
|
||||
u8 *state;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(local, temp_sta->sta.addr);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
state = &sta->ampdu_mlme.tid_state_tx[tid];
|
||||
/* check if the TID waits for addBA response */
|
||||
spin_lock_bh(&sta->lock);
|
||||
if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
|
||||
spin_unlock_bh(&sta->lock);
|
||||
*state = HT_AGG_STATE_IDLE;
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "timer expired on tid %d but we are not "
|
||||
"expecting addBA response there", tid);
|
||||
#endif
|
||||
goto timer_expired_exit;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
|
||||
#endif
|
||||
|
||||
/* go through the state check in stop_BA_session */
|
||||
*state = HT_AGG_STATE_OPERATIONAL;
|
||||
spin_unlock_bh(&sta->lock);
|
||||
ieee80211_stop_tx_ba_session(hw, temp_sta->sta.addr, tid,
|
||||
WLAN_BACK_INITIATOR);
|
||||
|
||||
timer_expired_exit:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < STA_TID_NUM; i++) {
|
||||
ieee80211_stop_tx_ba_session(&local->hw, addr, i,
|
||||
WLAN_BACK_INITIATOR);
|
||||
ieee80211_sta_stop_rx_ba_session(sdata, addr, i,
|
||||
WLAN_BACK_RECIPIENT,
|
||||
WLAN_REASON_QSTA_LEAVE_QBSS);
|
||||
}
|
||||
}
|
||||
|
||||
int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
u16 start_seq_num;
|
||||
u8 *state;
|
||||
int ret = 0;
|
||||
|
||||
if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
|
||||
return -EINVAL;
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
|
||||
ra, tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(local, ra);
|
||||
if (!sta) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Could not find the station\n");
|
||||
#endif
|
||||
ret = -ENOENT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
|
||||
/* we have tried too many times, receiver does not want A-MPDU */
|
||||
if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
|
||||
ret = -EBUSY;
|
||||
goto err_unlock_sta;
|
||||
}
|
||||
|
||||
state = &sta->ampdu_mlme.tid_state_tx[tid];
|
||||
/* check if the TID is not in aggregation flow already */
|
||||
if (*state != HT_AGG_STATE_IDLE) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "BA request denied - session is not "
|
||||
"idle on tid %u\n", tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
ret = -EAGAIN;
|
||||
goto err_unlock_sta;
|
||||
}
|
||||
|
||||
/* prepare A-MPDU MLME for Tx aggregation */
|
||||
sta->ampdu_mlme.tid_tx[tid] =
|
||||
kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
|
||||
if (!sta->ampdu_mlme.tid_tx[tid]) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
|
||||
tid);
|
||||
#endif
|
||||
ret = -ENOMEM;
|
||||
goto err_unlock_sta;
|
||||
}
|
||||
/* Tx timer */
|
||||
sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
|
||||
sta_addba_resp_timer_expired;
|
||||
sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data =
|
||||
(unsigned long)&sta->timer_to_tid[tid];
|
||||
init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
|
||||
|
||||
if (hw->ampdu_queues) {
|
||||
/* create a new queue for this aggregation */
|
||||
ret = ieee80211_ht_agg_queue_add(local, sta, tid);
|
||||
|
||||
/* case no queue is available to aggregation
|
||||
* don't switch to aggregation */
|
||||
if (ret) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "BA request denied - "
|
||||
"queue unavailable for tid %d\n", tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
goto err_unlock_queue;
|
||||
}
|
||||
}
|
||||
sdata = sta->sdata;
|
||||
|
||||
/* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
|
||||
* call back right away, it must see that the flow has begun */
|
||||
*state |= HT_ADDBA_REQUESTED_MSK;
|
||||
|
||||
/* This is slightly racy because the queue isn't stopped */
|
||||
start_seq_num = sta->tid_seq[tid];
|
||||
|
||||
if (local->ops->ampdu_action)
|
||||
ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
|
||||
&sta->sta, tid, &start_seq_num);
|
||||
|
||||
if (ret) {
|
||||
/* No need to requeue the packets in the agg queue, since we
|
||||
* held the tx lock: no packet could be enqueued to the newly
|
||||
* allocated queue */
|
||||
if (hw->ampdu_queues)
|
||||
ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "BA request denied - HW unavailable for"
|
||||
" tid %d\n", tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
*state = HT_AGG_STATE_IDLE;
|
||||
goto err_unlock_queue;
|
||||
}
|
||||
|
||||
/* Will put all the packets in the new SW queue */
|
||||
if (hw->ampdu_queues)
|
||||
ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
|
||||
spin_unlock_bh(&sta->lock);
|
||||
|
||||
/* send an addBA request */
|
||||
sta->ampdu_mlme.dialog_token_allocator++;
|
||||
sta->ampdu_mlme.tid_tx[tid]->dialog_token =
|
||||
sta->ampdu_mlme.dialog_token_allocator;
|
||||
sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
|
||||
|
||||
|
||||
ieee80211_send_addba_request(sta->sdata, ra, tid,
|
||||
sta->ampdu_mlme.tid_tx[tid]->dialog_token,
|
||||
sta->ampdu_mlme.tid_tx[tid]->ssn,
|
||||
0x40, 5000);
|
||||
/* activate the timer for the recipient's addBA response */
|
||||
sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
|
||||
jiffies + ADDBA_RESP_INTERVAL;
|
||||
add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
|
||||
#endif
|
||||
goto exit;
|
||||
|
||||
err_unlock_queue:
|
||||
kfree(sta->ampdu_mlme.tid_tx[tid]);
|
||||
sta->ampdu_mlme.tid_tx[tid] = NULL;
|
||||
ret = -EBUSY;
|
||||
err_unlock_sta:
|
||||
spin_unlock_bh(&sta->lock);
|
||||
exit:
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
|
||||
|
||||
int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
|
||||
u8 *ra, u16 tid,
|
||||
enum ieee80211_back_parties initiator)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct sta_info *sta;
|
||||
u8 *state;
|
||||
int ret = 0;
|
||||
|
||||
if (tid >= STA_TID_NUM)
|
||||
return -EINVAL;
|
||||
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(local, ra);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* check if the TID is in aggregation */
|
||||
state = &sta->ampdu_mlme.tid_state_tx[tid];
|
||||
spin_lock_bh(&sta->lock);
|
||||
|
||||
if (*state != HT_AGG_STATE_OPERATIONAL) {
|
||||
ret = -ENOENT;
|
||||
goto stop_BA_exit;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
|
||||
ra, tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
|
||||
if (hw->ampdu_queues)
|
||||
ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]);
|
||||
|
||||
*state = HT_AGG_STATE_REQ_STOP_BA_MSK |
|
||||
(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
|
||||
|
||||
if (local->ops->ampdu_action)
|
||||
ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP,
|
||||
&sta->sta, tid, NULL);
|
||||
|
||||
/* case HW denied going back to legacy */
|
||||
if (ret) {
|
||||
WARN_ON(ret != -EBUSY);
|
||||
*state = HT_AGG_STATE_OPERATIONAL;
|
||||
if (hw->ampdu_queues)
|
||||
ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
|
||||
goto stop_BA_exit;
|
||||
}
|
||||
|
||||
stop_BA_exit:
|
||||
spin_unlock_bh(&sta->lock);
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
|
||||
|
||||
void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct sta_info *sta;
|
||||
u8 *state;
|
||||
|
||||
if (tid >= STA_TID_NUM) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
|
||||
tid, STA_TID_NUM);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(local, ra);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Could not find station: %pM\n", ra);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
state = &sta->ampdu_mlme.tid_state_tx[tid];
|
||||
spin_lock_bh(&sta->lock);
|
||||
|
||||
if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
|
||||
*state);
|
||||
#endif
|
||||
spin_unlock_bh(&sta->lock);
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK);
|
||||
|
||||
*state |= HT_ADDBA_DRV_READY_MSK;
|
||||
|
||||
if (*state == HT_AGG_STATE_OPERATIONAL) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
|
||||
#endif
|
||||
if (hw->ampdu_queues)
|
||||
ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
|
||||
}
|
||||
spin_unlock_bh(&sta->lock);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
|
||||
|
||||
void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct sta_info *sta;
|
||||
u8 *state;
|
||||
int agg_queue;
|
||||
|
||||
if (tid >= STA_TID_NUM) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
|
||||
tid, STA_TID_NUM);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n",
|
||||
ra, tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(local, ra);
|
||||
if (!sta) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Could not find station: %pM\n", ra);
|
||||
#endif
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
state = &sta->ampdu_mlme.tid_state_tx[tid];
|
||||
|
||||
/* NOTE: no need to use sta->lock in this state check, as
|
||||
* ieee80211_stop_tx_ba_session will let only one stop call to
|
||||
* pass through per sta/tid
|
||||
*/
|
||||
if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
|
||||
#endif
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
if (*state & HT_AGG_STATE_INITIATOR_MSK)
|
||||
ieee80211_send_delba(sta->sdata, ra, tid,
|
||||
WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
|
||||
|
||||
if (hw->ampdu_queues) {
|
||||
agg_queue = sta->tid_to_tx_q[tid];
|
||||
ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
|
||||
|
||||
/* We just requeued the all the frames that were in the
|
||||
* removed queue, and since we might miss a softirq we do
|
||||
* netif_schedule_queue. ieee80211_wake_queue is not used
|
||||
* here as this queue is not necessarily stopped
|
||||
*/
|
||||
netif_schedule_queue(netdev_get_tx_queue(local->mdev,
|
||||
agg_queue));
|
||||
}
|
||||
spin_lock_bh(&sta->lock);
|
||||
*state = HT_AGG_STATE_IDLE;
|
||||
sta->ampdu_mlme.addba_req_num[tid] = 0;
|
||||
kfree(sta->ampdu_mlme.tid_tx[tid]);
|
||||
sta->ampdu_mlme.tid_tx[tid] = NULL;
|
||||
spin_unlock_bh(&sta->lock);
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
|
||||
|
||||
void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
|
||||
const u8 *ra, u16 tid)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_ra_tid *ra_tid;
|
||||
struct sk_buff *skb = dev_alloc_skb(0);
|
||||
|
||||
if (unlikely(!skb)) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_WARNING "%s: Not enough memory, "
|
||||
"dropping start BA session", skb->dev->name);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
|
||||
memcpy(&ra_tid->ra, ra, ETH_ALEN);
|
||||
ra_tid->tid = tid;
|
||||
|
||||
skb->pkt_type = IEEE80211_ADDBA_MSG;
|
||||
skb_queue_tail(&local->skb_queue, skb);
|
||||
tasklet_schedule(&local->tasklet);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
|
||||
|
||||
void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
|
||||
const u8 *ra, u16 tid)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_ra_tid *ra_tid;
|
||||
struct sk_buff *skb = dev_alloc_skb(0);
|
||||
|
||||
if (unlikely(!skb)) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_WARNING "%s: Not enough memory, "
|
||||
"dropping stop BA session", skb->dev->name);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
|
||||
memcpy(&ra_tid->ra, ra, ETH_ALEN);
|
||||
ra_tid->tid = tid;
|
||||
|
||||
skb->pkt_type = IEEE80211_DELBA_MSG;
|
||||
skb_queue_tail(&local->skb_queue, skb);
|
||||
tasklet_schedule(&local->tasklet);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
|
||||
|
||||
/*
|
||||
* After accepting the AddBA Request we activated a timer,
|
||||
* resetting it after each frame that arrives from the originator.
|
||||
* if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
|
||||
*/
|
||||
static void sta_rx_agg_session_timer_expired(unsigned long data)
|
||||
{
|
||||
/* not an elegant detour, but there is no choice as the timer passes
|
||||
* only one argument, and various sta_info are needed here, so init
|
||||
* flow in sta_info_create gives the TID as data, while the timer_to_id
|
||||
* array gives the sta through container_of */
|
||||
u8 *ptid = (u8 *)data;
|
||||
u8 *timer_to_id = ptid - *ptid;
|
||||
struct sta_info *sta = container_of(timer_to_id, struct sta_info,
|
||||
timer_to_tid[0]);
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
|
||||
#endif
|
||||
ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
|
||||
(u16)*ptid, WLAN_BACK_TIMER,
|
||||
WLAN_REASON_QSTA_TIMEOUT);
|
||||
}
|
||||
|
||||
void ieee80211_process_addba_request(struct ieee80211_local *local,
|
||||
struct sta_info *sta,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
size_t len)
|
||||
{
|
||||
struct ieee80211_hw *hw = &local->hw;
|
||||
struct ieee80211_conf *conf = &hw->conf;
|
||||
struct tid_ampdu_rx *tid_agg_rx;
|
||||
u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status;
|
||||
u8 dialog_token;
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
/* extract session parameters from addba request frame */
|
||||
dialog_token = mgmt->u.action.u.addba_req.dialog_token;
|
||||
timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
|
||||
start_seq_num =
|
||||
le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
|
||||
|
||||
capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
|
||||
ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
|
||||
tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
|
||||
buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
|
||||
|
||||
status = WLAN_STATUS_REQUEST_DECLINED;
|
||||
|
||||
/* sanity check for incoming parameters:
|
||||
* check if configuration can support the BA policy
|
||||
* and if buffer size does not exceeds max value */
|
||||
/* XXX: check own ht delayed BA capability?? */
|
||||
if (((ba_policy != 1)
|
||||
&& (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA)))
|
||||
|| (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
|
||||
status = WLAN_STATUS_INVALID_QOS_PARAM;
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_DEBUG "AddBA Req with bad params from "
|
||||
"%pM on tid %u. policy %d, buffer size %d\n",
|
||||
mgmt->sa, tid, ba_policy,
|
||||
buf_size);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
goto end_no_lock;
|
||||
}
|
||||
/* determine default buffer size */
|
||||
if (buf_size == 0) {
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
sband = local->hw.wiphy->bands[conf->channel->band];
|
||||
buf_size = IEEE80211_MIN_AMPDU_BUF;
|
||||
buf_size = buf_size << sband->ht_cap.ampdu_factor;
|
||||
}
|
||||
|
||||
|
||||
/* examine state machine */
|
||||
spin_lock_bh(&sta->lock);
|
||||
|
||||
if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_DEBUG "unexpected AddBA Req from "
|
||||
"%pM on tid %u\n",
|
||||
mgmt->sa, tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* prepare A-MPDU MLME for Rx aggregation */
|
||||
sta->ampdu_mlme.tid_rx[tid] =
|
||||
kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
|
||||
if (!sta->ampdu_mlme.tid_rx[tid]) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_ERR "allocate rx mlme to tid %d failed\n",
|
||||
tid);
|
||||
#endif
|
||||
goto end;
|
||||
}
|
||||
/* rx timer */
|
||||
sta->ampdu_mlme.tid_rx[tid]->session_timer.function =
|
||||
sta_rx_agg_session_timer_expired;
|
||||
sta->ampdu_mlme.tid_rx[tid]->session_timer.data =
|
||||
(unsigned long)&sta->timer_to_tid[tid];
|
||||
init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
|
||||
|
||||
tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
|
||||
|
||||
/* prepare reordering buffer */
|
||||
tid_agg_rx->reorder_buf =
|
||||
kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC);
|
||||
if (!tid_agg_rx->reorder_buf) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_ERR "can not allocate reordering buffer "
|
||||
"to tid %d\n", tid);
|
||||
#endif
|
||||
kfree(sta->ampdu_mlme.tid_rx[tid]);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (local->ops->ampdu_action)
|
||||
ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START,
|
||||
&sta->sta, tid, &start_seq_num);
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
|
||||
if (ret) {
|
||||
kfree(tid_agg_rx->reorder_buf);
|
||||
kfree(tid_agg_rx);
|
||||
sta->ampdu_mlme.tid_rx[tid] = NULL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* change state and send addba resp */
|
||||
sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL;
|
||||
tid_agg_rx->dialog_token = dialog_token;
|
||||
tid_agg_rx->ssn = start_seq_num;
|
||||
tid_agg_rx->head_seq_num = start_seq_num;
|
||||
tid_agg_rx->buf_size = buf_size;
|
||||
tid_agg_rx->timeout = timeout;
|
||||
tid_agg_rx->stored_mpdu_num = 0;
|
||||
status = WLAN_STATUS_SUCCESS;
|
||||
end:
|
||||
spin_unlock_bh(&sta->lock);
|
||||
|
||||
end_no_lock:
|
||||
ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
|
||||
dialog_token, status, 1, buf_size, timeout);
|
||||
}
|
||||
|
||||
void ieee80211_process_addba_resp(struct ieee80211_local *local,
|
||||
struct sta_info *sta,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
size_t len)
|
||||
{
|
||||
struct ieee80211_hw *hw = &local->hw;
|
||||
u16 capab;
|
||||
u16 tid, start_seq_num;
|
||||
u8 *state;
|
||||
|
||||
capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
|
||||
tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
|
||||
|
||||
state = &sta->ampdu_mlme.tid_state_tx[tid];
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
|
||||
if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
|
||||
spin_unlock_bh(&sta->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mgmt->u.action.u.addba_resp.dialog_token !=
|
||||
sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
|
||||
spin_unlock_bh(&sta->lock);
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
return;
|
||||
}
|
||||
|
||||
del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
|
||||
== WLAN_STATUS_SUCCESS) {
|
||||
*state |= HT_ADDBA_RECEIVED_MSK;
|
||||
sta->ampdu_mlme.addba_req_num[tid] = 0;
|
||||
|
||||
if (*state == HT_AGG_STATE_OPERATIONAL &&
|
||||
local->hw.ampdu_queues)
|
||||
ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
|
||||
|
||||
if (local->ops->ampdu_action) {
|
||||
(void)local->ops->ampdu_action(hw,
|
||||
IEEE80211_AMPDU_TX_RESUME,
|
||||
&sta->sta, tid, &start_seq_num);
|
||||
}
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
spin_unlock_bh(&sta->lock);
|
||||
} else {
|
||||
sta->ampdu_mlme.addba_req_num[tid]++;
|
||||
/* this will allow the state check in stop_BA_session */
|
||||
*state = HT_AGG_STATE_OPERATIONAL;
|
||||
spin_unlock_bh(&sta->lock);
|
||||
ieee80211_stop_tx_ba_session(hw, sta->sta.addr, tid,
|
||||
WLAN_BACK_INITIATOR);
|
||||
}
|
||||
}
|
||||
|
||||
void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta,
|
||||
struct ieee80211_mgmt *mgmt, size_t len)
|
||||
|
@ -57,6 +57,8 @@ struct ieee80211_local;
|
||||
*/
|
||||
#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ)
|
||||
|
||||
#define TU_TO_EXP_TIME(x) (jiffies + usecs_to_jiffies((x) * 1024))
|
||||
|
||||
struct ieee80211_fragment_entry {
|
||||
unsigned long first_frag_time;
|
||||
unsigned int seq;
|
||||
@ -70,43 +72,36 @@ struct ieee80211_fragment_entry {
|
||||
|
||||
|
||||
struct ieee80211_bss {
|
||||
struct list_head list;
|
||||
struct ieee80211_bss *hnext;
|
||||
/* Yes, this is a hack */
|
||||
struct cfg80211_bss cbss;
|
||||
|
||||
/* don't want to look up all the time */
|
||||
size_t ssid_len;
|
||||
|
||||
atomic_t users;
|
||||
|
||||
u8 bssid[ETH_ALEN];
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
|
||||
u8 dtim_period;
|
||||
u16 capability; /* host byte order */
|
||||
enum ieee80211_band band;
|
||||
int freq;
|
||||
int signal, noise, qual;
|
||||
u8 *ies; /* all information elements from the last Beacon or Probe
|
||||
* Response frames; note Beacon frame is not allowed to
|
||||
* override values from Probe Response */
|
||||
size_t ies_len;
|
||||
|
||||
bool wmm_used;
|
||||
|
||||
unsigned long last_probe_resp;
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
u8 *mesh_id;
|
||||
size_t mesh_id_len;
|
||||
u8 *mesh_cfg;
|
||||
#endif
|
||||
|
||||
#define IEEE80211_MAX_SUPP_RATES 32
|
||||
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
|
||||
size_t supp_rates_len;
|
||||
u64 timestamp;
|
||||
int beacon_int;
|
||||
|
||||
unsigned long last_probe_resp;
|
||||
unsigned long last_update;
|
||||
|
||||
/* during assocation, we save an ERP value from a probe response so
|
||||
/*
|
||||
* During assocation, we save an ERP value from a probe response so
|
||||
* that we can feed ERP info to the driver when handling the
|
||||
* association completes. these fields probably won't be up-to-date
|
||||
* otherwise, you probably don't want to use them. */
|
||||
int has_erp_value;
|
||||
* otherwise, you probably don't want to use them.
|
||||
*/
|
||||
bool has_erp_value;
|
||||
u8 erp_value;
|
||||
};
|
||||
|
||||
@ -292,8 +287,6 @@ struct ieee80211_if_sta {
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
enum ieee80211_sta_mlme_state state;
|
||||
size_t ssid_len;
|
||||
u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
|
||||
size_t scan_ssid_len;
|
||||
u16 aid;
|
||||
u16 ap_capab, capab;
|
||||
u8 *extra_ie; /* to be added to the end of AssocReq */
|
||||
@ -599,7 +592,6 @@ struct ieee80211_local {
|
||||
int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss;
|
||||
unsigned int filter_flags; /* FIF_* */
|
||||
struct iw_statistics wstats;
|
||||
u8 wstats_flags;
|
||||
bool tim_in_locked_section; /* see ieee80211_beacon_get() */
|
||||
int tx_headroom; /* required headroom for hardware/radiotap */
|
||||
|
||||
@ -656,20 +648,18 @@ struct ieee80211_local {
|
||||
|
||||
/* Scanning and BSS list */
|
||||
bool sw_scanning, hw_scanning;
|
||||
struct cfg80211_ssid scan_ssid;
|
||||
struct cfg80211_scan_request int_scan_req;
|
||||
struct cfg80211_scan_request *scan_req;
|
||||
struct ieee80211_channel *scan_channel;
|
||||
int scan_channel_idx;
|
||||
enum ieee80211_band scan_band;
|
||||
|
||||
enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
|
||||
unsigned long last_scan_completed;
|
||||
struct delayed_work scan_work;
|
||||
struct ieee80211_sub_if_data *scan_sdata;
|
||||
struct ieee80211_channel *oper_channel, *scan_channel, *csa_channel;
|
||||
enum nl80211_channel_type oper_channel_type;
|
||||
u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
|
||||
size_t scan_ssid_len;
|
||||
struct list_head bss_list;
|
||||
struct ieee80211_bss *bss_hash[STA_HASH_SIZE];
|
||||
spinlock_t bss_lock;
|
||||
struct ieee80211_channel *oper_channel, *csa_channel;
|
||||
|
||||
/* SNMP counters */
|
||||
/* dot11CountersTable */
|
||||
@ -728,6 +718,7 @@ struct ieee80211_local {
|
||||
unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
|
||||
|
||||
bool powersave;
|
||||
bool pspolling;
|
||||
struct work_struct dynamic_ps_enable_work;
|
||||
struct work_struct dynamic_ps_disable_work;
|
||||
struct timer_list dynamic_ps_timer;
|
||||
@ -921,10 +912,12 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
|
||||
enum ieee80211_band band);
|
||||
void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
|
||||
u8 *ssid, size_t ssid_len);
|
||||
void ieee80211_send_pspoll(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
|
||||
/* scan/BSS handling */
|
||||
int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
|
||||
u8 *ssid, size_t ssid_len);
|
||||
struct cfg80211_scan_request *req);
|
||||
int ieee80211_scan_results(struct ieee80211_local *local,
|
||||
struct iw_request_info *info,
|
||||
char *buf, size_t len);
|
||||
@ -932,29 +925,27 @@ ieee80211_rx_result
|
||||
ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb,
|
||||
struct ieee80211_rx_status *rx_status);
|
||||
void ieee80211_rx_bss_list_init(struct ieee80211_local *local);
|
||||
void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local);
|
||||
int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata,
|
||||
char *ie, size_t len);
|
||||
|
||||
void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local);
|
||||
int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
|
||||
u8 *ssid, size_t ssid_len);
|
||||
struct cfg80211_scan_request *req);
|
||||
struct ieee80211_bss *
|
||||
ieee80211_bss_info_update(struct ieee80211_local *local,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
size_t len,
|
||||
struct ieee802_11_elems *elems,
|
||||
int freq, bool beacon);
|
||||
struct ieee80211_bss *
|
||||
ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq,
|
||||
u8 *ssid, u8 ssid_len);
|
||||
struct ieee80211_channel *channel,
|
||||
bool beacon);
|
||||
struct ieee80211_bss *
|
||||
ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
|
||||
u8 *ssid, u8 ssid_len);
|
||||
void ieee80211_rx_bss_put(struct ieee80211_local *local,
|
||||
struct ieee80211_bss *bss);
|
||||
void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid,
|
||||
int freq, u8 *ssid, u8 ssid_len);
|
||||
|
||||
/* interface handling */
|
||||
int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
||||
@ -980,10 +971,15 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_ht_info *hti,
|
||||
u16 ap_ht_cap_flags);
|
||||
void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn);
|
||||
void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *da, u16 tid,
|
||||
u16 initiator, u16 reason_code);
|
||||
|
||||
void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da,
|
||||
u16 tid, u16 initiator, u16 reason);
|
||||
void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr);
|
||||
void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
||||
u16 initiator, u16 reason);
|
||||
void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta);
|
||||
void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta,
|
||||
struct ieee80211_mgmt *mgmt, size_t len);
|
||||
@ -996,6 +992,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
size_t len);
|
||||
|
||||
int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
||||
enum ieee80211_back_parties initiator);
|
||||
|
||||
/* Spectrum management */
|
||||
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
|
@ -362,8 +362,7 @@ static int ieee80211_stop(struct net_device *dev)
|
||||
|
||||
list_for_each_entry_rcu(sta, &local->sta_list, list) {
|
||||
if (sta->sdata == sdata)
|
||||
ieee80211_sta_tear_down_BA_sessions(sdata,
|
||||
sta->sta.addr);
|
||||
ieee80211_sta_tear_down_BA_sessions(sta);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
@ -523,7 +522,7 @@ static int ieee80211_stop(struct net_device *dev)
|
||||
* scan event to userspace -- the scan is incomplete.
|
||||
*/
|
||||
if (local->sw_scanning)
|
||||
ieee80211_scan_completed(&local->hw);
|
||||
ieee80211_scan_completed(&local->hw, true);
|
||||
}
|
||||
|
||||
conf.vif = &sdata->vif;
|
||||
|
@ -210,6 +210,8 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
|
||||
!!rcu_dereference(sdata->u.ap.beacon);
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
conf.enable_beacon = !!sdata->u.sta.probe_resp;
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
conf.enable_beacon = true;
|
||||
break;
|
||||
@ -731,6 +733,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
||||
return NULL;
|
||||
|
||||
wiphy->privid = mac80211_wiphy_privid;
|
||||
wiphy->max_scan_ssids = 4;
|
||||
/* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
|
||||
wiphy->bss_priv_size = sizeof(struct ieee80211_bss) -
|
||||
sizeof(struct cfg80211_bss);
|
||||
|
||||
local = wiphy_priv(wiphy);
|
||||
local->hw.wiphy = wiphy;
|
||||
@ -815,25 +821,33 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
enum ieee80211_band band;
|
||||
struct net_device *mdev;
|
||||
struct ieee80211_master_priv *mpriv;
|
||||
int channels, i, j;
|
||||
|
||||
/*
|
||||
* generic code guarantees at least one band,
|
||||
* set this very early because much code assumes
|
||||
* that hw.conf.channel is assigned
|
||||
*/
|
||||
channels = 0;
|
||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
sband = local->hw.wiphy->bands[band];
|
||||
if (sband) {
|
||||
if (sband && !local->oper_channel) {
|
||||
/* init channel we're on */
|
||||
local->hw.conf.channel =
|
||||
local->oper_channel =
|
||||
local->scan_channel = &sband->channels[0];
|
||||
break;
|
||||
}
|
||||
if (sband)
|
||||
channels += sband->n_channels;
|
||||
}
|
||||
|
||||
local->int_scan_req.n_channels = channels;
|
||||
local->int_scan_req.channels = kzalloc(sizeof(void *) * channels, GFP_KERNEL);
|
||||
if (!local->int_scan_req.channels)
|
||||
return -ENOMEM;
|
||||
|
||||
/* if low-level driver supports AP, we also support VLAN */
|
||||
if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP))
|
||||
local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
|
||||
@ -843,7 +857,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
|
||||
result = wiphy_register(local->hw.wiphy);
|
||||
if (result < 0)
|
||||
return result;
|
||||
goto fail_wiphy_register;
|
||||
|
||||
/*
|
||||
* We use the number of queues for feature tests (QoS, HT) internally
|
||||
@ -866,8 +880,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
mpriv->local = local;
|
||||
local->mdev = mdev;
|
||||
|
||||
ieee80211_rx_bss_list_init(local);
|
||||
|
||||
local->hw.workqueue =
|
||||
create_singlethread_workqueue(wiphy_name(local->hw.wiphy));
|
||||
if (!local->hw.workqueue) {
|
||||
@ -893,14 +905,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
|
||||
local->hw.conf.listen_interval = local->hw.max_listen_interval;
|
||||
|
||||
local->wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |
|
||||
IEEE80211_HW_SIGNAL_DBM) ?
|
||||
IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID;
|
||||
local->wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ?
|
||||
IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID;
|
||||
if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
|
||||
local->wstats_flags |= IW_QUAL_DBM;
|
||||
|
||||
result = sta_info_start(local);
|
||||
if (result < 0)
|
||||
goto fail_sta_info;
|
||||
@ -946,6 +950,20 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
|
||||
ieee80211_led_init(local);
|
||||
|
||||
/* alloc internal scan request */
|
||||
i = 0;
|
||||
local->int_scan_req.ssids = &local->scan_ssid;
|
||||
local->int_scan_req.n_ssids = 1;
|
||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
||||
if (!hw->wiphy->bands[band])
|
||||
continue;
|
||||
for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) {
|
||||
local->int_scan_req.channels[i] =
|
||||
&hw->wiphy->bands[band]->channels[j];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail_wep:
|
||||
@ -964,6 +982,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
free_netdev(local->mdev);
|
||||
fail_mdev_alloc:
|
||||
wiphy_unregister(local->hw.wiphy);
|
||||
fail_wiphy_register:
|
||||
kfree(local->int_scan_req.channels);
|
||||
return result;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_register_hw);
|
||||
@ -991,7 +1011,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
|
||||
|
||||
rtnl_unlock();
|
||||
|
||||
ieee80211_rx_bss_list_deinit(local);
|
||||
ieee80211_clear_tx_pending(local);
|
||||
sta_info_stop(local);
|
||||
rate_control_deinitialize(local);
|
||||
@ -1009,6 +1028,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
|
||||
ieee80211_wep_free(local);
|
||||
ieee80211_led_exit(local);
|
||||
free_netdev(local->mdev);
|
||||
kfree(local->int_scan_req.channels);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_unregister_hw);
|
||||
|
||||
|
@ -275,16 +275,6 @@ u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, struct mesh_t
|
||||
& tbl->hash_mask;
|
||||
}
|
||||
|
||||
u8 mesh_id_hash(u8 *mesh_id, int mesh_id_len)
|
||||
{
|
||||
if (!mesh_id_len)
|
||||
return 1;
|
||||
else if (mesh_id_len == 1)
|
||||
return (u8) mesh_id[0];
|
||||
else
|
||||
return (u8) (mesh_id[0] + 2 * mesh_id[1]);
|
||||
}
|
||||
|
||||
struct mesh_table *mesh_table_alloc(int size_order)
|
||||
{
|
||||
int i;
|
||||
|
@ -196,7 +196,6 @@ struct mesh_rmc {
|
||||
|
||||
/* Public interfaces */
|
||||
/* Various */
|
||||
u8 mesh_id_hash(u8 *mesh_id, int mesh_id_len);
|
||||
int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr);
|
||||
int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
|
@ -58,7 +58,6 @@ static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae)
|
||||
#define PERR_IE_DST_ADDR(x) (x + 2)
|
||||
#define PERR_IE_DST_DSN(x) u32_field_get(x, 8, 0);
|
||||
|
||||
#define TU_TO_EXP_TIME(x) (jiffies + msecs_to_jiffies(x * 1024 / 1000))
|
||||
#define MSEC_TO_TU(x) (x*1000/1024)
|
||||
#define DSN_GT(x, y) ((long) (y) - (long) (x) < 0)
|
||||
#define DSN_LT(x, y) ((long) (x) - (long) (y) < 0)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -731,6 +731,39 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
||||
return result;
|
||||
}
|
||||
|
||||
static ieee80211_rx_result debug_noinline
|
||||
ieee80211_rx_h_check_more_data(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
struct ieee80211_local *local;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct sk_buff *skb;
|
||||
|
||||
local = rx->local;
|
||||
skb = rx->skb;
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
|
||||
if (!local->pspolling)
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (!ieee80211_has_fromds(hdr->frame_control))
|
||||
/* this is not from AP */
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (!ieee80211_is_data(hdr->frame_control))
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (!ieee80211_has_moredata(hdr->frame_control)) {
|
||||
/* AP has no more frames buffered for us */
|
||||
local->pspolling = false;
|
||||
return RX_CONTINUE;
|
||||
}
|
||||
|
||||
/* more data bit is set, let's request a new frame from the AP */
|
||||
ieee80211_send_pspoll(local, rx->sdata);
|
||||
|
||||
return RX_CONTINUE;
|
||||
}
|
||||
|
||||
static void ap_sta_ps_start(struct sta_info *sta)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
@ -1640,11 +1673,9 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
|
||||
start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4;
|
||||
|
||||
/* reset session timer */
|
||||
if (tid_agg_rx->timeout) {
|
||||
unsigned long expires =
|
||||
jiffies + (tid_agg_rx->timeout / 1000) * HZ;
|
||||
mod_timer(&tid_agg_rx->session_timer, expires);
|
||||
}
|
||||
if (tid_agg_rx->timeout)
|
||||
mod_timer(&tid_agg_rx->session_timer,
|
||||
TU_TO_EXP_TIME(tid_agg_rx->timeout));
|
||||
|
||||
/* manage reordering buffer according to requested */
|
||||
/* sequence number */
|
||||
@ -1737,6 +1768,17 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
||||
|
||||
switch (mgmt->u.action.category) {
|
||||
case WLAN_CATEGORY_BACK:
|
||||
/*
|
||||
* The aggregation code is not prepared to handle
|
||||
* anything but STA/AP due to the BSSID handling;
|
||||
* IBSS could work in the code but isn't supported
|
||||
* by drivers or the standard.
|
||||
*/
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
|
||||
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
||||
sdata->vif.type != NL80211_IFTYPE_AP)
|
||||
return RX_DROP_MONITOR;
|
||||
|
||||
switch (mgmt->u.action.u.addba_req.action_code) {
|
||||
case WLAN_ACTION_ADDBA_REQ:
|
||||
if (len < (IEEE80211_MIN_ACTION_SIZE +
|
||||
@ -1987,6 +2029,7 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
|
||||
CALL_RXH(ieee80211_rx_h_passive_scan)
|
||||
CALL_RXH(ieee80211_rx_h_check)
|
||||
CALL_RXH(ieee80211_rx_h_decrypt)
|
||||
CALL_RXH(ieee80211_rx_h_check_more_data)
|
||||
CALL_RXH(ieee80211_rx_h_sta_process)
|
||||
CALL_RXH(ieee80211_rx_h_defragment)
|
||||
CALL_RXH(ieee80211_rx_h_ps_poll)
|
||||
@ -2030,9 +2073,10 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
|
||||
/* main receive path */
|
||||
|
||||
static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
|
||||
u8 *bssid, struct ieee80211_rx_data *rx,
|
||||
struct ieee80211_rx_data *rx,
|
||||
struct ieee80211_hdr *hdr)
|
||||
{
|
||||
u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, sdata->vif.type);
|
||||
int multicast = is_multicast_ether_addr(hdr->addr1);
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
@ -2135,7 +2179,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
|
||||
int prepares;
|
||||
struct ieee80211_sub_if_data *prev = NULL;
|
||||
struct sk_buff *skb_new;
|
||||
u8 *bssid;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
memset(&rx, 0, sizeof(rx));
|
||||
@ -2174,9 +2217,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
|
||||
if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
|
||||
continue;
|
||||
|
||||
bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
|
||||
rx.flags |= IEEE80211_RX_RA_MATCH;
|
||||
prepares = prepare_for_handlers(sdata, bssid, &rx, hdr);
|
||||
prepares = prepare_for_handlers(sdata, &rx, hdr);
|
||||
|
||||
if (!prepares)
|
||||
continue;
|
||||
@ -2381,11 +2423,9 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
|
||||
/* new un-ordered ampdu frame - process it */
|
||||
|
||||
/* reset session timer */
|
||||
if (tid_agg_rx->timeout) {
|
||||
unsigned long expires =
|
||||
jiffies + (tid_agg_rx->timeout / 1000) * HZ;
|
||||
mod_timer(&tid_agg_rx->session_timer, expires);
|
||||
}
|
||||
if (tid_agg_rx->timeout)
|
||||
mod_timer(&tid_agg_rx->session_timer,
|
||||
TU_TO_EXP_TIME(tid_agg_rx->timeout));
|
||||
|
||||
/* if this mpdu is fragmented - terminate rx aggregation session */
|
||||
sc = le16_to_cpu(hdr->seq_ctrl);
|
||||
|
@ -12,11 +12,7 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/* TODO:
|
||||
* order BSS list by RSSI(?) ("quality of AP")
|
||||
* scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
|
||||
* SSID)
|
||||
*/
|
||||
/* TODO: figure out how to avoid that the "current BSS" expires */
|
||||
|
||||
#include <linux/wireless.h>
|
||||
#include <linux/if_arp.h>
|
||||
@ -31,192 +27,29 @@
|
||||
#define IEEE80211_CHANNEL_TIME (HZ / 33)
|
||||
#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5)
|
||||
|
||||
void ieee80211_rx_bss_list_init(struct ieee80211_local *local)
|
||||
{
|
||||
spin_lock_init(&local->bss_lock);
|
||||
INIT_LIST_HEAD(&local->bss_list);
|
||||
}
|
||||
|
||||
void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local)
|
||||
{
|
||||
struct ieee80211_bss *bss, *tmp;
|
||||
|
||||
list_for_each_entry_safe(bss, tmp, &local->bss_list, list)
|
||||
ieee80211_rx_bss_put(local, bss);
|
||||
}
|
||||
|
||||
struct ieee80211_bss *
|
||||
ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
|
||||
u8 *ssid, u8 ssid_len)
|
||||
{
|
||||
struct ieee80211_bss *bss;
|
||||
|
||||
spin_lock_bh(&local->bss_lock);
|
||||
bss = local->bss_hash[STA_HASH(bssid)];
|
||||
while (bss) {
|
||||
if (!bss_mesh_cfg(bss) &&
|
||||
!memcmp(bss->bssid, bssid, ETH_ALEN) &&
|
||||
bss->freq == freq &&
|
||||
bss->ssid_len == ssid_len &&
|
||||
(ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) {
|
||||
atomic_inc(&bss->users);
|
||||
break;
|
||||
}
|
||||
bss = bss->hnext;
|
||||
}
|
||||
spin_unlock_bh(&local->bss_lock);
|
||||
return bss;
|
||||
return (void *)cfg80211_get_bss(local->hw.wiphy,
|
||||
ieee80211_get_channel(local->hw.wiphy,
|
||||
freq),
|
||||
bssid, ssid, ssid_len,
|
||||
0, 0);
|
||||
}
|
||||
|
||||
/* Caller must hold local->bss_lock */
|
||||
static void __ieee80211_rx_bss_hash_add(struct ieee80211_local *local,
|
||||
struct ieee80211_bss *bss)
|
||||
static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss)
|
||||
{
|
||||
u8 hash_idx;
|
||||
struct ieee80211_bss *bss = (void *)cbss;
|
||||
|
||||
if (bss_mesh_cfg(bss))
|
||||
hash_idx = mesh_id_hash(bss_mesh_id(bss),
|
||||
bss_mesh_id_len(bss));
|
||||
else
|
||||
hash_idx = STA_HASH(bss->bssid);
|
||||
|
||||
bss->hnext = local->bss_hash[hash_idx];
|
||||
local->bss_hash[hash_idx] = bss;
|
||||
}
|
||||
|
||||
/* Caller must hold local->bss_lock */
|
||||
static void __ieee80211_rx_bss_hash_del(struct ieee80211_local *local,
|
||||
struct ieee80211_bss *bss)
|
||||
{
|
||||
struct ieee80211_bss *b, *prev = NULL;
|
||||
b = local->bss_hash[STA_HASH(bss->bssid)];
|
||||
while (b) {
|
||||
if (b == bss) {
|
||||
if (!prev)
|
||||
local->bss_hash[STA_HASH(bss->bssid)] =
|
||||
bss->hnext;
|
||||
else
|
||||
prev->hnext = bss->hnext;
|
||||
break;
|
||||
}
|
||||
prev = b;
|
||||
b = b->hnext;
|
||||
}
|
||||
}
|
||||
|
||||
struct ieee80211_bss *
|
||||
ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq,
|
||||
u8 *ssid, u8 ssid_len)
|
||||
{
|
||||
struct ieee80211_bss *bss;
|
||||
|
||||
bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
|
||||
if (!bss)
|
||||
return NULL;
|
||||
atomic_set(&bss->users, 2);
|
||||
memcpy(bss->bssid, bssid, ETH_ALEN);
|
||||
bss->freq = freq;
|
||||
if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) {
|
||||
memcpy(bss->ssid, ssid, ssid_len);
|
||||
bss->ssid_len = ssid_len;
|
||||
}
|
||||
|
||||
spin_lock_bh(&local->bss_lock);
|
||||
/* TODO: order by RSSI? */
|
||||
list_add_tail(&bss->list, &local->bss_list);
|
||||
__ieee80211_rx_bss_hash_add(local, bss);
|
||||
spin_unlock_bh(&local->bss_lock);
|
||||
return bss;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
static struct ieee80211_bss *
|
||||
ieee80211_rx_mesh_bss_get(struct ieee80211_local *local, u8 *mesh_id, int mesh_id_len,
|
||||
u8 *mesh_cfg, int freq)
|
||||
{
|
||||
struct ieee80211_bss *bss;
|
||||
|
||||
spin_lock_bh(&local->bss_lock);
|
||||
bss = local->bss_hash[mesh_id_hash(mesh_id, mesh_id_len)];
|
||||
while (bss) {
|
||||
if (bss_mesh_cfg(bss) &&
|
||||
!memcmp(bss_mesh_cfg(bss), mesh_cfg, MESH_CFG_CMP_LEN) &&
|
||||
bss->freq == freq &&
|
||||
mesh_id_len == bss->mesh_id_len &&
|
||||
(mesh_id_len == 0 || !memcmp(bss->mesh_id, mesh_id,
|
||||
mesh_id_len))) {
|
||||
atomic_inc(&bss->users);
|
||||
break;
|
||||
}
|
||||
bss = bss->hnext;
|
||||
}
|
||||
spin_unlock_bh(&local->bss_lock);
|
||||
return bss;
|
||||
}
|
||||
|
||||
static struct ieee80211_bss *
|
||||
ieee80211_rx_mesh_bss_add(struct ieee80211_local *local, u8 *mesh_id, int mesh_id_len,
|
||||
u8 *mesh_cfg, int mesh_config_len, int freq)
|
||||
{
|
||||
struct ieee80211_bss *bss;
|
||||
|
||||
if (mesh_config_len != IEEE80211_MESH_CONFIG_LEN)
|
||||
return NULL;
|
||||
|
||||
bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
|
||||
if (!bss)
|
||||
return NULL;
|
||||
|
||||
bss->mesh_cfg = kmalloc(MESH_CFG_CMP_LEN, GFP_ATOMIC);
|
||||
if (!bss->mesh_cfg) {
|
||||
kfree(bss);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mesh_id_len && mesh_id_len <= IEEE80211_MAX_MESH_ID_LEN) {
|
||||
bss->mesh_id = kmalloc(mesh_id_len, GFP_ATOMIC);
|
||||
if (!bss->mesh_id) {
|
||||
kfree(bss->mesh_cfg);
|
||||
kfree(bss);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(bss->mesh_id, mesh_id, mesh_id_len);
|
||||
}
|
||||
|
||||
atomic_set(&bss->users, 2);
|
||||
memcpy(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN);
|
||||
bss->mesh_id_len = mesh_id_len;
|
||||
bss->freq = freq;
|
||||
spin_lock_bh(&local->bss_lock);
|
||||
/* TODO: order by RSSI? */
|
||||
list_add_tail(&bss->list, &local->bss_list);
|
||||
__ieee80211_rx_bss_hash_add(local, bss);
|
||||
spin_unlock_bh(&local->bss_lock);
|
||||
return bss;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ieee80211_rx_bss_free(struct ieee80211_bss *bss)
|
||||
{
|
||||
kfree(bss->ies);
|
||||
kfree(bss_mesh_id(bss));
|
||||
kfree(bss_mesh_cfg(bss));
|
||||
kfree(bss);
|
||||
}
|
||||
|
||||
void ieee80211_rx_bss_put(struct ieee80211_local *local,
|
||||
struct ieee80211_bss *bss)
|
||||
{
|
||||
local_bh_disable();
|
||||
if (!atomic_dec_and_lock(&bss->users, &local->bss_lock)) {
|
||||
local_bh_enable();
|
||||
return;
|
||||
}
|
||||
|
||||
__ieee80211_rx_bss_hash_del(local, bss);
|
||||
list_del(&bss->list);
|
||||
spin_unlock_bh(&local->bss_lock);
|
||||
ieee80211_rx_bss_free(bss);
|
||||
cfg80211_put_bss((struct cfg80211_bss *)bss);
|
||||
}
|
||||
|
||||
struct ieee80211_bss *
|
||||
@ -225,49 +58,37 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
size_t len,
|
||||
struct ieee802_11_elems *elems,
|
||||
int freq, bool beacon)
|
||||
struct ieee80211_channel *channel,
|
||||
bool beacon)
|
||||
{
|
||||
struct ieee80211_bss *bss;
|
||||
int clen;
|
||||
enum cfg80211_signal_type sigtype = CFG80211_SIGNAL_TYPE_NONE;
|
||||
s32 signal = 0;
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
if (elems->mesh_config)
|
||||
bss = ieee80211_rx_mesh_bss_get(local, elems->mesh_id,
|
||||
elems->mesh_id_len, elems->mesh_config, freq);
|
||||
else
|
||||
#endif
|
||||
bss = ieee80211_rx_bss_get(local, mgmt->bssid, freq,
|
||||
elems->ssid, elems->ssid_len);
|
||||
if (!bss) {
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
if (elems->mesh_config)
|
||||
bss = ieee80211_rx_mesh_bss_add(local, elems->mesh_id,
|
||||
elems->mesh_id_len, elems->mesh_config,
|
||||
elems->mesh_config_len, freq);
|
||||
else
|
||||
#endif
|
||||
bss = ieee80211_rx_bss_add(local, mgmt->bssid, freq,
|
||||
elems->ssid, elems->ssid_len);
|
||||
if (!bss)
|
||||
return NULL;
|
||||
} else {
|
||||
#if 0
|
||||
/* TODO: order by RSSI? */
|
||||
spin_lock_bh(&local->bss_lock);
|
||||
list_move_tail(&bss->list, &local->bss_list);
|
||||
spin_unlock_bh(&local->bss_lock);
|
||||
#endif
|
||||
if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
|
||||
sigtype = CFG80211_SIGNAL_TYPE_MBM;
|
||||
signal = rx_status->signal * 100;
|
||||
} else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) {
|
||||
sigtype = CFG80211_SIGNAL_TYPE_UNSPEC;
|
||||
signal = (rx_status->signal * 100) / local->hw.max_signal;
|
||||
}
|
||||
|
||||
bss = (void *)cfg80211_inform_bss_frame(local->hw.wiphy, channel,
|
||||
mgmt, len, signal, sigtype,
|
||||
GFP_ATOMIC);
|
||||
|
||||
if (!bss)
|
||||
return NULL;
|
||||
|
||||
bss->cbss.free_priv = ieee80211_rx_bss_free;
|
||||
|
||||
/* save the ERP value so that it is available at association time */
|
||||
if (elems->erp_info && elems->erp_info_len >= 1) {
|
||||
bss->erp_value = elems->erp_info[0];
|
||||
bss->has_erp_value = 1;
|
||||
}
|
||||
|
||||
bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
|
||||
bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
|
||||
|
||||
if (elems->tim) {
|
||||
struct ieee80211_tim_ie *tim_ie =
|
||||
(struct ieee80211_tim_ie *)elems->tim;
|
||||
@ -296,37 +117,27 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
|
||||
bss->supp_rates_len += clen;
|
||||
}
|
||||
|
||||
bss->band = rx_status->band;
|
||||
|
||||
bss->timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
|
||||
bss->last_update = jiffies;
|
||||
bss->signal = rx_status->signal;
|
||||
bss->noise = rx_status->noise;
|
||||
bss->qual = rx_status->qual;
|
||||
bss->wmm_used = elems->wmm_param || elems->wmm_info;
|
||||
|
||||
if (!beacon)
|
||||
bss->last_probe_resp = jiffies;
|
||||
|
||||
/*
|
||||
* For probe responses, or if we don't have any information yet,
|
||||
* use the IEs from the beacon.
|
||||
*/
|
||||
if (!bss->ies || !beacon) {
|
||||
if (bss->ies == NULL || bss->ies_len < elems->total_len) {
|
||||
kfree(bss->ies);
|
||||
bss->ies = kmalloc(elems->total_len, GFP_ATOMIC);
|
||||
}
|
||||
if (bss->ies) {
|
||||
memcpy(bss->ies, elems->ie_start, elems->total_len);
|
||||
bss->ies_len = elems->total_len;
|
||||
} else
|
||||
bss->ies_len = 0;
|
||||
}
|
||||
|
||||
return bss;
|
||||
}
|
||||
|
||||
void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid,
|
||||
int freq, u8 *ssid, u8 ssid_len)
|
||||
{
|
||||
struct ieee80211_bss *bss;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
bss = ieee80211_rx_bss_get(local, bssid, freq, ssid, ssid_len);
|
||||
if (bss) {
|
||||
cfg80211_unlink_bss(local->hw.wiphy, (void *)bss);
|
||||
ieee80211_rx_bss_put(local, bss);
|
||||
}
|
||||
}
|
||||
|
||||
ieee80211_rx_result
|
||||
ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
@ -388,7 +199,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
|
||||
|
||||
bss = ieee80211_bss_info_update(sdata->local, rx_status,
|
||||
mgmt, skb->len, &elems,
|
||||
freq, beacon);
|
||||
channel, beacon);
|
||||
if (bss)
|
||||
ieee80211_rx_bss_put(sdata->local, bss);
|
||||
|
||||
@ -426,26 +237,22 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
|
||||
ieee80211_tx_skb(sdata, skb, 0);
|
||||
}
|
||||
|
||||
void ieee80211_scan_completed(struct ieee80211_hw *hw)
|
||||
void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
union iwreq_data wrqu;
|
||||
|
||||
if (WARN_ON(!local->hw_scanning && !local->sw_scanning))
|
||||
return;
|
||||
|
||||
local->last_scan_completed = jiffies;
|
||||
memset(&wrqu, 0, sizeof(wrqu));
|
||||
if (WARN_ON(!local->scan_req))
|
||||
return;
|
||||
|
||||
/*
|
||||
* local->scan_sdata could have been NULLed by the interface
|
||||
* down code in case we were scanning on an interface that is
|
||||
* being taken down.
|
||||
*/
|
||||
sdata = local->scan_sdata;
|
||||
if (sdata)
|
||||
wireless_send_event(sdata->dev, SIOCGIWSCAN, &wrqu, NULL);
|
||||
if (local->scan_req != &local->int_scan_req)
|
||||
cfg80211_scan_done(local->scan_req, aborted);
|
||||
local->scan_req = NULL;
|
||||
|
||||
local->last_scan_completed = jiffies;
|
||||
|
||||
if (local->hw_scanning) {
|
||||
local->hw_scanning = false;
|
||||
@ -487,7 +294,12 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
|
||||
} else
|
||||
netif_tx_wake_all_queues(sdata->dev);
|
||||
|
||||
ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED);
|
||||
/* re-enable beaconing */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
sdata->vif.type == NL80211_IFTYPE_ADHOC ||
|
||||
sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
|
||||
ieee80211_if_config(sdata,
|
||||
IEEE80211_IFCC_BEACON_ENABLED);
|
||||
}
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
|
||||
@ -502,9 +314,8 @@ void ieee80211_scan_work(struct work_struct *work)
|
||||
struct ieee80211_local *local =
|
||||
container_of(work, struct ieee80211_local, scan_work.work);
|
||||
struct ieee80211_sub_if_data *sdata = local->scan_sdata;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_channel *chan;
|
||||
int skip;
|
||||
int skip, i;
|
||||
unsigned long next_delay = 0;
|
||||
|
||||
/*
|
||||
@ -515,33 +326,13 @@ void ieee80211_scan_work(struct work_struct *work)
|
||||
|
||||
switch (local->scan_state) {
|
||||
case SCAN_SET_CHANNEL:
|
||||
/*
|
||||
* Get current scan band. scan_band may be IEEE80211_NUM_BANDS
|
||||
* after we successfully scanned the last channel of the last
|
||||
* band (and the last band is supported by the hw)
|
||||
*/
|
||||
if (local->scan_band < IEEE80211_NUM_BANDS)
|
||||
sband = local->hw.wiphy->bands[local->scan_band];
|
||||
else
|
||||
sband = NULL;
|
||||
|
||||
/*
|
||||
* If we are at an unsupported band and have more bands
|
||||
* left to scan, advance to the next supported one.
|
||||
*/
|
||||
while (!sband && local->scan_band < IEEE80211_NUM_BANDS - 1) {
|
||||
local->scan_band++;
|
||||
sband = local->hw.wiphy->bands[local->scan_band];
|
||||
local->scan_channel_idx = 0;
|
||||
}
|
||||
|
||||
/* if no more bands/channels left, complete scan */
|
||||
if (!sband || local->scan_channel_idx >= sband->n_channels) {
|
||||
ieee80211_scan_completed(local_to_hw(local));
|
||||
if (local->scan_channel_idx >= local->scan_req->n_channels) {
|
||||
ieee80211_scan_completed(local_to_hw(local), false);
|
||||
return;
|
||||
}
|
||||
skip = 0;
|
||||
chan = &sband->channels[local->scan_channel_idx];
|
||||
chan = local->scan_req->channels[local->scan_channel_idx];
|
||||
|
||||
if (chan->flags & IEEE80211_CHAN_DISABLED ||
|
||||
(sdata->vif.type == NL80211_IFTYPE_ADHOC &&
|
||||
@ -557,15 +348,6 @@ void ieee80211_scan_work(struct work_struct *work)
|
||||
|
||||
/* advance state machine to next channel/band */
|
||||
local->scan_channel_idx++;
|
||||
if (local->scan_channel_idx >= sband->n_channels) {
|
||||
/*
|
||||
* scan_band may end up == IEEE80211_NUM_BANDS, but
|
||||
* we'll catch that case above and complete the scan
|
||||
* if that is the case.
|
||||
*/
|
||||
local->scan_band++;
|
||||
local->scan_channel_idx = 0;
|
||||
}
|
||||
|
||||
if (skip)
|
||||
break;
|
||||
@ -578,10 +360,14 @@ void ieee80211_scan_work(struct work_struct *work)
|
||||
next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
|
||||
local->scan_state = SCAN_SET_CHANNEL;
|
||||
|
||||
if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN)
|
||||
if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
|
||||
!local->scan_req->n_ssids)
|
||||
break;
|
||||
ieee80211_send_probe_req(sdata, NULL, local->scan_ssid,
|
||||
local->scan_ssid_len);
|
||||
for (i = 0; i < local->scan_req->n_ssids; i++)
|
||||
ieee80211_send_probe_req(
|
||||
sdata, NULL,
|
||||
local->scan_req->ssids[i].ssid,
|
||||
local->scan_req->ssids[i].ssid_len);
|
||||
next_delay = IEEE80211_CHANNEL_TIME;
|
||||
break;
|
||||
}
|
||||
@ -592,14 +378,19 @@ void ieee80211_scan_work(struct work_struct *work)
|
||||
|
||||
|
||||
int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
|
||||
u8 *ssid, size_t ssid_len)
|
||||
struct cfg80211_scan_request *req)
|
||||
{
|
||||
struct ieee80211_local *local = scan_sdata->local;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
if (ssid_len > IEEE80211_MAX_SSID_LEN)
|
||||
if (!req)
|
||||
return -EINVAL;
|
||||
|
||||
if (local->scan_req && local->scan_req != req)
|
||||
return -EBUSY;
|
||||
|
||||
local->scan_req = req;
|
||||
|
||||
/* MLME-SCAN.request (page 118) page 144 (11.1.3.1)
|
||||
* BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS
|
||||
* BSSID: MACAddress
|
||||
@ -627,7 +418,7 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
|
||||
int rc;
|
||||
|
||||
local->hw_scanning = true;
|
||||
rc = local->ops->hw_scan(local_to_hw(local), ssid, ssid_len);
|
||||
rc = local->ops->hw_scan(local_to_hw(local), req);
|
||||
if (rc) {
|
||||
local->hw_scanning = false;
|
||||
return rc;
|
||||
@ -643,7 +434,12 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
|
||||
if (!netif_running(sdata->dev))
|
||||
continue;
|
||||
|
||||
ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED);
|
||||
/* disable beaconing */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
sdata->vif.type == NL80211_IFTYPE_ADHOC ||
|
||||
sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
|
||||
ieee80211_if_config(sdata,
|
||||
IEEE80211_IFCC_BEACON_ENABLED);
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
|
||||
@ -655,15 +451,10 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
|
||||
}
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
|
||||
if (ssid) {
|
||||
local->scan_ssid_len = ssid_len;
|
||||
memcpy(local->scan_ssid, ssid, ssid_len);
|
||||
} else
|
||||
local->scan_ssid_len = 0;
|
||||
local->scan_state = SCAN_SET_CHANNEL;
|
||||
local->scan_channel_idx = 0;
|
||||
local->scan_band = IEEE80211_BAND_2GHZ;
|
||||
local->scan_sdata = scan_sdata;
|
||||
local->scan_req = req;
|
||||
|
||||
netif_addr_lock_bh(local->mdev);
|
||||
local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
|
||||
@ -683,13 +474,21 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
|
||||
|
||||
|
||||
int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
|
||||
u8 *ssid, size_t ssid_len)
|
||||
struct cfg80211_scan_request *req)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_if_sta *ifsta;
|
||||
|
||||
if (!req)
|
||||
return -EINVAL;
|
||||
|
||||
if (local->scan_req && local->scan_req != req)
|
||||
return -EBUSY;
|
||||
|
||||
local->scan_req = req;
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
||||
return ieee80211_start_scan(sdata, ssid, ssid_len);
|
||||
return ieee80211_start_scan(sdata, req);
|
||||
|
||||
/*
|
||||
* STA has a state machine that might need to defer scanning
|
||||
@ -704,241 +503,8 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
ifsta = &sdata->u.sta;
|
||||
|
||||
ifsta->scan_ssid_len = ssid_len;
|
||||
if (ssid_len)
|
||||
memcpy(ifsta->scan_ssid, ssid, ssid_len);
|
||||
set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request);
|
||||
queue_work(local->hw.workqueue, &ifsta->work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void ieee80211_scan_add_ies(struct iw_request_info *info,
|
||||
struct ieee80211_bss *bss,
|
||||
char **current_ev, char *end_buf)
|
||||
{
|
||||
u8 *pos, *end, *next;
|
||||
struct iw_event iwe;
|
||||
|
||||
if (bss == NULL || bss->ies == NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If needed, fragment the IEs buffer (at IE boundaries) into short
|
||||
* enough fragments to fit into IW_GENERIC_IE_MAX octet messages.
|
||||
*/
|
||||
pos = bss->ies;
|
||||
end = pos + bss->ies_len;
|
||||
|
||||
while (end - pos > IW_GENERIC_IE_MAX) {
|
||||
next = pos + 2 + pos[1];
|
||||
while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX)
|
||||
next = next + 2 + next[1];
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = next - pos;
|
||||
*current_ev = iwe_stream_add_point(info, *current_ev,
|
||||
end_buf, &iwe, pos);
|
||||
|
||||
pos = next;
|
||||
}
|
||||
|
||||
if (end > pos) {
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = end - pos;
|
||||
*current_ev = iwe_stream_add_point(info, *current_ev,
|
||||
end_buf, &iwe, pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ieee80211_scan_result(struct ieee80211_local *local,
|
||||
struct iw_request_info *info,
|
||||
struct ieee80211_bss *bss,
|
||||
char *current_ev, char *end_buf)
|
||||
{
|
||||
struct iw_event iwe;
|
||||
char *buf;
|
||||
|
||||
if (time_after(jiffies,
|
||||
bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE))
|
||||
return current_ev;
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = SIOCGIWAP;
|
||||
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_ADDR_LEN);
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = SIOCGIWESSID;
|
||||
if (bss_mesh_cfg(bss)) {
|
||||
iwe.u.data.length = bss_mesh_id_len(bss);
|
||||
iwe.u.data.flags = 1;
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, bss_mesh_id(bss));
|
||||
} else {
|
||||
iwe.u.data.length = bss->ssid_len;
|
||||
iwe.u.data.flags = 1;
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, bss->ssid);
|
||||
}
|
||||
|
||||
if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)
|
||||
|| bss_mesh_cfg(bss)) {
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = SIOCGIWMODE;
|
||||
if (bss_mesh_cfg(bss))
|
||||
iwe.u.mode = IW_MODE_MESH;
|
||||
else if (bss->capability & WLAN_CAPABILITY_ESS)
|
||||
iwe.u.mode = IW_MODE_MASTER;
|
||||
else
|
||||
iwe.u.mode = IW_MODE_ADHOC;
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_UINT_LEN);
|
||||
}
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = SIOCGIWFREQ;
|
||||
iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
|
||||
iwe.u.freq.e = 0;
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_FREQ_LEN);
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = SIOCGIWFREQ;
|
||||
iwe.u.freq.m = bss->freq;
|
||||
iwe.u.freq.e = 6;
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_FREQ_LEN);
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVQUAL;
|
||||
iwe.u.qual.qual = bss->qual;
|
||||
iwe.u.qual.level = bss->signal;
|
||||
iwe.u.qual.noise = bss->noise;
|
||||
iwe.u.qual.updated = local->wstats_flags;
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_QUAL_LEN);
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = SIOCGIWENCODE;
|
||||
if (bss->capability & WLAN_CAPABILITY_PRIVACY)
|
||||
iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
|
||||
else
|
||||
iwe.u.data.flags = IW_ENCODE_DISABLED;
|
||||
iwe.u.data.length = 0;
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, "");
|
||||
|
||||
ieee80211_scan_add_ies(info, bss, ¤t_ev, end_buf);
|
||||
|
||||
if (bss->supp_rates_len > 0) {
|
||||
/* display all supported rates in readable format */
|
||||
char *p = current_ev + iwe_stream_lcp_len(info);
|
||||
int i;
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = SIOCGIWRATE;
|
||||
/* Those two flags are ignored... */
|
||||
iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
|
||||
|
||||
for (i = 0; i < bss->supp_rates_len; i++) {
|
||||
iwe.u.bitrate.value = ((bss->supp_rates[i] &
|
||||
0x7f) * 500000);
|
||||
p = iwe_stream_add_value(info, current_ev, p,
|
||||
end_buf, &iwe, IW_EV_PARAM_LEN);
|
||||
}
|
||||
current_ev = p;
|
||||
}
|
||||
|
||||
buf = kmalloc(30, GFP_ATOMIC);
|
||||
if (buf) {
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp));
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, buf);
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, " Last beacon: %dms ago",
|
||||
jiffies_to_msecs(jiffies - bss->last_update));
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf, &iwe, buf);
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
if (bss_mesh_cfg(bss)) {
|
||||
u8 *cfg = bss_mesh_cfg(bss);
|
||||
buf = kmalloc(50, GFP_ATOMIC);
|
||||
if (buf) {
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, "Mesh network (version %d)", cfg[0]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
sprintf(buf, "Path Selection Protocol ID: "
|
||||
"0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
|
||||
cfg[4]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
sprintf(buf, "Path Selection Metric ID: "
|
||||
"0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
|
||||
cfg[8]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
sprintf(buf, "Congestion Control Mode ID: "
|
||||
"0x%02X%02X%02X%02X", cfg[9], cfg[10],
|
||||
cfg[11], cfg[12]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
sprintf(buf, "Channel Precedence: "
|
||||
"0x%02X%02X%02X%02X", cfg[13], cfg[14],
|
||||
cfg[15], cfg[16]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
kfree(buf);
|
||||
}
|
||||
}
|
||||
|
||||
return current_ev;
|
||||
}
|
||||
|
||||
|
||||
int ieee80211_scan_results(struct ieee80211_local *local,
|
||||
struct iw_request_info *info,
|
||||
char *buf, size_t len)
|
||||
{
|
||||
char *current_ev = buf;
|
||||
char *end_buf = buf + len;
|
||||
struct ieee80211_bss *bss;
|
||||
|
||||
spin_lock_bh(&local->bss_lock);
|
||||
list_for_each_entry(bss, &local->bss_list, list) {
|
||||
if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
|
||||
spin_unlock_bh(&local->bss_lock);
|
||||
return -E2BIG;
|
||||
}
|
||||
current_ev = ieee80211_scan_result(local, info, bss,
|
||||
current_ev, end_buf);
|
||||
}
|
||||
spin_unlock_bh(&local->bss_lock);
|
||||
return current_ev - buf;
|
||||
}
|
||||
|
@ -102,8 +102,9 @@ void ieee80211_chswitch_work(struct work_struct *work)
|
||||
goto exit;
|
||||
|
||||
sdata->local->oper_channel = sdata->local->csa_channel;
|
||||
/* XXX: shouldn't really modify cfg80211-owned data! */
|
||||
if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL))
|
||||
bss->freq = sdata->local->oper_channel->center_freq;
|
||||
bss->cbss.channel = sdata->local->oper_channel;
|
||||
|
||||
ieee80211_rx_bss_put(sdata->local, bss);
|
||||
exit:
|
||||
@ -158,7 +159,9 @@ void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
||||
IEEE80211_QUEUE_STOP_REASON_CSA);
|
||||
ifsta->flags |= IEEE80211_STA_CSA_RECEIVED;
|
||||
mod_timer(&ifsta->chswitch_timer,
|
||||
jiffies + msecs_to_jiffies(sw_elem->count * bss->beacon_int));
|
||||
jiffies +
|
||||
msecs_to_jiffies(sw_elem->count *
|
||||
bss->cbss.beacon_interval));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,12 +194,41 @@ void sta_info_destroy(struct sta_info *sta)
|
||||
dev_kfree_skb_any(skb);
|
||||
|
||||
for (i = 0; i < STA_TID_NUM; i++) {
|
||||
struct tid_ampdu_rx *tid_rx;
|
||||
struct tid_ampdu_tx *tid_tx;
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
if (sta->ampdu_mlme.tid_rx[i])
|
||||
del_timer_sync(&sta->ampdu_mlme.tid_rx[i]->session_timer);
|
||||
if (sta->ampdu_mlme.tid_tx[i])
|
||||
del_timer_sync(&sta->ampdu_mlme.tid_tx[i]->addba_resp_timer);
|
||||
tid_rx = sta->ampdu_mlme.tid_rx[i];
|
||||
/* Make sure timer won't free the tid_rx struct, see below */
|
||||
if (tid_rx)
|
||||
tid_rx->shutdown = true;
|
||||
spin_unlock_bh(&sta->lock);
|
||||
|
||||
/*
|
||||
* Outside spinlock - shutdown is true now so that the timer
|
||||
* won't free tid_rx, we have to do that now. Can't let the
|
||||
* timer do it because we have to sync the timer outside the
|
||||
* lock that it takes itself.
|
||||
*/
|
||||
if (tid_rx) {
|
||||
del_timer_sync(&tid_rx->session_timer);
|
||||
kfree(tid_rx);
|
||||
}
|
||||
|
||||
/*
|
||||
* No need to do such complications for TX agg sessions, the
|
||||
* path leading to freeing the tid_tx struct goes via a call
|
||||
* from the driver, and thus needs to look up the sta struct
|
||||
* again, which cannot be found when we get here. Hence, we
|
||||
* just need to delete the timer and free the aggregation
|
||||
* info; we won't be telling the peer about it then but that
|
||||
* doesn't matter if we're not talking to it again anyway.
|
||||
*/
|
||||
tid_tx = sta->ampdu_mlme.tid_tx[i];
|
||||
if (tid_tx) {
|
||||
del_timer_sync(&tid_tx->addba_resp_timer);
|
||||
kfree(tid_tx);
|
||||
}
|
||||
}
|
||||
|
||||
__sta_info_free(local, sta);
|
||||
|
@ -65,7 +65,6 @@ enum ieee80211_sta_info_flags {
|
||||
#define HT_AGG_STATE_OPERATIONAL (HT_ADDBA_REQUESTED_MSK | \
|
||||
HT_ADDBA_DRV_READY_MSK | \
|
||||
HT_ADDBA_RECEIVED_MSK)
|
||||
#define HT_AGG_STATE_DEBUGFS_CTL BIT(7)
|
||||
|
||||
/**
|
||||
* struct tid_ampdu_tx - TID aggregation information (Tx).
|
||||
@ -89,7 +88,7 @@ struct tid_ampdu_tx {
|
||||
* @stored_mpdu_num: number of MPDUs in reordering buffer
|
||||
* @ssn: Starting Sequence Number expected to be aggregated.
|
||||
* @buf_size: buffer size for incoming A-MPDUs
|
||||
* @timeout: reset timer value.
|
||||
* @timeout: reset timer value (in TUs).
|
||||
* @dialog_token: dialog token for aggregation session
|
||||
*/
|
||||
struct tid_ampdu_rx {
|
||||
@ -101,6 +100,7 @@ struct tid_ampdu_rx {
|
||||
u16 buf_size;
|
||||
u16 timeout;
|
||||
u8 dialog_token;
|
||||
bool shutdown;
|
||||
};
|
||||
|
||||
/**
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user