0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include "hw.h"
0018 #include "hw-ops.h"
0019 #include <linux/export.h>
0020
0021
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
0134
0135
0136
0137
0138
0139 if (!test_bit(NFCAL_INTF, &cal->cal_flags))
0140 h[i].privNF = limit->max;
0141 }
0142 }
0143
0144
0145
0146
0147
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
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
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
0286
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
0296
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
0307
0308
0309
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
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
0335
0336
0337
0338
0339
0340
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
0351
0352
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
0473
0474
0475
0476
0477
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