719 lines · c
1/*2 * Copyright (c) 2008-2011 Atheros Communications Inc.3 *4 * Permission to use, copy, modify, and/or distribute this software for any5 * purpose with or without fee is hereby granted, provided that the above6 * copyright notice and this permission notice appear in all copies.7 *8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF14 * 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 221 22static 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 on30 * the operating mode of the station (AP or AdHoc). Parameters are AIFS31 * settings and channel width min/max32*/33static 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 else56 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 set69 * up rate codes, and channel flags. Beacons are always sent out at the70 * lowest rate, and are not retried.71*/72static 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 112static 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, 0);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 current169 * 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 staggered172 * beacons, then drain the cabq by dropping all the frames in173 * 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 195void 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 217void 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 244void 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_in_atomic(&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 302out:303 tasklet_enable(&sc->bcon_tasklet);304}305 306static 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 334static 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 the350 * beacon late, so need to adjust the TSF starting point to be351 * later in time (i.e. the theoretical first beacon has a TSF352 * 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 363bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif)364{365 if (!vif || !vif->bss_conf.csa_active)366 return false;367 368 if (!ieee80211_beacon_cntdwn_is_complete(vif, 0))369 return false;370 371 ieee80211_csa_finish(vif, 0);372 return true;373}374 375static 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 381void 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 388void ath9k_beacon_tasklet(struct tasklet_struct *t)389{390 struct ath_softc *sc = from_tasklet(sc, t, bcon_tasklet);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. If406 * not don't try to post another, skip this period407 * and wait for the next. Missed beacons indicate408 * a problem and should not occur. If we miss too409 * 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 transmitted418 * and a MAC/BB hang has been identified, return419 * here because a chip reset would have been420 * 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/leaves472 * an 11g network. The 802.11 layer notifies us via callback,473 * we mark updateslot, then wait one beacon before effecting474 * the change. This gives associated stations at least one475 * beacon interval to note the state change.476 *477 * NB: The slot time change state machine is clocked according478 * to whether we are bursting or staggering beacons. We479 * recognize the request to update and record the current480 * slot then don't transition until that slot is reached481 * again. If we miss a beacon for that slot then we'll be482 * slow to transition but we'll be sure at least one beacon483 * interval has passed. When bursting slot is always left484 * 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 */513static 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 527static 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 or538 * burst together. For the former arrange for the SWBA to be delivered for each539 * slot. Slots that are not occupied will generate nothing.540 */541static 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 550static 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 566static 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 the580 * 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 586static void ath9k_cache_beacon_config(struct ath_softc *sc,587 struct ath_chanctx *ctx,588 struct ieee80211_vif *vif)589{590 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;591 struct ath_common *common = ath9k_hw_common(sc->sc_ah);592 struct ath_beacon_config *cur_conf = &ctx->beacon;593 594 ath_dbg(common, BEACON,595 "Caching beacon data for BSS: %pM\n", bss_conf->bssid);596 597 cur_conf->beacon_interval = bss_conf->beacon_int;598 cur_conf->dtim_period = bss_conf->dtim_period;599 cur_conf->dtim_count = 1;600 cur_conf->ibss_creator = vif->cfg.ibss_creator;601 602 /*603 * It looks like mac80211 may end up using beacon interval of zero in604 * some cases (at least for mesh point). Avoid getting into an605 * infinite loop by using a bit safer value instead. To be safe,606 * do sanity check on beacon interval for all operating modes.607 */608 if (cur_conf->beacon_interval == 0)609 cur_conf->beacon_interval = 100;610 611 cur_conf->bmiss_timeout =612 ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;613 614 /*615 * We don't parse dtim period from mac80211 during the driver616 * initialization as it breaks association with hidden-ssid617 * AP and it causes latency in roaming618 */619 if (cur_conf->dtim_period == 0)620 cur_conf->dtim_period = 1;621 622 ath9k_set_tsfadjust(sc, cur_conf);623}624 625void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif,626 bool beacons)627{628 struct ath_hw *ah = sc->sc_ah;629 struct ath_common *common = ath9k_hw_common(ah);630 struct ath_vif *avp;631 struct ath_chanctx *ctx;632 struct ath_beacon_config *cur_conf;633 unsigned long flags;634 bool enabled;635 bool skip_beacon = false;636 637 if (!beacons) {638 clear_bit(ATH_OP_BEACONS, &common->op_flags);639 ath9k_beacon_stop(sc);640 return;641 }642 643 if (WARN_ON(!main_vif))644 return;645 646 avp = (void *)main_vif->drv_priv;647 ctx = avp->chanctx;648 cur_conf = &ctx->beacon;649 enabled = cur_conf->enable_beacon;650 cur_conf->enable_beacon = beacons;651 652 if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {653 ath9k_cache_beacon_config(sc, ctx, main_vif);654 655 ath9k_set_beacon(sc);656 set_bit(ATH_OP_BEACONS, &common->op_flags);657 return;658 }659 660 /* Update the beacon configuration. */661 ath9k_cache_beacon_config(sc, ctx, main_vif);662 663 /*664 * Configure the HW beacon registers only when we have a valid665 * beacon interval.666 */667 if (cur_conf->beacon_interval) {668 /* Special case to sync the TSF when joining an existing IBSS.669 * This is only done if no AP interface is active.670 * Note that mac80211 always resets the TSF when creating a new671 * IBSS interface.672 */673 if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC &&674 !enabled && beacons && !main_vif->cfg.ibss_creator) {675 spin_lock_irqsave(&sc->sc_pm_lock, flags);676 sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;677 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);678 skip_beacon = true;679 }680 681 /*682 * Do not set the ATH_OP_BEACONS flag for IBSS joiner mode683 * here, it is done in ath9k_beacon_config_adhoc().684 */685 if (beacons && !skip_beacon) {686 set_bit(ATH_OP_BEACONS, &common->op_flags);687 ath9k_set_beacon(sc);688 } else {689 clear_bit(ATH_OP_BEACONS, &common->op_flags);690 ath9k_beacon_stop(sc);691 }692 } else {693 clear_bit(ATH_OP_BEACONS, &common->op_flags);694 ath9k_beacon_stop(sc);695 }696}697 698void ath9k_set_beacon(struct ath_softc *sc)699{700 struct ath_common *common = ath9k_hw_common(sc->sc_ah);701 struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;702 703 switch (sc->sc_ah->opmode) {704 case NL80211_IFTYPE_AP:705 case NL80211_IFTYPE_MESH_POINT:706 ath9k_beacon_config_ap(sc, cur_conf);707 break;708 case NL80211_IFTYPE_ADHOC:709 ath9k_beacon_config_adhoc(sc, cur_conf);710 break;711 case NL80211_IFTYPE_STATION:712 ath9k_beacon_config_sta(sc->sc_ah, cur_conf);713 break;714 default:715 ath_dbg(common, CONFIG, "Unsupported beaconing mode\n");716 return;717 }718}719