diff options
Diffstat (limited to 'drivers/staging/rt3090/common/cmm_mac_pci.c')
-rw-r--r-- | drivers/staging/rt3090/common/cmm_mac_pci.c | 1757 |
1 files changed, 1757 insertions, 0 deletions
diff --git a/drivers/staging/rt3090/common/cmm_mac_pci.c b/drivers/staging/rt3090/common/cmm_mac_pci.c new file mode 100644 index 000000000000..8e1636315a8b --- /dev/null +++ b/drivers/staging/rt3090/common/cmm_mac_pci.c @@ -0,0 +1,1757 @@ +/* + ************************************************************************* + * 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 // |