1 1.1 alc /* 2 1.1 alc * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3 1.1 alc * Copyright (c) 2002-2008 Atheros Communications, Inc. 4 1.1 alc * 5 1.1 alc * Permission to use, copy, modify, and/or distribute this software for any 6 1.1 alc * purpose with or without fee is hereby granted, provided that the above 7 1.1 alc * copyright notice and this permission notice appear in all copies. 8 1.1 alc * 9 1.1 alc * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 1.1 alc * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 1.1 alc * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 1.1 alc * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 1.1 alc * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 1.1 alc * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 1.1 alc * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 1.1 alc * 17 1.2 martin * $Id: ar5416_beacon.c,v 1.2 2013/09/12 12:08:49 martin Exp $ 18 1.1 alc */ 19 1.1 alc #include "opt_ah.h" 20 1.1 alc 21 1.1 alc #include "ah.h" 22 1.1 alc #include "ah_internal.h" 23 1.1 alc 24 1.1 alc #include "ar5416/ar5416.h" 25 1.1 alc #include "ar5416/ar5416reg.h" 26 1.1 alc #include "ar5416/ar5416phy.h" 27 1.1 alc 28 1.1 alc #define TU_TO_USEC(_tu) ((_tu) << 10) 29 1.1 alc 30 1.1 alc /* 31 1.1 alc * Initialize all of the hardware registers used to 32 1.1 alc * send beacons. Note that for station operation the 33 1.1 alc * driver calls ar5416SetStaBeaconTimers instead. 34 1.1 alc */ 35 1.1 alc void 36 1.1 alc ar5416SetBeaconTimers(struct ath_hal *ah, const HAL_BEACON_TIMERS *bt) 37 1.1 alc { 38 1.1 alc uint32_t bperiod; 39 1.1 alc 40 1.1 alc OS_REG_WRITE(ah, AR_NEXT_TBTT, TU_TO_USEC(bt->bt_nexttbtt)); 41 1.1 alc OS_REG_WRITE(ah, AR_NEXT_DBA, TU_TO_USEC(bt->bt_nextdba) >> 3); 42 1.1 alc OS_REG_WRITE(ah, AR_NEXT_SWBA, TU_TO_USEC(bt->bt_nextswba) >> 3); 43 1.1 alc OS_REG_WRITE(ah, AR_NEXT_NDP, TU_TO_USEC(bt->bt_nextatim)); 44 1.1 alc 45 1.1 alc bperiod = TU_TO_USEC(bt->bt_intval & HAL_BEACON_PERIOD); 46 1.1 alc OS_REG_WRITE(ah, AR5416_BEACON_PERIOD, bperiod); 47 1.1 alc OS_REG_WRITE(ah, AR_DBA_PERIOD, bperiod); 48 1.1 alc OS_REG_WRITE(ah, AR_SWBA_PERIOD, bperiod); 49 1.1 alc OS_REG_WRITE(ah, AR_NDP_PERIOD, bperiod); 50 1.1 alc 51 1.1 alc /* 52 1.1 alc * Reset TSF if required. 53 1.1 alc */ 54 1.1 alc if (bt->bt_intval & AR_BEACON_RESET_TSF) 55 1.1 alc ar5416ResetTsf(ah); 56 1.1 alc 57 1.1 alc /* enable timers */ 58 1.1 alc /* NB: flags == 0 handled specially for backwards compatibility */ 59 1.1 alc OS_REG_SET_BIT(ah, AR_TIMER_MODE, 60 1.1 alc bt->bt_flags != 0 ? bt->bt_flags : 61 1.1 alc AR_TIMER_MODE_TBTT | AR_TIMER_MODE_DBA | AR_TIMER_MODE_SWBA); 62 1.1 alc } 63 1.1 alc 64 1.1 alc /* 65 1.1 alc * Initializes all of the hardware registers used to 66 1.1 alc * send beacons. Note that for station operation the 67 1.1 alc * driver calls ar5212SetStaBeaconTimers instead. 68 1.1 alc */ 69 1.1 alc void 70 1.1 alc ar5416BeaconInit(struct ath_hal *ah, 71 1.1 alc uint32_t next_beacon, uint32_t beacon_period) 72 1.1 alc { 73 1.1 alc HAL_BEACON_TIMERS bt; 74 1.1 alc 75 1.1 alc bt.bt_nexttbtt = next_beacon; 76 1.1 alc /* 77 1.1 alc * TIMER1: in AP/adhoc mode this controls the DMA beacon 78 1.1 alc * alert timer; otherwise it controls the next wakeup time. 79 1.1 alc * TIMER2: in AP mode, it controls the SBA beacon alert 80 1.1 alc * interrupt; otherwise it sets the start of the next CFP. 81 1.1 alc */ 82 1.1 alc bt.bt_flags = 0; 83 1.1 alc switch (AH_PRIVATE(ah)->ah_opmode) { 84 1.1 alc case HAL_M_STA: 85 1.1 alc case HAL_M_MONITOR: 86 1.1 alc bt.bt_nextdba = 0xffff; 87 1.1 alc bt.bt_nextswba = 0x7ffff; 88 1.1 alc bt.bt_flags |= AR_TIMER_MODE_TBTT; 89 1.1 alc break; 90 1.1 alc case HAL_M_IBSS: 91 1.1 alc OS_REG_SET_BIT(ah, AR_TXCFG, AR_TXCFG_ATIM_TXPOLICY); 92 1.1 alc bt.bt_flags |= AR_TIMER_MODE_NDP; 93 1.1 alc /* fall thru... */ 94 1.1 alc case HAL_M_HOSTAP: 95 1.1 alc bt.bt_nextdba = (next_beacon - 96 1.1 alc ath_hal_dma_beacon_response_time) << 3; /* 1/8 TU */ 97 1.1 alc bt.bt_nextswba = (next_beacon - 98 1.1 alc ath_hal_sw_beacon_response_time) << 3; /* 1/8 TU */ 99 1.1 alc bt.bt_flags |= AR_TIMER_MODE_TBTT 100 1.1 alc | AR_TIMER_MODE_DBA 101 1.1 alc | AR_TIMER_MODE_SWBA; 102 1.1 alc break; 103 1.1 alc } 104 1.1 alc /* 105 1.1 alc * Set the ATIM window 106 1.1 alc * Our hardware does not support an ATIM window of 0 107 1.1 alc * (beacons will not work). If the ATIM windows is 0, 108 1.1 alc * force it to 1. 109 1.1 alc */ 110 1.1 alc bt.bt_nextatim = next_beacon + 1; 111 1.1 alc bt.bt_intval = beacon_period & 112 1.1 alc (AR_BEACON_PERIOD | AR_BEACON_RESET_TSF | AR_BEACON_EN); 113 1.1 alc ar5416SetBeaconTimers(ah, &bt); 114 1.1 alc } 115 1.1 alc 116 1.1 alc #define AR_BEACON_PERIOD_MAX 0xffff 117 1.1 alc 118 1.1 alc void 119 1.1 alc ar5416ResetStaBeaconTimers(struct ath_hal *ah) 120 1.1 alc { 121 1.1 alc uint32_t val; 122 1.1 alc 123 1.1 alc OS_REG_WRITE(ah, AR_NEXT_TBTT, 0); /* no beacons */ 124 1.1 alc val = OS_REG_READ(ah, AR_STA_ID1); 125 1.1 alc val |= AR_STA_ID1_PWR_SAV; /* XXX */ 126 1.1 alc /* tell the h/w that the associated AP is not PCF capable */ 127 1.1 alc OS_REG_WRITE(ah, AR_STA_ID1, 128 1.1 alc val & ~(AR_STA_ID1_USE_DEFANT | AR_STA_ID1_PCF)); 129 1.1 alc OS_REG_WRITE(ah, AR5416_BEACON_PERIOD, AR_BEACON_PERIOD_MAX); 130 1.1 alc OS_REG_WRITE(ah, AR_DBA_PERIOD, AR_BEACON_PERIOD_MAX); 131 1.1 alc } 132 1.1 alc 133 1.1 alc /* 134 1.1 alc * Set all the beacon related bits on the h/w for stations 135 1.1 alc * i.e. initializes the corresponding h/w timers; 136 1.1 alc * also tells the h/w whether to anticipate PCF beacons 137 1.1 alc */ 138 1.1 alc void 139 1.1 alc ar5416SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs) 140 1.1 alc { 141 1.2 martin uint32_t nextTbtt,beaconintval, dtimperiod; 142 1.1 alc 143 1.1 alc HALASSERT(bs->bs_intval != 0); 144 1.1 alc 145 1.1 alc /* NB: no cfp setting since h/w automatically takes care */ 146 1.1 alc 147 1.1 alc OS_REG_WRITE(ah, AR_NEXT_TBTT, bs->bs_nexttbtt); 148 1.1 alc 149 1.1 alc /* 150 1.1 alc * Start the beacon timers by setting the BEACON register 151 1.1 alc * to the beacon interval; no need to write tim offset since 152 1.1 alc * h/w parses IEs. 153 1.1 alc */ 154 1.1 alc OS_REG_WRITE(ah, AR5416_BEACON_PERIOD, 155 1.1 alc TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD)); 156 1.1 alc OS_REG_WRITE(ah, AR_DBA_PERIOD, 157 1.1 alc TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD)); 158 1.1 alc 159 1.1 alc /* 160 1.1 alc * Configure the BMISS interrupt. Note that we 161 1.1 alc * assume the caller blocks interrupts while enabling 162 1.1 alc * the threshold. 163 1.1 alc */ 164 1.1 alc HALASSERT(bs->bs_bmissthreshold <= 165 1.1 alc (AR_RSSI_THR_BM_THR >> AR_RSSI_THR_BM_THR_S)); 166 1.1 alc OS_REG_RMW_FIELD(ah, AR_RSSI_THR, 167 1.1 alc AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold); 168 1.1 alc 169 1.1 alc /* 170 1.1 alc * Program the sleep registers to correlate with the beacon setup. 171 1.1 alc */ 172 1.1 alc 173 1.1 alc /* 174 1.1 alc * Oahu beacons timers on the station were used for power 175 1.1 alc * save operation (waking up in anticipation of a beacon) 176 1.1 alc * and any CFP function; Venice does sleep/power-save timers 177 1.1 alc * differently - so this is the right place to set them up; 178 1.1 alc * don't think the beacon timers are used by venice sta hw 179 1.1 alc * for any useful purpose anymore 180 1.1 alc * Setup venice's sleep related timers 181 1.1 alc * Current implementation assumes sw processing of beacons - 182 1.1 alc * assuming an interrupt is generated every beacon which 183 1.1 alc * causes the hardware to become awake until the sw tells 184 1.1 alc * it to go to sleep again; beacon timeout is to allow for 185 1.1 alc * beacon jitter; cab timeout is max time to wait for cab 186 1.1 alc * after seeing the last DTIM or MORE CAB bit 187 1.1 alc */ 188 1.1 alc #define CAB_TIMEOUT_VAL 10 /* in TU */ 189 1.1 alc #define BEACON_TIMEOUT_VAL 10 /* in TU */ 190 1.1 alc #define SLEEP_SLOP 3 /* in TU */ 191 1.1 alc 192 1.1 alc /* 193 1.1 alc * For max powersave mode we may want to sleep for longer than a 194 1.1 alc * beacon period and not want to receive all beacons; modify the 195 1.1 alc * timers accordingly; make sure to align the next TIM to the 196 1.1 alc * next DTIM if we decide to wake for DTIMs only 197 1.1 alc */ 198 1.1 alc beaconintval = bs->bs_intval & HAL_BEACON_PERIOD; 199 1.1 alc HALASSERT(beaconintval != 0); 200 1.1 alc if (bs->bs_sleepduration > beaconintval) { 201 1.1 alc HALASSERT(roundup(bs->bs_sleepduration, beaconintval) == 202 1.1 alc bs->bs_sleepduration); 203 1.1 alc beaconintval = bs->bs_sleepduration; 204 1.1 alc } 205 1.1 alc dtimperiod = bs->bs_dtimperiod; 206 1.1 alc if (bs->bs_sleepduration > dtimperiod) { 207 1.1 alc HALASSERT(dtimperiod == 0 || 208 1.1 alc roundup(bs->bs_sleepduration, dtimperiod) == 209 1.1 alc bs->bs_sleepduration); 210 1.1 alc dtimperiod = bs->bs_sleepduration; 211 1.1 alc } 212 1.1 alc HALASSERT(beaconintval <= dtimperiod); 213 1.1 alc if (beaconintval == dtimperiod) 214 1.1 alc nextTbtt = bs->bs_nextdtim; 215 1.1 alc else 216 1.1 alc nextTbtt = bs->bs_nexttbtt; 217 1.1 alc 218 1.1 alc OS_REG_WRITE(ah, AR_NEXT_DTIM, 219 1.1 alc TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP)); 220 1.1 alc OS_REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP)); 221 1.1 alc 222 1.1 alc /* cab timeout is now in 1/8 TU */ 223 1.1 alc OS_REG_WRITE(ah, AR_SLEEP1, 224 1.1 alc SM((CAB_TIMEOUT_VAL << 3), AR5416_SLEEP1_CAB_TIMEOUT) 225 1.1 alc | AR_SLEEP1_ASSUME_DTIM); 226 1.1 alc /* beacon timeout is now in 1/8 TU */ 227 1.1 alc OS_REG_WRITE(ah, AR_SLEEP2, 228 1.1 alc SM((BEACON_TIMEOUT_VAL << 3), AR5416_SLEEP2_BEACON_TIMEOUT)); 229 1.1 alc 230 1.1 alc OS_REG_WRITE(ah, AR_TIM_PERIOD, beaconintval); 231 1.1 alc OS_REG_WRITE(ah, AR_DTIM_PERIOD, dtimperiod); 232 1.1 alc OS_REG_SET_BIT(ah, AR_TIMER_MODE, 233 1.1 alc AR_TIMER_MODE_TBTT | AR_TIMER_MODE_TIM | AR_TIMER_MODE_DTIM); 234 1.1 alc HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: next DTIM %d\n", 235 1.1 alc __func__, bs->bs_nextdtim); 236 1.1 alc HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: next beacon %d\n", 237 1.1 alc __func__, nextTbtt); 238 1.1 alc HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: beacon period %d\n", 239 1.1 alc __func__, beaconintval); 240 1.1 alc HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: DTIM period %d\n", 241 1.1 alc __func__, dtimperiod); 242 1.1 alc #undef CAB_TIMEOUT_VAL 243 1.1 alc #undef BEACON_TIMEOUT_VAL 244 1.1 alc #undef SLEEP_SLOP 245 1.1 alc } 246