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