cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

beacon.c (20027B)


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