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$
18185377Ssam */
19185377Ssam#include "opt_ah.h"
20185377Ssam
21185377Ssam#include "ah.h"
22185377Ssam#include "ah_internal.h"
23243169Sadrian#include "ah_desc.h"
24185377Ssam
25185377Ssam#include "ar5212/ar5212.h"
26185377Ssam#include "ar5212/ar5212reg.h"
27185377Ssam#include "ar5212/ar5212desc.h"
28185377Ssam
29185377Ssam/*
30185377Ssam * Get the RXDP.
31185377Ssam */
32185377Ssamuint32_t
33238278Sadrianar5212GetRxDP(struct ath_hal *ath, HAL_RX_QUEUE qtype)
34185377Ssam{
35238278Sadrian
36238278Sadrian	HALASSERT(qtype == HAL_RX_QUEUE_HP);
37185377Ssam	return OS_REG_READ(ath, AR_RXDP);
38185377Ssam}
39185377Ssam
40185377Ssam/*
41185377Ssam * Set the RxDP.
42185377Ssam */
43185377Ssamvoid
44238278Sadrianar5212SetRxDP(struct ath_hal *ah, uint32_t rxdp, HAL_RX_QUEUE qtype)
45185377Ssam{
46238278Sadrian
47238278Sadrian	HALASSERT(qtype == HAL_RX_QUEUE_HP);
48185377Ssam	OS_REG_WRITE(ah, AR_RXDP, rxdp);
49185377Ssam	HALASSERT(OS_REG_READ(ah, AR_RXDP) == rxdp);
50185377Ssam}
51185377Ssam
52185377Ssam/*
53185377Ssam * Set Receive Enable bits.
54185377Ssam */
55185377Ssamvoid
56185377Ssamar5212EnableReceive(struct ath_hal *ah)
57185377Ssam{
58185377Ssam	OS_REG_WRITE(ah, AR_CR, AR_CR_RXE);
59185377Ssam}
60185377Ssam
61185377Ssam/*
62185377Ssam * Stop Receive at the DMA engine
63185377Ssam */
64185377SsamHAL_BOOL
65185377Ssamar5212StopDmaReceive(struct ath_hal *ah)
66185377Ssam{
67220423Sadrian	OS_MARK(ah, AH_MARK_RX_CTL, AH_MARK_RX_CTL_DMA_STOP);
68185377Ssam	OS_REG_WRITE(ah, AR_CR, AR_CR_RXD);	/* Set receive disable bit */
69185377Ssam	if (!ath_hal_wait(ah, AR_CR, AR_CR_RXE, 0)) {
70220423Sadrian		OS_MARK(ah, AH_MARK_RX_CTL, AH_MARK_RX_CTL_DMA_STOP_ERR);
71185377Ssam#ifdef AH_DEBUG
72185377Ssam		ath_hal_printf(ah, "%s: dma failed to stop in 10ms\n"
73185377Ssam			"AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n",
74185377Ssam			__func__,
75185377Ssam			OS_REG_READ(ah, AR_CR),
76185377Ssam			OS_REG_READ(ah, AR_DIAG_SW));
77185377Ssam#endif
78185377Ssam		return AH_FALSE;
79185377Ssam	} else {
80185377Ssam		return AH_TRUE;
81185377Ssam	}
82185377Ssam}
83185377Ssam
84185377Ssam/*
85185377Ssam * Start Transmit at the PCU engine (unpause receive)
86185377Ssam */
87185377Ssamvoid
88185377Ssamar5212StartPcuReceive(struct ath_hal *ah)
89185377Ssam{
90185377Ssam	struct ath_hal_private *ahp = AH_PRIVATE(ah);
91185377Ssam
92220423Sadrian	OS_MARK(ah, AH_MARK_RX_CTL, AH_MARK_RX_CTL_PCU_START);
93185377Ssam	OS_REG_WRITE(ah, AR_DIAG_SW,
94185377Ssam		OS_REG_READ(ah, AR_DIAG_SW) &~ AR_DIAG_RX_DIS);
95185377Ssam	ar5212EnableMibCounters(ah);
96185377Ssam	/* NB: restore current settings */
97185377Ssam	ar5212AniReset(ah, ahp->ah_curchan, ahp->ah_opmode, AH_TRUE);
98185377Ssam}
99185377Ssam
100185377Ssam/*
101185377Ssam * Stop Transmit at the PCU engine (pause receive)
102185377Ssam */
103185377Ssamvoid
104185377Ssamar5212StopPcuReceive(struct ath_hal *ah)
105185377Ssam{
106220423Sadrian	OS_MARK(ah, AH_MARK_RX_CTL, AH_MARK_RX_CTL_PCU_STOP);
107185377Ssam	OS_REG_WRITE(ah, AR_DIAG_SW,
108185377Ssam		OS_REG_READ(ah, AR_DIAG_SW) | AR_DIAG_RX_DIS);
109185377Ssam	ar5212DisableMibCounters(ah);
110185377Ssam}
111185377Ssam
112185377Ssam/*
113185377Ssam * Set multicast filter 0 (lower 32-bits)
114185377Ssam *               filter 1 (upper 32-bits)
115185377Ssam */
116185377Ssamvoid
117185377Ssamar5212SetMulticastFilter(struct ath_hal *ah, uint32_t filter0, uint32_t filter1)
118185377Ssam{
119185377Ssam	OS_REG_WRITE(ah, AR_MCAST_FIL0, filter0);
120185377Ssam	OS_REG_WRITE(ah, AR_MCAST_FIL1, filter1);
121185377Ssam}
122185377Ssam
123185377Ssam/*
124185377Ssam * Clear multicast filter by index
125185377Ssam */
126185377SsamHAL_BOOL
127185377Ssamar5212ClrMulticastFilterIndex(struct ath_hal *ah, uint32_t ix)
128185377Ssam{
129185377Ssam	uint32_t val;
130185377Ssam
131185377Ssam	if (ix >= 64)
132185377Ssam		return AH_FALSE;
133185377Ssam	if (ix >= 32) {
134185377Ssam		val = OS_REG_READ(ah, AR_MCAST_FIL1);
135185377Ssam		OS_REG_WRITE(ah, AR_MCAST_FIL1, (val &~ (1<<(ix-32))));
136185377Ssam	} else {
137185377Ssam		val = OS_REG_READ(ah, AR_MCAST_FIL0);
138185377Ssam		OS_REG_WRITE(ah, AR_MCAST_FIL0, (val &~ (1<<ix)));
139185377Ssam	}
140185377Ssam	return AH_TRUE;
141185377Ssam}
142185377Ssam
143185377Ssam/*
144185377Ssam * Set multicast filter by index
145185377Ssam */
146185377SsamHAL_BOOL
147185377Ssamar5212SetMulticastFilterIndex(struct ath_hal *ah, uint32_t ix)
148185377Ssam{
149185377Ssam	uint32_t val;
150185377Ssam
151185377Ssam	if (ix >= 64)
152185377Ssam		return AH_FALSE;
153185377Ssam	if (ix >= 32) {
154185377Ssam		val = OS_REG_READ(ah, AR_MCAST_FIL1);
155185377Ssam		OS_REG_WRITE(ah, AR_MCAST_FIL1, (val | (1<<(ix-32))));
156185377Ssam	} else {
157185377Ssam		val = OS_REG_READ(ah, AR_MCAST_FIL0);
158185377Ssam		OS_REG_WRITE(ah, AR_MCAST_FIL0, (val | (1<<ix)));
159185377Ssam	}
160185377Ssam	return AH_TRUE;
161185377Ssam}
162185377Ssam
163185377Ssam/*
164185377Ssam * Get the receive filter.
165185377Ssam */
166185377Ssamuint32_t
167185377Ssamar5212GetRxFilter(struct ath_hal *ah)
168185377Ssam{
169185377Ssam	uint32_t bits = OS_REG_READ(ah, AR_RX_FILTER);
170185377Ssam	uint32_t phybits = OS_REG_READ(ah, AR_PHY_ERR);
171185377Ssam	if (phybits & AR_PHY_ERR_RADAR)
172185377Ssam		bits |= HAL_RX_FILTER_PHYRADAR;
173185377Ssam	if (phybits & (AR_PHY_ERR_OFDM_TIMING|AR_PHY_ERR_CCK_TIMING))
174185377Ssam		bits |= HAL_RX_FILTER_PHYERR;
175195114Ssam	if (AH_PRIVATE(ah)->ah_caps.halBssidMatchSupport &&
176195809Ssam	    (AH5212(ah)->ah_miscMode & AR_MISC_MODE_BSSID_MATCH_FORCE))
177195114Ssam		bits |= HAL_RX_FILTER_BSSID;
178185377Ssam	return bits;
179185377Ssam}
180185377Ssam
181185377Ssam/*
182185377Ssam * Set the receive filter.
183185377Ssam */
184185377Ssamvoid
185185377Ssamar5212SetRxFilter(struct ath_hal *ah, uint32_t bits)
186185377Ssam{
187195809Ssam	struct ath_hal_5212 *ahp = AH5212(ah);
188185377Ssam	uint32_t phybits;
189185377Ssam
190185377Ssam	OS_REG_WRITE(ah, AR_RX_FILTER,
191195114Ssam	    bits &~ (HAL_RX_FILTER_PHYRADAR|HAL_RX_FILTER_PHYERR|
192195114Ssam	    HAL_RX_FILTER_BSSID));
193185377Ssam	phybits = 0;
194185377Ssam	if (bits & HAL_RX_FILTER_PHYRADAR)
195185377Ssam		phybits |= AR_PHY_ERR_RADAR;
196185377Ssam	if (bits & HAL_RX_FILTER_PHYERR)
197185377Ssam		phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING;
198185377Ssam	OS_REG_WRITE(ah, AR_PHY_ERR, phybits);
199185377Ssam	if (phybits) {
200185377Ssam		OS_REG_WRITE(ah, AR_RXCFG,
201185377Ssam			OS_REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA);
202185377Ssam	} else {
203185377Ssam		OS_REG_WRITE(ah, AR_RXCFG,
204185377Ssam			OS_REG_READ(ah, AR_RXCFG) &~ AR_RXCFG_ZLFDMA);
205185377Ssam	}
206195114Ssam	if (AH_PRIVATE(ah)->ah_caps.halBssidMatchSupport) {
207195114Ssam		if (bits & HAL_RX_FILTER_BSSID)
208195809Ssam			ahp->ah_miscMode |= AR_MISC_MODE_BSSID_MATCH_FORCE;
209195114Ssam		else
210195809Ssam			ahp->ah_miscMode &= ~AR_MISC_MODE_BSSID_MATCH_FORCE;
211219771Sadrian		OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE) | ahp->ah_miscMode);
212195114Ssam	}
213185377Ssam}
214185377Ssam
215185377Ssam/*
216185377Ssam * Initialize RX descriptor, by clearing the status and setting
217185377Ssam * the size (and any other flags).
218185377Ssam */
219185377SsamHAL_BOOL
220185377Ssamar5212SetupRxDesc(struct ath_hal *ah, struct ath_desc *ds,
221185377Ssam	uint32_t size, u_int flags)
222185377Ssam{
223185377Ssam	struct ar5212_desc *ads = AR5212DESC(ds);
224185377Ssam
225185377Ssam	HALASSERT((size &~ AR_BufLen) == 0);
226185377Ssam
227185377Ssam	ads->ds_ctl0 = 0;
228185377Ssam	ads->ds_ctl1 = size & AR_BufLen;
229185377Ssam
230185377Ssam	if (flags & HAL_RXDESC_INTREQ)
231185377Ssam		ads->ds_ctl1 |= AR_RxInterReq;
232185377Ssam	ads->ds_rxstatus0 = ads->ds_rxstatus1 = 0;
233185377Ssam
234185377Ssam	return AH_TRUE;
235185377Ssam}
236185377Ssam
237185377Ssam/*
238185377Ssam * Process an RX descriptor, and return the status to the caller.
239185377Ssam * Copy some hardware specific items into the software portion
240185377Ssam * of the descriptor.
241185377Ssam *
242185377Ssam * NB: the caller is responsible for validating the memory contents
243185377Ssam *     of the descriptor (e.g. flushing any cached copy).
244185377Ssam */
245185377SsamHAL_STATUS
246185377Ssamar5212ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds,
247185377Ssam	uint32_t pa, struct ath_desc *nds, uint64_t tsf,
248185377Ssam	struct ath_rx_status *rs)
249185377Ssam{
250185377Ssam	struct ar5212_desc *ads = AR5212DESC(ds);
251185377Ssam	struct ar5212_desc *ands = AR5212DESC(nds);
252185377Ssam
253185377Ssam	if ((ads->ds_rxstatus1 & AR_Done) == 0)
254185377Ssam		return HAL_EINPROGRESS;
255185377Ssam	/*
256185377Ssam	 * Given the use of a self-linked tail be very sure that the hw is
257185377Ssam	 * done with this descriptor; the hw may have done this descriptor
258185377Ssam	 * once and picked it up again...make sure the hw has moved on.
259185377Ssam	 */
260185377Ssam	if ((ands->ds_rxstatus1&AR_Done) == 0 && OS_REG_READ(ah, AR_RXDP) == pa)
261185377Ssam		return HAL_EINPROGRESS;
262185377Ssam
263185377Ssam	rs->rs_datalen = ads->ds_rxstatus0 & AR_DataLen;
264185377Ssam	rs->rs_tstamp = MS(ads->ds_rxstatus1, AR_RcvTimestamp);
265185377Ssam	rs->rs_status = 0;
266185377Ssam	/* XXX what about KeyCacheMiss? */
267185377Ssam	rs->rs_rssi = MS(ads->ds_rxstatus0, AR_RcvSigStrength);
268185377Ssam	/* discard invalid h/w rssi data */
269185377Ssam	if (rs->rs_rssi == -128)
270185377Ssam		rs->rs_rssi = 0;
271185377Ssam	if (ads->ds_rxstatus1 & AR_KeyIdxValid)
272185377Ssam		rs->rs_keyix = MS(ads->ds_rxstatus1, AR_KeyIdx);
273185377Ssam	else
274185377Ssam		rs->rs_keyix = HAL_RXKEYIX_INVALID;
275185377Ssam	/* NB: caller expected to do rate table mapping */
276185377Ssam	rs->rs_rate = MS(ads->ds_rxstatus0, AR_RcvRate);
277185377Ssam	rs->rs_antenna  = MS(ads->ds_rxstatus0, AR_RcvAntenna);
278185377Ssam	rs->rs_more = (ads->ds_rxstatus0 & AR_More) ? 1 : 0;
279185377Ssam
280239966Sadrian	/*
281239966Sadrian	 * The AR5413 (at least) sometimes sets both AR_CRCErr and
282239966Sadrian	 * AR_PHYErr when reporting radar pulses.  In this instance
283239966Sadrian	 * set HAL_RXERR_PHY as well as HAL_RXERR_CRC and
284239966Sadrian	 * let the driver layer figure out what to do.
285239966Sadrian	 *
286239966Sadrian	 * See PR kern/169362.
287239966Sadrian	 */
288185377Ssam	if ((ads->ds_rxstatus1 & AR_FrmRcvOK) == 0) {
289185377Ssam		/*
290185377Ssam		 * These four bits should not be set together.  The
291185377Ssam		 * 5212 spec states a Michael error can only occur if
292185377Ssam		 * DecryptCRCErr not set (and TKIP is used).  Experience
293185377Ssam		 * indicates however that you can also get Michael errors
294185377Ssam		 * when a CRC error is detected, but these are specious.
295185377Ssam		 * Consequently we filter them out here so we don't
296185377Ssam		 * confuse and/or complicate drivers.
297185377Ssam		 */
298239966Sadrian		if (ads->ds_rxstatus1 & AR_PHYErr) {
299185377Ssam			u_int phyerr;
300185377Ssam
301185377Ssam			rs->rs_status |= HAL_RXERR_PHY;
302185377Ssam			phyerr = MS(ads->ds_rxstatus1, AR_PHYErrCode);
303185377Ssam			rs->rs_phyerr = phyerr;
304185377Ssam			if (!AH5212(ah)->ah_hasHwPhyCounters &&
305185377Ssam			    phyerr != HAL_PHYERR_RADAR)
306185377Ssam				ar5212AniPhyErrReport(ah, rs);
307239966Sadrian		}
308239966Sadrian
309239966Sadrian		if (ads->ds_rxstatus1 & AR_CRCErr)
310239966Sadrian			rs->rs_status |= HAL_RXERR_CRC;
311239966Sadrian		else if (ads->ds_rxstatus1 & AR_DecryptCRCErr)
312185377Ssam			rs->rs_status |= HAL_RXERR_DECRYPT;
313185377Ssam		else if (ads->ds_rxstatus1 & AR_MichaelErr)
314185377Ssam			rs->rs_status |= HAL_RXERR_MIC;
315185377Ssam	}
316185377Ssam	return HAL_OK;
317185377Ssam}
318