ath9k_hw: clean up per-channel calibration data
authorFelix Fietkau <nbd@openwrt.org>
Fri, 30 Jul 2010 22:12:00 +0000 (00:12 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 4 Aug 2010 19:27:37 +0000 (15:27 -0400)
The noise floor history buffer is currently not kept per channel, which
can lead to problems when changing channels from a clean channel to a
noisy one. Also when switching from HT20 to HT40, the noise floor
history buffer is full of measurements, but none of them contain data
for the extension channel, which it needs quite a bit of time to recover
from.

This patch puts all the per-channel calibration data into a single data
structure, and gives the the driver control over whether that is used
per-channel or even not used for some channels.

For ath9k_htc, I decided to keep this per-channel in order to avoid
creating regressions.

For ath9k, the data is kept only for the operating channel, which saves
some space. ath9k_hw takes care of wiping old data when the operating
channel or its channel flags change.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
12 files changed:
drivers/net/wireless/ath/ath9k/ar9002_calib.c
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ar9003_paprd.c
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/calib.c
drivers/net/wireless/ath/ath9k/calib.h
drivers/net/wireless/ath/ath9k/htc.h
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/xmit.c

index 2387ad1a23a0706e7fb0584cb8675cea8df9c549..d28a8d37f01f5e6091fc0a4f82b8517376ad1486 100644 (file)
@@ -63,6 +63,7 @@ static bool ar9002_hw_per_calibration(struct ath_hw *ah,
                                      u8 rxchainmask,
                                      struct ath9k_cal_list *currCal)
 {
+       struct ath9k_hw_cal_data *caldata = ah->caldata;
        bool iscaldone = false;
 
        if (currCal->calState == CAL_RUNNING) {
@@ -81,14 +82,14 @@ static bool ar9002_hw_per_calibration(struct ath_hw *ah,
                                }
 
                                currCal->calData->calPostProc(ah, numChains);
-                               ichan->CalValid |= currCal->calData->calType;
+                               caldata->CalValid |= currCal->calData->calType;
                                currCal->calState = CAL_DONE;
                                iscaldone = true;
                        } else {
                                ar9002_hw_setup_calibration(ah, currCal);
                        }
                }
-       } else if (!(ichan->CalValid & currCal->calData->calType)) {
+       } else if (!(caldata->CalValid & currCal->calData->calType)) {
                ath9k_hw_reset_calibration(ah, currCal);
        }
 
@@ -900,7 +901,8 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
                        ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
        }
 
-       chan->CalValid = 0;
+       if (ah->caldata)
+               ah->caldata->CalValid = 0;
 
        return true;
 }
index f51ab89c989df9c61ac974fd4bf2e1571887f1ca..4674ea8c9c99497add7587ff30c6f94c7f7f6ef1 100644 (file)
@@ -68,6 +68,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah,
                                      u8 rxchainmask,
                                      struct ath9k_cal_list *currCal)
 {
+       struct ath9k_hw_cal_data *caldata = ah->caldata;
        /* Cal is assumed not done until explicitly set below */
        bool iscaldone = false;
 
@@ -95,7 +96,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah,
                                currCal->calData->calPostProc(ah, numChains);
 
                                /* Calibration has finished. */
-                               ichan->CalValid |= currCal->calData->calType;
+                               caldata->CalValid |= currCal->calData->calType;
                                currCal->calState = CAL_DONE;
                                iscaldone = true;
                        } else {
@@ -106,7 +107,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah,
                        ar9003_hw_setup_calibration(ah, currCal);
                        }
                }
-       } else if (!(ichan->CalValid & currCal->calData->calType)) {
+       } else if (!(caldata->CalValid & currCal->calData->calType)) {
                /* If current cal is marked invalid in channel, kick it off */
                ath9k_hw_reset_calibration(ah, currCal);
        }
@@ -793,7 +794,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
        if (ah->cal_list_curr)
                ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
 
-       chan->CalValid = 0;
+       if (ah->caldata)
+               ah->caldata->CalValid = 0;
 
        return true;
 }
index 49e0c865ce5c8da2ffb12a0beb9c31cf0d1616e0..7c38229ba670a28a624ab521a02820eae581c10a 100644 (file)
@@ -577,10 +577,11 @@ static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain)
 }
 
 void ar9003_paprd_populate_single_table(struct ath_hw *ah,
-                                       struct ath9k_channel *chan, int chain)
+                                       struct ath9k_hw_cal_data *caldata,
+                                       int chain)
 {
-       u32 *paprd_table_val = chan->pa_table[chain];
-       u32 small_signal_gain = chan->small_signal_gain[chain];
+       u32 *paprd_table_val = caldata->pa_table[chain];
+       u32 small_signal_gain = caldata->small_signal_gain[chain];
        u32 training_power;
        u32 reg = 0;
        int i;
@@ -654,17 +655,17 @@ int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain)
 }
 EXPORT_SYMBOL(ar9003_paprd_setup_gain_table);
 
-int ar9003_paprd_create_curve(struct ath_hw *ah, struct ath9k_channel *chan,
-                             int chain)
+int ar9003_paprd_create_curve(struct ath_hw *ah,
+                             struct ath9k_hw_cal_data *caldata, int chain)
 {
-       u16 *small_signal_gain = &chan->small_signal_gain[chain];
-       u32 *pa_table = chan->pa_table[chain];
+       u16 *small_signal_gain = &caldata->small_signal_gain[chain];
+       u32 *pa_table = caldata->pa_table[chain];
        u32 *data_L, *data_U;
        int i, status = 0;
        u32 *buf;
        u32 reg;
 
-       memset(chan->pa_table[chain], 0, sizeof(chan->pa_table[chain]));
+       memset(caldata->pa_table[chain], 0, sizeof(caldata->pa_table[chain]));
 
        buf = kmalloc(2 * 48 * sizeof(u32), GFP_ATOMIC);
        if (!buf)
index 11fc69bee58ffba118c7711ac88946699994e39d..07f26ee7a7235ac0f3c48c7966630ce849217cfc 100644 (file)
@@ -609,6 +609,7 @@ struct ath_softc {
 struct ath_wiphy {
        struct ath_softc *sc; /* shared for all virtual wiphys */
        struct ieee80211_hw *hw;
+       struct ath9k_hw_cal_data caldata;
        enum ath_wiphy_state {
                ATH_WIPHY_INACTIVE,
                ATH_WIPHY_ACTIVE,
index 294016f9ce7df04852abd11bce0a173f59861f8e..18b5c0dcc1fc571b2c38ef09a4fc78ba71d07ada 100644 (file)
 /* We can tune this as we go by monitoring really low values */
 #define ATH9K_NF_TOO_LOW       -60
 
-/* AR5416 may return very high value (like -31 dBm), in those cases the nf
- * 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_hw *ah, s16 nf)
-{
-       if (nf > ATH9K_NF_TOO_LOW) {
-               ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
-                         "noise floor value detected (%d) is "
-                         "lower than what we think is a "
-                         "reasonable value (%d)\n",
-                         nf, ATH9K_NF_TOO_LOW);
-               return false;
-       }
-       return true;
-}
-
 static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
 {
        int16_t nfval;
@@ -121,6 +104,19 @@ void ath9k_hw_reset_calibration(struct ath_hw *ah,
        ah->cal_samples = 0;
 }
 
+static s16 ath9k_hw_get_default_nf(struct ath_hw *ah,
+                                  struct ath9k_channel *chan)
+{
+       struct ath_nf_limits *limit;
+
+       if (!chan || IS_CHAN_2GHZ(chan))
+               limit = &ah->nf_2g;
+       else
+               limit = &ah->nf_5g;
+
+       return limit->nominal;
+}
+
 /* This is done for the currently configured channel */
 bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
 {
@@ -128,7 +124,7 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
        struct ieee80211_conf *conf = &common->hw->conf;
        struct ath9k_cal_list *currCal = ah->cal_list_curr;
 
-       if (!ah->curchan)
+       if (!ah->caldata)
                return true;
 
        if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
@@ -151,7 +147,7 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
                  "Resetting Cal %d state for channel %u\n",
                  currCal->calData->calType, conf->channel->center_freq);
 
-       ah->curchan->CalValid &= ~currCal->calData->calType;
+       ah->caldata->CalValid &= ~currCal->calData->calType;
        currCal->calState = CAL_WAITING;
 
        return false;
@@ -175,19 +171,28 @@ void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update)
 
 void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
 {
-       struct ath9k_nfcal_hist *h;
+       struct ath9k_nfcal_hist *h = NULL;
        unsigned i, j;
        int32_t val;
        u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
        struct ath_common *common = ath9k_hw_common(ah);
+       s16 default_nf = ath9k_hw_get_default_nf(ah, chan);
 
-       h = ah->nfCalHist;
+       if (ah->caldata)
+               h = ah->caldata->nfCalHist;
 
        for (i = 0; i < NUM_NF_READINGS; i++) {
                if (chainmask & (1 << i)) {
+                       s16 nfval;
+
+                       if (h)
+                               nfval = h[i].privNF;
+                       else
+                               nfval = default_nf;
+
                        val = REG_READ(ah, ah->nf_regs[i]);
                        val &= 0xFFFFFE00;
-                       val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
+                       val |= (((u32) nfval << 1) & 0x1ff);
                        REG_WRITE(ah, ah->nf_regs[i], val);
                }
        }
@@ -291,14 +296,18 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
        int16_t nfarray[NUM_NF_READINGS] = { 0 };
        struct ath9k_nfcal_hist *h;
        struct ieee80211_channel *c = chan->chan;
+       struct ath9k_hw_cal_data *caldata = ah->caldata;
+
+       if (!caldata)
+               return ath9k_hw_get_default_nf(ah, chan);
 
        chan->channelFlags &= (~CHANNEL_CW_INT);
        if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
                ath_print(common, ATH_DBG_CALIBRATE,
                          "NF did not complete in calibration window\n");
                nf = 0;
-               chan->rawNoiseFloor = nf;
-               return chan->rawNoiseFloor;
+               caldata->rawNoiseFloor = nf;
+               return caldata->rawNoiseFloor;
        } else {
                ath9k_hw_do_getnf(ah, nfarray);
                ath9k_hw_nf_sanitize(ah, nfarray);
@@ -313,47 +322,41 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
                }
        }
 
-       h = ah->nfCalHist;
+       h = caldata->nfCalHist;
 
        ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
-       chan->rawNoiseFloor = h[0].privNF;
+       caldata->rawNoiseFloor = h[0].privNF;
 
-       return chan->rawNoiseFloor;
+       return ah->caldata->rawNoiseFloor;
 }
 
-void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
+void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
+                                 struct ath9k_channel *chan)
 {
-       struct ath_nf_limits *limit;
+       struct ath9k_nfcal_hist *h;
+       s16 default_nf;
        int i, j;
 
-       if (!ah->curchan || IS_CHAN_2GHZ(ah->curchan))
-               limit = &ah->nf_2g;
-       else
-               limit = &ah->nf_5g;
+       if (!ah->caldata)
+               return;
 
+       h = ah->caldata->nfCalHist;
+       default_nf = ath9k_hw_get_default_nf(ah, chan);
        for (i = 0; i < NUM_NF_READINGS; i++) {
-               ah->nfCalHist[i].currIndex = 0;
-               ah->nfCalHist[i].privNF = limit->nominal;
-               ah->nfCalHist[i].invalidNFcount =
-                       AR_PHY_CCA_FILTERWINDOW_LENGTH;
+               h[i].currIndex = 0;
+               h[i].privNF = default_nf;
+               h[i].invalidNFcount = AR_PHY_CCA_FILTERWINDOW_LENGTH;
                for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
-                       ah->nfCalHist[i].nfCalBuffer[j] = limit->nominal;
+                       h[i].nfCalBuffer[j] = default_nf;
                }
        }
 }
 
 s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
 {
-       s16 nf;
-
-       if (chan->rawNoiseFloor == 0)
-               nf = -96;
-       else
-               nf = chan->rawNoiseFloor;
-
-       if (!ath9k_hw_nf_in_range(ah, nf))
-               nf = ATH_DEFAULT_NOISE_FLOOR;
+       if (!ah->caldata || !ah->caldata->rawNoiseFloor)
+               return ath9k_hw_get_default_nf(ah, chan);
 
-       return nf;
+       return ah->caldata->rawNoiseFloor;
 }
 EXPORT_SYMBOL(ath9k_hw_getchan_noise);
index bf4474220d1dcbbc1eee7de24c47ba87d03f6dea..ca2e6b39c1d4386e8c18dd1795d037ed631d1108 100644 (file)
@@ -112,7 +112,8 @@ void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update);
 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);
+void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
+                                 struct ath9k_channel *chan);
 s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan);
 void ath9k_hw_reset_calibration(struct ath_hw *ah,
                                struct ath9k_cal_list *currCal);
index 3756400e6bf95658903a1675cd85efd65d4222c4..43b9e21bc56284da1246ec1020cd23907a11d0df 100644 (file)
@@ -353,6 +353,8 @@ struct ath9k_htc_priv {
        u16 seq_no;
        u32 bmiss_cnt;
 
+       struct ath9k_hw_cal_data caldata[38];
+
        spinlock_t beacon_lock;
 
        bool tx_queues_stop;
index cf9bcc67ade2ea0f8c8a34b1d605c5e91cda2772..ebed9d1691a5110ee3222ab12e652da4dcdde9d5 100644 (file)
@@ -125,6 +125,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
        struct ieee80211_conf *conf = &common->hw->conf;
        bool fastcc = true;
        struct ieee80211_channel *channel = hw->conf.channel;
+       struct ath9k_hw_cal_data *caldata;
        enum htc_phymode mode;
        __be16 htc_mode;
        u8 cmd_rsp;
@@ -149,7 +150,8 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
                  priv->ah->curchan->channel,
                  channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf));
 
-       ret = ath9k_hw_reset(ah, hchan, fastcc);
+       caldata = &priv->caldata[channel->hw_value];
+       ret = ath9k_hw_reset(ah, hchan, caldata, fastcc);
        if (ret) {
                ath_print(common, ATH_DBG_FATAL,
                          "Unable to reset channel (%u Mhz) "
@@ -1028,7 +1030,7 @@ static void ath9k_htc_radio_enable(struct ieee80211_hw *hw)
                ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
 
        /* Reset the HW */
-       ret = ath9k_hw_reset(ah, ah->curchan, false);
+       ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
        if (ret) {
                ath_print(common, ATH_DBG_FATAL,
                          "Unable to reset hardware; reset status %d "
@@ -1091,7 +1093,7 @@ static void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
                ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
 
        /* Reset the HW */
-       ret = ath9k_hw_reset(ah, ah->curchan, false);
+       ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
        if (ret) {
                ath_print(common, ATH_DBG_FATAL,
                          "Unable to reset hardware; reset status %d "
@@ -1179,7 +1181,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
        ath9k_hw_configpcipowersave(ah, 0, 0);
 
        ath9k_hw_htc_resetinit(ah);
-       ret = ath9k_hw_reset(ah, init_channel, false);
+       ret = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
        if (ret) {
                ath_print(common, ATH_DBG_FATAL,
                          "Unable to reset hardware; reset status %d "
index 257b623185cd59397d99900ce8957e97f33d1541..3384ca1645622e4d3307d957ff193198f6b7e888 100644 (file)
@@ -610,7 +610,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)
        else
                ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S);
 
-       ath9k_init_nfcal_hist_buffer(ah);
        ah->bb_watchdog_timeout_ms = 25;
 
        common->state = ATH_HW_INITIALIZED;
@@ -1183,9 +1182,6 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
 
        ath9k_hw_spur_mitigate_freq(ah, chan);
 
-       if (!chan->oneTimeCalsDone)
-               chan->oneTimeCalsDone = true;
-
        return true;
 }
 
@@ -1218,7 +1214,7 @@ bool ath9k_hw_check_alive(struct ath_hw *ah)
 EXPORT_SYMBOL(ath9k_hw_check_alive);
 
 int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
-                   bool bChannelChange)
+                  struct ath9k_hw_cal_data *caldata, bool bChannelChange)
 {
        struct ath_common *common = ath9k_hw_common(ah);
        u32 saveLedState;
@@ -1243,9 +1239,19 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
                return -EIO;
 
-       if (curchan && !ah->chip_fullsleep)
+       if (curchan && !ah->chip_fullsleep && ah->caldata)
                ath9k_hw_getnf(ah, curchan);
 
+       ah->caldata = caldata;
+       if (caldata &&
+           (chan->channel != caldata->channel ||
+            (chan->channelFlags & ~CHANNEL_CW_INT) !=
+            (caldata->channelFlags & ~CHANNEL_CW_INT))) {
+               /* Operating channel changed, reset channel calibration data */
+               memset(caldata, 0, sizeof(*caldata));
+               ath9k_init_nfcal_hist_buffer(ah, chan);
+       }
+
        if (bChannelChange &&
            (ah->chip_fullsleep != true) &&
            (ah->curchan != NULL) &&
index 2d30efc0b94fd95587c493ad905512debb1cb14f..c1b701119d880cb4d4bf9923f465a9fd223189e1 100644 (file)
@@ -346,19 +346,24 @@ enum ath9k_int {
         CHANNEL_HT40PLUS |                     \
         CHANNEL_HT40MINUS)
 
-struct ath9k_channel {
-       struct ieee80211_channel *chan;
+struct ath9k_hw_cal_data {
        u16 channel;
        u32 channelFlags;
-       u32 chanmode;
        int32_t CalValid;
-       bool oneTimeCalsDone;
        int8_t iCoff;
        int8_t qCoff;
        int16_t rawNoiseFloor;
        bool paprd_done;
        u16 small_signal_gain[AR9300_MAX_CHAINS];
        u32 pa_table[AR9300_MAX_CHAINS][PAPRD_TABLE_SZ];
+       struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
+};
+
+struct ath9k_channel {
+       struct ieee80211_channel *chan;
+       u16 channel;
+       u32 channelFlags;
+       u32 chanmode;
 };
 
 #define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \
@@ -669,7 +674,7 @@ struct ath_hw {
        enum nl80211_iftype opmode;
        enum ath9k_power_mode power_mode;
 
-       struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
+       struct ath9k_hw_cal_data *caldata;
        struct ath9k_pacal_info pacal_info;
        struct ar5416Stats stats;
        struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES];
@@ -863,7 +868,7 @@ const char *ath9k_hw_probe(u16 vendorid, u16 devid);
 void ath9k_hw_deinit(struct ath_hw *ah);
 int ath9k_hw_init(struct ath_hw *ah);
 int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
-                  bool bChannelChange);
+                  struct ath9k_hw_cal_data *caldata, bool bChannelChange);
 int ath9k_hw_fill_cap_info(struct ath_hw *ah);
 u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan);
 
@@ -958,9 +963,10 @@ void ar9003_hw_bb_watchdog_read(struct ath_hw *ah);
 void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah);
 void ar9003_paprd_enable(struct ath_hw *ah, bool val);
 void ar9003_paprd_populate_single_table(struct ath_hw *ah,
-                                       struct ath9k_channel *chan, int chain);
-int ar9003_paprd_create_curve(struct ath_hw *ah, struct ath9k_channel *chan,
-                             int chain);
+                                       struct ath9k_hw_cal_data *caldata,
+                                       int chain);
+int ar9003_paprd_create_curve(struct ath_hw *ah,
+                             struct ath9k_hw_cal_data *caldata, int chain);
 int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain);
 int ar9003_paprd_init_table(struct ath_hw *ah);
 bool ar9003_paprd_is_done(struct ath_hw *ah);
index 8387ad5b4897288bcc423f05eaf616f575177b7f..3caa32316e7b4567c5cbb7372aef8330b8d2a747 100644 (file)
@@ -183,11 +183,13 @@ static void ath_start_ani(struct ath_common *common)
 int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
                    struct ath9k_channel *hchan)
 {
+       struct ath_wiphy *aphy = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ieee80211_conf *conf = &common->hw->conf;
        bool fastcc = true, stopped;
        struct ieee80211_channel *channel = hw->conf.channel;
+       struct ath9k_hw_cal_data *caldata = NULL;
        int r;
 
        if (sc->sc_flags & SC_OP_INVALID)
@@ -220,6 +222,9 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
        if (!stopped || !(sc->sc_flags & SC_OP_OFFCHANNEL))
                fastcc = false;
 
+       if (!(sc->sc_flags & SC_OP_OFFCHANNEL))
+               caldata = &aphy->caldata;
+
        ath_print(common, ATH_DBG_CONFIG,
                  "(%u MHz) -> (%u MHz), conf_is_ht40: %d\n",
                  sc->sc_ah->curchan->channel,
@@ -227,7 +232,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 
        spin_lock_bh(&sc->sc_resetlock);
 
-       r = ath9k_hw_reset(ah, hchan, fastcc);
+       r = ath9k_hw_reset(ah, hchan, caldata, fastcc);
        if (r) {
                ath_print(common, ATH_DBG_FATAL,
                          "Unable to reset channel (%u MHz), "
@@ -263,9 +268,10 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 static void ath_paprd_activate(struct ath_softc *sc)
 {
        struct ath_hw *ah = sc->sc_ah;
+       struct ath9k_hw_cal_data *caldata = ah->caldata;
        int chain;
 
-       if (!ah->curchan->paprd_done)
+       if (!caldata || !caldata->paprd_done)
                return;
 
        ath9k_ps_wakeup(sc);
@@ -274,7 +280,7 @@ static void ath_paprd_activate(struct ath_softc *sc)
                if (!(ah->caps.tx_chainmask & BIT(chain)))
                        continue;
 
-               ar9003_paprd_populate_single_table(ah, ah->curchan, chain);
+               ar9003_paprd_populate_single_table(ah, caldata, chain);
        }
 
        ar9003_paprd_enable(ah, true);
@@ -292,6 +298,7 @@ void ath_paprd_calibrate(struct work_struct *work)
        int band = hw->conf.channel->band;
        struct ieee80211_supported_band *sband = &sc->sbands[band];
        struct ath_tx_control txctl;
+       struct ath9k_hw_cal_data *caldata = ah->caldata;
        int qnum, ftype;
        int chain_ok = 0;
        int chain;
@@ -299,6 +306,9 @@ void ath_paprd_calibrate(struct work_struct *work)
        int time_left;
        int i;
 
+       if (!caldata)
+               return;
+
        skb = alloc_skb(len, GFP_KERNEL);
        if (!skb)
                return;
@@ -353,7 +363,7 @@ void ath_paprd_calibrate(struct work_struct *work)
                if (!ar9003_paprd_is_done(ah))
                        break;
 
-               if (ar9003_paprd_create_curve(ah, ah->curchan, chain) != 0)
+               if (ar9003_paprd_create_curve(ah, caldata, chain) != 0)
                        break;
 
                chain_ok = 1;
@@ -361,7 +371,7 @@ void ath_paprd_calibrate(struct work_struct *work)
        kfree_skb(skb);
 
        if (chain_ok) {
-               ah->curchan->paprd_done = true;
+               caldata->paprd_done = true;
                ath_paprd_activate(sc);
        }
 
@@ -470,8 +480,8 @@ set_timer:
                cal_interval = min(cal_interval, (u32)short_cal_interval);
 
        mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) {
-               if (!sc->sc_ah->curchan->paprd_done)
+       if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->caldata) {
+               if (!ah->caldata->paprd_done)
                        ieee80211_queue_work(sc->hw, &sc->paprd_work);
                else
                        ath_paprd_activate(sc);
@@ -829,7 +839,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
                ah->curchan = ath_get_curchannel(sc, sc->hw);
 
        spin_lock_bh(&sc->sc_resetlock);
-       r = ath9k_hw_reset(ah, ah->curchan, false);
+       r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
        if (r) {
                ath_print(common, ATH_DBG_FATAL,
                          "Unable to reset channel (%u MHz), "
@@ -889,7 +899,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
                ah->curchan = ath_get_curchannel(sc, hw);
 
        spin_lock_bh(&sc->sc_resetlock);
-       r = ath9k_hw_reset(ah, ah->curchan, false);
+       r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
        if (r) {
                ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
                          "Unable to reset channel (%u MHz), "
@@ -922,7 +932,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
        ath_flushrecv(sc);
 
        spin_lock_bh(&sc->sc_resetlock);
-       r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false);
+       r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
        if (r)
                ath_print(common, ATH_DBG_FATAL,
                          "Unable to reset hardware; reset status %d\n", r);
@@ -1097,7 +1107,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
         * and then setup of the interrupt mask.
         */
        spin_lock_bh(&sc->sc_resetlock);
-       r = ath9k_hw_reset(ah, init_channel, false);
+       r = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
        if (r) {
                ath_print(common, ATH_DBG_FATAL,
                          "Unable to reset hardware; reset status %d "
index 501b72821b4d426e5138b7f3b84e9a962d617361..700ba8dee5a50d195882d6179ca6f2aad9f0b580 100644 (file)
@@ -1181,7 +1181,7 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
                          "Failed to stop TX DMA. Resetting hardware!\n");
 
                spin_lock_bh(&sc->sc_resetlock);
-               r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false);
+               r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
                if (r)
                        ath_print(common, ATH_DBG_FATAL,
                                  "Unable to reset hardware; reset status %d\n",