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