📄 c6455_emac.c
字号:
/* ***********************************************************
* THIS PROGRAM IS PROVIDED "AS IS". TI MAKES NO WARRANTIES OR
* REPRESENTATIONS, EITHER EXPRESS, IMPLIED OR STATUTORY,
* INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR
* COMPLETENESS OF RESPONSES, RESULTS AND LACK OF NEGLIGENCE.
* TI DISCLAIMS ANY WARRANTY OF TITLE, QUIET ENJOYMENT, QUIET
* POSSESSION, AND NON-INFRINGEMENT OF ANY THIRD PARTY
* INTELLECTUAL PROPERTY RIGHTS WITH REGARD TO THE PROGRAM OR
* YOUR USE OF THE PROGRAM.
*
* IN NO EVENT SHALL TI BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
* CONSEQUENTIAL OR INDIRECT DAMAGES, HOWEVER CAUSED, ON ANY
* THEORY OF LIABILITY AND WHETHER OR NOT TI HAS BEEN ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGES, ARISING IN ANY WAY OUT
* OF THIS AGREEMENT, THE PROGRAM, OR YOUR USE OF THE PROGRAM.
* EXCLUDED DAMAGES INCLUDE, BUT ARE NOT LIMITED TO, COST OF
* REMOVAL OR REINSTALLATION, COMPUTER TIME, LABOR COSTS, LOSS
* OF GOODWILL, LOSS OF PROFITS, LOSS OF SAVINGS, OR LOSS OF
* USE OR INTERRUPTION OF BUSINESS. IN NO EVENT WILL TI'S
* AGGREGATE LIABILITY UNDER THIS AGREEMENT OR ARISING OUT OF
* YOUR USE OF THE PROGRAM EXCEED FIVE HUNDRED DOLLARS
* (U.S.$500).
*
* Unless otherwise stated, the Program written and copyrighted
* by Texas Instruments is distributed as "freeware". You may,
* only under TI's copyright in the Program, use and modify the
* Program without any charge or restriction. You may
* distribute to third parties, provided that you transfer a
* copy of this license to the third party and the third party
* agrees to these terms by its first use of the Program. You
* must reproduce the copyright notice and any other legend of
* ownership on each copy or partial copy, of the Program.
*
* You acknowledge and agree that the Program contains
* copyrighted material, trade secrets and other TI proprietary
* information and is protected by copyright laws,
* international copyright treaties, and trade secret laws, as
* well as other intellectual property laws. To protect TI's
* rights in the Program, you agree not to decompile, reverse
* engineer, disassemble or otherwise translate any object code
* versions of the Program to a human-readable form. You agree
* that in no event will you alter, remove or destroy any
* copyright notice included in the Program. TI reserves all
* rights not specifically granted under this license. Except
* as specifically provided herein, nothing in this agreement
* shall be construed as conferring by implication, estoppel,
* or otherwise, upon you, any license or other right under any
* TI patents, copyrights or trade secrets.
*
* You may not use the Program in non-TI devices.
* ********************************************************* */
/*****************************************************************************\
* Copyright (C) 1999-2003 Texas Instruments Incorporated.
* All Rights Reserved
*------------------------------------------------------------------------------
* FILENAME...... c6455_emac.c
* DATE CREATED.. 12/15/2005 - ported to C6455
* LAST MODIFIED.
*------------------------------------------------------------------------------
* 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 <c6455_emac.h>
#define RAM_MCAST 1 // Set to 1 to enable multicasting in RAM, 0 to enable hash multicasting
#define USE_EMAC_OPT 1 // Set to 1 to enable receive optimizations, 0 to disable
#define USE_JUMBO_PKT 1 // Set to 1 to enable jumbo packets, 0 to use standard Ethernet packets
#ifdef USE_JUMBO_PKT
#define OURMTU 10236 // 10K
#else
#define OURMTU 1514
#endif
extern void *memset(void *_mem, int _ch, uint _n);
extern Uint32 macsel;
/*
// 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 example)
*/
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 next 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 packet chain
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_REGS->RXGOODFRAMES;
pStatAddr = (Uint32 *)(&pd->Stats);
/*
// There are "EMAC_NUMSTATS" statistics registers
// Note that when GMIIEN 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;
volatile Uint32 *pRegAddr;
/*
// 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 */
pRegAddr = &EMAC_REGS->TX0HDP;
*(pRegAddr + 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;
volatile Uint32 *pRegAddr;
/* Get the status of the ACK descriptor */
PktFlgLen = pDescAck->PktFlgLen;
/* Calculate 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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -