Path: blob/main/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c
39566 views
/*-1* SPDX-License-Identifier: ISC2*3* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting4* Copyright (c) 2002-2008 Atheros Communications, Inc.5*6* Permission to use, copy, modify, and/or distribute this software for any7* purpose with or without fee is hereby granted, provided that the above8* copyright notice and this permission notice appear in all copies.9*10* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES11* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF12* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR13* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES14* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN15* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF16* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.17*/18#include "opt_ah.h"1920#include "ah.h"21#include "ah_internal.h"2223#include "ar5416/ar5416.h"24#include "ar5416/ar5416reg.h"25#include "ar5416/ar5416phy.h"2627#define TU_TO_USEC(_tu) ((_tu) << 10)28#define ONE_EIGHTH_TU_TO_USEC(_tu8) ((_tu8) << 7)2930/*31* Return the hardware NextTBTT in TSF32*/33uint64_t34ar5416GetNextTBTT(struct ath_hal *ah)35{36return OS_REG_READ(ah, AR_NEXT_TBTT);37}3839/*40* Initialize all of the hardware registers used to41* send beacons. Note that for station operation the42* driver calls ar5416SetStaBeaconTimers instead.43*/44void45ar5416SetBeaconTimers(struct ath_hal *ah, const HAL_BEACON_TIMERS *bt)46{47uint32_t bperiod;48struct ath_hal_5212 *ahp = AH5212(ah);4950OS_REG_WRITE(ah, AR_NEXT_TBTT, TU_TO_USEC(bt->bt_nexttbtt));51OS_REG_WRITE(ah, AR_NEXT_DBA, ONE_EIGHTH_TU_TO_USEC(bt->bt_nextdba));52OS_REG_WRITE(ah, AR_NEXT_SWBA, ONE_EIGHTH_TU_TO_USEC(bt->bt_nextswba));53OS_REG_WRITE(ah, AR_NEXT_NDP, TU_TO_USEC(bt->bt_nextatim));5455bperiod = TU_TO_USEC(bt->bt_intval & HAL_BEACON_PERIOD);56ahp->ah_beaconInterval = bt->bt_intval & HAL_BEACON_PERIOD;57OS_REG_WRITE(ah, AR5416_BEACON_PERIOD, bperiod);58OS_REG_WRITE(ah, AR_DBA_PERIOD, bperiod);59OS_REG_WRITE(ah, AR_SWBA_PERIOD, bperiod);60OS_REG_WRITE(ah, AR_NDP_PERIOD, bperiod);6162/*63* Reset TSF if required.64*/65if (bt->bt_intval & AR_BEACON_RESET_TSF)66ar5416ResetTsf(ah);6768/* enable timers */69/* NB: flags == 0 handled specially for backwards compatibility */70OS_REG_SET_BIT(ah, AR_TIMER_MODE,71bt->bt_flags != 0 ? bt->bt_flags :72AR_TIMER_MODE_TBTT | AR_TIMER_MODE_DBA | AR_TIMER_MODE_SWBA);73}7475/*76* Initializes all of the hardware registers used to77* send beacons. Note that for station operation the78* driver calls ar5212SetStaBeaconTimers instead.79*/80void81ar5416BeaconInit(struct ath_hal *ah,82uint32_t next_beacon, uint32_t beacon_period)83{84HAL_BEACON_TIMERS bt;8586bt.bt_nexttbtt = next_beacon;87/*88* TIMER1: in AP/adhoc mode this controls the DMA beacon89* alert timer; otherwise it controls the next wakeup time.90* TIMER2: in AP mode, it controls the SBA beacon alert91* interrupt; otherwise it sets the start of the next CFP.92*/93bt.bt_flags = 0;94switch (AH_PRIVATE(ah)->ah_opmode) {95case HAL_M_STA:96case HAL_M_MONITOR:97bt.bt_nextdba = 0xffff;98bt.bt_nextswba = 0x7ffff;99bt.bt_flags |= AR_TIMER_MODE_TBTT;100break;101case HAL_M_IBSS:102OS_REG_SET_BIT(ah, AR_TXCFG, AR_TXCFG_ATIM_TXPOLICY);103bt.bt_flags |= AR_TIMER_MODE_NDP;104/* fall thru... */105case HAL_M_HOSTAP:106bt.bt_nextdba = (next_beacon -107ah->ah_config.ah_dma_beacon_response_time) << 3; /* 1/8 TU */108bt.bt_nextswba = (next_beacon -109ah->ah_config.ah_sw_beacon_response_time) << 3; /* 1/8 TU */110bt.bt_flags |= AR_TIMER_MODE_TBTT111| AR_TIMER_MODE_DBA112| AR_TIMER_MODE_SWBA;113break;114}115/*116* Set the ATIM window117* Our hardware does not support an ATIM window of 0118* (beacons will not work). If the ATIM windows is 0,119* force it to 1.120*/121bt.bt_nextatim = next_beacon + 1;122bt.bt_intval = beacon_period &123(AR_BEACON_PERIOD | AR_BEACON_RESET_TSF | AR_BEACON_EN);124ar5416SetBeaconTimers(ah, &bt);125}126127#define AR_BEACON_PERIOD_MAX 0xffff128129void130ar5416ResetStaBeaconTimers(struct ath_hal *ah)131{132uint32_t val;133134OS_REG_WRITE(ah, AR_NEXT_TBTT, 0); /* no beacons */135val = OS_REG_READ(ah, AR_STA_ID1);136val |= AR_STA_ID1_PWR_SAV; /* XXX */137/* tell the h/w that the associated AP is not PCF capable */138OS_REG_WRITE(ah, AR_STA_ID1,139val & ~(AR_STA_ID1_USE_DEFANT | AR_STA_ID1_PCF));140OS_REG_WRITE(ah, AR5416_BEACON_PERIOD, AR_BEACON_PERIOD_MAX);141OS_REG_WRITE(ah, AR_DBA_PERIOD, AR_BEACON_PERIOD_MAX);142}143144/*145* Set all the beacon related bits on the h/w for stations146* i.e. initializes the corresponding h/w timers;147* also tells the h/w whether to anticipate PCF beacons148*/149void150ar5416SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs)151{152uint32_t nextTbtt, nextdtim,beaconintval, dtimperiod;153154HALASSERT(bs->bs_intval != 0);155156/* NB: no cfp setting since h/w automatically takes care */157158OS_REG_WRITE(ah, AR_NEXT_TBTT, TU_TO_USEC(bs->bs_nexttbtt));159160/*161* Start the beacon timers by setting the BEACON register162* to the beacon interval; no need to write tim offset since163* h/w parses IEs.164*/165OS_REG_WRITE(ah, AR5416_BEACON_PERIOD,166TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD));167OS_REG_WRITE(ah, AR_DBA_PERIOD,168TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD));169170/*171* Configure the BMISS interrupt. Note that we172* assume the caller blocks interrupts while enabling173* the threshold.174*/175HALASSERT(bs->bs_bmissthreshold <=176(AR_RSSI_THR_BM_THR >> AR_RSSI_THR_BM_THR_S));177OS_REG_RMW_FIELD(ah, AR_RSSI_THR,178AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold);179180/*181* Program the sleep registers to correlate with the beacon setup.182*/183184/*185* Oahu beacons timers on the station were used for power186* save operation (waking up in anticipation of a beacon)187* and any CFP function; Venice does sleep/power-save timers188* differently - so this is the right place to set them up;189* don't think the beacon timers are used by venice sta hw190* for any useful purpose anymore191* Setup venice's sleep related timers192* Current implementation assumes sw processing of beacons -193* assuming an interrupt is generated every beacon which194* causes the hardware to become awake until the sw tells195* it to go to sleep again; beacon timeout is to allow for196* beacon jitter; cab timeout is max time to wait for cab197* after seeing the last DTIM or MORE CAB bit198*/199200/*201* I've bumped these to 30TU for now.202*203* Some APs (AR933x/AR934x?) in 2GHz especially seem to not always204* transmit beacon frames at exactly the right times and with it set205* to 10TU, the NIC starts not waking up at the right times to hear206* these slightly-larger-jitering beacons. It also never recovers207* from that (it doesn't resync? I'm not sure.)208*209* So for now bump this to 30TU. Ideally we'd cap this based on210* the beacon interval so the sum of CAB+BEACON timeouts never211* exceeded the beacon interval.212*213* Now, since we're doing all the math in the ath(4) driver in TU214* rather than TSF, we may be seeing the result of dumb rounding215* errors causing the jitter to actually be a much bigger problem.216* I'll have to investigate that with a fine tooth comb.217*/218#define CAB_TIMEOUT_VAL 10 /* in TU */219#define BEACON_TIMEOUT_VAL 10 /* in TU */220#define SLEEP_SLOP 3 /* in TU */221222/*223* For max powersave mode we may want to sleep for longer than a224* beacon period and not want to receive all beacons; modify the225* timers accordingly; make sure to align the next TIM to the226* next DTIM if we decide to wake for DTIMs only227*/228beaconintval = bs->bs_intval & HAL_BEACON_PERIOD;229HALASSERT(beaconintval != 0);230if (bs->bs_sleepduration > beaconintval) {231HALASSERT(roundup(bs->bs_sleepduration, beaconintval) ==232bs->bs_sleepduration);233beaconintval = bs->bs_sleepduration;234}235dtimperiod = bs->bs_dtimperiod;236if (bs->bs_sleepduration > dtimperiod) {237HALASSERT(dtimperiod == 0 ||238roundup(bs->bs_sleepduration, dtimperiod) ==239bs->bs_sleepduration);240dtimperiod = bs->bs_sleepduration;241}242HALASSERT(beaconintval <= dtimperiod);243if (beaconintval == dtimperiod)244nextTbtt = bs->bs_nextdtim;245else246nextTbtt = bs->bs_nexttbtt;247nextdtim = bs->bs_nextdtim;248249OS_REG_WRITE(ah, AR_NEXT_DTIM,250TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP));251OS_REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP));252253/* cab timeout is now in 1/8 TU */254OS_REG_WRITE(ah, AR5416_SLEEP1,255SM((CAB_TIMEOUT_VAL << 3), AR5416_SLEEP1_CAB_TIMEOUT)256| AR5416_SLEEP1_ASSUME_DTIM);257258/* XXX autosleep? Use min beacon timeout; check ath9k -adrian */259/* beacon timeout is now in 1/8 TU */260OS_REG_WRITE(ah, AR5416_SLEEP2,261SM((BEACON_TIMEOUT_VAL << 3), AR5416_SLEEP2_BEACON_TIMEOUT));262263/* TIM_PERIOD and DTIM_PERIOD are now in uS. */264OS_REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval));265OS_REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod));266267OS_REG_SET_BIT(ah, AR_TIMER_MODE,268AR_TIMER_MODE_TBTT | AR_TIMER_MODE_TIM | AR_TIMER_MODE_DTIM);269270#define HAL_TSFOOR_THRESHOLD 0x00004240 /* TSF OOR threshold (16k us) */271272/* TSF out of range threshold */273// OS_REG_WRITE(ah, AR_TSFOOR_THRESHOLD, bs->bs_tsfoor_threshold);274OS_REG_WRITE(ah, AR_TSFOOR_THRESHOLD, HAL_TSFOOR_THRESHOLD);275276HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: next DTIM %d\n",277__func__, bs->bs_nextdtim);278HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: next beacon %d\n",279__func__, nextTbtt);280HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: beacon period %d\n",281__func__, beaconintval);282HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: DTIM period %d\n",283__func__, dtimperiod);284#undef CAB_TIMEOUT_VAL285#undef BEACON_TIMEOUT_VAL286#undef SLEEP_SLOP287}288289290