📄 mplreceive.c
字号:
//******************************************************************************
//
// MPLRECEIVE.C
//
// Copyright (c) 2004 National Semiconductor Corporation.
// All Rights Reserved
//
// MPL Receive engine.
//
// This file contains the API implementations for
// o MPL receive engine configuration
// o MPL packet reception and completion handlers
// o Receive engine filter configuration
//
//******************************************************************************
#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_RECV, fn)
#define EXIT(fn) MPL_CEXIT(DZONE_MPL_RECV, fn)
#define ASSERT(le) MPL_CASSERT(DZONE_MPL_RECV, le)
#define PRINT(fmt) MPL_CTRACE(DZONE_MPL_RECV, fmt)
#define PRINTI(v) MPL_CTRACE(DZONE_MPL_RECV, (" "#v": %x \n",(NS_UINT)(v)))
#define PRINTS(v) MPL_CTRACE(DZONE_MPL_RECV, (" "#v": %s \n", v))
#define TBREAK(fmt) MPL_CTRACEBREAK(DZONE_MPL_RECV, fmt)
// Locals
static NS_VOID setRxCfg(MPL_CONTEXT *pMplCtx, MPL_RECEIVE_CFG *pCfgReceive);
static MPL_STATUS allocRxdRing(MPL_CONTEXT *pMplCtx);
static NS_VOID setupRxdRing(MPL_CONTEXT *pMplCtx);
//*****************************************************************************
// MplReceiveCfg
// Configures the receive engine on the device.
//
// Parameters
// pMplHandle
// MPL device handle returned following a call to MplInitialize
// pCfgReceive
// Pointer to a caller allocated MPL_RECEIVE_CFG structure with
// configuration values for the receive engine
//
// Return Value
// NS_STATUS_SUCCESS
// The configurations were successfully applied
// NS_STATUS_INVALID_PARM
// An invalid parameter value was detected
//
//*****************************************************************************
MPL_STATUS
MplReceiveCfg (
IN NS_VOID *pMplHandle,
IN MPL_RECEIVE_CFG *pCfgReceive
)
{
MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
ENTER(MplReceiveCfg);
// FM: Assert for pCfgReceive == NULL
// Configure FIFO and DMA if client desires
if (pCfgReceive->cfgFlags & MPL_RECEIVE_CFG_FIFO)
{
// Validate the FIFO thresholds and DMA burst size
if ((pCfgReceive->drainThreshold < pMplCtx->caps.rxCaps.minDrain) ||
(pCfgReceive->maxDmaBurst > pMplCtx->caps.rxCaps.maxDma))
{
EXIT(MplReceiveCfg);
return NS_STATUS_INVALID_PARM;
}
// Notify the hardware about the FIFO thresholds and DMA burst
setRxCfg(pMplCtx, pCfgReceive);
}
// Configure Rx queues if client desires
if (pCfgReceive->cfgFlags & MPL_RECEIVE_CFG_QUEUES)
{
// Validate the priority queue count
if (pCfgReceive->priorityQueueCnt > pMplCtx->caps.rxCaps.priorityQCnt)
{
EXIT(MplReceiveCfg);
return NS_STATUS_INVALID_PARM;
}
// If this is a runtime reconfiguration request, then free the old ring
if (pMplCtx->rxDescCnt)
{
freeRxdRing(pMplCtx);
}
// Get the Rxd count - Only one Rx queue
pMplCtx->rxQueue.descCnt = pCfgReceive->descCnt[0x0];
pMplCtx->rxDescCnt = pCfgReceive->descCnt[0x0];
// Note max receive done indications to be passed to NSM in one pass
pMplCtx->maxRxDones = pCfgReceive->maxIndications;
// Allocate Rxd ring
if (allocRxdRing(pMplCtx) != NS_STATUS_SUCCESS)
{
EXIT(MplReceiveCfg);
return NS_STATUS_RESOURCES;
}
// Setup Rxd ring
setupRxdRing(pMplCtx);
// Notify the device about the head node on the ring
MPL_WRITE32(pMplCtx, RXDP, pMplCtx->rxQueue.ringPA);
}
EXIT(MplReceiveCfg);
return NS_STATUS_SUCCESS; // All done
}
//*****************************************************************************
// MplReceiveSetFilter
// MplReceiveSetFilter enables receive filters on the device.
//
// Parameters
// pMplHandle
// MPL device handle returned following a call to MplInitialize
// filterFlag
// Bit-map of receiver filter types that need to be enabled on the
// device
// Note: This function overwrites all previous filter settings and
// sets the device's behavior to that of the filterFlag passed to it.
//
// Return Value
// NS_STATUS_SUCCESS
// The filter configurations were successfully applied
// NS_STATUS_NOT_SUPPORTED
// The device did not support one or more filters
//
//*****************************************************************************
MPL_STATUS
MplReceiveSetFilter (
IN NS_VOID *pMplHandle,
IN NS_UINT filterFlag
)
{
MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
NS_UINT32 fltrRegSetting = 0x0, regVal;
ENTER(MplReceiveSetFilter);
// Check for Promiscuous Mode
if (filterFlag & MPL_RECEIVE_FILTER_PROMISCUOUS_MODE)
{
fltrRegSetting |= (ACCEPT_ALLBCAST | ACCEPT_ALLMCAST | ACCEPT_ALLUNICAST);
}
else
{
// Various individual filters
if (filterFlag & MPL_RECEIVE_FILTER_ACCEPTALL_BROADCAST)
{
fltrRegSetting |= ACCEPT_ALLBCAST;
}
if (filterFlag & MPL_RECEIVE_FILTER_ACCEPTALL_MCAST)
{
fltrRegSetting |= ACCEPT_ALLMCAST;
}
if (filterFlag & MPL_RECEIVE_FILTER_ACCEPTALL_UNICAST)
{
fltrRegSetting |= ACCEPT_ALLUNICAST;
}
if (filterFlag & MPL_RECEIVE_FILTER_ACCEPTALL_ARP)
{
fltrRegSetting |= ACCEPT_ALLARP;
}
if (filterFlag & MPL_RECEIVE_FILTER_DIRECTED_UNICAST)
{
fltrRegSetting |= ACCEPT_PERFECTMATCH;
}
if (filterFlag & MPL_RECEIVE_FILTER_DIRECTED_MCAST)
{
fltrRegSetting |= MCASTHASH_EN;
}
}
// Disable Rx Filter - Before changing it
regVal = MPL_READ32(pMplCtx, RFCR);
MPL_WRITE32(pMplCtx, RFCR, regVal & ~RXFLTR_EN);
regVal &= (~(ACCEPT_ALLBCAST | ACCEPT_ALLMCAST | ACCEPT_ALLUNICAST
| ACCEPT_ALLARP | ACCEPT_PERFECTMATCH));
regVal |= (fltrRegSetting | RXFLTR_EN);
MPL_WRITE32(pMplCtx, RFCR, regVal);
// In Promiscuous or Accept Err mode - Enable acceptance of runts, CRC err,
// FAE, in-range-length errors
// Acceptance of long packets depends on the MTU size and NSM's ablility to
// provide larger buffers etc. - So this function does not deal with it.
// NSM can call MplCfgMTU to accept Long packets
regVal = MPL_READ32(pMplCtx, RXCFG);
if ((filterFlag & MPL_RECEIVE_FILTER_ERROREDPKTS) ||
(filterFlag & MPL_RECEIVE_FILTER_PROMISCUOUS_MODE))
{
regVal |= (ACCEPT_CRCALIGNERR | ACCEPT_RUNTS | ACCEPT_INRNG_LENERR);
}
else
{
// Clear all Err acceptance
regVal &= (~(ACCEPT_CRCALIGNERR | ACCEPT_RUNTS | ACCEPT_INRNG_LENERR));
}
MPL_WRITE32(pMplCtx, RXCFG, regVal);
EXIT(MplReceiveSetFilter);
return NS_STATUS_SUCCESS;
}
//*****************************************************************************
// MplReceive
// Handles the packet reception event and moves the received packet from
// the device to the host.
//
// Parameters
// pMplHandle
// MPL device handle returned following a call to MplInitialize
// maxEvents
// The maximum receive engine related events (e.g. receive complete)
// that MPL should process before returning back to the caller.
// pBufFragConsumed
// A caller supplied pointer variable in which this function returns the
// number of buffer fragments that were consumed while processing this
// receive pass.
//
// Return Value
// NS_STATUS_SUCCESS
// The receive events were successfully processed.
// NS_STATUS_ABORTED
// The processing was aborted since the maximum event count specified
// was met.
//
//*****************************************************************************
MPL_STATUS
MplReceive (
IN NS_VOID *pMplHandle,
IN NS_UINT maxEvents,
OUT NS_UINT *pBufFragConsumed
)
{
MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
NS_UINT entry, pendRxds, evtCnt = 0x0, pktCnt = 0x0;
NS_UINT32 cmdSts = 0x0;
MPL_PKT_FRAG *currFrag;
MPL_DESC *currRxd;
MPL_STATUS status = NS_STATUS_SUCCESS;
ENTER(MplReceive);
// Get the starting Rxd and number of Rxds to process
entry = pMplCtx->rxQueue.curr % pMplCtx->rxQueue.descCnt;
currRxd = &pMplCtx->rxQueue.pRing[entry];
pendRxds = pMplCtx->rxQueue.dirty + pMplCtx->rxQueue.descCnt
- pMplCtx->rxQueue.curr;
*pBufFragConsumed = 0x0;
// Process the Rxd ring - We break once all pending Rxds are processed or
// the maxEvents are processed
while ((currRxd->cmdSts & CS_OWN_ES) && (pendRxds--))
{
// The software now owns this Rxd
cmdSts = MPL_LTOH32(currRxd->cmdSts);
// Check if we reached limit
if ((maxEvents != 0x0) && (evtCnt >= maxEvents))
{
status = NS_STATUS_ABORTED;
break;
}
// Get the frag ptr
currFrag = (MPL_PKT_FRAG *)currRxd->mplPriv;
// Copy the physical addr of Rxd - for diag mode operations only
currFrag->pMplPrivate = (NS_VOID *)(pMplCtx->rxQueue.ringPA +
(entry * sizeof(MPL_DESC)));
// Setup reference ptr to handle situations where a packet spans
// into multiple Rxds, and we need to link them all up
if (pMplCtx->rxQueue.pFragHead == NULL)
{
pMplCtx->rxQueue.pFragHead = currFrag; // Head frag
}
else
{
pMplCtx->rxQueue.pFragTail->pNextFrag = currFrag; // Tail Frag
}
pMplCtx->rxQueue.fragCnt++;
// Accumulate the frag sizes
currFrag->fragSize = cmdSts & CS_LEN_MASK;
pMplCtx->rxQueue.packetSize += currFrag->fragSize;
// Check if this packet has more Rxds coming
if (cmdSts & CS_MORE)
{
PRINT(("Multi Rxd cmdSts = %x \n", (NS_UINT)cmdSts));
// Add to the tail of pending list
pMplCtx->rxQueue.pFragTail = currFrag;
}
else
{
// We have all Rxd frags for this pkt - Prepare a indication
*pBufFragConsumed += pMplCtx->rxQueue.fragCnt;
currFrag->pNextFrag = NULL; // End list
pMplCtx->rxDone[pktCnt].fragCount = pMplCtx->rxQueue.fragCnt;
pMplCtx->rxDone[pktCnt].pFragHead = pMplCtx->rxQueue.pFragHead;
pMplCtx->rxDone[pktCnt].rxOOB.cmdSts = cmdSts;
pMplCtx->rxDone[pktCnt].packetSize = pMplCtx->rxQueue.packetSize;
#ifdef MPL_TASK_VLAN
// If VLAN is enabled then get the extended status
pMplCtx->rxDone[pktCnt].rxOOB.extSts = MPL_LTOH32(currRxd->extCtlSts);
#endif
if (cmdSts & CS_OK)
{
pMplCtx->rxDone[pktCnt].packetStatus = NS_STATUS_SUCCESS;
}
else
{
// PacketQry APIs return more details on the error
pMplCtx->rxDone[pktCnt].packetStatus = NS_STATUS_FAILURE;
}
// Increment pkt count
pktCnt++;
// Check if it is time to report to NSM
if (pktCnt >= pMplCtx->maxRxDones)
{
NsmReceive(pMplCtx->pClientHandle, pktCnt, pMplCtx->rxDone);
pktCnt = 0x0;
}
// Clean up partial tracker
pMplCtx->rxQueue.pFragHead = pMplCtx->rxQueue.pFragTail = NULL;
pMplCtx->rxQueue.fragCnt = pMplCtx->rxQueue.packetSize = 0x0 ;
// FM : Define event.. Is it per pkt or per processed Rxd?
// Below it is defined as per packet
evtCnt++;
}
// Get the next Rxd and Read its cmdSts
entry = (++pMplCtx->rxQueue.curr) % pMplCtx->rxQueue.descCnt;
currRxd = &pMplCtx->rxQueue.pRing[entry];
}
// Report remaining completed packets to NSM
if (pktCnt > 0x0)
{
NsmReceive(pMplCtx->pClientHandle, pktCnt, pMplCtx->rxDone);
}
EXIT(MplReceive);
return status;
}
//*****************************************************************************
// MplReceiveReplenish
// Restock the MPL receive engine with fresh buffers for packet reception.
//
// Parameters
// pMplHandle
// MPL device handle returned following a call to MplInitialize.
// bufFragCount
// Number of buffer fragments being replenished.
// pFragList
// Pointer to a caller supplied variable of type MPL_PKT_FRAG pointing
// to the head node of the buffer fragment list being replenished.
// If all the buffer fragments were not consumed by MPL then the
// pointer to the first unused fragment is returned back to NSM.
//
// Return Value
// NS_STATUS_SUCCESS
// The buffers were successfully replenished.
//
//*****************************************************************************
MPL_STATUS
MplReceiveReplenish (
IN NS_VOID *pMplHandle,
IN NS_UINT bufFragCount,
IN OUT MPL_PKT_FRAG **pFragList
)
{
MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
MPL_PKT_FRAG *currFrag;
MPL_DESC *currRxd;
NS_UINT entry;
ENTER(MplReceiveReplenish);
// Loop through the Rxd ring filling it up with new buffers
currFrag = *pFragList;
for (;bufFragCount && (pMplCtx->rxQueue.curr - pMplCtx->rxQueue.dirty > 0x0);
pMplCtx->rxQueue.dirty++, bufFragCount--)
{
entry = pMplCtx->rxQueue.dirty % pMplCtx->rxQueue.descCnt;
currRxd = &pMplCtx->rxQueue.pRing[entry];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -