beacon.c 23.9 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.
 */

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

19 20
#define FUDGE 2

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

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

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

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

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

81 82
	ath9k_reset_beacon_status(sc);

83 84 85
	ds = bf->bf_desc;
	flags = ATH9K_TXDESC_NOACK;

86
	ds->ds_link = 0;
87

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

	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);
99 100

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

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

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

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

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

145 146
	ath9k_reset_beacon_status(sc);

S
Sujith 已提交
147
	avp = (void *)vif->drv_priv;
S
Sujith 已提交
148
	cabq = sc->beacon.cabq;
149

150
	if ((avp->av_bcbuf == NULL) || !avp->is_bslot_active)
151
		return NULL;
S
Sujith 已提交
152

S
Sujith 已提交
153 154
	/* Release the old beacon first */

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

S
Sujith 已提交
164 165
	/* Get a new beacon from mac80211 */

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

173 174 175 176 177 178
	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 已提交
179
		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
S
Sujith 已提交
180
		sc->tx.seq_no += 0x10;
181
		hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
S
Sujith 已提交
182
		hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
183
	}
S
Sujith 已提交
184

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

195
	skb = ieee80211_get_buffered_bc(hw, vif);
196 197 198 199

	/*
	 * if the CABQ traffic from previous DTIM is pending and the current
	 *  beacon is also a DTIM.
S
Sujith 已提交
200 201
	 *  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
202
	 *     beacons, then drain the cabq by dropping all the frames in
S
Sujith 已提交
203
	 *     the cabq so that the current vifs cab traffic can be scheduled.
204 205 206 207 208
	 */
	spin_lock_bh(&cabq->axq_lock);
	cabq_depth = cabq->axq_depth;
	spin_unlock_bh(&cabq->axq_lock);

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

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

219
	while (skb) {
220 221
		ath_tx_cabq(hw, skb);
		skb = ieee80211_get_buffered_bc(hw, vif);
222
	}
223 224 225 226

	return bf;
}

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

S
Sujith 已提交
236
	avp = (void *)vif->drv_priv;
237 238 239

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

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

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

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

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

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

291
		intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
292 293

		/*
294 295 296 297 298 299
		 * 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.
300
		 */
301 302
		tsfadjust = TU_TO_USEC(intval * avp->av_bslot) / ATH_BCBUF;
		avp->tsf_adjust = cpu_to_le64(tsfadjust);
303

J
Joe Perches 已提交
304 305 306
		ath_dbg(common, ATH_DBG_BEACON,
			"stagger beacons, bslot %d intval %u tsfadjust %llu\n",
			avp->av_bslot, intval, (unsigned long long)tsfadjust);
307

308 309 310 311
		((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp =
			avp->tsf_adjust;
	} else
		avp->tsf_adjust = cpu_to_le64(0);
312

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

	return 0;
}

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

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

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

		avp->av_bcbuf = NULL;
	}
}

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

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

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

390 391
		return;
	}
S
Sujith 已提交
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 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
	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 已提交
419 420


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

		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;
		}
435
	}
S
Sujith 已提交
436

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

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

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

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

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

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

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

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

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

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

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

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

545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
	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 已提交
565
	tsf = ath9k_hw_gettsf64(ah);
566
	tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
567 568 569 570 571

	num_beacons = tsftu / intval + 1;
	offset = tsftu % intval;
	nexttbtt = tsftu - offset;
	if (offset)
572
		nexttbtt += intval;
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587

	/* 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;
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605

	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;
606
	} else {
607 608 609 610 611
		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;
612 613
	}

614 615 616 617 618 619 620 621
	/*
	 * 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 已提交
622

623 624 625
	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 已提交
626

627 628
	/* TSF out of range threshold fixed at 1 second */
	bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
629

J
Joe Perches 已提交
630 631 632 633 634
	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);
635

636
	/* Set the computed STA beacon timers */
S
Sujith 已提交
637

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

	/*
	 * If the beacon config is called beacause of TSFOOR,
	 * Interrupts will be enabled back at the end of ath9k_tasklet
	 */
	if (!(sc->ps_flags & PS_TSFOOR_SYNC))
		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
	u32 tsf, delta, intval, nexttbtt;

657 658
	ath9k_reset_beacon_status(sc);

659 660 661 662 663 664 665 666 667 668
	tsf = ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE);
	intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD);

	if (!sc->beacon.bc_tstamp)
		nexttbtt = tsf + intval;
	else {
		if (tsf > sc->beacon.bc_tstamp)
			delta = (tsf - sc->beacon.bc_tstamp);
		else
			delta = (tsf + 1 + (~0U - sc->beacon.bc_tstamp));
669
		nexttbtt = tsf + intval - (delta % intval);
670
	}
671

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

676 677 678 679 680
	/*
	 * 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.
	 */
681
	ah->imask |= ATH9K_INT_SWBA;
S
Sujith 已提交
682

683 684 685 686
	ath_beaconq_config(sc);

	/* Set the computed ADHOC beacon timers */

687
	ath9k_hw_disable_interrupts(ah);
688
	ath9k_beacon_init(sc, nexttbtt, intval);
689
	sc->beacon.bmisscnt = 0;
690 691 692 693 694 695
	/*
	 * If the beacon config is called beacause of TSFOOR,
	 * Interrupts will be enabled back at the end of ath9k_tasklet
	 */
	if (!(sc->ps_flags & PS_TSFOOR_SYNC))
		ath9k_hw_set_interrupts(ah, ah->imask);
696 697
}

698 699
static bool ath9k_allow_beacon_config(struct ath_softc *sc,
				      struct ieee80211_vif *vif)
700
{
701
	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
702
	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
703 704
	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
	struct ath_vif *avp = (void *)vif->drv_priv;
705

706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
	/*
	 * 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;
740
	}
741 742 743 744 745 746 747
	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;
748

749 750 751 752 753 754
	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;
755 756 757 758
	cur_conf->listen_interval = 1;
	cur_conf->dtim_count = 1;
	cur_conf->bmiss_timeout =
		ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
759

760 761 762 763 764 765 766 767
	/*
	 * 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;
768

769
	/*
770 771 772
	 * 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
773 774 775 776
	 */
	if (cur_conf->dtim_period == 0)
		cur_conf->dtim_period = 1;

777 778 779
	ath_set_beacon(sc);
}

780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
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;
}


799 800 801 802 803
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;

804
	switch (sc->sc_ah->opmode) {
805
	case NL80211_IFTYPE_AP:
806 807
		if (ath_has_valid_bslot(sc))
			ath_beacon_config_ap(sc, cur_conf);
808 809 810
		break;
	case NL80211_IFTYPE_ADHOC:
	case NL80211_IFTYPE_MESH_POINT:
811
		ath_beacon_config_adhoc(sc, cur_conf);
812 813 814 815 816
		break;
	case NL80211_IFTYPE_STATION:
		ath_beacon_config_sta(sc, cur_conf);
		break;
	default:
J
Joe Perches 已提交
817 818
		ath_dbg(common, ATH_DBG_CONFIG,
			"Unsupported beaconing mode\n");
819 820 821 822
		return;
	}

	sc->sc_flags |= SC_OP_BEACONS;
823
}
824 825 826 827 828

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

829
	if (!ath_has_valid_bslot(sc))
830 831 832 833 834 835 836
		return;

	ath9k_ps_wakeup(sc);
	if (status) {
		/* Re-enable beaconing */
		ah->imask |= ATH9K_INT_SWBA;
		ath9k_hw_set_interrupts(ah, ah->imask);
837 838 839 840 841
	} else {
		/* Disable SWBA interrupt */
		ah->imask &= ~ATH9K_INT_SWBA;
		ath9k_hw_set_interrupts(ah, ah->imask);
		tasklet_kill(&sc->bcon_tasklet);
842
		ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
843 844 845
	}
	ath9k_ps_restore(sc);
}