]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/staging/rt2860/common/cmm_data_2860.c
Staging: rt2860: reduce superfluous exclamation marks
[net-next-2.6.git] / drivers / staging / rt2860 / common / cmm_data_2860.c
1 /*
2  *************************************************************************
3  * Ralink Tech Inc.
4  * 5F., No.36, Taiyuan St., Jhubei City,
5  * Hsinchu County 302,
6  * Taiwan, R.O.C.
7  *
8  * (c) Copyright 2002-2007, Ralink Technology, Inc.
9  *
10  * This program is free software; you can redistribute it and/or modify  *
11  * it under the terms of the GNU General Public License as published by  *
12  * the Free Software Foundation; either version 2 of the License, or     *
13  * (at your option) any later version.                                   *
14  *                                                                       *
15  * This program is distributed in the hope that it will be useful,       *
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
18  * GNU General Public License for more details.                          *
19  *                                                                       *
20  * You should have received a copy of the GNU General Public License     *
21  * along with this program; if not, write to the                         *
22  * Free Software Foundation, Inc.,                                       *
23  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
24  *                                                                       *
25  *************************************************************************
26 */
27
28 /*
29    All functions in this file must be PCI-depended, or you should out your function
30         in other files.
31
32 */
33 #include "../rt_config.h"
34
35 extern RTMP_RF_REGS RF2850RegTable[];
36 extern UCHAR    NUM_OF_2850_CHNL;
37
38 USHORT RtmpPCI_WriteTxResource(
39         IN      PRTMP_ADAPTER   pAd,
40         IN      TX_BLK                  *pTxBlk,
41         IN      BOOLEAN                 bIsLast,
42         OUT     USHORT                  *FreeNumber)
43 {
44
45         UCHAR                   *pDMAHeaderBufVA;
46         USHORT                  TxIdx, RetTxIdx;
47         PTXD_STRUC              pTxD;
48         UINT32                  BufBasePaLow;
49         PRTMP_TX_RING   pTxRing;
50         USHORT                  hwHeaderLen;
51
52         //
53         // get Tx Ring Resource
54         //
55         pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
56         TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx;
57         pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa;
58         BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa);
59
60         // copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
61         if (pTxBlk->TxFrameType == TX_AMSDU_FRAME)
62         {
63                 hwHeaderLen = pTxBlk->MpduHeaderLen - LENGTH_AMSDU_SUBFRAMEHEAD + pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD;
64         }
65         else
66         {
67                 hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
68         }
69         NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHeaderLen);
70
71         pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
72         pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
73
74         //
75         // build Tx Descriptor
76         //
77
78         pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
79         NdisZeroMemory(pTxD, TXD_SIZE);
80
81         pTxD->SDPtr0 = BufBasePaLow;
82         pTxD->SDLen0 = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; // include padding
83         pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);;
84         pTxD->SDLen1 = pTxBlk->SrcBufLen;
85         pTxD->LastSec0 = 0;
86         pTxD->LastSec1 = (bIsLast) ? 1 : 0;
87
88         RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
89
90         RetTxIdx = TxIdx;
91         //
92         // Update Tx index
93         //
94         INC_RING_INDEX(TxIdx, TX_RING_SIZE);
95         pTxRing->TxCpuIdx = TxIdx;
96
97         *FreeNumber -= 1;
98
99         return RetTxIdx;
100 }
101
102
103 USHORT RtmpPCI_WriteSingleTxResource(
104         IN      PRTMP_ADAPTER   pAd,
105         IN      TX_BLK                  *pTxBlk,
106         IN      BOOLEAN                 bIsLast,
107         OUT     USHORT                  *FreeNumber)
108 {
109
110         UCHAR                   *pDMAHeaderBufVA;
111         USHORT                  TxIdx, RetTxIdx;
112         PTXD_STRUC              pTxD;
113         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         if (!pTxD)
367                 return 0;
368
369         pAd->MgmtRing.Cell[SwIdx].pNdisPacket = pPacket;
370         pAd->MgmtRing.Cell[SwIdx].pNextNdisPacket = NULL;
371
372         RTMPWriteTxDescriptor(pAd, pTxD, TRUE, FIFO_MGMT);
373         pTxD->LastSec0 = 1;
374         pTxD->LastSec1 = 1;
375         pTxD->DMADONE = 0;
376         pTxD->SDLen1 = 0;
377         pTxD->SDPtr0 = PCI_MAP_SINGLE(pAd, pSrcBufVA, SrcBufLen, 0, PCI_DMA_TODEVICE);;
378         pTxD->SDLen0 = SrcBufLen;
379
380         pAd->RalinkCounters.KickTxCount++;
381         pAd->RalinkCounters.OneSecTxDoneCount++;
382
383         // Increase TX_CTX_IDX, but write to register later.
384         INC_RING_INDEX(pAd->MgmtRing.TxCpuIdx, MGMT_RING_SIZE);
385
386         RTMP_IO_WRITE32(pAd, TX_MGMTCTX_IDX,  pAd->MgmtRing.TxCpuIdx);
387
388         return 0;
389 }
390
391 /*
392         ========================================================================
393
394         Routine Description:
395                 Check Rx descriptor, return NDIS_STATUS_FAILURE if any error dound
396
397         Arguments:
398                 pRxD            Pointer to the Rx descriptor
399
400         Return Value:
401                 NDIS_STATUS_SUCCESS     No err
402                 NDIS_STATUS_FAILURE     Error
403
404         Note:
405
406         ========================================================================
407 */
408 NDIS_STATUS RTMPCheckRxError(
409         IN      PRTMP_ADAPTER           pAd,
410         IN      PHEADER_802_11          pHeader,
411         IN      PRXWI_STRUC             pRxWI,
412         IN  PRT28XX_RXD_STRUC   pRxD)
413 {
414         PCIPHER_KEY pWpaKey;
415         INT dBm;
416
417         // Phy errors & CRC errors
418         if (/*(pRxD->PhyErr) ||*/ (pRxD->Crc))
419         {
420                 // Check RSSI for Noise Hist statistic collection.
421                 dBm = (INT) (pRxWI->RSSI0) - pAd->BbpRssiToDbmDelta;
422                 if (dBm <= -87)
423                         pAd->StaCfg.RPIDensity[0] += 1;
424                 else if (dBm <= -82)
425                         pAd->StaCfg.RPIDensity[1] += 1;
426                 else if (dBm <= -77)
427                         pAd->StaCfg.RPIDensity[2] += 1;
428                 else if (dBm <= -72)
429                         pAd->StaCfg.RPIDensity[3] += 1;
430                 else if (dBm <= -67)
431                         pAd->StaCfg.RPIDensity[4] += 1;
432                 else if (dBm <= -62)
433                         pAd->StaCfg.RPIDensity[5] += 1;
434                 else if (dBm <= -57)
435                         pAd->StaCfg.RPIDensity[6] += 1;
436                 else if (dBm > -57)
437                         pAd->StaCfg.RPIDensity[7] += 1;
438
439                 return(NDIS_STATUS_FAILURE);
440         }
441
442         // Add Rx size to channel load counter, we should ignore error counts
443         pAd->StaCfg.CLBusyBytes += (pRxD->SDL0 + 14);
444
445         // Drop ToDs promiscous frame, it is opened due to CCX 2 channel load statistics
446         if (pHeader != NULL)
447         {
448                 if (pHeader->FC.ToDs)
449                 {
450                         return(NDIS_STATUS_FAILURE);
451                 }
452         }
453
454         // Drop not U2M frames, cant's drop here because we will drop beacon in this case
455         // I am kind of doubting the U2M bit operation
456         // if (pRxD->U2M == 0)
457         //      return(NDIS_STATUS_FAILURE);
458
459         // drop decyption fail frame
460         if (pRxD->CipherErr)
461         {
462                 if (pRxD->CipherErr == 2)
463                         {DBGPRINT_RAW(RT_DEBUG_TRACE,("pRxD ERROR: ICV ok but MICErr "));}
464                 else if (pRxD->CipherErr == 1)
465                         {DBGPRINT_RAW(RT_DEBUG_TRACE,("pRxD ERROR: ICV Err "));}
466                 else if (pRxD->CipherErr == 3)
467                         DBGPRINT_RAW(RT_DEBUG_TRACE,("pRxD ERROR: Key not valid "));
468
469         if (((pRxD->CipherErr & 1) == 1) && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd))
470             RTMPSendWirelessEvent(pAd, IW_ICV_ERROR_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
471
472                 DBGPRINT_RAW(RT_DEBUG_TRACE,(" %d (len=%d, Mcast=%d, MyBss=%d, Wcid=%d, KeyId=%d)\n",
473                         pRxD->CipherErr,
474                         pRxD->SDL0,
475                         pRxD->Mcast | pRxD->Bcast,
476                         pRxD->MyBss,
477                         pRxWI->WirelessCliID,
478                         pRxWI->KeyIndex));
479
480                 //
481                 // MIC Error
482                 //
483                 if (pRxD->CipherErr == 2)
484                 {
485                         pWpaKey = &pAd->SharedKey[BSS0][pRxWI->KeyIndex];
486
487             if (pAd->StaCfg.WpaSupplicantUP)
488                 WpaSendMicFailureToWpaSupplicant(pAd,
489                                    (pWpaKey->Type == PAIRWISEKEY) ? TRUE:FALSE);
490             else
491                             RTMPReportMicError(pAd, pWpaKey);
492
493             if (((pRxD->CipherErr & 2) == 2) && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd))
494                 RTMPSendWirelessEvent(pAd, IW_MIC_ERROR_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
495
496                         DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error\n"));
497                 }
498
499                 if (pHeader == NULL)
500                         return(NDIS_STATUS_SUCCESS);
501
502                 return(NDIS_STATUS_FAILURE);
503         }
504
505         return(NDIS_STATUS_SUCCESS);
506 }
507
508 /*
509         ==========================================================================
510         Description:
511                 This routine sends command to firmware and turn our chip to power save mode.
512                 Both RadioOff and .11 power save function needs to call this routine.
513         Input:
514                 Level = GUIRADIO_OFF  : GUI Radio Off mode
515                 Level = DOT11POWERSAVE  : 802.11 power save mode
516                 Level = RTMP_HALT  : When Disable device.
517
518         ==========================================================================
519  */
520 VOID RT28xxPciAsicRadioOff(
521         IN PRTMP_ADAPTER    pAd,
522         IN UCHAR            Level,
523         IN USHORT           TbttNumToNextWakeUp)
524 {
525         WPDMA_GLO_CFG_STRUC     DmaCfg;
526         UCHAR           i, tempBBP_R3 = 0;
527         BOOLEAN         brc = FALSE, Cancelled;
528     UINT32              TbTTTime = 0;
529         UINT32          PsPollTime = 0, MACValue;
530     ULONG               BeaconPeriodTime;
531     UINT32              RxDmaIdx, RxCpuIdx;
532         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));
533
534     // Check Rx DMA busy status, if more than half is occupied, give up this radio off.
535         RTMP_IO_READ32(pAd, RX_DRX_IDX , &RxDmaIdx);
536         RTMP_IO_READ32(pAd, RX_CRX_IDX , &RxCpuIdx);
537         if ((RxDmaIdx > RxCpuIdx) && ((RxDmaIdx - RxCpuIdx) > RX_RING_SIZE/3))
538         {
539                 DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return1. RxDmaIdx = %d ,  RxCpuIdx = %d. \n", RxDmaIdx, RxCpuIdx));
540                 return;
541         }
542         else if ((RxCpuIdx >= RxDmaIdx) && ((RxCpuIdx - RxDmaIdx) < RX_RING_SIZE/3))
543         {
544                 DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return2.  RxCpuIdx = %d. RxDmaIdx = %d ,  \n", RxCpuIdx, RxDmaIdx));
545                 return;
546         }
547
548     // Once go into this function, disable tx because don't want too many packets in queue to prevent HW stops.
549         RTMP_SET_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
550
551         if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
552         {
553             RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
554             RTMPCancelTimer(&pAd->Mlme.PsPollTimer,     &Cancelled);
555
556             if (Level == DOT11POWERSAVE)
557                 {
558                         RTMP_IO_READ32(pAd, TBTT_TIMER, &TbTTTime);
559                         TbTTTime &= 0x1ffff;
560                         // 00. check if need to do sleep in this DTIM period.   If next beacon will arrive within 30ms , ...doesn't necessarily sleep.
561                         // TbTTTime uint = 64us, LEAD_TIME unit = 1024us, PsPollTime unit = 1ms
562                 if  (((64*TbTTTime) <((LEAD_TIME*1024) + 40000)) && (TbttNumToNextWakeUp == 0))
563                         {
564                                 DBGPRINT(RT_DEBUG_TRACE, ("TbTTTime = 0x%x , give up this sleep. \n", TbTTTime));
565                     OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
566                                 RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
567                                 return;
568                         }
569                         else
570                         {
571                                 PsPollTime = (64*TbTTTime- LEAD_TIME*1024)/1000;
572                                 PsPollTime -= 3;
573
574                     BeaconPeriodTime = pAd->CommonCfg.BeaconPeriod*102/100;
575                                 if (TbttNumToNextWakeUp > 0)
576                                         PsPollTime += ((TbttNumToNextWakeUp -1) * BeaconPeriodTime);
577
578                     pAd->Mlme.bPsPollTimerRunning = TRUE;
579                                 RTMPSetTimer(&pAd->Mlme.PsPollTimer, PsPollTime);
580                         }
581                 }
582         }
583
584     // 0. Disable Tx DMA.
585         RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
586         DmaCfg.field.EnableTxDMA = 0;
587         RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
588
589         // 1. Wait DMA not busy
590         i = 0;
591         do
592         {
593                 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
594                 if ((DmaCfg.field.TxDMABusy == 0) && (DmaCfg.field.RxDMABusy == 0))
595                         break;
596                 RTMPusecDelay(20);
597                 i++;
598         }while(i < 50);
599
600         if (i >= 50)
601         {
602                 DBGPRINT(RT_DEBUG_TRACE, ("DMA keeps busy.  return on RT28xxPciAsicRadioOff ()\n"));
603                 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
604                 DmaCfg.field.EnableTxDMA = 1;
605                 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
606                 pAd->CheckDmaBusyCount++;
607                 return;
608         }
609         else
610         {
611                 pAd->CheckDmaBusyCount = 0;
612         }
613
614     RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
615
616     // Set to 1R.
617         if (pAd->Antenna.field.RxPath > 1)
618         {
619                 tempBBP_R3 = (pAd->StaCfg.BBPR3 & 0xE7);
620                 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, tempBBP_R3);
621         }
622
623         // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
624         if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
625                 && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
626         {
627                 // Must using 40MHz.
628                 AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel);
629         }
630         else
631         {
632                 // Must using 20MHz.
633                 AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel);
634         }
635
636         if (Level != RTMP_HALT)
637         {
638                 // Change Interrupt bitmask.
639                 RTMP_IO_WRITE32(pAd, INT_MASK_CSR, AutoWakeupInt);
640         }
641         else
642         {
643                 NICDisableInterrupt(pAd);
644         }
645
646     RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx);
647         // Disable MAC Rx
648         RTMP_IO_READ32(pAd, MAC_SYS_CTRL , &MACValue);
649         MACValue &= 0xf7;
650         RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL , MACValue);
651
652         //  2. Send Sleep command
653         RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff);
654         RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff);
655         // send POWER-SAVE command to MCU. high-byte = 1 save power as much as possible. high byte = 0 save less power
656         AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x1);
657         //  2-1. Wait command success
658         // Status = 1 : success, Status = 2, already sleep, Status = 3, Maybe MAC is busy so can't finish this task.
659         brc = AsicCheckCommanOk(pAd, PowerSafeCID);
660
661     if (brc == FALSE)
662     {
663         // try again
664         AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x01);   // send POWER-SAVE command to MCU. Timeout unit:40us.
665         //RTMPusecDelay(200);
666         brc = AsicCheckCommanOk(pAd, PowerSafeCID);
667     }
668
669         //  3. After 0x30 command is ok, send radio off command. lowbyte = 0 for power safe.
670         // If 0x30 command is not ok this time, we can ignore 0x35 command. It will make sure not cause firmware'r problem.
671         if ((Level == DOT11POWERSAVE) && (brc == TRUE))
672         {
673                 AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 0, 0x00);     // lowbyte = 0 means to do power safe, NOT turn off radio.
674                 //  3-1. Wait command success
675                 AsicCheckCommanOk(pAd, PowerRadioOffCID);
676         }
677         else if (brc == TRUE)
678         {
679                 AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 1, 0x00);     // lowbyte = 0 means to do power safe, NOT turn off radio.
680                 //  3-1. Wait command success
681                 AsicCheckCommanOk(pAd, PowerRadioOffCID);
682         }
683
684     // Wait DMA not busy
685         i = 0;
686         do
687         {
688                 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
689                 if ((DmaCfg.field.RxDMABusy == 0) && (DmaCfg.field.TxDMABusy == 0))
690                         break;
691                 RTMPusecDelay(20);
692                 i++;
693         }while(i < 50);
694
695         if (i >= 50)
696         {
697                 pAd->CheckDmaBusyCount++;
698                 DBGPRINT(RT_DEBUG_TRACE, ("DMA Rx keeps busy.  on RT28xxPciAsicRadioOff ()\n"));
699         }
700         else
701         {
702                 pAd->CheckDmaBusyCount = 0;
703         }
704
705         if (Level == DOT11POWERSAVE)
706         {
707                 AUTO_WAKEUP_STRUC       AutoWakeupCfg;
708                 //RTMPSetTimer(&pAd->Mlme.PsPollTimer, 90);
709
710                 // we have decided to SLEEP, so at least do it for a BEACON period.
711                 if (TbttNumToNextWakeUp == 0)
712                         TbttNumToNextWakeUp = 1;
713
714                 AutoWakeupCfg.word = 0;
715                 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
716
717                 // 1. Set auto wake up timer.
718                 AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1;
719                 AutoWakeupCfg.field.EnableAutoWakeup = 1;
720                 AutoWakeupCfg.field.AutoLeadTime = LEAD_TIME;
721                 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
722         }
723
724         //  4-1. If it's to disable our device. Need to restore PCI Configuration Space to its original value.
725         if (Level == RTMP_HALT)
726         {
727                 if ((brc == TRUE) && (i < 50))
728                         RTMPPCIeLinkCtrlSetting(pAd, 0);
729         }
730         //  4. Set PCI configuration Space Link Comtrol fields.  Only Radio Off needs to call this function
731         else
732         {
733                 if ((brc == TRUE) && (i < 50))
734                         RTMPPCIeLinkCtrlSetting(pAd, 3);
735         }
736
737         RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
738 }
739
740
741 /*
742         ==========================================================================
743         Description:
744                 This routine sends command to firmware and turn our chip to wake up mode from power save mode.
745                 Both RadioOn and .11 power save function needs to call this routine.
746         Input:
747                 Level = GUIRADIO_OFF : call this function is from Radio Off to Radio On.  Need to restore PCI host value.
748                 Level = other value : normal wake up function.
749
750         ==========================================================================
751  */
752 BOOLEAN RT28xxPciAsicRadioOn(
753         IN PRTMP_ADAPTER pAd,
754         IN UCHAR     Level)
755 {
756     WPDMA_GLO_CFG_STRUC DmaCfg;
757         BOOLEAN                         Cancelled, brv = TRUE;
758     UINT32                          MACValue;
759
760         if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
761         {
762             pAd->Mlme.bPsPollTimerRunning = FALSE;
763                 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
764                 if ((Level == GUIRADIO_OFF) || (Level == GUI_IDLE_POWER_SAVE)
765                 || (RTMP_TEST_PSFLAG(pAd, fRTMP_PS_SET_PCI_CLK_OFF_COMMAND)))
766                 {
767                         DBGPRINT(RT_DEBUG_TRACE, ("RT28xxPciAsicRadioOn ()\n"));
768                         // 1. Set PCI Link Control in Configuration Space.
769                         RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
770                         RTMPusecDelay(6000);
771                 }
772         }
773
774     pAd->bPCIclkOff = FALSE;
775         RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0x3a80);
776         // 2. Send wake up command.
777         AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02);
778
779         // 2-1. wait command ok.
780         brv = AsicCheckCommanOk(pAd, PowerWakeCID);
781     if (brv)
782     {
783         NICEnableInterrupt(pAd);
784
785         // 3. Enable Tx DMA.
786         RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
787         DmaCfg.field.EnableTxDMA = 1;
788         DmaCfg.field.EnableRxDMA = 1;
789         RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
790
791         // Eable MAC Rx
792         RTMP_IO_READ32(pAd, MAC_SYS_CTRL , &MACValue);
793         MACValue |= 0x8;
794         RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL , MACValue);
795
796         RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
797         if (Level == GUI_IDLE_POWER_SAVE)
798         {
799                 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
800                 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
801                         && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
802                 {
803                         // Must using 40MHz.
804                         AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
805                         AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
806                 }
807                 else
808                 {
809                         // Must using 20MHz.
810                         AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
811                         AsicLockChannel(pAd, pAd->CommonCfg.Channel);
812                 }
813         }
814         return TRUE;
815     }
816     else
817         return FALSE;
818 }
819
820 VOID RT28xxPciStaAsicForceWakeup(
821         IN PRTMP_ADAPTER pAd,
822         IN UCHAR         Level)
823 {
824     AUTO_WAKEUP_STRUC   AutoWakeupCfg;
825
826     if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
827     {
828         DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
829         return;
830     }
831
832     OPSTATUS_SET_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
833         RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW);
834
835     if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
836     {
837         // Support PCIe Advance Power Save
838         if (((Level == FROM_TX) && (pAd->Mlme.bPsPollTimerRunning == TRUE)) ||
839                         (Level == RTMP_HALT))
840         {
841             pAd->Mlme.bPsPollTimerRunning = FALSE;
842                 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
843                 RTMPusecDelay(5000);
844             DBGPRINT(RT_DEBUG_TRACE, ("=======AsicForceWakeup===bFromTx\n"));
845         }
846
847                 AutoWakeupCfg.word = 0;
848                 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
849
850                 // If this is called from Halt. ALWAYS force wakeup!
851                 if (Level == RTMP_HALT)
852                 {
853                         RT28xxPciAsicRadioOn(pAd, RTMP_HALT);
854                 }
855                 else
856                 {
857                         if (RT28xxPciAsicRadioOn(pAd, DOT11POWERSAVE))
858                         {
859                                 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
860                                 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
861                                         && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
862                                 {
863                                         // Must using 40MHz.
864                                         AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
865                                         AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
866                                 }
867                                 else
868                                 {
869                                         // Must using 20MHz.
870                                         AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
871                                         AsicLockChannel(pAd, pAd->CommonCfg.Channel);
872                                 }
873                         }
874                 }
875     }
876     else
877     {
878         // PCI, 2860-PCIe
879         AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x00);
880                 AutoWakeupCfg.word = 0;
881                 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
882     }
883
884     OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
885     OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
886     DBGPRINT(RT_DEBUG_TRACE, ("<=======RT28xxPciStaAsicForceWakeup\n"));
887 }
888
889 VOID RT28xxPciStaAsicSleepThenAutoWakeup(
890         IN PRTMP_ADAPTER pAd,
891         IN USHORT TbttNumToNextWakeUp)
892 {
893     if (pAd->StaCfg.bRadio == FALSE)
894         {
895                 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
896                 return;
897         }
898     if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
899     {
900         ULONG   Now = 0;
901         if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
902         {
903             DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
904             OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
905             return;
906         }
907
908                 NdisGetSystemUpTime(&Now);
909                 // If last send NULL fram time is too close to this receiving beacon (within 8ms), don't go to sleep for this DTM.
910                 // Because Some AP can't queuing outgoing frames immediately.
911                 if (((pAd->Mlme.LastSendNULLpsmTime + 8) >= Now) && (pAd->Mlme.LastSendNULLpsmTime <= Now))
912                 {
913                         DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu :  RxCountSinceLastNULL = %lu. \n", Now, pAd->Mlme.LastSendNULLpsmTime, pAd->RalinkCounters.RxCountSinceLastNULL));
914                         return;
915                 }
916                 else if ((pAd->RalinkCounters.RxCountSinceLastNULL > 0) && ((pAd->Mlme.LastSendNULLpsmTime + pAd->CommonCfg.BeaconPeriod) >= Now))
917                 {
918                         DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu: RxCountSinceLastNULL = %lu > 0 \n", Now, pAd->Mlme.LastSendNULLpsmTime,  pAd->RalinkCounters.RxCountSinceLastNULL));
919                         return;
920                 }
921
922         RT28xxPciAsicRadioOff(pAd, DOT11POWERSAVE, TbttNumToNextWakeUp);
923     }
924     else
925     {
926         AUTO_WAKEUP_STRUC       AutoWakeupCfg;
927         // we have decided to SLEEP, so at least do it for a BEACON period.
928         if (TbttNumToNextWakeUp == 0)
929             TbttNumToNextWakeUp = 1;
930
931         AutoWakeupCfg.word = 0;
932         RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
933         AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1;
934         AutoWakeupCfg.field.EnableAutoWakeup = 1;
935         AutoWakeupCfg.field.AutoLeadTime = 5;
936         RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
937         AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x00);   // send POWER-SAVE command to MCU. Timeout 40us.
938         DBGPRINT(RT_DEBUG_TRACE, ("<-- %s, TbttNumToNextWakeUp=%d \n", __func__, TbttNumToNextWakeUp));
939     }
940     OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE);
941 }
942
943 VOID PsPollWakeExec(
944         IN PVOID SystemSpecific1,
945         IN PVOID FunctionContext,
946         IN PVOID SystemSpecific2,
947         IN PVOID SystemSpecific3)
948 {
949         RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
950         unsigned long flags;
951
952     DBGPRINT(RT_DEBUG_TRACE,("-->PsPollWakeExec \n"));
953         RTMP_INT_LOCK(&pAd->irq_lock, flags);
954     if (pAd->Mlme.bPsPollTimerRunning)
955     {
956             RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
957     }
958     pAd->Mlme.bPsPollTimerRunning = FALSE;
959         RTMP_INT_UNLOCK(&pAd->irq_lock, flags);
960 }
961
962 VOID  RadioOnExec(
963         IN PVOID SystemSpecific1,
964         IN PVOID FunctionContext,
965         IN PVOID SystemSpecific2,
966         IN PVOID SystemSpecific3)
967 {
968         RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
969         WPDMA_GLO_CFG_STRUC     DmaCfg;
970         BOOLEAN                         Cancelled;
971
972         if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
973         {
974                 DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on fOP_STATUS_DOZE == TRUE; \n"));
975                 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
976                 return;
977         }
978
979         if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
980         {
981                 DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on SCAN_IN_PROGRESS; \n"));
982                 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
983                 return;
984         }
985     pAd->Mlme.bPsPollTimerRunning = FALSE;
986         RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
987         if (pAd->StaCfg.bRadio == TRUE)
988         {
989                 pAd->bPCIclkOff = FALSE;
990         RTMPRingCleanUp(pAd, QID_AC_BK);
991                 RTMPRingCleanUp(pAd, QID_AC_BE);
992                 RTMPRingCleanUp(pAd, QID_AC_VI);
993                 RTMPRingCleanUp(pAd, QID_AC_VO);
994                 RTMPRingCleanUp(pAd, QID_HCCA);
995                 RTMPRingCleanUp(pAd, QID_MGMT);
996                 RTMPRingCleanUp(pAd, QID_RX);
997
998                 // 2. Send wake up command.
999                 AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02);
1000                 // 2-1. wait command ok.
1001                 AsicCheckCommanOk(pAd, PowerWakeCID);
1002
1003                 // When PCI clock is off, don't want to service interrupt. So when back to clock on, enable interrupt.
1004                 NICEnableInterrupt(pAd);
1005
1006                 // 3. Enable Tx DMA.
1007                 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
1008                 DmaCfg.field.EnableTxDMA = 1;
1009                 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
1010
1011                 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
1012                 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
1013                         && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
1014                 {
1015                         // Must using 40MHz.
1016                         AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
1017                         AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
1018                 }
1019                 else
1020                 {
1021                         // Must using 20MHz.
1022                         AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
1023                         AsicLockChannel(pAd, pAd->CommonCfg.Channel);
1024                 }
1025
1026                 // Clear Radio off flag
1027                 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1028
1029                 // Set LED
1030                 RTMPSetLED(pAd, LED_RADIO_ON);
1031
1032         if (pAd->StaCfg.Psm == PWR_ACTIVE)
1033         {
1034                 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, pAd->StaCfg.BBPR3);
1035         }
1036         }
1037         else
1038         {
1039                 RT28xxPciAsicRadioOff(pAd, GUIRADIO_OFF, 0);
1040         }
1041 }
1042
1043 VOID RT28xxPciMlmeRadioOn(
1044         IN PRTMP_ADAPTER pAd)
1045 {
1046     if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1047                 return;
1048
1049     DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
1050
1051     if ((pAd->OpMode == OPMODE_AP) ||
1052         ((pAd->OpMode == OPMODE_STA) && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))))
1053     {
1054         NICResetFromError(pAd);
1055
1056         /*
1057         RTMPRingCleanUp(pAd, QID_AC_BK);
1058         RTMPRingCleanUp(pAd, QID_AC_BE);
1059         RTMPRingCleanUp(pAd, QID_AC_VI);
1060         RTMPRingCleanUp(pAd, QID_AC_VO);
1061         RTMPRingCleanUp(pAd, QID_HCCA);
1062         RTMPRingCleanUp(pAd, QID_MGMT);
1063         RTMPRingCleanUp(pAd, QID_RX);
1064                 */
1065
1066         // Enable Tx/Rx
1067         RTMPEnableRxTx(pAd);
1068
1069         // Clear Radio off flag
1070         RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1071
1072             // Set LED
1073             RTMPSetLED(pAd, LED_RADIO_ON);
1074     }
1075
1076     if ((pAd->OpMode == OPMODE_STA) &&
1077         (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)))
1078     {
1079         BOOLEAN         Cancelled;
1080
1081         RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
1082
1083         pAd->Mlme.bPsPollTimerRunning = FALSE;
1084         RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1085         RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer,     &Cancelled);
1086         RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1087     }
1088 }
1089
1090 VOID RT28xxPciMlmeRadioOFF(
1091         IN PRTMP_ADAPTER pAd)
1092 {
1093     WPDMA_GLO_CFG_STRUC GloCfg;
1094         UINT32  i;
1095
1096         if (pAd->StaCfg.bRadio == TRUE)
1097         {
1098                 DBGPRINT(RT_DEBUG_TRACE,("-->MlmeRadioOff() return on bRadio == TRUE; \n"));
1099                 return;
1100         }
1101
1102     if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1103         return;
1104
1105     DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
1106
1107         // Set LED
1108         RTMPSetLED(pAd, LED_RADIO_OFF);
1109
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 }