Staging: rt2860: remove CONFIG_STA_SUPPORT ifdefs
[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 #ifdef WPA_SUPPLICANT_SUPPORT
485             if (pAd->StaCfg.WpaSupplicantUP)
486                 WpaSendMicFailureToWpaSupplicant(pAd,
487                                    (pWpaKey->Type == PAIRWISEKEY) ? TRUE:FALSE);
488             else
489 #endif // WPA_SUPPLICANT_SUPPORT //
490                             RTMPReportMicError(pAd, pWpaKey);
491
492             if (((pRxD->CipherErr & 2) == 2) && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd))
493                 RTMPSendWirelessEvent(pAd, IW_MIC_ERROR_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
494
495                         DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error\n"));
496                 }
497
498                 if (pHeader == NULL)
499                         return(NDIS_STATUS_SUCCESS);
500
501                 return(NDIS_STATUS_FAILURE);
502         }
503
504         return(NDIS_STATUS_SUCCESS);
505 }
506
507 /*
508         ==========================================================================
509         Description:
510                 This routine sends command to firmware and turn our chip to power save mode.
511                 Both RadioOff and .11 power save function needs to call this routine.
512         Input:
513                 Level = GUIRADIO_OFF  : GUI Radio Off mode
514                 Level = DOT11POWERSAVE  : 802.11 power save mode
515                 Level = RTMP_HALT  : When Disable device.
516
517         ==========================================================================
518  */
519 VOID RT28xxPciAsicRadioOff(
520         IN PRTMP_ADAPTER    pAd,
521         IN UCHAR            Level,
522         IN USHORT           TbttNumToNextWakeUp)
523 {
524         WPDMA_GLO_CFG_STRUC     DmaCfg;
525         UCHAR           i, tempBBP_R3 = 0;
526         BOOLEAN         brc = FALSE, Cancelled;
527     UINT32              TbTTTime = 0;
528         UINT32          PsPollTime = 0, MACValue;
529     ULONG               BeaconPeriodTime;
530     UINT32              RxDmaIdx, RxCpuIdx;
531         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));
532
533     // Check Rx DMA busy status, if more than half is occupied, give up this radio off.
534         RTMP_IO_READ32(pAd, RX_DRX_IDX , &RxDmaIdx);
535         RTMP_IO_READ32(pAd, RX_CRX_IDX , &RxCpuIdx);
536         if ((RxDmaIdx > RxCpuIdx) && ((RxDmaIdx - RxCpuIdx) > RX_RING_SIZE/3))
537         {
538                 DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return1. RxDmaIdx = %d ,  RxCpuIdx = %d. \n", RxDmaIdx, RxCpuIdx));
539                 return;
540         }
541         else if ((RxCpuIdx >= RxDmaIdx) && ((RxCpuIdx - RxDmaIdx) < RX_RING_SIZE/3))
542         {
543                 DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return2.  RxCpuIdx = %d. RxDmaIdx = %d ,  \n", RxCpuIdx, RxDmaIdx));
544                 return;
545         }
546
547     // Once go into this function, disable tx because don't want too many packets in queue to prevent HW stops.
548         RTMP_SET_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
549
550         if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
551         {
552             RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
553             RTMPCancelTimer(&pAd->Mlme.PsPollTimer,     &Cancelled);
554
555             if (Level == DOT11POWERSAVE)
556                 {
557                         RTMP_IO_READ32(pAd, TBTT_TIMER, &TbTTTime);
558                         TbTTTime &= 0x1ffff;
559                         // 00. check if need to do sleep in this DTIM period.   If next beacon will arrive within 30ms , ...doesn't necessarily sleep.
560                         // TbTTTime uint = 64us, LEAD_TIME unit = 1024us, PsPollTime unit = 1ms
561                 if  (((64*TbTTTime) <((LEAD_TIME*1024) + 40000)) && (TbttNumToNextWakeUp == 0))
562                         {
563                                 DBGPRINT(RT_DEBUG_TRACE, ("TbTTTime = 0x%x , give up this sleep. \n", TbTTTime));
564                     OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
565                                 RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
566                                 return;
567                         }
568                         else
569                         {
570                                 PsPollTime = (64*TbTTTime- LEAD_TIME*1024)/1000;
571                                 PsPollTime -= 3;
572
573                     BeaconPeriodTime = pAd->CommonCfg.BeaconPeriod*102/100;
574                                 if (TbttNumToNextWakeUp > 0)
575                                         PsPollTime += ((TbttNumToNextWakeUp -1) * BeaconPeriodTime);
576
577                     pAd->Mlme.bPsPollTimerRunning = TRUE;
578                                 RTMPSetTimer(&pAd->Mlme.PsPollTimer, PsPollTime);
579                         }
580                 }
581         }
582
583     // 0. Disable Tx DMA.
584         RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
585         DmaCfg.field.EnableTxDMA = 0;
586         RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
587
588         // 1. Wait DMA not busy
589         i = 0;
590         do
591         {
592                 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
593                 if ((DmaCfg.field.TxDMABusy == 0) && (DmaCfg.field.RxDMABusy == 0))
594                         break;
595                 RTMPusecDelay(20);
596                 i++;
597         }while(i < 50);
598
599         if (i >= 50)
600         {
601                 DBGPRINT(RT_DEBUG_TRACE, ("DMA keeps busy.  return on RT28xxPciAsicRadioOff ()\n"));
602                 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
603                 DmaCfg.field.EnableTxDMA = 1;
604                 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
605                 pAd->CheckDmaBusyCount++;
606                 return;
607         }
608         else
609         {
610                 pAd->CheckDmaBusyCount = 0;
611         }
612
613     RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
614
615     // Set to 1R.
616         if (pAd->Antenna.field.RxPath > 1)
617         {
618                 tempBBP_R3 = (pAd->StaCfg.BBPR3 & 0xE7);
619                 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, tempBBP_R3);
620         }
621
622         // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
623         if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
624                 && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
625         {
626                 // Must using 40MHz.
627                 AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel);
628         }
629         else
630         {
631                 // Must using 20MHz.
632                 AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel);
633         }
634
635         if (Level != RTMP_HALT)
636         {
637                 // Change Interrupt bitmask.
638                 RTMP_IO_WRITE32(pAd, INT_MASK_CSR, AutoWakeupInt);
639         }
640         else
641         {
642                 NICDisableInterrupt(pAd);
643         }
644
645     RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx);
646         // Disable MAC Rx
647         RTMP_IO_READ32(pAd, MAC_SYS_CTRL , &MACValue);
648         MACValue &= 0xf7;
649         RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL , MACValue);
650
651         //  2. Send Sleep command
652         RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff);
653         RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff);
654         // send POWER-SAVE command to MCU. high-byte = 1 save power as much as possible. high byte = 0 save less power
655         AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x1);
656         //  2-1. Wait command success
657         // Status = 1 : success, Status = 2, already sleep, Status = 3, Maybe MAC is busy so can't finish this task.
658         brc = AsicCheckCommanOk(pAd, PowerSafeCID);
659
660     if (brc == FALSE)
661     {
662         // try again
663         AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x01);   // send POWER-SAVE command to MCU. Timeout unit:40us.
664         //RTMPusecDelay(200);
665         brc = AsicCheckCommanOk(pAd, PowerSafeCID);
666     }
667
668         //  3. After 0x30 command is ok, send radio off command. lowbyte = 0 for power safe.
669         // If 0x30 command is not ok this time, we can ignore 0x35 command. It will make sure not cause firmware'r problem.
670         if ((Level == DOT11POWERSAVE) && (brc == TRUE))
671         {
672                 AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 0, 0x00);     // lowbyte = 0 means to do power safe, NOT turn off radio.
673                 //  3-1. Wait command success
674                 AsicCheckCommanOk(pAd, PowerRadioOffCID);
675         }
676         else if (brc == TRUE)
677         {
678                 AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 1, 0x00);     // lowbyte = 0 means to do power safe, NOT turn off radio.
679                 //  3-1. Wait command success
680                 AsicCheckCommanOk(pAd, PowerRadioOffCID);
681         }
682
683     // Wait DMA not busy
684         i = 0;
685         do
686         {
687                 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
688                 if ((DmaCfg.field.RxDMABusy == 0) && (DmaCfg.field.TxDMABusy == 0))
689                         break;
690                 RTMPusecDelay(20);
691                 i++;
692         }while(i < 50);
693
694         if (i >= 50)
695         {
696                 pAd->CheckDmaBusyCount++;
697                 DBGPRINT(RT_DEBUG_TRACE, ("DMA Rx keeps busy.  on RT28xxPciAsicRadioOff ()\n"));
698         }
699         else
700         {
701                 pAd->CheckDmaBusyCount = 0;
702         }
703
704         if (Level == DOT11POWERSAVE)
705         {
706                 AUTO_WAKEUP_STRUC       AutoWakeupCfg;
707                 //RTMPSetTimer(&pAd->Mlme.PsPollTimer, 90);
708
709                 // we have decided to SLEEP, so at least do it for a BEACON period.
710                 if (TbttNumToNextWakeUp == 0)
711                         TbttNumToNextWakeUp = 1;
712
713                 AutoWakeupCfg.word = 0;
714                 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
715
716                 // 1. Set auto wake up timer.
717                 AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1;
718                 AutoWakeupCfg.field.EnableAutoWakeup = 1;
719                 AutoWakeupCfg.field.AutoLeadTime = LEAD_TIME;
720                 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
721         }
722
723         //  4-1. If it's to disable our device. Need to restore PCI Configuration Space to its original value.
724         if (Level == RTMP_HALT)
725         {
726                 if ((brc == TRUE) && (i < 50))
727                         RTMPPCIeLinkCtrlSetting(pAd, 0);
728         }
729         //  4. Set PCI configuration Space Link Comtrol fields.  Only Radio Off needs to call this function
730         else
731         {
732                 if ((brc == TRUE) && (i < 50))
733                         RTMPPCIeLinkCtrlSetting(pAd, 3);
734         }
735
736         RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
737 }
738
739
740 /*
741         ==========================================================================
742         Description:
743                 This routine sends command to firmware and turn our chip to wake up mode from power save mode.
744                 Both RadioOn and .11 power save function needs to call this routine.
745         Input:
746                 Level = GUIRADIO_OFF : call this function is from Radio Off to Radio On.  Need to restore PCI host value.
747                 Level = other value : normal wake up function.
748
749         ==========================================================================
750  */
751 BOOLEAN RT28xxPciAsicRadioOn(
752         IN PRTMP_ADAPTER pAd,
753         IN UCHAR     Level)
754 {
755     WPDMA_GLO_CFG_STRUC DmaCfg;
756         BOOLEAN                         Cancelled, brv = TRUE;
757     UINT32                          MACValue;
758
759         if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
760         {
761             pAd->Mlme.bPsPollTimerRunning = FALSE;
762                 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
763                 if ((Level == GUIRADIO_OFF) || (Level == GUI_IDLE_POWER_SAVE)
764                 || (RTMP_TEST_PSFLAG(pAd, fRTMP_PS_SET_PCI_CLK_OFF_COMMAND)))
765                 {
766                         DBGPRINT(RT_DEBUG_TRACE, ("RT28xxPciAsicRadioOn ()\n"));
767                         // 1. Set PCI Link Control in Configuration Space.
768                         RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
769                         RTMPusecDelay(6000);
770                 }
771         }
772
773     pAd->bPCIclkOff = FALSE;
774         RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0x3a80);
775         // 2. Send wake up command.
776         AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02);
777
778         // 2-1. wait command ok.
779         brv = AsicCheckCommanOk(pAd, PowerWakeCID);
780     if (brv)
781     {
782         NICEnableInterrupt(pAd);
783
784         // 3. Enable Tx DMA.
785         RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
786         DmaCfg.field.EnableTxDMA = 1;
787         DmaCfg.field.EnableRxDMA = 1;
788         RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
789
790         // Eable MAC Rx
791         RTMP_IO_READ32(pAd, MAC_SYS_CTRL , &MACValue);
792         MACValue |= 0x8;
793         RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL , MACValue);
794
795         RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
796         if (Level == GUI_IDLE_POWER_SAVE)
797         {
798                 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
799                 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
800                         && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
801                 {
802                         // Must using 40MHz.
803                         AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
804                         AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
805                 }
806                 else
807                 {
808                         // Must using 20MHz.
809                         AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
810                         AsicLockChannel(pAd, pAd->CommonCfg.Channel);
811                 }
812         }
813         return TRUE;
814     }
815     else
816         return FALSE;
817 }
818
819 VOID RT28xxPciStaAsicForceWakeup(
820         IN PRTMP_ADAPTER pAd,
821         IN UCHAR         Level)
822 {
823     AUTO_WAKEUP_STRUC   AutoWakeupCfg;
824
825     if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
826     {
827         DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
828         return;
829     }
830
831     OPSTATUS_SET_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
832         RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW);
833
834     if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
835     {
836         // Support PCIe Advance Power Save
837         if (((Level == FROM_TX) && (pAd->Mlme.bPsPollTimerRunning == TRUE)) ||
838                         (Level == RTMP_HALT))
839         {
840             pAd->Mlme.bPsPollTimerRunning = FALSE;
841                 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
842                 RTMPusecDelay(5000);
843             DBGPRINT(RT_DEBUG_TRACE, ("=======AsicForceWakeup===bFromTx\n"));
844         }
845
846                 AutoWakeupCfg.word = 0;
847                 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
848
849                 // If this is called from Halt. ALWAYS force wakeup!!!
850                 if (Level == RTMP_HALT)
851                 {
852                         RT28xxPciAsicRadioOn(pAd, RTMP_HALT);
853                 }
854                 else
855                 {
856                         if (RT28xxPciAsicRadioOn(pAd, DOT11POWERSAVE))
857                         {
858                                 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
859                                 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
860                                         && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
861                                 {
862                                         // Must using 40MHz.
863                                         AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
864                                         AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
865                                 }
866                                 else
867                                 {
868                                         // Must using 20MHz.
869                                         AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
870                                         AsicLockChannel(pAd, pAd->CommonCfg.Channel);
871                                 }
872                         }
873                 }
874     }
875     else
876     {
877         // PCI, 2860-PCIe
878         AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x00);
879                 AutoWakeupCfg.word = 0;
880                 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
881     }
882
883     OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
884     OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
885     DBGPRINT(RT_DEBUG_TRACE, ("<=======RT28xxPciStaAsicForceWakeup\n"));
886 }
887
888 VOID RT28xxPciStaAsicSleepThenAutoWakeup(
889         IN PRTMP_ADAPTER pAd,
890         IN USHORT TbttNumToNextWakeUp)
891 {
892     if (pAd->StaCfg.bRadio == FALSE)
893         {
894                 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
895                 return;
896         }
897     if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
898     {
899         ULONG   Now = 0;
900         if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
901         {
902             DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
903             OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
904             return;
905         }
906
907                 NdisGetSystemUpTime(&Now);
908                 // If last send NULL fram time is too close to this receiving beacon (within 8ms), don't go to sleep for this DTM.
909                 // Because Some AP can't queuing outgoing frames immediately.
910                 if (((pAd->Mlme.LastSendNULLpsmTime + 8) >= Now) && (pAd->Mlme.LastSendNULLpsmTime <= Now))
911                 {
912                         DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu :  RxCountSinceLastNULL = %lu. \n", Now, pAd->Mlme.LastSendNULLpsmTime, pAd->RalinkCounters.RxCountSinceLastNULL));
913                         return;
914                 }
915                 else if ((pAd->RalinkCounters.RxCountSinceLastNULL > 0) && ((pAd->Mlme.LastSendNULLpsmTime + pAd->CommonCfg.BeaconPeriod) >= Now))
916                 {
917                         DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu: RxCountSinceLastNULL = %lu > 0 \n", Now, pAd->Mlme.LastSendNULLpsmTime,  pAd->RalinkCounters.RxCountSinceLastNULL));
918                         return;
919                 }
920
921         RT28xxPciAsicRadioOff(pAd, DOT11POWERSAVE, TbttNumToNextWakeUp);
922     }
923     else
924     {
925         AUTO_WAKEUP_STRUC       AutoWakeupCfg;
926         // we have decided to SLEEP, so at least do it for a BEACON period.
927         if (TbttNumToNextWakeUp == 0)
928             TbttNumToNextWakeUp = 1;
929
930         AutoWakeupCfg.word = 0;
931         RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
932         AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1;
933         AutoWakeupCfg.field.EnableAutoWakeup = 1;
934         AutoWakeupCfg.field.AutoLeadTime = 5;
935         RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
936         AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x00);   // send POWER-SAVE command to MCU. Timeout 40us.
937         DBGPRINT(RT_DEBUG_TRACE, ("<-- %s, TbttNumToNextWakeUp=%d \n", __func__, TbttNumToNextWakeUp));
938     }
939     OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE);
940 }
941
942 VOID PsPollWakeExec(
943         IN PVOID SystemSpecific1,
944         IN PVOID FunctionContext,
945         IN PVOID SystemSpecific2,
946         IN PVOID SystemSpecific3)
947 {
948         RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
949         unsigned long flags;
950
951     DBGPRINT(RT_DEBUG_TRACE,("-->PsPollWakeExec \n"));
952         RTMP_INT_LOCK(&pAd->irq_lock, flags);
953     if (pAd->Mlme.bPsPollTimerRunning)
954     {
955             RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
956     }
957     pAd->Mlme.bPsPollTimerRunning = FALSE;
958         RTMP_INT_UNLOCK(&pAd->irq_lock, flags);
959 }
960
961 VOID  RadioOnExec(
962         IN PVOID SystemSpecific1,
963         IN PVOID FunctionContext,
964         IN PVOID SystemSpecific2,
965         IN PVOID SystemSpecific3)
966 {
967         RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
968         WPDMA_GLO_CFG_STRUC     DmaCfg;
969         BOOLEAN                         Cancelled;
970
971         if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
972         {
973                 DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on fOP_STATUS_DOZE == TRUE; \n"));
974                 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
975                 return;
976         }
977
978         if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
979         {
980                 DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on SCAN_IN_PROGRESS; \n"));
981                 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
982                 return;
983         }
984     pAd->Mlme.bPsPollTimerRunning = FALSE;
985         RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
986         if (pAd->StaCfg.bRadio == TRUE)
987         {
988                 pAd->bPCIclkOff = FALSE;
989         RTMPRingCleanUp(pAd, QID_AC_BK);
990                 RTMPRingCleanUp(pAd, QID_AC_BE);
991                 RTMPRingCleanUp(pAd, QID_AC_VI);
992                 RTMPRingCleanUp(pAd, QID_AC_VO);
993                 RTMPRingCleanUp(pAd, QID_HCCA);
994                 RTMPRingCleanUp(pAd, QID_MGMT);
995                 RTMPRingCleanUp(pAd, QID_RX);
996
997                 // 2. Send wake up command.
998                 AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02);
999                 // 2-1. wait command ok.
1000                 AsicCheckCommanOk(pAd, PowerWakeCID);
1001
1002                 // When PCI clock is off, don't want to service interrupt. So when back to clock on, enable interrupt.
1003                 NICEnableInterrupt(pAd);
1004
1005                 // 3. Enable Tx DMA.
1006                 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
1007                 DmaCfg.field.EnableTxDMA = 1;
1008                 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
1009
1010                 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
1011                 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
1012                         && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
1013                 {
1014                         // Must using 40MHz.
1015                         AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
1016                         AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
1017                 }
1018                 else
1019                 {
1020                         // Must using 20MHz.
1021                         AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
1022                         AsicLockChannel(pAd, pAd->CommonCfg.Channel);
1023                 }
1024
1025                 // Clear Radio off flag
1026                 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1027
1028                 // Set LED
1029                 RTMPSetLED(pAd, LED_RADIO_ON);
1030
1031         if (pAd->StaCfg.Psm == PWR_ACTIVE)
1032         {
1033                 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, pAd->StaCfg.BBPR3);
1034         }
1035         }
1036         else
1037         {
1038                 RT28xxPciAsicRadioOff(pAd, GUIRADIO_OFF, 0);
1039         }
1040 }
1041
1042 VOID RT28xxPciMlmeRadioOn(
1043         IN PRTMP_ADAPTER pAd)
1044 {
1045     if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1046                 return;
1047
1048     DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
1049
1050     if ((pAd->OpMode == OPMODE_AP) ||
1051         ((pAd->OpMode == OPMODE_STA) && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))))
1052     {
1053         NICResetFromError(pAd);
1054
1055         /*
1056         RTMPRingCleanUp(pAd, QID_AC_BK);
1057         RTMPRingCleanUp(pAd, QID_AC_BE);
1058         RTMPRingCleanUp(pAd, QID_AC_VI);
1059         RTMPRingCleanUp(pAd, QID_AC_VO);
1060         RTMPRingCleanUp(pAd, QID_HCCA);
1061         RTMPRingCleanUp(pAd, QID_MGMT);
1062         RTMPRingCleanUp(pAd, QID_RX);
1063                 */
1064
1065         // Enable Tx/Rx
1066         RTMPEnableRxTx(pAd);
1067
1068         // Clear Radio off flag
1069         RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1070
1071             // Set LED
1072             RTMPSetLED(pAd, LED_RADIO_ON);
1073     }
1074
1075     if ((pAd->OpMode == OPMODE_STA) &&
1076         (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)))
1077     {
1078         BOOLEAN         Cancelled;
1079
1080         RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
1081
1082         pAd->Mlme.bPsPollTimerRunning = FALSE;
1083         RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1084         RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer,     &Cancelled);
1085         RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1086     }
1087 }
1088
1089 VOID RT28xxPciMlmeRadioOFF(
1090         IN PRTMP_ADAPTER pAd)
1091 {
1092     WPDMA_GLO_CFG_STRUC GloCfg;
1093         UINT32  i;
1094
1095         if (pAd->StaCfg.bRadio == TRUE)
1096         {
1097                 DBGPRINT(RT_DEBUG_TRACE,("-->MlmeRadioOff() return on bRadio == TRUE; \n"));
1098                 return;
1099         }
1100
1101     if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1102         return;
1103
1104     DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
1105
1106         // Set LED
1107         RTMPSetLED(pAd, LED_RADIO_OFF);
1108
1109         IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
1110     {
1111         BOOLEAN         Cancelled;
1112
1113         if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
1114         {
1115                         RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled);
1116                         RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);
1117         }
1118
1119                 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
1120         {
1121             BOOLEAN Cancelled;
1122
1123                         // Always radio on since the NIC needs to set the MCU command (LED_RADIO_OFF).\r
1124                         if ((pAd->OpMode == OPMODE_STA) && \r
1125                              (IDLE_ON(pAd)) && \r
1126                              (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF)))\r
1127                         {\r
1128                                 RT28xxPciAsicRadioOn(pAd, GUI_IDLE_POWER_SAVE);\r
1129                         }
1130
1131             pAd->Mlme.bPsPollTimerRunning = FALSE;
1132             RTMPCancelTimer(&pAd->Mlme.PsPollTimer,     &Cancelled);
1133                 RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer,     &Cancelled);
1134         }
1135
1136         // Link down first if any association exists
1137         if (INFRA_ON(pAd) || ADHOC_ON(pAd))
1138             LinkDown(pAd, FALSE);
1139         RTMPusecDelay(10000);
1140         //==========================================
1141         // Clean up old bss table
1142         BssTableInit(&pAd->ScanTab);
1143
1144                 RTMPRingCleanUp(pAd, QID_AC_BK);
1145         RTMPRingCleanUp(pAd, QID_AC_BE);
1146         RTMPRingCleanUp(pAd, QID_AC_VI);
1147         RTMPRingCleanUp(pAd, QID_AC_VO);
1148         RTMPRingCleanUp(pAd, QID_HCCA);
1149         RTMPRingCleanUp(pAd, QID_MGMT);
1150         RTMPRingCleanUp(pAd, QID_RX);
1151
1152                 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
1153                 {
1154                         RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 500);
1155                         return;
1156                 }
1157     }
1158
1159         // Set Radio off flag
1160         RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1161
1162         // Disable Tx/Rx DMA
1163         RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);          // disable DMA
1164         GloCfg.field.EnableTxDMA = 0;
1165         GloCfg.field.EnableRxDMA = 0;
1166         RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word);          // abort all TX rings
1167
1168
1169         // MAC_SYS_CTRL => value = 0x0 => 40mA
1170         RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0);
1171
1172         // PWR_PIN_CFG => value = 0x0 => 40mA
1173         RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0);
1174
1175         // TX_PIN_CFG => value = 0x0 => 20mA
1176         RTMP_IO_WRITE32(pAd, TX_PIN_CFG, 0);
1177
1178         if (pAd->CommonCfg.BBPCurrentBW == BW_40)
1179         {
1180                 // Must using 40MHz.
1181                 AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel);
1182         }
1183         else
1184         {
1185                 // Must using 20MHz.
1186                 AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel);
1187         }
1188
1189         // Waiting for DMA idle
1190         i = 0;
1191         do
1192         {
1193                 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
1194                 if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0))
1195                         break;
1196
1197                 RTMPusecDelay(1000);
1198         }while (i++ < 100);
1199 }