diff options
author | Luis R. Rodriguez <lrodriguez@atheros.com> | 2009-09-10 20:52:45 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-10-07 16:39:28 -0400 |
commit | 13b81559200b8e54473e5b140323cbb5f2bb21c0 (patch) | |
tree | 0c326b1daaa9cf73ef36b82de600f6599610dfa9 | |
parent | e5aa847489e543e33a7c72898e72183871ce2916 (diff) |
atheros: define shared bssidmask setting
Also make ath5k and ath9k use it, and share register definitions.
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ath/Makefile | 5 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/ath5k.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/attach.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/base.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/initvals.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/pcu.c | 121 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/reg.h | 8 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw.c | 10 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/recv.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/reg.h | 5 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/virtual.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/hw.c | 126 | ||||
-rw-r--r-- | drivers/net/wireless/ath/reg.h | 27 |
15 files changed, 179 insertions, 140 deletions
diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile index 4bb0132ada37..6ebf2148167a 100644 --- a/drivers/net/wireless/ath/Makefile +++ b/drivers/net/wireless/ath/Makefile | |||
@@ -3,4 +3,7 @@ obj-$(CONFIG_ATH9K) += ath9k/ | |||
3 | obj-$(CONFIG_AR9170_USB) += ar9170/ | 3 | obj-$(CONFIG_AR9170_USB) += ar9170/ |
4 | 4 | ||
5 | obj-$(CONFIG_ATH_COMMON) += ath.o | 5 | obj-$(CONFIG_ATH_COMMON) += ath.o |
6 | ath-objs := main.o regd.o | 6 | |
7 | ath-objs := main.o \ | ||
8 | regd.o \ | ||
9 | hw.o | ||
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index be68cb8cf705..0582ee4a493e 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h | |||
@@ -45,6 +45,7 @@ struct ath_ops { | |||
45 | }; | 45 | }; |
46 | 46 | ||
47 | struct ath_common { | 47 | struct ath_common { |
48 | void *ah; | ||
48 | u16 cachelsz; | 49 | u16 cachelsz; |
49 | u16 curaid; | 50 | u16 curaid; |
50 | u8 macaddr[ETH_ALEN]; | 51 | u8 macaddr[ETH_ALEN]; |
@@ -58,4 +59,6 @@ struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, | |||
58 | u32 len, | 59 | u32 len, |
59 | gfp_t gfp_mask); | 60 | gfp_t gfp_mask); |
60 | 61 | ||
62 | void ath_hw_setbssidmask(struct ath_common *common); | ||
63 | |||
61 | #endif /* ATH_H */ | 64 | #endif /* ATH_H */ |
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 1416562e4d19..43585d54c270 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h | |||
@@ -1192,7 +1192,7 @@ extern int ath5k_hw_set_opmode(struct ath5k_hw *ah); | |||
1192 | /* BSSID Functions */ | 1192 | /* BSSID Functions */ |
1193 | extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac); | 1193 | extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac); |
1194 | extern void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id); | 1194 | extern void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id); |
1195 | extern int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask); | 1195 | extern void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask); |
1196 | /* Receive start/stop functions */ | 1196 | /* Receive start/stop functions */ |
1197 | extern void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah); | 1197 | extern void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah); |
1198 | extern void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah); | 1198 | extern void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah); |
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index c0840aba2715..e230de8ad320 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c | |||
@@ -104,7 +104,7 @@ static int ath5k_hw_post(struct ath5k_hw *ah) | |||
104 | int ath5k_hw_attach(struct ath5k_softc *sc) | 104 | int ath5k_hw_attach(struct ath5k_softc *sc) |
105 | { | 105 | { |
106 | struct ath5k_hw *ah = sc->ah; | 106 | struct ath5k_hw *ah = sc->ah; |
107 | struct ath_common *common; | 107 | struct ath_common *common = ath5k_hw_common(ah); |
108 | struct pci_dev *pdev = sc->pdev; | 108 | struct pci_dev *pdev = sc->pdev; |
109 | struct ath5k_eeprom_info *ee; | 109 | struct ath5k_eeprom_info *ee; |
110 | int ret; | 110 | int ret; |
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 13bbf3dfc6c3..1abbebc2bd26 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c | |||
@@ -593,6 +593,7 @@ ath5k_pci_probe(struct pci_dev *pdev, | |||
593 | sc->ah->ah_iobase = sc->iobase; | 593 | sc->ah->ah_iobase = sc->iobase; |
594 | common = ath5k_hw_common(sc->ah); | 594 | common = ath5k_hw_common(sc->ah); |
595 | common->ops = &ath5k_common_ops; | 595 | common->ops = &ath5k_common_ops; |
596 | common->ah = sc->ah; | ||
596 | common->cachelsz = csz << 2; /* convert to bytes */ | 597 | common->cachelsz = csz << 2; /* convert to bytes */ |
597 | 598 | ||
598 | /* Initialize device */ | 599 | /* Initialize device */ |
diff --git a/drivers/net/wireless/ath/ath5k/initvals.c b/drivers/net/wireless/ath/ath5k/initvals.c index 18eb5190ce4b..8fa439308828 100644 --- a/drivers/net/wireless/ath/ath5k/initvals.c +++ b/drivers/net/wireless/ath/ath5k/initvals.c | |||
@@ -560,8 +560,8 @@ static const struct ath5k_ini ar5212_ini_common_start[] = { | |||
560 | { AR5K_SLEEP0, 0x0002aaaa }, | 560 | { AR5K_SLEEP0, 0x0002aaaa }, |
561 | { AR5K_SLEEP1, 0x02005555 }, | 561 | { AR5K_SLEEP1, 0x02005555 }, |
562 | { AR5K_SLEEP2, 0x00000000 }, | 562 | { AR5K_SLEEP2, 0x00000000 }, |
563 | { AR5K_BSS_IDM0, 0xffffffff }, | 563 | { AR_BSSMSKL, 0xffffffff }, |
564 | { AR5K_BSS_IDM1, 0x0000ffff }, | 564 | { AR_BSSMSKU, 0x0000ffff }, |
565 | { AR5K_TXPC, 0x00000000 }, | 565 | { AR5K_TXPC, 0x00000000 }, |
566 | { AR5K_PROFCNT_TX, 0x00000000 }, | 566 | { AR5K_PROFCNT_TX, 0x00000000 }, |
567 | { AR5K_PROFCNT_RX, 0x00000000 }, | 567 | { AR5K_PROFCNT_RX, 0x00000000 }, |
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index f03c06d583e6..9ac763875a98 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c | |||
@@ -290,10 +290,10 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) | |||
290 | */ | 290 | */ |
291 | if (ah->ah_version == AR5K_AR5212) { | 291 | if (ah->ah_version == AR5K_AR5212) { |
292 | ath5k_hw_reg_write(ah, get_unaligned_le32(common->bssidmask), | 292 | ath5k_hw_reg_write(ah, get_unaligned_le32(common->bssidmask), |
293 | AR5K_BSS_IDM0); | 293 | AR_BSSMSKL); |
294 | ath5k_hw_reg_write(ah, | 294 | ath5k_hw_reg_write(ah, |
295 | get_unaligned_le16(common->curbssid + 4), | 295 | get_unaligned_le16(common->curbssid + 4), |
296 | AR5K_BSS_IDM1); | 296 | AR_BSSMSKU); |
297 | } | 297 | } |
298 | 298 | ||
299 | /* | 299 | /* |
@@ -301,9 +301,9 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) | |||
301 | */ | 301 | */ |
302 | low_id = get_unaligned_le32(bssid); | 302 | low_id = get_unaligned_le32(bssid); |
303 | high_id = get_unaligned_le16(bssid); | 303 | high_id = get_unaligned_le16(bssid); |
304 | ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0); | 304 | ath5k_hw_reg_write(ah, low_id, AR_BSSMSKL); |
305 | ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) << | 305 | ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) << |
306 | AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1); | 306 | AR5K_BSS_ID1_AID_S), AR_BSSMSKU); |
307 | 307 | ||
308 | if (assoc_id == 0) { | 308 | if (assoc_id == 0) { |
309 | ath5k_hw_disable_pspoll(ah); | 309 | ath5k_hw_disable_pspoll(ah); |
@@ -316,125 +316,18 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) | |||
316 | ath5k_hw_enable_pspoll(ah, NULL, 0); | 316 | ath5k_hw_enable_pspoll(ah, NULL, 0); |
317 | } | 317 | } |
318 | 318 | ||
319 | /** | 319 | void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) |
320 | * ath5k_hw_set_bssid_mask - filter out bssids we listen | ||
321 | * | ||
322 | * @ah: the &struct ath5k_hw | ||
323 | * @mask: the bssid_mask, a u8 array of size ETH_ALEN | ||
324 | * | ||
325 | * BSSID masking is a method used by AR5212 and newer hardware to inform PCU | ||
326 | * which bits of the interface's MAC address should be looked at when trying | ||
327 | * to decide which packets to ACK. In station mode and AP mode with a single | ||
328 | * BSS every bit matters since we lock to only one BSS. In AP mode with | ||
329 | * multiple BSSes (virtual interfaces) not every bit matters because hw must | ||
330 | * accept frames for all BSSes and so we tweak some bits of our mac address | ||
331 | * in order to have multiple BSSes. | ||
332 | * | ||
333 | * NOTE: This is a simple filter and does *not* filter out all | ||
334 | * relevant frames. Some frames that are not for us might get ACKed from us | ||
335 | * by PCU because they just match the mask. | ||
336 | * | ||
337 | * When handling multiple BSSes you can get the BSSID mask by computing the | ||
338 | * set of ~ ( MAC XOR BSSID ) for all bssids we handle. | ||
339 | * | ||
340 | * When you do this you are essentially computing the common bits of all your | ||
341 | * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with | ||
342 | * the MAC address to obtain the relevant bits and compare the result with | ||
343 | * (frame's BSSID & mask) to see if they match. | ||
344 | */ | ||
345 | /* | ||
346 | * Simple example: on your card you have have two BSSes you have created with | ||
347 | * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address. | ||
348 | * There is another BSSID-03 but you are not part of it. For simplicity's sake, | ||
349 | * assuming only 4 bits for a mac address and for BSSIDs you can then have: | ||
350 | * | ||
351 | * \ | ||
352 | * MAC: 0001 | | ||
353 | * BSSID-01: 0100 | --> Belongs to us | ||
354 | * BSSID-02: 1001 | | ||
355 | * / | ||
356 | * ------------------- | ||
357 | * BSSID-03: 0110 | --> External | ||
358 | * ------------------- | ||
359 | * | ||
360 | * Our bssid_mask would then be: | ||
361 | * | ||
362 | * On loop iteration for BSSID-01: | ||
363 | * ~(0001 ^ 0100) -> ~(0101) | ||
364 | * -> 1010 | ||
365 | * bssid_mask = 1010 | ||
366 | * | ||
367 | * On loop iteration for BSSID-02: | ||
368 | * bssid_mask &= ~(0001 ^ 1001) | ||
369 | * bssid_mask = (1010) & ~(0001 ^ 1001) | ||
370 | * bssid_mask = (1010) & ~(1001) | ||
371 | * bssid_mask = (1010) & (0110) | ||
372 | * bssid_mask = 0010 | ||
373 | * | ||
374 | * A bssid_mask of 0010 means "only pay attention to the second least | ||
375 | * significant bit". This is because its the only bit common | ||
376 | * amongst the MAC and all BSSIDs we support. To findout what the real | ||
377 | * common bit is we can simply "&" the bssid_mask now with any BSSID we have | ||
378 | * or our MAC address (we assume the hardware uses the MAC address). | ||
379 | * | ||
380 | * Now, suppose there's an incoming frame for BSSID-03: | ||
381 | * | ||
382 | * IFRAME-01: 0110 | ||
383 | * | ||
384 | * An easy eye-inspeciton of this already should tell you that this frame | ||
385 | * will not pass our check. This is beacuse the bssid_mask tells the | ||
386 | * hardware to only look at the second least significant bit and the | ||
387 | * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB | ||
388 | * as 1, which does not match 0. | ||
389 | * | ||
390 | * So with IFRAME-01 we *assume* the hardware will do: | ||
391 | * | ||
392 | * allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; | ||
393 | * --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0; | ||
394 | * --> allow = (0010) == 0000 ? 1 : 0; | ||
395 | * --> allow = 0 | ||
396 | * | ||
397 | * Lets now test a frame that should work: | ||
398 | * | ||
399 | * IFRAME-02: 0001 (we should allow) | ||
400 | * | ||
401 | * allow = (0001 & 1010) == 1010 | ||
402 | * | ||
403 | * allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; | ||
404 | * --> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0; | ||
405 | * --> allow = (0010) == (0010) | ||
406 | * --> allow = 1 | ||
407 | * | ||
408 | * Other examples: | ||
409 | * | ||
410 | * IFRAME-03: 0100 --> allowed | ||
411 | * IFRAME-04: 1001 --> allowed | ||
412 | * IFRAME-05: 1101 --> allowed but its not for us!!! | ||
413 | * | ||
414 | */ | ||
415 | int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) | ||
416 | { | 320 | { |
417 | struct ath_common *common = ath5k_hw_common(ah); | 321 | struct ath_common *common = ath5k_hw_common(ah); |
418 | u32 low_id, high_id; | ||
419 | ATH5K_TRACE(ah->ah_sc); | 322 | ATH5K_TRACE(ah->ah_sc); |
420 | 323 | ||
421 | /* Cache bssid mask so that we can restore it | 324 | /* Cache bssid mask so that we can restore it |
422 | * on reset */ | 325 | * on reset */ |
423 | memcpy(common->bssidmask, mask, ETH_ALEN); | 326 | memcpy(common->bssidmask, mask, ETH_ALEN); |
424 | if (ah->ah_version == AR5K_AR5212) { | 327 | if (ah->ah_version == AR5K_AR5212) |
425 | low_id = get_unaligned_le32(mask); | 328 | ath_hw_setbssidmask(common); |
426 | high_id = get_unaligned_le16(mask + 4); | ||
427 | |||
428 | ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0); | ||
429 | ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1); | ||
430 | |||
431 | return 0; | ||
432 | } | ||
433 | |||
434 | return -EIO; | ||
435 | } | 329 | } |
436 | 330 | ||
437 | |||
438 | /************\ | 331 | /************\ |
439 | * RX Control * | 332 | * RX Control * |
440 | \************/ | 333 | \************/ |
diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index c63ea6afd96f..64227abe3c20 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h | |||
@@ -35,7 +35,7 @@ | |||
35 | * released by Atheros and on various debug messages found on the net. | 35 | * released by Atheros and on various debug messages found on the net. |
36 | */ | 36 | */ |
37 | 37 | ||
38 | 38 | #include "../reg.h" | |
39 | 39 | ||
40 | /*====MAC DMA REGISTERS====*/ | 40 | /*====MAC DMA REGISTERS====*/ |
41 | 41 | ||
@@ -1650,12 +1650,6 @@ | |||
1650 | #define AR5K_SLEEP2_DTIM_PER_S 16 | 1650 | #define AR5K_SLEEP2_DTIM_PER_S 16 |
1651 | 1651 | ||
1652 | /* | 1652 | /* |
1653 | * BSSID mask registers | ||
1654 | */ | ||
1655 | #define AR5K_BSS_IDM0 0x80e0 /* Upper bits */ | ||
1656 | #define AR5K_BSS_IDM1 0x80e4 /* Lower bits */ | ||
1657 | |||
1658 | /* | ||
1659 | * TX power control (TPC) register | 1653 | * TX power control (TPC) register |
1660 | * | 1654 | * |
1661 | * XXX: PCDAC steps (0.5dbm) or DBM ? | 1655 | * XXX: PCDAC steps (0.5dbm) or DBM ? |
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 0ad25987d85c..5fb94fa45ff9 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
@@ -2441,7 +2441,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | |||
2441 | | ah->sta_id1_defaults); | 2441 | | ah->sta_id1_defaults); |
2442 | ath9k_hw_set_operating_mode(ah, ah->opmode); | 2442 | ath9k_hw_set_operating_mode(ah, ah->opmode); |
2443 | 2443 | ||
2444 | ath9k_hw_setbssidmask(ah); | 2444 | ath_hw_setbssidmask(common); |
2445 | 2445 | ||
2446 | REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna); | 2446 | REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna); |
2447 | 2447 | ||
@@ -3990,14 +3990,6 @@ void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1) | |||
3990 | REG_WRITE(ah, AR_MCAST_FIL1, filter1); | 3990 | REG_WRITE(ah, AR_MCAST_FIL1, filter1); |
3991 | } | 3991 | } |
3992 | 3992 | ||
3993 | void ath9k_hw_setbssidmask(struct ath_hw *ah) | ||
3994 | { | ||
3995 | struct ath_common *common = ath9k_hw_common(ah); | ||
3996 | |||
3997 | REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(common->bssidmask)); | ||
3998 | REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(common->bssidmask + 4)); | ||
3999 | } | ||
4000 | |||
4001 | void ath9k_hw_write_associd(struct ath_hw *ah) | 3993 | void ath9k_hw_write_associd(struct ath_hw *ah) |
4002 | { | 3994 | { |
4003 | struct ath_common *common = ath9k_hw_common(ah); | 3995 | struct ath_common *common = ath9k_hw_common(ah); |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 4a85f6ccb509..d752b167f5ad 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -1570,6 +1570,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) | |||
1570 | 1570 | ||
1571 | common = ath9k_hw_common(ah); | 1571 | common = ath9k_hw_common(ah); |
1572 | common->ops = &ath9k_common_ops; | 1572 | common->ops = &ath9k_common_ops; |
1573 | common->ah = ah; | ||
1573 | 1574 | ||
1574 | /* | 1575 | /* |
1575 | * Cache line size is used to size and align various | 1576 | * Cache line size is used to size and align various |
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 97a5efe18d66..fb635a0a34e8 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -282,7 +282,7 @@ static void ath_opmode_init(struct ath_softc *sc) | |||
282 | 282 | ||
283 | /* configure bssid mask */ | 283 | /* configure bssid mask */ |
284 | if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) | 284 | if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) |
285 | ath9k_hw_setbssidmask(ah); | 285 | ath_hw_setbssidmask(common); |
286 | 286 | ||
287 | /* configure operational mode */ | 287 | /* configure operational mode */ |
288 | ath9k_hw_setopmode(ah); | 288 | ath9k_hw_setopmode(ah); |
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index d83b77f821e9..ceed0095efac 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h | |||
@@ -17,6 +17,8 @@ | |||
17 | #ifndef REG_H | 17 | #ifndef REG_H |
18 | #define REG_H | 18 | #define REG_H |
19 | 19 | ||
20 | #include "../reg.h" | ||
21 | |||
20 | #define AR_CR 0x0008 | 22 | #define AR_CR 0x0008 |
21 | #define AR_CR_RXE 0x00000004 | 23 | #define AR_CR_RXE 0x00000004 |
22 | #define AR_CR_RXD 0x00000020 | 24 | #define AR_CR_RXD 0x00000020 |
@@ -1421,9 +1423,6 @@ enum { | |||
1421 | #define AR_SLEEP2_BEACON_TIMEOUT 0xFFE00000 | 1423 | #define AR_SLEEP2_BEACON_TIMEOUT 0xFFE00000 |
1422 | #define AR_SLEEP2_BEACON_TIMEOUT_S 21 | 1424 | #define AR_SLEEP2_BEACON_TIMEOUT_S 21 |
1423 | 1425 | ||
1424 | #define AR_BSSMSKL 0x80e0 | ||
1425 | #define AR_BSSMSKU 0x80e4 | ||
1426 | |||
1427 | #define AR_TPC 0x80e8 | 1426 | #define AR_TPC 0x80e8 |
1428 | #define AR_TPC_ACK 0x0000003f | 1427 | #define AR_TPC_ACK 0x0000003f |
1429 | #define AR_TPC_ACK_S 0x00 | 1428 | #define AR_TPC_ACK_S 0x00 |
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index 7b763b6555fd..bc7d173b6fae 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c | |||
@@ -94,7 +94,7 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw) | |||
94 | common->bssidmask[4] = ~mask[4]; | 94 | common->bssidmask[4] = ~mask[4]; |
95 | common->bssidmask[5] = ~mask[5]; | 95 | common->bssidmask[5] = ~mask[5]; |
96 | 96 | ||
97 | ath9k_hw_setbssidmask(sc->sc_ah); | 97 | ath_hw_setbssidmask(common); |
98 | } | 98 | } |
99 | 99 | ||
100 | int ath9k_wiphy_add(struct ath_softc *sc) | 100 | int ath9k_wiphy_add(struct ath_softc *sc) |
diff --git a/drivers/net/wireless/ath/hw.c b/drivers/net/wireless/ath/hw.c new file mode 100644 index 000000000000..ecc9eb01f4fa --- /dev/null +++ b/drivers/net/wireless/ath/hw.c | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2009 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <asm/unaligned.h> | ||
18 | |||
19 | #include "ath.h" | ||
20 | #include "reg.h" | ||
21 | |||
22 | #define REG_READ common->ops->read | ||
23 | #define REG_WRITE common->ops->write | ||
24 | |||
25 | /** | ||
26 | * ath_hw_set_bssid_mask - filter out bssids we listen | ||
27 | * | ||
28 | * @common: the ath_common struct for the device. | ||
29 | * | ||
30 | * BSSID masking is a method used by AR5212 and newer hardware to inform PCU | ||
31 | * which bits of the interface's MAC address should be looked at when trying | ||
32 | * to decide which packets to ACK. In station mode and AP mode with a single | ||
33 | * BSS every bit matters since we lock to only one BSS. In AP mode with | ||
34 | * multiple BSSes (virtual interfaces) not every bit matters because hw must | ||
35 | * accept frames for all BSSes and so we tweak some bits of our mac address | ||
36 | * in order to have multiple BSSes. | ||
37 | * | ||
38 | * NOTE: This is a simple filter and does *not* filter out all | ||
39 | * relevant frames. Some frames that are not for us might get ACKed from us | ||
40 | * by PCU because they just match the mask. | ||
41 | * | ||
42 | * When handling multiple BSSes you can get the BSSID mask by computing the | ||
43 | * set of ~ ( MAC XOR BSSID ) for all bssids we handle. | ||
44 | * | ||
45 | * When you do this you are essentially computing the common bits of all your | ||
46 | * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with | ||
47 | * the MAC address to obtain the relevant bits and compare the result with | ||
48 | * (frame's BSSID & mask) to see if they match. | ||
49 | * | ||
50 | * Simple example: on your card you have have two BSSes you have created with | ||
51 | * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address. | ||
52 | * There is another BSSID-03 but you are not part of it. For simplicity's sake, | ||
53 | * assuming only 4 bits for a mac address and for BSSIDs you can then have: | ||
54 | * | ||
55 | * \ | ||
56 | * MAC: 0001 | | ||
57 | * BSSID-01: 0100 | --> Belongs to us | ||
58 | * BSSID-02: 1001 | | ||
59 | * / | ||
60 | * ------------------- | ||
61 | * BSSID-03: 0110 | --> External | ||
62 | * ------------------- | ||
63 | * | ||
64 | * Our bssid_mask would then be: | ||
65 | * | ||
66 | * On loop iteration for BSSID-01: | ||
67 | * ~(0001 ^ 0100) -> ~(0101) | ||
68 | * -> 1010 | ||
69 | * bssid_mask = 1010 | ||
70 | * | ||
71 | * On loop iteration for BSSID-02: | ||
72 | * bssid_mask &= ~(0001 ^ 1001) | ||
73 | * bssid_mask = (1010) & ~(0001 ^ 1001) | ||
74 | * bssid_mask = (1010) & ~(1001) | ||
75 | * bssid_mask = (1010) & (0110) | ||
76 | * bssid_mask = 0010 | ||
77 | * | ||
78 | * A bssid_mask of 0010 means "only pay attention to the second least | ||
79 | * significant bit". This is because its the only bit common | ||
80 | * amongst the MAC and all BSSIDs we support. To findout what the real | ||
81 | * common bit is we can simply "&" the bssid_mask now with any BSSID we have | ||
82 | * or our MAC address (we assume the hardware uses the MAC address). | ||
83 | * | ||
84 | * Now, suppose there's an incoming frame for BSSID-03: | ||
85 | * | ||
86 | * IFRAME-01: 0110 | ||
87 | * | ||
88 | * An easy eye-inspeciton of this already should tell you that this frame | ||
89 | * will not pass our check. This is beacuse the bssid_mask tells the | ||
90 | * hardware to only look at the second least significant bit and the | ||
91 | * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB | ||
92 | * as 1, which does not match 0. | ||
93 | * | ||
94 | * So with IFRAME-01 we *assume* the hardware will do: | ||
95 | * | ||
96 | * allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; | ||
97 | * --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0; | ||
98 | * --> allow = (0010) == 0000 ? 1 : 0; | ||
99 | * --> allow = 0 | ||
100 | * | ||
101 | * Lets now test a frame that should work: | ||
102 | * | ||
103 | * IFRAME-02: 0001 (we should allow) | ||
104 | * | ||
105 | * allow = (0001 & 1010) == 1010 | ||
106 | * | ||
107 | * allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; | ||
108 | * --> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0; | ||
109 | * --> allow = (0010) == (0010) | ||
110 | * --> allow = 1 | ||
111 | * | ||
112 | * Other examples: | ||
113 | * | ||
114 | * IFRAME-03: 0100 --> allowed | ||
115 | * IFRAME-04: 1001 --> allowed | ||
116 | * IFRAME-05: 1101 --> allowed but its not for us!!! | ||
117 | * | ||
118 | */ | ||
119 | void ath_hw_setbssidmask(struct ath_common *common) | ||
120 | { | ||
121 | void *ah = common->ah; | ||
122 | |||
123 | REG_WRITE(ah, get_unaligned_le32(common->bssidmask), AR_BSSMSKL); | ||
124 | REG_WRITE(ah, get_unaligned_le16(common->bssidmask + 4), AR_BSSMSKU); | ||
125 | } | ||
126 | EXPORT_SYMBOL(ath_hw_setbssidmask); | ||
diff --git a/drivers/net/wireless/ath/reg.h b/drivers/net/wireless/ath/reg.h new file mode 100644 index 000000000000..dfe1fbec24f5 --- /dev/null +++ b/drivers/net/wireless/ath/reg.h | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008-2009 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #ifndef ATH_REGISTERS_H | ||
18 | #define ATH_REGISTERS_H | ||
19 | |||
20 | /* | ||
21 | * BSSID mask registers. See ath_hw_set_bssid_mask() | ||
22 | * for detailed documentation about these registers. | ||
23 | */ | ||
24 | #define AR_BSSMSKL 0x80e0 | ||
25 | #define AR_BSSMSKU 0x80e4 | ||
26 | |||
27 | #endif /* ATH_REGISTERS_H */ | ||