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;
369 pAd->MgmtRing.Cell[SwIdx].pNdisPacket = pPacket;
370 pAd->MgmtRing.Cell[SwIdx].pNextNdisPacket = NULL;
372 RTMPWriteTxDescriptor(pAd, pTxD, TRUE, FIFO_MGMT);
377 pTxD->SDPtr0 = PCI_MAP_SINGLE(pAd, pSrcBufVA, SrcBufLen, 0, PCI_DMA_TODEVICE);;
378 pTxD->SDLen0 = SrcBufLen;
380 pAd->RalinkCounters.KickTxCount++;
381 pAd->RalinkCounters.OneSecTxDoneCount++;
383 // Increase TX_CTX_IDX, but write to register later.
384 INC_RING_INDEX(pAd->MgmtRing.TxCpuIdx, MGMT_RING_SIZE);
386 RTMP_IO_WRITE32(pAd, TX_MGMTCTX_IDX, pAd->MgmtRing.TxCpuIdx);
392 ========================================================================
395 Check Rx descriptor, return NDIS_STATUS_FAILURE if any error dound
398 pRxD Pointer to the Rx descriptor
401 NDIS_STATUS_SUCCESS No err
402 NDIS_STATUS_FAILURE Error
406 ========================================================================
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)
417 // Phy errors & CRC errors
418 if (/*(pRxD->PhyErr) ||*/ (pRxD->Crc))
420 // Check RSSI for Noise Hist statistic collection.
421 dBm = (INT) (pRxWI->RSSI0) - pAd->BbpRssiToDbmDelta;
423 pAd->StaCfg.RPIDensity[0] += 1;
425 pAd->StaCfg.RPIDensity[1] += 1;
427 pAd->StaCfg.RPIDensity[2] += 1;
429 pAd->StaCfg.RPIDensity[3] += 1;
431 pAd->StaCfg.RPIDensity[4] += 1;
433 pAd->StaCfg.RPIDensity[5] += 1;
435 pAd->StaCfg.RPIDensity[6] += 1;
437 pAd->StaCfg.RPIDensity[7] += 1;
439 return(NDIS_STATUS_FAILURE);
442 // Add Rx size to channel load counter, we should ignore error counts
443 pAd->StaCfg.CLBusyBytes += (pRxD->SDL0 + 14);
445 // Drop ToDs promiscous frame, it is opened due to CCX 2 channel load statistics
448 if (pHeader->FC.ToDs)
450 return(NDIS_STATUS_FAILURE);
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);
459 // drop decyption fail frame
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 "));
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);
472 DBGPRINT_RAW(RT_DEBUG_TRACE,(" %d (len=%d, Mcast=%d, MyBss=%d, Wcid=%d, KeyId=%d)\n",
475 pRxD->Mcast | pRxD->Bcast,
477 pRxWI->WirelessCliID,
483 if (pRxD->CipherErr == 2)
485 pWpaKey = &pAd->SharedKey[BSS0][pRxWI->KeyIndex];
487 if (pAd->StaCfg.WpaSupplicantUP)
488 WpaSendMicFailureToWpaSupplicant(pAd,
489 (pWpaKey->Type == PAIRWISEKEY) ? TRUE:FALSE);
491 RTMPReportMicError(pAd, pWpaKey);
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);
496 DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error\n"));
500 return(NDIS_STATUS_SUCCESS);
502 return(NDIS_STATUS_FAILURE);
505 return(NDIS_STATUS_SUCCESS);
509 ==========================================================================
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.
514 Level = GUIRADIO_OFF : GUI Radio Off mode
515 Level = DOT11POWERSAVE : 802.11 power save mode
516 Level = RTMP_HALT : When Disable device.
518 ==========================================================================
520 VOID RT28xxPciAsicRadioOff(
521 IN PRTMP_ADAPTER pAd,
523 IN USHORT TbttNumToNextWakeUp)
525 WPDMA_GLO_CFG_STRUC DmaCfg;
526 UCHAR i, tempBBP_R3 = 0;
527 BOOLEAN brc = FALSE, Cancelled;
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));
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))
539 DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return1. RxDmaIdx = %d , RxCpuIdx = %d. \n", RxDmaIdx, RxCpuIdx));
542 else if ((RxCpuIdx >= RxDmaIdx) && ((RxCpuIdx - RxDmaIdx) < RX_RING_SIZE/3))
544 DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return2. RxCpuIdx = %d. RxDmaIdx = %d , \n", RxCpuIdx, RxDmaIdx));
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);
551 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
553 RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
554 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
556 if (Level == DOT11POWERSAVE)
558 RTMP_IO_READ32(pAd, TBTT_TIMER, &TbTTTime);
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))
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);
571 PsPollTime = (64*TbTTTime- LEAD_TIME*1024)/1000;
574 BeaconPeriodTime = pAd->CommonCfg.BeaconPeriod*102/100;
575 if (TbttNumToNextWakeUp > 0)
576 PsPollTime += ((TbttNumToNextWakeUp -1) * BeaconPeriodTime);
578 pAd->Mlme.bPsPollTimerRunning = TRUE;
579 RTMPSetTimer(&pAd->Mlme.PsPollTimer, PsPollTime);
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);
589 // 1. Wait DMA not busy
593 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
594 if ((DmaCfg.field.TxDMABusy == 0) && (DmaCfg.field.RxDMABusy == 0))
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++;
611 pAd->CheckDmaBusyCount = 0;
614 RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
617 if (pAd->Antenna.field.RxPath > 1)
619 tempBBP_R3 = (pAd->StaCfg.BBPR3 & 0xE7);
620 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, tempBBP_R3);
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))
628 AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel);
633 AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel);
636 if (Level != RTMP_HALT)
638 // Change Interrupt bitmask.
639 RTMP_IO_WRITE32(pAd, INT_MASK_CSR, AutoWakeupInt);
643 NICDisableInterrupt(pAd);
646 RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx);
648 RTMP_IO_READ32(pAd, MAC_SYS_CTRL , &MACValue);
650 RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL , MACValue);
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);
664 AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x01); // send POWER-SAVE command to MCU. Timeout unit:40us.
665 //RTMPusecDelay(200);
666 brc = AsicCheckCommanOk(pAd, PowerSafeCID);
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))
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);
677 else if (brc == TRUE)
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);
688 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
689 if ((DmaCfg.field.RxDMABusy == 0) && (DmaCfg.field.TxDMABusy == 0))
697 pAd->CheckDmaBusyCount++;
698 DBGPRINT(RT_DEBUG_TRACE, ("DMA Rx keeps busy. on RT28xxPciAsicRadioOff ()\n"));
702 pAd->CheckDmaBusyCount = 0;
705 if (Level == DOT11POWERSAVE)
707 AUTO_WAKEUP_STRUC AutoWakeupCfg;
708 //RTMPSetTimer(&pAd->Mlme.PsPollTimer, 90);
710 // we have decided to SLEEP, so at least do it for a BEACON period.
711 if (TbttNumToNextWakeUp == 0)
712 TbttNumToNextWakeUp = 1;
714 AutoWakeupCfg.word = 0;
715 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
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);
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)
727 if ((brc == TRUE) && (i < 50))
728 RTMPPCIeLinkCtrlSetting(pAd, 0);
730 // 4. Set PCI configuration Space Link Comtrol fields. Only Radio Off needs to call this function
733 if ((brc == TRUE) && (i < 50))
734 RTMPPCIeLinkCtrlSetting(pAd, 3);
737 RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
742 ==========================================================================
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.
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.
750 ==========================================================================
752 BOOLEAN RT28xxPciAsicRadioOn(
753 IN PRTMP_ADAPTER pAd,
756 WPDMA_GLO_CFG_STRUC DmaCfg;
757 BOOLEAN Cancelled, brv = TRUE;
760 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
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)))
767 DBGPRINT(RT_DEBUG_TRACE, ("RT28xxPciAsicRadioOn ()\n"));
768 // 1. Set PCI Link Control in Configuration Space.
769 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
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);
779 // 2-1. wait command ok.
780 brv = AsicCheckCommanOk(pAd, PowerWakeCID);
783 NICEnableInterrupt(pAd);
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);
792 RTMP_IO_READ32(pAd, MAC_SYS_CTRL , &MACValue);
794 RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL , MACValue);
796 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
797 if (Level == GUI_IDLE_POWER_SAVE)
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))
804 AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
805 AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
810 AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
811 AsicLockChannel(pAd, pAd->CommonCfg.Channel);
820 VOID RT28xxPciStaAsicForceWakeup(
821 IN PRTMP_ADAPTER pAd,
824 AUTO_WAKEUP_STRUC AutoWakeupCfg;
826 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
828 DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
832 OPSTATUS_SET_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
833 RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW);
835 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
837 // Support PCIe Advance Power Save
838 if (((Level == FROM_TX) && (pAd->Mlme.bPsPollTimerRunning == TRUE)) ||
839 (Level == RTMP_HALT))
841 pAd->Mlme.bPsPollTimerRunning = FALSE;
842 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
844 DBGPRINT(RT_DEBUG_TRACE, ("=======AsicForceWakeup===bFromTx\n"));
847 AutoWakeupCfg.word = 0;
848 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
850 // If this is called from Halt. ALWAYS force wakeup!!!
851 if (Level == RTMP_HALT)
853 RT28xxPciAsicRadioOn(pAd, RTMP_HALT);
857 if (RT28xxPciAsicRadioOn(pAd, DOT11POWERSAVE))
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))
864 AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
865 AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
870 AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
871 AsicLockChannel(pAd, pAd->CommonCfg.Channel);
879 AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x00);
880 AutoWakeupCfg.word = 0;
881 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
884 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
885 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
886 DBGPRINT(RT_DEBUG_TRACE, ("<=======RT28xxPciStaAsicForceWakeup\n"));
889 VOID RT28xxPciStaAsicSleepThenAutoWakeup(
890 IN PRTMP_ADAPTER pAd,
891 IN USHORT TbttNumToNextWakeUp)
893 if (pAd->StaCfg.bRadio == FALSE)
895 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
898 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
901 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
903 DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
904 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
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))
913 DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu : RxCountSinceLastNULL = %lu. \n", Now, pAd->Mlme.LastSendNULLpsmTime, pAd->RalinkCounters.RxCountSinceLastNULL));
916 else if ((pAd->RalinkCounters.RxCountSinceLastNULL > 0) && ((pAd->Mlme.LastSendNULLpsmTime + pAd->CommonCfg.BeaconPeriod) >= Now))
918 DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu: RxCountSinceLastNULL = %lu > 0 \n", Now, pAd->Mlme.LastSendNULLpsmTime, pAd->RalinkCounters.RxCountSinceLastNULL));
922 RT28xxPciAsicRadioOff(pAd, DOT11POWERSAVE, TbttNumToNextWakeUp);
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;
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));
940 OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE);
944 IN PVOID SystemSpecific1,
945 IN PVOID FunctionContext,
946 IN PVOID SystemSpecific2,
947 IN PVOID SystemSpecific3)
949 RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
952 DBGPRINT(RT_DEBUG_TRACE,("-->PsPollWakeExec \n"));
953 RTMP_INT_LOCK(&pAd->irq_lock, flags);
954 if (pAd->Mlme.bPsPollTimerRunning)
956 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
958 pAd->Mlme.bPsPollTimerRunning = FALSE;
959 RTMP_INT_UNLOCK(&pAd->irq_lock, flags);
963 IN PVOID SystemSpecific1,
964 IN PVOID FunctionContext,
965 IN PVOID SystemSpecific2,
966 IN PVOID SystemSpecific3)
968 RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
969 WPDMA_GLO_CFG_STRUC DmaCfg;
972 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
974 DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on fOP_STATUS_DOZE == TRUE; \n"));
975 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
979 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
981 DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on SCAN_IN_PROGRESS; \n"));
982 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
985 pAd->Mlme.bPsPollTimerRunning = FALSE;
986 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
987 if (pAd->StaCfg.bRadio == TRUE)
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);
998 // 2. Send wake up command.
999 AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02);
1000 // 2-1. wait command ok.
1001 AsicCheckCommanOk(pAd, PowerWakeCID);
1003 // When PCI clock is off, don't want to service interrupt. So when back to clock on, enable interrupt.
1004 NICEnableInterrupt(pAd);
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);
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))
1015 // Must using 40MHz.
1016 AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
1017 AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
1021 // Must using 20MHz.
1022 AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
1023 AsicLockChannel(pAd, pAd->CommonCfg.Channel);
1026 // Clear Radio off flag
1027 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1030 RTMPSetLED(pAd, LED_RADIO_ON);
1032 if (pAd->StaCfg.Psm == PWR_ACTIVE)
1034 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, pAd->StaCfg.BBPR3);
1039 RT28xxPciAsicRadioOff(pAd, GUIRADIO_OFF, 0);
1043 VOID RT28xxPciMlmeRadioOn(
1044 IN PRTMP_ADAPTER pAd)
1046 if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1049 DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
1051 if ((pAd->OpMode == OPMODE_AP) ||
1052 ((pAd->OpMode == OPMODE_STA) && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))))
1054 NICResetFromError(pAd);
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);
1067 RTMPEnableRxTx(pAd);
1069 // Clear Radio off flag
1070 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1073 RTMPSetLED(pAd, LED_RADIO_ON);
1076 if ((pAd->OpMode == OPMODE_STA) &&
1077 (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)))
1081 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
1083 pAd->Mlme.bPsPollTimerRunning = FALSE;
1084 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1085 RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
1086 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1090 VOID RT28xxPciMlmeRadioOFF(
1091 IN PRTMP_ADAPTER pAd)
1093 WPDMA_GLO_CFG_STRUC GloCfg;
1096 if (pAd->StaCfg.bRadio == TRUE)
1098 DBGPRINT(RT_DEBUG_TRACE,("-->MlmeRadioOff() return on bRadio == TRUE; \n"));
1102 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1105 DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
1108 RTMPSetLED(pAd, LED_RADIO_OFF);
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);