1 /* 2 * Copyright (c) 2008-2009 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 20 /* Common calibration code */ 21 22 #define ATH9K_NF_TOO_HIGH -60 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 { 63 return ath9k_hw_get_nf_limits(ah, chan)->nominal; 64 } 65 66 67 static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah, 68 struct ath9k_hw_cal_data *cal, 69 int16_t *nfarray) 70 { 71 struct ath_common *common = ath9k_hw_common(ah); 72 struct ath_nf_limits *limit; 73 struct ath9k_nfcal_hist *h; 74 bool high_nf_mid = false; 75 int i; 76 77 h = cal->nfCalHist; 78 limit = ath9k_hw_get_nf_limits(ah, ah->curchan); 79 80 for (i = 0; i < NUM_NF_READINGS; i++) { 81 h[i].nfCalBuffer[h[i].currIndex] = nfarray[i]; 82 83 if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX) 84 h[i].currIndex = 0; 85 86 if (h[i].invalidNFcount > 0) { 87 h[i].invalidNFcount--; 88 h[i].privNF = nfarray[i]; 89 } else { 90 h[i].privNF = 91 ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer); 92 } 93 94 if (!h[i].privNF) 95 continue; 96 97 if (h[i].privNF > limit->max) { 98 high_nf_mid = true; 99 100 ath_dbg(common, ATH_DBG_CALIBRATE, 101 "NFmid[%d] (%d) > MAX (%d), %s\n", 102 i, h[i].privNF, limit->max, 103 (cal->nfcal_interference ? 104 "not corrected (due to interference)" : 105 "correcting to MAX")); 106 107 /* 108 * Normally we limit the average noise floor by the 109 * hardware specific maximum here. However if we have 110 * encountered stuck beacons because of interference, 111 * we bypass this limit here in order to better deal 112 * with our environment. 113 */ 114 if (!cal->nfcal_interference) 115 h[i].privNF = limit->max; 116 } 117 } 118 119 /* 120 * If the noise floor seems normal for all chains, assume that 121 * there is no significant interference in the environment anymore. 122 * Re-enable the enforcement of the NF maximum again. 123 */ 124 if (!high_nf_mid) 125 cal->nfcal_interference = false; 126 } 127 128 static bool ath9k_hw_get_nf_thresh(struct ath_hw *ah, 129 enum ieee80211_band band, 130 int16_t *nft) 131 { 132 switch (band) { 133 case IEEE80211_BAND_5GHZ: 134 *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_5); 135 break; 136 case IEEE80211_BAND_2GHZ: 137 *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_2); 138 break; 139 default: 140 BUG_ON(1); 141 return false; 142 } 143 144 return true; 145 } 146 147 void ath9k_hw_reset_calibration(struct ath_hw *ah, 148 struct ath9k_cal_list *currCal) 149 { 150 int i; 151 152 ath9k_hw_setup_calibration(ah, currCal); 153 154 currCal->calState = CAL_RUNNING; 155 156 for (i = 0; i < AR5416_MAX_CHAINS; i++) { 157 ah->meas0.sign[i] = 0; 158 ah->meas1.sign[i] = 0; 159 ah->meas2.sign[i] = 0; 160 ah->meas3.sign[i] = 0; 161 } 162 163 ah->cal_samples = 0; 164 } 165 166 /* This is done for the currently configured channel */ 167 bool ath9k_hw_reset_calvalid(struct ath_hw *ah) 168 { 169 struct ath_common *common = ath9k_hw_common(ah); 170 struct ieee80211_conf *conf = &common->hw->conf; 171 struct ath9k_cal_list *currCal = ah->cal_list_curr; 172 173 if (!ah->caldata) 174 return true; 175 176 if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah)) 177 return true; 178 179 if (currCal == NULL) 180 return true; 181 182 if (currCal->calState != CAL_DONE) { 183 ath_dbg(common, ATH_DBG_CALIBRATE, 184 "Calibration state incorrect, %d\n", 185 currCal->calState); 186 return true; 187 } 188 189 if (!(ah->supp_cals & currCal->calData->calType)) 190 return true; 191 192 ath_dbg(common, ATH_DBG_CALIBRATE, 193 "Resetting Cal %d state for channel %u\n", 194 currCal->calData->calType, conf->channel->center_freq); 195 196 ah->caldata->CalValid &= ~currCal->calData->calType; 197 currCal->calState = CAL_WAITING; 198 199 return false; 200 } 201 EXPORT_SYMBOL(ath9k_hw_reset_calvalid); 202 203 void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update) 204 { 205 if (ah->caldata) 206 ah->caldata->nfcal_pending = true; 207 208 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, 209 AR_PHY_AGC_CONTROL_ENABLE_NF); 210 211 if (update) 212 REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, 213 AR_PHY_AGC_CONTROL_NO_UPDATE_NF); 214 else 215 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, 216 AR_PHY_AGC_CONTROL_NO_UPDATE_NF); 217 218 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); 219 } 220 221 void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) 222 { 223 struct ath9k_nfcal_hist *h = NULL; 224 unsigned i, j; 225 int32_t val; 226 u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask; 227 struct ath_common *common = ath9k_hw_common(ah); 228 s16 default_nf = ath9k_hw_get_default_nf(ah, chan); 229 230 if (ah->caldata) 231 h = ah->caldata->nfCalHist; 232 233 for (i = 0; i < NUM_NF_READINGS; i++) { 234 if (chainmask & (1 << i)) { 235 s16 nfval; 236 237 if (h) 238 nfval = h[i].privNF; 239 else 240 nfval = default_nf; 241 242 val = REG_READ(ah, ah->nf_regs[i]); 243 val &= 0xFFFFFE00; 244 val |= (((u32) nfval << 1) & 0x1ff); 245 REG_WRITE(ah, ah->nf_regs[i], val); 246 } 247 } 248 249 /* 250 * Load software filtered NF value into baseband internal minCCApwr 251 * variable. 252 */ 253 REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, 254 AR_PHY_AGC_CONTROL_ENABLE_NF); 255 REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, 256 AR_PHY_AGC_CONTROL_NO_UPDATE_NF); 257 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); 258 259 /* 260 * Wait for load to complete, should be fast, a few 10s of us. 261 * The max delay was changed from an original 250us to 10000us 262 * since 250us often results in NF load timeout and causes deaf 263 * condition during stress testing 12/12/2009 264 */ 265 for (j = 0; j < 1000; j++) { 266 if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & 267 AR_PHY_AGC_CONTROL_NF) == 0) 268 break; 269 udelay(10); 270 } 271 272 /* 273 * We timed out waiting for the noisefloor to load, probably due to an 274 * in-progress rx. Simply return here and allow the load plenty of time 275 * to complete before the next calibration interval. We need to avoid 276 * trying to load -50 (which happens below) while the previous load is 277 * still in progress as this can cause rx deafness. Instead by returning 278 * here, the baseband nf cal will just be capped by our present 279 * noisefloor until the next calibration timer. 280 */ 281 if (j == 1000) { 282 ath_dbg(common, ATH_DBG_ANY, 283 "Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n", 284 REG_READ(ah, AR_PHY_AGC_CONTROL)); 285 return; 286 } 287 288 /* 289 * Restore maxCCAPower register parameter again so that we're not capped 290 * by the median we just loaded. This will be initial (and max) value 291 * of next noise floor calibration the baseband does. 292 */ 293 ENABLE_REGWRITE_BUFFER(ah); 294 for (i = 0; i < NUM_NF_READINGS; i++) { 295 if (chainmask & (1 << i)) { 296 val = REG_READ(ah, ah->nf_regs[i]); 297 val &= 0xFFFFFE00; 298 val |= (((u32) (-50) << 1) & 0x1ff); 299 REG_WRITE(ah, ah->nf_regs[i], val); 300 } 301 } 302 REGWRITE_BUFFER_FLUSH(ah); 303 } 304 305 306 static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf) 307 { 308 struct ath_common *common = ath9k_hw_common(ah); 309 struct ath_nf_limits *limit; 310 int i; 311 312 if (IS_CHAN_2GHZ(ah->curchan)) 313 limit = &ah->nf_2g; 314 else 315 limit = &ah->nf_5g; 316 317 for (i = 0; i < NUM_NF_READINGS; i++) { 318 if (!nf[i]) 319 continue; 320 321 ath_dbg(common, ATH_DBG_CALIBRATE, 322 "NF calibrated [%s] [chain %d] is %d\n", 323 (i >= 3 ? "ext" : "ctl"), i % 3, nf[i]); 324 325 if (nf[i] > ATH9K_NF_TOO_HIGH) { 326 ath_dbg(common, ATH_DBG_CALIBRATE, 327 "NF[%d] (%d) > MAX (%d), correcting to MAX\n", 328 i, nf[i], ATH9K_NF_TOO_HIGH); 329 nf[i] = limit->max; 330 } else if (nf[i] < limit->min) { 331 ath_dbg(common, ATH_DBG_CALIBRATE, 332 "NF[%d] (%d) < MIN (%d), correcting to NOM\n", 333 i, nf[i], limit->min); 334 nf[i] = limit->nominal; 335 } 336 } 337 } 338 339 bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan) 340 { 341 struct ath_common *common = ath9k_hw_common(ah); 342 int16_t nf, nfThresh; 343 int16_t nfarray[NUM_NF_READINGS] = { 0 }; 344 struct ath9k_nfcal_hist *h; 345 struct ieee80211_channel *c = chan->chan; 346 struct ath9k_hw_cal_data *caldata = ah->caldata; 347 348 chan->channelFlags &= (~CHANNEL_CW_INT); 349 if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { 350 ath_dbg(common, ATH_DBG_CALIBRATE, 351 "NF did not complete in calibration window\n"); 352 return false; 353 } 354 355 ath9k_hw_do_getnf(ah, nfarray); 356 ath9k_hw_nf_sanitize(ah, nfarray); 357 nf = nfarray[0]; 358 if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh) 359 && nf > nfThresh) { 360 ath_dbg(common, ATH_DBG_CALIBRATE, 361 "noise floor failed detected; detected %d, threshold %d\n", 362 nf, nfThresh); 363 chan->channelFlags |= CHANNEL_CW_INT; 364 } 365 366 if (!caldata) { 367 chan->noisefloor = nf; 368 return false; 369 } 370 371 h = caldata->nfCalHist; 372 caldata->nfcal_pending = false; 373 ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray); 374 chan->noisefloor = h[0].privNF; 375 return true; 376 } 377 378 void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, 379 struct ath9k_channel *chan) 380 { 381 struct ath9k_nfcal_hist *h; 382 s16 default_nf; 383 int i, j; 384 385 if (!ah->caldata) 386 return; 387 388 h = ah->caldata->nfCalHist; 389 default_nf = ath9k_hw_get_default_nf(ah, chan); 390 for (i = 0; i < NUM_NF_READINGS; i++) { 391 h[i].currIndex = 0; 392 h[i].privNF = default_nf; 393 h[i].invalidNFcount = AR_PHY_CCA_FILTERWINDOW_LENGTH; 394 for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { 395 h[i].nfCalBuffer[j] = default_nf; 396 } 397 } 398 } 399 400 s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) 401 { 402 if (!ah->curchan || !ah->curchan->noisefloor) 403 return ath9k_hw_get_default_nf(ah, chan); 404 405 return ah->curchan->noisefloor; 406 } 407 EXPORT_SYMBOL(ath9k_hw_getchan_noise); 408 409 void ath9k_hw_bstuck_nfcal(struct ath_hw *ah) 410 { 411 struct ath9k_hw_cal_data *caldata = ah->caldata; 412 413 if (unlikely(!caldata)) 414 return; 415 416 /* 417 * If beacons are stuck, the most likely cause is interference. 418 * Triggering a noise floor calibration at this point helps the 419 * hardware adapt to a noisy environment much faster. 420 * To ensure that we recover from stuck beacons quickly, let 421 * the baseband update the internal NF value itself, similar to 422 * what is being done after a full reset. 423 */ 424 if (!caldata->nfcal_pending) 425 ath9k_hw_start_nfcal(ah, true); 426 else if (!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF)) 427 ath9k_hw_getnf(ah, ah->curchan); 428 429 caldata->nfcal_interference = true; 430 } 431 EXPORT_SYMBOL(ath9k_hw_bstuck_nfcal); 432 433