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);
-@@ -641,7 +639,6 @@ void ath_ant_comb_update(struct ath_soft
+@@ -334,9 +332,8 @@ void ath_txq_lock(struct ath_softc *sc,
+ void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq);
+ void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq);
+ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
+-bool 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);
++bool ath_drain_all_txq(struct ath_softc *sc);
++void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq);
+ 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);
+@@ -641,7 +638,6 @@ void ath_ant_comb_update(struct ath_soft
enum sc_op_flags {
SC_OP_INVALID,
SC_OP_BEACONS,
}
skb = ieee80211_beacon_get(hw, vif);
+@@ -198,7 +199,7 @@ static struct ath_buf *ath9k_beacon_gene
+ if (sc->nvifs > 1) {
+ ath_dbg(common, BEACON,
+ "Flushing previous cabq traffic\n");
+- ath_draintxq(sc, cabq, false);
++ ath_draintxq(sc, cabq);
+ }
+ }
+
@@ -359,7 +360,6 @@ void ath9k_beacon_tasklet(unsigned long
return;
}
-static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush)
-+static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx)
++static bool ath_prepare_reset(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
bool ret = true;
-@@ -196,19 +196,15 @@ static bool ath_prepare_reset(struct ath
+@@ -196,20 +196,12 @@ static bool ath_prepare_reset(struct ath
ath9k_debug_samp_bb_mac(sc);
ath9k_hw_disable_interrupts(ah);
-+ tasklet_disable(&sc->intr_tq);
-+
- if (!ath_stoprecv(sc))
+- if (!ath_stoprecv(sc))
++ if (!ath_drain_all_txq(sc))
ret = false;
- if (!ath_drain_all_txq(sc, retry_tx))
+- if (!ath_drain_all_txq(sc, retry_tx))
++ if (!ath_stoprecv(sc))
ret = false;
- if (!flush) {
- } else {
- ath_flushrecv(sc);
- }
-+ tasklet_enable(&sc->intr_tq);
-
+-
return ret;
}
-@@ -262,7 +258,6 @@ static int ath_reset_internal(struct ath
+
+@@ -255,18 +247,17 @@ static bool ath_complete_reset(struct at
+ return true;
+ }
+
+-static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
+- bool retry_tx)
++static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
+ {
+ struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_cal_data *caldata = NULL;
bool fastcc = true;
int r;
__ath_cancel_work(sc);
-@@ -276,11 +271,10 @@ static int ath_reset_internal(struct ath
+
++ tasklet_disable(&sc->intr_tq);
+ spin_lock_bh(&sc->sc_pcu_lock);
+
+ if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) {
+@@ -276,11 +267,10 @@ static int ath_reset_internal(struct ath
if (!hchan) {
fastcc = false;
}
- if (!ath_prepare_reset(sc, retry_tx, flush))
-+ if (!ath_prepare_reset(sc, retry_tx))
++ if (!ath_prepare_reset(sc))
fastcc = false;
ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n",
-@@ -804,7 +798,7 @@ static void ath9k_stop(struct ieee80211_
+@@ -302,6 +292,8 @@ static int ath_reset_internal(struct ath
+
+ out:
+ spin_unlock_bh(&sc->sc_pcu_lock);
++ tasklet_enable(&sc->intr_tq);
++
+ return r;
+ }
+
+@@ -319,7 +311,7 @@ static int ath_set_channel(struct ath_so
+ if (test_bit(SC_OP_INVALID, &sc->sc_flags))
+ return -EIO;
+
+- r = ath_reset_internal(sc, hchan, false);
++ r = ath_reset_internal(sc, hchan);
+
+ return r;
+ }
+@@ -549,23 +541,21 @@ chip_reset:
+ #undef SCHED_INTR
+ }
+
+-static int ath_reset(struct ath_softc *sc, bool retry_tx)
++static int ath_reset(struct ath_softc *sc)
+ {
+- int r;
++ int i, r;
+
+ ath9k_ps_wakeup(sc);
+
+- r = ath_reset_internal(sc, NULL, retry_tx);
++ r = ath_reset_internal(sc, NULL);
+
+- if (retry_tx) {
+- int i;
+- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+- if (ATH_TXQ_SETUP(sc, i)) {
+- spin_lock_bh(&sc->tx.txq[i].axq_lock);
+- ath_txq_schedule(sc, &sc->tx.txq[i]);
+- spin_unlock_bh(&sc->tx.txq[i].axq_lock);
+- }
+- }
++ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
++ if (!ATH_TXQ_SETUP(sc, i))
++ continue;
++
++ spin_lock_bh(&sc->tx.txq[i].axq_lock);
++ ath_txq_schedule(sc, &sc->tx.txq[i]);
++ spin_unlock_bh(&sc->tx.txq[i].axq_lock);
+ }
+
+ ath9k_ps_restore(sc);
+@@ -586,7 +576,7 @@ void ath_reset_work(struct work_struct *
+ {
+ struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work);
+
+- ath_reset(sc, true);
++ ath_reset(sc);
+ }
+
+ /**********************/
+@@ -804,7 +794,7 @@ static void ath9k_stop(struct ieee80211_
ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
}
- ath_prepare_reset(sc, false, true);
-+ ath_prepare_reset(sc, false);
++ ath_prepare_reset(sc);
if (sc->rx.frag) {
dev_kfree_skb_any(sc->rx.frag);
+@@ -1731,11 +1721,11 @@ static void ath9k_flush(struct ieee80211
+ if (drop) {
+ ath9k_ps_wakeup(sc);
+ spin_lock_bh(&sc->sc_pcu_lock);
+- drain_txq = ath_drain_all_txq(sc, false);
++ drain_txq = ath_drain_all_txq(sc);
+ spin_unlock_bh(&sc->sc_pcu_lock);
+
+ if (!drain_txq)
+- ath_reset(sc, false);
++ ath_reset(sc);
+
+ ath9k_ps_restore(sc);
+ ieee80211_wake_queues(hw);
+@@ -1835,6 +1825,9 @@ static u32 fill_chainmask(u32 cap, u32 n
+
+ static bool validate_antenna_mask(struct ath_hw *ah, u32 val)
+ {
++ if (AR_SREV_9300_20_OR_LATER(ah))
++ return true;
++
+ switch (val & 0x7) {
+ case 0x1:
+ case 0x3:
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -248,8 +248,6 @@ rx_init_fail:
channelSel = freq / 75;
chan_frac = ((freq % 75) * 0x20000) / 75;
channelSel = (channelSel << 17) | chan_frac;
+@@ -586,32 +589,19 @@ static void ar9003_hw_init_bb(struct ath
+ ath9k_hw_synth_delay(ah, chan, synthDelay);
+ }
+
+-static void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
++void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
+ {
+- switch (rx) {
+- case 0x5:
++ if (ah->caps.tx_chainmask == 5 || ah->caps.rx_chainmask == 5)
+ REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
+ AR_PHY_SWAP_ALT_CHAIN);
+- case 0x3:
+- case 0x1:
+- case 0x2:
+- case 0x7:
+- REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx);
+- REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx);
+- break;
+- default:
+- break;
+- }
++
++ REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx);
++ REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx);
+
+ if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && (tx == 0x7))
+- REG_WRITE(ah, AR_SELFGEN_MASK, 0x3);
+- else
+- REG_WRITE(ah, AR_SELFGEN_MASK, tx);
++ tx = 3;
+
+- if (tx == 0x5) {
+- REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
+- AR_PHY_SWAP_ALT_CHAIN);
+- }
++ REG_WRITE(ah, AR_SELFGEN_MASK, tx);
+ }
+
+ /*
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -1028,7 +1028,7 @@
bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT);
u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
AR_PHY_AGC_CONTROL_FLTR_CAL |
-@@ -1013,7 +1013,8 @@ static bool ar9003_hw_init_cal(struct at
+@@ -977,6 +977,8 @@ static bool ar9003_hw_init_cal(struct at
+ AR_PHY_CL_TAB_1,
+ AR_PHY_CL_TAB_2 };
+
++ ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);
++
+ if (rtt) {
+ if (!ar9003_hw_rtt_restore(ah, chan))
+ run_rtt_cal = true;
+@@ -1013,7 +1015,8 @@ static bool ar9003_hw_init_cal(struct at
}
}
goto skip_tx_iqcal;
/* Do Tx IQ Calibration */
-@@ -1033,21 +1034,22 @@ static bool ar9003_hw_init_cal(struct at
+@@ -1033,21 +1036,22 @@ static bool ar9003_hw_init_cal(struct at
REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
txiqcal_done = run_agc_cal = true;
default:
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
-@@ -485,9 +485,7 @@ static int ar5008_hw_rf_alloc_ext_banks(
- ATH_ALLOC_BANK(ah->analogBank2Data, ah->iniBank2.ia_rows);
- ATH_ALLOC_BANK(ah->analogBank3Data, ah->iniBank3.ia_rows);
- ATH_ALLOC_BANK(ah->analogBank6Data, ah->iniBank6.ia_rows);
+@@ -18,6 +18,7 @@
+ #include "hw-ops.h"
+ #include "../regd.h"
+ #include "ar9002_phy.h"
++#include "ar5008_initvals.h"
+
+ /* All code below is for AR5008, AR9001, AR9002 */
+
+@@ -43,23 +44,16 @@ static const int m2ThreshLowExt_off = 12
+ static const int m1ThreshExt_off = 127;
+ static const int m2ThreshExt_off = 127;
+
++static const struct ar5416IniArray bank0 = STATIC_INI_ARRAY(ar5416Bank0);
++static const struct ar5416IniArray bank1 = STATIC_INI_ARRAY(ar5416Bank1);
++static const struct ar5416IniArray bank2 = STATIC_INI_ARRAY(ar5416Bank2);
++static const struct ar5416IniArray bank3 = STATIC_INI_ARRAY(ar5416Bank3);
++static const struct ar5416IniArray bank7 = STATIC_INI_ARRAY(ar5416Bank7);
+
+-static void ar5008_rf_bank_setup(u32 *bank, struct ar5416IniArray *array,
+- int col)
+-{
+- int i;
+-
+- for (i = 0; i < array->ia_rows; i++)
+- bank[i] = INI_RA(array, i, col);
+-}
+-
+-
+-#define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) \
+- ar5008_write_rf_array(ah, iniarray, regData, &(regWr))
+-
+-static void ar5008_write_rf_array(struct ath_hw *ah, struct ar5416IniArray *array,
+- u32 *data, unsigned int *writecnt)
++static void ar5008_write_bank6(struct ath_hw *ah, unsigned int *writecnt)
+ {
++ struct ar5416IniArray *array = &ah->iniBank6;
++ u32 *data = ah->analogBank6Data;
+ int r;
+
+ ENABLE_REGWRITE_BUFFER(ah);
+@@ -165,7 +159,7 @@ static void ar5008_hw_force_bias(struct
+ ar5008_hw_phy_modify_rx_buffer(ah->analogBank6Data, tmp_reg, 3, 181, 3);
+
+ /* write Bank 6 with new params */
+- REG_WRITE_RF_ARRAY(&ah->iniBank6, ah->analogBank6Data, reg_writes);
++ ar5008_write_bank6(ah, ®_writes);
+ }
+
+ /**
+@@ -469,31 +463,16 @@ static void ar5008_hw_spur_mitigate(stru
+ */
+ static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah)
+ {
+-#define ATH_ALLOC_BANK(bank, size) do { \
+- bank = devm_kzalloc(ah->dev, sizeof(u32) * size, GFP_KERNEL); \
+- if (!bank) \
+- goto error; \
+- } while (0);
+-
+- struct ath_common *common = ath9k_hw_common(ah);
++ int size = ah->iniBank6.ia_rows * sizeof(u32);
+
+ if (AR_SREV_9280_20_OR_LATER(ah))
+ return 0;
+
+- ATH_ALLOC_BANK(ah->analogBank0Data, ah->iniBank0.ia_rows);
+- ATH_ALLOC_BANK(ah->analogBank1Data, ah->iniBank1.ia_rows);
+- ATH_ALLOC_BANK(ah->analogBank2Data, ah->iniBank2.ia_rows);
+- ATH_ALLOC_BANK(ah->analogBank3Data, ah->iniBank3.ia_rows);
+- ATH_ALLOC_BANK(ah->analogBank6Data, ah->iniBank6.ia_rows);
- ATH_ALLOC_BANK(ah->analogBank6TPCData, ah->iniBank6TPC.ia_rows);
- ATH_ALLOC_BANK(ah->analogBank7Data, ah->iniBank7.ia_rows);
+- ATH_ALLOC_BANK(ah->analogBank7Data, ah->iniBank7.ia_rows);
- ATH_ALLOC_BANK(ah->bank6Temp, ah->iniBank6.ia_rows);
++ ah->analogBank6Data = devm_kzalloc(ah->dev, size, GFP_KERNEL);
++ if (!ah->analogBank6Data)
++ return -ENOMEM;
return 0;
- #undef ATH_ALLOC_BANK
-@@ -517,6 +515,7 @@ static bool ar5008_hw_set_rf_regs(struct
+-#undef ATH_ALLOC_BANK
+-error:
+- ath_err(common, "Cannot allocate RF banks\n");
+- return -ENOMEM;
+ }
+
+
+@@ -517,6 +496,7 @@ static bool ar5008_hw_set_rf_regs(struct
u32 ob5GHz = 0, db5GHz = 0;
u32 ob2GHz = 0, db2GHz = 0;
int regWrites = 0;
/*
* Software does not need to program bank data
-@@ -541,13 +540,9 @@ static bool ar5008_hw_set_rf_regs(struct
- /* Setup Bank 6 Write */
- ar5008_rf_bank_setup(ah->analogBank3Data, &ah->iniBank3,
- modesIndex);
+@@ -529,25 +509,8 @@ static bool ar5008_hw_set_rf_regs(struct
+ /* Setup rf parameters */
+ eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV);
+
+- /* Setup Bank 0 Write */
+- ar5008_rf_bank_setup(ah->analogBank0Data, &ah->iniBank0, 1);
+-
+- /* Setup Bank 1 Write */
+- ar5008_rf_bank_setup(ah->analogBank1Data, &ah->iniBank1, 1);
+-
+- /* Setup Bank 2 Write */
+- ar5008_rf_bank_setup(ah->analogBank2Data, &ah->iniBank2, 1);
+-
+- /* Setup Bank 6 Write */
+- ar5008_rf_bank_setup(ah->analogBank3Data, &ah->iniBank3,
+- modesIndex);
- {
- int i;
- for (i = 0; i < ah->iniBank6TPC.ia_rows; i++) {
- INI_RA(&ah->iniBank6TPC, i, modesIndex);
- }
- }
-+
+ for (i = 0; i < ah->iniBank6.ia_rows; i++)
+ ah->analogBank6Data[i] = INI_RA(&ah->iniBank6, i, modesIndex);
/* Only the 5 or 2 GHz OB/DB need to be set for a mode */
if (eepMinorRev >= 2) {
-@@ -572,18 +567,12 @@ static bool ar5008_hw_set_rf_regs(struct
- ar5008_rf_bank_setup(ah->analogBank7Data, &ah->iniBank7, 1);
+@@ -568,22 +531,13 @@ static bool ar5008_hw_set_rf_regs(struct
+ }
+ }
+- /* Setup Bank 7 Setup */
+- ar5008_rf_bank_setup(ah->analogBank7Data, &ah->iniBank7, 1);
+-
/* Write Analog registers */
- REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data,
- regWrites);
- regWrites);
- REG_WRITE_RF_ARRAY(&ah->iniBank7, ah->analogBank7Data,
- regWrites);
-+ REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data, regWrites);
-+ REG_WRITE_RF_ARRAY(&ah->iniBank1, ah->analogBank1Data, regWrites);
-+ REG_WRITE_RF_ARRAY(&ah->iniBank2, ah->analogBank2Data, regWrites);
-+ REG_WRITE_RF_ARRAY(&ah->iniBank3, ah->analogBank3Data, regWrites);
-+ REG_WRITE_RF_ARRAY(&ah->iniBank6, ah->analogBank6Data, regWrites);
-+ REG_WRITE_RF_ARRAY(&ah->iniBank7, ah->analogBank7Data, regWrites);
++ REG_WRITE_ARRAY(&bank0, 1, regWrites);
++ REG_WRITE_ARRAY(&bank1, 1, regWrites);
++ REG_WRITE_ARRAY(&bank2, 1, regWrites);
++ REG_WRITE_ARRAY(&bank3, modesIndex, regWrites);
++ ar5008_write_bank6(ah, ®Writes);
++ REG_WRITE_ARRAY(&bank7, 1, regWrites);
return true;
}
INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac);
}
-@@ -86,14 +84,11 @@ static void ar9002_hw_init_mode_regs(str
- INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3);
- INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7);
+@@ -80,20 +78,11 @@ static void ar9002_hw_init_mode_regs(str
+ /* Common for AR5416, AR913x, AR9160 */
+ INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain);
+- INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0);
+- INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1);
+- INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2);
+- INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3);
+- INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7);
+-
- /* Common for AR5416, AR9160 */
- if (!AR_SREV_9100(ah))
- INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6);
}
/* iniAddac needs to be modified for these chips */
-@@ -104,7 +99,7 @@ static void ar9002_hw_init_mode_regs(str
+@@ -104,7 +93,7 @@ static void ar9002_hw_init_mode_regs(str
data = devm_kzalloc(ah->dev, size, GFP_KERNEL);
if (!data)
memcpy(data, addac->ia_array, size);
addac->ia_array = data;
-@@ -120,6 +115,7 @@ static void ar9002_hw_init_mode_regs(str
+@@ -120,6 +109,7 @@ static void ar9002_hw_init_mode_regs(str
INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
ar9287Common_japan_2484_cck_fir_coeff_9287_1_1);
}
}
static void ar9280_20_hw_init_rxgain_ini(struct ath_hw *ah)
-@@ -415,7 +411,10 @@ int ar9002_hw_attach_ops(struct ath_hw *
+@@ -415,7 +405,10 @@ int ar9002_hw_attach_ops(struct ath_hw *
struct ath_hw_ops *ops = ath9k_hw_ops(ah);
int ret;
static u32 ath9k_hw_compute_pll_control(struct ath_hw *ah,
struct ath9k_channel *chan)
{
-@@ -670,8 +665,6 @@ static int __ath9k_hw_init(struct ath_hw
+@@ -208,7 +203,7 @@ void ath9k_hw_synth_delay(struct ath_hw
+ udelay(hw_delay + BASE_ACTIVATE_DELAY);
+ }
+
+-void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array,
++void ath9k_hw_write_array(struct ath_hw *ah, const struct ar5416IniArray *array,
+ int column, unsigned int *writecnt)
+ {
+ int r;
+@@ -554,10 +549,8 @@ static int ath9k_hw_post_init(struct ath
+ ah->eep_ops->get_eeprom_ver(ah),
+ ah->eep_ops->get_eeprom_rev(ah));
+
+- if (ah->config.enable_ani) {
+- ath9k_hw_ani_setup(ah);
++ if (ah->config.enable_ani)
+ ath9k_hw_ani_init(ah);
+- }
+
+ return 0;
+ }
+@@ -670,8 +663,6 @@ static int __ath9k_hw_init(struct ath_hw
if (!AR_SREV_9300_20_OR_LATER(ah))
ah->ani_function &= ~ATH9K_ANI_MRC_CCK;
void (*init_mode_gain_regs)(struct ath_hw *ah);
void (*setup_calibration)(struct ath_hw *ah,
struct ath9k_cal_list *currCal);
-@@ -815,9 +813,7 @@ struct ath_hw {
- u32 *analogBank2Data;
- u32 *analogBank3Data;
+@@ -810,14 +808,7 @@ struct ath_hw {
+ struct ath_hw_ops ops;
+
+ /* Used to program the radio on non single-chip devices */
+- u32 *analogBank0Data;
+- u32 *analogBank1Data;
+- u32 *analogBank2Data;
+- u32 *analogBank3Data;
u32 *analogBank6Data;
- u32 *analogBank6TPCData;
- u32 *analogBank7Data;
+- u32 *analogBank7Data;
- u32 *bank6Temp;
int coverage_class;
u32 slottime;
-@@ -858,7 +854,6 @@ struct ath_hw {
- struct ar5416IniArray iniBank2;
- struct ar5416IniArray iniBank3;
+@@ -826,10 +817,6 @@ struct ath_hw {
+ /* ANI */
+ u32 proc_phyerr;
+ u32 aniperiod;
+- int totalSizeDesired[5];
+- int coarse_high[5];
+- int coarse_low[5];
+- int firpwr[5];
+ enum ath9k_ani_cmd ani_function;
+ u32 ani_skip_count;
+
+@@ -852,14 +839,8 @@ struct ath_hw {
+
+ struct ar5416IniArray iniModes;
+ struct ar5416IniArray iniCommon;
+- struct ar5416IniArray iniBank0;
+ struct ar5416IniArray iniBB_RfGain;
+- struct ar5416IniArray iniBank1;
+- struct ar5416IniArray iniBank2;
+- struct ar5416IniArray iniBank3;
struct ar5416IniArray iniBank6;
- struct ar5416IniArray iniBank6TPC;
- struct ar5416IniArray iniBank7;
+- struct ar5416IniArray iniBank7;
struct ar5416IniArray iniAddac;
struct ar5416IniArray iniPcieSerdes;
+ #ifdef CONFIG_PM_SLEEP
+@@ -975,7 +956,7 @@ void ath9k_hw_setantenna(struct ath_hw *
+ void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan,
+ int hw_delay);
+ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
+-void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array,
++void ath9k_hw_write_array(struct ath_hw *ah, const struct ar5416IniArray *array,
+ int column, unsigned int *writecnt);
+ u32 ath9k_hw_reverse_bits(u32 val, u32 n);
+ u16 ath9k_hw_computetxtime(struct ath_hw *ah,
+@@ -1062,6 +1043,7 @@ void ar9003_paprd_setup_gain_table(struc
+ int ar9003_paprd_init_table(struct ath_hw *ah);
+ bool ar9003_paprd_is_done(struct ath_hw *ah);
+ bool ar9003_is_paprd_enabled(struct ath_hw *ah);
++void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
+
+ /* Hardware family op attach helpers */
+ int ar5008_hw_attach_phy_ops(struct ath_hw *ah);
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1677,10 +1677,10 @@ netdev_tx_t ieee80211_monitor_start_xmit
/*
* Frame injection is not allowed if beaconing is not allowed
+--- a/drivers/net/wireless/ath/ath9k/ani.c
++++ b/drivers/net/wireless/ath/ath9k/ani.c
+@@ -152,7 +152,8 @@ static void ath9k_hw_set_ofdm_nil(struct
+ ath_dbg(common, ANI, "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
+ aniState->ofdmNoiseImmunityLevel,
+ immunityLevel, BEACON_RSSI(ah),
+- aniState->rssiThrLow, aniState->rssiThrHigh);
++ ATH9K_ANI_RSSI_THR_LOW,
++ ATH9K_ANI_RSSI_THR_HIGH);
+
+ if (!scan)
+ aniState->ofdmNoiseImmunityLevel = immunityLevel;
+@@ -173,7 +174,7 @@ static void ath9k_hw_set_ofdm_nil(struct
+
+ weak_sig = entry_ofdm->ofdm_weak_signal_on;
+ if (ah->opmode == NL80211_IFTYPE_STATION &&
+- BEACON_RSSI(ah) <= aniState->rssiThrHigh)
++ BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH)
+ weak_sig = true;
+
+ if (aniState->ofdmWeakSigDetect != weak_sig)
+@@ -216,11 +217,11 @@ static void ath9k_hw_set_cck_nil(struct
+
+ ath_dbg(common, ANI, "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
+ aniState->cckNoiseImmunityLevel, immunityLevel,
+- BEACON_RSSI(ah), aniState->rssiThrLow,
+- aniState->rssiThrHigh);
++ BEACON_RSSI(ah), ATH9K_ANI_RSSI_THR_LOW,
++ ATH9K_ANI_RSSI_THR_HIGH);
+
+ if (ah->opmode == NL80211_IFTYPE_STATION &&
+- BEACON_RSSI(ah) <= aniState->rssiThrLow &&
++ BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_LOW &&
+ immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI)
+ immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI;
+
+@@ -418,9 +419,6 @@ void ath9k_hw_ani_monitor(struct ath_hw
+ return;
+
+ aniState = &ah->curchan->ani;
+- if (WARN_ON(!aniState))
+- return;
+-
+ if (!ath9k_hw_ani_read_counters(ah))
+ return;
+
+@@ -489,23 +487,6 @@ void ath9k_hw_disable_mib_counters(struc
+ }
+ EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
+
+-void ath9k_hw_ani_setup(struct ath_hw *ah)
+-{
+- int i;
+-
+- static const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
+- static const int coarseHigh[] = { -14, -14, -14, -14, -12 };
+- static const int coarseLow[] = { -64, -64, -64, -64, -70 };
+- static const int firpwr[] = { -78, -78, -78, -78, -80 };
+-
+- for (i = 0; i < 5; 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_init(struct ath_hw *ah)
+ {
+ struct ath_common *common = ath9k_hw_common(ah);
+@@ -531,8 +512,6 @@ void ath9k_hw_ani_init(struct ath_hw *ah
+
+ ani->ofdmsTurn = true;
+
+- ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
+- ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
+ ani->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG;
+ ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
+ ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL;
+--- a/drivers/net/wireless/ath/ath9k/ani.h
++++ b/drivers/net/wireless/ath/ath9k/ani.h
+@@ -104,7 +104,6 @@ struct ath9k_ani_default {
+ };
+
+ struct ar5416AniState {
+- struct ath9k_channel *c;
+ u8 noiseImmunityLevel;
+ u8 ofdmNoiseImmunityLevel;
+ u8 cckNoiseImmunityLevel;
+@@ -113,15 +112,9 @@ struct ar5416AniState {
+ u8 spurImmunityLevel;
+ u8 firstepLevel;
+ u8 ofdmWeakSigDetect;
+- u8 cckWeakSigThreshold;
+ u32 listenTime;
+- int32_t rssiThrLow;
+- int32_t rssiThrHigh;
+ u32 ofdmPhyErrCount;
+ u32 cckPhyErrCount;
+- int16_t pktRssi[2];
+- int16_t ofdmErrRssi[2];
+- int16_t cckErrRssi[2];
+ struct ath9k_ani_default iniDef;
+ };
+
+@@ -147,7 +140,6 @@ struct ar5416Stats {
+
+ void ath9k_enable_mib_counters(struct ath_hw *ah);
+ void ath9k_hw_disable_mib_counters(struct ath_hw *ah);
+-void ath9k_hw_ani_setup(struct ath_hw *ah);
+ void ath9k_hw_ani_init(struct ath_hw *ah);
+
+ #endif /* ANI_H */
+--- a/drivers/net/wireless/ath/ath9k/calib.h
++++ b/drivers/net/wireless/ath/ath9k/calib.h
+@@ -33,6 +33,12 @@ struct ar5416IniArray {
+ u32 ia_columns;
+ };
+
++#define STATIC_INI_ARRAY(array) { \
++ .ia_array = (u32 *)(array), \
++ .ia_rows = ARRAY_SIZE(array), \
++ .ia_columns = ARRAY_SIZE(array[0]), \
++ }
++
+ #define INIT_INI_ARRAY(iniarray, array) do { \
+ (iniarray)->ia_array = (u32 *)(array); \
+ (iniarray)->ia_rows = ARRAY_SIZE(array); \
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -378,7 +378,7 @@ static void ath_tx_count_frames(struct a
+
+ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_buf *bf, struct list_head *bf_q,
+- struct ath_tx_status *ts, int txok, bool retry)
++ struct ath_tx_status *ts, int txok)
+ {
+ struct ath_node *an = NULL;
+ struct sk_buff *skb;
+@@ -490,7 +490,7 @@ static void ath_tx_complete_aggr(struct
+ } else if (!isaggr && txok) {
+ /* transmit completion */
+ acked_cnt++;
+- } else if ((tid->state & AGGR_CLEANUP) || !retry) {
++ } else if (tid->state & AGGR_CLEANUP) {
+ /*
+ * cleanup in progress, just fail
+ * the un-acked sub-frames
+@@ -604,6 +604,37 @@ static void ath_tx_complete_aggr(struct
+ ath9k_queue_reset(sc, RESET_TYPE_TX_ERROR);
+ }
+
++static bool bf_is_ampdu_not_probing(struct ath_buf *bf)
++{
++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu);
++ return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
++}
++
++static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
++ struct ath_tx_status *ts, struct ath_buf *bf,
++ struct list_head *bf_head)
++{
++ bool txok, flush;
++
++ txok = !(ts->ts_status & ATH9K_TXERR_MASK);
++ flush = !!(ts->ts_status & ATH9K_TX_FLUSH);
++ txq->axq_tx_inprogress = false;
++
++ txq->axq_depth--;
++ if (bf_is_ampdu_not_probing(bf))
++ txq->axq_ampdu_depth--;
++
++ if (!bf_isampdu(bf)) {
++ if (!flush)
++ ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
++ ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok);
++ } else
++ ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok);
++
++ if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && !flush)
++ ath_txq_schedule(sc, txq);
++}
++
+ static bool ath_lookup_legacy(struct ath_buf *bf)
+ {
+ struct sk_buff *skb;
+@@ -1331,23 +1362,6 @@ void ath_tx_aggr_resume(struct ath_softc
+ /* Queue Management */
+ /********************/
+
+-static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
+- struct ath_txq *txq)
+-{
+- struct ath_atx_ac *ac, *ac_tmp;
+- struct ath_atx_tid *tid, *tid_tmp;
+-
+- list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
+- list_del(&ac->list);
+- ac->sched = false;
+- list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
+- list_del(&tid->list);
+- tid->sched = false;
+- ath_tid_drain(sc, txq, tid);
+- }
+- }
+-}
+-
+ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
+ {
+ struct ath_hw *ah = sc->sc_ah;
+@@ -1470,14 +1484,8 @@ int ath_cabq_update(struct ath_softc *sc
+ return 0;
+ }
+
+-static bool bf_is_ampdu_not_probing(struct ath_buf *bf)
+-{
+- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu);
+- return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
+-}
+-
+ static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
+- struct list_head *list, bool retry_tx)
++ struct list_head *list)
+ {
+ struct ath_buf *bf, *lastbf;
+ struct list_head bf_head;
+@@ -1499,16 +1507,7 @@ static void ath_drain_txq_list(struct at
+
+ lastbf = bf->bf_lastbf;
+ list_cut_position(&bf_head, list, &lastbf->list);
+-
+- txq->axq_depth--;
+- if (bf_is_ampdu_not_probing(bf))
+- txq->axq_ampdu_depth--;
+-
+- if (bf_isampdu(bf))
+- ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
+- retry_tx);
+- else
+- ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
++ ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
+ }
+ }
+
+@@ -1518,7 +1517,7 @@ static void ath_drain_txq_list(struct at
+ * This assumes output has been stopped and
+ * we do not need to block ath_tx_tasklet.
+ */
+-void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
++void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq)
+ {
+ ath_txq_lock(sc, txq);
+
+@@ -1526,8 +1525,7 @@ void ath_draintxq(struct ath_softc *sc,
+ int idx = txq->txq_tailidx;
+
+ while (!list_empty(&txq->txq_fifo[idx])) {
+- ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx],
+- retry_tx);
++ ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx]);
+
+ INCR(idx, ATH_TXFIFO_DEPTH);
+ }
+@@ -1536,16 +1534,12 @@ void ath_draintxq(struct ath_softc *sc,
+
+ txq->axq_link = NULL;
+ txq->axq_tx_inprogress = false;
+- ath_drain_txq_list(sc, txq, &txq->axq_q, retry_tx);
+-
+- /* flush any pending frames if aggregation is enabled */
+- if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && !retry_tx)
+- ath_txq_drain_pending_buffers(sc, txq);
++ ath_drain_txq_list(sc, txq, &txq->axq_q);
+
+ ath_txq_unlock_complete(sc, txq);
+ }
+
+-bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
++bool ath_drain_all_txq(struct ath_softc *sc)
+ {
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+@@ -1581,7 +1575,7 @@ bool ath_drain_all_txq(struct ath_softc
+ */
+ txq = &sc->tx.txq[i];
+ txq->stopped = false;
+- ath_draintxq(sc, txq, retry_tx);
++ ath_draintxq(sc, txq);
+ }
+
+ return !npend;
+@@ -2175,28 +2169,6 @@ static void ath_tx_rc_status(struct ath_
+ tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
+ }
+
+-static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
+- struct ath_tx_status *ts, struct ath_buf *bf,
+- struct list_head *bf_head)
+-{
+- int txok;
+-
+- txq->axq_depth--;
+- txok = !(ts->ts_status & ATH9K_TXERR_MASK);
+- txq->axq_tx_inprogress = false;
+- if (bf_is_ampdu_not_probing(bf))
+- txq->axq_ampdu_depth--;
+-
+- if (!bf_isampdu(bf)) {
+- ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
+- ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok);
+- } else
+- ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true);
+-
+- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
+- ath_txq_schedule(sc, txq);
+-}
+-
+ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
+ {
+ struct ath_hw *ah = sc->sc_ah;
+--- a/net/mac80211/rc80211_minstrel.c
++++ b/net/mac80211/rc80211_minstrel.c
+@@ -494,6 +494,33 @@ minstrel_free_sta(void *priv, struct iee
+ kfree(mi);
+ }
+
++static void
++minstrel_init_cck_rates(struct minstrel_priv *mp)
++{
++ static const int bitrates[4] = { 10, 20, 55, 110 };
++ struct ieee80211_supported_band *sband;
++ int i, j;
++
++ sband = mp->hw->wiphy->bands[IEEE80211_BAND_2GHZ];
++ if (!sband)
++ return;
++
++ for (i = 0, j = 0; i < sband->n_bitrates; i++) {
++ struct ieee80211_rate *rate = &sband->bitrates[i];
++
++ if (rate->flags & IEEE80211_RATE_ERP_G)
++ continue;
++
++ for (j = 0; j < ARRAY_SIZE(bitrates); j++) {
++ if (rate->bitrate != bitrates[j])
++ continue;
++
++ mp->cck_rates[j] = i;
++ break;
++ }
++ }
++}
++
+ static void *
+ minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
+ {
+@@ -539,6 +566,8 @@ minstrel_alloc(struct ieee80211_hw *hw,
+ S_IRUGO | S_IWUGO, debugfsdir, &mp->fixed_rate_idx);
+ #endif
+
++ minstrel_init_cck_rates(mp);
++
+ return mp;
+ }
+
+--- a/net/mac80211/rc80211_minstrel.h
++++ b/net/mac80211/rc80211_minstrel.h
+@@ -79,6 +79,8 @@ struct minstrel_priv {
+ unsigned int lookaround_rate;
+ unsigned int lookaround_rate_mrr;
+
++ u8 cck_rates[4];
++
+ #ifdef CONFIG_MAC80211_DEBUGFS
+ /*
+ * enable fixed rate processing per RC
+--- a/net/mac80211/rc80211_minstrel_ht.c
++++ b/net/mac80211/rc80211_minstrel_ht.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
++ * Copyright (C) 2010-2013 Felix Fietkau <nbd@openwrt.org>
+ *
+ * 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
+@@ -63,6 +63,30 @@
+ } \
+ }
+
++#define CCK_DURATION(_bitrate, _short, _len) \
++ (10 /* SIFS */ + \
++ (_short ? 72 + 24 : 144 + 48 ) + \
++ (8 * (_len + 4) * 10) / (_bitrate))
++
++#define CCK_ACK_DURATION(_bitrate, _short) \
++ (CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) + \
++ CCK_DURATION(_bitrate, _short, AVG_PKT_SIZE))
++
++#define CCK_DURATION_LIST(_short) \
++ CCK_ACK_DURATION(10, _short), \
++ CCK_ACK_DURATION(20, _short), \
++ CCK_ACK_DURATION(55, _short), \
++ CCK_ACK_DURATION(110, _short)
++
++#define CCK_GROUP \
++ { \
++ .streams = 0, \
++ .duration = { \
++ CCK_DURATION_LIST(false), \
++ CCK_DURATION_LIST(true) \
++ } \
++ }
++
+ /*
+ * To enable sufficiently targeted rate sampling, MCS rates are divided into
+ * groups, based on the number of streams and flags (HT40, SGI) that they
+@@ -95,8 +119,13 @@ const struct mcs_group minstrel_mcs_grou
+ #if MINSTREL_MAX_STREAMS >= 3
+ MCS_GROUP(3, 1, 1),
+ #endif
++
++ /* must be last */
++ CCK_GROUP
+ };
+
++#define MINSTREL_CCK_GROUP (ARRAY_SIZE(minstrel_mcs_groups) - 1)
++
+ static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES];
+
+ /*
+@@ -119,6 +148,29 @@ minstrel_ht_get_group_idx(struct ieee802
+ !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH));
+ }
+
++struct minstrel_rate_stats *
++minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
++ struct ieee80211_tx_rate *rate)
++{
++ int group, idx;
++
++ if (rate->flags & IEEE80211_TX_RC_MCS) {
++ group = minstrel_ht_get_group_idx(rate);
++ idx = rate->idx % MCS_GROUP_RATES;
++ } else {
++ group = MINSTREL_CCK_GROUP;
++
++ for (idx = 0; idx <= ARRAY_SIZE(mp->cck_rates); idx++)
++ if (rate->idx == mp->cck_rates[idx])
++ break;
++
++ /* short preamble */
++ if (!(mi->groups[group].supported & BIT(idx)))
++ idx += 4;
++ }
++ return &mi->groups[group].rates[idx];
++}
++
+ static inline struct minstrel_rate_stats *
+ minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index)
+ {
+@@ -159,7 +211,7 @@ static void
+ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
+ {
+ struct minstrel_rate_stats *mr;
+- unsigned int usecs;
++ unsigned int usecs = 0;
+
+ mr = &mi->groups[group].rates[rate];
+
+@@ -168,7 +220,9 @@ minstrel_ht_calc_tp(struct minstrel_ht_s
+ return;
+ }
+
+- usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
++ if (group != MINSTREL_CCK_GROUP)
++ usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
++
+ usecs += minstrel_mcs_groups[group].duration[rate];
+ mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability);
+ }
+@@ -231,10 +285,6 @@ minstrel_ht_update_stats(struct minstrel
+ if (!mr->cur_tp)
+ continue;
+
+- /* ignore the lowest rate of each single-stream group */
+- if (!i && minstrel_mcs_groups[group].streams == 1)
+- continue;
+-
+ if ((mr->cur_tp > cur_prob_tp && mr->probability >
+ MINSTREL_FRAC(3, 4)) || mr->probability > cur_prob) {
+ mg->max_prob_rate = index;
+@@ -297,7 +347,7 @@ minstrel_ht_update_stats(struct minstrel
+ }
+
+ static bool
+-minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate)
++minstrel_ht_txstat_valid(struct minstrel_priv *mp, struct ieee80211_tx_rate *rate)
+ {
+ if (rate->idx < 0)
+ return false;
+@@ -305,7 +355,13 @@ minstrel_ht_txstat_valid(struct ieee8021
+ if (!rate->count)
+ return false;
+
+- return !!(rate->flags & IEEE80211_TX_RC_MCS);
++ if (rate->flags & IEEE80211_TX_RC_MCS);
++ return true;
++
++ return rate->idx == mp->cck_rates[0] ||
++ rate->idx == mp->cck_rates[1] ||
++ rate->idx == mp->cck_rates[2] ||
++ rate->idx == mp->cck_rates[3];
+ }
+
+ static void
+@@ -390,7 +446,6 @@ minstrel_ht_tx_status(void *priv, struct
+ struct minstrel_rate_stats *rate, *rate2;
+ struct minstrel_priv *mp = priv;
+ bool last;
+- int group;
+ int i;
+
+ if (!msp->is_ht)
+@@ -419,13 +474,12 @@ minstrel_ht_tx_status(void *priv, struct
+ if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
+ mi->sample_packets += info->status.ampdu_len;
+
+- last = !minstrel_ht_txstat_valid(&ar[0]);
++ last = !minstrel_ht_txstat_valid(mp, &ar[0]);
+ for (i = 0; !last; i++) {
+ last = (i == IEEE80211_TX_MAX_RATES - 1) ||
+- !minstrel_ht_txstat_valid(&ar[i + 1]);
++ !minstrel_ht_txstat_valid(mp, &ar[i + 1]);
+
+- group = minstrel_ht_get_group_idx(&ar[i]);
+- rate = &mi->groups[group].rates[ar[i].idx % 8];
++ rate = minstrel_ht_get_stats(mp, mi, &ar[i]);
+
+ if (last)
+ rate->success += info->status.ampdu_ack_len;
+@@ -451,7 +505,8 @@ minstrel_ht_tx_status(void *priv, struct
+
+ if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) {
+ minstrel_ht_update_stats(mp, mi);
+- if (!(info->flags & IEEE80211_TX_CTL_AMPDU))
++ if (!(info->flags & IEEE80211_TX_CTL_AMPDU) &&
++ mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP)
+ minstrel_aggr_check(sta, skb);
+ }
+ }
+@@ -467,6 +522,7 @@ minstrel_calc_retransmit(struct minstrel
+ unsigned int ctime = 0;
+ unsigned int t_slot = 9; /* FIXME */
+ unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len);
++ unsigned int overhead = 0, overhead_rtscts = 0;
+
+ mr = minstrel_get_ratestats(mi, index);
+ if (mr->probability < MINSTREL_FRAC(1, 10)) {
+@@ -488,9 +544,14 @@ minstrel_calc_retransmit(struct minstrel
+ ctime += (t_slot * cw) >> 1;
+ cw = min((cw << 1) | 1, mp->cw_max);
+
++ if (index / MCS_GROUP_RATES != MINSTREL_CCK_GROUP) {
++ overhead = mi->overhead;
++ overhead_rtscts = mi->overhead_rtscts;
++ }
++
+ /* Total TX time for data and Contention after first 2 tries */
+- tx_time = ctime + 2 * (mi->overhead + tx_time_data);
+- tx_time_rtscts = ctime + 2 * (mi->overhead_rtscts + tx_time_data);
++ tx_time = ctime + 2 * (overhead + tx_time_data);
++ tx_time_rtscts = ctime + 2 * (overhead_rtscts + tx_time_data);
+
+ /* See how many more tries we can fit inside segment size */
+ do {
+@@ -499,8 +560,8 @@ minstrel_calc_retransmit(struct minstrel
+ cw = min((cw << 1) | 1, mp->cw_max);
+
+ /* Total TX time after this try */
+- tx_time += ctime + mi->overhead + tx_time_data;
+- tx_time_rtscts += ctime + mi->overhead_rtscts + tx_time_data;
++ tx_time += ctime + overhead + tx_time_data;
++ tx_time_rtscts += ctime + overhead_rtscts + tx_time_data;
+
+ if (tx_time_rtscts < mp->segment_size)
+ mr->retry_count_rtscts++;
+@@ -530,9 +591,16 @@ minstrel_ht_set_rate(struct minstrel_pri
+ else
+ rate->count = mr->retry_count;
+
+- rate->flags = IEEE80211_TX_RC_MCS | group->flags;
++ rate->flags = 0;
+ if (rtscts)
+ rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS;
++
++ if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) {
++ rate->idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)];
++ return;
++ }
++
++ rate->flags |= IEEE80211_TX_RC_MCS | group->flags;
+ rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES;
+ }
+
+@@ -596,6 +664,22 @@ minstrel_get_sample_rate(struct minstrel
+ }
+
+ static void
++minstrel_ht_check_cck_shortpreamble(struct minstrel_priv *mp,
++ struct minstrel_ht_sta *mi, bool val)
++{
++ u8 supported = mi->groups[MINSTREL_CCK_GROUP].supported;
++
++ if (!supported || !mi->cck_supported_short)
++ return;
++
++ if (supported & (mi->cck_supported_short << (val * 4)))
++ return;
++
++ supported ^= mi->cck_supported_short | (mi->cck_supported_short << 4);
++ mi->groups[MINSTREL_CCK_GROUP].supported = supported;
++}
++
++static void
+ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
+ struct ieee80211_tx_rate_control *txrc)
+ {
+@@ -614,6 +698,7 @@ minstrel_ht_get_rate(void *priv, struct
+ return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc);
+
+ info->flags |= mi->tx_flags;
++ minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble);
+
+ /* Don't use EAPOL frames for sampling on non-mrr hw */
+ if (mp->hw->max_rates == 1 &&
+@@ -687,6 +772,30 @@ minstrel_ht_get_rate(void *priv, struct
+ }
+
+ static void
++minstrel_ht_update_cck(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
++ struct ieee80211_supported_band *sband,
++ struct ieee80211_sta *sta)
++{
++ int i;
++
++ if (sband->band != IEEE80211_BAND_2GHZ)
++ return;
++
++ mi->cck_supported = 0;
++ mi->cck_supported_short = 0;
++ for (i = 0; i < 4; i++) {
++ if (!rate_supported(sta, sband->band, mp->cck_rates[i]))
++ continue;
++
++ mi->cck_supported |= BIT(i);
++ if (sband->bitrates[i].flags & IEEE80211_RATE_SHORT_PREAMBLE)
++ mi->cck_supported_short |= BIT(i);
++ }
++
++ mi->groups[MINSTREL_CCK_GROUP].supported = mi->cck_supported;
++}
++
++static void
+ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta, void *priv_sta)
+ {
+@@ -706,7 +815,7 @@ minstrel_ht_update_caps(void *priv, stru
+ goto use_legacy;
+
+ BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) !=
+- MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS);
++ MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS + 1);
+
+ msp->is_ht = true;
+ memset(mi, 0, sizeof(*mi));
+@@ -742,6 +851,11 @@ minstrel_ht_update_caps(void *priv, stru
+ u16 req = 0;
+
+ mi->groups[i].supported = 0;
++ if (i == MINSTREL_CCK_GROUP) {
++ minstrel_ht_update_cck(mp, mi, sband, sta);
++ continue;
++ }
++
+ if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) {
+ if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ req |= IEEE80211_HT_CAP_SGI_40;
+--- a/net/mac80211/rc80211_minstrel_ht.h
++++ b/net/mac80211/rc80211_minstrel_ht.h
+@@ -107,8 +107,11 @@ struct minstrel_ht_sta {
+ /* current MCS group to be sampled */
+ u8 sample_group;
+
++ u8 cck_supported;
++ u8 cck_supported_short;
++
+ /* MCS rate group info and statistics */
+- struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS];
++ struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS + 1];
+ };
+
+ struct minstrel_ht_sta_priv {
+--- a/net/mac80211/rc80211_minstrel_ht_debugfs.c
++++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
+@@ -15,13 +15,76 @@
+ #include "rc80211_minstrel.h"
+ #include "rc80211_minstrel_ht.h"
+
++static char *
++minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
++{
++ unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS;
++ const struct mcs_group *mg;
++ unsigned int j, tp, prob, eprob;
++ char htmode = '2';
++ char gimode = 'L';
++
++ if (!mi->groups[i].supported)
++ return p;
++
++ mg = &minstrel_mcs_groups[i];
++ if (mg->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
++ htmode = '4';
++ if (mg->flags & IEEE80211_TX_RC_SHORT_GI)
++ gimode = 'S';
++
++ for (j = 0; j < MCS_GROUP_RATES; j++) {
++ struct minstrel_rate_stats *mr = &mi->groups[i].rates[j];
++ static const int bitrates[4] = { 10, 20, 55, 110 };
++ int idx = i * MCS_GROUP_RATES + j;
++
++ if (!(mi->groups[i].supported & BIT(j)))
++ continue;
++
++ if (i == max_mcs)
++ p += sprintf(p, "CCK/%cP ", j < 4 ? 'L' : 'S');
++ else
++ p += sprintf(p, "HT%c0/%cGI ", htmode, gimode);
++
++ *(p++) = (idx == mi->max_tp_rate) ? 'T' : ' ';
++ *(p++) = (idx == mi->max_tp_rate2) ? 't' : ' ';
++ *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' ';
++
++ if (i == max_mcs) {
++ int r = bitrates[j % 4];
++ p += sprintf(p, " %2u.%1uM", r / 10, r % 10);
++ } else {
++ p += sprintf(p, " MCS%-2u", (mg->streams - 1) *
++ MCS_GROUP_RATES + j);
++ }
++
++ tp = mr->cur_tp / 10;
++ prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
++ eprob = MINSTREL_TRUNC(mr->probability * 1000);
++
++ p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u "
++ "%3u %3u(%3u) %8llu %8llu\n",
++ tp / 10, tp % 10,
++ eprob / 10, eprob % 10,
++ prob / 10, prob % 10,
++ mr->retry_count,
++ mr->last_success,
++ mr->last_attempts,
++ (unsigned long long)mr->succ_hist,
++ (unsigned long long)mr->att_hist);
++ }
++
++ return p;
++}
++
+ static int
+ minstrel_ht_stats_open(struct inode *inode, struct file *file)
+ {
+ struct minstrel_ht_sta_priv *msp = inode->i_private;
+ struct minstrel_ht_sta *mi = &msp->ht;
+ struct minstrel_debugfs_info *ms;
+- unsigned int i, j, tp, prob, eprob;
++ unsigned int i;
++ unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS;
+ char *p;
+ int ret;
+
+@@ -38,50 +101,13 @@ minstrel_ht_stats_open(struct inode *ino
+
+ file->private_data = ms;
+ p = ms->buf;
+- p += sprintf(p, "type rate throughput ewma prob this prob "
+- "this succ/attempt success attempts\n");
+- for (i = 0; i < MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; i++) {
+- char htmode = '2';
+- char gimode = 'L';
+-
+- if (!mi->groups[i].supported)
+- continue;
+-
+- if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+- htmode = '4';
+- if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI)
+- gimode = 'S';
+-
+- for (j = 0; j < MCS_GROUP_RATES; j++) {
+- struct minstrel_rate_stats *mr = &mi->groups[i].rates[j];
+- int idx = i * MCS_GROUP_RATES + j;
++ p += sprintf(p, "type rate throughput ewma prob this prob "
++ "retry this succ/attempt success attempts\n");
+
+- if (!(mi->groups[i].supported & BIT(j)))
+- continue;
++ p = minstrel_ht_stats_dump(mi, max_mcs, p);
++ for (i = 0; i < max_mcs; i++)
++ p = minstrel_ht_stats_dump(mi, i, p);
+
+- p += sprintf(p, "HT%c0/%cGI ", htmode, gimode);
+-
+- *(p++) = (idx == mi->max_tp_rate) ? 'T' : ' ';
+- *(p++) = (idx == mi->max_tp_rate2) ? 't' : ' ';
+- *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' ';
+- p += sprintf(p, "MCS%-2u", (minstrel_mcs_groups[i].streams - 1) *
+- MCS_GROUP_RATES + j);
+-
+- tp = mr->cur_tp / 10;
+- prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
+- eprob = MINSTREL_TRUNC(mr->probability * 1000);
+-
+- p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u "
+- "%3u(%3u) %8llu %8llu\n",
+- tp / 10, tp % 10,
+- eprob / 10, eprob % 10,
+- prob / 10, prob % 10,
+- mr->last_success,
+- mr->last_attempts,
+- (unsigned long long)mr->succ_hist,
+- (unsigned long long)mr->att_hist);
+- }
+- }
+ p += sprintf(p, "\nTotal packet count:: ideal %d "
+ "lookaround %d\n",
+ max(0, (int) mi->total_packets - (int) mi->sample_packets),