1250003Sadrian/* 2250003Sadrian * Copyright (c) 2013 Qualcomm Atheros, Inc. 3250003Sadrian * 4250003Sadrian * Permission to use, copy, modify, and/or distribute this software for any 5250003Sadrian * purpose with or without fee is hereby granted, provided that the above 6250003Sadrian * copyright notice and this permission notice appear in all copies. 7250003Sadrian * 8250003Sadrian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9250003Sadrian * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10250003Sadrian * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11250003Sadrian * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12250003Sadrian * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 13250003Sadrian * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14250003Sadrian * PERFORMANCE OF THIS SOFTWARE. 15250003Sadrian */ 16250003Sadrian 17250003Sadrian#include "opt_ah.h" 18250003Sadrian 19250003Sadrian#include "ah.h" 20250003Sadrian#include "ah_internal.h" 21250003Sadrian 22250003Sadrian#include "ar9300/ar9300.h" 23250003Sadrian#include "ar9300/ar9300reg.h" 24250003Sadrian 25250003Sadrian#define TU_TO_USEC(_tu) ((_tu) << 10) 26250008Sadrian#define ONE_EIGHTH_TU_TO_USEC(_tu8) ((_tu8) << 7) 27250003Sadrian 28250003Sadrianextern u_int32_t ar9300_num_tx_pending(struct ath_hal *ah, u_int q); 29250003Sadrian 30250003Sadrian/* 31250003Sadrian * Initializes all of the hardware registers used to 32250003Sadrian * send beacons. Note that for station operation the 33250003Sadrian * driver calls ar9300_set_sta_beacon_timers instead. 34250003Sadrian */ 35250003Sadrianvoid 36250003Sadrianar9300_beacon_init(struct ath_hal *ah, 37278741Sadrian u_int32_t next_beacon, u_int32_t beacon_period, 38278741Sadrian u_int32_t beacon_period_fraction, HAL_OPMODE opmode) 39250003Sadrian{ 40250003Sadrian u_int32_t beacon_period_usec; 41250003Sadrian 42250003Sadrian HALASSERT(opmode == HAL_M_IBSS || opmode == HAL_M_HOSTAP); 43250003Sadrian if (opmode == HAL_M_IBSS) { 44250003Sadrian OS_REG_SET_BIT(ah, AR_TXCFG, AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); 45250003Sadrian } 46250003Sadrian OS_REG_WRITE(ah, AR_NEXT_TBTT_TIMER, ONE_EIGHTH_TU_TO_USEC(next_beacon)); 47250003Sadrian OS_REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, 48250003Sadrian (ONE_EIGHTH_TU_TO_USEC(next_beacon) - 49250008Sadrian ah->ah_config.ah_dma_beacon_response_time)); 50250003Sadrian OS_REG_WRITE(ah, AR_NEXT_SWBA, 51250003Sadrian (ONE_EIGHTH_TU_TO_USEC(next_beacon) - 52250008Sadrian ah->ah_config.ah_sw_beacon_response_time)); 53250003Sadrian 54250003Sadrian beacon_period_usec = 55250003Sadrian ONE_EIGHTH_TU_TO_USEC(beacon_period & HAL_BEACON_PERIOD_TU8); 56278741Sadrian 57278741Sadrian /* Add the fraction adjustment lost due to unit conversions. */ 58278741Sadrian beacon_period_usec += beacon_period_fraction; 59278741Sadrian 60278807Sadrian HALDEBUG(ah, HAL_DEBUG_BEACON, 61278807Sadrian "%s: next_beacon=0x%08x, beacon_period=%d, opmode=%d, beacon_period_usec=%d\n", 62278807Sadrian __func__, next_beacon, beacon_period, opmode, beacon_period_usec); 63278741Sadrian 64250003Sadrian OS_REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period_usec); 65250003Sadrian OS_REG_WRITE(ah, AR_DMA_BEACON_PERIOD, beacon_period_usec); 66250003Sadrian OS_REG_WRITE(ah, AR_SWBA_PERIOD, beacon_period_usec); 67250003Sadrian 68250003Sadrian /* reset TSF if required */ 69250003Sadrian if (beacon_period & HAL_BEACON_RESET_TSF) { 70250003Sadrian ar9300_reset_tsf(ah); 71250003Sadrian } 72250003Sadrian 73250003Sadrian /* enable timers */ 74250003Sadrian OS_REG_SET_BIT(ah, AR_TIMER_MODE, 75250003Sadrian AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN); 76250003Sadrian} 77250003Sadrian 78250003Sadrian/* 79250003Sadrian * Set all the beacon related bits on the h/w for stations 80250003Sadrian * i.e. initializes the corresponding h/w timers; 81250003Sadrian */ 82250003Sadrianvoid 83250003Sadrianar9300_set_sta_beacon_timers(struct ath_hal *ah, const HAL_BEACON_STATE *bs) 84250003Sadrian{ 85250003Sadrian u_int32_t next_tbtt, beaconintval, dtimperiod, beacontimeout; 86250003Sadrian HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps; 87250003Sadrian 88250003Sadrian HALASSERT(bs->bs_intval != 0); 89250003Sadrian 90250003Sadrian /* no cfp setting since h/w automatically takes care */ 91250003Sadrian OS_REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt)); 92250003Sadrian 93250003Sadrian /* 94250003Sadrian * Start the beacon timers by setting the BEACON register 95250003Sadrian * to the beacon interval; no need to write tim offset since 96250003Sadrian * h/w parses IEs. 97250003Sadrian */ 98250003Sadrian OS_REG_WRITE(ah, AR_BEACON_PERIOD, 99250003Sadrian TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD)); 100250003Sadrian OS_REG_WRITE(ah, AR_DMA_BEACON_PERIOD, 101250003Sadrian TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD)); 102250003Sadrian /* 103250003Sadrian * Configure the BMISS interrupt. Note that we 104250003Sadrian * assume the caller blocks interrupts while enabling 105250003Sadrian * the threshold. 106250003Sadrian */ 107250003Sadrian HALASSERT(bs->bs_bmissthreshold <= 108250003Sadrian (AR_RSSI_THR_BM_THR >> AR_RSSI_THR_BM_THR_S)); 109250003Sadrian OS_REG_RMW_FIELD(ah, AR_RSSI_THR, 110250003Sadrian AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold); 111250003Sadrian 112250003Sadrian /* 113250003Sadrian * Program the sleep registers to correlate with the beacon setup. 114250003Sadrian */ 115250003Sadrian 116250003Sadrian /* 117250003Sadrian * Current implementation assumes sw processing of beacons - 118250003Sadrian * assuming an interrupt is generated every beacon which 119250003Sadrian * causes the hardware to become awake until the sw tells 120250003Sadrian * it to go to sleep again; beacon timeout is to allow for 121250003Sadrian * beacon jitter; cab timeout is max time to wait for cab 122250003Sadrian * after seeing the last DTIM or MORE CAB bit 123250003Sadrian */ 124250003Sadrian#define CAB_TIMEOUT_VAL 10 /* in TU */ 125250003Sadrian#define BEACON_TIMEOUT_VAL 10 /* in TU */ 126250003Sadrian#define MIN_BEACON_TIMEOUT_VAL 1 /* in 1/8 TU */ 127250003Sadrian#define SLEEP_SLOP 3 /* in TU */ 128250003Sadrian 129250003Sadrian /* 130250003Sadrian * For max powersave mode we may want to sleep for longer than a 131250003Sadrian * beacon period and not want to receive all beacons; modify the 132250003Sadrian * timers accordingly; make sure to align the next TIM to the 133250003Sadrian * next DTIM if we decide to wake for DTIMs only 134250003Sadrian */ 135250003Sadrian beaconintval = bs->bs_intval & HAL_BEACON_PERIOD; 136250003Sadrian HALASSERT(beaconintval != 0); 137250003Sadrian if (bs->bs_sleepduration > beaconintval) { 138250003Sadrian HALASSERT(roundup(bs->bs_sleepduration, beaconintval) == 139250003Sadrian bs->bs_sleepduration); 140250003Sadrian beaconintval = bs->bs_sleepduration; 141250003Sadrian } 142250003Sadrian dtimperiod = bs->bs_dtimperiod; 143250003Sadrian if (bs->bs_sleepduration > dtimperiod) { 144250003Sadrian HALASSERT(dtimperiod == 0 || 145250003Sadrian roundup(bs->bs_sleepduration, dtimperiod) == 146250003Sadrian bs->bs_sleepduration); 147250003Sadrian dtimperiod = bs->bs_sleepduration; 148250003Sadrian } 149250003Sadrian HALASSERT(beaconintval <= dtimperiod); 150250003Sadrian if (beaconintval == dtimperiod) { 151250003Sadrian next_tbtt = bs->bs_nextdtim; 152250003Sadrian } else { 153250003Sadrian next_tbtt = bs->bs_nexttbtt; 154250003Sadrian } 155250003Sadrian 156250003Sadrian HALDEBUG(ah, HAL_DEBUG_BEACON, 157250003Sadrian "%s: next DTIM %d\n", __func__, bs->bs_nextdtim); 158250003Sadrian HALDEBUG(ah, HAL_DEBUG_BEACON, 159250003Sadrian "%s: next beacon %d\n", __func__, next_tbtt); 160250003Sadrian HALDEBUG(ah, HAL_DEBUG_BEACON, 161250003Sadrian "%s: beacon period %d\n", __func__, beaconintval); 162250003Sadrian HALDEBUG(ah, HAL_DEBUG_BEACON, 163250003Sadrian "%s: DTIM period %d\n", __func__, dtimperiod); 164250003Sadrian 165250003Sadrian OS_REG_WRITE(ah, AR_NEXT_DTIM, TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP)); 166250003Sadrian OS_REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(next_tbtt - SLEEP_SLOP)); 167250003Sadrian 168250003Sadrian /* cab timeout is now in 1/8 TU */ 169250003Sadrian OS_REG_WRITE(ah, AR_SLEEP1, 170250003Sadrian SM((CAB_TIMEOUT_VAL << 3), AR_SLEEP1_CAB_TIMEOUT) 171250003Sadrian | AR_SLEEP1_ASSUME_DTIM); 172250003Sadrian 173250003Sadrian /* beacon timeout is now in 1/8 TU */ 174250008Sadrian if (p_cap->halAutoSleepSupport) { 175250003Sadrian beacontimeout = (BEACON_TIMEOUT_VAL << 3); 176250003Sadrian } else { 177250003Sadrian /* 178250003Sadrian * Use a very small value to make sure the timeout occurs before 179250003Sadrian * the TBTT. In this case the chip will not go back to sleep 180250003Sadrian * automatically, instead it will wait for the SW to explicitly 181250003Sadrian * set it to that mode. 182250003Sadrian */ 183250003Sadrian beacontimeout = MIN_BEACON_TIMEOUT_VAL; 184250003Sadrian } 185250003Sadrian 186250003Sadrian OS_REG_WRITE(ah, AR_SLEEP2, 187250003Sadrian SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT)); 188250003Sadrian 189250003Sadrian OS_REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval)); 190250003Sadrian OS_REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod)); 191250003Sadrian 192250003Sadrian /* clear HOST AP related timers first */ 193250003Sadrian OS_REG_CLR_BIT(ah, AR_TIMER_MODE, (AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN)); 194250003Sadrian 195250003Sadrian OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN 196250003Sadrian | AR_DTIM_TIMER_EN); 197250003Sadrian 198250003Sadrian /* TSF out of range threshold */ 199250003Sadrian OS_REG_WRITE(ah, AR_TSFOOR_THRESHOLD, bs->bs_tsfoor_threshold); 200250003Sadrian 201250003Sadrian#undef CAB_TIMEOUT_VAL 202250003Sadrian#undef BEACON_TIMEOUT_VAL 203250003Sadrian#undef SLEEP_SLOP 204250003Sadrian} 205