This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Running the NDK without a PHY



Hi,

I am working on a new design for a board with a DM642 processor and an on-board Ethernet switch.  Since the switch is on the same board as the DM642, we can connect the DM642 directly to the switch, with no PHY in between.  I am wondering how the NDK would be affected by this configuration.  Will the stack still work if it does not detect (via the MDIO interface) that a connection has been made to the (in this case non-existent) PHY?  Will I have to rebuild the NDK to remove the code that tries to talk to the PHY?

Any help on this would be greatly appreciated.

Paul

  • This is a little late I know, but I just happened to come across this so I thought I would make a quick comment...

    Paul Randall said:
    Will the stack still work if it does not detect (via the MDIO interface) that a connection has been made to the (in this case non-existent) PHY?  Will I have to rebuild the NDK to remove the code that tries to talk to the PHY?

    Out of the box you would likely get some sort of failure, but the way the stack is designed the hardware interface is abstracted to the inner stack itself, so you should be able to do this by modifying the Hardware Abstraction Layer (HAL) which is included in source to plug up any functions that would have used the MDIO connection to the PHY. This being said you should not have to rebuild the stack code to do this, just the HAL library (the rough equivalent of the low level driver). On the other hand this is not something i have seen done myself, so there may be some unforeseen 'gotchas' doing this making it harder than it sounds.

  • Bernie,

    Thanks for the guidance.

    I was able to get the hal_eth_dm642.lib library rebuilt with all MDIO CSL calls removed.  I was then able to run the stack without a PHY.  I have included the dm642.c file with my changes below.

    In our design, we connected the MDIO interface to the Ethernet switch and used the MDIO CSL calls to configure the switch.  It worked out beautifully.

    I did also have to rebuild the hal_userled_dm642.lib library since the prebuilt version was turning the LED on and off via a EVMDM642 FPGA register which conflicted with something else in our custom board's memory map.

    Paul Randall

     

    /**
     *   @file  dm642.c
     *
     *   @brief
     *       DM642 Ethernet Packet Driver written using NIMU
     *         Packet Architecture guidelines.
     *
     *  \par
     *  NOTE:
     *      (C) Copyright 2008, Texas Instruments, Inc.
     *
     *  \par
     */
    #include <std.h>
    #include <sys.h>
    #include <hwi.h>
    #include <c62.h>
    #include <csl.h>
    #include <csl_cache.h>
    #include <csl_emachal.h>
    #include <csl_mdio.h>
    #include <stkmain.h>
    #include "nimu_dm642.h"

    /**********************************************************************
     ****************** Global Variables / Definitions ********************
     **********************************************************************/
    //
    // 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)

    /**
     *  \brief Transmit/Receive Descriptor Channel Structure
     *
     *  (One receive and up to 8 transmit in this example)
     */
    typedef struct _EMAC_DescCh {
        PBMQ            DescQueue;
        /**< Packets queued as desc                                             */
        Uint32          DescMax;
        /**< Max number of desc (buffs)                                         */
        Uint32          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;


    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 to work properly.
    //
    #define EMAC_MAX_RX     16

    // Local instance information pointer for our single device instance
    static PDINFO *pPDI = 0;
    //PWR 7/26/10 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 );


    /**********************************************************************
     *************************** EMAC Functions ***************************
     **********************************************************************/

    /**
     *  @b HwPktInit
     *  @n
     *      Initializes the device MAC address to use and returns
     *      instance count
     *
     *  @param[in]  void
     *
     *  @retval
     *      Success -   1
     *  @retval
     *      Error   -   0
     */
    uint HwPktInit()
    {
        //
        // Get our MAC address and interrupt to use
        //
        DM642EMAC_getConfig( bMacAddr, &IntVector );
        IntFlag = 1<<IntVector;
        return(1);
    }

    /**
     *  @b HwPktShutdown
     *  @n
     *      Shutdown Device Environment
     *
     *  @param[in]  void
     *
     *  @retval
     *       void
     */
    void HwPktShutdown()
    {
    }


    /**
     *  @b HwPktOpen
     *  @n
     *      Opens and configures EMAC device instance. Configures Interrupts.
     *
     *  @param[in]  pi
     *      PDINFO structure pointer.
     *
     *  @retval
     *      Success -   0
     *  @retval
     *      Error   -   >0
     */
    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);
    }

    /**
     *  @b HwPktClose
     *  @n
     *      Closes EMAC and disables interrupts.
     *
     *  @param[in]  pi
     *      PDINFO structure pointer.
     *
     *  @retval
     *      void
     */
    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
        //PWR 7/26/10 MDIO_close( hMDIO );
    }

    /**
     *  @b HwPktSetRx
     *  @n
     *      Update Rx Mode (Rx filter and multicast hash table).
     *
     *  @param[in]  pi
     *      PDINFO structure pointer.
     *
     *  @retval
     *      void
     */
    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 numeric 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 );
     }

    /**
     *  @b HwPktTxNext
     *  @n
     *     Transmit Next Packet on Tx Queue
     *
     *  @param[in]  pi
     *      PDINFO structure pointer.
     *
     *  @retval
     *      void
     */
    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 );
    }

    /**
     *  @b _HwPktPoll
     *  @n
     *      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.
     *
     *  @param[in]  pi
     *      PDINFO structure pointer.
     *  @param[in]  fTimerTick
     *      Flag for timer, set when called on a 100ms event.
     *
     *  @retval
     *      void
     */
    void _HwPktPoll( PDINFO *pi, uint fTimerTick )
    {
        uint intmask;
        uint mdioStatus,phy,linkStatus;

        (void)pi;

        if( fTimerTick ) //PWR 7/26/10 && hMDIO )
        {
            LED_TOGGLE( USER_LED2 );
            if( FlashActiveLED )
            {
                FlashActiveLED = 0;
                LED_TOGGLE( USER_LED3 );
            }

            llEnter();
            intmask = C62_disableIER( IntFlag );

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

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

                // 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 );

                        //enable GMIIEN
                }

                else
                {
                    //on link down disable GMIIEN = 0;
                }

                // Tell application
                // PWR 7/26/10 - don't tell application because
                // we don't want a lot of PHY link messages printed
                //DM642EMAC_linkStatus( phy, linkStatus );
            }

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

            C62_enableIER( intmask );
            llExit();
        }
    }

    /**
     *  @b HwInt
     *  @n
     *      EMAC Hardware Interrupt handler.
     *
     *  @param[in]  void
     *
     *  @retval
     *      void
     */
    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);

            /*
            // There are "EMAC_NUMSTATS" statistics registers
            // Note that when MIIEN is set in MACCONTROL, these registers
            // are "write to decrement".
            */
            for( tmp=0; tmp<EMAC_NUMSTATS; tmp++ )
            {
                statval = *pRegAddr;
                *pRegAddr++ = statval;
            }
        }

        // Look for TX interrupt (channel 0)
        if( intflags & EMAC_FMK( MACINVECTOR, TXPEND, 1<<0 ) )
        {
            Desc = EMAC_RGET( TX0INTACK );
            EMAC_RSET( TX0INTACK, Desc );

            emacDequeueTx( (EMAC_Desc *)Desc );
        }

        // Look for RX interrupt (channel 0)
        if( intflags & EMAC_FMK( MACINVECTOR, RXPEND, 1<<0 ) )
        {
            Desc = EMAC_RGET( RX0INTACK );
            EMAC_RSET( RX0INTACK, Desc );

            emacDequeueRx( (EMAC_Desc *)Desc );
        }

        // Enable EMAC/MDIO interrupts in wrapper
        EMAC_FSETS( EWCTL, INTEN, ENABLE );
    }

    /**
     *  @b emacInit
     *  @n
     *      Initialize EMAC. Return "1" if all is OK.
     *
     *  @param[in]  void
     *
     *  @retval
     *      void
     */
    static uint emacInit()
    {
        Uint32          tmpval;
        int             i;
        volatile Uint32 *pRegAddr;
        uint            utemp1;
        EMAC_Desc       *pDesc;
        PBM_Handle      hPkt;

        /*
        //  Initialize the EMAC and MDIO devices
        */

        /*
        // Globally disable EMAC/MDIO interrupts in wrapper and put both
        // EMAC and MDIO modules into reset
        */
        EMAC_RSET( EWCTL, EMAC_FMKS( EWCTL, INTEN, DISABLE ) |
                          EMAC_FMKS( EWCTL, EMACRST, YES ) |
                          EMAC_FMKS( EWCTL, MDIORST, YES ) );

        /* Wait about 100 cycles */
        for( i=0; i<5; i++ )
            tmpval = EMAC_RGET( EWCTL );

        /* Leave EMAC/MDIO interrupts disabled and take both
           EMAC and MDIO modules out of reset */
        EMAC_RSET( EWCTL, EMAC_FMKS( EWCTL, INTEN, DISABLE ) |
                          EMAC_FMKS( EWCTL, EMACRST, NO ) |
                          EMAC_FMKS( EWCTL, MDIORST, NO ) );

        /* Wait about 100 cycles */
        for( i=0; i<5; i++ )
            tmpval = EMAC_RGET( EWCTL );

        /* Program the interrupt pacer */
        EMAC_RSET( EWINTTCNT, 4000 );

        /* Start the MII Configuration */
        //PWR 7/26/10 hMDIO = MDIO_open( MDIO_MODEFLG_AUTONEG );

        /*
        //  Setup the EMAC
        */

        /* Reset MAC Control */
        EMAC_RSET( MACCONTROL, 0 );

        /* Must manually init HDPs to NULL */
        pRegAddr = EMAC_ADDR(TX0HDP);
        for( i=0; i<8; i++ )
            *pRegAddr++ = 0;
        pRegAddr = EMAC_ADDR(RX0HDP);
        for( i=0; i<8; i++ )
            *pRegAddr++ = 0;

        /*
        // While MIIEN is clear in MACCONTROL, we can write directly to
        // the statistics registers (there are "EMAC_NUMSTATS" of them).
        */
        pRegAddr = EMAC_ADDR(RXGOODFRAMES);
        for( i=0; i<EMAC_NUMSTATS; i++ )
            *pRegAddr++ = 0;

        /* Setup device MAC address */
        EMAC_RSET( MACADDRL0, *(pPDI->bMacAddr+5) );
        EMAC_RSET( MACADDRM, *(pPDI->bMacAddr+4) );
        tmpval = 0;
        for( i=3; i>=0; i-- )
            tmpval = (tmpval<<8) | *(pPDI->bMacAddr+i);
        EMAC_RSET( MACADDRH, tmpval );

        /* For us buffer offset will always be zero */
        EMAC_RSET( RXBUFFEROFFSET, 0 );

        /* Reset RX (M)ulticast (B)roadcast (P)romiscuous Enable register */
        EMAC_RSET( RXMBPENABLE, 0 );
        EMAC_RSET( MACHASH1, 0 );
        EMAC_RSET( MACHASH2, 0 );

        /* Clear Unicast RX on channel 0-7 */
        EMAC_RSET( RXUNICASTCLEAR, 0xFF );

        /* Set the pass RX CRC mode */
        EMAC_FSETS( RXMBPENABLE, RXPASSCRC, INCLUDE );

        /* Set MAC loopback if requested */
        //  EMAC_FSETS( MACCONTROL, LOOPBACK, ENABLE );

        /*
        // Enable TX and RX channel interrupts (set mask bits)
        // Enable Host interrupts
        */
        EMAC_RSET( RXINTMASKCLEAR, 0xFF );
        EMAC_RSET( TXINTMASKCLEAR, 0xFF );
        EMAC_RSET( RXINTMASKSET, 1 );
        EMAC_RSET( TXINTMASKSET, 1 );
        EMAC_RSET( MACINTMASKSET, EMAC_FMK(MACINTMASKSET,HOSTERRINT,1) |
                                  EMAC_FMK(MACINTMASKSET,STATINT,1) );

        /*
        // Setup Receive Buffers
        */

        /* Pointer to first descriptor to use on RX */
        pDesc = (EMAC_Desc *)_EMAC_DSC_BASE_ADDR;

        /* Number of descriptors for RX channel */
        utemp1 = EMAC_MAX_RX;

        /* Init Rx channel */
        mmZeroInit( &chRx, sizeof(EMAC_DescCh) );
        chRx.DescMax    = utemp1;
        chRx.pDescFirst = pDesc;
        chRx.pDescLast  = pDesc + (utemp1 - 1);
        chRx.pDescRead  = pDesc;
        chRx.pDescWrite = pDesc;

        /* Fill the descriptor table */
        emacEnqueueRx(0);

        /*
        // If we didn't get the number of descriptor buffers that we
        // wanted to, abort now.
        */
        if( chRx.DescCount < utemp1 )
        {
            /* Free all RX descriptors */
            while( hPkt = PBMQ_deq( &chRx.DescQueue ) )
                PBM_free(hPkt);

            /* Close the MDIO Module */
            //PWR 7/26/10 MDIO_close( hMDIO );

            /* Return the error condition */
            return( 0 );
        }

        /*
        // Setup Transmit Buffers
        */

        /* Pointer to first descriptor to use on TX */
        pDesc += utemp1;

        /* Number of descriptors (max) for TX channel */
        utemp1 = (_EDMA_DSC_ENTRY_COUNT-utemp1);

        /* Init TX channel */
        mmZeroInit( &chTx, sizeof(EMAC_DescCh) );
        chTx.DescMax    = utemp1;
        chTx.pDescFirst = pDesc;
        chTx.pDescLast  = pDesc + (utemp1 - 1);
        chTx.pDescRead  = pDesc;
        chTx.pDescWrite = pDesc;


        /*
        // Enable RX, TX, and MII
        //
        // Note in full duplex mode we also need to set the FULLDUPLEX
        // bit in MACCRONTROL. However, we don't know what to set until
        // we have a link. Also, we must be able to dynamically change
        // this bit if the cable is unplugged and re-linked with a different
        // duplex.
        */
        EMAC_FSETS( TXCONTROL, TXEN, ENABLE );
        EMAC_FSETS( RXCONTROL, RXEN, ENABLE );
        EMAC_FSETS( MACCONTROL, MIIEN, ENABLE );

        /* Startup RX */
        EMAC_RSET( RX0HDP, (Uint32)chRx.pDescRead );

        /* Enable global interrupt in wrapper */
        ICR = IntFlag;
        EMAC_FSETS( EWCTL, INTEN, ENABLE );

        return(1);
    }

    /**
     *  @b emacDequeueTx
     *  @n
     *      Dequeue all completed TX packets and return buffers to application
     *
     *  @param[in]  pDescAck
     *      Buffer descriptor to be be cleaned up.
     *
     *  @retval
     *      void
     */
    static void emacDequeueTx( EMAC_Desc *pDescAck )
    {
        PBM_Handle  hPkt;
        Uint32      PktFlgLen;
        register uint  i,j = (uint)chTx.pDescRead;

        /* Get the status of the ACK descriptor */
        PktFlgLen = pDescAck->PktFlgLen;

        /* Calc the new "Read" descriptor */
        if( pDescAck == chTx.pDescLast )
            chTx.pDescRead = chTx.pDescFirst;
        else
            chTx.pDescRead = pDescAck+1;

        i = (uint)chTx.pDescRead;

        /* Turn i into a descriptor count */
        if( j < i )
            i = (i-j)/sizeof(EMAC_Desc);
        else
            i = chTx.DescMax - ((j-i)/sizeof(EMAC_Desc));

        chTx.DescCount -= i;

        /* Pop & Free Buffers 'till the last Descriptor */
        while( i-- )
        {
            // Recover the packet and free it
            hPkt = PBMQ_deq( &chTx.DescQueue );
            if( hPkt )
                PBM_free( hPkt );
        }

        // If the transmitter stopped and we have more descriptors, then restart
        if( (PktFlgLen & EMAC_DSC_FLAG_EOQ) && chTx.DescCount )
            EMAC_RSET( TX0HDP, (Uint32)chTx.pDescRead );
    }


    /**
     *  @b emacEnqueueRx
     *  @n
     *      Fill any empty RX descriptors with new buffers from the application
     *
     *  @param[in]  fRestart
     *      Flag that indicates whether the Rx HDP needs to be reset.
     *
     *  @retval
     *      void
     */
    static void emacEnqueueRx( uint fRestart )
    {
        PBM_Handle  hPkt;
        EMAC_Desc   *pDesc;
        uint        CountOrg;
        UINT8       *buffer;

        // Keep the old count around
        CountOrg = chRx.DescCount;

        // Fill RX Packets Until Full
        while( chRx.DescCount < chRx.DescMax )
        {
            // Try and get a buffer.
            hPkt = PBM_alloc( 1518 + PKT_PREPAD );

            if( !hPkt )
                break;

            PBM_setDataOffset( hPkt, PKT_PREPAD );
            buffer = PBM_getDataBuffer(hPkt) + PKT_PREPAD;

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

            // Fill in the descriptor for this buffer
            pDesc = chRx.pDescWrite;

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

            // Fill in the descriptor
            pDesc->pNext     = 0;
            pDesc->pBuffer   = buffer;
            pDesc->BufOffLen = 1518;
            pDesc->PktFlgLen = EMAC_DSC_FLAG_OWNER;

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

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

            // Make the previous buffer point to us
            if( pDesc == chRx.pDescFirst )
                 chRx.pDescLast->pNext = pDesc;
            else
                (pDesc-1)->pNext = pDesc;
        }

        /* Restart RX if we had ran out of descriptors and got some here */
        if( fRestart && !CountOrg && chRx.DescCount )
            EMAC_RSET( RX0HDP, (Uint32)chRx.pDescRead );
    }


    /**
     *  @b emacDequeueRx
     *  @n
     *      Dequeue all completed RX packets and give buffers to application
     *
     *  @param[in]  pDescAck
     *      Buffer descriptor last acked.
     *
     *  @retval
     *      void
     */
    static void emacDequeueRx( EMAC_Desc *pDescAck )
    {
        PBM_Handle  hPkt;
        uint        tmp;
        Uint32      PktFlgLen;
        uint        NeedService = 0;
        EMAC_Desc   *pDescNewRxFirst,*pDescNewRxLast=0,*pTemp;
        UINT8       *buffer;

        /* Remember the first new descriptor slot */
        pDescNewRxFirst = chRx.pDescWrite;

        /*
        // Pop & Free Buffers 'till the last Descriptor
        // One thing we know for sure is that all the decriptors from
        // the read pointer to pDescAsk are linked to each other via
        // their pNext field.
        */
        for( tmp=1; tmp; )
        {
            /* Get the status of this descriptor */
            PktFlgLen = chRx.pDescRead->PktFlgLen;

            // Recover the packet and pass it on
            hPkt = PBMQ_deq( &chRx.DescQueue );
            if( hPkt )
            {
                // Enqueue the packet and signal the stack
    #ifndef _INCLUDE_NIMU_CODE
                PBM_setIFRx( hPkt, pPDI->hEther );
                PBM_setValidLen(hPkt,(PktFlgLen & 0xFFFF));
                PBMQ_enq( &PBMQ_rx, hPkt );
    #else
                PktFlgLen = (PktFlgLen & 0xFFFF) - 4;
                PBM_setValidLen(hPkt,PktFlgLen);
                PBMQ_enq( &pPDI->PBMQ_rx, hPkt );
    #endif
                NeedService = 1;
            }

            /* See if this was the last buffer */
            if( chRx.pDescRead == pDescAck )
                tmp = 0;

            /* Move the read pointer and decrement count */
            if( chRx.pDescRead == chRx.pDescLast )
                chRx.pDescRead = chRx.pDescFirst;
            else
                chRx.pDescRead++;
            chRx.DescCount--;

            // Try and get a buffer.
            hPkt = PBM_alloc( 1518 + PKT_PREPAD );

            if( hPkt )
            {
                PBM_setDataOffset( hPkt, PKT_PREPAD );
                buffer = PBM_getDataBuffer(hPkt) + PKT_PREPAD;

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

                // Fill in the descriptor for this buffer
                pDescNewRxLast = chRx.pDescWrite;

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

                // Fill in the descriptor
                pDescNewRxLast->pBuffer   = buffer;
                pDescNewRxLast->BufOffLen = 1518;
                pDescNewRxLast->PktFlgLen = EMAC_DSC_FLAG_OWNER;

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

        /*
        // If we added descriptors, make the pNext of the last NULL, and
        // make the previous descriptor point to the new list we added.
        */
        if( pDescNewRxLast )
        {
            pDescNewRxLast->pNext = 0;

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

            /* Make the previous buffer point to us */
            if( pDescNewRxFirst == chRx.pDescFirst )
                pTemp = chRx.pDescLast;
            else
                pTemp = pDescNewRxFirst-1;

            /*
            // If these pointers wrapped, the RX engine is stopped
            // Otherwise; tack the new list to the old
            */
            if( pTemp != pDescNewRxLast )
                pTemp->pNext = pDescNewRxFirst;
        }

        /* If the receiver stopped and we have more descriptors, then restart */
        if( (PktFlgLen & EMAC_DSC_FLAG_EOQ) && chRx.DescCount )
            EMAC_RSET( RX0HDP, (Uint32)chRx.pDescRead );

        // Signal the stack if needed
        if( NeedService )
        {
            FlashActiveLED = 1;
            STKEVENT_signal( pPDI->hEvent, STKEVENT_ETHERNET, 1 );
        }
    }

  • I am glad to hear this worked, and many thanks for sharing your changes!