Path: blob/main/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_beacon.c
48525 views
/*1* Copyright (c) 2013 Qualcomm Atheros, Inc.2*3* Permission to use, copy, modify, and/or distribute this software for any4* purpose with or without fee is hereby granted, provided that the above5* copyright notice and this permission notice appear in all copies.6*7* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH8* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY9* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,10* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM11* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR12* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR13* PERFORMANCE OF THIS SOFTWARE.14*/1516#include "opt_ah.h"1718#include "ah.h"19#include "ah_internal.h"2021#include "ar9300/ar9300.h"22#include "ar9300/ar9300reg.h"2324#define TU_TO_USEC(_tu) ((_tu) << 10)25#define ONE_EIGHTH_TU_TO_USEC(_tu8) ((_tu8) << 7)2627extern u_int32_t ar9300_num_tx_pending(struct ath_hal *ah, u_int q);2829/*30* Initializes all of the hardware registers used to31* send beacons. Note that for station operation the32* driver calls ar9300_set_sta_beacon_timers instead.33*/34void35ar9300_beacon_init(struct ath_hal *ah,36u_int32_t next_beacon, u_int32_t beacon_period,37u_int32_t beacon_period_fraction, HAL_OPMODE opmode)38{39u_int32_t beacon_period_usec;4041HALASSERT(opmode == HAL_M_IBSS || opmode == HAL_M_HOSTAP);42if (opmode == HAL_M_IBSS) {43OS_REG_SET_BIT(ah, AR_TXCFG, AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY);44}45OS_REG_WRITE(ah, AR_NEXT_TBTT_TIMER, ONE_EIGHTH_TU_TO_USEC(next_beacon));46OS_REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT,47(ONE_EIGHTH_TU_TO_USEC(next_beacon) -48ah->ah_config.ah_dma_beacon_response_time));49OS_REG_WRITE(ah, AR_NEXT_SWBA,50(ONE_EIGHTH_TU_TO_USEC(next_beacon) -51ah->ah_config.ah_sw_beacon_response_time));5253beacon_period_usec =54ONE_EIGHTH_TU_TO_USEC(beacon_period & HAL_BEACON_PERIOD_TU8);5556/* Add the fraction adjustment lost due to unit conversions. */57beacon_period_usec += beacon_period_fraction;5859HALDEBUG(ah, HAL_DEBUG_BEACON,60"%s: next_beacon=0x%08x, beacon_period=%d, opmode=%d, beacon_period_usec=%d\n",61__func__, next_beacon, beacon_period, opmode, beacon_period_usec);6263OS_REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period_usec);64OS_REG_WRITE(ah, AR_DMA_BEACON_PERIOD, beacon_period_usec);65OS_REG_WRITE(ah, AR_SWBA_PERIOD, beacon_period_usec);6667/* reset TSF if required */68if (beacon_period & HAL_BEACON_RESET_TSF) {69ar9300_reset_tsf(ah);70}7172/* enable timers */73OS_REG_SET_BIT(ah, AR_TIMER_MODE,74AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN);75}7677/*78* Set all the beacon related bits on the h/w for stations79* i.e. initializes the corresponding h/w timers;80*/81void82ar9300_set_sta_beacon_timers(struct ath_hal *ah, const HAL_BEACON_STATE *bs)83{84u_int32_t next_tbtt, beaconintval, dtimperiod, beacontimeout;85HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps;8687HALASSERT(bs->bs_intval != 0);8889/* no cfp setting since h/w automatically takes care */90OS_REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt));9192/*93* Start the beacon timers by setting the BEACON register94* to the beacon interval; no need to write tim offset since95* h/w parses IEs.96*/97OS_REG_WRITE(ah, AR_BEACON_PERIOD,98TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD));99OS_REG_WRITE(ah, AR_DMA_BEACON_PERIOD,100TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD));101/*102* Configure the BMISS interrupt. Note that we103* assume the caller blocks interrupts while enabling104* the threshold.105*/106HALASSERT(bs->bs_bmissthreshold <=107(AR_RSSI_THR_BM_THR >> AR_RSSI_THR_BM_THR_S));108OS_REG_RMW_FIELD(ah, AR_RSSI_THR,109AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold);110111/*112* Program the sleep registers to correlate with the beacon setup.113*/114115/*116* Current implementation assumes sw processing of beacons -117* assuming an interrupt is generated every beacon which118* causes the hardware to become awake until the sw tells119* it to go to sleep again; beacon timeout is to allow for120* beacon jitter; cab timeout is max time to wait for cab121* after seeing the last DTIM or MORE CAB bit122*/123#define CAB_TIMEOUT_VAL 10 /* in TU */124#define BEACON_TIMEOUT_VAL 10 /* in TU */125#define MIN_BEACON_TIMEOUT_VAL 1 /* in 1/8 TU */126#define SLEEP_SLOP 3 /* in TU */127128/*129* For max powersave mode we may want to sleep for longer than a130* beacon period and not want to receive all beacons; modify the131* timers accordingly; make sure to align the next TIM to the132* next DTIM if we decide to wake for DTIMs only133*/134beaconintval = bs->bs_intval & HAL_BEACON_PERIOD;135HALASSERT(beaconintval != 0);136if (bs->bs_sleepduration > beaconintval) {137HALASSERT(roundup(bs->bs_sleepduration, beaconintval) ==138bs->bs_sleepduration);139beaconintval = bs->bs_sleepduration;140}141dtimperiod = bs->bs_dtimperiod;142if (bs->bs_sleepduration > dtimperiod) {143HALASSERT(dtimperiod == 0 ||144roundup(bs->bs_sleepduration, dtimperiod) ==145bs->bs_sleepduration);146dtimperiod = bs->bs_sleepduration;147}148HALASSERT(beaconintval <= dtimperiod);149if (beaconintval == dtimperiod) {150next_tbtt = bs->bs_nextdtim;151} else {152next_tbtt = bs->bs_nexttbtt;153}154155HALDEBUG(ah, HAL_DEBUG_BEACON,156"%s: next DTIM %d\n", __func__, bs->bs_nextdtim);157HALDEBUG(ah, HAL_DEBUG_BEACON,158"%s: next beacon %d\n", __func__, next_tbtt);159HALDEBUG(ah, HAL_DEBUG_BEACON,160"%s: beacon period %d\n", __func__, beaconintval);161HALDEBUG(ah, HAL_DEBUG_BEACON,162"%s: DTIM period %d\n", __func__, dtimperiod);163164OS_REG_WRITE(ah, AR_NEXT_DTIM, TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP));165OS_REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(next_tbtt - SLEEP_SLOP));166167/* cab timeout is now in 1/8 TU */168OS_REG_WRITE(ah, AR_SLEEP1,169SM((CAB_TIMEOUT_VAL << 3), AR_SLEEP1_CAB_TIMEOUT)170| AR_SLEEP1_ASSUME_DTIM);171172/* beacon timeout is now in 1/8 TU */173if (p_cap->halAutoSleepSupport) {174beacontimeout = (BEACON_TIMEOUT_VAL << 3);175} else {176/*177* Use a very small value to make sure the timeout occurs before178* the TBTT. In this case the chip will not go back to sleep179* automatically, instead it will wait for the SW to explicitly180* set it to that mode.181*/182beacontimeout = MIN_BEACON_TIMEOUT_VAL;183}184185OS_REG_WRITE(ah, AR_SLEEP2,186SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT));187188OS_REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval));189OS_REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod));190191/* clear HOST AP related timers first */192OS_REG_CLR_BIT(ah, AR_TIMER_MODE, (AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN));193194OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN195| AR_DTIM_TIMER_EN);196197/* TSF out of range threshold */198OS_REG_WRITE(ah, AR_TSFOOR_THRESHOLD, bs->bs_tsfoor_threshold);199200#undef CAB_TIMEOUT_VAL201#undef BEACON_TIMEOUT_VAL202#undef SLEEP_SLOP203}204205206