 /**
 *   @file  ethdriver.c
 *
 *   @brief
 *       Ethernet Packet Driver written using the CSL and NIMU
 *		 Packet Architecture guidelines.
 *
 *  \par
 *  NOTE:
 *      (C) Copyright 2008, Texas Instruments, Inc.
 *
 *  \par
 */

#include <std.h>
#include <sys.h>
#include <bcache.h>
#include <c64.h>
#include <stkmain.h>
#include <stdio.h>
#include "nimu_eth.h"
#include "csl_emac.h"
#include "csl_emacAux.h"
#include <csl_mdio.h>
#include <c6x.h>
#include <csl_sgmii.h>
#include <cslr_ectl.h>
#include <evminit.h>

/**********************************************************************
 ****************** Global Variables / Definitions ********************
 **********************************************************************/

extern cregister volatile unsigned int  IER;

#define     Disable_DSP_Interrupts()    IER &= ~0xC0
#define     Enable_DSP_Interrupts()     IER |= 0xC0

#define     EXTMEM                      0x80000000
#define     PKT_MAX                     64
#define     RXMAXPKTPOOL                8

Handle           				        hEMAC = 0;          /* Handle to our EMAC instance */
static      PDINFO					    *pPDI = 0;          /* Handle to Device Info */
static      Handle 					    hMDIO = 0;          /* Handle to MDIO instance */
static      Uint32 					    csl_errors = 0;     /* CSL returned error due to software */
static      Uint32					    emac_fatal_error = 0;    /* EMAC fatal error */
static      Uint32                      PktMTU;
static      UINT8                       bMacAddr[6];        /* Device MAC address */

EMAC_Pkt    rcv_pkt[PKT_MAX];           /* Array of pre-allocated/initialized EMAC packet buffers to handle incoming packets */
EMAC_Pkt    send_pkt[PKT_MAX];          /* Array of EMAC packet placeholders to handle tx packets */
int         memory_squeeze_error = 0;


/**
 * @brief
 *  EMAC_Pkt Queue Data Structure
 *
 * @details
 *  Maintains the count of queued elements and head and tail to EMAC_Pkt queue.
 */
typedef struct pkt_queue
{
   /**
    * @brief   Number of packets in queue
    */
    Uint32            Count;

   /**
    * @brief   Pointer to first packet
    */
    EMAC_Pkt          *pHead;

   /**
    * @brief   Pointer to last packet
    */
    EMAC_Pkt          *pTail;
} PKT_QUEUE;

PKT_QUEUE     RxQueue;                  /* Receive Queue */
PKT_QUEUE     TxQueue;                  /* Transmit Queue */

static EMAC_Pkt *Queue_pop( PKT_QUEUE *pq );
static void Queue_push( PKT_QUEUE *pq, EMAC_Pkt *pPktHdr );
void Interrupt_init(void);
void Interrupt_end(void);

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

/**
 *  @b Queue_pop
 *  @n
 *      Dequeues a packet from EMAC_Pkt queue.
 *
 *  @param[in]  pq
 *      Packet queue of type PKT_QUEUE .
 *
 *  @retval
 *      EMAC_Pkt popped from the queue.
 */
static EMAC_Pkt *Queue_pop( PKT_QUEUE *pq )
{
    EMAC_Pkt *pPktHdr = NULL;

    Disable_DSP_Interrupts();

    pPktHdr = pq->pHead;

    if( pPktHdr )
    {
        pq->pHead = pPktHdr->pNext;
        pq->Count--;
        pPktHdr->pPrev = pPktHdr->pNext = 0;
    }

	Enable_DSP_Interrupts();

    return( pPktHdr );
}


/**
 *  @b Queue_push
 *  @n
 *      Enqueues a packet in EMAC_Pkt queue.
 *
 *  @param[in]  pq
 *      Packet queue of type PKT_QUEUE .
 *  @param[in]  pPktHdr
 *      EMAC_Pkt type packet to push.
 *
 *  @retval
 *      void
 */
static void Queue_push( PKT_QUEUE *pq, EMAC_Pkt *pPktHdr )
{
    Disable_DSP_Interrupts();

    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++;

	Enable_DSP_Interrupts();
}


/**
 *  @b GetPacket
 *  @n
 *      Returns a packet from the RxQueue.
 *
 *  @param[in]  hApplication
 *      Driver's handle.
 *
 *  @retval
 *		EMAC_Pkt pointer of a packet with buffer to replenish CSL.
 */
static EMAC_Pkt *GetPacket( Handle hApplication )
{
    EMAC_Pkt *pPkt = NULL;

    if( (Uint32)hApplication != 0x12345678 )
    {
        return NULL;
    }

    pPkt = Queue_pop(&RxQueue);

    if( pPkt )
        pPkt->DataOffset = 0;

#ifdef EXTERNAL_MEMORY
	/* Clean the cache for external addesses */
	if( (UINT32)(PBM_getDataBuffer(pPkt->AppPrivate)) & EXTMEM )
        OEMCacheClean( (void *)(PBM_getDataBuffer(pPkt->AppPrivate)), PBM_getBufferLen(pPkt->AppPrivate) );
#endif

    return( pPkt );
}

/**
 *  @b FreePacket
 *  @n
 *      Called by CSL to free the buffer.
 *
 *  @param[in]  hApplication
 *      Driver's handle.
 *  @param[in]  cslPkt
 *      EMAC_Pkt type packet passed by CSL.
 *
 *  @retval
 *      void
 */
static void FreePacket( Handle hApplication, EMAC_Pkt *cslPkt )
{
    if( (Uint32)hApplication != 0x12345678 )
    {
        return;
    }

    PBM_free( (PBM_Handle)cslPkt->AppPrivate );
    Queue_push( &TxQueue, cslPkt );
}

/**
 *  @b RxPacket
 *  @n
 *      Function called by CSL to pass the received packet to the driver.
 *
 *  @param[in]  hApplication
 *      Driver's handle.
 *  @param[in]  cslPkt
 *      EMAC_Pkt type packet passed by CSL.
 *
 *  @retval
 *		EMAC_Pkt pointer of a packet with buffer to replenish CSL.
 */
static EMAC_Pkt *RxPacket(Handle hApplication, EMAC_Pkt *cslPkt)
{
	PBM_Handle  hPkt;
    Uint32      dataOffset, protocol;
    UINT8*       pBuffer;

	if( (Uint32)hApplication != 0x12345678 )
    {
	    return NULL;
    }

	if ((hPkt = PBM_alloc(PktMTU)))
	{
        PBM_setValidLen((PBM_Handle) cslPkt->AppPrivate, cslPkt->ValidLen);
	    PBM_setIFRx((PBM_Handle) cslPkt->AppPrivate, pPDI->hEther );
	
        /* Handle raw frames separately, i.e. check the
         * Ethernet Protocol type in this packet and see
         * if its a well known ether type. If so, this is normal
         * IP stream, enqueue this is in usual Rx queue and let the
         * stack know that a packet has arrived for it. However, if
         * the ethernet type in the packet is not a well known one,
         * this could be a custom raw ethernet packet, enqueue it
         * separately in the Raw Rx queue and notiofy stack. The Raw
         * Ethernet packets when being handed over are given 
         * preferential treatment and are serviced before the normal
         * IP traffic. Hence the 2 queues.
         */
		dataOffset = PBM_getDataOffset((PBM_Handle) cslPkt->AppPrivate);
		pBuffer = PBM_getDataBuffer((PBM_Handle) cslPkt->AppPrivate) + dataOffset;
		
        /* Extract the ethernet type from the packet. */
		protocol = ( pBuffer[12] << 8) | pBuffer[13] ;
        protocol = (protocol & 0xFFFFu);

        /* Is it a standard ethernet type? */
		if (protocol != ETHERTYPE_IP && protocol != ETHERTYPE_IPv6 && protocol != ETHERTYPE_VLAN
           && protocol != ETHERTYPE_PPPOECTL && protocol != ETHERTYPE_PPPOEDATA )        
        {
            /* This is a raw packet, enqueue in Raw Rx Queue */
	        PBMQ_enq( &pPDI->PBMQ_rawrx, (PBM_Handle) cslPkt->AppPrivate );
        }
        else
        {
            /* This is a normal IP packet. Enqueue in Rx Queue */
	    PBMQ_enq( &pPDI->PBMQ_rx, (PBM_Handle) cslPkt->AppPrivate );
        }

        cslPkt->AppPrivate  = (Uint32)hPkt;
        cslPkt->pDataBuffer = PBM_getDataBuffer(hPkt);
        cslPkt->BufferLen   = PBM_getBufferLen(hPkt);
        cslPkt->DataOffset = 0;

        /* Notify NDK stack of pending Rx Ethernet packet */
        STKEVENT_signal( pPDI->hEvent, STKEVENT_ETHERNET, 1 );

#ifdef EXTERNAL_MEMORY
		/* Clean the cache for external addesses */
        if( (UINT32)(PBM_getDataBuffer(cslPkt->AppPrivate)) & EXTMEM )
		   OEMCacheClean( (void *)(PBM_getDataBuffer(cslPkt->AppPrivate)), PBM_getBufferLen(cslPkt->AppPrivate) );
#endif
		return( cslPkt );
	}

	/* Increment the statistics to account for packets dropped because
	 * of memory squeeze
     */
	memory_squeeze_error++;
	return cslPkt;
}

/**
 *  @b StatusUpdate
 *  @n
 *      Called from CSL on Rx/Tx MACFATAL error and from CSL timer tick function.
 *		Tells the driver of a status update.
 *
 *  @param[in]  hApplication
 *     Driver's Handle.
 *
 *  @retval
 *      void
 */
static void StatusUpdate( Handle hApplication )
{
    if( (Uint32)hApplication != 0x12345678 )
    {
        return;
    }

	emac_fatal_error++;
}

/**
 *  @b StatisticsUpdate
 *  @n
 *     Called by CSL to indicate a statistic update
 *     interrupt.
 *
 *  @param[in]  hApplication
 *     Driver's Handle.
 *
 *  @retval
 *      void
 */
static void StatisticsUpdate( Handle hApplication )
{
    if( (Uint32)hApplication != 0x12345678 )
    {
        return;
    }
}

/**
 *  @b HwPktInit
 *  @n
 *      Initializes the device MAC address to use.
 *
 *  @param[in]  void
 *
 *  @retval
 *      Success -   1
 *  @retval
 *      Error   -   0
 */
uint HwPktInit()
{
    /* Initialize our MAC address */
    mmZeroInit(bMacAddr, 6);

    /* Get our EMAC address to use */
	EMAC_getConfig(bMacAddr);

    return (1);
}

/**
 *  @b HwPktShutdown
 *  @n
 *      Void
 *
 *  @param[in]  void
 *
 *  @retval
 *       void
 */
void HwPktShutdown()
{
    return;        
}

/**
 *  @b HwPktOpen
 *  @n
 *      Opens and configures EMAC. Configures Interrupts, SGMII,
 *      and send and receive queues.
 *
 *  @param[in]  pi
 *      PDINFO structure pointer.
 *
 *  @retval
 *      Success -   0
 *  @retval
 *      Error   -   >0
 */
uint HwPktOpen( PDINFO *pi )
{
	Uint32          i, j, stat;
    PBM_Handle      hPkt;
	EMAC_Config     ecfg;
	EMAC_AddrConfig *addrCfg;
	SGMII_Config    SgmiiCfg;

    pPDI = pi;

    /* Initialize EMAC setup */
	mmZeroInit( &RxQueue, sizeof(PKT_QUEUE) );
    mmZeroInit( &TxQueue, sizeof(PKT_QUEUE) );

	ecfg.UseMdio            = 1;
	ecfg.PktMTU             = 1514;
	ecfg.TotalNumOfMacAddrs = 2;        /* We are using two channels, so lets configure two MAC addresses */
	ecfg.DescBase           = EMAC_DESC_BASE_CPPI;

	PktMTU                  = ecfg.PktMTU;

    /* Queue up some initialized receive buffers */
	for( i=0; i<PKT_MAX; i++ )
	{
		hPkt = PBM_alloc(ecfg.PktMTU);
        /* Couldnt allocate memory, return error */
		if (hPkt == NULL)
			return 1;
		rcv_pkt[i].AppPrivate   = (Uint32)hPkt;
		rcv_pkt[i].pDataBuffer  = PBM_getDataBuffer(hPkt);
		rcv_pkt[i].BufferLen    = PBM_getBufferLen(hPkt);
        Queue_push( &RxQueue, &rcv_pkt[i] );
    }

    /* Queue up some transmit buffers */
	for( i=0; i<PKT_MAX; i++ )
	{
        Queue_push( &TxQueue, &send_pkt[i] );
    }

    /* Enable SGMII configuration, Gigabit and Full duplex operation on EMAC */
    ecfg.ModeFlags              = EMAC_CONFIG_MODEFLG_FULLDUPLEX |
                                  EMAC_CONFIG_MODEFLG_GIGABIT;

    /* Autonegotiation is supported by underlying PHY. Turn it on */
	ecfg.MdioModeFlags          = MDIO_MODEFLG_AUTONEG;

    ecfg.ChannelInfo.TxChanEnable = 0x9;  /* 00001001, Enable channel 0 for IP packets, channel 3 for Raw Packets Transmission */
	ecfg.ChannelInfo.RxChanEnable = 0x9;  /* 00001001, Enable channel 0 for IP packets, channel 3 for Raw Packets Reception */

    ecfg.RxMaxPktPool           = RXMAXPKTPOOL;
    ecfg.pfcbGetPacket          = &GetPacket;
    ecfg.pfcbFreePacket         = &FreePacket;
    ecfg.pfcbRxPacket           = &RxPacket;
    ecfg.pfcbStatus             = &StatusUpdate;
    ecfg.pfcbStatistics         = &StatisticsUpdate;

	ecfg.MacAddr = (EMAC_AddrConfig **)
     		       mmAlloc(ecfg.TotalNumOfMacAddrs * sizeof(EMAC_AddrConfig *));

	for ( j=0; j<ecfg.TotalNumOfMacAddrs; j++ )
    {
		ecfg.MacAddr[j] = (EMAC_AddrConfig *)mmAlloc(sizeof(EMAC_AddrConfig));
	}

    /* Generate a default MAC address to use */
    for( j=0; (Uint8)j<(ecfg.TotalNumOfMacAddrs); j++ )
    {
		addrCfg = ecfg.MacAddr[j];
		addrCfg->ChannelNum = 0;
		if( j == 1 )
			addrCfg->ChannelNum = 1;
		if( j == 2  )
			addrCfg->ChannelNum = 2;
		if( j == 3  )
			addrCfg->ChannelNum = 3;
		if( j == 4  )
			addrCfg->ChannelNum = 4;
		if( j == 5  )
			addrCfg->ChannelNum = 5;
		if( j == 6  )
			addrCfg->ChannelNum = 6;
		if( j == 7  )
			addrCfg->ChannelNum = 7;
   		for( i=0; i<6; i++ )
        {
		 	addrCfg->Addr[i] = j * 0x10 + i ;
		}
	}

	addrCfg = ecfg.MacAddr[0];

    /*  Check if EMAC_getConfig had returned a valid MAC address to use. If not,
     *  use the default generated above.
     */
    for( i=0; (i<6) && (!(bMacAddr[i])); i++ );
    if( i==6 )
    {
		/* Copy the MAC Address into the PDI Structure */
        mmCopy( (void *)&pPDI->bMacAddr[0], (void *)&addrCfg->Addr[0], 6 );
		printf("Since EFUSE MAC address is Zero we use the MAC Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
               pPDI->bMacAddr[0],pPDI->bMacAddr[1],pPDI->bMacAddr[2],pPDI->bMacAddr[3],pPDI->bMacAddr[4],pPDI->bMacAddr[5]);
    }
    else
    {
        mmCopy( (void *)&addrCfg->Addr[0], (void *)&bMacAddr[0], 6 );

		/* Copy the MAC Address into the PDI Structure */
		mmCopy ((void *)&pPDI->bMacAddr[0], (void *)&addrCfg->Addr[0], 6);

		printf("EFUSED MAC Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
               pPDI->bMacAddr[0],pPDI->bMacAddr[1],pPDI->bMacAddr[2],pPDI->bMacAddr[3],pPDI->bMacAddr[4],pPDI->bMacAddr[5]);
    }

    /* Bring EMAC out of power down */
    EVM_powerOnEMAC();

    i = EMAC_open( 1, (Handle)0x12345678, &ecfg, &hEMAC );

    if( i )
	{
        printf("EMAC OPEN Returned error \n");
		csl_errors++;
		return i;
	}

	Interrupt_init();

    hMDIO = ((EMAC_Device *)hEMAC)->hMDIO;

    /* Wait for link to come up */
    pi->TxFree = 0;

    i = SGMII_reset();

    if ( i == 0 )
        printf("SGMII reset successful........\n");
    else
    {
        csl_errors++;
        printf("SGMII reset NOT successful........\n");
    }

    /* set sgmii lock mode */
    *(volatile Uint32 *)(CSL_ECTL_0_REGS + 0x88) = 1;        

    SgmiiCfg.masterEn   = 0x0;          // Disable SGMII Master
    SgmiiCfg.loopbackEn = 0x0;          // Disable SGMII loopback
    SgmiiCfg.txConfig   = 0x00000a21;   // Enable tx
    SgmiiCfg.rxConfig   = 0x00081021;   // Enable rx
    // Setup for 125 MHz ref clock
    SgmiiCfg.auxConfig  = 0x0000000B;   // Enable PLL
    SgmiiCfg.modeOfOperation = SGMII_MODE_OF_OPERATION_WITH_AN;    //Auto Negotiation on

    i = SGMII_config(&SgmiiCfg);

    if( i == 0 )
        printf("SGMII config successful........\n");
    else
    {
        csl_errors++;
        printf("SGMII config NOT successful........\n");
        return i;
    }

    /* wait for the sgmii lock */
    do
    {
        stat = SGMII_REGS->STATUS;
        stat = stat & 0x10;
    } while( stat != 0x10 );    

    /* wait for the Link to Come Up */
    do
    {
        stat = SGMII_REGS->STATUS;
        stat = stat & 0x5;
    } while( stat != 0x5 );

    printf("SerDes should be up and running ...\n");

    /* Return success */
    return 0;
}

/**
 *  @b HwPktClose
 *  @n
 *      Closes EMAC and disables interrupts.
 *
 *  @param[in]  pi
 *      PDINFO structure pointer.
 *
 *  @retval
 *      void
 */
void HwPktClose( PDINFO *pi )
{
	Uint32 i;

    (void)pi;

	Interrupt_end();

    printf("Calling EMAC_close()\n");

    i = EMAC_close( hEMAC );

	if( i )
	{
		csl_errors++;
        printf("EMAC Close Returned error %08x\n",i);
    }

    hEMAC = 0;
}

/**
 *  @b HwPktSetRx
 *  @n
 *      Sets the filter for EMAC. Also sets ram or hash multicast addresses.
 *
 *  @param[in]  pi
 *      PDINFO structure pointer.
 *
 *  @retval
 *      void
 */
void HwPktSetRx( PDINFO *pi )
{
    uint        tmp1,tmp2;
    int         i;
    Uint8       HashVal,tmpval,*pMCastList;
    UINT32      temp,temp1,MacHash1,MacHash2;

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

    if ( RAM_MCAST && (PKT_MAX_MCAST < 32) )        /* Use RAM based multicast list */
    {

        /* Clear the multicast list */
        for (i = 1; i < 32; i++)
        {
            EMAC_REGS->MACINDEX = i;
            EMAC_REGS->MACADDRHI = 0;
            EMAC_REGS->MACADDRLO = 0;
        }

        /* For each address in the list, add it to the RAM */
        pMCastList = pi->bMCast;
        for( tmp1=0; tmp1<pi->MCastCnt; tmp1++ )
        {
            EMAC_REGS->MACINDEX = tmp1+1;

            temp = 0;

            for( i=3; i>=0; i-- )
                    temp = (temp<<8) | *(pMCastList+i);
            EMAC_REGS->MACADDRHI = temp;

            temp = *(pMCastList+4);
            temp1 = *(pMCastList+5);
            EMAC_REGS->MACADDRLO =  CSL_FMKT( EMAC_MACADDRLO_VALID, VALID ) |
                                    CSL_FMKT( EMAC_MACADDRLO_MATCHFILT, MATCH ) |
                                    CSL_FMK( EMAC_MACADDRLO_CHANNEL, 0 ) |
                                    (temp1<<8) | temp ;
			pMCastList+=6;
        }
	}


    if ( HASH_MCAST )       /* Use hash tables multicast */
    {
        /* 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));
        }
	}

	((EMAC_Device *)hEMAC)->MacHash1 = MacHash1;
	((EMAC_Device *)hEMAC)->MacHash2 = MacHash2;

    /* Enable Channel 0 as the master channel, i.e. the one
     * which receives and processes broadcast traffic.
     */
	Disable_DSP_Interrupts();
	i = EMAC_setReceiveFilter( hEMAC, pi->Filter, 0);
	Enable_DSP_Interrupts();

	if( i )
	{
		csl_errors++;
		printf("EMAC_setReceiveFilter Returned error %08x\n",i);
		HwPktClose (pi);
	}
}

/**
 *  @b HwPktTxNext
 *  @n
 *      Routine to send out a packet.
 *
 *  @param[in]  pi
 *      PDINFO structure pointer.
 *
 *  @retval
 *      void
 */
void HwPktTxNext( PDINFO *pi )
{
#ifdef EXTERNAL_MEMORY
    register UINT8     *buffer;
    register uint      length;
#endif
    PBM_Handle         hPkt;
	EMAC_Pkt*		   csl_send_pkt;
	Uint32             i;

    /* Checking for any queued packets to be transmitted */

    /* First check the Raw Packet Tx Queue. If there are any
     * pending packets in this queue, always transmit them
     * first over the IP packets.
     */
    hPkt = PBMQ_deq(&pi->PBMQ_rawtx);
   
    /* Check if no raw packet to transmit and if any
     * IP packet to transmit. If no raw or IP packets to 
     * transmit, set the "Transmitter Free" TxFree
     * flag for this device to 1.
     */
    if( !hPkt && !(hPkt = PBMQ_deq(&pi->PBMQ_tx)) )
    {
        pi->TxFree = 1;
        return;
    }

#ifdef EXTERNAL_MEMORY
    buffer = PBM_getDataBuffer(hPkt) + PBM_getDataOffset(hPkt);
    length = PBM_getBufferLen(hPkt);

    /* Clean the cache for external addesses */
    if( (UINT32)buffer & EXTMEM )
        OEMCacheClean( (void *)buffer, length );
#endif

	csl_send_pkt = Queue_pop( &TxQueue );

	if( csl_send_pkt )
	{
		csl_send_pkt->AppPrivate 	= (Uint32)hPkt;
		csl_send_pkt->pDataBuffer	= PBM_getDataBuffer(hPkt);
	    csl_send_pkt->BufferLen  	= PBM_getBufferLen(hPkt);
	    csl_send_pkt->Flags      	= EMAC_PKT_FLAGS_SOP | EMAC_PKT_FLAGS_EOP;
	    csl_send_pkt->ValidLen   	= PBM_getValidLen(hPkt);
	    csl_send_pkt->DataOffset 	= PBM_getDataOffset(hPkt);
	    csl_send_pkt->PktChannel 	= pPDI->PhysIdx;
	    csl_send_pkt->PktLength  	= PBM_getValidLen(hPkt);
	    csl_send_pkt->PktFrags   	= 1;

		Disable_DSP_Interrupts();
		i = EMAC_sendPacket(hEMAC, csl_send_pkt);
		Enable_DSP_Interrupts();

		if( i )
		{
			csl_errors++;
            printf("EMAC_sendPacket() returned error %08x\n",i);

			/* Free the packet as the packet did not go on the wire*/
			PBM_free( (PBM_Handle)csl_send_pkt->AppPrivate );

			Queue_push( &TxQueue, csl_send_pkt );
        }

		/* Packet has been transmitted */
		return;
	}

	/* Free the packet as the packet did not go on the wire. */
	PBM_free((PBM_Handle)hPkt);
	return;
}


/**
 *  @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 mdioStatus,phy,linkStatus;

    (void)pi;

    if( fTimerTick && hMDIO )
    {
        llEnter();
        Disable_DSP_Interrupts();
	        
        /* 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
                    || linkStatus == MDIO_LINKSTATUS_FD1000 )
                {
                    CSL_FINST( EMAC_REGS->MACCONTROL, EMAC_MACCONTROL_FULLDUPLEX, ENABLE );
                }
                else
                {
                    CSL_FINST( EMAC_REGS->MACCONTROL, EMAC_MACCONTROL_FULLDUPLEX, DISABLE );
                }

                if( linkStatus == MDIO_LINKSTATUS_FD1000 )
                    CSL_FINST(EMAC_REGS->MACCONTROL, EMAC_MACCONTROL_GIG, ENABLE );

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

            /* Notify application of link status change */
	        EMAC_linkStatus( phy, linkStatus );
        }
        else if ( mdioStatus == MDIO_EVENT_PHYERROR)
		{
		    printf(" NO PHY CONNECTED \n");
        }

	    Enable_DSP_Interrupts();
	    llExit();
    }
}

/**
 *  @b HwRxInt
 *  @n
 *      Receive Packet ISR.
 *
 *  @param[in]  void
 *
 *  @retval
 *      void
 */
void HwRxInt(void)
{
	Uint32 i;

	if ( hEMAC )
    {
        i = EMAC_RxServiceCheck(hEMAC);

		if( i )
		{
			if (i == EMAC_ERROR_MACFATAL)
				emac_fatal_error++;
			else
				csl_errors++;
		}
    }

    return;
}

/**
 *  @b HwTxInt
 *  @n
 *      Transmit Complete ISR.
 *
 *  @param[in]  void
 *
 *  @retval
 *      void
 */
void HwTxInt(void)
{
	Uint32 i;

    if (hEMAC)
    {
        i = EMAC_TxServiceCheck(hEMAC);

		if(i)
		{
			if (i == EMAC_ERROR_MACFATAL)
				emac_fatal_error++;
			else
				csl_errors++;
		}
    }

    return;
}

/**
 *  @b Interrupt_init
 *  @n
 *      Registering Interrupts and Enabling global interrupts.
 *
 *  @param[in]  void
 *
 *  @retval
 *      void
 */
void Interrupt_init(void)
{
    IntSetup    hwi_intSetup;
    Uint32      retVal;

    /* Setup the Rx Int using NDK's Interrupt Manager */
    hwi_intSetup.intVectId = 6;
    hwi_intSetup.sysEvtCount = 1;
    hwi_intSetup.sysEvtId[0] = CSL_INTC_EVENTID_MACRXINT;
    hwi_intSetup.pCallbackFxn = &HwRxInt;
    hwi_intSetup.pCallbackArg = 0;
    hwi_intSetup.bEnable = 1;

    retVal = Interrupt_add(&hwi_intSetup);
    if(retVal != 0)
        printf("Error setting up Rx Interrupts \n");

    /* Setup the Tx Int using NDK's Interrupt Manager */
    hwi_intSetup.intVectId = 7;
    hwi_intSetup.sysEvtCount = 1;
    hwi_intSetup.sysEvtId[0] = CSL_INTC_EVENTID_MACTXINT;
    hwi_intSetup.pCallbackFxn = &HwTxInt;
    hwi_intSetup.pCallbackArg = 0;
    hwi_intSetup.bEnable = 1;

    retVal = Interrupt_add(&hwi_intSetup);
    if(retVal != 0)
        printf("Error setting up Tx Interrupts \n");
   
   Enable_DSP_Interrupts();
}


/**
 *  @b Interrupt_end
 *  @n
 *      Deregistering the interrupts and disabling global interrupts.
 *
 *  @param[in]  void
 *
 *  @retval
 *      void
 */
void Interrupt_end(void)
{
   Disable_DSP_Interrupts();
}
