1577 lines
44 KiB
C
1577 lines
44 KiB
C
|
/*
|
||
|
*************************************************************************
|
||
|
* 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;i<TX_RING_SIZE;i++)
|
||
|
{
|
||
|
ptemp= (PULONG)pAd->TxRing[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;i<TX_RING_SIZE;i++)
|
||
|
{
|
||
|
ptemp= (PULONG)pAd->TxRing[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;i<TX_RING_SIZE;i++)
|
||
|
{
|
||
|
ptemp= (PULONG)pAd->TxRing[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;i<TX_RING_SIZE;i++)
|
||
|
{
|
||
|
ptemp= (PULONG)pAd->TxRing[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;i<MGMT_RING_SIZE;i++)
|
||
|
{
|
||
|
ptemp= (PULONG)pAd->MgmtRing.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;i<RX_RING_SIZE;i++)
|
||
|
{
|
||
|
ptemp = (UINT32 *)pAd->RxRing.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;
|
||
|
}
|