📄 csl_emac.c
字号:
/*****************************************************************************\
* Copyright (C) 1999-2003 Texas Instruments Incorporated.
* All Rights Reserved
*------------------------------------------------------------------------------
* FILENAME...... csl_emac.c
* DATE CREATED.. 02/08/2002
* LAST MODIFIED. 05/23/2003
*------------------------------------------------------------------------------
* NOTE:
* When used in an multitasking environment, no EMAC function may be
* called while another EMAC function is operating on the same device
* handle in another thread. It is the responsibility of the application
* to assure adherence to this restriction.
*
\******************************************************************************/
/* Include the EMAC file from CSL */
#include <csl_emachal.h>
#include <csl_emac.h>
#include <csl_mdio.h>
#if (EMAC_SUPPORT)
extern void *memset(void *_mem, int _ch, uint _n);
/*
// We keep a local packet queue for transmit and receive packets.
// The queue structure is OS independent.
*/
/*
// Packet Queue
*/
typedef struct _pktq {
uint Count; // Number of packets in queue
EMAC_Pkt *pHead; // Pointer to first packet
EMAC_Pkt *pTail; // Pointer to last packet
} PKTQ;
/*
// Queue Helper Functions
*/
static EMAC_Pkt *pqPop( PKTQ *pq );
static void pqPush( PKTQ *pq, EMAC_Pkt *pPktHdr );
static void pqPushChain( PKTQ *pq, EMAC_Pkt *pPktHdrFirst,
EMAC_Pkt *pPktHdrLast, uint Count );
/*
// Transmit/Receive Descriptor Channel Structure
// (One receive and up to 8 transmit in this driver)
*/
typedef struct _EMAC_DescCh {
struct _EMAC_Device *pd; /* Pointer to parent structure */
PKTQ DescQueue; /* Packets queued as desc */
PKTQ WaitQueue; /* Packets waiting for TX desc */
uint ChannelIndex; /* Channel index 0-7 */
uint DescMax; /* Max number of desc (buffs) */
uint DescCount; /* Current number of desc */
EMAC_Desc *pDescFirst; /* First desc location */
EMAC_Desc *pDescLast; /* Last desc location */
EMAC_Desc *pDescRead; /* Location to read next desc */
EMAC_Desc *pDescWrite; /* Location to write nest desc */
} EMAC_DescCh;
/*
// Main Device Instance Structure
*/
typedef struct _EMAC_Device {
Uint32 DevMagic; /* Magic ID for this instance */
Handle hApplication; /* Calling Application's Handle */
Handle hMDIO; /* Handle to MDIO Module */
uint RxFilter; /* Current RX filter value */
uint PktMTU; /* Max physical packet size */
Uint32 MacHash1; /* Hash value cache */
Uint32 MacHash2; /* Hash value cache */
Uint32 FatalError; /* Fatal Error Code */
EMAC_Config Config; /* Original User Configuration */
EMAC_Statistics Stats; /* Current running statistics */
EMAC_DescCh RxCh; /* Receive channel status */
EMAC_DescCh TxCh[8]; /* Transmit channel status */
} EMAC_Device;
/*
// Although the EMAC API is defined to support multiple device instances,
// this version supports a single device instance
*/
/* Local copy of the EMAC device instance */
static uint openFlag = 0;
static EMAC_Device localDev;
#define EMAC_DEVMAGIC 0x0aceface
#define EMAC_NUMSTATS 36 /* The number of statistics regs */
/*
// Local Helper Functions
*/
static void emacUpdateStats( EMAC_Device *pd );
static void emacEnqueueTx( EMAC_DescCh *pdc );
static void emacDequeueTx( EMAC_DescCh *pdc, EMAC_Desc *pDescLast );
static void emacEnqueueRx( EMAC_DescCh *pdc, uint fRestart );
static void emacDequeueRx( EMAC_DescCh *pdc, EMAC_Desc *pDescAck );
/*--------------------------------------------------------------------*\
* pqPop()
*
* Pop a desc buffer off a queue
\*--------------------------------------------------------------------*/
static EMAC_Pkt *pqPop( PKTQ *pq )
{
EMAC_Pkt *pPktHdr;
pPktHdr = pq->pHead;
if( pPktHdr )
{
pq->pHead = pPktHdr->pNext;
pq->Count--;
}
pPktHdr->pPrev = pPktHdr->pNext = 0;
return( pPktHdr );
}
/*--------------------------------------------------------------------*\
* pqPush()
*
* Push a desc buffer onto a queue
\*--------------------------------------------------------------------*/
static void pqPush( PKTQ *pq, EMAC_Pkt *pPktHdr )
{
pPktHdr->pNext = 0;
if( !pq->pHead )
{
// Queue is empty - Initialize it with this one packet
pq->pHead = pPktHdr;
pq->pTail = pPktHdr;
}
else
{
// Queue is not empty - Push onto END
pq->pTail->pNext = pPktHdr;
pq->pTail = pPktHdr;
}
pq->Count++;
}
/*--------------------------------------------------------------------*\
* pqPushChain()
*
* Push a desc buffer chain onto a queue
\*--------------------------------------------------------------------*/
static void pqPushChain( PKTQ *pq, EMAC_Pkt *pPktHdrFirst,
EMAC_Pkt *pPktHdrLast, uint Count )
{
pPktHdrLast->pNext = 0;
if( !pq->pHead )
{
// Queue is empty - Initialize it with this one packet
pq->pHead = pPktHdrFirst;
pq->pTail = pPktHdrLast;
}
else
{
// Queue is not empty - Push onto END
pq->pTail->pNext = pPktHdrFirst;
pq->pTail = pPktHdrLast;
}
pq->Count += Count;
}
/*--------------------------------------------------------------------*\
* emacUpdateStats()
*
* Update our local copy of the statistics
\*--------------------------------------------------------------------*/
static void emacUpdateStats( EMAC_Device *pd )
{
int i;
volatile Uint32 *pRegAddr;
Uint32 *pStatAddr;
Uint32 statval;
pRegAddr = EMAC_ADDR(RXGOODFRAMES);
pStatAddr = (Uint32 *)(&pd->Stats);
/*
// There are "EMAC_NUMSTATS" statistics registers
// Note that when MIIEN is set in MACCONTROL, these registers
// are "write to decrement".
*/
for( i=0; i<EMAC_NUMSTATS; i++ )
{
statval = *pRegAddr;
*pRegAddr++ = statval;
statval += *pStatAddr;
*pStatAddr++ = statval;
}
}
/*--------------------------------------------------------------------*\
* emacEnqueueTx()
*
* Enqueue a TX packet and restart transmitter as needed
\*--------------------------------------------------------------------*/
static void emacEnqueueTx( EMAC_DescCh *pdc )
{
EMAC_Desc *pDescOrg,*pDescThis;
EMAC_Pkt *pPkt;
uint PktFrags;
uint CountOrg;
/*
// We need to be careful that we don't post half a packet to
// the list. Otherwise; we just fill in as much packet descriptor
// stuff as we can.
*/
pDescOrg = pdc->pDescWrite;
CountOrg = pdc->DescCount;
/* Try to post any waiting packets */
while( pdc->WaitQueue.Count )
{
/* See if we have enough room for a new packet */
pPkt = pdc->WaitQueue.pHead;
PktFrags = pPkt->PktFrags;
/* If we don't have room, break out */
if( (PktFrags+pdc->DescCount) > pdc->DescMax )
break;
/* The next packet will fit, post it. */
while( PktFrags )
{
/* Pop the next frag off the wait queue */
pPkt = pqPop( &pdc->WaitQueue );
/* Assign the pointer to "this" desc */
pDescThis = pdc->pDescWrite;
/* Move the write pointer and bump count */
if( pdc->pDescWrite == pdc->pDescLast )
pdc->pDescWrite = pdc->pDescFirst;
else
pdc->pDescWrite++;
pdc->DescCount++;
/*
// If this is the last frag, the forward pointer is NULL
// Otherwise; this desc points to the next frag's desc
*/
if( PktFrags==1 )
pDescThis->pNext = 0;
else
pDescThis->pNext = pdc->pDescWrite;
pDescThis->pBuffer = pPkt->pDataBuffer + pPkt->DataOffset;
pDescThis->BufOffLen = pPkt->ValidLen;
if( pPkt->Flags & EMAC_PKT_FLAGS_SOP )
pDescThis->PktFlgLen = ((pPkt->Flags&
(EMAC_PKT_FLAGS_SOP|EMAC_PKT_FLAGS_EOP))
|pPkt->PktLength|EMAC_DSC_FLAG_OWNER);
else
pDescThis->PktFlgLen = (pPkt->Flags&EMAC_PKT_FLAGS_EOP)
|EMAC_DSC_FLAG_OWNER;
/* Enqueue this frag onto the desc queue */
pqPush( &pdc->DescQueue, pPkt );
PktFrags--;
}
}
/* If we posted anything, chain on the list or start the transmitter */
if( CountOrg != pdc->DescCount )
{
if( CountOrg )
{
/*
// Transmitter is already running. Just tack this packet on
// to the end of the list (we need to "back up" one descriptor)
*/
if( pDescOrg == pdc->pDescFirst )
pDescThis = pdc->pDescLast;
else
pDescThis = pDescOrg - 1;
pDescThis->pNext = pDescOrg;
}
else
{
/* Transmitter is not running, start it up */
EMAC_RSETI( TXHDP, pdc->ChannelIndex, (Uint32)pDescOrg );
}
}
}
/*--------------------------------------------------------------------*\
* emacDequeueTx()
*
* Dequeue all completed TX packets and return buffers to application
\*--------------------------------------------------------------------*/
static void emacDequeueTx( EMAC_DescCh *pdc, EMAC_Desc *pDescAck )
{
EMAC_Pkt *pPkt;
Uint32 PktFlgLen;
register uint i,j = (uint)pdc->pDescRead;
/* Get the status of the ACK descriptor */
PktFlgLen = pDescAck->PktFlgLen;
/* Calc the new "Read" descriptor */
if( pDescAck == pdc->pDescLast )
pdc->pDescRead = pdc->pDescFirst;
else
pdc->pDescRead = pDescAck+1;
i = (uint)pdc->pDescRead;
/* Turn i into a descriptor count */
if( j < i )
i = (i-j)/sizeof(EMAC_Desc);
else
i = pdc->DescMax - ((j-i)/sizeof(EMAC_Desc));
pdc->DescCount-=i;
/* Pop & Free Buffers 'till the last Descriptor */
while(i--)
{
/* Recover the buffer and free it */
pPkt = pqPop( &pdc->DescQueue );
if( pPkt )
(*localDev.Config.pfcbFreePacket)(pdc->pd->hApplication,pPkt);
}
/* If the transmitter stopped and we have more descriptors, then restart */
if( (PktFlgLen & EMAC_DSC_FLAG_EOQ) && pdc->DescCount )
EMAC_RSETI( TXHDP, pdc->ChannelIndex, (Uint32)pdc->pDescRead );
/* Try to post any waiting TX packets */
if( pdc->WaitQueue.Count )
emacEnqueueTx( pdc );
}
/*--------------------------------------------------------------------*\
* emacEnqueueRx()
*
* Fill any empty RX descriptors with new buffers from the application
\*--------------------------------------------------------------------*/
static void emacEnqueueRx( EMAC_DescCh *pdc, uint fRestart )
{
EMAC_Pkt *pPkt;
EMAC_Desc *pDesc;
uint CountOrg;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -