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