ar5212_recv.c revision 220423
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 *
17195114Ssam * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_recv.c 220423 2011-04-07 13:14:51Z adrian $
18185377Ssam */
19185377Ssam#include "opt_ah.h"
20185377Ssam
21185377Ssam#include "ah.h"
22185377Ssam#include "ah_internal.h"
23185377Ssam
24185377Ssam#include "ar5212/ar5212.h"
25185377Ssam#include "ar5212/ar5212reg.h"
26185377Ssam#include "ar5212/ar5212desc.h"
27185377Ssam
28185377Ssam/*
29185377Ssam * Get the RXDP.
30185377Ssam */
31185377Ssamuint32_t
32185377Ssamar5212GetRxDP(struct ath_hal *ath)
33185377Ssam{
34185377Ssam	return OS_REG_READ(ath, AR_RXDP);
35185377Ssam}
36185377Ssam
37185377Ssam/*
38185377Ssam * Set the RxDP.
39185377Ssam */
40185377Ssamvoid
41185377Ssamar5212SetRxDP(struct ath_hal *ah, uint32_t rxdp)
42185377Ssam{
43185377Ssam	OS_REG_WRITE(ah, AR_RXDP, rxdp);
44185377Ssam	HALASSERT(OS_REG_READ(ah, AR_RXDP) == rxdp);
45185377Ssam}
46185377Ssam
47185377Ssam/*
48185377Ssam * Set Receive Enable bits.
49185377Ssam */
50185377Ssamvoid
51185377Ssamar5212EnableReceive(struct ath_hal *ah)
52185377Ssam{
53185377Ssam	OS_REG_WRITE(ah, AR_CR, AR_CR_RXE);
54185377Ssam}
55185377Ssam
56185377Ssam/*
57185377Ssam * Stop Receive at the DMA engine
58185377Ssam */
59185377SsamHAL_BOOL
60185377Ssamar5212StopDmaReceive(struct ath_hal *ah)
61185377Ssam{
62220423Sadrian	OS_MARK(ah, AH_MARK_RX_CTL, AH_MARK_RX_CTL_DMA_STOP);
63185377Ssam	OS_REG_WRITE(ah, AR_CR, AR_CR_RXD);	/* Set receive disable bit */
64185377Ssam	if (!ath_hal_wait(ah, AR_CR, AR_CR_RXE, 0)) {
65220423Sadrian		OS_MARK(ah, AH_MARK_RX_CTL, AH_MARK_RX_CTL_DMA_STOP_ERR);
66185377Ssam#ifdef AH_DEBUG
67185377Ssam		ath_hal_printf(ah, "%s: dma failed to stop in 10ms\n"
68185377Ssam			"AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n",
69185377Ssam			__func__,
70185377Ssam			OS_REG_READ(ah, AR_CR),
71185377Ssam			OS_REG_READ(ah, AR_DIAG_SW));
72185377Ssam#endif
73185377Ssam		return AH_FALSE;
74185377Ssam	} else {
75185377Ssam		return AH_TRUE;
76185377Ssam	}
77185377Ssam}
78185377Ssam
79185377Ssam/*
80185377Ssam * Start Transmit at the PCU engine (unpause receive)
81185377Ssam */
82185377Ssamvoid
83185377Ssamar5212StartPcuReceive(struct ath_hal *ah)
84185377Ssam{
85185377Ssam	struct ath_hal_private *ahp = AH_PRIVATE(ah);
86185377Ssam
87220423Sadrian	OS_MARK(ah, AH_MARK_RX_CTL, AH_MARK_RX_CTL_PCU_START);
88185377Ssam	OS_REG_WRITE(ah, AR_DIAG_SW,
89185377Ssam		OS_REG_READ(ah, AR_DIAG_SW) &~ AR_DIAG_RX_DIS);
90185377Ssam	ar5212EnableMibCounters(ah);
91185377Ssam	/* NB: restore current settings */
92185377Ssam	ar5212AniReset(ah, ahp->ah_curchan, ahp->ah_opmode, AH_TRUE);
93185377Ssam}
94185377Ssam
95185377Ssam/*
96185377Ssam * Stop Transmit at the PCU engine (pause receive)
97185377Ssam */
98185377Ssamvoid
99185377Ssamar5212StopPcuReceive(struct ath_hal *ah)
100185377Ssam{
101220423Sadrian	OS_MARK(ah, AH_MARK_RX_CTL, AH_MARK_RX_CTL_PCU_STOP);
102185377Ssam	OS_REG_WRITE(ah, AR_DIAG_SW,
103185377Ssam		OS_REG_READ(ah, AR_DIAG_SW) | AR_DIAG_RX_DIS);
104185377Ssam	ar5212DisableMibCounters(ah);
105185377Ssam}
106185377Ssam
107185377Ssam/*
108185377Ssam * Set multicast filter 0 (lower 32-bits)
109185377Ssam *               filter 1 (upper 32-bits)
110185377Ssam */
111185377Ssamvoid
112185377Ssamar5212SetMulticastFilter(struct ath_hal *ah, uint32_t filter0, uint32_t filter1)
113185377Ssam{
114185377Ssam	OS_REG_WRITE(ah, AR_MCAST_FIL0, filter0);
115185377Ssam	OS_REG_WRITE(ah, AR_MCAST_FIL1, filter1);
116185377Ssam}
117185377Ssam
118185377Ssam/*
119185377Ssam * Clear multicast filter by index
120185377Ssam */
121185377SsamHAL_BOOL
122185377Ssamar5212ClrMulticastFilterIndex(struct ath_hal *ah, uint32_t ix)
123185377Ssam{
124185377Ssam	uint32_t val;
125185377Ssam
126185377Ssam	if (ix >= 64)
127185377Ssam		return AH_FALSE;
128185377Ssam	if (ix >= 32) {
129185377Ssam		val = OS_REG_READ(ah, AR_MCAST_FIL1);
130185377Ssam		OS_REG_WRITE(ah, AR_MCAST_FIL1, (val &~ (1<<(ix-32))));
131185377Ssam	} else {
132185377Ssam		val = OS_REG_READ(ah, AR_MCAST_FIL0);
133185377Ssam		OS_REG_WRITE(ah, AR_MCAST_FIL0, (val &~ (1<<ix)));
134185377Ssam	}
135185377Ssam	return AH_TRUE;
136185377Ssam}
137185377Ssam
138185377Ssam/*
139185377Ssam * Set multicast filter by index
140185377Ssam */
141185377SsamHAL_BOOL
142185377Ssamar5212SetMulticastFilterIndex(struct ath_hal *ah, uint32_t ix)
143185377Ssam{
144185377Ssam	uint32_t val;
145185377Ssam
146185377Ssam	if (ix >= 64)
147185377Ssam		return AH_FALSE;
148185377Ssam	if (ix >= 32) {
149185377Ssam		val = OS_REG_READ(ah, AR_MCAST_FIL1);
150185377Ssam		OS_REG_WRITE(ah, AR_MCAST_FIL1, (val | (1<<(ix-32))));
151185377Ssam	} else {
152185377Ssam		val = OS_REG_READ(ah, AR_MCAST_FIL0);
153185377Ssam		OS_REG_WRITE(ah, AR_MCAST_FIL0, (val | (1<<ix)));
154185377Ssam	}
155185377Ssam	return AH_TRUE;
156185377Ssam}
157185377Ssam
158185377Ssam/*
159185377Ssam * Get the receive filter.
160185377Ssam */
161185377Ssamuint32_t
162185377Ssamar5212GetRxFilter(struct ath_hal *ah)
163185377Ssam{
164185377Ssam	uint32_t bits = OS_REG_READ(ah, AR_RX_FILTER);
165185377Ssam	uint32_t phybits = OS_REG_READ(ah, AR_PHY_ERR);
166185377Ssam	if (phybits & AR_PHY_ERR_RADAR)
167185377Ssam		bits |= HAL_RX_FILTER_PHYRADAR;
168185377Ssam	if (phybits & (AR_PHY_ERR_OFDM_TIMING|AR_PHY_ERR_CCK_TIMING))
169185377Ssam		bits |= HAL_RX_FILTER_PHYERR;
170195114Ssam	if (AH_PRIVATE(ah)->ah_caps.halBssidMatchSupport &&
171195809Ssam	    (AH5212(ah)->ah_miscMode & AR_MISC_MODE_BSSID_MATCH_FORCE))
172195114Ssam		bits |= HAL_RX_FILTER_BSSID;
173185377Ssam	return bits;
174185377Ssam}
175185377Ssam
176185377Ssam/*
177185377Ssam * Set the receive filter.
178185377Ssam */
179185377Ssamvoid
180185377Ssamar5212SetRxFilter(struct ath_hal *ah, uint32_t bits)
181185377Ssam{
182195809Ssam	struct ath_hal_5212 *ahp = AH5212(ah);
183185377Ssam	uint32_t phybits;
184185377Ssam
185185377Ssam	OS_REG_WRITE(ah, AR_RX_FILTER,
186195114Ssam	    bits &~ (HAL_RX_FILTER_PHYRADAR|HAL_RX_FILTER_PHYERR|
187195114Ssam	    HAL_RX_FILTER_BSSID));
188185377Ssam	phybits = 0;
189185377Ssam	if (bits & HAL_RX_FILTER_PHYRADAR)
190185377Ssam		phybits |= AR_PHY_ERR_RADAR;
191185377Ssam	if (bits & HAL_RX_FILTER_PHYERR)
192185377Ssam		phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING;
193185377Ssam	OS_REG_WRITE(ah, AR_PHY_ERR, phybits);
194185377Ssam	if (phybits) {
195185377Ssam		OS_REG_WRITE(ah, AR_RXCFG,
196185377Ssam			OS_REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA);
197185377Ssam	} else {
198185377Ssam		OS_REG_WRITE(ah, AR_RXCFG,
199185377Ssam			OS_REG_READ(ah, AR_RXCFG) &~ AR_RXCFG_ZLFDMA);
200185377Ssam	}
201195114Ssam	if (AH_PRIVATE(ah)->ah_caps.halBssidMatchSupport) {
202195114Ssam		if (bits & HAL_RX_FILTER_BSSID)
203195809Ssam			ahp->ah_miscMode |= AR_MISC_MODE_BSSID_MATCH_FORCE;
204195114Ssam		else
205195809Ssam			ahp->ah_miscMode &= ~AR_MISC_MODE_BSSID_MATCH_FORCE;
206219771Sadrian		OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE) | ahp->ah_miscMode);
207195114Ssam	}
208185377Ssam}
209185377Ssam
210185377Ssam/*
211185377Ssam * Initialize RX descriptor, by clearing the status and setting
212185377Ssam * the size (and any other flags).
213185377Ssam */
214185377SsamHAL_BOOL
215185377Ssamar5212SetupRxDesc(struct ath_hal *ah, struct ath_desc *ds,
216185377Ssam	uint32_t size, u_int flags)
217185377Ssam{
218185377Ssam	struct ar5212_desc *ads = AR5212DESC(ds);
219185377Ssam
220185377Ssam	HALASSERT((size &~ AR_BufLen) == 0);
221185377Ssam
222185377Ssam	ads->ds_ctl0 = 0;
223185377Ssam	ads->ds_ctl1 = size & AR_BufLen;
224185377Ssam
225185377Ssam	if (flags & HAL_RXDESC_INTREQ)
226185377Ssam		ads->ds_ctl1 |= AR_RxInterReq;
227185377Ssam	ads->ds_rxstatus0 = ads->ds_rxstatus1 = 0;
228185377Ssam
229185377Ssam	return AH_TRUE;
230185377Ssam}
231185377Ssam
232185377Ssam/*
233185377Ssam * Process an RX descriptor, and return the status to the caller.
234185377Ssam * Copy some hardware specific items into the software portion
235185377Ssam * of the descriptor.
236185377Ssam *
237185377Ssam * NB: the caller is responsible for validating the memory contents
238185377Ssam *     of the descriptor (e.g. flushing any cached copy).
239185377Ssam */
240185377SsamHAL_STATUS
241185377Ssamar5212ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds,
242185377Ssam	uint32_t pa, struct ath_desc *nds, uint64_t tsf,
243185377Ssam	struct ath_rx_status *rs)
244185377Ssam{
245185377Ssam	struct ar5212_desc *ads = AR5212DESC(ds);
246185377Ssam	struct ar5212_desc *ands = AR5212DESC(nds);
247185377Ssam
248185377Ssam	if ((ads->ds_rxstatus1 & AR_Done) == 0)
249185377Ssam		return HAL_EINPROGRESS;
250185377Ssam	/*
251185377Ssam	 * Given the use of a self-linked tail be very sure that the hw is
252185377Ssam	 * done with this descriptor; the hw may have done this descriptor
253185377Ssam	 * once and picked it up again...make sure the hw has moved on.
254185377Ssam	 */
255185377Ssam	if ((ands->ds_rxstatus1&AR_Done) == 0 && OS_REG_READ(ah, AR_RXDP) == pa)
256185377Ssam		return HAL_EINPROGRESS;
257185377Ssam
258185377Ssam	rs->rs_datalen = ads->ds_rxstatus0 & AR_DataLen;
259185377Ssam	rs->rs_tstamp = MS(ads->ds_rxstatus1, AR_RcvTimestamp);
260185377Ssam	rs->rs_status = 0;
261185377Ssam	/* XXX what about KeyCacheMiss? */
262185377Ssam	rs->rs_rssi = MS(ads->ds_rxstatus0, AR_RcvSigStrength);
263185377Ssam	/* discard invalid h/w rssi data */
264185377Ssam	if (rs->rs_rssi == -128)
265185377Ssam		rs->rs_rssi = 0;
266185377Ssam	if (ads->ds_rxstatus1 & AR_KeyIdxValid)
267185377Ssam		rs->rs_keyix = MS(ads->ds_rxstatus1, AR_KeyIdx);
268185377Ssam	else
269185377Ssam		rs->rs_keyix = HAL_RXKEYIX_INVALID;
270185377Ssam	/* NB: caller expected to do rate table mapping */
271185377Ssam	rs->rs_rate = MS(ads->ds_rxstatus0, AR_RcvRate);
272185377Ssam	rs->rs_antenna  = MS(ads->ds_rxstatus0, AR_RcvAntenna);
273185377Ssam	rs->rs_more = (ads->ds_rxstatus0 & AR_More) ? 1 : 0;
274185377Ssam
275185377Ssam	if ((ads->ds_rxstatus1 & AR_FrmRcvOK) == 0) {
276185377Ssam		/*
277185377Ssam		 * These four bits should not be set together.  The
278185377Ssam		 * 5212 spec states a Michael error can only occur if
279185377Ssam		 * DecryptCRCErr not set (and TKIP is used).  Experience
280185377Ssam		 * indicates however that you can also get Michael errors
281185377Ssam		 * when a CRC error is detected, but these are specious.
282185377Ssam		 * Consequently we filter them out here so we don't
283185377Ssam		 * confuse and/or complicate drivers.
284185377Ssam		 */
285185377Ssam		if (ads->ds_rxstatus1 & AR_CRCErr)
286185377Ssam			rs->rs_status |= HAL_RXERR_CRC;
287185377Ssam		else if (ads->ds_rxstatus1 & AR_PHYErr) {
288185377Ssam			u_int phyerr;
289185377Ssam
290185377Ssam			rs->rs_status |= HAL_RXERR_PHY;
291185377Ssam			phyerr = MS(ads->ds_rxstatus1, AR_PHYErrCode);
292185377Ssam			rs->rs_phyerr = phyerr;
293185377Ssam			if (!AH5212(ah)->ah_hasHwPhyCounters &&
294185377Ssam			    phyerr != HAL_PHYERR_RADAR)
295185377Ssam				ar5212AniPhyErrReport(ah, rs);
296185377Ssam		} else if (ads->ds_rxstatus1 & AR_DecryptCRCErr)
297185377Ssam			rs->rs_status |= HAL_RXERR_DECRYPT;
298185377Ssam		else if (ads->ds_rxstatus1 & AR_MichaelErr)
299185377Ssam			rs->rs_status |= HAL_RXERR_MIC;
300185377Ssam	}
301185377Ssam	return HAL_OK;
302185377Ssam}
303