root/drivers/net/wireless/ath/ath9k/calib.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ath9k_hw_get_nf_hist_mid
  2. ath9k_hw_get_nf_limits
  3. ath9k_hw_get_default_nf
  4. ath9k_hw_getchan_noise
  5. ath9k_hw_update_nfcal_hist_buffer
  6. ath9k_hw_get_nf_thresh
  7. ath9k_hw_reset_calibration
  8. ath9k_hw_reset_calvalid
  9. ath9k_hw_start_nfcal
  10. ath9k_hw_loadnf
  11. ath9k_hw_nf_sanitize
  12. ath9k_hw_getnf
  13. ath9k_init_nfcal_hist_buffer
  14. ath9k_hw_bstuck_nfcal

   1 /*
   2  * Copyright (c) 2008-2011 Atheros Communications Inc.
   3  *
   4  * Permission to use, copy, modify, and/or distribute this software for any
   5  * purpose with or without fee is hereby granted, provided that the above
   6  * copyright notice and this permission notice appear in all copies.
   7  *
   8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15  */
  16 
  17 #include "hw.h"
  18 #include "hw-ops.h"
  19 #include <linux/export.h>
  20 
  21 /* Common calibration code */
  22 
  23 
  24 static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
  25 {
  26         int16_t nfval;
  27         int16_t sort[ATH9K_NF_CAL_HIST_MAX];
  28         int i, j;
  29 
  30         for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++)
  31                 sort[i] = nfCalBuffer[i];
  32 
  33         for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) {
  34                 for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) {
  35                         if (sort[j] > sort[j - 1]) {
  36                                 nfval = sort[j];
  37                                 sort[j] = sort[j - 1];
  38                                 sort[j - 1] = nfval;
  39                         }
  40                 }
  41         }
  42         nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1];
  43 
  44         return nfval;
  45 }
  46 
  47 static struct ath_nf_limits *ath9k_hw_get_nf_limits(struct ath_hw *ah,
  48                                                     struct ath9k_channel *chan)
  49 {
  50         struct ath_nf_limits *limit;
  51 
  52         if (!chan || IS_CHAN_2GHZ(chan))
  53                 limit = &ah->nf_2g;
  54         else
  55                 limit = &ah->nf_5g;
  56 
  57         return limit;
  58 }
  59 
  60 static s16 ath9k_hw_get_default_nf(struct ath_hw *ah,
  61                                    struct ath9k_channel *chan,
  62                                    int chain)
  63 {
  64         s16 calib_nf = ath9k_hw_get_nf_limits(ah, chan)->cal[chain];
  65 
  66         if (calib_nf)
  67                 return calib_nf;
  68         else
  69                 return ath9k_hw_get_nf_limits(ah, chan)->nominal;
  70 }
  71 
  72 s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan,
  73                            s16 nf)
  74 {
  75         s8 noise = ATH_DEFAULT_NOISE_FLOOR;
  76 
  77         if (nf) {
  78                 s8 delta = nf - ATH9K_NF_CAL_NOISE_THRESH -
  79                            ath9k_hw_get_default_nf(ah, chan, 0);
  80                 if (delta > 0)
  81                         noise += delta;
  82         }
  83         return noise;
  84 }
  85 EXPORT_SYMBOL(ath9k_hw_getchan_noise);
  86 
  87 static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah,
  88                                               struct ath9k_hw_cal_data *cal,
  89                                               int16_t *nfarray)
  90 {
  91         struct ath_common *common = ath9k_hw_common(ah);
  92         struct ath_nf_limits *limit;
  93         struct ath9k_nfcal_hist *h;
  94         bool high_nf_mid = false;
  95         u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
  96         int i;
  97 
  98         h = cal->nfCalHist;
  99         limit = ath9k_hw_get_nf_limits(ah, ah->curchan);
 100 
 101         for (i = 0; i < NUM_NF_READINGS; i++) {
 102                 if (!(chainmask & (1 << i)) ||
 103                     ((i >= AR5416_MAX_CHAINS) && !IS_CHAN_HT40(ah->curchan)))
 104                         continue;
 105 
 106                 h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
 107 
 108                 if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX)
 109                         h[i].currIndex = 0;
 110 
 111                 if (h[i].invalidNFcount > 0) {
 112                         h[i].invalidNFcount--;
 113                         h[i].privNF = nfarray[i];
 114                 } else {
 115                         h[i].privNF =
 116                                 ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
 117                 }
 118 
 119                 if (!h[i].privNF)
 120                         continue;
 121 
 122                 if (h[i].privNF > limit->max) {
 123                         high_nf_mid = true;
 124 
 125                         ath_dbg(common, CALIBRATE,
 126                                 "NFmid[%d] (%d) > MAX (%d), %s\n",
 127                                 i, h[i].privNF, limit->max,
 128                                 (test_bit(NFCAL_INTF, &cal->cal_flags) ?
 129                                  "not corrected (due to interference)" :
 130                                  "correcting to MAX"));
 131 
 132                         /*
 133                          * Normally we limit the average noise floor by the
 134                          * hardware specific maximum here. However if we have
 135                          * encountered stuck beacons because of interference,
 136                          * we bypass this limit here in order to better deal
 137                          * with our environment.
 138                          */
 139                         if (!test_bit(NFCAL_INTF, &cal->cal_flags))
 140                                 h[i].privNF = limit->max;
 141                 }
 142         }
 143 
 144         /*
 145          * If the noise floor seems normal for all chains, assume that
 146          * there is no significant interference in the environment anymore.
 147          * Re-enable the enforcement of the NF maximum again.
 148          */
 149         if (!high_nf_mid)
 150                 clear_bit(NFCAL_INTF, &cal->cal_flags);
 151 }
 152 
 153 static bool ath9k_hw_get_nf_thresh(struct ath_hw *ah,
 154                                    enum nl80211_band band,
 155                                    int16_t *nft)
 156 {
 157         switch (band) {
 158         case NL80211_BAND_5GHZ:
 159                 *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_5);
 160                 break;
 161         case NL80211_BAND_2GHZ:
 162                 *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_2);
 163                 break;
 164         default:
 165                 BUG_ON(1);
 166                 return false;
 167         }
 168 
 169         return true;
 170 }
 171 
 172 void ath9k_hw_reset_calibration(struct ath_hw *ah,
 173                                 struct ath9k_cal_list *currCal)
 174 {
 175         int i;
 176 
 177         ath9k_hw_setup_calibration(ah, currCal);
 178 
 179         currCal->calState = CAL_RUNNING;
 180 
 181         for (i = 0; i < AR5416_MAX_CHAINS; i++) {
 182                 ah->meas0.sign[i] = 0;
 183                 ah->meas1.sign[i] = 0;
 184                 ah->meas2.sign[i] = 0;
 185                 ah->meas3.sign[i] = 0;
 186         }
 187 
 188         ah->cal_samples = 0;
 189 }
 190 
 191 /* This is done for the currently configured channel */
 192 bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
 193 {
 194         struct ath_common *common = ath9k_hw_common(ah);
 195         struct ath9k_cal_list *currCal = ah->cal_list_curr;
 196 
 197         if (!ah->caldata)
 198                 return true;
 199 
 200         if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
 201                 return true;
 202 
 203         if (currCal == NULL)
 204                 return true;
 205 
 206         if (currCal->calState != CAL_DONE) {
 207                 ath_dbg(common, CALIBRATE, "Calibration state incorrect, %d\n",
 208                         currCal->calState);
 209                 return true;
 210         }
 211 
 212         if (!(ah->supp_cals & currCal->calData->calType))
 213                 return true;
 214 
 215         ath_dbg(common, CALIBRATE, "Resetting Cal %d state for channel %u\n",
 216                 currCal->calData->calType, ah->curchan->chan->center_freq);
 217 
 218         ah->caldata->CalValid &= ~currCal->calData->calType;
 219         currCal->calState = CAL_WAITING;
 220 
 221         return false;
 222 }
 223 EXPORT_SYMBOL(ath9k_hw_reset_calvalid);
 224 
 225 void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update)
 226 {
 227         if (ah->caldata)
 228                 set_bit(NFCAL_PENDING, &ah->caldata->cal_flags);
 229 
 230         REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
 231                     AR_PHY_AGC_CONTROL_ENABLE_NF);
 232 
 233         if (update)
 234                 REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
 235                     AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
 236         else
 237                 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
 238                     AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
 239 
 240         REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
 241 }
 242 
 243 int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
 244 {
 245         struct ath9k_nfcal_hist *h = NULL;
 246         unsigned i, j;
 247         u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
 248         struct ath_common *common = ath9k_hw_common(ah);
 249         s16 default_nf = ath9k_hw_get_nf_limits(ah, chan)->nominal;
 250         u32 bb_agc_ctl = REG_READ(ah, AR_PHY_AGC_CONTROL);
 251 
 252         if (ah->caldata)
 253                 h = ah->caldata->nfCalHist;
 254 
 255         ENABLE_REG_RMW_BUFFER(ah);
 256         for (i = 0; i < NUM_NF_READINGS; i++) {
 257                 if (chainmask & (1 << i)) {
 258                         s16 nfval;
 259 
 260                         if ((i >= AR5416_MAX_CHAINS) && !IS_CHAN_HT40(chan))
 261                                 continue;
 262 
 263                         if (ah->nf_override)
 264                                 nfval = ah->nf_override;
 265                         else if (h)
 266                                 nfval = h[i].privNF;
 267                         else {
 268                                 /* Try to get calibrated noise floor value */
 269                                 nfval =
 270                                     ath9k_hw_get_nf_limits(ah, chan)->cal[i];
 271                                 if (nfval > -60 || nfval < -127)
 272                                         nfval = default_nf;
 273                         }
 274 
 275                         REG_RMW(ah, ah->nf_regs[i],
 276                                 (((u32) nfval << 1) & 0x1ff), 0x1ff);
 277                 }
 278         }
 279 
 280         /*
 281          * stop NF cal if ongoing to ensure NF load completes immediately
 282          * (or after end rx/tx frame if ongoing)
 283          */
 284         if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) {
 285                 REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
 286                 REG_RMW_BUFFER_FLUSH(ah);
 287                 ENABLE_REG_RMW_BUFFER(ah);
 288         }
 289 
 290         /*
 291          * Load software filtered NF value into baseband internal minCCApwr
 292          * variable.
 293          */
 294         REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
 295                     AR_PHY_AGC_CONTROL_ENABLE_NF);
 296         REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
 297                     AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
 298         REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
 299         REG_RMW_BUFFER_FLUSH(ah);
 300 
 301         /*
 302          * Wait for load to complete, should be fast, a few 10s of us.
 303          * The max delay was changed from an original 250us to 22.2 msec.
 304          * This would increase timeout to the longest possible frame
 305          * (11n max length 22.1 msec)
 306          */
 307         for (j = 0; j < 22200; j++) {
 308                 if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
 309                               AR_PHY_AGC_CONTROL_NF) == 0)
 310                         break;
 311                 udelay(10);
 312         }
 313 
 314         /*
 315          * Restart NF so it can continue.
 316          */
 317         if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) {
 318                 ENABLE_REG_RMW_BUFFER(ah);
 319                 if (bb_agc_ctl & AR_PHY_AGC_CONTROL_ENABLE_NF)
 320                         REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
 321                                     AR_PHY_AGC_CONTROL_ENABLE_NF);
 322                 if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NO_UPDATE_NF)
 323                         REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
 324                                     AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
 325                 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
 326                 REG_RMW_BUFFER_FLUSH(ah);
 327         }
 328 
 329         /*
 330          * We timed out waiting for the noisefloor to load, probably due to an
 331          * in-progress rx. Simply return here and allow the load plenty of time
 332          * to complete before the next calibration interval.  We need to avoid
 333          * trying to load -50 (which happens below) while the previous load is
 334          * still in progress as this can cause rx deafness. Instead by returning
 335          * here, the baseband nf cal will just be capped by our present
 336          * noisefloor until the next calibration timer.
 337          */
 338         if (j == 22200) {
 339                 ath_dbg(common, ANY,
 340                         "Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n",
 341                         REG_READ(ah, AR_PHY_AGC_CONTROL));
 342                 return -ETIMEDOUT;
 343         }
 344 
 345         /*
 346          * Restore maxCCAPower register parameter again so that we're not capped
 347          * by the median we just loaded.  This will be initial (and max) value
 348          * of next noise floor calibration the baseband does.
 349          */
 350         ENABLE_REG_RMW_BUFFER(ah);
 351         for (i = 0; i < NUM_NF_READINGS; i++) {
 352                 if (chainmask & (1 << i)) {
 353                         if ((i >= AR5416_MAX_CHAINS) && !IS_CHAN_HT40(chan))
 354                                 continue;
 355 
 356                         REG_RMW(ah, ah->nf_regs[i],
 357                                         (((u32) (-50) << 1) & 0x1ff), 0x1ff);
 358                 }
 359         }
 360         REG_RMW_BUFFER_FLUSH(ah);
 361 
 362         return 0;
 363 }
 364 EXPORT_SYMBOL(ath9k_hw_loadnf);
 365 
 366 
 367 static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
 368 {
 369         struct ath_common *common = ath9k_hw_common(ah);
 370         struct ath_nf_limits *limit;
 371         int i;
 372 
 373         if (IS_CHAN_2GHZ(ah->curchan))
 374                 limit = &ah->nf_2g;
 375         else
 376                 limit = &ah->nf_5g;
 377 
 378         for (i = 0; i < NUM_NF_READINGS; i++) {
 379                 if (!nf[i])
 380                         continue;
 381 
 382                 ath_dbg(common, CALIBRATE,
 383                         "NF calibrated [%s] [chain %d] is %d\n",
 384                         (i >= 3 ? "ext" : "ctl"), i % 3, nf[i]);
 385 
 386                 if (nf[i] > limit->max) {
 387                         ath_dbg(common, CALIBRATE,
 388                                 "NF[%d] (%d) > MAX (%d), correcting to MAX\n",
 389                                 i, nf[i], limit->max);
 390                         nf[i] = limit->max;
 391                 } else if (nf[i] < limit->min) {
 392                         ath_dbg(common, CALIBRATE,
 393                                 "NF[%d] (%d) < MIN (%d), correcting to NOM\n",
 394                                 i, nf[i], limit->min);
 395                         nf[i] = limit->nominal;
 396                 }
 397         }
 398 }
 399 
 400 bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
 401 {
 402         struct ath_common *common = ath9k_hw_common(ah);
 403         int16_t nf, nfThresh;
 404         int16_t nfarray[NUM_NF_READINGS] = { 0 };
 405         struct ath9k_nfcal_hist *h;
 406         struct ieee80211_channel *c = chan->chan;
 407         struct ath9k_hw_cal_data *caldata = ah->caldata;
 408 
 409         if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
 410                 ath_dbg(common, CALIBRATE,
 411                         "NF did not complete in calibration window\n");
 412                 return false;
 413         }
 414 
 415         ath9k_hw_do_getnf(ah, nfarray);
 416         ath9k_hw_nf_sanitize(ah, nfarray);
 417         nf = nfarray[0];
 418         if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh)
 419             && nf > nfThresh) {
 420                 ath_dbg(common, CALIBRATE,
 421                         "noise floor failed detected; detected %d, threshold %d\n",
 422                         nf, nfThresh);
 423         }
 424 
 425         if (!caldata) {
 426                 chan->noisefloor = nf;
 427                 return false;
 428         }
 429 
 430         h = caldata->nfCalHist;
 431         clear_bit(NFCAL_PENDING, &caldata->cal_flags);
 432         ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray);
 433         chan->noisefloor = h[0].privNF;
 434         ah->noise = ath9k_hw_getchan_noise(ah, chan, chan->noisefloor);
 435         return true;
 436 }
 437 EXPORT_SYMBOL(ath9k_hw_getnf);
 438 
 439 void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
 440                                   struct ath9k_channel *chan)
 441 {
 442         struct ath9k_nfcal_hist *h;
 443         int i, j, k = 0;
 444 
 445         ah->caldata->channel = chan->channel;
 446         ah->caldata->channelFlags = chan->channelFlags;
 447         h = ah->caldata->nfCalHist;
 448         for (i = 0; i < NUM_NF_READINGS; i++) {
 449                 h[i].currIndex = 0;
 450                 h[i].privNF = ath9k_hw_get_default_nf(ah, chan, k);
 451                 h[i].invalidNFcount = AR_PHY_CCA_FILTERWINDOW_LENGTH;
 452                 for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++)
 453                         h[i].nfCalBuffer[j] = h[i].privNF;
 454                 if (++k >= AR5416_MAX_CHAINS)
 455                         k = 0;
 456         }
 457 }
 458 
 459 
 460 void ath9k_hw_bstuck_nfcal(struct ath_hw *ah)
 461 {
 462         struct ath9k_hw_cal_data *caldata = ah->caldata;
 463 
 464         if (unlikely(!caldata))
 465                 return;
 466 
 467         /*
 468          * If beacons are stuck, the most likely cause is interference.
 469          * Triggering a noise floor calibration at this point helps the
 470          * hardware adapt to a noisy environment much faster.
 471          * To ensure that we recover from stuck beacons quickly, let
 472          * the baseband update the internal NF value itself, similar to
 473          * what is being done after a full reset.
 474          */
 475         if (!test_bit(NFCAL_PENDING, &caldata->cal_flags))
 476                 ath9k_hw_start_nfcal(ah, true);
 477         else if (!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF))
 478                 ath9k_hw_getnf(ah, ah->curchan);
 479 
 480         set_bit(NFCAL_INTF, &caldata->cal_flags);
 481 }
 482 EXPORT_SYMBOL(ath9k_hw_bstuck_nfcal);
 483 

/* [<][>][^][v][top][bottom][index][help] */