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