ar5212_recv.c revision 219771
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 219771 2011-03-19 03:15:28Z 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{
62185377Ssam	OS_REG_WRITE(ah, AR_CR, AR_CR_RXD);	/* Set receive disable bit */
63185377Ssam	if (!ath_hal_wait(ah, AR_CR, AR_CR_RXE, 0)) {
64185377Ssam#ifdef AH_DEBUG
65185377Ssam		ath_hal_printf(ah, "%s: dma failed to stop in 10ms\n"
66185377Ssam			"AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n",
67185377Ssam			__func__,
68185377Ssam			OS_REG_READ(ah, AR_CR),
69185377Ssam			OS_REG_READ(ah, AR_DIAG_SW));
70185377Ssam#endif
71185377Ssam		return AH_FALSE;
72185377Ssam	} else {
73185377Ssam		return AH_TRUE;
74185377Ssam	}
75185377Ssam}
76185377Ssam
77185377Ssam/*
78185377Ssam * Start Transmit at the PCU engine (unpause receive)
79185377Ssam */
80185377Ssamvoid
81185377Ssamar5212StartPcuReceive(struct ath_hal *ah)
82185377Ssam{
83185377Ssam	struct ath_hal_private *ahp = AH_PRIVATE(ah);
84185377Ssam
85185377Ssam	OS_REG_WRITE(ah, AR_DIAG_SW,
86185377Ssam		OS_REG_READ(ah, AR_DIAG_SW) &~ AR_DIAG_RX_DIS);
87185377Ssam	ar5212EnableMibCounters(ah);
88185377Ssam	/* NB: restore current settings */
89185377Ssam	ar5212AniReset(ah, ahp->ah_curchan, ahp->ah_opmode, AH_TRUE);
90185377Ssam}
91185377Ssam
92185377Ssam/*
93185377Ssam * Stop Transmit at the PCU engine (pause receive)
94185377Ssam */
95185377Ssamvoid
96185377Ssamar5212StopPcuReceive(struct ath_hal *ah)
97185377Ssam{
98185377Ssam	OS_REG_WRITE(ah, AR_DIAG_SW,
99185377Ssam		OS_REG_READ(ah, AR_DIAG_SW) | AR_DIAG_RX_DIS);
100185377Ssam	ar5212DisableMibCounters(ah);
101185377Ssam}
102185377Ssam
103185377Ssam/*
104185377Ssam * Set multicast filter 0 (lower 32-bits)
105185377Ssam *               filter 1 (upper 32-bits)
106185377Ssam */
107185377Ssamvoid
108185377Ssamar5212SetMulticastFilter(struct ath_hal *ah, uint32_t filter0, uint32_t filter1)
109185377Ssam{
110185377Ssam	OS_REG_WRITE(ah, AR_MCAST_FIL0, filter0);
111185377Ssam	OS_REG_WRITE(ah, AR_MCAST_FIL1, filter1);
112185377Ssam}
113185377Ssam
114185377Ssam/*
115185377Ssam * Clear multicast filter by index
116185377Ssam */
117185377SsamHAL_BOOL
118185377Ssamar5212ClrMulticastFilterIndex(struct ath_hal *ah, uint32_t ix)
119185377Ssam{
120185377Ssam	uint32_t val;
121185377Ssam
122185377Ssam	if (ix >= 64)
123185377Ssam		return AH_FALSE;
124185377Ssam	if (ix >= 32) {
125185377Ssam		val = OS_REG_READ(ah, AR_MCAST_FIL1);
126185377Ssam		OS_REG_WRITE(ah, AR_MCAST_FIL1, (val &~ (1<<(ix-32))));
127185377Ssam	} else {
128185377Ssam		val = OS_REG_READ(ah, AR_MCAST_FIL0);
129185377Ssam		OS_REG_WRITE(ah, AR_MCAST_FIL0, (val &~ (1<<ix)));
130185377Ssam	}
131185377Ssam	return AH_TRUE;
132185377Ssam}
133185377Ssam
134185377Ssam/*
135185377Ssam * Set multicast filter by index
136185377Ssam */
137185377SsamHAL_BOOL
138185377Ssamar5212SetMulticastFilterIndex(struct ath_hal *ah, uint32_t ix)
139185377Ssam{
140185377Ssam	uint32_t val;
141185377Ssam
142185377Ssam	if (ix >= 64)
143185377Ssam		return AH_FALSE;
144185377Ssam	if (ix >= 32) {
145185377Ssam		val = OS_REG_READ(ah, AR_MCAST_FIL1);
146185377Ssam		OS_REG_WRITE(ah, AR_MCAST_FIL1, (val | (1<<(ix-32))));
147185377Ssam	} else {
148185377Ssam		val = OS_REG_READ(ah, AR_MCAST_FIL0);
149185377Ssam		OS_REG_WRITE(ah, AR_MCAST_FIL0, (val | (1<<ix)));
150185377Ssam	}
151185377Ssam	return AH_TRUE;
152185377Ssam}
153185377Ssam
154185377Ssam/*
155185377Ssam * Get the receive filter.
156185377Ssam */
157185377Ssamuint32_t
158185377Ssamar5212GetRxFilter(struct ath_hal *ah)
159185377Ssam{
160185377Ssam	uint32_t bits = OS_REG_READ(ah, AR_RX_FILTER);
161185377Ssam	uint32_t phybits = OS_REG_READ(ah, AR_PHY_ERR);
162185377Ssam	if (phybits & AR_PHY_ERR_RADAR)
163185377Ssam		bits |= HAL_RX_FILTER_PHYRADAR;
164185377Ssam	if (phybits & (AR_PHY_ERR_OFDM_TIMING|AR_PHY_ERR_CCK_TIMING))
165185377Ssam		bits |= HAL_RX_FILTER_PHYERR;
166195114Ssam	if (AH_PRIVATE(ah)->ah_caps.halBssidMatchSupport &&
167195809Ssam	    (AH5212(ah)->ah_miscMode & AR_MISC_MODE_BSSID_MATCH_FORCE))
168195114Ssam		bits |= HAL_RX_FILTER_BSSID;
169185377Ssam	return bits;
170185377Ssam}
171185377Ssam
172185377Ssam/*
173185377Ssam * Set the receive filter.
174185377Ssam */
175185377Ssamvoid
176185377Ssamar5212SetRxFilter(struct ath_hal *ah, uint32_t bits)
177185377Ssam{
178195809Ssam	struct ath_hal_5212 *ahp = AH5212(ah);
179185377Ssam	uint32_t phybits;
180185377Ssam
181185377Ssam	OS_REG_WRITE(ah, AR_RX_FILTER,
182195114Ssam	    bits &~ (HAL_RX_FILTER_PHYRADAR|HAL_RX_FILTER_PHYERR|
183195114Ssam	    HAL_RX_FILTER_BSSID));
184185377Ssam	phybits = 0;
185185377Ssam	if (bits & HAL_RX_FILTER_PHYRADAR)
186185377Ssam		phybits |= AR_PHY_ERR_RADAR;
187185377Ssam	if (bits & HAL_RX_FILTER_PHYERR)
188185377Ssam		phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING;
189185377Ssam	OS_REG_WRITE(ah, AR_PHY_ERR, phybits);
190185377Ssam	if (phybits) {
191185377Ssam		OS_REG_WRITE(ah, AR_RXCFG,
192185377Ssam			OS_REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA);
193185377Ssam	} else {
194185377Ssam		OS_REG_WRITE(ah, AR_RXCFG,
195185377Ssam			OS_REG_READ(ah, AR_RXCFG) &~ AR_RXCFG_ZLFDMA);
196185377Ssam	}
197195114Ssam	if (AH_PRIVATE(ah)->ah_caps.halBssidMatchSupport) {
198195114Ssam		if (bits & HAL_RX_FILTER_BSSID)
199195809Ssam			ahp->ah_miscMode |= AR_MISC_MODE_BSSID_MATCH_FORCE;
200195114Ssam		else
201195809Ssam			ahp->ah_miscMode &= ~AR_MISC_MODE_BSSID_MATCH_FORCE;
202219771Sadrian		OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE) | ahp->ah_miscMode);
203195114Ssam	}
204185377Ssam}
205185377Ssam
206185377Ssam/*
207185377Ssam * Initialize RX descriptor, by clearing the status and setting
208185377Ssam * the size (and any other flags).
209185377Ssam */
210185377SsamHAL_BOOL
211185377Ssamar5212SetupRxDesc(struct ath_hal *ah, struct ath_desc *ds,
212185377Ssam	uint32_t size, u_int flags)
213185377Ssam{
214185377Ssam	struct ar5212_desc *ads = AR5212DESC(ds);
215185377Ssam
216185377Ssam	HALASSERT((size &~ AR_BufLen) == 0);
217185377Ssam
218185377Ssam	ads->ds_ctl0 = 0;
219185377Ssam	ads->ds_ctl1 = size & AR_BufLen;
220185377Ssam
221185377Ssam	if (flags & HAL_RXDESC_INTREQ)
222185377Ssam		ads->ds_ctl1 |= AR_RxInterReq;
223185377Ssam	ads->ds_rxstatus0 = ads->ds_rxstatus1 = 0;
224185377Ssam
225185377Ssam	return AH_TRUE;
226185377Ssam}
227185377Ssam
228185377Ssam/*
229185377Ssam * Process an RX descriptor, and return the status to the caller.
230185377Ssam * Copy some hardware specific items into the software portion
231185377Ssam * of the descriptor.
232185377Ssam *
233185377Ssam * NB: the caller is responsible for validating the memory contents
234185377Ssam *     of the descriptor (e.g. flushing any cached copy).
235185377Ssam */
236185377SsamHAL_STATUS
237185377Ssamar5212ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds,
238185377Ssam	uint32_t pa, struct ath_desc *nds, uint64_t tsf,
239185377Ssam	struct ath_rx_status *rs)
240185377Ssam{
241185377Ssam	struct ar5212_desc *ads = AR5212DESC(ds);
242185377Ssam	struct ar5212_desc *ands = AR5212DESC(nds);
243185377Ssam
244185377Ssam	if ((ads->ds_rxstatus1 & AR_Done) == 0)
245185377Ssam		return HAL_EINPROGRESS;
246185377Ssam	/*
247185377Ssam	 * Given the use of a self-linked tail be very sure that the hw is
248185377Ssam	 * done with this descriptor; the hw may have done this descriptor
249185377Ssam	 * once and picked it up again...make sure the hw has moved on.
250185377Ssam	 */
251185377Ssam	if ((ands->ds_rxstatus1&AR_Done) == 0 && OS_REG_READ(ah, AR_RXDP) == pa)
252185377Ssam		return HAL_EINPROGRESS;
253185377Ssam
254185377Ssam	rs->rs_datalen = ads->ds_rxstatus0 & AR_DataLen;
255185377Ssam	rs->rs_tstamp = MS(ads->ds_rxstatus1, AR_RcvTimestamp);
256185377Ssam	rs->rs_status = 0;
257185377Ssam	/* XXX what about KeyCacheMiss? */
258185377Ssam	rs->rs_rssi = MS(ads->ds_rxstatus0, AR_RcvSigStrength);
259185377Ssam	/* discard invalid h/w rssi data */
260185377Ssam	if (rs->rs_rssi == -128)
261185377Ssam		rs->rs_rssi = 0;
262185377Ssam	if (ads->ds_rxstatus1 & AR_KeyIdxValid)
263185377Ssam		rs->rs_keyix = MS(ads->ds_rxstatus1, AR_KeyIdx);
264185377Ssam	else
265185377Ssam		rs->rs_keyix = HAL_RXKEYIX_INVALID;
266185377Ssam	/* NB: caller expected to do rate table mapping */
267185377Ssam	rs->rs_rate = MS(ads->ds_rxstatus0, AR_RcvRate);
268185377Ssam	rs->rs_antenna  = MS(ads->ds_rxstatus0, AR_RcvAntenna);
269185377Ssam	rs->rs_more = (ads->ds_rxstatus0 & AR_More) ? 1 : 0;
270185377Ssam
271185377Ssam	if ((ads->ds_rxstatus1 & AR_FrmRcvOK) == 0) {
272185377Ssam		/*
273185377Ssam		 * These four bits should not be set together.  The
274185377Ssam		 * 5212 spec states a Michael error can only occur if
275185377Ssam		 * DecryptCRCErr not set (and TKIP is used).  Experience
276185377Ssam		 * indicates however that you can also get Michael errors
277185377Ssam		 * when a CRC error is detected, but these are specious.
278185377Ssam		 * Consequently we filter them out here so we don't
279185377Ssam		 * confuse and/or complicate drivers.
280185377Ssam		 */
281185377Ssam		if (ads->ds_rxstatus1 & AR_CRCErr)
282185377Ssam			rs->rs_status |= HAL_RXERR_CRC;
283185377Ssam		else if (ads->ds_rxstatus1 & AR_PHYErr) {
284185377Ssam			u_int phyerr;
285185377Ssam
286185377Ssam			rs->rs_status |= HAL_RXERR_PHY;
287185377Ssam			phyerr = MS(ads->ds_rxstatus1, AR_PHYErrCode);
288185377Ssam			rs->rs_phyerr = phyerr;
289185377Ssam			if (!AH5212(ah)->ah_hasHwPhyCounters &&
290185377Ssam			    phyerr != HAL_PHYERR_RADAR)
291185377Ssam				ar5212AniPhyErrReport(ah, rs);
292185377Ssam		} else if (ads->ds_rxstatus1 & AR_DecryptCRCErr)
293185377Ssam			rs->rs_status |= HAL_RXERR_DECRYPT;
294185377Ssam		else if (ads->ds_rxstatus1 & AR_MichaelErr)
295185377Ssam			rs->rs_status |= HAL_RXERR_MIC;
296185377Ssam	}
297185377Ssam	return HAL_OK;
298185377Ssam}
299