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

📄 dm642.c

📁 dm642网络传输程序
💻 C
📖 第 1 页 / 共 2 页
字号:
//--------------------------------------------------------------------------
// IP Stack
//--------------------------------------------------------------------------
// dm642.c
//
// DM642 EMAC Packet Driver
//
// Author: Michael A. Denio
// Copyright 2000, 2003 by Texas Instruments Inc.
//-------------------------------------------------------------------------
#include <std.h>
#include <sys.h>
#include <hwi.h>
#include <c62.h>
#include <stkmain.h>
#include <csl.h>
#include <csl_cache.h>
#include "llpacket.h"
#include "csl_emachal.h"
#include "csl_mdio.h"

//
// This single global can be checked via CCS if there's trouble
//
uint  DM642EMAC_FatalError = 0;

extern cregister volatile uint ICR;

//
// Configuration (Obtained via callback)
//
extern void DM642EMAC_getConfig( UINT8 *pMacAddr, uint *pIntVector );
extern void DM642EMAC_linkStatus( uint phy, uint linkStatus );
static UINT8   bMacAddr[6];            // MAC Address
static uint    IntVector = 5;          // Interrupt vector to use
static uint    IntFlag;                // Interrupt flag (1<<IntVector)

// Transmit/Receive Descriptor Channel Structure
// (One receive and one transmit in this driver)
typedef struct _EMAC_DescCh {
    PBMQ            DescQueue;    // Packets queued as desc
    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;

static EMAC_DescCh chTx;
static EMAC_DescCh chRx;

static uint FlashActiveLED = 0;

#define EMAC_NUMSTATS   36         // The number of statistics regs

//
// RX Buffer Depth
//
// We set this to 12 by default. This is the max (typical) number
// of free buffers ready for rx packets.
//
// Note that this driver always assumes it can enqueue a new TX
// packet to the EMAC. It justifies this by assuming that the size of
// its transmit descriptor chain (256 - EMAC_MAX_RX) is greater than
// or equal to the size of the free packet buffer pool (defined by
// PKT_NUM_FRAMEBUF in pbm.c). Thus the value of EMAC_MAX_RX
// plus the size of PKT_NUM_FRAMEBUF (defaults to 48) must be less
// than or equal to 256 for the driver work properly.
//
#define EMAC_MAX_RX     16

// Local instance information pointer for our single device instance
static PDINFO *pPDI = 0;
static Handle hMDIO = 0;

// Local Functions
static void HwInt();
static uint emacInit();
static void emacDequeueTx( EMAC_Desc *pDescAck );
static void emacEnqueueRx( uint fRestart );
static void emacDequeueRx( EMAC_Desc *pDescAck );


//--------------------------------------------------------------------
// HwPktInit()
//
// Initialize Device environment and return instance count
//--------------------------------------------------------------------
uint HwPktInit()
{
    //
    // Get our MAC address and interrupt to use
    //
    DM642EMAC_getConfig( bMacAddr, &IntVector );
    IntFlag = 1<<IntVector;
    return(1);
}

//--------------------------------------------------------------------
// HwPktShutdown()
//
// Shutdown Device Environment
//--------------------------------------------------------------------
void HwPktShutdown()
{
}

//--------------------------------------------------------------------
// HwPktOpen()
//
// Open Device Instance
//--------------------------------------------------------------------
uint HwPktOpen( PDINFO *pi )
{
    uint        ReturnCode = 1;

    // We only have one device, so store off the PDINFO pointer as
    // global to this module. Otherwise; we'd pick an unclaimed device
    // and associate it with the PDINFO.

    // Disable our general purpose interrupt
    C62_disableIER( IntFlag );

    // IF pPDI is aleady set, this is a restart.
    if( !pPDI )
    {
        //
        // Now initialize the EMAC device
        //
        pPDI = pi;

        // Map the EMAC interrupt to DSP interrupt
        IRQ_map( 0x18, IntVector );

        // Hook our interrupt
        HWI_dispatchPlug( IntVector, (Fxn)HwInt, -1, 0 );
        CACHE_invalidate( CACHE_L1PALL, 0, 0 );
    }

    // Use the new PDINFO
    pPDI = pi;

    // Copy in the MAC address from the configuration
    mmCopy( pPDI->bMacAddr, bMacAddr, 6 );

    // Initialize the EMAC
    ReturnCode = emacInit();

    // Enable our general purpose interrupt
    C62_enableIER( IntFlag );

    // Say not ready to send (we wait for link)
    pi->TxFree = 0;

    return(ReturnCode);
}

//--------------------------------------------------------------------
// HwPktClose()
//
// Close Device Instance
//--------------------------------------------------------------------
void HwPktClose( PDINFO *pi )
{
    PBM_Handle  hPkt;

    (void)pi;

    // Disable the DSP interrupt
    C62_disableIER( IntFlag );

    // Disable EMAC/MDIO interrupts in wrapper
    EMAC_FSETS( EWCTL, INTEN, DISABLE );

    // Teardown RX
    EMAC_RSET( RXTEARDOWN, 0 );

    // Teardown TX
    EMAC_RSET( TXTEARDOWN, 0 );

    // Disable RX, TX, and Clear MACCONTROL
    EMAC_FSETS( TXCONTROL, TXEN, DISABLE );
    EMAC_FSETS( RXCONTROL, RXEN, DISABLE );
    EMAC_RSET( MACCONTROL, 0 );

    // Free all RX buffers
    while( hPkt = PBMQ_deq( &chRx.DescQueue ) )
        PBM_free( hPkt );

    // Free all TX buffers
    while( hPkt = PBMQ_deq( &chTx.DescQueue ) )
        PBM_free( hPkt );

    // Close the MDIO Module
    MDIO_close( hMDIO );
}

//--------------------------------------------------------------------
// HwPktSetRx()
//
// Update Rx Mode (Rx filter and multicast hash table)
//--------------------------------------------------------------------
void HwPktSetRx( PDINFO *pi )
{
    uint        tmp1,tmp2;
    Uint8       HashVal,tmpval,*pMCastList;
    UINT32      MacHash1,MacHash2;

    // Clear the hash bits
    MacHash1 = 0;
    MacHash2 = 0;

    // For each address in the list, hash and set the bit
    pMCastList = pi->bMCast;
    for( tmp1=0; tmp1<pi->MCastCnt; 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 )
            MacHash2 |= (1<<(HashVal&0x1f));
        else
            MacHash1 |= (1<<(HashVal&0x1f));
    }

    // The following code relies on the numberic relation of the filter
    // value such that the higher filter values receive more types of
    // packets.

    // Disable Section
    if( pi->Filter < ETH_PKTFLT_ALL )
        EMAC_FSETS( RXMBPENABLE, RXCAFEN, DISABLE );
    if( pi->Filter < ETH_PKTFLT_ALLMULTICAST )
    {
        EMAC_RSET( MACHASH1, MacHash1 );
        EMAC_RSET( MACHASH2, MacHash2 );
    }
    if( pi->Filter < ETH_PKTFLT_MULTICAST )
        EMAC_FSETS( RXMBPENABLE, MULTEN, DISABLE );
    if( pi->Filter < ETH_PKTFLT_BROADCAST )
        EMAC_FSETS( RXMBPENABLE, BROADEN, DISABLE );
    if( pi->Filter < ETH_PKTFLT_DIRECT )
        EMAC_RSET( RXUNICASTCLEAR, 1 );

    // Enable Section
    if( pi->Filter >= ETH_PKTFLT_DIRECT )
        EMAC_RSET( RXUNICASTSET, 1 );
    if( pi->Filter >= ETH_PKTFLT_BROADCAST )
        EMAC_FSETS( RXMBPENABLE, BROADEN, ENABLE );
    if( pi->Filter >= ETH_PKTFLT_MULTICAST )
        EMAC_FSETS( RXMBPENABLE, MULTEN, ENABLE );
    if( pi->Filter >= ETH_PKTFLT_ALLMULTICAST )
    {
        EMAC_RSET( MACHASH1, 0xffffffff );
        EMAC_RSET( MACHASH1, 0xffffffff );
    }
    if( pi->Filter == ETH_PKTFLT_ALL )
        EMAC_FSETS( RXMBPENABLE, RXCAFEN, ENABLE );
 }

//--------------------------------------------------------------------
// HwPktTxNext()
//
// Transmit Next Packet on Tx Queue
//--------------------------------------------------------------------
void HwPktTxNext( PDINFO *pi )
{
    register EMAC_Desc *pDescThis;
    register UINT8     *buffer;
    register uint      length;
    PBM_Handle         hPkt;
    uint               intmask;

    // Make sure we have a packet to send
    if( !(hPkt = PBMQ_deq(&pi->PBMQ_tx)) )
    {
        pi->TxFree = 1;
        return;
    }

    buffer = PBM_getDataBuffer(hPkt) + PBM_getDataOffset(hPkt);
    length = PBM_getValidLen(hPkt);

    // Clean the cache for external addesses
    if( (UINT32)buffer & 0x80000000 )
        OEMCacheClean( (void *)buffer, length );

    // Disable our device interrupt
    intmask = C62_disableIER( IntFlag );

    // This can't happen, but check anyway
    if( chTx.DescCount == chTx.DescMax )
    {
        PBM_free( hPkt );
        goto send_exit;
    }

    // Assign the pointer to "this" desc
    pDescThis = chTx.pDescWrite;

    // Move the write pointer and bump count
    if( pDescThis == chTx.pDescLast )
        chTx.pDescWrite = chTx.pDescFirst;
    else
        chTx.pDescWrite++;
    chTx.DescCount++;

    // Fill out the descriptor
    pDescThis->pNext     = 0;
    pDescThis->pBuffer   = buffer;
    pDescThis->BufOffLen = length;
    pDescThis->PktFlgLen = EMAC_DSC_FLAG_SOP | EMAC_DSC_FLAG_EOP |
                           length | EMAC_DSC_FLAG_OWNER;

    // Enqueue this packet onto the desc queue
    PBMQ_enq( &chTx.DescQueue, hPkt );

    // Synch the cache
    if( (UINT32)buffer & 0x80000000 )
        OEMCacheCleanSynch();

    // Start it sending
    if( chTx.DescCount > 1 )
    {
        // Transmitter is already running.
        // Make the previous buffer point to us
        if( pDescThis == chTx.pDescFirst )
             chTx.pDescLast->pNext = pDescThis;
        else
            (pDescThis-1)->pNext = pDescThis;
    }
    else
    {
        // Transmitter is not running, start it up
        EMAC_RSET( TX0HDP, (Uint32)pDescThis );
    }

send_exit:
    C62_enableIER( intmask );
}

//--------------------------------------------------------------------
// _HwPktPoll()
//
// Poll routine - CALLED OUTSIDE OF KERNEL MODE
//
// This function is called at least every 100ms, faster in a
// polling environment. The fTimerTick flag is set only when
// called on a 100ms event.
//--------------------------------------------------------------------
void _HwPktPoll( PDINFO *pi, uint fTimerTick )
{
    uint intmask;
    uint mdioStatus,phy,linkStatus;

    (void)pi;

    if( fTimerTick && hMDIO )
    {
        LED_TOGGLE( USER_LED2 );
        if( FlashActiveLED )
        {
            FlashActiveLED = 0;
            LED_TOGGLE( USER_LED3 );
        }

        llEnter();
        intmask = C62_disableIER( IntFlag );

        // Signal the MDIO
        mdioStatus = MDIO_timerTick( hMDIO );

        // Track new or lost link
        if( mdioStatus == MDIO_EVENT_LINKDOWN ||
            mdioStatus == MDIO_EVENT_LINKUP )
        {
            MDIO_getStatus( hMDIO, &phy, &linkStatus );

            // On a new link, set the EMAC duplex
            if( mdioStatus == MDIO_EVENT_LINKUP )
            {
                if( linkStatus == MDIO_LINKSTATUS_FD10 ||
                    linkStatus == MDIO_LINKSTATUS_FD100 )
                {
                    EMAC_FSETS( MACCONTROL, FULLDUPLEX, ENABLE );
                }
                else
                {
                    EMAC_FSETS( MACCONTROL, FULLDUPLEX, DISABLE );
                }

                // Now that we have a link, send any queued packets
                while( !pi->TxFree )
                    HwPktTxNext( pi );
            }

            // Tell application
            DM642EMAC_linkStatus( phy, linkStatus );
        }

        // Re-fill Rx buffer queue if needed
        if( chRx.DescCount != chRx.DescMax )
            emacEnqueueRx( 1 );

        C62_enableIER( intmask );
        llExit();
    }
}

//--------------------------------------------------------------------
// HwInt()
//
// EMAC Hardware Interrupt
//--------------------------------------------------------------------
void HwInt(void)
{
    Uint32      intflags,Desc;
    uint        tmp;

    // 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 ) )
    {
        // A fatal error can only be caused by a software
        // logic error. We'll read the fatal error code
        // and exit with the EMAC interrupt still disabled.
        // This will halt all network functionality. The
        // application programmer can manually check the
        // status of DM642EMAC_FatalError. If the network
        // stops working.
        DM642EMAC_FatalError = EMAC_RGET( MACSTATUS );
        return;
    }

    // Look for statistics interrupt
    if( intflags & EMAC_FMK( MACINVECTOR, STATPEND, 1 ) )
    {
        volatile Uint32 *pRegAddr;
        Uint32 statval;

        pRegAddr = EMAC_ADDR(RXGOODFRAMES);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -