ar5210_beacon.c revision 223459
1185377Ssam/*
2185377Ssam * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3185377Ssam * Copyright (c) 2002-2004 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 *
17204644Srpaulo * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c 223459 2011-06-23 02:38:36Z adrian $
18185377Ssam */
19185377Ssam#include "opt_ah.h"
20185377Ssam
21185377Ssam#include "ah.h"
22185377Ssam#include "ah_internal.h"
23185377Ssam#include "ah_desc.h"
24185377Ssam
25185377Ssam#include "ar5210/ar5210.h"
26185377Ssam#include "ar5210/ar5210reg.h"
27185377Ssam#include "ar5210/ar5210desc.h"
28185377Ssam
29185377Ssam/*
30185377Ssam * Initialize all of the hardware registers used to send beacons.
31185377Ssam */
32185377Ssamvoid
33185377Ssamar5210SetBeaconTimers(struct ath_hal *ah, const HAL_BEACON_TIMERS *bt)
34185377Ssam{
35185377Ssam
36185377Ssam	OS_REG_WRITE(ah, AR_TIMER0, bt->bt_nexttbtt);
37185377Ssam	OS_REG_WRITE(ah, AR_TIMER1, bt->bt_nextdba);
38185377Ssam	OS_REG_WRITE(ah, AR_TIMER2, bt->bt_nextswba);
39185377Ssam	OS_REG_WRITE(ah, AR_TIMER3, bt->bt_nextatim);
40185377Ssam	/*
41185377Ssam	 * Set the Beacon register after setting all timers.
42185377Ssam	 */
43185377Ssam	OS_REG_WRITE(ah, AR_BEACON, bt->bt_intval);
44185377Ssam}
45185377Ssam
46185377Ssam/*
47185377Ssam * Legacy api to Initialize all of the beacon registers.
48185377Ssam */
49185377Ssamvoid
50185377Ssamar5210BeaconInit(struct ath_hal *ah,
51185377Ssam	uint32_t next_beacon, uint32_t beacon_period)
52185377Ssam{
53185377Ssam	HAL_BEACON_TIMERS bt;
54185377Ssam
55185377Ssam	bt.bt_nexttbtt = next_beacon;
56185377Ssam
57185377Ssam	if (AH_PRIVATE(ah)->ah_opmode != HAL_M_STA) {
58185377Ssam		bt.bt_nextdba = (next_beacon -
59223459Sadrian			ah->ah_config.ah_dma_beacon_response_time) << 3; /* 1/8 TU */
60185377Ssam		bt.bt_nextswba = (next_beacon -
61223459Sadrian            ah->ah_config.ah_sw_beacon_response_time) << 3;	/* 1/8 TU */
62185377Ssam		/*
63185377Ssam		 * The SWBA interrupt is not used for beacons in ad hoc mode
64185377Ssam		 * as we don't yet support ATIMs. So since the beacon never
65185377Ssam		 * changes, the beacon descriptor is set up once and read
66185377Ssam		 * into a special HW buffer, from which it will be
67185377Ssam		 * automagically retrieved at each DMA Beacon Alert (DBA).
68185377Ssam		 */
69185377Ssam
70185377Ssam		/* Set the ATIM window */
71185377Ssam		bt.bt_nextatim = next_beacon + 0;	/* NB: no ATIMs */
72185377Ssam	} else {
73185377Ssam		bt.bt_nextdba = ~0;
74185377Ssam		bt.bt_nextswba = ~0;
75185377Ssam		bt.bt_nextatim = 1;
76185377Ssam	}
77185377Ssam	bt.bt_intval = beacon_period &
78185377Ssam		(AR_BEACON_PERIOD | AR_BEACON_RESET_TSF | AR_BEACON_EN);
79185377Ssam	ar5210SetBeaconTimers(ah, &bt);
80185377Ssam}
81185377Ssam
82185377Ssamvoid
83185377Ssamar5210ResetStaBeaconTimers(struct ath_hal *ah)
84185377Ssam{
85185377Ssam	uint32_t val;
86185377Ssam
87185377Ssam	OS_REG_WRITE(ah, AR_TIMER0, 0);		/* no beacons */
88185377Ssam	val = OS_REG_READ(ah, AR_STA_ID1);
89185377Ssam	val |= AR_STA_ID1_NO_PSPOLL;		/* XXX */
90185377Ssam	/* tell the h/w that the associated AP is not PCF capable */
91185377Ssam	OS_REG_WRITE(ah, AR_STA_ID1,
92185377Ssam		val & ~(AR_STA_ID1_DEFAULT_ANTENNA | AR_STA_ID1_PCF));
93185377Ssam	OS_REG_WRITE(ah, AR_BEACON, AR_BEACON_PERIOD);
94185377Ssam}
95185377Ssam
96185377Ssam/*
97185377Ssam * Set all the beacon related bits on the h/w for stations
98185377Ssam * i.e. initializes the corresponding h/w timers;
99185377Ssam * also tells the h/w whether to anticipate PCF beacons
100185377Ssam *
101185377Ssam * dtim_count and cfp_count from the current beacon - their current
102185377Ssam * values aren't necessarily maintained in the device struct
103185377Ssam */
104185377Ssamvoid
105185377Ssamar5210SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs)
106185377Ssam{
107185377Ssam	struct ath_hal_5210 *ahp = AH5210(ah);
108185377Ssam
109185377Ssam	HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: setting beacon timers\n", __func__);
110185377Ssam
111185377Ssam	HALASSERT(bs->bs_intval != 0);
112185377Ssam	/* if the AP will do PCF */
113185377Ssam	if (bs->bs_cfpmaxduration != 0) {
114185377Ssam		/* tell the h/w that the associated AP is PCF capable */
115185377Ssam		OS_REG_WRITE(ah, AR_STA_ID1,
116185377Ssam			(OS_REG_READ(ah, AR_STA_ID1) &~ AR_STA_ID1_DEFAULT_ANTENNA)
117185377Ssam			| AR_STA_ID1_PCF);
118185377Ssam
119185377Ssam		/* set CFP_PERIOD(1.024ms) register */
120185377Ssam		OS_REG_WRITE(ah, AR_CFP_PERIOD, bs->bs_cfpperiod);
121185377Ssam
122185377Ssam		/* set CFP_DUR(1.024ms) register to max cfp duration */
123185377Ssam		OS_REG_WRITE(ah, AR_CFP_DUR, bs->bs_cfpmaxduration);
124185377Ssam
125185377Ssam		/* set TIMER2(128us) to anticipated time of next CFP */
126185377Ssam		OS_REG_WRITE(ah, AR_TIMER2, bs->bs_cfpnext << 3);
127185377Ssam	} else {
128185377Ssam		/* tell the h/w that the associated AP is not PCF capable */
129185377Ssam		OS_REG_WRITE(ah, AR_STA_ID1,
130185377Ssam			OS_REG_READ(ah, AR_STA_ID1) &~ (AR_STA_ID1_DEFAULT_ANTENNA | AR_STA_ID1_PCF));
131185377Ssam	}
132185377Ssam
133185377Ssam	/*
134185377Ssam	 * Set TIMER0(1.024ms) to the anticipated time of the next beacon.
135185377Ssam	 */
136185377Ssam	OS_REG_WRITE(ah, AR_TIMER0, bs->bs_nexttbtt);
137185377Ssam
138185377Ssam	/*
139185377Ssam	 * Start the beacon timers by setting the BEACON register
140185377Ssam	 * to the beacon interval; also write the tim offset which
141185377Ssam	 * we should know by now.  The code, in ar5211WriteAssocid,
142185377Ssam	 * also sets the tim offset once the AID is known which can
143185377Ssam	 * be left as such for now.
144185377Ssam	 */
145185377Ssam	OS_REG_WRITE(ah, AR_BEACON,
146185377Ssam		(OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_PERIOD|AR_BEACON_TIM))
147185377Ssam		| SM(bs->bs_intval, AR_BEACON_PERIOD)
148185377Ssam		| SM(bs->bs_timoffset ? bs->bs_timoffset + 4 : 0, AR_BEACON_TIM)
149185377Ssam	);
150185377Ssam
151185377Ssam	/*
152185377Ssam	 * Configure the BMISS interrupt.  Note that we
153185377Ssam	 * assume the caller blocks interrupts while enabling
154185377Ssam	 * the threshold.
155185377Ssam	 */
156185377Ssam
157185377Ssam	/*
158185377Ssam	 * Interrupt works only on Crete.
159185377Ssam	 */
160185377Ssam	if (AH_PRIVATE(ah)->ah_macRev < AR_SREV_CRETE)
161185377Ssam		return;
162185377Ssam	/*
163185377Ssam	 * Counter is only 3-bits.
164185377Ssam	 * Count of 0 with BMISS interrupt enabled will hang the system
165185377Ssam	 * with too many interrupts
166185377Ssam	 */
167185377Ssam	if (AH_PRIVATE(ah)->ah_macRev >= AR_SREV_CRETE &&
168185377Ssam	    (bs->bs_bmissthreshold&7) == 0) {
169185377Ssam#ifdef AH_DEBUG
170185377Ssam		ath_hal_printf(ah, "%s: invalid beacon miss threshold %u\n",
171185377Ssam			__func__, bs->bs_bmissthreshold);
172185377Ssam#endif
173185377Ssam		return;
174185377Ssam	}
175185377Ssam#define	BMISS_MAX	(AR_RSSI_THR_BM_THR >> AR_RSSI_THR_BM_THR_S)
176185377Ssam	/*
177185377Ssam	 * Configure the BMISS interrupt.  Note that we
178185377Ssam	 * assume the caller blocks interrupts while enabling
179185377Ssam	 * the threshold.
180185377Ssam	 *
181185377Ssam	 * NB: the beacon miss count field is only 3 bits which
182185377Ssam	 *     is much smaller than what's found on later parts;
183185377Ssam	 *     clamp overflow values as a safeguard.
184185377Ssam	 */
185185377Ssam	ahp->ah_rssiThr = (ahp->ah_rssiThr &~ AR_RSSI_THR_BM_THR)
186185377Ssam			| SM(bs->bs_bmissthreshold > BMISS_MAX ?
187185377Ssam				BMISS_MAX : bs->bs_bmissthreshold,
188185377Ssam			     AR_RSSI_THR_BM_THR);
189185377Ssam	OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr);
190185377Ssam#undef BMISS_MAX
191185377Ssam}
192