iPXE
Macros | Functions
ath_hw.c File Reference
#include <ipxe/io.h>
#include "ath.h"
#include "reg.h"

Go to the source code of this file.

Macros

#define REG_READ   (common->ops->read)
 
#define REG_WRITE   (common->ops->write)
 

Functions

void ath_hw_setbssidmask (struct ath_common *common)
 ath_hw_set_bssid_mask - filter out bssids we listen More...
 
void ath_hw_cycle_counters_update (struct ath_common *common)
 ath_hw_cycle_counters_update - common function to update cycle counters More...
 
int32_t ath_hw_get_listen_time (struct ath_common *common)
 

Macro Definition Documentation

◆ REG_READ

#define REG_READ   (common->ops->read)

Definition at line 25 of file ath_hw.c.

◆ REG_WRITE

#define REG_WRITE   (common->ops->write)

Definition at line 26 of file ath_hw.c.

Function Documentation

◆ ath_hw_setbssidmask()

void ath_hw_setbssidmask ( struct ath_common common)

ath_hw_set_bssid_mask - filter out bssids we listen

@common: the ath_common struct for the device.

BSSID masking is a method used by AR5212 and newer hardware to inform PCU which bits of the interface's MAC address should be looked at when trying to decide which packets to ACK. In station mode and AP mode with a single BSS every bit matters since we lock to only one BSS. In AP mode with multiple BSSes (virtual interfaces) not every bit matters because hw must accept frames for all BSSes and so we tweak some bits of our mac address in order to have multiple BSSes.

NOTE: This is a simple filter and does not filter out all relevant frames. Some frames that are not for us might get ACKed from us by PCU because they just match the mask.

When handling multiple BSSes you can get the BSSID mask by computing the set of ~ ( MAC XOR BSSID ) for all bssids we handle.

When you do this you are essentially computing the common bits of all your BSSes. Later it is assumed the hardware will "and" (&) the BSSID mask with the MAC address to obtain the relevant bits and compare the result with (frame's BSSID & mask) to see if they match.

Simple example: on your card you have have two BSSes you have created with BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address. There is another BSSID-03 but you are not part of it. For simplicity's sake, assuming only 4 bits for a mac address and for BSSIDs you can then have:

             \

MAC: 0001 | BSSID-01: 0100 | --> Belongs to us BSSID-02: 1001 |

/

BSSID-03: 0110 | --> External

Our bssid_mask would then be:

        On loop iteration for BSSID-01:
        ~(0001 ^ 0100)  -> ~(0101)
                        ->   1010
        bssid_mask      =    1010

        On loop iteration for BSSID-02:
        bssid_mask &= ~(0001   ^   1001)
        bssid_mask =   (1010)  & ~(0001 ^ 1001)
        bssid_mask =   (1010)  & ~(1000)
        bssid_mask =   (1010)  &  (0111)
        bssid_mask =   0010

A bssid_mask of 0010 means "only pay attention to the second least significant bit". This is because its the only bit common amongst the MAC and all BSSIDs we support. To findout what the real common bit is we can simply "&" the bssid_mask now with any BSSID we have or our MAC address (we assume the hardware uses the MAC address).

Now, suppose there's an incoming frame for BSSID-03:

IFRAME-01: 0110

An easy eye-inspeciton of this already should tell you that this frame will not pass our check. This is because the bssid_mask tells the hardware to only look at the second least significant bit and the common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB as 1, which does not match 0.

So with IFRAME-01 we assume the hardware will do:

allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;

--> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0; --> allow = (0010) == 0000 ? 1 : 0; --> allow = 0

Lets now test a frame that should work:

IFRAME-02: 0001 (we should allow)

allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;

--> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0; --> allow = (0000) == (0000) --> allow = 1

Other examples:

IFRAME-03: 0100 --> allowed IFRAME-04: 1001 --> allowed IFRAME-05: 1101 --> allowed but its not for us!!!

Definition at line 120 of file ath_hw.c.

121 {
122  void *ah = common->ah;
123 
125  REG_WRITE(ah, get_unaligned_le16(common->bssidmask + 4), AR_BSSMSKU);
126 }
#define AR_BSSMSKL
Definition: reg.h:35
#define REG_WRITE
Definition: ath_hw.c:26
static u32 get_unaligned_le32(const void *p)
Definition: ath.h:87
static u16 get_unaligned_le16(const void *p)
Definition: ath.h:83
#define AR_BSSMSKU
Definition: reg.h:36
struct ib_cm_common common
Definition: ib_mad.h:11
uint8_t ah
Definition: registers.h:85

References ah, AR_BSSMSKL, AR_BSSMSKU, common, get_unaligned_le16(), get_unaligned_le32(), and REG_WRITE.

Referenced by ath9k_hw_reset(), and ath_opmode_init().

◆ ath_hw_cycle_counters_update()

void ath_hw_cycle_counters_update ( struct ath_common common)

ath_hw_cycle_counters_update - common function to update cycle counters

@common: the ath_common struct for the device.

This function is used to update all cycle counters in one place. It has to be called while holding common->cc_lock!

Definition at line 137 of file ath_hw.c.

138 {
139  u32 cycles, busy, rx, tx;
140  void *ah = common->ah;
141 
142  /* freeze */
144 
145  /* read */
146  cycles = REG_READ(ah, AR_CCCNT);
147  busy = REG_READ(ah, AR_RCCNT);
148  rx = REG_READ(ah, AR_RFCNT);
149  tx = REG_READ(ah, AR_TFCNT);
150 
151  /* clear */
152  REG_WRITE(ah, 0, AR_CCCNT);
153  REG_WRITE(ah, 0, AR_RFCNT);
154  REG_WRITE(ah, 0, AR_RCCNT);
155  REG_WRITE(ah, 0, AR_TFCNT);
156 
157  /* unfreeze */
158  REG_WRITE(ah, 0, AR_MIBC);
159 
160  /* update all cycle counters here */
161  common->cc_ani.cycles += cycles;
162  common->cc_ani.rx_busy += busy;
163  common->cc_ani.rx_frame += rx;
164  common->cc_ani.tx_frame += tx;
165 
166  common->cc_survey.cycles += cycles;
167  common->cc_survey.rx_busy += busy;
168  common->cc_survey.rx_frame += rx;
169  common->cc_survey.tx_frame += tx;
170 }
#define AR_RCCNT
Definition: reg.h:40
#define REG_WRITE
Definition: ath_hw.c:26
#define REG_READ
Definition: ath_hw.c:25
#define AR_TFCNT
Definition: reg.h:38
#define AR_CCCNT
Definition: reg.h:41
struct ib_cm_common common
Definition: ib_mad.h:11
u8 rx[WPA_TKIP_MIC_KEY_LEN]
MIC key for packets from the AP.
Definition: wpa.h:234
uint8_t ah
Definition: registers.h:85
#define AR_MIBC
Definition: reg.h:25
#define AR_MIBC_FMC
Definition: reg.h:27
#define AR_RFCNT
Definition: reg.h:39
uint32_t u32
Definition: stdint.h:23
u8 tx[WPA_TKIP_MIC_KEY_LEN]
MIC key for packets to the AP.
Definition: wpa.h:237

References ah, AR_CCCNT, AR_MIBC, AR_MIBC_FMC, AR_RCCNT, AR_RFCNT, AR_TFCNT, common, REG_READ, REG_WRITE, rx, and tx.

Referenced by ath9k_hw_ani_read_counters(), and ath_update_survey_stats().

◆ ath_hw_get_listen_time()

int32_t ath_hw_get_listen_time ( struct ath_common common)

Definition at line 172 of file ath_hw.c.

173 {
174  struct ath_cycle_counters *cc = &common->cc_ani;
175  int32_t listen_time;
176 
177  listen_time = (cc->cycles - cc->rx_frame - cc->tx_frame) /
178  (common->clockrate * 1000);
179 
180  memset(cc, 0, sizeof(*cc));
181 
182  return listen_time;
183 }
struct ib_cm_common common
Definition: ib_mad.h:11
signed int int32_t
Definition: stdint.h:17
void * memset(void *dest, int character, size_t len) __nonnull

References common, ath_cycle_counters::cycles, memset(), ath_cycle_counters::rx_frame, and ath_cycle_counters::tx_frame.

Referenced by ath9k_hw_ani_read_counters().