beacon.c revision 1a20034a73a40b8056731f9db0c535cec2961eb7
1f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez/* 2cee075a24eec64f1f5b2b3b14753b2d4b8ecce55Sujith * Copyright (c) 2008-2009 Atheros Communications Inc. 3f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * 4f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * Permission to use, copy, modify, and/or distribute this software for any 5f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * purpose with or without fee is hereby granted, provided that the above 6f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * copyright notice and this permission notice appear in all copies. 7f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * 8f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez */ 16f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 17394cf0a1ca02e7998c8d01975b60a3cdc121e7d8Sujith#include "ath9k.h" 18f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 195379c8a26686e12058e23322615df68f9123bccdSujith#define FUDGE 2 205379c8a26686e12058e23322615df68f9123bccdSujith 21f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez/* 22f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * This function will modify certain transmit queue properties depending on 23f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * the operating mode of the station (AP or AdHoc). Parameters are AIFS 24f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * settings and channel width min/max 25f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez*/ 2694db29368a658b13a088db87c7b0bf59b1a7492dVivek Natarajanint ath_beaconq_config(struct ath_softc *sc) 27f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez{ 28cbe61d8a41210600bc76b212edcd4dc0f55c014fSujith struct ath_hw *ah = sc->sc_ah; 29c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez struct ath_common *common = ath9k_hw_common(ah); 3094db29368a658b13a088db87c7b0bf59b1a7492dVivek Natarajan struct ath9k_tx_queue_info qi, qi_be; 3194db29368a658b13a088db87c7b0bf59b1a7492dVivek Natarajan int qnum; 32f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 33b77f483fcf0579de28873828897f53371a33a0eaSujith ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi); 342660b81a378ab227b78c4cc618453fa7e19a7c7bSujith if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { 35f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez /* Always burst out beacon and CAB traffic. */ 36f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez qi.tqi_aifs = 1; 37f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez qi.tqi_cwmin = 0; 38f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez qi.tqi_cwmax = 0; 39f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } else { 40f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez /* Adhoc mode; important thing is to use 2x cwmin. */ 4194db29368a658b13a088db87c7b0bf59b1a7492dVivek Natarajan qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, 4294db29368a658b13a088db87c7b0bf59b1a7492dVivek Natarajan ATH9K_WME_AC_BE); 4394db29368a658b13a088db87c7b0bf59b1a7492dVivek Natarajan ath9k_hw_get_txq_props(ah, qnum, &qi_be); 4494db29368a658b13a088db87c7b0bf59b1a7492dVivek Natarajan qi.tqi_aifs = qi_be.tqi_aifs; 4594db29368a658b13a088db87c7b0bf59b1a7492dVivek Natarajan qi.tqi_cwmin = 4*qi_be.tqi_cwmin; 4694db29368a658b13a088db87c7b0bf59b1a7492dVivek Natarajan qi.tqi_cwmax = qi_be.tqi_cwmax; 47f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 48f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 49b77f483fcf0579de28873828897f53371a33a0eaSujith if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) { 50c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez ath_print(common, ATH_DBG_FATAL, 51c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez "Unable to update h/w beacon queue parameters\n"); 52f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez return 0; 53f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } else { 549fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith ath9k_hw_resettxqueue(ah, sc->beacon.beaconq); 55f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez return 1; 56f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 57f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez} 58f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 59f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez/* 60f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * Associates the beacon frame buffer with a transmit descriptor. Will set 61f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * up all required antenna switch parameters, rate codes, and channel flags. 62f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * Beacons are always sent out at the lowest rate, and are not retried. 63f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez*/ 649fc9ab0a6929c9f137747df0ecf294e9582607f9Sujithstatic void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, 659fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith struct ath_buf *bf) 66f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez{ 67a22be22ab8fe571cce88d0d30b49f297a563c4a7Sujith struct sk_buff *skb = bf->bf_mpdu; 68cbe61d8a41210600bc76b212edcd4dc0f55c014fSujith struct ath_hw *ah = sc->sc_ah; 6943c2761364b77cd7fd20eb1f14cfee4cd1462abdLuis R. Rodriguez struct ath_common *common = ath9k_hw_common(ah); 70f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez struct ath_desc *ds; 71980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith struct ath9k_11n_rate_series series[4]; 729fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith int flags, antenna, ctsrate = 0, ctsduration = 0; 73545750d36fa78203e28acefb4bab61ebb7c4d197Felix Fietkau struct ieee80211_supported_band *sband; 74545750d36fa78203e28acefb4bab61ebb7c4d197Felix Fietkau u8 rate = 0; 75f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 76f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez ds = bf->bf_desc; 77f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez flags = ATH9K_TXDESC_NOACK; 78f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 799cb5412b0760981d43ac3e612992c90cea690e72Pat Erley if (((sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || 809cb5412b0760981d43ac3e612992c90cea690e72Pat Erley (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) && 812660b81a378ab227b78c4cc618453fa7e19a7c7bSujith (ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) { 82f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez ds->ds_link = bf->bf_daddr; /* self-linked */ 83f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez flags |= ATH9K_TXDESC_VEOL; 84f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez /* Let hardware handle antenna switching. */ 85f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez antenna = 0; 86f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } else { 87f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez ds->ds_link = 0; 88f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez /* 89f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * Switch antenna every beacon. 909fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith * Should only switch every beacon period, not for every SWBA 919fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith * XXX assumes two antennae 92f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez */ 9317d7904de85125c62c7258d7cb21207f26d04048Sujith antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1); 94f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 95f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 96f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez ds->ds_data = bf->bf_buf_addr; 97f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 98545750d36fa78203e28acefb4bab61ebb7c4d197Felix Fietkau sband = &sc->sbands[common->hw->conf.channel->band]; 99545750d36fa78203e28acefb4bab61ebb7c4d197Felix Fietkau rate = sband->bitrates[0].hw_value; 100672840ac04f79f499b60b9f0eb41799c837db4ebSujith if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) 101545750d36fa78203e28acefb4bab61ebb7c4d197Felix Fietkau rate |= sband->bitrates[0].hw_value_short; 1029fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith 1039fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith ath9k_hw_set11n_txdesc(ah, ds, skb->len + FCS_LEN, 1049fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith ATH9K_PKT_TYPE_BEACON, 1059fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith MAX_RATE_POWER, 1069fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith ATH9K_TXKEYIX_INVALID, 1079fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith ATH9K_KEY_TYPE_CLEAR, 1089fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith flags); 109f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 110f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez /* NB: beacon's BufLen must be a multiple of 4 bytes */ 1119fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith ath9k_hw_filltxdesc(ah, ds, roundup(skb->len, 4), 1129fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith true, true, ds); 113f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 1140345f37be64905846a1ef38378061d4c2730242eLuis R. Rodriguez memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); 115f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez series[0].Tries = 1; 116f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez series[0].Rate = rate; 11743c2761364b77cd7fd20eb1f14cfee4cd1462abdLuis R. Rodriguez series[0].ChSel = common->tx_chainmask; 118f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0; 1199fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, ctsrate, ctsduration, 1209fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith series, 4, 0); 121f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez} 122f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 123c52f33d05e5f8d59f02722fbc308f5f391575ca5Jouni Malinenstatic struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, 1242c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinen struct ieee80211_vif *vif) 125f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez{ 126c52f33d05e5f8d59f02722fbc308f5f391575ca5Jouni Malinen struct ath_wiphy *aphy = hw->priv; 127c52f33d05e5f8d59f02722fbc308f5f391575ca5Jouni Malinen struct ath_softc *sc = aphy->sc; 128c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez struct ath_common *common = ath9k_hw_common(sc->sc_ah); 129f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez struct ath_buf *bf; 13017d7904de85125c62c7258d7cb21207f26d04048Sujith struct ath_vif *avp; 131f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez struct sk_buff *skb; 132f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez struct ath_txq *cabq; 133147583c057c43095925b5f331fe304f2d5b997baJouni Malinen struct ieee80211_tx_info *info; 134980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith int cabq_depth; 135980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith 136f0ed85c6c7960b26666db013e02e748b56eef98aJouni Malinen if (aphy->state != ATH_WIPHY_ACTIVE) 137f0ed85c6c7960b26666db013e02e748b56eef98aJouni Malinen return NULL; 138f0ed85c6c7960b26666db013e02e748b56eef98aJouni Malinen 1395640b08ef7e88b606c740e746cb77bc97d78508eSujith avp = (void *)vif->drv_priv; 140b77f483fcf0579de28873828897f53371a33a0eaSujith cabq = sc->beacon.cabq; 141f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 142d8baa9392666d1c50ef42e9f6fbbb0cf536327b9Sujith if (avp->av_bcbuf == NULL) 143f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez return NULL; 144980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith 1459fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith /* Release the old beacon first */ 1469fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith 147f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez bf = avp->av_bcbuf; 148a22be22ab8fe571cce88d0d30b49f297a563c4a7Sujith skb = bf->bf_mpdu; 149a8fff50e4d6aad520b261b3c32e2c67a7dfb7228Jouni Malinen if (skb) { 1507da3c55ce849e17fd9017c7bf770a03fa083d95bGabor Juhos dma_unmap_single(sc->dev, bf->bf_dmacontext, 1519fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith skb->len, DMA_TO_DEVICE); 1523fbb9d95a96c6a03f2e484bb1665d089412640dcJouni Malinen dev_kfree_skb_any(skb); 153a8fff50e4d6aad520b261b3c32e2c67a7dfb7228Jouni Malinen } 154f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 1559fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith /* Get a new beacon from mac80211 */ 1569fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith 157c52f33d05e5f8d59f02722fbc308f5f391575ca5Jouni Malinen skb = ieee80211_beacon_get(hw, vif); 158a8fff50e4d6aad520b261b3c32e2c67a7dfb7228Jouni Malinen bf->bf_mpdu = skb; 159a8fff50e4d6aad520b261b3c32e2c67a7dfb7228Jouni Malinen if (skb == NULL) 160a8fff50e4d6aad520b261b3c32e2c67a7dfb7228Jouni Malinen return NULL; 1614ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp = 1624ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen avp->tsf_adjust; 163980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith 164147583c057c43095925b5f331fe304f2d5b997baJouni Malinen info = IEEE80211_SKB_CB(skb); 165147583c057c43095925b5f331fe304f2d5b997baJouni Malinen if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { 166147583c057c43095925b5f331fe304f2d5b997baJouni Malinen /* 167147583c057c43095925b5f331fe304f2d5b997baJouni Malinen * TODO: make sure the seq# gets assigned properly (vs. other 168147583c057c43095925b5f331fe304f2d5b997baJouni Malinen * TX frames) 169147583c057c43095925b5f331fe304f2d5b997baJouni Malinen */ 170980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 171b77f483fcf0579de28873828897f53371a33a0eaSujith sc->tx.seq_no += 0x10; 172147583c057c43095925b5f331fe304f2d5b997baJouni Malinen hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); 173b77f483fcf0579de28873828897f53371a33a0eaSujith hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); 174147583c057c43095925b5f331fe304f2d5b997baJouni Malinen } 175980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith 176a8fff50e4d6aad520b261b3c32e2c67a7dfb7228Jouni Malinen bf->bf_buf_addr = bf->bf_dmacontext = 1777da3c55ce849e17fd9017c7bf770a03fa083d95bGabor Juhos dma_map_single(sc->dev, skb->data, 1789fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith skb->len, DMA_TO_DEVICE); 1797da3c55ce849e17fd9017c7bf770a03fa083d95bGabor Juhos if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { 180f8316df10c4e3bec5b4c3a5a8e026c577640c3a6Luis R. Rodriguez dev_kfree_skb_any(skb); 181f8316df10c4e3bec5b4c3a5a8e026c577640c3a6Luis R. Rodriguez bf->bf_mpdu = NULL; 182c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez ath_print(common, ATH_DBG_FATAL, 183c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez "dma_mapping_error on beaconing\n"); 184f8316df10c4e3bec5b4c3a5a8e026c577640c3a6Luis R. Rodriguez return NULL; 185f8316df10c4e3bec5b4c3a5a8e026c577640c3a6Luis R. Rodriguez } 186f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 187c52f33d05e5f8d59f02722fbc308f5f391575ca5Jouni Malinen skb = ieee80211_get_buffered_bc(hw, vif); 188f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 189f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez /* 190f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * if the CABQ traffic from previous DTIM is pending and the current 191f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * beacon is also a DTIM. 19217d7904de85125c62c7258d7cb21207f26d04048Sujith * 1) if there is only one vif let the cab traffic continue. 19317d7904de85125c62c7258d7cb21207f26d04048Sujith * 2) if there are more than one vif and we are using staggered 194f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * beacons, then drain the cabq by dropping all the frames in 19517d7904de85125c62c7258d7cb21207f26d04048Sujith * the cabq so that the current vifs cab traffic can be scheduled. 196f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez */ 197f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez spin_lock_bh(&cabq->axq_lock); 198f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez cabq_depth = cabq->axq_depth; 199f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez spin_unlock_bh(&cabq->axq_lock); 200f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 201e022edbd2bfb5f9a7ddf1cca43544f7b54c6fe02Jouni Malinen if (skb && cabq_depth) { 20217d7904de85125c62c7258d7cb21207f26d04048Sujith if (sc->nvifs > 1) { 203c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez ath_print(common, ATH_DBG_BEACON, 204c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez "Flushing previous cabq traffic\n"); 2059fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith ath_draintxq(sc, cabq, false); 206f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 207f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 208f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 209f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez ath_beacon_setup(sc, avp, bf); 210f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 211e022edbd2bfb5f9a7ddf1cca43544f7b54c6fe02Jouni Malinen while (skb) { 212c52f33d05e5f8d59f02722fbc308f5f391575ca5Jouni Malinen ath_tx_cabq(hw, skb); 213c52f33d05e5f8d59f02722fbc308f5f391575ca5Jouni Malinen skb = ieee80211_get_buffered_bc(hw, vif); 214e022edbd2bfb5f9a7ddf1cca43544f7b54c6fe02Jouni Malinen } 215f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 216f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez return bf; 217f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez} 218f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 219f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez/* 220f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * Startup beacon transmission for adhoc mode when they are sent entirely 221f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * by the hardware using the self-linked descriptor + veol trick. 222f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez*/ 2232c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinenstatic void ath_beacon_start_adhoc(struct ath_softc *sc, 2242c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinen struct ieee80211_vif *vif) 225f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez{ 226cbe61d8a41210600bc76b212edcd4dc0f55c014fSujith struct ath_hw *ah = sc->sc_ah; 227c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez struct ath_common *common = ath9k_hw_common(ah); 228f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez struct ath_buf *bf; 22917d7904de85125c62c7258d7cb21207f26d04048Sujith struct ath_vif *avp; 230f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez struct sk_buff *skb; 231f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 2325640b08ef7e88b606c740e746cb77bc97d78508eSujith avp = (void *)vif->drv_priv; 233f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 2349fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith if (avp->av_bcbuf == NULL) 235f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez return; 2369fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith 237f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez bf = avp->av_bcbuf; 238a22be22ab8fe571cce88d0d30b49f297a563c4a7Sujith skb = bf->bf_mpdu; 239f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 240f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez ath_beacon_setup(sc, avp, bf); 241f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 242f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez /* NB: caller is known to have already stopped tx dma */ 243b77f483fcf0579de28873828897f53371a33a0eaSujith ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr); 244b77f483fcf0579de28873828897f53371a33a0eaSujith ath9k_hw_txstart(ah, sc->beacon.beaconq); 245c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez ath_print(common, ATH_DBG_BEACON, "TXDP%u = %llx (%p)\n", 246c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc); 247f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez} 248f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 249c52f33d05e5f8d59f02722fbc308f5f391575ca5Jouni Malinenint ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) 250f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez{ 251c52f33d05e5f8d59f02722fbc308f5f391575ca5Jouni Malinen struct ath_softc *sc = aphy->sc; 252c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez struct ath_common *common = ath9k_hw_common(sc->sc_ah); 25317d7904de85125c62c7258d7cb21207f26d04048Sujith struct ath_vif *avp; 254f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez struct ath_buf *bf; 255f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez struct sk_buff *skb; 256459f5f90f1bd959ced04761406415b178b315177Sujith __le64 tstamp; 257f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 2585640b08ef7e88b606c740e746cb77bc97d78508eSujith avp = (void *)vif->drv_priv; 259f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 260f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez /* Allocate a beacon descriptor if we haven't done so. */ 261f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez if (!avp->av_bcbuf) { 262980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith /* Allocate beacon state for hostap/ibss. We know 263980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith * a buffer is available. */ 264b77f483fcf0579de28873828897f53371a33a0eaSujith avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf, 265980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith struct ath_buf, list); 266f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez list_del(&avp->av_bcbuf->list); 267f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 2682660b81a378ab227b78c4cc618453fa7e19a7c7bSujith if (sc->sc_ah->opmode == NL80211_IFTYPE_AP || 2692660b81a378ab227b78c4cc618453fa7e19a7c7bSujith !(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) { 270f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez int slot; 271f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez /* 27217d7904de85125c62c7258d7cb21207f26d04048Sujith * Assign the vif to a beacon xmit slot. As 273f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * above, this cannot fail to find one. 274f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez */ 275f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez avp->av_bslot = 0; 276f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez for (slot = 0; slot < ATH_BCBUF; slot++) 2772c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinen if (sc->beacon.bslot[slot] == NULL) { 278f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez /* 279f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * XXX hack, space out slots to better 280f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * deal with misses 281f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez */ 282f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez if (slot+1 < ATH_BCBUF && 2832c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinen sc->beacon.bslot[slot+1] == NULL) { 284f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez avp->av_bslot = slot+1; 285f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez break; 286f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 287f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez avp->av_bslot = slot; 288f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez /* NB: keep looking for a double slot */ 289f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 2902c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinen BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL); 2912c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinen sc->beacon.bslot[avp->av_bslot] = vif; 292c52f33d05e5f8d59f02722fbc308f5f391575ca5Jouni Malinen sc->beacon.bslot_aphy[avp->av_bslot] = aphy; 29317d7904de85125c62c7258d7cb21207f26d04048Sujith sc->nbcnvifs++; 294f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 295f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 296f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 2979fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith /* release the previous beacon frame, if it already exists. */ 298f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez bf = avp->av_bcbuf; 299f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez if (bf->bf_mpdu != NULL) { 300a22be22ab8fe571cce88d0d30b49f297a563c4a7Sujith skb = bf->bf_mpdu; 3017da3c55ce849e17fd9017c7bf770a03fa083d95bGabor Juhos dma_unmap_single(sc->dev, bf->bf_dmacontext, 3029fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith skb->len, DMA_TO_DEVICE); 303f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez dev_kfree_skb_any(skb); 304f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez bf->bf_mpdu = NULL; 305f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 306f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 3079fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith /* NB: the beacon data buffer must be 32-bit aligned. */ 3085640b08ef7e88b606c740e746cb77bc97d78508eSujith skb = ieee80211_beacon_get(sc->hw, vif); 309f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez if (skb == NULL) { 310c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez ath_print(common, ATH_DBG_BEACON, "cannot get skb\n"); 311f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez return -ENOMEM; 312f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 313f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 314459f5f90f1bd959ced04761406415b178b315177Sujith tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; 315b77f483fcf0579de28873828897f53371a33a0eaSujith sc->beacon.bc_tstamp = le64_to_cpu(tstamp); 3164ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen /* Calculate a TSF adjustment factor required for staggered beacons. */ 317f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez if (avp->av_bslot > 0) { 318f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez u64 tsfadjust; 319f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez int intval; 320f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 32157c4d7b4c4986037be51476b8e3025d5ba18d8b8Johannes Berg intval = sc->beacon_interval ? : ATH_DEFAULT_BINTVAL; 322f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 323f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez /* 3244ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen * Calculate the TSF offset for this beacon slot, i.e., the 3254ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen * number of usecs that need to be added to the timestamp field 3264ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen * in Beacon and Probe Response frames. Beacon slot 0 is 3274ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen * processed at the correct offset, so it does not require TSF 3284ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen * adjustment. Other slots are adjusted to get the timestamp 3294ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen * close to the TBTT for the BSS. 330f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez */ 3314ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen tsfadjust = intval * avp->av_bslot / ATH_BCBUF; 3324ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); 333f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 334c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez ath_print(common, ATH_DBG_BEACON, 335c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez "stagger beacons, bslot %d intval " 336c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez "%u tsfadjust %llu\n", 337c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez avp->av_bslot, intval, (unsigned long long)tsfadjust); 338f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 3394ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp = 3404ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen avp->tsf_adjust; 3414ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen } else 3424ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen avp->tsf_adjust = cpu_to_le64(0); 343f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 344f8316df10c4e3bec5b4c3a5a8e026c577640c3a6Luis R. Rodriguez bf->bf_mpdu = skb; 345a8fff50e4d6aad520b261b3c32e2c67a7dfb7228Jouni Malinen bf->bf_buf_addr = bf->bf_dmacontext = 3467da3c55ce849e17fd9017c7bf770a03fa083d95bGabor Juhos dma_map_single(sc->dev, skb->data, 3479fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith skb->len, DMA_TO_DEVICE); 3487da3c55ce849e17fd9017c7bf770a03fa083d95bGabor Juhos if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { 349f8316df10c4e3bec5b4c3a5a8e026c577640c3a6Luis R. Rodriguez dev_kfree_skb_any(skb); 350f8316df10c4e3bec5b4c3a5a8e026c577640c3a6Luis R. Rodriguez bf->bf_mpdu = NULL; 351c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez ath_print(common, ATH_DBG_FATAL, 352c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez "dma_mapping_error on beacon alloc\n"); 353f8316df10c4e3bec5b4c3a5a8e026c577640c3a6Luis R. Rodriguez return -ENOMEM; 354f8316df10c4e3bec5b4c3a5a8e026c577640c3a6Luis R. Rodriguez } 355f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 356f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez return 0; 357f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez} 358f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 35917d7904de85125c62c7258d7cb21207f26d04048Sujithvoid ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp) 360f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez{ 361f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez if (avp->av_bcbuf != NULL) { 362f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez struct ath_buf *bf; 363f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 364f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez if (avp->av_bslot != -1) { 3652c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinen sc->beacon.bslot[avp->av_bslot] = NULL; 366c52f33d05e5f8d59f02722fbc308f5f391575ca5Jouni Malinen sc->beacon.bslot_aphy[avp->av_bslot] = NULL; 36717d7904de85125c62c7258d7cb21207f26d04048Sujith sc->nbcnvifs--; 368f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 369f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 370f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez bf = avp->av_bcbuf; 371f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez if (bf->bf_mpdu != NULL) { 372a22be22ab8fe571cce88d0d30b49f297a563c4a7Sujith struct sk_buff *skb = bf->bf_mpdu; 3737da3c55ce849e17fd9017c7bf770a03fa083d95bGabor Juhos dma_unmap_single(sc->dev, bf->bf_dmacontext, 3749fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith skb->len, DMA_TO_DEVICE); 375f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez dev_kfree_skb_any(skb); 376f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez bf->bf_mpdu = NULL; 377f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 378b77f483fcf0579de28873828897f53371a33a0eaSujith list_add_tail(&bf->list, &sc->beacon.bbuf); 379f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 380f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez avp->av_bcbuf = NULL; 381f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 382f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez} 383f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 3849fc9ab0a6929c9f137747df0ecf294e9582607f9Sujithvoid ath_beacon_tasklet(unsigned long data) 385f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez{ 386f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez struct ath_softc *sc = (struct ath_softc *)data; 387cbe61d8a41210600bc76b212edcd4dc0f55c014fSujith struct ath_hw *ah = sc->sc_ah; 388c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez struct ath_common *common = ath9k_hw_common(ah); 389f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez struct ath_buf *bf = NULL; 3902c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinen struct ieee80211_vif *vif; 391c52f33d05e5f8d59f02722fbc308f5f391575ca5Jouni Malinen struct ath_wiphy *aphy; 3922c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinen int slot; 3939546aae0863c12a3d00b1ed5cbd316520733200bSujith u32 bfaddr, bc = 0, tsftu; 394f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez u64 tsf; 395f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez u16 intval; 396f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 397f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez /* 398f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * Check if the previous beacon has gone out. If 399f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * not don't try to post another, skip this period 400f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * and wait for the next. Missed beacons indicate 401f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * a problem and should not occur. If we miss too 402f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * many consecutive beacons reset the device. 403f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez */ 404b77f483fcf0579de28873828897f53371a33a0eaSujith if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) { 405b77f483fcf0579de28873828897f53371a33a0eaSujith sc->beacon.bmisscnt++; 4069546aae0863c12a3d00b1ed5cbd316520733200bSujith 407b77f483fcf0579de28873828897f53371a33a0eaSujith if (sc->beacon.bmisscnt < BSTUCK_THRESH) { 408c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez ath_print(common, ATH_DBG_BEACON, 409c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez "missed %u consecutive beacons\n", 410c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez sc->beacon.bmisscnt); 411b77f483fcf0579de28873828897f53371a33a0eaSujith } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { 412c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez ath_print(common, ATH_DBG_BEACON, 413c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez "beacon is officially stuck\n"); 414b74444f8a9039603715973a56df588a5d800c4efJeff Hansen sc->sc_flags |= SC_OP_TSF_RESET; 4159546aae0863c12a3d00b1ed5cbd316520733200bSujith ath_reset(sc, false); 416f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 4179546aae0863c12a3d00b1ed5cbd316520733200bSujith 418f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez return; 419f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 420980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith 421b77f483fcf0579de28873828897f53371a33a0eaSujith if (sc->beacon.bmisscnt != 0) { 422c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez ath_print(common, ATH_DBG_BEACON, 423c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez "resume beacon xmit after %u misses\n", 424c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez sc->beacon.bmisscnt); 425b77f483fcf0579de28873828897f53371a33a0eaSujith sc->beacon.bmisscnt = 0; 426f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 427f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 428f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez /* 429f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * Generate beacon frames. we are sending frames 430f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * staggered so calculate the slot for this frame based 431f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * on the tsf to safeguard against missing an swba. 432f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez */ 433f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 43457c4d7b4c4986037be51476b8e3025d5ba18d8b8Johannes Berg intval = sc->beacon_interval ? : ATH_DEFAULT_BINTVAL; 435f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 436f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez tsf = ath9k_hw_gettsf64(ah); 437f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez tsftu = TSF_TO_TU(tsf>>32, tsf); 438f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez slot = ((tsftu % intval) * ATH_BCBUF) / intval; 4394ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen /* 4404ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen * Reverse the slot order to get slot 0 on the TBTT offset that does 4414ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen * not require TSF adjustment and other slots adding 4424ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen * slot/ATH_BCBUF * beacon_int to timestamp. For example, with 4434ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen * ATH_BCBUF = 4, we process beacon slots as follows: 3 2 1 0 3 2 1 .. 4444ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen * and slot 0 is at correct offset to TBTT. 4454ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen */ 4464ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen slot = ATH_BCBUF - slot - 1; 4474ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen vif = sc->beacon.bslot[slot]; 4484ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen aphy = sc->beacon.bslot_aphy[slot]; 449980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith 450c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez ath_print(common, ATH_DBG_BEACON, 451c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", 452c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez slot, tsf, tsftu, intval, vif); 453980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith 454f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez bfaddr = 0; 4552c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinen if (vif) { 456c52f33d05e5f8d59f02722fbc308f5f391575ca5Jouni Malinen bf = ath_beacon_generate(aphy->hw, vif); 457f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez if (bf != NULL) { 458f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez bfaddr = bf->bf_daddr; 459f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez bc = 1; 460f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 461f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 4629546aae0863c12a3d00b1ed5cbd316520733200bSujith 463f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez /* 464f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * Handle slot time change when a non-ERP station joins/leaves 465f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * an 11g network. The 802.11 layer notifies us via callback, 466f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * we mark updateslot, then wait one beacon before effecting 467f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * the change. This gives associated stations at least one 468f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * beacon interval to note the state change. 469f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * 470f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * NB: The slot time change state machine is clocked according 471f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * to whether we are bursting or staggering beacons. We 472f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * recognize the request to update and record the current 473f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * slot then don't transition until that slot is reached 474f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * again. If we miss a beacon for that slot then we'll be 475f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * slow to transition but we'll be sure at least one beacon 476f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * interval has passed. When bursting slot is always left 477f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * set to ATH_BCBUF so this check is a noop. 478f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez */ 479b77f483fcf0579de28873828897f53371a33a0eaSujith if (sc->beacon.updateslot == UPDATE) { 480b77f483fcf0579de28873828897f53371a33a0eaSujith sc->beacon.updateslot = COMMIT; /* commit next beacon */ 481b77f483fcf0579de28873828897f53371a33a0eaSujith sc->beacon.slotupdate = slot; 482b77f483fcf0579de28873828897f53371a33a0eaSujith } else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) { 4830005baf4a31efe6de6f922f73ccbd3762a110062Felix Fietkau ah->slottime = sc->beacon.slottime; 4840005baf4a31efe6de6f922f73ccbd3762a110062Felix Fietkau ath9k_hw_init_global_settings(ah); 485b77f483fcf0579de28873828897f53371a33a0eaSujith sc->beacon.updateslot = OK; 486ff37e337beb838d4c2540fa93b2c4c632ee17750Sujith } 487f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez if (bfaddr != 0) { 488f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez /* 489f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * Stop any current dma and put the new frame(s) on the queue. 490f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * This should never fail since we check above that no frames 491f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez * are still pending on the queue. 492f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez */ 493b77f483fcf0579de28873828897f53371a33a0eaSujith if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) { 494c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez ath_print(common, ATH_DBG_FATAL, 495b77f483fcf0579de28873828897f53371a33a0eaSujith "beacon queue %u did not stop?\n", sc->beacon.beaconq); 496f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 497f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 498f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez /* NB: cabq traffic should already be queued and primed */ 499b77f483fcf0579de28873828897f53371a33a0eaSujith ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr); 500b77f483fcf0579de28873828897f53371a33a0eaSujith ath9k_hw_txstart(ah, sc->beacon.beaconq); 501f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 50217d7904de85125c62c7258d7cb21207f26d04048Sujith sc->beacon.ast_be_xmit += bc; /* XXX per-vif? */ 503f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 504f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez} 505f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 50621526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguezstatic void ath9k_beacon_init(struct ath_softc *sc, 50721526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez u32 next_beacon, 50821526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez u32 beacon_period) 50921526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez{ 51021526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez if (beacon_period & ATH9K_BEACON_RESET_TSF) 51121526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez ath9k_ps_wakeup(sc); 51221526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez 51321526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period); 51421526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez 51521526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez if (beacon_period & ATH9K_BEACON_RESET_TSF) 51621526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez ath9k_ps_restore(sc); 51721526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez} 51821526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez 519f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez/* 5205379c8a26686e12058e23322615df68f9123bccdSujith * For multi-bss ap support beacons are either staggered evenly over N slots or 5215379c8a26686e12058e23322615df68f9123bccdSujith * burst together. For the former arrange for the SWBA to be delivered for each 5225379c8a26686e12058e23322615df68f9123bccdSujith * slot. Slots that are not occupied will generate nothing. 523f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez */ 5245379c8a26686e12058e23322615df68f9123bccdSujithstatic void ath_beacon_config_ap(struct ath_softc *sc, 525d31e20af9f65e38429a3ed32175f8e233bdcd2b2Vasanthakumar Thiagarajan struct ath_beacon_config *conf) 526f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez{ 527980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith u32 nexttbtt, intval; 528f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 529b238e90e99fe51aed14d20eae8a6a1c04ce4ca30Sujith /* Configure the timers only when the TSF has to be reset */ 530b238e90e99fe51aed14d20eae8a6a1c04ce4ca30Sujith 531b238e90e99fe51aed14d20eae8a6a1c04ce4ca30Sujith if (!(sc->sc_flags & SC_OP_TSF_RESET)) 532b238e90e99fe51aed14d20eae8a6a1c04ce4ca30Sujith return; 533b238e90e99fe51aed14d20eae8a6a1c04ce4ca30Sujith 5345379c8a26686e12058e23322615df68f9123bccdSujith /* NB: the beacon interval is kept internally in TU's */ 5355379c8a26686e12058e23322615df68f9123bccdSujith intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; 5365379c8a26686e12058e23322615df68f9123bccdSujith intval /= ATH_BCBUF; /* for staggered beacons */ 5375379c8a26686e12058e23322615df68f9123bccdSujith nexttbtt = intval; 5385379c8a26686e12058e23322615df68f9123bccdSujith intval |= ATH9K_BEACON_RESET_TSF; 539f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 5405379c8a26686e12058e23322615df68f9123bccdSujith /* 5415379c8a26686e12058e23322615df68f9123bccdSujith * In AP mode we enable the beacon timers and SWBA interrupts to 5425379c8a26686e12058e23322615df68f9123bccdSujith * prepare beacon frames. 5435379c8a26686e12058e23322615df68f9123bccdSujith */ 5445379c8a26686e12058e23322615df68f9123bccdSujith intval |= ATH9K_BEACON_ENA; 5455379c8a26686e12058e23322615df68f9123bccdSujith sc->imask |= ATH9K_INT_SWBA; 5465379c8a26686e12058e23322615df68f9123bccdSujith ath_beaconq_config(sc); 547f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 5485379c8a26686e12058e23322615df68f9123bccdSujith /* Set the computed AP beacon timers */ 549f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 5505379c8a26686e12058e23322615df68f9123bccdSujith ath9k_hw_set_interrupts(sc->sc_ah, 0); 55121526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez ath9k_beacon_init(sc, nexttbtt, intval); 5525379c8a26686e12058e23322615df68f9123bccdSujith sc->beacon.bmisscnt = 0; 5535379c8a26686e12058e23322615df68f9123bccdSujith ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); 554b238e90e99fe51aed14d20eae8a6a1c04ce4ca30Sujith 555b238e90e99fe51aed14d20eae8a6a1c04ce4ca30Sujith /* Clear the reset TSF flag, so that subsequent beacon updation 556b238e90e99fe51aed14d20eae8a6a1c04ce4ca30Sujith will not reset the HW TSF. */ 557b238e90e99fe51aed14d20eae8a6a1c04ce4ca30Sujith 558b238e90e99fe51aed14d20eae8a6a1c04ce4ca30Sujith sc->sc_flags &= ~SC_OP_TSF_RESET; 5595379c8a26686e12058e23322615df68f9123bccdSujith} 560459f5f90f1bd959ced04761406415b178b315177Sujith 5615379c8a26686e12058e23322615df68f9123bccdSujith/* 5625379c8a26686e12058e23322615df68f9123bccdSujith * This sets up the beacon timers according to the timestamp of the last 5635379c8a26686e12058e23322615df68f9123bccdSujith * received beacon and the current TSF, configures PCF and DTIM 5645379c8a26686e12058e23322615df68f9123bccdSujith * handling, programs the sleep registers so the hardware will wakeup in 5655379c8a26686e12058e23322615df68f9123bccdSujith * time to receive beacons, and configures the beacon miss handling so 5665379c8a26686e12058e23322615df68f9123bccdSujith * we'll receive a BMISS interrupt when we stop seeing beacons from the AP 5675379c8a26686e12058e23322615df68f9123bccdSujith * we've associated with. 5685379c8a26686e12058e23322615df68f9123bccdSujith */ 5695379c8a26686e12058e23322615df68f9123bccdSujithstatic void ath_beacon_config_sta(struct ath_softc *sc, 570d31e20af9f65e38429a3ed32175f8e233bdcd2b2Vasanthakumar Thiagarajan struct ath_beacon_config *conf) 5715379c8a26686e12058e23322615df68f9123bccdSujith{ 572c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez struct ath_common *common = ath9k_hw_common(sc->sc_ah); 5735379c8a26686e12058e23322615df68f9123bccdSujith struct ath9k_beacon_state bs; 5745379c8a26686e12058e23322615df68f9123bccdSujith int dtimperiod, dtimcount, sleepduration; 5755379c8a26686e12058e23322615df68f9123bccdSujith int cfpperiod, cfpcount; 5765379c8a26686e12058e23322615df68f9123bccdSujith u32 nexttbtt = 0, intval, tsftu; 5775379c8a26686e12058e23322615df68f9123bccdSujith u64 tsf; 578267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen int num_beacons, offset, dtim_dec_count, cfp_dec_count; 5795379c8a26686e12058e23322615df68f9123bccdSujith 5801a20034a73a40b8056731f9db0c535cec2961eb7Senthil Balasubramanian /* No need to configure beacon if we are not associated */ 5811a20034a73a40b8056731f9db0c535cec2961eb7Senthil Balasubramanian if (!common->curaid) { 5821a20034a73a40b8056731f9db0c535cec2961eb7Senthil Balasubramanian ath_print(common, ATH_DBG_BEACON, 5831a20034a73a40b8056731f9db0c535cec2961eb7Senthil Balasubramanian "STA is not yet associated..skipping beacon config\n"); 5841a20034a73a40b8056731f9db0c535cec2961eb7Senthil Balasubramanian return; 5851a20034a73a40b8056731f9db0c535cec2961eb7Senthil Balasubramanian } 5861a20034a73a40b8056731f9db0c535cec2961eb7Senthil Balasubramanian 5875379c8a26686e12058e23322615df68f9123bccdSujith memset(&bs, 0, sizeof(bs)); 5885379c8a26686e12058e23322615df68f9123bccdSujith intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; 5895379c8a26686e12058e23322615df68f9123bccdSujith 5905379c8a26686e12058e23322615df68f9123bccdSujith /* 5915379c8a26686e12058e23322615df68f9123bccdSujith * Setup dtim and cfp parameters according to 5925379c8a26686e12058e23322615df68f9123bccdSujith * last beacon we received (which may be none). 5935379c8a26686e12058e23322615df68f9123bccdSujith */ 5945379c8a26686e12058e23322615df68f9123bccdSujith dtimperiod = conf->dtim_period; 5955379c8a26686e12058e23322615df68f9123bccdSujith if (dtimperiod <= 0) /* NB: 0 if not known */ 5965379c8a26686e12058e23322615df68f9123bccdSujith dtimperiod = 1; 5975379c8a26686e12058e23322615df68f9123bccdSujith dtimcount = conf->dtim_count; 5985379c8a26686e12058e23322615df68f9123bccdSujith if (dtimcount >= dtimperiod) /* NB: sanity check */ 5995379c8a26686e12058e23322615df68f9123bccdSujith dtimcount = 0; 6005379c8a26686e12058e23322615df68f9123bccdSujith cfpperiod = 1; /* NB: no PCF support yet */ 6015379c8a26686e12058e23322615df68f9123bccdSujith cfpcount = 0; 6025379c8a26686e12058e23322615df68f9123bccdSujith 6035379c8a26686e12058e23322615df68f9123bccdSujith sleepduration = conf->listen_interval * intval; 6045379c8a26686e12058e23322615df68f9123bccdSujith if (sleepduration <= 0) 6055379c8a26686e12058e23322615df68f9123bccdSujith sleepduration = intval; 6065379c8a26686e12058e23322615df68f9123bccdSujith 6075379c8a26686e12058e23322615df68f9123bccdSujith /* 6085379c8a26686e12058e23322615df68f9123bccdSujith * Pull nexttbtt forward to reflect the current 6095379c8a26686e12058e23322615df68f9123bccdSujith * TSF and calculate dtim+cfp state for the result. 6105379c8a26686e12058e23322615df68f9123bccdSujith */ 6115379c8a26686e12058e23322615df68f9123bccdSujith tsf = ath9k_hw_gettsf64(sc->sc_ah); 6125379c8a26686e12058e23322615df68f9123bccdSujith tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; 613267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen 614267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen num_beacons = tsftu / intval + 1; 615267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen offset = tsftu % intval; 616267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen nexttbtt = tsftu - offset; 617267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen if (offset) 6185379c8a26686e12058e23322615df68f9123bccdSujith nexttbtt += intval; 619267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen 620267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen /* DTIM Beacon every dtimperiod Beacon */ 621267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen dtim_dec_count = num_beacons % dtimperiod; 622267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen /* CFP every cfpperiod DTIM Beacon */ 623267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod; 624267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen if (dtim_dec_count) 625267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen cfp_dec_count++; 626267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen 627267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen dtimcount -= dtim_dec_count; 628267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen if (dtimcount < 0) 629267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen dtimcount += dtimperiod; 630267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen 631267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen cfpcount -= cfp_dec_count; 632267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen if (cfpcount < 0) 633267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen cfpcount += cfpperiod; 6345379c8a26686e12058e23322615df68f9123bccdSujith 6355379c8a26686e12058e23322615df68f9123bccdSujith bs.bs_intval = intval; 6365379c8a26686e12058e23322615df68f9123bccdSujith bs.bs_nexttbtt = nexttbtt; 6375379c8a26686e12058e23322615df68f9123bccdSujith bs.bs_dtimperiod = dtimperiod*intval; 6385379c8a26686e12058e23322615df68f9123bccdSujith bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval; 6395379c8a26686e12058e23322615df68f9123bccdSujith bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod; 6405379c8a26686e12058e23322615df68f9123bccdSujith bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod; 6415379c8a26686e12058e23322615df68f9123bccdSujith bs.bs_cfpmaxduration = 0; 6425379c8a26686e12058e23322615df68f9123bccdSujith 6435379c8a26686e12058e23322615df68f9123bccdSujith /* 6445379c8a26686e12058e23322615df68f9123bccdSujith * Calculate the number of consecutive beacons to miss* before taking 6455379c8a26686e12058e23322615df68f9123bccdSujith * a BMISS interrupt. The configuration is specified in TU so we only 6465379c8a26686e12058e23322615df68f9123bccdSujith * need calculate based on the beacon interval. Note that we clamp the 6475379c8a26686e12058e23322615df68f9123bccdSujith * result to at most 15 beacons. 6485379c8a26686e12058e23322615df68f9123bccdSujith */ 6495379c8a26686e12058e23322615df68f9123bccdSujith if (sleepduration > intval) { 6505379c8a26686e12058e23322615df68f9123bccdSujith bs.bs_bmissthreshold = conf->listen_interval * 6515379c8a26686e12058e23322615df68f9123bccdSujith ATH_DEFAULT_BMISS_LIMIT / 2; 652f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } else { 6535379c8a26686e12058e23322615df68f9123bccdSujith bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval); 6545379c8a26686e12058e23322615df68f9123bccdSujith if (bs.bs_bmissthreshold > 15) 6555379c8a26686e12058e23322615df68f9123bccdSujith bs.bs_bmissthreshold = 15; 6565379c8a26686e12058e23322615df68f9123bccdSujith else if (bs.bs_bmissthreshold <= 0) 6575379c8a26686e12058e23322615df68f9123bccdSujith bs.bs_bmissthreshold = 1; 658f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez } 659f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 6605379c8a26686e12058e23322615df68f9123bccdSujith /* 6615379c8a26686e12058e23322615df68f9123bccdSujith * Calculate sleep duration. The configuration is given in ms. 6625379c8a26686e12058e23322615df68f9123bccdSujith * We ensure a multiple of the beacon period is used. Also, if the sleep 6635379c8a26686e12058e23322615df68f9123bccdSujith * duration is greater than the DTIM period then it makes senses 6645379c8a26686e12058e23322615df68f9123bccdSujith * to make it a multiple of that. 6655379c8a26686e12058e23322615df68f9123bccdSujith * 6665379c8a26686e12058e23322615df68f9123bccdSujith * XXX fixed at 100ms 6675379c8a26686e12058e23322615df68f9123bccdSujith */ 668980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith 6695379c8a26686e12058e23322615df68f9123bccdSujith bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration); 6705379c8a26686e12058e23322615df68f9123bccdSujith if (bs.bs_sleepduration > bs.bs_dtimperiod) 6715379c8a26686e12058e23322615df68f9123bccdSujith bs.bs_sleepduration = bs.bs_dtimperiod; 672980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith 6735379c8a26686e12058e23322615df68f9123bccdSujith /* TSF out of range threshold fixed at 1 second */ 6745379c8a26686e12058e23322615df68f9123bccdSujith bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; 675f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 676c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez ath_print(common, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu); 677c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez ath_print(common, ATH_DBG_BEACON, 678c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", 679c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez bs.bs_bmissthreshold, bs.bs_sleepduration, 680c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext); 681f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 6825379c8a26686e12058e23322615df68f9123bccdSujith /* Set the computed STA beacon timers */ 683980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith 6845379c8a26686e12058e23322615df68f9123bccdSujith ath9k_hw_set_interrupts(sc->sc_ah, 0); 6855379c8a26686e12058e23322615df68f9123bccdSujith ath9k_hw_set_sta_beacon_timers(sc->sc_ah, &bs); 6865379c8a26686e12058e23322615df68f9123bccdSujith sc->imask |= ATH9K_INT_BMISS; 6875379c8a26686e12058e23322615df68f9123bccdSujith ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); 6885379c8a26686e12058e23322615df68f9123bccdSujith} 689f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 6905379c8a26686e12058e23322615df68f9123bccdSujithstatic void ath_beacon_config_adhoc(struct ath_softc *sc, 6915379c8a26686e12058e23322615df68f9123bccdSujith struct ath_beacon_config *conf, 6922c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinen struct ieee80211_vif *vif) 6935379c8a26686e12058e23322615df68f9123bccdSujith{ 694c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez struct ath_common *common = ath9k_hw_common(sc->sc_ah); 6955379c8a26686e12058e23322615df68f9123bccdSujith u64 tsf; 6965379c8a26686e12058e23322615df68f9123bccdSujith u32 tsftu, intval, nexttbtt; 697f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 6985379c8a26686e12058e23322615df68f9123bccdSujith intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; 699f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 700546256fbd06d70a87381020ea8553fb78c9abf43Jouni Malinen 7015379c8a26686e12058e23322615df68f9123bccdSujith /* Pull nexttbtt forward to reflect the current TSF */ 7024af9cf4fda28c5f794861c52e0db5a3de9ee574dSujith 7035379c8a26686e12058e23322615df68f9123bccdSujith nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); 7045379c8a26686e12058e23322615df68f9123bccdSujith if (nexttbtt == 0) 7055379c8a26686e12058e23322615df68f9123bccdSujith nexttbtt = intval; 7065379c8a26686e12058e23322615df68f9123bccdSujith else if (intval) 7075379c8a26686e12058e23322615df68f9123bccdSujith nexttbtt = roundup(nexttbtt, intval); 7089fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith 7095379c8a26686e12058e23322615df68f9123bccdSujith tsf = ath9k_hw_gettsf64(sc->sc_ah); 7105379c8a26686e12058e23322615df68f9123bccdSujith tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE; 7115379c8a26686e12058e23322615df68f9123bccdSujith do { 7125379c8a26686e12058e23322615df68f9123bccdSujith nexttbtt += intval; 7135379c8a26686e12058e23322615df68f9123bccdSujith } while (nexttbtt < tsftu); 714f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 715c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez ath_print(common, ATH_DBG_BEACON, 716c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez "IBSS nexttbtt %u intval %u (%u)\n", 717c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez nexttbtt, intval, conf->beacon_interval); 7189fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith 7195379c8a26686e12058e23322615df68f9123bccdSujith /* 7205379c8a26686e12058e23322615df68f9123bccdSujith * In IBSS mode enable the beacon timers but only enable SWBA interrupts 7215379c8a26686e12058e23322615df68f9123bccdSujith * if we need to manually prepare beacon frames. Otherwise we use a 7225379c8a26686e12058e23322615df68f9123bccdSujith * self-linked tx descriptor and let the hardware deal with things. 7235379c8a26686e12058e23322615df68f9123bccdSujith */ 7245379c8a26686e12058e23322615df68f9123bccdSujith intval |= ATH9K_BEACON_ENA; 7255379c8a26686e12058e23322615df68f9123bccdSujith if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) 7265379c8a26686e12058e23322615df68f9123bccdSujith sc->imask |= ATH9K_INT_SWBA; 7279fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith 7285379c8a26686e12058e23322615df68f9123bccdSujith ath_beaconq_config(sc); 7295379c8a26686e12058e23322615df68f9123bccdSujith 7305379c8a26686e12058e23322615df68f9123bccdSujith /* Set the computed ADHOC beacon timers */ 7315379c8a26686e12058e23322615df68f9123bccdSujith 7325379c8a26686e12058e23322615df68f9123bccdSujith ath9k_hw_set_interrupts(sc->sc_ah, 0); 73321526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez ath9k_beacon_init(sc, nexttbtt, intval); 7345379c8a26686e12058e23322615df68f9123bccdSujith sc->beacon.bmisscnt = 0; 7355379c8a26686e12058e23322615df68f9123bccdSujith ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); 7365379c8a26686e12058e23322615df68f9123bccdSujith 7376b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan /* FIXME: Handle properly when vif is NULL */ 7386b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan if (vif && sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL) 7392c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinen ath_beacon_start_adhoc(sc, vif); 740f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez} 741f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez 7422c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinenvoid ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) 743f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez{ 7446b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; 745c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez struct ath_common *common = ath9k_hw_common(sc->sc_ah); 7466b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan enum nl80211_iftype iftype; 7475379c8a26686e12058e23322615df68f9123bccdSujith 7485379c8a26686e12058e23322615df68f9123bccdSujith /* Setup the beacon configuration parameters */ 7492c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinen if (vif) { 7506b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; 7516b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan 7526b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan iftype = vif->type; 7535379c8a26686e12058e23322615df68f9123bccdSujith 7546b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan cur_conf->beacon_interval = bss_conf->beacon_int; 7556b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan cur_conf->dtim_period = bss_conf->dtim_period; 7566b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan cur_conf->listen_interval = 1; 7576b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan cur_conf->dtim_count = 1; 7586b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan cur_conf->bmiss_timeout = 7596b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; 7606b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan } else { 7616b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan iftype = sc->sc_ah->opmode; 7625379c8a26686e12058e23322615df68f9123bccdSujith } 7636b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan 764c4f9f16b309b65f9f578ec4ba78b3efa106cf65dVasanthakumar Thiagarajan /* 765c4f9f16b309b65f9f578ec4ba78b3efa106cf65dVasanthakumar Thiagarajan * It looks like mac80211 may end up using beacon interval of zero in 766c4f9f16b309b65f9f578ec4ba78b3efa106cf65dVasanthakumar Thiagarajan * some cases (at least for mesh point). Avoid getting into an 767c4f9f16b309b65f9f578ec4ba78b3efa106cf65dVasanthakumar Thiagarajan * infinite loop by using a bit safer value instead. To be safe, 768c4f9f16b309b65f9f578ec4ba78b3efa106cf65dVasanthakumar Thiagarajan * do sanity check on beacon interval for all operating modes. 769c4f9f16b309b65f9f578ec4ba78b3efa106cf65dVasanthakumar Thiagarajan */ 770c4f9f16b309b65f9f578ec4ba78b3efa106cf65dVasanthakumar Thiagarajan if (cur_conf->beacon_interval == 0) 771c4f9f16b309b65f9f578ec4ba78b3efa106cf65dVasanthakumar Thiagarajan cur_conf->beacon_interval = 100; 7726b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan 7736b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan switch (iftype) { 7746b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan case NL80211_IFTYPE_AP: 7756b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan ath_beacon_config_ap(sc, cur_conf); 7766b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan break; 7776b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan case NL80211_IFTYPE_ADHOC: 7786b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan case NL80211_IFTYPE_MESH_POINT: 7796b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan ath_beacon_config_adhoc(sc, cur_conf, vif); 7806b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan break; 7816b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan case NL80211_IFTYPE_STATION: 7826b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan ath_beacon_config_sta(sc, cur_conf); 7836b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan break; 7846b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan default: 785c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez ath_print(common, ATH_DBG_CONFIG, 786c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez "Unsupported beaconing mode\n"); 7876b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan return; 7886b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan } 7896b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan 7906b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan sc->sc_flags |= SC_OP_BEACONS; 791f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez} 792