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