beacon.c 22.6 KB
Newer Older
1
/*
2
 * Copyright (c) 2008-2009 Atheros Communications Inc.
3 4 5 6 7 8 9 10 11 12 13 14 15 16
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

S
Sujith 已提交
17
#include "ath9k.h"
18

19 20
#define FUDGE 2

21 22 23 24 25
/*
 *  This function will modify certain transmit queue properties depending on
 *  the operating mode of the station (AP or AdHoc).  Parameters are AIFS
 *  settings and channel width min/max
*/
26
int ath_beaconq_config(struct ath_softc *sc)
27
{
28
	struct ath_hw *ah = sc->sc_ah;
29
	struct ath_common *common = ath9k_hw_common(ah);
30
	struct ath9k_tx_queue_info qi, qi_be;
31
	struct ath_txq *txq;
32

S
Sujith 已提交
33
	ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi);
34
	if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
35 36 37 38 39 40
		/* Always burst out beacon and CAB traffic. */
		qi.tqi_aifs = 1;
		qi.tqi_cwmin = 0;
		qi.tqi_cwmax = 0;
	} else {
		/* Adhoc mode; important thing is to use 2x cwmin. */
41 42
		txq = sc->tx.txq_map[WME_AC_BE];
		ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be);
43 44 45
		qi.tqi_aifs = qi_be.tqi_aifs;
		qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
		qi.tqi_cwmax = qi_be.tqi_cwmax;
46 47
	}

S
Sujith 已提交
48
	if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) {
49 50
		ath_err(common,
			"Unable to update h/w beacon queue parameters\n");
51 52
		return 0;
	} else {
S
Sujith 已提交
53
		ath9k_hw_resettxqueue(ah, sc->beacon.beaconq);
54 55 56 57 58 59 60 61 62
		return 1;
	}
}

/*
 *  Associates the beacon frame buffer with a transmit descriptor.  Will set
 *  up all required antenna switch parameters, rate codes, and channel flags.
 *  Beacons are always sent out at the lowest rate, and are not retried.
*/
S
Sujith 已提交
63
static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
64
			     struct ath_buf *bf, int rateidx)
65
{
S
Sujith 已提交
66
	struct sk_buff *skb = bf->bf_mpdu;
67
	struct ath_hw *ah = sc->sc_ah;
68
	struct ath_common *common = ath9k_hw_common(ah);
69
	struct ath_desc *ds;
S
Sujith 已提交
70
	struct ath9k_11n_rate_series series[4];
S
Sujith 已提交
71
	int flags, antenna, ctsrate = 0, ctsduration = 0;
72 73
	struct ieee80211_supported_band *sband;
	u8 rate = 0;
74 75 76 77

	ds = bf->bf_desc;
	flags = ATH9K_TXDESC_NOACK;

78 79 80 81 82 83 84
	ds->ds_link = 0;
	/*
	 * Switch antenna every beacon.
	 * Should only switch every beacon period, not for every SWBA
	 * XXX assumes two antennae
	 */
	antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1);
85

86
	sband = &sc->sbands[common->hw->conf.channel->band];
87
	rate = sband->bitrates[rateidx].hw_value;
S
Sujith 已提交
88
	if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
89
		rate |= sband->bitrates[rateidx].hw_value_short;
S
Sujith 已提交
90 91 92 93 94 95 96

	ath9k_hw_set11n_txdesc(ah, ds, skb->len + FCS_LEN,
			       ATH9K_PKT_TYPE_BEACON,
			       MAX_RATE_POWER,
			       ATH9K_TXKEYIX_INVALID,
			       ATH9K_KEY_TYPE_CLEAR,
			       flags);
97 98

	/* NB: beacon's BufLen must be a multiple of 4 bytes */
S
Sujith 已提交
99
	ath9k_hw_filltxdesc(ah, ds, roundup(skb->len, 4),
100 101
			    true, true, ds, bf->bf_buf_addr,
			    sc->beacon.beaconq);
102

103
	memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
104 105
	series[0].Tries = 1;
	series[0].Rate = rate;
106 107
	series[0].ChSel = ath_txchainmask_reduction(sc,
			common->tx_chainmask, series[0].Rate);
108
	series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0;
S
Sujith 已提交
109 110
	ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, ctsrate, ctsduration,
				     series, 4, 0);
111 112
}

113 114
static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
{
115
	struct ath_softc *sc = hw->priv;
116 117 118 119 120 121
	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
	struct ath_tx_control txctl;

	memset(&txctl, 0, sizeof(struct ath_tx_control));
	txctl.txq = sc->beacon.cabq;

J
Joe Perches 已提交
122 123
	ath_dbg(common, ATH_DBG_XMIT,
		"transmitting CABQ packet, skb: %p\n", skb);
124 125

	if (ath_tx_start(hw, skb, &txctl) != 0) {
J
Joe Perches 已提交
126
		ath_dbg(common, ATH_DBG_XMIT, "CABQ TX failed\n");
127 128 129 130
		dev_kfree_skb_any(skb);
	}
}

131
static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
132
					   struct ieee80211_vif *vif)
133
{
134
	struct ath_softc *sc = hw->priv;
135
	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
136
	struct ath_buf *bf;
S
Sujith 已提交
137
	struct ath_vif *avp;
138 139
	struct sk_buff *skb;
	struct ath_txq *cabq;
140
	struct ieee80211_tx_info *info;
S
Sujith 已提交
141 142
	int cabq_depth;

S
Sujith 已提交
143
	avp = (void *)vif->drv_priv;
S
Sujith 已提交
144
	cabq = sc->beacon.cabq;
145

146
	if ((avp->av_bcbuf == NULL) || !avp->is_bslot_active)
147
		return NULL;
S
Sujith 已提交
148

S
Sujith 已提交
149 150
	/* Release the old beacon first */

151
	bf = avp->av_bcbuf;
S
Sujith 已提交
152
	skb = bf->bf_mpdu;
153
	if (skb) {
B
Ben Greear 已提交
154
		dma_unmap_single(sc->dev, bf->bf_buf_addr,
S
Sujith 已提交
155
				 skb->len, DMA_TO_DEVICE);
J
Jouni Malinen 已提交
156
		dev_kfree_skb_any(skb);
157
		bf->bf_buf_addr = 0;
158
	}
159

S
Sujith 已提交
160 161
	/* Get a new beacon from mac80211 */

162
	skb = ieee80211_beacon_get(hw, vif);
163 164 165
	bf->bf_mpdu = skb;
	if (skb == NULL)
		return NULL;
166 167
	((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp =
		avp->tsf_adjust;
S
Sujith 已提交
168

169 170 171 172 173 174
	info = IEEE80211_SKB_CB(skb);
	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
		/*
		 * TODO: make sure the seq# gets assigned properly (vs. other
		 * TX frames)
		 */
S
Sujith 已提交
175
		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
S
Sujith 已提交
176
		sc->tx.seq_no += 0x10;
177
		hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
S
Sujith 已提交
178
		hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
179
	}
S
Sujith 已提交
180

B
Ben Greear 已提交
181 182
	bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
					 skb->len, DMA_TO_DEVICE);
183
	if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
184 185
		dev_kfree_skb_any(skb);
		bf->bf_mpdu = NULL;
186
		bf->bf_buf_addr = 0;
187
		ath_err(common, "dma_mapping_error on beaconing\n");
188 189
		return NULL;
	}
190

191
	skb = ieee80211_get_buffered_bc(hw, vif);
192 193 194 195

	/*
	 * if the CABQ traffic from previous DTIM is pending and the current
	 *  beacon is also a DTIM.
S
Sujith 已提交
196 197
	 *  1) if there is only one vif let the cab traffic continue.
	 *  2) if there are more than one vif and we are using staggered
198
	 *     beacons, then drain the cabq by dropping all the frames in
S
Sujith 已提交
199
	 *     the cabq so that the current vifs cab traffic can be scheduled.
200 201 202 203 204
	 */
	spin_lock_bh(&cabq->axq_lock);
	cabq_depth = cabq->axq_depth;
	spin_unlock_bh(&cabq->axq_lock);

205
	if (skb && cabq_depth) {
S
Sujith 已提交
206
		if (sc->nvifs > 1) {
J
Joe Perches 已提交
207 208
			ath_dbg(common, ATH_DBG_BEACON,
				"Flushing previous cabq traffic\n");
S
Sujith 已提交
209
			ath_draintxq(sc, cabq, false);
210 211 212
		}
	}

213
	ath_beacon_setup(sc, avp, bf, info->control.rates[0].idx);
214

215
	while (skb) {
216 217
		ath_tx_cabq(hw, skb);
		skb = ieee80211_get_buffered_bc(hw, vif);
218
	}
219 220 221 222

	return bf;
}

223
int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif)
224
{
225
	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
S
Sujith 已提交
226
	struct ath_vif *avp;
227 228
	struct ath_buf *bf;
	struct sk_buff *skb;
229
	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
S
Sujith 已提交
230
	__le64 tstamp;
231

S
Sujith 已提交
232
	avp = (void *)vif->drv_priv;
233 234 235

	/* Allocate a beacon descriptor if we haven't done so. */
	if (!avp->av_bcbuf) {
S
Sujith 已提交
236 237
		/* Allocate beacon state for hostap/ibss.  We know
		 * a buffer is available. */
S
Sujith 已提交
238
		avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf,
S
Sujith 已提交
239
						 struct ath_buf, list);
240 241
		list_del(&avp->av_bcbuf->list);

242
		if (ath9k_uses_beacons(vif->type)) {
243 244
			int slot;
			/*
S
Sujith 已提交
245
			 * Assign the vif to a beacon xmit slot. As
246 247 248 249
			 * above, this cannot fail to find one.
			 */
			avp->av_bslot = 0;
			for (slot = 0; slot < ATH_BCBUF; slot++)
250
				if (sc->beacon.bslot[slot] == NULL) {
251
					avp->av_bslot = slot;
252
					avp->is_bslot_active = false;
253

254
					/* NB: keep looking for a double slot */
255 256
					if (slot == 0 || !sc->beacon.bslot[slot-1])
						break;
257
				}
258 259
			BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL);
			sc->beacon.bslot[avp->av_bslot] = vif;
S
Sujith 已提交
260
			sc->nbcnvifs++;
261 262 263
		}
	}

S
Sujith 已提交
264
	/* release the previous beacon frame, if it already exists. */
265 266
	bf = avp->av_bcbuf;
	if (bf->bf_mpdu != NULL) {
S
Sujith 已提交
267
		skb = bf->bf_mpdu;
B
Ben Greear 已提交
268
		dma_unmap_single(sc->dev, bf->bf_buf_addr,
S
Sujith 已提交
269
				 skb->len, DMA_TO_DEVICE);
270 271
		dev_kfree_skb_any(skb);
		bf->bf_mpdu = NULL;
272
		bf->bf_buf_addr = 0;
273 274
	}

S
Sujith 已提交
275
	/* NB: the beacon data buffer must be 32-bit aligned. */
S
Sujith 已提交
276
	skb = ieee80211_beacon_get(sc->hw, vif);
277
	if (skb == NULL)
278 279
		return -ENOMEM;

S
Sujith 已提交
280
	tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
S
Sujith 已提交
281
	sc->beacon.bc_tstamp = le64_to_cpu(tstamp);
282
	/* Calculate a TSF adjustment factor required for staggered beacons. */
283 284 285 286
	if (avp->av_bslot > 0) {
		u64 tsfadjust;
		int intval;

287
		intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
288 289

		/*
290 291 292 293 294 295
		 * Calculate the TSF offset for this beacon slot, i.e., the
		 * number of usecs that need to be added to the timestamp field
		 * in Beacon and Probe Response frames. Beacon slot 0 is
		 * processed at the correct offset, so it does not require TSF
		 * adjustment. Other slots are adjusted to get the timestamp
		 * close to the TBTT for the BSS.
296
		 */
297 298
		tsfadjust = intval * avp->av_bslot / ATH_BCBUF;
		avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust));
299

J
Joe Perches 已提交
300 301 302
		ath_dbg(common, ATH_DBG_BEACON,
			"stagger beacons, bslot %d intval %u tsfadjust %llu\n",
			avp->av_bslot, intval, (unsigned long long)tsfadjust);
303

304 305 306 307
		((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp =
			avp->tsf_adjust;
	} else
		avp->tsf_adjust = cpu_to_le64(0);
308

309
	bf->bf_mpdu = skb;
B
Ben Greear 已提交
310 311
	bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
					 skb->len, DMA_TO_DEVICE);
312
	if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
313 314
		dev_kfree_skb_any(skb);
		bf->bf_mpdu = NULL;
315
		bf->bf_buf_addr = 0;
316
		ath_err(common, "dma_mapping_error on beacon alloc\n");
317 318
		return -ENOMEM;
	}
319
	avp->is_bslot_active = true;
320 321 322 323

	return 0;
}

S
Sujith 已提交
324
void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp)
325 326 327 328 329
{
	if (avp->av_bcbuf != NULL) {
		struct ath_buf *bf;

		if (avp->av_bslot != -1) {
330
			sc->beacon.bslot[avp->av_bslot] = NULL;
S
Sujith 已提交
331
			sc->nbcnvifs--;
332 333 334 335
		}

		bf = avp->av_bcbuf;
		if (bf->bf_mpdu != NULL) {
S
Sujith 已提交
336
			struct sk_buff *skb = bf->bf_mpdu;
B
Ben Greear 已提交
337
			dma_unmap_single(sc->dev, bf->bf_buf_addr,
S
Sujith 已提交
338
					 skb->len, DMA_TO_DEVICE);
339 340
			dev_kfree_skb_any(skb);
			bf->bf_mpdu = NULL;
341
			bf->bf_buf_addr = 0;
342
		}
S
Sujith 已提交
343
		list_add_tail(&bf->list, &sc->beacon.bbuf);
344 345 346 347 348

		avp->av_bcbuf = NULL;
	}
}

S
Sujith 已提交
349
void ath_beacon_tasklet(unsigned long data)
350 351
{
	struct ath_softc *sc = (struct ath_softc *)data;
352
	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
353
	struct ath_hw *ah = sc->sc_ah;
354
	struct ath_common *common = ath9k_hw_common(ah);
355
	struct ath_buf *bf = NULL;
356 357
	struct ieee80211_vif *vif;
	int slot;
S
Sujith 已提交
358
	u32 bfaddr, bc = 0, tsftu;
359 360 361 362 363 364 365 366 367 368
	u64 tsf;
	u16 intval;

	/*
	 * Check if the previous beacon has gone out.  If
	 * not don't try to post another, skip this period
	 * and wait for the next.  Missed beacons indicate
	 * a problem and should not occur.  If we miss too
	 * many consecutive beacons reset the device.
	 */
S
Sujith 已提交
369 370
	if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) {
		sc->beacon.bmisscnt++;
S
Sujith 已提交
371

S
Sujith 已提交
372
		if (sc->beacon.bmisscnt < BSTUCK_THRESH) {
J
Joe Perches 已提交
373 374 375
			ath_dbg(common, ATH_DBG_BSTUCK,
				"missed %u consecutive beacons\n",
				sc->beacon.bmisscnt);
376
			ath9k_hw_bstuck_nfcal(ah);
S
Sujith 已提交
377
		} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
J
Joe Perches 已提交
378 379
			ath_dbg(common, ATH_DBG_BSTUCK,
				"beacon is officially stuck\n");
380
			sc->sc_flags |= SC_OP_TSF_RESET;
381
			ath_reset(sc, true);
382
		}
S
Sujith 已提交
383

384 385
		return;
	}
S
Sujith 已提交
386

S
Sujith 已提交
387
	if (sc->beacon.bmisscnt != 0) {
J
Joe Perches 已提交
388 389 390
		ath_dbg(common, ATH_DBG_BSTUCK,
			"resume beacon xmit after %u misses\n",
			sc->beacon.bmisscnt);
S
Sujith 已提交
391
		sc->beacon.bmisscnt = 0;
392 393 394 395 396 397 398 399
	}

	/*
	 * Generate beacon frames. we are sending frames
	 * staggered so calculate the slot for this frame based
	 * on the tsf to safeguard against missing an swba.
	 */

400
	intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
401 402 403 404

	tsf = ath9k_hw_gettsf64(ah);
	tsftu = TSF_TO_TU(tsf>>32, tsf);
	slot = ((tsftu % intval) * ATH_BCBUF) / intval;
405 406 407 408 409 410 411 412 413
	/*
	 * Reverse the slot order to get slot 0 on the TBTT offset that does
	 * not require TSF adjustment and other slots adding
	 * slot/ATH_BCBUF * beacon_int to timestamp. For example, with
	 * ATH_BCBUF = 4, we process beacon slots as follows: 3 2 1 0 3 2 1 ..
	 * and slot 0 is at correct offset to TBTT.
	 */
	slot = ATH_BCBUF - slot - 1;
	vif = sc->beacon.bslot[slot];
S
Sujith 已提交
414

J
Joe Perches 已提交
415 416 417
	ath_dbg(common, ATH_DBG_BEACON,
		"slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
		slot, tsf, tsftu, intval, vif);
S
Sujith 已提交
418

419
	bfaddr = 0;
420
	if (vif) {
421
		bf = ath_beacon_generate(sc->hw, vif);
422 423 424 425 426
		if (bf != NULL) {
			bfaddr = bf->bf_daddr;
			bc = 1;
		}
	}
S
Sujith 已提交
427

428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
	/*
	 * Handle slot time change when a non-ERP station joins/leaves
	 * an 11g network.  The 802.11 layer notifies us via callback,
	 * we mark updateslot, then wait one beacon before effecting
	 * the change.  This gives associated stations at least one
	 * beacon interval to note the state change.
	 *
	 * NB: The slot time change state machine is clocked according
	 *     to whether we are bursting or staggering beacons.  We
	 *     recognize the request to update and record the current
	 *     slot then don't transition until that slot is reached
	 *     again.  If we miss a beacon for that slot then we'll be
	 *     slow to transition but we'll be sure at least one beacon
	 *     interval has passed.  When bursting slot is always left
	 *     set to ATH_BCBUF so this check is a noop.
	 */
S
Sujith 已提交
444 445 446 447
	if (sc->beacon.updateslot == UPDATE) {
		sc->beacon.updateslot = COMMIT; /* commit next beacon */
		sc->beacon.slotupdate = slot;
	} else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) {
448 449
		ah->slottime = sc->beacon.slottime;
		ath9k_hw_init_global_settings(ah);
S
Sujith 已提交
450
		sc->beacon.updateslot = OK;
S
Sujith 已提交
451
	}
452 453 454 455 456 457
	if (bfaddr != 0) {
		/*
		 * Stop any current dma and put the new frame(s) on the queue.
		 * This should never fail since we check above that no frames
		 * are still pending on the queue.
		 */
S
Sujith 已提交
458
		if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) {
459 460
			ath_err(common, "beacon queue %u did not stop?\n",
				sc->beacon.beaconq);
461 462 463
		}

		/* NB: cabq traffic should already be queued and primed */
S
Sujith 已提交
464 465
		ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr);
		ath9k_hw_txstart(ah, sc->beacon.beaconq);
466

S
Sujith 已提交
467
		sc->beacon.ast_be_xmit += bc;     /* XXX per-vif? */
468 469 470
	}
}

471 472 473 474 475 476 477 478 479 480 481 482 483
static void ath9k_beacon_init(struct ath_softc *sc,
			      u32 next_beacon,
			      u32 beacon_period)
{
	if (beacon_period & ATH9K_BEACON_RESET_TSF)
		ath9k_ps_wakeup(sc);

	ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period);

	if (beacon_period & ATH9K_BEACON_RESET_TSF)
		ath9k_ps_restore(sc);
}

484
/*
485 486 487
 * For multi-bss ap support beacons are either staggered evenly over N slots or
 * burst together.  For the former arrange for the SWBA to be delivered for each
 * slot. Slots that are not occupied will generate nothing.
488
 */
489
static void ath_beacon_config_ap(struct ath_softc *sc,
490
				 struct ath_beacon_config *conf)
491
{
P
Pavel Roskin 已提交
492
	struct ath_hw *ah = sc->sc_ah;
S
Sujith 已提交
493
	u32 nexttbtt, intval;
494

495 496 497 498
	/* NB: the beacon interval is kept internally in TU's */
	intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
	intval /= ATH_BCBUF;    /* for staggered beacons */
	nexttbtt = intval;
499 500 501

	if (sc->sc_flags & SC_OP_TSF_RESET)
		intval |= ATH9K_BEACON_RESET_TSF;
502

503 504 505 506 507
	/*
	 * In AP mode we enable the beacon timers and SWBA interrupts to
	 * prepare beacon frames.
	 */
	intval |= ATH9K_BEACON_ENA;
P
Pavel Roskin 已提交
508
	ah->imask |= ATH9K_INT_SWBA;
509
	ath_beaconq_config(sc);
510

511
	/* Set the computed AP beacon timers */
512

513
	ath9k_hw_disable_interrupts(ah);
514
	ath9k_beacon_init(sc, nexttbtt, intval);
515
	sc->beacon.bmisscnt = 0;
P
Pavel Roskin 已提交
516
	ath9k_hw_set_interrupts(ah, ah->imask);
S
Sujith 已提交
517 518 519 520 521

	/* Clear the reset TSF flag, so that subsequent beacon updation
	   will not reset the HW TSF. */

	sc->sc_flags &= ~SC_OP_TSF_RESET;
522
}
S
Sujith 已提交
523

524 525 526 527 528 529 530 531 532
/*
 * This sets up the beacon timers according to the timestamp of the last
 * received beacon and the current TSF, configures PCF and DTIM
 * handling, programs the sleep registers so the hardware will wakeup in
 * time to receive beacons, and configures the beacon miss handling so
 * we'll receive a BMISS interrupt when we stop seeing beacons from the AP
 * we've associated with.
 */
static void ath_beacon_config_sta(struct ath_softc *sc,
533
				  struct ath_beacon_config *conf)
534
{
P
Pavel Roskin 已提交
535 536
	struct ath_hw *ah = sc->sc_ah;
	struct ath_common *common = ath9k_hw_common(ah);
537 538 539 540 541
	struct ath9k_beacon_state bs;
	int dtimperiod, dtimcount, sleepduration;
	int cfpperiod, cfpcount;
	u32 nexttbtt = 0, intval, tsftu;
	u64 tsf;
542
	int num_beacons, offset, dtim_dec_count, cfp_dec_count;
543

544 545
	/* No need to configure beacon if we are not associated */
	if (!common->curaid) {
J
Joe Perches 已提交
546 547
		ath_dbg(common, ATH_DBG_BEACON,
			"STA is not yet associated..skipping beacon config\n");
548 549 550
		return;
	}

551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
	memset(&bs, 0, sizeof(bs));
	intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;

	/*
	 * Setup dtim and cfp parameters according to
	 * last beacon we received (which may be none).
	 */
	dtimperiod = conf->dtim_period;
	dtimcount = conf->dtim_count;
	if (dtimcount >= dtimperiod)	/* NB: sanity check */
		dtimcount = 0;
	cfpperiod = 1;			/* NB: no PCF support yet */
	cfpcount = 0;

	sleepduration = conf->listen_interval * intval;

	/*
	 * Pull nexttbtt forward to reflect the current
	 * TSF and calculate dtim+cfp state for the result.
	 */
P
Pavel Roskin 已提交
571
	tsf = ath9k_hw_gettsf64(ah);
572
	tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
573 574 575 576 577

	num_beacons = tsftu / intval + 1;
	offset = tsftu % intval;
	nexttbtt = tsftu - offset;
	if (offset)
578
		nexttbtt += intval;
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593

	/* DTIM Beacon every dtimperiod Beacon */
	dtim_dec_count = num_beacons % dtimperiod;
	/* CFP every cfpperiod DTIM Beacon */
	cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod;
	if (dtim_dec_count)
		cfp_dec_count++;

	dtimcount -= dtim_dec_count;
	if (dtimcount < 0)
		dtimcount += dtimperiod;

	cfpcount -= cfp_dec_count;
	if (cfpcount < 0)
		cfpcount += cfpperiod;
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611

	bs.bs_intval = intval;
	bs.bs_nexttbtt = nexttbtt;
	bs.bs_dtimperiod = dtimperiod*intval;
	bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval;
	bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod;
	bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
	bs.bs_cfpmaxduration = 0;

	/*
	 * Calculate the number of consecutive beacons to miss* before taking
	 * a BMISS interrupt. The configuration is specified in TU so we only
	 * need calculate based	on the beacon interval.  Note that we clamp the
	 * result to at most 15 beacons.
	 */
	if (sleepduration > intval) {
		bs.bs_bmissthreshold = conf->listen_interval *
			ATH_DEFAULT_BMISS_LIMIT / 2;
612
	} else {
613 614 615 616 617
		bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval);
		if (bs.bs_bmissthreshold > 15)
			bs.bs_bmissthreshold = 15;
		else if (bs.bs_bmissthreshold <= 0)
			bs.bs_bmissthreshold = 1;
618 619
	}

620 621 622 623 624 625 626 627
	/*
	 * Calculate sleep duration. The configuration is given in ms.
	 * We ensure a multiple of the beacon period is used. Also, if the sleep
	 * duration is greater than the DTIM period then it makes senses
	 * to make it a multiple of that.
	 *
	 * XXX fixed at 100ms
	 */
S
Sujith 已提交
628

629 630 631
	bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration);
	if (bs.bs_sleepduration > bs.bs_dtimperiod)
		bs.bs_sleepduration = bs.bs_dtimperiod;
S
Sujith 已提交
632

633 634
	/* TSF out of range threshold fixed at 1 second */
	bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
635

J
Joe Perches 已提交
636 637 638 639 640
	ath_dbg(common, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu);
	ath_dbg(common, ATH_DBG_BEACON,
		"bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
		bs.bs_bmissthreshold, bs.bs_sleepduration,
		bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
641

642
	/* Set the computed STA beacon timers */
S
Sujith 已提交
643

644
	ath9k_hw_disable_interrupts(ah);
P
Pavel Roskin 已提交
645 646 647
	ath9k_hw_set_sta_beacon_timers(ah, &bs);
	ah->imask |= ATH9K_INT_BMISS;
	ath9k_hw_set_interrupts(ah, ah->imask);
648
}
649

650
static void ath_beacon_config_adhoc(struct ath_softc *sc,
651
				    struct ath_beacon_config *conf)
652
{
P
Pavel Roskin 已提交
653 654
	struct ath_hw *ah = sc->sc_ah;
	struct ath_common *common = ath9k_hw_common(ah);
655 656
	u64 tsf;
	u32 tsftu, intval, nexttbtt;
657

658
	intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
659

660

661
	/* Pull nexttbtt forward to reflect the current TSF */
662

663 664 665 666 667
	nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp);
	if (nexttbtt == 0)
                nexttbtt = intval;
        else if (intval)
                nexttbtt = roundup(nexttbtt, intval);
S
Sujith 已提交
668

P
Pavel Roskin 已提交
669
	tsf = ath9k_hw_gettsf64(ah);
670 671 672 673
	tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE;
	do {
		nexttbtt += intval;
	} while (nexttbtt < tsftu);
674

J
Joe Perches 已提交
675 676 677
	ath_dbg(common, ATH_DBG_BEACON,
		"IBSS nexttbtt %u intval %u (%u)\n",
		nexttbtt, intval, conf->beacon_interval);
S
Sujith 已提交
678

679 680 681 682 683 684
	/*
	 * In IBSS mode enable the beacon timers but only enable SWBA interrupts
	 * if we need to manually prepare beacon frames.  Otherwise we use a
	 * self-linked tx descriptor and let the hardware deal with things.
	 */
	intval |= ATH9K_BEACON_ENA;
685
	ah->imask |= ATH9K_INT_SWBA;
S
Sujith 已提交
686

687 688 689 690
	ath_beaconq_config(sc);

	/* Set the computed ADHOC beacon timers */

691
	ath9k_hw_disable_interrupts(ah);
692
	ath9k_beacon_init(sc, nexttbtt, intval);
693
	sc->beacon.bmisscnt = 0;
P
Pavel Roskin 已提交
694
	ath9k_hw_set_interrupts(ah, ah->imask);
695 696
}

697
void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
698
{
699
	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
700
	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
701
	enum nl80211_iftype iftype;
702 703

	/* Setup the beacon configuration parameters */
704
	if (vif) {
705 706 707 708
		struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
		iftype = vif->type;
		cur_conf->beacon_interval = bss_conf->beacon_int;
		cur_conf->dtim_period = bss_conf->dtim_period;
709 710 711 712
	} else {
		iftype = sc->sc_ah->opmode;
	}

713 714 715 716
	cur_conf->listen_interval = 1;
	cur_conf->dtim_count = 1;
	cur_conf->bmiss_timeout =
		ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
717

718 719 720 721 722 723 724 725
	/*
	 * It looks like mac80211 may end up using beacon interval of zero in
	 * some cases (at least for mesh point). Avoid getting into an
	 * infinite loop by using a bit safer value instead. To be safe,
	 * do sanity check on beacon interval for all operating modes.
	 */
	if (cur_conf->beacon_interval == 0)
		cur_conf->beacon_interval = 100;
726

727
	/*
728 729 730
	 * We don't parse dtim period from mac80211 during the driver
	 * initialization as it breaks association with hidden-ssid
	 * AP and it causes latency in roaming
731 732 733 734
	 */
	if (cur_conf->dtim_period == 0)
		cur_conf->dtim_period = 1;

735 736 737 738 739 740
	switch (iftype) {
	case NL80211_IFTYPE_AP:
		ath_beacon_config_ap(sc, cur_conf);
		break;
	case NL80211_IFTYPE_ADHOC:
	case NL80211_IFTYPE_MESH_POINT:
741
		ath_beacon_config_adhoc(sc, cur_conf);
742 743 744 745 746
		break;
	case NL80211_IFTYPE_STATION:
		ath_beacon_config_sta(sc, cur_conf);
		break;
	default:
J
Joe Perches 已提交
747 748
		ath_dbg(common, ATH_DBG_CONFIG,
			"Unsupported beaconing mode\n");
749 750 751 752
		return;
	}

	sc->sc_flags |= SC_OP_BEACONS;
753
}
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786

void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
{
	struct ath_hw *ah = sc->sc_ah;
	struct ath_vif *avp;
	int slot;
	bool found = false;

	ath9k_ps_wakeup(sc);
	if (status) {
		for (slot = 0; slot < ATH_BCBUF; slot++) {
			if (sc->beacon.bslot[slot]) {
				avp = (void *)sc->beacon.bslot[slot]->drv_priv;
				if (avp->is_bslot_active) {
					found = true;
					break;
				}
			}
		}
		if (found) {
			/* Re-enable beaconing */
			ah->imask |= ATH9K_INT_SWBA;
			ath9k_hw_set_interrupts(ah, ah->imask);
		}
	} else {
		/* Disable SWBA interrupt */
		ah->imask &= ~ATH9K_INT_SWBA;
		ath9k_hw_set_interrupts(ah, ah->imask);
		tasklet_kill(&sc->bcon_tasklet);
		ath9k_hw_stoptxdma(ah, sc->beacon.beaconq);
	}
	ath9k_ps_restore(sc);
}