📄 if_cs.c
字号:
(pCS->Rdy4TxInts) += 1;
/* The chip is ready for transmission now */
/* If a TX is pending, copy the frame to the chip to start transmission */
if( pCS->pTxFrameChain != NULL )
{
csCopyTxFrame( pCS, pCS->pTxFrameChain );
}
}
else if ( BufEvent & BUF_EVENT_SW_INT )
{
LOGMSG("csBufferEvent: unit %d, Software initiated interrupt\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
}
}
/*******************************************************************************
*
* csTransmitEvent -
*
* This routine is called whenever the transmission of a packet has completed
* successfully or unsuccessfully. If the transmission was not successful,
* then the output error count is incremented. If there are more packets in the
* transmit queue, then the next packet is started immediately.
*
*/
LOCAL void csTransmitEvent( CS_SOFTC *pCS, USHORT TxEvent )
{
struct ifnet *pIf;
pIf = &pCS->ArpCom.ac_if;
/* WE only get here if the transmit in progress has completed, either
* successfully or due to an error condition. In any event, queue the
* mbuf chain for freeing at task level and NULL the frame pointer to mark
* the TX no longer in progress.
*/
csEnqueue( pCS->pTxBuffFreeList, pCS->pTxFrameChain );
pCS->pTxFrameChain = NULL;
pCS->TxInProgress = FALSE;
/* If there were any errors transmitting this frame */
if ( TxEvent & (TX_EVENT_LOSS_CRS | TX_EVENT_SQE_ERR | TX_EVENT_OUT_WIN |
TX_EVENT_JABBER | TX_EVENT_16_COLL) )
{
/* Increment the output error count */
/* @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."*/
/*pIf->if_opackets--;*/
pIf->if_oerrors++;
/* If debugging is enabled then log error messages */
if ( csDebug == TRUE )
{
if ( TxEvent & TX_EVENT_LOSS_CRS )
{
LOGMSG("csTransmitEvent: unit %d, Loss of carrier\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
}
if ( TxEvent & TX_EVENT_SQE_ERR )
{
LOGMSG("csTransmitEvent: unit %d, SQE error\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
}
if ( TxEvent & TX_EVENT_OUT_WIN )
{
LOGMSG("csTransmitEvent: unit %d, Out-of-window collision\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
}
if ( TxEvent & TX_EVENT_JABBER )
{
LOGMSG("csTransmitEvent: unit %d, Jabber\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
}
if ( TxEvent & TX_EVENT_16_COLL )
{
LOGMSG("csTransmitEvent: unit %d, 16 collisions\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
}
}
}
/* 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_SOFTC *pCS, USHORT RxEvent )
{
struct ifnet *pIf;
PRXBUF pRxBuff;
pIf = &pCS->ArpCom.ac_if;
/* If the frame was not received OK */
if ( !(RxEvent & RX_EVENT_RX_OK) )
{
/* Increment the input error count */
pIf->if_ierrors++;
/* If debugging is enabled then log error messages */
if ( csDebug == TRUE )
{
/* If an error bit is set */
if ( RxEvent != REG_NUM_RX_EVENT )
{
if ( RxEvent & RX_EVENT_RUNT )
{
LOGMSG("csReceiveEvent: unit %d, Runt\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
}
if ( RxEvent & RX_EVENT_X_DATA )
{
LOGMSG("csReceiveEvent: unit %d, Extra data\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
}
if ( RxEvent & RX_EVENT_CRC_ERR )
{
if ( RxEvent & RX_EVENT_DRIBBLE )
{
LOGMSG("csReceiveEvent: unit %d, Alignment error\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
}
else
{
LOGMSG("csReceiveEvent: unit %d, CRC Error\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
}
}
else if ( RxEvent & RX_EVENT_DRIBBLE )
{
LOGMSG("csReceiveEvent: unit %d, Dribble bits\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
}
}
}
/* 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 */
pRxBuff = csAllocRxBuff( pCS );
if ( pRxBuff == NULL ) /* If no buffer available */
{
/* Increment the input error count */
pIf->if_ierrors++;
#if ( ! STRESS_TESTING )
LOGMSG("csReceiveEvent: unit %d, No receive buffer available\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
#endif
/* 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 */
csCopyRxFrame( pCS, pRxBuff );
/* Queue a pointer to the buffer to be processed at task level */
csEnqueue( pCS->pRxBuffProcessList, (PTXBUF)pRxBuff );
}
/*******************************************************************************
* 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_SOFTC *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 );
m_freem( 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
*
*/
#ifdef BSD43_DRIVER
LOCAL void csStartOutput( int Unit )
{
FAST CS_SOFTC *pCS;
FAST struct mbuf *pMbuf;
struct ifqueue *pTxQueue;
int Spl;
BOOL QError;
if ( Unit >= CS_MAX_NUM_UNITS )
return;
pCS = &cs_softc[Unit];
#else /* BSD4.4 DRIVER */
LOCAL void csStartOutput
(
CS_SOFTC * pCS /* pointer to control structure */
)
{
FAST struct mbuf *pMbuf;
struct ifqueue *pTxQueue;
int Spl;
BOOL QError;
#endif /* BSD43_DRIVER */
pTxQueue = &pCS->ArpCom.ac_if.if_snd;
/* Note the maximum depth of the transmit queue */
if ( pTxQueue->ifq_len > pCS->MaxTxDepth )
pCS->MaxTxDepth = pTxQueue->ifq_len;
/* Drain the interface's send queue into the local TX queue */
while ( pTxQueue->ifq_head != NULL )
{
Spl = splnet();
/* Dequeue an mbuf chain from the transmit queue */
IF_DEQUEUE( pTxQueue, pMbuf );
splx( Spl );
QError = csEnqueue( pCS->pTxQueue, pMbuf );
if ( QError )
{
/* TxQueue is full -- dump the frame and exit loop */
m_freem( (PTXBUF)pMbuf );
/* Update output stats */
pCS->ArpCom.ac_if.if_oerrors++;
LOGMSG("csStartOutput: unit %d, Transmit queue overflow\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
/* Local TX queue is full so exit loop */
break;
}
/* @kml*/
pCS->ArpCom.ac_if.if_opackets++;
#ifdef CS_DEBUG_ENABLE
pCS->TxQueueDepth++;
if ( pCS->TxQueueDepth > pCS->MaxTxQueueDepth )
pCS->MaxTxQueueDepth = pCS->TxQueueDepth;
#endif
}
/* 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_SOFTC *pCS )
{
int State = 0;
USHORT BusStatus;
PMBUF pMbuf;
/* etherOutputHookRtn is not supported in a standard way. It does not
* perform an "alternative TX operation". To do so would require copying
* the TX data to a local linear buffer (too expensive). Since we don't
* have a linear buffer, simply pass a NULL as the second and third
* parameters.
*/
if (etherOutputHookRtn != NULL)
{
(* etherOutputHookRtn) (&pCS->ArpCom, NULL, NULL);
}
/* Transmit the next frame in the local TxQueue */
while( !csQueueEmpty( pCS->pTxQueue ) )
{
#ifdef CS_DEBUG_ENABLE
pCS->TxQueueDepth--;
#endif
if ( !pCS->InISR )
{
/* Ensure the transmit bid and copy to chip is atomic */
State = intLock( );
}
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->m_next )
{
pCS->TxLength += pMbuf->m_len;
}
/* 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;
if ( !pCS->InISR )
{
/* Re-enable interrupts at the CPU */
intUnlock( State );
}
/* Transmission now in progress */
break;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -