beacon.c 23.4 KB
Newer Older
1
/*
2
 * Copyright (c) 2008-2011 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.
 */

17
#include <linux/dma-mapping.h>
S
Sujith 已提交
18
#include "ath9k.h"
19

20 21
#define FUDGE 2

22 23 24 25 26 27
static void ath9k_reset_beacon_status(struct ath_softc *sc)
{
	sc->beacon.tx_processed = false;
	sc->beacon.tx_last = false;
}

28 29 30 31 32
/*
 *  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
*/
33
int ath_beaconq_config(struct ath_softc *sc)
34
{
35
	struct ath_hw *ah = sc->sc_ah;
36
	struct ath_common *common = ath9k_hw_common(ah);
37
	struct ath9k_tx_queue_info qi, qi_be;
38
	struct ath_txq *txq;
39

S
Sujith 已提交
40
	ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi);
41
	if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
42 43 44 45 46 47
		/* 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. */
48 49
		txq = sc->tx.txq_map[WME_AC_BE];
		ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be);
50 51 52
		qi.tqi_aifs = qi_be.tqi_aifs;
		qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
		qi.tqi_cwmax = qi_be.tqi_cwmax;
53 54
	}

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

/*
 *  Associates the beacon frame buffer with a transmit descriptor.  Will set
67 68
 *  up rate codes, and channel flags. Beacons are always sent out at the
 *  lowest rate, and are not retried.
69
*/
S
Sujith 已提交
70
static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
71
			     struct ath_buf *bf, int rateidx)
72
{
S
Sujith 已提交
73
	struct sk_buff *skb = bf->bf_mpdu;
74
	struct ath_hw *ah = sc->sc_ah;
75
	struct ath_common *common = ath9k_hw_common(ah);
76
	struct ath_tx_info info;
77
	struct ieee80211_supported_band *sband;
78
	u8 chainmask = ah->txchainmask;
79
	u8 rate = 0;
80

81 82
	ath9k_reset_beacon_status(sc);

83
	sband = &sc->sbands[common->hw->conf.channel->band];
84
	rate = sband->bitrates[rateidx].hw_value;
S
Sujith 已提交
85
	if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
86
		rate |= sband->bitrates[rateidx].hw_value_short;
S
Sujith 已提交
87

88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
	memset(&info, 0, sizeof(info));
	info.pkt_len = skb->len + FCS_LEN;
	info.type = ATH9K_PKT_TYPE_BEACON;
	info.txpower = MAX_RATE_POWER;
	info.keyix = ATH9K_TXKEYIX_INVALID;
	info.keytype = ATH9K_KEY_TYPE_CLEAR;
	info.flags = ATH9K_TXDESC_NOACK;

	info.buf_addr[0] = bf->bf_buf_addr;
	info.buf_len[0] = roundup(skb->len, 4);

	info.is_first = true;
	info.is_last = true;

	info.qcu = sc->beacon.beaconq;

	info.rates[0].Tries = 1;
	info.rates[0].Rate = rate;
	info.rates[0].ChSel = ath_txchainmask_reduction(sc, chainmask, rate);

	ath9k_hw_set_txdesc(ah, bf->bf_desc, &info);
109 110
}

111 112
static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
{
113
	struct ath_softc *sc = hw->priv;
114 115 116 117 118 119
	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 已提交
120 121
	ath_dbg(common, ATH_DBG_XMIT,
		"transmitting CABQ packet, skb: %p\n", skb);
122 123

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

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

141 142
	ath9k_reset_beacon_status(sc);

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;
281
	sc->beacon.bc_tstamp = (u32) 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 = TU_TO_USEC(intval * avp->av_bslot) / ATH_BCBUF;
		avp->tsf_adjust = cpu_to_le64(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
{
	if (avp->av_bcbuf != NULL) {
		struct ath_buf *bf;

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

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

		avp->av_bcbuf = NULL;
	}
}

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

	/*
	 * 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 已提交
370 371
	if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) {
		sc->beacon.bmisscnt++;
S
Sujith 已提交
372

373
		if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) {
J
Joe Perches 已提交
374 375 376
			ath_dbg(common, ATH_DBG_BSTUCK,
				"missed %u consecutive beacons\n",
				sc->beacon.bmisscnt);
377
			ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
378 379
			if (sc->beacon.bmisscnt > 3)
				ath9k_hw_bstuck_nfcal(ah);
S
Sujith 已提交
380
		} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
J
Joe Perches 已提交
381 382
			ath_dbg(common, ATH_DBG_BSTUCK,
				"beacon is officially stuck\n");
383
			sc->sc_flags |= SC_OP_TSF_RESET;
384
			ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
385
		}
S
Sujith 已提交
386

387 388
		return;
	}
S
Sujith 已提交
389

390 391 392 393 394 395 396
	/*
	 * 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.
	 */


397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415
	if (ah->opmode == NL80211_IFTYPE_AP) {
		u16 intval;
		u32 tsftu;
		u64 tsf;

		intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
		tsf = ath9k_hw_gettsf64(ah);
		tsf += TU_TO_USEC(ah->config.sw_beacon_response_time);
		tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF);
		slot = (tsftu % (intval * ATH_BCBUF)) / intval;
		vif = sc->beacon.bslot[slot];

		ath_dbg(common, ATH_DBG_BEACON,
			"slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
			slot, tsf, tsftu / ATH_BCBUF, intval, vif);
	} else {
		slot = 0;
		vif = sc->beacon.bslot[slot];
	}
S
Sujith 已提交
416 417


418
	bfaddr = 0;
419
	if (vif) {
420
		bf = ath_beacon_generate(sc->hw, vif);
421 422 423 424
		if (bf != NULL) {
			bfaddr = bf->bf_daddr;
			bc = 1;
		}
425 426 427 428 429 430 431

		if (sc->beacon.bmisscnt != 0) {
			ath_dbg(common, ATH_DBG_BSTUCK,
				"resume beacon xmit after %u misses\n",
				sc->beacon.bmisscnt);
			sc->beacon.bmisscnt = 0;
		}
432
	}
S
Sujith 已提交
433

434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
	/*
	 * 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 已提交
450 451 452 453
	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) {
454 455
		ah->slottime = sc->beacon.slottime;
		ath9k_hw_init_global_settings(ah);
S
Sujith 已提交
456
		sc->beacon.updateslot = OK;
S
Sujith 已提交
457
	}
458 459
	if (bfaddr != 0) {
		/* NB: cabq traffic should already be queued and primed */
S
Sujith 已提交
460 461
		ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr);
		ath9k_hw_txstart(ah, sc->beacon.beaconq);
462

S
Sujith 已提交
463
		sc->beacon.ast_be_xmit += bc;     /* XXX per-vif? */
464 465 466 467 468
		if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
			spin_lock_bh(&sc->sc_pcu_lock);
			ath9k_hw_txprocdesc(ah, bf->bf_desc, (void *)&ts);
			spin_unlock_bh(&sc->sc_pcu_lock);
		}
469 470 471
	}
}

472 473 474 475
static void ath9k_beacon_init(struct ath_softc *sc,
			      u32 next_beacon,
			      u32 beacon_period)
{
476
	if (sc->sc_flags & SC_OP_TSF_RESET) {
477
		ath9k_ps_wakeup(sc);
478 479
		ath9k_hw_reset_tsf(sc->sc_ah);
	}
480 481 482

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

483
	if (sc->sc_flags & SC_OP_TSF_RESET) {
484
		ath9k_ps_restore(sc);
485 486
		sc->sc_flags &= ~SC_OP_TSF_RESET;
	}
487 488
}

489
/*
490 491 492
 * 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.
493
 */
494
static void ath_beacon_config_ap(struct ath_softc *sc,
495
				 struct ath_beacon_config *conf)
496
{
P
Pavel Roskin 已提交
497
	struct ath_hw *ah = sc->sc_ah;
S
Sujith 已提交
498
	u32 nexttbtt, intval;
499

500
	/* NB: the beacon interval is kept internally in TU's */
501
	intval = TU_TO_USEC(conf->beacon_interval);
502 503
	intval /= ATH_BCBUF;    /* for staggered beacons */
	nexttbtt = intval;
504

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

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

514
	ath9k_hw_disable_interrupts(ah);
515
	sc->sc_flags |= SC_OP_TSF_RESET;
516
	ath9k_beacon_init(sc, nexttbtt, intval);
517
	sc->beacon.bmisscnt = 0;
518
	ath9k_hw_set_interrupts(ah);
519
	ath9k_hw_enable_interrupts(ah);
520
}
S
Sujith 已提交
521

522 523 524 525 526 527 528 529 530
/*
 * 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,
531
				  struct ath_beacon_config *conf)
532
{
P
Pavel Roskin 已提交
533 534
	struct ath_hw *ah = sc->sc_ah;
	struct ath_common *common = ath9k_hw_common(ah);
535 536 537 538 539
	struct ath9k_beacon_state bs;
	int dtimperiod, dtimcount, sleepduration;
	int cfpperiod, cfpcount;
	u32 nexttbtt = 0, intval, tsftu;
	u64 tsf;
540
	int num_beacons, offset, dtim_dec_count, cfp_dec_count;
541

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

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

	/*
	 * 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 已提交
569
	tsf = ath9k_hw_gettsf64(ah);
570
	tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
571 572 573 574 575

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

	/* 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;
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609

	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;
610
	} else {
611 612 613 614 615
		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;
616 617
	}

618 619 620 621 622 623 624 625
	/*
	 * 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 已提交
626

627 628 629
	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 已提交
630

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

J
Joe Perches 已提交
634 635 636 637 638
	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);
639

640
	/* Set the computed STA beacon timers */
S
Sujith 已提交
641

642
	ath9k_hw_disable_interrupts(ah);
P
Pavel Roskin 已提交
643 644
	ath9k_hw_set_sta_beacon_timers(ah, &bs);
	ah->imask |= ATH9K_INT_BMISS;
645

646
	ath9k_hw_set_interrupts(ah);
647
	ath9k_hw_enable_interrupts(ah);
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
	u32 tsf, intval, nexttbtt;
656

657 658
	ath9k_reset_beacon_status(sc);

659
	intval = TU_TO_USEC(conf->beacon_interval);
660 661
	tsf = roundup(ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE), intval);
	nexttbtt = tsf + intval;
662

J
Joe Perches 已提交
663 664 665
	ath_dbg(common, ATH_DBG_BEACON,
		"IBSS nexttbtt %u intval %u (%u)\n",
		nexttbtt, intval, conf->beacon_interval);
S
Sujith 已提交
666

667 668 669 670 671
	/*
	 * 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.
	 */
672
	ah->imask |= ATH9K_INT_SWBA;
S
Sujith 已提交
673

674 675 676 677
	ath_beaconq_config(sc);

	/* Set the computed ADHOC beacon timers */

678
	ath9k_hw_disable_interrupts(ah);
679
	ath9k_beacon_init(sc, nexttbtt, intval);
680
	sc->beacon.bmisscnt = 0;
681

682
	ath9k_hw_set_interrupts(ah);
683
	ath9k_hw_enable_interrupts(ah);
684 685
}

686 687
static bool ath9k_allow_beacon_config(struct ath_softc *sc,
				      struct ieee80211_vif *vif)
688
{
689
	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
690
	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
691 692
	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
	struct ath_vif *avp = (void *)vif->drv_priv;
693

694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
	/*
	 * Can not have different beacon interval on multiple
	 * AP interface case
	 */
	if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
	    (sc->nbcnvifs > 1) &&
	    (vif->type == NL80211_IFTYPE_AP) &&
	    (cur_conf->beacon_interval != bss_conf->beacon_int)) {
		ath_dbg(common, ATH_DBG_CONFIG,
			"Changing beacon interval of multiple \
			AP interfaces !\n");
		return false;
	}
	/*
	 * Can not configure station vif's beacon config
	 * while on AP opmode
	 */
	if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
	    (vif->type != NL80211_IFTYPE_AP)) {
		ath_dbg(common, ATH_DBG_CONFIG,
			"STA vif's beacon not allowed on AP mode\n");
		return false;
	}
	/*
	 * Do not allow beacon config if HW was already configured
	 * with another STA vif
	 */
	if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
	    (vif->type == NL80211_IFTYPE_STATION) &&
	    (sc->sc_flags & SC_OP_BEACONS) &&
	    !avp->primary_sta_vif) {
		ath_dbg(common, ATH_DBG_CONFIG,
			"Beacon already configured for a station interface\n");
		return false;
728
	}
729 730 731 732 733 734 735
	return true;
}

void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
{
	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
736

737 738 739 740 741 742
	if (!ath9k_allow_beacon_config(sc, vif))
		return;

	/* Setup the beacon configuration parameters */
	cur_conf->beacon_interval = bss_conf->beacon_int;
	cur_conf->dtim_period = bss_conf->dtim_period;
743 744 745 746
	cur_conf->listen_interval = 1;
	cur_conf->dtim_count = 1;
	cur_conf->bmiss_timeout =
		ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
747

748 749 750 751 752 753 754 755
	/*
	 * 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;
756

757
	/*
758 759 760
	 * 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
761 762 763 764
	 */
	if (cur_conf->dtim_period == 0)
		cur_conf->dtim_period = 1;

765 766 767
	ath_set_beacon(sc);
}

768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786
static bool ath_has_valid_bslot(struct ath_softc *sc)
{
	struct ath_vif *avp;
	int slot;
	bool found = false;

	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;
			}
		}
	}
	return found;
}


787 788 789 790 791
void ath_set_beacon(struct ath_softc *sc)
{
	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;

792
	switch (sc->sc_ah->opmode) {
793
	case NL80211_IFTYPE_AP:
794 795
		if (ath_has_valid_bslot(sc))
			ath_beacon_config_ap(sc, cur_conf);
796 797 798
		break;
	case NL80211_IFTYPE_ADHOC:
	case NL80211_IFTYPE_MESH_POINT:
799
		ath_beacon_config_adhoc(sc, cur_conf);
800 801 802 803 804
		break;
	case NL80211_IFTYPE_STATION:
		ath_beacon_config_sta(sc, cur_conf);
		break;
	default:
J
Joe Perches 已提交
805 806
		ath_dbg(common, ATH_DBG_CONFIG,
			"Unsupported beaconing mode\n");
807 808 809 810
		return;
	}

	sc->sc_flags |= SC_OP_BEACONS;
811
}
812 813 814 815 816

void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
{
	struct ath_hw *ah = sc->sc_ah;

817
	if (!ath_has_valid_bslot(sc))
818 819 820 821 822 823
		return;

	ath9k_ps_wakeup(sc);
	if (status) {
		/* Re-enable beaconing */
		ah->imask |= ATH9K_INT_SWBA;
824
		ath9k_hw_set_interrupts(ah);
825 826 827
	} else {
		/* Disable SWBA interrupt */
		ah->imask &= ~ATH9K_INT_SWBA;
828
		ath9k_hw_set_interrupts(ah);
829
		tasklet_kill(&sc->bcon_tasklet);
830
		ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
831 832 833
	}
	ath9k_ps_restore(sc);
}