]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/staging/rt2860/common/cmm_data_2860.c
Staging: rt2860sta: prevent a panic when disabling when associated
[mirror_ubuntu-artful-kernel.git] / drivers / staging / rt2860 / common / cmm_data_2860.c
1 /*
2 *************************************************************************
3 * Ralink Tech Inc.
4 * 5F., No.36, Taiyuan St., Jhubei City,
5 * Hsinchu County 302,
6 * Taiwan, R.O.C.
7 *
8 * (c) Copyright 2002-2007, Ralink Technology, Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
19 * *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program; if not, write to the *
22 * Free Software Foundation, Inc., *
23 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
24 * *
25 *************************************************************************
26 */
27
28 /*
29 All functions in this file must be PCI-depended, or you should out your function
30 in other files.
31
32 */
33 #include "../rt_config.h"
34
35 extern RTMP_RF_REGS RF2850RegTable[];
36 extern UCHAR NUM_OF_2850_CHNL;
37
38 USHORT RtmpPCI_WriteTxResource(
39 IN PRTMP_ADAPTER pAd,
40 IN TX_BLK *pTxBlk,
41 IN BOOLEAN bIsLast,
42 OUT USHORT *FreeNumber)
43 {
44
45 UCHAR *pDMAHeaderBufVA;
46 USHORT TxIdx, RetTxIdx;
47 PTXD_STRUC pTxD;
48 UINT32 BufBasePaLow;
49 PRTMP_TX_RING pTxRing;
50 USHORT hwHeaderLen;
51
52 //
53 // get Tx Ring Resource
54 //
55 pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
56 TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx;
57 pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa;
58 BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa);
59
60 // copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
61 if (pTxBlk->TxFrameType == TX_AMSDU_FRAME)
62 {
63 hwHeaderLen = pTxBlk->MpduHeaderLen - LENGTH_AMSDU_SUBFRAMEHEAD + pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD;
64 }
65 else
66 {
67 hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
68 }
69 NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHeaderLen);
70
71 pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
72 pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
73
74 //
75 // build Tx Descriptor
76 //
77
78 pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
79 NdisZeroMemory(pTxD, TXD_SIZE);
80
81 pTxD->SDPtr0 = BufBasePaLow;
82 pTxD->SDLen0 = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; // include padding
83 pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);;
84 pTxD->SDLen1 = pTxBlk->SrcBufLen;
85 pTxD->LastSec0 = 0;
86 pTxD->LastSec1 = (bIsLast) ? 1 : 0;
87
88 RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
89
90 RetTxIdx = TxIdx;
91 //
92 // Update Tx index
93 //
94 INC_RING_INDEX(TxIdx, TX_RING_SIZE);
95 pTxRing->TxCpuIdx = TxIdx;
96
97 *FreeNumber -= 1;
98
99 return RetTxIdx;
100 }
101
102
103 USHORT RtmpPCI_WriteSingleTxResource(
104 IN PRTMP_ADAPTER pAd,
105 IN TX_BLK *pTxBlk,
106 IN BOOLEAN bIsLast,
107 OUT USHORT *FreeNumber)
108 {
109
110 UCHAR *pDMAHeaderBufVA;
111 USHORT TxIdx, RetTxIdx;
112 PTXD_STRUC pTxD;
113 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).
1124 if ((pAd->OpMode == OPMODE_STA) &&
1125 (IDLE_ON(pAd)) &&
1126 (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF)))
1127 {
1128 RT28xxPciAsicRadioOn(pAd, GUI_IDLE_POWER_SAVE);
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 }