ar5211_recv.c revision 185377
1214152Sed/*
2214152Sed * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3214152Sed * Copyright (c) 2002-2006 Atheros Communications, Inc.
4214152Sed *
5222656Sed * Permission to use, copy, modify, and/or distribute this software for any
6222656Sed * purpose with or without fee is hereby granted, provided that the above
7214152Sed * copyright notice and this permission notice appear in all copies.
8214152Sed *
9214152Sed * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10214152Sed * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11214152Sed * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12214152Sed * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13214152Sed * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14214152Sed * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15214152Sed * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16214152Sed *
17222656Sed * $Id: ar5211_recv.c,v 1.4 2008/11/10 04:08:02 sam Exp $
18214152Sed */
19214152Sed#include "opt_ah.h"
20214152Sed
21222656Sed#ifdef AH_SUPPORT_AR5211
22214152Sed
23214152Sed#include "ah.h"
24214152Sed#include "ah_internal.h"
25214152Sed#include "ah_desc.h"
26214152Sed
27214152Sed#include "ar5211/ar5211.h"
28214152Sed#include "ar5211/ar5211reg.h"
29214152Sed#include "ar5211/ar5211desc.h"
30214152Sed
31214152Sed/*
32214152Sed * Get the RXDP.
33 */
34uint32_t
35ar5211GetRxDP(struct ath_hal *ah)
36{
37	return OS_REG_READ(ah, AR_RXDP);
38}
39
40/*
41 * Set the RxDP.
42 */
43void
44ar5211SetRxDP(struct ath_hal *ah, uint32_t rxdp)
45{
46	OS_REG_WRITE(ah, AR_RXDP, rxdp);
47	HALASSERT(OS_REG_READ(ah, AR_RXDP) == rxdp);
48}
49
50
51/*
52 * Set Receive Enable bits.
53 */
54void
55ar5211EnableReceive(struct ath_hal *ah)
56{
57	OS_REG_WRITE(ah, AR_CR, AR_CR_RXE);
58}
59
60/*
61 * Stop Receive at the DMA engine
62 */
63HAL_BOOL
64ar5211StopDmaReceive(struct ath_hal *ah)
65{
66	OS_REG_WRITE(ah, AR_CR, AR_CR_RXD);	/* Set receive disable bit */
67	if (!ath_hal_wait(ah, AR_CR, AR_CR_RXE, 0)) {
68#ifdef AH_DEBUG
69		ath_hal_printf(ah, "%s failed to stop in 10ms\n"
70				   "AR_CR=0x%08X\nAR_DIAG_SW=0x%08X\n"
71				   , __func__
72				   , OS_REG_READ(ah, AR_CR)
73				   , OS_REG_READ(ah, AR_DIAG_SW)
74		);
75#endif
76		return AH_FALSE;
77	} else {
78		return AH_TRUE;
79	}
80}
81
82/*
83 * Start Transmit at the PCU engine (unpause receive)
84 */
85void
86ar5211StartPcuReceive(struct ath_hal *ah)
87{
88	OS_REG_WRITE(ah, AR_DIAG_SW,
89		OS_REG_READ(ah, AR_DIAG_SW) & ~(AR_DIAG_SW_DIS_RX));
90}
91
92/*
93 * Stop Transmit at the PCU engine (pause receive)
94 */
95void
96ar5211StopPcuReceive(struct ath_hal *ah)
97{
98	OS_REG_WRITE(ah, AR_DIAG_SW,
99		OS_REG_READ(ah, AR_DIAG_SW) | AR_DIAG_SW_DIS_RX);
100}
101
102/*
103 * Set multicast filter 0 (lower 32-bits)
104 *			   filter 1 (upper 32-bits)
105 */
106void
107ar5211SetMulticastFilter(struct ath_hal *ah, uint32_t filter0, uint32_t filter1)
108{
109	OS_REG_WRITE(ah, AR_MCAST_FIL0, filter0);
110	OS_REG_WRITE(ah, AR_MCAST_FIL1, filter1);
111}
112
113/*
114 * Clear multicast filter by index
115 */
116HAL_BOOL
117ar5211ClrMulticastFilterIndex(struct ath_hal *ah, uint32_t ix)
118{
119	uint32_t val;
120
121	if (ix >= 64)
122		return AH_FALSE;
123	if (ix >= 32) {
124		val = OS_REG_READ(ah, AR_MCAST_FIL1);
125		OS_REG_WRITE(ah, AR_MCAST_FIL1, (val &~ (1<<(ix-32))));
126	} else {
127		val = OS_REG_READ(ah, AR_MCAST_FIL0);
128		OS_REG_WRITE(ah, AR_MCAST_FIL0, (val &~ (1<<ix)));
129	}
130	return AH_TRUE;
131}
132
133/*
134 * Set multicast filter by index
135 */
136HAL_BOOL
137ar5211SetMulticastFilterIndex(struct ath_hal *ah, uint32_t ix)
138{
139	uint32_t val;
140
141	if (ix >= 64)
142		return AH_FALSE;
143	if (ix >= 32) {
144		val = OS_REG_READ(ah, AR_MCAST_FIL1);
145		OS_REG_WRITE(ah, AR_MCAST_FIL1, (val | (1<<(ix-32))));
146	} else {
147		val = OS_REG_READ(ah, AR_MCAST_FIL0);
148		OS_REG_WRITE(ah, AR_MCAST_FIL0, (val | (1<<ix)));
149	}
150	return AH_TRUE;
151}
152
153/*
154 * Get receive filter.
155 */
156uint32_t
157ar5211GetRxFilter(struct ath_hal *ah)
158{
159	return OS_REG_READ(ah, AR_RX_FILTER);
160}
161
162/*
163 * Set receive filter.
164 */
165void
166ar5211SetRxFilter(struct ath_hal *ah, uint32_t bits)
167{
168	OS_REG_WRITE(ah, AR_RX_FILTER, bits);
169}
170
171/*
172 * Initialize RX descriptor, by clearing the status and clearing
173 * the size.  This is not strictly HW dependent, but we want the
174 * control and status words to be opaque above the hal.
175 */
176HAL_BOOL
177ar5211SetupRxDesc(struct ath_hal *ah, struct ath_desc *ds,
178	uint32_t size, u_int flags)
179{
180	struct ar5211_desc *ads = AR5211DESC(ds);
181
182	ads->ds_ctl0 = 0;
183	ads->ds_ctl1 = size & AR_BufLen;
184	if (ads->ds_ctl1 != size) {
185		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: buffer size %u too large\n",
186		    __func__, size);
187		return AH_FALSE;
188	}
189	if (flags & HAL_RXDESC_INTREQ)
190		ads->ds_ctl1 |= AR_RxInterReq;
191	ads->ds_status0 = ads->ds_status1 = 0;
192
193	return AH_TRUE;
194}
195
196/*
197 * Process an RX descriptor, and return the status to the caller.
198 * Copy some hardware specific items into the software portion
199 * of the descriptor.
200 *
201 * NB: the caller is responsible for validating the memory contents
202 *     of the descriptor (e.g. flushing any cached copy).
203 */
204HAL_STATUS
205ar5211ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds,
206	uint32_t pa, struct ath_desc *nds, uint64_t tsf,
207	struct ath_rx_status *rs)
208{
209	struct ar5211_desc *ads = AR5211DESC(ds);
210	struct ar5211_desc *ands = AR5211DESC(nds);
211
212	if ((ads->ds_status1 & AR_Done) == 0)
213		return HAL_EINPROGRESS;
214	/*
215	 * Given the use of a self-linked tail be very sure that the hw is
216	 * done with this descriptor; the hw may have done this descriptor
217	 * once and picked it up again...make sure the hw has moved on.
218	 */
219	if ((ands->ds_status1 & AR_Done) == 0 && OS_REG_READ(ah, AR_RXDP) == pa)
220		return HAL_EINPROGRESS;
221
222	rs->rs_datalen = ads->ds_status0 & AR_DataLen;
223	rs->rs_tstamp = MS(ads->ds_status1, AR_RcvTimestamp);
224	rs->rs_status = 0;
225	if ((ads->ds_status1 & AR_FrmRcvOK) == 0) {
226		if (ads->ds_status1 & AR_CRCErr)
227			rs->rs_status |= HAL_RXERR_CRC;
228		else if (ads->ds_status1 & AR_DecryptCRCErr)
229			rs->rs_status |= HAL_RXERR_DECRYPT;
230		else {
231			rs->rs_status |= HAL_RXERR_PHY;
232			rs->rs_phyerr = MS(ads->ds_status1, AR_PHYErr);
233		}
234	}
235	/* XXX what about KeyCacheMiss? */
236	rs->rs_rssi = MS(ads->ds_status0, AR_RcvSigStrength);
237	if (ads->ds_status1 & AR_KeyIdxValid)
238		rs->rs_keyix = MS(ads->ds_status1, AR_KeyIdx);
239	else
240		rs->rs_keyix = HAL_RXKEYIX_INVALID;
241	/* NB: caller expected to do rate table mapping */
242	rs->rs_rate = MS(ads->ds_status0, AR_RcvRate);
243	rs->rs_antenna  = MS(ads->ds_status0, AR_RcvAntenna);
244	rs->rs_more = (ads->ds_status0 & AR_More) ? 1 : 0;
245
246	return HAL_OK;
247}
248#endif /* AH_SUPPORT_AR5211 */
249