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];
485 if (pAd->StaCfg.WpaSupplicantUP)
486 WpaSendMicFailureToWpaSupplicant(pAd,
487 (pWpaKey->Type == PAIRWISEKEY) ? TRUE:FALSE);
489 RTMPReportMicError(pAd, pWpaKey);
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);
494 DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error\n"));
498 return(NDIS_STATUS_SUCCESS);
500 return(NDIS_STATUS_FAILURE);
503 return(NDIS_STATUS_SUCCESS);
507 ==========================================================================
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.
512 Level = GUIRADIO_OFF : GUI Radio Off mode
513 Level = DOT11POWERSAVE : 802.11 power save mode
514 Level = RTMP_HALT : When Disable device.
516 ==========================================================================
518 VOID RT28xxPciAsicRadioOff(
519 IN PRTMP_ADAPTER pAd,
521 IN USHORT TbttNumToNextWakeUp)
523 WPDMA_GLO_CFG_STRUC DmaCfg;
524 UCHAR i, tempBBP_R3 = 0;
525 BOOLEAN brc = FALSE, Cancelled;
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));
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))
537 DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return1. RxDmaIdx = %d , RxCpuIdx = %d. \n", RxDmaIdx, RxCpuIdx));
540 else if ((RxCpuIdx >= RxDmaIdx) && ((RxCpuIdx - RxDmaIdx) < RX_RING_SIZE/3))
542 DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return2. RxCpuIdx = %d. RxDmaIdx = %d , \n", RxCpuIdx, RxDmaIdx));
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);
549 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
551 RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
552 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
554 if (Level == DOT11POWERSAVE)
556 RTMP_IO_READ32(pAd, TBTT_TIMER, &TbTTTime);
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))
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);
569 PsPollTime = (64*TbTTTime- LEAD_TIME*1024)/1000;
572 BeaconPeriodTime = pAd->CommonCfg.BeaconPeriod*102/100;
573 if (TbttNumToNextWakeUp > 0)
574 PsPollTime += ((TbttNumToNextWakeUp -1) * BeaconPeriodTime);
576 pAd->Mlme.bPsPollTimerRunning = TRUE;
577 RTMPSetTimer(&pAd->Mlme.PsPollTimer, PsPollTime);
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);
587 // 1. Wait DMA not busy
591 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
592 if ((DmaCfg.field.TxDMABusy == 0) && (DmaCfg.field.RxDMABusy == 0))
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++;
609 pAd->CheckDmaBusyCount = 0;
612 RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
615 if (pAd->Antenna.field.RxPath > 1)
617 tempBBP_R3 = (pAd->StaCfg.BBPR3 & 0xE7);
618 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, tempBBP_R3);
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))
626 AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel);
631 AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel);
634 if (Level != RTMP_HALT)
636 // Change Interrupt bitmask.
637 RTMP_IO_WRITE32(pAd, INT_MASK_CSR, AutoWakeupInt);
641 NICDisableInterrupt(pAd);
644 RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx);
646 RTMP_IO_READ32(pAd, MAC_SYS_CTRL , &MACValue);
648 RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL , MACValue);
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);
662 AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x01); // send POWER-SAVE command to MCU. Timeout unit:40us.
663 //RTMPusecDelay(200);
664 brc = AsicCheckCommanOk(pAd, PowerSafeCID);
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))
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);
675 else if (brc == TRUE)
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);
686 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
687 if ((DmaCfg.field.RxDMABusy == 0) && (DmaCfg.field.TxDMABusy == 0))
695 pAd->CheckDmaBusyCount++;
696 DBGPRINT(RT_DEBUG_TRACE, ("DMA Rx keeps busy. on RT28xxPciAsicRadioOff ()\n"));
700 pAd->CheckDmaBusyCount = 0;
703 if (Level == DOT11POWERSAVE)
705 AUTO_WAKEUP_STRUC AutoWakeupCfg;
706 //RTMPSetTimer(&pAd->Mlme.PsPollTimer, 90);
708 // we have decided to SLEEP, so at least do it for a BEACON period.
709 if (TbttNumToNextWakeUp == 0)
710 TbttNumToNextWakeUp = 1;
712 AutoWakeupCfg.word = 0;
713 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
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);
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)
725 if ((brc == TRUE) && (i < 50))
726 RTMPPCIeLinkCtrlSetting(pAd, 0);
728 // 4. Set PCI configuration Space Link Comtrol fields. Only Radio Off needs to call this function
731 if ((brc == TRUE) && (i < 50))
732 RTMPPCIeLinkCtrlSetting(pAd, 3);
735 RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
740 ==========================================================================
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.
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.
748 ==========================================================================
750 BOOLEAN RT28xxPciAsicRadioOn(
751 IN PRTMP_ADAPTER pAd,
754 WPDMA_GLO_CFG_STRUC DmaCfg;
755 BOOLEAN Cancelled, brv = TRUE;
758 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
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)))
765 DBGPRINT(RT_DEBUG_TRACE, ("RT28xxPciAsicRadioOn ()\n"));
766 // 1. Set PCI Link Control in Configuration Space.
767 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
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);
777 // 2-1. wait command ok.
778 brv = AsicCheckCommanOk(pAd, PowerWakeCID);
781 NICEnableInterrupt(pAd);
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);
790 RTMP_IO_READ32(pAd, MAC_SYS_CTRL , &MACValue);
792 RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL , MACValue);
794 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
795 if (Level == GUI_IDLE_POWER_SAVE)
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))
802 AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
803 AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
808 AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
809 AsicLockChannel(pAd, pAd->CommonCfg.Channel);
818 VOID RT28xxPciStaAsicForceWakeup(
819 IN PRTMP_ADAPTER pAd,
822 AUTO_WAKEUP_STRUC AutoWakeupCfg;
824 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
826 DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
830 OPSTATUS_SET_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
831 RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW);
833 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
835 // Support PCIe Advance Power Save
836 if (((Level == FROM_TX) && (pAd->Mlme.bPsPollTimerRunning == TRUE)) ||
837 (Level == RTMP_HALT))
839 pAd->Mlme.bPsPollTimerRunning = FALSE;
840 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
842 DBGPRINT(RT_DEBUG_TRACE, ("=======AsicForceWakeup===bFromTx\n"));
845 AutoWakeupCfg.word = 0;
846 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
848 // If this is called from Halt. ALWAYS force wakeup!!!
849 if (Level == RTMP_HALT)
851 RT28xxPciAsicRadioOn(pAd, RTMP_HALT);
855 if (RT28xxPciAsicRadioOn(pAd, DOT11POWERSAVE))
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))
862 AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
863 AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
868 AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
869 AsicLockChannel(pAd, pAd->CommonCfg.Channel);
877 AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x00);
878 AutoWakeupCfg.word = 0;
879 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
882 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
883 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
884 DBGPRINT(RT_DEBUG_TRACE, ("<=======RT28xxPciStaAsicForceWakeup\n"));
887 VOID RT28xxPciStaAsicSleepThenAutoWakeup(
888 IN PRTMP_ADAPTER pAd,
889 IN USHORT TbttNumToNextWakeUp)
891 if (pAd->StaCfg.bRadio == FALSE)
893 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
896 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
899 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
901 DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
902 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
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))
911 DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu : RxCountSinceLastNULL = %lu. \n", Now, pAd->Mlme.LastSendNULLpsmTime, pAd->RalinkCounters.RxCountSinceLastNULL));
914 else if ((pAd->RalinkCounters.RxCountSinceLastNULL > 0) && ((pAd->Mlme.LastSendNULLpsmTime + pAd->CommonCfg.BeaconPeriod) >= Now))
916 DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu: RxCountSinceLastNULL = %lu > 0 \n", Now, pAd->Mlme.LastSendNULLpsmTime, pAd->RalinkCounters.RxCountSinceLastNULL));
920 RT28xxPciAsicRadioOff(pAd, DOT11POWERSAVE, TbttNumToNextWakeUp);
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;
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));
938 OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE);
942 IN PVOID SystemSpecific1,
943 IN PVOID FunctionContext,
944 IN PVOID SystemSpecific2,
945 IN PVOID SystemSpecific3)
947 RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
950 DBGPRINT(RT_DEBUG_TRACE,("-->PsPollWakeExec \n"));
951 RTMP_INT_LOCK(&pAd->irq_lock, flags);
952 if (pAd->Mlme.bPsPollTimerRunning)
954 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
956 pAd->Mlme.bPsPollTimerRunning = FALSE;
957 RTMP_INT_UNLOCK(&pAd->irq_lock, flags);
961 IN PVOID SystemSpecific1,
962 IN PVOID FunctionContext,
963 IN PVOID SystemSpecific2,
964 IN PVOID SystemSpecific3)
966 RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
967 WPDMA_GLO_CFG_STRUC DmaCfg;
970 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
972 DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on fOP_STATUS_DOZE == TRUE; \n"));
973 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
977 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
979 DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on SCAN_IN_PROGRESS; \n"));
980 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
983 pAd->Mlme.bPsPollTimerRunning = FALSE;
984 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
985 if (pAd->StaCfg.bRadio == TRUE)
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);
996 // 2. Send wake up command.
997 AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02);
998 // 2-1. wait command ok.
999 AsicCheckCommanOk(pAd, PowerWakeCID);
1001 // When PCI clock is off, don't want to service interrupt. So when back to clock on, enable interrupt.
1002 NICEnableInterrupt(pAd);
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);
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))
1013 // Must using 40MHz.
1014 AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
1015 AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
1019 // Must using 20MHz.
1020 AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
1021 AsicLockChannel(pAd, pAd->CommonCfg.Channel);
1024 // Clear Radio off flag
1025 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1028 RTMPSetLED(pAd, LED_RADIO_ON);
1030 if (pAd->StaCfg.Psm == PWR_ACTIVE)
1032 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, pAd->StaCfg.BBPR3);
1037 RT28xxPciAsicRadioOff(pAd, GUIRADIO_OFF, 0);
1041 VOID RT28xxPciMlmeRadioOn(
1042 IN PRTMP_ADAPTER pAd)
1044 if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1047 DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
1049 if ((pAd->OpMode == OPMODE_AP) ||
1050 ((pAd->OpMode == OPMODE_STA) && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))))
1052 NICResetFromError(pAd);
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);
1065 RTMPEnableRxTx(pAd);
1067 // Clear Radio off flag
1068 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1071 RTMPSetLED(pAd, LED_RADIO_ON);
1074 if ((pAd->OpMode == OPMODE_STA) &&
1075 (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)))
1079 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
1081 pAd->Mlme.bPsPollTimerRunning = FALSE;
1082 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1083 RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
1084 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1088 VOID RT28xxPciMlmeRadioOFF(
1089 IN PRTMP_ADAPTER pAd)
1091 WPDMA_GLO_CFG_STRUC GloCfg;
1094 if (pAd->StaCfg.bRadio == TRUE)
1096 DBGPRINT(RT_DEBUG_TRACE,("-->MlmeRadioOff() return on bRadio == TRUE; \n"));
1100 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1103 DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
1106 RTMPSetLED(pAd, LED_RADIO_OFF);
1111 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
1113 RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled);
1114 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);
1117 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
1121 // Always radio on since the NIC needs to set the MCU command (LED_RADIO_OFF).
\r
1122 if ((pAd->OpMode == OPMODE_STA) &&
\r
1123 (IDLE_ON(pAd)) &&
\r
1124 (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF)))
\r
1126 RT28xxPciAsicRadioOn(pAd, GUI_IDLE_POWER_SAVE);
\r
1129 pAd->Mlme.bPsPollTimerRunning = FALSE;
1130 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1131 RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
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);
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);
1150 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
1152 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 500);
1157 // Set Radio off flag
1158 RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
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
1167 // MAC_SYS_CTRL => value = 0x0 => 40mA
1168 RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0);
1170 // PWR_PIN_CFG => value = 0x0 => 40mA
1171 RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0);
1173 // TX_PIN_CFG => value = 0x0 => 20mA
1174 RTMP_IO_WRITE32(pAd, TX_PIN_CFG, 0);
1176 if (pAd->CommonCfg.BBPCurrentBW == BW_40)
1178 // Must using 40MHz.
1179 AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel);
1183 // Must using 20MHz.
1184 AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel);
1187 // Waiting for DMA idle
1191 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
1192 if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0))
1195 RTMPusecDelay(1000);