ar9300_beacon.c revision 250007
1193326Sed/* 2193326Sed * Copyright (c) 2013 Qualcomm Atheros, Inc. 3193326Sed * 4193326Sed * Permission to use, copy, modify, and/or distribute this software for any 5193326Sed * purpose with or without fee is hereby granted, provided that the above 6193326Sed * copyright notice and this permission notice appear in all copies. 7193326Sed * 8193326Sed * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9243830Sdim * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10243830Sdim * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11243830Sdim * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12243830Sdim * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 13193326Sed * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14193326Sed * PERFORMANCE OF THIS SOFTWARE. 15193326Sed */ 16193326Sed 17193326Sed#include "opt_ah.h" 18249423Sdim 19249423Sdim#ifdef AH_SUPPORT_AR9300 20249423Sdim 21249423Sdim#include "ah.h" 22276479Sdim#include "ah_internal.h" 23249423Sdim 24249423Sdim#include "ar9300/ar9300.h" 25249423Sdim#include "ar9300/ar9300reg.h" 26249423Sdim 27249423Sdim#define TU_TO_USEC(_tu) ((_tu) << 10) 28221345Sdim 29193326Sedextern u_int32_t ar9300_num_tx_pending(struct ath_hal *ah, u_int q); 30193326Sed 31296417Sdim/* 32198893Srdivacky * Initializes all of the hardware registers used to 33206084Srdivacky * send beacons. Note that for station operation the 34280031Sdim * driver calls ar9300_set_sta_beacon_timers instead. 35221345Sdim */ 36193326Sedvoid 37193326Sedar9300_beacon_init(struct ath_hal *ah, 38221345Sdim u_int32_t next_beacon, u_int32_t beacon_period, HAL_OPMODE opmode) 39203955Srdivacky{ 40234353Sdim struct ath_hal_private *ap = AH_PRIVATE(ah); 41193326Sed u_int32_t beacon_period_usec; 42276479Sdim 43193326Sed HALASSERT(opmode == HAL_M_IBSS || opmode == HAL_M_HOSTAP); 44193326Sed if (opmode == HAL_M_IBSS) { 45193326Sed OS_REG_SET_BIT(ah, AR_TXCFG, AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); 46193326Sed } 47193326Sed OS_REG_WRITE(ah, AR_NEXT_TBTT_TIMER, ONE_EIGHTH_TU_TO_USEC(next_beacon)); 48193326Sed OS_REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, 49193326Sed (ONE_EIGHTH_TU_TO_USEC(next_beacon) - 50193326Sed ap->ah_config.ath_hal_dma_beacon_response_time)); 51261991Sdim OS_REG_WRITE(ah, AR_NEXT_SWBA, 52193326Sed (ONE_EIGHTH_TU_TO_USEC(next_beacon) - 53199482Srdivacky ap->ah_config.ath_hal_sw_beacon_response_time)); 54201361Srdivacky 55226633Sdim beacon_period_usec = 56193326Sed ONE_EIGHTH_TU_TO_USEC(beacon_period & HAL_BEACON_PERIOD_TU8); 57218893Sdim OS_REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period_usec); 58193326Sed OS_REG_WRITE(ah, AR_DMA_BEACON_PERIOD, beacon_period_usec); 59261991Sdim OS_REG_WRITE(ah, AR_SWBA_PERIOD, beacon_period_usec); 60193326Sed 61193326Sed /* reset TSF if required */ 62212904Sdim if (beacon_period & HAL_BEACON_RESET_TSF) { 63261991Sdim ar9300_reset_tsf(ah); 64193326Sed } 65218893Sdim 66198092Srdivacky /* enable timers */ 67193326Sed OS_REG_SET_BIT(ah, AR_TIMER_MODE, 68249423Sdim AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN); 69198092Srdivacky} 70200583Srdivacky 71276479Sdim/* 72198092Srdivacky * Set all the beacon related bits on the h/w for stations 73194179Sed * i.e. initializes the corresponding h/w timers; 74296417Sdim */ 75198092Srdivackyvoid 76239462Sdimar9300_set_sta_beacon_timers(struct ath_hal *ah, const HAL_BEACON_STATE *bs) 77239462Sdim{ 78239462Sdim u_int32_t next_tbtt, beaconintval, dtimperiod, beacontimeout; 79239462Sdim HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps; 80280031Sdim 81280031Sdim HALASSERT(bs->bs_intval != 0); 82280031Sdim 83280031Sdim /* no cfp setting since h/w automatically takes care */ 84280031Sdim OS_REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt)); 85280031Sdim 86280031Sdim /* 87280031Sdim * Start the beacon timers by setting the BEACON register 88280031Sdim * to the beacon interval; no need to write tim offset since 89243830Sdim * h/w parses IEs. 90243830Sdim */ 91234353Sdim OS_REG_WRITE(ah, AR_BEACON_PERIOD, 92210299Sed TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD)); 93210299Sed OS_REG_WRITE(ah, AR_DMA_BEACON_PERIOD, 94249423Sdim TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD)); 95218893Sdim /* 96218893Sdim * Configure the BMISS interrupt. Note that we 97218893Sdim * assume the caller blocks interrupts while enabling 98276479Sdim * the threshold. 99218893Sdim */ 100218893Sdim HALASSERT(bs->bs_bmissthreshold <= 101218893Sdim (AR_RSSI_THR_BM_THR >> AR_RSSI_THR_BM_THR_S)); 102218893Sdim OS_REG_RMW_FIELD(ah, AR_RSSI_THR, 103218893Sdim AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold); 104218893Sdim 105218893Sdim /* 106218893Sdim * Program the sleep registers to correlate with the beacon setup. 107218893Sdim */ 108218893Sdim 109218893Sdim /* 110218893Sdim * Current implementation assumes sw processing of beacons - 111221345Sdim * assuming an interrupt is generated every beacon which 112221345Sdim * causes the hardware to become awake until the sw tells 113218893Sdim * it to go to sleep again; beacon timeout is to allow for 114218893Sdim * beacon jitter; cab timeout is max time to wait for cab 115218893Sdim * after seeing the last DTIM or MORE CAB bit 116218893Sdim */ 117218893Sdim#define CAB_TIMEOUT_VAL 10 /* in TU */ 118218893Sdim#define BEACON_TIMEOUT_VAL 10 /* in TU */ 119218893Sdim#define MIN_BEACON_TIMEOUT_VAL 1 /* in 1/8 TU */ 120218893Sdim#define SLEEP_SLOP 3 /* in TU */ 121210299Sed 122218893Sdim /* 123218893Sdim * For max powersave mode we may want to sleep for longer than a 124218893Sdim * beacon period and not want to receive all beacons; modify the 125218893Sdim * timers accordingly; make sure to align the next TIM to the 126218893Sdim * next DTIM if we decide to wake for DTIMs only 127210299Sed */ 128218893Sdim beaconintval = bs->bs_intval & HAL_BEACON_PERIOD; 129218893Sdim HALASSERT(beaconintval != 0); 130218893Sdim if (bs->bs_sleepduration > beaconintval) { 131219077Sdim HALASSERT(roundup(bs->bs_sleepduration, beaconintval) == 132226633Sdim bs->bs_sleepduration); 133218893Sdim beaconintval = bs->bs_sleepduration; 134296417Sdim } 135193326Sed dtimperiod = bs->bs_dtimperiod; 136218893Sdim if (bs->bs_sleepduration > dtimperiod) { 137218893Sdim HALASSERT(dtimperiod == 0 || 138224145Sdim roundup(bs->bs_sleepduration, dtimperiod) == 139224145Sdim bs->bs_sleepduration); 140224145Sdim dtimperiod = bs->bs_sleepduration; 141224145Sdim } 142218893Sdim HALASSERT(beaconintval <= dtimperiod); 143218893Sdim if (beaconintval == dtimperiod) { 144193326Sed next_tbtt = bs->bs_nextdtim; 145193326Sed } else { 146193326Sed next_tbtt = bs->bs_nexttbtt; 147218893Sdim } 148218893Sdim 149193326Sed HALDEBUG(ah, HAL_DEBUG_BEACON, 150193326Sed "%s: next DTIM %d\n", __func__, bs->bs_nextdtim); 151243830Sdim HALDEBUG(ah, HAL_DEBUG_BEACON, 152243830Sdim "%s: next beacon %d\n", __func__, next_tbtt); 153243830Sdim HALDEBUG(ah, HAL_DEBUG_BEACON, 154218893Sdim "%s: beacon period %d\n", __func__, beaconintval); 155218893Sdim HALDEBUG(ah, HAL_DEBUG_BEACON, 156218893Sdim "%s: DTIM period %d\n", __func__, dtimperiod); 157218893Sdim 158193326Sed OS_REG_WRITE(ah, AR_NEXT_DTIM, TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP)); 159243830Sdim OS_REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(next_tbtt - SLEEP_SLOP)); 160280031Sdim 161234353Sdim /* cab timeout is now in 1/8 TU */ 162234353Sdim OS_REG_WRITE(ah, AR_SLEEP1, 163243830Sdim SM((CAB_TIMEOUT_VAL << 3), AR_SLEEP1_CAB_TIMEOUT) 164261991Sdim | AR_SLEEP1_ASSUME_DTIM); 165200583Srdivacky 166198092Srdivacky /* beacon timeout is now in 1/8 TU */ 167198092Srdivacky if (p_cap->hal_auto_sleep_support) { 168226633Sdim beacontimeout = (BEACON_TIMEOUT_VAL << 3); 169226633Sdim } else { 170226633Sdim /* 171226633Sdim * Use a very small value to make sure the timeout occurs before 172198092Srdivacky * the TBTT. In this case the chip will not go back to sleep 173218893Sdim * automatically, instead it will wait for the SW to explicitly 174218893Sdim * set it to that mode. 175218893Sdim */ 176226633Sdim beacontimeout = MIN_BEACON_TIMEOUT_VAL; 177243830Sdim } 178226633Sdim 179226633Sdim OS_REG_WRITE(ah, AR_SLEEP2, 180226633Sdim SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT)); 181261991Sdim 182296417Sdim OS_REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval)); 183296417Sdim OS_REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod)); 184296417Sdim 185261991Sdim /* clear HOST AP related timers first */ 186261991Sdim OS_REG_CLR_BIT(ah, AR_TIMER_MODE, (AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN)); 187210299Sed 188210299Sed OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN 189210299Sed | AR_DTIM_TIMER_EN); 190210299Sed 191210299Sed /* TSF out of range threshold */ 192210299Sed OS_REG_WRITE(ah, AR_TSFOOR_THRESHOLD, bs->bs_tsfoor_threshold); 193210299Sed 194210299Sed#undef CAB_TIMEOUT_VAL 195210299Sed#undef BEACON_TIMEOUT_VAL 196210299Sed#undef SLEEP_SLOP 197210299Sed} 198210299Sed#endif /* AH_SUPPORT_AR9300 */ 199210299Sed