aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/calib.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/calib.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.c211
1 files changed, 142 insertions, 69 deletions
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index 45208690c0ec..a1250c586e40 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2008-2009 Atheros Communications Inc. 2 * Copyright (c) 2008-2011 Atheros Communications Inc.
3 * 3 *
4 * Permission to use, copy, modify, and/or distribute this software for any 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 5 * purpose with or without fee is hereby granted, provided that the above
@@ -19,8 +19,7 @@
19 19
20/* Common calibration code */ 20/* Common calibration code */
21 21
22/* We can tune this as we go by monitoring really low values */ 22#define ATH9K_NF_TOO_HIGH -60
23#define ATH9K_NF_TOO_LOW -60
24 23
25static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer) 24static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
26{ 25{
@@ -45,12 +44,46 @@ static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
45 return nfval; 44 return nfval;
46} 45}
47 46
48static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h, 47static 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
60static 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
67static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah,
68 struct ath9k_hw_cal_data *cal,
49 int16_t *nfarray) 69 int16_t *nfarray)
50{ 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;
51 int i; 77 int i;
52 78
79 h = cal->nfCalHist;
80 limit = ath9k_hw_get_nf_limits(ah, ah->curchan);
81
53 for (i = 0; i < NUM_NF_READINGS; i++) { 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
54 h[i].nfCalBuffer[h[i].currIndex] = nfarray[i]; 87 h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
55 88
56 if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX) 89 if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX)
@@ -63,7 +96,39 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
63 h[i].privNF = 96 h[i].privNF =
64 ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer); 97 ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
65 } 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 }
66 } 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;
67} 132}
68 133
69static bool ath9k_hw_get_nf_thresh(struct ath_hw *ah, 134static bool ath9k_hw_get_nf_thresh(struct ath_hw *ah,
@@ -104,19 +169,6 @@ void ath9k_hw_reset_calibration(struct ath_hw *ah,
104 ah->cal_samples = 0; 169 ah->cal_samples = 0;
105} 170}
106 171
107static s16 ath9k_hw_get_default_nf(struct ath_hw *ah,
108 struct ath9k_channel *chan)
109{
110 struct ath_nf_limits *limit;
111
112 if (!chan || IS_CHAN_2GHZ(chan))
113 limit = &ah->nf_2g;
114 else
115 limit = &ah->nf_5g;
116
117 return limit->nominal;
118}
119
120/* This is done for the currently configured channel */ 172/* This is done for the currently configured channel */
121bool ath9k_hw_reset_calvalid(struct ath_hw *ah) 173bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
122{ 174{
@@ -134,18 +186,18 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
134 return true; 186 return true;
135 187
136 if (currCal->calState != CAL_DONE) { 188 if (currCal->calState != CAL_DONE) {
137 ath_print(common, ATH_DBG_CALIBRATE, 189 ath_dbg(common, ATH_DBG_CALIBRATE,
138 "Calibration state incorrect, %d\n", 190 "Calibration state incorrect, %d\n",
139 currCal->calState); 191 currCal->calState);
140 return true; 192 return true;
141 } 193 }
142 194
143 if (!ath9k_hw_iscal_supported(ah, currCal->calData->calType)) 195 if (!(ah->supp_cals & currCal->calData->calType))
144 return true; 196 return true;
145 197
146 ath_print(common, ATH_DBG_CALIBRATE, 198 ath_dbg(common, ATH_DBG_CALIBRATE,
147 "Resetting Cal %d state for channel %u\n", 199 "Resetting Cal %d state for channel %u\n",
148 currCal->calData->calType, conf->channel->center_freq); 200 currCal->calData->calType, conf->channel->center_freq);
149 201
150 ah->caldata->CalValid &= ~currCal->calData->calType; 202 ah->caldata->CalValid &= ~currCal->calData->calType;
151 currCal->calState = CAL_WAITING; 203 currCal->calState = CAL_WAITING;
@@ -179,6 +231,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
179 int32_t val; 231 int32_t val;
180 u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask; 232 u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
181 struct ath_common *common = ath9k_hw_common(ah); 233 struct ath_common *common = ath9k_hw_common(ah);
234 struct ieee80211_conf *conf = &common->hw->conf;
182 s16 default_nf = ath9k_hw_get_default_nf(ah, chan); 235 s16 default_nf = ath9k_hw_get_default_nf(ah, chan);
183 236
184 if (ah->caldata) 237 if (ah->caldata)
@@ -188,6 +241,9 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
188 if (chainmask & (1 << i)) { 241 if (chainmask & (1 << i)) {
189 s16 nfval; 242 s16 nfval;
190 243
244 if ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf))
245 continue;
246
191 if (h) 247 if (h)
192 nfval = h[i].privNF; 248 nfval = h[i].privNF;
193 else 249 else
@@ -216,7 +272,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
216 * since 250us often results in NF load timeout and causes deaf 272 * since 250us often results in NF load timeout and causes deaf
217 * condition during stress testing 12/12/2009 273 * condition during stress testing 12/12/2009
218 */ 274 */
219 for (j = 0; j < 1000; j++) { 275 for (j = 0; j < 10000; j++) {
220 if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & 276 if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
221 AR_PHY_AGC_CONTROL_NF) == 0) 277 AR_PHY_AGC_CONTROL_NF) == 0)
222 break; 278 break;
@@ -232,10 +288,10 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
232 * here, the baseband nf cal will just be capped by our present 288 * here, the baseband nf cal will just be capped by our present
233 * noisefloor until the next calibration timer. 289 * noisefloor until the next calibration timer.
234 */ 290 */
235 if (j == 1000) { 291 if (j == 10000) {
236 ath_print(common, ATH_DBG_ANY, "Timeout while waiting for nf " 292 ath_dbg(common, ATH_DBG_ANY,
237 "to load: AR_PHY_AGC_CONTROL=0x%x\n", 293 "Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n",
238 REG_READ(ah, AR_PHY_AGC_CONTROL)); 294 REG_READ(ah, AR_PHY_AGC_CONTROL));
239 return; 295 return;
240 } 296 }
241 297
@@ -247,6 +303,9 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
247 ENABLE_REGWRITE_BUFFER(ah); 303 ENABLE_REGWRITE_BUFFER(ah);
248 for (i = 0; i < NUM_NF_READINGS; i++) { 304 for (i = 0; i < NUM_NF_READINGS; i++) {
249 if (chainmask & (1 << i)) { 305 if (chainmask & (1 << i)) {
306 if ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf))
307 continue;
308
250 val = REG_READ(ah, ah->nf_regs[i]); 309 val = REG_READ(ah, ah->nf_regs[i]);
251 val &= 0xFFFFFE00; 310 val &= 0xFFFFFE00;
252 val |= (((u32) (-50) << 1) & 0x1ff); 311 val |= (((u32) (-50) << 1) & 0x1ff);
@@ -254,7 +313,6 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
254 } 313 }
255 } 314 }
256 REGWRITE_BUFFER_FLUSH(ah); 315 REGWRITE_BUFFER_FLUSH(ah);
257 DISABLE_REGWRITE_BUFFER(ah);
258} 316}
259 317
260 318
@@ -273,19 +331,19 @@ static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
273 if (!nf[i]) 331 if (!nf[i])
274 continue; 332 continue;
275 333
276 ath_print(common, ATH_DBG_CALIBRATE, 334 ath_dbg(common, ATH_DBG_CALIBRATE,
277 "NF calibrated [%s] [chain %d] is %d\n", 335 "NF calibrated [%s] [chain %d] is %d\n",
278 (i >= 3 ? "ext" : "ctl"), i % 3, nf[i]); 336 (i >= 3 ? "ext" : "ctl"), i % 3, nf[i]);
279 337
280 if (nf[i] > limit->max) { 338 if (nf[i] > ATH9K_NF_TOO_HIGH) {
281 ath_print(common, ATH_DBG_CALIBRATE, 339 ath_dbg(common, ATH_DBG_CALIBRATE,
282 "NF[%d] (%d) > MAX (%d), correcting to MAX", 340 "NF[%d] (%d) > MAX (%d), correcting to MAX\n",
283 i, nf[i], limit->max); 341 i, nf[i], ATH9K_NF_TOO_HIGH);
284 nf[i] = limit->max; 342 nf[i] = limit->max;
285 } else if (nf[i] < limit->min) { 343 } else if (nf[i] < limit->min) {
286 ath_print(common, ATH_DBG_CALIBRATE, 344 ath_dbg(common, ATH_DBG_CALIBRATE,
287 "NF[%d] (%d) < MIN (%d), correcting to NOM", 345 "NF[%d] (%d) < MIN (%d), correcting to NOM\n",
288 i, nf[i], limit->min); 346 i, nf[i], limit->min);
289 nf[i] = limit->nominal; 347 nf[i] = limit->nominal;
290 } 348 }
291 } 349 }
@@ -300,34 +358,33 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
300 struct ieee80211_channel *c = chan->chan; 358 struct ieee80211_channel *c = chan->chan;
301 struct ath9k_hw_cal_data *caldata = ah->caldata; 359 struct ath9k_hw_cal_data *caldata = ah->caldata;
302 360
303 if (!caldata)
304 return false;
305
306 chan->channelFlags &= (~CHANNEL_CW_INT); 361 chan->channelFlags &= (~CHANNEL_CW_INT);
307 if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { 362 if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
308 ath_print(common, ATH_DBG_CALIBRATE, 363 ath_dbg(common, ATH_DBG_CALIBRATE,
309 "NF did not complete in calibration window\n"); 364 "NF did not complete in calibration window\n");
310 nf = 0; 365 return false;
311 caldata->rawNoiseFloor = nf; 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;
312 return false; 381 return false;
313 } else {
314 ath9k_hw_do_getnf(ah, nfarray);
315 ath9k_hw_nf_sanitize(ah, nfarray);
316 nf = nfarray[0];
317 if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh)
318 && nf > nfThresh) {
319 ath_print(common, ATH_DBG_CALIBRATE,
320 "noise floor failed detected; "
321 "detected %d, threshold %d\n",
322 nf, nfThresh);
323 chan->channelFlags |= CHANNEL_CW_INT;
324 }
325 } 382 }
326 383
327 h = caldata->nfCalHist; 384 h = caldata->nfCalHist;
328 caldata->nfcal_pending = false; 385 caldata->nfcal_pending = false;
329 ath9k_hw_update_nfcal_hist_buffer(h, nfarray); 386 ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray);
330 caldata->rawNoiseFloor = h[0].privNF; 387 chan->noisefloor = h[0].privNF;
331 return true; 388 return true;
332} 389}
333 390
@@ -338,9 +395,8 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
338 s16 default_nf; 395 s16 default_nf;
339 int i, j; 396 int i, j;
340 397
341 if (!ah->caldata) 398 ah->caldata->channel = chan->channel;
342 return; 399 ah->caldata->channelFlags = chan->channelFlags & ~CHANNEL_CW_INT;
343
344 h = ah->caldata->nfCalHist; 400 h = ah->caldata->nfCalHist;
345 default_nf = ath9k_hw_get_default_nf(ah, chan); 401 default_nf = ath9k_hw_get_default_nf(ah, chan);
346 for (i = 0; i < NUM_NF_READINGS; i++) { 402 for (i = 0; i < NUM_NF_READINGS; i++) {
@@ -353,11 +409,28 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
353 } 409 }
354} 410}
355 411
356s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) 412
413void ath9k_hw_bstuck_nfcal(struct ath_hw *ah)
357{ 414{
358 if (!ah->caldata || !ah->caldata->rawNoiseFloor) 415 struct ath9k_hw_cal_data *caldata = ah->caldata;
359 return ath9k_hw_get_default_nf(ah, chan); 416
417 if (unlikely(!caldata))
418 return;
360 419
361 return ah->caldata->rawNoiseFloor; 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;
362} 434}
363EXPORT_SYMBOL(ath9k_hw_getchan_noise); 435EXPORT_SYMBOL(ath9k_hw_bstuck_nfcal);
436