iPXE
ath9k_calib.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2008-2011 Atheros Communications Inc.
3 *
4 * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
5 * Original from Linux kernel 3.0.1
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20FILE_SECBOOT ( FORBIDDEN );
21
22#include "hw.h"
23#include "hw-ops.h"
24
25/* Common calibration code */
26
27#define ATH9K_NF_TOO_HIGH -60
28
30{
31 int16_t nfval;
33 int i, j;
34
35 for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++)
36 sort[i] = nfCalBuffer[i];
37
38 for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) {
39 for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) {
40 if (sort[j] > sort[j - 1]) {
41 nfval = sort[j];
42 sort[j] = sort[j - 1];
43 sort[j - 1] = nfval;
44 }
45 }
46 }
47 nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1];
48
49 return nfval;
50}
51
53 struct ath9k_channel *chan)
54{
55 struct ath_nf_limits *limit;
56
57 if (!chan || IS_CHAN_2GHZ(chan))
58 limit = &ah->nf_2g;
59 else
60 limit = &ah->nf_5g;
61
62 return limit;
63}
64
66 struct ath9k_channel *chan)
67{
68 return ath9k_hw_get_nf_limits(ah, chan)->nominal;
69}
70
71
73 struct ath9k_hw_cal_data *cal,
74 int16_t *nfarray)
75{
76 struct ath_nf_limits *limit;
77 struct ath9k_nfcal_hist *h;
78 int high_nf_mid = 0;
79 u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
80 int i;
81
82 h = cal->nfCalHist;
83 limit = ath9k_hw_get_nf_limits(ah, ah->curchan);
84
85 for (i = 0; i < NUM_NF_READINGS; i++) {
86 if (!(chainmask & (1 << i)) ||
87 (i >= AR5416_MAX_CHAINS))
88 continue;
89
90 h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
91
93 h[i].currIndex = 0;
94
95 if (h[i].invalidNFcount > 0) {
96 h[i].invalidNFcount--;
97 h[i].privNF = nfarray[i];
98 } else {
99 h[i].privNF =
101 }
102
103 if (!h[i].privNF)
104 continue;
105
106 if (h[i].privNF > limit->max) {
107 high_nf_mid = 1;
108
109 DBG2("ath9k: "
110 "NFmid[%d] (%d) > MAX (%d), %s\n",
111 i, h[i].privNF, limit->max,
112 (cal->nfcal_interference ?
113 "not corrected (due to interference)" :
114 "correcting to MAX"));
115
116 /*
117 * Normally we limit the average noise floor by the
118 * hardware specific maximum here. However if we have
119 * encountered stuck beacons because of interference,
120 * we bypass this limit here in order to better deal
121 * with our environment.
122 */
123 if (!cal->nfcal_interference)
124 h[i].privNF = limit->max;
125 }
126 }
127
128 /*
129 * If the noise floor seems normal for all chains, assume that
130 * there is no significant interference in the environment anymore.
131 * Re-enable the enforcement of the NF maximum again.
132 */
133 if (!high_nf_mid)
134 cal->nfcal_interference = 0;
135}
136
138 int band,
139 int16_t *nft)
140{
141 switch (band) {
143 *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_5);
144 break;
146 *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_2);
147 break;
148 default:
149 return 0;
150 }
151
152 return 1;
153}
154
156 struct ath9k_cal_list *currCal)
157{
158 int i;
159
161
162 currCal->calState = CAL_RUNNING;
163
164 for (i = 0; i < AR5416_MAX_CHAINS; i++) {
165 ah->meas0.sign[i] = 0;
166 ah->meas1.sign[i] = 0;
167 ah->meas2.sign[i] = 0;
168 ah->meas3.sign[i] = 0;
169 }
170
171 ah->cal_samples = 0;
172}
173
174/* This is done for the currently configured channel */
176{
177 struct ath9k_cal_list *currCal = ah->cal_list_curr;
178
179 if (!ah->caldata)
180 return 1;
181
183 return 1;
184
185 if (currCal == NULL)
186 return 1;
187
188 if (currCal->calState != CAL_DONE) {
189 DBG("ath9k: "
190 "Calibration state incorrect, %d\n",
191 currCal->calState);
192 return 1;
193 }
194
195 if (!(ah->supp_cals & currCal->calData->calType))
196 return 1;
197
198 DBG("ath9k: "
199 "Resetting Cal %d state for channel %d\n",
200 currCal->calData->calType, (ah->dev->channels + ah->dev->channel)->center_freq);
201
202 ah->caldata->CalValid &= ~currCal->calData->calType;
203 currCal->calState = CAL_WAITING;
204
205 return 0;
206}
207
208void ath9k_hw_start_nfcal(struct ath_hw *ah, int update)
209{
210 if (ah->caldata)
211 ah->caldata->nfcal_pending = 1;
212
215
216 if (update)
219 else
222
224}
225
226void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
227{
228 struct ath9k_nfcal_hist *h = NULL;
229 unsigned i, j;
230 int32_t val;
231 u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
232 s16 default_nf = ath9k_hw_get_default_nf(ah, chan);
233
234 if (ah->caldata)
235 h = ah->caldata->nfCalHist;
236
237 for (i = 0; i < NUM_NF_READINGS; i++) {
238 if (chainmask & (1 << i)) {
239 s16 nfval;
240
241 if (i >= AR5416_MAX_CHAINS)
242 continue;
243
244 if (h)
245 nfval = h[i].privNF;
246 else
247 nfval = default_nf;
248
249 val = REG_READ(ah, ah->nf_regs[i]);
250 val &= 0xFFFFFE00;
251 val |= (((u32) nfval << 1) & 0x1ff);
252 REG_WRITE(ah, ah->nf_regs[i], val);
253 }
254 }
255
256 /*
257 * Load software filtered NF value into baseband internal minCCApwr
258 * variable.
259 */
265
266 /*
267 * Wait for load to complete, should be fast, a few 10s of us.
268 * The max delay was changed from an original 250us to 10000us
269 * since 250us often results in NF load timeout and causes deaf
270 * condition during stress testing 12/12/2009
271 */
272 for (j = 0; j < 10000; j++) {
275 break;
276 udelay(10);
277 }
278
279 /*
280 * We timed out waiting for the noisefloor to load, probably due to an
281 * in-progress rx. Simply return here and allow the load plenty of time
282 * to complete before the next calibration interval. We need to avoid
283 * trying to load -50 (which happens below) while the previous load is
284 * still in progress as this can cause rx deafness. Instead by returning
285 * here, the baseband nf cal will just be capped by our present
286 * noisefloor until the next calibration timer.
287 */
288 if (j == 10000) {
289 DBG("ath9k: "
290 "Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n",
292 return;
293 }
294
295 /*
296 * Restore maxCCAPower register parameter again so that we're not capped
297 * by the median we just loaded. This will be initial (and max) value
298 * of next noise floor calibration the baseband does.
299 */
301 for (i = 0; i < NUM_NF_READINGS; i++) {
302 if (chainmask & (1 << i)) {
303 if (i >= AR5416_MAX_CHAINS)
304 continue;
305
306 val = REG_READ(ah, ah->nf_regs[i]);
307 val &= 0xFFFFFE00;
308 val |= (((u32) (-50) << 1) & 0x1ff);
309 REG_WRITE(ah, ah->nf_regs[i], val);
310 }
311 }
313}
314
315
316static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
317{
318 struct ath_nf_limits *limit;
319 int i;
320
321 if (IS_CHAN_2GHZ(ah->curchan))
322 limit = &ah->nf_2g;
323 else
324 limit = &ah->nf_5g;
325
326 for (i = 0; i < NUM_NF_READINGS; i++) {
327 if (!nf[i])
328 continue;
329
330 DBG2("ath9k: "
331 "NF calibrated [%s] [chain %d] is %d\n",
332 (i >= 3 ? "ext" : "ctl"), i % 3, nf[i]);
333
334 if (nf[i] > ATH9K_NF_TOO_HIGH) {
335 DBG("ath9k: "
336 "NF[%d] (%d) > MAX (%d), correcting to MAX\n",
337 i, nf[i], ATH9K_NF_TOO_HIGH);
338 nf[i] = limit->max;
339 } else if (nf[i] < limit->min) {
340 DBG("ath9k: "
341 "NF[%d] (%d) < MIN (%d), correcting to NOM\n",
342 i, nf[i], limit->min);
343 nf[i] = limit->nominal;
344 }
345 }
346}
347
348int ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
349{
350 int16_t nf, nfThresh;
351 int16_t nfarray[NUM_NF_READINGS] = { 0 };
352 struct ath9k_nfcal_hist *h;
353 struct net80211_channel *c = chan->chan;
354 struct ath9k_hw_cal_data *caldata = ah->caldata;
355
356 chan->channelFlags &= (~CHANNEL_CW_INT);
358 DBG("ath9k: "
359 "NF did not complete in calibration window\n");
360 return 0;
361 }
362
363 ath9k_hw_do_getnf(ah, nfarray);
364 ath9k_hw_nf_sanitize(ah, nfarray);
365 nf = nfarray[0];
366 if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh)
367 && nf > nfThresh) {
368 DBG2("ath9k: "
369 "noise floor failed detected; detected %d, threshold %d\n",
370 nf, nfThresh);
372 }
373
374 if (!caldata) {
375 chan->noisefloor = nf;
376 return 0;
377 }
378
379 h = caldata->nfCalHist;
380 caldata->nfcal_pending = 0;
381 ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray);
382 chan->noisefloor = h[0].privNF;
383 return 1;
384}
385
387 struct ath9k_channel *chan)
388{
389 struct ath9k_nfcal_hist *h;
390 s16 default_nf;
391 int i, j;
392
393 ah->caldata->channel = chan->channel;
394 ah->caldata->channelFlags = chan->channelFlags & ~CHANNEL_CW_INT;
395 h = ah->caldata->nfCalHist;
396 default_nf = ath9k_hw_get_default_nf(ah, chan);
397 for (i = 0; i < NUM_NF_READINGS; i++) {
398 h[i].currIndex = 0;
399 h[i].privNF = default_nf;
400 h[i].invalidNFcount = AR_PHY_CCA_FILTERWINDOW_LENGTH;
401 for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
402 h[i].nfCalBuffer[j] = default_nf;
403 }
404 }
405}
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
signed short int16_t
Definition stdint.h:16
signed int int32_t
Definition stdint.h:17
signed char int8_t
Definition stdint.h:15
#define CHANNEL_CW_INT
Definition ath5k.h:630
@ EEP_NFTHRESH_5
Definition eeprom.h:227
@ EEP_NFTHRESH_2
Definition eeprom.h:228
#define AR5416_MAX_CHAINS
Definition eeprom.h:160
#define AR_PHY_AGC_CONTROL_NF
Definition reg.h:1903
#define AR_SREV_9100(ah)
Definition reg.h:811
#define AR_PHY_AGC_CONTROL_ENABLE_NF
Definition reg.h:1905
#define AR_SREV_9160_10_OR_LATER(_ah)
Definition reg.h:818
#define AR_PHY_AGC_CONTROL_NO_UPDATE_NF
Definition reg.h:1907
#define AR_PHY_AGC_CONTROL
Definition reg.h:1901
static s16 ath9k_hw_get_default_nf(struct ath_hw *ah, struct ath9k_channel *chan)
Definition ath9k_calib.c:65
#define ATH9K_NF_TOO_HIGH
Definition ath9k_calib.c:27
void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
void ath9k_hw_start_nfcal(struct ath_hw *ah, int update)
void ath9k_hw_reset_calibration(struct ath_hw *ah, struct ath9k_cal_list *currCal)
int ath9k_hw_reset_calvalid(struct ath_hw *ah)
int ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah, struct ath9k_hw_cal_data *cal, int16_t *nfarray)
Definition ath9k_calib.c:72
static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
Definition ath9k_calib.c:29
static int ath9k_hw_get_nf_thresh(struct ath_hw *ah, int band, int16_t *nft)
static struct ath_nf_limits * ath9k_hw_get_nf_limits(struct ath_hw *ah, struct ath9k_channel *chan)
Definition ath9k_calib.c:52
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, struct ath9k_channel *chan)
@ CAL_DONE
Definition calib.h:71
@ CAL_RUNNING
Definition calib.h:70
@ CAL_WAITING
Definition calib.h:69
#define ATH9K_NF_CAL_HIST_MAX
Definition calib.h:32
#define NUM_NF_READINGS
Definition calib.h:31
#define AR_PHY_CCA_FILTERWINDOW_LENGTH
Definition calib.h:29
#define DBG2(...)
Definition compiler.h:515
#define DBG(...)
Print a debugging message.
Definition compiler.h:498
#define NET80211_BAND_2GHZ
The 2.4 GHz ISM band, unlicensed in most countries.
Definition net80211.h:45
#define NET80211_BAND_5GHZ
The band from 4.9 GHz to 5.7 GHz, which tends to be more restricted.
Definition net80211.h:47
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
static void ath9k_hw_setup_calibration(struct ath_hw *ah, struct ath9k_cal_list *currCal)
Definition hw-ops.h:265
static void ath9k_hw_do_getnf(struct ath_hw *ah, int16_t nfarray[NUM_NF_READINGS])
Definition hw-ops.h:253
#define REGWRITE_BUFFER_FLUSH(_ah)
Definition hw.h:96
#define REG_WRITE(_ah, _reg, _val)
Definition hw.h:78
#define REG_READ(_ah, _reg)
Definition hw.h:81
#define ENABLE_REGWRITE_BUFFER(_ah)
Definition hw.h:90
#define REG_CLR_BIT(_a, _r, _f)
Definition hw.h:110
#define IS_CHAN_2GHZ(_c)
Definition hw.h:362
#define REG_SET_BIT(_a, _r, _f)
Definition hw.h:108
#define u8
Definition igbvf_osdep.h:40
void __asmcall int val
Definition setjmp.h:12
int16_t s16
Definition stdint.h:21
uint16_t limit
Limit.
Definition librm.h:1
uint8_t h
Definition registers.h:4
uint8_t ah
Definition registers.h:1
enum ath9k_cal_state calState
Definition calib.h:90
const struct ath9k_percal_data * calData
Definition calib.h:89
u16 channel
Definition hw.h:350
struct net80211_channel * chan
Definition hw.h:348
s16 noisefloor
Definition hw.h:353
u32 channelFlags
Definition hw.h:351
int nfcal_interference
Definition hw.h:341
int nfcal_pending
Definition hw.h:340
struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]
Definition hw.h:344
u8 invalidNFcount
Definition calib.h:98
int16_t nfCalBuffer[ATH9K_NF_CAL_HIST_MAX]
Definition calib.h:95
int16_t privNF
Definition calib.h:97
Definition hw.h:657
s16 nominal
Definition hw.h:650
An 802.11 RF channel.
Definition net80211.h:386
u8 band
The band with which this channel is associated.
Definition net80211.h:388
void udelay(unsigned long usecs)
Delay for a fixed number of microseconds.
Definition timer.c:61
#define u32
Definition vga.h:21