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-2004 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 #include "ah_desc.h"
2414779705SSam Leffler
2514779705SSam Leffler #include "ar5210/ar5210.h"
2614779705SSam Leffler #include "ar5210/ar5210reg.h"
2714779705SSam Leffler #include "ar5210/ar5210desc.h"
2814779705SSam Leffler
2914779705SSam Leffler /*
30fc4de9b7SAdrian Chadd * Return the hardware NextTBTT in TSF
31fc4de9b7SAdrian Chadd */
32fc4de9b7SAdrian Chadd uint64_t
ar5210GetNextTBTT(struct ath_hal * ah)33fc4de9b7SAdrian Chadd ar5210GetNextTBTT(struct ath_hal *ah)
34fc4de9b7SAdrian Chadd {
35fc4de9b7SAdrian Chadd #define TU_TO_TSF(_tu) (((uint64_t)(_tu)) << 10)
36fc4de9b7SAdrian Chadd return TU_TO_TSF(OS_REG_READ(ah, AR_TIMER0));
37fc4de9b7SAdrian Chadd #undef TU_TO_TSF
38fc4de9b7SAdrian Chadd }
39fc4de9b7SAdrian Chadd
40fc4de9b7SAdrian Chadd /*
4114779705SSam Leffler * Initialize all of the hardware registers used to send beacons.
4214779705SSam Leffler */
4314779705SSam Leffler void
ar5210SetBeaconTimers(struct ath_hal * ah,const HAL_BEACON_TIMERS * bt)4414779705SSam Leffler ar5210SetBeaconTimers(struct ath_hal *ah, const HAL_BEACON_TIMERS *bt)
4514779705SSam Leffler {
4614779705SSam Leffler
4714779705SSam Leffler OS_REG_WRITE(ah, AR_TIMER0, bt->bt_nexttbtt);
4814779705SSam Leffler OS_REG_WRITE(ah, AR_TIMER1, bt->bt_nextdba);
4914779705SSam Leffler OS_REG_WRITE(ah, AR_TIMER2, bt->bt_nextswba);
5014779705SSam Leffler OS_REG_WRITE(ah, AR_TIMER3, bt->bt_nextatim);
5114779705SSam Leffler /*
5214779705SSam Leffler * Set the Beacon register after setting all timers.
5314779705SSam Leffler */
5414779705SSam Leffler OS_REG_WRITE(ah, AR_BEACON, bt->bt_intval);
5514779705SSam Leffler }
5614779705SSam Leffler
5714779705SSam Leffler /*
5814779705SSam Leffler * Legacy api to Initialize all of the beacon registers.
5914779705SSam Leffler */
6014779705SSam Leffler void
ar5210BeaconInit(struct ath_hal * ah,uint32_t next_beacon,uint32_t beacon_period)6114779705SSam Leffler ar5210BeaconInit(struct ath_hal *ah,
6214779705SSam Leffler uint32_t next_beacon, uint32_t beacon_period)
6314779705SSam Leffler {
6414779705SSam Leffler HAL_BEACON_TIMERS bt;
6514779705SSam Leffler
6614779705SSam Leffler bt.bt_nexttbtt = next_beacon;
6714779705SSam Leffler
6814779705SSam Leffler if (AH_PRIVATE(ah)->ah_opmode != HAL_M_STA) {
6914779705SSam Leffler bt.bt_nextdba = (next_beacon -
7037931a35SAdrian Chadd ah->ah_config.ah_dma_beacon_response_time) << 3; /* 1/8 TU */
7114779705SSam Leffler bt.bt_nextswba = (next_beacon -
7237931a35SAdrian Chadd ah->ah_config.ah_sw_beacon_response_time) << 3; /* 1/8 TU */
7314779705SSam Leffler /*
7414779705SSam Leffler * The SWBA interrupt is not used for beacons in ad hoc mode
7514779705SSam Leffler * as we don't yet support ATIMs. So since the beacon never
7614779705SSam Leffler * changes, the beacon descriptor is set up once and read
7714779705SSam Leffler * into a special HW buffer, from which it will be
7814779705SSam Leffler * automagically retrieved at each DMA Beacon Alert (DBA).
7914779705SSam Leffler */
8014779705SSam Leffler
8114779705SSam Leffler /* Set the ATIM window */
8214779705SSam Leffler bt.bt_nextatim = next_beacon + 0; /* NB: no ATIMs */
8314779705SSam Leffler } else {
8414779705SSam Leffler bt.bt_nextdba = ~0;
8514779705SSam Leffler bt.bt_nextswba = ~0;
8614779705SSam Leffler bt.bt_nextatim = 1;
8714779705SSam Leffler }
8814779705SSam Leffler bt.bt_intval = beacon_period &
8914779705SSam Leffler (AR_BEACON_PERIOD | AR_BEACON_RESET_TSF | AR_BEACON_EN);
9014779705SSam Leffler ar5210SetBeaconTimers(ah, &bt);
9114779705SSam Leffler }
9214779705SSam Leffler
9314779705SSam Leffler void
ar5210ResetStaBeaconTimers(struct ath_hal * ah)9414779705SSam Leffler ar5210ResetStaBeaconTimers(struct ath_hal *ah)
9514779705SSam Leffler {
9614779705SSam Leffler uint32_t val;
9714779705SSam Leffler
9814779705SSam Leffler OS_REG_WRITE(ah, AR_TIMER0, 0); /* no beacons */
9914779705SSam Leffler val = OS_REG_READ(ah, AR_STA_ID1);
10014779705SSam Leffler val |= AR_STA_ID1_NO_PSPOLL; /* XXX */
10114779705SSam Leffler /* tell the h/w that the associated AP is not PCF capable */
10214779705SSam Leffler OS_REG_WRITE(ah, AR_STA_ID1,
10314779705SSam Leffler val & ~(AR_STA_ID1_DEFAULT_ANTENNA | AR_STA_ID1_PCF));
10414779705SSam Leffler OS_REG_WRITE(ah, AR_BEACON, AR_BEACON_PERIOD);
10514779705SSam Leffler }
10614779705SSam Leffler
10714779705SSam Leffler /*
10814779705SSam Leffler * Set all the beacon related bits on the h/w for stations
10914779705SSam Leffler * i.e. initializes the corresponding h/w timers;
11014779705SSam Leffler * also tells the h/w whether to anticipate PCF beacons
11114779705SSam Leffler *
11214779705SSam Leffler * dtim_count and cfp_count from the current beacon - their current
11314779705SSam Leffler * values aren't necessarily maintained in the device struct
11414779705SSam Leffler */
11514779705SSam Leffler void
ar5210SetStaBeaconTimers(struct ath_hal * ah,const HAL_BEACON_STATE * bs)11614779705SSam Leffler ar5210SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs)
11714779705SSam Leffler {
11814779705SSam Leffler struct ath_hal_5210 *ahp = AH5210(ah);
11914779705SSam Leffler
12014779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: setting beacon timers\n", __func__);
12114779705SSam Leffler
12214779705SSam Leffler HALASSERT(bs->bs_intval != 0);
12314779705SSam Leffler /* if the AP will do PCF */
12414779705SSam Leffler if (bs->bs_cfpmaxduration != 0) {
12514779705SSam Leffler /* tell the h/w that the associated AP is PCF capable */
12614779705SSam Leffler OS_REG_WRITE(ah, AR_STA_ID1,
12714779705SSam Leffler (OS_REG_READ(ah, AR_STA_ID1) &~ AR_STA_ID1_DEFAULT_ANTENNA)
12814779705SSam Leffler | AR_STA_ID1_PCF);
12914779705SSam Leffler
13014779705SSam Leffler /* set CFP_PERIOD(1.024ms) register */
13114779705SSam Leffler OS_REG_WRITE(ah, AR_CFP_PERIOD, bs->bs_cfpperiod);
13214779705SSam Leffler
13314779705SSam Leffler /* set CFP_DUR(1.024ms) register to max cfp duration */
13414779705SSam Leffler OS_REG_WRITE(ah, AR_CFP_DUR, bs->bs_cfpmaxduration);
13514779705SSam Leffler
13614779705SSam Leffler /* set TIMER2(128us) to anticipated time of next CFP */
13714779705SSam Leffler OS_REG_WRITE(ah, AR_TIMER2, bs->bs_cfpnext << 3);
13814779705SSam Leffler } else {
13914779705SSam Leffler /* tell the h/w that the associated AP is not PCF capable */
14014779705SSam Leffler OS_REG_WRITE(ah, AR_STA_ID1,
14114779705SSam Leffler OS_REG_READ(ah, AR_STA_ID1) &~ (AR_STA_ID1_DEFAULT_ANTENNA | AR_STA_ID1_PCF));
14214779705SSam Leffler }
14314779705SSam Leffler
14414779705SSam Leffler /*
14514779705SSam Leffler * Set TIMER0(1.024ms) to the anticipated time of the next beacon.
14614779705SSam Leffler */
14714779705SSam Leffler OS_REG_WRITE(ah, AR_TIMER0, bs->bs_nexttbtt);
14814779705SSam Leffler
14914779705SSam Leffler /*
15014779705SSam Leffler * Start the beacon timers by setting the BEACON register
15114779705SSam Leffler * to the beacon interval; also write the tim offset which
15214779705SSam Leffler * we should know by now. The code, in ar5211WriteAssocid,
15314779705SSam Leffler * also sets the tim offset once the AID is known which can
15414779705SSam Leffler * be left as such for now.
15514779705SSam Leffler */
15614779705SSam Leffler OS_REG_WRITE(ah, AR_BEACON,
15714779705SSam Leffler (OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_PERIOD|AR_BEACON_TIM))
15814779705SSam Leffler | SM(bs->bs_intval, AR_BEACON_PERIOD)
15914779705SSam Leffler | SM(bs->bs_timoffset ? bs->bs_timoffset + 4 : 0, AR_BEACON_TIM)
16014779705SSam Leffler );
16114779705SSam Leffler
16214779705SSam Leffler /*
16314779705SSam Leffler * Configure the BMISS interrupt. Note that we
16414779705SSam Leffler * assume the caller blocks interrupts while enabling
16514779705SSam Leffler * the threshold.
16614779705SSam Leffler */
16714779705SSam Leffler
16814779705SSam Leffler /*
16914779705SSam Leffler * Interrupt works only on Crete.
17014779705SSam Leffler */
17114779705SSam Leffler if (AH_PRIVATE(ah)->ah_macRev < AR_SREV_CRETE)
17214779705SSam Leffler return;
17314779705SSam Leffler /*
17414779705SSam Leffler * Counter is only 3-bits.
17514779705SSam Leffler * Count of 0 with BMISS interrupt enabled will hang the system
17614779705SSam Leffler * with too many interrupts
17714779705SSam Leffler */
17814779705SSam Leffler if (AH_PRIVATE(ah)->ah_macRev >= AR_SREV_CRETE &&
17914779705SSam Leffler (bs->bs_bmissthreshold&7) == 0) {
18014779705SSam Leffler #ifdef AH_DEBUG
18114779705SSam Leffler ath_hal_printf(ah, "%s: invalid beacon miss threshold %u\n",
18214779705SSam Leffler __func__, bs->bs_bmissthreshold);
18314779705SSam Leffler #endif
18414779705SSam Leffler return;
18514779705SSam Leffler }
18614779705SSam Leffler #define BMISS_MAX (AR_RSSI_THR_BM_THR >> AR_RSSI_THR_BM_THR_S)
18714779705SSam Leffler /*
18814779705SSam Leffler * Configure the BMISS interrupt. Note that we
18914779705SSam Leffler * assume the caller blocks interrupts while enabling
19014779705SSam Leffler * the threshold.
19114779705SSam Leffler *
19214779705SSam Leffler * NB: the beacon miss count field is only 3 bits which
19314779705SSam Leffler * is much smaller than what's found on later parts;
19414779705SSam Leffler * clamp overflow values as a safeguard.
19514779705SSam Leffler */
19614779705SSam Leffler ahp->ah_rssiThr = (ahp->ah_rssiThr &~ AR_RSSI_THR_BM_THR)
19714779705SSam Leffler | SM(bs->bs_bmissthreshold > BMISS_MAX ?
19814779705SSam Leffler BMISS_MAX : bs->bs_bmissthreshold,
19914779705SSam Leffler AR_RSSI_THR_BM_THR);
20014779705SSam Leffler OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr);
20114779705SSam Leffler #undef BMISS_MAX
20214779705SSam Leffler }
203