brintos

brintos / linux-shallow public Read only

0
0
Text · 19.6 KiB · b399a79 Raw
719 lines · c
1/*2 * Copyright (c) 2008-2011 Atheros Communications Inc.3 *4 * Permission to use, copy, modify, and/or distribute this software for any5 * purpose with or without fee is hereby granted, provided that the above6 * copyright notice and this permission notice appear in all copies.7 *8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF14 * 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 221 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 on30 *  the operating mode of the station (AP or AdHoc).  Parameters are AIFS31 *  settings and channel width min/max32*/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		else56			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 set69 *  up rate codes, and channel flags. Beacons are always sent out at the70 *  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, 0);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 current169	 *  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 staggered172	 *     beacons, then drain the cabq by dropping all the frames in173	 *     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 the350		 * beacon late, so need to adjust the TSF starting point to be351		 * later in time (i.e. the theoretical first beacon has a TSF352		 * 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->bss_conf.csa_active)366		return false;367 368	if (!ieee80211_beacon_cntdwn_is_complete(vif, 0))369		return false;370 371	ieee80211_csa_finish(vif, 0);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.  If406	 * not don't try to post another, skip this period407	 * and wait for the next.  Missed beacons indicate408	 * a problem and should not occur.  If we miss too409	 * 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 transmitted418		 * and a MAC/BB hang has been identified, return419		 * here because a chip reset would have been420		 * 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/leaves472	 * an 11g network.  The 802.11 layer notifies us via callback,473	 * we mark updateslot, then wait one beacon before effecting474	 * the change.  This gives associated stations at least one475	 * beacon interval to note the state change.476	 *477	 * NB: The slot time change state machine is clocked according478	 *     to whether we are bursting or staggering beacons.  We479	 *     recognize the request to update and record the current480	 *     slot then don't transition until that slot is reached481	 *     again.  If we miss a beacon for that slot then we'll be482	 *     slow to transition but we'll be sure at least one beacon483	 *     interval has passed.  When bursting slot is always left484	 *     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 or538 * burst together.  For the former arrange for the SWBA to be delivered for each539 * 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 the580	 * 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_vif *vif)589{590	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;591	struct ath_common *common = ath9k_hw_common(sc->sc_ah);592	struct ath_beacon_config *cur_conf = &ctx->beacon;593 594	ath_dbg(common, BEACON,595		"Caching beacon data for BSS: %pM\n", bss_conf->bssid);596 597	cur_conf->beacon_interval = bss_conf->beacon_int;598	cur_conf->dtim_period = bss_conf->dtim_period;599	cur_conf->dtim_count = 1;600	cur_conf->ibss_creator = vif->cfg.ibss_creator;601 602	/*603	 * It looks like mac80211 may end up using beacon interval of zero in604	 * some cases (at least for mesh point). Avoid getting into an605	 * infinite loop by using a bit safer value instead. To be safe,606	 * do sanity check on beacon interval for all operating modes.607	 */608	if (cur_conf->beacon_interval == 0)609		cur_conf->beacon_interval = 100;610 611	cur_conf->bmiss_timeout =612		ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;613 614	/*615	 * We don't parse dtim period from mac80211 during the driver616	 * initialization as it breaks association with hidden-ssid617	 * AP and it causes latency in roaming618	 */619	if (cur_conf->dtim_period == 0)620		cur_conf->dtim_period = 1;621 622	ath9k_set_tsfadjust(sc, cur_conf);623}624 625void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif,626			 bool beacons)627{628	struct ath_hw *ah = sc->sc_ah;629	struct ath_common *common = ath9k_hw_common(ah);630	struct ath_vif *avp;631	struct ath_chanctx *ctx;632	struct ath_beacon_config *cur_conf;633	unsigned long flags;634	bool enabled;635	bool skip_beacon = false;636 637	if (!beacons) {638		clear_bit(ATH_OP_BEACONS, &common->op_flags);639		ath9k_beacon_stop(sc);640		return;641	}642 643	if (WARN_ON(!main_vif))644		return;645 646	avp = (void *)main_vif->drv_priv;647	ctx = avp->chanctx;648	cur_conf = &ctx->beacon;649	enabled = cur_conf->enable_beacon;650	cur_conf->enable_beacon = beacons;651 652	if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {653		ath9k_cache_beacon_config(sc, ctx, main_vif);654 655		ath9k_set_beacon(sc);656		set_bit(ATH_OP_BEACONS, &common->op_flags);657		return;658	}659 660	/* Update the beacon configuration. */661	ath9k_cache_beacon_config(sc, ctx, main_vif);662 663	/*664	 * Configure the HW beacon registers only when we have a valid665	 * beacon interval.666	 */667	if (cur_conf->beacon_interval) {668		/* Special case to sync the TSF when joining an existing IBSS.669		 * This is only done if no AP interface is active.670		 * Note that mac80211 always resets the TSF when creating a new671		 * IBSS interface.672		 */673		if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC &&674		    !enabled && beacons && !main_vif->cfg.ibss_creator) {675			spin_lock_irqsave(&sc->sc_pm_lock, flags);676			sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;677			spin_unlock_irqrestore(&sc->sc_pm_lock, flags);678			skip_beacon = true;679		}680 681		/*682		 * Do not set the ATH_OP_BEACONS flag for IBSS joiner mode683		 * here, it is done in ath9k_beacon_config_adhoc().684		 */685		if (beacons && !skip_beacon) {686			set_bit(ATH_OP_BEACONS, &common->op_flags);687			ath9k_set_beacon(sc);688		} else {689			clear_bit(ATH_OP_BEACONS, &common->op_flags);690			ath9k_beacon_stop(sc);691		}692	} else {693		clear_bit(ATH_OP_BEACONS, &common->op_flags);694		ath9k_beacon_stop(sc);695	}696}697 698void ath9k_set_beacon(struct ath_softc *sc)699{700	struct ath_common *common = ath9k_hw_common(sc->sc_ah);701	struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;702 703	switch (sc->sc_ah->opmode) {704	case NL80211_IFTYPE_AP:705	case NL80211_IFTYPE_MESH_POINT:706		ath9k_beacon_config_ap(sc, cur_conf);707		break;708	case NL80211_IFTYPE_ADHOC:709		ath9k_beacon_config_adhoc(sc, cur_conf);710		break;711	case NL80211_IFTYPE_STATION:712		ath9k_beacon_config_sta(sc->sc_ah, cur_conf);713		break;714	default:715		ath_dbg(common, CONFIG, "Unsupported beaconing mode\n");716		return;717	}718}719