diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath5k')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/ani.c | 744 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/ani.h | 104 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/ath5k.h | 68 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/attach.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/base.c | 129 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/base.h | 21 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/caps.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/debug.c | 170 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/debug.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/desc.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/desc.h | 35 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/pcu.c | 44 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/phy.c | 37 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/reg.h | 40 |
15 files changed, 1281 insertions, 123 deletions
diff --git a/drivers/net/wireless/ath/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile index 090dc6d268a3..cc09595b781a 100644 --- a/drivers/net/wireless/ath/ath5k/Makefile +++ b/drivers/net/wireless/ath/ath5k/Makefile | |||
@@ -12,5 +12,6 @@ ath5k-y += attach.o | |||
12 | ath5k-y += base.o | 12 | ath5k-y += base.o |
13 | ath5k-y += led.o | 13 | ath5k-y += led.o |
14 | ath5k-y += rfkill.o | 14 | ath5k-y += rfkill.o |
15 | ath5k-y += ani.o | ||
15 | ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o | 16 | ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o |
16 | obj-$(CONFIG_ATH5K) += ath5k.o | 17 | obj-$(CONFIG_ATH5K) += ath5k.o |
diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c new file mode 100644 index 000000000000..584a32859bdb --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/ani.c | |||
@@ -0,0 +1,744 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 Bruno Randolf <br1@einfach.org> | ||
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 "ath5k.h" | ||
18 | #include "base.h" | ||
19 | #include "reg.h" | ||
20 | #include "debug.h" | ||
21 | #include "ani.h" | ||
22 | |||
23 | /** | ||
24 | * DOC: Basic ANI Operation | ||
25 | * | ||
26 | * Adaptive Noise Immunity (ANI) controls five noise immunity parameters | ||
27 | * depending on the amount of interference in the environment, increasing | ||
28 | * or reducing sensitivity as necessary. | ||
29 | * | ||
30 | * The parameters are: | ||
31 | * - "noise immunity" | ||
32 | * - "spur immunity" | ||
33 | * - "firstep level" | ||
34 | * - "OFDM weak signal detection" | ||
35 | * - "CCK weak signal detection" | ||
36 | * | ||
37 | * Basically we look at the amount of ODFM and CCK timing errors we get and then | ||
38 | * raise or lower immunity accordingly by setting one or more of these | ||
39 | * parameters. | ||
40 | * Newer chipsets have PHY error counters in hardware which will generate a MIB | ||
41 | * interrupt when they overflow. Older hardware has too enable PHY error frames | ||
42 | * by setting a RX flag and then count every single PHY error. When a specified | ||
43 | * threshold of errors has been reached we will raise immunity. | ||
44 | * Also we regularly check the amount of errors and lower or raise immunity as | ||
45 | * necessary. | ||
46 | */ | ||
47 | |||
48 | |||
49 | /*** ANI parameter control ***/ | ||
50 | |||
51 | /** | ||
52 | * ath5k_ani_set_noise_immunity_level() - Set noise immunity level | ||
53 | * | ||
54 | * @level: level between 0 and @ATH5K_ANI_MAX_NOISE_IMM_LVL | ||
55 | */ | ||
56 | void | ||
57 | ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level) | ||
58 | { | ||
59 | /* TODO: | ||
60 | * ANI documents suggest the following five levels to use, but the HAL | ||
61 | * and ath9k use only use the last two levels, making this | ||
62 | * essentially an on/off option. There *may* be a reason for this (???), | ||
63 | * so i stick with the HAL version for now... | ||
64 | */ | ||
65 | #if 0 | ||
66 | const s8 hi[] = { -18, -18, -16, -14, -12 }; | ||
67 | const s8 lo[] = { -52, -56, -60, -64, -70 }; | ||
68 | const s8 sz[] = { -34, -41, -48, -55, -62 }; | ||
69 | const s8 fr[] = { -70, -72, -75, -78, -80 }; | ||
70 | #else | ||
71 | const s8 sz[] = { -55, -62 }; | ||
72 | const s8 lo[] = { -64, -70 }; | ||
73 | const s8 hi[] = { -14, -12 }; | ||
74 | const s8 fr[] = { -78, -80 }; | ||
75 | #endif | ||
76 | if (level < 0 || level > ARRAY_SIZE(sz)) { | ||
77 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, | ||
78 | "level out of range %d", level); | ||
79 | return; | ||
80 | } | ||
81 | |||
82 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE, | ||
83 | AR5K_PHY_DESIRED_SIZE_TOT, sz[level]); | ||
84 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_AGCCOARSE, | ||
85 | AR5K_PHY_AGCCOARSE_LO, lo[level]); | ||
86 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_AGCCOARSE, | ||
87 | AR5K_PHY_AGCCOARSE_HI, hi[level]); | ||
88 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SIG, | ||
89 | AR5K_PHY_SIG_FIRPWR, fr[level]); | ||
90 | |||
91 | ah->ah_sc->ani_state.noise_imm_level = level; | ||
92 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "new level %d", level); | ||
93 | } | ||
94 | |||
95 | |||
96 | /** | ||
97 | * ath5k_ani_set_spur_immunity_level() - Set spur immunity level | ||
98 | * | ||
99 | * @level: level between 0 and @max_spur_level (the maximum level is dependent | ||
100 | * on the chip revision). | ||
101 | */ | ||
102 | void | ||
103 | ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level) | ||
104 | { | ||
105 | const int val[] = { 2, 4, 6, 8, 10, 12, 14, 16 }; | ||
106 | |||
107 | if (level < 0 || level > ARRAY_SIZE(val) || | ||
108 | level > ah->ah_sc->ani_state.max_spur_level) { | ||
109 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, | ||
110 | "level out of range %d", level); | ||
111 | return; | ||
112 | } | ||
113 | |||
114 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR, | ||
115 | AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1, val[level]); | ||
116 | |||
117 | ah->ah_sc->ani_state.spur_level = level; | ||
118 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "new level %d", level); | ||
119 | } | ||
120 | |||
121 | |||
122 | /** | ||
123 | * ath5k_ani_set_firstep_level() - Set "firstep" level | ||
124 | * | ||
125 | * @level: level between 0 and @ATH5K_ANI_MAX_FIRSTEP_LVL | ||
126 | */ | ||
127 | void | ||
128 | ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level) | ||
129 | { | ||
130 | const int val[] = { 0, 4, 8 }; | ||
131 | |||
132 | if (level < 0 || level > ARRAY_SIZE(val)) { | ||
133 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, | ||
134 | "level out of range %d", level); | ||
135 | return; | ||
136 | } | ||
137 | |||
138 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SIG, | ||
139 | AR5K_PHY_SIG_FIRSTEP, val[level]); | ||
140 | |||
141 | ah->ah_sc->ani_state.firstep_level = level; | ||
142 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "new level %d", level); | ||
143 | } | ||
144 | |||
145 | |||
146 | /** | ||
147 | * ath5k_ani_set_ofdm_weak_signal_detection() - Control OFDM weak signal | ||
148 | * detection | ||
149 | * | ||
150 | * @on: turn on or off | ||
151 | */ | ||
152 | void | ||
153 | ath5k_ani_set_ofdm_weak_signal_detection(struct ath5k_hw *ah, bool on) | ||
154 | { | ||
155 | const int m1l[] = { 127, 50 }; | ||
156 | const int m2l[] = { 127, 40 }; | ||
157 | const int m1[] = { 127, 0x4d }; | ||
158 | const int m2[] = { 127, 0x40 }; | ||
159 | const int m2cnt[] = { 31, 16 }; | ||
160 | const int m2lcnt[] = { 63, 48 }; | ||
161 | |||
162 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR, | ||
163 | AR5K_PHY_WEAK_OFDM_LOW_THR_M1, m1l[on]); | ||
164 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR, | ||
165 | AR5K_PHY_WEAK_OFDM_LOW_THR_M2, m2l[on]); | ||
166 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_HIGH_THR, | ||
167 | AR5K_PHY_WEAK_OFDM_HIGH_THR_M1, m1[on]); | ||
168 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_HIGH_THR, | ||
169 | AR5K_PHY_WEAK_OFDM_HIGH_THR_M2, m2[on]); | ||
170 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_HIGH_THR, | ||
171 | AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT, m2cnt[on]); | ||
172 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR, | ||
173 | AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT, m2lcnt[on]); | ||
174 | |||
175 | if (on) | ||
176 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR, | ||
177 | AR5K_PHY_WEAK_OFDM_LOW_THR_SELFCOR_EN); | ||
178 | else | ||
179 | AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR, | ||
180 | AR5K_PHY_WEAK_OFDM_LOW_THR_SELFCOR_EN); | ||
181 | |||
182 | ah->ah_sc->ani_state.ofdm_weak_sig = on; | ||
183 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "turned %s", | ||
184 | on ? "on" : "off"); | ||
185 | } | ||
186 | |||
187 | |||
188 | /** | ||
189 | * ath5k_ani_set_cck_weak_signal_detection() - control CCK weak signal detection | ||
190 | * | ||
191 | * @on: turn on or off | ||
192 | */ | ||
193 | void | ||
194 | ath5k_ani_set_cck_weak_signal_detection(struct ath5k_hw *ah, bool on) | ||
195 | { | ||
196 | const int val[] = { 8, 6 }; | ||
197 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_CCK_CROSSCORR, | ||
198 | AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR, val[on]); | ||
199 | ah->ah_sc->ani_state.cck_weak_sig = on; | ||
200 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "turned %s", | ||
201 | on ? "on" : "off"); | ||
202 | } | ||
203 | |||
204 | |||
205 | /*** ANI algorithm ***/ | ||
206 | |||
207 | /** | ||
208 | * ath5k_ani_raise_immunity() - Increase noise immunity | ||
209 | * | ||
210 | * @ofdm_trigger: If this is true we are called because of too many OFDM errors, | ||
211 | * the algorithm will tune more parameters then. | ||
212 | * | ||
213 | * Try to raise noise immunity (=decrease sensitivity) in several steps | ||
214 | * depending on the average RSSI of the beacons we received. | ||
215 | */ | ||
216 | static void | ||
217 | ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as, | ||
218 | bool ofdm_trigger) | ||
219 | { | ||
220 | int rssi = ah->ah_beacon_rssi_avg.avg; | ||
221 | |||
222 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "raise immunity (%s)", | ||
223 | ofdm_trigger ? "ODFM" : "CCK"); | ||
224 | |||
225 | /* first: raise noise immunity */ | ||
226 | if (as->noise_imm_level < ATH5K_ANI_MAX_NOISE_IMM_LVL) { | ||
227 | ath5k_ani_set_noise_immunity_level(ah, as->noise_imm_level + 1); | ||
228 | return; | ||
229 | } | ||
230 | |||
231 | /* only OFDM: raise spur immunity level */ | ||
232 | if (ofdm_trigger && | ||
233 | as->spur_level < ah->ah_sc->ani_state.max_spur_level) { | ||
234 | ath5k_ani_set_spur_immunity_level(ah, as->spur_level + 1); | ||
235 | return; | ||
236 | } | ||
237 | |||
238 | /* AP mode */ | ||
239 | if (ah->ah_sc->opmode == NL80211_IFTYPE_AP) { | ||
240 | if (as->firstep_level < ATH5K_ANI_MAX_FIRSTEP_LVL) | ||
241 | ath5k_ani_set_firstep_level(ah, as->firstep_level + 1); | ||
242 | return; | ||
243 | } | ||
244 | |||
245 | /* STA and IBSS mode */ | ||
246 | |||
247 | /* TODO: for IBSS mode it would be better to keep a beacon RSSI average | ||
248 | * per each neighbour node and use the minimum of these, to make sure we | ||
249 | * don't shut out a remote node by raising immunity too high. */ | ||
250 | |||
251 | if (rssi > ATH5K_ANI_RSSI_THR_HIGH) { | ||
252 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, | ||
253 | "beacon RSSI high"); | ||
254 | /* only OFDM: beacon RSSI is high, we can disable ODFM weak | ||
255 | * signal detection */ | ||
256 | if (ofdm_trigger && as->ofdm_weak_sig == true) { | ||
257 | ath5k_ani_set_ofdm_weak_signal_detection(ah, false); | ||
258 | ath5k_ani_set_spur_immunity_level(ah, 0); | ||
259 | return; | ||
260 | } | ||
261 | /* as a last resort or CCK: raise firstep level */ | ||
262 | if (as->firstep_level < ATH5K_ANI_MAX_FIRSTEP_LVL) { | ||
263 | ath5k_ani_set_firstep_level(ah, as->firstep_level + 1); | ||
264 | return; | ||
265 | } | ||
266 | } else if (rssi > ATH5K_ANI_RSSI_THR_LOW) { | ||
267 | /* beacon RSSI in mid range, we need OFDM weak signal detect, | ||
268 | * but can raise firstep level */ | ||
269 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, | ||
270 | "beacon RSSI mid"); | ||
271 | if (ofdm_trigger && as->ofdm_weak_sig == false) | ||
272 | ath5k_ani_set_ofdm_weak_signal_detection(ah, true); | ||
273 | if (as->firstep_level < ATH5K_ANI_MAX_FIRSTEP_LVL) | ||
274 | ath5k_ani_set_firstep_level(ah, as->firstep_level + 1); | ||
275 | return; | ||
276 | } else if (ah->ah_current_channel->band == IEEE80211_BAND_2GHZ) { | ||
277 | /* beacon RSSI is low. in B/G mode turn of OFDM weak signal | ||
278 | * detect and zero firstep level to maximize CCK sensitivity */ | ||
279 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, | ||
280 | "beacon RSSI low, 2GHz"); | ||
281 | if (ofdm_trigger && as->ofdm_weak_sig == true) | ||
282 | ath5k_ani_set_ofdm_weak_signal_detection(ah, false); | ||
283 | if (as->firstep_level > 0) | ||
284 | ath5k_ani_set_firstep_level(ah, 0); | ||
285 | return; | ||
286 | } | ||
287 | |||
288 | /* TODO: why not?: | ||
289 | if (as->cck_weak_sig == true) { | ||
290 | ath5k_ani_set_cck_weak_signal_detection(ah, false); | ||
291 | } | ||
292 | */ | ||
293 | } | ||
294 | |||
295 | |||
296 | /** | ||
297 | * ath5k_ani_lower_immunity() - Decrease noise immunity | ||
298 | * | ||
299 | * Try to lower noise immunity (=increase sensitivity) in several steps | ||
300 | * depending on the average RSSI of the beacons we received. | ||
301 | */ | ||
302 | static void | ||
303 | ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as) | ||
304 | { | ||
305 | int rssi = ah->ah_beacon_rssi_avg.avg; | ||
306 | |||
307 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "lower immunity"); | ||
308 | |||
309 | if (ah->ah_sc->opmode == NL80211_IFTYPE_AP) { | ||
310 | /* AP mode */ | ||
311 | if (as->firstep_level > 0) { | ||
312 | ath5k_ani_set_firstep_level(ah, as->firstep_level - 1); | ||
313 | return; | ||
314 | } | ||
315 | } else { | ||
316 | /* STA and IBSS mode (see TODO above) */ | ||
317 | if (rssi > ATH5K_ANI_RSSI_THR_HIGH) { | ||
318 | /* beacon signal is high, leave OFDM weak signal | ||
319 | * detection off or it may oscillate | ||
320 | * TODO: who said it's off??? */ | ||
321 | } else if (rssi > ATH5K_ANI_RSSI_THR_LOW) { | ||
322 | /* beacon RSSI is mid-range: turn on ODFM weak signal | ||
323 | * detection and next, lower firstep level */ | ||
324 | if (as->ofdm_weak_sig == false) { | ||
325 | ath5k_ani_set_ofdm_weak_signal_detection(ah, | ||
326 | true); | ||
327 | return; | ||
328 | } | ||
329 | if (as->firstep_level > 0) { | ||
330 | ath5k_ani_set_firstep_level(ah, | ||
331 | as->firstep_level - 1); | ||
332 | return; | ||
333 | } | ||
334 | } else { | ||
335 | /* beacon signal is low: only reduce firstep level */ | ||
336 | if (as->firstep_level > 0) { | ||
337 | ath5k_ani_set_firstep_level(ah, | ||
338 | as->firstep_level - 1); | ||
339 | return; | ||
340 | } | ||
341 | } | ||
342 | } | ||
343 | |||
344 | /* all modes */ | ||
345 | if (as->spur_level > 0) { | ||
346 | ath5k_ani_set_spur_immunity_level(ah, as->spur_level - 1); | ||
347 | return; | ||
348 | } | ||
349 | |||
350 | /* finally, reduce noise immunity */ | ||
351 | if (as->noise_imm_level > 0) { | ||
352 | ath5k_ani_set_noise_immunity_level(ah, as->noise_imm_level - 1); | ||
353 | return; | ||
354 | } | ||
355 | } | ||
356 | |||
357 | |||
358 | /** | ||
359 | * ath5k_hw_ani_get_listen_time() - Calculate time spent listening | ||
360 | * | ||
361 | * Return an approximation of the time spent "listening" in milliseconds (ms) | ||
362 | * since the last call of this function by deducting the cycles spent | ||
363 | * transmitting and receiving from the total cycle count. | ||
364 | * Save profile count values for debugging/statistics and because we might want | ||
365 | * to use them later. | ||
366 | * | ||
367 | * We assume no one else clears these registers! | ||
368 | */ | ||
369 | static int | ||
370 | ath5k_hw_ani_get_listen_time(struct ath5k_hw *ah, struct ath5k_ani_state *as) | ||
371 | { | ||
372 | int listen; | ||
373 | |||
374 | /* freeze */ | ||
375 | ath5k_hw_reg_write(ah, AR5K_MIBC_FMC, AR5K_MIBC); | ||
376 | /* read */ | ||
377 | as->pfc_cycles = ath5k_hw_reg_read(ah, AR5K_PROFCNT_CYCLE); | ||
378 | as->pfc_busy = ath5k_hw_reg_read(ah, AR5K_PROFCNT_RXCLR); | ||
379 | as->pfc_tx = ath5k_hw_reg_read(ah, AR5K_PROFCNT_TX); | ||
380 | as->pfc_rx = ath5k_hw_reg_read(ah, AR5K_PROFCNT_RX); | ||
381 | /* clear */ | ||
382 | ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX); | ||
383 | ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX); | ||
384 | ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR); | ||
385 | ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE); | ||
386 | /* un-freeze */ | ||
387 | ath5k_hw_reg_write(ah, 0, AR5K_MIBC); | ||
388 | |||
389 | /* TODO: where does 44000 come from? (11g clock rate?) */ | ||
390 | listen = (as->pfc_cycles - as->pfc_rx - as->pfc_tx) / 44000; | ||
391 | |||
392 | if (as->pfc_cycles == 0 || listen < 0) | ||
393 | return 0; | ||
394 | return listen; | ||
395 | } | ||
396 | |||
397 | |||
398 | /** | ||
399 | * ath5k_ani_save_and_clear_phy_errors() - Clear and save PHY error counters | ||
400 | * | ||
401 | * Clear the PHY error counters as soon as possible, since this might be called | ||
402 | * from a MIB interrupt and we want to make sure we don't get interrupted again. | ||
403 | * Add the count of CCK and OFDM errors to our internal state, so it can be used | ||
404 | * by the algorithm later. | ||
405 | * | ||
406 | * Will be called from interrupt and tasklet context. | ||
407 | * Returns 0 if both counters are zero. | ||
408 | */ | ||
409 | static int | ||
410 | ath5k_ani_save_and_clear_phy_errors(struct ath5k_hw *ah, | ||
411 | struct ath5k_ani_state *as) | ||
412 | { | ||
413 | unsigned int ofdm_err, cck_err; | ||
414 | |||
415 | if (!ah->ah_capabilities.cap_has_phyerr_counters) | ||
416 | return 0; | ||
417 | |||
418 | ofdm_err = ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1); | ||
419 | cck_err = ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2); | ||
420 | |||
421 | /* reset counters first, we might be in a hurry (interrupt) */ | ||
422 | ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_OFDM_TRIG_HIGH, | ||
423 | AR5K_PHYERR_CNT1); | ||
424 | ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_CCK_TRIG_HIGH, | ||
425 | AR5K_PHYERR_CNT2); | ||
426 | |||
427 | ofdm_err = ATH5K_ANI_OFDM_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - ofdm_err); | ||
428 | cck_err = ATH5K_ANI_CCK_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - cck_err); | ||
429 | |||
430 | /* sometimes both can be zero, especially when there is a superfluous | ||
431 | * second interrupt. detect that here and return an error. */ | ||
432 | if (ofdm_err <= 0 && cck_err <= 0) | ||
433 | return 0; | ||
434 | |||
435 | /* avoid negative values should one of the registers overflow */ | ||
436 | if (ofdm_err > 0) { | ||
437 | as->ofdm_errors += ofdm_err; | ||
438 | as->sum_ofdm_errors += ofdm_err; | ||
439 | } | ||
440 | if (cck_err > 0) { | ||
441 | as->cck_errors += cck_err; | ||
442 | as->sum_cck_errors += cck_err; | ||
443 | } | ||
444 | return 1; | ||
445 | } | ||
446 | |||
447 | |||
448 | /** | ||
449 | * ath5k_ani_period_restart() - Restart ANI period | ||
450 | * | ||
451 | * Just reset counters, so they are clear for the next "ani period". | ||
452 | */ | ||
453 | static void | ||
454 | ath5k_ani_period_restart(struct ath5k_hw *ah, struct ath5k_ani_state *as) | ||
455 | { | ||
456 | /* keep last values for debugging */ | ||
457 | as->last_ofdm_errors = as->ofdm_errors; | ||
458 | as->last_cck_errors = as->cck_errors; | ||
459 | as->last_listen = as->listen_time; | ||
460 | |||
461 | as->ofdm_errors = 0; | ||
462 | as->cck_errors = 0; | ||
463 | as->listen_time = 0; | ||
464 | } | ||
465 | |||
466 | |||
467 | /** | ||
468 | * ath5k_ani_calibration() - The main ANI calibration function | ||
469 | * | ||
470 | * We count OFDM and CCK errors relative to the time where we did not send or | ||
471 | * receive ("listen" time) and raise or lower immunity accordingly. | ||
472 | * This is called regularly (every second) from the calibration timer, but also | ||
473 | * when an error threshold has been reached. | ||
474 | * | ||
475 | * In order to synchronize access from different contexts, this should be | ||
476 | * called only indirectly by scheduling the ANI tasklet! | ||
477 | */ | ||
478 | void | ||
479 | ath5k_ani_calibration(struct ath5k_hw *ah) | ||
480 | { | ||
481 | struct ath5k_ani_state *as = &ah->ah_sc->ani_state; | ||
482 | int listen, ofdm_high, ofdm_low, cck_high, cck_low; | ||
483 | |||
484 | if (as->ani_mode != ATH5K_ANI_MODE_AUTO) | ||
485 | return; | ||
486 | |||
487 | /* get listen time since last call and add it to the counter because we | ||
488 | * might not have restarted the "ani period" last time */ | ||
489 | listen = ath5k_hw_ani_get_listen_time(ah, as); | ||
490 | as->listen_time += listen; | ||
491 | |||
492 | ath5k_ani_save_and_clear_phy_errors(ah, as); | ||
493 | |||
494 | ofdm_high = as->listen_time * ATH5K_ANI_OFDM_TRIG_HIGH / 1000; | ||
495 | cck_high = as->listen_time * ATH5K_ANI_CCK_TRIG_HIGH / 1000; | ||
496 | ofdm_low = as->listen_time * ATH5K_ANI_OFDM_TRIG_LOW / 1000; | ||
497 | cck_low = as->listen_time * ATH5K_ANI_CCK_TRIG_LOW / 1000; | ||
498 | |||
499 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, | ||
500 | "listen %d (now %d)", as->listen_time, listen); | ||
501 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, | ||
502 | "check high ofdm %d/%d cck %d/%d", | ||
503 | as->ofdm_errors, ofdm_high, as->cck_errors, cck_high); | ||
504 | |||
505 | if (as->ofdm_errors > ofdm_high || as->cck_errors > cck_high) { | ||
506 | /* too many PHY errors - we have to raise immunity */ | ||
507 | bool ofdm_flag = as->ofdm_errors > ofdm_high ? true : false; | ||
508 | ath5k_ani_raise_immunity(ah, as, ofdm_flag); | ||
509 | ath5k_ani_period_restart(ah, as); | ||
510 | |||
511 | } else if (as->listen_time > 5 * ATH5K_ANI_LISTEN_PERIOD) { | ||
512 | /* If more than 5 (TODO: why 5?) periods have passed and we got | ||
513 | * relatively little errors we can try to lower immunity */ | ||
514 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, | ||
515 | "check low ofdm %d/%d cck %d/%d", | ||
516 | as->ofdm_errors, ofdm_low, as->cck_errors, cck_low); | ||
517 | |||
518 | if (as->ofdm_errors <= ofdm_low && as->cck_errors <= cck_low) | ||
519 | ath5k_ani_lower_immunity(ah, as); | ||
520 | |||
521 | ath5k_ani_period_restart(ah, as); | ||
522 | } | ||
523 | } | ||
524 | |||
525 | |||
526 | /*** INTERRUPT HANDLER ***/ | ||
527 | |||
528 | /** | ||
529 | * ath5k_ani_mib_intr() - Interrupt handler for ANI MIB counters | ||
530 | * | ||
531 | * Just read & reset the registers quickly, so they don't generate more | ||
532 | * interrupts, save the counters and schedule the tasklet to decide whether | ||
533 | * to raise immunity or not. | ||
534 | * | ||
535 | * We just need to handle PHY error counters, ath5k_hw_update_mib_counters() | ||
536 | * should take care of all "normal" MIB interrupts. | ||
537 | */ | ||
538 | void | ||
539 | ath5k_ani_mib_intr(struct ath5k_hw *ah) | ||
540 | { | ||
541 | struct ath5k_ani_state *as = &ah->ah_sc->ani_state; | ||
542 | |||
543 | /* nothing to do here if HW does not have PHY error counters - they | ||
544 | * can't be the reason for the MIB interrupt then */ | ||
545 | if (!ah->ah_capabilities.cap_has_phyerr_counters) | ||
546 | return; | ||
547 | |||
548 | /* not in use but clear anyways */ | ||
549 | ath5k_hw_reg_write(ah, 0, AR5K_OFDM_FIL_CNT); | ||
550 | ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT); | ||
551 | |||
552 | if (ah->ah_sc->ani_state.ani_mode != ATH5K_ANI_MODE_AUTO) | ||
553 | return; | ||
554 | |||
555 | /* if one of the errors triggered, we can get a superfluous second | ||
556 | * interrupt, even though we have already reset the register. the | ||
557 | * function detects that so we can return early */ | ||
558 | if (ath5k_ani_save_and_clear_phy_errors(ah, as) == 0) | ||
559 | return; | ||
560 | |||
561 | if (as->ofdm_errors > ATH5K_ANI_OFDM_TRIG_HIGH || | ||
562 | as->cck_errors > ATH5K_ANI_CCK_TRIG_HIGH) | ||
563 | tasklet_schedule(&ah->ah_sc->ani_tasklet); | ||
564 | } | ||
565 | |||
566 | |||
567 | /** | ||
568 | * ath5k_ani_phy_error_report() - Used by older HW to report PHY errors | ||
569 | * | ||
570 | * This is used by hardware without PHY error counters to report PHY errors | ||
571 | * on a frame-by-frame basis, instead of the interrupt. | ||
572 | */ | ||
573 | void | ||
574 | ath5k_ani_phy_error_report(struct ath5k_hw *ah, | ||
575 | enum ath5k_phy_error_code phyerr) | ||
576 | { | ||
577 | struct ath5k_ani_state *as = &ah->ah_sc->ani_state; | ||
578 | |||
579 | if (phyerr == AR5K_RX_PHY_ERROR_OFDM_TIMING) { | ||
580 | as->ofdm_errors++; | ||
581 | if (as->ofdm_errors > ATH5K_ANI_OFDM_TRIG_HIGH) | ||
582 | tasklet_schedule(&ah->ah_sc->ani_tasklet); | ||
583 | } else if (phyerr == AR5K_RX_PHY_ERROR_CCK_TIMING) { | ||
584 | as->cck_errors++; | ||
585 | if (as->cck_errors > ATH5K_ANI_CCK_TRIG_HIGH) | ||
586 | tasklet_schedule(&ah->ah_sc->ani_tasklet); | ||
587 | } | ||
588 | } | ||
589 | |||
590 | |||
591 | /*** INIT ***/ | ||
592 | |||
593 | /** | ||
594 | * ath5k_enable_phy_err_counters() - Enable PHY error counters | ||
595 | * | ||
596 | * Enable PHY error counters for OFDM and CCK timing errors. | ||
597 | */ | ||
598 | static void | ||
599 | ath5k_enable_phy_err_counters(struct ath5k_hw *ah) | ||
600 | { | ||
601 | ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_OFDM_TRIG_HIGH, | ||
602 | AR5K_PHYERR_CNT1); | ||
603 | ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_CCK_TRIG_HIGH, | ||
604 | AR5K_PHYERR_CNT2); | ||
605 | ath5k_hw_reg_write(ah, AR5K_PHY_ERR_FIL_OFDM, AR5K_PHYERR_CNT1_MASK); | ||
606 | ath5k_hw_reg_write(ah, AR5K_PHY_ERR_FIL_CCK, AR5K_PHYERR_CNT2_MASK); | ||
607 | |||
608 | /* not in use */ | ||
609 | ath5k_hw_reg_write(ah, 0, AR5K_OFDM_FIL_CNT); | ||
610 | ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT); | ||
611 | } | ||
612 | |||
613 | |||
614 | /** | ||
615 | * ath5k_disable_phy_err_counters() - Disable PHY error counters | ||
616 | * | ||
617 | * Disable PHY error counters for OFDM and CCK timing errors. | ||
618 | */ | ||
619 | static void | ||
620 | ath5k_disable_phy_err_counters(struct ath5k_hw *ah) | ||
621 | { | ||
622 | ath5k_hw_reg_write(ah, 0, AR5K_PHYERR_CNT1); | ||
623 | ath5k_hw_reg_write(ah, 0, AR5K_PHYERR_CNT2); | ||
624 | ath5k_hw_reg_write(ah, 0, AR5K_PHYERR_CNT1_MASK); | ||
625 | ath5k_hw_reg_write(ah, 0, AR5K_PHYERR_CNT2_MASK); | ||
626 | |||
627 | /* not in use */ | ||
628 | ath5k_hw_reg_write(ah, 0, AR5K_OFDM_FIL_CNT); | ||
629 | ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT); | ||
630 | } | ||
631 | |||
632 | |||
633 | /** | ||
634 | * ath5k_ani_init() - Initialize ANI | ||
635 | * @mode: Which mode to use (auto, manual high, manual low, off) | ||
636 | * | ||
637 | * Initialize ANI according to mode. | ||
638 | */ | ||
639 | void | ||
640 | ath5k_ani_init(struct ath5k_hw *ah, enum ath5k_ani_mode mode) | ||
641 | { | ||
642 | /* ANI is only possible on 5212 and newer */ | ||
643 | if (ah->ah_version < AR5K_AR5212) | ||
644 | return; | ||
645 | |||
646 | /* clear old state information */ | ||
647 | memset(&ah->ah_sc->ani_state, 0, sizeof(ah->ah_sc->ani_state)); | ||
648 | |||
649 | /* older hardware has more spur levels than newer */ | ||
650 | if (ah->ah_mac_srev < AR5K_SREV_AR2414) | ||
651 | ah->ah_sc->ani_state.max_spur_level = 7; | ||
652 | else | ||
653 | ah->ah_sc->ani_state.max_spur_level = 2; | ||
654 | |||
655 | /* initial values for our ani parameters */ | ||
656 | if (mode == ATH5K_ANI_MODE_OFF) { | ||
657 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "ANI off\n"); | ||
658 | } else if (mode == ATH5K_ANI_MODE_MANUAL_LOW) { | ||
659 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, | ||
660 | "ANI manual low -> high sensitivity\n"); | ||
661 | ath5k_ani_set_noise_immunity_level(ah, 0); | ||
662 | ath5k_ani_set_spur_immunity_level(ah, 0); | ||
663 | ath5k_ani_set_firstep_level(ah, 0); | ||
664 | ath5k_ani_set_ofdm_weak_signal_detection(ah, true); | ||
665 | ath5k_ani_set_cck_weak_signal_detection(ah, true); | ||
666 | } else if (mode == ATH5K_ANI_MODE_MANUAL_HIGH) { | ||
667 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, | ||
668 | "ANI manual high -> low sensitivity\n"); | ||
669 | ath5k_ani_set_noise_immunity_level(ah, | ||
670 | ATH5K_ANI_MAX_NOISE_IMM_LVL); | ||
671 | ath5k_ani_set_spur_immunity_level(ah, | ||
672 | ah->ah_sc->ani_state.max_spur_level); | ||
673 | ath5k_ani_set_firstep_level(ah, ATH5K_ANI_MAX_FIRSTEP_LVL); | ||
674 | ath5k_ani_set_ofdm_weak_signal_detection(ah, false); | ||
675 | ath5k_ani_set_cck_weak_signal_detection(ah, false); | ||
676 | } else if (mode == ATH5K_ANI_MODE_AUTO) { | ||
677 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "ANI auto\n"); | ||
678 | ath5k_ani_set_noise_immunity_level(ah, 0); | ||
679 | ath5k_ani_set_spur_immunity_level(ah, 0); | ||
680 | ath5k_ani_set_firstep_level(ah, 0); | ||
681 | ath5k_ani_set_ofdm_weak_signal_detection(ah, true); | ||
682 | ath5k_ani_set_cck_weak_signal_detection(ah, false); | ||
683 | } | ||
684 | |||
685 | /* newer hardware has PHY error counter registers which we can use to | ||
686 | * get OFDM and CCK error counts. older hardware has to set rxfilter and | ||
687 | * report every single PHY error by calling ath5k_ani_phy_error_report() | ||
688 | */ | ||
689 | if (mode == ATH5K_ANI_MODE_AUTO) { | ||
690 | if (ah->ah_capabilities.cap_has_phyerr_counters) | ||
691 | ath5k_enable_phy_err_counters(ah); | ||
692 | else | ||
693 | ath5k_hw_set_rx_filter(ah, ath5k_hw_get_rx_filter(ah) | | ||
694 | AR5K_RX_FILTER_PHYERR); | ||
695 | } else { | ||
696 | if (ah->ah_capabilities.cap_has_phyerr_counters) | ||
697 | ath5k_disable_phy_err_counters(ah); | ||
698 | else | ||
699 | ath5k_hw_set_rx_filter(ah, ath5k_hw_get_rx_filter(ah) & | ||
700 | ~AR5K_RX_FILTER_PHYERR); | ||
701 | } | ||
702 | |||
703 | ah->ah_sc->ani_state.ani_mode = mode; | ||
704 | } | ||
705 | |||
706 | |||
707 | /*** DEBUG ***/ | ||
708 | |||
709 | #ifdef CONFIG_ATH5K_DEBUG | ||
710 | |||
711 | void | ||
712 | ath5k_ani_print_counters(struct ath5k_hw *ah) | ||
713 | { | ||
714 | /* clears too */ | ||
715 | printk(KERN_NOTICE "ACK fail\t%d\n", | ||
716 | ath5k_hw_reg_read(ah, AR5K_ACK_FAIL)); | ||
717 | printk(KERN_NOTICE "RTS fail\t%d\n", | ||
718 | ath5k_hw_reg_read(ah, AR5K_RTS_FAIL)); | ||
719 | printk(KERN_NOTICE "RTS success\t%d\n", | ||
720 | ath5k_hw_reg_read(ah, AR5K_RTS_OK)); | ||
721 | printk(KERN_NOTICE "FCS error\t%d\n", | ||
722 | ath5k_hw_reg_read(ah, AR5K_FCS_FAIL)); | ||
723 | |||
724 | /* no clear */ | ||
725 | printk(KERN_NOTICE "tx\t%d\n", | ||
726 | ath5k_hw_reg_read(ah, AR5K_PROFCNT_TX)); | ||
727 | printk(KERN_NOTICE "rx\t%d\n", | ||
728 | ath5k_hw_reg_read(ah, AR5K_PROFCNT_RX)); | ||
729 | printk(KERN_NOTICE "busy\t%d\n", | ||
730 | ath5k_hw_reg_read(ah, AR5K_PROFCNT_RXCLR)); | ||
731 | printk(KERN_NOTICE "cycles\t%d\n", | ||
732 | ath5k_hw_reg_read(ah, AR5K_PROFCNT_CYCLE)); | ||
733 | |||
734 | printk(KERN_NOTICE "AR5K_PHYERR_CNT1\t%d\n", | ||
735 | ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1)); | ||
736 | printk(KERN_NOTICE "AR5K_PHYERR_CNT2\t%d\n", | ||
737 | ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2)); | ||
738 | printk(KERN_NOTICE "AR5K_OFDM_FIL_CNT\t%d\n", | ||
739 | ath5k_hw_reg_read(ah, AR5K_OFDM_FIL_CNT)); | ||
740 | printk(KERN_NOTICE "AR5K_CCK_FIL_CNT\t%d\n", | ||
741 | ath5k_hw_reg_read(ah, AR5K_CCK_FIL_CNT)); | ||
742 | } | ||
743 | |||
744 | #endif | ||
diff --git a/drivers/net/wireless/ath/ath5k/ani.h b/drivers/net/wireless/ath/ath5k/ani.h new file mode 100644 index 000000000000..55cf26d8522c --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/ani.h | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 Bruno Randolf <br1@einfach.org> | ||
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 | #ifndef ANI_H | ||
17 | #define ANI_H | ||
18 | |||
19 | /* these thresholds are relative to the ATH5K_ANI_LISTEN_PERIOD */ | ||
20 | #define ATH5K_ANI_LISTEN_PERIOD 100 | ||
21 | #define ATH5K_ANI_OFDM_TRIG_HIGH 500 | ||
22 | #define ATH5K_ANI_OFDM_TRIG_LOW 200 | ||
23 | #define ATH5K_ANI_CCK_TRIG_HIGH 200 | ||
24 | #define ATH5K_ANI_CCK_TRIG_LOW 100 | ||
25 | |||
26 | /* average beacon RSSI thresholds */ | ||
27 | #define ATH5K_ANI_RSSI_THR_HIGH 40 | ||
28 | #define ATH5K_ANI_RSSI_THR_LOW 7 | ||
29 | |||
30 | /* maximum availabe levels */ | ||
31 | #define ATH5K_ANI_MAX_FIRSTEP_LVL 2 | ||
32 | #define ATH5K_ANI_MAX_NOISE_IMM_LVL 1 | ||
33 | |||
34 | |||
35 | /** | ||
36 | * enum ath5k_ani_mode - mode for ANI / noise sensitivity | ||
37 | * | ||
38 | * @ATH5K_ANI_MODE_OFF: Turn ANI off. This can be useful to just stop the ANI | ||
39 | * algorithm after it has been on auto mode. | ||
40 | * ATH5K_ANI_MODE_MANUAL_LOW: Manually set all immunity parameters to low, | ||
41 | * maximizing sensitivity. ANI will not run. | ||
42 | * ATH5K_ANI_MODE_MANUAL_HIGH: Manually set all immunity parameters to high, | ||
43 | * minimizing sensitivity. ANI will not run. | ||
44 | * ATH5K_ANI_MODE_AUTO: Automatically control immunity parameters based on the | ||
45 | * amount of OFDM and CCK frame errors (default). | ||
46 | */ | ||
47 | enum ath5k_ani_mode { | ||
48 | ATH5K_ANI_MODE_OFF = 0, | ||
49 | ATH5K_ANI_MODE_MANUAL_LOW = 1, | ||
50 | ATH5K_ANI_MODE_MANUAL_HIGH = 2, | ||
51 | ATH5K_ANI_MODE_AUTO = 3 | ||
52 | }; | ||
53 | |||
54 | |||
55 | /** | ||
56 | * struct ath5k_ani_state - ANI state and associated counters | ||
57 | * | ||
58 | * @max_spur_level: the maximum spur level is chip dependent | ||
59 | */ | ||
60 | struct ath5k_ani_state { | ||
61 | enum ath5k_ani_mode ani_mode; | ||
62 | |||
63 | /* state */ | ||
64 | int noise_imm_level; | ||
65 | int spur_level; | ||
66 | int firstep_level; | ||
67 | bool ofdm_weak_sig; | ||
68 | bool cck_weak_sig; | ||
69 | |||
70 | int max_spur_level; | ||
71 | |||
72 | /* used by the algorithm */ | ||
73 | unsigned int listen_time; | ||
74 | unsigned int ofdm_errors; | ||
75 | unsigned int cck_errors; | ||
76 | |||
77 | /* debug/statistics only: numbers from last ANI calibration */ | ||
78 | unsigned int pfc_tx; | ||
79 | unsigned int pfc_rx; | ||
80 | unsigned int pfc_busy; | ||
81 | unsigned int pfc_cycles; | ||
82 | unsigned int last_listen; | ||
83 | unsigned int last_ofdm_errors; | ||
84 | unsigned int last_cck_errors; | ||
85 | unsigned int sum_ofdm_errors; | ||
86 | unsigned int sum_cck_errors; | ||
87 | }; | ||
88 | |||
89 | void ath5k_ani_init(struct ath5k_hw *ah, enum ath5k_ani_mode mode); | ||
90 | void ath5k_ani_mib_intr(struct ath5k_hw *ah); | ||
91 | void ath5k_ani_calibration(struct ath5k_hw *ah); | ||
92 | void ath5k_ani_phy_error_report(struct ath5k_hw *ah, | ||
93 | enum ath5k_phy_error_code phyerr); | ||
94 | |||
95 | /* for manual control */ | ||
96 | void ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level); | ||
97 | void ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level); | ||
98 | void ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level); | ||
99 | void ath5k_ani_set_ofdm_weak_signal_detection(struct ath5k_hw *ah, bool on); | ||
100 | void ath5k_ani_set_cck_weak_signal_detection(struct ath5k_hw *ah, bool on); | ||
101 | |||
102 | void ath5k_ani_print_counters(struct ath5k_hw *ah); | ||
103 | |||
104 | #endif /* ANI_H */ | ||
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 1d7491c85460..2785946f659a 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h | |||
@@ -202,6 +202,8 @@ | |||
202 | #define AR5K_TUNE_MAX_TXPOWER 63 | 202 | #define AR5K_TUNE_MAX_TXPOWER 63 |
203 | #define AR5K_TUNE_DEFAULT_TXPOWER 25 | 203 | #define AR5K_TUNE_DEFAULT_TXPOWER 25 |
204 | #define AR5K_TUNE_TPC_TXPOWER false | 204 | #define AR5K_TUNE_TPC_TXPOWER false |
205 | #define ATH5K_TUNE_CALIBRATION_INTERVAL_FULL 10000 /* 10 sec */ | ||
206 | #define ATH5K_TUNE_CALIBRATION_INTERVAL_ANI 1000 /* 1 sec */ | ||
205 | 207 | ||
206 | #define AR5K_INIT_CARR_SENSE_EN 1 | 208 | #define AR5K_INIT_CARR_SENSE_EN 1 |
207 | 209 | ||
@@ -799,9 +801,9 @@ struct ath5k_athchan_2ghz { | |||
799 | * @AR5K_INT_TXURN: received when we should increase the TX trigger threshold | 801 | * @AR5K_INT_TXURN: received when we should increase the TX trigger threshold |
800 | * We currently do increments on interrupt by | 802 | * We currently do increments on interrupt by |
801 | * (AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2 | 803 | * (AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2 |
802 | * @AR5K_INT_MIB: Indicates the Management Information Base counters should be | 804 | * @AR5K_INT_MIB: Indicates the either Management Information Base counters or |
803 | * checked. We should do this with ath5k_hw_update_mib_counters() but | 805 | * one of the PHY error counters reached the maximum value and should be |
804 | * it seems we should also then do some noise immunity work. | 806 | * read and cleared. |
805 | * @AR5K_INT_RXPHY: RX PHY Error | 807 | * @AR5K_INT_RXPHY: RX PHY Error |
806 | * @AR5K_INT_RXKCM: RX Key cache miss | 808 | * @AR5K_INT_RXKCM: RX Key cache miss |
807 | * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a | 809 | * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a |
@@ -889,10 +891,11 @@ enum ath5k_int { | |||
889 | AR5K_INT_NOCARD = 0xffffffff | 891 | AR5K_INT_NOCARD = 0xffffffff |
890 | }; | 892 | }; |
891 | 893 | ||
892 | /* Software interrupts used for calibration */ | 894 | /* mask which calibration is active at the moment */ |
893 | enum ath5k_software_interrupt { | 895 | enum ath5k_calibration_mask { |
894 | AR5K_SWI_FULL_CALIBRATION = 0x01, | 896 | AR5K_CALIBRATION_FULL = 0x01, |
895 | AR5K_SWI_SHORT_CALIBRATION = 0x02, | 897 | AR5K_CALIBRATION_SHORT = 0x02, |
898 | AR5K_CALIBRATION_ANI = 0x04, | ||
896 | }; | 899 | }; |
897 | 900 | ||
898 | /* | 901 | /* |
@@ -981,6 +984,8 @@ struct ath5k_capabilities { | |||
981 | struct { | 984 | struct { |
982 | u8 q_tx_num; | 985 | u8 q_tx_num; |
983 | } cap_queues; | 986 | } cap_queues; |
987 | |||
988 | bool cap_has_phyerr_counters; | ||
984 | }; | 989 | }; |
985 | 990 | ||
986 | /* size of noise floor history (keep it a power of two) */ | 991 | /* size of noise floor history (keep it a power of two) */ |
@@ -991,6 +996,15 @@ struct ath5k_nfcal_hist | |||
991 | s16 nfval[ATH5K_NF_CAL_HIST_MAX]; /* last few noise floors */ | 996 | s16 nfval[ATH5K_NF_CAL_HIST_MAX]; /* last few noise floors */ |
992 | }; | 997 | }; |
993 | 998 | ||
999 | /** | ||
1000 | * struct avg_val - Helper structure for average calculation | ||
1001 | * @avg: contains the actual average value | ||
1002 | * @avg_weight: is used internally during calculation to prevent rounding errors | ||
1003 | */ | ||
1004 | struct ath5k_avg_val { | ||
1005 | int avg; | ||
1006 | int avg_weight; | ||
1007 | }; | ||
994 | 1008 | ||
995 | /***************************************\ | 1009 | /***************************************\ |
996 | HARDWARE ABSTRACTION LAYER STRUCTURE | 1010 | HARDWARE ABSTRACTION LAYER STRUCTURE |
@@ -1095,17 +1109,18 @@ struct ath5k_hw { | |||
1095 | 1109 | ||
1096 | struct ath5k_nfcal_hist ah_nfcal_hist; | 1110 | struct ath5k_nfcal_hist ah_nfcal_hist; |
1097 | 1111 | ||
1112 | /* average beacon RSSI in our BSS (used by ANI) */ | ||
1113 | struct ath5k_avg_val ah_beacon_rssi_avg; | ||
1114 | |||
1098 | /* noise floor from last periodic calibration */ | 1115 | /* noise floor from last periodic calibration */ |
1099 | s32 ah_noise_floor; | 1116 | s32 ah_noise_floor; |
1100 | 1117 | ||
1101 | /* Calibration timestamp */ | 1118 | /* Calibration timestamp */ |
1102 | unsigned long ah_cal_tstamp; | 1119 | unsigned long ah_cal_next_full; |
1103 | 1120 | unsigned long ah_cal_next_ani; | |
1104 | /* Calibration interval (secs) */ | ||
1105 | u8 ah_cal_intval; | ||
1106 | 1121 | ||
1107 | /* Software interrupt mask */ | 1122 | /* Calibration mask */ |
1108 | u8 ah_swi_mask; | 1123 | u8 ah_cal_mask; |
1109 | 1124 | ||
1110 | /* | 1125 | /* |
1111 | * Function pointers | 1126 | * Function pointers |
@@ -1163,8 +1178,7 @@ int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase); | |||
1163 | bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah); | 1178 | bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah); |
1164 | int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask); | 1179 | int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask); |
1165 | enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask); | 1180 | enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask); |
1166 | void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, | 1181 | void ath5k_hw_update_mib_counters(struct ath5k_hw *ah); |
1167 | struct ieee80211_low_level_stats *stats); | ||
1168 | 1182 | ||
1169 | /* EEPROM access functions */ | 1183 | /* EEPROM access functions */ |
1170 | int ath5k_eeprom_init(struct ath5k_hw *ah); | 1184 | int ath5k_eeprom_init(struct ath5k_hw *ah); |
@@ -1256,7 +1270,6 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel); | |||
1256 | void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah); | 1270 | void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah); |
1257 | int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, | 1271 | int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, |
1258 | struct ieee80211_channel *channel); | 1272 | struct ieee80211_channel *channel); |
1259 | void ath5k_hw_calibration_poll(struct ath5k_hw *ah); | ||
1260 | /* Spur mitigation */ | 1273 | /* Spur mitigation */ |
1261 | bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, | 1274 | bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, |
1262 | struct ieee80211_channel *channel); | 1275 | struct ieee80211_channel *channel); |
@@ -1308,4 +1321,27 @@ static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits) | |||
1308 | return retval; | 1321 | return retval; |
1309 | } | 1322 | } |
1310 | 1323 | ||
1324 | #define AVG_SAMPLES 8 | ||
1325 | #define AVG_FACTOR 1000 | ||
1326 | |||
1327 | /** | ||
1328 | * ath5k_moving_average - Exponentially weighted moving average | ||
1329 | * @avg: average structure | ||
1330 | * @val: current value | ||
1331 | * | ||
1332 | * This implementation make use of a struct ath5k_avg_val to prevent rounding | ||
1333 | * errors. | ||
1334 | */ | ||
1335 | static inline struct ath5k_avg_val | ||
1336 | ath5k_moving_average(const struct ath5k_avg_val avg, const int val) | ||
1337 | { | ||
1338 | struct ath5k_avg_val new; | ||
1339 | new.avg_weight = avg.avg_weight ? | ||
1340 | (((avg.avg_weight * ((AVG_SAMPLES) - 1)) + | ||
1341 | (val * (AVG_FACTOR))) / (AVG_SAMPLES)) : | ||
1342 | (val * (AVG_FACTOR)); | ||
1343 | new.avg = new.avg_weight / (AVG_FACTOR); | ||
1344 | return new; | ||
1345 | } | ||
1346 | |||
1311 | #endif | 1347 | #endif |
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index f571ad1a225e..e0c244b02f05 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c | |||
@@ -124,6 +124,8 @@ int ath5k_hw_attach(struct ath5k_softc *sc) | |||
124 | ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY; | 124 | ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY; |
125 | ah->ah_software_retry = false; | 125 | ah->ah_software_retry = false; |
126 | ah->ah_ant_mode = AR5K_ANTMODE_DEFAULT; | 126 | ah->ah_ant_mode = AR5K_ANTMODE_DEFAULT; |
127 | ah->ah_noise_floor = -95; /* until first NF calibration is run */ | ||
128 | sc->ani_state.ani_mode = ATH5K_ANI_MODE_AUTO; | ||
127 | 129 | ||
128 | /* | 130 | /* |
129 | * Find the mac version | 131 | * Find the mac version |
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 7ac3a720e52c..93005f1d326d 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c | |||
@@ -59,8 +59,8 @@ | |||
59 | #include "base.h" | 59 | #include "base.h" |
60 | #include "reg.h" | 60 | #include "reg.h" |
61 | #include "debug.h" | 61 | #include "debug.h" |
62 | #include "ani.h" | ||
62 | 63 | ||
63 | static u8 ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ | ||
64 | static int modparam_nohwcrypt; | 64 | static int modparam_nohwcrypt; |
65 | module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); | 65 | module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); |
66 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); | 66 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); |
@@ -365,6 +365,7 @@ static void ath5k_beacon_send(struct ath5k_softc *sc); | |||
365 | static void ath5k_beacon_config(struct ath5k_softc *sc); | 365 | static void ath5k_beacon_config(struct ath5k_softc *sc); |
366 | static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); | 366 | static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); |
367 | static void ath5k_tasklet_beacon(unsigned long data); | 367 | static void ath5k_tasklet_beacon(unsigned long data); |
368 | static void ath5k_tasklet_ani(unsigned long data); | ||
368 | 369 | ||
369 | static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) | 370 | static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) |
370 | { | 371 | { |
@@ -830,6 +831,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) | |||
830 | tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); | 831 | tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); |
831 | tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc); | 832 | tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc); |
832 | tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc); | 833 | tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc); |
834 | tasklet_init(&sc->ani_tasklet, ath5k_tasklet_ani, (unsigned long)sc); | ||
833 | 835 | ||
834 | ret = ath5k_eeprom_read_mac(ah, mac); | 836 | ret = ath5k_eeprom_read_mac(ah, mac); |
835 | if (ret) { | 837 | if (ret) { |
@@ -1635,7 +1637,6 @@ ath5k_txq_cleanup(struct ath5k_softc *sc) | |||
1635 | sc->txqs[i].link); | 1637 | sc->txqs[i].link); |
1636 | } | 1638 | } |
1637 | } | 1639 | } |
1638 | ieee80211_wake_queues(sc->hw); /* XXX move to callers */ | ||
1639 | 1640 | ||
1640 | for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) | 1641 | for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) |
1641 | if (sc->txqs[i].setup) | 1642 | if (sc->txqs[i].setup) |
@@ -1805,6 +1806,25 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, | |||
1805 | } | 1806 | } |
1806 | } | 1807 | } |
1807 | 1808 | ||
1809 | static void | ||
1810 | ath5k_update_beacon_rssi(struct ath5k_softc *sc, struct sk_buff *skb, int rssi) | ||
1811 | { | ||
1812 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; | ||
1813 | struct ath5k_hw *ah = sc->ah; | ||
1814 | struct ath_common *common = ath5k_hw_common(ah); | ||
1815 | |||
1816 | /* only beacons from our BSSID */ | ||
1817 | if (!ieee80211_is_beacon(mgmt->frame_control) || | ||
1818 | memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) != 0) | ||
1819 | return; | ||
1820 | |||
1821 | ah->ah_beacon_rssi_avg = ath5k_moving_average(ah->ah_beacon_rssi_avg, | ||
1822 | rssi); | ||
1823 | |||
1824 | /* in IBSS mode we should keep RSSI statistics per neighbour */ | ||
1825 | /* le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS */ | ||
1826 | } | ||
1827 | |||
1808 | /* | 1828 | /* |
1809 | * Compute padding position. skb must contains an IEEE 802.11 frame | 1829 | * Compute padding position. skb must contains an IEEE 802.11 frame |
1810 | */ | 1830 | */ |
@@ -1923,6 +1943,8 @@ ath5k_tasklet_rx(unsigned long data) | |||
1923 | sc->stats.rxerr_fifo++; | 1943 | sc->stats.rxerr_fifo++; |
1924 | if (rs.rs_status & AR5K_RXERR_PHY) { | 1944 | if (rs.rs_status & AR5K_RXERR_PHY) { |
1925 | sc->stats.rxerr_phy++; | 1945 | sc->stats.rxerr_phy++; |
1946 | if (rs.rs_phyerr > 0 && rs.rs_phyerr < 32) | ||
1947 | sc->stats.rxerr_phy_code[rs.rs_phyerr]++; | ||
1926 | goto next; | 1948 | goto next; |
1927 | } | 1949 | } |
1928 | if (rs.rs_status & AR5K_RXERR_DECRYPT) { | 1950 | if (rs.rs_status & AR5K_RXERR_DECRYPT) { |
@@ -2024,6 +2046,8 @@ accept: | |||
2024 | 2046 | ||
2025 | ath5k_debug_dump_skb(sc, skb, "RX ", 0); | 2047 | ath5k_debug_dump_skb(sc, skb, "RX ", 0); |
2026 | 2048 | ||
2049 | ath5k_update_beacon_rssi(sc, skb, rs.rs_rssi); | ||
2050 | |||
2027 | /* check beacons in IBSS mode */ | 2051 | /* check beacons in IBSS mode */ |
2028 | if (sc->opmode == NL80211_IFTYPE_ADHOC) | 2052 | if (sc->opmode == NL80211_IFTYPE_ADHOC) |
2029 | ath5k_check_ibss_tsf(sc, skb, rxs); | 2053 | ath5k_check_ibss_tsf(sc, skb, rxs); |
@@ -2060,6 +2084,17 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) | |||
2060 | list_for_each_entry_safe(bf, bf0, &txq->q, list) { | 2084 | list_for_each_entry_safe(bf, bf0, &txq->q, list) { |
2061 | ds = bf->desc; | 2085 | ds = bf->desc; |
2062 | 2086 | ||
2087 | /* | ||
2088 | * It's possible that the hardware can say the buffer is | ||
2089 | * completed when it hasn't yet loaded the ds_link from | ||
2090 | * host memory and moved on. If there are more TX | ||
2091 | * descriptors in the queue, wait for TXDP to change | ||
2092 | * before processing this one. | ||
2093 | */ | ||
2094 | if (ath5k_hw_get_txdp(sc->ah, txq->qnum) == bf->daddr && | ||
2095 | !list_is_last(&bf->list, &txq->q)) | ||
2096 | break; | ||
2097 | |||
2063 | ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); | 2098 | ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); |
2064 | if (unlikely(ret == -EINPROGRESS)) | 2099 | if (unlikely(ret == -EINPROGRESS)) |
2065 | break; | 2100 | break; |
@@ -2095,7 +2130,7 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) | |||
2095 | info->status.rates[ts.ts_final_idx].count++; | 2130 | info->status.rates[ts.ts_final_idx].count++; |
2096 | 2131 | ||
2097 | if (unlikely(ts.ts_status)) { | 2132 | if (unlikely(ts.ts_status)) { |
2098 | sc->ll_stats.dot11ACKFailureCount++; | 2133 | sc->stats.ack_fail++; |
2099 | if (ts.ts_status & AR5K_TXERR_FILT) { | 2134 | if (ts.ts_status & AR5K_TXERR_FILT) { |
2100 | info->flags |= IEEE80211_TX_STAT_TX_FILTERED; | 2135 | info->flags |= IEEE80211_TX_STAT_TX_FILTERED; |
2101 | sc->stats.txerr_filt++; | 2136 | sc->stats.txerr_filt++; |
@@ -2498,9 +2533,6 @@ ath5k_init(struct ath5k_softc *sc) | |||
2498 | */ | 2533 | */ |
2499 | ath5k_stop_locked(sc); | 2534 | ath5k_stop_locked(sc); |
2500 | 2535 | ||
2501 | /* Set PHY calibration interval */ | ||
2502 | ah->ah_cal_intval = ath5k_calinterval; | ||
2503 | |||
2504 | /* | 2536 | /* |
2505 | * The basic interface to setting the hardware in a good | 2537 | * The basic interface to setting the hardware in a good |
2506 | * state is ``reset''. On return the hardware is known to | 2538 | * state is ``reset''. On return the hardware is known to |
@@ -2512,7 +2544,8 @@ ath5k_init(struct ath5k_softc *sc) | |||
2512 | sc->curband = &sc->sbands[sc->curchan->band]; | 2544 | sc->curband = &sc->sbands[sc->curchan->band]; |
2513 | sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | | 2545 | sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | |
2514 | AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | | 2546 | AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | |
2515 | AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_SWI; | 2547 | AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB; |
2548 | |||
2516 | ret = ath5k_reset(sc, NULL); | 2549 | ret = ath5k_reset(sc, NULL); |
2517 | if (ret) | 2550 | if (ret) |
2518 | goto done; | 2551 | goto done; |
@@ -2526,8 +2559,7 @@ ath5k_init(struct ath5k_softc *sc) | |||
2526 | for (i = 0; i < AR5K_KEYTABLE_SIZE; i++) | 2559 | for (i = 0; i < AR5K_KEYTABLE_SIZE; i++) |
2527 | ath5k_hw_reset_key(ah, i); | 2560 | ath5k_hw_reset_key(ah, i); |
2528 | 2561 | ||
2529 | /* Set ack to be sent at low bit-rates */ | 2562 | ath5k_hw_set_ack_bitrate_high(ah, true); |
2530 | ath5k_hw_set_ack_bitrate_high(ah, false); | ||
2531 | ret = 0; | 2563 | ret = 0; |
2532 | done: | 2564 | done: |
2533 | mmiowb(); | 2565 | mmiowb(); |
@@ -2624,12 +2656,33 @@ ath5k_stop_hw(struct ath5k_softc *sc) | |||
2624 | tasklet_kill(&sc->restq); | 2656 | tasklet_kill(&sc->restq); |
2625 | tasklet_kill(&sc->calib); | 2657 | tasklet_kill(&sc->calib); |
2626 | tasklet_kill(&sc->beacontq); | 2658 | tasklet_kill(&sc->beacontq); |
2659 | tasklet_kill(&sc->ani_tasklet); | ||
2627 | 2660 | ||
2628 | ath5k_rfkill_hw_stop(sc->ah); | 2661 | ath5k_rfkill_hw_stop(sc->ah); |
2629 | 2662 | ||
2630 | return ret; | 2663 | return ret; |
2631 | } | 2664 | } |
2632 | 2665 | ||
2666 | static void | ||
2667 | ath5k_intr_calibration_poll(struct ath5k_hw *ah) | ||
2668 | { | ||
2669 | if (time_is_before_eq_jiffies(ah->ah_cal_next_ani) && | ||
2670 | !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL)) { | ||
2671 | /* run ANI only when full calibration is not active */ | ||
2672 | ah->ah_cal_next_ani = jiffies + | ||
2673 | msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_ANI); | ||
2674 | tasklet_schedule(&ah->ah_sc->ani_tasklet); | ||
2675 | |||
2676 | } else if (time_is_before_eq_jiffies(ah->ah_cal_next_full)) { | ||
2677 | ah->ah_cal_next_full = jiffies + | ||
2678 | msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL); | ||
2679 | tasklet_schedule(&ah->ah_sc->calib); | ||
2680 | } | ||
2681 | /* we could use SWI to generate enough interrupts to meet our | ||
2682 | * calibration interval requirements, if necessary: | ||
2683 | * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */ | ||
2684 | } | ||
2685 | |||
2633 | static irqreturn_t | 2686 | static irqreturn_t |
2634 | ath5k_intr(int irq, void *dev_id) | 2687 | ath5k_intr(int irq, void *dev_id) |
2635 | { | 2688 | { |
@@ -2653,7 +2706,20 @@ ath5k_intr(int irq, void *dev_id) | |||
2653 | */ | 2706 | */ |
2654 | tasklet_schedule(&sc->restq); | 2707 | tasklet_schedule(&sc->restq); |
2655 | } else if (unlikely(status & AR5K_INT_RXORN)) { | 2708 | } else if (unlikely(status & AR5K_INT_RXORN)) { |
2656 | tasklet_schedule(&sc->restq); | 2709 | /* |
2710 | * Receive buffers are full. Either the bus is busy or | ||
2711 | * the CPU is not fast enough to process all received | ||
2712 | * frames. | ||
2713 | * Older chipsets need a reset to come out of this | ||
2714 | * condition, but we treat it as RX for newer chips. | ||
2715 | * We don't know exactly which versions need a reset - | ||
2716 | * this guess is copied from the HAL. | ||
2717 | */ | ||
2718 | sc->stats.rxorn_intr++; | ||
2719 | if (ah->ah_mac_srev < AR5K_SREV_AR5212) | ||
2720 | tasklet_schedule(&sc->restq); | ||
2721 | else | ||
2722 | tasklet_schedule(&sc->rxtq); | ||
2657 | } else { | 2723 | } else { |
2658 | if (status & AR5K_INT_SWBA) { | 2724 | if (status & AR5K_INT_SWBA) { |
2659 | tasklet_hi_schedule(&sc->beacontq); | 2725 | tasklet_hi_schedule(&sc->beacontq); |
@@ -2678,15 +2744,10 @@ ath5k_intr(int irq, void *dev_id) | |||
2678 | if (status & AR5K_INT_BMISS) { | 2744 | if (status & AR5K_INT_BMISS) { |
2679 | /* TODO */ | 2745 | /* TODO */ |
2680 | } | 2746 | } |
2681 | if (status & AR5K_INT_SWI) { | ||
2682 | tasklet_schedule(&sc->calib); | ||
2683 | } | ||
2684 | if (status & AR5K_INT_MIB) { | 2747 | if (status & AR5K_INT_MIB) { |
2685 | /* | 2748 | sc->stats.mib_intr++; |
2686 | * These stats are also used for ANI i think | 2749 | ath5k_hw_update_mib_counters(ah); |
2687 | * so how about updating them more often ? | 2750 | ath5k_ani_mib_intr(ah); |
2688 | */ | ||
2689 | ath5k_hw_update_mib_counters(ah, &sc->ll_stats); | ||
2690 | } | 2751 | } |
2691 | if (status & AR5K_INT_GPIO) | 2752 | if (status & AR5K_INT_GPIO) |
2692 | tasklet_schedule(&sc->rf_kill.toggleq); | 2753 | tasklet_schedule(&sc->rf_kill.toggleq); |
@@ -2697,7 +2758,7 @@ ath5k_intr(int irq, void *dev_id) | |||
2697 | if (unlikely(!counter)) | 2758 | if (unlikely(!counter)) |
2698 | ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); | 2759 | ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); |
2699 | 2760 | ||
2700 | ath5k_hw_calibration_poll(ah); | 2761 | ath5k_intr_calibration_poll(ah); |
2701 | 2762 | ||
2702 | return IRQ_HANDLED; | 2763 | return IRQ_HANDLED; |
2703 | } | 2764 | } |
@@ -2721,8 +2782,7 @@ ath5k_tasklet_calibrate(unsigned long data) | |||
2721 | struct ath5k_hw *ah = sc->ah; | 2782 | struct ath5k_hw *ah = sc->ah; |
2722 | 2783 | ||
2723 | /* Only full calibration for now */ | 2784 | /* Only full calibration for now */ |
2724 | if (ah->ah_swi_mask != AR5K_SWI_FULL_CALIBRATION) | 2785 | ah->ah_cal_mask |= AR5K_CALIBRATION_FULL; |
2725 | return; | ||
2726 | 2786 | ||
2727 | /* Stop queues so that calibration | 2787 | /* Stop queues so that calibration |
2728 | * doesn't interfere with tx */ | 2788 | * doesn't interfere with tx */ |
@@ -2738,18 +2798,29 @@ ath5k_tasklet_calibrate(unsigned long data) | |||
2738 | * to load new gain values. | 2798 | * to load new gain values. |
2739 | */ | 2799 | */ |
2740 | ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n"); | 2800 | ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n"); |
2741 | ath5k_reset_wake(sc); | 2801 | ath5k_reset(sc, sc->curchan); |
2742 | } | 2802 | } |
2743 | if (ath5k_hw_phy_calibrate(ah, sc->curchan)) | 2803 | if (ath5k_hw_phy_calibrate(ah, sc->curchan)) |
2744 | ATH5K_ERR(sc, "calibration of channel %u failed\n", | 2804 | ATH5K_ERR(sc, "calibration of channel %u failed\n", |
2745 | ieee80211_frequency_to_channel( | 2805 | ieee80211_frequency_to_channel( |
2746 | sc->curchan->center_freq)); | 2806 | sc->curchan->center_freq)); |
2747 | 2807 | ||
2748 | ah->ah_swi_mask = 0; | ||
2749 | |||
2750 | /* Wake queues */ | 2808 | /* Wake queues */ |
2751 | ieee80211_wake_queues(sc->hw); | 2809 | ieee80211_wake_queues(sc->hw); |
2752 | 2810 | ||
2811 | ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL; | ||
2812 | } | ||
2813 | |||
2814 | |||
2815 | static void | ||
2816 | ath5k_tasklet_ani(unsigned long data) | ||
2817 | { | ||
2818 | struct ath5k_softc *sc = (void *)data; | ||
2819 | struct ath5k_hw *ah = sc->ah; | ||
2820 | |||
2821 | ah->ah_cal_mask |= AR5K_CALIBRATION_ANI; | ||
2822 | ath5k_ani_calibration(ah); | ||
2823 | ah->ah_cal_mask &= ~AR5K_CALIBRATION_ANI; | ||
2753 | } | 2824 | } |
2754 | 2825 | ||
2755 | 2826 | ||
@@ -2852,6 +2923,8 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan) | |||
2852 | goto err; | 2923 | goto err; |
2853 | } | 2924 | } |
2854 | 2925 | ||
2926 | ath5k_ani_init(ah, ah->ah_sc->ani_state.ani_mode); | ||
2927 | |||
2855 | /* | 2928 | /* |
2856 | * Change channels and update the h/w rate map if we're switching; | 2929 | * Change channels and update the h/w rate map if we're switching; |
2857 | * e.g. 11a to 11b/g. | 2930 | * e.g. 11a to 11b/g. |
@@ -3207,12 +3280,14 @@ ath5k_get_stats(struct ieee80211_hw *hw, | |||
3207 | struct ieee80211_low_level_stats *stats) | 3280 | struct ieee80211_low_level_stats *stats) |
3208 | { | 3281 | { |
3209 | struct ath5k_softc *sc = hw->priv; | 3282 | struct ath5k_softc *sc = hw->priv; |
3210 | struct ath5k_hw *ah = sc->ah; | ||
3211 | 3283 | ||
3212 | /* Force update */ | 3284 | /* Force update */ |
3213 | ath5k_hw_update_mib_counters(ah, &sc->ll_stats); | 3285 | ath5k_hw_update_mib_counters(sc->ah); |
3214 | 3286 | ||
3215 | memcpy(stats, &sc->ll_stats, sizeof(sc->ll_stats)); | 3287 | stats->dot11ACKFailureCount = sc->stats.ack_fail; |
3288 | stats->dot11RTSFailureCount = sc->stats.rts_fail; | ||
3289 | stats->dot11RTSSuccessCount = sc->stats.rts_ok; | ||
3290 | stats->dot11FCSErrorCount = sc->stats.fcs_error; | ||
3216 | 3291 | ||
3217 | return 0; | 3292 | return 0; |
3218 | } | 3293 | } |
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 33f1d8b87ee1..56221bc7c8cd 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h | |||
@@ -50,6 +50,7 @@ | |||
50 | 50 | ||
51 | #include "ath5k.h" | 51 | #include "ath5k.h" |
52 | #include "debug.h" | 52 | #include "debug.h" |
53 | #include "ani.h" | ||
53 | 54 | ||
54 | #include "../regd.h" | 55 | #include "../regd.h" |
55 | #include "../ath.h" | 56 | #include "../ath.h" |
@@ -105,14 +106,18 @@ struct ath5k_rfkill { | |||
105 | struct tasklet_struct toggleq; | 106 | struct tasklet_struct toggleq; |
106 | }; | 107 | }; |
107 | 108 | ||
108 | /* statistics (only used for debugging now) */ | 109 | /* statistics */ |
109 | struct ath5k_statistics { | 110 | struct ath5k_statistics { |
111 | /* antenna use */ | ||
110 | unsigned int antenna_rx[5]; /* frames count per antenna RX */ | 112 | unsigned int antenna_rx[5]; /* frames count per antenna RX */ |
111 | unsigned int antenna_tx[5]; /* frames count per antenna TX */ | 113 | unsigned int antenna_tx[5]; /* frames count per antenna TX */ |
114 | |||
115 | /* frame errors */ | ||
112 | unsigned int rx_all_count; /* all RX frames, including errors */ | 116 | unsigned int rx_all_count; /* all RX frames, including errors */ |
113 | unsigned int tx_all_count; /* all TX frames, including errors */ | 117 | unsigned int tx_all_count; /* all TX frames, including errors */ |
114 | unsigned int rxerr_crc; | 118 | unsigned int rxerr_crc; |
115 | unsigned int rxerr_phy; | 119 | unsigned int rxerr_phy; |
120 | unsigned int rxerr_phy_code[32]; | ||
116 | unsigned int rxerr_fifo; | 121 | unsigned int rxerr_fifo; |
117 | unsigned int rxerr_decrypt; | 122 | unsigned int rxerr_decrypt; |
118 | unsigned int rxerr_mic; | 123 | unsigned int rxerr_mic; |
@@ -121,6 +126,16 @@ struct ath5k_statistics { | |||
121 | unsigned int txerr_retry; | 126 | unsigned int txerr_retry; |
122 | unsigned int txerr_fifo; | 127 | unsigned int txerr_fifo; |
123 | unsigned int txerr_filt; | 128 | unsigned int txerr_filt; |
129 | |||
130 | /* MIB counters */ | ||
131 | unsigned int ack_fail; | ||
132 | unsigned int rts_fail; | ||
133 | unsigned int rts_ok; | ||
134 | unsigned int fcs_error; | ||
135 | unsigned int beacons; | ||
136 | |||
137 | unsigned int mib_intr; | ||
138 | unsigned int rxorn_intr; | ||
124 | }; | 139 | }; |
125 | 140 | ||
126 | #if CHAN_DEBUG | 141 | #if CHAN_DEBUG |
@@ -135,7 +150,6 @@ struct ath5k_softc { | |||
135 | struct pci_dev *pdev; /* for dma mapping */ | 150 | struct pci_dev *pdev; /* for dma mapping */ |
136 | void __iomem *iobase; /* address of the device */ | 151 | void __iomem *iobase; /* address of the device */ |
137 | struct mutex lock; /* dev-level lock */ | 152 | struct mutex lock; /* dev-level lock */ |
138 | struct ieee80211_low_level_stats ll_stats; | ||
139 | struct ieee80211_hw *hw; /* IEEE 802.11 common */ | 153 | struct ieee80211_hw *hw; /* IEEE 802.11 common */ |
140 | struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; | 154 | struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; |
141 | struct ieee80211_channel channels[ATH_CHAN_MAX]; | 155 | struct ieee80211_channel channels[ATH_CHAN_MAX]; |
@@ -211,6 +225,9 @@ struct ath5k_softc { | |||
211 | bool enable_beacon; /* true if beacons are on */ | 225 | bool enable_beacon; /* true if beacons are on */ |
212 | 226 | ||
213 | struct ath5k_statistics stats; | 227 | struct ath5k_statistics stats; |
228 | |||
229 | struct ath5k_ani_state ani_state; | ||
230 | struct tasklet_struct ani_tasklet; /* ANI calibration */ | ||
214 | }; | 231 | }; |
215 | 232 | ||
216 | #define ath5k_hw_hasbssidmask(_ah) \ | 233 | #define ath5k_hw_hasbssidmask(_ah) \ |
diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c index e618e71b1ce6..74f007126f41 100644 --- a/drivers/net/wireless/ath/ath5k/caps.c +++ b/drivers/net/wireless/ath/ath5k/caps.c | |||
@@ -109,6 +109,12 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah) | |||
109 | else | 109 | else |
110 | ah->ah_capabilities.cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES; | 110 | ah->ah_capabilities.cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES; |
111 | 111 | ||
112 | /* newer hardware has PHY error counters */ | ||
113 | if (ah->ah_mac_srev >= AR5K_SREV_AR5213A) | ||
114 | ah->ah_capabilities.cap_has_phyerr_counters = true; | ||
115 | else | ||
116 | ah->ah_capabilities.cap_has_phyerr_counters = false; | ||
117 | |||
112 | return 0; | 118 | return 0; |
113 | } | 119 | } |
114 | 120 | ||
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index bccd4a78027e..6fb5c5ffa5b1 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c | |||
@@ -69,6 +69,7 @@ module_param_named(debug, ath5k_debug, uint, 0); | |||
69 | 69 | ||
70 | #include <linux/seq_file.h> | 70 | #include <linux/seq_file.h> |
71 | #include "reg.h" | 71 | #include "reg.h" |
72 | #include "ani.h" | ||
72 | 73 | ||
73 | static struct dentry *ath5k_global_debugfs; | 74 | static struct dentry *ath5k_global_debugfs; |
74 | 75 | ||
@@ -307,6 +308,7 @@ static const struct { | |||
307 | { ATH5K_DEBUG_DUMP_TX, "dumptx", "print transmit skb content" }, | 308 | { ATH5K_DEBUG_DUMP_TX, "dumptx", "print transmit skb content" }, |
308 | { ATH5K_DEBUG_DUMPBANDS, "dumpbands", "dump bands" }, | 309 | { ATH5K_DEBUG_DUMPBANDS, "dumpbands", "dump bands" }, |
309 | { ATH5K_DEBUG_TRACE, "trace", "trace function calls" }, | 310 | { ATH5K_DEBUG_TRACE, "trace", "trace function calls" }, |
311 | { ATH5K_DEBUG_ANI, "ani", "adaptive noise immunity" }, | ||
310 | { ATH5K_DEBUG_ANY, "all", "show all debug levels" }, | 312 | { ATH5K_DEBUG_ANY, "all", "show all debug levels" }, |
311 | }; | 313 | }; |
312 | 314 | ||
@@ -474,6 +476,7 @@ static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf, | |||
474 | struct ath5k_statistics *st = &sc->stats; | 476 | struct ath5k_statistics *st = &sc->stats; |
475 | char buf[700]; | 477 | char buf[700]; |
476 | unsigned int len = 0; | 478 | unsigned int len = 0; |
479 | int i; | ||
477 | 480 | ||
478 | len += snprintf(buf+len, sizeof(buf)-len, | 481 | len += snprintf(buf+len, sizeof(buf)-len, |
479 | "RX\n---------------------\n"); | 482 | "RX\n---------------------\n"); |
@@ -485,6 +488,13 @@ static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf, | |||
485 | st->rxerr_phy, | 488 | st->rxerr_phy, |
486 | st->rx_all_count > 0 ? | 489 | st->rx_all_count > 0 ? |
487 | st->rxerr_phy*100/st->rx_all_count : 0); | 490 | st->rxerr_phy*100/st->rx_all_count : 0); |
491 | for (i = 0; i < 32; i++) { | ||
492 | if (st->rxerr_phy_code[i]) | ||
493 | len += snprintf(buf+len, sizeof(buf)-len, | ||
494 | " phy_err[%d]\t%d\n", | ||
495 | i, st->rxerr_phy_code[i]); | ||
496 | } | ||
497 | |||
488 | len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%d\t(%d%%)\n", | 498 | len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%d\t(%d%%)\n", |
489 | st->rxerr_fifo, | 499 | st->rxerr_fifo, |
490 | st->rx_all_count > 0 ? | 500 | st->rx_all_count > 0 ? |
@@ -565,6 +575,160 @@ static const struct file_operations fops_frameerrors = { | |||
565 | }; | 575 | }; |
566 | 576 | ||
567 | 577 | ||
578 | /* debugfs: ani */ | ||
579 | |||
580 | static ssize_t read_file_ani(struct file *file, char __user *user_buf, | ||
581 | size_t count, loff_t *ppos) | ||
582 | { | ||
583 | struct ath5k_softc *sc = file->private_data; | ||
584 | struct ath5k_statistics *st = &sc->stats; | ||
585 | struct ath5k_ani_state *as = &sc->ani_state; | ||
586 | |||
587 | char buf[700]; | ||
588 | unsigned int len = 0; | ||
589 | |||
590 | len += snprintf(buf+len, sizeof(buf)-len, | ||
591 | "HW has PHY error counters:\t%s\n", | ||
592 | sc->ah->ah_capabilities.cap_has_phyerr_counters ? | ||
593 | "yes" : "no"); | ||
594 | len += snprintf(buf+len, sizeof(buf)-len, | ||
595 | "HW max spur immunity level:\t%d\n", | ||
596 | as->max_spur_level); | ||
597 | len += snprintf(buf+len, sizeof(buf)-len, | ||
598 | "\nANI state\n--------------------------------------------\n"); | ||
599 | len += snprintf(buf+len, sizeof(buf)-len, "operating mode:\t\t\t"); | ||
600 | switch (as->ani_mode) { | ||
601 | case ATH5K_ANI_MODE_OFF: | ||
602 | len += snprintf(buf+len, sizeof(buf)-len, "OFF\n"); | ||
603 | break; | ||
604 | case ATH5K_ANI_MODE_MANUAL_LOW: | ||
605 | len += snprintf(buf+len, sizeof(buf)-len, | ||
606 | "MANUAL LOW\n"); | ||
607 | break; | ||
608 | case ATH5K_ANI_MODE_MANUAL_HIGH: | ||
609 | len += snprintf(buf+len, sizeof(buf)-len, | ||
610 | "MANUAL HIGH\n"); | ||
611 | break; | ||
612 | case ATH5K_ANI_MODE_AUTO: | ||
613 | len += snprintf(buf+len, sizeof(buf)-len, "AUTO\n"); | ||
614 | break; | ||
615 | default: | ||
616 | len += snprintf(buf+len, sizeof(buf)-len, | ||
617 | "??? (not good)\n"); | ||
618 | break; | ||
619 | } | ||
620 | len += snprintf(buf+len, sizeof(buf)-len, | ||
621 | "noise immunity level:\t\t%d\n", | ||
622 | as->noise_imm_level); | ||
623 | len += snprintf(buf+len, sizeof(buf)-len, | ||
624 | "spur immunity level:\t\t%d\n", | ||
625 | as->spur_level); | ||
626 | len += snprintf(buf+len, sizeof(buf)-len, "firstep level:\t\t\t%d\n", | ||
627 | as->firstep_level); | ||
628 | len += snprintf(buf+len, sizeof(buf)-len, | ||
629 | "OFDM weak signal detection:\t%s\n", | ||
630 | as->ofdm_weak_sig ? "on" : "off"); | ||
631 | len += snprintf(buf+len, sizeof(buf)-len, | ||
632 | "CCK weak signal detection:\t%s\n", | ||
633 | as->cck_weak_sig ? "on" : "off"); | ||
634 | |||
635 | len += snprintf(buf+len, sizeof(buf)-len, | ||
636 | "\nMIB INTERRUPTS:\t\t%u\n", | ||
637 | st->mib_intr); | ||
638 | len += snprintf(buf+len, sizeof(buf)-len, | ||
639 | "beacon RSSI average:\t%d\n", | ||
640 | sc->ah->ah_beacon_rssi_avg.avg); | ||
641 | len += snprintf(buf+len, sizeof(buf)-len, "profcnt tx\t\t%u\t(%d%%)\n", | ||
642 | as->pfc_tx, | ||
643 | as->pfc_cycles > 0 ? | ||
644 | as->pfc_tx*100/as->pfc_cycles : 0); | ||
645 | len += snprintf(buf+len, sizeof(buf)-len, "profcnt rx\t\t%u\t(%d%%)\n", | ||
646 | as->pfc_rx, | ||
647 | as->pfc_cycles > 0 ? | ||
648 | as->pfc_rx*100/as->pfc_cycles : 0); | ||
649 | len += snprintf(buf+len, sizeof(buf)-len, "profcnt busy\t\t%u\t(%d%%)\n", | ||
650 | as->pfc_busy, | ||
651 | as->pfc_cycles > 0 ? | ||
652 | as->pfc_busy*100/as->pfc_cycles : 0); | ||
653 | len += snprintf(buf+len, sizeof(buf)-len, "profcnt cycles\t\t%u\n", | ||
654 | as->pfc_cycles); | ||
655 | len += snprintf(buf+len, sizeof(buf)-len, | ||
656 | "listen time\t\t%d\tlast: %d\n", | ||
657 | as->listen_time, as->last_listen); | ||
658 | len += snprintf(buf+len, sizeof(buf)-len, | ||
659 | "OFDM errors\t\t%u\tlast: %u\tsum: %u\n", | ||
660 | as->ofdm_errors, as->last_ofdm_errors, | ||
661 | as->sum_ofdm_errors); | ||
662 | len += snprintf(buf+len, sizeof(buf)-len, | ||
663 | "CCK errors\t\t%u\tlast: %u\tsum: %u\n", | ||
664 | as->cck_errors, as->last_cck_errors, | ||
665 | as->sum_cck_errors); | ||
666 | len += snprintf(buf+len, sizeof(buf)-len, | ||
667 | "AR5K_PHYERR_CNT1\t%x\t(=%d)\n", | ||
668 | ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT1), | ||
669 | ATH5K_ANI_OFDM_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - | ||
670 | ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT1))); | ||
671 | len += snprintf(buf+len, sizeof(buf)-len, | ||
672 | "AR5K_PHYERR_CNT2\t%x\t(=%d)\n", | ||
673 | ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT2), | ||
674 | ATH5K_ANI_CCK_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - | ||
675 | ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT2))); | ||
676 | |||
677 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
678 | } | ||
679 | |||
680 | static ssize_t write_file_ani(struct file *file, | ||
681 | const char __user *userbuf, | ||
682 | size_t count, loff_t *ppos) | ||
683 | { | ||
684 | struct ath5k_softc *sc = file->private_data; | ||
685 | char buf[20]; | ||
686 | |||
687 | if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) | ||
688 | return -EFAULT; | ||
689 | |||
690 | if (strncmp(buf, "sens-low", 8) == 0) { | ||
691 | ath5k_ani_init(sc->ah, ATH5K_ANI_MODE_MANUAL_HIGH); | ||
692 | } else if (strncmp(buf, "sens-high", 9) == 0) { | ||
693 | ath5k_ani_init(sc->ah, ATH5K_ANI_MODE_MANUAL_LOW); | ||
694 | } else if (strncmp(buf, "ani-off", 7) == 0) { | ||
695 | ath5k_ani_init(sc->ah, ATH5K_ANI_MODE_OFF); | ||
696 | } else if (strncmp(buf, "ani-on", 6) == 0) { | ||
697 | ath5k_ani_init(sc->ah, ATH5K_ANI_MODE_AUTO); | ||
698 | } else if (strncmp(buf, "noise-low", 9) == 0) { | ||
699 | ath5k_ani_set_noise_immunity_level(sc->ah, 0); | ||
700 | } else if (strncmp(buf, "noise-high", 10) == 0) { | ||
701 | ath5k_ani_set_noise_immunity_level(sc->ah, | ||
702 | ATH5K_ANI_MAX_NOISE_IMM_LVL); | ||
703 | } else if (strncmp(buf, "spur-low", 8) == 0) { | ||
704 | ath5k_ani_set_spur_immunity_level(sc->ah, 0); | ||
705 | } else if (strncmp(buf, "spur-high", 9) == 0) { | ||
706 | ath5k_ani_set_spur_immunity_level(sc->ah, | ||
707 | sc->ani_state.max_spur_level); | ||
708 | } else if (strncmp(buf, "fir-low", 7) == 0) { | ||
709 | ath5k_ani_set_firstep_level(sc->ah, 0); | ||
710 | } else if (strncmp(buf, "fir-high", 8) == 0) { | ||
711 | ath5k_ani_set_firstep_level(sc->ah, ATH5K_ANI_MAX_FIRSTEP_LVL); | ||
712 | } else if (strncmp(buf, "ofdm-off", 8) == 0) { | ||
713 | ath5k_ani_set_ofdm_weak_signal_detection(sc->ah, false); | ||
714 | } else if (strncmp(buf, "ofdm-on", 7) == 0) { | ||
715 | ath5k_ani_set_ofdm_weak_signal_detection(sc->ah, true); | ||
716 | } else if (strncmp(buf, "cck-off", 7) == 0) { | ||
717 | ath5k_ani_set_cck_weak_signal_detection(sc->ah, false); | ||
718 | } else if (strncmp(buf, "cck-on", 6) == 0) { | ||
719 | ath5k_ani_set_cck_weak_signal_detection(sc->ah, true); | ||
720 | } | ||
721 | return count; | ||
722 | } | ||
723 | |||
724 | static const struct file_operations fops_ani = { | ||
725 | .read = read_file_ani, | ||
726 | .write = write_file_ani, | ||
727 | .open = ath5k_debugfs_open, | ||
728 | .owner = THIS_MODULE, | ||
729 | }; | ||
730 | |||
731 | |||
568 | /* init */ | 732 | /* init */ |
569 | 733 | ||
570 | void | 734 | void |
@@ -603,6 +767,11 @@ ath5k_debug_init_device(struct ath5k_softc *sc) | |||
603 | S_IWUSR | S_IRUSR, | 767 | S_IWUSR | S_IRUSR, |
604 | sc->debug.debugfs_phydir, sc, | 768 | sc->debug.debugfs_phydir, sc, |
605 | &fops_frameerrors); | 769 | &fops_frameerrors); |
770 | |||
771 | sc->debug.debugfs_ani = debugfs_create_file("ani", | ||
772 | S_IWUSR | S_IRUSR, | ||
773 | sc->debug.debugfs_phydir, sc, | ||
774 | &fops_ani); | ||
606 | } | 775 | } |
607 | 776 | ||
608 | void | 777 | void |
@@ -620,6 +789,7 @@ ath5k_debug_finish_device(struct ath5k_softc *sc) | |||
620 | debugfs_remove(sc->debug.debugfs_reset); | 789 | debugfs_remove(sc->debug.debugfs_reset); |
621 | debugfs_remove(sc->debug.debugfs_antenna); | 790 | debugfs_remove(sc->debug.debugfs_antenna); |
622 | debugfs_remove(sc->debug.debugfs_frameerrors); | 791 | debugfs_remove(sc->debug.debugfs_frameerrors); |
792 | debugfs_remove(sc->debug.debugfs_ani); | ||
623 | debugfs_remove(sc->debug.debugfs_phydir); | 793 | debugfs_remove(sc->debug.debugfs_phydir); |
624 | } | 794 | } |
625 | 795 | ||
diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h index da24ff52e274..ddd5b3a99e8d 100644 --- a/drivers/net/wireless/ath/ath5k/debug.h +++ b/drivers/net/wireless/ath/ath5k/debug.h | |||
@@ -76,6 +76,7 @@ struct ath5k_dbg_info { | |||
76 | struct dentry *debugfs_reset; | 76 | struct dentry *debugfs_reset; |
77 | struct dentry *debugfs_antenna; | 77 | struct dentry *debugfs_antenna; |
78 | struct dentry *debugfs_frameerrors; | 78 | struct dentry *debugfs_frameerrors; |
79 | struct dentry *debugfs_ani; | ||
79 | }; | 80 | }; |
80 | 81 | ||
81 | /** | 82 | /** |
@@ -115,6 +116,7 @@ enum ath5k_debug_level { | |||
115 | ATH5K_DEBUG_DUMP_TX = 0x00000200, | 116 | ATH5K_DEBUG_DUMP_TX = 0x00000200, |
116 | ATH5K_DEBUG_DUMPBANDS = 0x00000400, | 117 | ATH5K_DEBUG_DUMPBANDS = 0x00000400, |
117 | ATH5K_DEBUG_TRACE = 0x00001000, | 118 | ATH5K_DEBUG_TRACE = 0x00001000, |
119 | ATH5K_DEBUG_ANI = 0x00002000, | ||
118 | ATH5K_DEBUG_ANY = 0xffffffff | 120 | ATH5K_DEBUG_ANY = 0xffffffff |
119 | }; | 121 | }; |
120 | 122 | ||
diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index 9d920fb14d5d..7d7b646ab65a 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c | |||
@@ -645,6 +645,7 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, | |||
645 | rs->rs_status |= AR5K_RXERR_PHY; | 645 | rs->rs_status |= AR5K_RXERR_PHY; |
646 | rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1, | 646 | rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1, |
647 | AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE); | 647 | AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE); |
648 | ath5k_ani_phy_error_report(ah, rs->rs_phyerr); | ||
648 | } | 649 | } |
649 | 650 | ||
650 | if (rx_status->rx_status_1 & | 651 | if (rx_status->rx_status_1 & |
diff --git a/drivers/net/wireless/ath/ath5k/desc.h b/drivers/net/wireless/ath/ath5k/desc.h index 56158c804e3e..64538fbe4167 100644 --- a/drivers/net/wireless/ath/ath5k/desc.h +++ b/drivers/net/wireless/ath/ath5k/desc.h | |||
@@ -112,15 +112,32 @@ struct ath5k_hw_rx_error { | |||
112 | #define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE 0x0000ff00 | 112 | #define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE 0x0000ff00 |
113 | #define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S 8 | 113 | #define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S 8 |
114 | 114 | ||
115 | /* PHY Error codes */ | 115 | /** |
116 | #define AR5K_DESC_RX_PHY_ERROR_NONE 0x00 | 116 | * enum ath5k_phy_error_code - PHY Error codes |
117 | #define AR5K_DESC_RX_PHY_ERROR_TIMING 0x20 | 117 | */ |
118 | #define AR5K_DESC_RX_PHY_ERROR_PARITY 0x40 | 118 | enum ath5k_phy_error_code { |
119 | #define AR5K_DESC_RX_PHY_ERROR_RATE 0x60 | 119 | AR5K_RX_PHY_ERROR_UNDERRUN = 0, /* Transmit underrun */ |
120 | #define AR5K_DESC_RX_PHY_ERROR_LENGTH 0x80 | 120 | AR5K_RX_PHY_ERROR_TIMING = 1, /* Timing error */ |
121 | #define AR5K_DESC_RX_PHY_ERROR_64QAM 0xa0 | 121 | AR5K_RX_PHY_ERROR_PARITY = 2, /* Illegal parity */ |
122 | #define AR5K_DESC_RX_PHY_ERROR_SERVICE 0xc0 | 122 | AR5K_RX_PHY_ERROR_RATE = 3, /* Illegal rate */ |
123 | #define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR 0xe0 | 123 | AR5K_RX_PHY_ERROR_LENGTH = 4, /* Illegal length */ |
124 | AR5K_RX_PHY_ERROR_RADAR = 5, /* Radar detect */ | ||
125 | AR5K_RX_PHY_ERROR_SERVICE = 6, /* Illegal service */ | ||
126 | AR5K_RX_PHY_ERROR_TOR = 7, /* Transmit override receive */ | ||
127 | /* these are specific to the 5212 */ | ||
128 | AR5K_RX_PHY_ERROR_OFDM_TIMING = 17, | ||
129 | AR5K_RX_PHY_ERROR_OFDM_SIGNAL_PARITY = 18, | ||
130 | AR5K_RX_PHY_ERROR_OFDM_RATE_ILLEGAL = 19, | ||
131 | AR5K_RX_PHY_ERROR_OFDM_LENGTH_ILLEGAL = 20, | ||
132 | AR5K_RX_PHY_ERROR_OFDM_POWER_DROP = 21, | ||
133 | AR5K_RX_PHY_ERROR_OFDM_SERVICE = 22, | ||
134 | AR5K_RX_PHY_ERROR_OFDM_RESTART = 23, | ||
135 | AR5K_RX_PHY_ERROR_CCK_TIMING = 25, | ||
136 | AR5K_RX_PHY_ERROR_CCK_HEADER_CRC = 26, | ||
137 | AR5K_RX_PHY_ERROR_CCK_RATE_ILLEGAL = 27, | ||
138 | AR5K_RX_PHY_ERROR_CCK_SERVICE = 30, | ||
139 | AR5K_RX_PHY_ERROR_CCK_RESTART = 31, | ||
140 | }; | ||
124 | 141 | ||
125 | /* | 142 | /* |
126 | * 5210/5211 hardware 2-word TX control descriptor | 143 | * 5210/5211 hardware 2-word TX control descriptor |
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 1b9fcb842167..174412fc81f8 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c | |||
@@ -113,39 +113,26 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) | |||
113 | } | 113 | } |
114 | 114 | ||
115 | /** | 115 | /** |
116 | * ath5k_hw_update - Update mib counters (mac layer statistics) | 116 | * ath5k_hw_update - Update MIB counters (mac layer statistics) |
117 | * | 117 | * |
118 | * @ah: The &struct ath5k_hw | 118 | * @ah: The &struct ath5k_hw |
119 | * @stats: The &struct ieee80211_low_level_stats we use to track | ||
120 | * statistics on the driver | ||
121 | * | 119 | * |
122 | * Reads MIB counters from PCU and updates sw statistics. Must be | 120 | * Reads MIB counters from PCU and updates sw statistics. Is called after a |
123 | * called after a MIB interrupt. | 121 | * MIB interrupt, because one of these counters might have reached their maximum |
122 | * and triggered the MIB interrupt, to let us read and clear the counter. | ||
123 | * | ||
124 | * Is called in interrupt context! | ||
124 | */ | 125 | */ |
125 | void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, | 126 | void ath5k_hw_update_mib_counters(struct ath5k_hw *ah) |
126 | struct ieee80211_low_level_stats *stats) | ||
127 | { | 127 | { |
128 | ATH5K_TRACE(ah->ah_sc); | 128 | struct ath5k_statistics *stats = &ah->ah_sc->stats; |
129 | 129 | ||
130 | /* Read-And-Clear */ | 130 | /* Read-And-Clear */ |
131 | stats->dot11ACKFailureCount += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL); | 131 | stats->ack_fail += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL); |
132 | stats->dot11RTSFailureCount += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL); | 132 | stats->rts_fail += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL); |
133 | stats->dot11RTSSuccessCount += ath5k_hw_reg_read(ah, AR5K_RTS_OK); | 133 | stats->rts_ok += ath5k_hw_reg_read(ah, AR5K_RTS_OK); |
134 | stats->dot11FCSErrorCount += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL); | 134 | stats->fcs_error += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL); |
135 | 135 | stats->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT); | |
136 | /* XXX: Should we use this to track beacon count ? | ||
137 | * -we read it anyway to clear the register */ | ||
138 | ath5k_hw_reg_read(ah, AR5K_BEACON_CNT); | ||
139 | |||
140 | /* Reset profile count registers on 5212*/ | ||
141 | if (ah->ah_version == AR5K_AR5212) { | ||
142 | ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX); | ||
143 | ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX); | ||
144 | ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR); | ||
145 | ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE); | ||
146 | } | ||
147 | |||
148 | /* TODO: Handle ANI stats */ | ||
149 | } | 136 | } |
150 | 137 | ||
151 | /** | 138 | /** |
@@ -167,9 +154,9 @@ void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high) | |||
167 | else { | 154 | else { |
168 | u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB; | 155 | u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB; |
169 | if (high) | 156 | if (high) |
170 | AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val); | ||
171 | else | ||
172 | AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val); | 157 | AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val); |
158 | else | ||
159 | AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val); | ||
173 | } | 160 | } |
174 | } | 161 | } |
175 | 162 | ||
@@ -392,7 +379,6 @@ void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) | |||
392 | * (ACK etc). | 379 | * (ACK etc). |
393 | * | 380 | * |
394 | * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma | 381 | * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma |
395 | * TODO: Init ANI here | ||
396 | */ | 382 | */ |
397 | void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) | 383 | void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) |
398 | { | 384 | { |
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 3ee74c839768..3ce9afba1d88 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c | |||
@@ -980,7 +980,7 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah, | |||
980 | return -EINVAL; | 980 | return -EINVAL; |
981 | 981 | ||
982 | data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8); | 982 | data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8); |
983 | } else if ((c - (c % 5)) != 2 || c > 5435) { | 983 | } else if ((c % 5) != 2 || c > 5435) { |
984 | if (!(c % 20) && c >= 5120) { | 984 | if (!(c % 20) && c >= 5120) { |
985 | data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8); | 985 | data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8); |
986 | data2 = ath5k_hw_bitswap(3, 2); | 986 | data2 = ath5k_hw_bitswap(3, 2); |
@@ -993,7 +993,7 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah, | |||
993 | } else | 993 | } else |
994 | return -EINVAL; | 994 | return -EINVAL; |
995 | } else { | 995 | } else { |
996 | data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8); | 996 | data0 = ath5k_hw_bitswap((10 * (c - 2 - 4800)) / 25 + 1, 8); |
997 | data2 = ath5k_hw_bitswap(0, 2); | 997 | data2 = ath5k_hw_bitswap(0, 2); |
998 | } | 998 | } |
999 | 999 | ||
@@ -1021,7 +1021,7 @@ static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah, | |||
1021 | data0 = ath5k_hw_bitswap((c - 2272), 8); | 1021 | data0 = ath5k_hw_bitswap((c - 2272), 8); |
1022 | data2 = 0; | 1022 | data2 = 0; |
1023 | /* ? 5GHz ? */ | 1023 | /* ? 5GHz ? */ |
1024 | } else if ((c - (c % 5)) != 2 || c > 5435) { | 1024 | } else if ((c % 5) != 2 || c > 5435) { |
1025 | if (!(c % 20) && c < 5120) | 1025 | if (!(c % 20) && c < 5120) |
1026 | data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8); | 1026 | data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8); |
1027 | else if (!(c % 10)) | 1027 | else if (!(c % 10)) |
@@ -1032,7 +1032,7 @@ static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah, | |||
1032 | return -EINVAL; | 1032 | return -EINVAL; |
1033 | data2 = ath5k_hw_bitswap(1, 2); | 1033 | data2 = ath5k_hw_bitswap(1, 2); |
1034 | } else { | 1034 | } else { |
1035 | data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8); | 1035 | data0 = ath5k_hw_bitswap((10 * (c - 2 - 4800)) / 25 + 1, 8); |
1036 | data2 = ath5k_hw_bitswap(0, 2); | 1036 | data2 = ath5k_hw_bitswap(0, 2); |
1037 | } | 1037 | } |
1038 | 1038 | ||
@@ -1103,28 +1103,6 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) | |||
1103 | PHY calibration | 1103 | PHY calibration |
1104 | \*****************/ | 1104 | \*****************/ |
1105 | 1105 | ||
1106 | void | ||
1107 | ath5k_hw_calibration_poll(struct ath5k_hw *ah) | ||
1108 | { | ||
1109 | /* Calibration interval in jiffies */ | ||
1110 | unsigned long cal_intval; | ||
1111 | |||
1112 | cal_intval = msecs_to_jiffies(ah->ah_cal_intval * 1000); | ||
1113 | |||
1114 | /* Initialize timestamp if needed */ | ||
1115 | if (!ah->ah_cal_tstamp) | ||
1116 | ah->ah_cal_tstamp = jiffies; | ||
1117 | |||
1118 | /* For now we always do full calibration | ||
1119 | * Mark software interrupt mask and fire software | ||
1120 | * interrupt (bit gets auto-cleared) */ | ||
1121 | if (time_is_before_eq_jiffies(ah->ah_cal_tstamp + cal_intval)) { | ||
1122 | ah->ah_cal_tstamp = jiffies; | ||
1123 | ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION; | ||
1124 | AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); | ||
1125 | } | ||
1126 | } | ||
1127 | |||
1128 | static int sign_extend(int val, const int nbits) | 1106 | static int sign_extend(int val, const int nbits) |
1129 | { | 1107 | { |
1130 | int order = BIT(nbits-1); | 1108 | int order = BIT(nbits-1); |
@@ -1411,7 +1389,10 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah, | |||
1411 | i_coff = (-iq_corr) / i_coffd; | 1389 | i_coff = (-iq_corr) / i_coffd; |
1412 | i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */ | 1390 | i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */ |
1413 | 1391 | ||
1414 | q_coff = (i_pwr / q_coffd) - 128; | 1392 | if (ah->ah_version == AR5K_AR5211) |
1393 | q_coff = (i_pwr / q_coffd) - 64; | ||
1394 | else | ||
1395 | q_coff = (i_pwr / q_coffd) - 128; | ||
1415 | q_coff = clamp(q_coff, -16, 15); /* signed 5 bit */ | 1396 | q_coff = clamp(q_coff, -16, 15); /* signed 5 bit */ |
1416 | 1397 | ||
1417 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, | 1398 | ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, |
@@ -2580,7 +2561,7 @@ ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah, | |||
2580 | max_idx = (pdadc_n < table_size) ? pdadc_n : table_size; | 2561 | max_idx = (pdadc_n < table_size) ? pdadc_n : table_size; |
2581 | 2562 | ||
2582 | /* Fill pdadc_out table */ | 2563 | /* Fill pdadc_out table */ |
2583 | while (pdadc_0 < max_idx) | 2564 | while (pdadc_0 < max_idx && pdadc_i < 128) |
2584 | pdadc_out[pdadc_i++] = pdadc_tmp[pdadc_0++]; | 2565 | pdadc_out[pdadc_i++] = pdadc_tmp[pdadc_0++]; |
2585 | 2566 | ||
2586 | /* Need to extrapolate above this pdgain? */ | 2567 | /* Need to extrapolate above this pdgain? */ |
diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index 47f04932ab8b..55b4ac6d236f 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h | |||
@@ -212,10 +212,10 @@ | |||
212 | * MIB control register | 212 | * MIB control register |
213 | */ | 213 | */ |
214 | #define AR5K_MIBC 0x0040 /* Register Address */ | 214 | #define AR5K_MIBC 0x0040 /* Register Address */ |
215 | #define AR5K_MIBC_COW 0x00000001 /* Warn test indicator */ | 215 | #define AR5K_MIBC_COW 0x00000001 /* Counter Overflow Warning */ |
216 | #define AR5K_MIBC_FMC 0x00000002 /* Freeze MIB Counters */ | 216 | #define AR5K_MIBC_FMC 0x00000002 /* Freeze MIB Counters */ |
217 | #define AR5K_MIBC_CMC 0x00000004 /* Clean MIB Counters */ | 217 | #define AR5K_MIBC_CMC 0x00000004 /* Clear MIB Counters */ |
218 | #define AR5K_MIBC_MCS 0x00000008 /* MIB counter strobe */ | 218 | #define AR5K_MIBC_MCS 0x00000008 /* MIB counter strobe, increment all */ |
219 | 219 | ||
220 | /* | 220 | /* |
221 | * Timeout prescale register | 221 | * Timeout prescale register |
@@ -1139,8 +1139,8 @@ | |||
1139 | #define AR5K_STA_ID1_DEFAULT_ANTENNA 0x00200000 /* Use default antenna */ | 1139 | #define AR5K_STA_ID1_DEFAULT_ANTENNA 0x00200000 /* Use default antenna */ |
1140 | #define AR5K_STA_ID1_DESC_ANTENNA 0x00400000 /* Update antenna from descriptor */ | 1140 | #define AR5K_STA_ID1_DESC_ANTENNA 0x00400000 /* Update antenna from descriptor */ |
1141 | #define AR5K_STA_ID1_RTS_DEF_ANTENNA 0x00800000 /* Use default antenna for RTS */ | 1141 | #define AR5K_STA_ID1_RTS_DEF_ANTENNA 0x00800000 /* Use default antenna for RTS */ |
1142 | #define AR5K_STA_ID1_ACKCTS_6MB 0x01000000 /* Use 6Mbit/s for ACK/CTS */ | 1142 | #define AR5K_STA_ID1_ACKCTS_6MB 0x01000000 /* Rate to use for ACK/CTS. 0: highest mandatory rate <= RX rate; 1: 1Mbps in B mode */ |
1143 | #define AR5K_STA_ID1_BASE_RATE_11B 0x02000000 /* Use 11b base rate for ACK/CTS [5211+] */ | 1143 | #define AR5K_STA_ID1_BASE_RATE_11B 0x02000000 /* 802.11b base rate. 0: 1, 2, 5.5 and 11Mbps; 1: 1 and 2Mbps. [5211+] */ |
1144 | #define AR5K_STA_ID1_SELFGEN_DEF_ANT 0x04000000 /* Use def. antenna for self generated frames */ | 1144 | #define AR5K_STA_ID1_SELFGEN_DEF_ANT 0x04000000 /* Use def. antenna for self generated frames */ |
1145 | #define AR5K_STA_ID1_CRYPT_MIC_EN 0x08000000 /* Enable MIC */ | 1145 | #define AR5K_STA_ID1_CRYPT_MIC_EN 0x08000000 /* Enable MIC */ |
1146 | #define AR5K_STA_ID1_KEYSRCH_MODE 0x10000000 /* Look up key when key id != 0 */ | 1146 | #define AR5K_STA_ID1_KEYSRCH_MODE 0x10000000 /* Look up key when key id != 0 */ |
@@ -1516,7 +1516,14 @@ | |||
1516 | AR5K_NAV_5210 : AR5K_NAV_5211) | 1516 | AR5K_NAV_5210 : AR5K_NAV_5211) |
1517 | 1517 | ||
1518 | /* | 1518 | /* |
1519 | * RTS success register | 1519 | * MIB counters: |
1520 | * | ||
1521 | * max value is 0xc000, if this is reached we get a MIB interrupt. | ||
1522 | * they can be controlled via AR5K_MIBC and are cleared on read. | ||
1523 | */ | ||
1524 | |||
1525 | /* | ||
1526 | * RTS success (MIB counter) | ||
1520 | */ | 1527 | */ |
1521 | #define AR5K_RTS_OK_5210 0x8090 | 1528 | #define AR5K_RTS_OK_5210 0x8090 |
1522 | #define AR5K_RTS_OK_5211 0x8088 | 1529 | #define AR5K_RTS_OK_5211 0x8088 |
@@ -1524,7 +1531,7 @@ | |||
1524 | AR5K_RTS_OK_5210 : AR5K_RTS_OK_5211) | 1531 | AR5K_RTS_OK_5210 : AR5K_RTS_OK_5211) |
1525 | 1532 | ||
1526 | /* | 1533 | /* |
1527 | * RTS failure register | 1534 | * RTS failure (MIB counter) |
1528 | */ | 1535 | */ |
1529 | #define AR5K_RTS_FAIL_5210 0x8094 | 1536 | #define AR5K_RTS_FAIL_5210 0x8094 |
1530 | #define AR5K_RTS_FAIL_5211 0x808c | 1537 | #define AR5K_RTS_FAIL_5211 0x808c |
@@ -1532,7 +1539,7 @@ | |||
1532 | AR5K_RTS_FAIL_5210 : AR5K_RTS_FAIL_5211) | 1539 | AR5K_RTS_FAIL_5210 : AR5K_RTS_FAIL_5211) |
1533 | 1540 | ||
1534 | /* | 1541 | /* |
1535 | * ACK failure register | 1542 | * ACK failure (MIB counter) |
1536 | */ | 1543 | */ |
1537 | #define AR5K_ACK_FAIL_5210 0x8098 | 1544 | #define AR5K_ACK_FAIL_5210 0x8098 |
1538 | #define AR5K_ACK_FAIL_5211 0x8090 | 1545 | #define AR5K_ACK_FAIL_5211 0x8090 |
@@ -1540,7 +1547,7 @@ | |||
1540 | AR5K_ACK_FAIL_5210 : AR5K_ACK_FAIL_5211) | 1547 | AR5K_ACK_FAIL_5210 : AR5K_ACK_FAIL_5211) |
1541 | 1548 | ||
1542 | /* | 1549 | /* |
1543 | * FCS failure register | 1550 | * FCS failure (MIB counter) |
1544 | */ | 1551 | */ |
1545 | #define AR5K_FCS_FAIL_5210 0x809c | 1552 | #define AR5K_FCS_FAIL_5210 0x809c |
1546 | #define AR5K_FCS_FAIL_5211 0x8094 | 1553 | #define AR5K_FCS_FAIL_5211 0x8094 |
@@ -1667,11 +1674,17 @@ | |||
1667 | 1674 | ||
1668 | /* | 1675 | /* |
1669 | * Profile count registers | 1676 | * Profile count registers |
1677 | * | ||
1678 | * These registers can be cleared and freezed with ATH5K_MIBC, but they do not | ||
1679 | * generate a MIB interrupt. | ||
1680 | * Instead of overflowing, they shift by one bit to the right. All registers | ||
1681 | * shift together, i.e. when one reaches the max, all shift at the same time by | ||
1682 | * one bit to the right. This way we should always get consistent values. | ||
1670 | */ | 1683 | */ |
1671 | #define AR5K_PROFCNT_TX 0x80ec /* Tx count */ | 1684 | #define AR5K_PROFCNT_TX 0x80ec /* Tx count */ |
1672 | #define AR5K_PROFCNT_RX 0x80f0 /* Rx count */ | 1685 | #define AR5K_PROFCNT_RX 0x80f0 /* Rx count */ |
1673 | #define AR5K_PROFCNT_RXCLR 0x80f4 /* Clear Rx count */ | 1686 | #define AR5K_PROFCNT_RXCLR 0x80f4 /* Busy count */ |
1674 | #define AR5K_PROFCNT_CYCLE 0x80f8 /* Cycle count (?) */ | 1687 | #define AR5K_PROFCNT_CYCLE 0x80f8 /* Cycle counter */ |
1675 | 1688 | ||
1676 | /* | 1689 | /* |
1677 | * Quiet period control registers | 1690 | * Quiet period control registers |
@@ -1758,7 +1771,7 @@ | |||
1758 | #define AR5K_CCK_FIL_CNT 0x8128 | 1771 | #define AR5K_CCK_FIL_CNT 0x8128 |
1759 | 1772 | ||
1760 | /* | 1773 | /* |
1761 | * PHY Error Counters (?) | 1774 | * PHY Error Counters (same masks as AR5K_PHY_ERR_FIL) |
1762 | */ | 1775 | */ |
1763 | #define AR5K_PHYERR_CNT1 0x812c | 1776 | #define AR5K_PHYERR_CNT1 0x812c |
1764 | #define AR5K_PHYERR_CNT1_MASK 0x8130 | 1777 | #define AR5K_PHYERR_CNT1_MASK 0x8130 |
@@ -1766,6 +1779,9 @@ | |||
1766 | #define AR5K_PHYERR_CNT2 0x8134 | 1779 | #define AR5K_PHYERR_CNT2 0x8134 |
1767 | #define AR5K_PHYERR_CNT2_MASK 0x8138 | 1780 | #define AR5K_PHYERR_CNT2_MASK 0x8138 |
1768 | 1781 | ||
1782 | /* if the PHY Error Counters reach this maximum, we get MIB interrupts */ | ||
1783 | #define ATH5K_PHYERR_CNT_MAX 0x00c00000 | ||
1784 | |||
1769 | /* | 1785 | /* |
1770 | * TSF Threshold register (?) | 1786 | * TSF Threshold register (?) |
1771 | */ | 1787 | */ |