Commit | Line | Data |
---|---|---|
ca97b838 BZ |
1 | /* |
2 | ************************************************************************* | |
3 | * Ralink Tech Inc. | |
4 | * 5F., No.36, Taiyuan St., Jhubei City, | |
5 | * Hsinchu County 302, | |
6 | * Taiwan, R.O.C. | |
7 | * | |
8 | * (c) Copyright 2002-2007, Ralink Technology, Inc. | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify * | |
11 | * it under the terms of the GNU General Public License as published by * | |
12 | * the Free Software Foundation; either version 2 of the License, or * | |
13 | * (at your option) any later version. * | |
14 | * * | |
15 | * This program is distributed in the hope that it will be useful, * | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
18 | * GNU General Public License for more details. * | |
19 | * * | |
20 | * You should have received a copy of the GNU General Public License * | |
21 | * along with this program; if not, write to the * | |
22 | * Free Software Foundation, Inc., * | |
23 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | |
24 | * * | |
25 | ************************************************************************* | |
26 | */ | |
27 | ||
28 | /* | |
29 | All functions in this file must be PCI-depended, or you should out your function | |
30 | in other files. | |
31 | ||
32 | */ | |
33 | #include "../rt_config.h" | |
34 | ||
96b3c83d BZ |
35 | USHORT RtmpPCI_WriteTxResource(IN PRTMP_ADAPTER pAd, |
36 | IN TX_BLK * pTxBlk, | |
37 | IN BOOLEAN bIsLast, OUT USHORT * FreeNumber) | |
ca97b838 BZ |
38 | { |
39 | ||
96b3c83d BZ |
40 | UCHAR *pDMAHeaderBufVA; |
41 | USHORT TxIdx, RetTxIdx; | |
42 | PTXD_STRUC pTxD; | |
43 | UINT32 BufBasePaLow; | |
44 | PRTMP_TX_RING pTxRing; | |
45 | USHORT hwHeaderLen; | |
ca97b838 | 46 | |
ec278fa2 BZ |
47 | /* */ |
48 | /* get Tx Ring Resource */ | |
49 | /* */ | |
ca97b838 BZ |
50 | pTxRing = &pAd->TxRing[pTxBlk->QueIdx]; |
51 | TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx; | |
52 | pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa; | |
96b3c83d BZ |
53 | BufBasePaLow = |
54 | RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa); | |
ca97b838 | 55 | |
ec278fa2 | 56 | /* copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer */ |
96b3c83d | 57 | if (pTxBlk->TxFrameType == TX_AMSDU_FRAME) { |
ec278fa2 | 58 | /*hwHeaderLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD, 4)+LENGTH_AMSDU_SUBFRAMEHEAD; */ |
96b3c83d BZ |
59 | hwHeaderLen = |
60 | pTxBlk->MpduHeaderLen - LENGTH_AMSDU_SUBFRAMEHEAD + | |
61 | pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD; | |
62 | } else { | |
ec278fa2 | 63 | /*hwHeaderLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); */ |
ca97b838 BZ |
64 | hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; |
65 | } | |
96b3c83d BZ |
66 | NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, |
67 | TXINFO_SIZE + TXWI_SIZE + hwHeaderLen); | |
ca97b838 BZ |
68 | |
69 | pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket; | |
70 | pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; | |
71 | ||
ec278fa2 BZ |
72 | /* */ |
73 | /* build Tx Descriptor */ | |
74 | /* */ | |
ca97b838 BZ |
75 | |
76 | pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; | |
77 | NdisZeroMemory(pTxD, TXD_SIZE); | |
78 | ||
79 | pTxD->SDPtr0 = BufBasePaLow; | |
ec278fa2 | 80 | pTxD->SDLen0 = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; /* include padding */ |
ca97b838 BZ |
81 | pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE); |
82 | pTxD->SDLen1 = pTxBlk->SrcBufLen; | |
83 | pTxD->LastSec0 = 0; | |
84 | pTxD->LastSec1 = (bIsLast) ? 1 : 0; | |
85 | ||
86 | RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); | |
87 | ||
88 | RetTxIdx = TxIdx; | |
ec278fa2 BZ |
89 | /* */ |
90 | /* Update Tx index */ | |
91 | /* */ | |
ca97b838 BZ |
92 | INC_RING_INDEX(TxIdx, TX_RING_SIZE); |
93 | pTxRing->TxCpuIdx = TxIdx; | |
94 | ||
95 | *FreeNumber -= 1; | |
96 | ||
97 | return RetTxIdx; | |
98 | } | |
99 | ||
96b3c83d BZ |
100 | USHORT RtmpPCI_WriteSingleTxResource(IN PRTMP_ADAPTER pAd, |
101 | IN TX_BLK * pTxBlk, | |
102 | IN BOOLEAN bIsLast, | |
103 | OUT USHORT * FreeNumber) | |
ca97b838 BZ |
104 | { |
105 | ||
96b3c83d BZ |
106 | UCHAR *pDMAHeaderBufVA; |
107 | USHORT TxIdx, RetTxIdx; | |
108 | PTXD_STRUC pTxD; | |
109 | UINT32 BufBasePaLow; | |
110 | PRTMP_TX_RING pTxRing; | |
111 | USHORT hwHeaderLen; | |
ca97b838 | 112 | |
ec278fa2 BZ |
113 | /* */ |
114 | /* get Tx Ring Resource */ | |
115 | /* */ | |
ca97b838 BZ |
116 | pTxRing = &pAd->TxRing[pTxBlk->QueIdx]; |
117 | TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx; | |
118 | pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa; | |
96b3c83d BZ |
119 | BufBasePaLow = |
120 | RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa); | |
ca97b838 | 121 | |
ec278fa2 BZ |
122 | /* copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer */ |
123 | /*hwHeaderLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); */ | |
ca97b838 BZ |
124 | hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; |
125 | ||
96b3c83d BZ |
126 | NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, |
127 | TXINFO_SIZE + TXWI_SIZE + hwHeaderLen); | |
ca97b838 BZ |
128 | |
129 | pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket; | |
130 | pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; | |
131 | ||
ec278fa2 BZ |
132 | /* */ |
133 | /* build Tx Descriptor */ | |
134 | /* */ | |
ca97b838 BZ |
135 | pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; |
136 | NdisZeroMemory(pTxD, TXD_SIZE); | |
137 | ||
138 | pTxD->SDPtr0 = BufBasePaLow; | |
ec278fa2 | 139 | pTxD->SDLen0 = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; /* include padding */ |
ca97b838 BZ |
140 | pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);; |
141 | pTxD->SDLen1 = pTxBlk->SrcBufLen; | |
142 | pTxD->LastSec0 = 0; | |
143 | pTxD->LastSec1 = (bIsLast) ? 1 : 0; | |
144 | ||
145 | RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); | |
146 | ||
147 | RetTxIdx = TxIdx; | |
ec278fa2 BZ |
148 | /* */ |
149 | /* Update Tx index */ | |
150 | /* */ | |
ca97b838 BZ |
151 | INC_RING_INDEX(TxIdx, TX_RING_SIZE); |
152 | pTxRing->TxCpuIdx = TxIdx; | |
153 | ||
154 | *FreeNumber -= 1; | |
155 | ||
156 | return RetTxIdx; | |
157 | } | |
158 | ||
96b3c83d BZ |
159 | USHORT RtmpPCI_WriteMultiTxResource(IN PRTMP_ADAPTER pAd, |
160 | IN TX_BLK * pTxBlk, | |
161 | IN UCHAR frameNum, OUT USHORT * FreeNumber) | |
ca97b838 BZ |
162 | { |
163 | BOOLEAN bIsLast; | |
96b3c83d BZ |
164 | UCHAR *pDMAHeaderBufVA; |
165 | USHORT TxIdx, RetTxIdx; | |
166 | PTXD_STRUC pTxD; | |
167 | UINT32 BufBasePaLow; | |
168 | PRTMP_TX_RING pTxRing; | |
169 | USHORT hwHdrLen; | |
170 | UINT32 firstDMALen; | |
ca97b838 BZ |
171 | |
172 | bIsLast = ((frameNum == (pTxBlk->TotalFrameNum - 1)) ? 1 : 0); | |
173 | ||
ec278fa2 BZ |
174 | /* */ |
175 | /* get Tx Ring Resource */ | |
176 | /* */ | |
ca97b838 BZ |
177 | pTxRing = &pAd->TxRing[pTxBlk->QueIdx]; |
178 | TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx; | |
179 | pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa; | |
96b3c83d BZ |
180 | BufBasePaLow = |
181 | RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa); | |
ca97b838 | 182 | |
96b3c83d | 183 | if (frameNum == 0) { |
ec278fa2 | 184 | /* copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer */ |
ca97b838 | 185 | if (pTxBlk->TxFrameType == TX_AMSDU_FRAME) |
ec278fa2 | 186 | /*hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD, 4)+LENGTH_AMSDU_SUBFRAMEHEAD; */ |
96b3c83d BZ |
187 | hwHdrLen = |
188 | pTxBlk->MpduHeaderLen - LENGTH_AMSDU_SUBFRAMEHEAD + | |
189 | pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD; | |
ca97b838 | 190 | else if (pTxBlk->TxFrameType == TX_RALINK_FRAME) |
ec278fa2 | 191 | /*hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_ARALINK_HEADER_FIELD, 4)+LENGTH_ARALINK_HEADER_FIELD; */ |
96b3c83d BZ |
192 | hwHdrLen = |
193 | pTxBlk->MpduHeaderLen - | |
194 | LENGTH_ARALINK_HEADER_FIELD + pTxBlk->HdrPadLen + | |
195 | LENGTH_ARALINK_HEADER_FIELD; | |
ca97b838 | 196 | else |
ec278fa2 | 197 | /*hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); */ |
ca97b838 BZ |
198 | hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; |
199 | ||
200 | firstDMALen = TXINFO_SIZE + TXWI_SIZE + hwHdrLen; | |
96b3c83d | 201 | } else { |
ca97b838 BZ |
202 | firstDMALen = pTxBlk->MpduHeaderLen; |
203 | } | |
204 | ||
205 | NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, firstDMALen); | |
206 | ||
207 | pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket; | |
208 | pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; | |
209 | ||
ec278fa2 BZ |
210 | /* */ |
211 | /* build Tx Descriptor */ | |
212 | /* */ | |
ca97b838 BZ |
213 | pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; |
214 | NdisZeroMemory(pTxD, TXD_SIZE); | |
215 | ||
216 | pTxD->SDPtr0 = BufBasePaLow; | |
ec278fa2 | 217 | pTxD->SDLen0 = firstDMALen; /* include padding */ |
ca97b838 BZ |
218 | pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);; |
219 | pTxD->SDLen1 = pTxBlk->SrcBufLen; | |
220 | pTxD->LastSec0 = 0; | |
221 | pTxD->LastSec1 = (bIsLast) ? 1 : 0; | |
222 | ||
223 | RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); | |
224 | ||
ca97b838 | 225 | RetTxIdx = TxIdx; |
ec278fa2 BZ |
226 | /* */ |
227 | /* Update Tx index */ | |
228 | /* */ | |
ca97b838 BZ |
229 | INC_RING_INDEX(TxIdx, TX_RING_SIZE); |
230 | pTxRing->TxCpuIdx = TxIdx; | |
231 | ||
232 | *FreeNumber -= 1; | |
233 | ||
234 | return RetTxIdx; | |
235 | ||
236 | } | |
237 | ||
96b3c83d BZ |
238 | VOID RtmpPCI_FinalWriteTxResource(IN PRTMP_ADAPTER pAd, |
239 | IN TX_BLK * pTxBlk, | |
240 | IN USHORT totalMPDUSize, IN USHORT FirstTxIdx) | |
ca97b838 BZ |
241 | { |
242 | ||
96b3c83d BZ |
243 | PTXWI_STRUC pTxWI; |
244 | PRTMP_TX_RING pTxRing; | |
ca97b838 | 245 | |
ec278fa2 BZ |
246 | /* */ |
247 | /* get Tx Ring Resource */ | |
248 | /* */ | |
ca97b838 BZ |
249 | pTxRing = &pAd->TxRing[pTxBlk->QueIdx]; |
250 | pTxWI = (PTXWI_STRUC) pTxRing->Cell[FirstTxIdx].DmaBuf.AllocVa; | |
251 | pTxWI->MPDUtotalByteCount = totalMPDUSize; | |
252 | ||
253 | } | |
254 | ||
96b3c83d BZ |
255 | VOID RtmpPCIDataLastTxIdx(IN PRTMP_ADAPTER pAd, |
256 | IN UCHAR QueIdx, IN USHORT LastTxIdx) | |
ca97b838 | 257 | { |
96b3c83d BZ |
258 | PTXD_STRUC pTxD; |
259 | PRTMP_TX_RING pTxRing; | |
ca97b838 | 260 | |
ec278fa2 BZ |
261 | /* */ |
262 | /* get Tx Ring Resource */ | |
263 | /* */ | |
ca97b838 BZ |
264 | pTxRing = &pAd->TxRing[QueIdx]; |
265 | ||
ec278fa2 BZ |
266 | /* */ |
267 | /* build Tx Descriptor */ | |
268 | /* */ | |
ca97b838 BZ |
269 | pTxD = (PTXD_STRUC) pTxRing->Cell[LastTxIdx].AllocVa; |
270 | ||
271 | pTxD->LastSec1 = 1; | |
272 | ||
ca97b838 BZ |
273 | } |
274 | ||
96b3c83d BZ |
275 | USHORT RtmpPCI_WriteFragTxResource(IN PRTMP_ADAPTER pAd, |
276 | IN TX_BLK * pTxBlk, | |
277 | IN UCHAR fragNum, OUT USHORT * FreeNumber) | |
ca97b838 | 278 | { |
96b3c83d BZ |
279 | UCHAR *pDMAHeaderBufVA; |
280 | USHORT TxIdx, RetTxIdx; | |
281 | PTXD_STRUC pTxD; | |
282 | UINT32 BufBasePaLow; | |
283 | PRTMP_TX_RING pTxRing; | |
284 | USHORT hwHeaderLen; | |
285 | UINT32 firstDMALen; | |
ca97b838 | 286 | |
ec278fa2 BZ |
287 | /* */ |
288 | /* Get Tx Ring Resource */ | |
289 | /* */ | |
ca97b838 BZ |
290 | pTxRing = &pAd->TxRing[pTxBlk->QueIdx]; |
291 | TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx; | |
292 | pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa; | |
96b3c83d BZ |
293 | BufBasePaLow = |
294 | RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa); | |
ca97b838 | 295 | |
ec278fa2 BZ |
296 | /* */ |
297 | /* Copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer */ | |
298 | /* */ | |
299 | /*hwHeaderLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); */ | |
ca97b838 BZ |
300 | hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; |
301 | ||
302 | firstDMALen = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; | |
303 | NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, firstDMALen); | |
304 | ||
ec278fa2 BZ |
305 | /* */ |
306 | /* Build Tx Descriptor */ | |
307 | /* */ | |
ca97b838 BZ |
308 | pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; |
309 | NdisZeroMemory(pTxD, TXD_SIZE); | |
310 | ||
96b3c83d | 311 | if (fragNum == pTxBlk->TotalFragNum) { |
ca97b838 BZ |
312 | pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket; |
313 | pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; | |
314 | } | |
315 | ||
316 | pTxD->SDPtr0 = BufBasePaLow; | |
ec278fa2 | 317 | pTxD->SDLen0 = firstDMALen; /* include padding */ |
ca97b838 BZ |
318 | pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE); |
319 | pTxD->SDLen1 = pTxBlk->SrcBufLen; | |
320 | pTxD->LastSec0 = 0; | |
321 | pTxD->LastSec1 = 1; | |
322 | ||
323 | RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); | |
324 | ||
ca97b838 BZ |
325 | RetTxIdx = TxIdx; |
326 | pTxBlk->Priv += pTxBlk->SrcBufLen; | |
327 | ||
ec278fa2 BZ |
328 | /* */ |
329 | /* Update Tx index */ | |
330 | /* */ | |
ca97b838 BZ |
331 | INC_RING_INDEX(TxIdx, TX_RING_SIZE); |
332 | pTxRing->TxCpuIdx = TxIdx; | |
333 | ||
334 | *FreeNumber -= 1; | |
335 | ||
336 | return RetTxIdx; | |
337 | ||
338 | } | |
339 | ||
ca97b838 BZ |
340 | /* |
341 | Must be run in Interrupt context | |
342 | This function handle PCI specific TxDesc and cpu index update and kick the packet out. | |
343 | */ | |
96b3c83d BZ |
344 | int RtmpPCIMgmtKickOut(IN RTMP_ADAPTER * pAd, |
345 | IN UCHAR QueIdx, | |
346 | IN PNDIS_PACKET pPacket, | |
347 | IN PUCHAR pSrcBufVA, IN UINT SrcBufLen) | |
ca97b838 | 348 | { |
96b3c83d BZ |
349 | PTXD_STRUC pTxD; |
350 | ULONG SwIdx = pAd->MgmtRing.TxCpuIdx; | |
ca97b838 | 351 | |
96b3c83d | 352 | pTxD = (PTXD_STRUC) pAd->MgmtRing.Cell[SwIdx].AllocVa; |
ca97b838 BZ |
353 | |
354 | pAd->MgmtRing.Cell[SwIdx].pNdisPacket = pPacket; | |
355 | pAd->MgmtRing.Cell[SwIdx].pNextNdisPacket = NULL; | |
356 | ||
357 | RTMPWriteTxDescriptor(pAd, pTxD, TRUE, FIFO_MGMT); | |
358 | pTxD->LastSec0 = 1; | |
359 | pTxD->LastSec1 = 1; | |
360 | pTxD->DMADONE = 0; | |
361 | pTxD->SDLen1 = 0; | |
96b3c83d BZ |
362 | pTxD->SDPtr0 = |
363 | PCI_MAP_SINGLE(pAd, pSrcBufVA, SrcBufLen, 0, PCI_DMA_TODEVICE); | |
ca97b838 BZ |
364 | pTxD->SDLen0 = SrcBufLen; |
365 | ||
ec278fa2 | 366 | /*================================================================== */ |
ca97b838 BZ |
367 | /* DBGPRINT_RAW(RT_DEBUG_TRACE, ("MLMEHardTransmit\n")); |
368 | for (i = 0; i < (TXWI_SIZE+24); i++) | |
369 | { | |
370 | ||
371 | DBGPRINT_RAW(RT_DEBUG_TRACE, ("%x:", *(pSrcBufVA+i))); | |
372 | if ( i%4 == 3) | |
373 | DBGPRINT_RAW(RT_DEBUG_TRACE, (" :: ")); | |
374 | if ( i%16 == 15) | |
375 | DBGPRINT_RAW(RT_DEBUG_TRACE, ("\n ")); | |
376 | } | |
377 | DBGPRINT_RAW(RT_DEBUG_TRACE, ("\n "));*/ | |
ec278fa2 | 378 | /*======================================================================= */ |
ca97b838 BZ |
379 | |
380 | pAd->RalinkCounters.KickTxCount++; | |
381 | pAd->RalinkCounters.OneSecTxDoneCount++; | |
382 | ||
ec278fa2 | 383 | /* Increase TX_CTX_IDX, but write to register later. */ |
ca97b838 BZ |
384 | INC_RING_INDEX(pAd->MgmtRing.TxCpuIdx, MGMT_RING_SIZE); |
385 | ||
96b3c83d | 386 | RTMP_IO_WRITE32(pAd, TX_MGMTCTX_IDX, pAd->MgmtRing.TxCpuIdx); |
ca97b838 BZ |
387 | |
388 | return 0; | |
389 | } | |
390 | ||
ca97b838 BZ |
391 | /* |
392 | ======================================================================== | |
393 | ||
394 | Routine Description: | |
395 | Check Rx descriptor, return NDIS_STATUS_FAILURE if any error dound | |
396 | ||
397 | Arguments: | |
398 | pRxD Pointer to the Rx descriptor | |
399 | ||
400 | Return Value: | |
401 | NDIS_STATUS_SUCCESS No err | |
402 | NDIS_STATUS_FAILURE Error | |
403 | ||
404 | Note: | |
405 | ||
406 | ======================================================================== | |
407 | */ | |
96b3c83d BZ |
408 | NDIS_STATUS RTMPCheckRxError(IN PRTMP_ADAPTER pAd, |
409 | IN PHEADER_802_11 pHeader, | |
410 | IN PRXWI_STRUC pRxWI, IN PRT28XX_RXD_STRUC pRxD) | |
ca97b838 BZ |
411 | { |
412 | PCIPHER_KEY pWpaKey; | |
413 | INT dBm; | |
414 | ||
ec278fa2 | 415 | /* Phy errors & CRC errors */ |
96b3c83d | 416 | if ( /*(pRxD->PhyErr) || */ (pRxD->Crc)) { |
ec278fa2 | 417 | /* Check RSSI for Noise Hist statistic collection. */ |
ca97b838 BZ |
418 | dBm = (INT) (pRxWI->RSSI0) - pAd->BbpRssiToDbmDelta; |
419 | if (dBm <= -87) | |
420 | pAd->StaCfg.RPIDensity[0] += 1; | |
421 | else if (dBm <= -82) | |
422 | pAd->StaCfg.RPIDensity[1] += 1; | |
423 | else if (dBm <= -77) | |
424 | pAd->StaCfg.RPIDensity[2] += 1; | |
425 | else if (dBm <= -72) | |
426 | pAd->StaCfg.RPIDensity[3] += 1; | |
427 | else if (dBm <= -67) | |
428 | pAd->StaCfg.RPIDensity[4] += 1; | |
429 | else if (dBm <= -62) | |
430 | pAd->StaCfg.RPIDensity[5] += 1; | |
431 | else if (dBm <= -57) | |
432 | pAd->StaCfg.RPIDensity[6] += 1; | |
433 | else if (dBm > -57) | |
434 | pAd->StaCfg.RPIDensity[7] += 1; | |
435 | ||
96b3c83d | 436 | return (NDIS_STATUS_FAILURE); |
ca97b838 | 437 | } |
ec278fa2 | 438 | /* Add Rx size to channel load counter, we should ignore error counts */ |
ca97b838 BZ |
439 | pAd->StaCfg.CLBusyBytes += (pRxD->SDL0 + 14); |
440 | ||
ec278fa2 | 441 | /* Drop ToDs promiscous frame, it is opened due to CCX 2 channel load statistics */ |
96b3c83d BZ |
442 | if (pHeader != NULL) { |
443 | if (pHeader->FC.ToDs) { | |
444 | return (NDIS_STATUS_FAILURE); | |
ca97b838 BZ |
445 | } |
446 | } | |
ec278fa2 BZ |
447 | /* Drop not U2M frames, cant's drop here because we will drop beacon in this case */ |
448 | /* I am kind of doubting the U2M bit operation */ | |
449 | /* if (pRxD->U2M == 0) */ | |
450 | /* return(NDIS_STATUS_FAILURE); */ | |
ca97b838 | 451 | |
ec278fa2 | 452 | /* drop decyption fail frame */ |
96b3c83d BZ |
453 | if (pRxD->CipherErr) { |
454 | if (pRxD->CipherErr == 2) { | |
455 | DBGPRINT_RAW(RT_DEBUG_TRACE, | |
456 | ("pRxD ERROR: ICV ok but MICErr ")); | |
457 | } else if (pRxD->CipherErr == 1) { | |
458 | DBGPRINT_RAW(RT_DEBUG_TRACE, ("pRxD ERROR: ICV Err ")); | |
459 | } else if (pRxD->CipherErr == 3) | |
460 | DBGPRINT_RAW(RT_DEBUG_TRACE, | |
461 | ("pRxD ERROR: Key not valid ")); | |
462 | ||
463 | if (((pRxD->CipherErr & 1) == 1) | |
464 | && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd)) | |
465 | RTMPSendWirelessEvent(pAd, IW_ICV_ERROR_EVENT_FLAG, | |
466 | pAd->MacTab.Content[BSSID_WCID]. | |
467 | Addr, BSS0, 0); | |
468 | ||
469 | DBGPRINT_RAW(RT_DEBUG_TRACE, | |
470 | (" %d (len=%d, Mcast=%d, MyBss=%d, Wcid=%d, KeyId=%d)\n", | |
471 | pRxD->CipherErr, pRxD->SDL0, | |
472 | pRxD->Mcast | pRxD->Bcast, pRxD->MyBss, | |
473 | pRxWI->WirelessCliID, | |
ec278fa2 | 474 | /* CipherName[pRxD->CipherAlg], */ |
96b3c83d | 475 | pRxWI->KeyIndex)); |
ca97b838 | 476 | |
ec278fa2 BZ |
477 | /* */ |
478 | /* MIC Error */ | |
479 | /* */ | |
96b3c83d | 480 | if (pRxD->CipherErr == 2) { |
ca97b838 | 481 | pWpaKey = &pAd->SharedKey[BSS0][pRxWI->KeyIndex]; |
96b3c83d BZ |
482 | if (pAd->StaCfg.WpaSupplicantUP) |
483 | WpaSendMicFailureToWpaSupplicant(pAd, | |
484 | (pWpaKey-> | |
485 | Type == | |
486 | PAIRWISEKEY) ? | |
487 | TRUE : FALSE); | |
488 | else | |
489 | RTMPReportMicError(pAd, pWpaKey); | |
490 | ||
491 | if (((pRxD->CipherErr & 2) == 2) | |
492 | && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd)) | |
493 | RTMPSendWirelessEvent(pAd, | |
494 | IW_MIC_ERROR_EVENT_FLAG, | |
495 | pAd->MacTab. | |
496 | Content[BSSID_WCID].Addr, | |
497 | BSS0, 0); | |
498 | ||
499 | DBGPRINT_RAW(RT_DEBUG_ERROR, ("Rx MIC Value error\n")); | |
ca97b838 BZ |
500 | } |
501 | ||
502 | if (pHeader == NULL) | |
96b3c83d | 503 | return (NDIS_STATUS_SUCCESS); |
ca97b838 | 504 | /*if ((pRxD->CipherAlg == CIPHER_AES) && |
96b3c83d BZ |
505 | (pHeader->Sequence == pAd->FragFrame.Sequence)) |
506 | { | |
507 | // | |
508 | // Acceptable since the First FragFrame no CipherErr problem. | |
509 | // | |
510 | return(NDIS_STATUS_SUCCESS); | |
511 | } */ | |
ca97b838 | 512 | |
96b3c83d | 513 | return (NDIS_STATUS_FAILURE); |
ca97b838 BZ |
514 | } |
515 | ||
96b3c83d | 516 | return (NDIS_STATUS_SUCCESS); |
ca97b838 BZ |
517 | } |
518 | ||
96b3c83d | 519 | BOOLEAN RTMPFreeTXDUponTxDmaDone(IN PRTMP_ADAPTER pAd, IN UCHAR QueIdx) |
ca97b838 BZ |
520 | { |
521 | PRTMP_TX_RING pTxRing; | |
96b3c83d BZ |
522 | PTXD_STRUC pTxD; |
523 | PNDIS_PACKET pPacket; | |
524 | UCHAR FREE = 0; | |
525 | TXD_STRUC TxD, *pOriTxD; | |
ec278fa2 | 526 | /*ULONG IrqFlags; */ |
96b3c83d | 527 | BOOLEAN bReschedule = FALSE; |
ca97b838 BZ |
528 | |
529 | ASSERT(QueIdx < NUM_OF_TX_RING); | |
530 | pTxRing = &pAd->TxRing[QueIdx]; | |
531 | ||
96b3c83d BZ |
532 | RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QueIdx * RINGREG_DIFF, |
533 | &pTxRing->TxDmaIdx); | |
534 | while (pTxRing->TxSwFreeIdx != pTxRing->TxDmaIdx) { | |
ec278fa2 | 535 | /* RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); */ |
ca97b838 | 536 | |
ec278fa2 BZ |
537 | /* static rate also need NICUpdateFifoStaCounters() function. */ |
538 | /*if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)) */ | |
96b3c83d | 539 | NICUpdateFifoStaCounters(pAd); |
ca97b838 BZ |
540 | |
541 | /* Note : If (pAd->ate.bQATxStart == TRUE), we will never reach here. */ | |
542 | FREE++; | |
96b3c83d BZ |
543 | pTxD = |
544 | (PTXD_STRUC) (pTxRing->Cell[pTxRing->TxSwFreeIdx].AllocVa); | |
ca97b838 | 545 | pOriTxD = pTxD; |
96b3c83d | 546 | NdisMoveMemory(&TxD, pTxD, sizeof(TXD_STRUC)); |
ca97b838 BZ |
547 | pTxD = &TxD; |
548 | ||
549 | pTxD->DMADONE = 0; | |
550 | ||
ca97b838 | 551 | { |
96b3c83d BZ |
552 | pPacket = |
553 | pTxRing->Cell[pTxRing->TxSwFreeIdx].pNdisPacket; | |
554 | if (pPacket) { | |
555 | PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, | |
556 | pTxD->SDLen1, | |
557 | PCI_DMA_TODEVICE); | |
558 | RELEASE_NDIS_PACKET(pAd, pPacket, | |
559 | NDIS_STATUS_SUCCESS); | |
ca97b838 | 560 | } |
ec278fa2 | 561 | /*Always assign pNdisPacket as NULL after clear */ |
ca97b838 BZ |
562 | pTxRing->Cell[pTxRing->TxSwFreeIdx].pNdisPacket = NULL; |
563 | ||
96b3c83d BZ |
564 | pPacket = |
565 | pTxRing->Cell[pTxRing->TxSwFreeIdx].pNextNdisPacket; | |
ca97b838 BZ |
566 | |
567 | ASSERT(pPacket == NULL); | |
96b3c83d BZ |
568 | if (pPacket) { |
569 | PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, | |
570 | pTxD->SDLen1, | |
571 | PCI_DMA_TODEVICE); | |
572 | RELEASE_NDIS_PACKET(pAd, pPacket, | |
573 | NDIS_STATUS_SUCCESS); | |
ca97b838 | 574 | } |
ec278fa2 | 575 | /*Always assign pNextNdisPacket as NULL after clear */ |
96b3c83d BZ |
576 | pTxRing->Cell[pTxRing->TxSwFreeIdx].pNextNdisPacket = |
577 | NULL; | |
ca97b838 BZ |
578 | } |
579 | ||
96b3c83d BZ |
580 | pAd->RalinkCounters.TransmittedByteCount += |
581 | (pTxD->SDLen1 + pTxD->SDLen0); | |
582 | pAd->RalinkCounters.OneSecDmaDoneCount[QueIdx]++; | |
ca97b838 BZ |
583 | INC_RING_INDEX(pTxRing->TxSwFreeIdx, TX_RING_SIZE); |
584 | /* get tx_tdx_idx again */ | |
96b3c83d BZ |
585 | RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QueIdx * RINGREG_DIFF, |
586 | &pTxRing->TxDmaIdx); | |
587 | NdisMoveMemory(pOriTxD, pTxD, sizeof(TXD_STRUC)); | |
ca97b838 | 588 | |
ec278fa2 | 589 | /* RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); */ |
ca97b838 BZ |
590 | } |
591 | ||
96b3c83d | 592 | return bReschedule; |
ca97b838 BZ |
593 | |
594 | } | |
595 | ||
ca97b838 BZ |
596 | /* |
597 | ======================================================================== | |
598 | ||
599 | Routine Description: | |
600 | Process TX Rings DMA Done interrupt, running in DPC level | |
601 | ||
602 | Arguments: | |
603 | Adapter Pointer to our adapter | |
604 | ||
605 | Return Value: | |
606 | None | |
607 | ||
608 | IRQL = DISPATCH_LEVEL | |
609 | ||
610 | ======================================================================== | |
611 | */ | |
96b3c83d BZ |
612 | BOOLEAN RTMPHandleTxRingDmaDoneInterrupt(IN PRTMP_ADAPTER pAd, |
613 | IN INT_SOURCE_CSR_STRUC TxRingBitmap) | |
ca97b838 | 614 | { |
ec278fa2 | 615 | /* UCHAR Count = 0; */ |
96b3c83d BZ |
616 | unsigned long IrqFlags; |
617 | BOOLEAN bReschedule = FALSE; | |
ca97b838 | 618 | |
ec278fa2 BZ |
619 | /* Make sure Tx ring resource won't be used by other threads */ |
620 | /*NdisAcquireSpinLock(&pAd->TxRingLock); */ | |
ca97b838 BZ |
621 | |
622 | RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); | |
623 | ||
624 | if (TxRingBitmap.field.Ac0DmaDone) | |
625 | bReschedule = RTMPFreeTXDUponTxDmaDone(pAd, QID_AC_BE); | |
626 | ||
ca97b838 BZ |
627 | if (TxRingBitmap.field.Ac3DmaDone) |
628 | bReschedule |= RTMPFreeTXDUponTxDmaDone(pAd, QID_AC_VO); | |
629 | ||
630 | if (TxRingBitmap.field.Ac2DmaDone) | |
631 | bReschedule |= RTMPFreeTXDUponTxDmaDone(pAd, QID_AC_VI); | |
632 | ||
633 | if (TxRingBitmap.field.Ac1DmaDone) | |
634 | bReschedule |= RTMPFreeTXDUponTxDmaDone(pAd, QID_AC_BK); | |
635 | ||
ec278fa2 BZ |
636 | /* Make sure to release Tx ring resource */ |
637 | /*NdisReleaseSpinLock(&pAd->TxRingLock); */ | |
ca97b838 BZ |
638 | RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); |
639 | ||
ec278fa2 | 640 | /* Dequeue outgoing frames from TxSwQueue[] and process it */ |
ca97b838 BZ |
641 | RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); |
642 | ||
96b3c83d | 643 | return bReschedule; |
ca97b838 BZ |
644 | } |
645 | ||
ca97b838 BZ |
646 | /* |
647 | ======================================================================== | |
648 | ||
649 | Routine Description: | |
650 | Process MGMT ring DMA done interrupt, running in DPC level | |
651 | ||
652 | Arguments: | |
653 | pAd Pointer to our adapter | |
654 | ||
655 | Return Value: | |
656 | None | |
657 | ||
658 | IRQL = DISPATCH_LEVEL | |
659 | ||
660 | Note: | |
661 | ||
662 | ======================================================================== | |
663 | */ | |
96b3c83d | 664 | VOID RTMPHandleMgmtRingDmaDoneInterrupt(IN PRTMP_ADAPTER pAd) |
ca97b838 | 665 | { |
96b3c83d | 666 | PTXD_STRUC pTxD; |
ca97b838 | 667 | PNDIS_PACKET pPacket; |
ec278fa2 | 668 | /* int i; */ |
96b3c83d | 669 | UCHAR FREE = 0; |
ca97b838 BZ |
670 | PRTMP_MGMT_RING pMgmtRing = &pAd->MgmtRing; |
671 | ||
672 | NdisAcquireSpinLock(&pAd->MgmtRingLock); | |
673 | ||
674 | RTMP_IO_READ32(pAd, TX_MGMTDTX_IDX, &pMgmtRing->TxDmaIdx); | |
96b3c83d | 675 | while (pMgmtRing->TxSwFreeIdx != pMgmtRing->TxDmaIdx) { |
ca97b838 | 676 | FREE++; |
96b3c83d BZ |
677 | pTxD = |
678 | (PTXD_STRUC) (pMgmtRing->Cell[pAd->MgmtRing.TxSwFreeIdx]. | |
679 | AllocVa); | |
ca97b838 BZ |
680 | pTxD->DMADONE = 0; |
681 | pPacket = pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNdisPacket; | |
682 | ||
96b3c83d BZ |
683 | if (pPacket) { |
684 | PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, | |
685 | PCI_DMA_TODEVICE); | |
ca97b838 BZ |
686 | RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); |
687 | } | |
688 | pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNdisPacket = NULL; | |
689 | ||
96b3c83d BZ |
690 | pPacket = |
691 | pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNextNdisPacket; | |
692 | if (pPacket) { | |
693 | PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, | |
694 | PCI_DMA_TODEVICE); | |
ca97b838 BZ |
695 | RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); |
696 | } | |
697 | pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNextNdisPacket = NULL; | |
698 | INC_RING_INDEX(pMgmtRing->TxSwFreeIdx, MGMT_RING_SIZE); | |
699 | ||
700 | } | |
701 | NdisReleaseSpinLock(&pAd->MgmtRingLock); | |
702 | ||
703 | } | |
704 | ||
ca97b838 BZ |
705 | /* |
706 | ======================================================================== | |
707 | ||
708 | Routine Description: | |
709 | Arguments: | |
710 | Adapter Pointer to our adapter. Dequeue all power safe delayed braodcast frames after beacon. | |
711 | ||
712 | IRQL = DISPATCH_LEVEL | |
713 | ||
714 | ======================================================================== | |
715 | */ | |
96b3c83d | 716 | VOID RTMPHandleTBTTInterrupt(IN PRTMP_ADAPTER pAd) |
ca97b838 BZ |
717 | { |
718 | { | |
96b3c83d | 719 | if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) { |
ca97b838 BZ |
720 | } |
721 | } | |
722 | } | |
723 | ||
ca97b838 BZ |
724 | /* |
725 | ======================================================================== | |
726 | ||
727 | Routine Description: | |
728 | Arguments: | |
729 | pAd Pointer to our adapter. Rewrite beacon content before next send-out. | |
730 | ||
731 | IRQL = DISPATCH_LEVEL | |
732 | ||
733 | ======================================================================== | |
734 | */ | |
96b3c83d | 735 | VOID RTMPHandlePreTBTTInterrupt(IN PRTMP_ADAPTER pAd) |
ca97b838 BZ |
736 | { |
737 | { | |
96b3c83d BZ |
738 | if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) { |
739 | DBGPRINT(RT_DEBUG_TRACE, | |
740 | ("RTMPHandlePreTBTTInterrupt...\n")); | |
ca97b838 BZ |
741 | } |
742 | } | |
743 | ||
ca97b838 BZ |
744 | } |
745 | ||
96b3c83d | 746 | VOID RTMPHandleRxCoherentInterrupt(IN PRTMP_ADAPTER pAd) |
ca97b838 | 747 | { |
96b3c83d | 748 | WPDMA_GLO_CFG_STRUC GloCfg; |
ca97b838 | 749 | |
96b3c83d | 750 | if (pAd == NULL) { |
ca97b838 BZ |
751 | DBGPRINT(RT_DEBUG_TRACE, ("====> pAd is NULL, return.\n")); |
752 | return; | |
753 | } | |
754 | ||
755 | DBGPRINT(RT_DEBUG_TRACE, ("==> RTMPHandleRxCoherentInterrupt \n")); | |
756 | ||
96b3c83d | 757 | RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); |
ca97b838 BZ |
758 | |
759 | GloCfg.field.EnTXWriteBackDDONE = 0; | |
760 | GloCfg.field.EnableRxDMA = 0; | |
761 | GloCfg.field.EnableTxDMA = 0; | |
762 | RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); | |
763 | ||
764 | RTMPRingCleanUp(pAd, QID_AC_BE); | |
765 | RTMPRingCleanUp(pAd, QID_AC_BK); | |
766 | RTMPRingCleanUp(pAd, QID_AC_VI); | |
767 | RTMPRingCleanUp(pAd, QID_AC_VO); | |
ca97b838 BZ |
768 | RTMPRingCleanUp(pAd, QID_MGMT); |
769 | RTMPRingCleanUp(pAd, QID_RX); | |
770 | ||
771 | RTMPEnableRxTx(pAd); | |
772 | ||
773 | DBGPRINT(RT_DEBUG_TRACE, ("<== RTMPHandleRxCoherentInterrupt \n")); | |
774 | } | |
775 | ||
96b3c83d BZ |
776 | PNDIS_PACKET GetPacketFromRxRing(IN PRTMP_ADAPTER pAd, |
777 | OUT PRT28XX_RXD_STRUC pSaveRxD, | |
778 | OUT BOOLEAN * pbReschedule, | |
779 | IN OUT UINT32 * pRxPending) | |
ca97b838 | 780 | { |
96b3c83d BZ |
781 | PRXD_STRUC pRxD; |
782 | PNDIS_PACKET pRxPacket = NULL; | |
783 | PNDIS_PACKET pNewPacket; | |
784 | PVOID AllocVa; | |
785 | NDIS_PHYSICAL_ADDRESS AllocPa; | |
786 | BOOLEAN bReschedule = FALSE; | |
787 | RTMP_DMACB *pRxCell; | |
ca97b838 BZ |
788 | |
789 | RTMP_SEM_LOCK(&pAd->RxRingLock); | |
790 | ||
96b3c83d | 791 | if (*pRxPending == 0) { |
ec278fa2 | 792 | /* Get how may packets had been received */ |
96b3c83d | 793 | RTMP_IO_READ32(pAd, RX_DRX_IDX, &pAd->RxRing.RxDmaIdx); |
ca97b838 | 794 | |
96b3c83d | 795 | if (pAd->RxRing.RxSwReadIdx == pAd->RxRing.RxDmaIdx) { |
ec278fa2 | 796 | /* no more rx packets */ |
ca97b838 BZ |
797 | bReschedule = FALSE; |
798 | goto done; | |
799 | } | |
ec278fa2 | 800 | /* get rx pending count */ |
ca97b838 | 801 | if (pAd->RxRing.RxDmaIdx > pAd->RxRing.RxSwReadIdx) |
96b3c83d BZ |
802 | *pRxPending = |
803 | pAd->RxRing.RxDmaIdx - pAd->RxRing.RxSwReadIdx; | |
ca97b838 | 804 | else |
96b3c83d BZ |
805 | *pRxPending = |
806 | pAd->RxRing.RxDmaIdx + RX_RING_SIZE - | |
807 | pAd->RxRing.RxSwReadIdx; | |
ca97b838 BZ |
808 | |
809 | } | |
810 | ||
811 | pRxCell = &pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx]; | |
812 | ||
ec278fa2 | 813 | /* Point to Rx indexed rx ring descriptor */ |
ca97b838 BZ |
814 | pRxD = (PRXD_STRUC) pRxCell->AllocVa; |
815 | ||
96b3c83d | 816 | if (pRxD->DDONE == 0) { |
ca97b838 | 817 | *pRxPending = 0; |
ec278fa2 | 818 | /* DMAIndx had done but DDONE bit not ready */ |
ca97b838 BZ |
819 | bReschedule = TRUE; |
820 | goto done; | |
821 | } | |
822 | ||
ec278fa2 | 823 | /* return rx descriptor */ |
ca97b838 BZ |
824 | NdisMoveMemory(pSaveRxD, pRxD, RXD_SIZE); |
825 | ||
96b3c83d BZ |
826 | pNewPacket = |
827 | RTMP_AllocateRxPacketBuffer(pAd, RX_BUFFER_AGGRESIZE, FALSE, | |
828 | &AllocVa, &AllocPa); | |
ca97b838 | 829 | |
96b3c83d | 830 | if (pNewPacket) { |
ec278fa2 | 831 | /* unmap the rx buffer */ |
ca97b838 | 832 | PCI_UNMAP_SINGLE(pAd, pRxCell->DmaBuf.AllocPa, |
96b3c83d | 833 | pRxCell->DmaBuf.AllocSize, PCI_DMA_FROMDEVICE); |
ca97b838 BZ |
834 | pRxPacket = pRxCell->pNdisPacket; |
835 | ||
96b3c83d BZ |
836 | pRxCell->DmaBuf.AllocSize = RX_BUFFER_AGGRESIZE; |
837 | pRxCell->pNdisPacket = (PNDIS_PACKET) pNewPacket; | |
838 | pRxCell->DmaBuf.AllocVa = AllocVa; | |
839 | pRxCell->DmaBuf.AllocPa = AllocPa; | |
ca97b838 BZ |
840 | /* update SDP0 to new buffer of rx packet */ |
841 | pRxD->SDP0 = AllocPa; | |
96b3c83d | 842 | } else { |
ec278fa2 | 843 | /*DBGPRINT(RT_DEBUG_TRACE,("No Rx Buffer\n")); */ |
ca97b838 BZ |
844 | pRxPacket = NULL; |
845 | bReschedule = TRUE; | |
846 | } | |
847 | ||
848 | pRxD->DDONE = 0; | |
849 | ||
ec278fa2 | 850 | /* had handled one rx packet */ |
ca97b838 BZ |
851 | *pRxPending = *pRxPending - 1; |
852 | ||
ec278fa2 | 853 | /* update rx descriptor and kick rx */ |
ca97b838 BZ |
854 | INC_RING_INDEX(pAd->RxRing.RxSwReadIdx, RX_RING_SIZE); |
855 | ||
96b3c83d BZ |
856 | pAd->RxRing.RxCpuIdx = |
857 | (pAd->RxRing.RxSwReadIdx == | |
858 | 0) ? (RX_RING_SIZE - 1) : (pAd->RxRing.RxSwReadIdx - 1); | |
ca97b838 BZ |
859 | RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx); |
860 | ||
861 | done: | |
862 | RTMP_SEM_UNLOCK(&pAd->RxRingLock); | |
863 | *pbReschedule = bReschedule; | |
864 | return pRxPacket; | |
865 | } | |
866 | ||
96b3c83d BZ |
867 | NDIS_STATUS MlmeHardTransmitTxRing(IN PRTMP_ADAPTER pAd, |
868 | IN UCHAR QueIdx, IN PNDIS_PACKET pPacket) | |
ca97b838 | 869 | { |
96b3c83d BZ |
870 | PACKET_INFO PacketInfo; |
871 | PUCHAR pSrcBufVA; | |
872 | UINT SrcBufLen; | |
873 | PTXD_STRUC pTxD; | |
874 | PHEADER_802_11 pHeader_802_11; | |
875 | BOOLEAN bAckRequired, bInsertTimestamp; | |
876 | ULONG SrcBufPA; | |
ec278fa2 | 877 | /*UCHAR TxBufIdx; */ |
96b3c83d BZ |
878 | UCHAR MlmeRate; |
879 | ULONG SwIdx = pAd->TxRing[QueIdx].TxCpuIdx; | |
880 | PTXWI_STRUC pFirstTxWI; | |
ec278fa2 BZ |
881 | /*ULONG i; */ |
882 | /*HTTRANSMIT_SETTING MlmeTransmit; //Rate for this MGMT frame. */ | |
96b3c83d BZ |
883 | ULONG FreeNum; |
884 | MAC_TABLE_ENTRY *pMacEntry = NULL; | |
ca97b838 BZ |
885 | |
886 | RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); | |
887 | ||
96b3c83d | 888 | if (pSrcBufVA == NULL) { |
ec278fa2 | 889 | /* The buffer shouldn't be NULL */ |
ca97b838 BZ |
890 | return NDIS_STATUS_FAILURE; |
891 | } | |
ec278fa2 BZ |
892 | /* Make sure MGMT ring resource won't be used by other threads */ |
893 | /*NdisAcquireSpinLock(&pAd->TxRingLock); */ | |
ca97b838 BZ |
894 | |
895 | FreeNum = GET_TXRING_FREENO(pAd, QueIdx); | |
896 | ||
96b3c83d | 897 | if (FreeNum == 0) { |
ec278fa2 | 898 | /*NdisReleaseSpinLock(&pAd->TxRingLock); */ |
ca97b838 BZ |
899 | return NDIS_STATUS_FAILURE; |
900 | } | |
901 | ||
902 | SwIdx = pAd->TxRing[QueIdx].TxCpuIdx; | |
903 | ||
96b3c83d | 904 | pTxD = (PTXD_STRUC) pAd->TxRing[QueIdx].Cell[SwIdx].AllocVa; |
ca97b838 | 905 | |
96b3c83d | 906 | if (pAd->TxRing[QueIdx].Cell[SwIdx].pNdisPacket) { |
ca97b838 | 907 | DBGPRINT(RT_DEBUG_OFF, ("MlmeHardTransmit Error\n")); |
ec278fa2 | 908 | /*NdisReleaseSpinLock(&pAd->TxRingLock); */ |
ca97b838 BZ |
909 | return NDIS_STATUS_FAILURE; |
910 | } | |
911 | ||
912 | { | |
ec278fa2 BZ |
913 | /* outgoing frame always wakeup PHY to prevent frame lost */ |
914 | /* if (pAd->StaCfg.Psm == PWR_SAVE) */ | |
ca97b838 BZ |
915 | if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) |
916 | AsicForceWakeup(pAd, TRUE); | |
917 | } | |
96b3c83d | 918 | pFirstTxWI = (PTXWI_STRUC) pSrcBufVA; |
ca97b838 BZ |
919 | |
920 | pHeader_802_11 = (PHEADER_802_11) (pSrcBufVA + TXWI_SIZE); | |
96b3c83d | 921 | if (pHeader_802_11->Addr1[0] & 0x01) { |
ca97b838 | 922 | MlmeRate = pAd->CommonCfg.BasicMlmeRate; |
96b3c83d | 923 | } else { |
ca97b838 BZ |
924 | MlmeRate = pAd->CommonCfg.MlmeRate; |
925 | } | |
926 | ||
927 | if ((pHeader_802_11->FC.Type == BTYPE_DATA) && | |
96b3c83d | 928 | (pHeader_802_11->FC.SubType == SUBTYPE_QOS_NULL)) { |
ca97b838 BZ |
929 | pMacEntry = MacTableLookup(pAd, pHeader_802_11->Addr1); |
930 | } | |
ec278fa2 BZ |
931 | /* Verify Mlme rate for a / g bands. */ |
932 | if ((pAd->LatchRfRegs.Channel > 14) && (MlmeRate < RATE_6)) /* 11A band */ | |
ca97b838 BZ |
933 | MlmeRate = RATE_6; |
934 | ||
ec278fa2 BZ |
935 | /* */ |
936 | /* Should not be hard code to set PwrMgmt to 0 (PWR_ACTIVE) */ | |
937 | /* Snice it's been set to 0 while on MgtMacHeaderInit */ | |
938 | /* By the way this will cause frame to be send on PWR_SAVE failed. */ | |
939 | /* */ | |
940 | /* */ | |
941 | /* In WMM-UAPSD, mlme frame should be set psm as power saving but probe request frame */ | |
942 | /* Data-Null packets alse pass through MMRequest in RT2860, however, we hope control the psm bit to pass APSD */ | |
96b3c83d BZ |
943 | if (pHeader_802_11->FC.Type != BTYPE_DATA) { |
944 | if ((pHeader_802_11->FC.SubType == SUBTYPE_PROBE_REQ) | |
945 | || !(pAd->CommonCfg.bAPSDCapable | |
946 | && pAd->CommonCfg.APEdcaParm.bAPSDCapable)) { | |
947 | pHeader_802_11->FC.PwrMgmt = PWR_ACTIVE; | |
948 | } else { | |
949 | pHeader_802_11->FC.PwrMgmt = | |
950 | pAd->CommonCfg.bAPSDForcePowerSave; | |
951 | } | |
ca97b838 | 952 | } |
ca97b838 BZ |
953 | |
954 | bInsertTimestamp = FALSE; | |
ec278fa2 | 955 | if (pHeader_802_11->FC.Type == BTYPE_CNTL) /* must be PS-POLL */ |
ca97b838 BZ |
956 | { |
957 | bAckRequired = FALSE; | |
ec278fa2 | 958 | } else /* BTYPE_MGMT or BTYPE_DATA(must be NULL frame) */ |
ca97b838 | 959 | { |
ec278fa2 | 960 | if (pHeader_802_11->Addr1[0] & 0x01) /* MULTICAST, BROADCAST */ |
ca97b838 BZ |
961 | { |
962 | bAckRequired = FALSE; | |
963 | pHeader_802_11->Duration = 0; | |
96b3c83d | 964 | } else { |
ca97b838 | 965 | bAckRequired = TRUE; |
96b3c83d BZ |
966 | pHeader_802_11->Duration = |
967 | RTMPCalcDuration(pAd, MlmeRate, 14); | |
968 | if (pHeader_802_11->FC.SubType == SUBTYPE_PROBE_RSP) { | |
ca97b838 BZ |
969 | bInsertTimestamp = TRUE; |
970 | } | |
971 | } | |
972 | } | |
973 | pHeader_802_11->Sequence = pAd->Sequence++; | |
974 | if (pAd->Sequence > 0xfff) | |
975 | pAd->Sequence = 0; | |
ec278fa2 BZ |
976 | /* Before radar detection done, mgmt frame can not be sent but probe req */ |
977 | /* Because we need to use probe req to trigger driver to send probe req in passive scan */ | |
ca97b838 | 978 | if ((pHeader_802_11->FC.SubType != SUBTYPE_PROBE_REQ) |
96b3c83d BZ |
979 | && (pAd->CommonCfg.bIEEE80211H == 1) |
980 | && (pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE)) { | |
981 | DBGPRINT(RT_DEBUG_ERROR, | |
982 | ("MlmeHardTransmit --> radar detect not in normal mode !!!\n")); | |
ec278fa2 | 983 | /*NdisReleaseSpinLock(&pAd->TxRingLock); */ |
ca97b838 BZ |
984 | return (NDIS_STATUS_FAILURE); |
985 | } | |
ec278fa2 BZ |
986 | /* */ |
987 | /* fill scatter-and-gather buffer list into TXD. Internally created NDIS PACKET */ | |
988 | /* should always has only one ohysical buffer, and the whole frame size equals */ | |
989 | /* to the first scatter buffer size */ | |
990 | /* */ | |
991 | ||
992 | /* Initialize TX Descriptor */ | |
993 | /* For inter-frame gap, the number is for this frame and next frame */ | |
994 | /* For MLME rate, we will fix as 2Mb to match other vendor's implement */ | |
995 | /* pAd->CommonCfg.MlmeTransmit.field.MODE = 1; */ | |
996 | ||
997 | /* management frame doesn't need encryption. so use RESERVED_WCID no matter u are sending to specific wcid or not. */ | |
998 | /* Only beacon use Nseq=TRUE. So here we use Nseq=FALSE. */ | |
96b3c83d BZ |
999 | if (pMacEntry == NULL) { |
1000 | RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, bInsertTimestamp, | |
1001 | FALSE, bAckRequired, FALSE, 0, RESERVED_WCID, | |
1002 | (SrcBufLen - TXWI_SIZE), PID_MGMT, 0, | |
1003 | (UCHAR) pAd->CommonCfg.MlmeTransmit.field.MCS, | |
1004 | IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit); | |
1005 | } else { | |
ca97b838 | 1006 | RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, |
96b3c83d BZ |
1007 | bInsertTimestamp, FALSE, bAckRequired, FALSE, |
1008 | 0, pMacEntry->Aid, (SrcBufLen - TXWI_SIZE), | |
1009 | pMacEntry->MaxHTPhyMode.field.MCS, 0, | |
1010 | (UCHAR) pMacEntry->MaxHTPhyMode.field.MCS, | |
1011 | IFS_BACKOFF, FALSE, &pMacEntry->MaxHTPhyMode); | |
ca97b838 BZ |
1012 | } |
1013 | ||
1014 | pAd->TxRing[QueIdx].Cell[SwIdx].pNdisPacket = pPacket; | |
1015 | pAd->TxRing[QueIdx].Cell[SwIdx].pNextNdisPacket = NULL; | |
ec278fa2 | 1016 | /* pFirstTxWI->MPDUtotalByteCount = SrcBufLen - TXWI_SIZE; */ |
96b3c83d BZ |
1017 | SrcBufPA = |
1018 | PCI_MAP_SINGLE(pAd, pSrcBufVA, SrcBufLen, 0, PCI_DMA_TODEVICE); | |
ca97b838 BZ |
1019 | |
1020 | RTMPWriteTxDescriptor(pAd, pTxD, TRUE, FIFO_EDCA); | |
1021 | pTxD->LastSec0 = 1; | |
1022 | pTxD->LastSec1 = 1; | |
1023 | pTxD->SDLen0 = SrcBufLen; | |
1024 | pTxD->SDLen1 = 0; | |
1025 | pTxD->SDPtr0 = SrcBufPA; | |
1026 | pTxD->DMADONE = 0; | |
1027 | ||
ca97b838 BZ |
1028 | pAd->RalinkCounters.KickTxCount++; |
1029 | pAd->RalinkCounters.OneSecTxDoneCount++; | |
1030 | ||
ec278fa2 | 1031 | /* Increase TX_CTX_IDX, but write to register later. */ |
ca97b838 BZ |
1032 | INC_RING_INDEX(pAd->TxRing[QueIdx].TxCpuIdx, TX_RING_SIZE); |
1033 | ||
96b3c83d BZ |
1034 | RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + QueIdx * 0x10, |
1035 | pAd->TxRing[QueIdx].TxCpuIdx); | |
ca97b838 | 1036 | |
ec278fa2 BZ |
1037 | /* Make sure to release MGMT ring resource */ |
1038 | /* NdisReleaseSpinLock(&pAd->TxRingLock); */ | |
ca97b838 BZ |
1039 | |
1040 | return NDIS_STATUS_SUCCESS; | |
1041 | } | |
1042 | ||
96b3c83d BZ |
1043 | NDIS_STATUS MlmeDataHardTransmit(IN PRTMP_ADAPTER pAd, |
1044 | IN UCHAR QueIdx, IN PNDIS_PACKET pPacket) | |
ca97b838 BZ |
1045 | { |
1046 | if ((pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE) | |
96b3c83d | 1047 | ) { |
ca97b838 BZ |
1048 | return NDIS_STATUS_FAILURE; |
1049 | } | |
1050 | ||
96b3c83d | 1051 | return MlmeHardTransmitTxRing(pAd, QueIdx, pPacket); |
ca97b838 BZ |
1052 | } |
1053 | ||
ca97b838 BZ |
1054 | /* |
1055 | ======================================================================== | |
1056 | ||
1057 | Routine Description: | |
1058 | Calculates the duration which is required to transmit out frames | |
1059 | with given size and specified rate. | |
1060 | ||
1061 | Arguments: | |
1062 | pTxD Pointer to transmit descriptor | |
1063 | Ack Setting for Ack requirement bit | |
1064 | Fragment Setting for Fragment bit | |
1065 | RetryMode Setting for retry mode | |
1066 | Ifs Setting for IFS gap | |
1067 | Rate Setting for transmit rate | |
1068 | Service Setting for service | |
1069 | Length Frame length | |
1070 | TxPreamble Short or Long preamble when using CCK rates | |
1071 | QueIdx - 0-3, according to 802.11e/d4.4 June/2003 | |
1072 | ||
1073 | Return Value: | |
1074 | None | |
1075 | ||
1076 | IRQL = PASSIVE_LEVEL | |
1077 | IRQL = DISPATCH_LEVEL | |
1078 | ||
1079 | ======================================================================== | |
1080 | */ | |
96b3c83d BZ |
1081 | VOID RTMPWriteTxDescriptor(IN PRTMP_ADAPTER pAd, |
1082 | IN PTXD_STRUC pTxD, | |
1083 | IN BOOLEAN bWIV, IN UCHAR QueueSEL) | |
ca97b838 | 1084 | { |
ec278fa2 BZ |
1085 | /* */ |
1086 | /* Always use Long preamble before verifiation short preamble functionality works well. */ | |
1087 | /* Todo: remove the following line if short preamble functionality works */ | |
1088 | /* */ | |
ca97b838 BZ |
1089 | OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); |
1090 | ||
96b3c83d BZ |
1091 | pTxD->WIV = (bWIV) ? 1 : 0; |
1092 | pTxD->QSEL = (QueueSEL); | |
ec278fa2 BZ |
1093 | /*RT2860c?? fixed using EDCA queue for test... We doubt Queue1 has problem. 2006-09-26 Jan */ |
1094 | /*pTxD->QSEL= FIFO_EDCA; */ | |
ca97b838 BZ |
1095 | pTxD->DMADONE = 0; |
1096 | } |