162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2008-2011 Atheros Communications Inc. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 562306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 662306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 962306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1062306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1162306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1262306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1362306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1462306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1862306a36Sopenharmony_ci#include "ath9k.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define FUDGE 2 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic void ath9k_reset_beacon_status(struct ath_softc *sc) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci sc->beacon.tx_processed = false; 2562306a36Sopenharmony_ci sc->beacon.tx_last = false; 2662306a36Sopenharmony_ci} 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* 2962306a36Sopenharmony_ci * This function will modify certain transmit queue properties depending on 3062306a36Sopenharmony_ci * the operating mode of the station (AP or AdHoc). Parameters are AIFS 3162306a36Sopenharmony_ci * settings and channel width min/max 3262306a36Sopenharmony_ci*/ 3362306a36Sopenharmony_cistatic void ath9k_beaconq_config(struct ath_softc *sc) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 3662306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 3762306a36Sopenharmony_ci struct ath9k_tx_queue_info qi, qi_be; 3862306a36Sopenharmony_ci struct ath_txq *txq; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (sc->sc_ah->opmode == NL80211_IFTYPE_AP || 4362306a36Sopenharmony_ci sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) { 4462306a36Sopenharmony_ci /* Always burst out beacon and CAB traffic. */ 4562306a36Sopenharmony_ci qi.tqi_aifs = 1; 4662306a36Sopenharmony_ci qi.tqi_cwmin = 0; 4762306a36Sopenharmony_ci qi.tqi_cwmax = 0; 4862306a36Sopenharmony_ci } else { 4962306a36Sopenharmony_ci /* Adhoc mode; important thing is to use 2x cwmin. */ 5062306a36Sopenharmony_ci txq = sc->tx.txq_map[IEEE80211_AC_BE]; 5162306a36Sopenharmony_ci ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be); 5262306a36Sopenharmony_ci qi.tqi_aifs = qi_be.tqi_aifs; 5362306a36Sopenharmony_ci if (ah->slottime == 20) 5462306a36Sopenharmony_ci qi.tqi_cwmin = 2*qi_be.tqi_cwmin; 5562306a36Sopenharmony_ci else 5662306a36Sopenharmony_ci qi.tqi_cwmin = 4*qi_be.tqi_cwmin; 5762306a36Sopenharmony_ci qi.tqi_cwmax = qi_be.tqi_cwmax; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) { 6162306a36Sopenharmony_ci ath_err(common, "Unable to update h/w beacon queue parameters\n"); 6262306a36Sopenharmony_ci } else { 6362306a36Sopenharmony_ci ath9k_hw_resettxqueue(ah, sc->beacon.beaconq); 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* 6862306a36Sopenharmony_ci * Associates the beacon frame buffer with a transmit descriptor. Will set 6962306a36Sopenharmony_ci * up rate codes, and channel flags. Beacons are always sent out at the 7062306a36Sopenharmony_ci * lowest rate, and are not retried. 7162306a36Sopenharmony_ci*/ 7262306a36Sopenharmony_cistatic void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, 7362306a36Sopenharmony_ci struct ath_buf *bf, int rateidx) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct sk_buff *skb = bf->bf_mpdu; 7662306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 7762306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 7862306a36Sopenharmony_ci struct ath_tx_info info; 7962306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 8062306a36Sopenharmony_ci u8 chainmask = ah->txchainmask; 8162306a36Sopenharmony_ci u8 i, rate = 0; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci sband = &common->sbands[sc->cur_chandef.chan->band]; 8462306a36Sopenharmony_ci rate = sband->bitrates[rateidx].hw_value; 8562306a36Sopenharmony_ci if (vif->bss_conf.use_short_preamble) 8662306a36Sopenharmony_ci rate |= sband->bitrates[rateidx].hw_value_short; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci memset(&info, 0, sizeof(info)); 8962306a36Sopenharmony_ci info.pkt_len = skb->len + FCS_LEN; 9062306a36Sopenharmony_ci info.type = ATH9K_PKT_TYPE_BEACON; 9162306a36Sopenharmony_ci for (i = 0; i < 4; i++) 9262306a36Sopenharmony_ci info.txpower[i] = MAX_RATE_POWER; 9362306a36Sopenharmony_ci info.keyix = ATH9K_TXKEYIX_INVALID; 9462306a36Sopenharmony_ci info.keytype = ATH9K_KEY_TYPE_CLEAR; 9562306a36Sopenharmony_ci info.flags = ATH9K_TXDESC_NOACK | ATH9K_TXDESC_CLRDMASK; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci info.buf_addr[0] = bf->bf_buf_addr; 9862306a36Sopenharmony_ci info.buf_len[0] = roundup(skb->len, 4); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci info.is_first = true; 10162306a36Sopenharmony_ci info.is_last = true; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci info.qcu = sc->beacon.beaconq; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci info.rates[0].Tries = 1; 10662306a36Sopenharmony_ci info.rates[0].Rate = rate; 10762306a36Sopenharmony_ci info.rates[0].ChSel = ath_txchainmask_reduction(sc, chainmask, rate); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci ath9k_hw_set_txdesc(ah, bf->bf_desc, &info); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw, 11362306a36Sopenharmony_ci struct ieee80211_vif *vif) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 11662306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 11762306a36Sopenharmony_ci struct ath_buf *bf; 11862306a36Sopenharmony_ci struct ath_vif *avp = (void *)vif->drv_priv; 11962306a36Sopenharmony_ci struct sk_buff *skb; 12062306a36Sopenharmony_ci struct ath_txq *cabq = sc->beacon.cabq; 12162306a36Sopenharmony_ci struct ieee80211_tx_info *info; 12262306a36Sopenharmony_ci struct ieee80211_mgmt *mgmt_hdr; 12362306a36Sopenharmony_ci int cabq_depth; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (avp->av_bcbuf == NULL) 12662306a36Sopenharmony_ci return NULL; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci bf = avp->av_bcbuf; 12962306a36Sopenharmony_ci skb = bf->bf_mpdu; 13062306a36Sopenharmony_ci if (skb) { 13162306a36Sopenharmony_ci dma_unmap_single(sc->dev, bf->bf_buf_addr, 13262306a36Sopenharmony_ci skb->len, DMA_TO_DEVICE); 13362306a36Sopenharmony_ci dev_kfree_skb_any(skb); 13462306a36Sopenharmony_ci bf->bf_buf_addr = 0; 13562306a36Sopenharmony_ci bf->bf_mpdu = NULL; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci skb = ieee80211_beacon_get(hw, vif, 0); 13962306a36Sopenharmony_ci if (skb == NULL) 14062306a36Sopenharmony_ci return NULL; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci bf->bf_mpdu = skb; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci mgmt_hdr = (struct ieee80211_mgmt *)skb->data; 14562306a36Sopenharmony_ci mgmt_hdr->u.beacon.timestamp = avp->tsf_adjust; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci ath_assign_seq(common, skb); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* Always assign NOA attr when MCC enabled */ 15262306a36Sopenharmony_ci if (ath9k_is_chanctx_enabled()) 15362306a36Sopenharmony_ci ath9k_beacon_add_noa(sc, avp, skb); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, 15662306a36Sopenharmony_ci skb->len, DMA_TO_DEVICE); 15762306a36Sopenharmony_ci if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { 15862306a36Sopenharmony_ci dev_kfree_skb_any(skb); 15962306a36Sopenharmony_ci bf->bf_mpdu = NULL; 16062306a36Sopenharmony_ci bf->bf_buf_addr = 0; 16162306a36Sopenharmony_ci ath_err(common, "dma_mapping_error on beaconing\n"); 16262306a36Sopenharmony_ci return NULL; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci skb = ieee80211_get_buffered_bc(hw, vif); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* 16862306a36Sopenharmony_ci * if the CABQ traffic from previous DTIM is pending and the current 16962306a36Sopenharmony_ci * beacon is also a DTIM. 17062306a36Sopenharmony_ci * 1) if there is only one vif let the cab traffic continue. 17162306a36Sopenharmony_ci * 2) if there are more than one vif and we are using staggered 17262306a36Sopenharmony_ci * beacons, then drain the cabq by dropping all the frames in 17362306a36Sopenharmony_ci * the cabq so that the current vifs cab traffic can be scheduled. 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci spin_lock_bh(&cabq->axq_lock); 17662306a36Sopenharmony_ci cabq_depth = cabq->axq_depth; 17762306a36Sopenharmony_ci spin_unlock_bh(&cabq->axq_lock); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if (skb && cabq_depth) { 18062306a36Sopenharmony_ci if (sc->cur_chan->nvifs > 1) { 18162306a36Sopenharmony_ci ath_dbg(common, BEACON, 18262306a36Sopenharmony_ci "Flushing previous cabq traffic\n"); 18362306a36Sopenharmony_ci ath_draintxq(sc, cabq); 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci ath9k_beacon_setup(sc, vif, bf, info->control.rates[0].idx); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (skb) 19062306a36Sopenharmony_ci ath_tx_cabq(hw, vif, skb); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci return bf; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_civoid ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 19862306a36Sopenharmony_ci struct ath_vif *avp = (void *)vif->drv_priv; 19962306a36Sopenharmony_ci int slot; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf, struct ath_buf, list); 20262306a36Sopenharmony_ci list_del(&avp->av_bcbuf->list); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci for (slot = 0; slot < ATH_BCBUF; slot++) { 20562306a36Sopenharmony_ci if (sc->beacon.bslot[slot] == NULL) { 20662306a36Sopenharmony_ci avp->av_bslot = slot; 20762306a36Sopenharmony_ci break; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci sc->beacon.bslot[avp->av_bslot] = vif; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n", 21462306a36Sopenharmony_ci avp->av_bslot); 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_civoid ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 22062306a36Sopenharmony_ci struct ath_vif *avp = (void *)vif->drv_priv; 22162306a36Sopenharmony_ci struct ath_buf *bf = avp->av_bcbuf; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n", 22462306a36Sopenharmony_ci avp->av_bslot); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci tasklet_disable(&sc->bcon_tasklet); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (bf && bf->bf_mpdu) { 22962306a36Sopenharmony_ci struct sk_buff *skb = bf->bf_mpdu; 23062306a36Sopenharmony_ci dma_unmap_single(sc->dev, bf->bf_buf_addr, 23162306a36Sopenharmony_ci skb->len, DMA_TO_DEVICE); 23262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 23362306a36Sopenharmony_ci bf->bf_mpdu = NULL; 23462306a36Sopenharmony_ci bf->bf_buf_addr = 0; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci avp->av_bcbuf = NULL; 23862306a36Sopenharmony_ci sc->beacon.bslot[avp->av_bslot] = NULL; 23962306a36Sopenharmony_ci list_add_tail(&bf->list, &sc->beacon.bbuf); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci tasklet_enable(&sc->bcon_tasklet); 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_civoid ath9k_beacon_ensure_primary_slot(struct ath_softc *sc) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 24762306a36Sopenharmony_ci struct ieee80211_vif *vif; 24862306a36Sopenharmony_ci struct ath_vif *avp; 24962306a36Sopenharmony_ci s64 tsfadjust; 25062306a36Sopenharmony_ci u32 offset; 25162306a36Sopenharmony_ci int first_slot = ATH_BCBUF; 25262306a36Sopenharmony_ci int slot; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci tasklet_disable_in_atomic(&sc->bcon_tasklet); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci /* Find first taken slot. */ 25762306a36Sopenharmony_ci for (slot = 0; slot < ATH_BCBUF; slot++) { 25862306a36Sopenharmony_ci if (sc->beacon.bslot[slot]) { 25962306a36Sopenharmony_ci first_slot = slot; 26062306a36Sopenharmony_ci break; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci if (first_slot == 0) 26462306a36Sopenharmony_ci goto out; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci /* Re-enumarate all slots, moving them forward. */ 26762306a36Sopenharmony_ci for (slot = 0; slot < ATH_BCBUF; slot++) { 26862306a36Sopenharmony_ci if (slot + first_slot < ATH_BCBUF) { 26962306a36Sopenharmony_ci vif = sc->beacon.bslot[slot + first_slot]; 27062306a36Sopenharmony_ci sc->beacon.bslot[slot] = vif; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (vif) { 27362306a36Sopenharmony_ci avp = (void *)vif->drv_priv; 27462306a36Sopenharmony_ci avp->av_bslot = slot; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci } else { 27762306a36Sopenharmony_ci sc->beacon.bslot[slot] = NULL; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci vif = sc->beacon.bslot[0]; 28262306a36Sopenharmony_ci if (WARN_ON(!vif)) 28362306a36Sopenharmony_ci goto out; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci /* Get the tsf_adjust value for the new first slot. */ 28662306a36Sopenharmony_ci avp = (void *)vif->drv_priv; 28762306a36Sopenharmony_ci tsfadjust = le64_to_cpu(avp->tsf_adjust); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci ath_dbg(common, CONFIG, 29062306a36Sopenharmony_ci "Adjusting global TSF after beacon slot reassignment: %lld\n", 29162306a36Sopenharmony_ci (signed long long)tsfadjust); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci /* Modify TSF as required and update the HW. */ 29462306a36Sopenharmony_ci avp->chanctx->tsf_val += tsfadjust; 29562306a36Sopenharmony_ci if (sc->cur_chan == avp->chanctx) { 29662306a36Sopenharmony_ci offset = ath9k_hw_get_tsf_offset(&avp->chanctx->tsf_ts, NULL); 29762306a36Sopenharmony_ci ath9k_hw_settsf64(sc->sc_ah, avp->chanctx->tsf_val + offset); 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci /* The slots tsf_adjust will be updated by ath9k_beacon_config later. */ 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ciout: 30362306a36Sopenharmony_ci tasklet_enable(&sc->bcon_tasklet); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic int ath9k_beacon_choose_slot(struct ath_softc *sc) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 30962306a36Sopenharmony_ci struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; 31062306a36Sopenharmony_ci u16 intval; 31162306a36Sopenharmony_ci u32 tsftu; 31262306a36Sopenharmony_ci u64 tsf; 31362306a36Sopenharmony_ci int slot; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (sc->sc_ah->opmode != NL80211_IFTYPE_AP && 31662306a36Sopenharmony_ci sc->sc_ah->opmode != NL80211_IFTYPE_MESH_POINT) { 31762306a36Sopenharmony_ci ath_dbg(common, BEACON, "slot 0, tsf: %llu\n", 31862306a36Sopenharmony_ci ath9k_hw_gettsf64(sc->sc_ah)); 31962306a36Sopenharmony_ci return 0; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL; 32362306a36Sopenharmony_ci tsf = ath9k_hw_gettsf64(sc->sc_ah); 32462306a36Sopenharmony_ci tsf += TU_TO_USEC(sc->sc_ah->config.sw_beacon_response_time); 32562306a36Sopenharmony_ci tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF); 32662306a36Sopenharmony_ci slot = (tsftu % (intval * ATH_BCBUF)) / intval; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci ath_dbg(common, BEACON, "slot: %d tsf: %llu tsftu: %u\n", 32962306a36Sopenharmony_ci slot, tsf, tsftu / ATH_BCBUF); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci return slot; 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic void ath9k_set_tsfadjust(struct ath_softc *sc, 33562306a36Sopenharmony_ci struct ath_beacon_config *cur_conf) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 33862306a36Sopenharmony_ci s64 tsfadjust; 33962306a36Sopenharmony_ci int slot; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci for (slot = 0; slot < ATH_BCBUF; slot++) { 34262306a36Sopenharmony_ci struct ath_vif *avp; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (!sc->beacon.bslot[slot]) 34562306a36Sopenharmony_ci continue; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci avp = (void *)sc->beacon.bslot[slot]->drv_priv; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* tsf_adjust is added to the TSF value. We send out the 35062306a36Sopenharmony_ci * beacon late, so need to adjust the TSF starting point to be 35162306a36Sopenharmony_ci * later in time (i.e. the theoretical first beacon has a TSF 35262306a36Sopenharmony_ci * of 0 after correction). 35362306a36Sopenharmony_ci */ 35462306a36Sopenharmony_ci tsfadjust = cur_conf->beacon_interval * avp->av_bslot; 35562306a36Sopenharmony_ci tsfadjust = -TU_TO_USEC(tsfadjust) / ATH_BCBUF; 35662306a36Sopenharmony_ci avp->tsf_adjust = cpu_to_le64(tsfadjust); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci ath_dbg(common, CONFIG, "tsfadjust is: %lld for bslot: %d\n", 35962306a36Sopenharmony_ci (signed long long)tsfadjust, avp->av_bslot); 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cibool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci if (!vif || !vif->bss_conf.csa_active) 36662306a36Sopenharmony_ci return false; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if (!ieee80211_beacon_cntdwn_is_complete(vif)) 36962306a36Sopenharmony_ci return false; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci ieee80211_csa_finish(vif); 37262306a36Sopenharmony_ci return true; 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic void ath9k_csa_update_vif(void *data, u8 *mac, struct ieee80211_vif *vif) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci struct ath_softc *sc = data; 37862306a36Sopenharmony_ci ath9k_csa_is_finished(sc, vif); 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_civoid ath9k_csa_update(struct ath_softc *sc) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic(sc->hw, 38462306a36Sopenharmony_ci IEEE80211_IFACE_ITER_NORMAL, 38562306a36Sopenharmony_ci ath9k_csa_update_vif, sc); 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_civoid ath9k_beacon_tasklet(struct tasklet_struct *t) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci struct ath_softc *sc = from_tasklet(sc, t, bcon_tasklet); 39162306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 39262306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 39362306a36Sopenharmony_ci struct ath_buf *bf = NULL; 39462306a36Sopenharmony_ci struct ieee80211_vif *vif; 39562306a36Sopenharmony_ci bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); 39662306a36Sopenharmony_ci int slot; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) { 39962306a36Sopenharmony_ci ath_dbg(common, RESET, 40062306a36Sopenharmony_ci "reset work is pending, skip beaconing now\n"); 40162306a36Sopenharmony_ci return; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci /* 40562306a36Sopenharmony_ci * Check if the previous beacon has gone out. If 40662306a36Sopenharmony_ci * not don't try to post another, skip this period 40762306a36Sopenharmony_ci * and wait for the next. Missed beacons indicate 40862306a36Sopenharmony_ci * a problem and should not occur. If we miss too 40962306a36Sopenharmony_ci * many consecutive beacons reset the device. 41062306a36Sopenharmony_ci */ 41162306a36Sopenharmony_ci if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) { 41262306a36Sopenharmony_ci sc->beacon.bmisscnt++; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci ath9k_hw_check_nav(ah); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /* 41762306a36Sopenharmony_ci * If the previous beacon has not been transmitted 41862306a36Sopenharmony_ci * and a MAC/BB hang has been identified, return 41962306a36Sopenharmony_ci * here because a chip reset would have been 42062306a36Sopenharmony_ci * initiated. 42162306a36Sopenharmony_ci */ 42262306a36Sopenharmony_ci if (!ath_hw_check(sc)) 42362306a36Sopenharmony_ci return; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) { 42662306a36Sopenharmony_ci ath_dbg(common, BSTUCK, 42762306a36Sopenharmony_ci "missed %u consecutive beacons\n", 42862306a36Sopenharmony_ci sc->beacon.bmisscnt); 42962306a36Sopenharmony_ci ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq); 43062306a36Sopenharmony_ci if (sc->beacon.bmisscnt > 3) 43162306a36Sopenharmony_ci ath9k_hw_bstuck_nfcal(ah); 43262306a36Sopenharmony_ci } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { 43362306a36Sopenharmony_ci ath_dbg(common, BSTUCK, "beacon is officially stuck\n"); 43462306a36Sopenharmony_ci sc->beacon.bmisscnt = 0; 43562306a36Sopenharmony_ci ath9k_queue_reset(sc, RESET_TYPE_BEACON_STUCK); 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci return; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci slot = ath9k_beacon_choose_slot(sc); 44262306a36Sopenharmony_ci vif = sc->beacon.bslot[slot]; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci /* EDMA devices check that in the tx completion function. */ 44562306a36Sopenharmony_ci if (!edma) { 44662306a36Sopenharmony_ci if (ath9k_is_chanctx_enabled()) { 44762306a36Sopenharmony_ci ath_chanctx_beacon_sent_ev(sc, 44862306a36Sopenharmony_ci ATH_CHANCTX_EVENT_BEACON_SENT); 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (ath9k_csa_is_finished(sc, vif)) 45262306a36Sopenharmony_ci return; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (!vif || !vif->bss_conf.enable_beacon) 45662306a36Sopenharmony_ci return; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (ath9k_is_chanctx_enabled()) { 45962306a36Sopenharmony_ci ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_BEACON_PREPARE); 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci bf = ath9k_beacon_generate(sc->hw, vif); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci if (sc->beacon.bmisscnt != 0) { 46562306a36Sopenharmony_ci ath_dbg(common, BSTUCK, "resume beacon xmit after %u misses\n", 46662306a36Sopenharmony_ci sc->beacon.bmisscnt); 46762306a36Sopenharmony_ci sc->beacon.bmisscnt = 0; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci /* 47162306a36Sopenharmony_ci * Handle slot time change when a non-ERP station joins/leaves 47262306a36Sopenharmony_ci * an 11g network. The 802.11 layer notifies us via callback, 47362306a36Sopenharmony_ci * we mark updateslot, then wait one beacon before effecting 47462306a36Sopenharmony_ci * the change. This gives associated stations at least one 47562306a36Sopenharmony_ci * beacon interval to note the state change. 47662306a36Sopenharmony_ci * 47762306a36Sopenharmony_ci * NB: The slot time change state machine is clocked according 47862306a36Sopenharmony_ci * to whether we are bursting or staggering beacons. We 47962306a36Sopenharmony_ci * recognize the request to update and record the current 48062306a36Sopenharmony_ci * slot then don't transition until that slot is reached 48162306a36Sopenharmony_ci * again. If we miss a beacon for that slot then we'll be 48262306a36Sopenharmony_ci * slow to transition but we'll be sure at least one beacon 48362306a36Sopenharmony_ci * interval has passed. When bursting slot is always left 48462306a36Sopenharmony_ci * set to ATH_BCBUF so this check is a noop. 48562306a36Sopenharmony_ci */ 48662306a36Sopenharmony_ci if (sc->beacon.updateslot == UPDATE) { 48762306a36Sopenharmony_ci sc->beacon.updateslot = COMMIT; 48862306a36Sopenharmony_ci sc->beacon.slotupdate = slot; 48962306a36Sopenharmony_ci } else if (sc->beacon.updateslot == COMMIT && 49062306a36Sopenharmony_ci sc->beacon.slotupdate == slot) { 49162306a36Sopenharmony_ci ah->slottime = sc->beacon.slottime; 49262306a36Sopenharmony_ci ath9k_hw_init_global_settings(ah); 49362306a36Sopenharmony_ci sc->beacon.updateslot = OK; 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci if (bf) { 49762306a36Sopenharmony_ci ath9k_reset_beacon_status(sc); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci ath_dbg(common, BEACON, 50062306a36Sopenharmony_ci "Transmitting beacon for slot: %d\n", slot); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* NB: cabq traffic should already be queued and primed */ 50362306a36Sopenharmony_ci ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci if (!edma) 50662306a36Sopenharmony_ci ath9k_hw_txstart(ah, sc->beacon.beaconq); 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci/* 51162306a36Sopenharmony_ci * Both nexttbtt and intval have to be in usecs. 51262306a36Sopenharmony_ci */ 51362306a36Sopenharmony_cistatic void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, 51462306a36Sopenharmony_ci u32 intval) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci ath9k_hw_disable_interrupts(ah); 51962306a36Sopenharmony_ci ath9k_beaconq_config(sc); 52062306a36Sopenharmony_ci ath9k_hw_beaconinit(ah, nexttbtt, intval); 52162306a36Sopenharmony_ci ah->imask |= ATH9K_INT_SWBA; 52262306a36Sopenharmony_ci sc->beacon.bmisscnt = 0; 52362306a36Sopenharmony_ci ath9k_hw_set_interrupts(ah); 52462306a36Sopenharmony_ci ath9k_hw_enable_interrupts(ah); 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic void ath9k_beacon_stop(struct ath_softc *sc) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci ath9k_hw_disable_interrupts(sc->sc_ah); 53062306a36Sopenharmony_ci sc->sc_ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); 53162306a36Sopenharmony_ci sc->beacon.bmisscnt = 0; 53262306a36Sopenharmony_ci ath9k_hw_set_interrupts(sc->sc_ah); 53362306a36Sopenharmony_ci ath9k_hw_enable_interrupts(sc->sc_ah); 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci/* 53762306a36Sopenharmony_ci * For multi-bss ap support beacons are either staggered evenly over N slots or 53862306a36Sopenharmony_ci * burst together. For the former arrange for the SWBA to be delivered for each 53962306a36Sopenharmony_ci * slot. Slots that are not occupied will generate nothing. 54062306a36Sopenharmony_ci */ 54162306a36Sopenharmony_cistatic void ath9k_beacon_config_ap(struct ath_softc *sc, 54262306a36Sopenharmony_ci struct ath_beacon_config *conf) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci ath9k_cmn_beacon_config_ap(ah, conf, ATH_BCBUF); 54762306a36Sopenharmony_ci ath9k_beacon_init(sc, conf->nexttbtt, conf->intval); 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_cistatic void ath9k_beacon_config_sta(struct ath_hw *ah, 55162306a36Sopenharmony_ci struct ath_beacon_config *conf) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci struct ath9k_beacon_state bs; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if (ath9k_cmn_beacon_config_sta(ah, conf, &bs) == -EPERM) 55662306a36Sopenharmony_ci return; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci ath9k_hw_disable_interrupts(ah); 55962306a36Sopenharmony_ci ath9k_hw_set_sta_beacon_timers(ah, &bs); 56062306a36Sopenharmony_ci ah->imask |= ATH9K_INT_BMISS; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci ath9k_hw_set_interrupts(ah); 56362306a36Sopenharmony_ci ath9k_hw_enable_interrupts(ah); 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_cistatic void ath9k_beacon_config_adhoc(struct ath_softc *sc, 56762306a36Sopenharmony_ci struct ath_beacon_config *conf) 56862306a36Sopenharmony_ci{ 56962306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 57062306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci ath9k_reset_beacon_status(sc); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci ath9k_cmn_beacon_config_adhoc(ah, conf); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci ath9k_beacon_init(sc, conf->nexttbtt, conf->intval); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci /* 57962306a36Sopenharmony_ci * Set the global 'beacon has been configured' flag for the 58062306a36Sopenharmony_ci * joiner case in IBSS mode. 58162306a36Sopenharmony_ci */ 58262306a36Sopenharmony_ci if (!conf->ibss_creator && conf->enable_beacon) 58362306a36Sopenharmony_ci set_bit(ATH_OP_BEACONS, &common->op_flags); 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic void ath9k_cache_beacon_config(struct ath_softc *sc, 58762306a36Sopenharmony_ci struct ath_chanctx *ctx, 58862306a36Sopenharmony_ci struct ieee80211_vif *vif) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; 59162306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 59262306a36Sopenharmony_ci struct ath_beacon_config *cur_conf = &ctx->beacon; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci ath_dbg(common, BEACON, 59562306a36Sopenharmony_ci "Caching beacon data for BSS: %pM\n", bss_conf->bssid); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci cur_conf->beacon_interval = bss_conf->beacon_int; 59862306a36Sopenharmony_ci cur_conf->dtim_period = bss_conf->dtim_period; 59962306a36Sopenharmony_ci cur_conf->dtim_count = 1; 60062306a36Sopenharmony_ci cur_conf->ibss_creator = vif->cfg.ibss_creator; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci /* 60362306a36Sopenharmony_ci * It looks like mac80211 may end up using beacon interval of zero in 60462306a36Sopenharmony_ci * some cases (at least for mesh point). Avoid getting into an 60562306a36Sopenharmony_ci * infinite loop by using a bit safer value instead. To be safe, 60662306a36Sopenharmony_ci * do sanity check on beacon interval for all operating modes. 60762306a36Sopenharmony_ci */ 60862306a36Sopenharmony_ci if (cur_conf->beacon_interval == 0) 60962306a36Sopenharmony_ci cur_conf->beacon_interval = 100; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci cur_conf->bmiss_timeout = 61262306a36Sopenharmony_ci ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci /* 61562306a36Sopenharmony_ci * We don't parse dtim period from mac80211 during the driver 61662306a36Sopenharmony_ci * initialization as it breaks association with hidden-ssid 61762306a36Sopenharmony_ci * AP and it causes latency in roaming 61862306a36Sopenharmony_ci */ 61962306a36Sopenharmony_ci if (cur_conf->dtim_period == 0) 62062306a36Sopenharmony_ci cur_conf->dtim_period = 1; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci ath9k_set_tsfadjust(sc, cur_conf); 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_civoid ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif, 62662306a36Sopenharmony_ci bool beacons) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 62962306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 63062306a36Sopenharmony_ci struct ath_vif *avp; 63162306a36Sopenharmony_ci struct ath_chanctx *ctx; 63262306a36Sopenharmony_ci struct ath_beacon_config *cur_conf; 63362306a36Sopenharmony_ci unsigned long flags; 63462306a36Sopenharmony_ci bool enabled; 63562306a36Sopenharmony_ci bool skip_beacon = false; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci if (!beacons) { 63862306a36Sopenharmony_ci clear_bit(ATH_OP_BEACONS, &common->op_flags); 63962306a36Sopenharmony_ci ath9k_beacon_stop(sc); 64062306a36Sopenharmony_ci return; 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (WARN_ON(!main_vif)) 64462306a36Sopenharmony_ci return; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci avp = (void *)main_vif->drv_priv; 64762306a36Sopenharmony_ci ctx = avp->chanctx; 64862306a36Sopenharmony_ci cur_conf = &ctx->beacon; 64962306a36Sopenharmony_ci enabled = cur_conf->enable_beacon; 65062306a36Sopenharmony_ci cur_conf->enable_beacon = beacons; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { 65362306a36Sopenharmony_ci ath9k_cache_beacon_config(sc, ctx, main_vif); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci ath9k_set_beacon(sc); 65662306a36Sopenharmony_ci set_bit(ATH_OP_BEACONS, &common->op_flags); 65762306a36Sopenharmony_ci return; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci /* Update the beacon configuration. */ 66162306a36Sopenharmony_ci ath9k_cache_beacon_config(sc, ctx, main_vif); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* 66462306a36Sopenharmony_ci * Configure the HW beacon registers only when we have a valid 66562306a36Sopenharmony_ci * beacon interval. 66662306a36Sopenharmony_ci */ 66762306a36Sopenharmony_ci if (cur_conf->beacon_interval) { 66862306a36Sopenharmony_ci /* Special case to sync the TSF when joining an existing IBSS. 66962306a36Sopenharmony_ci * This is only done if no AP interface is active. 67062306a36Sopenharmony_ci * Note that mac80211 always resets the TSF when creating a new 67162306a36Sopenharmony_ci * IBSS interface. 67262306a36Sopenharmony_ci */ 67362306a36Sopenharmony_ci if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC && 67462306a36Sopenharmony_ci !enabled && beacons && !main_vif->cfg.ibss_creator) { 67562306a36Sopenharmony_ci spin_lock_irqsave(&sc->sc_pm_lock, flags); 67662306a36Sopenharmony_ci sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; 67762306a36Sopenharmony_ci spin_unlock_irqrestore(&sc->sc_pm_lock, flags); 67862306a36Sopenharmony_ci skip_beacon = true; 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci /* 68262306a36Sopenharmony_ci * Do not set the ATH_OP_BEACONS flag for IBSS joiner mode 68362306a36Sopenharmony_ci * here, it is done in ath9k_beacon_config_adhoc(). 68462306a36Sopenharmony_ci */ 68562306a36Sopenharmony_ci if (beacons && !skip_beacon) { 68662306a36Sopenharmony_ci set_bit(ATH_OP_BEACONS, &common->op_flags); 68762306a36Sopenharmony_ci ath9k_set_beacon(sc); 68862306a36Sopenharmony_ci } else { 68962306a36Sopenharmony_ci clear_bit(ATH_OP_BEACONS, &common->op_flags); 69062306a36Sopenharmony_ci ath9k_beacon_stop(sc); 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci } else { 69362306a36Sopenharmony_ci clear_bit(ATH_OP_BEACONS, &common->op_flags); 69462306a36Sopenharmony_ci ath9k_beacon_stop(sc); 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_civoid ath9k_set_beacon(struct ath_softc *sc) 69962306a36Sopenharmony_ci{ 70062306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 70162306a36Sopenharmony_ci struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci switch (sc->sc_ah->opmode) { 70462306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 70562306a36Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 70662306a36Sopenharmony_ci ath9k_beacon_config_ap(sc, cur_conf); 70762306a36Sopenharmony_ci break; 70862306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 70962306a36Sopenharmony_ci ath9k_beacon_config_adhoc(sc, cur_conf); 71062306a36Sopenharmony_ci break; 71162306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 71262306a36Sopenharmony_ci ath9k_beacon_config_sta(sc->sc_ah, cur_conf); 71362306a36Sopenharmony_ci break; 71462306a36Sopenharmony_ci default: 71562306a36Sopenharmony_ci ath_dbg(common, CONFIG, "Unsupported beaconing mode\n"); 71662306a36Sopenharmony_ci return; 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci} 719