Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[linux-2.6] / 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         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  */
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
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
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
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
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
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
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 }