ar5211_beacon.c revision 185377
1218822Sdim/* 2218822Sdim * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3218822Sdim * Copyright (c) 2002-2006 Atheros Communications, Inc. 4218822Sdim * 5218822Sdim * Permission to use, copy, modify, and/or distribute this software for any 6218822Sdim * purpose with or without fee is hereby granted, provided that the above 7218822Sdim * copyright notice and this permission notice appear in all copies. 8218822Sdim * 9218822Sdim * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1038889Sjdp * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1138889Sjdp * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1238889Sjdp * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1338889Sjdp * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1438889Sjdp * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1538889Sjdp * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1638889Sjdp * 1738889Sjdp * $Id: ar5211_beacon.c,v 1.4 2008/11/10 04:08:02 sam Exp $ 1838889Sjdp */ 1938889Sjdp#include "opt_ah.h" 2038889Sjdp 2138889Sjdp#ifdef AH_SUPPORT_AR5211 22218822Sdim 2338889Sjdp#include "ah.h" 2438889Sjdp#include "ah_internal.h" 2538889Sjdp 2638889Sjdp#include "ar5211/ar5211.h" 2738889Sjdp#include "ar5211/ar5211reg.h" 2838889Sjdp#include "ar5211/ar5211desc.h" 29218822Sdim 30218822Sdim/* 31218822Sdim * Routines used to initialize and generated beacons for the AR5211/AR5311. 32218822Sdim */ 33218822Sdim 34218822Sdim/* 35218822Sdim * Initialize all of the hardware registers used to send beacons. 36218822Sdim */ 37218822Sdimvoid 38218822Sdimar5211SetBeaconTimers(struct ath_hal *ah, const HAL_BEACON_TIMERS *bt) 39218822Sdim{ 40218822Sdim 41218822Sdim OS_REG_WRITE(ah, AR_TIMER0, bt->bt_nexttbtt); 42218822Sdim OS_REG_WRITE(ah, AR_TIMER1, bt->bt_nextdba); 43218822Sdim OS_REG_WRITE(ah, AR_TIMER2, bt->bt_nextswba); 44218822Sdim OS_REG_WRITE(ah, AR_TIMER3, bt->bt_nextatim); 45218822Sdim /* 46218822Sdim * Set the Beacon register after setting all timers. 47218822Sdim */ 48218822Sdim OS_REG_WRITE(ah, AR_BEACON, bt->bt_intval); 49218822Sdim} 50218822Sdim 51218822Sdim/* 52218822Sdim * Legacy api to initialize all of the beacon registers. 53218822Sdim */ 54218822Sdimvoid 55218822Sdimar5211BeaconInit(struct ath_hal *ah, 56218822Sdim uint32_t next_beacon, uint32_t beacon_period) 57218822Sdim{ 58218822Sdim HAL_BEACON_TIMERS bt; 59218822Sdim 60218822Sdim bt.bt_nexttbtt = next_beacon; 61218822Sdim /* 62218822Sdim * TIMER1: in AP/adhoc mode this controls the DMA beacon 63218822Sdim * alert timer; otherwise it controls the next wakeup time. 64218822Sdim * TIMER2: in AP mode, it controls the SBA beacon alert 65218822Sdim * interrupt; otherwise it sets the start of the next CFP. 66218822Sdim */ 67218822Sdim switch (AH_PRIVATE(ah)->ah_opmode) { 68218822Sdim case HAL_M_STA: 69218822Sdim case HAL_M_MONITOR: 70218822Sdim bt.bt_nextdba = 0xffff; 71218822Sdim bt.bt_nextswba = 0x7ffff; 72218822Sdim break; 73218822Sdim case HAL_M_IBSS: 74218822Sdim case HAL_M_HOSTAP: 75218822Sdim bt.bt_nextdba = (next_beacon - 76218822Sdim ath_hal_dma_beacon_response_time) << 3; /* 1/8 TU */ 77218822Sdim bt.bt_nextswba = (next_beacon - 78218822Sdim ath_hal_sw_beacon_response_time) << 3; /* 1/8 TU */ 79218822Sdim break; 80218822Sdim } 81218822Sdim /* 82218822Sdim * Set the ATIM window 83218822Sdim * Our hardware does not support an ATIM window of 0 84218822Sdim * (beacons will not work). If the ATIM windows is 0, 85218822Sdim * force it to 1. 86218822Sdim */ 87218822Sdim bt.bt_nextatim = next_beacon + 1; 88218822Sdim bt.bt_intval = beacon_period & 89218822Sdim (AR_BEACON_PERIOD | AR_BEACON_RESET_TSF | AR_BEACON_EN); 90218822Sdim ar5211SetBeaconTimers(ah, &bt); 91218822Sdim} 92218822Sdim 93218822Sdimvoid 94218822Sdimar5211ResetStaBeaconTimers(struct ath_hal *ah) 95218822Sdim{ 96218822Sdim uint32_t val; 97218822Sdim 98218822Sdim OS_REG_WRITE(ah, AR_TIMER0, 0); /* no beacons */ 99218822Sdim val = OS_REG_READ(ah, AR_STA_ID1); 100218822Sdim val |= AR_STA_ID1_PWR_SAV; /* XXX */ 101218822Sdim /* tell the h/w that the associated AP is not PCF capable */ 102218822Sdim OS_REG_WRITE(ah, AR_STA_ID1, 103218822Sdim val & ~(AR_STA_ID1_DEFAULT_ANTENNA | AR_STA_ID1_PCF)); 104218822Sdim OS_REG_WRITE(ah, AR_BEACON, AR_BEACON_PERIOD); 105218822Sdim} 106218822Sdim 107218822Sdim/* 108218822Sdim * Set all the beacon related bits on the h/w for stations 109218822Sdim * i.e. initializes the corresponding h/w timers; 110218822Sdim * also tells the h/w whether to anticipate PCF beacons 111218822Sdim */ 112218822Sdimvoid 113218822Sdimar5211SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs) 114218822Sdim{ 115218822Sdim struct ath_hal_5211 *ahp = AH5211(ah); 116218822Sdim 117218822Sdim HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: setting beacon timers\n", __func__); 118218822Sdim 119218822Sdim HALASSERT(bs->bs_intval != 0); 120218822Sdim /* if the AP will do PCF */ 121218822Sdim if (bs->bs_cfpmaxduration != 0) { 122218822Sdim /* tell the h/w that the associated AP is PCF capable */ 123218822Sdim OS_REG_WRITE(ah, AR_STA_ID1, 124218822Sdim OS_REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PCF); 125218822Sdim 126218822Sdim /* set CFP_PERIOD(1.024ms) register */ 127218822Sdim OS_REG_WRITE(ah, AR_CFP_PERIOD, bs->bs_cfpperiod); 128218822Sdim 129218822Sdim /* set CFP_DUR(1.024ms) register to max cfp duration */ 130218822Sdim OS_REG_WRITE(ah, AR_CFP_DUR, bs->bs_cfpmaxduration); 131218822Sdim 132218822Sdim /* set TIMER2(128us) to anticipated time of next CFP */ 133218822Sdim OS_REG_WRITE(ah, AR_TIMER2, bs->bs_cfpnext << 3); 134218822Sdim } else { 135218822Sdim /* tell the h/w that the associated AP is not PCF capable */ 136218822Sdim OS_REG_WRITE(ah, AR_STA_ID1, 137218822Sdim OS_REG_READ(ah, AR_STA_ID1) &~ AR_STA_ID1_PCF); 138218822Sdim } 139218822Sdim 140218822Sdim /* 141218822Sdim * Set TIMER0(1.024ms) to the anticipated time of the next beacon. 142218822Sdim */ 143218822Sdim OS_REG_WRITE(ah, AR_TIMER0, bs->bs_nexttbtt); 144218822Sdim 145218822Sdim /* 146218822Sdim * Start the beacon timers by setting the BEACON register 147218822Sdim * to the beacon interval; also write the tim offset which 148218822Sdim * we should know by now. The code, in ar5211WriteAssocid, 149218822Sdim * also sets the tim offset once the AID is known which can 150218822Sdim * be left as such for now. 151218822Sdim */ 152218822Sdim OS_REG_WRITE(ah, AR_BEACON, 153218822Sdim (OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_PERIOD|AR_BEACON_TIM)) 154218822Sdim | SM(bs->bs_intval, AR_BEACON_PERIOD) 155218822Sdim | SM(bs->bs_timoffset ? bs->bs_timoffset + 4 : 0, AR_BEACON_TIM) 156218822Sdim ); 157218822Sdim 158218822Sdim /* 159218822Sdim * Configure the BMISS interrupt. Note that we 160218822Sdim * assume the caller blocks interrupts while enabling 161218822Sdim * the threshold. 162218822Sdim */ 163218822Sdim HALASSERT(bs->bs_bmissthreshold <= MS(0xffffffff, AR_RSSI_THR_BM_THR)); 164218822Sdim ahp->ah_rssiThr = (ahp->ah_rssiThr &~ AR_RSSI_THR_BM_THR) 165218822Sdim | SM(bs->bs_bmissthreshold, AR_RSSI_THR_BM_THR); 166218822Sdim OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr); 167218822Sdim 168218822Sdim /* 169218822Sdim * Set the sleep duration in 1/8 TU's. 170218822Sdim */ 171218822Sdim#define SLEEP_SLOP 3 172218822Sdim OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLDUR, 173218822Sdim (bs->bs_sleepduration - SLEEP_SLOP) << 3); 174218822Sdim#undef SLEEP_SLOP 175218822Sdim} 176218822Sdim#endif /* AH_SUPPORT_AR5211 */ 177218822Sdim