2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3 * Copyright (c) 2002-2008 Atheros Communications, Inc.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 * $Id: ar5212_beacon.c,v 1.1.1.1 2008/12/11 04:46:40 alc Exp $
22 #include "ah_internal.h"
24 #include "ar5212/ar5212.h"
25 #include "ar5212/ar5212reg.h"
26 #include "ar5212/ar5212desc.h"
29 * Initialize all of the hardware registers used to
30 * send beacons. Note that for station operation the
31 * driver calls ar5212SetStaBeaconTimers instead.
34 ar5212SetBeaconTimers(struct ath_hal
*ah
, const HAL_BEACON_TIMERS
*bt
)
37 OS_REG_WRITE(ah
, AR_TIMER0
, bt
->bt_nexttbtt
);
38 OS_REG_WRITE(ah
, AR_TIMER1
, bt
->bt_nextdba
);
39 OS_REG_WRITE(ah
, AR_TIMER2
, bt
->bt_nextswba
);
40 OS_REG_WRITE(ah
, AR_TIMER3
, bt
->bt_nextatim
);
42 * Set the Beacon register after setting all timers.
44 if (bt
->bt_intval
& AR_BEACON_RESET_TSF
) {
46 * When resetting the TSF,
47 * write twice to the corresponding register; each
48 * write to the RESET_TSF bit toggles the internal
49 * signal to cause a reset of the TSF - but if the signal
50 * is left high, it will reset the TSF on the next
51 * chip reset also! writing the bit an even number
52 * of times fixes this issue
54 OS_REG_WRITE(ah
, AR_BEACON
, AR_BEACON_RESET_TSF
);
56 OS_REG_WRITE(ah
, AR_BEACON
, bt
->bt_intval
);
60 * Old api for setting up beacon timer registers when
61 * operating in !station mode. Note the fixed constants
62 * adjusting the DBA and SWBA timers and the fixed ATIM
66 ar5212BeaconInit(struct ath_hal
*ah
,
67 uint32_t next_beacon
, uint32_t beacon_period
)
71 bt
.bt_nexttbtt
= next_beacon
;
73 * TIMER1: in AP/adhoc mode this controls the DMA beacon
74 * alert timer; otherwise it controls the next wakeup time.
75 * TIMER2: in AP mode, it controls the SBA beacon alert
76 * interrupt; otherwise it sets the start of the next CFP.
78 switch (AH_PRIVATE(ah
)->ah_opmode
) {
81 bt
.bt_nextdba
= 0xffff;
82 bt
.bt_nextswba
= 0x7ffff;
86 bt
.bt_nextdba
= (next_beacon
-
87 ath_hal_dma_beacon_response_time
) << 3; /* 1/8 TU */
88 bt
.bt_nextswba
= (next_beacon
-
89 ath_hal_sw_beacon_response_time
) << 3; /* 1/8 TU */
94 * Our hardware does not support an ATIM window of 0
95 * (beacons will not work). If the ATIM windows is 0,
98 bt
.bt_nextatim
= next_beacon
+ 1;
99 bt
.bt_intval
= beacon_period
&
100 (AR_BEACON_PERIOD
| AR_BEACON_RESET_TSF
| AR_BEACON_EN
);
101 ar5212SetBeaconTimers(ah
, &bt
);
105 ar5212ResetStaBeaconTimers(struct ath_hal
*ah
)
109 OS_REG_WRITE(ah
, AR_TIMER0
, 0); /* no beacons */
110 val
= OS_REG_READ(ah
, AR_STA_ID1
);
111 val
|= AR_STA_ID1_PWR_SAV
; /* XXX */
112 /* tell the h/w that the associated AP is not PCF capable */
113 OS_REG_WRITE(ah
, AR_STA_ID1
,
114 val
& ~(AR_STA_ID1_USE_DEFANT
| AR_STA_ID1_PCF
));
115 OS_REG_WRITE(ah
, AR_BEACON
, AR_BEACON_PERIOD
);
119 * Set all the beacon related bits on the h/w for stations
120 * i.e. initializes the corresponding h/w timers;
121 * also tells the h/w whether to anticipate PCF beacons
124 ar5212SetStaBeaconTimers(struct ath_hal
*ah
, const HAL_BEACON_STATE
*bs
)
126 struct ath_hal_5212
*ahp
= AH5212(ah
);
127 uint32_t nextTbtt
, nextdtim
,beaconintval
, dtimperiod
;
129 HALASSERT(bs
->bs_intval
!= 0);
130 /* if the AP will do PCF */
131 if (bs
->bs_cfpmaxduration
!= 0) {
132 /* tell the h/w that the associated AP is PCF capable */
133 OS_REG_WRITE(ah
, AR_STA_ID1
,
134 OS_REG_READ(ah
, AR_STA_ID1
) | AR_STA_ID1_PCF
);
136 /* set CFP_PERIOD(1.024ms) register */
137 OS_REG_WRITE(ah
, AR_CFP_PERIOD
, bs
->bs_cfpperiod
);
139 /* set CFP_DUR(1.024ms) register to max cfp duration */
140 OS_REG_WRITE(ah
, AR_CFP_DUR
, bs
->bs_cfpmaxduration
);
142 /* set TIMER2(128us) to anticipated time of next CFP */
143 OS_REG_WRITE(ah
, AR_TIMER2
, bs
->bs_cfpnext
<< 3);
145 /* tell the h/w that the associated AP is not PCF capable */
146 OS_REG_WRITE(ah
, AR_STA_ID1
,
147 OS_REG_READ(ah
, AR_STA_ID1
) &~ AR_STA_ID1_PCF
);
151 * Set TIMER0(1.024ms) to the anticipated time of the next beacon.
153 OS_REG_WRITE(ah
, AR_TIMER0
, bs
->bs_nexttbtt
);
156 * Start the beacon timers by setting the BEACON register
157 * to the beacon interval; also write the tim offset which
158 * we should know by now. The code, in ar5211WriteAssocid,
159 * also sets the tim offset once the AID is known which can
160 * be left as such for now.
162 OS_REG_WRITE(ah
, AR_BEACON
,
163 (OS_REG_READ(ah
, AR_BEACON
) &~ (AR_BEACON_PERIOD
|AR_BEACON_TIM
))
164 | SM(bs
->bs_intval
, AR_BEACON_PERIOD
)
165 | SM(bs
->bs_timoffset
? bs
->bs_timoffset
+ 4 : 0, AR_BEACON_TIM
)
169 * Configure the BMISS interrupt. Note that we
170 * assume the caller blocks interrupts while enabling
173 HALASSERT(bs
->bs_bmissthreshold
<= MS(0xffffffff, AR_RSSI_THR_BM_THR
));
174 ahp
->ah_rssiThr
= (ahp
->ah_rssiThr
&~ AR_RSSI_THR_BM_THR
)
175 | SM(bs
->bs_bmissthreshold
, AR_RSSI_THR_BM_THR
);
176 OS_REG_WRITE(ah
, AR_RSSI_THR
, ahp
->ah_rssiThr
);
179 * Program the sleep registers to correlate with the beacon setup.
183 * Oahu beacons timers on the station were used for power
184 * save operation (waking up in anticipation of a beacon)
185 * and any CFP function; Venice does sleep/power-save timers
186 * differently - so this is the right place to set them up;
187 * don't think the beacon timers are used by venice sta hw
188 * for any useful purpose anymore
189 * Setup venice's sleep related timers
190 * Current implementation assumes sw processing of beacons -
191 * assuming an interrupt is generated every beacon which
192 * causes the hardware to become awake until the sw tells
193 * it to go to sleep again; beacon timeout is to allow for
194 * beacon jitter; cab timeout is max time to wait for cab
195 * after seeing the last DTIM or MORE CAB bit
197 #define CAB_TIMEOUT_VAL 10 /* in TU */
198 #define BEACON_TIMEOUT_VAL 10 /* in TU */
199 #define SLEEP_SLOP 3 /* in TU */
202 * For max powersave mode we may want to sleep for longer than a
203 * beacon period and not want to receive all beacons; modify the
204 * timers accordingly; make sure to align the next TIM to the
205 * next DTIM if we decide to wake for DTIMs only
207 beaconintval
= bs
->bs_intval
& HAL_BEACON_PERIOD
;
208 HALASSERT(beaconintval
!= 0);
209 if (bs
->bs_sleepduration
> beaconintval
) {
210 HALASSERT(roundup(bs
->bs_sleepduration
, beaconintval
) ==
211 bs
->bs_sleepduration
);
212 beaconintval
= bs
->bs_sleepduration
;
214 dtimperiod
= bs
->bs_dtimperiod
;
215 if (bs
->bs_sleepduration
> dtimperiod
) {
216 HALASSERT(dtimperiod
== 0 ||
217 roundup(bs
->bs_sleepduration
, dtimperiod
) ==
218 bs
->bs_sleepduration
);
219 dtimperiod
= bs
->bs_sleepduration
;
221 HALASSERT(beaconintval
<= dtimperiod
);
222 if (beaconintval
== dtimperiod
)
223 nextTbtt
= bs
->bs_nextdtim
;
225 nextTbtt
= bs
->bs_nexttbtt
;
226 nextdtim
= bs
->bs_nextdtim
;
228 OS_REG_WRITE(ah
, AR_SLEEP1
,
229 SM((nextdtim
- SLEEP_SLOP
) << 3, AR_SLEEP1_NEXT_DTIM
)
230 | SM(CAB_TIMEOUT_VAL
, AR_SLEEP1_CAB_TIMEOUT
)
231 | AR_SLEEP1_ASSUME_DTIM
232 | AR_SLEEP1_ENH_SLEEP_ENA
234 OS_REG_WRITE(ah
, AR_SLEEP2
,
235 SM((nextTbtt
- SLEEP_SLOP
) << 3, AR_SLEEP2_NEXT_TIM
)
236 | SM(BEACON_TIMEOUT_VAL
, AR_SLEEP2_BEACON_TIMEOUT
)
238 OS_REG_WRITE(ah
, AR_SLEEP3
,
239 SM(beaconintval
, AR_SLEEP3_TIM_PERIOD
)
240 | SM(dtimperiod
, AR_SLEEP3_DTIM_PERIOD
)
242 HALDEBUG(ah
, HAL_DEBUG_BEACON
, "%s: next DTIM %d\n",
243 __func__
, bs
->bs_nextdtim
);
244 HALDEBUG(ah
, HAL_DEBUG_BEACON
, "%s: next beacon %d\n",
246 HALDEBUG(ah
, HAL_DEBUG_BEACON
, "%s: beacon period %d\n",
247 __func__
, beaconintval
);
248 HALDEBUG(ah
, HAL_DEBUG_BEACON
, "%s: DTIM period %d\n",
249 __func__
, dtimperiod
);
250 #undef CAB_TIMEOUT_VAL
251 #undef BEACON_TIMEOUT_VAL