blob: 8e1636315a8b332edc8522a77a4c66d03bf92fb1 [file] [log] [blame]
/*
*************************************************************************
* Ralink Tech Inc.
* 5F., No.36, Taiyuan St., Jhubei City,
* Hsinchu County 302,
* Taiwan, R.O.C.
*
* (c) Copyright 2002-2007, Ralink Technology, Inc.
*
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
* *
*************************************************************************
*/
#ifdef RTMP_MAC_PCI
#include "../rt_config.h"
/*
========================================================================
Routine Description:
Allocate DMA memory blocks for send, receive
Arguments:
Adapter Pointer to our adapter
Return Value:
NDIS_STATUS_SUCCESS
NDIS_STATUS_FAILURE
NDIS_STATUS_RESOURCES
IRQL = PASSIVE_LEVEL
Note:
========================================================================
*/
NDIS_STATUS RTMPAllocTxRxRingMemory(
IN PRTMP_ADAPTER pAd)
{
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
ULONG RingBasePaHigh;
ULONG RingBasePaLow;
PVOID RingBaseVa;
INT index, num;
PTXD_STRUC pTxD;
PRXD_STRUC pRxD;
ULONG ErrorValue = 0;
PRTMP_TX_RING pTxRing;
PRTMP_DMABUF pDmaBuf;
PNDIS_PACKET pPacket;
// PRTMP_REORDERBUF pReorderBuf;
DBGPRINT(RT_DEBUG_TRACE, ("--> RTMPAllocTxRxRingMemory\n"));
do
{
//
// Allocate all ring descriptors, include TxD, RxD, MgmtD.
// Although each size is different, to prevent cacheline and alignment
// issue, I intentional set them all to 64 bytes.
//
for (num=0; num<NUM_OF_TX_RING; num++)
{
ULONG BufBasePaHigh;
ULONG BufBasePaLow;
PVOID BufBaseVa;
//
// Allocate Tx ring descriptor's memory (5 TX rings = 4 ACs + 1 HCCA)
//
pAd->TxDescRing[num].AllocSize = TX_RING_SIZE * TXD_SIZE;
RTMP_AllocateTxDescMemory(
pAd,
num,
pAd->TxDescRing[num].AllocSize,
FALSE,
&pAd->TxDescRing[num].AllocVa,
&pAd->TxDescRing[num].AllocPa);
if (pAd->TxDescRing[num].AllocVa == NULL)
{
ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
DBGPRINT_ERR(("Failed to allocate a big buffer\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
// Zero init this memory block
NdisZeroMemory(pAd->TxDescRing[num].AllocVa, pAd->TxDescRing[num].AllocSize);
// Save PA & VA for further operation
RingBasePaHigh = RTMP_GetPhysicalAddressHigh(pAd->TxDescRing[num].AllocPa);
RingBasePaLow = RTMP_GetPhysicalAddressLow (pAd->TxDescRing[num].AllocPa);
RingBaseVa = pAd->TxDescRing[num].AllocVa;
//
// Allocate all 1st TXBuf's memory for this TxRing
//
pAd->TxBufSpace[num].AllocSize = TX_RING_SIZE * TX_DMA_1ST_BUFFER_SIZE;
RTMP_AllocateFirstTxBuffer(
pAd,
num,
pAd->TxBufSpace[num].AllocSize,
FALSE,
&pAd->TxBufSpace[num].AllocVa,
&pAd->TxBufSpace[num].AllocPa);
if (pAd->TxBufSpace[num].AllocVa == NULL)
{
ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
DBGPRINT_ERR(("Failed to allocate a big buffer\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
// Zero init this memory block
NdisZeroMemory(pAd->TxBufSpace[num].AllocVa, pAd->TxBufSpace[num].AllocSize);
// Save PA & VA for further operation
BufBasePaHigh = RTMP_GetPhysicalAddressHigh(pAd->TxBufSpace[num].AllocPa);
BufBasePaLow = RTMP_GetPhysicalAddressLow (pAd->TxBufSpace[num].AllocPa);
BufBaseVa = pAd->TxBufSpace[num].AllocVa;
//
// Initialize Tx Ring Descriptor and associated buffer memory
//
pTxRing = &pAd->TxRing[num];
for (index = 0; index < TX_RING_SIZE; index++)
{
pTxRing->Cell[index].pNdisPacket = NULL;
pTxRing->Cell[index].pNextNdisPacket = NULL;
// Init Tx Ring Size, Va, Pa variables
pTxRing->Cell[index].AllocSize = TXD_SIZE;
pTxRing->Cell[index].AllocVa = RingBaseVa;
RTMP_SetPhysicalAddressHigh(pTxRing->Cell[index].AllocPa, RingBasePaHigh);
RTMP_SetPhysicalAddressLow (pTxRing->Cell[index].AllocPa, RingBasePaLow);
// Setup Tx Buffer size & address. only 802.11 header will store in this space
pDmaBuf = &pTxRing->Cell[index].DmaBuf;
pDmaBuf->AllocSize = TX_DMA_1ST_BUFFER_SIZE;
pDmaBuf->AllocVa = BufBaseVa;
RTMP_SetPhysicalAddressHigh(pDmaBuf->AllocPa, BufBasePaHigh);
RTMP_SetPhysicalAddressLow(pDmaBuf->AllocPa, BufBasePaLow);
// link the pre-allocated TxBuf to TXD
pTxD = (PTXD_STRUC) pTxRing->Cell[index].AllocVa;
pTxD->SDPtr0 = BufBasePaLow;
// advance to next ring descriptor address
pTxD->DMADONE = 1;
#ifdef RT_BIG_ENDIAN
RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD);
#endif
RingBasePaLow += TXD_SIZE;
RingBaseVa = (PUCHAR) RingBaseVa + TXD_SIZE;
// advance to next TxBuf address
BufBasePaLow += TX_DMA_1ST_BUFFER_SIZE;
BufBaseVa = (PUCHAR) BufBaseVa + TX_DMA_1ST_BUFFER_SIZE;
}
DBGPRINT(RT_DEBUG_TRACE, ("TxRing[%d]: total %d entry allocated\n", num, index));
}
if (Status == NDIS_STATUS_RESOURCES)
break;
//
// Allocate MGMT ring descriptor's memory except Tx ring which allocated eariler
//
pAd->MgmtDescRing.AllocSize = MGMT_RING_SIZE * TXD_SIZE;
RTMP_AllocateMgmtDescMemory(
pAd,
pAd->MgmtDescRing.AllocSize,
FALSE,
&pAd->MgmtDescRing.AllocVa,
&pAd->MgmtDescRing.AllocPa);
if (pAd->MgmtDescRing.AllocVa == NULL)
{
ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
DBGPRINT_ERR(("Failed to allocate a big buffer\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
// Zero init this memory block
NdisZeroMemory(pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocSize);
// Save PA & VA for further operation
RingBasePaHigh = RTMP_GetPhysicalAddressHigh(pAd->MgmtDescRing.AllocPa);
RingBasePaLow = RTMP_GetPhysicalAddressLow (pAd->MgmtDescRing.AllocPa);
RingBaseVa = pAd->MgmtDescRing.AllocVa;
//
// Initialize MGMT Ring and associated buffer memory
//
for (index = 0; index < MGMT_RING_SIZE; index++)
{
pAd->MgmtRing.Cell[index].pNdisPacket = NULL;
pAd->MgmtRing.Cell[index].pNextNdisPacket = NULL;
// Init MGMT Ring Size, Va, Pa variables
pAd->MgmtRing.Cell[index].AllocSize = TXD_SIZE;
pAd->MgmtRing.Cell[index].AllocVa = RingBaseVa;
RTMP_SetPhysicalAddressHigh(pAd->MgmtRing.Cell[index].AllocPa, RingBasePaHigh);
RTMP_SetPhysicalAddressLow (pAd->MgmtRing.Cell[index].AllocPa, RingBasePaLow);
// Offset to next ring descriptor address
RingBasePaLow += TXD_SIZE;
RingBaseVa = (PUCHAR) RingBaseVa + TXD_SIZE;
// link the pre-allocated TxBuf to TXD
pTxD = (PTXD_STRUC) pAd->MgmtRing.Cell[index].AllocVa;
pTxD->DMADONE = 1;
#ifdef RT_BIG_ENDIAN
RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD);
#endif
// no pre-allocated buffer required in MgmtRing for scatter-gather case
}
DBGPRINT(RT_DEBUG_TRACE, ("MGMT Ring: total %d entry allocated\n", index));
//
// Allocate RX ring descriptor's memory except Tx ring which allocated eariler
//
pAd->RxDescRing.AllocSize = RX_RING_SIZE * RXD_SIZE;
RTMP_AllocateRxDescMemory(
pAd,
pAd->RxDescRing.AllocSize,
FALSE,
&pAd->RxDescRing.AllocVa,
&pAd->RxDescRing.AllocPa);
if (pAd->RxDescRing.AllocVa == NULL)
{
ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
DBGPRINT_ERR(("Failed to allocate a big buffer\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
// Zero init this memory block
NdisZeroMemory(pAd->RxDescRing.AllocVa, pAd->RxDescRing.AllocSize);
DBGPRINT(RT_DEBUG_OFF,
("RX DESC %p size = %ld\n", pAd->RxDescRing.AllocVa, pAd->RxDescRing.AllocSize));
// Save PA & VA for further operation
RingBasePaHigh = RTMP_GetPhysicalAddressHigh(pAd->RxDescRing.AllocPa);
RingBasePaLow = RTMP_GetPhysicalAddressLow (pAd->RxDescRing.AllocPa);
RingBaseVa = pAd->RxDescRing.AllocVa;
//
// Initialize Rx Ring and associated buffer memory
//
for (index = 0; index < RX_RING_SIZE; index++)
{
// Init RX Ring Size, Va, Pa variables
pAd->RxRing.Cell[index].AllocSize = RXD_SIZE;
pAd->RxRing.Cell[index].AllocVa = RingBaseVa;
RTMP_SetPhysicalAddressHigh(pAd->RxRing.Cell[index].AllocPa, RingBasePaHigh);
RTMP_SetPhysicalAddressLow (pAd->RxRing.Cell[index].AllocPa, RingBasePaLow);
//NdisZeroMemory(RingBaseVa, RXD_SIZE);
// Offset to next ring descriptor address
RingBasePaLow += RXD_SIZE;
RingBaseVa = (PUCHAR) RingBaseVa + RXD_SIZE;
// Setup Rx associated Buffer size & allocate share memory
pDmaBuf = &pAd->RxRing.Cell[index].DmaBuf;
pDmaBuf->AllocSize = RX_BUFFER_AGGRESIZE;
pPacket = RTMP_AllocateRxPacketBuffer(
pAd,
pDmaBuf->AllocSize,
FALSE,
&pDmaBuf->AllocVa,
&pDmaBuf->AllocPa);
/* keep allocated rx packet */
pAd->RxRing.Cell[index].pNdisPacket = pPacket;
// Error handling
if (pDmaBuf->AllocVa == NULL)
{
ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
DBGPRINT_ERR(("Failed to allocate RxRing's 1st buffer\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
// Zero init this memory block
NdisZeroMemory(pDmaBuf->AllocVa, pDmaBuf->AllocSize);
// Write RxD buffer address & allocated buffer length
pRxD = (PRXD_STRUC) pAd->RxRing.Cell[index].AllocVa;
pRxD->SDP0 = RTMP_GetPhysicalAddressLow(pDmaBuf->AllocPa);
pRxD->DDONE = 0;
#ifdef RT_BIG_ENDIAN
RTMPDescriptorEndianChange((PUCHAR)pRxD, TYPE_RXD);
#endif
}
DBGPRINT(RT_DEBUG_TRACE, ("Rx Ring: total %d entry allocated\n", index));
} while (FALSE);
NdisZeroMemory(&pAd->FragFrame, sizeof(FRAGMENT_FRAME));
pAd->FragFrame.pFragPacket = RTMP_AllocateFragPacketBuffer(pAd, RX_BUFFER_NORMSIZE);
if (pAd->FragFrame.pFragPacket == NULL)
{
Status = NDIS_STATUS_RESOURCES;
}
if (Status != NDIS_STATUS_SUCCESS)
{
// Log error inforamtion
NdisWriteErrorLogEntry(
pAd->AdapterHandle,
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
1,
ErrorValue);
}
// Following code segment get from original func:NICInitTxRxRingAndBacklogQueue(), now should integrate it to here.
{
DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitTxRxRingAndBacklogQueue\n"));
/*
// Disable DMA.
RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
GloCfg.word &= 0xff0;
GloCfg.field.EnTXWriteBackDDONE =1;
RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word);
*/
// Initialize all transmit related software queues
for(index = 0; index < NUM_OF_TX_RING; index++)
{
InitializeQueueHeader(&pAd->TxSwQueue[index]);
// Init TX rings index pointer
pAd->TxRing[index].TxSwFreeIdx = 0;
pAd->TxRing[index].TxCpuIdx = 0;
//RTMP_IO_WRITE32(pAd, (TX_CTX_IDX0 + i * 0x10) , pAd->TxRing[i].TX_CTX_IDX);
}
// Init RX Ring index pointer
pAd->RxRing.RxSwReadIdx = 0;
pAd->RxRing.RxCpuIdx = RX_RING_SIZE - 1;
//RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RX_CRX_IDX0);
// init MGMT ring index pointer
pAd->MgmtRing.TxSwFreeIdx = 0;
pAd->MgmtRing.TxCpuIdx = 0;
pAd->PrivateInfo.TxRingFullCnt = 0;
DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitTxRxRingAndBacklogQueue\n"));
}
DBGPRINT_S(Status, ("<-- RTMPAllocTxRxRingMemory, Status=%x\n", Status));
return Status;
}
/*
========================================================================
Routine Description:
Reset NIC Asics. Call after rest DMA. So reset TX_CTX_IDX to zero.
Arguments:
Adapter Pointer to our adapter
Return Value:
None
IRQL = PASSIVE_LEVEL
IRQL = DISPATCH_LEVEL
Note:
Reset NIC to initial state AS IS system boot up time.
========================================================================
*/
VOID RTMPRingCleanUp(
IN PRTMP_ADAPTER pAd,
IN UCHAR RingType)
{
PTXD_STRUC pTxD;
PRXD_STRUC pRxD;
PQUEUE_ENTRY pEntry;
PNDIS_PACKET pPacket;
int i;
PRTMP_TX_RING pTxRing;
unsigned long IrqFlags;
//UINT32 RxSwReadIdx;
DBGPRINT(RT_DEBUG_TRACE,("RTMPRingCleanUp(RingIdx=%d, Pending-NDIS=%ld)\n", RingType, pAd->RalinkCounters.PendingNdisPacketCount));
switch (RingType)
{
case QID_AC_BK:
case QID_AC_BE:
case QID_AC_VI:
case QID_AC_VO:
/*case QID_HCCA:*/
pTxRing = &pAd->TxRing[RingType];
RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags);
// We have to clean all descriptors in case some error happened with reset
for (i=0; i<TX_RING_SIZE; i++) // We have to scan all TX ring
{
pTxD = (PTXD_STRUC) pTxRing->Cell[i].AllocVa;
pPacket = (PNDIS_PACKET) pTxRing->Cell[i].pNdisPacket;
// release scatter-and-gather NDIS_PACKET
if (pPacket)
{
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
pTxRing->Cell[i].pNdisPacket = NULL;
}
pPacket = (PNDIS_PACKET) pTxRing->Cell[i].pNextNdisPacket;
// release scatter-and-gather NDIS_PACKET
if (pPacket)
{
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
pTxRing->Cell[i].pNextNdisPacket = NULL;
}
}
RTMP_IO_READ32(pAd, TX_DTX_IDX0 + RingType * 0x10, &pTxRing->TxDmaIdx);
pTxRing->TxSwFreeIdx = pTxRing->TxDmaIdx;
pTxRing->TxCpuIdx = pTxRing->TxDmaIdx;
RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + RingType * 0x10, pTxRing->TxCpuIdx);
RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags);
while (pAd->TxSwQueue[RingType].Head != NULL)
{
pEntry = RemoveHeadQueue(&pAd->TxSwQueue[RingType]);
pPacket = QUEUE_ENTRY_TO_PACKET(pEntry);
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
DBGPRINT(RT_DEBUG_TRACE,("Release 1 NDIS packet from s/w backlog queue\n"));
}
RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
break;
case QID_MGMT:
// We have to clean all descriptors in case some error happened with reset
NdisAcquireSpinLock(&pAd->MgmtRingLock);
for (i=0; i<MGMT_RING_SIZE; i++)
{
pTxD = (PTXD_STRUC) pAd->MgmtRing.Cell[i].AllocVa;
pPacket = (PNDIS_PACKET) pAd->MgmtRing.Cell[i].pNdisPacket;
// rlease scatter-and-gather NDIS_PACKET
if (pPacket)
{
PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE);
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
}
pAd->MgmtRing.Cell[i].pNdisPacket = NULL;
pPacket = (PNDIS_PACKET) pAd->MgmtRing.Cell[i].pNextNdisPacket;
// release scatter-and-gather NDIS_PACKET
if (pPacket)
{
PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE);
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
}
pAd->MgmtRing.Cell[i].pNextNdisPacket = NULL;
}
RTMP_IO_READ32(pAd, TX_MGMTDTX_IDX, &pAd->MgmtRing.TxDmaIdx);
pAd->MgmtRing.TxSwFreeIdx = pAd->MgmtRing.TxDmaIdx;
pAd->MgmtRing.TxCpuIdx = pAd->MgmtRing.TxDmaIdx;
RTMP_IO_WRITE32(pAd, TX_MGMTCTX_IDX, pAd->MgmtRing.TxCpuIdx);
NdisReleaseSpinLock(&pAd->MgmtRingLock);
pAd->RalinkCounters.MgmtRingFullCount = 0;
break;
case QID_RX:
// We have to clean all descriptors in case some error happened with reset
NdisAcquireSpinLock(&pAd->RxRingLock);
for (i=0; i<RX_RING_SIZE; i++)
{
pRxD = (PRXD_STRUC) pAd->RxRing.Cell[i].AllocVa;
pRxD->DDONE = 0 ;
}
RTMP_IO_READ32(pAd, RX_DRX_IDX, &pAd->RxRing.RxDmaIdx);
pAd->RxRing.RxSwReadIdx = pAd->RxRing.RxDmaIdx;
pAd->RxRing.RxCpuIdx = ((pAd->RxRing.RxDmaIdx == 0) ? (RX_RING_SIZE-1) : (pAd->RxRing.RxDmaIdx-1));
RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx);
NdisReleaseSpinLock(&pAd->RxRingLock);
break;
default:
break;
}
}
VOID RTMPFreeTxRxRingMemory(
IN PRTMP_ADAPTER pAd)
{
int index, num , j;
PRTMP_TX_RING pTxRing;
PTXD_STRUC pTxD;
PNDIS_PACKET pPacket;
unsigned int IrqFlags;
//POS_COOKIE pObj =(POS_COOKIE) pAd->OS_Cookie;
DBGPRINT(RT_DEBUG_TRACE, ("--> RTMPFreeTxRxRingMemory\n"));
// Free TxSwQueue Packet
for (index=0; index <NUM_OF_TX_RING; index++)
{
PQUEUE_ENTRY pEntry;
PNDIS_PACKET pPacket;
PQUEUE_HEADER pQueue;
RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags);
pQueue = &pAd->TxSwQueue[index];
while (pQueue->Head)
{
pEntry = RemoveHeadQueue(pQueue);
pPacket = QUEUE_ENTRY_TO_PACKET(pEntry);
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
}
RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
}
// Free Tx Ring Packet
for (index=0;index< NUM_OF_TX_RING;index++)
{
pTxRing = &pAd->TxRing[index];
for (j=0; j< TX_RING_SIZE; j++)
{
pTxD = (PTXD_STRUC) (pTxRing->Cell[j].AllocVa);
pPacket = pTxRing->Cell[j].pNdisPacket;
if (pPacket)
{
PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE);
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS);
}
//Always assign pNdisPacket as NULL after clear
pTxRing->Cell[j].pNdisPacket = NULL;
pPacket = pTxRing->Cell[j].pNextNdisPacket;
if (pPacket)
{
PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE);
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS);
}
//Always assign pNextNdisPacket as NULL after clear
pTxRing->Cell[pTxRing->TxSwFreeIdx].pNextNdisPacket = NULL;
}
}
for (index = RX_RING_SIZE - 1 ; index >= 0; index--)
{
if ((pAd->RxRing.Cell[index].DmaBuf.AllocVa) && (pAd->RxRing.Cell[index].pNdisPacket))
{
PCI_UNMAP_SINGLE(pAd, pAd->RxRing.Cell[index].DmaBuf.AllocPa, pAd->RxRing.Cell[index].DmaBuf.AllocSize, PCI_DMA_FROMDEVICE);
RELEASE_NDIS_PACKET(pAd, pAd->RxRing.Cell[index].pNdisPacket, NDIS_STATUS_SUCCESS);
}
}
NdisZeroMemory(pAd->RxRing.Cell, RX_RING_SIZE * sizeof(RTMP_DMACB));
if (pAd->RxDescRing.AllocVa)
{
RTMP_FreeDescMemory(pAd, pAd->RxDescRing.AllocSize, pAd->RxDescRing.AllocVa, pAd->RxDescRing.AllocPa);
}
NdisZeroMemory(&pAd->RxDescRing, sizeof(RTMP_DMABUF));
if (pAd->MgmtDescRing.AllocVa)
{
RTMP_FreeDescMemory(pAd, pAd->MgmtDescRing.AllocSize, pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocPa);
}
NdisZeroMemory(&pAd->MgmtDescRing, sizeof(RTMP_DMABUF));
for (num = 0; num < NUM_OF_TX_RING; num++)
{
if (pAd->TxBufSpace[num].AllocVa)
{
RTMP_FreeFirstTxBuffer(pAd, pAd->TxBufSpace[num].AllocSize, FALSE, pAd->TxBufSpace[num].AllocVa, pAd->TxBufSpace[num].AllocPa);
}
NdisZeroMemory(&pAd->TxBufSpace[num], sizeof(RTMP_DMABUF));
if (pAd->TxDescRing[num].AllocVa)
{
RTMP_FreeDescMemory(pAd, pAd->TxDescRing[num].AllocSize, pAd->TxDescRing[num].AllocVa, pAd->TxDescRing[num].AllocPa);
}
NdisZeroMemory(&pAd->TxDescRing[num], sizeof(RTMP_DMABUF));
}
if (pAd->FragFrame.pFragPacket)
RELEASE_NDIS_PACKET(pAd, pAd->FragFrame.pFragPacket, NDIS_STATUS_SUCCESS);
DBGPRINT(RT_DEBUG_TRACE, ("<-- RTMPFreeTxRxRingMemory\n"));
}
/***************************************************************************
*
* register related procedures.
*
**************************************************************************/
/*
========================================================================
Routine Description:
Disable DMA.
Arguments:
*pAd the raxx interface data pointer
Return Value:
None
Note:
========================================================================
*/
VOID RT28XXDMADisable(
IN RTMP_ADAPTER *pAd)
{
WPDMA_GLO_CFG_STRUC GloCfg;
RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
GloCfg.word &= 0xff0;
GloCfg.field.EnTXWriteBackDDONE =1;
RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word);
}
/*
========================================================================
Routine Description:
Enable DMA.
Arguments:
*pAd the raxx interface data pointer
Return Value:
None
Note:
========================================================================
*/
VOID RT28XXDMAEnable(
IN RTMP_ADAPTER *pAd)
{
WPDMA_GLO_CFG_STRUC GloCfg;
int i = 0;
RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x4);
do
{
RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0))
break;
DBGPRINT(RT_DEBUG_TRACE, ("==> DMABusy\n"));
RTMPusecDelay(1000);
i++;
}while ( i <200);
RTMPusecDelay(50);
GloCfg.field.EnTXWriteBackDDONE = 1;
GloCfg.field.WPDMABurstSIZE = 2;
GloCfg.field.EnableRxDMA = 1;
GloCfg.field.EnableTxDMA = 1;
DBGPRINT(RT_DEBUG_TRACE, ("<== WRITE DMA offset 0x208 = 0x%x\n", GloCfg.word));
RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word);
}
BOOLEAN AsicCheckCommanOk(
IN PRTMP_ADAPTER pAd,
IN UCHAR Command)
{
UINT32 CmdStatus = 0, CID = 0, i;
UINT32 ThisCIDMask = 0;
i = 0;
do
{
RTMP_IO_READ32(pAd, H2M_MAILBOX_CID, &CID);
// Find where the command is. Because this is randomly specified by firmware.
if ((CID & CID0MASK) == Command)
{
ThisCIDMask = CID0MASK;
break;
}
else if ((((CID & CID1MASK)>>8) & 0xff) == Command)
{
ThisCIDMask = CID1MASK;
break;
}
else if ((((CID & CID2MASK)>>16) & 0xff) == Command)
{
ThisCIDMask = CID2MASK;
break;
}
else if ((((CID & CID3MASK)>>24) & 0xff) == Command)
{
ThisCIDMask = CID3MASK;
break;
}
RTMPusecDelay(100);
i++;
}while (i < 200);
// Get CommandStatus Value
RTMP_IO_READ32(pAd, H2M_MAILBOX_STATUS, &CmdStatus);
// This command's status is at the same position as command. So AND command position's bitmask to read status.
if (i < 200)
{
// If Status is 1, the comamnd is success.
if (((CmdStatus & ThisCIDMask) == 0x1) || ((CmdStatus & ThisCIDMask) == 0x100)
|| ((CmdStatus & ThisCIDMask) == 0x10000) || ((CmdStatus & ThisCIDMask) == 0x1000000))
{
DBGPRINT(RT_DEBUG_TRACE, ("--> AsicCheckCommanOk CID = 0x%x, CmdStatus= 0x%x \n", CID, CmdStatus));
RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff);
RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff);
return TRUE;
}
DBGPRINT(RT_DEBUG_TRACE, ("--> AsicCheckCommanFail1 CID = 0x%x, CmdStatus= 0x%x \n", CID, CmdStatus));
}
else
{
DBGPRINT(RT_DEBUG_TRACE, ("--> AsicCheckCommanFail2 Timeout Command = %d, CmdStatus= 0x%x \n", Command, CmdStatus));
}
// Clear Command and Status.
RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff);
RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff);
return FALSE;
}
/*
========================================================================
Routine Description:
Write Beacon buffer to Asic.
Arguments:
*pAd the raxx interface data pointer
Return Value:
None
Note:
========================================================================
*/
VOID RT28xx_UpdateBeaconToAsic(
IN RTMP_ADAPTER *pAd,
IN INT apidx,
IN ULONG FrameLen,
IN ULONG UpdatePos)
{
ULONG CapInfoPos = 0;
UCHAR *ptr, *ptr_update, *ptr_capinfo;
UINT i;
BOOLEAN bBcnReq = FALSE;
UCHAR bcn_idx = 0;
{
DBGPRINT(RT_DEBUG_ERROR, ("%s() : No valid Interface be found.\n", __FUNCTION__));
return;
}
//if ((pAd->WdsTab.Mode == WDS_BRIDGE_MODE)
// || ((pAd->ApCfg.MBSSID[apidx].MSSIDDev == NULL)
// || !(pAd->ApCfg.MBSSID[apidx].MSSIDDev->flags & IFF_UP))
// )
if (bBcnReq == FALSE)
{
/* when the ra interface is down, do not send its beacon frame */
/* clear all zero */
for(i=0; i<TXWI_SIZE; i+=4)
RTMP_IO_WRITE32(pAd, pAd->BeaconOffset[bcn_idx] + i, 0x00);
}
else
{
ptr = (PUCHAR)&pAd->BeaconTxWI;
#ifdef RT_BIG_ENDIAN
RTMPWIEndianChange(ptr, TYPE_TXWI);
#endif
for (i=0; i<TXWI_SIZE; i+=4) // 16-byte TXWI field
{
UINT32 longptr = *ptr + (*(ptr+1)<<8) + (*(ptr+2)<<16) + (*(ptr+3)<<24);
RTMP_IO_WRITE32(pAd, pAd->BeaconOffset[bcn_idx] + i, longptr);
ptr += 4;
}
// Update CapabilityInfo in Beacon
for (i = CapInfoPos; i < (CapInfoPos+2); i++)
{
RTMP_IO_WRITE8(pAd, pAd->BeaconOffset[bcn_idx] + TXWI_SIZE + i, *ptr_capinfo);
ptr_capinfo ++;
}
if (FrameLen > UpdatePos)
{
for (i= UpdatePos; i< (FrameLen); i++)
{
RTMP_IO_WRITE8(pAd, pAd->BeaconOffset[bcn_idx] + TXWI_SIZE + i, *ptr_update);
ptr_update ++;
}
}
}
}
#ifdef CONFIG_STA_SUPPORT
VOID RT28xxPciStaAsicForceWakeup(
IN PRTMP_ADAPTER pAd,
IN BOOLEAN bFromTx)
{
AUTO_WAKEUP_STRUC AutoWakeupCfg;
if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
return;
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
{
DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
return;
}
OPSTATUS_SET_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW);
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
&&pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)
{
// Support PCIe Advance Power Save
if (bFromTx == TRUE
&&(pAd->Mlme.bPsPollTimerRunning == TRUE))
{
pAd->Mlme.bPsPollTimerRunning = FALSE;
RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
RTMPusecDelay(3000);
DBGPRINT(RT_DEBUG_TRACE, ("=======AsicForceWakeup===bFromTx\n"));
}
AutoWakeupCfg.word = 0;
RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
if (RT28xxPciAsicRadioOn(pAd, DOT11POWERSAVE))
{
#ifdef PCIE_PS_SUPPORT
// add by johnli, RF power sequence setup, load RF normal operation-mode setup
if ((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) && IS_VERSION_AFTER_F(pAd))
{
RTMP_CHIP_OP *pChipOps = &pAd->chipOps;
if (pChipOps->AsicReverseRfFromSleepMode)
pChipOps->AsicReverseRfFromSleepMode(pAd);
}
else
#endif // PCIE_PS_SUPPORT //
{
// end johnli
// In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
&& (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
{
// Must using 40MHz.
AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
}
else
{
// Must using 20MHz.
AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
AsicLockChannel(pAd, pAd->CommonCfg.Channel);
}
}
}
#ifdef PCIE_PS_SUPPORT
// 3090 MCU Wakeup command needs more time to be stable.
// Before stable, don't issue other MCU command to prevent from firmware error.
if (((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) && IS_VERSION_AFTER_F(pAd)) && IS_VERSION_AFTER_F(pAd)
&& (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3)
&& (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE))
{
DBGPRINT(RT_DEBUG_TRACE, ("<==RT28xxPciStaAsicForceWakeup::Release the MCU Lock(3090)\n"));
RTMP_SEM_LOCK(&pAd->McuCmdLock);
pAd->brt30xxBanMcuCmd = FALSE;
RTMP_SEM_UNLOCK(&pAd->McuCmdLock);
}
#endif // PCIE_PS_SUPPORT //
}
else
{
// PCI, 2860-PCIe
DBGPRINT(RT_DEBUG_TRACE, ("<==RT28xxPciStaAsicForceWakeup::Original PCI Power Saving\n"));
AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x02);
AutoWakeupCfg.word = 0;
RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
}
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
DBGPRINT(RT_DEBUG_TRACE, ("<=======RT28xxPciStaAsicForceWakeup\n"));
}
VOID RT28xxPciStaAsicSleepThenAutoWakeup(
IN PRTMP_ADAPTER pAd,
IN USHORT TbttNumToNextWakeUp)
{
BOOLEAN brc;
if (pAd->StaCfg.bRadio == FALSE)
{
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
return;
}
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
&&pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)
{
ULONG Now = 0;
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
{
DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
return;
}
NdisGetSystemUpTime(&Now);
// If last send NULL fram time is too close to this receiving beacon (within 8ms), don't go to sleep for this DTM.
// Because Some AP can't queuing outgoing frames immediately.
if (((pAd->Mlme.LastSendNULLpsmTime + 8) >= Now) && (pAd->Mlme.LastSendNULLpsmTime <= Now))
{
DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu : RxCountSinceLastNULL = %lu. \n", Now, pAd->Mlme.LastSendNULLpsmTime, pAd->RalinkCounters.RxCountSinceLastNULL));
return;
}
else if ((pAd->RalinkCounters.RxCountSinceLastNULL > 0) && ((pAd->Mlme.LastSendNULLpsmTime + pAd->CommonCfg.BeaconPeriod) >= Now))
{
DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu: RxCountSinceLastNULL = %lu > 0 \n", Now, pAd->Mlme.LastSendNULLpsmTime, pAd->RalinkCounters.RxCountSinceLastNULL));
return;
}
brc = RT28xxPciAsicRadioOff(pAd, DOT11POWERSAVE, TbttNumToNextWakeUp);
if (brc==TRUE)
OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE);
}
else
{
AUTO_WAKEUP_STRUC AutoWakeupCfg;
// we have decided to SLEEP, so at least do it for a BEACON period.
if (TbttNumToNextWakeUp == 0)
TbttNumToNextWakeUp = 1;
//RTMP_IO_WRITE32(pAd, INT_MASK_CSR, AutoWakeupInt);
AutoWakeupCfg.word = 0;
RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1;
AutoWakeupCfg.field.EnableAutoWakeup = 1;
AutoWakeupCfg.field.AutoLeadTime = 5;
RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x00); // send POWER-SAVE command to MCU. Timeout 40us.
OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE);
DBGPRINT(RT_DEBUG_TRACE, ("<-- %s, TbttNumToNextWakeUp=%d \n", __FUNCTION__, TbttNumToNextWakeUp));
}
}
VOID PsPollWakeExec(
IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3)
{
RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
unsigned long flags;
DBGPRINT(RT_DEBUG_TRACE,("-->PsPollWakeExec \n"));
RTMP_INT_LOCK(&pAd->irq_lock, flags);
if (pAd->Mlme.bPsPollTimerRunning)
{
RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
}
pAd->Mlme.bPsPollTimerRunning = FALSE;
RTMP_INT_UNLOCK(&pAd->irq_lock, flags);
#ifdef PCIE_PS_SUPPORT
// For rt30xx power solution 3, Use software timer to wake up in psm. So call
// AsicForceWakeup here instead of handling twakeup interrupt.
if (((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) && IS_VERSION_AFTER_F(pAd))
&& (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3)
&& (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE))
{
DBGPRINT(RT_DEBUG_TRACE,("<--PsPollWakeExec::3090 calls AsicForceWakeup(pAd, DOT11POWERSAVE) in advance \n"));
AsicForceWakeup(pAd, DOT11POWERSAVE);
}
#endif // PCIE_PS_SUPPORT //
}
VOID RadioOnExec(
IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3)
{
RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
RTMP_CHIP_OP *pChipOps = &pAd->chipOps;
WPDMA_GLO_CFG_STRUC DmaCfg;
BOOLEAN Cancelled;
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
{
DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on fOP_STATUS_DOZE == TRUE; \n"));
//KH Debug: Add the compile flag "RT2860 and condition
#ifdef RTMP_PCI_SUPPORT
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
&&pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)
RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
#endif // RTMP_PCI_SUPPORT //
return;
}
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
{
DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on SCAN_IN_PROGRESS; \n"));
#ifdef RTMP_PCI_SUPPORT
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
&&pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)
RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
#endif // RTMP_PCI_SUPPORT //
return;
}
//KH Debug: need to check. I add the compile flag "CONFIG_STA_SUPPORT" to enclose the following codes.
#ifdef RTMP_PCI_SUPPORT
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
&&pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)
{
pAd->Mlme.bPsPollTimerRunning = FALSE;
RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
}
#endif // RTMP_PCI_SUPPORT //
if (pAd->StaCfg.bRadio == TRUE)
{
pAd->bPCIclkOff = FALSE;
RTMPRingCleanUp(pAd, QID_AC_BK);
RTMPRingCleanUp(pAd, QID_AC_BE);
RTMPRingCleanUp(pAd, QID_AC_VI);
RTMPRingCleanUp(pAd, QID_AC_VO);
/*RTMPRingCleanUp(pAd, QID_HCCA);*/
RTMPRingCleanUp(pAd, QID_MGMT);
RTMPRingCleanUp(pAd, QID_RX);
// 2. Send wake up command.
AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02);
// 2-1. wait command ok.
AsicCheckCommanOk(pAd, PowerWakeCID);
// When PCI clock is off, don't want to service interrupt. So when back to clock on, enable interrupt.
//RTMP_IO_WRITE32(pAd, INT_MASK_CSR, (DELAYINTMASK|RxINT));
RTMP_ASIC_INTERRUPT_ENABLE(pAd);
// 3. Enable Tx DMA.
RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
DmaCfg.field.EnableTxDMA = 1;
RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
// In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
&& (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
{
// Must using 40MHz.
AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
}
else
{
// Must using 20MHz.
AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
AsicLockChannel(pAd, pAd->CommonCfg.Channel);
}
//KH Debug:The following codes should be enclosed by RT3090 compile flag
if (pChipOps->AsicReverseRfFromSleepMode)
pChipOps->AsicReverseRfFromSleepMode(pAd);
#ifdef PCIE_PS_SUPPORT
#ifdef CONFIG_STA_SUPPORT
// 3090 MCU Wakeup command needs more time to be stable.
// Before stable, don't issue other MCU command to prevent from firmware error.
if ((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) && IS_VERSION_AFTER_F(pAd)
&& (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3)
&& (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE))
{
RTMP_SEM_LOCK(&pAd->McuCmdLock);
pAd->brt30xxBanMcuCmd = FALSE;
RTMP_SEM_UNLOCK(&pAd->McuCmdLock);
}
#endif // CONFIG_STA_SUPPORT //
#endif // PCIE_PS_SUPPORT //
// Clear Radio off flag
RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
// Set LED
RTMPSetLED(pAd, LED_RADIO_ON);
if (pAd->StaCfg.Psm == PWR_ACTIVE)
{
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, pAd->StaCfg.BBPR3);
}
}
else
{
RT28xxPciAsicRadioOff(pAd, GUIRADIO_OFF, 0);
}
}
#endif // CONFIG_STA_SUPPORT //
/*
==========================================================================
Description:
This routine sends command to firmware and turn our chip to wake up mode from power save mode.
Both RadioOn and .11 power save function needs to call this routine.
Input:
Level = GUIRADIO_OFF : call this function is from Radio Off to Radio On. Need to restore PCI host value.
Level = other value : normal wake up function.
==========================================================================
*/
BOOLEAN RT28xxPciAsicRadioOn(
IN PRTMP_ADAPTER pAd,
IN UCHAR Level)
{
//WPDMA_GLO_CFG_STRUC DmaCfg;
#ifdef CONFIG_STA_SUPPORT
BOOLEAN Cancelled;
#endif // CONFIG_STA_SUPPORT //
//UINT32 MACValue;
if (pAd->OpMode == OPMODE_AP && Level==DOT11POWERSAVE)
return FALSE;
#ifdef CONFIG_STA_SUPPORT
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE))
{
if (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)
{
pAd->Mlme.bPsPollTimerRunning = FALSE;
RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
}
if ((pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)&&
((Level == GUIRADIO_OFF) || (Level == GUI_IDLE_POWER_SAVE))
||(RTMP_TEST_PSFLAG(pAd, fRTMP_PS_SET_PCI_CLK_OFF_COMMAND)))
{
// Some chips don't need to delay 6ms, so copy RTMPPCIePowerLinkCtrlRestore
// return condition here.
/*
if (((pAd->MACVersion&0xffff0000) != 0x28600000)
&& ((pAd->DeviceID == NIC2860_PCIe_DEVICE_ID)
||(pAd->DeviceID == NIC2790_PCIe_DEVICE_ID)))
*/
{
DBGPRINT(RT_DEBUG_TRACE, ("RT28xxPciAsicRadioOn ()\n"));
// 1. Set PCI Link Control in Configuration Space.
RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
RTMPusecDelay(6000);
}
}
}
#ifdef PCIE_PS_SUPPORT
if (!(((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) && IS_VERSION_AFTER_F(pAd)
&& (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3)
&& (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE))))
#endif // PCIE_PS_SUPPORT //
{
pAd->bPCIclkOff = FALSE;
DBGPRINT(RT_DEBUG_TRACE, ("PSM :309xbPCIclkOff == %d\n", pAd->bPCIclkOff));
}
#endif // CONFIG_STA_SUPPORT //
// 2. Send wake up command.
AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02);
pAd->bPCIclkOff = FALSE;
// 2-1. wait command ok.
AsicCheckCommanOk(pAd, PowerWakeCID);
RTMP_ASIC_INTERRUPT_ENABLE(pAd);
RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
if (Level == GUI_IDLE_POWER_SAVE)
{
#ifdef PCIE_PS_SUPPORT
// add by johnli, RF power sequence setup, load RF normal operation-mode setup
if ((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)))
{
RTMP_CHIP_OP *pChipOps = &pAd->chipOps;
if (pChipOps->AsicReverseRfFromSleepMode)
pChipOps->AsicReverseRfFromSleepMode(pAd);
#ifdef CONFIG_STA_SUPPORT
// 3090 MCU Wakeup command needs more time to be stable.
// Before stable, don't issue other MCU command to prevent from firmware error.
if ((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) && IS_VERSION_AFTER_F(pAd)
&& (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3)
&& (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE))
{
RTMP_SEM_LOCK(&pAd->McuCmdLock);
pAd->brt30xxBanMcuCmd = FALSE;
RTMP_SEM_UNLOCK(&pAd->McuCmdLock);
}
#endif // CONFIG_STA_SUPPORT //
}
else
// end johnli
#endif // PCIE_PS_SUPPORT //
{
// In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
&& (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
{
// Must using 40MHz.
AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
}
else
{
// Must using 20MHz.
AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
AsicLockChannel(pAd, pAd->CommonCfg.Channel);
}
}
#endif // CONFIG_STA_SUPPORT //
}
}
return TRUE;
}
/*
==========================================================================
Description:
This routine sends command to firmware and turn our chip to power save mode.
Both RadioOff and .11 power save function needs to call this routine.
Input:
Level = GUIRADIO_OFF : GUI Radio Off mode
Level = DOT11POWERSAVE : 802.11 power save mode
Level = RTMP_HALT : When Disable device.
==========================================================================
*/
BOOLEAN RT28xxPciAsicRadioOff(
IN PRTMP_ADAPTER pAd,
IN UCHAR Level,
IN USHORT TbttNumToNextWakeUp)
{
#ifdef CONFIG_STA_SUPPORT
WPDMA_GLO_CFG_STRUC DmaCfg;
UCHAR i, tempBBP_R3 = 0;
#endif // CONFIG_STA_SUPPORT //
BOOLEAN brc = FALSE, Cancelled;
UINT32 TbTTTime = 0;
UINT32 PsPollTime = 0/*, MACValue*/;
ULONG BeaconPeriodTime;
UINT32 RxDmaIdx, RxCpuIdx;
DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> Lv= %d, TxCpuIdx = %d, TxDmaIdx = %d. RxCpuIdx = %d, RxDmaIdx = %d.\n", Level,pAd->TxRing[0].TxCpuIdx, pAd->TxRing[0].TxDmaIdx, pAd->RxRing.RxCpuIdx, pAd->RxRing.RxDmaIdx));
if (pAd->OpMode == OPMODE_AP && Level==DOT11POWERSAVE)
return FALSE;
// Check Rx DMA busy status, if more than half is occupied, give up this radio off.
RTMP_IO_READ32(pAd, RX_DRX_IDX , &RxDmaIdx);
RTMP_IO_READ32(pAd, RX_CRX_IDX , &RxCpuIdx);
if ((RxDmaIdx > RxCpuIdx) && ((RxDmaIdx - RxCpuIdx) > RX_RING_SIZE/3))
{
DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return1. RxDmaIdx = %d , RxCpuIdx = %d. \n", RxDmaIdx, RxCpuIdx));
return FALSE;
}
else if ((RxCpuIdx >= RxDmaIdx) && ((RxCpuIdx - RxDmaIdx) < RX_RING_SIZE/3))
{
DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return2. RxCpuIdx = %d. RxDmaIdx = %d , \n", RxCpuIdx, RxDmaIdx));
return FALSE;
}
// Once go into this function, disable tx because don't want too many packets in queue to prevent HW stops.
//pAd->bPCIclkOffDisableTx = TRUE;
RTMP_SET_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
&& pAd->OpMode == OPMODE_STA
#ifdef CONFIG_STA_SUPPORT
&&pAd->StaCfg.PSControl.field.EnableNewPS == TRUE
#endif // CONFIG_STA_SUPPORT //
)
{
RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
if (Level == DOT11POWERSAVE)
{
RTMP_IO_READ32(pAd, TBTT_TIMER, &TbTTTime);
TbTTTime &= 0x1ffff;
// 00. check if need to do sleep in this DTIM period. If next beacon will arrive within 30ms , ...doesn't necessarily sleep.
// TbTTTime uint = 64us, LEAD_TIME unit = 1024us, PsPollTime unit = 1ms
if (((64*TbTTTime) <((LEAD_TIME*1024) + 40000)) && (TbttNumToNextWakeUp == 0))
{
DBGPRINT(RT_DEBUG_TRACE, ("TbTTTime = 0x%x , give up this sleep. \n", TbTTTime));
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
//pAd->bPCIclkOffDisableTx = FALSE;
RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
return FALSE;
}
else
{
PsPollTime = (64*TbTTTime- LEAD_TIME*1024)/1000;
#ifdef PCIE_PS_SUPPORT
#ifdef CONFIG_STA_SUPPORT
if ((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) && IS_VERSION_AFTER_F(pAd)
&& (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3)
&& (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE))
{
PsPollTime -= 5;
}
else
#endif // CONFIG_STA_SUPPORT //
#endif // PCIE_PS_SUPPORT //
PsPollTime -= 3;
BeaconPeriodTime = pAd->CommonCfg.BeaconPeriod*102/100;
if (TbttNumToNextWakeUp > 0)
PsPollTime += ((TbttNumToNextWakeUp -1) * BeaconPeriodTime);
pAd->Mlme.bPsPollTimerRunning = TRUE;
RTMPSetTimer(&pAd->Mlme.PsPollTimer, PsPollTime);
}
}
}
else
{
DBGPRINT(RT_DEBUG_TRACE, ("RT28xxPciAsicRadioOff::Level!=DOT11POWERSAVE \n"));
}
pAd->bPCIclkOffDisableTx = FALSE;
RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
#ifdef CONFIG_STA_SUPPORT
// Set to 1R.
if (pAd->Antenna.field.RxPath > 1 && pAd->OpMode == OPMODE_STA)
{
tempBBP_R3 = (pAd->StaCfg.BBPR3 & 0xE7);
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, tempBBP_R3);
}
#endif // CONFIG_STA_SUPPORT //
// In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
if ((INFRA_ON(pAd) || pAd->OpMode == OPMODE_AP) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
&& (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
{
// Must using 40MHz.
AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel);
}
else
{
// Must using 20MHz.
AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel);
}
if (Level != RTMP_HALT)
{
// Change Interrupt bitmask.
// When PCI clock is off, don't want to service interrupt.
RTMP_IO_WRITE32(pAd, INT_MASK_CSR, AutoWakeupInt);
}
else
{
RTMP_ASIC_INTERRUPT_DISABLE(pAd);
}
RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx);
// 2. Send Sleep command
RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff);
RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff);
// send POWER-SAVE command to MCU. high-byte = 1 save power as much as possible. high byte = 0 save less power
AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x1);
// 2-1. Wait command success
// Status = 1 : success, Status = 2, already sleep, Status = 3, Maybe MAC is busy so can't finish this task.
brc = AsicCheckCommanOk(pAd, PowerSafeCID);
// 3. After 0x30 command is ok, send radio off command. lowbyte = 0 for power safe.
// If 0x30 command is not ok this time, we can ignore 0x35 command. It will make sure not cause firmware'r problem.
if ((Level == DOT11POWERSAVE) && (brc == TRUE))
{
AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 0, 0x00); // lowbyte = 0 means to do power safe, NOT turn off radio.
// 3-1. Wait command success
AsicCheckCommanOk(pAd, PowerRadioOffCID);
}
else if (brc == TRUE)
{
AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 1, 0x00); // lowbyte = 0 means to do power safe, NOT turn off radio.
// 3-1. Wait command success
AsicCheckCommanOk(pAd, PowerRadioOffCID);
}
#ifdef CONFIG_STA_SUPPORT
// 1. Wait DMA not busy
i = 0;
do
{
RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
if ((DmaCfg.field.RxDMABusy == 0) && (DmaCfg.field.TxDMABusy == 0))
break;
RTMPusecDelay(20);
i++;
}while(i < 50);
/*
if (i >= 50)
{
pAd->CheckDmaBusyCount++;
DBGPRINT(RT_DEBUG_TRACE, ("DMA Rx keeps busy. return on AsicRadioOff () CheckDmaBusyCount = %d \n", pAd->CheckDmaBusyCount));
}
else
{
pAd->CheckDmaBusyCount = 0;
}
*/
#endif // CONFIG_STA_SUPPORT //
//KH Debug:My original codes have the follwoing codes, but currecnt codes do not have it.
// Disable for stability. If PCIE Link Control is modified for advance power save, re-covery this code segment.
RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0x1280);
//OPSTATUS_SET_FLAG(pAd, fOP_STATUS_CLKSELECT_40MHZ);
#ifdef PCIE_PS_SUPPORT
#ifdef CONFIG_STA_SUPPORT
if ((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) && IS_VERSION_AFTER_F(pAd)
&& (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3)
&& (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE))
{
DBGPRINT(RT_DEBUG_TRACE, ("RT28xxPciAsicRadioOff::3090 return to skip the following TbttNumToNextWakeUp setting for 279x\n"));
pAd->bPCIclkOff = TRUE;
RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
// For this case, doesn't need to below actions, so return here.
return brc;
}
#endif // CONFIG_STA_SUPPORT //
#endif // PCIE_PS_SUPPORT //
if (Level == DOT11POWERSAVE)
{
AUTO_WAKEUP_STRUC AutoWakeupCfg;
//RTMPSetTimer(&pAd->Mlme.PsPollTimer, 90);
// we have decided to SLEEP, so at least do it for a BEACON period.
if (TbttNumToNextWakeUp == 0)
TbttNumToNextWakeUp = 1;
AutoWakeupCfg.word = 0;
RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
// 1. Set auto wake up timer.
AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1;
AutoWakeupCfg.field.EnableAutoWakeup = 1;
AutoWakeupCfg.field.AutoLeadTime = LEAD_TIME;
RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
}
#ifdef CONFIG_STA_SUPPORT
// 4-1. If it's to disable our device. Need to restore PCI Configuration Space to its original value.
if (Level == RTMP_HALT && pAd->OpMode == OPMODE_STA)
{
if ((brc == TRUE) && (i < 50))
RTMPPCIeLinkCtrlSetting(pAd, 1);
}
// 4. Set PCI configuration Space Link Comtrol fields. Only Radio Off needs to call this function
else if (pAd->OpMode == OPMODE_STA)
{
if ((brc == TRUE) && (i < 50))
RTMPPCIeLinkCtrlSetting(pAd, 3);
}
#endif // CONFIG_STA_SUPPORT //
//pAd->bPCIclkOffDisableTx = FALSE;
RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
return TRUE;
}
VOID RT28xxPciMlmeRadioOn(
IN PRTMP_ADAPTER pAd)
{
if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
return;
DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __FUNCTION__));
if ((pAd->OpMode == OPMODE_AP) ||
((pAd->OpMode == OPMODE_STA)
&& (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
#ifdef CONFIG_STA_SUPPORT
||pAd->StaCfg.PSControl.field.EnableNewPS == FALSE
#endif // CONFIG_STA_SUPPORT //
)))
{
RT28xxPciAsicRadioOn(pAd, GUI_IDLE_POWER_SAVE);
//NICResetFromError(pAd);
RTMPRingCleanUp(pAd, QID_AC_BK);
RTMPRingCleanUp(pAd, QID_AC_BE);
RTMPRingCleanUp(pAd, QID_AC_VI);
RTMPRingCleanUp(pAd, QID_AC_VO);
/*RTMPRingCleanUp(pAd, QID_HCCA);*/
RTMPRingCleanUp(pAd, QID_MGMT);
RTMPRingCleanUp(pAd, QID_RX);
// Enable Tx/Rx
RTMPEnableRxTx(pAd);
// Clear Radio off flag
RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
// Set LED
RTMPSetLED(pAd, LED_RADIO_ON);
}
#ifdef CONFIG_STA_SUPPORT
if ((pAd->OpMode == OPMODE_STA) &&
(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE))
&&(pAd->StaCfg.PSControl.field.EnableNewPS == TRUE))
{
BOOLEAN Cancelled;
RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
pAd->Mlme.bPsPollTimerRunning = FALSE;
RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 40);
}
#endif // CONFIG_STA_SUPPORT //
}
VOID RT28xxPciMlmeRadioOFF(
IN PRTMP_ADAPTER pAd)
{
BOOLEAN brc=TRUE;
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
return;
#ifdef CONFIG_STA_SUPPORT
// Link down first if any association exists
if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))
{
if (INFRA_ON(pAd) || ADHOC_ON(pAd))
{
MLME_DISASSOC_REQ_STRUCT DisReq;
MLME_QUEUE_ELEM *pMsgElem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG);
if (pMsgElem)
{
COPY_MAC_ADDR(&DisReq.Addr, pAd->CommonCfg.Bssid);
DisReq.Reason = REASON_DISASSOC_STA_LEAVING;
pMsgElem->Machine = ASSOC_STATE_MACHINE;
pMsgElem->MsgType = MT2_MLME_DISASSOC_REQ;
pMsgElem->MsgLen = sizeof(MLME_DISASSOC_REQ_STRUCT);
NdisMoveMemory(pMsgElem->Msg, &DisReq, sizeof(MLME_DISASSOC_REQ_STRUCT));
MlmeDisassocReqAction(pAd, pMsgElem);
kfree(pMsgElem);
RTMPusecDelay(1000);
}
}
}
#endif // CONFIG_STA_SUPPORT //
DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __FUNCTION__));
// Set LED
//RTMPSetLED(pAd, LED_RADIO_OFF);
// Set Radio off flag
RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
BOOLEAN Cancelled;
if (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)
{
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
{
RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled);
RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);
}
// If during power safe mode.
if (pAd->StaCfg.bRadio == TRUE)
{
DBGPRINT(RT_DEBUG_TRACE,("-->MlmeRadioOff() return on bRadio == TRUE; \n"));
return;
}
// Always radio on since the NIC needs to set the MCU command (LED_RADIO_OFF).
if (IDLE_ON(pAd) &&
(RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF)))
{
RT28xxPciAsicRadioOn(pAd, GUI_IDLE_POWER_SAVE);
}
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE))
{
BOOLEAN Cancelled;
pAd->Mlme.bPsPollTimerRunning = FALSE;
RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
}
}
// Link down first if any association exists
if (INFRA_ON(pAd) || ADHOC_ON(pAd))
LinkDown(pAd, FALSE);
RTMPusecDelay(10000);
//==========================================
// Clean up old bss table
BssTableInit(&pAd->ScanTab);
/*
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE))
{
RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
return;
}
*/
}
#endif // CONFIG_STA_SUPPORT //
// Set LED.Move to here for fixing LED bug. This flag must be called after LinkDown
RTMPSetLED(pAd, LED_RADIO_OFF);
#ifdef CONFIG_STA_SUPPORT
//KH Debug:All PCIe devices need to use timer to execute radio off function, or the PCIe&&EnableNewPS needs.
//KH Ans:It is right, because only when the PCIe and EnableNewPs is true, we need to delay the RadioOffTimer
//to avoid the deadlock with PCIe Power saving function.
if (pAd->OpMode == OPMODE_STA&&
OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)&&
pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)
{
RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
}
else
#endif // CONFIG_STA_SUPPORT //
{
brc=RT28xxPciAsicRadioOff(pAd, GUIRADIO_OFF, 0);
if (brc==FALSE)
{
DBGPRINT(RT_DEBUG_ERROR,("%s call RT28xxPciAsicRadioOff fail !!\n", __FUNCTION__));
}
}
/*
// Disable Tx/Rx DMA
RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); // disable DMA
GloCfg.field.EnableTxDMA = 0;
GloCfg.field.EnableRxDMA = 0;
RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); // abort all TX rings
// MAC_SYS_CTRL => value = 0x0 => 40mA
RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0);
// PWR_PIN_CFG => value = 0x0 => 40mA
RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0);
// TX_PIN_CFG => value = 0x0 => 20mA
RTMP_IO_WRITE32(pAd, TX_PIN_CFG, 0);
if (pAd->CommonCfg.BBPCurrentBW == BW_40)
{
// Must using 40MHz.
AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel);
}
else
{
// Must using 20MHz.
AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel);
}
// Waiting for DMA idle
i = 0;
do
{
RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0))
break;
RTMPusecDelay(1000);
}while (i++ < 100);
*/
}
#endif // RTMP_MAC_PCI //