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).
1124
if ((pAd->OpMode == OPMODE_STA) &&
1126
(RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF)))
1128
RT28xxPciAsicRadioOn(pAd, GUI_IDLE_POWER_SAVE);
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);