📄 csend.c
字号:
if ( TxEvent & TX_EVENT_LOSS_CRS )
{
LOGMSG("csTransmitEvent: CS_END_DEVICE %d, Loss of carrier\n",
pCS->unit, 0,0,0,0,0 );
}
if ( TxEvent & TX_EVENT_SQE_ERR )
{
LOGMSG("csTransmitEvent: CS_END_DEVICE %d, SQE error\n",
pCS->unit, 0,0,0,0,0 );
}
if ( TxEvent & TX_EVENT_OUT_WIN )
{
LOGMSG("csTransmitEvent: CS_END_DEVICE %d, Out-of-window collision\n",
pCS->unit, 0,0,0,0,0 );
}
if ( TxEvent & TX_EVENT_JABBER )
{
LOGMSG("csTransmitEvent: CS_END_DEVICE %d, Jabber\n",
pCS->unit, 0,0,0,0,0 );
}
if ( TxEvent & TX_EVENT_16_COLL )
{
LOGMSG("csTransmitEvent: CS_END_DEVICE %d, 16 collisions\n",
pCS->unit, 0,0,0,0,0 );
}
#endif
}
/* Previous TX complete so start the next TX now if more to transmit */
csTxNextFrame( pCS );
}
/*******************************************************************************
*
* csReceiveEvent -
*
* This routine is called whenever a packet is received at the chip. If the
* packet is received with errors, then the input error count is incremented.
* If the packet is received OK, then the data is copied to an internal receive
* buffer and processed at task level (in csEventHandler).
*
* RETURNS: Nothing
*/
LOCAL void csReceiveEvent( CS_END_DEVICE *pCS, USHORT RxEvent )
{
M_BLK_ID pMblk;
CL_BLK_ID pClBlk;
char *pData;
int DataLen;
/* If the frame was not received OK */
if ( !(RxEvent & RX_EVENT_RX_OK) )
{
/* Increment the input error count */
/*pIf->if_ierrors++;*/
END_ERR_ADD (&pCS->end, MIB2_IN_ERRS, +1);
/* If debugging is enabled then log error messages */
#ifdef CS_DEBUG_ENABLE
/* If an error bit is set */
if ( RxEvent != REG_NUM_RX_EVENT )
{
if ( RxEvent & RX_EVENT_RUNT )
{
LOGMSG("csReceiveEvent: CS_END_DEVICE %d, Runt\n",
pCS->unit, 0,0,0,0,0 );
}
if ( RxEvent & RX_EVENT_X_DATA )
{
LOGMSG("csReceiveEvent: CS_END_DEVICE %d, Extra data\n",
pCS->unit, 0,0,0,0,0 );
}
if ( RxEvent & RX_EVENT_CRC_ERR )
{
if ( RxEvent & RX_EVENT_DRIBBLE )
{
LOGMSG("csReceiveEvent: CS_END_DEVICE %d, Alignment error\n",
pCS->unit, 0,0,0,0,0 );
}
else
{
LOGMSG("csReceiveEvent: CS_END_DEVICE %d, CRC Error\n",
pCS->unit, 0,0,0,0,0 );
}
}
else if ( RxEvent & RX_EVENT_DRIBBLE )
{
LOGMSG("csReceiveEvent: CS_END_DEVICE %d, Dribble bits\n",
pCS->unit, 0,0,0,0,0 );
}
}
#endif
/* Skip this error frame */
csReadPacketPage( pCS, PKTPG_RX_LENGTH );
csWritePacketPage( pCS, PKTPG_RX_CFG,
csReadPacketPage(pCS,PKTPG_RX_CFG) | RX_CFG_SKIP );
return;
}
/* Get a receive frame buffer */
pData = netClusterGet(pCS->end.pNetPool, pCS->pClPoolId);
/* Grab a cluster block to marry to the cluster we received. */
pClBlk = netClBlkGet (pCS->end.pNetPool, M_DONTWAIT);
/*
* OK we've got a spare, let's get an M_BLK_ID and marry it to the
* one in the ring.
*/
pMblk = mBlkGet (pCS->end.pNetPool, M_DONTWAIT, MT_DATA);
if ( pData == NULL || pClBlk == NULL || pMblk == NULL) /* If no buffer available */
{
if (pData) {
netClFree (pCS->end.pNetPool, pData);
}
if (pClBlk) {
netClBlkFree (pCS->end.pNetPool, pClBlk);
}
if ( pMblk ) {
netMblkFree (pCS->end.pNetPool, pMblk);
}
/* Increment the input error count */
/*pIf->if_ierrors++;*/
END_ERR_ADD (&pCS->end, MIB2_IN_ERRS, +1);
LOGMSG("csReceiveEvent(): unit=%d, No receive buffer available!\n",
pCS->unit, 0,0,0,0,0 );
/* Must read the length of all received frames */
csReadPacketPage( pCS, PKTPG_RX_LENGTH );
/* Skip the received frame */
csWritePacketPage( pCS, PKTPG_RX_CFG,
csReadPacketPage(pCS,PKTPG_RX_CFG) | RX_CFG_SKIP );
return;
}
/* Copy the received frame from the chip to the buffer */
/* Set offset 2 to the receiving buffer pointer so that the IP heater starts the
17th bytes for 32-bits alignment*/
DataLen=csCopyRxFrame( pCS, pData+2);
/* Join the cluster to the MBlock */
netClBlkJoin (pClBlk, pData, DataLen, NULL, 0, 0, 0);
netMblkClJoin (pMblk, pClBlk);
/* Set offset 2 to the receiving buffer pointer so that the IP heater starts the
17th bytes for 32-bits alignment*/
/*pMblk->mBlkHdr.mData += pDrvCtrl->offset;*/
pMblk->mBlkHdr.mData += 2;
pMblk->mBlkHdr.mLen = DataLen;
pMblk->mBlkHdr.mFlags |= M_PKTHDR;
pMblk->mBlkPktHdr.len = DataLen;
/* Queue a pointer to the buffer to be processed at task level */
csEnqueue( pCS->pRxBuffProcessList, pMblk );
}
/*******************************************************************************
* csEventHandler -
*
* This routine runs at the task level to processes RX frames and frees TX'd
* mbuf chains queued at the ISR level. Up to two instances of this
* routine may be queued to tNetTask to prevent a race condition between final
* checking of a queue here and an enqueue at the ISR level. A netJob
* "counter" is decremented each time this routine starts.
*
* RETURNS: Nothing.
*
*/
LOCAL void csEventHandler( CS_END_DEVICE *pCS )
{
void *pBuff;
if( pCS->NetJobDepth > 0 )
pCS->NetJobDepth--;
while( !csQueueEmpty( pCS->pRxBuffProcessList ) )
{
/* Process an RX frame */
pBuff = csDequeue( pCS->pRxBuffProcessList );
csProcessReceive( pCS, pBuff );
}
while( !csQueueEmpty( pCS->pTxBuffFreeList ) )
{
/* Free up the TX'd mbuf chains */
pBuff = csDequeue( pCS->pTxBuffFreeList );
netMblkClChainFree (pBuff);
}
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *
* Transmit-releated Routines *
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/*******************************************************************************
*
* csStartOutput -
*
* This routine is called to start the transmission of the packet at the head
* of the transmit queue. This routine is called by the ether_output() routine
* when a new packet is added to the transmit queue.
*
* RETURNS: Nothing
*
*/
LOCAL void csStartOutput( CS_END_DEVICE *pCS, M_BLK_ID pMBuf)
{
BOOL QError;
END_TX_SEM_TAKE(&pCS->end, WAIT_FOREVER);
QError = csEnqueue( pCS->pTxQueue, pMBuf );
END_TX_SEM_GIVE(&pCS->end);
if ( QError )
{
/* TxQueue is full -- dump the frame and exit loop */
netMblkClChainFree (pMBuf);
/* Update output stats */
END_ERR_ADD (&pCS->end, MIB2_OUT_ERRS, +1);
LOGMSG("csStartOutput: CS_END_DEVICE %d, Transmit queue overflow\n",
pCS->unit, 0,0,0,0,0 );
}
#ifdef CS_DEBUG_ENABLE
pCS->TxQueueDepth++;
if ( pCS->TxQueueDepth > pCS->MaxTxQueueDepth )
pCS->MaxTxQueueDepth = pCS->TxQueueDepth;
#endif
/* Update output stats */
END_ERR_ADD (&pCS->end, MIB2_OUT_UCAST, +1);
/* Transmit another frame if a TX is not currently in progress */
if ( !pCS->TxInProgress )
{
csTxNextFrame( pCS );
}
}
/*******************************************************************************
* csTxNextFrame -
*
* This routine start the TX of the next frame in the local TX send queue.
* If an error occurs, the output error count is incremented and the mbuf chain
* is freed, either by immediately calling mfree_m() if we are at task level,
* or queueing the mbuf chain for release at the task level if we are currently
* at the ISR level.
*
* RETURNS: Nothing
*
*/
LOCAL void csTxNextFrame ( CS_END_DEVICE *pCS )
{
USHORT BusStatus;
M_BLK_ID pMbuf;
/* Transmit the next frame in the local TxQueue */
while( !csQueueEmpty( pCS->pTxQueue ) )
{
#ifdef CS_DEBUG_ENABLE
pCS->TxQueueDepth--;
#endif
pCS->pTxFrameChain = csDequeue( pCS->pTxQueue );
/* Find the total length of the data to transmit */
pCS->TxLength = 0;
for ( pMbuf = pCS->pTxFrameChain; pMbuf!=NULL; pMbuf=pMbuf->mBlkHdr.mNext )
{
pCS->TxLength += pMbuf->mBlkHdr.mLen;
}
/* Bid for space on the chip and start the TX if bid successful */
if ( pCS->InMemoryMode )
{
csWritePacketPage( pCS, PKTPG_TX_CMD, pCS->TxStartCMD );
csWritePacketPage( pCS, PKTPG_TX_LENGTH, BYTE_SWAP(pCS->TxLength) );
}
else /* In IO mode */
{
SYS_ENET_OUT_WORD( (pCS->IOAddr)+PORT_TX_CMD, pCS->TxStartCMD );
SYS_ENET_OUT_WORD( (pCS->IOAddr)+PORT_TX_LENGTH,
BYTE_SWAP(pCS->TxLength));
}
/* Read BusStatus register which indicates success of the request */
BusStatus = csReadPacketPage( pCS, PKTPG_BUS_ST );
if ( BusStatus & BUS_ST_RDY4TXNOW )
{
/* The chip is ready for transmission now */
/* Copy the frame to the chip to start transmission */
csCopyTxFrame( pCS, pCS->pTxFrameChain );
/* Mark TX as in progress */
pCS->TxInProgress = TRUE;
/* Transmission now in progress */
break;
}
else /* Not ready for TX */
{
/* If there was an error in the transmit bid */
if ( BusStatus & BUS_ST_TX_BID_ERR )
{
/* Set TX not in progress */
pMbuf = pCS->pTxFrameChain;
pCS->pTxFrameChain = NULL;
pCS->TxInProgress = FALSE;
if ( !pCS->InISR )
{
/* Free the bad mbuf chain */
netMblkClChainFree (pMbuf);
}
else
{
/* queue the mbuf chain to be freed at task level */
csEnqueue( pCS->pTxBuffFreeList, pMbuf );
}
/* Update output stats */
END_ERR_ADD (&pCS->end, MIB2_OUT_ERRS, +1);
/* END_ERR_ADD (&pCS->end, MIB2_OUT_UCAST, -1);*/
/* @kml The definition of the MIB-II variable ifOutUcastPkts in Interface
group from RFC 1158 is "The total number of packets that higher-level
protocols requested be transmitted to a subnetwork-unicast address,
INCLUDE those that were discarded or not sent."*/
LOGMSG("csStartOutput: CS_END_DEVICE %d, Transmit bid error (too big)\n",
pCS->unit, 0,0,0,0,0 );
/* Loop up to transmit the next chain */
}
else /* Not Rdy4Tx and Not Bid Error */
{
/* Start the TX on Rdy4Tx interrupt */
/* TX buff space not available now. */
/* Mark TX as in progress */
pCS->TxInProgress = TRUE;
/* Exit loop */
break;
}
}
}
}
/*******************************************************************************
*
* csCopyTxFrame -
*
* This routine copies the packet from a chain of mbufs to the chip. When all
* the data has been copied, then the chip automatically begins transmitting
* the data.
*
* The reason why this "simple" copy routine is so long and complicated is
* because all reads and writes to the chip must be done as 16-bit words.
* If an mbuf has an odd number of bytes, then the last byte must be saved
* and combined with the first byte of the next mbuf. Also, some processors,
* such as the MIPS do not allow word writes to non-word aligned addresses.
*
*/
LOCAL void csCopyTxFrame( CS_END_DEVICE *pCS, M_BLK_ID pMbufChain )
{
M_BLK_ID pMbuf;
FAST USHORT *pFrame;
FAST USHORT *pBuff;
FAST USHORT *pBuffLimit;
IOADDR TxDataPort;
UCHAR *pStart;
USHORT Length;
BOOL HaveExtraByte;
union
{
UCHAR byte[2];
USHORT word;
} Straddle;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -