diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/pcu.c')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/pcu.c | 829 |
1 files changed, 454 insertions, 375 deletions
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 86fdb6ddfaaa..712a9ac4000e 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c | |||
@@ -31,87 +31,169 @@ | |||
31 | #include "debug.h" | 31 | #include "debug.h" |
32 | #include "base.h" | 32 | #include "base.h" |
33 | 33 | ||
34 | /* | ||
35 | * AR5212+ can use higher rates for ack transmition | ||
36 | * based on current tx rate instead of the base rate. | ||
37 | * It does this to better utilize channel usage. | ||
38 | * This is a mapping between G rates (that cover both | ||
39 | * CCK and OFDM) and ack rates that we use when setting | ||
40 | * rate -> duration table. This mapping is hw-based so | ||
41 | * don't change anything. | ||
42 | * | ||
43 | * To enable this functionality we must set | ||
44 | * ah->ah_ack_bitrate_high to true else base rate is | ||
45 | * used (1Mb for CCK, 6Mb for OFDM). | ||
46 | */ | ||
47 | static const unsigned int ack_rates_high[] = | ||
48 | /* Tx -> ACK */ | ||
49 | /* 1Mb -> 1Mb */ { 0, | ||
50 | /* 2MB -> 2Mb */ 1, | ||
51 | /* 5.5Mb -> 2Mb */ 1, | ||
52 | /* 11Mb -> 2Mb */ 1, | ||
53 | /* 6Mb -> 6Mb */ 4, | ||
54 | /* 9Mb -> 6Mb */ 4, | ||
55 | /* 12Mb -> 12Mb */ 6, | ||
56 | /* 18Mb -> 12Mb */ 6, | ||
57 | /* 24Mb -> 24Mb */ 8, | ||
58 | /* 36Mb -> 24Mb */ 8, | ||
59 | /* 48Mb -> 24Mb */ 8, | ||
60 | /* 54Mb -> 24Mb */ 8 }; | ||
61 | |||
34 | /*******************\ | 62 | /*******************\ |
35 | * Generic functions * | 63 | * Helper functions * |
36 | \*******************/ | 64 | \*******************/ |
37 | 65 | ||
38 | /** | 66 | /** |
39 | * ath5k_hw_set_opmode - Set PCU operating mode | 67 | * ath5k_hw_get_frame_duration - Get tx time of a frame |
40 | * | 68 | * |
41 | * @ah: The &struct ath5k_hw | 69 | * @ah: The &struct ath5k_hw |
42 | * @op_mode: &enum nl80211_iftype operating mode | 70 | * @len: Frame's length in bytes |
71 | * @rate: The @struct ieee80211_rate | ||
43 | * | 72 | * |
44 | * Initialize PCU for the various operating modes (AP/STA etc) | 73 | * Calculate tx duration of a frame given it's rate and length |
74 | * It extends ieee80211_generic_frame_duration for non standard | ||
75 | * bwmodes. | ||
45 | */ | 76 | */ |
46 | int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) | 77 | int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, |
78 | int len, struct ieee80211_rate *rate, bool shortpre) | ||
47 | { | 79 | { |
48 | struct ath_common *common = ath5k_hw_common(ah); | 80 | struct ath5k_softc *sc = ah->ah_sc; |
49 | u32 pcu_reg, beacon_reg, low_id, high_id; | 81 | int sifs, preamble, plcp_bits, sym_time; |
82 | int bitrate, bits, symbols, symbol_bits; | ||
83 | int dur; | ||
84 | |||
85 | /* Fallback */ | ||
86 | if (!ah->ah_bwmode) { | ||
87 | __le16 raw_dur = ieee80211_generic_frame_duration(sc->hw, | ||
88 | NULL, len, rate); | ||
89 | |||
90 | /* subtract difference between long and short preamble */ | ||
91 | dur = le16_to_cpu(raw_dur); | ||
92 | if (shortpre) | ||
93 | dur -= 96; | ||
94 | |||
95 | return dur; | ||
96 | } | ||
50 | 97 | ||
51 | ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_MODE, "mode %d\n", op_mode); | 98 | bitrate = rate->bitrate; |
99 | preamble = AR5K_INIT_OFDM_PREAMPLE_TIME; | ||
100 | plcp_bits = AR5K_INIT_OFDM_PLCP_BITS; | ||
101 | sym_time = AR5K_INIT_OFDM_SYMBOL_TIME; | ||
52 | 102 | ||
53 | /* Preserve rest settings */ | 103 | switch (ah->ah_bwmode) { |
54 | pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; | 104 | case AR5K_BWMODE_40MHZ: |
55 | pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP | 105 | sifs = AR5K_INIT_SIFS_TURBO; |
56 | | AR5K_STA_ID1_KEYSRCH_MODE | 106 | preamble = AR5K_INIT_OFDM_PREAMBLE_TIME_MIN; |
57 | | (ah->ah_version == AR5K_AR5210 ? | 107 | break; |
58 | (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0)); | 108 | case AR5K_BWMODE_10MHZ: |
109 | sifs = AR5K_INIT_SIFS_HALF_RATE; | ||
110 | preamble *= 2; | ||
111 | sym_time *= 2; | ||
112 | break; | ||
113 | case AR5K_BWMODE_5MHZ: | ||
114 | sifs = AR5K_INIT_SIFS_QUARTER_RATE; | ||
115 | preamble *= 4; | ||
116 | sym_time *= 4; | ||
117 | break; | ||
118 | default: | ||
119 | sifs = AR5K_INIT_SIFS_DEFAULT_BG; | ||
120 | break; | ||
121 | } | ||
59 | 122 | ||
60 | beacon_reg = 0; | 123 | bits = plcp_bits + (len << 3); |
124 | /* Bit rate is in 100Kbits */ | ||
125 | symbol_bits = bitrate * sym_time; | ||
126 | symbols = DIV_ROUND_UP(bits * 10, symbol_bits); | ||
61 | 127 | ||
62 | switch (op_mode) { | 128 | dur = sifs + preamble + (sym_time * symbols); |
63 | case NL80211_IFTYPE_ADHOC: | ||
64 | pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE; | ||
65 | beacon_reg |= AR5K_BCR_ADHOC; | ||
66 | if (ah->ah_version == AR5K_AR5210) | ||
67 | pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; | ||
68 | else | ||
69 | AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS); | ||
70 | break; | ||
71 | 129 | ||
72 | case NL80211_IFTYPE_AP: | 130 | return dur; |
73 | case NL80211_IFTYPE_MESH_POINT: | 131 | } |
74 | pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE; | ||
75 | beacon_reg |= AR5K_BCR_AP; | ||
76 | if (ah->ah_version == AR5K_AR5210) | ||
77 | pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; | ||
78 | else | ||
79 | AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS); | ||
80 | break; | ||
81 | 132 | ||
82 | case NL80211_IFTYPE_STATION: | 133 | /** |
83 | pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE | 134 | * ath5k_hw_get_default_slottime - Get the default slot time for current mode |
84 | | (ah->ah_version == AR5K_AR5210 ? | 135 | * |
85 | AR5K_STA_ID1_PWR_SV : 0); | 136 | * @ah: The &struct ath5k_hw |
86 | case NL80211_IFTYPE_MONITOR: | 137 | */ |
87 | pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE | 138 | unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah) |
88 | | (ah->ah_version == AR5K_AR5210 ? | 139 | { |
89 | AR5K_STA_ID1_NO_PSPOLL : 0); | 140 | struct ieee80211_channel *channel = ah->ah_current_channel; |
90 | break; | 141 | unsigned int slot_time; |
91 | 142 | ||
143 | switch (ah->ah_bwmode) { | ||
144 | case AR5K_BWMODE_40MHZ: | ||
145 | slot_time = AR5K_INIT_SLOT_TIME_TURBO; | ||
146 | break; | ||
147 | case AR5K_BWMODE_10MHZ: | ||
148 | slot_time = AR5K_INIT_SLOT_TIME_HALF_RATE; | ||
149 | break; | ||
150 | case AR5K_BWMODE_5MHZ: | ||
151 | slot_time = AR5K_INIT_SLOT_TIME_QUARTER_RATE; | ||
152 | break; | ||
153 | case AR5K_BWMODE_DEFAULT: | ||
92 | default: | 154 | default: |
93 | return -EINVAL; | 155 | slot_time = AR5K_INIT_SLOT_TIME_DEFAULT; |
156 | if ((channel->hw_value & CHANNEL_CCK) && !ah->ah_short_slot) | ||
157 | slot_time = AR5K_INIT_SLOT_TIME_B; | ||
158 | break; | ||
94 | } | 159 | } |
95 | 160 | ||
96 | /* | 161 | return slot_time; |
97 | * Set PCU registers | 162 | } |
98 | */ | ||
99 | low_id = get_unaligned_le32(common->macaddr); | ||
100 | high_id = get_unaligned_le16(common->macaddr + 4); | ||
101 | ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); | ||
102 | ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); | ||
103 | 163 | ||
104 | /* | 164 | /** |
105 | * Set Beacon Control Register on 5210 | 165 | * ath5k_hw_get_default_sifs - Get the default SIFS for current mode |
106 | */ | 166 | * |
107 | if (ah->ah_version == AR5K_AR5210) | 167 | * @ah: The &struct ath5k_hw |
108 | ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR); | 168 | */ |
169 | unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah) | ||
170 | { | ||
171 | struct ieee80211_channel *channel = ah->ah_current_channel; | ||
172 | unsigned int sifs; | ||
109 | 173 | ||
110 | return 0; | 174 | switch (ah->ah_bwmode) { |
175 | case AR5K_BWMODE_40MHZ: | ||
176 | sifs = AR5K_INIT_SIFS_TURBO; | ||
177 | break; | ||
178 | case AR5K_BWMODE_10MHZ: | ||
179 | sifs = AR5K_INIT_SIFS_HALF_RATE; | ||
180 | break; | ||
181 | case AR5K_BWMODE_5MHZ: | ||
182 | sifs = AR5K_INIT_SIFS_QUARTER_RATE; | ||
183 | break; | ||
184 | case AR5K_BWMODE_DEFAULT: | ||
185 | sifs = AR5K_INIT_SIFS_DEFAULT_BG; | ||
186 | default: | ||
187 | if (channel->hw_value & CHANNEL_5GHZ) | ||
188 | sifs = AR5K_INIT_SIFS_DEFAULT_A; | ||
189 | break; | ||
190 | } | ||
191 | |||
192 | return sifs; | ||
111 | } | 193 | } |
112 | 194 | ||
113 | /** | 195 | /** |
114 | * ath5k_hw_update - Update MIB counters (mac layer statistics) | 196 | * ath5k_hw_update_mib_counters - Update MIB counters (mac layer statistics) |
115 | * | 197 | * |
116 | * @ah: The &struct ath5k_hw | 198 | * @ah: The &struct ath5k_hw |
117 | * | 199 | * |
@@ -133,35 +215,72 @@ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah) | |||
133 | stats->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT); | 215 | stats->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT); |
134 | } | 216 | } |
135 | 217 | ||
218 | |||
219 | /******************\ | ||
220 | * ACK/CTS Timeouts * | ||
221 | \******************/ | ||
222 | |||
136 | /** | 223 | /** |
137 | * ath5k_hw_set_ack_bitrate - set bitrate for ACKs | 224 | * ath5k_hw_write_rate_duration - fill rate code to duration table |
138 | * | 225 | * |
139 | * @ah: The &struct ath5k_hw | 226 | * @ah: the &struct ath5k_hw |
140 | * @high: Flag to determine if we want to use high transmition rate | 227 | * @mode: one of enum ath5k_driver_mode |
141 | * for ACKs or not | 228 | * |
229 | * Write the rate code to duration table upon hw reset. This is a helper for | ||
230 | * ath5k_hw_pcu_init(). It seems all this is doing is setting an ACK timeout on | ||
231 | * the hardware, based on current mode, for each rate. The rates which are | ||
232 | * capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have | ||
233 | * different rate code so we write their value twice (one for long preamble | ||
234 | * and one for short). | ||
235 | * | ||
236 | * Note: Band doesn't matter here, if we set the values for OFDM it works | ||
237 | * on both a and g modes. So all we have to do is set values for all g rates | ||
238 | * that include all OFDM and CCK rates. | ||
142 | * | 239 | * |
143 | * If high flag is set, we tell hw to use a set of control rates based on | ||
144 | * the current transmition rate (check out control_rates array inside reset.c). | ||
145 | * If not hw just uses the lowest rate available for the current modulation | ||
146 | * scheme being used (1Mbit for CCK and 6Mbits for OFDM). | ||
147 | */ | 240 | */ |
148 | void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high) | 241 | static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah) |
149 | { | 242 | { |
150 | if (ah->ah_version != AR5K_AR5212) | 243 | struct ath5k_softc *sc = ah->ah_sc; |
151 | return; | 244 | struct ieee80211_rate *rate; |
152 | else { | 245 | unsigned int i; |
153 | u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB; | 246 | /* 802.11g covers both OFDM and CCK */ |
154 | if (high) | 247 | u8 band = IEEE80211_BAND_2GHZ; |
155 | AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val); | 248 | |
249 | /* Write rate duration table */ | ||
250 | for (i = 0; i < sc->sbands[band].n_bitrates; i++) { | ||
251 | u32 reg; | ||
252 | u16 tx_time; | ||
253 | |||
254 | if (ah->ah_ack_bitrate_high) | ||
255 | rate = &sc->sbands[band].bitrates[ack_rates_high[i]]; | ||
256 | /* CCK -> 1Mb */ | ||
257 | else if (i < 4) | ||
258 | rate = &sc->sbands[band].bitrates[0]; | ||
259 | /* OFDM -> 6Mb */ | ||
156 | else | 260 | else |
157 | AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val); | 261 | rate = &sc->sbands[band].bitrates[4]; |
158 | } | ||
159 | } | ||
160 | 262 | ||
263 | /* Set ACK timeout */ | ||
264 | reg = AR5K_RATE_DUR(rate->hw_value); | ||
161 | 265 | ||
162 | /******************\ | 266 | /* An ACK frame consists of 10 bytes. If you add the FCS, |
163 | * ACK/CTS Timeouts * | 267 | * which ieee80211_generic_frame_duration() adds, |
164 | \******************/ | 268 | * its 14 bytes. Note we use the control rate and not the |
269 | * actual rate for this rate. See mac80211 tx.c | ||
270 | * ieee80211_duration() for a brief description of | ||
271 | * what rate we should choose to TX ACKs. */ | ||
272 | tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false); | ||
273 | |||
274 | ath5k_hw_reg_write(ah, tx_time, reg); | ||
275 | |||
276 | if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)) | ||
277 | continue; | ||
278 | |||
279 | tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, true); | ||
280 | ath5k_hw_reg_write(ah, tx_time, | ||
281 | reg + (AR5K_SET_SHORT_PREAMBLE << 2)); | ||
282 | } | ||
283 | } | ||
165 | 284 | ||
166 | /** | 285 | /** |
167 | * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU | 286 | * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU |
@@ -199,85 +318,10 @@ static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) | |||
199 | return 0; | 318 | return 0; |
200 | } | 319 | } |
201 | 320 | ||
202 | /** | ||
203 | * ath5k_hw_htoclock - Translate usec to hw clock units | ||
204 | * | ||
205 | * @ah: The &struct ath5k_hw | ||
206 | * @usec: value in microseconds | ||
207 | */ | ||
208 | unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec) | ||
209 | { | ||
210 | return usec * ath5k_hw_get_clockrate(ah); | ||
211 | } | ||
212 | |||
213 | /** | ||
214 | * ath5k_hw_clocktoh - Translate hw clock units to usec | ||
215 | * @clock: value in hw clock units | ||
216 | */ | ||
217 | unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock) | ||
218 | { | ||
219 | return clock / ath5k_hw_get_clockrate(ah); | ||
220 | } | ||
221 | |||
222 | /** | ||
223 | * ath5k_hw_get_clockrate - Get the clock rate for current mode | ||
224 | * | ||
225 | * @ah: The &struct ath5k_hw | ||
226 | */ | ||
227 | unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah) | ||
228 | { | ||
229 | struct ieee80211_channel *channel = ah->ah_current_channel; | ||
230 | int clock; | ||
231 | |||
232 | if (channel->hw_value & CHANNEL_5GHZ) | ||
233 | clock = 40; /* 802.11a */ | ||
234 | else if (channel->hw_value & CHANNEL_CCK) | ||
235 | clock = 22; /* 802.11b */ | ||
236 | else | ||
237 | clock = 44; /* 802.11g */ | ||
238 | |||
239 | /* Clock rate in turbo modes is twice the normal rate */ | ||
240 | if (channel->hw_value & CHANNEL_TURBO) | ||
241 | clock *= 2; | ||
242 | |||
243 | return clock; | ||
244 | } | ||
245 | 321 | ||
246 | /** | 322 | /*******************\ |
247 | * ath5k_hw_get_default_slottime - Get the default slot time for current mode | 323 | * RX filter Control * |
248 | * | 324 | \*******************/ |
249 | * @ah: The &struct ath5k_hw | ||
250 | */ | ||
251 | static unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah) | ||
252 | { | ||
253 | struct ieee80211_channel *channel = ah->ah_current_channel; | ||
254 | |||
255 | if (channel->hw_value & CHANNEL_TURBO) | ||
256 | return 6; /* both turbo modes */ | ||
257 | |||
258 | if (channel->hw_value & CHANNEL_CCK) | ||
259 | return 20; /* 802.11b */ | ||
260 | |||
261 | return 9; /* 802.11 a/g */ | ||
262 | } | ||
263 | |||
264 | /** | ||
265 | * ath5k_hw_get_default_sifs - Get the default SIFS for current mode | ||
266 | * | ||
267 | * @ah: The &struct ath5k_hw | ||
268 | */ | ||
269 | static unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah) | ||
270 | { | ||
271 | struct ieee80211_channel *channel = ah->ah_current_channel; | ||
272 | |||
273 | if (channel->hw_value & CHANNEL_TURBO) | ||
274 | return 8; /* both turbo modes */ | ||
275 | |||
276 | if (channel->hw_value & CHANNEL_5GHZ) | ||
277 | return 16; /* 802.11a */ | ||
278 | |||
279 | return 10; /* 802.11 b/g */ | ||
280 | } | ||
281 | 325 | ||
282 | /** | 326 | /** |
283 | * ath5k_hw_set_lladdr - Set station id | 327 | * ath5k_hw_set_lladdr - Set station id |
@@ -308,27 +352,26 @@ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) | |||
308 | } | 352 | } |
309 | 353 | ||
310 | /** | 354 | /** |
311 | * ath5k_hw_set_associd - Set BSSID for association | 355 | * ath5k_hw_set_bssid - Set current BSSID on hw |
312 | * | 356 | * |
313 | * @ah: The &struct ath5k_hw | 357 | * @ah: The &struct ath5k_hw |
314 | * @bssid: BSSID | ||
315 | * @assoc_id: Assoc id | ||
316 | * | 358 | * |
317 | * Sets the BSSID which trigers the "SME Join" operation | 359 | * Sets the current BSSID and BSSID mask we have from the |
360 | * common struct into the hardware | ||
318 | */ | 361 | */ |
319 | void ath5k_hw_set_associd(struct ath5k_hw *ah) | 362 | void ath5k_hw_set_bssid(struct ath5k_hw *ah) |
320 | { | 363 | { |
321 | struct ath_common *common = ath5k_hw_common(ah); | 364 | struct ath_common *common = ath5k_hw_common(ah); |
322 | u16 tim_offset = 0; | 365 | u16 tim_offset = 0; |
323 | 366 | ||
324 | /* | 367 | /* |
325 | * Set simple BSSID mask on 5212 | 368 | * Set BSSID mask on 5212 |
326 | */ | 369 | */ |
327 | if (ah->ah_version == AR5K_AR5212) | 370 | if (ah->ah_version == AR5K_AR5212) |
328 | ath_hw_setbssidmask(common); | 371 | ath_hw_setbssidmask(common); |
329 | 372 | ||
330 | /* | 373 | /* |
331 | * Set BSSID which triggers the "SME Join" operation | 374 | * Set BSSID |
332 | */ | 375 | */ |
333 | ath5k_hw_reg_write(ah, | 376 | ath5k_hw_reg_write(ah, |
334 | get_unaligned_le32(common->curbssid), | 377 | get_unaligned_le32(common->curbssid), |
@@ -360,39 +403,6 @@ void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) | |||
360 | ath_hw_setbssidmask(common); | 403 | ath_hw_setbssidmask(common); |
361 | } | 404 | } |
362 | 405 | ||
363 | /************\ | ||
364 | * RX Control * | ||
365 | \************/ | ||
366 | |||
367 | /** | ||
368 | * ath5k_hw_start_rx_pcu - Start RX engine | ||
369 | * | ||
370 | * @ah: The &struct ath5k_hw | ||
371 | * | ||
372 | * Starts RX engine on PCU so that hw can process RXed frames | ||
373 | * (ACK etc). | ||
374 | * | ||
375 | * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma | ||
376 | */ | ||
377 | void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) | ||
378 | { | ||
379 | AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); | ||
380 | } | ||
381 | |||
382 | /** | ||
383 | * at5k_hw_stop_rx_pcu - Stop RX engine | ||
384 | * | ||
385 | * @ah: The &struct ath5k_hw | ||
386 | * | ||
387 | * Stops RX engine on PCU | ||
388 | * | ||
389 | * TODO: Detach ANI here | ||
390 | */ | ||
391 | void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah) | ||
392 | { | ||
393 | AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); | ||
394 | } | ||
395 | |||
396 | /* | 406 | /* |
397 | * Set multicast filter | 407 | * Set multicast filter |
398 | */ | 408 | */ |
@@ -455,7 +465,7 @@ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) | |||
455 | } | 465 | } |
456 | 466 | ||
457 | /* | 467 | /* |
458 | * The AR5210 uses promiscous mode to detect radar activity | 468 | * The AR5210 uses promiscuous mode to detect radar activity |
459 | */ | 469 | */ |
460 | if (ah->ah_version == AR5K_AR5210 && | 470 | if (ah->ah_version == AR5K_AR5210 && |
461 | (filter & AR5K_RX_FILTER_RADARERR)) { | 471 | (filter & AR5K_RX_FILTER_RADARERR)) { |
@@ -496,6 +506,10 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) | |||
496 | { | 506 | { |
497 | u32 tsf_lower, tsf_upper1, tsf_upper2; | 507 | u32 tsf_lower, tsf_upper1, tsf_upper2; |
498 | int i; | 508 | int i; |
509 | unsigned long flags; | ||
510 | |||
511 | /* This code is time critical - we don't want to be interrupted here */ | ||
512 | local_irq_save(flags); | ||
499 | 513 | ||
500 | /* | 514 | /* |
501 | * While reading TSF upper and then lower part, the clock is still | 515 | * While reading TSF upper and then lower part, the clock is still |
@@ -518,6 +532,8 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) | |||
518 | tsf_upper1 = tsf_upper2; | 532 | tsf_upper1 = tsf_upper2; |
519 | } | 533 | } |
520 | 534 | ||
535 | local_irq_restore(flags); | ||
536 | |||
521 | WARN_ON( i == ATH5K_MAX_TSF_READ ); | 537 | WARN_ON( i == ATH5K_MAX_TSF_READ ); |
522 | 538 | ||
523 | return (((u64)tsf_upper1 << 32) | tsf_lower); | 539 | return (((u64)tsf_upper1 << 32) | tsf_lower); |
@@ -601,7 +617,7 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) | |||
601 | /* Timer3 marks the end of our ATIM window | 617 | /* Timer3 marks the end of our ATIM window |
602 | * a zero length window is not allowed because | 618 | * a zero length window is not allowed because |
603 | * we 'll get no beacons */ | 619 | * we 'll get no beacons */ |
604 | timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1); | 620 | timer3 = next_beacon + 1; |
605 | 621 | ||
606 | /* | 622 | /* |
607 | * Set the beacon register and enable all timers. | 623 | * Set the beacon register and enable all timers. |
@@ -641,218 +657,281 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) | |||
641 | 657 | ||
642 | } | 658 | } |
643 | 659 | ||
660 | /** | ||
661 | * ath5k_check_timer_win - Check if timer B is timer A + window | ||
662 | * | ||
663 | * @a: timer a (before b) | ||
664 | * @b: timer b (after a) | ||
665 | * @window: difference between a and b | ||
666 | * @intval: timers are increased by this interval | ||
667 | * | ||
668 | * This helper function checks if timer B is timer A + window and covers | ||
669 | * cases where timer A or B might have already been updated or wrapped | ||
670 | * around (Timers are 16 bit). | ||
671 | * | ||
672 | * Returns true if O.K. | ||
673 | */ | ||
674 | static inline bool | ||
675 | ath5k_check_timer_win(int a, int b, int window, int intval) | ||
676 | { | ||
677 | /* | ||
678 | * 1.) usually B should be A + window | ||
679 | * 2.) A already updated, B not updated yet | ||
680 | * 3.) A already updated and has wrapped around | ||
681 | * 4.) B has wrapped around | ||
682 | */ | ||
683 | if ((b - a == window) || /* 1.) */ | ||
684 | (a - b == intval - window) || /* 2.) */ | ||
685 | ((a | 0x10000) - b == intval - window) || /* 3.) */ | ||
686 | ((b | 0x10000) - a == window)) /* 4.) */ | ||
687 | return true; /* O.K. */ | ||
688 | return false; | ||
689 | } | ||
644 | 690 | ||
645 | /*********************\ | 691 | /** |
646 | * Key table functions * | 692 | * ath5k_hw_check_beacon_timers - Check if the beacon timers are correct |
647 | \*********************/ | 693 | * |
648 | 694 | * @ah: The &struct ath5k_hw | |
649 | /* | 695 | * @intval: beacon interval |
650 | * Reset a key entry on the table | 696 | * |
697 | * This is a workaround for IBSS mode: | ||
698 | * | ||
699 | * The need for this function arises from the fact that we have 4 separate | ||
700 | * HW timer registers (TIMER0 - TIMER3), which are closely related to the | ||
701 | * next beacon target time (NBTT), and that the HW updates these timers | ||
702 | * separately based on the current TSF value. The hardware increments each | ||
703 | * timer by the beacon interval, when the local TSF converted to TU is equal | ||
704 | * to the value stored in the timer. | ||
705 | * | ||
706 | * The reception of a beacon with the same BSSID can update the local HW TSF | ||
707 | * at any time - this is something we can't avoid. If the TSF jumps to a | ||
708 | * time which is later than the time stored in a timer, this timer will not | ||
709 | * be updated until the TSF in TU wraps around at 16 bit (the size of the | ||
710 | * timers) and reaches the time which is stored in the timer. | ||
711 | * | ||
712 | * The problem is that these timers are closely related to TIMER0 (NBTT) and | ||
713 | * that they define a time "window". When the TSF jumps between two timers | ||
714 | * (e.g. ATIM and NBTT), the one in the past will be left behind (not | ||
715 | * updated), while the one in the future will be updated every beacon | ||
716 | * interval. This causes the window to get larger, until the TSF wraps | ||
717 | * around as described above and the timer which was left behind gets | ||
718 | * updated again. But - because the beacon interval is usually not an exact | ||
719 | * divisor of the size of the timers (16 bit), an unwanted "window" between | ||
720 | * these timers has developed! | ||
721 | * | ||
722 | * This is especially important with the ATIM window, because during | ||
723 | * the ATIM window only ATIM frames and no data frames are allowed to be | ||
724 | * sent, which creates transmission pauses after each beacon. This symptom | ||
725 | * has been described as "ramping ping" because ping times increase linearly | ||
726 | * for some time and then drop down again. A wrong window on the DMA beacon | ||
727 | * timer has the same effect, so we check for these two conditions. | ||
728 | * | ||
729 | * Returns true if O.K. | ||
651 | */ | 730 | */ |
652 | int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) | 731 | bool |
732 | ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval) | ||
653 | { | 733 | { |
654 | unsigned int i, type; | 734 | unsigned int nbtt, atim, dma; |
655 | u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; | ||
656 | 735 | ||
657 | AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); | 736 | nbtt = ath5k_hw_reg_read(ah, AR5K_TIMER0); |
737 | atim = ath5k_hw_reg_read(ah, AR5K_TIMER3); | ||
738 | dma = ath5k_hw_reg_read(ah, AR5K_TIMER1) >> 3; | ||
658 | 739 | ||
659 | type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry)); | 740 | /* NOTE: SWBA is different. Having a wrong window there does not |
741 | * stop us from sending data and this condition is catched thru | ||
742 | * other means (SWBA interrupt) */ | ||
660 | 743 | ||
661 | for (i = 0; i < AR5K_KEYCACHE_SIZE; i++) | 744 | if (ath5k_check_timer_win(nbtt, atim, 1, intval) && |
662 | ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i)); | 745 | ath5k_check_timer_win(dma, nbtt, AR5K_TUNE_DMA_BEACON_RESP, |
746 | intval)) | ||
747 | return true; /* O.K. */ | ||
748 | return false; | ||
749 | } | ||
663 | 750 | ||
664 | /* Reset associated MIC entry if TKIP | 751 | /** |
665 | * is enabled located at offset (entry + 64) */ | 752 | * ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class |
666 | if (type == AR5K_KEYTABLE_TYPE_TKIP) { | 753 | * |
667 | AR5K_ASSERT_ENTRY(micentry, AR5K_KEYTABLE_SIZE); | 754 | * @ah: The &struct ath5k_hw |
668 | for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++) | 755 | * @coverage_class: IEEE 802.11 coverage class number |
669 | ath5k_hw_reg_write(ah, 0, | 756 | * |
670 | AR5K_KEYTABLE_OFF(micentry, i)); | 757 | * Sets IFS intervals and ACK/CTS timeouts for given coverage class. |
671 | } | 758 | */ |
759 | void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class) | ||
760 | { | ||
761 | /* As defined by IEEE 802.11-2007 17.3.8.6 */ | ||
762 | int slot_time = ath5k_hw_get_default_slottime(ah) + 3 * coverage_class; | ||
763 | int ack_timeout = ath5k_hw_get_default_sifs(ah) + slot_time; | ||
764 | int cts_timeout = ack_timeout; | ||
672 | 765 | ||
673 | /* | 766 | ath5k_hw_set_ifs_intervals(ah, slot_time); |
674 | * Set NULL encryption on AR5212+ | 767 | ath5k_hw_set_ack_timeout(ah, ack_timeout); |
675 | * | 768 | ath5k_hw_set_cts_timeout(ah, cts_timeout); |
676 | * Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5) | ||
677 | * AR5K_KEYTABLE_TYPE_NULL -> 0x00000007 | ||
678 | * | ||
679 | * Note2: Windows driver (ndiswrapper) sets this to | ||
680 | * 0x00000714 instead of 0x00000007 | ||
681 | */ | ||
682 | if (ah->ah_version >= AR5K_AR5211) { | ||
683 | ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, | ||
684 | AR5K_KEYTABLE_TYPE(entry)); | ||
685 | 769 | ||
686 | if (type == AR5K_KEYTABLE_TYPE_TKIP) { | 770 | ah->ah_coverage_class = coverage_class; |
687 | ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, | 771 | } |
688 | AR5K_KEYTABLE_TYPE(micentry)); | ||
689 | } | ||
690 | } | ||
691 | 772 | ||
692 | return 0; | 773 | /***************************\ |
774 | * Init/Start/Stop functions * | ||
775 | \***************************/ | ||
776 | |||
777 | /** | ||
778 | * ath5k_hw_start_rx_pcu - Start RX engine | ||
779 | * | ||
780 | * @ah: The &struct ath5k_hw | ||
781 | * | ||
782 | * Starts RX engine on PCU so that hw can process RXed frames | ||
783 | * (ACK etc). | ||
784 | * | ||
785 | * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma | ||
786 | */ | ||
787 | void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) | ||
788 | { | ||
789 | AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); | ||
693 | } | 790 | } |
694 | 791 | ||
695 | static | 792 | /** |
696 | int ath5k_keycache_type(const struct ieee80211_key_conf *key) | 793 | * at5k_hw_stop_rx_pcu - Stop RX engine |
794 | * | ||
795 | * @ah: The &struct ath5k_hw | ||
796 | * | ||
797 | * Stops RX engine on PCU | ||
798 | */ | ||
799 | void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah) | ||
697 | { | 800 | { |
698 | switch (key->alg) { | 801 | AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); |
699 | case ALG_TKIP: | ||
700 | return AR5K_KEYTABLE_TYPE_TKIP; | ||
701 | case ALG_CCMP: | ||
702 | return AR5K_KEYTABLE_TYPE_CCM; | ||
703 | case ALG_WEP: | ||
704 | if (key->keylen == WLAN_KEY_LEN_WEP40) | ||
705 | return AR5K_KEYTABLE_TYPE_40; | ||
706 | else if (key->keylen == WLAN_KEY_LEN_WEP104) | ||
707 | return AR5K_KEYTABLE_TYPE_104; | ||
708 | return -EINVAL; | ||
709 | default: | ||
710 | return -EINVAL; | ||
711 | } | ||
712 | return -EINVAL; | ||
713 | } | 802 | } |
714 | 803 | ||
715 | /* | 804 | /** |
716 | * Set a key entry on the table | 805 | * ath5k_hw_set_opmode - Set PCU operating mode |
806 | * | ||
807 | * @ah: The &struct ath5k_hw | ||
808 | * @op_mode: &enum nl80211_iftype operating mode | ||
809 | * | ||
810 | * Configure PCU for the various operating modes (AP/STA etc) | ||
717 | */ | 811 | */ |
718 | int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, | 812 | int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) |
719 | const struct ieee80211_key_conf *key, const u8 *mac) | ||
720 | { | 813 | { |
721 | unsigned int i; | 814 | struct ath_common *common = ath5k_hw_common(ah); |
722 | int keylen; | 815 | u32 pcu_reg, beacon_reg, low_id, high_id; |
723 | __le32 key_v[5] = {}; | ||
724 | __le32 key0 = 0, key1 = 0; | ||
725 | __le32 *rxmic, *txmic; | ||
726 | int keytype; | ||
727 | u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; | ||
728 | bool is_tkip; | ||
729 | const u8 *key_ptr; | ||
730 | 816 | ||
731 | is_tkip = (key->alg == ALG_TKIP); | 817 | ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_MODE, "mode %d\n", op_mode); |
732 | 818 | ||
733 | /* | 819 | /* Preserve rest settings */ |
734 | * key->keylen comes in from mac80211 in bytes. | 820 | pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; |
735 | * TKIP is 128 bit + 128 bit mic | 821 | pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP |
736 | */ | 822 | | AR5K_STA_ID1_KEYSRCH_MODE |
737 | keylen = (is_tkip) ? (128 / 8) : key->keylen; | 823 | | (ah->ah_version == AR5K_AR5210 ? |
824 | (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0)); | ||
738 | 825 | ||
739 | if (entry > AR5K_KEYTABLE_SIZE || | 826 | beacon_reg = 0; |
740 | (is_tkip && micentry > AR5K_KEYTABLE_SIZE)) | ||
741 | return -EOPNOTSUPP; | ||
742 | 827 | ||
743 | if (unlikely(keylen > 16)) | 828 | switch (op_mode) { |
744 | return -EOPNOTSUPP; | 829 | case NL80211_IFTYPE_ADHOC: |
830 | pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE; | ||
831 | beacon_reg |= AR5K_BCR_ADHOC; | ||
832 | if (ah->ah_version == AR5K_AR5210) | ||
833 | pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; | ||
834 | else | ||
835 | AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS); | ||
836 | break; | ||
745 | 837 | ||
746 | keytype = ath5k_keycache_type(key); | 838 | case NL80211_IFTYPE_AP: |
747 | if (keytype < 0) | 839 | case NL80211_IFTYPE_MESH_POINT: |
748 | return keytype; | 840 | pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE; |
841 | beacon_reg |= AR5K_BCR_AP; | ||
842 | if (ah->ah_version == AR5K_AR5210) | ||
843 | pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; | ||
844 | else | ||
845 | AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS); | ||
846 | break; | ||
749 | 847 | ||
750 | /* | 848 | case NL80211_IFTYPE_STATION: |
751 | * each key block is 6 bytes wide, written as pairs of | 849 | pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE |
752 | * alternating 32 and 16 bit le values. | 850 | | (ah->ah_version == AR5K_AR5210 ? |
753 | */ | 851 | AR5K_STA_ID1_PWR_SV : 0); |
754 | key_ptr = key->key; | 852 | case NL80211_IFTYPE_MONITOR: |
755 | for (i = 0; keylen >= 6; keylen -= 6) { | 853 | pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE |
756 | memcpy(&key_v[i], key_ptr, 6); | 854 | | (ah->ah_version == AR5K_AR5210 ? |
757 | i += 2; | 855 | AR5K_STA_ID1_NO_PSPOLL : 0); |
758 | key_ptr += 6; | 856 | break; |
759 | } | ||
760 | if (keylen) | ||
761 | memcpy(&key_v[i], key_ptr, keylen); | ||
762 | 857 | ||
763 | /* intentionally corrupt key until mic is installed */ | 858 | default: |
764 | if (is_tkip) { | 859 | return -EINVAL; |
765 | key0 = key_v[0] = ~key_v[0]; | ||
766 | key1 = key_v[1] = ~key_v[1]; | ||
767 | } | 860 | } |
768 | 861 | ||
769 | for (i = 0; i < ARRAY_SIZE(key_v); i++) | 862 | /* |
770 | ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), | 863 | * Set PCU registers |
771 | AR5K_KEYTABLE_OFF(entry, i)); | 864 | */ |
772 | 865 | low_id = get_unaligned_le32(common->macaddr); | |
773 | ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry)); | 866 | high_id = get_unaligned_le16(common->macaddr + 4); |
774 | 867 | ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); | |
775 | if (is_tkip) { | 868 | ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); |
776 | /* Install rx/tx MIC */ | ||
777 | rxmic = (__le32 *) &key->key[16]; | ||
778 | txmic = (__le32 *) &key->key[24]; | ||
779 | 869 | ||
780 | if (ah->ah_combined_mic) { | 870 | /* |
781 | key_v[0] = rxmic[0]; | 871 | * Set Beacon Control Register on 5210 |
782 | key_v[1] = cpu_to_le32(le32_to_cpu(txmic[0]) >> 16); | 872 | */ |
783 | key_v[2] = rxmic[1]; | 873 | if (ah->ah_version == AR5K_AR5210) |
784 | key_v[3] = cpu_to_le32(le32_to_cpu(txmic[0]) & 0xffff); | 874 | ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR); |
785 | key_v[4] = txmic[1]; | ||
786 | } else { | ||
787 | key_v[0] = rxmic[0]; | ||
788 | key_v[1] = 0; | ||
789 | key_v[2] = rxmic[1]; | ||
790 | key_v[3] = 0; | ||
791 | key_v[4] = 0; | ||
792 | } | ||
793 | for (i = 0; i < ARRAY_SIZE(key_v); i++) | ||
794 | ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), | ||
795 | AR5K_KEYTABLE_OFF(micentry, i)); | ||
796 | |||
797 | ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, | ||
798 | AR5K_KEYTABLE_TYPE(micentry)); | ||
799 | ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC0(micentry)); | ||
800 | ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC1(micentry)); | ||
801 | |||
802 | /* restore first 2 words of key */ | ||
803 | ath5k_hw_reg_write(ah, le32_to_cpu(~key0), | ||
804 | AR5K_KEYTABLE_OFF(entry, 0)); | ||
805 | ath5k_hw_reg_write(ah, le32_to_cpu(~key1), | ||
806 | AR5K_KEYTABLE_OFF(entry, 1)); | ||
807 | } | ||
808 | 875 | ||
809 | return ath5k_hw_set_key_lladdr(ah, entry, mac); | 876 | return 0; |
810 | } | 877 | } |
811 | 878 | ||
812 | int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac) | 879 | void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode, |
880 | u8 mode) | ||
813 | { | 881 | { |
814 | u32 low_id, high_id; | 882 | /* Set bssid and bssid mask */ |
815 | 883 | ath5k_hw_set_bssid(ah); | |
816 | /* Invalid entry (key table overflow) */ | ||
817 | AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); | ||
818 | 884 | ||
819 | /* | 885 | /* Set PCU config */ |
820 | * MAC may be NULL if it's a broadcast key. In this case no need to | 886 | ath5k_hw_set_opmode(ah, op_mode); |
821 | * to compute get_unaligned_le32 and get_unaligned_le16 as we | ||
822 | * already know it. | ||
823 | */ | ||
824 | if (!mac) { | ||
825 | low_id = 0xffffffff; | ||
826 | high_id = 0xffff | AR5K_KEYTABLE_VALID; | ||
827 | } else { | ||
828 | low_id = get_unaligned_le32(mac); | ||
829 | high_id = get_unaligned_le16(mac + 4) | AR5K_KEYTABLE_VALID; | ||
830 | } | ||
831 | 887 | ||
832 | ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry)); | 888 | /* Write rate duration table only on AR5212 and if |
833 | ath5k_hw_reg_write(ah, high_id, AR5K_KEYTABLE_MAC1(entry)); | 889 | * virtual interface has already been brought up |
890 | * XXX: rethink this after new mode changes to | ||
891 | * mac80211 are integrated */ | ||
892 | if (ah->ah_version == AR5K_AR5212 && | ||
893 | ah->ah_sc->nvifs) | ||
894 | ath5k_hw_write_rate_duration(ah); | ||
834 | 895 | ||
835 | return 0; | 896 | /* Set RSSI/BRSSI thresholds |
836 | } | 897 | * |
898 | * Note: If we decide to set this value | ||
899 | * dynamicaly, have in mind that when AR5K_RSSI_THR | ||
900 | * register is read it might return 0x40 if we haven't | ||
901 | * wrote anything to it plus BMISS RSSI threshold is zeroed. | ||
902 | * So doing a save/restore procedure here isn't the right | ||
903 | * choice. Instead store it on ath5k_hw */ | ||
904 | ath5k_hw_reg_write(ah, (AR5K_TUNE_RSSI_THRES | | ||
905 | AR5K_TUNE_BMISS_THRES << | ||
906 | AR5K_RSSI_THR_BMISS_S), | ||
907 | AR5K_RSSI_THR); | ||
908 | |||
909 | /* MIC QoS support */ | ||
910 | if (ah->ah_mac_srev >= AR5K_SREV_AR2413) { | ||
911 | ath5k_hw_reg_write(ah, 0x000100aa, AR5K_MIC_QOS_CTL); | ||
912 | ath5k_hw_reg_write(ah, 0x00003210, AR5K_MIC_QOS_SEL); | ||
913 | } | ||
837 | 914 | ||
838 | /** | 915 | /* QoS NOACK Policy */ |
839 | * ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class | 916 | if (ah->ah_version == AR5K_AR5212) { |
840 | * | 917 | ath5k_hw_reg_write(ah, |
841 | * @ah: The &struct ath5k_hw | 918 | AR5K_REG_SM(2, AR5K_QOS_NOACK_2BIT_VALUES) | |
842 | * @coverage_class: IEEE 802.11 coverage class number | 919 | AR5K_REG_SM(5, AR5K_QOS_NOACK_BIT_OFFSET) | |
843 | * | 920 | AR5K_REG_SM(0, AR5K_QOS_NOACK_BYTE_OFFSET), |
844 | * Sets slot time, ACK timeout and CTS timeout for given coverage class. | 921 | AR5K_QOS_NOACK); |
845 | */ | 922 | } |
846 | void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class) | ||
847 | { | ||
848 | /* As defined by IEEE 802.11-2007 17.3.8.6 */ | ||
849 | int slot_time = ath5k_hw_get_default_slottime(ah) + 3 * coverage_class; | ||
850 | int ack_timeout = ath5k_hw_get_default_sifs(ah) + slot_time; | ||
851 | int cts_timeout = ack_timeout; | ||
852 | 923 | ||
853 | ath5k_hw_set_slot_time(ah, slot_time); | 924 | /* Restore slot time and ACK timeouts */ |
854 | ath5k_hw_set_ack_timeout(ah, ack_timeout); | 925 | if (ah->ah_coverage_class > 0) |
855 | ath5k_hw_set_cts_timeout(ah, cts_timeout); | 926 | ath5k_hw_set_coverage_class(ah, ah->ah_coverage_class); |
856 | 927 | ||
857 | ah->ah_coverage_class = coverage_class; | 928 | /* Set ACK bitrate mode (see ack_rates_high) */ |
929 | if (ah->ah_version == AR5K_AR5212) { | ||
930 | u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB; | ||
931 | if (ah->ah_ack_bitrate_high) | ||
932 | AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val); | ||
933 | else | ||
934 | AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val); | ||
935 | } | ||
936 | return; | ||
858 | } | 937 | } |