Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2008-2011 Atheros Communications Inc.
0003  *
0004  * Permission to use, copy, modify, and/or distribute this software for any
0005  * purpose with or without fee is hereby granted, provided that the above
0006  * copyright notice and this permission notice appear in all copies.
0007  *
0008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0011  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0013  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0014  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0015  */
0016 
0017 #include <linux/dma-mapping.h>
0018 #include "ath9k.h"
0019 
0020 #define FUDGE 2
0021 
0022 static void ath9k_reset_beacon_status(struct ath_softc *sc)
0023 {
0024     sc->beacon.tx_processed = false;
0025     sc->beacon.tx_last = false;
0026 }
0027 
0028 /*
0029  *  This function will modify certain transmit queue properties depending on
0030  *  the operating mode of the station (AP or AdHoc).  Parameters are AIFS
0031  *  settings and channel width min/max
0032 */
0033 static void ath9k_beaconq_config(struct ath_softc *sc)
0034 {
0035     struct ath_hw *ah = sc->sc_ah;
0036     struct ath_common *common = ath9k_hw_common(ah);
0037     struct ath9k_tx_queue_info qi, qi_be;
0038     struct ath_txq *txq;
0039 
0040     ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi);
0041 
0042     if (sc->sc_ah->opmode == NL80211_IFTYPE_AP ||
0043         sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) {
0044         /* Always burst out beacon and CAB traffic. */
0045         qi.tqi_aifs = 1;
0046         qi.tqi_cwmin = 0;
0047         qi.tqi_cwmax = 0;
0048     } else {
0049         /* Adhoc mode; important thing is to use 2x cwmin. */
0050         txq = sc->tx.txq_map[IEEE80211_AC_BE];
0051         ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be);
0052         qi.tqi_aifs = qi_be.tqi_aifs;
0053         if (ah->slottime == 20)
0054             qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
0055         else
0056             qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
0057         qi.tqi_cwmax = qi_be.tqi_cwmax;
0058     }
0059 
0060     if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) {
0061         ath_err(common, "Unable to update h/w beacon queue parameters\n");
0062     } else {
0063         ath9k_hw_resettxqueue(ah, sc->beacon.beaconq);
0064     }
0065 }
0066 
0067 /*
0068  *  Associates the beacon frame buffer with a transmit descriptor.  Will set
0069  *  up rate codes, and channel flags. Beacons are always sent out at the
0070  *  lowest rate, and are not retried.
0071 */
0072 static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
0073                  struct ath_buf *bf, int rateidx)
0074 {
0075     struct sk_buff *skb = bf->bf_mpdu;
0076     struct ath_hw *ah = sc->sc_ah;
0077     struct ath_common *common = ath9k_hw_common(ah);
0078     struct ath_tx_info info;
0079     struct ieee80211_supported_band *sband;
0080     u8 chainmask = ah->txchainmask;
0081     u8 i, rate = 0;
0082 
0083     sband = &common->sbands[sc->cur_chandef.chan->band];
0084     rate = sband->bitrates[rateidx].hw_value;
0085     if (vif->bss_conf.use_short_preamble)
0086         rate |= sband->bitrates[rateidx].hw_value_short;
0087 
0088     memset(&info, 0, sizeof(info));
0089     info.pkt_len = skb->len + FCS_LEN;
0090     info.type = ATH9K_PKT_TYPE_BEACON;
0091     for (i = 0; i < 4; i++)
0092         info.txpower[i] = MAX_RATE_POWER;
0093     info.keyix = ATH9K_TXKEYIX_INVALID;
0094     info.keytype = ATH9K_KEY_TYPE_CLEAR;
0095     info.flags = ATH9K_TXDESC_NOACK | ATH9K_TXDESC_CLRDMASK;
0096 
0097     info.buf_addr[0] = bf->bf_buf_addr;
0098     info.buf_len[0] = roundup(skb->len, 4);
0099 
0100     info.is_first = true;
0101     info.is_last = true;
0102 
0103     info.qcu = sc->beacon.beaconq;
0104 
0105     info.rates[0].Tries = 1;
0106     info.rates[0].Rate = rate;
0107     info.rates[0].ChSel = ath_txchainmask_reduction(sc, chainmask, rate);
0108 
0109     ath9k_hw_set_txdesc(ah, bf->bf_desc, &info);
0110 }
0111 
0112 static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
0113                          struct ieee80211_vif *vif)
0114 {
0115     struct ath_softc *sc = hw->priv;
0116     struct ath_common *common = ath9k_hw_common(sc->sc_ah);
0117     struct ath_buf *bf;
0118     struct ath_vif *avp = (void *)vif->drv_priv;
0119     struct sk_buff *skb;
0120     struct ath_txq *cabq = sc->beacon.cabq;
0121     struct ieee80211_tx_info *info;
0122     struct ieee80211_mgmt *mgmt_hdr;
0123     int cabq_depth;
0124 
0125     if (avp->av_bcbuf == NULL)
0126         return NULL;
0127 
0128     bf = avp->av_bcbuf;
0129     skb = bf->bf_mpdu;
0130     if (skb) {
0131         dma_unmap_single(sc->dev, bf->bf_buf_addr,
0132                  skb->len, DMA_TO_DEVICE);
0133         dev_kfree_skb_any(skb);
0134         bf->bf_buf_addr = 0;
0135         bf->bf_mpdu = NULL;
0136     }
0137 
0138     skb = ieee80211_beacon_get(hw, vif, 0);
0139     if (skb == NULL)
0140         return NULL;
0141 
0142     bf->bf_mpdu = skb;
0143 
0144     mgmt_hdr = (struct ieee80211_mgmt *)skb->data;
0145     mgmt_hdr->u.beacon.timestamp = avp->tsf_adjust;
0146 
0147     info = IEEE80211_SKB_CB(skb);
0148 
0149     ath_assign_seq(common, skb);
0150 
0151     /* Always assign NOA attr when MCC enabled */
0152     if (ath9k_is_chanctx_enabled())
0153         ath9k_beacon_add_noa(sc, avp, skb);
0154 
0155     bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
0156                      skb->len, DMA_TO_DEVICE);
0157     if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
0158         dev_kfree_skb_any(skb);
0159         bf->bf_mpdu = NULL;
0160         bf->bf_buf_addr = 0;
0161         ath_err(common, "dma_mapping_error on beaconing\n");
0162         return NULL;
0163     }
0164 
0165     skb = ieee80211_get_buffered_bc(hw, vif);
0166 
0167     /*
0168      * if the CABQ traffic from previous DTIM is pending and the current
0169      *  beacon is also a DTIM.
0170      *  1) if there is only one vif let the cab traffic continue.
0171      *  2) if there are more than one vif and we are using staggered
0172      *     beacons, then drain the cabq by dropping all the frames in
0173      *     the cabq so that the current vifs cab traffic can be scheduled.
0174      */
0175     spin_lock_bh(&cabq->axq_lock);
0176     cabq_depth = cabq->axq_depth;
0177     spin_unlock_bh(&cabq->axq_lock);
0178 
0179     if (skb && cabq_depth) {
0180         if (sc->cur_chan->nvifs > 1) {
0181             ath_dbg(common, BEACON,
0182                 "Flushing previous cabq traffic\n");
0183             ath_draintxq(sc, cabq);
0184         }
0185     }
0186 
0187     ath9k_beacon_setup(sc, vif, bf, info->control.rates[0].idx);
0188 
0189     if (skb)
0190         ath_tx_cabq(hw, vif, skb);
0191 
0192     return bf;
0193 }
0194 
0195 void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
0196 {
0197     struct ath_common *common = ath9k_hw_common(sc->sc_ah);
0198     struct ath_vif *avp = (void *)vif->drv_priv;
0199     int slot;
0200 
0201     avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf, struct ath_buf, list);
0202     list_del(&avp->av_bcbuf->list);
0203 
0204     for (slot = 0; slot < ATH_BCBUF; slot++) {
0205         if (sc->beacon.bslot[slot] == NULL) {
0206             avp->av_bslot = slot;
0207             break;
0208         }
0209     }
0210 
0211     sc->beacon.bslot[avp->av_bslot] = vif;
0212 
0213     ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n",
0214         avp->av_bslot);
0215 }
0216 
0217 void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
0218 {
0219     struct ath_common *common = ath9k_hw_common(sc->sc_ah);
0220     struct ath_vif *avp = (void *)vif->drv_priv;
0221     struct ath_buf *bf = avp->av_bcbuf;
0222 
0223     ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n",
0224         avp->av_bslot);
0225 
0226     tasklet_disable(&sc->bcon_tasklet);
0227 
0228     if (bf && bf->bf_mpdu) {
0229         struct sk_buff *skb = bf->bf_mpdu;
0230         dma_unmap_single(sc->dev, bf->bf_buf_addr,
0231                  skb->len, DMA_TO_DEVICE);
0232         dev_kfree_skb_any(skb);
0233         bf->bf_mpdu = NULL;
0234         bf->bf_buf_addr = 0;
0235     }
0236 
0237     avp->av_bcbuf = NULL;
0238     sc->beacon.bslot[avp->av_bslot] = NULL;
0239     list_add_tail(&bf->list, &sc->beacon.bbuf);
0240 
0241     tasklet_enable(&sc->bcon_tasklet);
0242 }
0243 
0244 void ath9k_beacon_ensure_primary_slot(struct ath_softc *sc)
0245 {
0246     struct ath_common *common = ath9k_hw_common(sc->sc_ah);
0247     struct ieee80211_vif *vif;
0248     struct ath_vif *avp;
0249     s64 tsfadjust;
0250     u32 offset;
0251     int first_slot = ATH_BCBUF;
0252     int slot;
0253 
0254     tasklet_disable_in_atomic(&sc->bcon_tasklet);
0255 
0256     /* Find first taken slot. */
0257     for (slot = 0; slot < ATH_BCBUF; slot++) {
0258         if (sc->beacon.bslot[slot]) {
0259             first_slot = slot;
0260             break;
0261         }
0262     }
0263     if (first_slot == 0)
0264         goto out;
0265 
0266     /* Re-enumarate all slots, moving them forward. */
0267     for (slot = 0; slot < ATH_BCBUF; slot++) {
0268         if (slot + first_slot < ATH_BCBUF) {
0269             vif = sc->beacon.bslot[slot + first_slot];
0270             sc->beacon.bslot[slot] = vif;
0271 
0272             if (vif) {
0273                 avp = (void *)vif->drv_priv;
0274                 avp->av_bslot = slot;
0275             }
0276         } else {
0277             sc->beacon.bslot[slot] = NULL;
0278         }
0279     }
0280 
0281     vif = sc->beacon.bslot[0];
0282     if (WARN_ON(!vif))
0283         goto out;
0284 
0285     /* Get the tsf_adjust value for the new first slot. */
0286     avp = (void *)vif->drv_priv;
0287     tsfadjust = le64_to_cpu(avp->tsf_adjust);
0288 
0289     ath_dbg(common, CONFIG,
0290         "Adjusting global TSF after beacon slot reassignment: %lld\n",
0291         (signed long long)tsfadjust);
0292 
0293     /* Modify TSF as required and update the HW. */
0294     avp->chanctx->tsf_val += tsfadjust;
0295     if (sc->cur_chan == avp->chanctx) {
0296         offset = ath9k_hw_get_tsf_offset(&avp->chanctx->tsf_ts, NULL);
0297         ath9k_hw_settsf64(sc->sc_ah, avp->chanctx->tsf_val + offset);
0298     }
0299 
0300     /* The slots tsf_adjust will be updated by ath9k_beacon_config later. */
0301 
0302 out:
0303     tasklet_enable(&sc->bcon_tasklet);
0304 }
0305 
0306 static int ath9k_beacon_choose_slot(struct ath_softc *sc)
0307 {
0308     struct ath_common *common = ath9k_hw_common(sc->sc_ah);
0309     struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
0310     u16 intval;
0311     u32 tsftu;
0312     u64 tsf;
0313     int slot;
0314 
0315     if (sc->sc_ah->opmode != NL80211_IFTYPE_AP &&
0316         sc->sc_ah->opmode != NL80211_IFTYPE_MESH_POINT) {
0317         ath_dbg(common, BEACON, "slot 0, tsf: %llu\n",
0318             ath9k_hw_gettsf64(sc->sc_ah));
0319         return 0;
0320     }
0321 
0322     intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
0323     tsf = ath9k_hw_gettsf64(sc->sc_ah);
0324     tsf += TU_TO_USEC(sc->sc_ah->config.sw_beacon_response_time);
0325     tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF);
0326     slot = (tsftu % (intval * ATH_BCBUF)) / intval;
0327 
0328     ath_dbg(common, BEACON, "slot: %d tsf: %llu tsftu: %u\n",
0329         slot, tsf, tsftu / ATH_BCBUF);
0330 
0331     return slot;
0332 }
0333 
0334 static void ath9k_set_tsfadjust(struct ath_softc *sc,
0335                 struct ath_beacon_config *cur_conf)
0336 {
0337     struct ath_common *common = ath9k_hw_common(sc->sc_ah);
0338     s64 tsfadjust;
0339     int slot;
0340 
0341     for (slot = 0; slot < ATH_BCBUF; slot++) {
0342         struct ath_vif *avp;
0343 
0344         if (!sc->beacon.bslot[slot])
0345             continue;
0346 
0347         avp = (void *)sc->beacon.bslot[slot]->drv_priv;
0348 
0349         /* tsf_adjust is added to the TSF value. We send out the
0350          * beacon late, so need to adjust the TSF starting point to be
0351          * later in time (i.e. the theoretical first beacon has a TSF
0352          * of 0 after correction).
0353          */
0354         tsfadjust = cur_conf->beacon_interval * avp->av_bslot;
0355         tsfadjust = -TU_TO_USEC(tsfadjust) / ATH_BCBUF;
0356         avp->tsf_adjust = cpu_to_le64(tsfadjust);
0357 
0358         ath_dbg(common, CONFIG, "tsfadjust is: %lld for bslot: %d\n",
0359             (signed long long)tsfadjust, avp->av_bslot);
0360     }
0361 }
0362 
0363 bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif)
0364 {
0365     if (!vif || !vif->bss_conf.csa_active)
0366         return false;
0367 
0368     if (!ieee80211_beacon_cntdwn_is_complete(vif))
0369         return false;
0370 
0371     ieee80211_csa_finish(vif);
0372     return true;
0373 }
0374 
0375 static void ath9k_csa_update_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
0376 {
0377     struct ath_softc *sc = data;
0378     ath9k_csa_is_finished(sc, vif);
0379 }
0380 
0381 void ath9k_csa_update(struct ath_softc *sc)
0382 {
0383     ieee80211_iterate_active_interfaces_atomic(sc->hw,
0384                            IEEE80211_IFACE_ITER_NORMAL,
0385                            ath9k_csa_update_vif, sc);
0386 }
0387 
0388 void ath9k_beacon_tasklet(struct tasklet_struct *t)
0389 {
0390     struct ath_softc *sc = from_tasklet(sc, t, bcon_tasklet);
0391     struct ath_hw *ah = sc->sc_ah;
0392     struct ath_common *common = ath9k_hw_common(ah);
0393     struct ath_buf *bf = NULL;
0394     struct ieee80211_vif *vif;
0395     bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
0396     int slot;
0397 
0398     if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) {
0399         ath_dbg(common, RESET,
0400             "reset work is pending, skip beaconing now\n");
0401         return;
0402     }
0403 
0404     /*
0405      * Check if the previous beacon has gone out.  If
0406      * not don't try to post another, skip this period
0407      * and wait for the next.  Missed beacons indicate
0408      * a problem and should not occur.  If we miss too
0409      * many consecutive beacons reset the device.
0410      */
0411     if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) {
0412         sc->beacon.bmisscnt++;
0413 
0414         ath9k_hw_check_nav(ah);
0415 
0416         /*
0417          * If the previous beacon has not been transmitted
0418          * and a MAC/BB hang has been identified, return
0419          * here because a chip reset would have been
0420          * initiated.
0421          */
0422         if (!ath_hw_check(sc))
0423             return;
0424 
0425         if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) {
0426             ath_dbg(common, BSTUCK,
0427                 "missed %u consecutive beacons\n",
0428                 sc->beacon.bmisscnt);
0429             ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
0430             if (sc->beacon.bmisscnt > 3)
0431                 ath9k_hw_bstuck_nfcal(ah);
0432         } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
0433             ath_dbg(common, BSTUCK, "beacon is officially stuck\n");
0434             sc->beacon.bmisscnt = 0;
0435             ath9k_queue_reset(sc, RESET_TYPE_BEACON_STUCK);
0436         }
0437 
0438         return;
0439     }
0440 
0441     slot = ath9k_beacon_choose_slot(sc);
0442     vif = sc->beacon.bslot[slot];
0443 
0444     /* EDMA devices check that in the tx completion function. */
0445     if (!edma) {
0446         if (ath9k_is_chanctx_enabled()) {
0447             ath_chanctx_beacon_sent_ev(sc,
0448                       ATH_CHANCTX_EVENT_BEACON_SENT);
0449         }
0450 
0451         if (ath9k_csa_is_finished(sc, vif))
0452             return;
0453     }
0454 
0455     if (!vif || !vif->bss_conf.enable_beacon)
0456         return;
0457 
0458     if (ath9k_is_chanctx_enabled()) {
0459         ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_BEACON_PREPARE);
0460     }
0461 
0462     bf = ath9k_beacon_generate(sc->hw, vif);
0463 
0464     if (sc->beacon.bmisscnt != 0) {
0465         ath_dbg(common, BSTUCK, "resume beacon xmit after %u misses\n",
0466             sc->beacon.bmisscnt);
0467         sc->beacon.bmisscnt = 0;
0468     }
0469 
0470     /*
0471      * Handle slot time change when a non-ERP station joins/leaves
0472      * an 11g network.  The 802.11 layer notifies us via callback,
0473      * we mark updateslot, then wait one beacon before effecting
0474      * the change.  This gives associated stations at least one
0475      * beacon interval to note the state change.
0476      *
0477      * NB: The slot time change state machine is clocked according
0478      *     to whether we are bursting or staggering beacons.  We
0479      *     recognize the request to update and record the current
0480      *     slot then don't transition until that slot is reached
0481      *     again.  If we miss a beacon for that slot then we'll be
0482      *     slow to transition but we'll be sure at least one beacon
0483      *     interval has passed.  When bursting slot is always left
0484      *     set to ATH_BCBUF so this check is a noop.
0485      */
0486     if (sc->beacon.updateslot == UPDATE) {
0487         sc->beacon.updateslot = COMMIT;
0488         sc->beacon.slotupdate = slot;
0489     } else if (sc->beacon.updateslot == COMMIT &&
0490            sc->beacon.slotupdate == slot) {
0491         ah->slottime = sc->beacon.slottime;
0492         ath9k_hw_init_global_settings(ah);
0493         sc->beacon.updateslot = OK;
0494     }
0495 
0496     if (bf) {
0497         ath9k_reset_beacon_status(sc);
0498 
0499         ath_dbg(common, BEACON,
0500             "Transmitting beacon for slot: %d\n", slot);
0501 
0502         /* NB: cabq traffic should already be queued and primed */
0503         ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr);
0504 
0505         if (!edma)
0506             ath9k_hw_txstart(ah, sc->beacon.beaconq);
0507     }
0508 }
0509 
0510 /*
0511  * Both nexttbtt and intval have to be in usecs.
0512  */
0513 static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt,
0514                   u32 intval)
0515 {
0516     struct ath_hw *ah = sc->sc_ah;
0517 
0518     ath9k_hw_disable_interrupts(ah);
0519     ath9k_beaconq_config(sc);
0520     ath9k_hw_beaconinit(ah, nexttbtt, intval);
0521     ah->imask |= ATH9K_INT_SWBA;
0522     sc->beacon.bmisscnt = 0;
0523     ath9k_hw_set_interrupts(ah);
0524     ath9k_hw_enable_interrupts(ah);
0525 }
0526 
0527 static void ath9k_beacon_stop(struct ath_softc *sc)
0528 {
0529     ath9k_hw_disable_interrupts(sc->sc_ah);
0530     sc->sc_ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
0531     sc->beacon.bmisscnt = 0;
0532     ath9k_hw_set_interrupts(sc->sc_ah);
0533     ath9k_hw_enable_interrupts(sc->sc_ah);
0534 }
0535 
0536 /*
0537  * For multi-bss ap support beacons are either staggered evenly over N slots or
0538  * burst together.  For the former arrange for the SWBA to be delivered for each
0539  * slot. Slots that are not occupied will generate nothing.
0540  */
0541 static void ath9k_beacon_config_ap(struct ath_softc *sc,
0542                    struct ath_beacon_config *conf)
0543 {
0544     struct ath_hw *ah = sc->sc_ah;
0545 
0546     ath9k_cmn_beacon_config_ap(ah, conf, ATH_BCBUF);
0547     ath9k_beacon_init(sc, conf->nexttbtt, conf->intval);
0548 }
0549 
0550 static void ath9k_beacon_config_sta(struct ath_hw *ah,
0551                     struct ath_beacon_config *conf)
0552 {
0553     struct ath9k_beacon_state bs;
0554 
0555     if (ath9k_cmn_beacon_config_sta(ah, conf, &bs) == -EPERM)
0556         return;
0557 
0558     ath9k_hw_disable_interrupts(ah);
0559     ath9k_hw_set_sta_beacon_timers(ah, &bs);
0560     ah->imask |= ATH9K_INT_BMISS;
0561 
0562     ath9k_hw_set_interrupts(ah);
0563     ath9k_hw_enable_interrupts(ah);
0564 }
0565 
0566 static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
0567                       struct ath_beacon_config *conf)
0568 {
0569     struct ath_hw *ah = sc->sc_ah;
0570     struct ath_common *common = ath9k_hw_common(ah);
0571 
0572     ath9k_reset_beacon_status(sc);
0573 
0574     ath9k_cmn_beacon_config_adhoc(ah, conf);
0575 
0576     ath9k_beacon_init(sc, conf->nexttbtt, conf->intval);
0577 
0578     /*
0579      * Set the global 'beacon has been configured' flag for the
0580      * joiner case in IBSS mode.
0581      */
0582     if (!conf->ibss_creator && conf->enable_beacon)
0583         set_bit(ATH_OP_BEACONS, &common->op_flags);
0584 }
0585 
0586 static void ath9k_cache_beacon_config(struct ath_softc *sc,
0587                       struct ath_chanctx *ctx,
0588                       struct ieee80211_vif *vif)
0589 {
0590     struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
0591     struct ath_common *common = ath9k_hw_common(sc->sc_ah);
0592     struct ath_beacon_config *cur_conf = &ctx->beacon;
0593 
0594     ath_dbg(common, BEACON,
0595         "Caching beacon data for BSS: %pM\n", bss_conf->bssid);
0596 
0597     cur_conf->beacon_interval = bss_conf->beacon_int;
0598     cur_conf->dtim_period = bss_conf->dtim_period;
0599     cur_conf->dtim_count = 1;
0600     cur_conf->ibss_creator = vif->cfg.ibss_creator;
0601 
0602     /*
0603      * It looks like mac80211 may end up using beacon interval of zero in
0604      * some cases (at least for mesh point). Avoid getting into an
0605      * infinite loop by using a bit safer value instead. To be safe,
0606      * do sanity check on beacon interval for all operating modes.
0607      */
0608     if (cur_conf->beacon_interval == 0)
0609         cur_conf->beacon_interval = 100;
0610 
0611     cur_conf->bmiss_timeout =
0612         ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
0613 
0614     /*
0615      * We don't parse dtim period from mac80211 during the driver
0616      * initialization as it breaks association with hidden-ssid
0617      * AP and it causes latency in roaming
0618      */
0619     if (cur_conf->dtim_period == 0)
0620         cur_conf->dtim_period = 1;
0621 
0622     ath9k_set_tsfadjust(sc, cur_conf);
0623 }
0624 
0625 void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif,
0626              bool beacons)
0627 {
0628     struct ath_hw *ah = sc->sc_ah;
0629     struct ath_common *common = ath9k_hw_common(ah);
0630     struct ath_vif *avp;
0631     struct ath_chanctx *ctx;
0632     struct ath_beacon_config *cur_conf;
0633     unsigned long flags;
0634     bool enabled;
0635     bool skip_beacon = false;
0636 
0637     if (!beacons) {
0638         clear_bit(ATH_OP_BEACONS, &common->op_flags);
0639         ath9k_beacon_stop(sc);
0640         return;
0641     }
0642 
0643     if (WARN_ON(!main_vif))
0644         return;
0645 
0646     avp = (void *)main_vif->drv_priv;
0647     ctx = avp->chanctx;
0648     cur_conf = &ctx->beacon;
0649     enabled = cur_conf->enable_beacon;
0650     cur_conf->enable_beacon = beacons;
0651 
0652     if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
0653         ath9k_cache_beacon_config(sc, ctx, main_vif);
0654 
0655         ath9k_set_beacon(sc);
0656         set_bit(ATH_OP_BEACONS, &common->op_flags);
0657         return;
0658     }
0659 
0660     /* Update the beacon configuration. */
0661     ath9k_cache_beacon_config(sc, ctx, main_vif);
0662 
0663     /*
0664      * Configure the HW beacon registers only when we have a valid
0665      * beacon interval.
0666      */
0667     if (cur_conf->beacon_interval) {
0668         /* Special case to sync the TSF when joining an existing IBSS.
0669          * This is only done if no AP interface is active.
0670          * Note that mac80211 always resets the TSF when creating a new
0671          * IBSS interface.
0672          */
0673         if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC &&
0674             !enabled && beacons && !main_vif->cfg.ibss_creator) {
0675             spin_lock_irqsave(&sc->sc_pm_lock, flags);
0676             sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
0677             spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
0678             skip_beacon = true;
0679         }
0680 
0681         /*
0682          * Do not set the ATH_OP_BEACONS flag for IBSS joiner mode
0683          * here, it is done in ath9k_beacon_config_adhoc().
0684          */
0685         if (beacons && !skip_beacon) {
0686             set_bit(ATH_OP_BEACONS, &common->op_flags);
0687             ath9k_set_beacon(sc);
0688         } else {
0689             clear_bit(ATH_OP_BEACONS, &common->op_flags);
0690             ath9k_beacon_stop(sc);
0691         }
0692     } else {
0693         clear_bit(ATH_OP_BEACONS, &common->op_flags);
0694         ath9k_beacon_stop(sc);
0695     }
0696 }
0697 
0698 void ath9k_set_beacon(struct ath_softc *sc)
0699 {
0700     struct ath_common *common = ath9k_hw_common(sc->sc_ah);
0701     struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
0702 
0703     switch (sc->sc_ah->opmode) {
0704     case NL80211_IFTYPE_AP:
0705     case NL80211_IFTYPE_MESH_POINT:
0706         ath9k_beacon_config_ap(sc, cur_conf);
0707         break;
0708     case NL80211_IFTYPE_ADHOC:
0709         ath9k_beacon_config_adhoc(sc, cur_conf);
0710         break;
0711     case NL80211_IFTYPE_STATION:
0712         ath9k_beacon_config_sta(sc->sc_ah, cur_conf);
0713         break;
0714     default:
0715         ath_dbg(common, CONFIG, "Unsupported beaconing mode\n");
0716         return;
0717     }
0718 }