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