⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 csl_emac.c

📁 dsp642 for easm based on BIOS
💻 C
📖 第 1 页 / 共 4 页
字号:
/*****************************************************************************\
*           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 + -