📄 c6455_emac.c
字号:
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;
Uint32 temp,temp1;
int i;
/* Validate our handle */
if( !pd || pd->DevMagic != EMAC_DEVMAGIC || (AddrCnt && !pMCastList) )
return( EMAC_ERROR_INVALID );
#if RAM_MCAST
if (AddrCnt > 31)
return ( EMAC_ERROR_INVALID );
// Clear the multicast list
for (i = 1; i < 32; i++)
{
EMAC_REGS->MACINDEX = i;
EMAC_REGS->MACADDRHI = 0;
EMAC_REGS->MACADDRLO = 0;
}
// For each address in the list, add it to the RAM
for( tmp1=0; tmp1<AddrCnt; tmp1++ )
{
EMAC_REGS->MACINDEX = tmp1+1;
temp = 0;
for( i=3; i>=0; i-- )
temp = (temp<<8) | *(pMCastList+i);
EMAC_REGS->MACADDRHI = temp;
temp = *(pMCastList+4);
temp1 = *(pMCastList+5);
EMAC_REGS->MACADDRLO = CSL_FMKT( EMAC_MACADDRLO_VALID, VALID ) |
CSL_FMKT( EMAC_MACADDRLO_MATCHFILT, MATCH ) |
CSL_FMK( EMAC_MACADDRLO_CHANNEL, 0 ) |
(temp1<<8) | temp ;
pMCastList+=6;
}
#else
/* 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_REGS->MACHASH1 = pd->MacHash1;
EMAC_REGS->MACHASH2 = pd->MacHash2;
}
#endif
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;
volatile Uint32 *pRegAddr;
/* Validate our handle */
if( !pd || pd->DevMagic != EMAC_DEVMAGIC )
return( EMAC_ERROR_INVALID );
/* Disable EMAC/MDIO interrupts in wrapper */
CSL_FINST(ECTL_REGS->EWCTL, ECTL_EWCTL_INTEN, DISABLE );
/* Read the interrupt cause */
intflags = EMAC_REGS->MACINVECTOR;
/* Look for fatal errors first */
if( intflags & CSL_FMK( EMAC_MACINVECTOR_HOSTPEND, 1 ) )
{
/* Read the error status - we'll decode it by hand */
pd->FatalError = EMAC_REGS->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 & CSL_FMK( EMAC_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);
}
pRegAddr = &EMAC_REGS->TX0CP;
/* Look for TX interrupt (channel 0-max) */
for( tmp=0; tmp<pd->Config.TxChannels; tmp++ )
{
mask = CSL_FMK( EMAC_MACINVECTOR_TXPEND, 1<<tmp );
if( intflags & mask )
{
Desc = *(pRegAddr + tmp);
*(pRegAddr + tmp) = Desc;
emacDequeueTx( &pd->TxCh[tmp], (EMAC_Desc *)Desc );
}
}
/* Look for RX interrupt (channel 0) */
if( intflags & CSL_FMK( EMAC_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_REGS->RX0CP ;
EMAC_REGS->RX0CP = Desc;
emacDequeueRx( &pd->RxCh, (EMAC_Desc *)Desc );
}
/* Enable EMAC/MDIO interrupts in wrapper */
CSL_FINST(ECTL_REGS->EWCTL, ECTL_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 multiple 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 configuration appropriate for the interface used */
if( mdioStatus == MDIO_EVENT_LINKUP )
{
MDIO_getStatus( pd->hMDIO, 0, &linkStatus );
if( linkStatus == MDIO_LINKSTATUS_FD10 ||
linkStatus == MDIO_LINKSTATUS_FD100 ||
linkStatus == MDIO_LINKSTATUS_FD1000 )
{
CSL_FINST(EMAC_REGS->MACCONTROL, EMAC_MACCONTROL_FULLDUPLEX, ENABLE );
if ( macsel == CSL_DEV_DEVSTAT_MACSEL_RMII )
CSL_FINST(EMAC_REGS->MACCONTROL, EMAC_MACCONTROL_RMIIDUPLEXMODE, FULLDUPLEX );
}
else
{
CSL_FINST(EMAC_REGS->MACCONTROL, EMAC_MACCONTROL_FULLDUPLEX, DISABLE );
if ( macsel == CSL_DEV_DEVSTAT_MACSEL_RMII )
CSL_FINST(EMAC_REGS->MACCONTROL, EMAC_MACCONTROL_RMIIDUPLEXMODE, HALFDUPLEX );
}
if( linkStatus == MDIO_LINKSTATUS_FD1000 )
CSL_FINST(EMAC_REGS->MACCONTROL, EMAC_MACCONTROL_GIG, ENABLE );
if(( (linkStatus == MDIO_LINKSTATUS_HD10 ) ||
( linkStatus == MDIO_LINKSTATUS_FD10 )) &&
( macsel == CSL_DEV_DEVSTAT_MACSEL_RMII ))
CSL_FINST(EMAC_REGS->MACCONTROL, EMAC_MACCONTROL_RMIISPEED, 2_5MHZ );
if(( (linkStatus == MDIO_LINKSTATUS_HD100 ) ||
( linkStatus == MDIO_LINKSTATUS_FD100 )) &&
( macsel == CSL_DEV_DEVSTAT_MACSEL_RMII ))
CSL_FINST(EMAC_REGS->MACCONTROL, EMAC_MACCONTROL_RMIISPEED, 25MHZ );
/* The following 2 settings apply only to PG 2.0 */
if ( macsel == CSL_DEV_DEVSTAT_MACSEL_RMII ) // Take RMII out of reset
CSL_FINST(DEV_REGS->EMACCFG, DEV_EMACCFG_RMIIRST, RELEASE );
if ( macsel == CSL_DEV_DEVSTAT_MACSEL_RGMII ) // Put RGMII in forced link mode
CSL_FINST(EMAC_REGS->MACCONTROL, EMAC_MACCONTROL_RGMIIEN, 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 );
}
/******************************************************************************\
* End of himalaya_emac.c
\******************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -