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