root/drivers/net/wireless/ath/hw.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ath_hw_setbssidmask
  2. ath_hw_cycle_counters_update
  3. ath_hw_get_listen_time

   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 <linux/export.h>
  18 #include <asm/unaligned.h>
  19 
  20 #include "ath.h"
  21 #include "reg.h"
  22 
  23 #define REG_READ                        (common->ops->read)
  24 #define REG_WRITE(_ah, _reg, _val)      (common->ops->write)(_ah, _val, _reg)
  25 
  26 /**
  27  * ath_hw_set_bssid_mask - filter out bssids we listen
  28  *
  29  * @common: the ath_common struct for the device.
  30  *
  31  * BSSID masking is a method used by AR5212 and newer hardware to inform PCU
  32  * which bits of the interface's MAC address should be looked at when trying
  33  * to decide which packets to ACK. In station mode and AP mode with a single
  34  * BSS every bit matters since we lock to only one BSS. In AP mode with
  35  * multiple BSSes (virtual interfaces) not every bit matters because hw must
  36  * accept frames for all BSSes and so we tweak some bits of our mac address
  37  * in order to have multiple BSSes.
  38  *
  39  * NOTE: This is a simple filter and does *not* filter out all
  40  * relevant frames. Some frames that are not for us might get ACKed from us
  41  * by PCU because they just match the mask.
  42  *
  43  * When handling multiple BSSes you can get the BSSID mask by computing the
  44  * set of  ~ ( MAC XOR BSSID ) for all bssids we handle.
  45  *
  46  * When you do this you are essentially computing the common bits of all your
  47  * BSSes. Later it is assumed the hardware will "and" (&) the BSSID mask with
  48  * the MAC address to obtain the relevant bits and compare the result with
  49  * (frame's BSSID & mask) to see if they match.
  50  *
  51  * Simple example: on your card you have have two BSSes you have created with
  52  * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address.
  53  * There is another BSSID-03 but you are not part of it. For simplicity's sake,
  54  * assuming only 4 bits for a mac address and for BSSIDs you can then have:
  55  *
  56  *                  \
  57  * MAC:        0001 |
  58  * BSSID-01:   0100 | --> Belongs to us
  59  * BSSID-02:   1001 |
  60  *                  /
  61  * -------------------
  62  * BSSID-03:   0110  | --> External
  63  * -------------------
  64  *
  65  * Our bssid_mask would then be:
  66  *
  67  *             On loop iteration for BSSID-01:
  68  *             ~(0001 ^ 0100)  -> ~(0101)
  69  *                             ->   1010
  70  *             bssid_mask      =    1010
  71  *
  72  *             On loop iteration for BSSID-02:
  73  *             bssid_mask &= ~(0001   ^   1001)
  74  *             bssid_mask =   (1010)  & ~(0001 ^ 1001)
  75  *             bssid_mask =   (1010)  & ~(1000)
  76  *             bssid_mask =   (1010)  &  (0111)
  77  *             bssid_mask =   0010
  78  *
  79  * A bssid_mask of 0010 means "only pay attention to the second least
  80  * significant bit". This is because its the only bit common
  81  * amongst the MAC and all BSSIDs we support. To findout what the real
  82  * common bit is we can simply "&" the bssid_mask now with any BSSID we have
  83  * or our MAC address (we assume the hardware uses the MAC address).
  84  *
  85  * Now, suppose there's an incoming frame for BSSID-03:
  86  *
  87  * IFRAME-01:  0110
  88  *
  89  * An easy eye-inspeciton of this already should tell you that this frame
  90  * will not pass our check. This is because the bssid_mask tells the
  91  * hardware to only look at the second least significant bit and the
  92  * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB
  93  * as 1, which does not match 0.
  94  *
  95  * So with IFRAME-01 we *assume* the hardware will do:
  96  *
  97  *     allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
  98  *  --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0;
  99  *  --> allow = (0010) == 0000 ? 1 : 0;
 100  *  --> allow = 0
 101  *
 102  *  Lets now test a frame that should work:
 103  *
 104  * IFRAME-02:  0001 (we should allow)
 105  *
 106  *     allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
 107  *  --> allow = (0001 & 0010) ==  (0010 & 0001) ? 1 :0;
 108  *  --> allow = (0000) == (0000)
 109  *  --> allow = 1
 110  *
 111  * Other examples:
 112  *
 113  * IFRAME-03:  0100 --> allowed
 114  * IFRAME-04:  1001 --> allowed
 115  * IFRAME-05:  1101 --> allowed but its not for us!!!
 116  *
 117  */
 118 void ath_hw_setbssidmask(struct ath_common *common)
 119 {
 120         void *ah = common->ah;
 121         u32 id1;
 122 
 123         REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr));
 124         id1 = REG_READ(ah, AR_STA_ID1) & ~AR_STA_ID1_SADH_MASK;
 125         id1 |= get_unaligned_le16(common->macaddr + 4);
 126         REG_WRITE(ah, AR_STA_ID1, id1);
 127 
 128         REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(common->bssidmask));
 129         REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(common->bssidmask + 4));
 130 }
 131 EXPORT_SYMBOL(ath_hw_setbssidmask);
 132 
 133 
 134 /**
 135  * ath_hw_cycle_counters_update - common function to update cycle counters
 136  *
 137  * @common: the ath_common struct for the device.
 138  *
 139  * This function is used to update all cycle counters in one place.
 140  * It has to be called while holding common->cc_lock!
 141  */
 142 void ath_hw_cycle_counters_update(struct ath_common *common)
 143 {
 144         u32 cycles, busy, rx, tx;
 145         void *ah = common->ah;
 146 
 147         /* freeze */
 148         REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC);
 149 
 150         /* read */
 151         cycles = REG_READ(ah, AR_CCCNT);
 152         busy = REG_READ(ah, AR_RCCNT);
 153         rx = REG_READ(ah, AR_RFCNT);
 154         tx = REG_READ(ah, AR_TFCNT);
 155 
 156         /* clear */
 157         REG_WRITE(ah, AR_CCCNT, 0);
 158         REG_WRITE(ah, AR_RFCNT, 0);
 159         REG_WRITE(ah, AR_RCCNT, 0);
 160         REG_WRITE(ah, AR_TFCNT, 0);
 161 
 162         /* unfreeze */
 163         REG_WRITE(ah, AR_MIBC, 0);
 164 
 165         /* update all cycle counters here */
 166         common->cc_ani.cycles += cycles;
 167         common->cc_ani.rx_busy += busy;
 168         common->cc_ani.rx_frame += rx;
 169         common->cc_ani.tx_frame += tx;
 170 
 171         common->cc_survey.cycles += cycles;
 172         common->cc_survey.rx_busy += busy;
 173         common->cc_survey.rx_frame += rx;
 174         common->cc_survey.tx_frame += tx;
 175 }
 176 EXPORT_SYMBOL(ath_hw_cycle_counters_update);
 177 
 178 int32_t ath_hw_get_listen_time(struct ath_common *common)
 179 {
 180         struct ath_cycle_counters *cc = &common->cc_ani;
 181         int32_t listen_time;
 182 
 183         listen_time = (cc->cycles - cc->rx_frame - cc->tx_frame) /
 184                       (common->clockrate * 1000);
 185 
 186         memset(cc, 0, sizeof(*cc));
 187 
 188         return listen_time;
 189 }
 190 EXPORT_SYMBOL(ath_hw_get_listen_time);

/* [<][>][^][v][top][bottom][index][help] */