Staging: rt2860: Ported v1.7.1.1 changes into v1.8.0.0, becoming v1.8.1.1
[pandora-kernel.git] / drivers / staging / rt2860 / common / cmm_data_2860.c
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
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
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
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
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
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
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  */
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 */
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  */
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         RTMP_SET_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
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                                 RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
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                 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
692                 DmaCfg.field.EnableTxDMA = 1;
693                 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
694                 pAd->CheckDmaBusyCount++;
695                 return;
696         }
697         else
698         {
699                 pAd->CheckDmaBusyCount = 0;
700         }
701
702     RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
703
704     // Set to 1R.
705         if (pAd->Antenna.field.RxPath > 1)
706         {
707                 tempBBP_R3 = (pAd->StaCfg.BBPR3 & 0xE7);
708                 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, tempBBP_R3);
709         }
710
711         // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
712         if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
713                 && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
714         {
715                 // Must using 40MHz.
716                 AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel);
717         }
718         else
719         {
720                 // Must using 20MHz.
721                 AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel);
722         }
723
724         if (Level != RTMP_HALT)
725         {
726                 // Change Interrupt bitmask.
727                 RTMP_IO_WRITE32(pAd, INT_MASK_CSR, AutoWakeupInt);
728         }
729         else
730         {
731                 NICDisableInterrupt(pAd);
732         }
733
734     RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx);
735         // Disable MAC Rx
736         RTMP_IO_READ32(pAd, MAC_SYS_CTRL , &MACValue);
737         MACValue &= 0xf7;
738         RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL , MACValue);
739
740         //  2. Send Sleep command
741         RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff);
742         RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff);
743         // send POWER-SAVE command to MCU. high-byte = 1 save power as much as possible. high byte = 0 save less power
744         AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x1);
745         //  2-1. Wait command success
746         // Status = 1 : success, Status = 2, already sleep, Status = 3, Maybe MAC is busy so can't finish this task.
747         brc = AsicCheckCommanOk(pAd, PowerSafeCID);
748
749     if (brc == FALSE)
750     {
751         // try again
752         AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x01);   // send POWER-SAVE command to MCU. Timeout unit:40us.
753         //RTMPusecDelay(200);
754         brc = AsicCheckCommanOk(pAd, PowerSafeCID);
755     }
756
757         //  3. After 0x30 command is ok, send radio off command. lowbyte = 0 for power safe.
758         // If 0x30 command is not ok this time, we can ignore 0x35 command. It will make sure not cause firmware'r problem.
759         if ((Level == DOT11POWERSAVE) && (brc == TRUE))
760         {
761                 AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 0, 0x00);     // lowbyte = 0 means to do power safe, NOT turn off radio.
762                 //  3-1. Wait command success
763                 AsicCheckCommanOk(pAd, PowerRadioOffCID);
764         }
765         else if (brc == TRUE)
766         {
767                 AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 1, 0x00);     // lowbyte = 0 means to do power safe, NOT turn off radio.
768                 //  3-1. Wait command success
769                 AsicCheckCommanOk(pAd, PowerRadioOffCID);
770         }
771
772     // Wait DMA not busy
773         i = 0;
774         do
775         {
776                 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
777                 if ((DmaCfg.field.RxDMABusy == 0) && (DmaCfg.field.TxDMABusy == 0))
778                         break;
779                 RTMPusecDelay(20);
780                 i++;
781         }while(i < 50);
782
783         if (i >= 50)
784         {
785                 pAd->CheckDmaBusyCount++;
786                 DBGPRINT(RT_DEBUG_TRACE, ("DMA Rx keeps busy.  on RT28xxPciAsicRadioOff ()\n"));
787         }
788         else
789         {
790                 pAd->CheckDmaBusyCount = 0;
791         }
792
793         if (Level == DOT11POWERSAVE)
794         {
795                 AUTO_WAKEUP_STRUC       AutoWakeupCfg;
796                 //RTMPSetTimer(&pAd->Mlme.PsPollTimer, 90);
797
798                 // we have decided to SLEEP, so at least do it for a BEACON period.
799                 if (TbttNumToNextWakeUp == 0)
800                         TbttNumToNextWakeUp = 1;
801
802                 AutoWakeupCfg.word = 0;
803                 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
804
805                 // 1. Set auto wake up timer.
806                 AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1;
807                 AutoWakeupCfg.field.EnableAutoWakeup = 1;
808                 AutoWakeupCfg.field.AutoLeadTime = LEAD_TIME;
809                 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
810         }
811
812         //  4-1. If it's to disable our device. Need to restore PCI Configuration Space to its original value.
813         if (Level == RTMP_HALT)
814         {
815                 if ((brc == TRUE) && (i < 50))
816                         RTMPPCIeLinkCtrlSetting(pAd, 0);
817         }
818         //  4. Set PCI configuration Space Link Comtrol fields.  Only Radio Off needs to call this function
819         else
820         {
821                 if ((brc == TRUE) && (i < 50))
822                         RTMPPCIeLinkCtrlSetting(pAd, 3);
823         }
824
825         RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
826 }
827
828
829 /*
830         ==========================================================================
831         Description:
832                 This routine sends command to firmware and turn our chip to wake up mode from power save mode.
833                 Both RadioOn and .11 power save function needs to call this routine.
834         Input:
835                 Level = GUIRADIO_OFF : call this function is from Radio Off to Radio On.  Need to restore PCI host value.
836                 Level = other value : normal wake up function.
837
838         ==========================================================================
839  */
840 BOOLEAN RT28xxPciAsicRadioOn(
841         IN PRTMP_ADAPTER pAd,
842         IN UCHAR     Level)
843 {
844     WPDMA_GLO_CFG_STRUC DmaCfg;
845         BOOLEAN                         Cancelled, brv = TRUE;
846     UINT32                          MACValue;
847
848         if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
849         {
850             pAd->Mlme.bPsPollTimerRunning = FALSE;
851                 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
852                 if ((Level == GUIRADIO_OFF) || (Level == GUI_IDLE_POWER_SAVE)
853                 || (RTMP_TEST_PSFLAG(pAd, fRTMP_PS_SET_PCI_CLK_OFF_COMMAND)))
854                 {
855                         DBGPRINT(RT_DEBUG_TRACE, ("RT28xxPciAsicRadioOn ()\n"));
856                         // 1. Set PCI Link Control in Configuration Space.
857                         RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
858                         RTMPusecDelay(6000);
859                 }
860         }
861
862     pAd->bPCIclkOff = FALSE;
863         RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0x3a80);
864         // 2. Send wake up command.
865         AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02);
866
867         // 2-1. wait command ok.
868         brv = AsicCheckCommanOk(pAd, PowerWakeCID);
869     if (brv)
870     {
871         NICEnableInterrupt(pAd);
872
873         // 3. Enable Tx DMA.
874         RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
875         DmaCfg.field.EnableTxDMA = 1;
876         DmaCfg.field.EnableRxDMA = 1;
877         RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
878
879         // Eable MAC Rx
880         RTMP_IO_READ32(pAd, MAC_SYS_CTRL , &MACValue);
881         MACValue |= 0x8;
882         RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL , MACValue);
883
884         RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
885         if (Level == GUI_IDLE_POWER_SAVE)
886         {
887                 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
888                 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
889                         && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
890                 {
891                         // Must using 40MHz.
892                         AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
893                         AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
894                 }
895                 else
896                 {
897                         // Must using 20MHz.
898                         AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
899                         AsicLockChannel(pAd, pAd->CommonCfg.Channel);
900                 }
901         }
902         return TRUE;
903     }
904     else
905         return FALSE;
906 }
907
908 VOID RT28xxPciStaAsicForceWakeup(
909         IN PRTMP_ADAPTER pAd,
910         IN UCHAR         Level)
911 {
912     AUTO_WAKEUP_STRUC   AutoWakeupCfg;
913
914     if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
915     {
916         DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
917         return;
918     }
919
920     OPSTATUS_SET_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
921         RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW);
922
923     if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
924     {
925         // Support PCIe Advance Power Save
926         if (((Level == FROM_TX) && (pAd->Mlme.bPsPollTimerRunning == TRUE)) ||
927                         (Level == RTMP_HALT))
928         {
929             pAd->Mlme.bPsPollTimerRunning = FALSE;
930                 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
931                 RTMPusecDelay(5000);
932             DBGPRINT(RT_DEBUG_TRACE, ("=======AsicForceWakeup===bFromTx\n"));
933         }
934
935                 AutoWakeupCfg.word = 0;
936                 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
937
938                 // If this is called from Halt. ALWAYS force wakeup!!!
939                 if (Level == RTMP_HALT)
940                 {
941                         RT28xxPciAsicRadioOn(pAd, RTMP_HALT);
942                 }
943                 else
944                 {
945                         if (RT28xxPciAsicRadioOn(pAd, DOT11POWERSAVE))
946                         {
947                                 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
948                                 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
949                                         && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
950                                 {
951                                         // Must using 40MHz.
952                                         AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
953                                         AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
954                                 }
955                                 else
956                                 {
957                                         // Must using 20MHz.
958                                         AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
959                                         AsicLockChannel(pAd, pAd->CommonCfg.Channel);
960                                 }
961                         }
962                 }
963     }
964     else
965     {
966         // PCI, 2860-PCIe
967         AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x00);
968                 AutoWakeupCfg.word = 0;
969                 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
970     }
971
972     OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
973     OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
974     DBGPRINT(RT_DEBUG_TRACE, ("<=======RT28xxPciStaAsicForceWakeup\n"));
975 }
976
977 VOID RT28xxPciStaAsicSleepThenAutoWakeup(
978         IN PRTMP_ADAPTER pAd,
979         IN USHORT TbttNumToNextWakeUp)
980 {
981     if (pAd->StaCfg.bRadio == FALSE)
982         {
983                 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
984                 return;
985         }
986     if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
987     {
988         ULONG   Now = 0;
989         if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
990         {
991             DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
992             OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
993             return;
994         }
995
996                 NdisGetSystemUpTime(&Now);
997                 // If last send NULL fram time is too close to this receiving beacon (within 8ms), don't go to sleep for this DTM.
998                 // Because Some AP can't queuing outgoing frames immediately.
999                 if (((pAd->Mlme.LastSendNULLpsmTime + 8) >= Now) && (pAd->Mlme.LastSendNULLpsmTime <= Now))
1000                 {
1001                         DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu :  RxCountSinceLastNULL = %lu. \n", Now, pAd->Mlme.LastSendNULLpsmTime, pAd->RalinkCounters.RxCountSinceLastNULL));
1002                         return;
1003                 }
1004                 else if ((pAd->RalinkCounters.RxCountSinceLastNULL > 0) && ((pAd->Mlme.LastSendNULLpsmTime + pAd->CommonCfg.BeaconPeriod) >= Now))
1005                 {
1006                         DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu: RxCountSinceLastNULL = %lu > 0 \n", Now, pAd->Mlme.LastSendNULLpsmTime,  pAd->RalinkCounters.RxCountSinceLastNULL));
1007                         return;
1008                 }
1009
1010         RT28xxPciAsicRadioOff(pAd, DOT11POWERSAVE, TbttNumToNextWakeUp);
1011     }
1012     else
1013     {
1014         AUTO_WAKEUP_STRUC       AutoWakeupCfg;
1015         // we have decided to SLEEP, so at least do it for a BEACON period.
1016         if (TbttNumToNextWakeUp == 0)
1017             TbttNumToNextWakeUp = 1;
1018
1019         AutoWakeupCfg.word = 0;
1020         RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
1021         AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1;
1022         AutoWakeupCfg.field.EnableAutoWakeup = 1;
1023         AutoWakeupCfg.field.AutoLeadTime = 5;
1024         RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
1025         AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x00);   // send POWER-SAVE command to MCU. Timeout 40us.
1026         DBGPRINT(RT_DEBUG_TRACE, ("<-- %s, TbttNumToNextWakeUp=%d \n", __func__, TbttNumToNextWakeUp));
1027     }
1028     OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE);
1029 }
1030
1031 VOID PsPollWakeExec(
1032         IN PVOID SystemSpecific1,
1033         IN PVOID FunctionContext,
1034         IN PVOID SystemSpecific2,
1035         IN PVOID SystemSpecific3)
1036 {
1037         RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
1038         unsigned long flags;
1039
1040     DBGPRINT(RT_DEBUG_TRACE,("-->PsPollWakeExec \n"));
1041         RTMP_INT_LOCK(&pAd->irq_lock, flags);
1042     if (pAd->Mlme.bPsPollTimerRunning)
1043     {
1044             RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
1045     }
1046     pAd->Mlme.bPsPollTimerRunning = FALSE;
1047         RTMP_INT_UNLOCK(&pAd->irq_lock, flags);
1048 }
1049
1050 VOID  RadioOnExec(
1051         IN PVOID SystemSpecific1,
1052         IN PVOID FunctionContext,
1053         IN PVOID SystemSpecific2,
1054         IN PVOID SystemSpecific3)
1055 {
1056         RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
1057         WPDMA_GLO_CFG_STRUC     DmaCfg;
1058         BOOLEAN                         Cancelled;
1059
1060         if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
1061         {
1062                 DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on fOP_STATUS_DOZE == TRUE; \n"));
1063                 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1064                 return;
1065         }
1066
1067         if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
1068         {
1069                 DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on SCAN_IN_PROGRESS; \n"));
1070                 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1071                 return;
1072         }
1073     pAd->Mlme.bPsPollTimerRunning = FALSE;
1074         RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1075         if (pAd->StaCfg.bRadio == TRUE)
1076         {
1077                 pAd->bPCIclkOff = FALSE;
1078         RTMPRingCleanUp(pAd, QID_AC_BK);
1079                 RTMPRingCleanUp(pAd, QID_AC_BE);
1080                 RTMPRingCleanUp(pAd, QID_AC_VI);
1081                 RTMPRingCleanUp(pAd, QID_AC_VO);
1082                 RTMPRingCleanUp(pAd, QID_HCCA);
1083                 RTMPRingCleanUp(pAd, QID_MGMT);
1084                 RTMPRingCleanUp(pAd, QID_RX);
1085
1086                 // 2. Send wake up command.
1087                 AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02);
1088                 // 2-1. wait command ok.
1089                 AsicCheckCommanOk(pAd, PowerWakeCID);
1090
1091                 // When PCI clock is off, don't want to service interrupt. So when back to clock on, enable interrupt.
1092                 NICEnableInterrupt(pAd);
1093
1094                 // 3. Enable Tx DMA.
1095                 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
1096                 DmaCfg.field.EnableTxDMA = 1;
1097                 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
1098
1099                 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
1100                 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
1101                         && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
1102                 {
1103                         // Must using 40MHz.
1104                         AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
1105                         AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
1106                 }
1107                 else
1108                 {
1109                         // Must using 20MHz.
1110                         AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
1111                         AsicLockChannel(pAd, pAd->CommonCfg.Channel);
1112                 }
1113
1114                 // Clear Radio off flag
1115                 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1116
1117                 // Set LED
1118                 RTMPSetLED(pAd, LED_RADIO_ON);
1119
1120         if (pAd->StaCfg.Psm == PWR_ACTIVE)
1121         {
1122                 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, pAd->StaCfg.BBPR3);
1123         }
1124         }
1125         else
1126         {
1127                 RT28xxPciAsicRadioOff(pAd, GUIRADIO_OFF, 0);
1128         }
1129 }
1130
1131 #endif // CONFIG_STA_SUPPORT //
1132
1133 VOID RT28xxPciMlmeRadioOn(
1134         IN PRTMP_ADAPTER pAd)
1135 {
1136     if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1137                 return;
1138
1139     DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
1140
1141     if ((pAd->OpMode == OPMODE_AP) ||
1142         ((pAd->OpMode == OPMODE_STA) && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))))
1143     {
1144         NICResetFromError(pAd);
1145
1146         /*
1147         RTMPRingCleanUp(pAd, QID_AC_BK);
1148         RTMPRingCleanUp(pAd, QID_AC_BE);
1149         RTMPRingCleanUp(pAd, QID_AC_VI);
1150         RTMPRingCleanUp(pAd, QID_AC_VO);
1151         RTMPRingCleanUp(pAd, QID_HCCA);
1152         RTMPRingCleanUp(pAd, QID_MGMT);
1153         RTMPRingCleanUp(pAd, QID_RX);
1154                 */
1155
1156         // Enable Tx/Rx
1157         RTMPEnableRxTx(pAd);
1158
1159         // Clear Radio off flag
1160         RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1161
1162             // Set LED
1163             RTMPSetLED(pAd, LED_RADIO_ON);
1164     }
1165
1166 #ifdef CONFIG_STA_SUPPORT
1167     if ((pAd->OpMode == OPMODE_STA) &&
1168         (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)))
1169     {
1170         BOOLEAN         Cancelled;
1171
1172         RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
1173
1174         pAd->Mlme.bPsPollTimerRunning = FALSE;
1175         RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1176         RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer,     &Cancelled);
1177         RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1178     }
1179 #endif // CONFIG_STA_SUPPORT //
1180 }
1181
1182 VOID RT28xxPciMlmeRadioOFF(
1183         IN PRTMP_ADAPTER pAd)
1184 {
1185     WPDMA_GLO_CFG_STRUC GloCfg;
1186         UINT32  i;
1187
1188         if (pAd->StaCfg.bRadio == TRUE)
1189         {
1190                 DBGPRINT(RT_DEBUG_TRACE,("-->MlmeRadioOff() return on bRadio == TRUE; \n"));
1191                 return;
1192         }
1193
1194     if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1195         return;
1196
1197     DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
1198
1199         // Set LED
1200         RTMPSetLED(pAd, LED_RADIO_OFF);
1201
1202 #ifdef CONFIG_STA_SUPPORT
1203         IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
1204     {
1205         BOOLEAN         Cancelled;
1206
1207         if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
1208         {
1209                         RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled);
1210                         RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);
1211         }
1212
1213                 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
1214         {
1215             BOOLEAN Cancelled;
1216
1217                         // Always radio on since the NIC needs to set the MCU command (LED_RADIO_OFF).\r
1218                         if ((pAd->OpMode == OPMODE_STA) && \r
1219                              (IDLE_ON(pAd)) && \r
1220                              (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF)))\r
1221                         {\r
1222                                 RT28xxPciAsicRadioOn(pAd, GUI_IDLE_POWER_SAVE);\r
1223                         }
1224
1225             pAd->Mlme.bPsPollTimerRunning = FALSE;
1226             RTMPCancelTimer(&pAd->Mlme.PsPollTimer,     &Cancelled);
1227                 RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer,     &Cancelled);
1228         }
1229
1230         // Link down first if any association exists
1231         if (INFRA_ON(pAd) || ADHOC_ON(pAd))
1232             LinkDown(pAd, FALSE);
1233         RTMPusecDelay(10000);
1234         //==========================================
1235         // Clean up old bss table
1236         BssTableInit(&pAd->ScanTab);
1237
1238                 RTMPRingCleanUp(pAd, QID_AC_BK);
1239         RTMPRingCleanUp(pAd, QID_AC_BE);
1240         RTMPRingCleanUp(pAd, QID_AC_VI);
1241         RTMPRingCleanUp(pAd, QID_AC_VO);
1242         RTMPRingCleanUp(pAd, QID_HCCA);
1243         RTMPRingCleanUp(pAd, QID_MGMT);
1244         RTMPRingCleanUp(pAd, QID_RX);
1245
1246                 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
1247                 {
1248                         RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 500);
1249                         return;
1250                 }
1251     }
1252 #endif // CONFIG_STA_SUPPORT //
1253
1254         // Set Radio off flag
1255         RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1256
1257         // Disable Tx/Rx DMA
1258         RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);          // disable DMA
1259         GloCfg.field.EnableTxDMA = 0;
1260         GloCfg.field.EnableRxDMA = 0;
1261         RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word);          // abort all TX rings
1262
1263
1264         // MAC_SYS_CTRL => value = 0x0 => 40mA
1265         RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0);
1266
1267         // PWR_PIN_CFG => value = 0x0 => 40mA
1268         RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0);
1269
1270         // TX_PIN_CFG => value = 0x0 => 20mA
1271         RTMP_IO_WRITE32(pAd, TX_PIN_CFG, 0);
1272
1273         if (pAd->CommonCfg.BBPCurrentBW == BW_40)
1274         {
1275                 // Must using 40MHz.
1276                 AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel);
1277         }
1278         else
1279         {
1280                 // Must using 20MHz.
1281                 AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel);
1282         }
1283
1284         // Waiting for DMA idle
1285         i = 0;
1286         do
1287         {
1288                 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
1289                 if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0))
1290                         break;
1291
1292                 RTMPusecDelay(1000);
1293         }while (i++ < 100);
1294 }