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
35 extern RTMP_RF_REGS RF2850RegTable[];
36 extern UCHAR NUM_OF_2850_CHNL;
37
RtmpPCI_WriteTxResource(IN PRTMP_ADAPTER pAd,IN TX_BLK * pTxBlk,IN BOOLEAN bIsLast,OUT USHORT * FreeNumber)38 USHORT RtmpPCI_WriteTxResource(
39 IN PRTMP_ADAPTER pAd,
40 IN TX_BLK *pTxBlk,
41 IN BOOLEAN bIsLast,
42 OUT USHORT *FreeNumber)
43 {
44
45 UCHAR *pDMAHeaderBufVA;
46 USHORT TxIdx, RetTxIdx;
47 PTXD_STRUC pTxD;
48 UINT32 BufBasePaLow;
49 PRTMP_TX_RING pTxRing;
50 USHORT hwHeaderLen;
51
52 //
53 // get Tx Ring Resource
54 //
55 pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
56 TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx;
57 pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa;
58 BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa);
59
60 // copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
61 if (pTxBlk->TxFrameType == TX_AMSDU_FRAME)
62 {
63 hwHeaderLen = pTxBlk->MpduHeaderLen - LENGTH_AMSDU_SUBFRAMEHEAD + pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD;
64 }
65 else
66 {
67 hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
68 }
69 NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHeaderLen);
70
71 pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
72 pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
73
74 //
75 // build Tx Descriptor
76 //
77
78 pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
79 NdisZeroMemory(pTxD, TXD_SIZE);
80
81 pTxD->SDPtr0 = BufBasePaLow;
82 pTxD->SDLen0 = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; // include padding
83 pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);;
84 pTxD->SDLen1 = pTxBlk->SrcBufLen;
85 pTxD->LastSec0 = 0;
86 pTxD->LastSec1 = (bIsLast) ? 1 : 0;
87
88 RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
89
90 RetTxIdx = TxIdx;
91 //
92 // Update Tx index
93 //
94 INC_RING_INDEX(TxIdx, TX_RING_SIZE);
95 pTxRing->TxCpuIdx = TxIdx;
96
97 *FreeNumber -= 1;
98
99 return RetTxIdx;
100 }
101
102
RtmpPCI_WriteSingleTxResource(IN PRTMP_ADAPTER pAd,IN TX_BLK * pTxBlk,IN BOOLEAN bIsLast,OUT USHORT * FreeNumber)103 USHORT RtmpPCI_WriteSingleTxResource(
104 IN PRTMP_ADAPTER pAd,
105 IN TX_BLK *pTxBlk,
106 IN BOOLEAN bIsLast,
107 OUT USHORT *FreeNumber)
108 {
109
110 UCHAR *pDMAHeaderBufVA;
111 USHORT TxIdx, RetTxIdx;
112 PTXD_STRUC pTxD;
113 #ifdef RT_BIG_ENDIAN
114 PTXD_STRUC pDestTxD;
115 TXD_STRUC TxD;
116 #endif
117 UINT32 BufBasePaLow;
118 PRTMP_TX_RING pTxRing;
119 USHORT hwHeaderLen;
120
121 //
122 // get Tx Ring Resource
123 //
124 pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
125 TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx;
126 pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa;
127 BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa);
128
129 // copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
130 hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
131
132 NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHeaderLen);
133
134 pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
135 pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
136
137 //
138 // build Tx Descriptor
139 //
140 #ifndef RT_BIG_ENDIAN
141 pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
142 #else
143 pDestTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
144 TxD = *pDestTxD;
145 pTxD = &TxD;
146 #endif
147 NdisZeroMemory(pTxD, TXD_SIZE);
148
149 pTxD->SDPtr0 = BufBasePaLow;
150 pTxD->SDLen0 = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; // include padding
151 pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);;
152 pTxD->SDLen1 = pTxBlk->SrcBufLen;
153 pTxD->LastSec0 = 0;
154 pTxD->LastSec1 = (bIsLast) ? 1 : 0;
155
156 RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
157 #ifdef RT_BIG_ENDIAN
158 RTMPWIEndianChange((PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE), TYPE_TXWI);
159 RTMPFrameEndianChange(pAd, (PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE);
160 RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD);
161 WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD);
162 #endif // RT_BIG_ENDIAN //
163
164 RetTxIdx = TxIdx;
165 //
166 // Update Tx index
167 //
168 INC_RING_INDEX(TxIdx, TX_RING_SIZE);
169 pTxRing->TxCpuIdx = TxIdx;
170
171 *FreeNumber -= 1;
172
173 return RetTxIdx;
174 }
175
176
RtmpPCI_WriteMultiTxResource(IN PRTMP_ADAPTER pAd,IN TX_BLK * pTxBlk,IN UCHAR frameNum,OUT USHORT * FreeNumber)177 USHORT RtmpPCI_WriteMultiTxResource(
178 IN PRTMP_ADAPTER pAd,
179 IN TX_BLK *pTxBlk,
180 IN UCHAR frameNum,
181 OUT USHORT *FreeNumber)
182 {
183 BOOLEAN bIsLast;
184 UCHAR *pDMAHeaderBufVA;
185 USHORT TxIdx, RetTxIdx;
186 PTXD_STRUC pTxD;
187 #ifdef RT_BIG_ENDIAN
188 PTXD_STRUC pDestTxD;
189 TXD_STRUC TxD;
190 #endif
191 UINT32 BufBasePaLow;
192 PRTMP_TX_RING pTxRing;
193 USHORT hwHdrLen;
194 UINT32 firstDMALen;
195
196 bIsLast = ((frameNum == (pTxBlk->TotalFrameNum - 1)) ? 1 : 0);
197
198 //
199 // get Tx Ring Resource
200 //
201 pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
202 TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx;
203 pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa;
204 BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa);
205
206 if (frameNum == 0)
207 {
208 // copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
209 if (pTxBlk->TxFrameType == TX_AMSDU_FRAME)
210 //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD, 4)+LENGTH_AMSDU_SUBFRAMEHEAD;
211 hwHdrLen = pTxBlk->MpduHeaderLen - LENGTH_AMSDU_SUBFRAMEHEAD + pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD;
212 else if (pTxBlk->TxFrameType == TX_RALINK_FRAME)
213 //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_ARALINK_HEADER_FIELD, 4)+LENGTH_ARALINK_HEADER_FIELD;
214 hwHdrLen = pTxBlk->MpduHeaderLen - LENGTH_ARALINK_HEADER_FIELD + pTxBlk->HdrPadLen + LENGTH_ARALINK_HEADER_FIELD;
215 else
216 //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4);
217 hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
218
219 firstDMALen = TXINFO_SIZE + TXWI_SIZE + hwHdrLen;
220 }
221 else
222 {
223 firstDMALen = pTxBlk->MpduHeaderLen;
224 }
225
226 NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, firstDMALen);
227
228 pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
229 pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
230
231 //
232 // build Tx Descriptor
233 //
234 #ifndef RT_BIG_ENDIAN
235 pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
236 #else
237 pDestTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
238 TxD = *pDestTxD;
239 pTxD = &TxD;
240 #endif
241 NdisZeroMemory(pTxD, TXD_SIZE);
242
243 pTxD->SDPtr0 = BufBasePaLow;
244 pTxD->SDLen0 = firstDMALen; // include padding
245 pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);;
246 pTxD->SDLen1 = pTxBlk->SrcBufLen;
247 pTxD->LastSec0 = 0;
248 pTxD->LastSec1 = (bIsLast) ? 1 : 0;
249
250 RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
251
252 #ifdef RT_BIG_ENDIAN
253 if (frameNum == 0)
254 RTMPFrameEndianChange(pAd, (PUCHAR)(pDMAHeaderBufVA+ TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE);
255
256 if (frameNum != 0)
257 RTMPWIEndianChange((PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE), TYPE_TXWI);
258
259 RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD);
260 WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD);
261 #endif // RT_BIG_ENDIAN //
262
263 RetTxIdx = TxIdx;
264 //
265 // Update Tx index
266 //
267 INC_RING_INDEX(TxIdx, TX_RING_SIZE);
268 pTxRing->TxCpuIdx = TxIdx;
269
270 *FreeNumber -= 1;
271
272 return RetTxIdx;
273
274 }
275
276
RtmpPCI_FinalWriteTxResource(IN PRTMP_ADAPTER pAd,IN TX_BLK * pTxBlk,IN USHORT totalMPDUSize,IN USHORT FirstTxIdx)277 VOID RtmpPCI_FinalWriteTxResource(
278 IN PRTMP_ADAPTER pAd,
279 IN TX_BLK *pTxBlk,
280 IN USHORT totalMPDUSize,
281 IN USHORT FirstTxIdx)
282 {
283
284 PTXWI_STRUC pTxWI;
285 PRTMP_TX_RING pTxRing;
286
287 //
288 // get Tx Ring Resource
289 //
290 pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
291 pTxWI = (PTXWI_STRUC) pTxRing->Cell[FirstTxIdx].DmaBuf.AllocVa;
292 pTxWI->MPDUtotalByteCount = totalMPDUSize;
293 #ifdef RT_BIG_ENDIAN
294 RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI);
295 #endif // RT_BIG_ENDIAN //
296
297 }
298
299
RtmpPCIDataLastTxIdx(IN PRTMP_ADAPTER pAd,IN UCHAR QueIdx,IN USHORT LastTxIdx)300 VOID RtmpPCIDataLastTxIdx(
301 IN PRTMP_ADAPTER pAd,
302 IN UCHAR QueIdx,
303 IN USHORT LastTxIdx)
304 {
305 PTXD_STRUC pTxD;
306 #ifdef RT_BIG_ENDIAN
307 PTXD_STRUC pDestTxD;
308 TXD_STRUC TxD;
309 #endif
310 PRTMP_TX_RING pTxRing;
311
312 //
313 // get Tx Ring Resource
314 //
315 pTxRing = &pAd->TxRing[QueIdx];
316
317 //
318 // build Tx Descriptor
319 //
320 #ifndef RT_BIG_ENDIAN
321 pTxD = (PTXD_STRUC) pTxRing->Cell[LastTxIdx].AllocVa;
322 #else
323 pDestTxD = (PTXD_STRUC) pTxRing->Cell[LastTxIdx].AllocVa;
324 TxD = *pDestTxD;
325 pTxD = &TxD;
326 #endif
327
328 pTxD->LastSec1 = 1;
329
330 #ifdef RT_BIG_ENDIAN
331 RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD);
332 WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD);
333 #endif // RT_BIG_ENDIAN //
334
335 }
336
337
RtmpPCI_WriteFragTxResource(IN PRTMP_ADAPTER pAd,IN TX_BLK * pTxBlk,IN UCHAR fragNum,OUT USHORT * FreeNumber)338 USHORT RtmpPCI_WriteFragTxResource(
339 IN PRTMP_ADAPTER pAd,
340 IN TX_BLK *pTxBlk,
341 IN UCHAR fragNum,
342 OUT USHORT *FreeNumber)
343 {
344 UCHAR *pDMAHeaderBufVA;
345 USHORT TxIdx, RetTxIdx;
346 PTXD_STRUC pTxD;
347 #ifdef RT_BIG_ENDIAN
348 PTXD_STRUC pDestTxD;
349 TXD_STRUC TxD;
350 #endif
351 UINT32 BufBasePaLow;
352 PRTMP_TX_RING pTxRing;
353 USHORT hwHeaderLen;
354 UINT32 firstDMALen;
355
356 //
357 // Get Tx Ring Resource
358 //
359 pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
360 TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx;
361 pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa;
362 BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa);
363
364 //
365 // Copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
366 //
367 hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
368
369 firstDMALen = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen;
370 NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, firstDMALen);
371
372
373 //
374 // Build Tx Descriptor
375 //
376 #ifndef RT_BIG_ENDIAN
377 pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
378 #else
379 pDestTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
380 TxD = *pDestTxD;
381 pTxD = &TxD;
382 #endif
383 NdisZeroMemory(pTxD, TXD_SIZE);
384
385 if (fragNum == pTxBlk->TotalFragNum)
386 {
387 pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
388 pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
389 }
390
391 pTxD->SDPtr0 = BufBasePaLow;
392 pTxD->SDLen0 = firstDMALen; // include padding
393 pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);
394 pTxD->SDLen1 = pTxBlk->SrcBufLen;
395 pTxD->LastSec0 = 0;
396 pTxD->LastSec1 = 1;
397
398 RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
399
400 #ifdef RT_BIG_ENDIAN
401 RTMPWIEndianChange((PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE), TYPE_TXWI);
402 RTMPFrameEndianChange(pAd, (PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE);
403 RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD);
404 WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD);
405 #endif // RT_BIG_ENDIAN //
406
407 RetTxIdx = TxIdx;
408 pTxBlk->Priv += pTxBlk->SrcBufLen;
409
410 //
411 // Update Tx index
412 //
413 INC_RING_INDEX(TxIdx, TX_RING_SIZE);
414 pTxRing->TxCpuIdx = TxIdx;
415
416 *FreeNumber -= 1;
417
418 return RetTxIdx;
419
420 }
421
422 /*
423 Must be run in Interrupt context
424 This function handle PCI specific TxDesc and cpu index update and kick the packet out.
425 */
RtmpPCIMgmtKickOut(IN RTMP_ADAPTER * pAd,IN UCHAR QueIdx,IN PNDIS_PACKET pPacket,IN PUCHAR pSrcBufVA,IN UINT SrcBufLen)426 int RtmpPCIMgmtKickOut(
427 IN RTMP_ADAPTER *pAd,
428 IN UCHAR QueIdx,
429 IN PNDIS_PACKET pPacket,
430 IN PUCHAR pSrcBufVA,
431 IN UINT SrcBufLen)
432 {
433 PTXD_STRUC pTxD;
434 #ifdef RT_BIG_ENDIAN
435 PTXD_STRUC pDestTxD;
436 TXD_STRUC TxD;
437 #endif
438 ULONG SwIdx = pAd->MgmtRing.TxCpuIdx;
439
440 #ifdef RT_BIG_ENDIAN
441 pDestTxD = (PTXD_STRUC)pAd->MgmtRing.Cell[SwIdx].AllocVa;
442 TxD = *pDestTxD;
443 pTxD = &TxD;
444 RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD);
445 #else
446 pTxD = (PTXD_STRUC) pAd->MgmtRing.Cell[SwIdx].AllocVa;
447 #endif
448
449 pAd->MgmtRing.Cell[SwIdx].pNdisPacket = pPacket;
450 pAd->MgmtRing.Cell[SwIdx].pNextNdisPacket = NULL;
451
452 RTMPWriteTxDescriptor(pAd, pTxD, TRUE, FIFO_MGMT);
453 pTxD->LastSec0 = 1;
454 pTxD->LastSec1 = 1;
455 pTxD->DMADONE = 0;
456 pTxD->SDLen1 = 0;
457 pTxD->SDPtr0 = PCI_MAP_SINGLE(pAd, pSrcBufVA, SrcBufLen, 0, PCI_DMA_TODEVICE);;
458 pTxD->SDLen0 = SrcBufLen;
459
460 #ifdef RT_BIG_ENDIAN
461 RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD);
462 WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD);
463 #endif
464
465 pAd->RalinkCounters.KickTxCount++;
466 pAd->RalinkCounters.OneSecTxDoneCount++;
467
468 // Increase TX_CTX_IDX, but write to register later.
469 INC_RING_INDEX(pAd->MgmtRing.TxCpuIdx, MGMT_RING_SIZE);
470
471 RTMP_IO_WRITE32(pAd, TX_MGMTCTX_IDX, pAd->MgmtRing.TxCpuIdx);
472
473 return 0;
474 }
475
476
477 #ifdef CONFIG_STA_SUPPORT
478 /*
479 ========================================================================
480
481 Routine Description:
482 Check Rx descriptor, return NDIS_STATUS_FAILURE if any error dound
483
484 Arguments:
485 pRxD Pointer to the Rx descriptor
486
487 Return Value:
488 NDIS_STATUS_SUCCESS No err
489 NDIS_STATUS_FAILURE Error
490
491 Note:
492
493 ========================================================================
494 */
RTMPCheckRxError(IN PRTMP_ADAPTER pAd,IN PHEADER_802_11 pHeader,IN PRXWI_STRUC pRxWI,IN PRT28XX_RXD_STRUC pRxD)495 NDIS_STATUS RTMPCheckRxError(
496 IN PRTMP_ADAPTER pAd,
497 IN PHEADER_802_11 pHeader,
498 IN PRXWI_STRUC pRxWI,
499 IN PRT28XX_RXD_STRUC pRxD)
500 {
501 PCIPHER_KEY pWpaKey;
502 INT dBm;
503
504 // Phy errors & CRC errors
505 if (/*(pRxD->PhyErr) ||*/ (pRxD->Crc))
506 {
507 // Check RSSI for Noise Hist statistic collection.
508 dBm = (INT) (pRxWI->RSSI0) - pAd->BbpRssiToDbmDelta;
509 if (dBm <= -87)
510 pAd->StaCfg.RPIDensity[0] += 1;
511 else if (dBm <= -82)
512 pAd->StaCfg.RPIDensity[1] += 1;
513 else if (dBm <= -77)
514 pAd->StaCfg.RPIDensity[2] += 1;
515 else if (dBm <= -72)
516 pAd->StaCfg.RPIDensity[3] += 1;
517 else if (dBm <= -67)
518 pAd->StaCfg.RPIDensity[4] += 1;
519 else if (dBm <= -62)
520 pAd->StaCfg.RPIDensity[5] += 1;
521 else if (dBm <= -57)
522 pAd->StaCfg.RPIDensity[6] += 1;
523 else if (dBm > -57)
524 pAd->StaCfg.RPIDensity[7] += 1;
525
526 return(NDIS_STATUS_FAILURE);
527 }
528
529 // Add Rx size to channel load counter, we should ignore error counts
530 pAd->StaCfg.CLBusyBytes += (pRxD->SDL0 + 14);
531
532 // Drop ToDs promiscous frame, it is opened due to CCX 2 channel load statistics
533 if (pHeader != NULL)
534 {
535 if (pHeader->FC.ToDs)
536 {
537 return(NDIS_STATUS_FAILURE);
538 }
539 }
540
541 // Drop not U2M frames, cant's drop here because we will drop beacon in this case
542 // I am kind of doubting the U2M bit operation
543 // if (pRxD->U2M == 0)
544 // return(NDIS_STATUS_FAILURE);
545
546 // drop decyption fail frame
547 if (pRxD->CipherErr)
548 {
549 if (pRxD->CipherErr == 2)
550 {DBGPRINT_RAW(RT_DEBUG_TRACE,("pRxD ERROR: ICV ok but MICErr "));}
551 else if (pRxD->CipherErr == 1)
552 {DBGPRINT_RAW(RT_DEBUG_TRACE,("pRxD ERROR: ICV Err "));}
553 else if (pRxD->CipherErr == 3)
554 DBGPRINT_RAW(RT_DEBUG_TRACE,("pRxD ERROR: Key not valid "));
555
556 if (((pRxD->CipherErr & 1) == 1) && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd))
557 RTMPSendWirelessEvent(pAd, IW_ICV_ERROR_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
558
559 DBGPRINT_RAW(RT_DEBUG_TRACE,(" %d (len=%d, Mcast=%d, MyBss=%d, Wcid=%d, KeyId=%d)\n",
560 pRxD->CipherErr,
561 pRxD->SDL0,
562 pRxD->Mcast | pRxD->Bcast,
563 pRxD->MyBss,
564 pRxWI->WirelessCliID,
565 pRxWI->KeyIndex));
566
567 //
568 // MIC Error
569 //
570 if (pRxD->CipherErr == 2)
571 {
572 pWpaKey = &pAd->SharedKey[BSS0][pRxWI->KeyIndex];
573 #ifdef WPA_SUPPLICANT_SUPPORT
574 if (pAd->StaCfg.WpaSupplicantUP)
575 WpaSendMicFailureToWpaSupplicant(pAd,
576 (pWpaKey->Type == PAIRWISEKEY) ? TRUE:FALSE);
577 else
578 #endif // WPA_SUPPLICANT_SUPPORT //
579 RTMPReportMicError(pAd, pWpaKey);
580
581 if (((pRxD->CipherErr & 2) == 2) && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd))
582 RTMPSendWirelessEvent(pAd, IW_MIC_ERROR_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
583
584 DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error\n"));
585 }
586
587 if (pHeader == NULL)
588 return(NDIS_STATUS_SUCCESS);
589
590 return(NDIS_STATUS_FAILURE);
591 }
592
593 return(NDIS_STATUS_SUCCESS);
594 }
595
596 /*
597 ==========================================================================
598 Description:
599 This routine sends command to firmware and turn our chip to power save mode.
600 Both RadioOff and .11 power save function needs to call this routine.
601 Input:
602 Level = GUIRADIO_OFF : GUI Radio Off mode
603 Level = DOT11POWERSAVE : 802.11 power save mode
604 Level = RTMP_HALT : When Disable device.
605
606 ==========================================================================
607 */
RT28xxPciAsicRadioOff(IN PRTMP_ADAPTER pAd,IN UCHAR Level,IN USHORT TbttNumToNextWakeUp)608 VOID RT28xxPciAsicRadioOff(
609 IN PRTMP_ADAPTER pAd,
610 IN UCHAR Level,
611 IN USHORT TbttNumToNextWakeUp)
612 {
613 WPDMA_GLO_CFG_STRUC DmaCfg;
614 UCHAR i, tempBBP_R3 = 0;
615 BOOLEAN brc = FALSE, Cancelled;
616 UINT32 TbTTTime = 0;
617 UINT32 PsPollTime = 0, MACValue;
618 ULONG BeaconPeriodTime;
619 UINT32 RxDmaIdx, RxCpuIdx;
620 DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> TxCpuIdx = %d, TxDmaIdx = %d. RxCpuIdx = %d, RxDmaIdx = %d.\n", pAd->TxRing[0].TxCpuIdx, pAd->TxRing[0].TxDmaIdx, pAd->RxRing.RxCpuIdx, pAd->RxRing.RxDmaIdx));
621
622 // Check Rx DMA busy status, if more than half is occupied, give up this radio off.
623 RTMP_IO_READ32(pAd, RX_DRX_IDX , &RxDmaIdx);
624 RTMP_IO_READ32(pAd, RX_CRX_IDX , &RxCpuIdx);
625 if ((RxDmaIdx > RxCpuIdx) && ((RxDmaIdx - RxCpuIdx) > RX_RING_SIZE/3))
626 {
627 DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return1. RxDmaIdx = %d , RxCpuIdx = %d. \n", RxDmaIdx, RxCpuIdx));
628 return;
629 }
630 else if ((RxCpuIdx >= RxDmaIdx) && ((RxCpuIdx - RxDmaIdx) < RX_RING_SIZE/3))
631 {
632 DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return2. RxCpuIdx = %d. RxDmaIdx = %d , \n", RxCpuIdx, RxDmaIdx));
633 return;
634 }
635
636 // Once go into this function, disable tx because don't want too many packets in queue to prevent HW stops.
637 pAd->bPCIclkOffDisableTx = TRUE;
638
639 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
640 {
641 RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
642 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
643
644 if (Level == DOT11POWERSAVE)
645 {
646 RTMP_IO_READ32(pAd, TBTT_TIMER, &TbTTTime);
647 TbTTTime &= 0x1ffff;
648 // 00. check if need to do sleep in this DTIM period. If next beacon will arrive within 30ms , ...doesn't necessarily sleep.
649 // TbTTTime uint = 64us, LEAD_TIME unit = 1024us, PsPollTime unit = 1ms
650 if (((64*TbTTTime) <((LEAD_TIME*1024) + 40000)) && (TbttNumToNextWakeUp == 0))
651 {
652 DBGPRINT(RT_DEBUG_TRACE, ("TbTTTime = 0x%x , give up this sleep. \n", TbTTTime));
653 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
654 pAd->bPCIclkOffDisableTx = FALSE;
655 return;
656 }
657 else
658 {
659 PsPollTime = (64*TbTTTime- LEAD_TIME*1024)/1000;
660 PsPollTime -= 3;
661
662 BeaconPeriodTime = pAd->CommonCfg.BeaconPeriod*102/100;
663 if (TbttNumToNextWakeUp > 0)
664 PsPollTime += ((TbttNumToNextWakeUp -1) * BeaconPeriodTime);
665
666 pAd->Mlme.bPsPollTimerRunning = TRUE;
667 RTMPSetTimer(&pAd->Mlme.PsPollTimer, PsPollTime);
668 }
669 }
670 }
671
672 // 0. Disable Tx DMA.
673 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
674 DmaCfg.field.EnableTxDMA = 0;
675 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
676
677 // 1. Wait DMA not busy
678 i = 0;
679 do
680 {
681 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
682 if ((DmaCfg.field.TxDMABusy == 0) && (DmaCfg.field.RxDMABusy == 0))
683 break;
684 RTMPusecDelay(20);
685 i++;
686 }while(i < 50);
687
688 if (i >= 50)
689 {
690 DBGPRINT(RT_DEBUG_TRACE, ("DMA keeps busy. return on RT28xxPciAsicRadioOff ()\n"));
691 pAd->bPCIclkOffDisableTx = FALSE;
692 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
693 DmaCfg.field.EnableTxDMA = 1;
694 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
695 return;
696 }
697
698 RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
699
700 // Set to 1R.
701 tempBBP_R3 = (pAd->StaCfg.BBPR3 & 0xE7);
702 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, tempBBP_R3);
703
704 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
705 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
706 && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
707 {
708 // Must using 40MHz.
709 AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel);
710 }
711 else
712 {
713 // Must using 20MHz.
714 AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel);
715 }
716
717 // When PCI clock is off, don't want to service interrupt.
718 RTMP_IO_WRITE32(pAd, INT_MASK_CSR, AutoWakeupInt);
719
720 RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx);
721 // Disable MAC Rx
722 RTMP_IO_READ32(pAd, MAC_SYS_CTRL , &MACValue);
723 MACValue &= 0xf7;
724 RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL , MACValue);
725
726 // 2. Send Sleep command
727 RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff);
728 RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff);
729 AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x00); // send POWER-SAVE command to MCU. Timeout unit:40us.
730 // 2-1. Wait command success
731 // Status = 1 : success, Status = 2, already sleep, Status = 3, Maybe MAC is busy so can't finish this task.
732 brc = AsicCheckCommanOk(pAd, PowerSafeCID);
733
734 if (brc == FALSE)
735 {
736 // try again
737 AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x00); // send POWER-SAVE command to MCU. Timeout unit:40us.
738 //RTMPusecDelay(200);
739 brc = AsicCheckCommanOk(pAd, PowerSafeCID);
740 }
741
742 // 3. After 0x30 command is ok, send radio off command. lowbyte = 0 for power safe.
743 // If 0x30 command is not ok this time, we can ignore 0x35 command. It will make sure not cause firmware'r problem.
744 if ((Level == DOT11POWERSAVE) && (brc == TRUE))
745 {
746 AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 0, 0x00); // lowbyte = 0 means to do power safe, NOT turn off radio.
747 // 3-1. Wait command success
748 AsicCheckCommanOk(pAd, PowerRadioOffCID);
749 }
750 else if (brc == TRUE)
751 {
752 AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 1, 0x00); // lowbyte = 0 means to do power safe, NOT turn off radio.
753 // 3-1. Wait command success
754 AsicCheckCommanOk(pAd, PowerRadioOffCID);
755 }
756
757 // Wait DMA not busy
758 i = 0;
759 do
760 {
761 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
762 if (DmaCfg.field.RxDMABusy == 0)
763 break;
764 RTMPusecDelay(20);
765 i++;
766 }while(i < 50);
767
768 if (i >= 50)
769 {
770 DBGPRINT(RT_DEBUG_TRACE, ("DMA Rx keeps busy. on RT28xxPciAsicRadioOff ()\n"));
771 }
772 // disable DMA Rx.
773 {
774 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
775 DmaCfg.field.EnableRxDMA = 0;
776 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
777 }
778
779 if (Level == DOT11POWERSAVE)
780 {
781 AUTO_WAKEUP_STRUC AutoWakeupCfg;
782 //RTMPSetTimer(&pAd->Mlme.PsPollTimer, 90);
783
784 // we have decided to SLEEP, so at least do it for a BEACON period.
785 if (TbttNumToNextWakeUp == 0)
786 TbttNumToNextWakeUp = 1;
787
788 AutoWakeupCfg.word = 0;
789 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
790
791 // 1. Set auto wake up timer.
792 AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1;
793 AutoWakeupCfg.field.EnableAutoWakeup = 1;
794 AutoWakeupCfg.field.AutoLeadTime = LEAD_TIME;
795 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
796 }
797
798 // 4-1. If it's to disable our device. Need to restore PCI Configuration Space to its original value.
799 if (Level == RTMP_HALT)
800 {
801 if ((brc == TRUE) && (i < 50))
802 RTMPPCIeLinkCtrlSetting(pAd, 1);
803 }
804 // 4. Set PCI configuration Space Link Comtrol fields. Only Radio Off needs to call this function
805 else
806 {
807 if ((brc == TRUE) && (i < 50))
808 RTMPPCIeLinkCtrlSetting(pAd, 3);
809 }
810
811 pAd->bPCIclkOffDisableTx = FALSE;
812 }
813
814
815 /*
816 ==========================================================================
817 Description:
818 This routine sends command to firmware and turn our chip to wake up mode from power save mode.
819 Both RadioOn and .11 power save function needs to call this routine.
820 Input:
821 Level = GUIRADIO_OFF : call this function is from Radio Off to Radio On. Need to restore PCI host value.
822 Level = other value : normal wake up function.
823
824 ==========================================================================
825 */
RT28xxPciAsicRadioOn(IN PRTMP_ADAPTER pAd,IN UCHAR Level)826 BOOLEAN RT28xxPciAsicRadioOn(
827 IN PRTMP_ADAPTER pAd,
828 IN UCHAR Level)
829 {
830 WPDMA_GLO_CFG_STRUC DmaCfg;
831 BOOLEAN Cancelled, brv = TRUE;
832 UINT32 MACValue;
833
834 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
835 {
836 pAd->Mlme.bPsPollTimerRunning = FALSE;
837 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
838 if ((Level == GUIRADIO_OFF) || (Level == GUI_IDLE_POWER_SAVE))
839 {
840 DBGPRINT(RT_DEBUG_TRACE, ("RT28xxPciAsicRadioOn ()\n"));
841 // 1. Set PCI Link Control in Configuration Space.
842 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
843 RTMPusecDelay(6000);
844 }
845 }
846
847 pAd->bPCIclkOff = FALSE;
848
849 // 2. Send wake up command.
850 AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x00);
851
852 // 2-1. wait command ok.
853 brv = AsicCheckCommanOk(pAd, PowerWakeCID);
854 if (brv)
855 {
856 //RTMP_IO_WRITE32(pAd, INT_MASK_CSR, (DELAYINTMASK|RxINT));
857 NICEnableInterrupt(pAd);
858
859 // 3. Enable Tx DMA.
860 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
861 DmaCfg.field.EnableTxDMA = 1;
862 DmaCfg.field.EnableRxDMA = 1;
863 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
864
865 // Eable MAC Rx
866 RTMP_IO_READ32(pAd, MAC_SYS_CTRL , &MACValue);
867 MACValue |= 0x8;
868 RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL , MACValue);
869
870 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
871 if (Level == GUI_IDLE_POWER_SAVE)
872 {
873 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
874 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
875 && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
876 {
877 // Must using 40MHz.
878 AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
879 AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
880 }
881 else
882 {
883 // Must using 20MHz.
884 AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
885 AsicLockChannel(pAd, pAd->CommonCfg.Channel);
886 }
887 }
888 return TRUE;
889 }
890 else
891 return FALSE;
892 }
893
RT28xxPciStaAsicForceWakeup(IN PRTMP_ADAPTER pAd,IN BOOLEAN bFromTx)894 VOID RT28xxPciStaAsicForceWakeup(
895 IN PRTMP_ADAPTER pAd,
896 IN BOOLEAN bFromTx)
897 {
898 AUTO_WAKEUP_STRUC AutoWakeupCfg;
899
900 if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
901 return;
902
903 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
904 {
905 DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
906 return;
907 }
908
909 OPSTATUS_SET_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
910
911 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
912 {
913 // Support PCIe Advance Power Save
914 if (bFromTx == TRUE)
915 {
916 pAd->Mlme.bPsPollTimerRunning = FALSE;
917 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
918 RTMPusecDelay(3000);
919 DBGPRINT(RT_DEBUG_TRACE, ("=======AsicForceWakeup===bFromTx\n"));
920 }
921
922 AutoWakeupCfg.word = 0;
923 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
924
925 if (RT28xxPciAsicRadioOn(pAd, DOT11POWERSAVE))
926 {
927 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
928 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
929 && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
930 {
931 // Must using 40MHz.
932 AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
933 AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
934 }
935 else
936 {
937 // Must using 20MHz.
938 AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
939 AsicLockChannel(pAd, pAd->CommonCfg.Channel);
940 }
941 }
942 }
943 else
944 {
945 // PCI, 2860-PCIe
946 AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x00);
947 AutoWakeupCfg.word = 0;
948 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
949 }
950
951 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
952 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
953 DBGPRINT(RT_DEBUG_TRACE, ("<=======RT28xxPciStaAsicForceWakeup\n"));
954 }
955
RT28xxPciStaAsicSleepThenAutoWakeup(IN PRTMP_ADAPTER pAd,IN USHORT TbttNumToNextWakeUp)956 VOID RT28xxPciStaAsicSleepThenAutoWakeup(
957 IN PRTMP_ADAPTER pAd,
958 IN USHORT TbttNumToNextWakeUp)
959 {
960 if (pAd->StaCfg.bRadio == FALSE)
961 {
962 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
963 return;
964 }
965 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
966 {
967 ULONG Now = 0;
968 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
969 {
970 DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
971 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
972 return;
973 }
974
975 NdisGetSystemUpTime(&Now);
976 // If last send NULL fram time is too close to this receiving beacon (within 8ms), don't go to sleep for this DTM.
977 // Because Some AP can't queuing outgoing frames immediately.
978 if (((pAd->Mlme.LastSendNULLpsmTime + 8) >= Now) && (pAd->Mlme.LastSendNULLpsmTime <= Now))
979 {
980 DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu : RxCountSinceLastNULL = %lu. \n", Now, pAd->Mlme.LastSendNULLpsmTime, pAd->RalinkCounters.RxCountSinceLastNULL));
981 return;
982 }
983 else if ((pAd->RalinkCounters.RxCountSinceLastNULL > 0) && ((pAd->Mlme.LastSendNULLpsmTime + pAd->CommonCfg.BeaconPeriod) >= Now))
984 {
985 DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu: RxCountSinceLastNULL = %lu > 0 \n", Now, pAd->Mlme.LastSendNULLpsmTime, pAd->RalinkCounters.RxCountSinceLastNULL));
986 return;
987 }
988
989 RT28xxPciAsicRadioOff(pAd, DOT11POWERSAVE, TbttNumToNextWakeUp);
990 }
991 else
992 {
993 AUTO_WAKEUP_STRUC AutoWakeupCfg;
994 // we have decided to SLEEP, so at least do it for a BEACON period.
995 if (TbttNumToNextWakeUp == 0)
996 TbttNumToNextWakeUp = 1;
997
998 AutoWakeupCfg.word = 0;
999 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
1000 AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1;
1001 AutoWakeupCfg.field.EnableAutoWakeup = 1;
1002 AutoWakeupCfg.field.AutoLeadTime = 5;
1003 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
1004 AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x00); // send POWER-SAVE command to MCU. Timeout 40us.
1005 DBGPRINT(RT_DEBUG_TRACE, ("<-- %s, TbttNumToNextWakeUp=%d \n", __func__, TbttNumToNextWakeUp));
1006 }
1007 OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE);
1008 }
1009
PsPollWakeExec(IN PVOID SystemSpecific1,IN PVOID FunctionContext,IN PVOID SystemSpecific2,IN PVOID SystemSpecific3)1010 VOID PsPollWakeExec(
1011 IN PVOID SystemSpecific1,
1012 IN PVOID FunctionContext,
1013 IN PVOID SystemSpecific2,
1014 IN PVOID SystemSpecific3)
1015 {
1016 RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
1017 unsigned long flags;
1018
1019 DBGPRINT(RT_DEBUG_TRACE,("-->PsPollWakeExec \n"));
1020 RTMP_INT_LOCK(&pAd->irq_lock, flags);
1021 if (pAd->Mlme.bPsPollTimerRunning)
1022 {
1023 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
1024 }
1025 pAd->Mlme.bPsPollTimerRunning = FALSE;
1026 RTMP_INT_UNLOCK(&pAd->irq_lock, flags);
1027 }
1028
RadioOnExec(IN PVOID SystemSpecific1,IN PVOID FunctionContext,IN PVOID SystemSpecific2,IN PVOID SystemSpecific3)1029 VOID RadioOnExec(
1030 IN PVOID SystemSpecific1,
1031 IN PVOID FunctionContext,
1032 IN PVOID SystemSpecific2,
1033 IN PVOID SystemSpecific3)
1034 {
1035 RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
1036 WPDMA_GLO_CFG_STRUC DmaCfg;
1037 BOOLEAN Cancelled;
1038
1039 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
1040 {
1041 DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on fOP_STATUS_DOZE == TRUE; \n"));
1042 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1043 return;
1044 }
1045
1046 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
1047 {
1048 DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on SCAN_IN_PROGRESS; \n"));
1049 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1050 return;
1051 }
1052 pAd->Mlme.bPsPollTimerRunning = FALSE;
1053 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1054 if (pAd->StaCfg.bRadio == TRUE)
1055 {
1056 pAd->bPCIclkOff = FALSE;
1057 RTMPRingCleanUp(pAd, QID_AC_BK);
1058 RTMPRingCleanUp(pAd, QID_AC_BE);
1059 RTMPRingCleanUp(pAd, QID_AC_VI);
1060 RTMPRingCleanUp(pAd, QID_AC_VO);
1061 RTMPRingCleanUp(pAd, QID_HCCA);
1062 RTMPRingCleanUp(pAd, QID_MGMT);
1063 RTMPRingCleanUp(pAd, QID_RX);
1064
1065 // 2. Send wake up command.
1066 AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02);
1067 // 2-1. wait command ok.
1068 AsicCheckCommanOk(pAd, PowerWakeCID);
1069
1070 // When PCI clock is off, don't want to service interrupt. So when back to clock on, enable interrupt.
1071 NICEnableInterrupt(pAd);
1072
1073 // 3. Enable Tx DMA.
1074 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
1075 DmaCfg.field.EnableTxDMA = 1;
1076 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
1077
1078 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
1079 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
1080 && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
1081 {
1082 // Must using 40MHz.
1083 AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
1084 AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
1085 }
1086 else
1087 {
1088 // Must using 20MHz.
1089 AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
1090 AsicLockChannel(pAd, pAd->CommonCfg.Channel);
1091 }
1092
1093 // Clear Radio off flag
1094 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1095
1096 // Set LED
1097 RTMPSetLED(pAd, LED_RADIO_ON);
1098
1099 if (pAd->StaCfg.Psm == PWR_ACTIVE)
1100 {
1101 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, pAd->StaCfg.BBPR3);
1102 }
1103 }
1104 else
1105 {
1106 RT28xxPciAsicRadioOff(pAd, GUIRADIO_OFF, 0);
1107 }
1108 }
1109
1110 #endif // CONFIG_STA_SUPPORT //
1111
RT28xxPciMlmeRadioOn(IN PRTMP_ADAPTER pAd)1112 VOID RT28xxPciMlmeRadioOn(
1113 IN PRTMP_ADAPTER pAd)
1114 {
1115 if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1116 return;
1117
1118 DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
1119
1120 if ((pAd->OpMode == OPMODE_AP) ||
1121 ((pAd->OpMode == OPMODE_STA) && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))))
1122 {
1123 NICResetFromError(pAd);
1124
1125 RTMPRingCleanUp(pAd, QID_AC_BK);
1126 RTMPRingCleanUp(pAd, QID_AC_BE);
1127 RTMPRingCleanUp(pAd, QID_AC_VI);
1128 RTMPRingCleanUp(pAd, QID_AC_VO);
1129 RTMPRingCleanUp(pAd, QID_HCCA);
1130 RTMPRingCleanUp(pAd, QID_MGMT);
1131 RTMPRingCleanUp(pAd, QID_RX);
1132
1133 // Enable Tx/Rx
1134 RTMPEnableRxTx(pAd);
1135
1136 // Clear Radio off flag
1137 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1138
1139 // Set LED
1140 RTMPSetLED(pAd, LED_RADIO_ON);
1141 }
1142
1143 #ifdef CONFIG_STA_SUPPORT
1144 if ((pAd->OpMode == OPMODE_STA) &&
1145 (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)))
1146 {
1147 BOOLEAN Cancelled;
1148
1149 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
1150
1151 pAd->Mlme.bPsPollTimerRunning = FALSE;
1152 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1153 RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
1154 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1155 }
1156 #endif // CONFIG_STA_SUPPORT //
1157 }
1158
RT28xxPciMlmeRadioOFF(IN PRTMP_ADAPTER pAd)1159 VOID RT28xxPciMlmeRadioOFF(
1160 IN PRTMP_ADAPTER pAd)
1161 {
1162 WPDMA_GLO_CFG_STRUC GloCfg;
1163 UINT32 i;
1164
1165 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1166 return;
1167
1168 DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
1169
1170 // Set LED
1171 RTMPSetLED(pAd, LED_RADIO_OFF);
1172 // Set Radio off flag
1173 RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1174
1175 #ifdef CONFIG_STA_SUPPORT
1176 IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
1177 {
1178 BOOLEAN Cancelled;
1179 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
1180 {
1181 RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled);
1182 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);
1183 }
1184
1185 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
1186 {
1187 BOOLEAN Cancelled;
1188 pAd->Mlme.bPsPollTimerRunning = FALSE;
1189 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1190 RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
1191 }
1192
1193 // Link down first if any association exists
1194 if (INFRA_ON(pAd) || ADHOC_ON(pAd))
1195 LinkDown(pAd, FALSE);
1196 RTMPusecDelay(10000);
1197 //==========================================
1198 // Clean up old bss table
1199 BssTableInit(&pAd->ScanTab);
1200 }
1201 #endif // CONFIG_STA_SUPPORT //
1202
1203 // Disable Tx/Rx DMA
1204 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); // disable DMA
1205 GloCfg.field.EnableTxDMA = 0;
1206 GloCfg.field.EnableRxDMA = 0;
1207 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); // abort all TX rings
1208
1209
1210 // MAC_SYS_CTRL => value = 0x0 => 40mA
1211 RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0);
1212
1213 // PWR_PIN_CFG => value = 0x0 => 40mA
1214 RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0);
1215
1216 // TX_PIN_CFG => value = 0x0 => 20mA
1217 RTMP_IO_WRITE32(pAd, TX_PIN_CFG, 0);
1218
1219 if (pAd->CommonCfg.BBPCurrentBW == BW_40)
1220 {
1221 // Must using 40MHz.
1222 AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel);
1223 }
1224 else
1225 {
1226 // Must using 20MHz.
1227 AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel);
1228 }
1229
1230 // Waiting for DMA idle
1231 i = 0;
1232 do
1233 {
1234 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
1235 if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0))
1236 break;
1237
1238 RTMPusecDelay(1000);
1239 }while (i++ < 100);
1240 }
1241