diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/net/wireless/ath/ath5k/pcu.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/pcu.c')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/pcu.c | 292 |
1 files changed, 135 insertions, 157 deletions
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 2942f13c9c4a..aefe84f9c04b 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c | |||
@@ -24,6 +24,8 @@ | |||
24 | * Protocol Control Unit Functions * | 24 | * Protocol Control Unit Functions * |
25 | \*********************************/ | 25 | \*********************************/ |
26 | 26 | ||
27 | #include <asm/unaligned.h> | ||
28 | |||
27 | #include "ath5k.h" | 29 | #include "ath5k.h" |
28 | #include "reg.h" | 30 | #include "reg.h" |
29 | #include "debug.h" | 31 | #include "debug.h" |
@@ -44,6 +46,7 @@ | |||
44 | */ | 46 | */ |
45 | int ath5k_hw_set_opmode(struct ath5k_hw *ah) | 47 | int ath5k_hw_set_opmode(struct ath5k_hw *ah) |
46 | { | 48 | { |
49 | struct ath_common *common = ath5k_hw_common(ah); | ||
47 | u32 pcu_reg, beacon_reg, low_id, high_id; | 50 | u32 pcu_reg, beacon_reg, low_id, high_id; |
48 | 51 | ||
49 | 52 | ||
@@ -95,8 +98,8 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah) | |||
95 | /* | 98 | /* |
96 | * Set PCU registers | 99 | * Set PCU registers |
97 | */ | 100 | */ |
98 | low_id = AR5K_LOW_ID(ah->ah_sta_id); | 101 | low_id = get_unaligned_le32(common->macaddr); |
99 | high_id = AR5K_HIGH_ID(ah->ah_sta_id); | 102 | high_id = get_unaligned_le16(common->macaddr + 4); |
100 | ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); | 103 | ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); |
101 | ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); | 104 | ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); |
102 | 105 | ||
@@ -184,8 +187,8 @@ unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah) | |||
184 | { | 187 | { |
185 | ATH5K_TRACE(ah->ah_sc); | 188 | ATH5K_TRACE(ah->ah_sc); |
186 | 189 | ||
187 | return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, | 190 | return ath5k_hw_clocktoh(ah, AR5K_REG_MS(ath5k_hw_reg_read(ah, |
188 | AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo); | 191 | AR5K_TIME_OUT), AR5K_TIME_OUT_ACK)); |
189 | } | 192 | } |
190 | 193 | ||
191 | /** | 194 | /** |
@@ -197,12 +200,12 @@ unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah) | |||
197 | int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) | 200 | int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) |
198 | { | 201 | { |
199 | ATH5K_TRACE(ah->ah_sc); | 202 | ATH5K_TRACE(ah->ah_sc); |
200 | if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK), | 203 | if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK)) |
201 | ah->ah_turbo) <= timeout) | 204 | <= timeout) |
202 | return -EINVAL; | 205 | return -EINVAL; |
203 | 206 | ||
204 | AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK, | 207 | AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK, |
205 | ath5k_hw_htoclock(timeout, ah->ah_turbo)); | 208 | ath5k_hw_htoclock(ah, timeout)); |
206 | 209 | ||
207 | return 0; | 210 | return 0; |
208 | } | 211 | } |
@@ -215,8 +218,8 @@ int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) | |||
215 | unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah) | 218 | unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah) |
216 | { | 219 | { |
217 | ATH5K_TRACE(ah->ah_sc); | 220 | ATH5K_TRACE(ah->ah_sc); |
218 | return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, | 221 | return ath5k_hw_clocktoh(ah, AR5K_REG_MS(ath5k_hw_reg_read(ah, |
219 | AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo); | 222 | AR5K_TIME_OUT), AR5K_TIME_OUT_CTS)); |
220 | } | 223 | } |
221 | 224 | ||
222 | /** | 225 | /** |
@@ -228,36 +231,94 @@ unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah) | |||
228 | int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) | 231 | int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) |
229 | { | 232 | { |
230 | ATH5K_TRACE(ah->ah_sc); | 233 | ATH5K_TRACE(ah->ah_sc); |
231 | if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS), | 234 | if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS)) |
232 | ah->ah_turbo) <= timeout) | 235 | <= timeout) |
233 | return -EINVAL; | 236 | return -EINVAL; |
234 | 237 | ||
235 | AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS, | 238 | AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS, |
236 | ath5k_hw_htoclock(timeout, ah->ah_turbo)); | 239 | ath5k_hw_htoclock(ah, timeout)); |
237 | 240 | ||
238 | return 0; | 241 | return 0; |
239 | } | 242 | } |
240 | 243 | ||
244 | /** | ||
245 | * ath5k_hw_htoclock - Translate usec to hw clock units | ||
246 | * | ||
247 | * @ah: The &struct ath5k_hw | ||
248 | * @usec: value in microseconds | ||
249 | */ | ||
250 | unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec) | ||
251 | { | ||
252 | return usec * ath5k_hw_get_clockrate(ah); | ||
253 | } | ||
241 | 254 | ||
242 | /****************\ | 255 | /** |
243 | * BSSID handling * | 256 | * ath5k_hw_clocktoh - Translate hw clock units to usec |
244 | \****************/ | 257 | * @clock: value in hw clock units |
258 | */ | ||
259 | unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock) | ||
260 | { | ||
261 | return clock / ath5k_hw_get_clockrate(ah); | ||
262 | } | ||
245 | 263 | ||
246 | /** | 264 | /** |
247 | * ath5k_hw_get_lladdr - Get station id | 265 | * ath5k_hw_get_clockrate - Get the clock rate for current mode |
248 | * | 266 | * |
249 | * @ah: The &struct ath5k_hw | 267 | * @ah: The &struct ath5k_hw |
250 | * @mac: The card's mac address | 268 | */ |
269 | unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah) | ||
270 | { | ||
271 | struct ieee80211_channel *channel = ah->ah_current_channel; | ||
272 | int clock; | ||
273 | |||
274 | if (channel->hw_value & CHANNEL_5GHZ) | ||
275 | clock = 40; /* 802.11a */ | ||
276 | else if (channel->hw_value & CHANNEL_CCK) | ||
277 | clock = 22; /* 802.11b */ | ||
278 | else | ||
279 | clock = 44; /* 802.11g */ | ||
280 | |||
281 | /* Clock rate in turbo modes is twice the normal rate */ | ||
282 | if (channel->hw_value & CHANNEL_TURBO) | ||
283 | clock *= 2; | ||
284 | |||
285 | return clock; | ||
286 | } | ||
287 | |||
288 | /** | ||
289 | * ath5k_hw_get_default_slottime - Get the default slot time for current mode | ||
251 | * | 290 | * |
252 | * Initialize ah->ah_sta_id using the mac address provided | 291 | * @ah: The &struct ath5k_hw |
253 | * (just a memcpy). | 292 | */ |
293 | unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah) | ||
294 | { | ||
295 | struct ieee80211_channel *channel = ah->ah_current_channel; | ||
296 | |||
297 | if (channel->hw_value & CHANNEL_TURBO) | ||
298 | return 6; /* both turbo modes */ | ||
299 | |||
300 | if (channel->hw_value & CHANNEL_CCK) | ||
301 | return 20; /* 802.11b */ | ||
302 | |||
303 | return 9; /* 802.11 a/g */ | ||
304 | } | ||
305 | |||
306 | /** | ||
307 | * ath5k_hw_get_default_sifs - Get the default SIFS for current mode | ||
254 | * | 308 | * |
255 | * TODO: Remove it once we merge ath5k_softc and ath5k_hw | 309 | * @ah: The &struct ath5k_hw |
256 | */ | 310 | */ |
257 | void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac) | 311 | unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah) |
258 | { | 312 | { |
259 | ATH5K_TRACE(ah->ah_sc); | 313 | struct ieee80211_channel *channel = ah->ah_current_channel; |
260 | memcpy(mac, ah->ah_sta_id, ETH_ALEN); | 314 | |
315 | if (channel->hw_value & CHANNEL_TURBO) | ||
316 | return 8; /* both turbo modes */ | ||
317 | |||
318 | if (channel->hw_value & CHANNEL_5GHZ) | ||
319 | return 16; /* 802.11a */ | ||
320 | |||
321 | return 10; /* 802.11 b/g */ | ||
261 | } | 322 | } |
262 | 323 | ||
263 | /** | 324 | /** |
@@ -270,17 +331,18 @@ void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac) | |||
270 | */ | 331 | */ |
271 | int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) | 332 | int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) |
272 | { | 333 | { |
334 | struct ath_common *common = ath5k_hw_common(ah); | ||
273 | u32 low_id, high_id; | 335 | u32 low_id, high_id; |
274 | u32 pcu_reg; | 336 | u32 pcu_reg; |
275 | 337 | ||
276 | ATH5K_TRACE(ah->ah_sc); | 338 | ATH5K_TRACE(ah->ah_sc); |
277 | /* Set new station ID */ | 339 | /* Set new station ID */ |
278 | memcpy(ah->ah_sta_id, mac, ETH_ALEN); | 340 | memcpy(common->macaddr, mac, ETH_ALEN); |
279 | 341 | ||
280 | pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; | 342 | pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; |
281 | 343 | ||
282 | low_id = AR5K_LOW_ID(mac); | 344 | low_id = get_unaligned_le32(mac); |
283 | high_id = AR5K_HIGH_ID(mac); | 345 | high_id = get_unaligned_le16(mac + 4); |
284 | 346 | ||
285 | ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); | 347 | ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); |
286 | ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); | 348 | ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); |
@@ -297,159 +359,51 @@ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) | |||
297 | * | 359 | * |
298 | * Sets the BSSID which trigers the "SME Join" operation | 360 | * Sets the BSSID which trigers the "SME Join" operation |
299 | */ | 361 | */ |
300 | void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) | 362 | void ath5k_hw_set_associd(struct ath5k_hw *ah) |
301 | { | 363 | { |
302 | u32 low_id, high_id; | 364 | struct ath_common *common = ath5k_hw_common(ah); |
303 | u16 tim_offset = 0; | 365 | u16 tim_offset = 0; |
304 | 366 | ||
305 | /* | 367 | /* |
306 | * Set simple BSSID mask on 5212 | 368 | * Set simple BSSID mask on 5212 |
307 | */ | 369 | */ |
308 | if (ah->ah_version == AR5K_AR5212) { | 370 | if (ah->ah_version == AR5K_AR5212) |
309 | ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_bssid_mask), | 371 | ath_hw_setbssidmask(common); |
310 | AR5K_BSS_IDM0); | ||
311 | ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask), | ||
312 | AR5K_BSS_IDM1); | ||
313 | } | ||
314 | 372 | ||
315 | /* | 373 | /* |
316 | * Set BSSID which triggers the "SME Join" operation | 374 | * Set BSSID which triggers the "SME Join" operation |
317 | */ | 375 | */ |
318 | low_id = AR5K_LOW_ID(bssid); | 376 | ath5k_hw_reg_write(ah, |
319 | high_id = AR5K_HIGH_ID(bssid); | 377 | get_unaligned_le32(common->curbssid), |
320 | ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0); | 378 | AR5K_BSS_ID0); |
321 | ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) << | 379 | ath5k_hw_reg_write(ah, |
322 | AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1); | 380 | get_unaligned_le16(common->curbssid + 4) | |
323 | 381 | ((common->curaid & 0x3fff) << AR5K_BSS_ID1_AID_S), | |
324 | if (assoc_id == 0) { | 382 | AR5K_BSS_ID1); |
383 | |||
384 | if (common->curaid == 0) { | ||
325 | ath5k_hw_disable_pspoll(ah); | 385 | ath5k_hw_disable_pspoll(ah); |
326 | return; | 386 | return; |
327 | } | 387 | } |
328 | 388 | ||
329 | AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM, | 389 | AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM, |
330 | tim_offset ? tim_offset + 4 : 0); | 390 | tim_offset ? tim_offset + 4 : 0); |
331 | 391 | ||
332 | ath5k_hw_enable_pspoll(ah, NULL, 0); | 392 | ath5k_hw_enable_pspoll(ah, NULL, 0); |
333 | } | 393 | } |
334 | 394 | ||
335 | /** | 395 | void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) |
336 | * ath5k_hw_set_bssid_mask - filter out bssids we listen | ||
337 | * | ||
338 | * @ah: the &struct ath5k_hw | ||
339 | * @mask: the bssid_mask, a u8 array of size ETH_ALEN | ||
340 | * | ||
341 | * BSSID masking is a method used by AR5212 and newer hardware to inform PCU | ||
342 | * which bits of the interface's MAC address should be looked at when trying | ||
343 | * to decide which packets to ACK. In station mode and AP mode with a single | ||
344 | * BSS every bit matters since we lock to only one BSS. In AP mode with | ||
345 | * multiple BSSes (virtual interfaces) not every bit matters because hw must | ||
346 | * accept frames for all BSSes and so we tweak some bits of our mac address | ||
347 | * in order to have multiple BSSes. | ||
348 | * | ||
349 | * NOTE: This is a simple filter and does *not* filter out all | ||
350 | * relevant frames. Some frames that are not for us might get ACKed from us | ||
351 | * by PCU because they just match the mask. | ||
352 | * | ||
353 | * When handling multiple BSSes you can get the BSSID mask by computing the | ||
354 | * set of ~ ( MAC XOR BSSID ) for all bssids we handle. | ||
355 | * | ||
356 | * When you do this you are essentially computing the common bits of all your | ||
357 | * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with | ||
358 | * the MAC address to obtain the relevant bits and compare the result with | ||
359 | * (frame's BSSID & mask) to see if they match. | ||
360 | */ | ||
361 | /* | ||
362 | * Simple example: on your card you have have two BSSes you have created with | ||
363 | * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address. | ||
364 | * There is another BSSID-03 but you are not part of it. For simplicity's sake, | ||
365 | * assuming only 4 bits for a mac address and for BSSIDs you can then have: | ||
366 | * | ||
367 | * \ | ||
368 | * MAC: 0001 | | ||
369 | * BSSID-01: 0100 | --> Belongs to us | ||
370 | * BSSID-02: 1001 | | ||
371 | * / | ||
372 | * ------------------- | ||
373 | * BSSID-03: 0110 | --> External | ||
374 | * ------------------- | ||
375 | * | ||
376 | * Our bssid_mask would then be: | ||
377 | * | ||
378 | * On loop iteration for BSSID-01: | ||
379 | * ~(0001 ^ 0100) -> ~(0101) | ||
380 | * -> 1010 | ||
381 | * bssid_mask = 1010 | ||
382 | * | ||
383 | * On loop iteration for BSSID-02: | ||
384 | * bssid_mask &= ~(0001 ^ 1001) | ||
385 | * bssid_mask = (1010) & ~(0001 ^ 1001) | ||
386 | * bssid_mask = (1010) & ~(1001) | ||
387 | * bssid_mask = (1010) & (0110) | ||
388 | * bssid_mask = 0010 | ||
389 | * | ||
390 | * A bssid_mask of 0010 means "only pay attention to the second least | ||
391 | * significant bit". This is because its the only bit common | ||
392 | * amongst the MAC and all BSSIDs we support. To findout what the real | ||
393 | * common bit is we can simply "&" the bssid_mask now with any BSSID we have | ||
394 | * or our MAC address (we assume the hardware uses the MAC address). | ||
395 | * | ||
396 | * Now, suppose there's an incoming frame for BSSID-03: | ||
397 | * | ||
398 | * IFRAME-01: 0110 | ||
399 | * | ||
400 | * An easy eye-inspeciton of this already should tell you that this frame | ||
401 | * will not pass our check. This is beacuse the bssid_mask tells the | ||
402 | * hardware to only look at the second least significant bit and the | ||
403 | * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB | ||
404 | * as 1, which does not match 0. | ||
405 | * | ||
406 | * So with IFRAME-01 we *assume* the hardware will do: | ||
407 | * | ||
408 | * allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; | ||
409 | * --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0; | ||
410 | * --> allow = (0010) == 0000 ? 1 : 0; | ||
411 | * --> allow = 0 | ||
412 | * | ||
413 | * Lets now test a frame that should work: | ||
414 | * | ||
415 | * IFRAME-02: 0001 (we should allow) | ||
416 | * | ||
417 | * allow = (0001 & 1010) == 1010 | ||
418 | * | ||
419 | * allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; | ||
420 | * --> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0; | ||
421 | * --> allow = (0010) == (0010) | ||
422 | * --> allow = 1 | ||
423 | * | ||
424 | * Other examples: | ||
425 | * | ||
426 | * IFRAME-03: 0100 --> allowed | ||
427 | * IFRAME-04: 1001 --> allowed | ||
428 | * IFRAME-05: 1101 --> allowed but its not for us!!! | ||
429 | * | ||
430 | */ | ||
431 | int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) | ||
432 | { | 396 | { |
433 | u32 low_id, high_id; | 397 | struct ath_common *common = ath5k_hw_common(ah); |
434 | ATH5K_TRACE(ah->ah_sc); | 398 | ATH5K_TRACE(ah->ah_sc); |
435 | 399 | ||
436 | /* Cache bssid mask so that we can restore it | 400 | /* Cache bssid mask so that we can restore it |
437 | * on reset */ | 401 | * on reset */ |
438 | memcpy(ah->ah_bssid_mask, mask, ETH_ALEN); | 402 | memcpy(common->bssidmask, mask, ETH_ALEN); |
439 | if (ah->ah_version == AR5K_AR5212) { | 403 | if (ah->ah_version == AR5K_AR5212) |
440 | low_id = AR5K_LOW_ID(mask); | 404 | ath_hw_setbssidmask(common); |
441 | high_id = AR5K_HIGH_ID(mask); | ||
442 | |||
443 | ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0); | ||
444 | ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1); | ||
445 | |||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | return -EIO; | ||
450 | } | 405 | } |
451 | 406 | ||
452 | |||
453 | /************\ | 407 | /************\ |
454 | * RX Control * | 408 | * RX Control * |
455 | \************/ | 409 | \************/ |
@@ -1157,14 +1111,17 @@ int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac) | |||
1157 | /* Invalid entry (key table overflow) */ | 1111 | /* Invalid entry (key table overflow) */ |
1158 | AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); | 1112 | AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); |
1159 | 1113 | ||
1160 | /* MAC may be NULL if it's a broadcast key. In this case no need to | 1114 | /* |
1161 | * to compute AR5K_LOW_ID and AR5K_HIGH_ID as we already know it. */ | 1115 | * MAC may be NULL if it's a broadcast key. In this case no need to |
1116 | * to compute get_unaligned_le32 and get_unaligned_le16 as we | ||
1117 | * already know it. | ||
1118 | */ | ||
1162 | if (!mac) { | 1119 | if (!mac) { |
1163 | low_id = 0xffffffff; | 1120 | low_id = 0xffffffff; |
1164 | high_id = 0xffff | AR5K_KEYTABLE_VALID; | 1121 | high_id = 0xffff | AR5K_KEYTABLE_VALID; |
1165 | } else { | 1122 | } else { |
1166 | low_id = AR5K_LOW_ID(mac); | 1123 | low_id = get_unaligned_le32(mac); |
1167 | high_id = AR5K_HIGH_ID(mac) | AR5K_KEYTABLE_VALID; | 1124 | high_id = get_unaligned_le16(mac + 4) | AR5K_KEYTABLE_VALID; |
1168 | } | 1125 | } |
1169 | 1126 | ||
1170 | ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry)); | 1127 | ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry)); |
@@ -1173,3 +1130,24 @@ int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac) | |||
1173 | return 0; | 1130 | return 0; |
1174 | } | 1131 | } |
1175 | 1132 | ||
1133 | /** | ||
1134 | * ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class | ||
1135 | * | ||
1136 | * @ah: The &struct ath5k_hw | ||
1137 | * @coverage_class: IEEE 802.11 coverage class number | ||
1138 | * | ||
1139 | * Sets slot time, ACK timeout and CTS timeout for given coverage class. | ||
1140 | */ | ||
1141 | void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class) | ||
1142 | { | ||
1143 | /* As defined by IEEE 802.11-2007 17.3.8.6 */ | ||
1144 | int slot_time = ath5k_hw_get_default_slottime(ah) + 3 * coverage_class; | ||
1145 | int ack_timeout = ath5k_hw_get_default_sifs(ah) + slot_time; | ||
1146 | int cts_timeout = ack_timeout; | ||
1147 | |||
1148 | ath5k_hw_set_slot_time(ah, slot_time); | ||
1149 | ath5k_hw_set_ack_timeout(ah, ack_timeout); | ||
1150 | ath5k_hw_set_cts_timeout(ah, cts_timeout); | ||
1151 | |||
1152 | ah->ah_coverage_class = coverage_class; | ||
1153 | } | ||