root/drivers/net/wireless/ath/ath9k/beacon.c

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

DEFINITIONS

This source file includes following definitions.
  1. ath9k_reset_beacon_status
  2. ath9k_beaconq_config
  3. ath9k_beacon_setup
  4. ath9k_beacon_generate
  5. ath9k_beacon_assign_slot
  6. ath9k_beacon_remove_slot
  7. ath9k_beacon_ensure_primary_slot
  8. ath9k_beacon_choose_slot
  9. ath9k_set_tsfadjust
  10. ath9k_csa_is_finished
  11. ath9k_csa_update_vif
  12. ath9k_csa_update
  13. ath9k_beacon_tasklet
  14. ath9k_beacon_init
  15. ath9k_beacon_stop
  16. ath9k_beacon_config_ap
  17. ath9k_beacon_config_sta
  18. ath9k_beacon_config_adhoc
  19. ath9k_cache_beacon_config
  20. ath9k_beacon_config
  21. ath9k_set_beacon

   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 static void ath9k_reset_beacon_status(struct ath_softc *sc)
  23 {
  24         sc->beacon.tx_processed = false;
  25         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 static void ath9k_beaconq_config(struct ath_softc *sc)
  34 {
  35         struct ath_hw *ah = sc->sc_ah;
  36         struct ath_common *common = ath9k_hw_common(ah);
  37         struct ath9k_tx_queue_info qi, qi_be;
  38         struct ath_txq *txq;
  39 
  40         ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi);
  41 
  42         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                 qi.tqi_aifs = 1;
  46                 qi.tqi_cwmin = 0;
  47                 qi.tqi_cwmax = 0;
  48         } else {
  49                 /* Adhoc mode; important thing is to use 2x cwmin. */
  50                 txq = sc->tx.txq_map[IEEE80211_AC_BE];
  51                 ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be);
  52                 qi.tqi_aifs = qi_be.tqi_aifs;
  53                 if (ah->slottime == 20)
  54                         qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
  55                 else
  56                         qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
  57                 qi.tqi_cwmax = qi_be.tqi_cwmax;
  58         }
  59 
  60         if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) {
  61                 ath_err(common, "Unable to update h/w beacon queue parameters\n");
  62         } else {
  63                 ath9k_hw_resettxqueue(ah, sc->beacon.beaconq);
  64         }
  65 }
  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 static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
 113                                              struct ieee80211_vif *vif)
 114 {
 115         struct ath_softc *sc = hw->priv;
 116         struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 117         struct ath_buf *bf;
 118         struct ath_vif *avp = (void *)vif->drv_priv;
 119         struct sk_buff *skb;
 120         struct ath_txq *cabq = sc->beacon.cabq;
 121         struct ieee80211_tx_info *info;
 122         struct ieee80211_mgmt *mgmt_hdr;
 123         int cabq_depth;
 124 
 125         if (avp->av_bcbuf == NULL)
 126                 return NULL;
 127 
 128         bf = avp->av_bcbuf;
 129         skb = bf->bf_mpdu;
 130         if (skb) {
 131                 dma_unmap_single(sc->dev, bf->bf_buf_addr,
 132                                  skb->len, DMA_TO_DEVICE);
 133                 dev_kfree_skb_any(skb);
 134                 bf->bf_buf_addr = 0;
 135                 bf->bf_mpdu = NULL;
 136         }
 137 
 138         skb = ieee80211_beacon_get(hw, vif);
 139         if (skb == NULL)
 140                 return NULL;
 141 
 142         bf->bf_mpdu = skb;
 143 
 144         mgmt_hdr = (struct ieee80211_mgmt *)skb->data;
 145         mgmt_hdr->u.beacon.timestamp = avp->tsf_adjust;
 146 
 147         info = IEEE80211_SKB_CB(skb);
 148 
 149         ath_assign_seq(common, skb);
 150 
 151         /* Always assign NOA attr when MCC enabled */
 152         if (ath9k_is_chanctx_enabled())
 153                 ath9k_beacon_add_noa(sc, avp, skb);
 154 
 155         bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
 156                                          skb->len, DMA_TO_DEVICE);
 157         if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
 158                 dev_kfree_skb_any(skb);
 159                 bf->bf_mpdu = NULL;
 160                 bf->bf_buf_addr = 0;
 161                 ath_err(common, "dma_mapping_error on beaconing\n");
 162                 return NULL;
 163         }
 164 
 165         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         spin_lock_bh(&cabq->axq_lock);
 176         cabq_depth = cabq->axq_depth;
 177         spin_unlock_bh(&cabq->axq_lock);
 178 
 179         if (skb && cabq_depth) {
 180                 if (sc->cur_chan->nvifs > 1) {
 181                         ath_dbg(common, BEACON,
 182                                 "Flushing previous cabq traffic\n");
 183                         ath_draintxq(sc, cabq);
 184                 }
 185         }
 186 
 187         ath9k_beacon_setup(sc, vif, bf, info->control.rates[0].idx);
 188 
 189         if (skb)
 190                 ath_tx_cabq(hw, vif, skb);
 191 
 192         return bf;
 193 }
 194 
 195 void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
 196 {
 197         struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 198         struct ath_vif *avp = (void *)vif->drv_priv;
 199         int slot;
 200 
 201         avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf, struct ath_buf, list);
 202         list_del(&avp->av_bcbuf->list);
 203 
 204         for (slot = 0; slot < ATH_BCBUF; slot++) {
 205                 if (sc->beacon.bslot[slot] == NULL) {
 206                         avp->av_bslot = slot;
 207                         break;
 208                 }
 209         }
 210 
 211         sc->beacon.bslot[avp->av_bslot] = vif;
 212 
 213         ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n",
 214                 avp->av_bslot);
 215 }
 216 
 217 void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
 218 {
 219         struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 220         struct ath_vif *avp = (void *)vif->drv_priv;
 221         struct ath_buf *bf = avp->av_bcbuf;
 222 
 223         ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n",
 224                 avp->av_bslot);
 225 
 226         tasklet_disable(&sc->bcon_tasklet);
 227 
 228         if (bf && bf->bf_mpdu) {
 229                 struct sk_buff *skb = bf->bf_mpdu;
 230                 dma_unmap_single(sc->dev, bf->bf_buf_addr,
 231                                  skb->len, DMA_TO_DEVICE);
 232                 dev_kfree_skb_any(skb);
 233                 bf->bf_mpdu = NULL;
 234                 bf->bf_buf_addr = 0;
 235         }
 236 
 237         avp->av_bcbuf = NULL;
 238         sc->beacon.bslot[avp->av_bslot] = NULL;
 239         list_add_tail(&bf->list, &sc->beacon.bbuf);
 240 
 241         tasklet_enable(&sc->bcon_tasklet);
 242 }
 243 
 244 void ath9k_beacon_ensure_primary_slot(struct ath_softc *sc)
 245 {
 246         struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 247         struct ieee80211_vif *vif;
 248         struct ath_vif *avp;
 249         s64 tsfadjust;
 250         u32 offset;
 251         int first_slot = ATH_BCBUF;
 252         int slot;
 253 
 254         tasklet_disable(&sc->bcon_tasklet);
 255 
 256         /* Find first taken slot. */
 257         for (slot = 0; slot < ATH_BCBUF; slot++) {
 258                 if (sc->beacon.bslot[slot]) {
 259                         first_slot = slot;
 260                         break;
 261                 }
 262         }
 263         if (first_slot == 0)
 264                 goto out;
 265 
 266         /* Re-enumarate all slots, moving them forward. */
 267         for (slot = 0; slot < ATH_BCBUF; slot++) {
 268                 if (slot + first_slot < ATH_BCBUF) {
 269                         vif = sc->beacon.bslot[slot + first_slot];
 270                         sc->beacon.bslot[slot] = vif;
 271 
 272                         if (vif) {
 273                                 avp = (void *)vif->drv_priv;
 274                                 avp->av_bslot = slot;
 275                         }
 276                 } else {
 277                         sc->beacon.bslot[slot] = NULL;
 278                 }
 279         }
 280 
 281         vif = sc->beacon.bslot[0];
 282         if (WARN_ON(!vif))
 283                 goto out;
 284 
 285         /* Get the tsf_adjust value for the new first slot. */
 286         avp = (void *)vif->drv_priv;
 287         tsfadjust = le64_to_cpu(avp->tsf_adjust);
 288 
 289         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         avp->chanctx->tsf_val += tsfadjust;
 295         if (sc->cur_chan == avp->chanctx) {
 296                 offset = ath9k_hw_get_tsf_offset(&avp->chanctx->tsf_ts, NULL);
 297                 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 out:
 303         tasklet_enable(&sc->bcon_tasklet);
 304 }
 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 bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif)
 364 {
 365         if (!vif || !vif->csa_active)
 366                 return false;
 367 
 368         if (!ieee80211_csa_is_complete(vif))
 369                 return false;
 370 
 371         ieee80211_csa_finish(vif);
 372         return true;
 373 }
 374 
 375 static void ath9k_csa_update_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
 376 {
 377         struct ath_softc *sc = data;
 378         ath9k_csa_is_finished(sc, vif);
 379 }
 380 
 381 void ath9k_csa_update(struct ath_softc *sc)
 382 {
 383         ieee80211_iterate_active_interfaces_atomic(sc->hw,
 384                                                    IEEE80211_IFACE_ITER_NORMAL,
 385                                                    ath9k_csa_update_vif, sc);
 386 }
 387 
 388 void ath9k_beacon_tasklet(unsigned long data)
 389 {
 390         struct ath_softc *sc = (struct ath_softc *)data;
 391         struct ath_hw *ah = sc->sc_ah;
 392         struct ath_common *common = ath9k_hw_common(ah);
 393         struct ath_buf *bf = NULL;
 394         struct ieee80211_vif *vif;
 395         bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
 396         int slot;
 397 
 398         if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) {
 399                 ath_dbg(common, RESET,
 400                         "reset work is pending, skip beaconing now\n");
 401                 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         if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) {
 412                 sc->beacon.bmisscnt++;
 413 
 414                 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                 if (!ath_hw_check(sc))
 423                         return;
 424 
 425                 if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) {
 426                         ath_dbg(common, BSTUCK,
 427                                 "missed %u consecutive beacons\n",
 428                                 sc->beacon.bmisscnt);
 429                         ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
 430                         if (sc->beacon.bmisscnt > 3)
 431                                 ath9k_hw_bstuck_nfcal(ah);
 432                 } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
 433                         ath_dbg(common, BSTUCK, "beacon is officially stuck\n");
 434                         sc->beacon.bmisscnt = 0;
 435                         ath9k_queue_reset(sc, RESET_TYPE_BEACON_STUCK);
 436                 }
 437 
 438                 return;
 439         }
 440 
 441         slot = ath9k_beacon_choose_slot(sc);
 442         vif = sc->beacon.bslot[slot];
 443 
 444         /* EDMA devices check that in the tx completion function. */
 445         if (!edma) {
 446                 if (ath9k_is_chanctx_enabled()) {
 447                         ath_chanctx_beacon_sent_ev(sc,
 448                                           ATH_CHANCTX_EVENT_BEACON_SENT);
 449                 }
 450 
 451                 if (ath9k_csa_is_finished(sc, vif))
 452                         return;
 453         }
 454 
 455         if (!vif || !vif->bss_conf.enable_beacon)
 456                 return;
 457 
 458         if (ath9k_is_chanctx_enabled()) {
 459                 ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_BEACON_PREPARE);
 460         }
 461 
 462         bf = ath9k_beacon_generate(sc->hw, vif);
 463 
 464         if (sc->beacon.bmisscnt != 0) {
 465                 ath_dbg(common, BSTUCK, "resume beacon xmit after %u misses\n",
 466                         sc->beacon.bmisscnt);
 467                 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         if (sc->beacon.updateslot == UPDATE) {
 487                 sc->beacon.updateslot = COMMIT;
 488                 sc->beacon.slotupdate = slot;
 489         } else if (sc->beacon.updateslot == COMMIT &&
 490                    sc->beacon.slotupdate == slot) {
 491                 ah->slottime = sc->beacon.slottime;
 492                 ath9k_hw_init_global_settings(ah);
 493                 sc->beacon.updateslot = OK;
 494         }
 495 
 496         if (bf) {
 497                 ath9k_reset_beacon_status(sc);
 498 
 499                 ath_dbg(common, BEACON,
 500                         "Transmitting beacon for slot: %d\n", slot);
 501 
 502                 /* NB: cabq traffic should already be queued and primed */
 503                 ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr);
 504 
 505                 if (!edma)
 506                         ath9k_hw_txstart(ah, sc->beacon.beaconq);
 507         }
 508 }
 509 
 510 /*
 511  * Both nexttbtt and intval have to be in usecs.
 512  */
 513 static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt,
 514                               u32 intval)
 515 {
 516         struct ath_hw *ah = sc->sc_ah;
 517 
 518         ath9k_hw_disable_interrupts(ah);
 519         ath9k_beaconq_config(sc);
 520         ath9k_hw_beaconinit(ah, nexttbtt, intval);
 521         ah->imask |= ATH9K_INT_SWBA;
 522         sc->beacon.bmisscnt = 0;
 523         ath9k_hw_set_interrupts(ah);
 524         ath9k_hw_enable_interrupts(ah);
 525 }
 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 static void ath9k_beacon_config_ap(struct ath_softc *sc,
 542                                    struct ath_beacon_config *conf)
 543 {
 544         struct ath_hw *ah = sc->sc_ah;
 545 
 546         ath9k_cmn_beacon_config_ap(ah, conf, ATH_BCBUF);
 547         ath9k_beacon_init(sc, conf->nexttbtt, conf->intval);
 548 }
 549 
 550 static void ath9k_beacon_config_sta(struct ath_hw *ah,
 551                                     struct ath_beacon_config *conf)
 552 {
 553         struct ath9k_beacon_state bs;
 554 
 555         if (ath9k_cmn_beacon_config_sta(ah, conf, &bs) == -EPERM)
 556                 return;
 557 
 558         ath9k_hw_disable_interrupts(ah);
 559         ath9k_hw_set_sta_beacon_timers(ah, &bs);
 560         ah->imask |= ATH9K_INT_BMISS;
 561 
 562         ath9k_hw_set_interrupts(ah);
 563         ath9k_hw_enable_interrupts(ah);
 564 }
 565 
 566 static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
 567                                       struct ath_beacon_config *conf)
 568 {
 569         struct ath_hw *ah = sc->sc_ah;
 570         struct ath_common *common = ath9k_hw_common(ah);
 571 
 572         ath9k_reset_beacon_status(sc);
 573 
 574         ath9k_cmn_beacon_config_adhoc(ah, conf);
 575 
 576         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         if (!conf->ibss_creator && conf->enable_beacon)
 583                 set_bit(ATH_OP_BEACONS, &common->op_flags);
 584 }
 585 
 586 static void ath9k_cache_beacon_config(struct ath_softc *sc,
 587                                       struct ath_chanctx *ctx,
 588                                       struct ieee80211_bss_conf *bss_conf)
 589 {
 590         struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 591         struct ath_beacon_config *cur_conf = &ctx->beacon;
 592 
 593         ath_dbg(common, BEACON,
 594                 "Caching beacon data for BSS: %pM\n", bss_conf->bssid);
 595 
 596         cur_conf->beacon_interval = bss_conf->beacon_int;
 597         cur_conf->dtim_period = bss_conf->dtim_period;
 598         cur_conf->dtim_count = 1;
 599         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         if (cur_conf->beacon_interval == 0)
 608                 cur_conf->beacon_interval = 100;
 609 
 610         cur_conf->bmiss_timeout =
 611                 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         if (cur_conf->dtim_period == 0)
 619                 cur_conf->dtim_period = 1;
 620 
 621         ath9k_set_tsfadjust(sc, cur_conf);
 622 }
 623 
 624 void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif,
 625                          bool beacons)
 626 {
 627         struct ath_hw *ah = sc->sc_ah;
 628         struct ath_common *common = ath9k_hw_common(ah);
 629         struct ath_vif *avp;
 630         struct ath_chanctx *ctx;
 631         struct ath_beacon_config *cur_conf;
 632         unsigned long flags;
 633         bool enabled;
 634         bool skip_beacon = false;
 635 
 636         if (!beacons) {
 637                 clear_bit(ATH_OP_BEACONS, &common->op_flags);
 638                 ath9k_beacon_stop(sc);
 639                 return;
 640         }
 641 
 642         if (WARN_ON(!main_vif))
 643                 return;
 644 
 645         avp = (void *)main_vif->drv_priv;
 646         ctx = avp->chanctx;
 647         cur_conf = &ctx->beacon;
 648         enabled = cur_conf->enable_beacon;
 649         cur_conf->enable_beacon = beacons;
 650 
 651         if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
 652                 ath9k_cache_beacon_config(sc, ctx, &main_vif->bss_conf);
 653 
 654                 ath9k_set_beacon(sc);
 655                 set_bit(ATH_OP_BEACONS, &common->op_flags);
 656                 return;
 657         }
 658 
 659         /* Update the beacon configuration. */
 660         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         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                 if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC &&
 673                     !enabled && beacons && !main_vif->bss_conf.ibss_creator) {
 674                         spin_lock_irqsave(&sc->sc_pm_lock, flags);
 675                         sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
 676                         spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 677                         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                 if (beacons && !skip_beacon) {
 685                         set_bit(ATH_OP_BEACONS, &common->op_flags);
 686                         ath9k_set_beacon(sc);
 687                 } else {
 688                         clear_bit(ATH_OP_BEACONS, &common->op_flags);
 689                         ath9k_beacon_stop(sc);
 690                 }
 691         } else {
 692                 clear_bit(ATH_OP_BEACONS, &common->op_flags);
 693                 ath9k_beacon_stop(sc);
 694         }
 695 }
 696 
 697 void ath9k_set_beacon(struct ath_softc *sc)
 698 {
 699         struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 700         struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
 701 
 702         switch (sc->sc_ah->opmode) {
 703         case NL80211_IFTYPE_AP:
 704         case NL80211_IFTYPE_MESH_POINT:
 705                 ath9k_beacon_config_ap(sc, cur_conf);
 706                 break;
 707         case NL80211_IFTYPE_ADHOC:
 708                 ath9k_beacon_config_adhoc(sc, cur_conf);
 709                 break;
 710         case NL80211_IFTYPE_STATION:
 711                 ath9k_beacon_config_sta(sc->sc_ah, cur_conf);
 712                 break;
 713         default:
 714                 ath_dbg(common, CONFIG, "Unsupported beaconing mode\n");
 715                 return;
 716         }
 717 }

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