📄 mpltransmit.c
字号:
//******************************************************************************
//
// MPLTRANSMIT.C
//
// Copyright (c) 2004 National Semiconductor Corporation.
// All Rights Reserved
//
// MPL Transmit Engine.
//
// This file contains the API implementations for
// o MPL transmit engine configuration
// o MPL packet transmit and completion handlers
// o Transmit engine reset
//
//******************************************************************************
#include <mplinternal.h>
// Local helful debug macros
#undef ENTER
#undef EXIT
#undef ASSERT
#undef PRINT
#undef PRINTI
#undef PRINTS
#undef TBREAK
#define ENTER(fn) MPL_CENTER(DZONE_MPL_TRANS, fn)
#define EXIT(fn) MPL_CEXIT(DZONE_MPL_TRANS, fn)
#define ASSERT(le) MPL_CASSERT(DZONE_MPL_TRANS, le)
#define PRINT(fmt) MPL_CTRACE(DZONE_MPL_TRANS, fmt)
#define PRINTI(v) MPL_CTRACE(DZONE_MPL_TRANS, (" "#v": %x \n",(NS_UINT)(v)))
#define PRINTS(v) MPL_CTRACE(DZONE_MPL_TRANS, (" "#v": %s \n", v))
#define TBREAK(fmt) MPL_CTRACEBREAK(DZONE_MPL_TRANS, fmt)
// Locals
static NS_VOID setTxCfg(MPL_CONTEXT *pMplCtx,MPL_TRANSMIT_CFG *pCfgTransmit);
static MPL_STATUS allocTxdRing(MPL_CONTEXT *pMplCtx);
static NS_VOID setupTxdRing(MPL_CONTEXT *pMplCtx);
//*****************************************************************************
// MplTransmitCfg
// Configures the transmit engine on the device.
//
// Parameters
// pMplHandle
// MPL device handle returned following a call to MplInitialize
// pCfgTransmit
// Pointer to a caller allocated MPL_TRANSMIT_CFG structure with
// configuration values for the transmit engine
//
// Return Value
// NS_STATUS_SUCCESS
// The configurations were successfully applied
// NS_STATUS_INVALID_PARM
// An invalid parameter value was detected
// NS_STATUS_RESOURCES
// Failed to allocate required resources
//
//*****************************************************************************
MPL_STATUS
MplTransmitCfg (
IN NS_VOID *pMplHandle,
IN MPL_TRANSMIT_CFG *pCfgTransmit
)
{
MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
NS_UINT8 i;
NS_UINT32 regVal;
// FM: Assert for pCfgTransmit == NULL
ENTER(MplTransmitCfg);
// Configure FIFO and DMA if client desires
if (pCfgTransmit->cfgFlags & MPL_TRANSMIT_CFG_FIFO)
{
// Validate the FIFO thresholds and DMA burst size
if ((pCfgTransmit->fillThreshold < pMplCtx->caps.txCaps.minFill) ||
(pCfgTransmit->drainThreshold < pMplCtx->caps.txCaps.minDrain) ||
((pCfgTransmit->fillThreshold + pCfgTransmit->drainThreshold) >
pMplCtx->caps.txCaps.fifoSize) ||
(pCfgTransmit->maxDmaBurst > pMplCtx->caps.txCaps.maxDma) ||
(pCfgTransmit->maxDmaBurst > pCfgTransmit->fillThreshold))
{
EXIT(MplTransmitCfg);
return NS_STATUS_INVALID_PARM;
}
// Notify the hardware about the FIFO thresholds and DMA burst
setTxCfg(pMplCtx, pCfgTransmit);
}
// Configure Tx queues if client desires
if (pCfgTransmit->cfgFlags & MPL_TRANSMIT_CFG_QUEUES)
{
// Validate the priority queue count - should be atleast 1!
if (pCfgTransmit->priorityQueueCnt > pMplCtx->caps.txCaps.priorityQCnt)
{
EXIT(MplTransmitCfg);
return NS_STATUS_INVALID_PARM;
}
// If this is a runtime reconfiguration request, then free the old ring
if (pMplCtx->txDescCnt)
{
freeTxdRing(pMplCtx);
}
// Get the Txd count - for all enabled queues
pMplCtx->txQueueCnt = pCfgTransmit->priorityQueueCnt;
for (i = 0x0; i < pMplCtx->txQueueCnt; i++)
{
pMplCtx->txQueue[i].descCnt = pCfgTransmit->descCnt[i]; //per queue
pMplCtx->txDescCnt += pCfgTransmit->descCnt[i];
}
// Note max transmit done indications to be passed to NSM in one pass
pMplCtx->maxTxDones = pCfgTransmit->maxIndications;
// Allocate Txd ring
if (allocTxdRing(pMplCtx) != NS_STATUS_SUCCESS)
{
EXIT(MplTransmitCfg);
return NS_STATUS_RESOURCES;
}
// Setup Txd ring
setupTxdRing(pMplCtx);
// Enable priority Queuing if more than one Tx queue is requested
if (pMplCtx->txQueueCnt > 0x01)
{
regVal = MPL_READ32(pMplCtx, PQCR);;
regVal |= TXPRIOQ_EN;
// Check if caller requests round-robin scheme for queue scheduling
if (pCfgTransmit->cfgFlags & MPL_TRANSMIT_CFG_QUEUE_RR)
regVal |= ROTPRIO_EN;
MPL_WRITE32(pMplCtx, PQCR, regVal);
}
// Notify the device about the head node on the ring
MPL_WRITE32(pMplCtx, TXDP, pMplCtx->txQueue[0].ringPA);
MPL_WRITE32(pMplCtx, TXDP1, pMplCtx->txQueue[1].ringPA);
MPL_WRITE32(pMplCtx, TXDP2, pMplCtx->txQueue[2].ringPA);
MPL_WRITE32(pMplCtx, TXDP3, pMplCtx->txQueue[3].ringPA);
}
EXIT(MplTransmitCfg);
return NS_STATUS_SUCCESS; // All done
}
//*****************************************************************************
// MplTransmitGetFreeDesc
// Returns the total free transmit descriptors currently available.
//
// Parameters
// pMplHandle
// MPL device handle returned following a call to MplInitialize
// pQueue
// Queue (1,2...max tx queues) from which the free count is desired
// pTxdCnt
// Pointer to a caller allocated fields in which the count of free
// transmit descriptors is returned
//
// Return Value
// NS_STATUS_SUCCESS
// The count was successfully returned.
// NS_STATUS_INVALID_PARM
// The priority queue count is invalid
//
//*****************************************************************************
MPL_STATUS
MplTransmitGetFreeDesc (
IN NS_VOID *pMplHandle,
IN NS_UINT8 pQueue,
OUT NS_UINT *pTxdCnt
)
{
MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
ENTER(MplTransmitGetFreeDesc);
// Validate the pQueue number
if (pQueue > pMplCtx->txQueueCnt)
{
EXIT(MplTransmitGetFreeDesc);
return NS_STATUS_INVALID_PARM;
}
// Get the free Txd count - Note we always hold one for ring termination
*pTxdCnt = (pMplCtx->txQueue[pQueue-1].descCnt - 1) -
(pMplCtx->txQueue[pQueue-1].curr - pMplCtx->txQueue[pQueue-1].dirty);
EXIT(MplTransmitGetFreeDesc);
return NS_STATUS_SUCCESS;
}
//*****************************************************************************
// MplTransmit
// Queues up one or more packets for transmission by the device.
// NOTE: This function is non-reentrant with respect to itself,
// MplTransmitReset and MplTransmitDone
//
// Parameters
// pMplHandle
// MPL device handle returned following a call to MplInitialize
// pktCount
// The count of packets being queued for transmission
// pPacket
// Pointer to a list of MPL_PKT structures due for transmission
//
// Return Value
// NS_STATUS_SUCCESS
// All packets were successfully queued up for transmission
// NS_STATUS_FAILURE
// One or more of the packets where unacceptable for transmission
// Clients need to check the status of each packet to detemine
// which one failed,
//
// Per packet status (pPacket->packetStatus) is one of
// NS_STATUS_INVALID_PARM
// The priority queue count is invalid
// NS_STATUS_RESOURCES
// Failed to allocate the required resources (Txds)
//
//*****************************************************************************
MPL_STATUS
MplTransmit (
IN NS_VOID *pMplHandle,
IN NS_UINT pktCount,
IN MPL_PKT *pPacket
)
{
MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
MPL_STATUS status = NS_STATUS_SUCCESS;
MPL_DESC *currTxd, *firstTxd;
MPL_PKT_FRAG *pFrag;
NS_UINT8 priQSel = 0x0, pQueue;
NS_UINT i, entry, fragIndex, cmdSts, csFlag, txdAvail;
ENTER(MplTransmit);
// Send each packet
for (i = 0x0; i < pktCount; i++)
{
// Get the priority queue number and validate
if ((pPacket->txOOB.pQueue > pMplCtx->txQueueCnt) ||
(pPacket->txOOB.pQueue < 0x1))
{
// Invalid Tx Q
pPacket->packetStatus = NS_STATUS_INVALID_PARM;
status = NS_STATUS_FAILURE;
continue; // To Next Pkt
}
// Set the priority queue select
pQueue = pPacket->txOOB.pQueue - 1;
// Get available Txd count
txdAvail = (pMplCtx->txQueue[pQueue].descCnt - 1) -
(pMplCtx->txQueue[pQueue].curr -
pMplCtx->txQueue[pQueue].dirty);
// Check availability - Each fragment needs a Txd
if (txdAvail < pPacket->fragCount)
{
pPacket->packetStatus = NS_STATUS_RESOURCES;
status = NS_STATUS_FAILURE;
continue; // To Next Pkt - Maybe it is on a diff Tx-Q
}
// Set the priority queue select
priQSel |= 1 << pQueue;
// Get the first Txd for this packet
entry = pMplCtx->txQueue[pQueue].curr % pMplCtx->txQueue[pQueue].descCnt;
firstTxd = &pMplCtx->txQueue[pQueue].pRing[entry];
// When dealing with multiple Txds per packet, the first Txd will
// have its OWN bit set last (to avoid Tx underruns)
csFlag = CS_INTR;
#ifdef MPL_TASK_VLAN
// If we are in VLAN per-pkt tag insertion mode then include the tag
if (pMplCtx->taskVlan.cfg & MPL_TASK_VLAN_PERPACKET)
{
firstTxd->extCtlSts = MPL_HTOL32(pPacket->txOOB.extCtl);
}
else
{
firstTxd->extCtlSts = 0x0; // Clear
}
#endif
// Get the frag head
pFrag = pPacket->pFragHead;
fragIndex = 0x0;
// Process each fragment
currTxd = firstTxd;
while (fragIndex < pPacket->fragCount)
{
// Check fragSize to be within max allowed
if (pFrag->fragSize > CS_MAX_FRAG_SIZE)
{
pPacket->packetStatus = NS_STATUS_INVALID_PARM;
status = NS_STATUS_FAILURE;
break; // Go to next packet
}
// Set the buffer length and buffer phy address
currTxd->bufptrPA = MPL_ADDR_HTOL(pFrag->physAddr);
cmdSts = pFrag->fragSize; // Swapped later
// Copy the physical addr of Txd - for diag mode operations only
pFrag->pMplPrivate = (NS_VOID *)(pMplCtx->txQueue[pQueue].ringPA +
(entry * sizeof(MPL_DESC)));
// Increment the frag count and check if this is the last fragment
if (++fragIndex < pPacket->fragCount)
{
PRINT(("Multi Txd? %d\n", pPacket->fragCount));
// More frags to go
// Set MORE on the current Txd
currTxd->cmdSts = MPL_HTOL32(cmdSts | csFlag | CS_MORE);
// Get the next Txd in the reserved order
entry = (entry + 1) % pMplCtx->txQueue[pQueue].descCnt;
currTxd = &pMplCtx->txQueue[pQueue].pRing[entry];
// All further fragments will have its OWN bit set
// Note: See the OWN bit for first fragment above
csFlag = CS_OWN_INTR;
// Move on to the next fragment
pFrag = pFrag->pNextFrag;
}
else
{
// Last frag
// Note the Client Handle in this last Txd
currTxd->mplPriv = pPacket->pNsmPrivate;
// Set OWN, no MORE
currTxd->cmdSts = MPL_HTOL32(cmdSts | CS_OWN_INTR);
// For cases with MPL_PKT having multiple fragments we need to
// hit the OWN bit for the first Txd - See notes above
if (currTxd != firstTxd)
{
firstTxd->cmdSts |= CS_OWN_ES;
}
// Move free Txd index
pMplCtx->txQueue[pQueue].curr += pPacket->fragCount;
// Note the status
pPacket->packetStatus = NS_STATUS_SUCCESS;
}
}
// Get the next packet
pPacket = pPacket->pNextPacket;
}
// FM: Evaulate if we should hit TXE per packet or a set of packets
MPL_WRITE32(pMplCtx, CR, (priQSel << TX_PQUEUE_OFF) | TX_EN);
EXIT(MplTransmit);
return status;
}
//*****************************************************************************
// MplTransmitDone
// Processes transmit engine related events.
// NOTE: This function is non-reentrant with respect to itself,
// MplTransmitReset and MplTransmit
//
// Parameters
// pMplHandle
// MPL device handle returned following a call to MplInitialize
// maxEvents
// The maximum transmit engine related events (e.g. transmit complete)
// that MPL should process before returning back to the caller.
//
// Return Value
// NS_STATUS_SUCCESS
// The transmit event was successfully handled.
// NS_STATUS_ABORTED
// The processing was aborted since the maximum event count specified
// was met.
//
//*****************************************************************************
MPL_STATUS
MplTransmitDone (
IN NS_VOID *pMplHandle,
IN NS_UINT maxEvents
)
{
MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
MPL_STATUS status = NS_STATUS_SUCCESS;
MPL_DESC *currTxd;
NS_UINT8 pQueue, qNum;
NS_UINT priQSel, entry, pktCnt = 0x0, evtCnt = 0x0;
ENTER(MplTransmitDone);
// Get the Priority Queues that have completion events
if (pMplCtx->txQueueCnt > 1)
{
priQSel = (pMplCtx->isrReg & TXDESC_MASK) >> TXDESC_OFF;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -