Merge remote-tracking branches 'spi/topic/atmel', 'spi/topic/bcm2385', 'spi/topic...
[linux-2.6-block.git] / drivers / net / wireless / ath / ath9k / beacon.c
CommitLineData
f078f209 1/*
5b68138e 2 * Copyright (c) 2008-2011 Atheros Communications Inc.
f078f209
LR
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
b7f080cf 17#include <linux/dma-mapping.h>
394cf0a1 18#include "ath9k.h"
f078f209 19
5379c8a2
S
20#define FUDGE 2
21
ba4903f9
FF
22static void ath9k_reset_beacon_status(struct ath_softc *sc)
23{
24 sc->beacon.tx_processed = false;
25 sc->beacon.tx_last = false;
26}
27
f078f209 28/*
f078f209
LR
29 * This function will modify certain transmit queue properties depending on
30 * the operating mode of the station (AP or AdHoc). Parameters are AIFS
31 * settings and channel width min/max
32*/
7e52c8aa 33static void ath9k_beaconq_config(struct ath_softc *sc)
f078f209 34{
cbe61d8a 35 struct ath_hw *ah = sc->sc_ah;
c46917bb 36 struct ath_common *common = ath9k_hw_common(ah);
94db2936 37 struct ath9k_tx_queue_info qi, qi_be;
066dae93 38 struct ath_txq *txq;
f078f209 39
b77f483f 40 ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi);
7e52c8aa 41
2664d666
TP
42 if (sc->sc_ah->opmode == NL80211_IFTYPE_AP ||
43 sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) {
f078f209
LR
44 /* Always burst out beacon and CAB traffic. */
45 qi.tqi_aifs = 1;
46 qi.tqi_cwmin = 0;
47 qi.tqi_cwmax = 0;
48 } else {
49 /* Adhoc mode; important thing is to use 2x cwmin. */
bea843c7 50 txq = sc->tx.txq_map[IEEE80211_AC_BE];
066dae93 51 ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be);
94db2936 52 qi.tqi_aifs = qi_be.tqi_aifs;
d202caff
VN
53 if (ah->slottime == ATH9K_SLOT_TIME_20)
54 qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
55 else
56 qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
94db2936 57 qi.tqi_cwmax = qi_be.tqi_cwmax;
f078f209
LR
58 }
59
b77f483f 60 if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) {
7e52c8aa 61 ath_err(common, "Unable to update h/w beacon queue parameters\n");
f078f209 62 } else {
9fc9ab0a 63 ath9k_hw_resettxqueue(ah, sc->beacon.beaconq);
f078f209
LR
64 }
65}
66
67/*
f078f209 68 * Associates the beacon frame buffer with a transmit descriptor. Will set
dd347f2f
FF
69 * up rate codes, and channel flags. Beacons are always sent out at the
70 * lowest rate, and are not retried.
f078f209 71*/
fb6e252f 72static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
64b84010 73 struct ath_buf *bf, int rateidx)
f078f209 74{
a22be22a 75 struct sk_buff *skb = bf->bf_mpdu;
cbe61d8a 76 struct ath_hw *ah = sc->sc_ah;
43c27613 77 struct ath_common *common = ath9k_hw_common(ah);
493cf04f 78 struct ath_tx_info info;
545750d3 79 struct ieee80211_supported_band *sband;
493cf04f 80 u8 chainmask = ah->txchainmask;
8b537686 81 u8 i, rate = 0;
f078f209 82
bff11766 83 sband = &common->sbands[sc->cur_chandef.chan->band];
64b84010 84 rate = sband->bitrates[rateidx].hw_value;
d47a61aa 85 if (vif->bss_conf.use_short_preamble)
64b84010 86 rate |= sband->bitrates[rateidx].hw_value_short;
9fc9ab0a 87
493cf04f
FF
88 memset(&info, 0, sizeof(info));
89 info.pkt_len = skb->len + FCS_LEN;
90 info.type = ATH9K_PKT_TYPE_BEACON;
8b537686
LB
91 for (i = 0; i < 4; i++)
92 info.txpower[i] = MAX_RATE_POWER;
493cf04f
FF
93 info.keyix = ATH9K_TXKEYIX_INVALID;
94 info.keytype = ATH9K_KEY_TYPE_CLEAR;
cd484aeb 95 info.flags = ATH9K_TXDESC_NOACK | ATH9K_TXDESC_CLRDMASK;
493cf04f
FF
96
97 info.buf_addr[0] = bf->bf_buf_addr;
98 info.buf_len[0] = roundup(skb->len, 4);
99
100 info.is_first = true;
101 info.is_last = true;
102
103 info.qcu = sc->beacon.beaconq;
104
105 info.rates[0].Tries = 1;
106 info.rates[0].Rate = rate;
107 info.rates[0].ChSel = ath_txchainmask_reduction(sc, chainmask, rate);
108
109 ath9k_hw_set_txdesc(ah, bf->bf_desc, &info);
f078f209
LR
110}
111
fb6e252f
SM
112static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
113 struct ieee80211_vif *vif)
f078f209 114{
9ac58615 115 struct ath_softc *sc = hw->priv;
c46917bb 116 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
f078f209 117 struct ath_buf *bf;
aa45fe96 118 struct ath_vif *avp = (void *)vif->drv_priv;
f078f209 119 struct sk_buff *skb;
aa45fe96 120 struct ath_txq *cabq = sc->beacon.cabq;
147583c0 121 struct ieee80211_tx_info *info;
fb6e252f 122 struct ieee80211_mgmt *mgmt_hdr;
980b24da
S
123 int cabq_depth;
124
aa45fe96 125 if (avp->av_bcbuf == NULL)
f078f209 126 return NULL;
980b24da 127
f078f209 128 bf = avp->av_bcbuf;
a22be22a 129 skb = bf->bf_mpdu;
a8fff50e 130 if (skb) {
c1739eb3 131 dma_unmap_single(sc->dev, bf->bf_buf_addr,
9fc9ab0a 132 skb->len, DMA_TO_DEVICE);
3fbb9d95 133 dev_kfree_skb_any(skb);
6cf9e995 134 bf->bf_buf_addr = 0;
1adb2e2b 135 bf->bf_mpdu = NULL;
a8fff50e 136 }
f078f209 137
c52f33d0 138 skb = ieee80211_beacon_get(hw, vif);
a8fff50e
JM
139 if (skb == NULL)
140 return NULL;
fb6e252f
SM
141
142 bf->bf_mpdu = skb;
143
144 mgmt_hdr = (struct ieee80211_mgmt *)skb->data;
145 mgmt_hdr->u.beacon.timestamp = avp->tsf_adjust;
980b24da 146
147583c0 147 info = IEEE80211_SKB_CB(skb);
ca14405e
SM
148
149 ath_assign_seq(common, skb);
980b24da 150
3ae07d39
FF
151 if (vif->p2p)
152 ath9k_beacon_add_noa(sc, avp, skb);
153
c1739eb3
BG
154 bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
155 skb->len, DMA_TO_DEVICE);
7da3c55c 156 if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
f8316df1
LR
157 dev_kfree_skb_any(skb);
158 bf->bf_mpdu = NULL;
6cf9e995 159 bf->bf_buf_addr = 0;
3800276a 160 ath_err(common, "dma_mapping_error on beaconing\n");
f8316df1
LR
161 return NULL;
162 }
f078f209 163
c52f33d0 164 skb = ieee80211_get_buffered_bc(hw, vif);
f078f209 165
f078f209
LR
166 /*
167 * if the CABQ traffic from previous DTIM is pending and the current
168 * beacon is also a DTIM.
17d7904d
S
169 * 1) if there is only one vif let the cab traffic continue.
170 * 2) if there are more than one vif and we are using staggered
f078f209 171 * beacons, then drain the cabq by dropping all the frames in
17d7904d 172 * the cabq so that the current vifs cab traffic can be scheduled.
f078f209
LR
173 */
174 spin_lock_bh(&cabq->axq_lock);
175 cabq_depth = cabq->axq_depth;
176 spin_unlock_bh(&cabq->axq_lock);
177
e022edbd 178 if (skb && cabq_depth) {
ca529c93 179 if (sc->cur_chan->nvifs > 1) {
d2182b69 180 ath_dbg(common, BEACON,
226afe68 181 "Flushing previous cabq traffic\n");
1381559b 182 ath_draintxq(sc, cabq);
f078f209
LR
183 }
184 }
185
fb6e252f 186 ath9k_beacon_setup(sc, vif, bf, info->control.rates[0].idx);
f078f209 187
59505c02
FF
188 if (skb)
189 ath_tx_cabq(hw, vif, skb);
f078f209 190
f078f209
LR
191 return bf;
192}
193
130ef6e9 194void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
f078f209 195{
c46917bb 196 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
130ef6e9
SM
197 struct ath_vif *avp = (void *)vif->drv_priv;
198 int slot;
f078f209 199
130ef6e9
SM
200 avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf, struct ath_buf, list);
201 list_del(&avp->av_bcbuf->list);
f078f209 202
130ef6e9
SM
203 for (slot = 0; slot < ATH_BCBUF; slot++) {
204 if (sc->beacon.bslot[slot] == NULL) {
205 avp->av_bslot = slot;
130ef6e9 206 break;
f078f209
LR
207 }
208 }
209
130ef6e9
SM
210 sc->beacon.bslot[avp->av_bslot] = vif;
211 sc->nbcnvifs++;
f078f209 212
130ef6e9
SM
213 ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n",
214 avp->av_bslot);
215}
f078f209 216
130ef6e9
SM
217void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
218{
219 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
220 struct ath_vif *avp = (void *)vif->drv_priv;
221 struct ath_buf *bf = avp->av_bcbuf;
1cf48f22 222 struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
f078f209 223
130ef6e9
SM
224 ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n",
225 avp->av_bslot);
f078f209 226
130ef6e9 227 tasklet_disable(&sc->bcon_tasklet);
f078f209 228
1cf48f22
FF
229 cur_conf->enable_beacon &= ~BIT(avp->av_bslot);
230
130ef6e9
SM
231 if (bf && bf->bf_mpdu) {
232 struct sk_buff *skb = bf->bf_mpdu;
233 dma_unmap_single(sc->dev, bf->bf_buf_addr,
234 skb->len, DMA_TO_DEVICE);
f8316df1
LR
235 dev_kfree_skb_any(skb);
236 bf->bf_mpdu = NULL;
6cf9e995 237 bf->bf_buf_addr = 0;
f8316df1 238 }
f078f209 239
130ef6e9 240 avp->av_bcbuf = NULL;
130ef6e9
SM
241 sc->beacon.bslot[avp->av_bslot] = NULL;
242 sc->nbcnvifs--;
243 list_add_tail(&bf->list, &sc->beacon.bbuf);
f078f209 244
130ef6e9 245 tasklet_enable(&sc->bcon_tasklet);
f078f209
LR
246}
247
fb6e252f
SM
248static int ath9k_beacon_choose_slot(struct ath_softc *sc)
249{
250 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
ca900ac9 251 struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
fb6e252f
SM
252 u16 intval;
253 u32 tsftu;
254 u64 tsf;
255 int slot;
256
2664d666
TP
257 if (sc->sc_ah->opmode != NL80211_IFTYPE_AP &&
258 sc->sc_ah->opmode != NL80211_IFTYPE_MESH_POINT) {
fb6e252f
SM
259 ath_dbg(common, BEACON, "slot 0, tsf: %llu\n",
260 ath9k_hw_gettsf64(sc->sc_ah));
261 return 0;
262 }
263
264 intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
265 tsf = ath9k_hw_gettsf64(sc->sc_ah);
266 tsf += TU_TO_USEC(sc->sc_ah->config.sw_beacon_response_time);
267 tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF);
268 slot = (tsftu % (intval * ATH_BCBUF)) / intval;
269
270 ath_dbg(common, BEACON, "slot: %d tsf: %llu tsftu: %u\n",
271 slot, tsf, tsftu / ATH_BCBUF);
272
273 return slot;
274}
275
c32e4e51 276static void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif)
2f8e82e8
SM
277{
278 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2f8e82e8 279 struct ath_vif *avp = (void *)vif->drv_priv;
9a9c4fbc 280 struct ath_beacon_config *cur_conf = &avp->chanctx->beacon;
63ded3f0 281 u32 tsfadjust;
2f8e82e8
SM
282
283 if (avp->av_bslot == 0)
284 return;
285
63ded3f0
FF
286 tsfadjust = cur_conf->beacon_interval * avp->av_bslot;
287 tsfadjust = TU_TO_USEC(tsfadjust) / ATH_BCBUF;
288 avp->tsf_adjust = cpu_to_le64(tsfadjust);
2f8e82e8
SM
289
290 ath_dbg(common, CONFIG, "tsfadjust is: %llu for bslot: %d\n",
291 (unsigned long long)tsfadjust, avp->av_bslot);
292}
293
4effc6fd 294bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif)
d074e8d5 295{
d074e8d5
SW
296 if (!vif || !vif->csa_active)
297 return false;
298
299 if (!ieee80211_csa_is_complete(vif))
300 return false;
301
302 ieee80211_csa_finish(vif);
d074e8d5
SW
303 return true;
304}
305
4effc6fd
MK
306static void ath9k_csa_update_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
307{
308 struct ath_softc *sc = data;
309 ath9k_csa_is_finished(sc, vif);
310}
311
312void ath9k_csa_update(struct ath_softc *sc)
313{
5869e795
FF
314 ieee80211_iterate_active_interfaces_atomic(sc->hw,
315 IEEE80211_IFACE_ITER_NORMAL,
316 ath9k_csa_update_vif, sc);
4effc6fd
MK
317}
318
fb6e252f 319void ath9k_beacon_tasklet(unsigned long data)
f078f209 320{
f078f209 321 struct ath_softc *sc = (struct ath_softc *)data;
cbe61d8a 322 struct ath_hw *ah = sc->sc_ah;
c46917bb 323 struct ath_common *common = ath9k_hw_common(ah);
f078f209 324 struct ath_buf *bf = NULL;
2c3db3d5 325 struct ieee80211_vif *vif;
98f0a5eb 326 bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
2c3db3d5 327 int slot;
f078f209 328
eefa01dd 329 if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) {
4e7fb718
RM
330 ath_dbg(common, RESET,
331 "reset work is pending, skip beaconing now\n");
332 return;
333 }
124b979b 334
f078f209
LR
335 /*
336 * Check if the previous beacon has gone out. If
337 * not don't try to post another, skip this period
338 * and wait for the next. Missed beacons indicate
339 * a problem and should not occur. If we miss too
340 * many consecutive beacons reset the device.
341 */
b77f483f
S
342 if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) {
343 sc->beacon.bmisscnt++;
9546aae0 344
1e516ca7
SM
345 ath9k_hw_check_nav(ah);
346
415ec61b
SM
347 /*
348 * If the previous beacon has not been transmitted
349 * and a MAC/BB hang has been identified, return
350 * here because a chip reset would have been
351 * initiated.
352 */
353 if (!ath_hw_check(sc))
354 return;
b381fa32 355
c944daf4 356 if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) {
d2182b69 357 ath_dbg(common, BSTUCK,
226afe68
JP
358 "missed %u consecutive beacons\n",
359 sc->beacon.bmisscnt);
efff395e 360 ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
87c510fe
FF
361 if (sc->beacon.bmisscnt > 3)
362 ath9k_hw_bstuck_nfcal(ah);
b77f483f 363 } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
d2182b69 364 ath_dbg(common, BSTUCK, "beacon is officially stuck\n");
4e7fb718 365 sc->beacon.bmisscnt = 0;
124b979b 366 ath9k_queue_reset(sc, RESET_TYPE_BEACON_STUCK);
f078f209 367 }
9546aae0 368
f078f209
LR
369 return;
370 }
980b24da 371
fb6e252f
SM
372 slot = ath9k_beacon_choose_slot(sc);
373 vif = sc->beacon.bslot[slot];
980b24da 374
4effc6fd 375 /* EDMA devices check that in the tx completion function. */
748299f2 376 if (!edma) {
27babf9f 377 if (ath9k_is_chanctx_enabled()) {
70b06dac
SM
378 ath_chanctx_beacon_sent_ev(sc,
379 ATH_CHANCTX_EVENT_BEACON_SENT);
27babf9f 380 }
748299f2
FF
381
382 if (ath9k_csa_is_finished(sc, vif))
383 return;
384 }
4effc6fd 385
fb6e252f
SM
386 if (!vif || !vif->bss_conf.enable_beacon)
387 return;
980b24da 388
27babf9f
SM
389 if (ath9k_is_chanctx_enabled()) {
390 ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_BEACON_PREPARE);
391 }
392
fb6e252f 393 bf = ath9k_beacon_generate(sc->hw, vif);
c944daf4 394
fb6e252f
SM
395 if (sc->beacon.bmisscnt != 0) {
396 ath_dbg(common, BSTUCK, "resume beacon xmit after %u misses\n",
397 sc->beacon.bmisscnt);
398 sc->beacon.bmisscnt = 0;
f078f209 399 }
9546aae0 400
f078f209
LR
401 /*
402 * Handle slot time change when a non-ERP station joins/leaves
403 * an 11g network. The 802.11 layer notifies us via callback,
404 * we mark updateslot, then wait one beacon before effecting
405 * the change. This gives associated stations at least one
406 * beacon interval to note the state change.
407 *
408 * NB: The slot time change state machine is clocked according
409 * to whether we are bursting or staggering beacons. We
410 * recognize the request to update and record the current
411 * slot then don't transition until that slot is reached
412 * again. If we miss a beacon for that slot then we'll be
413 * slow to transition but we'll be sure at least one beacon
414 * interval has passed. When bursting slot is always left
415 * set to ATH_BCBUF so this check is a noop.
416 */
b77f483f 417 if (sc->beacon.updateslot == UPDATE) {
fb6e252f 418 sc->beacon.updateslot = COMMIT;
b77f483f 419 sc->beacon.slotupdate = slot;
fb6e252f
SM
420 } else if (sc->beacon.updateslot == COMMIT &&
421 sc->beacon.slotupdate == slot) {
0005baf4
FF
422 ah->slottime = sc->beacon.slottime;
423 ath9k_hw_init_global_settings(ah);
b77f483f 424 sc->beacon.updateslot = OK;
ff37e337 425 }
fb6e252f
SM
426
427 if (bf) {
428 ath9k_reset_beacon_status(sc);
429
430 ath_dbg(common, BEACON,
431 "Transmitting beacon for slot: %d\n", slot);
432
f078f209 433 /* NB: cabq traffic should already be queued and primed */
fb6e252f 434 ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr);
98f0a5eb
MSS
435
436 if (!edma)
437 ath9k_hw_txstart(ah, sc->beacon.beaconq);
f078f209 438 }
f078f209
LR
439}
440
1a6404a1
SM
441/*
442 * Both nexttbtt and intval have to be in usecs.
443 */
444static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt,
445 u32 intval, bool reset_tsf)
21526d57 446{
ef4ad633 447 struct ath_hw *ah = sc->sc_ah;
21526d57 448
ef4ad633 449 ath9k_hw_disable_interrupts(ah);
1a6404a1
SM
450 if (reset_tsf)
451 ath9k_hw_reset_tsf(ah);
7e52c8aa 452 ath9k_beaconq_config(sc);
ef4ad633
SM
453 ath9k_hw_beaconinit(ah, nexttbtt, intval);
454 sc->beacon.bmisscnt = 0;
455 ath9k_hw_set_interrupts(ah);
456 ath9k_hw_enable_interrupts(ah);
21526d57
LR
457}
458
f078f209 459/*
5379c8a2
S
460 * For multi-bss ap support beacons are either staggered evenly over N slots or
461 * burst together. For the former arrange for the SWBA to be delivered for each
462 * slot. Slots that are not occupied will generate nothing.
f078f209 463 */
ef4ad633
SM
464static void ath9k_beacon_config_ap(struct ath_softc *sc,
465 struct ath_beacon_config *conf)
f078f209 466{
3069168c 467 struct ath_hw *ah = sc->sc_ah;
f078f209 468
fa7b52fa
OR
469 ath9k_cmn_beacon_config_ap(ah, conf, ATH_BCBUF);
470 ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, false);
5379c8a2 471}
459f5f90 472
cbbdf2ae 473static void ath9k_beacon_config_sta(struct ath_hw *ah,
ef4ad633 474 struct ath_beacon_config *conf)
5379c8a2
S
475{
476 struct ath9k_beacon_state bs;
5379c8a2 477
cbbdf2ae 478 if (ath9k_cmn_beacon_config_sta(ah, conf, &bs) == -EPERM)
1a20034a 479 return;
980b24da 480
4df3071e 481 ath9k_hw_disable_interrupts(ah);
3069168c
PR
482 ath9k_hw_set_sta_beacon_timers(ah, &bs);
483 ah->imask |= ATH9K_INT_BMISS;
deb75188 484
72d874c6 485 ath9k_hw_set_interrupts(ah);
e8fe7336 486 ath9k_hw_enable_interrupts(ah);
5379c8a2 487}
f078f209 488
ef4ad633
SM
489static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
490 struct ath_beacon_config *conf)
5379c8a2 491{
3069168c
PR
492 struct ath_hw *ah = sc->sc_ah;
493 struct ath_common *common = ath9k_hw_common(ah);
dd347f2f 494
ba4903f9
FF
495 ath9k_reset_beacon_status(sc);
496
4c9a1f32 497 ath9k_cmn_beacon_config_adhoc(ah, conf);
9fc9ab0a 498
4c9a1f32 499 ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, conf->ibss_creator);
1a6404a1
SM
500
501 /*
502 * Set the global 'beacon has been configured' flag for the
503 * joiner case in IBSS mode.
504 */
505 if (!conf->ibss_creator && conf->enable_beacon)
eefa01dd 506 set_bit(ATH_OP_BEACONS, &common->op_flags);
f078f209
LR
507}
508
c32e4e51
FF
509static bool ath9k_allow_beacon_config(struct ath_softc *sc,
510 struct ieee80211_vif *vif)
f078f209 511{
c46917bb 512 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
12a1b3d4
SM
513 struct ath_vif *avp = (void *)vif->drv_priv;
514
515 if (ath9k_is_chanctx_enabled()) {
516 /*
517 * If the VIF is not present in the current channel context,
518 * then we can't do the usual opmode checks. Allow the
519 * beacon config for the VIF to be updated in this case and
520 * return immediately.
521 */
522 if (sc->cur_chan != avp->chanctx)
523 return true;
524 }
5379c8a2 525
ef4ad633 526 if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
1cf48f22 527 if (vif->type != NL80211_IFTYPE_AP) {
ef4ad633
SM
528 ath_dbg(common, CONFIG,
529 "An AP interface is already present !\n");
530 return false;
531 }
99e4d43a 532 }
ef4ad633
SM
533
534 if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
535 if ((vif->type == NL80211_IFTYPE_STATION) &&
eefa01dd 536 test_bit(ATH_OP_BEACONS, &common->op_flags) &&
9a9c4fbc 537 vif != sc->cur_chan->primary_sta) {
ef4ad633
SM
538 ath_dbg(common, CONFIG,
539 "Beacon already configured for a station interface\n");
540 return false;
541 }
ee832d3e 542 }
ef4ad633 543
99e4d43a
RM
544 return true;
545}
546
ef4ad633 547static void ath9k_cache_beacon_config(struct ath_softc *sc,
9a9c4fbc 548 struct ath_chanctx *ctx,
ef4ad633 549 struct ieee80211_bss_conf *bss_conf)
99e4d43a 550{
ef4ad633 551 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
9a9c4fbc 552 struct ath_beacon_config *cur_conf = &ctx->beacon;
ee832d3e 553
ef4ad633
SM
554 ath_dbg(common, BEACON,
555 "Caching beacon data for BSS: %pM\n", bss_conf->bssid);
99e4d43a 556
99e4d43a
RM
557 cur_conf->beacon_interval = bss_conf->beacon_int;
558 cur_conf->dtim_period = bss_conf->dtim_period;
4801416c 559 cur_conf->dtim_count = 1;
1a6404a1 560 cur_conf->ibss_creator = bss_conf->ibss_creator;
6b96f93e 561
c4f9f16b
VT
562 /*
563 * It looks like mac80211 may end up using beacon interval of zero in
564 * some cases (at least for mesh point). Avoid getting into an
565 * infinite loop by using a bit safer value instead. To be safe,
566 * do sanity check on beacon interval for all operating modes.
567 */
568 if (cur_conf->beacon_interval == 0)
569 cur_conf->beacon_interval = 100;
6b96f93e 570
76c93983
BG
571 cur_conf->bmiss_timeout =
572 ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
573
ee832d3e 574 /*
3a2329f2
MSS
575 * We don't parse dtim period from mac80211 during the driver
576 * initialization as it breaks association with hidden-ssid
577 * AP and it causes latency in roaming
ee832d3e
MSS
578 */
579 if (cur_conf->dtim_period == 0)
580 cur_conf->dtim_period = 1;
581
99e4d43a
RM
582}
583
ef4ad633
SM
584void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
585 u32 changed)
8e22ad32 586{
ef4ad633 587 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
eefa01dd
OR
588 struct ath_hw *ah = sc->sc_ah;
589 struct ath_common *common = ath9k_hw_common(ah);
9a9c4fbc
RM
590 struct ath_vif *avp = (void *)vif->drv_priv;
591 struct ath_chanctx *ctx = avp->chanctx;
592 struct ath_beacon_config *cur_conf;
1a6404a1
SM
593 unsigned long flags;
594 bool skip_beacon = false;
8e22ad32 595
9a9c4fbc
RM
596 if (!ctx)
597 return;
598
599 cur_conf = &avp->chanctx->beacon;
c32e4e51
FF
600 if (vif->type == NL80211_IFTYPE_AP)
601 ath9k_set_tsfadjust(sc, vif);
602
603 if (!ath9k_allow_beacon_config(sc, vif))
604 return;
605
9a9c4fbc
RM
606 if (vif->type == NL80211_IFTYPE_STATION) {
607 ath9k_cache_beacon_config(sc, ctx, bss_conf);
608 if (ctx != sc->cur_chan)
609 return;
610
ef4ad633 611 ath9k_set_beacon(sc);
eefa01dd 612 set_bit(ATH_OP_BEACONS, &common->op_flags);
1a6404a1 613 return;
1a6404a1
SM
614 }
615
616 /*
617 * Take care of multiple interfaces when
618 * enabling/disabling SWBA.
619 */
620 if (changed & BSS_CHANGED_BEACON_ENABLED) {
1cf48f22
FF
621 bool enabled = cur_conf->enable_beacon;
622
623 if (!bss_conf->enable_beacon) {
624 cur_conf->enable_beacon &= ~BIT(avp->av_bslot);
625 } else {
626 cur_conf->enable_beacon |= BIT(avp->av_bslot);
627 if (!enabled)
628 ath9k_cache_beacon_config(sc, ctx, bss_conf);
8e22ad32 629 }
1a6404a1 630 }
ef4ad633 631
9a9c4fbc
RM
632 if (ctx != sc->cur_chan)
633 return;
634
1a6404a1
SM
635 /*
636 * Configure the HW beacon registers only when we have a valid
637 * beacon interval.
638 */
639 if (cur_conf->beacon_interval) {
640 /*
641 * If we are joining an existing IBSS network, start beaconing
642 * only after a TSF-sync has taken place. Ensure that this
643 * happens by setting the appropriate flags.
644 */
645 if ((changed & BSS_CHANGED_IBSS) && !bss_conf->ibss_creator &&
646 bss_conf->enable_beacon) {
647 spin_lock_irqsave(&sc->sc_pm_lock, flags);
648 sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
649 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
650 skip_beacon = true;
651 } else {
ef4ad633 652 ath9k_set_beacon(sc);
ef4ad633 653 }
1a6404a1
SM
654
655 /*
eefa01dd 656 * Do not set the ATH_OP_BEACONS flag for IBSS joiner mode
1a6404a1
SM
657 * here, it is done in ath9k_beacon_config_adhoc().
658 */
659 if (cur_conf->enable_beacon && !skip_beacon)
eefa01dd 660 set_bit(ATH_OP_BEACONS, &common->op_flags);
1a6404a1 661 else
eefa01dd 662 clear_bit(ATH_OP_BEACONS, &common->op_flags);
8e22ad32 663 }
8e22ad32
RM
664}
665
ef4ad633 666void ath9k_set_beacon(struct ath_softc *sc)
99e4d43a
RM
667{
668 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
ca900ac9 669 struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
99e4d43a 670
26cd322b 671 switch (sc->sc_ah->opmode) {
6b96f93e 672 case NL80211_IFTYPE_AP:
2664d666 673 case NL80211_IFTYPE_MESH_POINT:
ef4ad633 674 ath9k_beacon_config_ap(sc, cur_conf);
6b96f93e
VT
675 break;
676 case NL80211_IFTYPE_ADHOC:
ef4ad633 677 ath9k_beacon_config_adhoc(sc, cur_conf);
6b96f93e
VT
678 break;
679 case NL80211_IFTYPE_STATION:
cbbdf2ae 680 ath9k_beacon_config_sta(sc->sc_ah, cur_conf);
6b96f93e
VT
681 break;
682 default:
d2182b69 683 ath_dbg(common, CONFIG, "Unsupported beaconing mode\n");
6b96f93e
VT
684 return;
685 }
014cf3bb 686}