📄 csl_emac.c
字号:
/*-----------------------------------------------------------------------*\
* EMAC_getStatistics()
*
* Called to get the current device statistics. The statistics structure
* contains a collection of event counts for various packet sent and
* receive properties. Reading the statistics also clears the current
* statistic counters, so the values read represent a delta from the last
* call.
*
* The statistics information is copied into the structure pointed to
* by the pStatistics argument.
*
* The function returns zero on success, or an error code on failure.
*
* Possible error code include:
* EMAC_ERROR_INVALID - A calling parameter is invalid
*
\*-----------------------------------------------------------------------*/
uint EMAC_getStatistics( Handle hEMAC, EMAC_Statistics *pStatistics )
{
EMAC_Device *pd = (EMAC_Device *)hEMAC;
/* Validate our handle */
if( !pd || pd->DevMagic != EMAC_DEVMAGIC || !pStatistics )
return( EMAC_ERROR_INVALID );
/* Update the stats */
emacUpdateStats( pd );
/* Copy the updated stats to the application */
*pStatistics = pd->Stats;
/* Clear our copy */
memset( &pd->Stats, 0, sizeof(EMAC_Statistics) );
return(0);
}
/*-----------------------------------------------------------------------*\
* EMAC_setMulticast()
*
* This function is called to install a list of multicast addresses for
* use in multicast address filtering. Each time this function is called,
* any current multicast configuration is discarded in favor of the new
* list. Thus a set with a list size of zero will remove all multicast
* addresses from the device.
*
* Note that the multicast list configuration is stateless in that the
* list of multicast addresses used to build the configuration is not
* retained. Thus it is impossible to examine a list of currently installed
* addresses.
*
* The addresses to install are pointed to by pMCastList. The length of
* this list in bytes is 6 times the value of AddrCnt. When AddrCnt is
* zero, the pMCastList parameter can be NULL.
*
* The function returns zero on success, or an error code on failure.
* The multicast list settings are not altered in the event of a failure
* code.
*
* Possible error code include:
* EMAC_ERROR_INVALID - A calling parameter is invalid
*
\*-----------------------------------------------------------------------*/
uint EMAC_setMulticast( Handle hEMAC, uint AddrCnt, Uint8 *pMCastList )
{
EMAC_Device *pd = (EMAC_Device *)hEMAC;
uint tmp1,tmp2;
Uint8 HashVal,tmpval;
/* Validate our handle */
if( !pd || pd->DevMagic != EMAC_DEVMAGIC || (AddrCnt && !pMCastList) )
return( EMAC_ERROR_INVALID );
/* Clear the hash bits */
pd->MacHash1 = 0;
pd->MacHash2 = 0;
/* For each address in the list, hash and set the bit */
for( tmp1=0; tmp1<AddrCnt; tmp1++ )
{
HashVal=0;
for( tmp2=0; tmp2<2; tmp2++ )
{
tmpval = *pMCastList++;
HashVal ^= (tmpval>>2)^(tmpval<<4);
tmpval = *pMCastList++;
HashVal ^= (tmpval>>4)^(tmpval<<2);
tmpval = *pMCastList++;
HashVal ^= (tmpval>>6)^(tmpval);
}
if( HashVal & 0x20 )
pd->MacHash2 |= (1<<(HashVal&0x1f));
else
pd->MacHash1 |= (1<<(HashVal&0x1f));
}
/* We only write the hash table if the filter setting allows */
if( pd->RxFilter < EMAC_RXFILTER_ALLMULTICAST )
{
EMAC_RSET( MACHASH1, pd->MacHash1 );
EMAC_RSET( MACHASH2, pd->MacHash2 );
}
return(0);
}
/*-----------------------------------------------------------------------*\
* EMAC_sendPacket()
*
* Sends a Ethernet data packet out the EMAC device. On a non-error return,
* the EMAC device takes ownership of the packet. The packet is returned
* to the application's free pool once it has been transmitted.
*
* The function returns zero on success, or an error code on failure.
* When an error code is returned, the EMAC device has not taken ownership
* of the packet.
*
* Possible error codes include:
* EMAC_ERROR_INVALID - A calling parameter is invalid
* EMAC_ERROR_BADPACKET - The packet structure is invalid
*
\*-----------------------------------------------------------------------*/
uint EMAC_sendPacket( Handle hEMAC, EMAC_Pkt *pPkt )
{
EMAC_Device *pd = (EMAC_Device *)hEMAC;
uint fragcnt,pktlen;
EMAC_Pkt *pPktLast;
EMAC_DescCh *pdc;
/* Validate our handle */
if( !pd || pd->DevMagic != EMAC_DEVMAGIC || !pPkt )
return( EMAC_ERROR_INVALID );
/* Do some packet validation */
if( !(pPkt->Flags & EMAC_PKT_FLAGS_SOP) )
return( EMAC_ERROR_BADPACKET );
if( pPkt->PktChannel >= pd->Config.TxChannels )
return( EMAC_ERROR_BADPACKET );
if( pPkt->PktLength < 14 || pPkt->PktLength > pd->PktMTU )
return( EMAC_ERROR_BADPACKET );
/* Count the number of frags in this packet */
fragcnt = 1;
pktlen = pPkt->PktLength;
pPktLast = pPkt;
while( !(pPktLast->Flags & EMAC_PKT_FLAGS_EOP) )
{
if( !pPktLast->pNext )
return( EMAC_ERROR_INVALID );
pktlen -= pPktLast->ValidLen;
pPktLast = pPktLast->pNext;
fragcnt++;
/* At this point we can't have another SOP */
if( pPktLast->Flags & EMAC_PKT_FLAGS_SOP )
return( EMAC_ERROR_INVALID );
}
/* Make sure PktLength and ValidLen agree */
if( pktlen != pPkt->ValidLen )
return( EMAC_ERROR_BADPACKET );
/* The final packet frag must be the last in the list */
if( pPktLast->pNext )
return( EMAC_ERROR_BADPACKET );
/* The frag count must be correct */
if( fragcnt != pPkt->PktFrags )
return( EMAC_ERROR_BADPACKET );
/* Now pad for 60 byte min size. We only pad the last fragment */
if( pPkt->PktLength < 60 )
{
pktlen = 60 - pPkt->PktLength;
pPkt->PktLength = 60;
pPktLast->ValidLen += pktlen;
}
/* Get a local pointer to the descriptor channel */
pdc = &(pd->TxCh[pPkt->PktChannel]);
/* Make sure this packet does not have too many frags to fit */
if( fragcnt > pdc->DescMax )
return( EMAC_ERROR_BADPACKET );
/*
// Queue and packet and service transmitter
*/
pqPushChain( &pdc->WaitQueue, pPkt, pPktLast, fragcnt );
emacEnqueueTx( pdc );
return(0);
}
/*-----------------------------------------------------------------------*\
* EMAC_serviceCheck()
*
* This function should be called every time there is an EMAC device
* interrupt. It maintains the status the EMAC.
*
* Note that the application has the responsibility for mapping the
* physical device index to the correct EMAC_serviceCheck() function. If
* more than one EMAC device is on the same interrupt, the function must be
* called for each device.
*
* Possible error codes include:
* EMAC_ERROR_INVALID - A calling parameter is invalid
* EMAC_ERROR_MACFATAL - Fatal error in the MAC - Call EMAC_close()
*
\*-----------------------------------------------------------------------*/
uint EMAC_serviceCheck( Handle hEMAC )
{
EMAC_Device *pd = (EMAC_Device *)hEMAC;
Uint32 intflags,Desc,mask;
uint tmp;
/* Validate our handle */
if( !pd || pd->DevMagic != EMAC_DEVMAGIC )
return( EMAC_ERROR_INVALID );
/* Disable EMAC/MDIO interrupts in wrapper */
EMAC_FSETS( EWCTL, INTEN, DISABLE );
/* Read the interrupt cause */
intflags = EMAC_RGET( MACINVECTOR );
/* Look for fatal errors first */
if( intflags & EMAC_FMK( MACINVECTOR, HOSTPEND, 1 ) )
{
/* Read the error status - we'll decode it by hand */
pd->FatalError = EMAC_RGET( MACSTATUS );
/* Tell the application */
(*localDev.Config.pfcbStatus)(pd->hApplication);
/* return with interrupt disabled in the wrapper */
return( EMAC_ERROR_MACFATAL );
}
/* Look for statistics interrupt */
if( intflags & EMAC_FMK( MACINVECTOR, STATPEND, 1 ) )
{
/* Read the stats and reset to zero */
/* This is necessary to clear the interrupt */
emacUpdateStats( pd );
/* Tell the application */
(*localDev.Config.pfcbStatistics)(pd->hApplication);
}
/* Look for TX interrupt (channel 0-max) */
for( tmp=0; tmp<pd->Config.TxChannels; tmp++ )
{
mask = EMAC_FMK( MACINVECTOR, TXPEND, 1<<tmp );
if( intflags & mask )
{
/*
// For multichannel operation, we need to
// apply an errata workaround.
*/
do
{
Desc = EMAC_RGETI( TXINTACK, tmp );
EMAC_RSETI( TXINTACK, tmp, Desc );
} while( pd->Config.TxChannels>1 && (EMAC_RGET(MACINVECTOR)&mask) );
emacDequeueTx( &pd->TxCh[tmp], (EMAC_Desc *)Desc );
}
}
/* Look for RX interrupt (channel 0) */
if( intflags & EMAC_FMK( MACINVECTOR, RXPEND, 1<<0 ) )
{
/*
// For multichannel operation, we need to apply the
// same errata workaround as TX. However this driver
// example only supports one RX channel.
*/
Desc = EMAC_RGET( RX0INTACK );
EMAC_RSET( RX0INTACK, Desc );
emacDequeueRx( &pd->RxCh, (EMAC_Desc *)Desc );
}
/* Enable EMAC/MDIO interrupts in wrapper */
EMAC_FSETS( EWCTL, INTEN, ENABLE );
return(0);
}
/*-----------------------------------------------------------------------*\
* EMAC_timerTick()
*
* This function should be called for each device in the system on a
* periodic basis of 100mS (10 times a second). It is used to check the
* status of the EMAC and MDIO device, and to potentially recover from
* low Rx buffer conditions.
*
* Strict timing is not required, but the application should make a
* reasonable attempt to adhere to the 100mS mark. A missed call should
* not be "made up" by making mulitple sequential calls.
*
* A "polling" driver (one that calls EMAC_serviceCheck() in a tight loop),
* must also adhere to the 100mS timing on this function.
*
* Possible error codes include:
* EMAC_ERROR_INVALID - A calling parameter is invalid
*
\*-----------------------------------------------------------------------*/
uint EMAC_timerTick( Handle hEMAC )
{
EMAC_Device *pd = (EMAC_Device *)hEMAC;
uint mdioStatus,linkStatus;
/* Validate our handle */
if( !pd || pd->DevMagic != EMAC_DEVMAGIC )
return( EMAC_ERROR_INVALID );
/* Signal the MDIO */
mdioStatus = MDIO_timerTick( pd->hMDIO );
/* On a new link, set the EMAC duplex */
if( mdioStatus == MDIO_EVENT_LINKUP )
{
MDIO_getStatus( pd->hMDIO, 0, &linkStatus );
if( linkStatus == MDIO_LINKSTATUS_FD10 ||
linkStatus == MDIO_LINKSTATUS_FD100 )
{
EMAC_FSETS( MACCONTROL, FULLDUPLEX, ENABLE );
}
else
{
EMAC_FSETS( MACCONTROL, FULLDUPLEX, DISABLE );
}
}
if( mdioStatus != MDIO_EVENT_NOCHANGE )
(*localDev.Config.pfcbStatus)(pd->hApplication);
/* Re-fill Rx buffer queue if needed */
if( pd->RxCh.DescCount != pd->RxCh.DescMax )
emacEnqueueRx( &pd->RxCh, 1 );
return ( 0 );
}
#endif /* EMAC_SUPPORT */
/******************************************************************************\
* End of emac.c
\******************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -