Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2008-2011 Atheros Communications Inc.
0003  *
0004  * Permission to use, copy, modify, and/or distribute this software for any
0005  * purpose with or without fee is hereby granted, provided that the above
0006  * copyright notice and this permission notice appear in all copies.
0007  *
0008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0011  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0013  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0014  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0015  */
0016 
0017 #include "hw.h"
0018 #include "hw-ops.h"
0019 #include <linux/export.h>
0020 
0021 /* Common calibration code */
0022 
0023 
0024 static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
0025 {
0026     int16_t nfval;
0027     int16_t sort[ATH9K_NF_CAL_HIST_MAX];
0028     int i, j;
0029 
0030     for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++)
0031         sort[i] = nfCalBuffer[i];
0032 
0033     for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) {
0034         for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) {
0035             if (sort[j] > sort[j - 1]) {
0036                 nfval = sort[j];
0037                 sort[j] = sort[j - 1];
0038                 sort[j - 1] = nfval;
0039             }
0040         }
0041     }
0042     nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1];
0043 
0044     return nfval;
0045 }
0046 
0047 static struct ath_nf_limits *ath9k_hw_get_nf_limits(struct ath_hw *ah,
0048                             struct ath9k_channel *chan)
0049 {
0050     struct ath_nf_limits *limit;
0051 
0052     if (!chan || IS_CHAN_2GHZ(chan))
0053         limit = &ah->nf_2g;
0054     else
0055         limit = &ah->nf_5g;
0056 
0057     return limit;
0058 }
0059 
0060 static s16 ath9k_hw_get_default_nf(struct ath_hw *ah,
0061                    struct ath9k_channel *chan,
0062                    int chain)
0063 {
0064     s16 calib_nf = ath9k_hw_get_nf_limits(ah, chan)->cal[chain];
0065 
0066     if (calib_nf)
0067         return calib_nf;
0068     else
0069         return ath9k_hw_get_nf_limits(ah, chan)->nominal;
0070 }
0071 
0072 s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan,
0073                s16 nf)
0074 {
0075     s8 noise = ATH_DEFAULT_NOISE_FLOOR;
0076 
0077     if (nf) {
0078         s8 delta = nf - ATH9K_NF_CAL_NOISE_THRESH -
0079                ath9k_hw_get_default_nf(ah, chan, 0);
0080         if (delta > 0)
0081             noise += delta;
0082     }
0083     return noise;
0084 }
0085 EXPORT_SYMBOL(ath9k_hw_getchan_noise);
0086 
0087 static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah,
0088                           struct ath9k_hw_cal_data *cal,
0089                           int16_t *nfarray)
0090 {
0091     struct ath_common *common = ath9k_hw_common(ah);
0092     struct ath_nf_limits *limit;
0093     struct ath9k_nfcal_hist *h;
0094     bool high_nf_mid = false;
0095     u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
0096     int i;
0097 
0098     h = cal->nfCalHist;
0099     limit = ath9k_hw_get_nf_limits(ah, ah->curchan);
0100 
0101     for (i = 0; i < NUM_NF_READINGS; i++) {
0102         if (!(chainmask & (1 << i)) ||
0103             ((i >= AR5416_MAX_CHAINS) && !IS_CHAN_HT40(ah->curchan)))
0104             continue;
0105 
0106         h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
0107 
0108         if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX)
0109             h[i].currIndex = 0;
0110 
0111         if (h[i].invalidNFcount > 0) {
0112             h[i].invalidNFcount--;
0113             h[i].privNF = nfarray[i];
0114         } else {
0115             h[i].privNF =
0116                 ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
0117         }
0118 
0119         if (!h[i].privNF)
0120             continue;
0121 
0122         if (h[i].privNF > limit->max) {
0123             high_nf_mid = true;
0124 
0125             ath_dbg(common, CALIBRATE,
0126                 "NFmid[%d] (%d) > MAX (%d), %s\n",
0127                 i, h[i].privNF, limit->max,
0128                 (test_bit(NFCAL_INTF, &cal->cal_flags) ?
0129                  "not corrected (due to interference)" :
0130                  "correcting to MAX"));
0131 
0132             /*
0133              * Normally we limit the average noise floor by the
0134              * hardware specific maximum here. However if we have
0135              * encountered stuck beacons because of interference,
0136              * we bypass this limit here in order to better deal
0137              * with our environment.
0138              */
0139             if (!test_bit(NFCAL_INTF, &cal->cal_flags))
0140                 h[i].privNF = limit->max;
0141         }
0142     }
0143 
0144     /*
0145      * If the noise floor seems normal for all chains, assume that
0146      * there is no significant interference in the environment anymore.
0147      * Re-enable the enforcement of the NF maximum again.
0148      */
0149     if (!high_nf_mid)
0150         clear_bit(NFCAL_INTF, &cal->cal_flags);
0151 }
0152 
0153 static bool ath9k_hw_get_nf_thresh(struct ath_hw *ah,
0154                    enum nl80211_band band,
0155                    int16_t *nft)
0156 {
0157     switch (band) {
0158     case NL80211_BAND_5GHZ:
0159         *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_5);
0160         break;
0161     case NL80211_BAND_2GHZ:
0162         *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_2);
0163         break;
0164     default:
0165         BUG_ON(1);
0166         return false;
0167     }
0168 
0169     return true;
0170 }
0171 
0172 void ath9k_hw_reset_calibration(struct ath_hw *ah,
0173                 struct ath9k_cal_list *currCal)
0174 {
0175     int i;
0176 
0177     ath9k_hw_setup_calibration(ah, currCal);
0178 
0179     ah->cal_start_time = jiffies;
0180     currCal->calState = CAL_RUNNING;
0181 
0182     for (i = 0; i < AR5416_MAX_CHAINS; i++) {
0183         ah->meas0.sign[i] = 0;
0184         ah->meas1.sign[i] = 0;
0185         ah->meas2.sign[i] = 0;
0186         ah->meas3.sign[i] = 0;
0187     }
0188 
0189     ah->cal_samples = 0;
0190 }
0191 
0192 /* This is done for the currently configured channel */
0193 bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
0194 {
0195     struct ath_common *common = ath9k_hw_common(ah);
0196     struct ath9k_cal_list *currCal = ah->cal_list_curr;
0197 
0198     if (!ah->caldata)
0199         return true;
0200 
0201     if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
0202         return true;
0203 
0204     if (currCal == NULL)
0205         return true;
0206 
0207     if (currCal->calState != CAL_DONE) {
0208         ath_dbg(common, CALIBRATE, "Calibration state incorrect, %d\n",
0209             currCal->calState);
0210         return true;
0211     }
0212 
0213     currCal = ah->cal_list;
0214     do {
0215         ath_dbg(common, CALIBRATE, "Resetting Cal %d state for channel %u\n",
0216             currCal->calData->calType,
0217             ah->curchan->chan->center_freq);
0218 
0219         ah->caldata->CalValid &= ~currCal->calData->calType;
0220         currCal->calState = CAL_WAITING;
0221 
0222         currCal = currCal->calNext;
0223     } while (currCal != ah->cal_list);
0224 
0225     return false;
0226 }
0227 EXPORT_SYMBOL(ath9k_hw_reset_calvalid);
0228 
0229 void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update)
0230 {
0231     if (ah->caldata)
0232         set_bit(NFCAL_PENDING, &ah->caldata->cal_flags);
0233 
0234     REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
0235             AR_PHY_AGC_CONTROL_ENABLE_NF);
0236 
0237     if (update)
0238         REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
0239             AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
0240     else
0241         REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
0242             AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
0243 
0244     REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
0245 }
0246 
0247 int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
0248 {
0249     struct ath9k_nfcal_hist *h = NULL;
0250     unsigned i, j;
0251     u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
0252     struct ath_common *common = ath9k_hw_common(ah);
0253     s16 default_nf = ath9k_hw_get_nf_limits(ah, chan)->nominal;
0254     u32 bb_agc_ctl = REG_READ(ah, AR_PHY_AGC_CONTROL);
0255 
0256     if (ah->caldata)
0257         h = ah->caldata->nfCalHist;
0258 
0259     ENABLE_REG_RMW_BUFFER(ah);
0260     for (i = 0; i < NUM_NF_READINGS; i++) {
0261         if (chainmask & (1 << i)) {
0262             s16 nfval;
0263 
0264             if ((i >= AR5416_MAX_CHAINS) && !IS_CHAN_HT40(chan))
0265                 continue;
0266 
0267             if (ah->nf_override)
0268                 nfval = ah->nf_override;
0269             else if (h)
0270                 nfval = h[i].privNF;
0271             else {
0272                 /* Try to get calibrated noise floor value */
0273                 nfval =
0274                     ath9k_hw_get_nf_limits(ah, chan)->cal[i];
0275                 if (nfval > -60 || nfval < -127)
0276                     nfval = default_nf;
0277             }
0278 
0279             REG_RMW(ah, ah->nf_regs[i],
0280                 (((u32) nfval << 1) & 0x1ff), 0x1ff);
0281         }
0282     }
0283 
0284     /*
0285      * stop NF cal if ongoing to ensure NF load completes immediately
0286      * (or after end rx/tx frame if ongoing)
0287      */
0288     if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) {
0289         REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
0290         REG_RMW_BUFFER_FLUSH(ah);
0291         ENABLE_REG_RMW_BUFFER(ah);
0292     }
0293 
0294     /*
0295      * Load software filtered NF value into baseband internal minCCApwr
0296      * variable.
0297      */
0298     REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
0299             AR_PHY_AGC_CONTROL_ENABLE_NF);
0300     REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
0301             AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
0302     REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
0303     REG_RMW_BUFFER_FLUSH(ah);
0304 
0305     /*
0306      * Wait for load to complete, should be fast, a few 10s of us.
0307      * The max delay was changed from an original 250us to 22.2 msec.
0308      * This would increase timeout to the longest possible frame
0309      * (11n max length 22.1 msec)
0310      */
0311     for (j = 0; j < 22200; j++) {
0312         if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
0313                   AR_PHY_AGC_CONTROL_NF) == 0)
0314             break;
0315         udelay(10);
0316     }
0317 
0318     /*
0319      * Restart NF so it can continue.
0320      */
0321     if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) {
0322         ENABLE_REG_RMW_BUFFER(ah);
0323         if (bb_agc_ctl & AR_PHY_AGC_CONTROL_ENABLE_NF)
0324             REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
0325                     AR_PHY_AGC_CONTROL_ENABLE_NF);
0326         if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NO_UPDATE_NF)
0327             REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
0328                     AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
0329         REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
0330         REG_RMW_BUFFER_FLUSH(ah);
0331     }
0332 
0333     /*
0334      * We timed out waiting for the noisefloor to load, probably due to an
0335      * in-progress rx. Simply return here and allow the load plenty of time
0336      * to complete before the next calibration interval.  We need to avoid
0337      * trying to load -50 (which happens below) while the previous load is
0338      * still in progress as this can cause rx deafness. Instead by returning
0339      * here, the baseband nf cal will just be capped by our present
0340      * noisefloor until the next calibration timer.
0341      */
0342     if (j == 22200) {
0343         ath_dbg(common, ANY,
0344             "Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n",
0345             REG_READ(ah, AR_PHY_AGC_CONTROL));
0346         return -ETIMEDOUT;
0347     }
0348 
0349     /*
0350      * Restore maxCCAPower register parameter again so that we're not capped
0351      * by the median we just loaded.  This will be initial (and max) value
0352      * of next noise floor calibration the baseband does.
0353      */
0354     ENABLE_REG_RMW_BUFFER(ah);
0355     for (i = 0; i < NUM_NF_READINGS; i++) {
0356         if (chainmask & (1 << i)) {
0357             if ((i >= AR5416_MAX_CHAINS) && !IS_CHAN_HT40(chan))
0358                 continue;
0359 
0360             REG_RMW(ah, ah->nf_regs[i],
0361                     (((u32) (-50) << 1) & 0x1ff), 0x1ff);
0362         }
0363     }
0364     REG_RMW_BUFFER_FLUSH(ah);
0365 
0366     return 0;
0367 }
0368 EXPORT_SYMBOL(ath9k_hw_loadnf);
0369 
0370 
0371 static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
0372 {
0373     struct ath_common *common = ath9k_hw_common(ah);
0374     struct ath_nf_limits *limit;
0375     int i;
0376 
0377     if (IS_CHAN_2GHZ(ah->curchan))
0378         limit = &ah->nf_2g;
0379     else
0380         limit = &ah->nf_5g;
0381 
0382     for (i = 0; i < NUM_NF_READINGS; i++) {
0383         if (!nf[i])
0384             continue;
0385 
0386         ath_dbg(common, CALIBRATE,
0387             "NF calibrated [%s] [chain %d] is %d\n",
0388             (i >= 3 ? "ext" : "ctl"), i % 3, nf[i]);
0389 
0390         if (nf[i] > limit->max) {
0391             ath_dbg(common, CALIBRATE,
0392                 "NF[%d] (%d) > MAX (%d), correcting to MAX\n",
0393                 i, nf[i], limit->max);
0394             nf[i] = limit->max;
0395         } else if (nf[i] < limit->min) {
0396             ath_dbg(common, CALIBRATE,
0397                 "NF[%d] (%d) < MIN (%d), correcting to NOM\n",
0398                 i, nf[i], limit->min);
0399             nf[i] = limit->nominal;
0400         }
0401     }
0402 }
0403 
0404 bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
0405 {
0406     struct ath_common *common = ath9k_hw_common(ah);
0407     int16_t nf, nfThresh;
0408     int16_t nfarray[NUM_NF_READINGS] = { 0 };
0409     struct ath9k_nfcal_hist *h;
0410     struct ieee80211_channel *c = chan->chan;
0411     struct ath9k_hw_cal_data *caldata = ah->caldata;
0412 
0413     if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
0414         ath_dbg(common, CALIBRATE,
0415             "NF did not complete in calibration window\n");
0416         return false;
0417     }
0418 
0419     ath9k_hw_do_getnf(ah, nfarray);
0420     ath9k_hw_nf_sanitize(ah, nfarray);
0421     nf = nfarray[0];
0422     if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh)
0423         && nf > nfThresh) {
0424         ath_dbg(common, CALIBRATE,
0425             "noise floor failed detected; detected %d, threshold %d\n",
0426             nf, nfThresh);
0427     }
0428 
0429     if (!caldata) {
0430         chan->noisefloor = nf;
0431         return false;
0432     }
0433 
0434     h = caldata->nfCalHist;
0435     clear_bit(NFCAL_PENDING, &caldata->cal_flags);
0436     ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray);
0437     chan->noisefloor = h[0].privNF;
0438     ah->noise = ath9k_hw_getchan_noise(ah, chan, chan->noisefloor);
0439     return true;
0440 }
0441 EXPORT_SYMBOL(ath9k_hw_getnf);
0442 
0443 void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
0444                   struct ath9k_channel *chan)
0445 {
0446     struct ath9k_nfcal_hist *h;
0447     int i, j, k = 0;
0448 
0449     ah->caldata->channel = chan->channel;
0450     ah->caldata->channelFlags = chan->channelFlags;
0451     h = ah->caldata->nfCalHist;
0452     for (i = 0; i < NUM_NF_READINGS; i++) {
0453         h[i].currIndex = 0;
0454         h[i].privNF = ath9k_hw_get_default_nf(ah, chan, k);
0455         h[i].invalidNFcount = AR_PHY_CCA_FILTERWINDOW_LENGTH;
0456         for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++)
0457             h[i].nfCalBuffer[j] = h[i].privNF;
0458         if (++k >= AR5416_MAX_CHAINS)
0459             k = 0;
0460     }
0461 }
0462 
0463 
0464 void ath9k_hw_bstuck_nfcal(struct ath_hw *ah)
0465 {
0466     struct ath9k_hw_cal_data *caldata = ah->caldata;
0467 
0468     if (unlikely(!caldata))
0469         return;
0470 
0471     /*
0472      * If beacons are stuck, the most likely cause is interference.
0473      * Triggering a noise floor calibration at this point helps the
0474      * hardware adapt to a noisy environment much faster.
0475      * To ensure that we recover from stuck beacons quickly, let
0476      * the baseband update the internal NF value itself, similar to
0477      * what is being done after a full reset.
0478      */
0479     if (!test_bit(NFCAL_PENDING, &caldata->cal_flags))
0480         ath9k_hw_start_nfcal(ah, true);
0481     else if (!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF))
0482         ath9k_hw_getnf(ah, ah->curchan);
0483 
0484     set_bit(NFCAL_INTF, &caldata->cal_flags);
0485 }
0486 EXPORT_SYMBOL(ath9k_hw_bstuck_nfcal);
0487