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