beacon.c 21.1 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 26 27
/*
 *  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
*/
static int ath_beaconq_config(struct ath_softc *sc)
{
28
	struct ath_hw *ah = sc->sc_ah;
29
	struct ath9k_tx_queue_info qi;
30

S
Sujith 已提交
31
	ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi);
32
	if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
33 34 35 36 37 38
		/* 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. */
S
Sujith 已提交
39 40 41
		qi.tqi_aifs = sc->beacon.beacon_qi.tqi_aifs;
		qi.tqi_cwmin = 2*sc->beacon.beacon_qi.tqi_cwmin;
		qi.tqi_cwmax = sc->beacon.beacon_qi.tqi_cwmax;
42 43
	}

S
Sujith 已提交
44
	if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) {
45
		DPRINTF(sc, ATH_DBG_FATAL,
S
Sujith 已提交
46
			"Unable to update h/w beacon queue parameters\n");
47 48
		return 0;
	} else {
S
Sujith 已提交
49
		ath9k_hw_resettxqueue(ah, sc->beacon.beaconq);
50 51 52 53 54 55 56 57 58
		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 已提交
59 60
static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
			     struct ath_buf *bf)
61
{
S
Sujith 已提交
62
	struct sk_buff *skb = bf->bf_mpdu;
63
	struct ath_hw *ah = sc->sc_ah;
64
	struct ath_desc *ds;
S
Sujith 已提交
65
	struct ath9k_11n_rate_series series[4];
66
	const struct ath_rate_table *rt;
S
Sujith 已提交
67 68
	int flags, antenna, ctsrate = 0, ctsduration = 0;
	u8 rate;
69 70 71 72

	ds = bf->bf_desc;
	flags = ATH9K_TXDESC_NOACK;

73 74
	if (((sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) ||
	     (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) &&
75
	    (ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
76 77 78 79 80 81 82 83
		ds->ds_link = bf->bf_daddr; /* self-linked */
		flags |= ATH9K_TXDESC_VEOL;
		/* Let hardware handle antenna switching. */
		antenna = 0;
	} else {
		ds->ds_link = 0;
		/*
		 * Switch antenna every beacon.
S
Sujith 已提交
84 85
		 * Should only switch every beacon period, not for every SWBA
		 * XXX assumes two antennae
86
		 */
S
Sujith 已提交
87
		antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1);
88 89 90 91
	}

	ds->ds_data = bf->bf_buf_addr;

92
	rt = sc->cur_rate_table;
S
Sujith 已提交
93
	rate = rt->info[0].ratecode;
S
Sujith 已提交
94
	if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
S
Sujith 已提交
95 96 97 98 99 100 101 102
		rate |= rt->info[0].short_preamble;

	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);
103 104

	/* NB: beacon's BufLen must be a multiple of 4 bytes */
S
Sujith 已提交
105 106
	ath9k_hw_filltxdesc(ah, ds, roundup(skb->len, 4),
			    true, true, ds);
107

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

117
static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
118
					   struct ieee80211_vif *vif)
119
{
120 121
	struct ath_wiphy *aphy = hw->priv;
	struct ath_softc *sc = aphy->sc;
122
	struct ath_buf *bf;
S
Sujith 已提交
123
	struct ath_vif *avp;
124 125
	struct sk_buff *skb;
	struct ath_txq *cabq;
126
	struct ieee80211_tx_info *info;
S
Sujith 已提交
127 128
	int cabq_depth;

129 130 131
	if (aphy->state != ATH_WIPHY_ACTIVE)
		return NULL;

S
Sujith 已提交
132
	avp = (void *)vif->drv_priv;
S
Sujith 已提交
133
	cabq = sc->beacon.cabq;
134

S
Sujith 已提交
135
	if (avp->av_bcbuf == NULL)
136
		return NULL;
S
Sujith 已提交
137

S
Sujith 已提交
138 139
	/* Release the old beacon first */

140
	bf = avp->av_bcbuf;
S
Sujith 已提交
141
	skb = bf->bf_mpdu;
142
	if (skb) {
143
		dma_unmap_single(sc->dev, bf->bf_dmacontext,
S
Sujith 已提交
144
				 skb->len, DMA_TO_DEVICE);
J
Jouni Malinen 已提交
145
		dev_kfree_skb_any(skb);
146
	}
147

S
Sujith 已提交
148 149
	/* Get a new beacon from mac80211 */

150
	skb = ieee80211_beacon_get(hw, vif);
151 152 153
	bf->bf_mpdu = skb;
	if (skb == NULL)
		return NULL;
154 155
	((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp =
		avp->tsf_adjust;
S
Sujith 已提交
156

157 158 159 160 161 162
	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 已提交
163
		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
S
Sujith 已提交
164
		sc->tx.seq_no += 0x10;
165
		hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
S
Sujith 已提交
166
		hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
167
	}
S
Sujith 已提交
168

169
	bf->bf_buf_addr = bf->bf_dmacontext =
170
		dma_map_single(sc->dev, skb->data,
S
Sujith 已提交
171
			       skb->len, DMA_TO_DEVICE);
172
	if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
173 174
		dev_kfree_skb_any(skb);
		bf->bf_mpdu = NULL;
S
Sujith 已提交
175
		DPRINTF(sc, ATH_DBG_FATAL, "dma_mapping_error on beaconing\n");
176 177
		return NULL;
	}
178

179
	skb = ieee80211_get_buffered_bc(hw, vif);
180 181 182 183

	/*
	 * if the CABQ traffic from previous DTIM is pending and the current
	 *  beacon is also a DTIM.
S
Sujith 已提交
184 185
	 *  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
186
	 *     beacons, then drain the cabq by dropping all the frames in
S
Sujith 已提交
187
	 *     the cabq so that the current vifs cab traffic can be scheduled.
188 189 190 191 192
	 */
	spin_lock_bh(&cabq->axq_lock);
	cabq_depth = cabq->axq_depth;
	spin_unlock_bh(&cabq->axq_lock);

193
	if (skb && cabq_depth) {
S
Sujith 已提交
194
		if (sc->nvifs > 1) {
195
			DPRINTF(sc, ATH_DBG_BEACON,
S
Sujith 已提交
196 197
				"Flushing previous cabq traffic\n");
			ath_draintxq(sc, cabq, false);
198 199 200 201 202
		}
	}

	ath_beacon_setup(sc, avp, bf);

203
	while (skb) {
204 205
		ath_tx_cabq(hw, skb);
		skb = ieee80211_get_buffered_bc(hw, vif);
206
	}
207 208 209 210 211 212 213 214

	return bf;
}

/*
 * Startup beacon transmission for adhoc mode when they are sent entirely
 * by the hardware using the self-linked descriptor + veol trick.
*/
215 216
static void ath_beacon_start_adhoc(struct ath_softc *sc,
				   struct ieee80211_vif *vif)
217
{
218
	struct ath_hw *ah = sc->sc_ah;
219
	struct ath_buf *bf;
S
Sujith 已提交
220
	struct ath_vif *avp;
221 222
	struct sk_buff *skb;

S
Sujith 已提交
223
	avp = (void *)vif->drv_priv;
224

S
Sujith 已提交
225
	if (avp->av_bcbuf == NULL)
226
		return;
S
Sujith 已提交
227

228
	bf = avp->av_bcbuf;
S
Sujith 已提交
229
	skb = bf->bf_mpdu;
230 231 232 233

	ath_beacon_setup(sc, avp, bf);

	/* NB: caller is known to have already stopped tx dma */
S
Sujith 已提交
234 235
	ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr);
	ath9k_hw_txstart(ah, sc->beacon.beaconq);
S
Sujith 已提交
236
	DPRINTF(sc, ATH_DBG_BEACON, "TXDP%u = %llx (%p)\n",
S
Sujith 已提交
237
		sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc);
238 239
}

240
int ath_beaconq_setup(struct ath_hw *ah)
241
{
242
	struct ath9k_tx_queue_info qi;
243

244
	memset(&qi, 0, sizeof(qi));
245 246 247 248 249 250 251
	qi.tqi_aifs = 1;
	qi.tqi_cwmin = 0;
	qi.tqi_cwmax = 0;
	/* NB: don't enable any interrupts */
	return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi);
}

252
int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
253
{
254
	struct ath_softc *sc = aphy->sc;
S
Sujith 已提交
255
	struct ath_vif *avp;
256 257
	struct ath_buf *bf;
	struct sk_buff *skb;
S
Sujith 已提交
258
	__le64 tstamp;
259

S
Sujith 已提交
260
	avp = (void *)vif->drv_priv;
261 262 263

	/* Allocate a beacon descriptor if we haven't done so. */
	if (!avp->av_bcbuf) {
S
Sujith 已提交
264 265
		/* Allocate beacon state for hostap/ibss.  We know
		 * a buffer is available. */
S
Sujith 已提交
266
		avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf,
S
Sujith 已提交
267
						 struct ath_buf, list);
268 269
		list_del(&avp->av_bcbuf->list);

270 271
		if (sc->sc_ah->opmode == NL80211_IFTYPE_AP ||
		    !(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
272 273
			int slot;
			/*
S
Sujith 已提交
274
			 * Assign the vif to a beacon xmit slot. As
275 276 277 278
			 * above, this cannot fail to find one.
			 */
			avp->av_bslot = 0;
			for (slot = 0; slot < ATH_BCBUF; slot++)
279
				if (sc->beacon.bslot[slot] == NULL) {
280 281 282 283 284
					/*
					 * XXX hack, space out slots to better
					 * deal with misses
					 */
					if (slot+1 < ATH_BCBUF &&
285
					    sc->beacon.bslot[slot+1] == NULL) {
286 287 288 289 290 291
						avp->av_bslot = slot+1;
						break;
					}
					avp->av_bslot = slot;
					/* NB: keep looking for a double slot */
				}
292 293
			BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL);
			sc->beacon.bslot[avp->av_bslot] = vif;
294
			sc->beacon.bslot_aphy[avp->av_bslot] = aphy;
S
Sujith 已提交
295
			sc->nbcnvifs++;
296 297 298
		}
	}

S
Sujith 已提交
299
	/* release the previous beacon frame, if it already exists. */
300 301
	bf = avp->av_bcbuf;
	if (bf->bf_mpdu != NULL) {
S
Sujith 已提交
302
		skb = bf->bf_mpdu;
303
		dma_unmap_single(sc->dev, bf->bf_dmacontext,
S
Sujith 已提交
304
				 skb->len, DMA_TO_DEVICE);
305 306 307 308
		dev_kfree_skb_any(skb);
		bf->bf_mpdu = NULL;
	}

S
Sujith 已提交
309
	/* NB: the beacon data buffer must be 32-bit aligned. */
S
Sujith 已提交
310
	skb = ieee80211_beacon_get(sc->hw, vif);
311
	if (skb == NULL) {
S
Sujith 已提交
312
		DPRINTF(sc, ATH_DBG_BEACON, "cannot get skb\n");
313 314 315
		return -ENOMEM;
	}

S
Sujith 已提交
316
	tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
S
Sujith 已提交
317
	sc->beacon.bc_tstamp = le64_to_cpu(tstamp);
318
	/* Calculate a TSF adjustment factor required for staggered beacons. */
319 320 321 322
	if (avp->av_bslot > 0) {
		u64 tsfadjust;
		int intval;

323
		intval = sc->beacon_interval ? : ATH_DEFAULT_BINTVAL;
324 325

		/*
326 327 328 329 330 331
		 * 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.
332
		 */
333 334
		tsfadjust = intval * avp->av_bslot / ATH_BCBUF;
		avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust));
335 336

		DPRINTF(sc, ATH_DBG_BEACON,
S
Sujith 已提交
337
			"stagger beacons, bslot %d intval %u tsfadjust %llu\n",
338 339
			avp->av_bslot, intval, (unsigned long long)tsfadjust);

340 341 342 343
		((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp =
			avp->tsf_adjust;
	} else
		avp->tsf_adjust = cpu_to_le64(0);
344

345
	bf->bf_mpdu = skb;
346
	bf->bf_buf_addr = bf->bf_dmacontext =
347
		dma_map_single(sc->dev, skb->data,
S
Sujith 已提交
348
			       skb->len, DMA_TO_DEVICE);
349
	if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
350 351
		dev_kfree_skb_any(skb);
		bf->bf_mpdu = NULL;
S
Sujith 已提交
352 353
		DPRINTF(sc, ATH_DBG_FATAL,
			"dma_mapping_error on beacon alloc\n");
354 355
		return -ENOMEM;
	}
356 357 358 359

	return 0;
}

S
Sujith 已提交
360
void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp)
361 362 363 364 365
{
	if (avp->av_bcbuf != NULL) {
		struct ath_buf *bf;

		if (avp->av_bslot != -1) {
366
			sc->beacon.bslot[avp->av_bslot] = NULL;
367
			sc->beacon.bslot_aphy[avp->av_bslot] = NULL;
S
Sujith 已提交
368
			sc->nbcnvifs--;
369 370 371 372
		}

		bf = avp->av_bcbuf;
		if (bf->bf_mpdu != NULL) {
S
Sujith 已提交
373
			struct sk_buff *skb = bf->bf_mpdu;
374
			dma_unmap_single(sc->dev, bf->bf_dmacontext,
S
Sujith 已提交
375
					 skb->len, DMA_TO_DEVICE);
376 377 378
			dev_kfree_skb_any(skb);
			bf->bf_mpdu = NULL;
		}
S
Sujith 已提交
379
		list_add_tail(&bf->list, &sc->beacon.bbuf);
380 381 382 383 384

		avp->av_bcbuf = NULL;
	}
}

S
Sujith 已提交
385
void ath_beacon_tasklet(unsigned long data)
386 387
{
	struct ath_softc *sc = (struct ath_softc *)data;
388
	struct ath_hw *ah = sc->sc_ah;
389
	struct ath_buf *bf = NULL;
390
	struct ieee80211_vif *vif;
391
	struct ath_wiphy *aphy;
392
	int slot;
S
Sujith 已提交
393
	u32 bfaddr, bc = 0, tsftu;
394 395 396 397 398 399 400 401 402 403
	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 已提交
404 405
	if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) {
		sc->beacon.bmisscnt++;
S
Sujith 已提交
406

S
Sujith 已提交
407
		if (sc->beacon.bmisscnt < BSTUCK_THRESH) {
S
Sujith 已提交
408 409 410
			DPRINTF(sc, ATH_DBG_BEACON,
				"missed %u consecutive beacons\n",
				sc->beacon.bmisscnt);
S
Sujith 已提交
411
		} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
S
Sujith 已提交
412 413 414
			DPRINTF(sc, ATH_DBG_BEACON,
				"beacon is officially stuck\n");
			ath_reset(sc, false);
415
		}
S
Sujith 已提交
416

417 418
		return;
	}
S
Sujith 已提交
419

S
Sujith 已提交
420
	if (sc->beacon.bmisscnt != 0) {
S
Sujith 已提交
421 422 423
		DPRINTF(sc, ATH_DBG_BEACON,
			"resume beacon xmit after %u misses\n",
			sc->beacon.bmisscnt);
S
Sujith 已提交
424
		sc->beacon.bmisscnt = 0;
425 426 427 428 429 430 431 432
	}

	/*
	 * 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.
	 */

433
	intval = sc->beacon_interval ? : ATH_DEFAULT_BINTVAL;
434 435 436 437

	tsf = ath9k_hw_gettsf64(ah);
	tsftu = TSF_TO_TU(tsf>>32, tsf);
	slot = ((tsftu % intval) * ATH_BCBUF) / intval;
438 439 440 441 442 443 444 445 446 447
	/*
	 * 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];
	aphy = sc->beacon.bslot_aphy[slot];
S
Sujith 已提交
448

449
	DPRINTF(sc, ATH_DBG_BEACON,
450 451
		"slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
		slot, tsf, tsftu, intval, vif);
S
Sujith 已提交
452

453
	bfaddr = 0;
454
	if (vif) {
455
		bf = ath_beacon_generate(aphy->hw, vif);
456 457 458 459 460
		if (bf != NULL) {
			bfaddr = bf->bf_daddr;
			bc = 1;
		}
	}
S
Sujith 已提交
461

462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
	/*
	 * 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 已提交
478 479 480 481 482 483
	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) {
		ath9k_hw_setslottime(sc->sc_ah, sc->beacon.slottime);
		sc->beacon.updateslot = OK;
S
Sujith 已提交
484
	}
485 486 487 488 489 490
	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 已提交
491
		if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) {
492
			DPRINTF(sc, ATH_DBG_FATAL,
S
Sujith 已提交
493
				"beacon queue %u did not stop?\n", sc->beacon.beaconq);
494 495 496
		}

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

S
Sujith 已提交
500
		sc->beacon.ast_be_xmit += bc;     /* XXX per-vif? */
501 502 503 504
	}
}

/*
505 506 507
 * 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.
508
 */
509
static void ath_beacon_config_ap(struct ath_softc *sc,
510
				 struct ath_beacon_config *conf)
511
{
S
Sujith 已提交
512
	u32 nexttbtt, intval;
513

S
Sujith 已提交
514 515 516 517 518
	/* Configure the timers only when the TSF has to be reset */

	if (!(sc->sc_flags & SC_OP_TSF_RESET))
		return;

519 520 521 522 523
	/* 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;
	intval |= ATH9K_BEACON_RESET_TSF;
524

525 526 527 528 529 530 531
	/*
	 * In AP mode we enable the beacon timers and SWBA interrupts to
	 * prepare beacon frames.
	 */
	intval |= ATH9K_BEACON_ENA;
	sc->imask |= ATH9K_INT_SWBA;
	ath_beaconq_config(sc);
532

533
	/* Set the computed AP beacon timers */
534

535 536 537 538
	ath9k_hw_set_interrupts(sc->sc_ah, 0);
	ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval);
	sc->beacon.bmisscnt = 0;
	ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
S
Sujith 已提交
539 540 541 542 543

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

	sc->sc_flags &= ~SC_OP_TSF_RESET;
544
}
S
Sujith 已提交
545

546 547 548 549 550 551 552 553 554
/*
 * 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,
555
				  struct ath_beacon_config *conf)
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
{
	struct ath9k_beacon_state bs;
	int dtimperiod, dtimcount, sleepduration;
	int cfpperiod, cfpcount;
	u32 nexttbtt = 0, intval, tsftu;
	u64 tsf;

	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;
	if (dtimperiod <= 0)		/* NB: 0 if not known */
		dtimperiod = 1;
	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;
	if (sleepduration <= 0)
		sleepduration = intval;

	/*
	 * Pull nexttbtt forward to reflect the current
	 * TSF and calculate dtim+cfp state for the result.
	 */
	tsf = ath9k_hw_gettsf64(sc->sc_ah);
	tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
	do {
		nexttbtt += intval;
		if (--dtimcount < 0) {
			dtimcount = dtimperiod - 1;
			if (--cfpcount < 0)
				cfpcount = cfpperiod - 1;
		}
	} while (nexttbtt < tsftu);

	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;
615
	} else {
616 617 618 619 620
		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;
621 622
	}

623 624 625 626 627 628 629 630
	/*
	 * 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 已提交
631

632 633 634
	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 已提交
635

636 637
	/* TSF out of range threshold fixed at 1 second */
	bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
638

639 640 641 642 643
	DPRINTF(sc, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu);
	DPRINTF(sc, 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);
644

645
	/* Set the computed STA beacon timers */
S
Sujith 已提交
646

647 648 649 650 651
	ath9k_hw_set_interrupts(sc->sc_ah, 0);
	ath9k_hw_set_sta_beacon_timers(sc->sc_ah, &bs);
	sc->imask |= ATH9K_INT_BMISS;
	ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
}
652

653 654
static void ath_beacon_config_adhoc(struct ath_softc *sc,
				    struct ath_beacon_config *conf,
655
				    struct ieee80211_vif *vif)
656 657 658
{
	u64 tsf;
	u32 tsftu, intval, nexttbtt;
659

660
	intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
661

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

664 665 666 667 668
	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 已提交
669

670 671 672 673 674
	tsf = ath9k_hw_gettsf64(sc->sc_ah);
	tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE;
	do {
		nexttbtt += intval;
	} while (nexttbtt < tsftu);
675

676 677 678
	DPRINTF(sc, ATH_DBG_BEACON,
		"IBSS nexttbtt %u intval %u (%u)\n",
		nexttbtt, intval, conf->beacon_interval);
S
Sujith 已提交
679

680 681 682 683 684 685 686 687
	/*
	 * 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;
	if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL))
		sc->imask |= ATH9K_INT_SWBA;
S
Sujith 已提交
688

689 690 691 692 693 694 695 696 697 698
	ath_beaconq_config(sc);

	/* Set the computed ADHOC beacon timers */

	ath9k_hw_set_interrupts(sc->sc_ah, 0);
	ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval);
	sc->beacon.bmisscnt = 0;
	ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);

	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)
699
		ath_beacon_start_adhoc(sc, vif);
700 701
}

702
void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
703
{
704 705 706 707 708
	struct ath_beacon_config conf;

	/* Setup the beacon configuration parameters */

	memset(&conf, 0, sizeof(struct ath_beacon_config));
709
	conf.beacon_interval = sc->beacon_interval ? : ATH_DEFAULT_BINTVAL;
710 711 712 713 714
	conf.listen_interval = 1;
	conf.dtim_period = conf.beacon_interval;
	conf.dtim_count = 1;
	conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval;

715 716
	if (vif) {
		struct ath_vif *avp = (struct ath_vif *)vif->drv_priv;
717 718 719

		switch(avp->av_opmode) {
		case NL80211_IFTYPE_AP:
720
			ath_beacon_config_ap(sc, &conf);
721 722
			break;
		case NL80211_IFTYPE_ADHOC:
723
		case NL80211_IFTYPE_MESH_POINT:
724
			ath_beacon_config_adhoc(sc, &conf, vif);
725 726
			break;
		case NL80211_IFTYPE_STATION:
727
			ath_beacon_config_sta(sc, &conf);
728 729 730 731 732 733 734 735 736
			break;
		default:
			DPRINTF(sc, ATH_DBG_CONFIG,
				"Unsupported beaconing mode\n");
			return;
		}

		sc->sc_flags |= SC_OP_BEACONS;
	}
737
}