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