1f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez/*
25b68138e5659cbfd5df2879d17f9ba0b66477fecSujith Manoharan * Copyright (c) 2008-2011 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
17b7f080cfe223b3b7424872639d153695615a9255Alexey Dobriyan#include <linux/dma-mapping.h>
18394cf0a1ca02e7998c8d01975b60a3cdc121e7d8Sujith#include "ath9k.h"
19f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
205379c8a26686e12058e23322615df68f9123bccdSujith#define FUDGE 2
215379c8a26686e12058e23322615df68f9123bccdSujith
22ba4903f97a275ed0967b58ff882f8ab41bec24adFelix Fietkaustatic void ath9k_reset_beacon_status(struct ath_softc *sc)
23ba4903f97a275ed0967b58ff882f8ab41bec24adFelix Fietkau{
24ba4903f97a275ed0967b58ff882f8ab41bec24adFelix Fietkau	sc->beacon.tx_processed = false;
25ba4903f97a275ed0967b58ff882f8ab41bec24adFelix Fietkau	sc->beacon.tx_last = false;
26ba4903f97a275ed0967b58ff882f8ab41bec24adFelix Fietkau}
27ba4903f97a275ed0967b58ff882f8ab41bec24adFelix Fietkau
28f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez/*
29f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez *  This function will modify certain transmit queue properties depending on
30f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez *  the operating mode of the station (AP or AdHoc).  Parameters are AIFS
31f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez *  settings and channel width min/max
32f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez*/
3394db29368a658b13a088db87c7b0bf59b1a7492dVivek Natarajanint ath_beaconq_config(struct ath_softc *sc)
34f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez{
35cbe61d8a41210600bc76b212edcd4dc0f55c014fSujith	struct ath_hw *ah = sc->sc_ah;
36c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez	struct ath_common *common = ath9k_hw_common(ah);
3794db29368a658b13a088db87c7b0bf59b1a7492dVivek Natarajan	struct ath9k_tx_queue_info qi, qi_be;
38066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau	struct ath_txq *txq;
39f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
40b77f483fcf0579de28873828897f53371a33a0eaSujith	ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi);
412660b81a378ab227b78c4cc618453fa7e19a7c7bSujith	if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
42f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		/* Always burst out beacon and CAB traffic. */
43f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		qi.tqi_aifs = 1;
44f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		qi.tqi_cwmin = 0;
45f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		qi.tqi_cwmax = 0;
46f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	} else {
47f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		/* Adhoc mode; important thing is to use 2x cwmin. */
48066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau		txq = sc->tx.txq_map[WME_AC_BE];
49066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau		ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be);
5094db29368a658b13a088db87c7b0bf59b1a7492dVivek Natarajan		qi.tqi_aifs = qi_be.tqi_aifs;
5194db29368a658b13a088db87c7b0bf59b1a7492dVivek Natarajan		qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
5294db29368a658b13a088db87c7b0bf59b1a7492dVivek Natarajan		qi.tqi_cwmax = qi_be.tqi_cwmax;
53f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	}
54f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
55b77f483fcf0579de28873828897f53371a33a0eaSujith	if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) {
563800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(common,
573800276a40751539a920ef8e0537ef2e19126799Joe Perches			"Unable to update h/w beacon queue parameters\n");
58f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		return 0;
59f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	} else {
609fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith		ath9k_hw_resettxqueue(ah, sc->beacon.beaconq);
61f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		return 1;
62f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	}
63f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez}
64f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
65f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez/*
66f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez *  Associates the beacon frame buffer with a transmit descriptor.  Will set
67dd347f2fb2ddb20a80e9a8285252bf208ab91398Felix Fietkau *  up rate codes, and channel flags. Beacons are always sent out at the
68dd347f2fb2ddb20a80e9a8285252bf208ab91398Felix Fietkau *  lowest rate, and are not retried.
69f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez*/
70d47a61aa228709fe1704e18a2f444661c10b81c0Sujith Manoharanstatic void ath_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
7164b84010f9f85996a219fcc697396e7e11be3459Jouni Malinen			     struct ath_buf *bf, int rateidx)
72f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez{
73a22be22ab8fe571cce88d0d30b49f297a563c4a7Sujith	struct sk_buff *skb = bf->bf_mpdu;
74cbe61d8a41210600bc76b212edcd4dc0f55c014fSujith	struct ath_hw *ah = sc->sc_ah;
7543c2761364b77cd7fd20eb1f14cfee4cd1462abdLuis R. Rodriguez	struct ath_common *common = ath9k_hw_common(ah);
76493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau	struct ath_tx_info info;
77545750d36fa78203e28acefb4bab61ebb7c4d197Felix Fietkau	struct ieee80211_supported_band *sband;
78493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau	u8 chainmask = ah->txchainmask;
79545750d36fa78203e28acefb4bab61ebb7c4d197Felix Fietkau	u8 rate = 0;
80f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
81ba4903f97a275ed0967b58ff882f8ab41bec24adFelix Fietkau	ath9k_reset_beacon_status(sc);
82ba4903f97a275ed0967b58ff882f8ab41bec24adFelix Fietkau
83545750d36fa78203e28acefb4bab61ebb7c4d197Felix Fietkau	sband = &sc->sbands[common->hw->conf.channel->band];
8464b84010f9f85996a219fcc697396e7e11be3459Jouni Malinen	rate = sband->bitrates[rateidx].hw_value;
85d47a61aa228709fe1704e18a2f444661c10b81c0Sujith Manoharan	if (vif->bss_conf.use_short_preamble)
8664b84010f9f85996a219fcc697396e7e11be3459Jouni Malinen		rate |= sband->bitrates[rateidx].hw_value_short;
879fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith
88493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau	memset(&info, 0, sizeof(info));
89493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau	info.pkt_len = skb->len + FCS_LEN;
90493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau	info.type = ATH9K_PKT_TYPE_BEACON;
91493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau	info.txpower = MAX_RATE_POWER;
92493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau	info.keyix = ATH9K_TXKEYIX_INVALID;
93493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau	info.keytype = ATH9K_KEY_TYPE_CLEAR;
944e0ad2591adde7bec878a4b37a073427aec3e19cFelix Fietkau	info.flags = ATH9K_TXDESC_NOACK | ATH9K_TXDESC_INTREQ;
95493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau
96493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau	info.buf_addr[0] = bf->bf_buf_addr;
97493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau	info.buf_len[0] = roundup(skb->len, 4);
98493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau
99493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau	info.is_first = true;
100493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau	info.is_last = true;
101493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau
102493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau	info.qcu = sc->beacon.beaconq;
103493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau
104493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau	info.rates[0].Tries = 1;
105493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau	info.rates[0].Rate = rate;
106493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau	info.rates[0].ChSel = ath_txchainmask_reduction(sc, chainmask, rate);
107493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau
108493cf04fd37bf265dc3c9aad357e3e34654c86e3Felix Fietkau	ath9k_hw_set_txdesc(ah, bf->bf_desc, &info);
109f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez}
110f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
11128d167086227969fd6586953ee4ac682a3c394ffFelix Fietkaustatic void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
11228d167086227969fd6586953ee4ac682a3c394ffFelix Fietkau{
1139ac58615d93c8a28b1c649a90a5e2ede4dfd368aFelix Fietkau	struct ath_softc *sc = hw->priv;
11428d167086227969fd6586953ee4ac682a3c394ffFelix Fietkau	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
11528d167086227969fd6586953ee4ac682a3c394ffFelix Fietkau	struct ath_tx_control txctl;
11628d167086227969fd6586953ee4ac682a3c394ffFelix Fietkau
11728d167086227969fd6586953ee4ac682a3c394ffFelix Fietkau	memset(&txctl, 0, sizeof(struct ath_tx_control));
11828d167086227969fd6586953ee4ac682a3c394ffFelix Fietkau	txctl.txq = sc->beacon.cabq;
11928d167086227969fd6586953ee4ac682a3c394ffFelix Fietkau
120d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches	ath_dbg(common, XMIT, "transmitting CABQ packet, skb: %p\n", skb);
12128d167086227969fd6586953ee4ac682a3c394ffFelix Fietkau
12228d167086227969fd6586953ee4ac682a3c394ffFelix Fietkau	if (ath_tx_start(hw, skb, &txctl) != 0) {
123d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, XMIT, "CABQ TX failed\n");
12428d167086227969fd6586953ee4ac682a3c394ffFelix Fietkau		dev_kfree_skb_any(skb);
12528d167086227969fd6586953ee4ac682a3c394ffFelix Fietkau	}
12628d167086227969fd6586953ee4ac682a3c394ffFelix Fietkau}
12728d167086227969fd6586953ee4ac682a3c394ffFelix Fietkau
128c52f33d05e5f8d59f02722fbc308f5f391575ca5Jouni Malinenstatic struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
1292c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinen					   struct ieee80211_vif *vif)
130f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez{
1319ac58615d93c8a28b1c649a90a5e2ede4dfd368aFelix Fietkau	struct ath_softc *sc = hw->priv;
132c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
133f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	struct ath_buf *bf;
13417d7904de85125c62c7258d7cb21207f26d04048Sujith	struct ath_vif *avp;
135f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	struct sk_buff *skb;
136f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	struct ath_txq *cabq;
137147583c057c43095925b5f331fe304f2d5b997baJouni Malinen	struct ieee80211_tx_info *info;
138980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith	int cabq_depth;
139980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith
140ba4903f97a275ed0967b58ff882f8ab41bec24adFelix Fietkau	ath9k_reset_beacon_status(sc);
141ba4903f97a275ed0967b58ff882f8ab41bec24adFelix Fietkau
1425640b08ef7e88b606c740e746cb77bc97d78508eSujith	avp = (void *)vif->drv_priv;
143b77f483fcf0579de28873828897f53371a33a0eaSujith	cabq = sc->beacon.cabq;
144f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
145014cf3bb1e19a61c53666d7f990f584f1b7af364Rajkumar Manoharan	if ((avp->av_bcbuf == NULL) || !avp->is_bslot_active)
146f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		return NULL;
147980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith
1489fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith	/* Release the old beacon first */
1499fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith
150f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	bf = avp->av_bcbuf;
151a22be22ab8fe571cce88d0d30b49f297a563c4a7Sujith	skb = bf->bf_mpdu;
152a8fff50e4d6aad520b261b3c32e2c67a7dfb7228Jouni Malinen	if (skb) {
153c1739eb3e61e160f124bc842c219011916f63068Ben Greear		dma_unmap_single(sc->dev, bf->bf_buf_addr,
1549fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith				 skb->len, DMA_TO_DEVICE);
1553fbb9d95a96c6a03f2e484bb1665d089412640dcJouni Malinen		dev_kfree_skb_any(skb);
1566cf9e995f91e5bbffb2bef85feef490e5b67605dBen Greear		bf->bf_buf_addr = 0;
157a8fff50e4d6aad520b261b3c32e2c67a7dfb7228Jouni Malinen	}
158f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
1599fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith	/* Get a new beacon from mac80211 */
1609fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith
161c52f33d05e5f8d59f02722fbc308f5f391575ca5Jouni Malinen	skb = ieee80211_beacon_get(hw, vif);
162a8fff50e4d6aad520b261b3c32e2c67a7dfb7228Jouni Malinen	bf->bf_mpdu = skb;
163a8fff50e4d6aad520b261b3c32e2c67a7dfb7228Jouni Malinen	if (skb == NULL)
164a8fff50e4d6aad520b261b3c32e2c67a7dfb7228Jouni Malinen		return NULL;
1654ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen	((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp =
1664ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen		avp->tsf_adjust;
167980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith
168147583c057c43095925b5f331fe304f2d5b997baJouni Malinen	info = IEEE80211_SKB_CB(skb);
169147583c057c43095925b5f331fe304f2d5b997baJouni Malinen	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
170147583c057c43095925b5f331fe304f2d5b997baJouni Malinen		/*
171147583c057c43095925b5f331fe304f2d5b997baJouni Malinen		 * TODO: make sure the seq# gets assigned properly (vs. other
172147583c057c43095925b5f331fe304f2d5b997baJouni Malinen		 * TX frames)
173147583c057c43095925b5f331fe304f2d5b997baJouni Malinen		 */
174980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
175b77f483fcf0579de28873828897f53371a33a0eaSujith		sc->tx.seq_no += 0x10;
176147583c057c43095925b5f331fe304f2d5b997baJouni Malinen		hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
177b77f483fcf0579de28873828897f53371a33a0eaSujith		hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
178147583c057c43095925b5f331fe304f2d5b997baJouni Malinen	}
179980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith
180c1739eb3e61e160f124bc842c219011916f63068Ben Greear	bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
181c1739eb3e61e160f124bc842c219011916f63068Ben Greear					 skb->len, DMA_TO_DEVICE);
1827da3c55ce849e17fd9017c7bf770a03fa083d95bGabor Juhos	if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
183f8316df10c4e3bec5b4c3a5a8e026c577640c3a6Luis R. Rodriguez		dev_kfree_skb_any(skb);
184f8316df10c4e3bec5b4c3a5a8e026c577640c3a6Luis R. Rodriguez		bf->bf_mpdu = NULL;
1856cf9e995f91e5bbffb2bef85feef490e5b67605dBen Greear		bf->bf_buf_addr = 0;
1863800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(common, "dma_mapping_error on beaconing\n");
187f8316df10c4e3bec5b4c3a5a8e026c577640c3a6Luis R. Rodriguez		return NULL;
188f8316df10c4e3bec5b4c3a5a8e026c577640c3a6Luis R. Rodriguez	}
189f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
190c52f33d05e5f8d59f02722fbc308f5f391575ca5Jouni Malinen	skb = ieee80211_get_buffered_bc(hw, vif);
191f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
192f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	/*
193f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 * if the CABQ traffic from previous DTIM is pending and the current
194f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 *  beacon is also a DTIM.
19517d7904de85125c62c7258d7cb21207f26d04048Sujith	 *  1) if there is only one vif let the cab traffic continue.
19617d7904de85125c62c7258d7cb21207f26d04048Sujith	 *  2) if there are more than one vif and we are using staggered
197f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 *     beacons, then drain the cabq by dropping all the frames in
19817d7904de85125c62c7258d7cb21207f26d04048Sujith	 *     the cabq so that the current vifs cab traffic can be scheduled.
199f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 */
200f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	spin_lock_bh(&cabq->axq_lock);
201f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	cabq_depth = cabq->axq_depth;
202f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	spin_unlock_bh(&cabq->axq_lock);
203f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
204e022edbd2bfb5f9a7ddf1cca43544f7b54c6fe02Jouni Malinen	if (skb && cabq_depth) {
20517d7904de85125c62c7258d7cb21207f26d04048Sujith		if (sc->nvifs > 1) {
206d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			ath_dbg(common, BEACON,
207226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				"Flushing previous cabq traffic\n");
2089fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith			ath_draintxq(sc, cabq, false);
209f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		}
210f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	}
211f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
212d47a61aa228709fe1704e18a2f444661c10b81c0Sujith Manoharan	ath_beacon_setup(sc, vif, bf, info->control.rates[0].idx);
213f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
214e022edbd2bfb5f9a7ddf1cca43544f7b54c6fe02Jouni Malinen	while (skb) {
215c52f33d05e5f8d59f02722fbc308f5f391575ca5Jouni Malinen		ath_tx_cabq(hw, skb);
216c52f33d05e5f8d59f02722fbc308f5f391575ca5Jouni Malinen		skb = ieee80211_get_buffered_bc(hw, vif);
217e022edbd2bfb5f9a7ddf1cca43544f7b54c6fe02Jouni Malinen	}
218f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
219f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	return bf;
220f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez}
221f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
2229ac58615d93c8a28b1c649a90a5e2ede4dfd368aFelix Fietkauint ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif)
223f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez{
224c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
22517d7904de85125c62c7258d7cb21207f26d04048Sujith	struct ath_vif *avp;
226f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	struct ath_buf *bf;
227f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	struct sk_buff *skb;
2289814f6b34be5179849c0872e81eb99286ef4b051Steve Brown	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
229459f5f90f1bd959ced04761406415b178b315177Sujith	__le64 tstamp;
230f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
2315640b08ef7e88b606c740e746cb77bc97d78508eSujith	avp = (void *)vif->drv_priv;
232f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
233f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	/* Allocate a beacon descriptor if we haven't done so. */
234f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	if (!avp->av_bcbuf) {
235980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith		/* Allocate beacon state for hostap/ibss.  We know
236980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith		 * a buffer is available. */
237b77f483fcf0579de28873828897f53371a33a0eaSujith		avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf,
238980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith						 struct ath_buf, list);
239f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		list_del(&avp->av_bcbuf->list);
240f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
2414801416c76a3a355076d6d371c00270dfe332e1cBen Greear		if (ath9k_uses_beacons(vif->type)) {
242f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez			int slot;
243f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez			/*
24417d7904de85125c62c7258d7cb21207f26d04048Sujith			 * Assign the vif to a beacon xmit slot. As
245f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez			 * above, this cannot fail to find one.
246f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez			 */
247f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez			avp->av_bslot = 0;
248f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez			for (slot = 0; slot < ATH_BCBUF; slot++)
2492c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinen				if (sc->beacon.bslot[slot] == NULL) {
250f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez					avp->av_bslot = slot;
251014cf3bb1e19a61c53666d7f990f584f1b7af364Rajkumar Manoharan					avp->is_bslot_active = false;
252774610e4f26cb3d9da14a8b5974324c9e51017bdFelix Fietkau
253f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez					/* NB: keep looking for a double slot */
254774610e4f26cb3d9da14a8b5974324c9e51017bdFelix Fietkau					if (slot == 0 || !sc->beacon.bslot[slot-1])
255774610e4f26cb3d9da14a8b5974324c9e51017bdFelix Fietkau						break;
256f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez				}
2572c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinen			BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL);
2582c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinen			sc->beacon.bslot[avp->av_bslot] = vif;
25917d7904de85125c62c7258d7cb21207f26d04048Sujith			sc->nbcnvifs++;
260f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		}
261f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	}
262f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
2639fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith	/* release the previous beacon frame, if it already exists. */
264f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	bf = avp->av_bcbuf;
265f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	if (bf->bf_mpdu != NULL) {
266a22be22ab8fe571cce88d0d30b49f297a563c4a7Sujith		skb = bf->bf_mpdu;
267c1739eb3e61e160f124bc842c219011916f63068Ben Greear		dma_unmap_single(sc->dev, bf->bf_buf_addr,
2689fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith				 skb->len, DMA_TO_DEVICE);
269f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		dev_kfree_skb_any(skb);
270f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		bf->bf_mpdu = NULL;
2716cf9e995f91e5bbffb2bef85feef490e5b67605dBen Greear		bf->bf_buf_addr = 0;
272f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	}
273f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
2749fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith	/* NB: the beacon data buffer must be 32-bit aligned. */
2755640b08ef7e88b606c740e746cb77bc97d78508eSujith	skb = ieee80211_beacon_get(sc->hw, vif);
276d7e86c3219a1287dd1350a590ee79c8753ff2420Felix Fietkau	if (skb == NULL)
277f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		return -ENOMEM;
278f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
279459f5f90f1bd959ced04761406415b178b315177Sujith	tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
280dd347f2fb2ddb20a80e9a8285252bf208ab91398Felix Fietkau	sc->beacon.bc_tstamp = (u32) le64_to_cpu(tstamp);
2814ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen	/* Calculate a TSF adjustment factor required for staggered beacons. */
282f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	if (avp->av_bslot > 0) {
283f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		u64 tsfadjust;
284f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		int intval;
285f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
2869814f6b34be5179849c0872e81eb99286ef4b051Steve Brown		intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
287f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
288f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		/*
2894ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen		 * Calculate the TSF offset for this beacon slot, i.e., the
2904ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen		 * number of usecs that need to be added to the timestamp field
2914ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen		 * in Beacon and Probe Response frames. Beacon slot 0 is
2924ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen		 * processed at the correct offset, so it does not require TSF
2934ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen		 * adjustment. Other slots are adjusted to get the timestamp
2944ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen		 * close to the TBTT for the BSS.
295f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		 */
296dd347f2fb2ddb20a80e9a8285252bf208ab91398Felix Fietkau		tsfadjust = TU_TO_USEC(intval * avp->av_bslot) / ATH_BCBUF;
297dd347f2fb2ddb20a80e9a8285252bf208ab91398Felix Fietkau		avp->tsf_adjust = cpu_to_le64(tsfadjust);
298f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
299d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, BEACON,
300226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			"stagger beacons, bslot %d intval %u tsfadjust %llu\n",
301226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			avp->av_bslot, intval, (unsigned long long)tsfadjust);
302f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
3034ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen		((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp =
3044ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen			avp->tsf_adjust;
3054ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen	} else
3064ed96f04f8a1869757f4dd4a9283a18ec63c442fJouni Malinen		avp->tsf_adjust = cpu_to_le64(0);
307f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
308f8316df10c4e3bec5b4c3a5a8e026c577640c3a6Luis R. Rodriguez	bf->bf_mpdu = skb;
309c1739eb3e61e160f124bc842c219011916f63068Ben Greear	bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
310c1739eb3e61e160f124bc842c219011916f63068Ben Greear					 skb->len, DMA_TO_DEVICE);
3117da3c55ce849e17fd9017c7bf770a03fa083d95bGabor Juhos	if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
312f8316df10c4e3bec5b4c3a5a8e026c577640c3a6Luis R. Rodriguez		dev_kfree_skb_any(skb);
313f8316df10c4e3bec5b4c3a5a8e026c577640c3a6Luis R. Rodriguez		bf->bf_mpdu = NULL;
3146cf9e995f91e5bbffb2bef85feef490e5b67605dBen Greear		bf->bf_buf_addr = 0;
3153800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(common, "dma_mapping_error on beacon alloc\n");
316f8316df10c4e3bec5b4c3a5a8e026c577640c3a6Luis R. Rodriguez		return -ENOMEM;
317f8316df10c4e3bec5b4c3a5a8e026c577640c3a6Luis R. Rodriguez	}
318014cf3bb1e19a61c53666d7f990f584f1b7af364Rajkumar Manoharan	avp->is_bslot_active = true;
319f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
320f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	return 0;
321f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez}
322f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
32317d7904de85125c62c7258d7cb21207f26d04048Sujithvoid ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp)
324f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez{
325f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	if (avp->av_bcbuf != NULL) {
326f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		struct ath_buf *bf;
327f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
328f60c49b67dd6db2ccb740a6a671414f9dab00c4fRajkumar Manoharan		avp->is_bslot_active = false;
329f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		if (avp->av_bslot != -1) {
3302c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinen			sc->beacon.bslot[avp->av_bslot] = NULL;
33117d7904de85125c62c7258d7cb21207f26d04048Sujith			sc->nbcnvifs--;
33266da424177db4f4f2fa7a462db5912655aad966fRajkumar Manoharan			avp->av_bslot = -1;
333f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		}
334f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
335f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		bf = avp->av_bcbuf;
336f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		if (bf->bf_mpdu != NULL) {
337a22be22ab8fe571cce88d0d30b49f297a563c4a7Sujith			struct sk_buff *skb = bf->bf_mpdu;
338c1739eb3e61e160f124bc842c219011916f63068Ben Greear			dma_unmap_single(sc->dev, bf->bf_buf_addr,
3399fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith					 skb->len, DMA_TO_DEVICE);
340f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez			dev_kfree_skb_any(skb);
341f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez			bf->bf_mpdu = NULL;
3426cf9e995f91e5bbffb2bef85feef490e5b67605dBen Greear			bf->bf_buf_addr = 0;
343f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		}
344b77f483fcf0579de28873828897f53371a33a0eaSujith		list_add_tail(&bf->list, &sc->beacon.bbuf);
345f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
346f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		avp->av_bcbuf = NULL;
347f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	}
348f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez}
349f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
3509fc9ab0a6929c9f137747df0ecf294e9582607f9Sujithvoid ath_beacon_tasklet(unsigned long data)
351f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez{
352f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	struct ath_softc *sc = (struct ath_softc *)data;
3539814f6b34be5179849c0872e81eb99286ef4b051Steve Brown	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
354cbe61d8a41210600bc76b212edcd4dc0f55c014fSujith	struct ath_hw *ah = sc->sc_ah;
355c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez	struct ath_common *common = ath9k_hw_common(ah);
356f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	struct ath_buf *bf = NULL;
3572c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinen	struct ieee80211_vif *vif;
35898f0a5eb02bbfff662664bf65f469dc4abd701fdMohammed Shafi Shajakhan	bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
3592c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinen	int slot;
360c6820f1e6c8273ca4b8f94c2354193d19e1a5c47Felix Fietkau	u32 bfaddr, bc = 0;
361f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
362f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	/*
363f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 * Check if the previous beacon has gone out.  If
364f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 * not don't try to post another, skip this period
365f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 * and wait for the next.  Missed beacons indicate
366f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 * a problem and should not occur.  If we miss too
367f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 * many consecutive beacons reset the device.
368f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 */
369b77f483fcf0579de28873828897f53371a33a0eaSujith	if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) {
370b77f483fcf0579de28873828897f53371a33a0eaSujith		sc->beacon.bmisscnt++;
3719546aae0863c12a3d00b1ed5cbd316520733200bSujith
372c944daf46a8cfa50d6c1f54d4842180d0384c594Felix Fietkau		if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) {
373d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			ath_dbg(common, BSTUCK,
374226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				"missed %u consecutive beacons\n",
375226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				sc->beacon.bmisscnt);
376efff395e97fffd55c60c77c09a18deba8d84e2c0Felix Fietkau			ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
37787c510fe2d4f193cd4eb518364a2dfa5059b1218Felix Fietkau			if (sc->beacon.bmisscnt > 3)
37887c510fe2d4f193cd4eb518364a2dfa5059b1218Felix Fietkau				ath9k_hw_bstuck_nfcal(ah);
379b77f483fcf0579de28873828897f53371a33a0eaSujith		} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
380d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			ath_dbg(common, BSTUCK, "beacon is officially stuck\n");
381b74444f8a9039603715973a56df588a5d800c4efJeff Hansen			sc->sc_flags |= SC_OP_TSF_RESET;
382236de5149b9cbec3e76aef00a4663a8de7feeebeFelix Fietkau			ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
383f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		}
3849546aae0863c12a3d00b1ed5cbd316520733200bSujith
385f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		return;
386f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	}
387980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith
388f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	/*
389f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 * Generate beacon frames. we are sending frames
390f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 * staggered so calculate the slot for this frame based
391f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 * on the tsf to safeguard against missing an swba.
392f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 */
393f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
394f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
395c6820f1e6c8273ca4b8f94c2354193d19e1a5c47Felix Fietkau	if (ah->opmode == NL80211_IFTYPE_AP) {
396c6820f1e6c8273ca4b8f94c2354193d19e1a5c47Felix Fietkau		u16 intval;
397c6820f1e6c8273ca4b8f94c2354193d19e1a5c47Felix Fietkau		u32 tsftu;
398c6820f1e6c8273ca4b8f94c2354193d19e1a5c47Felix Fietkau		u64 tsf;
399c6820f1e6c8273ca4b8f94c2354193d19e1a5c47Felix Fietkau
400c6820f1e6c8273ca4b8f94c2354193d19e1a5c47Felix Fietkau		intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
401c6820f1e6c8273ca4b8f94c2354193d19e1a5c47Felix Fietkau		tsf = ath9k_hw_gettsf64(ah);
402c6820f1e6c8273ca4b8f94c2354193d19e1a5c47Felix Fietkau		tsf += TU_TO_USEC(ah->config.sw_beacon_response_time);
403c6820f1e6c8273ca4b8f94c2354193d19e1a5c47Felix Fietkau		tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF);
404c6820f1e6c8273ca4b8f94c2354193d19e1a5c47Felix Fietkau		slot = (tsftu % (intval * ATH_BCBUF)) / intval;
405c6820f1e6c8273ca4b8f94c2354193d19e1a5c47Felix Fietkau		vif = sc->beacon.bslot[slot];
406c6820f1e6c8273ca4b8f94c2354193d19e1a5c47Felix Fietkau
407d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, BEACON,
408c6820f1e6c8273ca4b8f94c2354193d19e1a5c47Felix Fietkau			"slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
409c6820f1e6c8273ca4b8f94c2354193d19e1a5c47Felix Fietkau			slot, tsf, tsftu / ATH_BCBUF, intval, vif);
410c6820f1e6c8273ca4b8f94c2354193d19e1a5c47Felix Fietkau	} else {
411c6820f1e6c8273ca4b8f94c2354193d19e1a5c47Felix Fietkau		slot = 0;
412c6820f1e6c8273ca4b8f94c2354193d19e1a5c47Felix Fietkau		vif = sc->beacon.bslot[slot];
413c6820f1e6c8273ca4b8f94c2354193d19e1a5c47Felix Fietkau	}
414980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith
415980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith
416f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	bfaddr = 0;
4172c3db3d51ee1fcf84f5828788905a4c091b9ae27Jouni Malinen	if (vif) {
4187545daf498c43e548506212310e6c75382d2731dFelix Fietkau		bf = ath_beacon_generate(sc->hw, vif);
419f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		if (bf != NULL) {
420f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez			bfaddr = bf->bf_daddr;
421f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez			bc = 1;
422f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		}
423c944daf46a8cfa50d6c1f54d4842180d0384c594Felix Fietkau
424c944daf46a8cfa50d6c1f54d4842180d0384c594Felix Fietkau		if (sc->beacon.bmisscnt != 0) {
425d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			ath_dbg(common, BSTUCK,
426c944daf46a8cfa50d6c1f54d4842180d0384c594Felix Fietkau				"resume beacon xmit after %u misses\n",
427c944daf46a8cfa50d6c1f54d4842180d0384c594Felix Fietkau				sc->beacon.bmisscnt);
428c944daf46a8cfa50d6c1f54d4842180d0384c594Felix Fietkau			sc->beacon.bmisscnt = 0;
429c944daf46a8cfa50d6c1f54d4842180d0384c594Felix Fietkau		}
430f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	}
4319546aae0863c12a3d00b1ed5cbd316520733200bSujith
432f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	/*
433f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 * Handle slot time change when a non-ERP station joins/leaves
434f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 * an 11g network.  The 802.11 layer notifies us via callback,
435f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 * we mark updateslot, then wait one beacon before effecting
436f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 * the change.  This gives associated stations at least one
437f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 * beacon interval to note the state change.
438f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 *
439f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 * NB: The slot time change state machine is clocked according
440f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 *     to whether we are bursting or staggering beacons.  We
441f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 *     recognize the request to update and record the current
442f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 *     slot then don't transition until that slot is reached
443f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 *     again.  If we miss a beacon for that slot then we'll be
444f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 *     slow to transition but we'll be sure at least one beacon
445f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 *     interval has passed.  When bursting slot is always left
446f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 *     set to ATH_BCBUF so this check is a noop.
447f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	 */
448b77f483fcf0579de28873828897f53371a33a0eaSujith	if (sc->beacon.updateslot == UPDATE) {
449b77f483fcf0579de28873828897f53371a33a0eaSujith		sc->beacon.updateslot = COMMIT; /* commit next beacon */
450b77f483fcf0579de28873828897f53371a33a0eaSujith		sc->beacon.slotupdate = slot;
451b77f483fcf0579de28873828897f53371a33a0eaSujith	} else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) {
4520005baf4a31efe6de6f922f73ccbd3762a110062Felix Fietkau		ah->slottime = sc->beacon.slottime;
4530005baf4a31efe6de6f922f73ccbd3762a110062Felix Fietkau		ath9k_hw_init_global_settings(ah);
454b77f483fcf0579de28873828897f53371a33a0eaSujith		sc->beacon.updateslot = OK;
455ff37e337beb838d4c2540fa93b2c4c632ee17750Sujith	}
456f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	if (bfaddr != 0) {
457f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez		/* NB: cabq traffic should already be queued and primed */
458b77f483fcf0579de28873828897f53371a33a0eaSujith		ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr);
45998f0a5eb02bbfff662664bf65f469dc4abd701fdMohammed Shafi Shajakhan
46098f0a5eb02bbfff662664bf65f469dc4abd701fdMohammed Shafi Shajakhan		if (!edma)
46198f0a5eb02bbfff662664bf65f469dc4abd701fdMohammed Shafi Shajakhan			ath9k_hw_txstart(ah, sc->beacon.beaconq);
462f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
46317d7904de85125c62c7258d7cb21207f26d04048Sujith		sc->beacon.ast_be_xmit += bc;     /* XXX per-vif? */
464f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	}
465f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez}
466f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
46721526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguezstatic void ath9k_beacon_init(struct ath_softc *sc,
46821526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez			      u32 next_beacon,
46921526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez			      u32 beacon_period)
47021526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez{
471dd347f2fb2ddb20a80e9a8285252bf208ab91398Felix Fietkau	if (sc->sc_flags & SC_OP_TSF_RESET) {
47221526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez		ath9k_ps_wakeup(sc);
473dd347f2fb2ddb20a80e9a8285252bf208ab91398Felix Fietkau		ath9k_hw_reset_tsf(sc->sc_ah);
474dd347f2fb2ddb20a80e9a8285252bf208ab91398Felix Fietkau	}
47521526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez
47621526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez	ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period);
47721526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez
478dd347f2fb2ddb20a80e9a8285252bf208ab91398Felix Fietkau	if (sc->sc_flags & SC_OP_TSF_RESET) {
47921526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez		ath9k_ps_restore(sc);
480dd347f2fb2ddb20a80e9a8285252bf208ab91398Felix Fietkau		sc->sc_flags &= ~SC_OP_TSF_RESET;
481dd347f2fb2ddb20a80e9a8285252bf208ab91398Felix Fietkau	}
48221526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez}
48321526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez
484f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez/*
4855379c8a26686e12058e23322615df68f9123bccdSujith * For multi-bss ap support beacons are either staggered evenly over N slots or
4865379c8a26686e12058e23322615df68f9123bccdSujith * burst together.  For the former arrange for the SWBA to be delivered for each
4875379c8a26686e12058e23322615df68f9123bccdSujith * slot. Slots that are not occupied will generate nothing.
488f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez */
4895379c8a26686e12058e23322615df68f9123bccdSujithstatic void ath_beacon_config_ap(struct ath_softc *sc,
490d31e20af9f65e38429a3ed32175f8e233bdcd2b2Vasanthakumar Thiagarajan				 struct ath_beacon_config *conf)
491f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez{
4923069168c82d65f88e4ac76eda09baff02adfd743Pavel Roskin	struct ath_hw *ah = sc->sc_ah;
493980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith	u32 nexttbtt, intval;
494f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
4955379c8a26686e12058e23322615df68f9123bccdSujith	/* NB: the beacon interval is kept internally in TU's */
496f29f5c0882bdd58c42b8176ee0b578f92589fda2Rajkumar Manoharan	intval = TU_TO_USEC(conf->beacon_interval);
4975379c8a26686e12058e23322615df68f9123bccdSujith	intval /= ATH_BCBUF;    /* for staggered beacons */
4985379c8a26686e12058e23322615df68f9123bccdSujith	nexttbtt = intval;
499d8728ee919282c7b01b65cd479ec1e2a9c5d3ba8Felix Fietkau
5005379c8a26686e12058e23322615df68f9123bccdSujith	/*
5015379c8a26686e12058e23322615df68f9123bccdSujith	 * In AP mode we enable the beacon timers and SWBA interrupts to
5025379c8a26686e12058e23322615df68f9123bccdSujith	 * prepare beacon frames.
5035379c8a26686e12058e23322615df68f9123bccdSujith	 */
5043069168c82d65f88e4ac76eda09baff02adfd743Pavel Roskin	ah->imask |= ATH9K_INT_SWBA;
5055379c8a26686e12058e23322615df68f9123bccdSujith	ath_beaconq_config(sc);
506f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
5075379c8a26686e12058e23322615df68f9123bccdSujith	/* Set the computed AP beacon timers */
508f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
5094df3071ebd92ef7115b409da64d0eb405d24a631Felix Fietkau	ath9k_hw_disable_interrupts(ah);
510c31c8261bf7b817e323d29ba66c031f6b0982680Felix Fietkau	sc->sc_flags |= SC_OP_TSF_RESET;
51121526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez	ath9k_beacon_init(sc, nexttbtt, intval);
5125379c8a26686e12058e23322615df68f9123bccdSujith	sc->beacon.bmisscnt = 0;
51372d874c67c3cdf21ca95045baabac6a5843222d8Felix Fietkau	ath9k_hw_set_interrupts(ah);
514b037b693265e5c83ddc3f003a713d19b9832bf24Rajkumar Manoharan	ath9k_hw_enable_interrupts(ah);
5155379c8a26686e12058e23322615df68f9123bccdSujith}
516459f5f90f1bd959ced04761406415b178b315177Sujith
5175379c8a26686e12058e23322615df68f9123bccdSujith/*
5185379c8a26686e12058e23322615df68f9123bccdSujith * This sets up the beacon timers according to the timestamp of the last
5195379c8a26686e12058e23322615df68f9123bccdSujith * received beacon and the current TSF, configures PCF and DTIM
5205379c8a26686e12058e23322615df68f9123bccdSujith * handling, programs the sleep registers so the hardware will wakeup in
5215379c8a26686e12058e23322615df68f9123bccdSujith * time to receive beacons, and configures the beacon miss handling so
5225379c8a26686e12058e23322615df68f9123bccdSujith * we'll receive a BMISS interrupt when we stop seeing beacons from the AP
5235379c8a26686e12058e23322615df68f9123bccdSujith * we've associated with.
5245379c8a26686e12058e23322615df68f9123bccdSujith */
5255379c8a26686e12058e23322615df68f9123bccdSujithstatic void ath_beacon_config_sta(struct ath_softc *sc,
526d31e20af9f65e38429a3ed32175f8e233bdcd2b2Vasanthakumar Thiagarajan				  struct ath_beacon_config *conf)
5275379c8a26686e12058e23322615df68f9123bccdSujith{
5283069168c82d65f88e4ac76eda09baff02adfd743Pavel Roskin	struct ath_hw *ah = sc->sc_ah;
5293069168c82d65f88e4ac76eda09baff02adfd743Pavel Roskin	struct ath_common *common = ath9k_hw_common(ah);
5305379c8a26686e12058e23322615df68f9123bccdSujith	struct ath9k_beacon_state bs;
5315379c8a26686e12058e23322615df68f9123bccdSujith	int dtimperiod, dtimcount, sleepduration;
5325379c8a26686e12058e23322615df68f9123bccdSujith	int cfpperiod, cfpcount;
5335379c8a26686e12058e23322615df68f9123bccdSujith	u32 nexttbtt = 0, intval, tsftu;
5345379c8a26686e12058e23322615df68f9123bccdSujith	u64 tsf;
535267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen	int num_beacons, offset, dtim_dec_count, cfp_dec_count;
5365379c8a26686e12058e23322615df68f9123bccdSujith
5371a20034a73a40b8056731f9db0c535cec2961eb7Senthil Balasubramanian	/* No need to configure beacon if we are not associated */
5381a20034a73a40b8056731f9db0c535cec2961eb7Senthil Balasubramanian	if (!common->curaid) {
539d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, BEACON,
540226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			"STA is not yet associated..skipping beacon config\n");
5411a20034a73a40b8056731f9db0c535cec2961eb7Senthil Balasubramanian		return;
5421a20034a73a40b8056731f9db0c535cec2961eb7Senthil Balasubramanian	}
5431a20034a73a40b8056731f9db0c535cec2961eb7Senthil Balasubramanian
5445379c8a26686e12058e23322615df68f9123bccdSujith	memset(&bs, 0, sizeof(bs));
545f29f5c0882bdd58c42b8176ee0b578f92589fda2Rajkumar Manoharan	intval = conf->beacon_interval;
5465379c8a26686e12058e23322615df68f9123bccdSujith
5475379c8a26686e12058e23322615df68f9123bccdSujith	/*
5485379c8a26686e12058e23322615df68f9123bccdSujith	 * Setup dtim and cfp parameters according to
5495379c8a26686e12058e23322615df68f9123bccdSujith	 * last beacon we received (which may be none).
5505379c8a26686e12058e23322615df68f9123bccdSujith	 */
5515379c8a26686e12058e23322615df68f9123bccdSujith	dtimperiod = conf->dtim_period;
5525379c8a26686e12058e23322615df68f9123bccdSujith	dtimcount = conf->dtim_count;
5535379c8a26686e12058e23322615df68f9123bccdSujith	if (dtimcount >= dtimperiod)	/* NB: sanity check */
5545379c8a26686e12058e23322615df68f9123bccdSujith		dtimcount = 0;
5555379c8a26686e12058e23322615df68f9123bccdSujith	cfpperiod = 1;			/* NB: no PCF support yet */
5565379c8a26686e12058e23322615df68f9123bccdSujith	cfpcount = 0;
5575379c8a26686e12058e23322615df68f9123bccdSujith
5585379c8a26686e12058e23322615df68f9123bccdSujith	sleepduration = conf->listen_interval * intval;
5595379c8a26686e12058e23322615df68f9123bccdSujith
5605379c8a26686e12058e23322615df68f9123bccdSujith	/*
5615379c8a26686e12058e23322615df68f9123bccdSujith	 * Pull nexttbtt forward to reflect the current
5625379c8a26686e12058e23322615df68f9123bccdSujith	 * TSF and calculate dtim+cfp state for the result.
5635379c8a26686e12058e23322615df68f9123bccdSujith	 */
5643069168c82d65f88e4ac76eda09baff02adfd743Pavel Roskin	tsf = ath9k_hw_gettsf64(ah);
5655379c8a26686e12058e23322615df68f9123bccdSujith	tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
566267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen
567267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen	num_beacons = tsftu / intval + 1;
568267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen	offset = tsftu % intval;
569267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen	nexttbtt = tsftu - offset;
570267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen	if (offset)
5715379c8a26686e12058e23322615df68f9123bccdSujith		nexttbtt += intval;
572267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen
573267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen	/* DTIM Beacon every dtimperiod Beacon */
574267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen	dtim_dec_count = num_beacons % dtimperiod;
575267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen	/* CFP every cfpperiod DTIM Beacon */
576267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen	cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod;
577267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen	if (dtim_dec_count)
578267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen		cfp_dec_count++;
579267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen
580267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen	dtimcount -= dtim_dec_count;
581267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen	if (dtimcount < 0)
582267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen		dtimcount += dtimperiod;
583267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen
584267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen	cfpcount -= cfp_dec_count;
585267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen	if (cfpcount < 0)
586267a90127472be70b02ab13cbd355b5013e2aa51Jouni Malinen		cfpcount += cfpperiod;
5875379c8a26686e12058e23322615df68f9123bccdSujith
5885379c8a26686e12058e23322615df68f9123bccdSujith	bs.bs_intval = intval;
5895379c8a26686e12058e23322615df68f9123bccdSujith	bs.bs_nexttbtt = nexttbtt;
5905379c8a26686e12058e23322615df68f9123bccdSujith	bs.bs_dtimperiod = dtimperiod*intval;
5915379c8a26686e12058e23322615df68f9123bccdSujith	bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval;
5925379c8a26686e12058e23322615df68f9123bccdSujith	bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod;
5935379c8a26686e12058e23322615df68f9123bccdSujith	bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
5945379c8a26686e12058e23322615df68f9123bccdSujith	bs.bs_cfpmaxduration = 0;
5955379c8a26686e12058e23322615df68f9123bccdSujith
5965379c8a26686e12058e23322615df68f9123bccdSujith	/*
5975379c8a26686e12058e23322615df68f9123bccdSujith	 * Calculate the number of consecutive beacons to miss* before taking
5985379c8a26686e12058e23322615df68f9123bccdSujith	 * a BMISS interrupt. The configuration is specified in TU so we only
5995379c8a26686e12058e23322615df68f9123bccdSujith	 * need calculate based	on the beacon interval.  Note that we clamp the
6005379c8a26686e12058e23322615df68f9123bccdSujith	 * result to at most 15 beacons.
6015379c8a26686e12058e23322615df68f9123bccdSujith	 */
6025379c8a26686e12058e23322615df68f9123bccdSujith	if (sleepduration > intval) {
6035379c8a26686e12058e23322615df68f9123bccdSujith		bs.bs_bmissthreshold = conf->listen_interval *
6045379c8a26686e12058e23322615df68f9123bccdSujith			ATH_DEFAULT_BMISS_LIMIT / 2;
605f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	} else {
6065379c8a26686e12058e23322615df68f9123bccdSujith		bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval);
6075379c8a26686e12058e23322615df68f9123bccdSujith		if (bs.bs_bmissthreshold > 15)
6085379c8a26686e12058e23322615df68f9123bccdSujith			bs.bs_bmissthreshold = 15;
6095379c8a26686e12058e23322615df68f9123bccdSujith		else if (bs.bs_bmissthreshold <= 0)
6105379c8a26686e12058e23322615df68f9123bccdSujith			bs.bs_bmissthreshold = 1;
611f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez	}
612f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
6135379c8a26686e12058e23322615df68f9123bccdSujith	/*
6145379c8a26686e12058e23322615df68f9123bccdSujith	 * Calculate sleep duration. The configuration is given in ms.
6155379c8a26686e12058e23322615df68f9123bccdSujith	 * We ensure a multiple of the beacon period is used. Also, if the sleep
6165379c8a26686e12058e23322615df68f9123bccdSujith	 * duration is greater than the DTIM period then it makes senses
6175379c8a26686e12058e23322615df68f9123bccdSujith	 * to make it a multiple of that.
6185379c8a26686e12058e23322615df68f9123bccdSujith	 *
6195379c8a26686e12058e23322615df68f9123bccdSujith	 * XXX fixed at 100ms
6205379c8a26686e12058e23322615df68f9123bccdSujith	 */
621980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith
6225379c8a26686e12058e23322615df68f9123bccdSujith	bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration);
6235379c8a26686e12058e23322615df68f9123bccdSujith	if (bs.bs_sleepduration > bs.bs_dtimperiod)
6245379c8a26686e12058e23322615df68f9123bccdSujith		bs.bs_sleepduration = bs.bs_dtimperiod;
625980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith
6265379c8a26686e12058e23322615df68f9123bccdSujith	/* TSF out of range threshold fixed at 1 second */
6275379c8a26686e12058e23322615df68f9123bccdSujith	bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
628f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
629d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches	ath_dbg(common, BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu);
630d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches	ath_dbg(common, BEACON,
631226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches		"bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
632226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches		bs.bs_bmissthreshold, bs.bs_sleepduration,
633226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches		bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
634f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
6355379c8a26686e12058e23322615df68f9123bccdSujith	/* Set the computed STA beacon timers */
636980b24da6f1725c2d0b32c9484d06cd7d09d3c4bSujith
6374df3071ebd92ef7115b409da64d0eb405d24a631Felix Fietkau	ath9k_hw_disable_interrupts(ah);
6383069168c82d65f88e4ac76eda09baff02adfd743Pavel Roskin	ath9k_hw_set_sta_beacon_timers(ah, &bs);
6393069168c82d65f88e4ac76eda09baff02adfd743Pavel Roskin	ah->imask |= ATH9K_INT_BMISS;
640deb751880af6f2dce6cdc232a7b023f2b58cd815Rajkumar Manoharan
64172d874c67c3cdf21ca95045baabac6a5843222d8Felix Fietkau	ath9k_hw_set_interrupts(ah);
642e8fe7336849e469978c9bbcc435903595912c4d3Rajkumar Manoharan	ath9k_hw_enable_interrupts(ah);
6435379c8a26686e12058e23322615df68f9123bccdSujith}
644f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
6455379c8a26686e12058e23322615df68f9123bccdSujithstatic void ath_beacon_config_adhoc(struct ath_softc *sc,
646ee832d3e9e72abf83931205a2f5379944be501c2Mohammed Shafi Shajakhan				    struct ath_beacon_config *conf)
6475379c8a26686e12058e23322615df68f9123bccdSujith{
6483069168c82d65f88e4ac76eda09baff02adfd743Pavel Roskin	struct ath_hw *ah = sc->sc_ah;
6493069168c82d65f88e4ac76eda09baff02adfd743Pavel Roskin	struct ath_common *common = ath9k_hw_common(ah);
65081168e509f06aa205b240c1804ec2b9b5add4772Fabrice Deyber	u32 tsf, intval, nexttbtt;
651dd347f2fb2ddb20a80e9a8285252bf208ab91398Felix Fietkau
652ba4903f97a275ed0967b58ff882f8ab41bec24adFelix Fietkau	ath9k_reset_beacon_status(sc);
653ba4903f97a275ed0967b58ff882f8ab41bec24adFelix Fietkau
654f29f5c0882bdd58c42b8176ee0b578f92589fda2Rajkumar Manoharan	intval = TU_TO_USEC(conf->beacon_interval);
65581168e509f06aa205b240c1804ec2b9b5add4772Fabrice Deyber	tsf = roundup(ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE), intval);
65681168e509f06aa205b240c1804ec2b9b5add4772Fabrice Deyber	nexttbtt = tsf + intval;
657f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
658d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches	ath_dbg(common, BEACON, "IBSS nexttbtt %u intval %u (%u)\n",
659226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches		nexttbtt, intval, conf->beacon_interval);
6609fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith
6615379c8a26686e12058e23322615df68f9123bccdSujith	/*
6625379c8a26686e12058e23322615df68f9123bccdSujith	 * In IBSS mode enable the beacon timers but only enable SWBA interrupts
6635379c8a26686e12058e23322615df68f9123bccdSujith	 * if we need to manually prepare beacon frames.  Otherwise we use a
6645379c8a26686e12058e23322615df68f9123bccdSujith	 * self-linked tx descriptor and let the hardware deal with things.
6655379c8a26686e12058e23322615df68f9123bccdSujith	 */
666a65e4cb402b5f3e120570ba1faca4354d47e8f2fFelix Fietkau	ah->imask |= ATH9K_INT_SWBA;
6679fc9ab0a6929c9f137747df0ecf294e9582607f9Sujith
6685379c8a26686e12058e23322615df68f9123bccdSujith	ath_beaconq_config(sc);
6695379c8a26686e12058e23322615df68f9123bccdSujith
6705379c8a26686e12058e23322615df68f9123bccdSujith	/* Set the computed ADHOC beacon timers */
6715379c8a26686e12058e23322615df68f9123bccdSujith
6724df3071ebd92ef7115b409da64d0eb405d24a631Felix Fietkau	ath9k_hw_disable_interrupts(ah);
67321526d57ad98635fe12dc8efe46a3d992439a443Luis R. Rodriguez	ath9k_beacon_init(sc, nexttbtt, intval);
6745379c8a26686e12058e23322615df68f9123bccdSujith	sc->beacon.bmisscnt = 0;
675e8fe7336849e469978c9bbcc435903595912c4d3Rajkumar Manoharan
67672d874c67c3cdf21ca95045baabac6a5843222d8Felix Fietkau	ath9k_hw_set_interrupts(ah);
677e8fe7336849e469978c9bbcc435903595912c4d3Rajkumar Manoharan	ath9k_hw_enable_interrupts(ah);
678f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez}
679f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez
68099e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharanstatic bool ath9k_allow_beacon_config(struct ath_softc *sc,
68199e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan				      struct ieee80211_vif *vif)
682f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez{
6836b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
684c46917bb53a546f60c7d3103407fe953c418dd5bLuis R. Rodriguez	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
68599e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
68699e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	struct ath_vif *avp = (void *)vif->drv_priv;
6875379c8a26686e12058e23322615df68f9123bccdSujith
68899e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	/*
68999e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	 * Can not have different beacon interval on multiple
69099e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	 * AP interface case
69199e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	 */
69299e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
69399e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	    (sc->nbcnvifs > 1) &&
69499e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	    (vif->type == NL80211_IFTYPE_AP) &&
69599e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	    (cur_conf->beacon_interval != bss_conf->beacon_int)) {
696d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CONFIG,
697d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			"Changing beacon interval of multiple AP interfaces !\n");
69899e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan		return false;
69999e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	}
70099e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	/*
70199e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	 * Can not configure station vif's beacon config
70299e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	 * while on AP opmode
70399e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	 */
70499e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
70599e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	    (vif->type != NL80211_IFTYPE_AP)) {
706d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CONFIG,
70799e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan			"STA vif's beacon not allowed on AP mode\n");
70899e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan		return false;
70999e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	}
71099e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	/*
71199e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	 * Do not allow beacon config if HW was already configured
71299e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	 * with another STA vif
71399e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	 */
71499e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
71599e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	    (vif->type == NL80211_IFTYPE_STATION) &&
71699e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	    (sc->sc_flags & SC_OP_BEACONS) &&
71799e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	    !avp->primary_sta_vif) {
718d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CONFIG,
71999e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan			"Beacon already configured for a station interface\n");
72099e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan		return false;
721ee832d3e9e72abf83931205a2f5379944be501c2Mohammed Shafi Shajakhan	}
72299e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	return true;
72399e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan}
72499e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan
72599e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharanvoid ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
72699e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan{
72799e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
72899e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
729ee832d3e9e72abf83931205a2f5379944be501c2Mohammed Shafi Shajakhan
73099e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	if (!ath9k_allow_beacon_config(sc, vif))
73199e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan		return;
73299e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan
73399e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	/* Setup the beacon configuration parameters */
73499e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	cur_conf->beacon_interval = bss_conf->beacon_int;
73599e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	cur_conf->dtim_period = bss_conf->dtim_period;
7364801416c76a3a355076d6d371c00270dfe332e1cBen Greear	cur_conf->listen_interval = 1;
7374801416c76a3a355076d6d371c00270dfe332e1cBen Greear	cur_conf->dtim_count = 1;
7384801416c76a3a355076d6d371c00270dfe332e1cBen Greear	cur_conf->bmiss_timeout =
7394801416c76a3a355076d6d371c00270dfe332e1cBen Greear		ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
7406b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan
741c4f9f16b309b65f9f578ec4ba78b3efa106cf65dVasanthakumar Thiagarajan	/*
742c4f9f16b309b65f9f578ec4ba78b3efa106cf65dVasanthakumar Thiagarajan	 * It looks like mac80211 may end up using beacon interval of zero in
743c4f9f16b309b65f9f578ec4ba78b3efa106cf65dVasanthakumar Thiagarajan	 * some cases (at least for mesh point). Avoid getting into an
744c4f9f16b309b65f9f578ec4ba78b3efa106cf65dVasanthakumar Thiagarajan	 * infinite loop by using a bit safer value instead. To be safe,
745c4f9f16b309b65f9f578ec4ba78b3efa106cf65dVasanthakumar Thiagarajan	 * do sanity check on beacon interval for all operating modes.
746c4f9f16b309b65f9f578ec4ba78b3efa106cf65dVasanthakumar Thiagarajan	 */
747c4f9f16b309b65f9f578ec4ba78b3efa106cf65dVasanthakumar Thiagarajan	if (cur_conf->beacon_interval == 0)
748c4f9f16b309b65f9f578ec4ba78b3efa106cf65dVasanthakumar Thiagarajan		cur_conf->beacon_interval = 100;
7496b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan
750ee832d3e9e72abf83931205a2f5379944be501c2Mohammed Shafi Shajakhan	/*
7513a2329f2680796b0c09ff207803ea880a481c3a4Mohammed Shafi Shajakhan	 * We don't parse dtim period from mac80211 during the driver
7523a2329f2680796b0c09ff207803ea880a481c3a4Mohammed Shafi Shajakhan	 * initialization as it breaks association with hidden-ssid
7533a2329f2680796b0c09ff207803ea880a481c3a4Mohammed Shafi Shajakhan	 * AP and it causes latency in roaming
754ee832d3e9e72abf83931205a2f5379944be501c2Mohammed Shafi Shajakhan	 */
755ee832d3e9e72abf83931205a2f5379944be501c2Mohammed Shafi Shajakhan	if (cur_conf->dtim_period == 0)
756ee832d3e9e72abf83931205a2f5379944be501c2Mohammed Shafi Shajakhan		cur_conf->dtim_period = 1;
757ee832d3e9e72abf83931205a2f5379944be501c2Mohammed Shafi Shajakhan
75899e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	ath_set_beacon(sc);
75999e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan}
76099e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan
7618e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharanstatic bool ath_has_valid_bslot(struct ath_softc *sc)
7628e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharan{
7638e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharan	struct ath_vif *avp;
7648e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharan	int slot;
7658e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharan	bool found = false;
7668e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharan
7678e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharan	for (slot = 0; slot < ATH_BCBUF; slot++) {
7688e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharan		if (sc->beacon.bslot[slot]) {
7698e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharan			avp = (void *)sc->beacon.bslot[slot]->drv_priv;
7708e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharan			if (avp->is_bslot_active) {
7718e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharan				found = true;
7728e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharan				break;
7738e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharan			}
7748e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharan		}
7758e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharan	}
7768e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharan	return found;
7778e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharan}
7788e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharan
7798e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharan
78099e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharanvoid ath_set_beacon(struct ath_softc *sc)
78199e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan{
78299e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
78399e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
78499e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan
78526cd322bacd3d65fffef6f8418c2fdad5b42e4b5Felix Fietkau	switch (sc->sc_ah->opmode) {
7866b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan	case NL80211_IFTYPE_AP:
7878e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharan		if (ath_has_valid_bslot(sc))
7888e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharan			ath_beacon_config_ap(sc, cur_conf);
7896b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan		break;
7906b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan	case NL80211_IFTYPE_ADHOC:
7916b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan	case NL80211_IFTYPE_MESH_POINT:
792ee832d3e9e72abf83931205a2f5379944be501c2Mohammed Shafi Shajakhan		ath_beacon_config_adhoc(sc, cur_conf);
7936b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan		break;
7946b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan	case NL80211_IFTYPE_STATION:
7956b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan		ath_beacon_config_sta(sc, cur_conf);
7966b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan		break;
7976b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan	default:
798d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CONFIG, "Unsupported beaconing mode\n");
7996b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan		return;
8006b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan	}
8016b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan
8026b96f93e962e25d38d7a73c0009597672d87c496Vasanthakumar Thiagarajan	sc->sc_flags |= SC_OP_BEACONS;
803f078f209704849c86bd43c0beccfc1f410ed1c66Luis R. Rodriguez}
804014cf3bb1e19a61c53666d7f990f584f1b7af364Rajkumar Manoharan
805014cf3bb1e19a61c53666d7f990f584f1b7af364Rajkumar Manoharanvoid ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
806014cf3bb1e19a61c53666d7f990f584f1b7af364Rajkumar Manoharan{
807014cf3bb1e19a61c53666d7f990f584f1b7af364Rajkumar Manoharan	struct ath_hw *ah = sc->sc_ah;
808014cf3bb1e19a61c53666d7f990f584f1b7af364Rajkumar Manoharan
8098e22ad323fb5b7cefb572bd8730e3abef95cdf90Rajkumar Manoharan	if (!ath_has_valid_bslot(sc))
81099e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan		return;
81199e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan
81299e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	ath9k_ps_wakeup(sc);
81399e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan	if (status) {
81499e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan		/* Re-enable beaconing */
81599e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4Rajkumar Manoharan		ah->imask |= ATH9K_INT_SWBA;
81672d874c67c3cdf21ca95045baabac6a5843222d8Felix Fietkau		ath9k_hw_set_interrupts(ah);
817014cf3bb1e19a61c53666d7f990f584f1b7af364Rajkumar Manoharan	} else {
818014cf3bb1e19a61c53666d7f990f584f1b7af364Rajkumar Manoharan		/* Disable SWBA interrupt */
819014cf3bb1e19a61c53666d7f990f584f1b7af364Rajkumar Manoharan		ah->imask &= ~ATH9K_INT_SWBA;
82072d874c67c3cdf21ca95045baabac6a5843222d8Felix Fietkau		ath9k_hw_set_interrupts(ah);
821014cf3bb1e19a61c53666d7f990f584f1b7af364Rajkumar Manoharan		tasklet_kill(&sc->bcon_tasklet);
822efff395e97fffd55c60c77c09a18deba8d84e2c0Felix Fietkau		ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
823014cf3bb1e19a61c53666d7f990f584f1b7af364Rajkumar Manoharan	}
824014cf3bb1e19a61c53666d7f990f584f1b7af364Rajkumar Manoharan	ath9k_ps_restore(sc);
825014cf3bb1e19a61c53666d7f990f584f1b7af364Rajkumar Manoharan}
826