/* ************************************************************************* * 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. * * * ************************************************************************* */ /* All functions in this file must be PCI-depended, or you should out your function in other files. */ #include "../rt_config.h" USHORT RtmpPCI_WriteTxResource( IN PRTMP_ADAPTER pAd, IN TX_BLK *pTxBlk, IN BOOLEAN bIsLast, OUT USHORT *FreeNumber) { UCHAR *pDMAHeaderBufVA; USHORT TxIdx, RetTxIdx; PTXD_STRUC pTxD; UINT32 BufBasePaLow; PRTMP_TX_RING pTxRing; USHORT hwHeaderLen; // // get Tx Ring Resource // pTxRing = &pAd->TxRing[pTxBlk->QueIdx]; TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx; pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa; BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa); // copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer if (pTxBlk->TxFrameType == TX_AMSDU_FRAME) { //hwHeaderLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD, 4)+LENGTH_AMSDU_SUBFRAMEHEAD; hwHeaderLen = pTxBlk->MpduHeaderLen - LENGTH_AMSDU_SUBFRAMEHEAD + pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD; } else { //hwHeaderLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; } NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHeaderLen); pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket; pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; // // build Tx Descriptor // pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; NdisZeroMemory(pTxD, TXD_SIZE); pTxD->SDPtr0 = BufBasePaLow; pTxD->SDLen0 = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; // include padding pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE); pTxD->SDLen1 = pTxBlk->SrcBufLen; pTxD->LastSec0 = 0; pTxD->LastSec1 = (bIsLast) ? 1 : 0; RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); RetTxIdx = TxIdx; // // Update Tx index // INC_RING_INDEX(TxIdx, TX_RING_SIZE); pTxRing->TxCpuIdx = TxIdx; *FreeNumber -= 1; return RetTxIdx; } USHORT RtmpPCI_WriteSingleTxResource( IN PRTMP_ADAPTER pAd, IN TX_BLK *pTxBlk, IN BOOLEAN bIsLast, OUT USHORT *FreeNumber) { UCHAR *pDMAHeaderBufVA; USHORT TxIdx, RetTxIdx; PTXD_STRUC pTxD; #ifdef RT_BIG_ENDIAN PTXD_STRUC pDestTxD; TXD_STRUC TxD; #endif UINT32 BufBasePaLow; PRTMP_TX_RING pTxRing; USHORT hwHeaderLen; // // get Tx Ring Resource // pTxRing = &pAd->TxRing[pTxBlk->QueIdx]; TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx; pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa; BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa); // copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer //hwHeaderLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHeaderLen); pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket; pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; // // build Tx Descriptor // #ifndef RT_BIG_ENDIAN pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; #else pDestTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; TxD = *pDestTxD; pTxD = &TxD; #endif NdisZeroMemory(pTxD, TXD_SIZE); pTxD->SDPtr0 = BufBasePaLow; pTxD->SDLen0 = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; // include padding pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);; pTxD->SDLen1 = pTxBlk->SrcBufLen; pTxD->LastSec0 = 0; pTxD->LastSec1 = (bIsLast) ? 1 : 0; RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); #ifdef RT_BIG_ENDIAN RTMPWIEndianChange((PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE), TYPE_TXWI); RTMPFrameEndianChange(pAd, (PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); #endif // RT_BIG_ENDIAN // RetTxIdx = TxIdx; // // Update Tx index // INC_RING_INDEX(TxIdx, TX_RING_SIZE); pTxRing->TxCpuIdx = TxIdx; *FreeNumber -= 1; return RetTxIdx; } USHORT RtmpPCI_WriteMultiTxResource( IN PRTMP_ADAPTER pAd, IN TX_BLK *pTxBlk, IN UCHAR frameNum, OUT USHORT *FreeNumber) { BOOLEAN bIsLast; UCHAR *pDMAHeaderBufVA; USHORT TxIdx, RetTxIdx; PTXD_STRUC pTxD; #ifdef RT_BIG_ENDIAN PTXD_STRUC pDestTxD; TXD_STRUC TxD; #endif UINT32 BufBasePaLow; PRTMP_TX_RING pTxRing; USHORT hwHdrLen; UINT32 firstDMALen; bIsLast = ((frameNum == (pTxBlk->TotalFrameNum - 1)) ? 1 : 0); // // get Tx Ring Resource // pTxRing = &pAd->TxRing[pTxBlk->QueIdx]; TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx; pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa; BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa); if (frameNum == 0) { // copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer if (pTxBlk->TxFrameType == TX_AMSDU_FRAME) //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD, 4)+LENGTH_AMSDU_SUBFRAMEHEAD; hwHdrLen = pTxBlk->MpduHeaderLen - LENGTH_AMSDU_SUBFRAMEHEAD + pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD; else if (pTxBlk->TxFrameType == TX_RALINK_FRAME) //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_ARALINK_HEADER_FIELD, 4)+LENGTH_ARALINK_HEADER_FIELD; hwHdrLen = pTxBlk->MpduHeaderLen - LENGTH_ARALINK_HEADER_FIELD + pTxBlk->HdrPadLen + LENGTH_ARALINK_HEADER_FIELD; else //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; firstDMALen = TXINFO_SIZE + TXWI_SIZE + hwHdrLen; } else { firstDMALen = pTxBlk->MpduHeaderLen; } NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, firstDMALen); pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket; pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; // // build Tx Descriptor // #ifndef RT_BIG_ENDIAN pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; #else pDestTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; TxD = *pDestTxD; pTxD = &TxD; #endif NdisZeroMemory(pTxD, TXD_SIZE); pTxD->SDPtr0 = BufBasePaLow; pTxD->SDLen0 = firstDMALen; // include padding pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);; pTxD->SDLen1 = pTxBlk->SrcBufLen; pTxD->LastSec0 = 0; pTxD->LastSec1 = (bIsLast) ? 1 : 0; RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); #ifdef RT_BIG_ENDIAN if (frameNum == 0) RTMPFrameEndianChange(pAd, (PUCHAR)(pDMAHeaderBufVA+ TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); if (frameNum != 0) RTMPWIEndianChange((PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE), TYPE_TXWI); RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); #endif // RT_BIG_ENDIAN // RetTxIdx = TxIdx; // // Update Tx index // INC_RING_INDEX(TxIdx, TX_RING_SIZE); pTxRing->TxCpuIdx = TxIdx; *FreeNumber -= 1; return RetTxIdx; } VOID RtmpPCI_FinalWriteTxResource( IN PRTMP_ADAPTER pAd, IN TX_BLK *pTxBlk, IN USHORT totalMPDUSize, IN USHORT FirstTxIdx) { PTXWI_STRUC pTxWI; PRTMP_TX_RING pTxRing; // // get Tx Ring Resource // pTxRing = &pAd->TxRing[pTxBlk->QueIdx]; pTxWI = (PTXWI_STRUC) pTxRing->Cell[FirstTxIdx].DmaBuf.AllocVa; pTxWI->MPDUtotalByteCount = totalMPDUSize; #ifdef RT_BIG_ENDIAN RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); #endif // RT_BIG_ENDIAN // } VOID RtmpPCIDataLastTxIdx( IN PRTMP_ADAPTER pAd, IN UCHAR QueIdx, IN USHORT LastTxIdx) { PTXD_STRUC pTxD; #ifdef RT_BIG_ENDIAN PTXD_STRUC pDestTxD; TXD_STRUC TxD; #endif PRTMP_TX_RING pTxRing; // // get Tx Ring Resource // pTxRing = &pAd->TxRing[QueIdx]; // // build Tx Descriptor // #ifndef RT_BIG_ENDIAN pTxD = (PTXD_STRUC) pTxRing->Cell[LastTxIdx].AllocVa; #else pDestTxD = (PTXD_STRUC) pTxRing->Cell[LastTxIdx].AllocVa; TxD = *pDestTxD; pTxD = &TxD; #endif pTxD->LastSec1 = 1; #ifdef RT_BIG_ENDIAN RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); #endif // RT_BIG_ENDIAN // } USHORT RtmpPCI_WriteFragTxResource( IN PRTMP_ADAPTER pAd, IN TX_BLK *pTxBlk, IN UCHAR fragNum, OUT USHORT *FreeNumber) { UCHAR *pDMAHeaderBufVA; USHORT TxIdx, RetTxIdx; PTXD_STRUC pTxD; #ifdef RT_BIG_ENDIAN PTXD_STRUC pDestTxD; TXD_STRUC TxD; #endif UINT32 BufBasePaLow; PRTMP_TX_RING pTxRing; USHORT hwHeaderLen; UINT32 firstDMALen; // // Get Tx Ring Resource // pTxRing = &pAd->TxRing[pTxBlk->QueIdx]; TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx; pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa; BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa); // // Copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer // //hwHeaderLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; firstDMALen = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, firstDMALen); // // Build Tx Descriptor // #ifndef RT_BIG_ENDIAN pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; #else pDestTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; TxD = *pDestTxD; pTxD = &TxD; #endif NdisZeroMemory(pTxD, TXD_SIZE); if (fragNum == pTxBlk->TotalFragNum) { pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket; pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; } pTxD->SDPtr0 = BufBasePaLow; pTxD->SDLen0 = firstDMALen; // include padding pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE); pTxD->SDLen1 = pTxBlk->SrcBufLen; pTxD->LastSec0 = 0; pTxD->LastSec1 = 1; RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); #ifdef RT_BIG_ENDIAN RTMPWIEndianChange((PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE), TYPE_TXWI); RTMPFrameEndianChange(pAd, (PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); #endif // RT_BIG_ENDIAN // RetTxIdx = TxIdx; pTxBlk->Priv += pTxBlk->SrcBufLen; // // Update Tx index // INC_RING_INDEX(TxIdx, TX_RING_SIZE); pTxRing->TxCpuIdx = TxIdx; *FreeNumber -= 1; return RetTxIdx; } /* Must be run in Interrupt context This function handle PCI specific TxDesc and cpu index update and kick the packet out. */ int RtmpPCIMgmtKickOut( IN RTMP_ADAPTER *pAd, IN UCHAR QueIdx, IN PNDIS_PACKET pPacket, IN PUCHAR pSrcBufVA, IN UINT SrcBufLen) { PTXD_STRUC pTxD; #ifdef RT_BIG_ENDIAN PTXD_STRUC pDestTxD; TXD_STRUC TxD; #endif ULONG SwIdx = pAd->MgmtRing.TxCpuIdx; #ifdef RT_BIG_ENDIAN pDestTxD = (PTXD_STRUC)pAd->MgmtRing.Cell[SwIdx].AllocVa; TxD = *pDestTxD; pTxD = &TxD; RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); #else pTxD = (PTXD_STRUC) pAd->MgmtRing.Cell[SwIdx].AllocVa; #endif pAd->MgmtRing.Cell[SwIdx].pNdisPacket = pPacket; pAd->MgmtRing.Cell[SwIdx].pNextNdisPacket = NULL; RTMPWriteTxDescriptor(pAd, pTxD, TRUE, FIFO_MGMT); pTxD->LastSec0 = 1; pTxD->LastSec1 = 1; pTxD->DMADONE = 0; pTxD->SDLen1 = 0; pTxD->SDPtr0 = PCI_MAP_SINGLE(pAd, pSrcBufVA, SrcBufLen, 0, PCI_DMA_TODEVICE); pTxD->SDLen0 = SrcBufLen; #ifdef RT_BIG_ENDIAN RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); #endif //================================================================== /* DBGPRINT_RAW(RT_DEBUG_TRACE, ("MLMEHardTransmit\n")); for (i = 0; i < (TXWI_SIZE+24); i++) { DBGPRINT_RAW(RT_DEBUG_TRACE, ("%x:", *(pSrcBufVA+i))); if ( i%4 == 3) DBGPRINT_RAW(RT_DEBUG_TRACE, (" :: ")); if ( i%16 == 15) DBGPRINT_RAW(RT_DEBUG_TRACE, ("\n ")); } DBGPRINT_RAW(RT_DEBUG_TRACE, ("\n "));*/ //======================================================================= pAd->RalinkCounters.KickTxCount++; pAd->RalinkCounters.OneSecTxDoneCount++; // Increase TX_CTX_IDX, but write to register later. INC_RING_INDEX(pAd->MgmtRing.TxCpuIdx, MGMT_RING_SIZE); RTMP_IO_WRITE32(pAd, TX_MGMTCTX_IDX, pAd->MgmtRing.TxCpuIdx); return 0; } #ifdef CONFIG_STA_SUPPORT /* ======================================================================== Routine Description: Check Rx descriptor, return NDIS_STATUS_FAILURE if any error dound Arguments: pRxD Pointer to the Rx descriptor Return Value: NDIS_STATUS_SUCCESS No err NDIS_STATUS_FAILURE Error Note: ======================================================================== */ NDIS_STATUS RTMPCheckRxError( IN PRTMP_ADAPTER pAd, IN PHEADER_802_11 pHeader, IN PRXWI_STRUC pRxWI, IN PRT28XX_RXD_STRUC pRxD) { PCIPHER_KEY pWpaKey; INT dBm; // Phy errors & CRC errors if (/*(pRxD->PhyErr) ||*/ (pRxD->Crc)) { // Check RSSI for Noise Hist statistic collection. dBm = (INT) (pRxWI->RSSI0) - pAd->BbpRssiToDbmDelta; if (dBm <= -87) pAd->StaCfg.RPIDensity[0] += 1; else if (dBm <= -82) pAd->StaCfg.RPIDensity[1] += 1; else if (dBm <= -77) pAd->StaCfg.RPIDensity[2] += 1; else if (dBm <= -72) pAd->StaCfg.RPIDensity[3] += 1; else if (dBm <= -67) pAd->StaCfg.RPIDensity[4] += 1; else if (dBm <= -62) pAd->StaCfg.RPIDensity[5] += 1; else if (dBm <= -57) pAd->StaCfg.RPIDensity[6] += 1; else if (dBm > -57) pAd->StaCfg.RPIDensity[7] += 1; return(NDIS_STATUS_FAILURE); } // Add Rx size to channel load counter, we should ignore error counts pAd->StaCfg.CLBusyBytes += (pRxD->SDL0 + 14); // Drop ToDs promiscous frame, it is opened due to CCX 2 channel load statistics if (pHeader != NULL) { if (pHeader->FC.ToDs) { return(NDIS_STATUS_FAILURE); } } // Drop not U2M frames, cant's drop here because we will drop beacon in this case // I am kind of doubting the U2M bit operation // if (pRxD->U2M == 0) // return(NDIS_STATUS_FAILURE); // drop decyption fail frame if (pRxD->CipherErr) { if (pRxD->CipherErr == 2) {DBGPRINT_RAW(RT_DEBUG_TRACE,("pRxD ERROR: ICV ok but MICErr "));} else if (pRxD->CipherErr == 1) {DBGPRINT_RAW(RT_DEBUG_TRACE,("pRxD ERROR: ICV Err "));} else if (pRxD->CipherErr == 3) DBGPRINT_RAW(RT_DEBUG_TRACE,("pRxD ERROR: Key not valid ")); if (((pRxD->CipherErr & 1) == 1) && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd)) RTMPSendWirelessEvent(pAd, IW_ICV_ERROR_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); DBGPRINT_RAW(RT_DEBUG_TRACE,(" %d (len=%d, Mcast=%d, MyBss=%d, Wcid=%d, KeyId=%d)\n", pRxD->CipherErr, pRxD->SDL0, pRxD->Mcast | pRxD->Bcast, pRxD->MyBss, pRxWI->WirelessCliID, // CipherName[pRxD->CipherAlg], pRxWI->KeyIndex)); // // MIC Error // if (pRxD->CipherErr == 2) { pWpaKey = &pAd->SharedKey[BSS0][pRxWI->KeyIndex]; #ifdef WPA_SUPPLICANT_SUPPORT if (pAd->StaCfg.WpaSupplicantUP) WpaSendMicFailureToWpaSupplicant(pAd, (pWpaKey->Type == PAIRWISEKEY) ? TRUE:FALSE); else #endif // WPA_SUPPLICANT_SUPPORT // RTMPReportMicError(pAd, pWpaKey); if (((pRxD->CipherErr & 2) == 2) && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd)) RTMPSendWirelessEvent(pAd, IW_MIC_ERROR_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error\n")); } if (pHeader == NULL) return(NDIS_STATUS_SUCCESS); /*if ((pRxD->CipherAlg == CIPHER_AES) && (pHeader->Sequence == pAd->FragFrame.Sequence)) { // // Acceptable since the First FragFrame no CipherErr problem. // return(NDIS_STATUS_SUCCESS); }*/ return(NDIS_STATUS_FAILURE); } return(NDIS_STATUS_SUCCESS); } #endif // CONFIG_STA_SUPPORT // BOOLEAN RTMPFreeTXDUponTxDmaDone( IN PRTMP_ADAPTER pAd, IN UCHAR QueIdx) { PRTMP_TX_RING pTxRing; PTXD_STRUC pTxD; #ifdef RT_BIG_ENDIAN PTXD_STRUC pDestTxD; #endif PNDIS_PACKET pPacket; UCHAR FREE = 0; TXD_STRUC TxD, *pOriTxD; //ULONG IrqFlags; BOOLEAN bReschedule = FALSE; ASSERT(QueIdx < NUM_OF_TX_RING); pTxRing = &pAd->TxRing[QueIdx]; RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QueIdx * RINGREG_DIFF, &pTxRing->TxDmaIdx); while (pTxRing->TxSwFreeIdx != pTxRing->TxDmaIdx) { // RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); #ifdef RALINK_ATE #ifdef RALINK_28xx_QA PHEADER_802_11 pHeader80211; if ((ATE_ON(pAd)) && (pAd->ate.bQATxStart == TRUE)) { if (pAd->ate.QID == QueIdx) { pAd->ate.TxDoneCount++; pAd->RalinkCounters.KickTxCount++; /* always use QID_AC_BE and FIFO_EDCA */ ASSERT(pAd->ate.QID == 0); pAd->ate.TxAc0++; FREE++; #ifndef RT_BIG_ENDIAN pTxD = (PTXD_STRUC) (pTxRing->Cell[pTxRing->TxSwFreeIdx].AllocVa); pOriTxD = pTxD; NdisMoveMemory(&TxD, pTxD, sizeof(TXD_STRUC)); pTxD = &TxD; #else pDestTxD = (PTXD_STRUC) (pTxRing->Cell[pTxRing->TxSwFreeIdx].AllocVa); pOriTxD = pDestTxD ; TxD = *pDestTxD; pTxD = &TxD; RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); #endif pTxD->DMADONE = 0; pHeader80211 = pTxRing->Cell[pTxRing->TxSwFreeIdx].DmaBuf.AllocVa + sizeof(TXWI_STRUC); #ifdef RT_BIG_ENDIAN RTMPFrameEndianChange(pAd, (PUCHAR)pHeader80211, DIR_READ, FALSE); #endif pHeader80211->Sequence = ++pAd->ate.seq; #ifdef RT_BIG_ENDIAN RTMPFrameEndianChange(pAd, (PUCHAR)pHeader80211, DIR_WRITE, FALSE); #endif if ((pAd->ate.bQATxStart == TRUE) && (pAd->ate.Mode & ATE_TXFRAME) && (pAd->ate.TxDoneCount < pAd->ate.TxCount)) { pAd->RalinkCounters.TransmittedByteCount += (pTxD->SDLen1 + pTxD->SDLen0); pAd->RalinkCounters.OneSecTransmittedByteCount += (pTxD->SDLen1 + pTxD->SDLen0); pAd->RalinkCounters.OneSecDmaDoneCount[QueIdx] ++; INC_RING_INDEX(pTxRing->TxSwFreeIdx, TX_RING_SIZE); /* get TX_DTX_IDX again */ RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QueIdx * RINGREG_DIFF , &pTxRing->TxDmaIdx); goto kick_out; } else if ((pAd->ate.TxStatus == 1)/* or (pAd->ate.bQATxStart == TRUE) ??? */ && (pAd->ate.TxDoneCount == pAd->ate.TxCount)) { DBGPRINT(RT_DEBUG_TRACE,("all Tx is done\n")); // Tx status enters idle mode. pAd->ate.TxStatus = 0; } else if (!(pAd->ate.Mode & ATE_TXFRAME)) { /* not complete sending yet, but someone press the Stop TX botton */ DBGPRINT(RT_DEBUG_ERROR,("not complete sending yet, but someone pressed the Stop TX bottom\n")); DBGPRINT(RT_DEBUG_ERROR,("pAd->ate.Mode = 0x%02x\n", pAd->ate.Mode)); } else { DBGPRINT(RT_DEBUG_OFF,("pTxRing->TxSwFreeIdx = %d\n", pTxRing->TxSwFreeIdx)); } #ifndef RT_BIG_ENDIAN NdisMoveMemory(pOriTxD, pTxD, sizeof(TXD_STRUC)); #else RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); *pDestTxD = TxD; #endif // RT_BIG_ENDIAN // INC_RING_INDEX(pTxRing->TxSwFreeIdx, TX_RING_SIZE); continue; } } #endif // RALINK_28xx_QA // #endif // RALINK_ATE // // static rate also need NICUpdateFifoStaCounters() function. //if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)) NICUpdateFifoStaCounters(pAd); /* Note : If (pAd->ate.bQATxStart == TRUE), we will never reach here. */ FREE++; #ifndef RT_BIG_ENDIAN pTxD = (PTXD_STRUC) (pTxRing->Cell[pTxRing->TxSwFreeIdx].AllocVa); pOriTxD = pTxD; NdisMoveMemory(&TxD, pTxD, sizeof(TXD_STRUC)); pTxD = &TxD; #else pDestTxD = (PTXD_STRUC) (pTxRing->Cell[pTxRing->TxSwFreeIdx].AllocVa); pOriTxD = pDestTxD ; TxD = *pDestTxD; pTxD = &TxD; RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); #endif pTxD->DMADONE = 0; #ifdef RALINK_ATE /* Execution of this block is not allowed when ATE is running. */ if (!(ATE_ON(pAd))) #endif // RALINK_ATE // { pPacket = pTxRing->Cell[pTxRing->TxSwFreeIdx].pNdisPacket; if (pPacket) { #ifdef CONFIG_5VT_ENHANCE if (RTMP_GET_PACKET_5VT(pPacket)) PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, 16, PCI_DMA_TODEVICE); else #endif // CONFIG_5VT_ENHANCE // PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE); RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); } //Always assign pNdisPacket as NULL after clear pTxRing->Cell[pTxRing->TxSwFreeIdx].pNdisPacket = NULL; pPacket = pTxRing->Cell[pTxRing->TxSwFreeIdx].pNextNdisPacket; ASSERT(pPacket == NULL); if (pPacket) { #ifdef CONFIG_5VT_ENHANCE if (RTMP_GET_PACKET_5VT(pPacket)) PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, 16, PCI_DMA_TODEVICE); else #endif // CONFIG_5VT_ENHANCE // 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; } pAd->RalinkCounters.TransmittedByteCount += (pTxD->SDLen1 + pTxD->SDLen0); pAd->RalinkCounters.OneSecDmaDoneCount[QueIdx] ++; INC_RING_INDEX(pTxRing->TxSwFreeIdx, TX_RING_SIZE); /* get tx_tdx_idx again */ RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QueIdx * RINGREG_DIFF , &pTxRing->TxDmaIdx); #ifdef RT_BIG_ENDIAN RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); *pDestTxD = TxD; #else NdisMoveMemory(pOriTxD, pTxD, sizeof(TXD_STRUC)); #endif #ifdef RALINK_ATE #ifdef RALINK_28xx_QA kick_out: #endif // RALINK_28xx_QA // /* ATE_TXCONT mode also need to send some normal frames, so let it in. ATE_STOP must be changed not to be 0xff to prevent it from running into this block. */ if ((pAd->ate.Mode & ATE_TXFRAME) && (pAd->ate.QID == QueIdx)) { // TxDoneCount++ has been done if QA is used. if (pAd->ate.bQATxStart == FALSE) { pAd->ate.TxDoneCount++; } if (((pAd->ate.TxCount - pAd->ate.TxDoneCount + 1) >= TX_RING_SIZE)) { /* Note : We increase TxCpuIdx here, not TxSwFreeIdx ! */ INC_RING_INDEX(pAd->TxRing[QueIdx].TxCpuIdx, TX_RING_SIZE); #ifndef RT_BIG_ENDIAN pTxD = (PTXD_STRUC) (pTxRing->Cell[pAd->TxRing[QueIdx].TxCpuIdx].AllocVa); pOriTxD = pTxD; NdisMoveMemory(&TxD, pTxD, sizeof(TXD_STRUC)); pTxD = &TxD; #else pDestTxD = (PTXD_STRUC) (pTxRing->Cell[pAd->TxRing[QueIdx].TxCpuIdx].AllocVa); pOriTxD = pDestTxD ; TxD = *pDestTxD; pTxD = &TxD; RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); #endif pTxD->DMADONE = 0; #ifndef RT_BIG_ENDIAN NdisMoveMemory(pOriTxD, pTxD, sizeof(TXD_STRUC)); #else RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); *pDestTxD = TxD; #endif // kick Tx-Ring RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + QueIdx * RINGREG_DIFF, pAd->TxRing[QueIdx].TxCpuIdx); pAd->RalinkCounters.KickTxCount++; } } #endif // RALINK_ATE // // RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); } return bReschedule; } /* ======================================================================== Routine Description: Process TX Rings DMA Done interrupt, running in DPC level Arguments: Adapter Pointer to our adapter Return Value: None IRQL = DISPATCH_LEVEL ======================================================================== */ BOOLEAN RTMPHandleTxRingDmaDoneInterrupt( IN PRTMP_ADAPTER pAd, IN INT_SOURCE_CSR_STRUC TxRingBitmap) { // UCHAR Count = 0; unsigned long IrqFlags; BOOLEAN bReschedule = FALSE; // Make sure Tx ring resource won't be used by other threads //NdisAcquireSpinLock(&pAd->TxRingLock); RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); if (TxRingBitmap.field.Ac0DmaDone) bReschedule = RTMPFreeTXDUponTxDmaDone(pAd, QID_AC_BE); /* if (TxRingBitmap.field.HccaDmaDone) bReschedule |= RTMPFreeTXDUponTxDmaDone(pAd, QID_HCCA); */ if (TxRingBitmap.field.Ac3DmaDone) bReschedule |= RTMPFreeTXDUponTxDmaDone(pAd, QID_AC_VO); if (TxRingBitmap.field.Ac2DmaDone) bReschedule |= RTMPFreeTXDUponTxDmaDone(pAd, QID_AC_VI); if (TxRingBitmap.field.Ac1DmaDone) bReschedule |= RTMPFreeTXDUponTxDmaDone(pAd, QID_AC_BK); // Make sure to release Tx ring resource //NdisReleaseSpinLock(&pAd->TxRingLock); RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); // Dequeue outgoing frames from TxSwQueue[] and process it RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); return bReschedule; } /* ======================================================================== Routine Description: Process MGMT ring DMA done interrupt, running in DPC level Arguments: pAd Pointer to our adapter Return Value: None IRQL = DISPATCH_LEVEL Note: ======================================================================== */ VOID RTMPHandleMgmtRingDmaDoneInterrupt( IN PRTMP_ADAPTER pAd) { PTXD_STRUC pTxD; #ifdef RT_BIG_ENDIAN PTXD_STRUC pDestTxD; TXD_STRUC TxD; #endif PNDIS_PACKET pPacket; // int i; UCHAR FREE = 0; PRTMP_MGMT_RING pMgmtRing = &pAd->MgmtRing; NdisAcquireSpinLock(&pAd->MgmtRingLock); RTMP_IO_READ32(pAd, TX_MGMTDTX_IDX, &pMgmtRing->TxDmaIdx); while (pMgmtRing->TxSwFreeIdx!= pMgmtRing->TxDmaIdx) { FREE++; #ifdef RT_BIG_ENDIAN pDestTxD = (PTXD_STRUC) (pMgmtRing->Cell[pAd->MgmtRing.TxSwFreeIdx].AllocVa); TxD = *pDestTxD; pTxD = &TxD; RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); #else pTxD = (PTXD_STRUC) (pMgmtRing->Cell[pAd->MgmtRing.TxSwFreeIdx].AllocVa); #endif pTxD->DMADONE = 0; pPacket = pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNdisPacket; if (pPacket) { PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE); RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); } pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNdisPacket = NULL; pPacket = pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNextNdisPacket; if (pPacket) { PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE); RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); } pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNextNdisPacket = NULL; INC_RING_INDEX(pMgmtRing->TxSwFreeIdx, MGMT_RING_SIZE); #ifdef RT_BIG_ENDIAN RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, TRUE, TYPE_TXD); #endif } NdisReleaseSpinLock(&pAd->MgmtRingLock); #ifdef CONFIG_STA_SUPPORT #endif // CONFIG_STA_SUPPORT // } /* ======================================================================== Routine Description: Arguments: Adapter Pointer to our adapter. Dequeue all power safe delayed braodcast frames after beacon. IRQL = DISPATCH_LEVEL ======================================================================== */ VOID RTMPHandleTBTTInterrupt( IN PRTMP_ADAPTER pAd) { { if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) { } } } /* ======================================================================== Routine Description: Arguments: pAd Pointer to our adapter. Rewrite beacon content before next send-out. IRQL = DISPATCH_LEVEL ======================================================================== */ VOID RTMPHandlePreTBTTInterrupt( IN PRTMP_ADAPTER pAd) { { if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) { DBGPRINT(RT_DEBUG_TRACE, ("RTMPHandlePreTBTTInterrupt...\n")); } } } VOID RTMPHandleRxCoherentInterrupt( IN PRTMP_ADAPTER pAd) { WPDMA_GLO_CFG_STRUC GloCfg; if (pAd == NULL) { DBGPRINT(RT_DEBUG_TRACE, ("====> pAd is NULL, return.\n")); return; } DBGPRINT(RT_DEBUG_TRACE, ("==> RTMPHandleRxCoherentInterrupt \n")); RTMP_IO_READ32(pAd, WPDMA_GLO_CFG , &GloCfg.word); GloCfg.field.EnTXWriteBackDDONE = 0; GloCfg.field.EnableRxDMA = 0; GloCfg.field.EnableTxDMA = 0; RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); RTMPRingCleanUp(pAd, QID_AC_BE); RTMPRingCleanUp(pAd, QID_AC_BK); RTMPRingCleanUp(pAd, QID_AC_VI); RTMPRingCleanUp(pAd, QID_AC_VO); /*RTMPRingCleanUp(pAd, QID_HCCA);*/ RTMPRingCleanUp(pAd, QID_MGMT); RTMPRingCleanUp(pAd, QID_RX); RTMPEnableRxTx(pAd); DBGPRINT(RT_DEBUG_TRACE, ("<== RTMPHandleRxCoherentInterrupt \n")); } VOID DBGPRINT_TX_RING( IN PRTMP_ADAPTER pAd, IN UCHAR QueIdx) { UINT32 Ac0Base; UINT32 Ac0HwIdx = 0, Ac0SwIdx = 0, AC0freeIdx; int i; // PULONG pTxD; PULONG ptemp; DBGPRINT_RAW(RT_DEBUG_TRACE, ("=====================================================\n " )); switch (QueIdx) { case QID_AC_BE: RTMP_IO_READ32(pAd, TX_BASE_PTR0, &Ac0Base); RTMP_IO_READ32(pAd, TX_CTX_IDX0, &Ac0SwIdx); RTMP_IO_READ32(pAd, TX_DTX_IDX0, &Ac0HwIdx); DBGPRINT_RAW(RT_DEBUG_TRACE, ("All QID_AC_BE DESCRIPTOR \n " )); for (i=0;iTxRing[QID_AC_BE].Cell[i].AllocVa; DBGPRINT_RAW(RT_DEBUG_TRACE, ("[%02d] %08lx: %08lx: %08lx: %08lx\n " , i, *ptemp,*(ptemp+1),*(ptemp+2),*(ptemp+3))); } DBGPRINT_RAW(RT_DEBUG_TRACE, (" \n " )); break; case QID_AC_BK: RTMP_IO_READ32(pAd, TX_BASE_PTR1, &Ac0Base); RTMP_IO_READ32(pAd, TX_CTX_IDX1, &Ac0SwIdx); RTMP_IO_READ32(pAd, TX_DTX_IDX1, &Ac0HwIdx); DBGPRINT_RAW(RT_DEBUG_TRACE, ("All QID_AC_BK DESCRIPTOR \n " )); for (i=0;iTxRing[QID_AC_BK].Cell[i].AllocVa; DBGPRINT_RAW(RT_DEBUG_TRACE, ("[%02d] %08lx: %08lx: %08lx: %08lx\n " , i, *ptemp,*(ptemp+1),*(ptemp+2),*(ptemp+3))); } DBGPRINT_RAW(RT_DEBUG_TRACE, (" \n " )); break; case QID_AC_VI: RTMP_IO_READ32(pAd, TX_BASE_PTR2, &Ac0Base); RTMP_IO_READ32(pAd, TX_CTX_IDX2, &Ac0SwIdx); RTMP_IO_READ32(pAd, TX_DTX_IDX2, &Ac0HwIdx); DBGPRINT_RAW(RT_DEBUG_TRACE, ("All QID_AC_VI DESCRIPTOR \n " )); for (i=0;iTxRing[QID_AC_VI].Cell[i].AllocVa; DBGPRINT_RAW(RT_DEBUG_TRACE, ("[%02d] %08lx: %08lx: %08lx: %08lx\n " , i, *ptemp,*(ptemp+1),*(ptemp+2),*(ptemp+3))); } DBGPRINT_RAW(RT_DEBUG_TRACE, (" \n " )); break; case QID_AC_VO: RTMP_IO_READ32(pAd, TX_BASE_PTR3, &Ac0Base); RTMP_IO_READ32(pAd, TX_CTX_IDX3, &Ac0SwIdx); RTMP_IO_READ32(pAd, TX_DTX_IDX3, &Ac0HwIdx); DBGPRINT_RAW(RT_DEBUG_TRACE, ("All QID_AC_VO DESCRIPTOR \n " )); for (i=0;iTxRing[QID_AC_VO].Cell[i].AllocVa; DBGPRINT_RAW(RT_DEBUG_TRACE, ("[%02d] %08lx: %08lx: %08lx: %08lx\n " , i, *ptemp,*(ptemp+1),*(ptemp+2),*(ptemp+3))); } DBGPRINT_RAW(RT_DEBUG_TRACE, (" \n " )); break; case QID_MGMT: RTMP_IO_READ32(pAd, TX_BASE_PTR5, &Ac0Base); RTMP_IO_READ32(pAd, TX_CTX_IDX5, &Ac0SwIdx); RTMP_IO_READ32(pAd, TX_DTX_IDX5, &Ac0HwIdx); DBGPRINT_RAW(RT_DEBUG_TRACE, (" All QID_MGMT DESCRIPTOR \n " )); for (i=0;iMgmtRing.Cell[i].AllocVa; DBGPRINT_RAW(RT_DEBUG_TRACE, ("[%02d] %08lx: %08lx: %08lx: %08lx\n " , i, *ptemp,*(ptemp+1),*(ptemp+2),*(ptemp+3))); } DBGPRINT_RAW(RT_DEBUG_TRACE, (" \n " )); break; default: DBGPRINT_ERR(("DBGPRINT_TX_RING(Ring %d) not supported\n", QueIdx)); break; } AC0freeIdx = pAd->TxRing[QueIdx].TxSwFreeIdx; DBGPRINT(RT_DEBUG_TRACE,("TxRing%d, TX_DTX_IDX=%d, TX_CTX_IDX=%d\n", QueIdx, Ac0HwIdx, Ac0SwIdx)); DBGPRINT_RAW(RT_DEBUG_TRACE,(" TxSwFreeIdx[%d]", AC0freeIdx)); DBGPRINT_RAW(RT_DEBUG_TRACE,(" pending-NDIS=%ld\n", pAd->RalinkCounters.PendingNdisPacketCount)); } VOID DBGPRINT_RX_RING( IN PRTMP_ADAPTER pAd) { UINT32 Ac0Base; UINT32 Ac0HwIdx = 0, Ac0SwIdx = 0, AC0freeIdx; // PULONG pTxD; int i; UINT32 *ptemp; // PRXD_STRUC pRxD; DBGPRINT_RAW(RT_DEBUG_TRACE, ("=====================================================\n " )); RTMP_IO_READ32(pAd, RX_BASE_PTR, &Ac0Base); RTMP_IO_READ32(pAd, RX_CRX_IDX, &Ac0SwIdx); RTMP_IO_READ32(pAd, RX_DRX_IDX, &Ac0HwIdx); AC0freeIdx = pAd->RxRing.RxSwReadIdx; DBGPRINT_RAW(RT_DEBUG_TRACE, ("All RX DSP \n " )); for (i=0;iRxRing.Cell[i].AllocVa; DBGPRINT_RAW(RT_DEBUG_TRACE, ("[%02d] %08x: %08x: %08x: %08x\n " , i, *ptemp,*(ptemp+1),*(ptemp+2),*(ptemp+3))); } DBGPRINT(RT_DEBUG_TRACE,("RxRing, RX_DRX_IDX=%d, RX_CRX_IDX=%d \n", Ac0HwIdx, Ac0SwIdx)); DBGPRINT_RAW(RT_DEBUG_TRACE,(" RxSwReadIdx [%d]=", AC0freeIdx)); DBGPRINT_RAW(RT_DEBUG_TRACE,(" pending-NDIS=%ld\n", pAd->RalinkCounters.PendingNdisPacketCount)); } PNDIS_PACKET GetPacketFromRxRing( IN PRTMP_ADAPTER pAd, OUT PRT28XX_RXD_STRUC pSaveRxD, OUT BOOLEAN *pbReschedule, IN OUT UINT32 *pRxPending) { PRXD_STRUC pRxD; #ifdef RT_BIG_ENDIAN PRXD_STRUC pDestRxD; RXD_STRUC RxD; #endif PNDIS_PACKET pRxPacket = NULL; PNDIS_PACKET pNewPacket; PVOID AllocVa; NDIS_PHYSICAL_ADDRESS AllocPa; BOOLEAN bReschedule = FALSE; RTMP_SEM_LOCK(&pAd->RxRingLock); if (*pRxPending == 0) { // Get how may packets had been received RTMP_IO_READ32(pAd, RX_DRX_IDX , &pAd->RxRing.RxDmaIdx); if (pAd->RxRing.RxSwReadIdx == pAd->RxRing.RxDmaIdx) { // no more rx packets bReschedule = FALSE; goto done; } // get rx pending count if (pAd->RxRing.RxDmaIdx > pAd->RxRing.RxSwReadIdx) *pRxPending = pAd->RxRing.RxDmaIdx - pAd->RxRing.RxSwReadIdx; else *pRxPending = pAd->RxRing.RxDmaIdx + RX_RING_SIZE - pAd->RxRing.RxSwReadIdx; } #ifdef RT_BIG_ENDIAN pDestRxD = (PRXD_STRUC) pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx].AllocVa; RxD = *pDestRxD; pRxD = &RxD; RTMPDescriptorEndianChange((PUCHAR)pRxD, TYPE_RXD); #else // Point to Rx indexed rx ring descriptor pRxD = (PRXD_STRUC) pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx].AllocVa; #endif if (pRxD->DDONE == 0) { *pRxPending = 0; // DMAIndx had done but DDONE bit not ready bReschedule = TRUE; goto done; } // return rx descriptor NdisMoveMemory(pSaveRxD, pRxD, RXD_SIZE); pNewPacket = RTMP_AllocateRxPacketBuffer(pAd, RX_BUFFER_AGGRESIZE, FALSE, &AllocVa, &AllocPa); if (pNewPacket) { // unmap the rx buffer PCI_UNMAP_SINGLE(pAd, pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx].DmaBuf.AllocPa, pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx].DmaBuf.AllocSize, PCI_DMA_FROMDEVICE); pRxPacket = pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx].pNdisPacket; pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx].DmaBuf.AllocSize = RX_BUFFER_AGGRESIZE; pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx].pNdisPacket = (PNDIS_PACKET) pNewPacket; pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx].DmaBuf.AllocVa = AllocVa; pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx].DmaBuf.AllocPa = AllocPa; /* update SDP0 to new buffer of rx packet */ pRxD->SDP0 = AllocPa; } else { //DBGPRINT(RT_DEBUG_TRACE,("No Rx Buffer\n")); pRxPacket = NULL; bReschedule = TRUE; } pRxD->DDONE = 0; // had handled one rx packet *pRxPending = *pRxPending - 1; // update rx descriptor and kick rx #ifdef RT_BIG_ENDIAN RTMPDescriptorEndianChange((PUCHAR)pRxD, TYPE_RXD); WriteBackToDescriptor((PUCHAR)pDestRxD, (PUCHAR)pRxD, FALSE, TYPE_RXD); #endif INC_RING_INDEX(pAd->RxRing.RxSwReadIdx, RX_RING_SIZE); pAd->RxRing.RxCpuIdx = (pAd->RxRing.RxSwReadIdx == 0) ? (RX_RING_SIZE-1) : (pAd->RxRing.RxSwReadIdx-1); RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx); done: RTMP_SEM_UNLOCK(&pAd->RxRingLock); *pbReschedule = bReschedule; return pRxPacket; } NDIS_STATUS MlmeHardTransmitTxRing( IN PRTMP_ADAPTER pAd, IN UCHAR QueIdx, IN PNDIS_PACKET pPacket) { PACKET_INFO PacketInfo; PUCHAR pSrcBufVA; UINT SrcBufLen; PTXD_STRUC pTxD; #ifdef RT_BIG_ENDIAN PTXD_STRUC pDestTxD; TXD_STRUC TxD; #endif PHEADER_802_11 pHeader_802_11; BOOLEAN bAckRequired, bInsertTimestamp; ULONG SrcBufPA; //UCHAR TxBufIdx; UCHAR MlmeRate; ULONG SwIdx = pAd->TxRing[QueIdx].TxCpuIdx; PTXWI_STRUC pFirstTxWI; //ULONG i; //HTTRANSMIT_SETTING MlmeTransmit; //Rate for this MGMT frame. ULONG FreeNum; MAC_TABLE_ENTRY *pMacEntry = NULL; RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); if (pSrcBufVA == NULL) { // The buffer shouldn't be NULL return NDIS_STATUS_FAILURE; } // Make sure MGMT ring resource won't be used by other threads //NdisAcquireSpinLock(&pAd->TxRingLock); FreeNum = GET_TXRING_FREENO(pAd, QueIdx); if (FreeNum == 0) { //NdisReleaseSpinLock(&pAd->TxRingLock); return NDIS_STATUS_FAILURE; } SwIdx = pAd->TxRing[QueIdx].TxCpuIdx; #ifndef RT_BIG_ENDIAN pTxD = (PTXD_STRUC) pAd->TxRing[QueIdx].Cell[SwIdx].AllocVa; #else pDestTxD = (PTXD_STRUC)pAd->TxRing[QueIdx].Cell[SwIdx].AllocVa; TxD = *pDestTxD; pTxD = &TxD; RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); #endif if (pAd->TxRing[QueIdx].Cell[SwIdx].pNdisPacket) { DBGPRINT(RT_DEBUG_OFF, ("MlmeHardTransmit Error\n")); //NdisReleaseSpinLock(&pAd->TxRingLock); return NDIS_STATUS_FAILURE; } #ifdef CONFIG_STA_SUPPORT IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { // outgoing frame always wakeup PHY to prevent frame lost // if (pAd->StaCfg.Psm == PWR_SAVE) if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) AsicForceWakeup(pAd, TRUE); } #endif // CONFIG_STA_SUPPORT // pFirstTxWI =(PTXWI_STRUC)pSrcBufVA; pHeader_802_11 = (PHEADER_802_11) (pSrcBufVA + TXWI_SIZE); if (pHeader_802_11->Addr1[0] & 0x01) { MlmeRate = pAd->CommonCfg.BasicMlmeRate; } else { MlmeRate = pAd->CommonCfg.MlmeRate; } if ((pHeader_802_11->FC.Type == BTYPE_DATA) && (pHeader_802_11->FC.SubType == SUBTYPE_QOS_NULL)) { pMacEntry = MacTableLookup(pAd, pHeader_802_11->Addr1); } // Verify Mlme rate for a / g bands. if ((pAd->LatchRfRegs.Channel > 14) && (MlmeRate < RATE_6)) // 11A band MlmeRate = RATE_6; // // Should not be hard code to set PwrMgmt to 0 (PWR_ACTIVE) // Snice it's been set to 0 while on MgtMacHeaderInit // By the way this will cause frame to be send on PWR_SAVE failed. // // // In WMM-UAPSD, mlme frame should be set psm as power saving but probe request frame #ifdef CONFIG_STA_SUPPORT // Data-Null packets alse pass through MMRequest in RT2860, however, we hope control the psm bit to pass APSD if (pHeader_802_11->FC.Type != BTYPE_DATA) { if ((pHeader_802_11->FC.SubType == SUBTYPE_PROBE_REQ) || !(pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable)) { pHeader_802_11->FC.PwrMgmt = PWR_ACTIVE; } else { pHeader_802_11->FC.PwrMgmt = pAd->CommonCfg.bAPSDForcePowerSave; } } #endif // CONFIG_STA_SUPPORT // bInsertTimestamp = FALSE; if (pHeader_802_11->FC.Type == BTYPE_CNTL) // must be PS-POLL { bAckRequired = FALSE; } else // BTYPE_MGMT or BTYPE_DATA(must be NULL frame) { if (pHeader_802_11->Addr1[0] & 0x01) // MULTICAST, BROADCAST { bAckRequired = FALSE; pHeader_802_11->Duration = 0; } else { bAckRequired = TRUE; pHeader_802_11->Duration = RTMPCalcDuration(pAd, MlmeRate, 14); if (pHeader_802_11->FC.SubType == SUBTYPE_PROBE_RSP) { bInsertTimestamp = TRUE; } } } pHeader_802_11->Sequence = pAd->Sequence++; if (pAd->Sequence > 0xfff) pAd->Sequence = 0; // Before radar detection done, mgmt frame can not be sent but probe req // Because we need to use probe req to trigger driver to send probe req in passive scan if ((pHeader_802_11->FC.SubType != SUBTYPE_PROBE_REQ) && (pAd->CommonCfg.bIEEE80211H == 1) && (pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE)) { DBGPRINT(RT_DEBUG_ERROR,("MlmeHardTransmit --> radar detect not in normal mode !!!\n")); //NdisReleaseSpinLock(&pAd->TxRingLock); return (NDIS_STATUS_FAILURE); } #ifdef RT_BIG_ENDIAN RTMPFrameEndianChange(pAd, (PUCHAR)pHeader_802_11, DIR_WRITE, FALSE); #endif // // fill scatter-and-gather buffer list into TXD. Internally created NDIS PACKET // should always has only one ohysical buffer, and the whole frame size equals // to the first scatter buffer size // // Initialize TX Descriptor // For inter-frame gap, the number is for this frame and next frame // For MLME rate, we will fix as 2Mb to match other vendor's implement // pAd->CommonCfg.MlmeTransmit.field.MODE = 1; // management frame doesn't need encryption. so use RESERVED_WCID no matter u are sending to specific wcid or not. // Only beacon use Nseq=TRUE. So here we use Nseq=FALSE. if (pMacEntry == NULL) { RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, bInsertTimestamp, FALSE, bAckRequired, FALSE, 0, RESERVED_WCID, (SrcBufLen - TXWI_SIZE), PID_MGMT, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit); } else { RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, bInsertTimestamp, FALSE, bAckRequired, FALSE, 0, pMacEntry->Aid, (SrcBufLen - TXWI_SIZE), pMacEntry->MaxHTPhyMode.field.MCS, 0, (UCHAR)pMacEntry->MaxHTPhyMode.field.MCS, IFS_BACKOFF, FALSE, &pMacEntry->MaxHTPhyMode); } pAd->TxRing[QueIdx].Cell[SwIdx].pNdisPacket = pPacket; pAd->TxRing[QueIdx].Cell[SwIdx].pNextNdisPacket = NULL; // pFirstTxWI->MPDUtotalByteCount = SrcBufLen - TXWI_SIZE; #ifdef RT_BIG_ENDIAN RTMPWIEndianChange((PUCHAR)pFirstTxWI, TYPE_TXWI); #endif SrcBufPA = PCI_MAP_SINGLE(pAd, pSrcBufVA, SrcBufLen, 0, PCI_DMA_TODEVICE); RTMPWriteTxDescriptor(pAd, pTxD, TRUE, FIFO_EDCA); pTxD->LastSec0 = 1; pTxD->LastSec1 = 1; pTxD->SDLen0 = SrcBufLen; pTxD->SDLen1 = 0; pTxD->SDPtr0 = SrcBufPA; pTxD->DMADONE = 0; #ifdef RT_BIG_ENDIAN RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); #endif pAd->RalinkCounters.KickTxCount++; pAd->RalinkCounters.OneSecTxDoneCount++; // Increase TX_CTX_IDX, but write to register later. INC_RING_INDEX(pAd->TxRing[QueIdx].TxCpuIdx, TX_RING_SIZE); RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + QueIdx*0x10, pAd->TxRing[QueIdx].TxCpuIdx); // Make sure to release MGMT ring resource // NdisReleaseSpinLock(&pAd->TxRingLock); return NDIS_STATUS_SUCCESS; } NDIS_STATUS MlmeDataHardTransmit( IN PRTMP_ADAPTER pAd, IN UCHAR QueIdx, IN PNDIS_PACKET pPacket) { if ((pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE) ) { return NDIS_STATUS_FAILURE; } return MlmeHardTransmitTxRing(pAd,QueIdx,pPacket); } /* ======================================================================== Routine Description: Calculates the duration which is required to transmit out frames with given size and specified rate. Arguments: pTxD Pointer to transmit descriptor Ack Setting for Ack requirement bit Fragment Setting for Fragment bit RetryMode Setting for retry mode Ifs Setting for IFS gap Rate Setting for transmit rate Service Setting for service Length Frame length TxPreamble Short or Long preamble when using CCK rates QueIdx - 0-3, according to 802.11e/d4.4 June/2003 Return Value: None IRQL = PASSIVE_LEVEL IRQL = DISPATCH_LEVEL ======================================================================== */ VOID RTMPWriteTxDescriptor( IN PRTMP_ADAPTER pAd, IN PTXD_STRUC pTxD, IN BOOLEAN bWIV, IN UCHAR QueueSEL) { // // Always use Long preamble before verifiation short preamble functionality works well. // Todo: remove the following line if short preamble functionality works // OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); pTxD->WIV = (bWIV) ? 1: 0; pTxD->QSEL= (QueueSEL); //RT2860c?? fixed using EDCA queue for test... We doubt Queue1 has problem. 2006-09-26 Jan //pTxD->QSEL= FIFO_EDCA; /* if (pAd->bGenOneHCCA == TRUE) pTxD->QSEL= FIFO_HCCA; */ pTxD->DMADONE = 0; }