1 | /* |
2 | * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting |
3 | * Copyright (c) 2002-2008 Atheros Communications, Inc. |
4 | * |
5 | * Permission to use, copy, modify, and/or distribute this software for any |
6 | * purpose with or without fee is hereby granted, provided that the above |
7 | * copyright notice and this permission notice appear in all copies. |
8 | * |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 | * |
17 | * $Id: ar5212_recv.c,v 1.2 2011/03/07 11:25:43 cegger Exp $ |
18 | */ |
19 | #include "opt_ah.h" |
20 | |
21 | #include "ah.h" |
22 | #include "ah_internal.h" |
23 | |
24 | #include "ar5212/ar5212.h" |
25 | #include "ar5212/ar5212reg.h" |
26 | #include "ar5212/ar5212desc.h" |
27 | |
28 | /* |
29 | * Get the RXDP. |
30 | */ |
31 | uint32_t |
32 | ar5212GetRxDP(struct ath_hal *ath) |
33 | { |
34 | return OS_REG_READ(ath, AR_RXDP); |
35 | } |
36 | |
37 | /* |
38 | * Set the RxDP. |
39 | */ |
40 | void |
41 | ar5212SetRxDP(struct ath_hal *ah, uint32_t rxdp) |
42 | { |
43 | OS_REG_WRITE(ah, AR_RXDP, rxdp); |
44 | HALASSERT(OS_REG_READ(ah, AR_RXDP) == rxdp); |
45 | } |
46 | |
47 | /* |
48 | * Set Receive Enable bits. |
49 | */ |
50 | void |
51 | ar5212EnableReceive(struct ath_hal *ah) |
52 | { |
53 | OS_REG_WRITE(ah, AR_CR, AR_CR_RXE); |
54 | } |
55 | |
56 | /* |
57 | * Stop Receive at the DMA engine |
58 | */ |
59 | HAL_BOOL |
60 | ar5212StopDmaReceive(struct ath_hal *ah) |
61 | { |
62 | OS_REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Set receive disable bit */ |
63 | if (!ath_hal_wait(ah, AR_CR, AR_CR_RXE, 0)) { |
64 | #ifdef AH_DEBUG |
65 | ath_hal_printf(ah, "%s: dma failed to stop in 10ms\n" |
66 | "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n" , |
67 | __func__, |
68 | OS_REG_READ(ah, AR_CR), |
69 | OS_REG_READ(ah, AR_DIAG_SW)); |
70 | #endif |
71 | return AH_FALSE; |
72 | } else { |
73 | return AH_TRUE; |
74 | } |
75 | } |
76 | |
77 | /* |
78 | * Start Transmit at the PCU engine (unpause receive) |
79 | */ |
80 | void |
81 | ar5212StartPcuReceive(struct ath_hal *ah) |
82 | { |
83 | struct ath_hal_private *ahp = AH_PRIVATE(ah); |
84 | |
85 | OS_REG_WRITE(ah, AR_DIAG_SW, |
86 | OS_REG_READ(ah, AR_DIAG_SW) &~ AR_DIAG_RX_DIS); |
87 | ar5212EnableMibCounters(ah); |
88 | /* NB: restore current settings */ |
89 | ar5212AniReset(ah, ahp->ah_curchan, ahp->ah_opmode, AH_TRUE); |
90 | } |
91 | |
92 | /* |
93 | * Stop Transmit at the PCU engine (pause receive) |
94 | */ |
95 | void |
96 | ar5212StopPcuReceive(struct ath_hal *ah) |
97 | { |
98 | OS_REG_WRITE(ah, AR_DIAG_SW, |
99 | OS_REG_READ(ah, AR_DIAG_SW) | AR_DIAG_RX_DIS); |
100 | ar5212DisableMibCounters(ah); |
101 | } |
102 | |
103 | /* |
104 | * Set multicast filter 0 (lower 32-bits) |
105 | * filter 1 (upper 32-bits) |
106 | */ |
107 | void |
108 | ar5212SetMulticastFilter(struct ath_hal *ah, uint32_t filter0, uint32_t filter1) |
109 | { |
110 | OS_REG_WRITE(ah, AR_MCAST_FIL0, filter0); |
111 | OS_REG_WRITE(ah, AR_MCAST_FIL1, filter1); |
112 | } |
113 | |
114 | /* |
115 | * Clear multicast filter by index |
116 | */ |
117 | HAL_BOOL |
118 | ar5212ClrMulticastFilterIndex(struct ath_hal *ah, uint32_t ix) |
119 | { |
120 | uint32_t val; |
121 | |
122 | if (ix >= 64) |
123 | return AH_FALSE; |
124 | if (ix >= 32) { |
125 | val = OS_REG_READ(ah, AR_MCAST_FIL1); |
126 | OS_REG_WRITE(ah, AR_MCAST_FIL1, (val &~ (1<<(ix-32)))); |
127 | } else { |
128 | val = OS_REG_READ(ah, AR_MCAST_FIL0); |
129 | OS_REG_WRITE(ah, AR_MCAST_FIL0, (val &~ (1<<ix))); |
130 | } |
131 | return AH_TRUE; |
132 | } |
133 | |
134 | /* |
135 | * Set multicast filter by index |
136 | */ |
137 | HAL_BOOL |
138 | ar5212SetMulticastFilterIndex(struct ath_hal *ah, uint32_t ix) |
139 | { |
140 | uint32_t val; |
141 | |
142 | if (ix >= 64) |
143 | return AH_FALSE; |
144 | if (ix >= 32) { |
145 | val = OS_REG_READ(ah, AR_MCAST_FIL1); |
146 | OS_REG_WRITE(ah, AR_MCAST_FIL1, (val | (1<<(ix-32)))); |
147 | } else { |
148 | val = OS_REG_READ(ah, AR_MCAST_FIL0); |
149 | OS_REG_WRITE(ah, AR_MCAST_FIL0, (val | (1<<ix))); |
150 | } |
151 | return AH_TRUE; |
152 | } |
153 | |
154 | /* |
155 | * Get the receive filter. |
156 | */ |
157 | uint32_t |
158 | ar5212GetRxFilter(struct ath_hal *ah) |
159 | { |
160 | uint32_t bits = OS_REG_READ(ah, AR_RX_FILTER); |
161 | uint32_t phybits = OS_REG_READ(ah, AR_PHY_ERR); |
162 | if (phybits & AR_PHY_ERR_RADAR) |
163 | bits |= HAL_RX_FILTER_PHYRADAR; |
164 | if (phybits & (AR_PHY_ERR_OFDM_TIMING|AR_PHY_ERR_CCK_TIMING)) |
165 | bits |= HAL_RX_FILTER_PHYERR; |
166 | if (AH_PRIVATE(ah)->ah_caps.halBssidMatchSupport && |
167 | (AH5212(ah)->ah_miscMode & AR_MISC_MODE_BSSID_MATCH_FORCE)) |
168 | bits |= HAL_RX_FILTER_BSSID; |
169 | return bits; |
170 | } |
171 | |
172 | /* |
173 | * Set the receive filter. |
174 | */ |
175 | void |
176 | ar5212SetRxFilter(struct ath_hal *ah, uint32_t bits) |
177 | { |
178 | struct ath_hal_5212 *ahp = AH5212(ah); |
179 | uint32_t phybits; |
180 | |
181 | OS_REG_WRITE(ah, AR_RX_FILTER, |
182 | bits &~ (HAL_RX_FILTER_PHYRADAR|HAL_RX_FILTER_PHYERR| |
183 | HAL_RX_FILTER_BSSID)); |
184 | phybits = 0; |
185 | if (bits & HAL_RX_FILTER_PHYRADAR) |
186 | phybits |= AR_PHY_ERR_RADAR; |
187 | if (bits & HAL_RX_FILTER_PHYERR) |
188 | phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING; |
189 | OS_REG_WRITE(ah, AR_PHY_ERR, phybits); |
190 | if (phybits) { |
191 | OS_REG_WRITE(ah, AR_RXCFG, |
192 | OS_REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA); |
193 | } else { |
194 | OS_REG_WRITE(ah, AR_RXCFG, |
195 | OS_REG_READ(ah, AR_RXCFG) &~ AR_RXCFG_ZLFDMA); |
196 | } |
197 | if (AH_PRIVATE(ah)->ah_caps.halBssidMatchSupport) { |
198 | if (bits & HAL_RX_FILTER_BSSID) |
199 | ahp->ah_miscMode |= AR_MISC_MODE_BSSID_MATCH_FORCE; |
200 | else |
201 | ahp->ah_miscMode &= ~AR_MISC_MODE_BSSID_MATCH_FORCE; |
202 | OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); |
203 | } |
204 | } |
205 | |
206 | /* |
207 | * Initialize RX descriptor, by clearing the status and setting |
208 | * the size (and any other flags). |
209 | */ |
210 | HAL_BOOL |
211 | ar5212SetupRxDesc(struct ath_hal *ah, struct ath_desc *ds, |
212 | uint32_t size, u_int flags) |
213 | { |
214 | struct ar5212_desc *ads = AR5212DESC(ds); |
215 | |
216 | HALASSERT((size &~ AR_BufLen) == 0); |
217 | |
218 | ads->ds_ctl0 = 0; |
219 | ads->ds_ctl1 = size & AR_BufLen; |
220 | |
221 | if (flags & HAL_RXDESC_INTREQ) |
222 | ads->ds_ctl1 |= AR_RxInterReq; |
223 | ads->ds_rxstatus0 = ads->ds_rxstatus1 = 0; |
224 | |
225 | return AH_TRUE; |
226 | } |
227 | |
228 | /* |
229 | * Process an RX descriptor, and return the status to the caller. |
230 | * Copy some hardware specific items into the software portion |
231 | * of the descriptor. |
232 | * |
233 | * NB: the caller is responsible for validating the memory contents |
234 | * of the descriptor (e.g. flushing any cached copy). |
235 | */ |
236 | HAL_STATUS |
237 | ar5212ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds, |
238 | uint32_t pa, struct ath_desc *nds, uint64_t tsf, |
239 | struct ath_rx_status *rs) |
240 | { |
241 | struct ar5212_desc *ads = AR5212DESC(ds); |
242 | struct ar5212_desc *ands = AR5212DESC(nds); |
243 | |
244 | if ((ads->ds_rxstatus1 & AR_Done) == 0) |
245 | return HAL_EINPROGRESS; |
246 | /* |
247 | * Given the use of a self-linked tail be very sure that the hw is |
248 | * done with this descriptor; the hw may have done this descriptor |
249 | * once and picked it up again...make sure the hw has moved on. |
250 | */ |
251 | if ((ands->ds_rxstatus1&AR_Done) == 0 && OS_REG_READ(ah, AR_RXDP) == pa) |
252 | return HAL_EINPROGRESS; |
253 | |
254 | rs->rs_datalen = ads->ds_rxstatus0 & AR_DataLen; |
255 | rs->rs_tstamp = MS(ads->ds_rxstatus1, AR_RcvTimestamp); |
256 | rs->rs_status = 0; |
257 | /* XXX what about KeyCacheMiss? */ |
258 | rs->rs_rssi = MS(ads->ds_rxstatus0, AR_RcvSigStrength); |
259 | /* discard invalid h/w rssi data */ |
260 | if (rs->rs_rssi == -128) |
261 | rs->rs_rssi = 0; |
262 | if (ads->ds_rxstatus1 & AR_KeyIdxValid) |
263 | rs->rs_keyix = MS(ads->ds_rxstatus1, AR_KeyIdx); |
264 | else |
265 | rs->rs_keyix = HAL_RXKEYIX_INVALID; |
266 | /* NB: caller expected to do rate table mapping */ |
267 | rs->rs_rate = MS(ads->ds_rxstatus0, AR_RcvRate); |
268 | rs->rs_antenna = MS(ads->ds_rxstatus0, AR_RcvAntenna); |
269 | rs->rs_more = (ads->ds_rxstatus0 & AR_More) ? 1 : 0; |
270 | |
271 | if ((ads->ds_rxstatus1 & AR_FrmRcvOK) == 0) { |
272 | /* |
273 | * These four bits should not be set together. The |
274 | * 5212 spec states a Michael error can only occur if |
275 | * DecryptCRCErr not set (and TKIP is used). Experience |
276 | * indicates however that you can also get Michael errors |
277 | * when a CRC error is detected, but these are specious. |
278 | * Consequently we filter them out here so we don't |
279 | * confuse and/or complicate drivers. |
280 | */ |
281 | if (ads->ds_rxstatus1 & AR_CRCErr) |
282 | rs->rs_status |= HAL_RXERR_CRC; |
283 | else if (ads->ds_rxstatus1 & AR_PHYErr) { |
284 | u_int phyerr; |
285 | |
286 | rs->rs_status |= HAL_RXERR_PHY; |
287 | phyerr = MS(ads->ds_rxstatus1, AR_PHYErrCode); |
288 | rs->rs_phyerr = phyerr; |
289 | if (!AH5212(ah)->ah_hasHwPhyCounters && |
290 | phyerr != HAL_PHYERR_RADAR) |
291 | ar5212AniPhyErrReport(ah, rs); |
292 | } else if (ads->ds_rxstatus1 & AR_DecryptCRCErr) |
293 | rs->rs_status |= HAL_RXERR_DECRYPT; |
294 | else if (ads->ds_rxstatus1 & AR_MichaelErr) |
295 | rs->rs_status |= HAL_RXERR_MIC; |
296 | } |
297 | return HAL_OK; |
298 | } |
299 | |