LCOV - code coverage report
Current view: top level - drivers/net/wireless/ath/ath9k - beacon.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 13 297 4.4 %
Date: 2022-03-28 13:20:08 Functions: 1 16 6.2 %
Branches: 2 154 1.3 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2008-2011 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/dma-mapping.h>
      18                 :            : #include "ath9k.h"
      19                 :            : 
      20                 :            : #define FUDGE 2
      21                 :            : 
      22                 :          0 : static void ath9k_reset_beacon_status(struct ath_softc *sc)
      23                 :            : {
      24                 :          0 :         sc->beacon.tx_processed = false;
      25                 :          0 :         sc->beacon.tx_last = false;
      26                 :            : }
      27                 :            : 
      28                 :            : /*
      29                 :            :  *  This function will modify certain transmit queue properties depending on
      30                 :            :  *  the operating mode of the station (AP or AdHoc).  Parameters are AIFS
      31                 :            :  *  settings and channel width min/max
      32                 :            : */
      33                 :          0 : static void ath9k_beaconq_config(struct ath_softc *sc)
      34                 :            : {
      35                 :          0 :         struct ath_hw *ah = sc->sc_ah;
      36                 :          0 :         struct ath_common *common = ath9k_hw_common(ah);
      37                 :          0 :         struct ath9k_tx_queue_info qi, qi_be;
      38                 :          0 :         struct ath_txq *txq;
      39                 :            : 
      40                 :          0 :         ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi);
      41                 :            : 
      42   [ #  #  #  # ]:          0 :         if (sc->sc_ah->opmode == NL80211_IFTYPE_AP ||
      43                 :            :             sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) {
      44                 :            :                 /* Always burst out beacon and CAB traffic. */
      45                 :          0 :                 qi.tqi_aifs = 1;
      46                 :          0 :                 qi.tqi_cwmin = 0;
      47                 :          0 :                 qi.tqi_cwmax = 0;
      48                 :            :         } else {
      49                 :            :                 /* Adhoc mode; important thing is to use 2x cwmin. */
      50                 :          0 :                 txq = sc->tx.txq_map[IEEE80211_AC_BE];
      51                 :          0 :                 ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be);
      52                 :          0 :                 qi.tqi_aifs = qi_be.tqi_aifs;
      53         [ #  # ]:          0 :                 if (ah->slottime == 20)
      54                 :          0 :                         qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
      55                 :            :                 else
      56                 :          0 :                         qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
      57                 :          0 :                 qi.tqi_cwmax = qi_be.tqi_cwmax;
      58                 :            :         }
      59                 :            : 
      60         [ #  # ]:          0 :         if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) {
      61                 :          0 :                 ath_err(common, "Unable to update h/w beacon queue parameters\n");
      62                 :            :         } else {
      63                 :          0 :                 ath9k_hw_resettxqueue(ah, sc->beacon.beaconq);
      64                 :            :         }
      65                 :          0 : }
      66                 :            : 
      67                 :            : /*
      68                 :            :  *  Associates the beacon frame buffer with a transmit descriptor.  Will set
      69                 :            :  *  up rate codes, and channel flags. Beacons are always sent out at the
      70                 :            :  *  lowest rate, and are not retried.
      71                 :            : */
      72                 :            : static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
      73                 :            :                              struct ath_buf *bf, int rateidx)
      74                 :            : {
      75                 :            :         struct sk_buff *skb = bf->bf_mpdu;
      76                 :            :         struct ath_hw *ah = sc->sc_ah;
      77                 :            :         struct ath_common *common = ath9k_hw_common(ah);
      78                 :            :         struct ath_tx_info info;
      79                 :            :         struct ieee80211_supported_band *sband;
      80                 :            :         u8 chainmask = ah->txchainmask;
      81                 :            :         u8 i, rate = 0;
      82                 :            : 
      83                 :            :         sband = &common->sbands[sc->cur_chandef.chan->band];
      84                 :            :         rate = sband->bitrates[rateidx].hw_value;
      85                 :            :         if (vif->bss_conf.use_short_preamble)
      86                 :            :                 rate |= sband->bitrates[rateidx].hw_value_short;
      87                 :            : 
      88                 :            :         memset(&info, 0, sizeof(info));
      89                 :            :         info.pkt_len = skb->len + FCS_LEN;
      90                 :            :         info.type = ATH9K_PKT_TYPE_BEACON;
      91                 :            :         for (i = 0; i < 4; i++)
      92                 :            :                 info.txpower[i] = MAX_RATE_POWER;
      93                 :            :         info.keyix = ATH9K_TXKEYIX_INVALID;
      94                 :            :         info.keytype = ATH9K_KEY_TYPE_CLEAR;
      95                 :            :         info.flags = ATH9K_TXDESC_NOACK | ATH9K_TXDESC_CLRDMASK;
      96                 :            : 
      97                 :            :         info.buf_addr[0] = bf->bf_buf_addr;
      98                 :            :         info.buf_len[0] = roundup(skb->len, 4);
      99                 :            : 
     100                 :            :         info.is_first = true;
     101                 :            :         info.is_last = true;
     102                 :            : 
     103                 :            :         info.qcu = sc->beacon.beaconq;
     104                 :            : 
     105                 :            :         info.rates[0].Tries = 1;
     106                 :            :         info.rates[0].Rate = rate;
     107                 :            :         info.rates[0].ChSel = ath_txchainmask_reduction(sc, chainmask, rate);
     108                 :            : 
     109                 :            :         ath9k_hw_set_txdesc(ah, bf->bf_desc, &info);
     110                 :            : }
     111                 :            : 
     112                 :          0 : static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
     113                 :            :                                              struct ieee80211_vif *vif)
     114                 :            : {
     115                 :          0 :         struct ath_softc *sc = hw->priv;
     116         [ #  # ]:          0 :         struct ath_common *common = ath9k_hw_common(sc->sc_ah);
     117                 :          0 :         struct ath_buf *bf;
     118                 :          0 :         struct ath_vif *avp = (void *)vif->drv_priv;
     119                 :          0 :         struct sk_buff *skb;
     120                 :          0 :         struct ath_txq *cabq = sc->beacon.cabq;
     121                 :          0 :         struct ieee80211_tx_info *info;
     122                 :          0 :         struct ieee80211_mgmt *mgmt_hdr;
     123                 :          0 :         int cabq_depth;
     124                 :            : 
     125         [ #  # ]:          0 :         if (avp->av_bcbuf == NULL)
     126                 :            :                 return NULL;
     127                 :            : 
     128                 :          0 :         bf = avp->av_bcbuf;
     129                 :          0 :         skb = bf->bf_mpdu;
     130         [ #  # ]:          0 :         if (skb) {
     131                 :          0 :                 dma_unmap_single(sc->dev, bf->bf_buf_addr,
     132                 :            :                                  skb->len, DMA_TO_DEVICE);
     133                 :          0 :                 dev_kfree_skb_any(skb);
     134                 :          0 :                 bf->bf_buf_addr = 0;
     135                 :          0 :                 bf->bf_mpdu = NULL;
     136                 :            :         }
     137                 :            : 
     138                 :          0 :         skb = ieee80211_beacon_get(hw, vif);
     139         [ #  # ]:          0 :         if (skb == NULL)
     140                 :            :                 return NULL;
     141                 :            : 
     142                 :          0 :         bf->bf_mpdu = skb;
     143                 :            : 
     144                 :          0 :         mgmt_hdr = (struct ieee80211_mgmt *)skb->data;
     145                 :          0 :         mgmt_hdr->u.beacon.timestamp = avp->tsf_adjust;
     146                 :            : 
     147                 :          0 :         info = IEEE80211_SKB_CB(skb);
     148                 :            : 
     149                 :          0 :         ath_assign_seq(common, skb);
     150                 :            : 
     151                 :            :         /* Always assign NOA attr when MCC enabled */
     152                 :          0 :         if (ath9k_is_chanctx_enabled())
     153                 :            :                 ath9k_beacon_add_noa(sc, avp, skb);
     154                 :            : 
     155                 :          0 :         bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
     156                 :            :                                          skb->len, DMA_TO_DEVICE);
     157         [ #  # ]:          0 :         if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
     158                 :          0 :                 dev_kfree_skb_any(skb);
     159                 :          0 :                 bf->bf_mpdu = NULL;
     160                 :          0 :                 bf->bf_buf_addr = 0;
     161                 :          0 :                 ath_err(common, "dma_mapping_error on beaconing\n");
     162                 :          0 :                 return NULL;
     163                 :            :         }
     164                 :            : 
     165                 :          0 :         skb = ieee80211_get_buffered_bc(hw, vif);
     166                 :            : 
     167                 :            :         /*
     168                 :            :          * if the CABQ traffic from previous DTIM is pending and the current
     169                 :            :          *  beacon is also a DTIM.
     170                 :            :          *  1) if there is only one vif let the cab traffic continue.
     171                 :            :          *  2) if there are more than one vif and we are using staggered
     172                 :            :          *     beacons, then drain the cabq by dropping all the frames in
     173                 :            :          *     the cabq so that the current vifs cab traffic can be scheduled.
     174                 :            :          */
     175                 :          0 :         spin_lock_bh(&cabq->axq_lock);
     176                 :          0 :         cabq_depth = cabq->axq_depth;
     177                 :          0 :         spin_unlock_bh(&cabq->axq_lock);
     178                 :            : 
     179   [ #  #  #  # ]:          0 :         if (skb && cabq_depth) {
     180         [ #  # ]:          0 :                 if (sc->cur_chan->nvifs > 1) {
     181         [ #  # ]:          0 :                         ath_dbg(common, BEACON,
     182                 :            :                                 "Flushing previous cabq traffic\n");
     183                 :          0 :                         ath_draintxq(sc, cabq);
     184                 :            :                 }
     185                 :            :         }
     186                 :            : 
     187                 :          0 :         ath9k_beacon_setup(sc, vif, bf, info->control.rates[0].idx);
     188                 :            : 
     189         [ #  # ]:          0 :         if (skb)
     190                 :          0 :                 ath_tx_cabq(hw, vif, skb);
     191                 :            : 
     192                 :            :         return bf;
     193                 :            : }
     194                 :            : 
     195                 :          0 : void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
     196                 :            : {
     197                 :          0 :         struct ath_common *common = ath9k_hw_common(sc->sc_ah);
     198                 :          0 :         struct ath_vif *avp = (void *)vif->drv_priv;
     199                 :          0 :         int slot;
     200                 :            : 
     201                 :          0 :         avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf, struct ath_buf, list);
     202                 :          0 :         list_del(&avp->av_bcbuf->list);
     203                 :            : 
     204         [ #  # ]:          0 :         for (slot = 0; slot < ATH_BCBUF; slot++) {
     205         [ #  # ]:          0 :                 if (sc->beacon.bslot[slot] == NULL) {
     206                 :          0 :                         avp->av_bslot = slot;
     207                 :          0 :                         break;
     208                 :            :                 }
     209                 :            :         }
     210                 :            : 
     211                 :          0 :         sc->beacon.bslot[avp->av_bslot] = vif;
     212                 :            : 
     213         [ #  # ]:          0 :         ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n",
     214                 :            :                 avp->av_bslot);
     215                 :          0 : }
     216                 :            : 
     217                 :          0 : void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
     218                 :            : {
     219         [ #  # ]:          0 :         struct ath_common *common = ath9k_hw_common(sc->sc_ah);
     220                 :          0 :         struct ath_vif *avp = (void *)vif->drv_priv;
     221                 :          0 :         struct ath_buf *bf = avp->av_bcbuf;
     222                 :            : 
     223         [ #  # ]:          0 :         ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n",
     224                 :            :                 avp->av_bslot);
     225                 :            : 
     226                 :          0 :         tasklet_disable(&sc->bcon_tasklet);
     227                 :            : 
     228   [ #  #  #  # ]:          0 :         if (bf && bf->bf_mpdu) {
     229                 :          0 :                 struct sk_buff *skb = bf->bf_mpdu;
     230                 :          0 :                 dma_unmap_single(sc->dev, bf->bf_buf_addr,
     231                 :            :                                  skb->len, DMA_TO_DEVICE);
     232                 :          0 :                 dev_kfree_skb_any(skb);
     233                 :          0 :                 bf->bf_mpdu = NULL;
     234                 :          0 :                 bf->bf_buf_addr = 0;
     235                 :            :         }
     236                 :            : 
     237                 :          0 :         avp->av_bcbuf = NULL;
     238                 :          0 :         sc->beacon.bslot[avp->av_bslot] = NULL;
     239                 :          0 :         list_add_tail(&bf->list, &sc->beacon.bbuf);
     240                 :            : 
     241                 :          0 :         tasklet_enable(&sc->bcon_tasklet);
     242                 :          0 : }
     243                 :            : 
     244                 :          0 : void ath9k_beacon_ensure_primary_slot(struct ath_softc *sc)
     245                 :            : {
     246                 :          0 :         struct ath_common *common = ath9k_hw_common(sc->sc_ah);
     247                 :          0 :         struct ieee80211_vif *vif;
     248                 :          0 :         struct ath_vif *avp;
     249                 :          0 :         s64 tsfadjust;
     250                 :          0 :         u32 offset;
     251                 :          0 :         int first_slot = ATH_BCBUF;
     252                 :          0 :         int slot;
     253                 :            : 
     254                 :          0 :         tasklet_disable(&sc->bcon_tasklet);
     255                 :            : 
     256                 :            :         /* Find first taken slot. */
     257         [ #  # ]:          0 :         for (slot = 0; slot < ATH_BCBUF; slot++) {
     258         [ #  # ]:          0 :                 if (sc->beacon.bslot[slot]) {
     259                 :            :                         first_slot = slot;
     260                 :            :                         break;
     261                 :            :                 }
     262                 :            :         }
     263         [ #  # ]:          0 :         if (first_slot == 0)
     264                 :          0 :                 goto out;
     265                 :            : 
     266                 :            :         /* Re-enumarate all slots, moving them forward. */
     267         [ #  # ]:          0 :         for (slot = 0; slot < ATH_BCBUF; slot++) {
     268         [ #  # ]:          0 :                 if (slot + first_slot < ATH_BCBUF) {
     269                 :          0 :                         vif = sc->beacon.bslot[slot + first_slot];
     270                 :          0 :                         sc->beacon.bslot[slot] = vif;
     271                 :            : 
     272         [ #  # ]:          0 :                         if (vif) {
     273                 :          0 :                                 avp = (void *)vif->drv_priv;
     274                 :          0 :                                 avp->av_bslot = slot;
     275                 :            :                         }
     276                 :            :                 } else {
     277                 :          0 :                         sc->beacon.bslot[slot] = NULL;
     278                 :            :                 }
     279                 :            :         }
     280                 :            : 
     281                 :          0 :         vif = sc->beacon.bslot[0];
     282   [ #  #  #  # ]:          0 :         if (WARN_ON(!vif))
     283                 :          0 :                 goto out;
     284                 :            : 
     285                 :            :         /* Get the tsf_adjust value for the new first slot. */
     286                 :          0 :         avp = (void *)vif->drv_priv;
     287                 :          0 :         tsfadjust = le64_to_cpu(avp->tsf_adjust);
     288                 :            : 
     289         [ #  # ]:          0 :         ath_dbg(common, CONFIG,
     290                 :            :                 "Adjusting global TSF after beacon slot reassignment: %lld\n",
     291                 :            :                 (signed long long)tsfadjust);
     292                 :            : 
     293                 :            :         /* Modify TSF as required and update the HW. */
     294                 :          0 :         avp->chanctx->tsf_val += tsfadjust;
     295         [ #  # ]:          0 :         if (sc->cur_chan == avp->chanctx) {
     296                 :          0 :                 offset = ath9k_hw_get_tsf_offset(&avp->chanctx->tsf_ts, NULL);
     297                 :          0 :                 ath9k_hw_settsf64(sc->sc_ah, avp->chanctx->tsf_val + offset);
     298                 :            :         }
     299                 :            : 
     300                 :            :         /* The slots tsf_adjust will be updated by ath9k_beacon_config later. */
     301                 :            : 
     302                 :          0 : out:
     303                 :          0 :         tasklet_enable(&sc->bcon_tasklet);
     304                 :          0 : }
     305                 :            : 
     306                 :            : static int ath9k_beacon_choose_slot(struct ath_softc *sc)
     307                 :            : {
     308                 :            :         struct ath_common *common = ath9k_hw_common(sc->sc_ah);
     309                 :            :         struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
     310                 :            :         u16 intval;
     311                 :            :         u32 tsftu;
     312                 :            :         u64 tsf;
     313                 :            :         int slot;
     314                 :            : 
     315                 :            :         if (sc->sc_ah->opmode != NL80211_IFTYPE_AP &&
     316                 :            :             sc->sc_ah->opmode != NL80211_IFTYPE_MESH_POINT) {
     317                 :            :                 ath_dbg(common, BEACON, "slot 0, tsf: %llu\n",
     318                 :            :                         ath9k_hw_gettsf64(sc->sc_ah));
     319                 :            :                 return 0;
     320                 :            :         }
     321                 :            : 
     322                 :            :         intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
     323                 :            :         tsf = ath9k_hw_gettsf64(sc->sc_ah);
     324                 :            :         tsf += TU_TO_USEC(sc->sc_ah->config.sw_beacon_response_time);
     325                 :            :         tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF);
     326                 :            :         slot = (tsftu % (intval * ATH_BCBUF)) / intval;
     327                 :            : 
     328                 :            :         ath_dbg(common, BEACON, "slot: %d tsf: %llu tsftu: %u\n",
     329                 :            :                 slot, tsf, tsftu / ATH_BCBUF);
     330                 :            : 
     331                 :            :         return slot;
     332                 :            : }
     333                 :            : 
     334                 :            : static void ath9k_set_tsfadjust(struct ath_softc *sc,
     335                 :            :                                 struct ath_beacon_config *cur_conf)
     336                 :            : {
     337                 :            :         struct ath_common *common = ath9k_hw_common(sc->sc_ah);
     338                 :            :         s64 tsfadjust;
     339                 :            :         int slot;
     340                 :            : 
     341                 :            :         for (slot = 0; slot < ATH_BCBUF; slot++) {
     342                 :            :                 struct ath_vif *avp;
     343                 :            : 
     344                 :            :                 if (!sc->beacon.bslot[slot])
     345                 :            :                         continue;
     346                 :            : 
     347                 :            :                 avp = (void *)sc->beacon.bslot[slot]->drv_priv;
     348                 :            : 
     349                 :            :                 /* tsf_adjust is added to the TSF value. We send out the
     350                 :            :                  * beacon late, so need to adjust the TSF starting point to be
     351                 :            :                  * later in time (i.e. the theoretical first beacon has a TSF
     352                 :            :                  * of 0 after correction).
     353                 :            :                  */
     354                 :            :                 tsfadjust = cur_conf->beacon_interval * avp->av_bslot;
     355                 :            :                 tsfadjust = -TU_TO_USEC(tsfadjust) / ATH_BCBUF;
     356                 :            :                 avp->tsf_adjust = cpu_to_le64(tsfadjust);
     357                 :            : 
     358                 :            :                 ath_dbg(common, CONFIG, "tsfadjust is: %lld for bslot: %d\n",
     359                 :            :                         (signed long long)tsfadjust, avp->av_bslot);
     360                 :            :         }
     361                 :            : }
     362                 :            : 
     363                 :          0 : bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif)
     364                 :            : {
     365   [ #  #  #  # ]:          0 :         if (!vif || !vif->csa_active)
     366                 :            :                 return false;
     367                 :            : 
     368         [ #  # ]:          0 :         if (!ieee80211_csa_is_complete(vif))
     369                 :            :                 return false;
     370                 :            : 
     371                 :          0 :         ieee80211_csa_finish(vif);
     372                 :          0 :         return true;
     373                 :            : }
     374                 :            : 
     375                 :          0 : static void ath9k_csa_update_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
     376                 :            : {
     377                 :          0 :         struct ath_softc *sc = data;
     378                 :          0 :         ath9k_csa_is_finished(sc, vif);
     379                 :          0 : }
     380                 :            : 
     381                 :          0 : void ath9k_csa_update(struct ath_softc *sc)
     382                 :            : {
     383                 :          0 :         ieee80211_iterate_active_interfaces_atomic(sc->hw,
     384                 :            :                                                    IEEE80211_IFACE_ITER_NORMAL,
     385                 :            :                                                    ath9k_csa_update_vif, sc);
     386                 :          0 : }
     387                 :            : 
     388                 :          0 : void ath9k_beacon_tasklet(unsigned long data)
     389                 :            : {
     390                 :          0 :         struct ath_softc *sc = (struct ath_softc *)data;
     391                 :          0 :         struct ath_hw *ah = sc->sc_ah;
     392                 :          0 :         struct ath_common *common = ath9k_hw_common(ah);
     393                 :          0 :         struct ath_buf *bf = NULL;
     394                 :          0 :         struct ieee80211_vif *vif;
     395                 :          0 :         bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
     396                 :          0 :         int slot;
     397                 :            : 
     398         [ #  # ]:          0 :         if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) {
     399         [ #  # ]:          0 :                 ath_dbg(common, RESET,
     400                 :            :                         "reset work is pending, skip beaconing now\n");
     401                 :          0 :                 return;
     402                 :            :         }
     403                 :            : 
     404                 :            :         /*
     405                 :            :          * Check if the previous beacon has gone out.  If
     406                 :            :          * not don't try to post another, skip this period
     407                 :            :          * and wait for the next.  Missed beacons indicate
     408                 :            :          * a problem and should not occur.  If we miss too
     409                 :            :          * many consecutive beacons reset the device.
     410                 :            :          */
     411         [ #  # ]:          0 :         if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) {
     412                 :          0 :                 sc->beacon.bmisscnt++;
     413                 :            : 
     414                 :          0 :                 ath9k_hw_check_nav(ah);
     415                 :            : 
     416                 :            :                 /*
     417                 :            :                  * If the previous beacon has not been transmitted
     418                 :            :                  * and a MAC/BB hang has been identified, return
     419                 :            :                  * here because a chip reset would have been
     420                 :            :                  * initiated.
     421                 :            :                  */
     422         [ #  # ]:          0 :                 if (!ath_hw_check(sc))
     423                 :            :                         return;
     424                 :            : 
     425         [ #  # ]:          0 :                 if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) {
     426         [ #  # ]:          0 :                         ath_dbg(common, BSTUCK,
     427                 :            :                                 "missed %u consecutive beacons\n",
     428                 :            :                                 sc->beacon.bmisscnt);
     429                 :          0 :                         ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
     430         [ #  # ]:          0 :                         if (sc->beacon.bmisscnt > 3)
     431                 :          0 :                                 ath9k_hw_bstuck_nfcal(ah);
     432         [ #  # ]:          0 :                 } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
     433         [ #  # ]:          0 :                         ath_dbg(common, BSTUCK, "beacon is officially stuck\n");
     434                 :          0 :                         sc->beacon.bmisscnt = 0;
     435                 :          0 :                         ath9k_queue_reset(sc, RESET_TYPE_BEACON_STUCK);
     436                 :            :                 }
     437                 :            : 
     438                 :          0 :                 return;
     439                 :            :         }
     440                 :            : 
     441                 :          0 :         slot = ath9k_beacon_choose_slot(sc);
     442                 :          0 :         vif = sc->beacon.bslot[slot];
     443                 :            : 
     444                 :            :         /* EDMA devices check that in the tx completion function. */
     445         [ #  # ]:          0 :         if (!edma) {
     446                 :          0 :                 if (ath9k_is_chanctx_enabled()) {
     447                 :            :                         ath_chanctx_beacon_sent_ev(sc,
     448                 :            :                                           ATH_CHANCTX_EVENT_BEACON_SENT);
     449                 :            :                 }
     450                 :            : 
     451         [ #  # ]:          0 :                 if (ath9k_csa_is_finished(sc, vif))
     452                 :            :                         return;
     453                 :            :         }
     454                 :            : 
     455   [ #  #  #  # ]:          0 :         if (!vif || !vif->bss_conf.enable_beacon)
     456                 :            :                 return;
     457                 :            : 
     458                 :          0 :         if (ath9k_is_chanctx_enabled()) {
     459                 :            :                 ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_BEACON_PREPARE);
     460                 :            :         }
     461                 :            : 
     462                 :          0 :         bf = ath9k_beacon_generate(sc->hw, vif);
     463                 :            : 
     464         [ #  # ]:          0 :         if (sc->beacon.bmisscnt != 0) {
     465         [ #  # ]:          0 :                 ath_dbg(common, BSTUCK, "resume beacon xmit after %u misses\n",
     466                 :            :                         sc->beacon.bmisscnt);
     467                 :          0 :                 sc->beacon.bmisscnt = 0;
     468                 :            :         }
     469                 :            : 
     470                 :            :         /*
     471                 :            :          * Handle slot time change when a non-ERP station joins/leaves
     472                 :            :          * an 11g network.  The 802.11 layer notifies us via callback,
     473                 :            :          * we mark updateslot, then wait one beacon before effecting
     474                 :            :          * the change.  This gives associated stations at least one
     475                 :            :          * beacon interval to note the state change.
     476                 :            :          *
     477                 :            :          * NB: The slot time change state machine is clocked according
     478                 :            :          *     to whether we are bursting or staggering beacons.  We
     479                 :            :          *     recognize the request to update and record the current
     480                 :            :          *     slot then don't transition until that slot is reached
     481                 :            :          *     again.  If we miss a beacon for that slot then we'll be
     482                 :            :          *     slow to transition but we'll be sure at least one beacon
     483                 :            :          *     interval has passed.  When bursting slot is always left
     484                 :            :          *     set to ATH_BCBUF so this check is a noop.
     485                 :            :          */
     486         [ #  # ]:          0 :         if (sc->beacon.updateslot == UPDATE) {
     487                 :          0 :                 sc->beacon.updateslot = COMMIT;
     488                 :          0 :                 sc->beacon.slotupdate = slot;
     489         [ #  # ]:          0 :         } else if (sc->beacon.updateslot == COMMIT &&
     490         [ #  # ]:          0 :                    sc->beacon.slotupdate == slot) {
     491                 :          0 :                 ah->slottime = sc->beacon.slottime;
     492                 :          0 :                 ath9k_hw_init_global_settings(ah);
     493                 :          0 :                 sc->beacon.updateslot = OK;
     494                 :            :         }
     495                 :            : 
     496         [ #  # ]:          0 :         if (bf) {
     497                 :          0 :                 ath9k_reset_beacon_status(sc);
     498                 :            : 
     499         [ #  # ]:          0 :                 ath_dbg(common, BEACON,
     500                 :            :                         "Transmitting beacon for slot: %d\n", slot);
     501                 :            : 
     502                 :            :                 /* NB: cabq traffic should already be queued and primed */
     503                 :          0 :                 ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr);
     504                 :            : 
     505         [ #  # ]:          0 :                 if (!edma)
     506                 :          0 :                         ath9k_hw_txstart(ah, sc->beacon.beaconq);
     507                 :            :         }
     508                 :            : }
     509                 :            : 
     510                 :            : /*
     511                 :            :  * Both nexttbtt and intval have to be in usecs.
     512                 :            :  */
     513                 :          0 : static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt,
     514                 :            :                               u32 intval)
     515                 :            : {
     516                 :          0 :         struct ath_hw *ah = sc->sc_ah;
     517                 :            : 
     518                 :          0 :         ath9k_hw_disable_interrupts(ah);
     519                 :          0 :         ath9k_beaconq_config(sc);
     520                 :          0 :         ath9k_hw_beaconinit(ah, nexttbtt, intval);
     521                 :          0 :         ah->imask |= ATH9K_INT_SWBA;
     522                 :          0 :         sc->beacon.bmisscnt = 0;
     523                 :          0 :         ath9k_hw_set_interrupts(ah);
     524                 :          0 :         ath9k_hw_enable_interrupts(ah);
     525                 :          0 : }
     526                 :            : 
     527                 :            : static void ath9k_beacon_stop(struct ath_softc *sc)
     528                 :            : {
     529                 :            :         ath9k_hw_disable_interrupts(sc->sc_ah);
     530                 :            :         sc->sc_ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
     531                 :            :         sc->beacon.bmisscnt = 0;
     532                 :            :         ath9k_hw_set_interrupts(sc->sc_ah);
     533                 :            :         ath9k_hw_enable_interrupts(sc->sc_ah);
     534                 :            : }
     535                 :            : 
     536                 :            : /*
     537                 :            :  * For multi-bss ap support beacons are either staggered evenly over N slots or
     538                 :            :  * burst together.  For the former arrange for the SWBA to be delivered for each
     539                 :            :  * slot. Slots that are not occupied will generate nothing.
     540                 :            :  */
     541                 :          0 : static void ath9k_beacon_config_ap(struct ath_softc *sc,
     542                 :            :                                    struct ath_beacon_config *conf)
     543                 :            : {
     544                 :          0 :         struct ath_hw *ah = sc->sc_ah;
     545                 :            : 
     546                 :          0 :         ath9k_cmn_beacon_config_ap(ah, conf, ATH_BCBUF);
     547                 :          0 :         ath9k_beacon_init(sc, conf->nexttbtt, conf->intval);
     548                 :          0 : }
     549                 :            : 
     550                 :          0 : static void ath9k_beacon_config_sta(struct ath_hw *ah,
     551                 :            :                                     struct ath_beacon_config *conf)
     552                 :            : {
     553                 :          0 :         struct ath9k_beacon_state bs;
     554                 :            : 
     555         [ #  # ]:          0 :         if (ath9k_cmn_beacon_config_sta(ah, conf, &bs) == -EPERM)
     556                 :          0 :                 return;
     557                 :            : 
     558                 :          0 :         ath9k_hw_disable_interrupts(ah);
     559                 :          0 :         ath9k_hw_set_sta_beacon_timers(ah, &bs);
     560                 :          0 :         ah->imask |= ATH9K_INT_BMISS;
     561                 :            : 
     562                 :          0 :         ath9k_hw_set_interrupts(ah);
     563                 :          0 :         ath9k_hw_enable_interrupts(ah);
     564                 :            : }
     565                 :            : 
     566                 :          0 : static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
     567                 :            :                                       struct ath_beacon_config *conf)
     568                 :            : {
     569                 :          0 :         struct ath_hw *ah = sc->sc_ah;
     570                 :          0 :         struct ath_common *common = ath9k_hw_common(ah);
     571                 :            : 
     572                 :          0 :         ath9k_reset_beacon_status(sc);
     573                 :            : 
     574                 :          0 :         ath9k_cmn_beacon_config_adhoc(ah, conf);
     575                 :            : 
     576                 :          0 :         ath9k_beacon_init(sc, conf->nexttbtt, conf->intval);
     577                 :            : 
     578                 :            :         /*
     579                 :            :          * Set the global 'beacon has been configured' flag for the
     580                 :            :          * joiner case in IBSS mode.
     581                 :            :          */
     582   [ #  #  #  # ]:          0 :         if (!conf->ibss_creator && conf->enable_beacon)
     583                 :          0 :                 set_bit(ATH_OP_BEACONS, &common->op_flags);
     584                 :          0 : }
     585                 :            : 
     586                 :          0 : static void ath9k_cache_beacon_config(struct ath_softc *sc,
     587                 :            :                                       struct ath_chanctx *ctx,
     588                 :            :                                       struct ieee80211_bss_conf *bss_conf)
     589                 :            : {
     590         [ #  # ]:          0 :         struct ath_common *common = ath9k_hw_common(sc->sc_ah);
     591                 :          0 :         struct ath_beacon_config *cur_conf = &ctx->beacon;
     592                 :            : 
     593         [ #  # ]:          0 :         ath_dbg(common, BEACON,
     594                 :            :                 "Caching beacon data for BSS: %pM\n", bss_conf->bssid);
     595                 :            : 
     596                 :          0 :         cur_conf->beacon_interval = bss_conf->beacon_int;
     597                 :          0 :         cur_conf->dtim_period = bss_conf->dtim_period;
     598                 :          0 :         cur_conf->dtim_count = 1;
     599                 :          0 :         cur_conf->ibss_creator = bss_conf->ibss_creator;
     600                 :            : 
     601                 :            :         /*
     602                 :            :          * It looks like mac80211 may end up using beacon interval of zero in
     603                 :            :          * some cases (at least for mesh point). Avoid getting into an
     604                 :            :          * infinite loop by using a bit safer value instead. To be safe,
     605                 :            :          * do sanity check on beacon interval for all operating modes.
     606                 :            :          */
     607         [ #  # ]:          0 :         if (cur_conf->beacon_interval == 0)
     608                 :          0 :                 cur_conf->beacon_interval = 100;
     609                 :            : 
     610                 :          0 :         cur_conf->bmiss_timeout =
     611                 :          0 :                 ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
     612                 :            : 
     613                 :            :         /*
     614                 :            :          * We don't parse dtim period from mac80211 during the driver
     615                 :            :          * initialization as it breaks association with hidden-ssid
     616                 :            :          * AP and it causes latency in roaming
     617                 :            :          */
     618         [ #  # ]:          0 :         if (cur_conf->dtim_period == 0)
     619                 :          0 :                 cur_conf->dtim_period = 1;
     620                 :            : 
     621                 :          0 :         ath9k_set_tsfadjust(sc, cur_conf);
     622                 :          0 : }
     623                 :            : 
     624                 :         65 : void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif,
     625                 :            :                          bool beacons)
     626                 :            : {
     627                 :         65 :         struct ath_hw *ah = sc->sc_ah;
     628         [ +  - ]:         65 :         struct ath_common *common = ath9k_hw_common(ah);
     629                 :         65 :         struct ath_vif *avp;
     630                 :         65 :         struct ath_chanctx *ctx;
     631                 :         65 :         struct ath_beacon_config *cur_conf;
     632                 :         65 :         unsigned long flags;
     633                 :         65 :         bool enabled;
     634                 :         65 :         bool skip_beacon = false;
     635                 :            : 
     636         [ +  - ]:         65 :         if (!beacons) {
     637                 :         65 :                 clear_bit(ATH_OP_BEACONS, &common->op_flags);
     638                 :         65 :                 ath9k_beacon_stop(sc);
     639                 :         65 :                 return;
     640                 :            :         }
     641                 :            : 
     642   [ #  #  #  # ]:          0 :         if (WARN_ON(!main_vif))
     643                 :            :                 return;
     644                 :            : 
     645                 :          0 :         avp = (void *)main_vif->drv_priv;
     646                 :          0 :         ctx = avp->chanctx;
     647                 :          0 :         cur_conf = &ctx->beacon;
     648                 :          0 :         enabled = cur_conf->enable_beacon;
     649                 :          0 :         cur_conf->enable_beacon = beacons;
     650                 :            : 
     651         [ #  # ]:          0 :         if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
     652                 :          0 :                 ath9k_cache_beacon_config(sc, ctx, &main_vif->bss_conf);
     653                 :            : 
     654                 :          0 :                 ath9k_set_beacon(sc);
     655                 :          0 :                 set_bit(ATH_OP_BEACONS, &common->op_flags);
     656                 :          0 :                 return;
     657                 :            :         }
     658                 :            : 
     659                 :            :         /* Update the beacon configuration. */
     660                 :          0 :         ath9k_cache_beacon_config(sc, ctx, &main_vif->bss_conf);
     661                 :            : 
     662                 :            :         /*
     663                 :            :          * Configure the HW beacon registers only when we have a valid
     664                 :            :          * beacon interval.
     665                 :            :          */
     666         [ #  # ]:          0 :         if (cur_conf->beacon_interval) {
     667                 :            :                 /* Special case to sync the TSF when joining an existing IBSS.
     668                 :            :                  * This is only done if no AP interface is active.
     669                 :            :                  * Note that mac80211 always resets the TSF when creating a new
     670                 :            :                  * IBSS interface.
     671                 :            :                  */
     672   [ #  #  #  # ]:          0 :                 if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC &&
     673         [ #  # ]:          0 :                     !enabled && beacons && !main_vif->bss_conf.ibss_creator) {
     674                 :          0 :                         spin_lock_irqsave(&sc->sc_pm_lock, flags);
     675                 :          0 :                         sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
     676                 :          0 :                         spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
     677                 :          0 :                         skip_beacon = true;
     678                 :            :                 }
     679                 :            : 
     680                 :            :                 /*
     681                 :            :                  * Do not set the ATH_OP_BEACONS flag for IBSS joiner mode
     682                 :            :                  * here, it is done in ath9k_beacon_config_adhoc().
     683                 :            :                  */
     684         [ #  # ]:          0 :                 if (beacons && !skip_beacon) {
     685                 :          0 :                         set_bit(ATH_OP_BEACONS, &common->op_flags);
     686                 :          0 :                         ath9k_set_beacon(sc);
     687                 :            :                 } else {
     688                 :          0 :                         clear_bit(ATH_OP_BEACONS, &common->op_flags);
     689                 :          0 :                         ath9k_beacon_stop(sc);
     690                 :            :                 }
     691                 :            :         } else {
     692                 :          0 :                 clear_bit(ATH_OP_BEACONS, &common->op_flags);
     693                 :          0 :                 ath9k_beacon_stop(sc);
     694                 :            :         }
     695                 :            : }
     696                 :            : 
     697                 :          0 : void ath9k_set_beacon(struct ath_softc *sc)
     698                 :            : {
     699   [ #  #  #  # ]:          0 :         struct ath_common *common = ath9k_hw_common(sc->sc_ah);
     700                 :          0 :         struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
     701                 :            : 
     702   [ #  #  #  # ]:          0 :         switch (sc->sc_ah->opmode) {
     703                 :          0 :         case NL80211_IFTYPE_AP:
     704                 :            :         case NL80211_IFTYPE_MESH_POINT:
     705                 :          0 :                 ath9k_beacon_config_ap(sc, cur_conf);
     706                 :          0 :                 break;
     707                 :          0 :         case NL80211_IFTYPE_ADHOC:
     708                 :          0 :                 ath9k_beacon_config_adhoc(sc, cur_conf);
     709                 :          0 :                 break;
     710                 :          0 :         case NL80211_IFTYPE_STATION:
     711                 :          0 :                 ath9k_beacon_config_sta(sc->sc_ah, cur_conf);
     712                 :          0 :                 break;
     713                 :          0 :         default:
     714         [ #  # ]:          0 :                 ath_dbg(common, CONFIG, "Unsupported beaconing mode\n");
     715                 :            :                 return;
     716                 :            :         }
     717                 :            : }

Generated by: LCOV version 1.14