2 *************************************************************************
4 * 5F., No.36, Taiyuan St., Jhubei City,
8 * (c) Copyright 2002-2007, Ralink Technology, Inc.
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. *
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. *
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. *
25 *************************************************************************
29 All functions in this file must be PCI-depended, or you should out your function
33 #include "../rt_config.h"
35 extern RTMP_RF_REGS RF2850RegTable[];
36 extern UCHAR NUM_OF_2850_CHNL;
38 USHORT RtmpPCI_WriteTxResource(
42 OUT USHORT *FreeNumber)
45 UCHAR *pDMAHeaderBufVA;
46 USHORT TxIdx, RetTxIdx;
49 PRTMP_TX_RING pTxRing;
53 // get Tx Ring Resource
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);
60 // copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
61 if (pTxBlk->TxFrameType == TX_AMSDU_FRAME)
63 hwHeaderLen = pTxBlk->MpduHeaderLen - LENGTH_AMSDU_SUBFRAMEHEAD + pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD;
67 hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
69 NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHeaderLen);
71 pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
72 pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
75 // build Tx Descriptor
78 pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
79 NdisZeroMemory(pTxD, TXD_SIZE);
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;
86 pTxD->LastSec1 = (bIsLast) ? 1 : 0;
88 RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
94 INC_RING_INDEX(TxIdx, TX_RING_SIZE);
95 pTxRing->TxCpuIdx = TxIdx;
103 USHORT RtmpPCI_WriteSingleTxResource(
104 IN PRTMP_ADAPTER pAd,
107 OUT USHORT *FreeNumber)
110 UCHAR *pDMAHeaderBufVA;
111 USHORT TxIdx, RetTxIdx;
114 PRTMP_TX_RING pTxRing;
118 // get Tx Ring Resource
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);
125 // copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
126 hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
128 NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHeaderLen);
130 pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
131 pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
134 // build Tx Descriptor
136 pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
138 NdisZeroMemory(pTxD, TXD_SIZE);
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;
145 pTxD->LastSec1 = (bIsLast) ? 1 : 0;
147 RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
153 INC_RING_INDEX(TxIdx, TX_RING_SIZE);
154 pTxRing->TxCpuIdx = TxIdx;
162 USHORT RtmpPCI_WriteMultiTxResource(
163 IN PRTMP_ADAPTER pAd,
166 OUT USHORT *FreeNumber)
169 UCHAR *pDMAHeaderBufVA;
170 USHORT TxIdx, RetTxIdx;
173 PRTMP_TX_RING pTxRing;
177 bIsLast = ((frameNum == (pTxBlk->TotalFrameNum - 1)) ? 1 : 0);
180 // get Tx Ring Resource
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);
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;
197 //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4);
198 hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
200 firstDMALen = TXINFO_SIZE + TXWI_SIZE + hwHdrLen;
204 firstDMALen = pTxBlk->MpduHeaderLen;
207 NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, firstDMALen);
209 pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
210 pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
213 // build Tx Descriptor
215 pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
217 NdisZeroMemory(pTxD, TXD_SIZE);
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;
224 pTxD->LastSec1 = (bIsLast) ? 1 : 0;
226 RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
232 INC_RING_INDEX(TxIdx, TX_RING_SIZE);
233 pTxRing->TxCpuIdx = TxIdx;
242 VOID RtmpPCI_FinalWriteTxResource(
243 IN PRTMP_ADAPTER pAd,
245 IN USHORT totalMPDUSize,
246 IN USHORT FirstTxIdx)
250 PRTMP_TX_RING pTxRing;
253 // get Tx Ring Resource
255 pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
256 pTxWI = (PTXWI_STRUC) pTxRing->Cell[FirstTxIdx].DmaBuf.AllocVa;
257 pTxWI->MPDUtotalByteCount = totalMPDUSize;
261 VOID RtmpPCIDataLastTxIdx(
262 IN PRTMP_ADAPTER pAd,
267 PRTMP_TX_RING pTxRing;
270 // get Tx Ring Resource
272 pTxRing = &pAd->TxRing[QueIdx];
275 // build Tx Descriptor
277 pTxD = (PTXD_STRUC) pTxRing->Cell[LastTxIdx].AllocVa;
283 USHORT RtmpPCI_WriteFragTxResource(
284 IN PRTMP_ADAPTER pAd,
287 OUT USHORT *FreeNumber)
289 UCHAR *pDMAHeaderBufVA;
290 USHORT TxIdx, RetTxIdx;
293 PRTMP_TX_RING pTxRing;
298 // Get Tx Ring Resource
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);
306 // Copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
308 hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
310 firstDMALen = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen;
311 NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, firstDMALen);
315 // Build Tx Descriptor
317 pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
319 NdisZeroMemory(pTxD, TXD_SIZE);
321 if (fragNum == pTxBlk->TotalFragNum)
323 pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
324 pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
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;
334 RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
337 pTxBlk->Priv += pTxBlk->SrcBufLen;
342 INC_RING_INDEX(TxIdx, TX_RING_SIZE);
343 pTxRing->TxCpuIdx = TxIdx;
352 Must be run in Interrupt context
353 This function handle PCI specific TxDesc and cpu index update and kick the packet out.
355 int RtmpPCIMgmtKickOut(
356 IN RTMP_ADAPTER *pAd,
358 IN PNDIS_PACKET pPacket,
363 ULONG SwIdx = pAd->MgmtRing.TxCpuIdx;
365 pTxD = (PTXD_STRUC) pAd->MgmtRing.Cell[SwIdx].AllocVa;
367 pAd->MgmtRing.Cell[SwIdx].pNdisPacket = pPacket;
368 pAd->MgmtRing.Cell[SwIdx].pNextNdisPacket = NULL;
370 RTMPWriteTxDescriptor(pAd, pTxD, TRUE, FIFO_MGMT);
375 pTxD->SDPtr0 = PCI_MAP_SINGLE(pAd, pSrcBufVA, SrcBufLen, 0, PCI_DMA_TODEVICE);;
376 pTxD->SDLen0 = SrcBufLen;
378 pAd->RalinkCounters.KickTxCount++;
379 pAd->RalinkCounters.OneSecTxDoneCount++;
381 // Increase TX_CTX_IDX, but write to register later.
382 INC_RING_INDEX(pAd->MgmtRing.TxCpuIdx, MGMT_RING_SIZE);
384 RTMP_IO_WRITE32(pAd, TX_MGMTCTX_IDX, pAd->MgmtRing.TxCpuIdx);
390 ========================================================================
393 Check Rx descriptor, return NDIS_STATUS_FAILURE if any error dound
396 pRxD Pointer to the Rx descriptor
399 NDIS_STATUS_SUCCESS No err
400 NDIS_STATUS_FAILURE Error
404 ========================================================================
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)
415 // Phy errors & CRC errors
416 if (/*(pRxD->PhyErr) ||*/ (pRxD->Crc))
418 // Check RSSI for Noise Hist statistic collection.
419 dBm = (INT) (pRxWI->RSSI0) - pAd->BbpRssiToDbmDelta;
421 pAd->StaCfg.RPIDensity[0] += 1;
423 pAd->StaCfg.RPIDensity[1] += 1;
425 pAd->StaCfg.RPIDensity[2] += 1;
427 pAd->StaCfg.RPIDensity[3] += 1;
429 pAd->StaCfg.RPIDensity[4] += 1;
431 pAd->StaCfg.RPIDensity[5] += 1;
433 pAd->StaCfg.RPIDensity[6] += 1;
435 pAd->StaCfg.RPIDensity[7] += 1;
437 return(NDIS_STATUS_FAILURE);
440 // Add Rx size to channel load counter, we should ignore error counts
441 pAd->StaCfg.CLBusyBytes += (pRxD->SDL0 + 14);
443 // Drop ToDs promiscous frame, it is opened due to CCX 2 channel load statistics
446 if (pHeader->FC.ToDs)
448 return(NDIS_STATUS_FAILURE);
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);
457 // drop decyption fail frame
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 "));
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);
470 DBGPRINT_RAW(RT_DEBUG_TRACE,(" %d (len=%d, Mcast=%d, MyBss=%d, Wcid=%d, KeyId=%d)\n",
473 pRxD->Mcast | pRxD->Bcast,
475 pRxWI->WirelessCliID,
481 if (pRxD->CipherErr == 2)
483 pWpaKey = &pAd->SharedKey[BSS0][pRxWI->KeyIndex];
484 #ifdef WPA_SUPPLICANT_SUPPORT
485 if (pAd->StaCfg.WpaSupplicantUP)
486 WpaSendMicFailureToWpaSupplicant(pAd,
487 (pWpaKey->Type == PAIRWISEKEY) ? TRUE:FALSE);
489 #endif // WPA_SUPPLICANT_SUPPORT //
490 RTMPReportMicError(pAd, pWpaKey);
492 if (((pRxD->CipherErr & 2) == 2) && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd))
493 RTMPSendWirelessEvent(pAd, IW_MIC_ERROR_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
495 DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error\n"));
499 return(NDIS_STATUS_SUCCESS);
501 return(NDIS_STATUS_FAILURE);
504 return(NDIS_STATUS_SUCCESS);
508 ==========================================================================
510 This routine sends command to firmware and turn our chip to power save mode.
511 Both RadioOff and .11 power save function needs to call this routine.
513 Level = GUIRADIO_OFF : GUI Radio Off mode
514 Level = DOT11POWERSAVE : 802.11 power save mode
515 Level = RTMP_HALT : When Disable device.
517 ==========================================================================
519 VOID RT28xxPciAsicRadioOff(
520 IN PRTMP_ADAPTER pAd,
522 IN USHORT TbttNumToNextWakeUp)
524 WPDMA_GLO_CFG_STRUC DmaCfg;
525 UCHAR i, tempBBP_R3 = 0;
526 BOOLEAN brc = FALSE, Cancelled;
528 UINT32 PsPollTime = 0, MACValue;
529 ULONG BeaconPeriodTime;
530 UINT32 RxDmaIdx, RxCpuIdx;
531 DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> TxCpuIdx = %d, TxDmaIdx = %d. RxCpuIdx = %d, RxDmaIdx = %d.\n", pAd->TxRing[0].TxCpuIdx, pAd->TxRing[0].TxDmaIdx, pAd->RxRing.RxCpuIdx, pAd->RxRing.RxDmaIdx));
533 // Check Rx DMA busy status, if more than half is occupied, give up this radio off.
534 RTMP_IO_READ32(pAd, RX_DRX_IDX , &RxDmaIdx);
535 RTMP_IO_READ32(pAd, RX_CRX_IDX , &RxCpuIdx);
536 if ((RxDmaIdx > RxCpuIdx) && ((RxDmaIdx - RxCpuIdx) > RX_RING_SIZE/3))
538 DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return1. RxDmaIdx = %d , RxCpuIdx = %d. \n", RxDmaIdx, RxCpuIdx));
541 else if ((RxCpuIdx >= RxDmaIdx) && ((RxCpuIdx - RxDmaIdx) < RX_RING_SIZE/3))
543 DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return2. RxCpuIdx = %d. RxDmaIdx = %d , \n", RxCpuIdx, RxDmaIdx));
547 // Once go into this function, disable tx because don't want too many packets in queue to prevent HW stops.
548 RTMP_SET_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
550 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
552 RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
553 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
555 if (Level == DOT11POWERSAVE)
557 RTMP_IO_READ32(pAd, TBTT_TIMER, &TbTTTime);
559 // 00. check if need to do sleep in this DTIM period. If next beacon will arrive within 30ms , ...doesn't necessarily sleep.
560 // TbTTTime uint = 64us, LEAD_TIME unit = 1024us, PsPollTime unit = 1ms
561 if (((64*TbTTTime) <((LEAD_TIME*1024) + 40000)) && (TbttNumToNextWakeUp == 0))
563 DBGPRINT(RT_DEBUG_TRACE, ("TbTTTime = 0x%x , give up this sleep. \n", TbTTTime));
564 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
565 RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
570 PsPollTime = (64*TbTTTime- LEAD_TIME*1024)/1000;
573 BeaconPeriodTime = pAd->CommonCfg.BeaconPeriod*102/100;
574 if (TbttNumToNextWakeUp > 0)
575 PsPollTime += ((TbttNumToNextWakeUp -1) * BeaconPeriodTime);
577 pAd->Mlme.bPsPollTimerRunning = TRUE;
578 RTMPSetTimer(&pAd->Mlme.PsPollTimer, PsPollTime);
583 // 0. Disable Tx DMA.
584 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
585 DmaCfg.field.EnableTxDMA = 0;
586 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
588 // 1. Wait DMA not busy
592 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
593 if ((DmaCfg.field.TxDMABusy == 0) && (DmaCfg.field.RxDMABusy == 0))
601 DBGPRINT(RT_DEBUG_TRACE, ("DMA keeps busy. return on RT28xxPciAsicRadioOff ()\n"));
602 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
603 DmaCfg.field.EnableTxDMA = 1;
604 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
605 pAd->CheckDmaBusyCount++;
610 pAd->CheckDmaBusyCount = 0;
613 RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
616 if (pAd->Antenna.field.RxPath > 1)
618 tempBBP_R3 = (pAd->StaCfg.BBPR3 & 0xE7);
619 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, tempBBP_R3);
622 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
623 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
624 && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
627 AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel);
632 AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel);
635 if (Level != RTMP_HALT)
637 // Change Interrupt bitmask.
638 RTMP_IO_WRITE32(pAd, INT_MASK_CSR, AutoWakeupInt);
642 NICDisableInterrupt(pAd);
645 RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx);
647 RTMP_IO_READ32(pAd, MAC_SYS_CTRL , &MACValue);
649 RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL , MACValue);
651 // 2. Send Sleep command
652 RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff);
653 RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff);
654 // send POWER-SAVE command to MCU. high-byte = 1 save power as much as possible. high byte = 0 save less power
655 AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x1);
656 // 2-1. Wait command success
657 // Status = 1 : success, Status = 2, already sleep, Status = 3, Maybe MAC is busy so can't finish this task.
658 brc = AsicCheckCommanOk(pAd, PowerSafeCID);
663 AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x01); // send POWER-SAVE command to MCU. Timeout unit:40us.
664 //RTMPusecDelay(200);
665 brc = AsicCheckCommanOk(pAd, PowerSafeCID);
668 // 3. After 0x30 command is ok, send radio off command. lowbyte = 0 for power safe.
669 // If 0x30 command is not ok this time, we can ignore 0x35 command. It will make sure not cause firmware'r problem.
670 if ((Level == DOT11POWERSAVE) && (brc == TRUE))
672 AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 0, 0x00); // lowbyte = 0 means to do power safe, NOT turn off radio.
673 // 3-1. Wait command success
674 AsicCheckCommanOk(pAd, PowerRadioOffCID);
676 else if (brc == TRUE)
678 AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 1, 0x00); // lowbyte = 0 means to do power safe, NOT turn off radio.
679 // 3-1. Wait command success
680 AsicCheckCommanOk(pAd, PowerRadioOffCID);
687 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
688 if ((DmaCfg.field.RxDMABusy == 0) && (DmaCfg.field.TxDMABusy == 0))
696 pAd->CheckDmaBusyCount++;
697 DBGPRINT(RT_DEBUG_TRACE, ("DMA Rx keeps busy. on RT28xxPciAsicRadioOff ()\n"));
701 pAd->CheckDmaBusyCount = 0;
704 if (Level == DOT11POWERSAVE)
706 AUTO_WAKEUP_STRUC AutoWakeupCfg;
707 //RTMPSetTimer(&pAd->Mlme.PsPollTimer, 90);
709 // we have decided to SLEEP, so at least do it for a BEACON period.
710 if (TbttNumToNextWakeUp == 0)
711 TbttNumToNextWakeUp = 1;
713 AutoWakeupCfg.word = 0;
714 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
716 // 1. Set auto wake up timer.
717 AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1;
718 AutoWakeupCfg.field.EnableAutoWakeup = 1;
719 AutoWakeupCfg.field.AutoLeadTime = LEAD_TIME;
720 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
723 // 4-1. If it's to disable our device. Need to restore PCI Configuration Space to its original value.
724 if (Level == RTMP_HALT)
726 if ((brc == TRUE) && (i < 50))
727 RTMPPCIeLinkCtrlSetting(pAd, 0);
729 // 4. Set PCI configuration Space Link Comtrol fields. Only Radio Off needs to call this function
732 if ((brc == TRUE) && (i < 50))
733 RTMPPCIeLinkCtrlSetting(pAd, 3);
736 RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
741 ==========================================================================
743 This routine sends command to firmware and turn our chip to wake up mode from power save mode.
744 Both RadioOn and .11 power save function needs to call this routine.
746 Level = GUIRADIO_OFF : call this function is from Radio Off to Radio On. Need to restore PCI host value.
747 Level = other value : normal wake up function.
749 ==========================================================================
751 BOOLEAN RT28xxPciAsicRadioOn(
752 IN PRTMP_ADAPTER pAd,
755 WPDMA_GLO_CFG_STRUC DmaCfg;
756 BOOLEAN Cancelled, brv = TRUE;
759 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
761 pAd->Mlme.bPsPollTimerRunning = FALSE;
762 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
763 if ((Level == GUIRADIO_OFF) || (Level == GUI_IDLE_POWER_SAVE)
764 || (RTMP_TEST_PSFLAG(pAd, fRTMP_PS_SET_PCI_CLK_OFF_COMMAND)))
766 DBGPRINT(RT_DEBUG_TRACE, ("RT28xxPciAsicRadioOn ()\n"));
767 // 1. Set PCI Link Control in Configuration Space.
768 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
773 pAd->bPCIclkOff = FALSE;
774 RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0x3a80);
775 // 2. Send wake up command.
776 AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02);
778 // 2-1. wait command ok.
779 brv = AsicCheckCommanOk(pAd, PowerWakeCID);
782 NICEnableInterrupt(pAd);
785 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
786 DmaCfg.field.EnableTxDMA = 1;
787 DmaCfg.field.EnableRxDMA = 1;
788 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
791 RTMP_IO_READ32(pAd, MAC_SYS_CTRL , &MACValue);
793 RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL , MACValue);
795 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
796 if (Level == GUI_IDLE_POWER_SAVE)
798 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
799 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
800 && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
803 AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
804 AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
809 AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
810 AsicLockChannel(pAd, pAd->CommonCfg.Channel);
819 VOID RT28xxPciStaAsicForceWakeup(
820 IN PRTMP_ADAPTER pAd,
823 AUTO_WAKEUP_STRUC AutoWakeupCfg;
825 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
827 DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
831 OPSTATUS_SET_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
832 RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW);
834 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
836 // Support PCIe Advance Power Save
837 if (((Level == FROM_TX) && (pAd->Mlme.bPsPollTimerRunning == TRUE)) ||
838 (Level == RTMP_HALT))
840 pAd->Mlme.bPsPollTimerRunning = FALSE;
841 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
843 DBGPRINT(RT_DEBUG_TRACE, ("=======AsicForceWakeup===bFromTx\n"));
846 AutoWakeupCfg.word = 0;
847 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
849 // If this is called from Halt. ALWAYS force wakeup!!!
850 if (Level == RTMP_HALT)
852 RT28xxPciAsicRadioOn(pAd, RTMP_HALT);
856 if (RT28xxPciAsicRadioOn(pAd, DOT11POWERSAVE))
858 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
859 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
860 && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
863 AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
864 AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
869 AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
870 AsicLockChannel(pAd, pAd->CommonCfg.Channel);
878 AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x00);
879 AutoWakeupCfg.word = 0;
880 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
883 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
884 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
885 DBGPRINT(RT_DEBUG_TRACE, ("<=======RT28xxPciStaAsicForceWakeup\n"));
888 VOID RT28xxPciStaAsicSleepThenAutoWakeup(
889 IN PRTMP_ADAPTER pAd,
890 IN USHORT TbttNumToNextWakeUp)
892 if (pAd->StaCfg.bRadio == FALSE)
894 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
897 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
900 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
902 DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
903 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
907 NdisGetSystemUpTime(&Now);
908 // If last send NULL fram time is too close to this receiving beacon (within 8ms), don't go to sleep for this DTM.
909 // Because Some AP can't queuing outgoing frames immediately.
910 if (((pAd->Mlme.LastSendNULLpsmTime + 8) >= Now) && (pAd->Mlme.LastSendNULLpsmTime <= Now))
912 DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu : RxCountSinceLastNULL = %lu. \n", Now, pAd->Mlme.LastSendNULLpsmTime, pAd->RalinkCounters.RxCountSinceLastNULL));
915 else if ((pAd->RalinkCounters.RxCountSinceLastNULL > 0) && ((pAd->Mlme.LastSendNULLpsmTime + pAd->CommonCfg.BeaconPeriod) >= Now))
917 DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu: RxCountSinceLastNULL = %lu > 0 \n", Now, pAd->Mlme.LastSendNULLpsmTime, pAd->RalinkCounters.RxCountSinceLastNULL));
921 RT28xxPciAsicRadioOff(pAd, DOT11POWERSAVE, TbttNumToNextWakeUp);
925 AUTO_WAKEUP_STRUC AutoWakeupCfg;
926 // we have decided to SLEEP, so at least do it for a BEACON period.
927 if (TbttNumToNextWakeUp == 0)
928 TbttNumToNextWakeUp = 1;
930 AutoWakeupCfg.word = 0;
931 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
932 AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1;
933 AutoWakeupCfg.field.EnableAutoWakeup = 1;
934 AutoWakeupCfg.field.AutoLeadTime = 5;
935 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
936 AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x00); // send POWER-SAVE command to MCU. Timeout 40us.
937 DBGPRINT(RT_DEBUG_TRACE, ("<-- %s, TbttNumToNextWakeUp=%d \n", __func__, TbttNumToNextWakeUp));
939 OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE);
943 IN PVOID SystemSpecific1,
944 IN PVOID FunctionContext,
945 IN PVOID SystemSpecific2,
946 IN PVOID SystemSpecific3)
948 RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
951 DBGPRINT(RT_DEBUG_TRACE,("-->PsPollWakeExec \n"));
952 RTMP_INT_LOCK(&pAd->irq_lock, flags);
953 if (pAd->Mlme.bPsPollTimerRunning)
955 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
957 pAd->Mlme.bPsPollTimerRunning = FALSE;
958 RTMP_INT_UNLOCK(&pAd->irq_lock, flags);
962 IN PVOID SystemSpecific1,
963 IN PVOID FunctionContext,
964 IN PVOID SystemSpecific2,
965 IN PVOID SystemSpecific3)
967 RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
968 WPDMA_GLO_CFG_STRUC DmaCfg;
971 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
973 DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on fOP_STATUS_DOZE == TRUE; \n"));
974 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
978 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
980 DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on SCAN_IN_PROGRESS; \n"));
981 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
984 pAd->Mlme.bPsPollTimerRunning = FALSE;
985 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
986 if (pAd->StaCfg.bRadio == TRUE)
988 pAd->bPCIclkOff = FALSE;
989 RTMPRingCleanUp(pAd, QID_AC_BK);
990 RTMPRingCleanUp(pAd, QID_AC_BE);
991 RTMPRingCleanUp(pAd, QID_AC_VI);
992 RTMPRingCleanUp(pAd, QID_AC_VO);
993 RTMPRingCleanUp(pAd, QID_HCCA);
994 RTMPRingCleanUp(pAd, QID_MGMT);
995 RTMPRingCleanUp(pAd, QID_RX);
997 // 2. Send wake up command.
998 AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02);
999 // 2-1. wait command ok.
1000 AsicCheckCommanOk(pAd, PowerWakeCID);
1002 // When PCI clock is off, don't want to service interrupt. So when back to clock on, enable interrupt.
1003 NICEnableInterrupt(pAd);
1005 // 3. Enable Tx DMA.
1006 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
1007 DmaCfg.field.EnableTxDMA = 1;
1008 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
1010 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
1011 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
1012 && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
1014 // Must using 40MHz.
1015 AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
1016 AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
1020 // Must using 20MHz.
1021 AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
1022 AsicLockChannel(pAd, pAd->CommonCfg.Channel);
1025 // Clear Radio off flag
1026 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1029 RTMPSetLED(pAd, LED_RADIO_ON);
1031 if (pAd->StaCfg.Psm == PWR_ACTIVE)
1033 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, pAd->StaCfg.BBPR3);
1038 RT28xxPciAsicRadioOff(pAd, GUIRADIO_OFF, 0);
1042 VOID RT28xxPciMlmeRadioOn(
1043 IN PRTMP_ADAPTER pAd)
1045 if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1048 DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
1050 if ((pAd->OpMode == OPMODE_AP) ||
1051 ((pAd->OpMode == OPMODE_STA) && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))))
1053 NICResetFromError(pAd);
1056 RTMPRingCleanUp(pAd, QID_AC_BK);
1057 RTMPRingCleanUp(pAd, QID_AC_BE);
1058 RTMPRingCleanUp(pAd, QID_AC_VI);
1059 RTMPRingCleanUp(pAd, QID_AC_VO);
1060 RTMPRingCleanUp(pAd, QID_HCCA);
1061 RTMPRingCleanUp(pAd, QID_MGMT);
1062 RTMPRingCleanUp(pAd, QID_RX);
1066 RTMPEnableRxTx(pAd);
1068 // Clear Radio off flag
1069 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1072 RTMPSetLED(pAd, LED_RADIO_ON);
1075 if ((pAd->OpMode == OPMODE_STA) &&
1076 (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)))
1080 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
1082 pAd->Mlme.bPsPollTimerRunning = FALSE;
1083 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1084 RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
1085 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1089 VOID RT28xxPciMlmeRadioOFF(
1090 IN PRTMP_ADAPTER pAd)
1092 WPDMA_GLO_CFG_STRUC GloCfg;
1095 if (pAd->StaCfg.bRadio == TRUE)
1097 DBGPRINT(RT_DEBUG_TRACE,("-->MlmeRadioOff() return on bRadio == TRUE; \n"));
1101 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1104 DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
1107 RTMPSetLED(pAd, LED_RADIO_OFF);
1109 IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
1113 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
1115 RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled);
1116 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);
1119 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
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
1128 RT28xxPciAsicRadioOn(pAd, GUI_IDLE_POWER_SAVE);
\r
1131 pAd->Mlme.bPsPollTimerRunning = FALSE;
1132 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1133 RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
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);
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);
1152 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
1154 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 500);
1159 // Set Radio off flag
1160 RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
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
1169 // MAC_SYS_CTRL => value = 0x0 => 40mA
1170 RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0);
1172 // PWR_PIN_CFG => value = 0x0 => 40mA
1173 RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0);
1175 // TX_PIN_CFG => value = 0x0 => 20mA
1176 RTMP_IO_WRITE32(pAd, TX_PIN_CFG, 0);
1178 if (pAd->CommonCfg.BBPCurrentBW == BW_40)
1180 // Must using 40MHz.
1181 AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel);
1185 // Must using 20MHz.
1186 AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel);
1189 // Waiting for DMA idle
1193 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
1194 if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0))
1197 RTMPusecDelay(1000);