LCOV - code coverage report
Current view: top level - drivers/net/wireless/ath - hw.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 32 39 82.1 %
Date: 2022-03-28 13:20:08 Functions: 2 3 66.7 %
Branches: 0 0 -

           Branch data     Line data    Source code
       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                 :        189 : void ath_hw_setbssidmask(struct ath_common *common)
     119                 :            : {
     120                 :        189 :         void *ah = common->ah;
     121                 :        189 :         u32 id1;
     122                 :            : 
     123                 :        189 :         REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr));
     124                 :        189 :         id1 = REG_READ(ah, AR_STA_ID1) & ~AR_STA_ID1_SADH_MASK;
     125                 :        189 :         id1 |= get_unaligned_le16(common->macaddr + 4);
     126                 :        189 :         REG_WRITE(ah, AR_STA_ID1, id1);
     127                 :            : 
     128                 :        189 :         REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(common->bssidmask));
     129                 :        189 :         REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(common->bssidmask + 4));
     130                 :        189 : }
     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                 :         65 : void ath_hw_cycle_counters_update(struct ath_common *common)
     143                 :            : {
     144                 :         65 :         u32 cycles, busy, rx, tx;
     145                 :         65 :         void *ah = common->ah;
     146                 :            : 
     147                 :            :         /* freeze */
     148                 :         65 :         REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC);
     149                 :            : 
     150                 :            :         /* read */
     151                 :         65 :         cycles = REG_READ(ah, AR_CCCNT);
     152                 :         65 :         busy = REG_READ(ah, AR_RCCNT);
     153                 :         65 :         rx = REG_READ(ah, AR_RFCNT);
     154                 :         65 :         tx = REG_READ(ah, AR_TFCNT);
     155                 :            : 
     156                 :            :         /* clear */
     157                 :         65 :         REG_WRITE(ah, AR_CCCNT, 0);
     158                 :         65 :         REG_WRITE(ah, AR_RFCNT, 0);
     159                 :         65 :         REG_WRITE(ah, AR_RCCNT, 0);
     160                 :         65 :         REG_WRITE(ah, AR_TFCNT, 0);
     161                 :            : 
     162                 :            :         /* unfreeze */
     163                 :         65 :         REG_WRITE(ah, AR_MIBC, 0);
     164                 :            : 
     165                 :            :         /* update all cycle counters here */
     166                 :         65 :         common->cc_ani.cycles += cycles;
     167                 :         65 :         common->cc_ani.rx_busy += busy;
     168                 :         65 :         common->cc_ani.rx_frame += rx;
     169                 :         65 :         common->cc_ani.tx_frame += tx;
     170                 :            : 
     171                 :         65 :         common->cc_survey.cycles += cycles;
     172                 :         65 :         common->cc_survey.rx_busy += busy;
     173                 :         65 :         common->cc_survey.rx_frame += rx;
     174                 :         65 :         common->cc_survey.tx_frame += tx;
     175                 :         65 : }
     176                 :            : EXPORT_SYMBOL(ath_hw_cycle_counters_update);
     177                 :            : 
     178                 :          0 : int32_t ath_hw_get_listen_time(struct ath_common *common)
     179                 :            : {
     180                 :          0 :         struct ath_cycle_counters *cc = &common->cc_ani;
     181                 :          0 :         int32_t listen_time;
     182                 :            : 
     183                 :          0 :         listen_time = (cc->cycles - cc->rx_frame - cc->tx_frame) /
     184                 :          0 :                       (common->clockrate * 1000);
     185                 :            : 
     186                 :          0 :         memset(cc, 0, sizeof(*cc));
     187                 :            : 
     188                 :          0 :         return listen_time;
     189                 :            : }
     190                 :            : EXPORT_SYMBOL(ath_hw_get_listen_time);

Generated by: LCOV version 1.14