1 | /* |
---|
2 | * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> |
---|
3 | * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> |
---|
4 | * Copyright (c) 2007-2008 Matthew W. S. Bell <mentor@madwifi.org> |
---|
5 | * Copyright (c) 2007-2008 Luis Rodriguez <mcgrof@winlab.rutgers.edu> |
---|
6 | * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org> |
---|
7 | * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com> |
---|
8 | * |
---|
9 | * Lightly modified for gPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>. |
---|
10 | * |
---|
11 | * Permission to use, copy, modify, and distribute this software for any |
---|
12 | * purpose with or without fee is hereby granted, provided that the above |
---|
13 | * copyright notice and this permission notice appear in all copies. |
---|
14 | * |
---|
15 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
---|
16 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
---|
17 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
---|
18 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
---|
19 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
---|
20 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
---|
21 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
---|
22 | * |
---|
23 | */ |
---|
24 | |
---|
25 | FILE_LICENCE ( MIT ); |
---|
26 | |
---|
27 | /*********************************\ |
---|
28 | * Protocol Control Unit Functions * |
---|
29 | \*********************************/ |
---|
30 | |
---|
31 | #include "ath5k.h" |
---|
32 | #include "reg.h" |
---|
33 | #include "base.h" |
---|
34 | |
---|
35 | /*******************\ |
---|
36 | * Generic functions * |
---|
37 | \*******************/ |
---|
38 | |
---|
39 | /** |
---|
40 | * ath5k_hw_set_opmode - Set PCU operating mode |
---|
41 | * |
---|
42 | * @ah: The &struct ath5k_hw |
---|
43 | * |
---|
44 | * Initialize PCU for the various operating modes (AP/STA etc) |
---|
45 | * |
---|
46 | * For gPXE we always assume STA mode. |
---|
47 | */ |
---|
48 | int ath5k_hw_set_opmode(struct ath5k_hw *ah) |
---|
49 | { |
---|
50 | u32 pcu_reg, beacon_reg, low_id, high_id; |
---|
51 | |
---|
52 | |
---|
53 | /* Preserve rest settings */ |
---|
54 | pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; |
---|
55 | pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP |
---|
56 | | AR5K_STA_ID1_KEYSRCH_MODE |
---|
57 | | (ah->ah_version == AR5K_AR5210 ? |
---|
58 | (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0)); |
---|
59 | |
---|
60 | beacon_reg = 0; |
---|
61 | |
---|
62 | pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE |
---|
63 | | (ah->ah_version == AR5K_AR5210 ? |
---|
64 | AR5K_STA_ID1_PWR_SV : 0); |
---|
65 | |
---|
66 | /* |
---|
67 | * Set PCU registers |
---|
68 | */ |
---|
69 | low_id = AR5K_LOW_ID(ah->ah_sta_id); |
---|
70 | high_id = AR5K_HIGH_ID(ah->ah_sta_id); |
---|
71 | ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); |
---|
72 | ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); |
---|
73 | |
---|
74 | /* |
---|
75 | * Set Beacon Control Register on 5210 |
---|
76 | */ |
---|
77 | if (ah->ah_version == AR5K_AR5210) |
---|
78 | ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR); |
---|
79 | |
---|
80 | return 0; |
---|
81 | } |
---|
82 | |
---|
83 | /** |
---|
84 | * ath5k_hw_set_ack_bitrate - set bitrate for ACKs |
---|
85 | * |
---|
86 | * @ah: The &struct ath5k_hw |
---|
87 | * @high: Flag to determine if we want to use high transmition rate |
---|
88 | * for ACKs or not |
---|
89 | * |
---|
90 | * If high flag is set, we tell hw to use a set of control rates based on |
---|
91 | * the current transmition rate (check out control_rates array inside reset.c). |
---|
92 | * If not hw just uses the lowest rate available for the current modulation |
---|
93 | * scheme being used (1Mbit for CCK and 6Mbits for OFDM). |
---|
94 | */ |
---|
95 | void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, int high) |
---|
96 | { |
---|
97 | if (ah->ah_version != AR5K_AR5212) |
---|
98 | return; |
---|
99 | else { |
---|
100 | u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB; |
---|
101 | if (high) |
---|
102 | AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val); |
---|
103 | else |
---|
104 | AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val); |
---|
105 | } |
---|
106 | } |
---|
107 | |
---|
108 | |
---|
109 | /******************\ |
---|
110 | * ACK/CTS Timeouts * |
---|
111 | \******************/ |
---|
112 | |
---|
113 | /** |
---|
114 | * ath5k_hw_het_ack_timeout - Get ACK timeout from PCU in usec |
---|
115 | * |
---|
116 | * @ah: The &struct ath5k_hw |
---|
117 | */ |
---|
118 | unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah) |
---|
119 | { |
---|
120 | return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, |
---|
121 | AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo); |
---|
122 | } |
---|
123 | |
---|
124 | /** |
---|
125 | * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU |
---|
126 | * |
---|
127 | * @ah: The &struct ath5k_hw |
---|
128 | * @timeout: Timeout in usec |
---|
129 | */ |
---|
130 | int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) |
---|
131 | { |
---|
132 | if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK), |
---|
133 | ah->ah_turbo) <= timeout) |
---|
134 | return -EINVAL; |
---|
135 | |
---|
136 | AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK, |
---|
137 | ath5k_hw_htoclock(timeout, ah->ah_turbo)); |
---|
138 | |
---|
139 | return 0; |
---|
140 | } |
---|
141 | |
---|
142 | /** |
---|
143 | * ath5k_hw_get_cts_timeout - Get CTS timeout from PCU in usec |
---|
144 | * |
---|
145 | * @ah: The &struct ath5k_hw |
---|
146 | */ |
---|
147 | unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah) |
---|
148 | { |
---|
149 | return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, |
---|
150 | AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo); |
---|
151 | } |
---|
152 | |
---|
153 | /** |
---|
154 | * ath5k_hw_set_cts_timeout - Set CTS timeout on PCU |
---|
155 | * |
---|
156 | * @ah: The &struct ath5k_hw |
---|
157 | * @timeout: Timeout in usec |
---|
158 | */ |
---|
159 | int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) |
---|
160 | { |
---|
161 | if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS), |
---|
162 | ah->ah_turbo) <= timeout) |
---|
163 | return -EINVAL; |
---|
164 | |
---|
165 | AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS, |
---|
166 | ath5k_hw_htoclock(timeout, ah->ah_turbo)); |
---|
167 | |
---|
168 | return 0; |
---|
169 | } |
---|
170 | |
---|
171 | |
---|
172 | /****************\ |
---|
173 | * BSSID handling * |
---|
174 | \****************/ |
---|
175 | |
---|
176 | /** |
---|
177 | * ath5k_hw_get_lladdr - Get station id |
---|
178 | * |
---|
179 | * @ah: The &struct ath5k_hw |
---|
180 | * @mac: The card's mac address |
---|
181 | * |
---|
182 | * Initialize ah->ah_sta_id using the mac address provided |
---|
183 | * (just a memcpy). |
---|
184 | * |
---|
185 | * TODO: Remove it once we merge ath5k_softc and ath5k_hw |
---|
186 | */ |
---|
187 | void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac) |
---|
188 | { |
---|
189 | memcpy(mac, ah->ah_sta_id, ETH_ALEN); |
---|
190 | } |
---|
191 | |
---|
192 | /** |
---|
193 | * ath5k_hw_set_lladdr - Set station id |
---|
194 | * |
---|
195 | * @ah: The &struct ath5k_hw |
---|
196 | * @mac: The card's mac address |
---|
197 | * |
---|
198 | * Set station id on hw using the provided mac address |
---|
199 | */ |
---|
200 | int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) |
---|
201 | { |
---|
202 | u32 low_id, high_id; |
---|
203 | u32 pcu_reg; |
---|
204 | |
---|
205 | /* Set new station ID */ |
---|
206 | memcpy(ah->ah_sta_id, mac, ETH_ALEN); |
---|
207 | |
---|
208 | pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; |
---|
209 | |
---|
210 | low_id = AR5K_LOW_ID(mac); |
---|
211 | high_id = AR5K_HIGH_ID(mac); |
---|
212 | |
---|
213 | ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); |
---|
214 | ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); |
---|
215 | |
---|
216 | return 0; |
---|
217 | } |
---|
218 | |
---|
219 | /** |
---|
220 | * ath5k_hw_set_associd - Set BSSID for association |
---|
221 | * |
---|
222 | * @ah: The &struct ath5k_hw |
---|
223 | * @bssid: BSSID |
---|
224 | * @assoc_id: Assoc id |
---|
225 | * |
---|
226 | * Sets the BSSID which trigers the "SME Join" operation |
---|
227 | */ |
---|
228 | void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) |
---|
229 | { |
---|
230 | u32 low_id, high_id; |
---|
231 | |
---|
232 | /* |
---|
233 | * Set simple BSSID mask on 5212 |
---|
234 | */ |
---|
235 | if (ah->ah_version == AR5K_AR5212) { |
---|
236 | ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_bssid_mask), |
---|
237 | AR5K_BSS_IDM0); |
---|
238 | ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask), |
---|
239 | AR5K_BSS_IDM1); |
---|
240 | } |
---|
241 | |
---|
242 | /* |
---|
243 | * Set BSSID which triggers the "SME Join" operation |
---|
244 | */ |
---|
245 | low_id = AR5K_LOW_ID(bssid); |
---|
246 | high_id = AR5K_HIGH_ID(bssid); |
---|
247 | ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0); |
---|
248 | ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) << |
---|
249 | AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1); |
---|
250 | } |
---|
251 | |
---|
252 | /** |
---|
253 | * ath5k_hw_set_bssid_mask - filter out bssids we listen |
---|
254 | * |
---|
255 | * @ah: the &struct ath5k_hw |
---|
256 | * @mask: the bssid_mask, a u8 array of size ETH_ALEN |
---|
257 | * |
---|
258 | * BSSID masking is a method used by AR5212 and newer hardware to inform PCU |
---|
259 | * which bits of the interface's MAC address should be looked at when trying |
---|
260 | * to decide which packets to ACK. In station mode and AP mode with a single |
---|
261 | * BSS every bit matters since we lock to only one BSS. In AP mode with |
---|
262 | * multiple BSSes (virtual interfaces) not every bit matters because hw must |
---|
263 | * accept frames for all BSSes and so we tweak some bits of our mac address |
---|
264 | * in order to have multiple BSSes. |
---|
265 | * |
---|
266 | * NOTE: This is a simple filter and does *not* filter out all |
---|
267 | * relevant frames. Some frames that are not for us might get ACKed from us |
---|
268 | * by PCU because they just match the mask. |
---|
269 | * |
---|
270 | * When handling multiple BSSes you can get the BSSID mask by computing the |
---|
271 | * set of ~ ( MAC XOR BSSID ) for all bssids we handle. |
---|
272 | * |
---|
273 | * When you do this you are essentially computing the common bits of all your |
---|
274 | * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with |
---|
275 | * the MAC address to obtain the relevant bits and compare the result with |
---|
276 | * (frame's BSSID & mask) to see if they match. |
---|
277 | */ |
---|
278 | /* |
---|
279 | * Simple example: on your card you have have two BSSes you have created with |
---|
280 | * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address. |
---|
281 | * There is another BSSID-03 but you are not part of it. For simplicity's sake, |
---|
282 | * assuming only 4 bits for a mac address and for BSSIDs you can then have: |
---|
283 | * |
---|
284 | * \ |
---|
285 | * MAC: 0001 | |
---|
286 | * BSSID-01: 0100 | --> Belongs to us |
---|
287 | * BSSID-02: 1001 | |
---|
288 | * / |
---|
289 | * ------------------- |
---|
290 | * BSSID-03: 0110 | --> External |
---|
291 | * ------------------- |
---|
292 | * |
---|
293 | * Our bssid_mask would then be: |
---|
294 | * |
---|
295 | * On loop iteration for BSSID-01: |
---|
296 | * ~(0001 ^ 0100) -> ~(0101) |
---|
297 | * -> 1010 |
---|
298 | * bssid_mask = 1010 |
---|
299 | * |
---|
300 | * On loop iteration for BSSID-02: |
---|
301 | * bssid_mask &= ~(0001 ^ 1001) |
---|
302 | * bssid_mask = (1010) & ~(0001 ^ 1001) |
---|
303 | * bssid_mask = (1010) & ~(1001) |
---|
304 | * bssid_mask = (1010) & (0110) |
---|
305 | * bssid_mask = 0010 |
---|
306 | * |
---|
307 | * A bssid_mask of 0010 means "only pay attention to the second least |
---|
308 | * significant bit". This is because its the only bit common |
---|
309 | * amongst the MAC and all BSSIDs we support. To findout what the real |
---|
310 | * common bit is we can simply "&" the bssid_mask now with any BSSID we have |
---|
311 | * or our MAC address (we assume the hardware uses the MAC address). |
---|
312 | * |
---|
313 | * Now, suppose there's an incoming frame for BSSID-03: |
---|
314 | * |
---|
315 | * IFRAME-01: 0110 |
---|
316 | * |
---|
317 | * An easy eye-inspeciton of this already should tell you that this frame |
---|
318 | * will not pass our check. This is beacuse the bssid_mask tells the |
---|
319 | * hardware to only look at the second least significant bit and the |
---|
320 | * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB |
---|
321 | * as 1, which does not match 0. |
---|
322 | * |
---|
323 | * So with IFRAME-01 we *assume* the hardware will do: |
---|
324 | * |
---|
325 | * allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; |
---|
326 | * --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0; |
---|
327 | * --> allow = (0010) == 0000 ? 1 : 0; |
---|
328 | * --> allow = 0 |
---|
329 | * |
---|
330 | * Lets now test a frame that should work: |
---|
331 | * |
---|
332 | * IFRAME-02: 0001 (we should allow) |
---|
333 | * |
---|
334 | * allow = (0001 & 1010) == 1010 |
---|
335 | * |
---|
336 | * allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; |
---|
337 | * --> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0; |
---|
338 | * --> allow = (0010) == (0010) |
---|
339 | * --> allow = 1 |
---|
340 | * |
---|
341 | * Other examples: |
---|
342 | * |
---|
343 | * IFRAME-03: 0100 --> allowed |
---|
344 | * IFRAME-04: 1001 --> allowed |
---|
345 | * IFRAME-05: 1101 --> allowed but its not for us!!! |
---|
346 | * |
---|
347 | */ |
---|
348 | int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) |
---|
349 | { |
---|
350 | u32 low_id, high_id; |
---|
351 | |
---|
352 | /* Cache bssid mask so that we can restore it |
---|
353 | * on reset */ |
---|
354 | memcpy(ah->ah_bssid_mask, mask, ETH_ALEN); |
---|
355 | if (ah->ah_version == AR5K_AR5212) { |
---|
356 | low_id = AR5K_LOW_ID(mask); |
---|
357 | high_id = AR5K_HIGH_ID(mask); |
---|
358 | |
---|
359 | ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0); |
---|
360 | ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1); |
---|
361 | |
---|
362 | return 0; |
---|
363 | } |
---|
364 | |
---|
365 | return -EIO; |
---|
366 | } |
---|
367 | |
---|
368 | |
---|
369 | /************\ |
---|
370 | * RX Control * |
---|
371 | \************/ |
---|
372 | |
---|
373 | /** |
---|
374 | * ath5k_hw_start_rx_pcu - Start RX engine |
---|
375 | * |
---|
376 | * @ah: The &struct ath5k_hw |
---|
377 | * |
---|
378 | * Starts RX engine on PCU so that hw can process RXed frames |
---|
379 | * (ACK etc). |
---|
380 | * |
---|
381 | * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma |
---|
382 | * TODO: Init ANI here |
---|
383 | */ |
---|
384 | void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) |
---|
385 | { |
---|
386 | AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); |
---|
387 | } |
---|
388 | |
---|
389 | /** |
---|
390 | * at5k_hw_stop_rx_pcu - Stop RX engine |
---|
391 | * |
---|
392 | * @ah: The &struct ath5k_hw |
---|
393 | * |
---|
394 | * Stops RX engine on PCU |
---|
395 | * |
---|
396 | * TODO: Detach ANI here |
---|
397 | */ |
---|
398 | void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah) |
---|
399 | { |
---|
400 | AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); |
---|
401 | } |
---|
402 | |
---|
403 | /* |
---|
404 | * Set multicast filter |
---|
405 | */ |
---|
406 | void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1) |
---|
407 | { |
---|
408 | /* Set the multicat filter */ |
---|
409 | ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0); |
---|
410 | ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1); |
---|
411 | } |
---|
412 | |
---|
413 | /** |
---|
414 | * ath5k_hw_get_rx_filter - Get current rx filter |
---|
415 | * |
---|
416 | * @ah: The &struct ath5k_hw |
---|
417 | * |
---|
418 | * Returns the RX filter by reading rx filter and |
---|
419 | * phy error filter registers. RX filter is used |
---|
420 | * to set the allowed frame types that PCU will accept |
---|
421 | * and pass to the driver. For a list of frame types |
---|
422 | * check out reg.h. |
---|
423 | */ |
---|
424 | u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah) |
---|
425 | { |
---|
426 | u32 data, filter = 0; |
---|
427 | |
---|
428 | filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER); |
---|
429 | |
---|
430 | /*Radar detection for 5212*/ |
---|
431 | if (ah->ah_version == AR5K_AR5212) { |
---|
432 | data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL); |
---|
433 | |
---|
434 | if (data & AR5K_PHY_ERR_FIL_RADAR) |
---|
435 | filter |= AR5K_RX_FILTER_RADARERR; |
---|
436 | if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK)) |
---|
437 | filter |= AR5K_RX_FILTER_PHYERR; |
---|
438 | } |
---|
439 | |
---|
440 | return filter; |
---|
441 | } |
---|
442 | |
---|
443 | /** |
---|
444 | * ath5k_hw_set_rx_filter - Set rx filter |
---|
445 | * |
---|
446 | * @ah: The &struct ath5k_hw |
---|
447 | * @filter: RX filter mask (see reg.h) |
---|
448 | * |
---|
449 | * Sets RX filter register and also handles PHY error filter |
---|
450 | * register on 5212 and newer chips so that we have proper PHY |
---|
451 | * error reporting. |
---|
452 | */ |
---|
453 | void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) |
---|
454 | { |
---|
455 | u32 data = 0; |
---|
456 | |
---|
457 | /* Set PHY error filter register on 5212*/ |
---|
458 | if (ah->ah_version == AR5K_AR5212) { |
---|
459 | if (filter & AR5K_RX_FILTER_RADARERR) |
---|
460 | data |= AR5K_PHY_ERR_FIL_RADAR; |
---|
461 | if (filter & AR5K_RX_FILTER_PHYERR) |
---|
462 | data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK; |
---|
463 | } |
---|
464 | |
---|
465 | /* |
---|
466 | * The AR5210 uses promiscous mode to detect radar activity |
---|
467 | */ |
---|
468 | if (ah->ah_version == AR5K_AR5210 && |
---|
469 | (filter & AR5K_RX_FILTER_RADARERR)) { |
---|
470 | filter &= ~AR5K_RX_FILTER_RADARERR; |
---|
471 | filter |= AR5K_RX_FILTER_PROM; |
---|
472 | } |
---|
473 | |
---|
474 | /*Zero length DMA (phy error reporting) */ |
---|
475 | if (data) |
---|
476 | AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); |
---|
477 | else |
---|
478 | AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); |
---|
479 | |
---|
480 | /*Write RX Filter register*/ |
---|
481 | ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER); |
---|
482 | |
---|
483 | /*Write PHY error filter register on 5212*/ |
---|
484 | if (ah->ah_version == AR5K_AR5212) |
---|
485 | ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL); |
---|
486 | |
---|
487 | } |
---|
488 | |
---|
489 | /*********************\ |
---|
490 | * Key table functions * |
---|
491 | \*********************/ |
---|
492 | |
---|
493 | /* |
---|
494 | * Reset a key entry on the table |
---|
495 | */ |
---|
496 | int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) |
---|
497 | { |
---|
498 | unsigned int i, type; |
---|
499 | u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; |
---|
500 | |
---|
501 | type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry)); |
---|
502 | |
---|
503 | for (i = 0; i < AR5K_KEYCACHE_SIZE; i++) |
---|
504 | ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i)); |
---|
505 | |
---|
506 | /* Reset associated MIC entry if TKIP |
---|
507 | * is enabled located at offset (entry + 64) */ |
---|
508 | if (type == AR5K_KEYTABLE_TYPE_TKIP) { |
---|
509 | for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++) |
---|
510 | ath5k_hw_reg_write(ah, 0, |
---|
511 | AR5K_KEYTABLE_OFF(micentry, i)); |
---|
512 | } |
---|
513 | |
---|
514 | /* |
---|
515 | * Set NULL encryption on AR5212+ |
---|
516 | * |
---|
517 | * Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5) |
---|
518 | * AR5K_KEYTABLE_TYPE_NULL -> 0x00000007 |
---|
519 | * |
---|
520 | * Note2: Windows driver (ndiswrapper) sets this to |
---|
521 | * 0x00000714 instead of 0x00000007 |
---|
522 | */ |
---|
523 | if (ah->ah_version >= AR5K_AR5211) { |
---|
524 | ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, |
---|
525 | AR5K_KEYTABLE_TYPE(entry)); |
---|
526 | |
---|
527 | if (type == AR5K_KEYTABLE_TYPE_TKIP) { |
---|
528 | ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, |
---|
529 | AR5K_KEYTABLE_TYPE(micentry)); |
---|
530 | } |
---|
531 | } |
---|
532 | |
---|
533 | return 0; |
---|
534 | } |
---|