ar5416_beacon.c revision 225125
1185377Ssam/* 2185377Ssam * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3185377Ssam * Copyright (c) 2002-2008 Atheros Communications, Inc. 4185377Ssam * 5185377Ssam * Permission to use, copy, modify, and/or distribute this software for any 6185377Ssam * purpose with or without fee is hereby granted, provided that the above 7185377Ssam * copyright notice and this permission notice appear in all copies. 8185377Ssam * 9185377Ssam * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10185377Ssam * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11185377Ssam * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12185377Ssam * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13185377Ssam * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14185377Ssam * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15185377Ssam * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16185377Ssam * 17203158Srpaulo * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c 225125 2011-08-24 00:45:53Z adrian $ 18185377Ssam */ 19185377Ssam#include "opt_ah.h" 20185377Ssam 21185377Ssam#include "ah.h" 22185377Ssam#include "ah_internal.h" 23185377Ssam 24185377Ssam#include "ar5416/ar5416.h" 25185377Ssam#include "ar5416/ar5416reg.h" 26185377Ssam#include "ar5416/ar5416phy.h" 27185377Ssam 28185377Ssam#define TU_TO_USEC(_tu) ((_tu) << 10) 29225111Sadrian#define ONE_EIGHTH_TU_TO_USEC(_tu8) ((_tu8) << 7) 30185377Ssam 31185377Ssam/* 32185377Ssam * Initialize all of the hardware registers used to 33185377Ssam * send beacons. Note that for station operation the 34185380Ssam * driver calls ar5416SetStaBeaconTimers instead. 35185377Ssam */ 36185377Ssamvoid 37185377Ssamar5416SetBeaconTimers(struct ath_hal *ah, const HAL_BEACON_TIMERS *bt) 38185377Ssam{ 39185377Ssam uint32_t bperiod; 40185377Ssam 41185377Ssam OS_REG_WRITE(ah, AR_NEXT_TBTT, TU_TO_USEC(bt->bt_nexttbtt)); 42225111Sadrian OS_REG_WRITE(ah, AR_NEXT_DBA, ONE_EIGHTH_TU_TO_USEC(bt->bt_nextdba)); 43225111Sadrian OS_REG_WRITE(ah, AR_NEXT_SWBA, ONE_EIGHTH_TU_TO_USEC(bt->bt_nextswba)); 44185377Ssam OS_REG_WRITE(ah, AR_NEXT_NDP, TU_TO_USEC(bt->bt_nextatim)); 45185377Ssam 46185377Ssam bperiod = TU_TO_USEC(bt->bt_intval & HAL_BEACON_PERIOD); 47185377Ssam OS_REG_WRITE(ah, AR5416_BEACON_PERIOD, bperiod); 48185377Ssam OS_REG_WRITE(ah, AR_DBA_PERIOD, bperiod); 49185377Ssam OS_REG_WRITE(ah, AR_SWBA_PERIOD, bperiod); 50185377Ssam OS_REG_WRITE(ah, AR_NDP_PERIOD, bperiod); 51185377Ssam 52185377Ssam /* 53185377Ssam * Reset TSF if required. 54185377Ssam */ 55185377Ssam if (bt->bt_intval & AR_BEACON_RESET_TSF) 56185377Ssam ar5416ResetTsf(ah); 57185377Ssam 58185377Ssam /* enable timers */ 59185377Ssam /* NB: flags == 0 handled specially for backwards compatibility */ 60185377Ssam OS_REG_SET_BIT(ah, AR_TIMER_MODE, 61185377Ssam bt->bt_flags != 0 ? bt->bt_flags : 62185377Ssam AR_TIMER_MODE_TBTT | AR_TIMER_MODE_DBA | AR_TIMER_MODE_SWBA); 63185377Ssam} 64185377Ssam 65185377Ssam/* 66185377Ssam * Initializes all of the hardware registers used to 67185377Ssam * send beacons. Note that for station operation the 68185377Ssam * driver calls ar5212SetStaBeaconTimers instead. 69185377Ssam */ 70185377Ssamvoid 71185377Ssamar5416BeaconInit(struct ath_hal *ah, 72185377Ssam uint32_t next_beacon, uint32_t beacon_period) 73185377Ssam{ 74185377Ssam HAL_BEACON_TIMERS bt; 75185377Ssam 76185377Ssam bt.bt_nexttbtt = next_beacon; 77185377Ssam /* 78185377Ssam * TIMER1: in AP/adhoc mode this controls the DMA beacon 79185377Ssam * alert timer; otherwise it controls the next wakeup time. 80185377Ssam * TIMER2: in AP mode, it controls the SBA beacon alert 81185377Ssam * interrupt; otherwise it sets the start of the next CFP. 82185377Ssam */ 83185377Ssam bt.bt_flags = 0; 84185377Ssam switch (AH_PRIVATE(ah)->ah_opmode) { 85185377Ssam case HAL_M_STA: 86185377Ssam case HAL_M_MONITOR: 87185377Ssam bt.bt_nextdba = 0xffff; 88185377Ssam bt.bt_nextswba = 0x7ffff; 89185377Ssam bt.bt_flags |= AR_TIMER_MODE_TBTT; 90185377Ssam break; 91185377Ssam case HAL_M_IBSS: 92185377Ssam OS_REG_SET_BIT(ah, AR_TXCFG, AR_TXCFG_ATIM_TXPOLICY); 93185377Ssam bt.bt_flags |= AR_TIMER_MODE_NDP; 94185377Ssam /* fall thru... */ 95185377Ssam case HAL_M_HOSTAP: 96185377Ssam bt.bt_nextdba = (next_beacon - 97223465Sadrian ah->ah_config.ah_dma_beacon_response_time) << 3; /* 1/8 TU */ 98185377Ssam bt.bt_nextswba = (next_beacon - 99223465Sadrian ah->ah_config.ah_sw_beacon_response_time) << 3; /* 1/8 TU */ 100185377Ssam bt.bt_flags |= AR_TIMER_MODE_TBTT 101185377Ssam | AR_TIMER_MODE_DBA 102185377Ssam | AR_TIMER_MODE_SWBA; 103185377Ssam break; 104185377Ssam } 105185377Ssam /* 106185377Ssam * Set the ATIM window 107185377Ssam * Our hardware does not support an ATIM window of 0 108185377Ssam * (beacons will not work). If the ATIM windows is 0, 109185377Ssam * force it to 1. 110185377Ssam */ 111185377Ssam bt.bt_nextatim = next_beacon + 1; 112185377Ssam bt.bt_intval = beacon_period & 113185377Ssam (AR_BEACON_PERIOD | AR_BEACON_RESET_TSF | AR_BEACON_EN); 114185377Ssam ar5416SetBeaconTimers(ah, &bt); 115185377Ssam} 116185377Ssam 117185377Ssam#define AR_BEACON_PERIOD_MAX 0xffff 118185377Ssam 119185377Ssamvoid 120185377Ssamar5416ResetStaBeaconTimers(struct ath_hal *ah) 121185377Ssam{ 122185377Ssam uint32_t val; 123185377Ssam 124185377Ssam OS_REG_WRITE(ah, AR_NEXT_TBTT, 0); /* no beacons */ 125185377Ssam val = OS_REG_READ(ah, AR_STA_ID1); 126185377Ssam val |= AR_STA_ID1_PWR_SAV; /* XXX */ 127185377Ssam /* tell the h/w that the associated AP is not PCF capable */ 128185377Ssam OS_REG_WRITE(ah, AR_STA_ID1, 129185377Ssam val & ~(AR_STA_ID1_USE_DEFANT | AR_STA_ID1_PCF)); 130185377Ssam OS_REG_WRITE(ah, AR5416_BEACON_PERIOD, AR_BEACON_PERIOD_MAX); 131185377Ssam OS_REG_WRITE(ah, AR_DBA_PERIOD, AR_BEACON_PERIOD_MAX); 132185377Ssam} 133185377Ssam 134185377Ssam/* 135185377Ssam * Set all the beacon related bits on the h/w for stations 136185377Ssam * i.e. initializes the corresponding h/w timers; 137185377Ssam * also tells the h/w whether to anticipate PCF beacons 138185377Ssam */ 139185377Ssamvoid 140185377Ssamar5416SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs) 141185377Ssam{ 142185377Ssam uint32_t nextTbtt, nextdtim,beaconintval, dtimperiod; 143185377Ssam 144185377Ssam HALASSERT(bs->bs_intval != 0); 145185377Ssam 146185377Ssam /* NB: no cfp setting since h/w automatically takes care */ 147185377Ssam 148225111Sadrian OS_REG_WRITE(ah, AR_NEXT_TBTT, TU_TO_USEC(bs->bs_nexttbtt)); 149185377Ssam 150185377Ssam /* 151185377Ssam * Start the beacon timers by setting the BEACON register 152185377Ssam * to the beacon interval; no need to write tim offset since 153185377Ssam * h/w parses IEs. 154185377Ssam */ 155185377Ssam OS_REG_WRITE(ah, AR5416_BEACON_PERIOD, 156185377Ssam TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD)); 157185377Ssam OS_REG_WRITE(ah, AR_DBA_PERIOD, 158185377Ssam TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD)); 159185377Ssam 160185377Ssam /* 161185377Ssam * Configure the BMISS interrupt. Note that we 162185377Ssam * assume the caller blocks interrupts while enabling 163185377Ssam * the threshold. 164185377Ssam */ 165185377Ssam HALASSERT(bs->bs_bmissthreshold <= 166185377Ssam (AR_RSSI_THR_BM_THR >> AR_RSSI_THR_BM_THR_S)); 167185377Ssam OS_REG_RMW_FIELD(ah, AR_RSSI_THR, 168185377Ssam AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold); 169185377Ssam 170185377Ssam /* 171185377Ssam * Program the sleep registers to correlate with the beacon setup. 172185377Ssam */ 173185377Ssam 174185377Ssam /* 175185377Ssam * Oahu beacons timers on the station were used for power 176185377Ssam * save operation (waking up in anticipation of a beacon) 177185377Ssam * and any CFP function; Venice does sleep/power-save timers 178185377Ssam * differently - so this is the right place to set them up; 179185377Ssam * don't think the beacon timers are used by venice sta hw 180185377Ssam * for any useful purpose anymore 181185377Ssam * Setup venice's sleep related timers 182185377Ssam * Current implementation assumes sw processing of beacons - 183185377Ssam * assuming an interrupt is generated every beacon which 184185377Ssam * causes the hardware to become awake until the sw tells 185185377Ssam * it to go to sleep again; beacon timeout is to allow for 186185377Ssam * beacon jitter; cab timeout is max time to wait for cab 187185377Ssam * after seeing the last DTIM or MORE CAB bit 188185377Ssam */ 189185377Ssam#define CAB_TIMEOUT_VAL 10 /* in TU */ 190185377Ssam#define BEACON_TIMEOUT_VAL 10 /* in TU */ 191185377Ssam#define SLEEP_SLOP 3 /* in TU */ 192185377Ssam 193185377Ssam /* 194185377Ssam * For max powersave mode we may want to sleep for longer than a 195185377Ssam * beacon period and not want to receive all beacons; modify the 196185377Ssam * timers accordingly; make sure to align the next TIM to the 197185377Ssam * next DTIM if we decide to wake for DTIMs only 198185377Ssam */ 199185377Ssam beaconintval = bs->bs_intval & HAL_BEACON_PERIOD; 200185377Ssam HALASSERT(beaconintval != 0); 201185377Ssam if (bs->bs_sleepduration > beaconintval) { 202185377Ssam HALASSERT(roundup(bs->bs_sleepduration, beaconintval) == 203185377Ssam bs->bs_sleepduration); 204185377Ssam beaconintval = bs->bs_sleepduration; 205185377Ssam } 206185377Ssam dtimperiod = bs->bs_dtimperiod; 207185377Ssam if (bs->bs_sleepduration > dtimperiod) { 208185377Ssam HALASSERT(dtimperiod == 0 || 209185377Ssam roundup(bs->bs_sleepduration, dtimperiod) == 210185377Ssam bs->bs_sleepduration); 211185377Ssam dtimperiod = bs->bs_sleepduration; 212185377Ssam } 213185377Ssam HALASSERT(beaconintval <= dtimperiod); 214185377Ssam if (beaconintval == dtimperiod) 215185377Ssam nextTbtt = bs->bs_nextdtim; 216185377Ssam else 217185377Ssam nextTbtt = bs->bs_nexttbtt; 218185377Ssam nextdtim = bs->bs_nextdtim; 219185377Ssam 220185377Ssam OS_REG_WRITE(ah, AR_NEXT_DTIM, 221185377Ssam TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP)); 222185377Ssam OS_REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP)); 223185377Ssam 224185377Ssam /* cab timeout is now in 1/8 TU */ 225225125Sadrian OS_REG_WRITE(ah, AR5416_SLEEP1, 226185377Ssam SM((CAB_TIMEOUT_VAL << 3), AR5416_SLEEP1_CAB_TIMEOUT) 227225125Sadrian | AR5416_SLEEP1_ASSUME_DTIM); 228225125Sadrian 229225125Sadrian /* XXX autosleep? Use min beacon timeout; check ath9k -adrian */ 230185377Ssam /* beacon timeout is now in 1/8 TU */ 231225125Sadrian OS_REG_WRITE(ah, AR5416_SLEEP2, 232185377Ssam SM((BEACON_TIMEOUT_VAL << 3), AR5416_SLEEP2_BEACON_TIMEOUT)); 233185377Ssam 234225125Sadrian /* TIM_PERIOD and DTIM_PERIOD are now in uS. */ 235225125Sadrian OS_REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval)); 236225125Sadrian OS_REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod)); 237225125Sadrian 238185377Ssam OS_REG_SET_BIT(ah, AR_TIMER_MODE, 239185377Ssam AR_TIMER_MODE_TBTT | AR_TIMER_MODE_TIM | AR_TIMER_MODE_DTIM); 240185377Ssam HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: next DTIM %d\n", 241185377Ssam __func__, bs->bs_nextdtim); 242185377Ssam HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: next beacon %d\n", 243185377Ssam __func__, nextTbtt); 244185377Ssam HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: beacon period %d\n", 245185377Ssam __func__, beaconintval); 246185377Ssam HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: DTIM period %d\n", 247185377Ssam __func__, dtimperiod); 248185377Ssam#undef CAB_TIMEOUT_VAL 249185377Ssam#undef BEACON_TIMEOUT_VAL 250185377Ssam#undef SLEEP_SLOP 251185377Ssam} 252