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