Commit | Line | Data |
---|---|---|
c6e387a2 NK |
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 | * Permission to use, copy, modify, and distribute this software for any | |
10 | * purpose with or without fee is hereby granted, provided that the above | |
11 | * copyright notice and this permission notice appear in all copies. | |
12 | * | |
13 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
14 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
15 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
16 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
17 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
18 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
19 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
20 | * | |
21 | */ | |
22 | ||
23 | /*********************************\ | |
24 | * Protocol Control Unit Functions * | |
25 | \*********************************/ | |
26 | ||
bcd8f54a LR |
27 | #include <asm/unaligned.h> |
28 | ||
c6e387a2 NK |
29 | #include "ath5k.h" |
30 | #include "reg.h" | |
31 | #include "debug.h" | |
32 | #include "base.h" | |
33 | ||
34 | /*******************\ | |
9320b5c4 | 35 | * Helper functions * |
c6e387a2 NK |
36 | \*******************/ |
37 | ||
38 | /** | |
9320b5c4 | 39 | * ath5k_hw_get_default_slottime - Get the default slot time for current mode |
c6e387a2 NK |
40 | * |
41 | * @ah: The &struct ath5k_hw | |
c6e387a2 | 42 | */ |
9320b5c4 | 43 | static unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah) |
c6e387a2 | 44 | { |
9320b5c4 | 45 | struct ieee80211_channel *channel = ah->ah_current_channel; |
3017fcab | 46 | unsigned int slot_time; |
c6e387a2 | 47 | |
3017fcab NK |
48 | switch (ah->ah_bwmode) { |
49 | case AR5K_BWMODE_40MHZ: | |
50 | slot_time = AR5K_INIT_SLOT_TIME_TURBO; | |
51 | break; | |
52 | case AR5K_BWMODE_10MHZ: | |
53 | slot_time = AR5K_INIT_SLOT_TIME_HALF_RATE; | |
54 | break; | |
55 | case AR5K_BWMODE_5MHZ: | |
56 | slot_time = AR5K_INIT_SLOT_TIME_QUARTER_RATE; | |
57 | break; | |
58 | case AR5K_BWMODE_DEFAULT: | |
59 | slot_time = AR5K_INIT_SLOT_TIME_DEFAULT; | |
60 | default: | |
61 | if (channel->hw_value & CHANNEL_CCK) | |
62 | slot_time = AR5K_INIT_SLOT_TIME_B; | |
63 | break; | |
64 | } | |
c6e387a2 | 65 | |
3017fcab | 66 | return slot_time; |
9320b5c4 | 67 | } |
c6e387a2 | 68 | |
9320b5c4 NK |
69 | /** |
70 | * ath5k_hw_get_default_sifs - Get the default SIFS for current mode | |
71 | * | |
72 | * @ah: The &struct ath5k_hw | |
73 | */ | |
3017fcab | 74 | unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah) |
9320b5c4 NK |
75 | { |
76 | struct ieee80211_channel *channel = ah->ah_current_channel; | |
3017fcab | 77 | unsigned int sifs; |
c6e387a2 | 78 | |
3017fcab NK |
79 | switch (ah->ah_bwmode) { |
80 | case AR5K_BWMODE_40MHZ: | |
81 | sifs = AR5K_INIT_SIFS_TURBO; | |
82 | break; | |
83 | case AR5K_BWMODE_10MHZ: | |
84 | sifs = AR5K_INIT_SIFS_HALF_RATE; | |
85 | break; | |
86 | case AR5K_BWMODE_5MHZ: | |
87 | sifs = AR5K_INIT_SIFS_QUARTER_RATE; | |
88 | break; | |
89 | case AR5K_BWMODE_DEFAULT: | |
90 | sifs = AR5K_INIT_SIFS_DEFAULT_BG; | |
91 | default: | |
92 | if (channel->hw_value & CHANNEL_5GHZ) | |
93 | sifs = AR5K_INIT_SIFS_DEFAULT_A; | |
94 | break; | |
95 | } | |
c6e387a2 | 96 | |
3017fcab | 97 | return sifs; |
c6e387a2 NK |
98 | } |
99 | ||
100 | /** | |
9320b5c4 | 101 | * ath5k_hw_update_mib_counters - Update MIB counters (mac layer statistics) |
c6e387a2 NK |
102 | * |
103 | * @ah: The &struct ath5k_hw | |
c6e387a2 | 104 | * |
495391d7 BR |
105 | * Reads MIB counters from PCU and updates sw statistics. Is called after a |
106 | * MIB interrupt, because one of these counters might have reached their maximum | |
107 | * and triggered the MIB interrupt, to let us read and clear the counter. | |
108 | * | |
109 | * Is called in interrupt context! | |
c6e387a2 | 110 | */ |
495391d7 | 111 | void ath5k_hw_update_mib_counters(struct ath5k_hw *ah) |
c6e387a2 | 112 | { |
495391d7 | 113 | struct ath5k_statistics *stats = &ah->ah_sc->stats; |
c6e387a2 NK |
114 | |
115 | /* Read-And-Clear */ | |
495391d7 BR |
116 | stats->ack_fail += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL); |
117 | stats->rts_fail += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL); | |
118 | stats->rts_ok += ath5k_hw_reg_read(ah, AR5K_RTS_OK); | |
119 | stats->fcs_error += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL); | |
120 | stats->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT); | |
c6e387a2 NK |
121 | } |
122 | ||
123 | /** | |
124 | * ath5k_hw_set_ack_bitrate - set bitrate for ACKs | |
125 | * | |
126 | * @ah: The &struct ath5k_hw | |
8801df86 | 127 | * @high: Flag to determine if we want to use high transmission rate |
c6e387a2 NK |
128 | * for ACKs or not |
129 | * | |
130 | * If high flag is set, we tell hw to use a set of control rates based on | |
8801df86 | 131 | * the current transmission rate (check out control_rates array inside reset.c). |
c6e387a2 NK |
132 | * If not hw just uses the lowest rate available for the current modulation |
133 | * scheme being used (1Mbit for CCK and 6Mbits for OFDM). | |
134 | */ | |
135 | void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high) | |
136 | { | |
137 | if (ah->ah_version != AR5K_AR5212) | |
138 | return; | |
139 | else { | |
140 | u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB; | |
141 | if (high) | |
c6e387a2 | 142 | AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val); |
0edc9a67 BR |
143 | else |
144 | AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val); | |
c6e387a2 NK |
145 | } |
146 | } | |
147 | ||
148 | ||
149 | /******************\ | |
150 | * ACK/CTS Timeouts * | |
151 | \******************/ | |
152 | ||
9320b5c4 NK |
153 | /* |
154 | * index into rates for control rates, we can set it up like this because | |
155 | * this is only used for AR5212 and we know it supports G mode | |
156 | */ | |
157 | static const unsigned int control_rates[] = | |
158 | { 0, 1, 1, 1, 4, 4, 6, 6, 8, 8, 8, 8 }; | |
159 | ||
160 | /** | |
161 | * ath5k_hw_write_rate_duration - fill rate code to duration table | |
162 | * | |
163 | * @ah: the &struct ath5k_hw | |
164 | * @mode: one of enum ath5k_driver_mode | |
165 | * | |
166 | * Write the rate code to duration table upon hw reset. This is a helper for | |
167 | * ath5k_hw_reset(). It seems all this is doing is setting an ACK timeout on | |
168 | * the hardware, based on current mode, for each rate. The rates which are | |
169 | * capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have | |
170 | * different rate code so we write their value twice (one for long preamble | |
171 | * and one for short). | |
172 | * | |
173 | * Note: Band doesn't matter here, if we set the values for OFDM it works | |
174 | * on both a and g modes. So all we have to do is set values for all g rates | |
175 | * that include all OFDM and CCK rates. If we operate in turbo or xr/half/ | |
176 | * quarter rate mode, we need to use another set of bitrates (that's why we | |
177 | * need the mode parameter) but we don't handle these proprietary modes yet. | |
178 | */ | |
179 | static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah, | |
180 | unsigned int mode) | |
181 | { | |
182 | struct ath5k_softc *sc = ah->ah_sc; | |
183 | struct ieee80211_rate *rate; | |
184 | unsigned int i; | |
185 | ||
186 | /* Write rate duration table */ | |
187 | for (i = 0; i < sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates; i++) { | |
188 | u32 reg; | |
189 | u16 tx_time; | |
190 | ||
191 | rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[control_rates[i]]; | |
192 | ||
193 | /* Set ACK timeout */ | |
194 | reg = AR5K_RATE_DUR(rate->hw_value); | |
195 | ||
196 | /* An ACK frame consists of 10 bytes. If you add the FCS, | |
197 | * which ieee80211_generic_frame_duration() adds, | |
198 | * its 14 bytes. Note we use the control rate and not the | |
199 | * actual rate for this rate. See mac80211 tx.c | |
200 | * ieee80211_duration() for a brief description of | |
201 | * what rate we should choose to TX ACKs. */ | |
202 | tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw, | |
203 | NULL, 10, rate)); | |
204 | ||
205 | ath5k_hw_reg_write(ah, tx_time, reg); | |
206 | ||
207 | if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)) | |
208 | continue; | |
209 | ||
210 | /* | |
211 | * We're not distinguishing short preamble here, | |
212 | * This is true, all we'll get is a longer value here | |
213 | * which is not necessarilly bad. We could use | |
214 | * export ieee80211_frame_duration() but that needs to be | |
215 | * fixed first to be properly used by mac802111 drivers: | |
216 | * | |
217 | * - remove erp stuff and let the routine figure ofdm | |
218 | * erp rates | |
219 | * - remove passing argument ieee80211_local as | |
220 | * drivers don't have access to it | |
221 | * - move drivers using ieee80211_generic_frame_duration() | |
222 | * to this | |
223 | */ | |
224 | ath5k_hw_reg_write(ah, tx_time, | |
225 | reg + (AR5K_SET_SHORT_PREAMBLE << 2)); | |
226 | } | |
227 | } | |
228 | ||
c6e387a2 NK |
229 | /** |
230 | * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU | |
231 | * | |
232 | * @ah: The &struct ath5k_hw | |
233 | * @timeout: Timeout in usec | |
234 | */ | |
626ede6b | 235 | static int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) |
c6e387a2 | 236 | { |
3578e6eb LT |
237 | if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK)) |
238 | <= timeout) | |
c6e387a2 NK |
239 | return -EINVAL; |
240 | ||
241 | AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK, | |
3578e6eb | 242 | ath5k_hw_htoclock(ah, timeout)); |
c6e387a2 NK |
243 | |
244 | return 0; | |
245 | } | |
246 | ||
c6e387a2 NK |
247 | /** |
248 | * ath5k_hw_set_cts_timeout - Set CTS timeout on PCU | |
249 | * | |
250 | * @ah: The &struct ath5k_hw | |
251 | * @timeout: Timeout in usec | |
252 | */ | |
626ede6b | 253 | static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) |
c6e387a2 | 254 | { |
3578e6eb LT |
255 | if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS)) |
256 | <= timeout) | |
c6e387a2 NK |
257 | return -EINVAL; |
258 | ||
259 | AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS, | |
3578e6eb | 260 | ath5k_hw_htoclock(ah, timeout)); |
c6e387a2 NK |
261 | |
262 | return 0; | |
263 | } | |
264 | ||
6e08d228 | 265 | |
9320b5c4 NK |
266 | /*******************\ |
267 | * RX filter Control * | |
268 | \*******************/ | |
6e08d228 | 269 | |
c6e387a2 NK |
270 | /** |
271 | * ath5k_hw_set_lladdr - Set station id | |
272 | * | |
273 | * @ah: The &struct ath5k_hw | |
274 | * @mac: The card's mac address | |
275 | * | |
276 | * Set station id on hw using the provided mac address | |
277 | */ | |
278 | int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) | |
279 | { | |
954fecea | 280 | struct ath_common *common = ath5k_hw_common(ah); |
c6e387a2 | 281 | u32 low_id, high_id; |
f6bac3ea | 282 | u32 pcu_reg; |
c6e387a2 | 283 | |
c6e387a2 | 284 | /* Set new station ID */ |
954fecea | 285 | memcpy(common->macaddr, mac, ETH_ALEN); |
c6e387a2 | 286 | |
f6bac3ea BC |
287 | pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; |
288 | ||
bcd8f54a LR |
289 | low_id = get_unaligned_le32(mac); |
290 | high_id = get_unaligned_le16(mac + 4); | |
c6e387a2 NK |
291 | |
292 | ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); | |
f6bac3ea | 293 | ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); |
c6e387a2 NK |
294 | |
295 | return 0; | |
296 | } | |
297 | ||
298 | /** | |
418de6d9 | 299 | * ath5k_hw_set_bssid - Set current BSSID on hw |
c6e387a2 NK |
300 | * |
301 | * @ah: The &struct ath5k_hw | |
c6e387a2 | 302 | * |
418de6d9 NK |
303 | * Sets the current BSSID and BSSID mask we have from the |
304 | * common struct into the hardware | |
c6e387a2 | 305 | */ |
418de6d9 | 306 | void ath5k_hw_set_bssid(struct ath5k_hw *ah) |
c6e387a2 | 307 | { |
954fecea | 308 | struct ath_common *common = ath5k_hw_common(ah); |
c6e387a2 NK |
309 | u16 tim_offset = 0; |
310 | ||
311 | /* | |
418de6d9 | 312 | * Set BSSID mask on 5212 |
c6e387a2 | 313 | */ |
a72d57a8 LR |
314 | if (ah->ah_version == AR5K_AR5212) |
315 | ath_hw_setbssidmask(common); | |
c6e387a2 NK |
316 | |
317 | /* | |
418de6d9 | 318 | * Set BSSID |
c6e387a2 | 319 | */ |
abba0686 LR |
320 | ath5k_hw_reg_write(ah, |
321 | get_unaligned_le32(common->curbssid), | |
a3f86bff | 322 | AR5K_BSS_ID0); |
abba0686 LR |
323 | ath5k_hw_reg_write(ah, |
324 | get_unaligned_le16(common->curbssid + 4) | | |
325 | ((common->curaid & 0x3fff) << AR5K_BSS_ID1_AID_S), | |
a3f86bff | 326 | AR5K_BSS_ID1); |
c6e387a2 | 327 | |
be5d6b75 | 328 | if (common->curaid == 0) { |
c6e387a2 NK |
329 | ath5k_hw_disable_pspoll(ah); |
330 | return; | |
331 | } | |
332 | ||
333 | AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM, | |
abba0686 | 334 | tim_offset ? tim_offset + 4 : 0); |
c6e387a2 NK |
335 | |
336 | ath5k_hw_enable_pspoll(ah, NULL, 0); | |
337 | } | |
338 | ||
13b81559 | 339 | void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) |
c6e387a2 | 340 | { |
954fecea | 341 | struct ath_common *common = ath5k_hw_common(ah); |
c6e387a2 | 342 | |
f07a6c49 NK |
343 | /* Cache bssid mask so that we can restore it |
344 | * on reset */ | |
954fecea | 345 | memcpy(common->bssidmask, mask, ETH_ALEN); |
13b81559 LR |
346 | if (ah->ah_version == AR5K_AR5212) |
347 | ath_hw_setbssidmask(common); | |
c6e387a2 NK |
348 | } |
349 | ||
c6e387a2 NK |
350 | /* |
351 | * Set multicast filter | |
352 | */ | |
353 | void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1) | |
354 | { | |
c6e387a2 NK |
355 | ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0); |
356 | ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1); | |
357 | } | |
358 | ||
c6e387a2 NK |
359 | /** |
360 | * ath5k_hw_get_rx_filter - Get current rx filter | |
361 | * | |
362 | * @ah: The &struct ath5k_hw | |
363 | * | |
364 | * Returns the RX filter by reading rx filter and | |
365 | * phy error filter registers. RX filter is used | |
366 | * to set the allowed frame types that PCU will accept | |
367 | * and pass to the driver. For a list of frame types | |
368 | * check out reg.h. | |
369 | */ | |
370 | u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah) | |
371 | { | |
372 | u32 data, filter = 0; | |
373 | ||
c6e387a2 NK |
374 | filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER); |
375 | ||
376 | /*Radar detection for 5212*/ | |
377 | if (ah->ah_version == AR5K_AR5212) { | |
378 | data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL); | |
379 | ||
380 | if (data & AR5K_PHY_ERR_FIL_RADAR) | |
381 | filter |= AR5K_RX_FILTER_RADARERR; | |
382 | if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK)) | |
383 | filter |= AR5K_RX_FILTER_PHYERR; | |
384 | } | |
385 | ||
386 | return filter; | |
387 | } | |
388 | ||
389 | /** | |
390 | * ath5k_hw_set_rx_filter - Set rx filter | |
391 | * | |
392 | * @ah: The &struct ath5k_hw | |
393 | * @filter: RX filter mask (see reg.h) | |
394 | * | |
395 | * Sets RX filter register and also handles PHY error filter | |
396 | * register on 5212 and newer chips so that we have proper PHY | |
397 | * error reporting. | |
398 | */ | |
399 | void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) | |
400 | { | |
401 | u32 data = 0; | |
402 | ||
c6e387a2 NK |
403 | /* Set PHY error filter register on 5212*/ |
404 | if (ah->ah_version == AR5K_AR5212) { | |
405 | if (filter & AR5K_RX_FILTER_RADARERR) | |
406 | data |= AR5K_PHY_ERR_FIL_RADAR; | |
407 | if (filter & AR5K_RX_FILTER_PHYERR) | |
408 | data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK; | |
409 | } | |
410 | ||
411 | /* | |
412 | * The AR5210 uses promiscous mode to detect radar activity | |
413 | */ | |
414 | if (ah->ah_version == AR5K_AR5210 && | |
415 | (filter & AR5K_RX_FILTER_RADARERR)) { | |
416 | filter &= ~AR5K_RX_FILTER_RADARERR; | |
417 | filter |= AR5K_RX_FILTER_PROM; | |
418 | } | |
419 | ||
f07a6c49 | 420 | /*Zero length DMA (phy error reporting) */ |
c6e387a2 NK |
421 | if (data) |
422 | AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); | |
423 | else | |
424 | AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); | |
425 | ||
426 | /*Write RX Filter register*/ | |
427 | ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER); | |
428 | ||
429 | /*Write PHY error filter register on 5212*/ | |
430 | if (ah->ah_version == AR5K_AR5212) | |
431 | ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL); | |
432 | ||
433 | } | |
434 | ||
435 | ||
436 | /****************\ | |
437 | * Beacon control * | |
438 | \****************/ | |
439 | ||
1c0fc65e BP |
440 | #define ATH5K_MAX_TSF_READ 10 |
441 | ||
c6e387a2 NK |
442 | /** |
443 | * ath5k_hw_get_tsf64 - Get the full 64bit TSF | |
444 | * | |
445 | * @ah: The &struct ath5k_hw | |
446 | * | |
447 | * Returns the current TSF | |
448 | */ | |
449 | u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) | |
450 | { | |
1c0fc65e BP |
451 | u32 tsf_lower, tsf_upper1, tsf_upper2; |
452 | int i; | |
28df897a BR |
453 | unsigned long flags; |
454 | ||
455 | /* This code is time critical - we don't want to be interrupted here */ | |
456 | local_irq_save(flags); | |
1c0fc65e BP |
457 | |
458 | /* | |
459 | * While reading TSF upper and then lower part, the clock is still | |
460 | * counting (or jumping in case of IBSS merge) so we might get | |
461 | * inconsistent values. To avoid this, we read the upper part again | |
462 | * and check it has not been changed. We make the hypothesis that a | |
463 | * maximum of 3 changes can happens in a row (we use 10 as a safe | |
464 | * value). | |
465 | * | |
466 | * Impact on performance is pretty small, since in most cases, only | |
467 | * 3 register reads are needed. | |
468 | */ | |
469 | ||
470 | tsf_upper1 = ath5k_hw_reg_read(ah, AR5K_TSF_U32); | |
471 | for (i = 0; i < ATH5K_MAX_TSF_READ; i++) { | |
472 | tsf_lower = ath5k_hw_reg_read(ah, AR5K_TSF_L32); | |
473 | tsf_upper2 = ath5k_hw_reg_read(ah, AR5K_TSF_U32); | |
474 | if (tsf_upper2 == tsf_upper1) | |
475 | break; | |
476 | tsf_upper1 = tsf_upper2; | |
477 | } | |
478 | ||
28df897a BR |
479 | local_irq_restore(flags); |
480 | ||
1c0fc65e BP |
481 | WARN_ON( i == ATH5K_MAX_TSF_READ ); |
482 | ||
1c0fc65e | 483 | return (((u64)tsf_upper1 << 32) | tsf_lower); |
c6e387a2 NK |
484 | } |
485 | ||
8cab7581 AF |
486 | /** |
487 | * ath5k_hw_set_tsf64 - Set a new 64bit TSF | |
488 | * | |
489 | * @ah: The &struct ath5k_hw | |
490 | * @tsf64: The new 64bit TSF | |
491 | * | |
492 | * Sets the new TSF | |
493 | */ | |
494 | void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64) | |
495 | { | |
8cab7581 | 496 | ath5k_hw_reg_write(ah, tsf64 & 0xffffffff, AR5K_TSF_L32); |
0ad65bd7 | 497 | ath5k_hw_reg_write(ah, (tsf64 >> 32) & 0xffffffff, AR5K_TSF_U32); |
8cab7581 AF |
498 | } |
499 | ||
c6e387a2 NK |
500 | /** |
501 | * ath5k_hw_reset_tsf - Force a TSF reset | |
502 | * | |
503 | * @ah: The &struct ath5k_hw | |
504 | * | |
505 | * Forces a TSF reset on PCU | |
506 | */ | |
507 | void ath5k_hw_reset_tsf(struct ath5k_hw *ah) | |
508 | { | |
14be9947 BC |
509 | u32 val; |
510 | ||
14be9947 BC |
511 | val = ath5k_hw_reg_read(ah, AR5K_BEACON) | AR5K_BEACON_RESET_TSF; |
512 | ||
513 | /* | |
514 | * Each write to the RESET_TSF bit toggles a hardware internal | |
515 | * signal to reset TSF, but if left high it will cause a TSF reset | |
516 | * on the next chip reset as well. Thus we always write the value | |
517 | * twice to clear the signal. | |
518 | */ | |
519 | ath5k_hw_reg_write(ah, val, AR5K_BEACON); | |
520 | ath5k_hw_reg_write(ah, val, AR5K_BEACON); | |
c6e387a2 NK |
521 | } |
522 | ||
523 | /* | |
524 | * Initialize beacon timers | |
525 | */ | |
526 | void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) | |
527 | { | |
528 | u32 timer1, timer2, timer3; | |
529 | ||
c6e387a2 NK |
530 | /* |
531 | * Set the additional timers by mode | |
532 | */ | |
ccfe5552 | 533 | switch (ah->ah_sc->opmode) { |
f07a6c49 | 534 | case NL80211_IFTYPE_MONITOR: |
05c914fe | 535 | case NL80211_IFTYPE_STATION: |
f07a6c49 NK |
536 | /* In STA mode timer1 is used as next wakeup |
537 | * timer and timer2 as next CFP duration start | |
538 | * timer. Both in 1/8TUs. */ | |
539 | /* TODO: PCF handling */ | |
c6e387a2 NK |
540 | if (ah->ah_version == AR5K_AR5210) { |
541 | timer1 = 0xffffffff; | |
542 | timer2 = 0xffffffff; | |
543 | } else { | |
544 | timer1 = 0x0000ffff; | |
545 | timer2 = 0x0007ffff; | |
546 | } | |
f07a6c49 NK |
547 | /* Mark associated AP as PCF incapable for now */ |
548 | AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PCF); | |
c6e387a2 | 549 | break; |
f07a6c49 NK |
550 | case NL80211_IFTYPE_ADHOC: |
551 | AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_ADHOC_BCN_ATIM); | |
c6e387a2 | 552 | default: |
f07a6c49 NK |
553 | /* On non-STA modes timer1 is used as next DMA |
554 | * beacon alert (DBA) timer and timer2 as next | |
555 | * software beacon alert. Both in 1/8TUs. */ | |
c6e387a2 NK |
556 | timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3; |
557 | timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3; | |
f07a6c49 | 558 | break; |
c6e387a2 NK |
559 | } |
560 | ||
f07a6c49 NK |
561 | /* Timer3 marks the end of our ATIM window |
562 | * a zero length window is not allowed because | |
563 | * we 'll get no beacons */ | |
4a79f2c5 | 564 | timer3 = next_beacon + 1; |
c6e387a2 NK |
565 | |
566 | /* | |
567 | * Set the beacon register and enable all timers. | |
c6e387a2 | 568 | */ |
35edf8aa | 569 | /* When in AP or Mesh Point mode zero timer0 to start TSF */ |
ccfe5552 BR |
570 | if (ah->ah_sc->opmode == NL80211_IFTYPE_AP || |
571 | ah->ah_sc->opmode == NL80211_IFTYPE_MESH_POINT) | |
f07a6c49 | 572 | ath5k_hw_reg_write(ah, 0, AR5K_TIMER0); |
428cbd4f NK |
573 | |
574 | ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0); | |
c6e387a2 NK |
575 | ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1); |
576 | ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2); | |
577 | ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3); | |
578 | ||
f07a6c49 NK |
579 | /* Force a TSF reset if requested and enable beacons */ |
580 | if (interval & AR5K_BEACON_RESET_TSF) | |
581 | ath5k_hw_reset_tsf(ah); | |
582 | ||
c6e387a2 | 583 | ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD | |
f07a6c49 NK |
584 | AR5K_BEACON_ENABLE), |
585 | AR5K_BEACON); | |
586 | ||
587 | /* Flush any pending BMISS interrupts on ISR by | |
588 | * performing a clear-on-write operation on PISR | |
589 | * register for the BMISS bit (writing a bit on | |
590 | * ISR togles a reset for that bit and leaves | |
591 | * the rest bits intact) */ | |
592 | if (ah->ah_version == AR5K_AR5210) | |
593 | ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_ISR); | |
594 | else | |
595 | ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_PISR); | |
596 | ||
597 | /* TODO: Set enchanced sleep registers on AR5212 | |
598 | * based on vif->bss_conf params, until then | |
599 | * disable power save reporting.*/ | |
600 | AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PWR_SV); | |
601 | ||
c6e387a2 NK |
602 | } |
603 | ||
7f896126 BR |
604 | /** |
605 | * ath5k_check_timer_win - Check if timer B is timer A + window | |
606 | * | |
607 | * @a: timer a (before b) | |
608 | * @b: timer b (after a) | |
609 | * @window: difference between a and b | |
610 | * @intval: timers are increased by this interval | |
611 | * | |
612 | * This helper function checks if timer B is timer A + window and covers | |
613 | * cases where timer A or B might have already been updated or wrapped | |
614 | * around (Timers are 16 bit). | |
615 | * | |
616 | * Returns true if O.K. | |
617 | */ | |
618 | static inline bool | |
619 | ath5k_check_timer_win(int a, int b, int window, int intval) | |
620 | { | |
621 | /* | |
622 | * 1.) usually B should be A + window | |
623 | * 2.) A already updated, B not updated yet | |
624 | * 3.) A already updated and has wrapped around | |
625 | * 4.) B has wrapped around | |
626 | */ | |
627 | if ((b - a == window) || /* 1.) */ | |
628 | (a - b == intval - window) || /* 2.) */ | |
629 | ((a | 0x10000) - b == intval - window) || /* 3.) */ | |
630 | ((b | 0x10000) - a == window)) /* 4.) */ | |
631 | return true; /* O.K. */ | |
632 | return false; | |
633 | } | |
634 | ||
635 | /** | |
636 | * ath5k_hw_check_beacon_timers - Check if the beacon timers are correct | |
637 | * | |
638 | * @ah: The &struct ath5k_hw | |
639 | * @intval: beacon interval | |
640 | * | |
641 | * This is a workaround for IBSS mode: | |
642 | * | |
643 | * The need for this function arises from the fact that we have 4 separate | |
644 | * HW timer registers (TIMER0 - TIMER3), which are closely related to the | |
645 | * next beacon target time (NBTT), and that the HW updates these timers | |
646 | * seperately based on the current TSF value. The hardware increments each | |
647 | * timer by the beacon interval, when the local TSF coverted to TU is equal | |
648 | * to the value stored in the timer. | |
649 | * | |
650 | * The reception of a beacon with the same BSSID can update the local HW TSF | |
651 | * at any time - this is something we can't avoid. If the TSF jumps to a | |
652 | * time which is later than the time stored in a timer, this timer will not | |
653 | * be updated until the TSF in TU wraps around at 16 bit (the size of the | |
654 | * timers) and reaches the time which is stored in the timer. | |
655 | * | |
656 | * The problem is that these timers are closely related to TIMER0 (NBTT) and | |
657 | * that they define a time "window". When the TSF jumps between two timers | |
658 | * (e.g. ATIM and NBTT), the one in the past will be left behind (not | |
659 | * updated), while the one in the future will be updated every beacon | |
660 | * interval. This causes the window to get larger, until the TSF wraps | |
661 | * around as described above and the timer which was left behind gets | |
662 | * updated again. But - because the beacon interval is usually not an exact | |
663 | * divisor of the size of the timers (16 bit), an unwanted "window" between | |
664 | * these timers has developed! | |
665 | * | |
666 | * This is especially important with the ATIM window, because during | |
667 | * the ATIM window only ATIM frames and no data frames are allowed to be | |
668 | * sent, which creates transmission pauses after each beacon. This symptom | |
669 | * has been described as "ramping ping" because ping times increase linearly | |
670 | * for some time and then drop down again. A wrong window on the DMA beacon | |
671 | * timer has the same effect, so we check for these two conditions. | |
672 | * | |
673 | * Returns true if O.K. | |
674 | */ | |
675 | bool | |
676 | ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval) | |
677 | { | |
678 | unsigned int nbtt, atim, dma; | |
679 | ||
680 | nbtt = ath5k_hw_reg_read(ah, AR5K_TIMER0); | |
681 | atim = ath5k_hw_reg_read(ah, AR5K_TIMER3); | |
682 | dma = ath5k_hw_reg_read(ah, AR5K_TIMER1) >> 3; | |
683 | ||
684 | /* NOTE: SWBA is different. Having a wrong window there does not | |
685 | * stop us from sending data and this condition is catched thru | |
686 | * other means (SWBA interrupt) */ | |
687 | ||
688 | if (ath5k_check_timer_win(nbtt, atim, 1, intval) && | |
689 | ath5k_check_timer_win(dma, nbtt, AR5K_TUNE_DMA_BEACON_RESP, | |
690 | intval)) | |
691 | return true; /* O.K. */ | |
692 | return false; | |
693 | } | |
694 | ||
6e08d228 LT |
695 | /** |
696 | * ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class | |
697 | * | |
698 | * @ah: The &struct ath5k_hw | |
699 | * @coverage_class: IEEE 802.11 coverage class number | |
700 | * | |
701 | * Sets slot time, ACK timeout and CTS timeout for given coverage class. | |
702 | */ | |
703 | void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class) | |
704 | { | |
705 | /* As defined by IEEE 802.11-2007 17.3.8.6 */ | |
706 | int slot_time = ath5k_hw_get_default_slottime(ah) + 3 * coverage_class; | |
707 | int ack_timeout = ath5k_hw_get_default_sifs(ah) + slot_time; | |
708 | int cts_timeout = ack_timeout; | |
709 | ||
710 | ath5k_hw_set_slot_time(ah, slot_time); | |
711 | ath5k_hw_set_ack_timeout(ah, ack_timeout); | |
712 | ath5k_hw_set_cts_timeout(ah, cts_timeout); | |
713 | ||
714 | ah->ah_coverage_class = coverage_class; | |
715 | } | |
9320b5c4 NK |
716 | |
717 | /***************************\ | |
718 | * Init/Start/Stop functions * | |
719 | \***************************/ | |
720 | ||
721 | /** | |
722 | * ath5k_hw_start_rx_pcu - Start RX engine | |
723 | * | |
724 | * @ah: The &struct ath5k_hw | |
725 | * | |
726 | * Starts RX engine on PCU so that hw can process RXed frames | |
727 | * (ACK etc). | |
728 | * | |
729 | * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma | |
730 | */ | |
731 | void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) | |
732 | { | |
733 | AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); | |
734 | } | |
735 | ||
736 | /** | |
737 | * at5k_hw_stop_rx_pcu - Stop RX engine | |
738 | * | |
739 | * @ah: The &struct ath5k_hw | |
740 | * | |
741 | * Stops RX engine on PCU | |
742 | */ | |
743 | void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah) | |
744 | { | |
745 | AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); | |
746 | } | |
747 | ||
748 | /** | |
749 | * ath5k_hw_set_opmode - Set PCU operating mode | |
750 | * | |
751 | * @ah: The &struct ath5k_hw | |
752 | * @op_mode: &enum nl80211_iftype operating mode | |
753 | * | |
754 | * Configure PCU for the various operating modes (AP/STA etc) | |
755 | */ | |
756 | int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) | |
757 | { | |
758 | struct ath_common *common = ath5k_hw_common(ah); | |
759 | u32 pcu_reg, beacon_reg, low_id, high_id; | |
760 | ||
761 | ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_MODE, "mode %d\n", op_mode); | |
762 | ||
763 | /* Preserve rest settings */ | |
764 | pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; | |
765 | pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP | |
766 | | AR5K_STA_ID1_KEYSRCH_MODE | |
767 | | (ah->ah_version == AR5K_AR5210 ? | |
768 | (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0)); | |
769 | ||
770 | beacon_reg = 0; | |
771 | ||
772 | switch (op_mode) { | |
773 | case NL80211_IFTYPE_ADHOC: | |
774 | pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE; | |
775 | beacon_reg |= AR5K_BCR_ADHOC; | |
776 | if (ah->ah_version == AR5K_AR5210) | |
777 | pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; | |
778 | else | |
779 | AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS); | |
780 | break; | |
781 | ||
782 | case NL80211_IFTYPE_AP: | |
783 | case NL80211_IFTYPE_MESH_POINT: | |
784 | pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE; | |
785 | beacon_reg |= AR5K_BCR_AP; | |
786 | if (ah->ah_version == AR5K_AR5210) | |
787 | pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; | |
788 | else | |
789 | AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS); | |
790 | break; | |
791 | ||
792 | case NL80211_IFTYPE_STATION: | |
793 | pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE | |
794 | | (ah->ah_version == AR5K_AR5210 ? | |
795 | AR5K_STA_ID1_PWR_SV : 0); | |
796 | case NL80211_IFTYPE_MONITOR: | |
797 | pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE | |
798 | | (ah->ah_version == AR5K_AR5210 ? | |
799 | AR5K_STA_ID1_NO_PSPOLL : 0); | |
800 | break; | |
801 | ||
802 | default: | |
803 | return -EINVAL; | |
804 | } | |
805 | ||
806 | /* | |
807 | * Set PCU registers | |
808 | */ | |
809 | low_id = get_unaligned_le32(common->macaddr); | |
810 | high_id = get_unaligned_le16(common->macaddr + 4); | |
811 | ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); | |
812 | ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); | |
813 | ||
814 | /* | |
815 | * Set Beacon Control Register on 5210 | |
816 | */ | |
817 | if (ah->ah_version == AR5K_AR5210) | |
818 | ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR); | |
819 | ||
820 | return 0; | |
821 | } | |
822 | ||
823 | void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode, | |
824 | u8 mode) | |
825 | { | |
826 | /* Set bssid and bssid mask */ | |
827 | ath5k_hw_set_bssid(ah); | |
828 | ||
829 | /* Set PCU config */ | |
830 | ath5k_hw_set_opmode(ah, op_mode); | |
831 | ||
832 | /* Write rate duration table only on AR5212 and if | |
833 | * virtual interface has already been brought up | |
834 | * XXX: rethink this after new mode changes to | |
835 | * mac80211 are integrated */ | |
836 | if (ah->ah_version == AR5K_AR5212 && | |
837 | ah->ah_sc->nvifs) | |
838 | ath5k_hw_write_rate_duration(ah, mode); | |
839 | ||
840 | /* Set RSSI/BRSSI thresholds | |
841 | * | |
842 | * Note: If we decide to set this value | |
843 | * dynamicaly, have in mind that when AR5K_RSSI_THR | |
844 | * register is read it might return 0x40 if we haven't | |
845 | * wrote anything to it plus BMISS RSSI threshold is zeroed. | |
846 | * So doing a save/restore procedure here isn't the right | |
847 | * choice. Instead store it on ath5k_hw */ | |
848 | ath5k_hw_reg_write(ah, (AR5K_TUNE_RSSI_THRES | | |
849 | AR5K_TUNE_BMISS_THRES << | |
850 | AR5K_RSSI_THR_BMISS_S), | |
851 | AR5K_RSSI_THR); | |
852 | ||
853 | /* MIC QoS support */ | |
854 | if (ah->ah_mac_srev >= AR5K_SREV_AR2413) { | |
855 | ath5k_hw_reg_write(ah, 0x000100aa, AR5K_MIC_QOS_CTL); | |
856 | ath5k_hw_reg_write(ah, 0x00003210, AR5K_MIC_QOS_SEL); | |
857 | } | |
858 | ||
859 | /* QoS NOACK Policy */ | |
860 | if (ah->ah_version == AR5K_AR5212) { | |
861 | ath5k_hw_reg_write(ah, | |
862 | AR5K_REG_SM(2, AR5K_QOS_NOACK_2BIT_VALUES) | | |
863 | AR5K_REG_SM(5, AR5K_QOS_NOACK_BIT_OFFSET) | | |
864 | AR5K_REG_SM(0, AR5K_QOS_NOACK_BYTE_OFFSET), | |
865 | AR5K_QOS_NOACK); | |
866 | } | |
867 | ||
868 | /* Restore slot time and ACK timeouts */ | |
869 | if (ah->ah_coverage_class > 0) | |
870 | ath5k_hw_set_coverage_class(ah, ah->ah_coverage_class); | |
871 | ||
872 | return; | |
873 | } |