xref: /freebsd/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
1*6e778a7eSPedro F. Giffuni /*-
2*6e778a7eSPedro F. Giffuni  * SPDX-License-Identifier: ISC
3*6e778a7eSPedro F. Giffuni  *
414779705SSam Leffler  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
514779705SSam Leffler  * Copyright (c) 2002-2006 Atheros Communications, Inc.
614779705SSam Leffler  *
714779705SSam Leffler  * Permission to use, copy, modify, and/or distribute this software for any
814779705SSam Leffler  * purpose with or without fee is hereby granted, provided that the above
914779705SSam Leffler  * copyright notice and this permission notice appear in all copies.
1014779705SSam Leffler  *
1114779705SSam Leffler  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1214779705SSam Leffler  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1314779705SSam Leffler  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1414779705SSam Leffler  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1514779705SSam Leffler  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1614779705SSam Leffler  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1714779705SSam Leffler  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1814779705SSam Leffler  */
1914779705SSam Leffler #include "opt_ah.h"
2014779705SSam Leffler 
2114779705SSam Leffler #include "ah.h"
2214779705SSam Leffler #include "ah_internal.h"
2314779705SSam Leffler 
2414779705SSam Leffler #include "ar5211/ar5211.h"
2514779705SSam Leffler #include "ar5211/ar5211reg.h"
2614779705SSam Leffler #include "ar5211/ar5211desc.h"
2714779705SSam Leffler 
2814779705SSam Leffler /*
2914779705SSam Leffler  * Routines used to initialize and generated beacons for the AR5211/AR5311.
3014779705SSam Leffler  */
3114779705SSam Leffler 
3214779705SSam Leffler /*
33fc4de9b7SAdrian Chadd  * Return the hardware NextTBTT in TSF
34fc4de9b7SAdrian Chadd  */
35fc4de9b7SAdrian Chadd uint64_t
ar5211GetNextTBTT(struct ath_hal * ah)36fc4de9b7SAdrian Chadd ar5211GetNextTBTT(struct ath_hal *ah)
37fc4de9b7SAdrian Chadd {
38fc4de9b7SAdrian Chadd #define TU_TO_TSF(_tu)	(((uint64_t)(_tu)) << 10)
39fc4de9b7SAdrian Chadd 	return TU_TO_TSF(OS_REG_READ(ah, AR_TIMER0));
40fc4de9b7SAdrian Chadd #undef TU_TO_TSF
41fc4de9b7SAdrian Chadd }
42fc4de9b7SAdrian Chadd 
43fc4de9b7SAdrian Chadd /*
4414779705SSam Leffler  * Initialize all of the hardware registers used to send beacons.
4514779705SSam Leffler  */
4614779705SSam Leffler void
ar5211SetBeaconTimers(struct ath_hal * ah,const HAL_BEACON_TIMERS * bt)4714779705SSam Leffler ar5211SetBeaconTimers(struct ath_hal *ah, const HAL_BEACON_TIMERS *bt)
4814779705SSam Leffler {
4914779705SSam Leffler 
5014779705SSam Leffler 	OS_REG_WRITE(ah, AR_TIMER0, bt->bt_nexttbtt);
5114779705SSam Leffler 	OS_REG_WRITE(ah, AR_TIMER1, bt->bt_nextdba);
5214779705SSam Leffler 	OS_REG_WRITE(ah, AR_TIMER2, bt->bt_nextswba);
5314779705SSam Leffler 	OS_REG_WRITE(ah, AR_TIMER3, bt->bt_nextatim);
5414779705SSam Leffler 	/*
5514779705SSam Leffler 	 * Set the Beacon register after setting all timers.
5614779705SSam Leffler 	 */
5714779705SSam Leffler 	OS_REG_WRITE(ah, AR_BEACON, bt->bt_intval);
5814779705SSam Leffler }
5914779705SSam Leffler 
6014779705SSam Leffler /*
6114779705SSam Leffler  * Legacy api to initialize all of the beacon registers.
6214779705SSam Leffler  */
6314779705SSam Leffler void
ar5211BeaconInit(struct ath_hal * ah,uint32_t next_beacon,uint32_t beacon_period)6414779705SSam Leffler ar5211BeaconInit(struct ath_hal *ah,
6514779705SSam Leffler 	uint32_t next_beacon, uint32_t beacon_period)
6614779705SSam Leffler {
6714779705SSam Leffler 	HAL_BEACON_TIMERS bt;
6814779705SSam Leffler 
6914779705SSam Leffler 	bt.bt_nexttbtt = next_beacon;
7014779705SSam Leffler 	/*
7114779705SSam Leffler 	 * TIMER1: in AP/adhoc mode this controls the DMA beacon
7214779705SSam Leffler 	 * alert timer; otherwise it controls the next wakeup time.
7314779705SSam Leffler 	 * TIMER2: in AP mode, it controls the SBA beacon alert
7414779705SSam Leffler 	 * interrupt; otherwise it sets the start of the next CFP.
7514779705SSam Leffler 	 */
7614779705SSam Leffler 	switch (AH_PRIVATE(ah)->ah_opmode) {
7714779705SSam Leffler 	case HAL_M_STA:
7814779705SSam Leffler 	case HAL_M_MONITOR:
7914779705SSam Leffler 		bt.bt_nextdba = 0xffff;
8014779705SSam Leffler 		bt.bt_nextswba = 0x7ffff;
8114779705SSam Leffler 		break;
8214779705SSam Leffler 	case HAL_M_IBSS:
8314779705SSam Leffler 	case HAL_M_HOSTAP:
8414779705SSam Leffler 		bt.bt_nextdba = (next_beacon -
8537931a35SAdrian Chadd 			ah->ah_config.ah_dma_beacon_response_time) << 3;	/* 1/8 TU */
8614779705SSam Leffler 		bt.bt_nextswba = (next_beacon -
8737931a35SAdrian Chadd             ah->ah_config.ah_sw_beacon_response_time) << 3;	/* 1/8 TU */
8814779705SSam Leffler 		break;
8914779705SSam Leffler 	}
9014779705SSam Leffler 	/*
9114779705SSam Leffler 	 * Set the ATIM window
9214779705SSam Leffler 	 * Our hardware does not support an ATIM window of 0
9314779705SSam Leffler 	 * (beacons will not work).  If the ATIM windows is 0,
9414779705SSam Leffler 	 * force it to 1.
9514779705SSam Leffler 	 */
9614779705SSam Leffler 	bt.bt_nextatim = next_beacon + 1;
9714779705SSam Leffler 	bt.bt_intval = beacon_period &
9814779705SSam Leffler 		(AR_BEACON_PERIOD | AR_BEACON_RESET_TSF | AR_BEACON_EN);
9914779705SSam Leffler 	ar5211SetBeaconTimers(ah, &bt);
10014779705SSam Leffler }
10114779705SSam Leffler 
10214779705SSam Leffler void
ar5211ResetStaBeaconTimers(struct ath_hal * ah)10314779705SSam Leffler ar5211ResetStaBeaconTimers(struct ath_hal *ah)
10414779705SSam Leffler {
10514779705SSam Leffler 	uint32_t val;
10614779705SSam Leffler 
10714779705SSam Leffler 	OS_REG_WRITE(ah, AR_TIMER0, 0);		/* no beacons */
10814779705SSam Leffler 	val = OS_REG_READ(ah, AR_STA_ID1);
10914779705SSam Leffler 	val |= AR_STA_ID1_PWR_SAV;		/* XXX */
11014779705SSam Leffler 	/* tell the h/w that the associated AP is not PCF capable */
11114779705SSam Leffler 	OS_REG_WRITE(ah, AR_STA_ID1,
11214779705SSam Leffler 		val & ~(AR_STA_ID1_DEFAULT_ANTENNA | AR_STA_ID1_PCF));
11314779705SSam Leffler 	OS_REG_WRITE(ah, AR_BEACON, AR_BEACON_PERIOD);
11414779705SSam Leffler }
11514779705SSam Leffler 
11614779705SSam Leffler /*
11714779705SSam Leffler  * Set all the beacon related bits on the h/w for stations
11814779705SSam Leffler  * i.e. initializes the corresponding h/w timers;
11914779705SSam Leffler  * also tells the h/w whether to anticipate PCF beacons
12014779705SSam Leffler  */
12114779705SSam Leffler void
ar5211SetStaBeaconTimers(struct ath_hal * ah,const HAL_BEACON_STATE * bs)12214779705SSam Leffler ar5211SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs)
12314779705SSam Leffler {
12414779705SSam Leffler 	struct ath_hal_5211 *ahp = AH5211(ah);
12514779705SSam Leffler 
12614779705SSam Leffler 	HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: setting beacon timers\n", __func__);
12714779705SSam Leffler 
12814779705SSam Leffler 	HALASSERT(bs->bs_intval != 0);
12914779705SSam Leffler 	/* if the AP will do PCF */
13014779705SSam Leffler 	if (bs->bs_cfpmaxduration != 0) {
13114779705SSam Leffler 		/* tell the h/w that the associated AP is PCF capable */
13214779705SSam Leffler 		OS_REG_WRITE(ah, AR_STA_ID1,
13314779705SSam Leffler 			OS_REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PCF);
13414779705SSam Leffler 
13514779705SSam Leffler 		/* set CFP_PERIOD(1.024ms) register */
13614779705SSam Leffler 		OS_REG_WRITE(ah, AR_CFP_PERIOD, bs->bs_cfpperiod);
13714779705SSam Leffler 
13814779705SSam Leffler 		/* set CFP_DUR(1.024ms) register to max cfp duration */
13914779705SSam Leffler 		OS_REG_WRITE(ah, AR_CFP_DUR, bs->bs_cfpmaxduration);
14014779705SSam Leffler 
14114779705SSam Leffler 		/* set TIMER2(128us) to anticipated time of next CFP */
14214779705SSam Leffler 		OS_REG_WRITE(ah, AR_TIMER2, bs->bs_cfpnext << 3);
14314779705SSam Leffler 	} else {
14414779705SSam Leffler 		/* tell the h/w that the associated AP is not PCF capable */
14514779705SSam Leffler 		OS_REG_WRITE(ah, AR_STA_ID1,
14614779705SSam Leffler 			OS_REG_READ(ah, AR_STA_ID1) &~ AR_STA_ID1_PCF);
14714779705SSam Leffler 	}
14814779705SSam Leffler 
14914779705SSam Leffler 	/*
15014779705SSam Leffler 	 * Set TIMER0(1.024ms) to the anticipated time of the next beacon.
15114779705SSam Leffler 	 */
15214779705SSam Leffler 	OS_REG_WRITE(ah, AR_TIMER0, bs->bs_nexttbtt);
15314779705SSam Leffler 
15414779705SSam Leffler 	/*
15514779705SSam Leffler 	 * Start the beacon timers by setting the BEACON register
15614779705SSam Leffler 	 * to the beacon interval; also write the tim offset which
15714779705SSam Leffler 	 * we should know by now.  The code, in ar5211WriteAssocid,
15814779705SSam Leffler 	 * also sets the tim offset once the AID is known which can
15914779705SSam Leffler 	 * be left as such for now.
16014779705SSam Leffler 	 */
16114779705SSam Leffler 	OS_REG_WRITE(ah, AR_BEACON,
16214779705SSam Leffler 		(OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_PERIOD|AR_BEACON_TIM))
16314779705SSam Leffler 		| SM(bs->bs_intval, AR_BEACON_PERIOD)
16414779705SSam Leffler 		| SM(bs->bs_timoffset ? bs->bs_timoffset + 4 : 0, AR_BEACON_TIM)
16514779705SSam Leffler 	);
16614779705SSam Leffler 
16714779705SSam Leffler 	/*
16814779705SSam Leffler 	 * Configure the BMISS interrupt.  Note that we
16914779705SSam Leffler 	 * assume the caller blocks interrupts while enabling
17014779705SSam Leffler 	 * the threshold.
17114779705SSam Leffler 	 */
17214779705SSam Leffler 	HALASSERT(bs->bs_bmissthreshold <= MS(0xffffffff, AR_RSSI_THR_BM_THR));
17314779705SSam Leffler 	ahp->ah_rssiThr = (ahp->ah_rssiThr &~ AR_RSSI_THR_BM_THR)
17414779705SSam Leffler 			| SM(bs->bs_bmissthreshold, AR_RSSI_THR_BM_THR);
17514779705SSam Leffler 	OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr);
17614779705SSam Leffler 
17714779705SSam Leffler 	/*
17814779705SSam Leffler 	 * Set the sleep duration in 1/8 TU's.
17914779705SSam Leffler 	 */
18014779705SSam Leffler #define	SLEEP_SLOP	3
18114779705SSam Leffler 	OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLDUR,
18214779705SSam Leffler 		(bs->bs_sleepduration - SLEEP_SLOP) << 3);
18314779705SSam Leffler #undef SLEEP_SLOP
18414779705SSam Leffler }
185