51f94a7b1f
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
898 lines
26 KiB
C
898 lines
26 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. *
|
|
* *
|
|
*************************************************************************
|
|
|
|
Module Name:
|
|
2860_rtmp_init.c
|
|
|
|
Abstract:
|
|
Miniport generic portion header file
|
|
|
|
Revision History:
|
|
Who When What
|
|
-------- ---------- ----------------------------------------------
|
|
Paul Lin 2002-08-01 created
|
|
John Chang 2004-08-20 RT2561/2661 use scatter-gather scheme
|
|
Jan Lee 2006-09-15 RT2860. Change for 802.11n , EEPROM, Led, BA, HT.
|
|
*/
|
|
#include "../rt_config.h"
|
|
|
|
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Allocate DMA memory blocks for send, receive
|
|
|
|
Arguments:
|
|
Adapter Pointer to our adapter
|
|
|
|
Return Value:
|
|
NDIS_STATUS_SUCCESS
|
|
NDIS_STATUS_FAILURE
|
|
NDIS_STATUS_RESOURCES
|
|
|
|
IRQL = PASSIVE_LEVEL
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
NDIS_STATUS RTMPAllocTxRxRingMemory(
|
|
IN PRTMP_ADAPTER pAd)
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
ULONG RingBasePaHigh;
|
|
ULONG RingBasePaLow;
|
|
PVOID RingBaseVa;
|
|
INT index, num;
|
|
PTXD_STRUC pTxD;
|
|
PRXD_STRUC pRxD;
|
|
ULONG ErrorValue = 0;
|
|
PRTMP_TX_RING pTxRing;
|
|
PRTMP_DMABUF pDmaBuf;
|
|
PNDIS_PACKET pPacket;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("--> RTMPAllocTxRxRingMemory\n"));
|
|
do
|
|
{
|
|
//
|
|
// Allocate all ring descriptors, include TxD, RxD, MgmtD.
|
|
// Although each size is different, to prevent cacheline and alignment
|
|
// issue, I intentional set them all to 64 bytes.
|
|
//
|
|
for (num=0; num<NUM_OF_TX_RING; num++)
|
|
{
|
|
ULONG BufBasePaHigh;
|
|
ULONG BufBasePaLow;
|
|
PVOID BufBaseVa;
|
|
|
|
//
|
|
// Allocate Tx ring descriptor's memory (5 TX rings = 4 ACs + 1 HCCA)
|
|
//
|
|
pAd->TxDescRing[num].AllocSize = TX_RING_SIZE * TXD_SIZE;
|
|
RTMP_AllocateTxDescMemory(
|
|
pAd,
|
|
num,
|
|
pAd->TxDescRing[num].AllocSize,
|
|
FALSE,
|
|
&pAd->TxDescRing[num].AllocVa,
|
|
&pAd->TxDescRing[num].AllocPa);
|
|
|
|
if (pAd->TxDescRing[num].AllocVa == NULL)
|
|
{
|
|
ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
|
|
DBGPRINT_ERR(("Failed to allocate a big buffer\n"));
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
// Zero init this memory block
|
|
NdisZeroMemory(pAd->TxDescRing[num].AllocVa, pAd->TxDescRing[num].AllocSize);
|
|
|
|
// Save PA & VA for further operation
|
|
RingBasePaHigh = RTMP_GetPhysicalAddressHigh(pAd->TxDescRing[num].AllocPa);
|
|
RingBasePaLow = RTMP_GetPhysicalAddressLow (pAd->TxDescRing[num].AllocPa);
|
|
RingBaseVa = pAd->TxDescRing[num].AllocVa;
|
|
|
|
//
|
|
// Allocate all 1st TXBuf's memory for this TxRing
|
|
//
|
|
pAd->TxBufSpace[num].AllocSize = TX_RING_SIZE * TX_DMA_1ST_BUFFER_SIZE;
|
|
RTMP_AllocateFirstTxBuffer(
|
|
pAd,
|
|
num,
|
|
pAd->TxBufSpace[num].AllocSize,
|
|
FALSE,
|
|
&pAd->TxBufSpace[num].AllocVa,
|
|
&pAd->TxBufSpace[num].AllocPa);
|
|
|
|
if (pAd->TxBufSpace[num].AllocVa == NULL)
|
|
{
|
|
ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
|
|
DBGPRINT_ERR(("Failed to allocate a big buffer\n"));
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
// Zero init this memory block
|
|
NdisZeroMemory(pAd->TxBufSpace[num].AllocVa, pAd->TxBufSpace[num].AllocSize);
|
|
|
|
// Save PA & VA for further operation
|
|
BufBasePaHigh = RTMP_GetPhysicalAddressHigh(pAd->TxBufSpace[num].AllocPa);
|
|
BufBasePaLow = RTMP_GetPhysicalAddressLow (pAd->TxBufSpace[num].AllocPa);
|
|
BufBaseVa = pAd->TxBufSpace[num].AllocVa;
|
|
|
|
//
|
|
// Initialize Tx Ring Descriptor and associated buffer memory
|
|
//
|
|
pTxRing = &pAd->TxRing[num];
|
|
for (index = 0; index < TX_RING_SIZE; index++)
|
|
{
|
|
pTxRing->Cell[index].pNdisPacket = NULL;
|
|
pTxRing->Cell[index].pNextNdisPacket = NULL;
|
|
// Init Tx Ring Size, Va, Pa variables
|
|
pTxRing->Cell[index].AllocSize = TXD_SIZE;
|
|
pTxRing->Cell[index].AllocVa = RingBaseVa;
|
|
RTMP_SetPhysicalAddressHigh(pTxRing->Cell[index].AllocPa, RingBasePaHigh);
|
|
RTMP_SetPhysicalAddressLow (pTxRing->Cell[index].AllocPa, RingBasePaLow);
|
|
|
|
// Setup Tx Buffer size & address. only 802.11 header will store in this space
|
|
pDmaBuf = &pTxRing->Cell[index].DmaBuf;
|
|
pDmaBuf->AllocSize = TX_DMA_1ST_BUFFER_SIZE;
|
|
pDmaBuf->AllocVa = BufBaseVa;
|
|
RTMP_SetPhysicalAddressHigh(pDmaBuf->AllocPa, BufBasePaHigh);
|
|
RTMP_SetPhysicalAddressLow(pDmaBuf->AllocPa, BufBasePaLow);
|
|
|
|
// link the pre-allocated TxBuf to TXD
|
|
pTxD = (PTXD_STRUC) pTxRing->Cell[index].AllocVa;
|
|
pTxD->SDPtr0 = BufBasePaLow;
|
|
// advance to next ring descriptor address
|
|
pTxD->DMADONE = 1;
|
|
RingBasePaLow += TXD_SIZE;
|
|
RingBaseVa = (PUCHAR) RingBaseVa + TXD_SIZE;
|
|
|
|
// advance to next TxBuf address
|
|
BufBasePaLow += TX_DMA_1ST_BUFFER_SIZE;
|
|
BufBaseVa = (PUCHAR) BufBaseVa + TX_DMA_1ST_BUFFER_SIZE;
|
|
}
|
|
DBGPRINT(RT_DEBUG_TRACE, ("TxRing[%d]: total %d entry allocated\n", num, index));
|
|
}
|
|
if (Status == NDIS_STATUS_RESOURCES)
|
|
break;
|
|
|
|
//
|
|
// Allocate MGMT ring descriptor's memory except Tx ring which allocated eariler
|
|
//
|
|
pAd->MgmtDescRing.AllocSize = MGMT_RING_SIZE * TXD_SIZE;
|
|
RTMP_AllocateMgmtDescMemory(
|
|
pAd,
|
|
pAd->MgmtDescRing.AllocSize,
|
|
FALSE,
|
|
&pAd->MgmtDescRing.AllocVa,
|
|
&pAd->MgmtDescRing.AllocPa);
|
|
|
|
if (pAd->MgmtDescRing.AllocVa == NULL)
|
|
{
|
|
ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
|
|
DBGPRINT_ERR(("Failed to allocate a big buffer\n"));
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
// Zero init this memory block
|
|
NdisZeroMemory(pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocSize);
|
|
|
|
// Save PA & VA for further operation
|
|
RingBasePaHigh = RTMP_GetPhysicalAddressHigh(pAd->MgmtDescRing.AllocPa);
|
|
RingBasePaLow = RTMP_GetPhysicalAddressLow (pAd->MgmtDescRing.AllocPa);
|
|
RingBaseVa = pAd->MgmtDescRing.AllocVa;
|
|
|
|
//
|
|
// Initialize MGMT Ring and associated buffer memory
|
|
//
|
|
for (index = 0; index < MGMT_RING_SIZE; index++)
|
|
{
|
|
pAd->MgmtRing.Cell[index].pNdisPacket = NULL;
|
|
pAd->MgmtRing.Cell[index].pNextNdisPacket = NULL;
|
|
// Init MGMT Ring Size, Va, Pa variables
|
|
pAd->MgmtRing.Cell[index].AllocSize = TXD_SIZE;
|
|
pAd->MgmtRing.Cell[index].AllocVa = RingBaseVa;
|
|
RTMP_SetPhysicalAddressHigh(pAd->MgmtRing.Cell[index].AllocPa, RingBasePaHigh);
|
|
RTMP_SetPhysicalAddressLow (pAd->MgmtRing.Cell[index].AllocPa, RingBasePaLow);
|
|
|
|
// Offset to next ring descriptor address
|
|
RingBasePaLow += TXD_SIZE;
|
|
RingBaseVa = (PUCHAR) RingBaseVa + TXD_SIZE;
|
|
|
|
// link the pre-allocated TxBuf to TXD
|
|
pTxD = (PTXD_STRUC) pAd->MgmtRing.Cell[index].AllocVa;
|
|
pTxD->DMADONE = 1;
|
|
|
|
// no pre-allocated buffer required in MgmtRing for scatter-gather case
|
|
}
|
|
DBGPRINT(RT_DEBUG_TRACE, ("MGMT Ring: total %d entry allocated\n", index));
|
|
|
|
//
|
|
// Allocate RX ring descriptor's memory except Tx ring which allocated eariler
|
|
//
|
|
pAd->RxDescRing.AllocSize = RX_RING_SIZE * RXD_SIZE;
|
|
RTMP_AllocateRxDescMemory(
|
|
pAd,
|
|
pAd->RxDescRing.AllocSize,
|
|
FALSE,
|
|
&pAd->RxDescRing.AllocVa,
|
|
&pAd->RxDescRing.AllocPa);
|
|
|
|
if (pAd->RxDescRing.AllocVa == NULL)
|
|
{
|
|
ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
|
|
DBGPRINT_ERR(("Failed to allocate a big buffer\n"));
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
// Zero init this memory block
|
|
NdisZeroMemory(pAd->RxDescRing.AllocVa, pAd->RxDescRing.AllocSize);
|
|
|
|
|
|
printk("RX DESC %p size = %ld\n", pAd->RxDescRing.AllocVa,
|
|
pAd->RxDescRing.AllocSize);
|
|
|
|
// Save PA & VA for further operation
|
|
RingBasePaHigh = RTMP_GetPhysicalAddressHigh(pAd->RxDescRing.AllocPa);
|
|
RingBasePaLow = RTMP_GetPhysicalAddressLow (pAd->RxDescRing.AllocPa);
|
|
RingBaseVa = pAd->RxDescRing.AllocVa;
|
|
|
|
//
|
|
// Initialize Rx Ring and associated buffer memory
|
|
//
|
|
for (index = 0; index < RX_RING_SIZE; index++)
|
|
{
|
|
// Init RX Ring Size, Va, Pa variables
|
|
pAd->RxRing.Cell[index].AllocSize = RXD_SIZE;
|
|
pAd->RxRing.Cell[index].AllocVa = RingBaseVa;
|
|
RTMP_SetPhysicalAddressHigh(pAd->RxRing.Cell[index].AllocPa, RingBasePaHigh);
|
|
RTMP_SetPhysicalAddressLow (pAd->RxRing.Cell[index].AllocPa, RingBasePaLow);
|
|
|
|
// Offset to next ring descriptor address
|
|
RingBasePaLow += RXD_SIZE;
|
|
RingBaseVa = (PUCHAR) RingBaseVa + RXD_SIZE;
|
|
|
|
// Setup Rx associated Buffer size & allocate share memory
|
|
pDmaBuf = &pAd->RxRing.Cell[index].DmaBuf;
|
|
pDmaBuf->AllocSize = RX_BUFFER_AGGRESIZE;
|
|
pPacket = RTMP_AllocateRxPacketBuffer(
|
|
pAd,
|
|
pDmaBuf->AllocSize,
|
|
FALSE,
|
|
&pDmaBuf->AllocVa,
|
|
&pDmaBuf->AllocPa);
|
|
|
|
/* keep allocated rx packet */
|
|
pAd->RxRing.Cell[index].pNdisPacket = pPacket;
|
|
|
|
// Error handling
|
|
if (pDmaBuf->AllocVa == NULL)
|
|
{
|
|
ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
|
|
DBGPRINT_ERR(("Failed to allocate RxRing's 1st buffer\n"));
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
// Zero init this memory block
|
|
NdisZeroMemory(pDmaBuf->AllocVa, pDmaBuf->AllocSize);
|
|
|
|
// Write RxD buffer address & allocated buffer length
|
|
pRxD = (PRXD_STRUC) pAd->RxRing.Cell[index].AllocVa;
|
|
pRxD->SDP0 = RTMP_GetPhysicalAddressLow(pDmaBuf->AllocPa);
|
|
pRxD->DDONE = 0;
|
|
}
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("Rx Ring: total %d entry allocated\n", index));
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
NdisZeroMemory(&pAd->FragFrame, sizeof(FRAGMENT_FRAME));
|
|
pAd->FragFrame.pFragPacket = RTMP_AllocateFragPacketBuffer(pAd, RX_BUFFER_NORMSIZE);
|
|
|
|
if (pAd->FragFrame.pFragPacket == NULL)
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
// Log error inforamtion
|
|
NdisWriteErrorLogEntry(
|
|
pAd->AdapterHandle,
|
|
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
|
|
1,
|
|
ErrorValue);
|
|
}
|
|
|
|
DBGPRINT_S(Status, ("<-- RTMPAllocTxRxRingMemory, Status=%x\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Initialize transmit data structures
|
|
|
|
Arguments:
|
|
Adapter Pointer to our adapter
|
|
|
|
Return Value:
|
|
None
|
|
|
|
IRQL = PASSIVE_LEVEL
|
|
|
|
Note:
|
|
Initialize all transmit releated private buffer, include those define
|
|
in RTMP_ADAPTER structure and all private data structures.
|
|
|
|
========================================================================
|
|
*/
|
|
VOID NICInitTxRxRingAndBacklogQueue(
|
|
IN PRTMP_ADAPTER pAd)
|
|
{
|
|
//WPDMA_GLO_CFG_STRUC GloCfg;
|
|
int i;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("<--> NICInitTxRxRingAndBacklogQueue\n"));
|
|
|
|
// Initialize all transmit related software queues
|
|
InitializeQueueHeader(&pAd->TxSwQueue[QID_AC_BE]);
|
|
InitializeQueueHeader(&pAd->TxSwQueue[QID_AC_BK]);
|
|
InitializeQueueHeader(&pAd->TxSwQueue[QID_AC_VI]);
|
|
InitializeQueueHeader(&pAd->TxSwQueue[QID_AC_VO]);
|
|
InitializeQueueHeader(&pAd->TxSwQueue[QID_HCCA]);
|
|
|
|
// Init RX Ring index pointer
|
|
pAd->RxRing.RxSwReadIdx = 0;
|
|
pAd->RxRing.RxCpuIdx = RX_RING_SIZE - 1;
|
|
|
|
// Init TX rings index pointer
|
|
for (i=0; i<NUM_OF_TX_RING; i++)
|
|
{
|
|
pAd->TxRing[i].TxSwFreeIdx = 0;
|
|
pAd->TxRing[i].TxCpuIdx = 0;
|
|
}
|
|
|
|
// init MGMT ring index pointer
|
|
pAd->MgmtRing.TxSwFreeIdx = 0;
|
|
pAd->MgmtRing.TxCpuIdx = 0;
|
|
|
|
pAd->PrivateInfo.TxRingFullCnt = 0;
|
|
}
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Reset NIC Asics. Call after rest DMA. So reset TX_CTX_IDX to zero.
|
|
|
|
Arguments:
|
|
Adapter Pointer to our adapter
|
|
|
|
Return Value:
|
|
None
|
|
|
|
IRQL = PASSIVE_LEVEL
|
|
IRQL = DISPATCH_LEVEL
|
|
|
|
Note:
|
|
Reset NIC to initial state AS IS system boot up time.
|
|
|
|
========================================================================
|
|
*/
|
|
VOID RTMPRingCleanUp(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN UCHAR RingType)
|
|
{
|
|
PTXD_STRUC pTxD;
|
|
PRXD_STRUC pRxD;
|
|
PQUEUE_ENTRY pEntry;
|
|
PNDIS_PACKET pPacket;
|
|
int i;
|
|
PRTMP_TX_RING pTxRing;
|
|
unsigned long IrqFlags;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE,("RTMPRingCleanUp(RingIdx=%d, Pending-NDIS=%ld)\n", RingType, pAd->RalinkCounters.PendingNdisPacketCount));
|
|
switch (RingType)
|
|
{
|
|
case QID_AC_BK:
|
|
case QID_AC_BE:
|
|
case QID_AC_VI:
|
|
case QID_AC_VO:
|
|
case QID_HCCA:
|
|
RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags);
|
|
pTxRing = &pAd->TxRing[RingType];
|
|
|
|
// We have to clean all descriptors in case some error happened with reset
|
|
for (i=0; i<TX_RING_SIZE; i++) // We have to scan all TX ring
|
|
{
|
|
pTxD = (PTXD_STRUC) pTxRing->Cell[i].AllocVa;
|
|
|
|
pPacket = (PNDIS_PACKET) pTxRing->Cell[i].pNdisPacket;
|
|
// release scatter-and-gather NDIS_PACKET
|
|
if (pPacket)
|
|
{
|
|
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
|
|
pTxRing->Cell[i].pNdisPacket = NULL;
|
|
}
|
|
|
|
pPacket = (PNDIS_PACKET) pTxRing->Cell[i].pNextNdisPacket;
|
|
// release scatter-and-gather NDIS_PACKET
|
|
if (pPacket)
|
|
{
|
|
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
|
|
pTxRing->Cell[i].pNextNdisPacket = NULL;
|
|
}
|
|
}
|
|
|
|
RTMP_IO_READ32(pAd, TX_DTX_IDX0 + RingType * 0x10, &pTxRing->TxDmaIdx);
|
|
pTxRing->TxSwFreeIdx = pTxRing->TxDmaIdx;
|
|
pTxRing->TxCpuIdx = pTxRing->TxDmaIdx;
|
|
RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + RingType * 0x10, pTxRing->TxCpuIdx);
|
|
|
|
RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
|
|
RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags);
|
|
while (pAd->TxSwQueue[RingType].Head != NULL)
|
|
{
|
|
pEntry = RemoveHeadQueue(&pAd->TxSwQueue[RingType]);
|
|
pPacket = QUEUE_ENTRY_TO_PACKET(pEntry);
|
|
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
|
|
DBGPRINT(RT_DEBUG_TRACE,("Release 1 NDIS packet from s/w backlog queue\n"));
|
|
}
|
|
RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
|
|
break;
|
|
|
|
case QID_MGMT:
|
|
// We have to clean all descriptors in case some error happened with reset
|
|
NdisAcquireSpinLock(&pAd->MgmtRingLock);
|
|
|
|
for (i=0; i<MGMT_RING_SIZE; i++)
|
|
{
|
|
pTxD = (PTXD_STRUC) pAd->MgmtRing.Cell[i].AllocVa;
|
|
|
|
pPacket = (PNDIS_PACKET) pAd->MgmtRing.Cell[i].pNdisPacket;
|
|
// rlease scatter-and-gather NDIS_PACKET
|
|
if (pPacket)
|
|
{
|
|
PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE);
|
|
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
|
|
}
|
|
pAd->MgmtRing.Cell[i].pNdisPacket = NULL;
|
|
|
|
pPacket = (PNDIS_PACKET) pAd->MgmtRing.Cell[i].pNextNdisPacket;
|
|
// release scatter-and-gather NDIS_PACKET
|
|
if (pPacket)
|
|
{
|
|
PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE);
|
|
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
|
|
}
|
|
pAd->MgmtRing.Cell[i].pNextNdisPacket = NULL;
|
|
|
|
}
|
|
|
|
RTMP_IO_READ32(pAd, TX_MGMTDTX_IDX, &pAd->MgmtRing.TxDmaIdx);
|
|
pAd->MgmtRing.TxSwFreeIdx = pAd->MgmtRing.TxDmaIdx;
|
|
pAd->MgmtRing.TxCpuIdx = pAd->MgmtRing.TxDmaIdx;
|
|
RTMP_IO_WRITE32(pAd, TX_MGMTCTX_IDX, pAd->MgmtRing.TxCpuIdx);
|
|
|
|
NdisReleaseSpinLock(&pAd->MgmtRingLock);
|
|
pAd->RalinkCounters.MgmtRingFullCount = 0;
|
|
break;
|
|
|
|
case QID_RX:
|
|
// We have to clean all descriptors in case some error happened with reset
|
|
NdisAcquireSpinLock(&pAd->RxRingLock);
|
|
|
|
for (i=0; i<RX_RING_SIZE; i++)
|
|
{
|
|
pRxD = (PRXD_STRUC) pAd->RxRing.Cell[i].AllocVa;
|
|
pRxD->DDONE = 0 ;
|
|
}
|
|
|
|
RTMP_IO_READ32(pAd, RX_DRX_IDX, &pAd->RxRing.RxDmaIdx);
|
|
pAd->RxRing.RxSwReadIdx = pAd->RxRing.RxDmaIdx;
|
|
pAd->RxRing.RxCpuIdx = ((pAd->RxRing.RxDmaIdx == 0) ? (RX_RING_SIZE-1) : (pAd->RxRing.RxDmaIdx-1));
|
|
RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx);
|
|
|
|
NdisReleaseSpinLock(&pAd->RxRingLock);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
NDIS_STATUS AdapterBlockAllocateMemory(
|
|
IN PVOID handle,
|
|
OUT PVOID *ppAd)
|
|
{
|
|
PPCI_DEV pci_dev;
|
|
dma_addr_t *phy_addr;
|
|
POS_COOKIE pObj = (POS_COOKIE) handle;
|
|
|
|
pci_dev = pObj->pci_dev;
|
|
phy_addr = &pObj->pAd_pa;
|
|
|
|
*ppAd = (PVOID)vmalloc(sizeof(RTMP_ADAPTER)); //pci_alloc_consistent(pci_dev, sizeof(RTMP_ADAPTER), phy_addr);
|
|
|
|
if (*ppAd)
|
|
{
|
|
NdisZeroMemory(*ppAd, sizeof(RTMP_ADAPTER));
|
|
((PRTMP_ADAPTER)*ppAd)->OS_Cookie = handle;
|
|
return (NDIS_STATUS_SUCCESS);
|
|
} else {
|
|
return (NDIS_STATUS_FAILURE);
|
|
}
|
|
}
|
|
|
|
|
|
void RTMP_AllocateTxDescMemory(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN UINT Index,
|
|
IN ULONG Length,
|
|
IN BOOLEAN Cached,
|
|
OUT PVOID *VirtualAddress,
|
|
OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress)
|
|
{
|
|
POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie;
|
|
|
|
*VirtualAddress = (PVOID)PCI_ALLOC_CONSISTENT(pObj->pci_dev,sizeof(char)*Length, PhysicalAddress);
|
|
|
|
}
|
|
|
|
void RTMP_AllocateMgmtDescMemory(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN ULONG Length,
|
|
IN BOOLEAN Cached,
|
|
OUT PVOID *VirtualAddress,
|
|
OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress)
|
|
{
|
|
POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie;
|
|
|
|
*VirtualAddress = (PVOID)PCI_ALLOC_CONSISTENT(pObj->pci_dev,sizeof(char)*Length, PhysicalAddress);
|
|
|
|
}
|
|
|
|
void RTMP_AllocateRxDescMemory(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN ULONG Length,
|
|
IN BOOLEAN Cached,
|
|
OUT PVOID *VirtualAddress,
|
|
OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress)
|
|
{
|
|
POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie;
|
|
|
|
*VirtualAddress = (PVOID)PCI_ALLOC_CONSISTENT(pObj->pci_dev,sizeof(char)*Length, PhysicalAddress);
|
|
|
|
}
|
|
|
|
void RTMP_FreeRxDescMemory(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN ULONG Length,
|
|
IN PVOID VirtualAddress,
|
|
IN NDIS_PHYSICAL_ADDRESS PhysicalAddress)
|
|
{
|
|
POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie;
|
|
|
|
PCI_FREE_CONSISTENT(pObj->pci_dev, Length, VirtualAddress, PhysicalAddress);
|
|
}
|
|
|
|
|
|
void RTMP_AllocateFirstTxBuffer(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN UINT Index,
|
|
IN ULONG Length,
|
|
IN BOOLEAN Cached,
|
|
OUT PVOID *VirtualAddress,
|
|
OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress)
|
|
{
|
|
POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie;
|
|
|
|
*VirtualAddress = (PVOID)PCI_ALLOC_CONSISTENT(pObj->pci_dev,sizeof(char)*Length, PhysicalAddress);
|
|
}
|
|
|
|
/*
|
|
* FUNCTION: Allocate a common buffer for DMA
|
|
* ARGUMENTS:
|
|
* AdapterHandle: AdapterHandle
|
|
* Length: Number of bytes to allocate
|
|
* Cached: Whether or not the memory can be cached
|
|
* VirtualAddress: Pointer to memory is returned here
|
|
* PhysicalAddress: Physical address corresponding to virtual address
|
|
*/
|
|
|
|
void RTMP_AllocateSharedMemory(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN ULONG Length,
|
|
IN BOOLEAN Cached,
|
|
OUT PVOID *VirtualAddress,
|
|
OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress)
|
|
{
|
|
POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie;
|
|
|
|
*VirtualAddress = (PVOID)PCI_ALLOC_CONSISTENT(pObj->pci_dev,sizeof(char)*Length, PhysicalAddress);
|
|
}
|
|
|
|
VOID RTMPFreeTxRxRingMemory(
|
|
IN PRTMP_ADAPTER pAd)
|
|
{
|
|
int index, num , j;
|
|
PRTMP_TX_RING pTxRing;
|
|
PTXD_STRUC pTxD;
|
|
PNDIS_PACKET pPacket;
|
|
unsigned int IrqFlags;
|
|
|
|
POS_COOKIE pObj =(POS_COOKIE) pAd->OS_Cookie;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("--> RTMPFreeTxRxRingMemory\n"));
|
|
|
|
// Free TxSwQueue Packet
|
|
for (index=0; index <NUM_OF_TX_RING; index++)
|
|
{
|
|
PQUEUE_ENTRY pEntry;
|
|
PNDIS_PACKET pPacket;
|
|
PQUEUE_HEADER pQueue;
|
|
|
|
RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags);
|
|
pQueue = &pAd->TxSwQueue[index];
|
|
while (pQueue->Head)
|
|
{
|
|
pEntry = RemoveHeadQueue(pQueue);
|
|
pPacket = QUEUE_ENTRY_TO_PACKET(pEntry);
|
|
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
|
|
}
|
|
RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
|
|
}
|
|
|
|
// Free Tx Ring Packet
|
|
for (index=0;index< NUM_OF_TX_RING;index++)
|
|
{
|
|
pTxRing = &pAd->TxRing[index];
|
|
|
|
for (j=0; j< TX_RING_SIZE; j++)
|
|
{
|
|
pTxD = (PTXD_STRUC) (pTxRing->Cell[j].AllocVa);
|
|
pPacket = pTxRing->Cell[j].pNdisPacket;
|
|
|
|
if (pPacket)
|
|
{
|
|
PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE);
|
|
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS);
|
|
}
|
|
//Always assign pNdisPacket as NULL after clear
|
|
pTxRing->Cell[j].pNdisPacket = NULL;
|
|
|
|
pPacket = pTxRing->Cell[j].pNextNdisPacket;
|
|
|
|
if (pPacket)
|
|
{
|
|
PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE);
|
|
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS);
|
|
}
|
|
//Always assign pNextNdisPacket as NULL after clear
|
|
pTxRing->Cell[pTxRing->TxSwFreeIdx].pNextNdisPacket = NULL;
|
|
|
|
}
|
|
}
|
|
|
|
for (index = RX_RING_SIZE - 1 ; index >= 0; index--)
|
|
{
|
|
if ((pAd->RxRing.Cell[index].DmaBuf.AllocVa) && (pAd->RxRing.Cell[index].pNdisPacket))
|
|
{
|
|
PCI_UNMAP_SINGLE(pObj->pci_dev, pAd->RxRing.Cell[index].DmaBuf.AllocPa, pAd->RxRing.Cell[index].DmaBuf.AllocSize, PCI_DMA_FROMDEVICE);
|
|
RELEASE_NDIS_PACKET(pAd, pAd->RxRing.Cell[index].pNdisPacket, NDIS_STATUS_SUCCESS);
|
|
}
|
|
}
|
|
NdisZeroMemory(pAd->RxRing.Cell, RX_RING_SIZE * sizeof(RTMP_DMACB));
|
|
|
|
if (pAd->RxDescRing.AllocVa)
|
|
{
|
|
PCI_FREE_CONSISTENT(pObj->pci_dev, pAd->RxDescRing.AllocSize, pAd->RxDescRing.AllocVa, pAd->RxDescRing.AllocPa);
|
|
}
|
|
NdisZeroMemory(&pAd->RxDescRing, sizeof(RTMP_DMABUF));
|
|
|
|
if (pAd->MgmtDescRing.AllocVa)
|
|
{
|
|
PCI_FREE_CONSISTENT(pObj->pci_dev, pAd->MgmtDescRing.AllocSize, pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocPa);
|
|
}
|
|
NdisZeroMemory(&pAd->MgmtDescRing, sizeof(RTMP_DMABUF));
|
|
|
|
for (num = 0; num < NUM_OF_TX_RING; num++)
|
|
{
|
|
if (pAd->TxBufSpace[num].AllocVa)
|
|
{
|
|
PCI_FREE_CONSISTENT(pObj->pci_dev, pAd->TxBufSpace[num].AllocSize, pAd->TxBufSpace[num].AllocVa, pAd->TxBufSpace[num].AllocPa);
|
|
}
|
|
NdisZeroMemory(&pAd->TxBufSpace[num], sizeof(RTMP_DMABUF));
|
|
|
|
if (pAd->TxDescRing[num].AllocVa)
|
|
{
|
|
PCI_FREE_CONSISTENT(pObj->pci_dev, pAd->TxDescRing[num].AllocSize, pAd->TxDescRing[num].AllocVa, pAd->TxDescRing[num].AllocPa);
|
|
}
|
|
NdisZeroMemory(&pAd->TxDescRing[num], sizeof(RTMP_DMABUF));
|
|
}
|
|
|
|
if (pAd->FragFrame.pFragPacket)
|
|
RELEASE_NDIS_PACKET(pAd, pAd->FragFrame.pFragPacket, NDIS_STATUS_SUCCESS);
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("<-- RTMPFreeTxRxRingMemory\n"));
|
|
}
|
|
|
|
|
|
/*
|
|
* FUNCTION: Allocate a packet buffer for DMA
|
|
* ARGUMENTS:
|
|
* AdapterHandle: AdapterHandle
|
|
* Length: Number of bytes to allocate
|
|
* Cached: Whether or not the memory can be cached
|
|
* VirtualAddress: Pointer to memory is returned here
|
|
* PhysicalAddress: Physical address corresponding to virtual address
|
|
* Notes:
|
|
* Cached is ignored: always cached memory
|
|
*/
|
|
PNDIS_PACKET RTMP_AllocateRxPacketBuffer(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN ULONG Length,
|
|
IN BOOLEAN Cached,
|
|
OUT PVOID *VirtualAddress,
|
|
OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress)
|
|
{
|
|
PNDIS_PACKET pkt;
|
|
|
|
pkt = RTPKT_TO_OSPKT(DEV_ALLOC_SKB(Length));
|
|
|
|
if (pkt == NULL) {
|
|
DBGPRINT(RT_DEBUG_ERROR, ("can't allocate rx %ld size packet\n",Length));
|
|
}
|
|
|
|
if (pkt) {
|
|
RTMP_SET_PACKET_SOURCE(pkt, PKTSRC_NDIS);
|
|
*VirtualAddress = (PVOID) RTPKT_TO_OSPKT(pkt)->data;
|
|
*PhysicalAddress = PCI_MAP_SINGLE(pAd, *VirtualAddress, Length, -1, PCI_DMA_FROMDEVICE);
|
|
} else {
|
|
*VirtualAddress = (PVOID) NULL;
|
|
*PhysicalAddress = (NDIS_PHYSICAL_ADDRESS) NULL;
|
|
}
|
|
|
|
return (PNDIS_PACKET) pkt;
|
|
}
|
|
|
|
|
|
VOID Invalid_Remaining_Packet(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN ULONG VirtualAddress)
|
|
{
|
|
NDIS_PHYSICAL_ADDRESS PhysicalAddress;
|
|
|
|
PhysicalAddress = PCI_MAP_SINGLE(pAd, (void *)(VirtualAddress+1600), RX_BUFFER_NORMSIZE-1600, -1, PCI_DMA_FROMDEVICE);
|
|
}
|
|
|
|
PNDIS_PACKET GetPacketFromRxRing(
|
|
IN PRTMP_ADAPTER pAd,
|
|
OUT PRT28XX_RXD_STRUC pSaveRxD,
|
|
OUT BOOLEAN *pbReschedule,
|
|
IN OUT UINT32 *pRxPending)
|
|
{
|
|
PRXD_STRUC pRxD;
|
|
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;
|
|
|
|
}
|
|
|
|
// Point to Rx indexed rx ring descriptor
|
|
pRxD = (PRXD_STRUC) pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx].AllocVa;
|
|
|
|
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
|
|
{
|
|
//printk("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
|
|
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;
|
|
}
|
|
/* End of 2860_rtmp_init.c */
|
|
|