/**
 * cpsw_impl.c
 * 
 *
 * Copyright (c) 2012 Texas Instruments Incorporated ALL RIGHTS RESERVED
 *
*/

/** ============================================================================
 *   @file  cpsw_impl.c
 *
 *   @brief  CPSW implementation using Starterware APIs
 *
 *  \par
 *  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.
 *
 *  \par
 *  Although the EMAC API is defined to support multiple device instances,
 *  this version supports a single device instance
 */

#include "cpsw_impl.h"
#include "cpsw_ethdriver.h"
#include "osdrv_tlk110.h"

#define CPSW3G_USE_INTERRUPT_PACING

static Uint32           openFlag = 0;
/**< Flag to indicate if the EMAC is already opened.                        */
static Cpsw3gDevice      localDev;
/**< Local copy of the EMAC device instance                                 */

Uint32                  cpswNumBdsAllocated = 0;
/* Number of EMAC BDs allocated so far. Shared global variable between the
 * Tx and Rx InitChannel routines.                                          */

extern cpsw_callback_ret_t cpsw_tx_packet_exception_callback;

#ifdef DEBUG_STATS
CPSW_RAWETH_STAT cpsw_raweth_stat;
#endif
/* Defines the num of ports, set using boardType */
extern UInt8 cpsw_num_ports;
extern UInt8 cpsw_num_mac_ports;
static void emacUpdateStats(Cpsw3gDevice *pd);
/* Queue Helper Functions                                                   */
static CPSW_Pkt *pqPop( CPSW_PKTQ *pq );
static void pqPush( CPSW_PKTQ *pq, CPSW_Pkt *pPktHdr );
static void pqPushChain( CPSW_PKTQ *pq, CPSW_Pkt *pPktHdrFirst, CPSW_Pkt *pPktHdrLast, Uint32 Count );
/**********************************************************************
 ********************** BD Management Functions ***********************
 **********************************************************************/
static void emacEnqueueTx(CPSW_DescCh *pdc);
static void emacDequeueTx(CPSW_DescCh *pdc, CPSW_Desc *pDescLast);
static void emacEnqueueRx(CPSW_DescCh *pdc, Uint32 fRestart);
static void emacDequeueRx(CPSW_DescCh *pdc, CPSW_Desc *pDescAck);

/** ============================================================================
 *  @n@b pqPop()
 *
 *  @b Description
 *  @n Pop a desc buffer off a queue
 *
 *  @b Arguments
 *  @verbatim
        pq      pointer to packet queue
    @endverbatim
 *
 *  <b> Return Value </b>  Pointer to EMAC packet
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b>
 *  @n  Descriptor buffer from the Queue is removed
 *
 *  @b Example
 *  @verbatim
        CPSW_PKTQ *pq;
        pqPop( pq );
    @endverbatim
 * ============================================================================
 */
static CPSW_Pkt *pqPop(CPSW_PKTQ *pq)
{
	CPSW_Pkt *pPktHdr;

    pPktHdr = pq->pHead;

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

    return (pPktHdr);
}

/** ============================================================================
 *  @n@b pqPush()
 *
 *  @b Description
 *  @n Push a desc buffer onto a queue
 *
 *  @b Arguments
 *  @verbatim
        pq      pointer to packet queue
        pPktHdr pointer to the EMAC packet
    @endverbatim
 *
 *
 *  <b> Return Value </b>  None
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b>
 *  @n  Descriptor buffer from the Queue is added
 *
 *  @b Example
 *  @verbatim
        CPSW_PKTQ *pq;
        CPSW_Pkt *pPktHdr

        pqPush( pq, pPktHdr );
    @endverbatim
 * ============================================================================
 */
static void pqPush(CPSW_PKTQ *pq, CPSW_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++;
}

/** ============================================================================
 *  @n@b pqPushChain()
 *
 *  @b Description
 *  @n Push a desc buffer chain onto a queue
 *
 *  @b Arguments
 *  @verbatim
        pq              pointer to packet queue
        pPktHdrFirst    pointer to the first element of the EMAC Packet.
        pPktHdrLast     pointer to the last element of the EMAC Packet.
        Count           count of elements to push
    @endverbatim
 *
 *
 *  <b> Return Value </b>  None
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b>
 *  @n  A chain of descriptor buffers are added to the Queue
 *
 *  @b Example
 *  @verbatim
        CPSW_PKTQ *pq;
        CPSW_Pkt *pPktHdrFirst, *pPktHdrLast;
        Uint32 Count;

        pqPushChain( pq, pPktHdrFirst, pPktHdrLast, Count );
    @endverbatim
 * ============================================================================
 */
static void pqPushChain(CPSW_PKTQ *pq, CPSW_Pkt *pPktHdrFirst,
		CPSW_Pkt *pPktHdrLast, Uint32 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;
}

/** ============================================================================
 *  @n@b emacUpdateStats()
 *
 *  @b Description
 *  @n Update our local copy of the statistics
 *
 *  @b Arguments
 *  @verbatim
        pd  pointer to EMAC object
    @endverbatim
 *  <b> Return Value </b>  None
 *
 *  <b> Pre Condition </b>
 *  @n  EMAC peripheral instance must be opened
 *
 *  <b> Post Condition </b>
 *  @n  Update local copy of the statistics to the EMAC registers
 *
 *  @b Example
 *  @verbatim
        Cpsw3gDevice *pd;

        emacUpdateStats( pd );
    @endverbatim
 * ============================================================================
 */
static void emacUpdateStats( Cpsw3gDevice *pd )
{
    int             i;

    unsigned long long          *pStatAddr;
    Uint32          statval;

    pStatAddr = (unsigned long long *)(&pd->Stats);

    /*
     * There are "CPSW_NUMSTATS" statistics registers
     * Note that when GMIIEN is set in MACCONTROL, these registers
     * are "write to decrement".
     */
    for (i = 0; i < CPSW_NUMSTATS; i++)
    {
        statval = CPSWSTATSRead(localDev.Config.baseConfig.stat_base, i);
		*pStatAddr += statval;
		*pStatAddr++;
    }
}

/** ============================================================================
 *  @n@b emacEnqueueTx()
 *
 *  @b Description
 *  @n Enqueue a TX packet and restart transmitter as needed
 *
 *  @b Arguments
 *  @verbatim
        pq  pointer to Channel descriptor
    @endverbatim
 *
 *  <b> Return Value </b>  None
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b>
 *  @n  Enqueue a TX packet and restart transmitter as needed
 *
 *  @b Example
 *  @verbatim
        CPSW_DescCh *pdc;

        emacEnqueueTx ( pdc );
    @endverbatim
 * ============================================================================
 */
static void emacEnqueueTx(CPSW_DescCh *pdc)
{
	CPSW_Desc       *pDescOrg;
	CPSW_Desc       *pDescThis;
    CPSW_Pkt        *pPkt;
    Uint32          PktFrags;
    Uint32          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 (void *)0
             * 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 & CPDMA_BUF_DESC_SOP)
                pDescThis->PktFlgLen = ((pPkt->Flags&
                                       (CPDMA_BUF_DESC_SOP|CPDMA_BUF_DESC_EOP))
                                       |pPkt->PktLength|CPDMA_BUF_DESC_OWNER);
            else
                pDescThis->PktFlgLen = (pPkt->Flags&CPDMA_BUF_DESC_EOP)
                                       |CPDMA_BUF_DESC_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 =  (CPSW_Desc *)(CPU_TO_HW((Uint32)pDescOrg));

        }
        else
        {
            /* Transmitter is not running, start it up */
            CPSWCPDMATxHdrDescPtrWrite(localDev.Config.baseConfig.cpdma_base, CPU_TO_HW(((Uint32)pDescOrg)), pdc->chInfo->chNum);

        }
    }
}

/** ============================================================================
 *  @n@b emacDequeueTx()
 *
 *  @b Description
 *  @n Dequeue all completed TX packets and return buffers to application
 *
 *  @b Arguments
 *  @verbatim
        pdc         pointer to channel descriptor
        pDescAck    pointer to Descriptor object
    @endverbatim
 *
 *  <b> Return Value </b>  None
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b>
 *  @n  Dequeue all completed TX packets and return buffers to application
 *
 *  @b Example
 *  @verbatim
        CPSW_DescCh *pdc;
        CPSW_Desc *pDescAck;

        emacDequeueTx ( pdc, pDescAck );
    @endverbatim
 * ============================================================================
 */
 
static void emacDequeueTx(CPSW_DescCh *pdc, CPSW_Desc *pDescAck)
{
	CPSW_Pkt        *pPkt;
    Uint32          PktFlgLen;
    register Uint32   i;
    register Uint32   j = (Uint32)pdc->pDescRead;
	
    /* address obbtained from Completion Pointer is HW address,convert to CPU */
    pDescAck = (CPSW_Desc*)  (  HW_TO_CPU(((Uint32)pDescAck))  );

    /* 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 = (Uint32)pdc->pDescRead;

    /* Turn i into a descriptor count */
    if( j < i )
        i = (i-j)/sizeof(CPSW_Desc);
    else
        i = pdc->DescMax - ((j-i)/sizeof(CPSW_Desc));

	if (pdc->DescCount == 0)
		i = 0;
	else
		pdc->DescCount -= i;	
    /* Pop & \nFree Buffers 'till the last Descriptor */
    while (((int)(i--)) > 0)
    {
        /* 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 & CPDMA_BUF_DESC_EOQ) && pdc->DescCount)
    {
        CPSWCPDMATxHdrDescPtrWrite(localDev.Config.baseConfig.cpdma_base, CPU_TO_HW(((Uint32)pdc->pDescRead)), pdc->chInfo->chNum);
    }

    /* Try to post any waiting TX packets */
    if (pdc->WaitQueue.Count)
        emacEnqueueTx(pdc);
}

/** ============================================================================
 *  @n@b emacEnqueueRx()
 *
 *  @b Description
 *  @n Fill any empty RX descriptors with new buffers from the application
 *
 *  @b Arguments
 *  @verbatim
        pdc         pointer to Descriptor object
        fRestart    re-fill packet
    @endverbatim
 *
 *  <b> Return Value </b>  None
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b>
 *  @n  Fill any empty RX descriptors with new buffers from the application.
 *
 *  @b Example
 *  @verbatim
        CPSW_DescCh  *pdc;
        Uint32         fRestart;

        emacEnqueueRx( pdc, fRestart );
    @endverbatim
 * ============================================================================
 */
static void emacEnqueueRx(CPSW_DescCh *pdc, Uint32 fRestart)
{
	CPSW_Pkt        *pPkt;
	CPSW_Desc       *pDesc;
    Uint32            CountOrg;

    /* Keep the old count around */
    CountOrg = pdc->DescCount;

    /* Fill RX Packets Until Full */
    while (pdc->DescCount < pdc->DescMax)
    {
        /* Get a buffer from the application */
        pPkt = (*localDev.Config.pfcbGetPacket)(pdc->pd->hApplication);

        /* If no more buffers are available, break out of loop */
        if (!pPkt)
            break;

        /* Fill in the descriptor for this buffer */
        pDesc = pdc->pDescWrite;

        /* Move the write pointer and bump count */
        if (pdc->pDescWrite == pdc->pDescLast)
            pdc->pDescWrite = pdc->pDescFirst;
        else
            pdc->pDescWrite++;
        pdc->DescCount++;

        /* Supply buffer pointer with application supplied offset */
        pDesc->pNext     = 0;
        pDesc->pBuffer   = pPkt->pDataBuffer + pPkt->DataOffset;
        pDesc->BufOffLen = 1518;//localDev.PktMTU;set in maccfg which is after dma config.hence it was zero
        pDesc->PktFlgLen = CPDMA_BUF_DESC_OWNER;

        /* Make the previous buffer point to us */
        if (pDesc == pdc->pDescFirst)
             pdc->pDescLast->pNext = (CPSW_Desc *)(CPU_TO_HW((Uint32)pDesc));
        else
            (pDesc-1)->pNext = (CPSW_Desc *)(CPU_TO_HW((Uint32)pDesc));

        /* Push the packet buffer on the local descriptor queue */
        pqPush(&pdc->DescQueue, pPkt);
    }

    /* Restart RX if we had ran out of descriptors and got some here */
    if (fRestart && !CountOrg && pdc->DescCount)
    {
        CPSWCPDMATxHdrDescPtrWrite(localDev.Config.baseConfig.cpdma_base, CPU_TO_HW(((Uint32)pdc->pDescRead)), pdc->chInfo->chNum);
    }
}

/** ============================================================================
 *  @n@b emacDequeueRx()
 *
 *  @b Description
 *  @n Dequeue all completed RX packets and give buffers to application
 *
 *  @b Arguments
 *  @verbatim
        pdc         pointer to descriptor channel object
        pDescAck    pointer to the acknowledge
    @endverbatim
 *
 *  <b> Return Value </b>  None
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b>
 *  @n  Dequeue all completed RX packets and give buffers to application
 *
 *  @b Example
 *  @verbatim
        CPSW_DescCh *pdc;
        CPSW_Desc   *pDescAck;

        emacDequeueRx( pdc, pDescAck );
    @endverbatim
 * ============================================================================
 */
static void emacDequeueRx(CPSW_DescCh *pdc, CPSW_Desc *pDescAck)
{
	CPSW_Pkt    *pPkt;
	CPSW_Pkt    *pPktNew;
	CPSW_Desc   *pDescNewRxFirst;
	CPSW_Desc   *pDescNewRxLast=0;
	CPSW_Desc   *pTemp;
    Uint32      tmp;
    Uint32      PktFlgLen;

	/* address obbtained from Completion Pointer is HW address,convert to CPU */
    pDescAck = (CPSW_Desc*)  ( HW_TO_CPU((Uint32)pDescAck)  );

    /* Remember the first new descriptor slot */
    pDescNewRxFirst = pdc->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 = pdc->pDescRead->PktFlgLen;

		/* Bit 16,17 and 18 indicate the port number(ingress)
		 * Passcrc bit is always set in the received packets.Clear it before putting the \
		 * packet in receive queue */
		PktFlgLen = PktFlgLen & 0xFBFFFFFF;
		
		/* Check the ownership of the packet */
        if (!(PktFlgLen & 0x20000000))
        {
			/* Recover the buffer and free it */
			pPkt = pqPop(&pdc->DescQueue);
			if (pPkt)
			{
				/* Fill in the necessary packet header fields */
				pPkt->Flags = PktFlgLen & 0xFFFF0000;
				pPkt->ValidLen = pPkt->PktLength = PktFlgLen & 0xFFFF;
				pPkt->PktChannel = pdc->chInfo->chNum;
				pPkt->PktFrags = 1;

				/* Pass the packet to the application */
				pPktNew = (*localDev.Config.pfcbRxPacket)
											   (pdc->pd->hApplication,pPkt);
			}

			/* See if this was the last buffer */
			if (pdc->pDescRead == pDescAck)
				tmp = 0;

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

			/* See if we got a replacement packet */
			if(pPktNew)
			{
				/* We know we can immediately queue this packet */

				/* Fill in the descriptor for this buffer */
				pDescNewRxLast = pdc->pDescWrite;

				/* Move the write pointer and bump count */
				if( pdc->pDescWrite == pdc->pDescLast )
					pdc->pDescWrite = pdc->pDescFirst;
				else
					pdc->pDescWrite++;
				pdc->DescCount++;

				/* Supply buffer pointer with application supplied offset */
				pDescNewRxLast->pBuffer   = pPktNew->pDataBuffer + pPktNew->DataOffset;
				pDescNewRxLast->BufOffLen = localDev.PktMTU;
				pDescNewRxLast->PktFlgLen = CPDMA_BUF_DESC_OWNER;

				/* Push the packet buffer on the local descriptor queue */
				pqPush(&pdc->DescQueue, pPktNew);
			}
		}
        else
        {
			tmp = 0;
		}
    }

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

        /* Make the previous buffer point to us */
        if (pDescNewRxFirst == pdc->pDescFirst)
            pTemp = pdc->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 = (CPSW_Desc *)(CPU_TO_HW((Uint32)pDescNewRxFirst));
    }

    /* If the receiver stopped and we have more descriptors, then restart */
    if ((PktFlgLen & CPDMA_BUF_DESC_EOQ) && pdc->DescCount)
    {
       CPSWCPDMARxHdrDescPtrWrite(localDev.Config.baseConfig.cpdma_base, (Uint32)(CPU_TO_HW((Uint32)pdc->pDescRead)), pdc->chInfo->chNum);
    }
}

/**********************************************************************
 ***************** Switch Configuration Functions *********************
 **********************************************************************/

Uint32 cpsw3g_get_interrupt()
{
	return CPSWCPDMAIntVectorGet(localDev.Config.baseConfig.cpdma_base);
}
/** ============================================================================
 *  @n@b cpsw3g_SetMacCfg()
 *
 *  @b Description
 *  @n Configures the MAC port settings.
 *
 *  @b Arguments
 *  @verbatim
        hPort       pointer to port object
    @endverbatim
 *
 *  <b> Return Value </b>  None
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b>
 *  @n  Configures the MAC_CONTROL register for the specific port
 *
 *  @b Example
    @endverbatim
 * ============================================================================
 */
static void cpsw3g_SetMacCfg(Cpsw3gPort* hPort)
{
    Cpsw3gInitConfig*   cpsw3gCfg = &localDev.Config;
    Uint32 portNo = 0,macNo = 0;
    CpgmacMacConfig*    lpMacConfign = 0;

    portNo = hPort->portNum;  
    if (portNo > 0) 
    	macNo =  portNo - 1;

    if(portNo > 2)//only GMAC port 0 and port 1 are valid 
    {
        /* error condition */
        info_printf("Error in SetMacCfg\n");
        /* return without doing anything, you
         * cant dereference past instances 0 & 1
         * of CPGMAC_SL config structures */
    }
    else
    {
    	Uint32 macInitCfg = 0;
    	macInitCfg = cpsw3gCfg->macInitCfg[macNo].macModeFlags;

    	lpMacConfign = &cpsw3gCfg->macInitCfg[macNo];

        localDev.PktMTU = (cpsw3gCfg->PktMTU);


		if (macInitCfg & CPSW_CONFIG_MODEFLG_GIGABIT)
			CPSWSlGMIIEnable(localDev.Config.baseConfig.port[macNo].sliver_base);

		if (macInitCfg & CPSW_CONFIG_MODEFLG_IFCTLA)
			CPSWSlIFCTLAEnable(localDev.Config.baseConfig.port[macNo].sliver_base);

		if (macInitCfg & CPSW_CONFIG_MODEFLG_FULLDUPLEX)
			CPSWSlFullDuplexEnable(localDev.Config.baseConfig.port[macNo].sliver_base);

	    /* Configure the MDIO params, i.e. speed, duplex */

        if(lpMacConfign->mdioModeFlags & CPSW_MDIO_MODEFLG_NOPHY)
            lpMacConfign->phyMode = NWAY_NOPHY;                
        else if(lpMacConfign->mdioModeFlags & CPSW_MDIO_MODEFLG_AUTONEG)
        {
            /* If this MAC port is marked for internal PHY loopback,
             * configure the MDIO parameters appropriately.
             */
            if(lpMacConfign->mdioModeFlags & CPSW_MDIO_MODEFLG_LOOPBACK)
                lpMacConfign->phyMode = NWAY_FD100|NWAY_FD10|NWAY_HD100|NWAY_HD10|NWAY_AUTO;
            else
                lpMacConfign->phyMode = NWAY_AUTO|NWAY_FD1000|NWAY_FD100|NWAY_FD10|NWAY_HD100|NWAY_HD10;

        }
        else 
        {
            if(lpMacConfign->mdioModeFlags & CPSW_MDIO_MODEFLG_HD10)
                lpMacConfign->phyMode = NWAY_HD10;
            if(lpMacConfign->mdioModeFlags & CPSW_MDIO_MODEFLG_FD10)
                lpMacConfign->phyMode |= NWAY_FD10;
            if(lpMacConfign->mdioModeFlags & CPSW_MDIO_MODEFLG_HD100)
                lpMacConfign->phyMode |= NWAY_HD100;
            if(lpMacConfign->mdioModeFlags & CPSW_MDIO_MODEFLG_FD100)
                lpMacConfign->phyMode |= NWAY_FD100;
            if(lpMacConfign->mdioModeFlags & CPSW_MDIO_MODEFLG_FD1000)
                lpMacConfign->phyMode |= NWAY_FD1000;
        }

    }

    return;
}


/** ============================================================================
 *  @n@b cpsw3g_SetCpswCfg()
 *
 *  @b Description
 *  @n Configures the switch settings based on user configuration.
 *
 *  @b Arguments
 *  @verbatim
 *      None
    @endverbatim
 *
 *  <b> Return Value </b>  None
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b>
 *  @n  Configures the CPSW_STAT_PORT_EN registers
 *      for the DMA port.
 *
 *  @b Example
    @endverbatim
 * ============================================================================
 */
static void cpsw3g_SetCpswCfg(void)
{
    Cpsw3gInitConfig*   cpsw3gCfg = &localDev.Config;
    /* Local Pointer to Switch Configuration */
    Cpsw3gConfig*       lpCpswCfg = &cpsw3gCfg->cpswCfg;

	if (lpCpswCfg->cpswStatModeFlags & CPSW_CONFIG_STAT_ENABLE)
		CPSWStatisticsEnable(cpsw3gCfg->baseConfig.ss_base);
}

/** ============================================================================
 *  @n@b cpsw3g_SetAleCfg()
 *
 *  @b Description
 *  @n Configures Address lookup engine (ALE) of EMAC.
 *
 *  @b Arguments
 *  @verbatim
 *      None
    @endverbatim
 *
 *  <b> Return Value </b>  None
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b>
 *  @n  Configures the ALE_CONTROL, ALE_PRESCALE, ALE_UNKNOWN_VLAN registers
 *
 *  @b Example
    @endverbatim
 * ============================================================================
 */
static void cpsw3g_SetAleCfg(void)
{
    Cpsw3gInitConfig*   cpsw3gCfg = &localDev.Config;
    /* Local Pointer to Ale Configuration */
    AleConfig*          lpAleConfig = &cpsw3gCfg->aleCfg;

    CPSWALEInit(cpsw3gCfg->baseConfig.ale_base);

    /* Clear out toggle bits */
    lpAleConfig->aleModeFlags &= ~(CPSW_CONFIG_ALE_CLRTABLE
                                 | CPSW_CONFIG_ALE_AGEOUTNOW);

    /* Configure ALE Prescale register */
    CPSWALEPrescaleSet(cpsw3gCfg->baseConfig.ale_base, lpAleConfig->alePrescale);
}

/** ============================================================================
 *  @n@b cpsw3g_SetAlePortCfg()
 *
 *  @b Description
 *  @n Configures Address lookup engine (ALE) settings for the specific MAC port.
 *
 *  @b Arguments
 *  @verbatim
 *      None
    @endverbatim
 *
 *  <b> Return Value </b>  None
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b>
 *  @n  Configures the ALE_PORTCTL register
 *
 *  @b Example
    @endverbatim
 * ============================================================================
 */
static void cpsw3g_SetAlePortCfg(Cpsw3gPort* hPort)
{
    Cpsw3gInitConfig*   cpsw3gCfg = &localDev.Config;
    Uint32 portNo = 0;
    /* Local Pointer to AlePort Configuration */
    AlePortConfig *lpAlePortConfign = 0;

    portNo = hPort->portNum;
    lpAlePortConfign = &cpsw3gCfg->alePortCfg[portNo];

	CPSWALEPortStateSet(cpsw3gCfg->baseConfig.ale_base, portNo, lpAlePortConfign->portState);
}

/** ============================================================================
 *  @n@b cpsw3g_Update_Phystatus()
 *
 *  @b Description
 *  @n This function configures the MACCONTROL register according to the user
 *  defined PHY speed, duplex link settings.
 *
 *  @b Arguments
 *  @verbatim
 *      gmacObject          GMAC Object whose PHY needs to be updated
 *      instanceNum         MAC port identifier
    @endverbatim
 *
 *  <b> Return Value </b>   
 *  @n  Always returns CPSW3G_SUCCESS
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b>
 *  @n  Configures the GMAC_MACCONTROL register
 *
 *  @b Example
    @endverbatim
 * ============================================================================
 */
Uint32 cpsw3g_Update_Phystatus(CpgmacObj* gmacObject , Uint32 instanceNum)
{
    Cpsw3gInitConfig*   cpsw3gCfg = &localDev.Config;
	Uint32              setPhyMode, macControl;
	CPSW_PHY_DEVICE*         PhyDev =  &gmacObject->PhyDev;
	
    setPhyMode = cpsw3gCfg->macInitCfg[instanceNum].phyMode;

  	macControl = CPSWSlMACControlGet(cpsw3gCfg->baseConfig.port[instanceNum].sliver_base);
  	/* No Phy Condition */
  	if(0u != (setPhyMode & NWAY_NOPHY))
   	{
        /* No Phy condition, always linked */
      	gmacObject->PhyLinked = 1;
      	gmacObject->PhySpeed = 1;
      	gmacObject->PhyDuplex = 1;
      	gmacObject->PhyNum = 0xFFFFFFFF;  /* No Phy */

      	CPSWSlMACControlSet(cpsw3gCfg->baseConfig.port[instanceNum].sliver_base, macControl);
    }
	else
	{
  	    /* If loopback set in hardware, set link to ON */
	    if(0u != (macControl & CPSW_SL_MACCONTROL_LOOPBACK))
    	{
       		gmacObject->PhyLinked = 1;
    	}
	    else
	    {
		    if(0u != (setPhyMode & NWAY_LPBK))
    	    {
		        gmacObject->PhyLinked = cpsw_MDIO_GetLoopback(PhyDev);
	        }
  	        else
    	    {
		        gmacObject->PhyLinked = cpsw_MDIO_GetLinked(PhyDev);
    	    }

		    if (0u != (gmacObject->PhyLinked) )
    	    {
      		    /*  Retreive Duplex and Speed and the Phy Number  */
		        if (0u != (setPhyMode & NWAY_LPBK))
		        {
			        gmacObject->PhyDuplex = 1; 
		        }
      		    else
		        { 
			        gmacObject->PhyDuplex = cpsw_MDIO_GetDuplex(PhyDev);
        	    }

		        gmacObject->PhySpeed  = cpsw_MDIO_GetSpeed(PhyDev);

		        if (gmacObject->PhySpeed != 2)
      		    {
      			    gmacObject->PhySpeed = (gmacObject->PhySpeed >> 10);
      		    }

		        gmacObject->PhyNum =  cpsw_MDIO_GetPhyNum(PhyDev);

      		    /* Set the duplex bit in maccontrol */
		        /* Commented out as a workout to the HD issue with CPSW */
		        //if (0u != (gmacObject->PhyDuplex))
		        //{
			        macControl |= (1 << CPSW_SL_MACCONTROL_FULLDUPLEX_SHIFT);
		        //}
      		    //else
		        //{
			    //    macControl &= ~(1 << CPSW_SL_MACCONTROL_FULLDUPLEX_SHIFT);
		        //}

		        if(0 == gmacObject->PhySpeed)
		        {
		        	macControl |= 1 << CPSW_SL_MACCONTROL_EXT_EN_SHIFT;
		        }
		        else
		        {
		        	macControl &= ~(1 << CPSW_SL_MACCONTROL_EXT_EN_SHIFT);
		        }
    	    }
  	
  	        /* Write mac control register from stored value */
	      	CPSWSlMACControlSet(cpsw3gCfg->baseConfig.port[instanceNum].sliver_base, macControl);

	    }
	}

	return (CPSW3G_SUCCESS);
}

/** ============================================================================
 *  @n@b cpsw3g_ControlCb()
 *
 *  @b Description
 *  @n This function is called to update the local copy of device configuration
 *  with the updated Phy status and parameters.
 *
 *  @b Arguments
 *  @verbatim
 *      devPtr              CPSW3G device pointer to be updated
 *      cmd                 Type of update being received. Currently, only one
 *                          supported, i.e. CPSW3G_PHY_STATUS_UPDATE
 *      cmdArg              Command argument, pointer to the updated link parameters
 *      param               Pointer to MAC port object to update.
    @endverbatim
 *
 *  <b> Return Value </b>   
 *  @n  Always returns CPSW3G_SUCCESS
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b> None
 *
 *  @b Example
    @endverbatim
 * ============================================================================
 */
void cpsw3g_ControlCb(Cpsw3gDevice* devPtr,Uint32 cmd,Ptr cmdArg, Ptr param)
{
    static Uint32 linkspeed[2]= {0};
	Cpsw3gPort *hPort = (Cpsw3gPort*)param;
	CpgmacMacStatus *macStat;		
		
    switch (cmd)
	{
        case CPSW3G_PHY_STATUS_UPDATE:
        {
		    macStat = (CpgmacMacStatus*)cmdArg;
						
			devPtr->Config.linkStatus[hPort->portNum] = macStat->PhyLinked;
			if(0u != (macStat->PhyLinked) )
			{
			    devPtr->Config.linkSpeed[hPort->portNum] = 
                                                (macStat->PhySpeed == 2) ? 1000000000 :((macStat->PhySpeed)?100000000 : 10000000);
				devPtr->Config.linkMode[hPort->portNum]  = ((macStat->PhyDuplex) ? 2 : 1);

				if(linkspeed[hPort->portNum]!= devPtr->Config.linkSpeed[hPort->portNum])
                {
                    if(devPtr->Config.linkSpeed[hPort->portNum]== 1000000000)
                    {
                        devPtr->Config.macInitCfg[hPort->portNum].macModeFlags |= CPSW_CONFIG_MODEFLG_GIGABIT;
                    }
                    else
                    {
                        devPtr->Config.macInitCfg[hPort->portNum].macModeFlags &= ~CPSW_CONFIG_MODEFLG_GIGABIT;
                    }

                    if(macStat->PhyDuplex == 1)
                        devPtr->Config.macInitCfg[hPort->portNum].macModeFlags |= CPSW_CONFIG_MODEFLG_FULLDUPLEX;
                    else
                        devPtr->Config.macInitCfg[hPort->portNum].macModeFlags &= ~CPSW_CONFIG_MODEFLG_FULLDUPLEX;
                    cpsw3g_SetMacCfg(hPort);
                }
			
                linkspeed[hPort->portNum]= devPtr->Config.linkSpeed[hPort->portNum];
            }
			else
			{
				if(  (0 == devPtr->Config.linkStatus[0] ) && ( 0 == devPtr->Config.linkStatus[1]) )
				{
				    devPtr->Config.linkSpeed[hPort->portNum] = 100000000;
                    devPtr->Config.linkMode[hPort->portNum]  = 1;
				}
			}
                     	
			break;
        }
		default:
        {
			break;
        }
	}
}

/** ============================================================================
 *  @n@b cpsw3g_SetPhyMode()
 *
 *  @b Description
 *  @n This function configures the appropriate registers with updated PHY
 *  settings and notifies a callback function to update the same in our local
 *  configuration copy.
 *
 *  @b Arguments
 *  @verbatim
 *      gmacObject          GMAC Object whose PHY needs to be updated
 *      instanceNum         MAC port identifier
    @endverbatim
 *
 *  <b> Return Value </b>   None
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b>
 *  @n  Configures the GMAC_MACCONTROL register and updates the local 
 *  config copy to reflect the same.
 *
 *  @b Example
    @endverbatim
 * ============================================================================
 */
static void cpsw3g_SetPhyMode(CpgmacObj* gmacObject,Uint32 instanceNum)
{
    Cpsw3gInitConfig*   cpsw3gCfg = &localDev.Config;
    Uint32 setPhyMode,PhyMode, tempPhyMode;
    CpgmacMacConfig * macInitCfg =  &cpsw3gCfg->macInitCfg[instanceNum];
    CpgmacMacStatus macStat;
    unsigned char disableAutoMDIX = 0;

    setPhyMode = macInitCfg->phyMode;
    PhyMode = 0;

    tempPhyMode = NWAY_AUTO | NWAY_FD10 | NWAY_FD100 | NWAY_FD1000
    					| NWAY_HD10 | NWAY_HD100 | NWAY_HD1000 | NWAY_LPBK | NWAY_AUTOMDIX;

    if(0u != (setPhyMode & tempPhyMode))
    	PhyMode |= (setPhyMode & tempPhyMode);

    /* Added for TLK AutoMDIX fix*/
    if(0u!= (setPhyMode & NWAY_FD10))
    {
	    disableAutoMDIX = 1;
    }
    if(0u != (setPhyMode & NWAY_FD100))
    {
	    disableAutoMDIX = 1;
    }
    if(0u != (setPhyMode & NWAY_HD10 ))
    {
	    disableAutoMDIX = 1;
    }
    if(0u != (setPhyMode & NWAY_HD100))
    {
	    disableAutoMDIX = 1;
    }


    cpsw_MDIO_SetPhyMode(&gmacObject->PhyDev, PhyMode);

    cpsw3g_Update_Phystatus(gmacObject,instanceNum);
	
    //fix for TLK110 MDIX issue
    if(disableAutoMDIX && (0u == (setPhyMode & NWAY_AUTO)))
    {
    	if(mac_configuration.tlk110Flag ==1)
    		tlkDisableAutoMDIX(gmacObject->PhyDev.miibase,mac_configuration.phyAddr[instanceNum]);
    	else
    		tlkEnableAutoMDIX(gmacObject->PhyDev.miibase,mac_configuration.phyAddr[instanceNum]);
    }
    else
    	tlkEnableAutoMDIX(gmacObject->PhyDev.miibase,mac_configuration.phyAddr[instanceNum]);

  	/**CHECK: notify status change thru callback here */
  	macStat.PhyDuplex = gmacObject->PhyDuplex;
  	macStat.PhyLinked =  gmacObject->PhyLinked;
  	macStat.PhyNum = gmacObject->PhyNum;
  	macStat.PhySpeed = gmacObject->PhySpeed;
  	
  	cpsw3g_ControlCb(&localDev, CPSW3G_PHY_STATUS_UPDATE, &macStat, &localDev.cpsw3gPort[instanceNum]);
}

/** ============================================================================
 *  @n@b cpsw3g_EnableChannel()
 *
 *  @b Description
 *  @n This function configures the appropriate registers to initialize a
 *  DMA channel.
 *
 *  @b Arguments
 *  @verbatim
 *      channel             Channel number
 *      direction           Channel Direction, i.e., CPSW_NET_CH_DIR_TX/CPSW_NET_CH_DIR_RX
    @endverbatim
 *
 *  <b> Return Value </b>   
 *  @n  Always returns CPSW3G_SUCCESS
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b>
 *  @n  Initializes the Tx/Rx HDP and enables interrupts on the specific channel.
 *
 *  @b Example
    @endverbatim
 * ============================================================================
 */
static Uint32 cpsw3g_EnableChannel(Uint32 channel, Uint32 direction)
{
    CpdmaObj *dmaObj = &localDev.cpdma;
    Cpsw3gInitConfig*   cpsw3gCfg = &localDev.Config;
    if(direction == CPSW_NET_CH_DIR_TX)
    {
        /* enable a TX Dma channel for transfers here */

        CPSWCPDMATxHdrDescPtrWrite(cpsw3gCfg->baseConfig.cpdma_base, 0, channel);
        CPSWCPDMATxIntEnable(cpsw3gCfg->baseConfig.cpdma_base, channel);
        CPSWWrCoreIntEnable(cpsw3gCfg->baseConfig.wrpr_base, 0, channel, CPSW_CORE_INT_TX_PULSE);

       /* mark the channel as open */
        dmaObj->chIsOpen[CPSW_NET_CH_DIR_TX][channel] = TRUE;
    }
    else
    {
        /* enable RX Dma channel for transfer here */
        Cpsw3gRxCppiCh  *rxChan;

        rxChan = &localDev.cpdma.rxCppi[channel];

        CPSWCPDMARxIntEnable(cpsw3gCfg->baseConfig.cpdma_base, channel);	/*cpswif reference */
        CPSWWrCoreIntEnable(cpsw3gCfg->baseConfig.wrpr_base, 0, channel, CPSW_CORE_INT_RX_PULSE);
        
        /* mark the channel as open */
        dmaObj->chIsOpen[CPSW_NET_CH_DIR_RX][channel] = TRUE;
        /* Init Head Pointer, created the chain in InitRxChannel */

        CPSWCPDMARxHdrDescPtrWrite(cpsw3gCfg->baseConfig.cpdma_base, CPU_TO_HW((Uint32)rxChan->pDescRead), channel);
    }
    
    return (CPSW3G_SUCCESS);
}

/** ============================================================================
 *  @n@b cpsw3g_DisableChannel()
 *
 *  @b Description
 *  @n This function configures the appropriate registers to de-initialize a
 *  DMA channel.
 *
 *  @b Arguments
 *  @verbatim
 *      channel             Channel number
 *      direction           Channel Direction, i.e., CPSW_NET_CH_DIR_TX/CPSW_NET_CH_DIR_RX
    @endverbatim
 *
 *  <b> Return Value </b>   
 *  @n  Always returns CPSW3G_SUCCESS
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b>
 *  @n  De-Initializes the channel by resetting Tx/Rx HDP and disabling interrupts on 
 *  the specific channel.
 *
 *  @b Example
    @endverbatim
 * ============================================================================
 */
static Uint32 cpsw3g_DisableChannel(Uint32 channel, Uint32 direction)
{
    CpdmaObj    *dmaObj = &localDev.cpdma;

    dmaObj->tdPending[direction][channel] = TRUE;

    if(direction == CPSW_NET_CH_DIR_TX)
    {
        /* disable the requested Tx DMA channel here */

        /* command teardown  */
    	CPSWCPDMATxTeardown(localDev.Config.baseConfig.cpdma_base, channel);

        /* wait for ack ,examine CP for 0xfffffffc */
        while(CPSWCPDMATxCPGet(localDev.Config.baseConfig.cpdma_base, channel)
        			!= 0xFFFFFFFC)
        {
        }

        /*disable Tx Interrupt on this channel */
        CPSWCPDMATxIntDisable(localDev.Config.baseConfig.cpdma_base, channel);

        /* also disable in the wrapper */
        CPSWWrCoreIntDisable(localDev.Config.baseConfig.wrpr_base, 0, channel, CPSW_CORE_INT_TX_PULSE);
    }
    else
    {
    	/* disable the requested Rx Dma channel here */

    	/* command teardown  */
    	CPSWCPDMARxTeardown(localDev.Config.baseConfig.cpdma_base, channel);

        /* wait for ack ,examine CP for 0xfffffffc */
	    while(CPSWCPDMARxCPGet(localDev.Config.baseConfig.cpdma_base, channel)
    			!= 0xFFFFFFFC)
	    {
	    }

        /*disable Tx Interrupt on this channel */
        CPSWCPDMARxIntDisable(localDev.Config.baseConfig.cpdma_base, channel);

        /* also disable in the wrapper */
        CPSWWrCoreIntDisable(localDev.Config.baseConfig.wrpr_base, 0, channel, CPSW_CORE_INT_RX_PULSE);
    }

    dmaObj->tdPending[direction][channel] = FALSE;
    dmaObj->chIsOpen[direction][channel] = FALSE;

    return (CPSW3G_SUCCESS);
}

/** ============================================================================
 *  @n@b cpsw3g_InitTxChannel()
 *
 *  @b Description
 *  @n This function sets up the Transmit Buffer descriptors.
 *
 *  @b Arguments
 *  @verbatim
 *      chInfo              Channel object
    @endverbatim
 *
 *  <b> Return Value </b>   
 *  CPSW3G_INVALID_PARAM  -   Returned on BD allocation error 
 *  CPSW3G_SUCCESS      -   On Success
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b>
 *  @n  Sets up the Tx Buffer descriptors. Tx channel ready for send.
 *
 *  @b Example
    @endverbatim
 * ============================================================================
 */
static Uint32 cpsw3g_InitTxChannel(Cpsw3gChInfo *chInfo)
{
    CpdmaObj*       dmaObj = &localDev.cpdma;
    Cpsw3gInitConfig*   cpsw3gCfg = &localDev.Config;
    Cpsw3gRxCppiCh* txChan = &dmaObj->txCppi[chInfo->chNum];
    CPSW_Desc       *pDesc;

    /* zero init the book keeping structure */
    memset(txChan, 0, sizeof(Cpsw3gTxCppiCh));

    /* store pointer to channel info structure */
    txChan->chInfo = chInfo;

    /*
     * Setup Transmit Buffers
     */

    /*
     * We give the first descriptors to RX. The rest of the descriptors
     * will be divided evenly among the TX channels. Odds are this
     * will leave TX with a very large number of TX descriptors, but
     * we'll only use what we need (driven from the application send
     * requests). The RX descriptors are always kept fully populated.
     */
    /* Pointer to first descriptor to use on RX */
	if (localDev.Config.DescBase == CPSW_DESC_BASE_CPPI)
		pDesc = (CPSW_Desc *)(cpsw3gCfg->baseConfig.cppi_ram_base);
	else {
		return (CPSW3G_INVALID_PARAM);
	}

    pDesc += cpswNumBdsAllocated; /* advance to next free BD */

    if( (cpswNumBdsAllocated + chInfo->numBD) > (_CPSW_DSC_ENTRY_COUNT))
    {
        /* not enough room for the requested number of BDs, fail request */
        info_printf("InitTx Channel : Unable to allocate %d BDs for channel %d.%d BDs already in use\n",
                chInfo->numBD,chInfo->chNum,cpswNumBdsAllocated);
        return CPSW3G_INVALID_PARAM;
    }

    /*
     * Setup Transmit Buffers
     */
    txChan->pd         = &localDev;
	txChan->DescMax    = chInfo->numBD;
	/*Pointer for first TX desc = pointer to RX + num of RX desc.*/
	txChan->pDescFirst = pDesc;
	txChan->pDescLast  = pDesc + (chInfo->numBD - 1);
	txChan->pDescRead  = pDesc;
	txChan->pDescWrite = pDesc;

    /* clear the teardown pending flag */
    dmaObj->tdPending[CPSW_NET_CH_DIR_TX][chInfo->chNum] = FALSE;
    /* update the Bd allocation count */
    cpswNumBdsAllocated += chInfo->numBD;

    dmaObj->chIsInit[CPSW_NET_CH_DIR_TX][chInfo->chNum] = TRUE;

    return (CPSW3G_SUCCESS);
}

/** ============================================================================
 *  @n@b cpsw3g_InitRxChannel()
 *
 *  @b Description
 *  @n This function sets up the Receive Buffer descriptors.
 *
 *  @b Arguments
 *  @verbatim
 *      chInfo              Channel object
    @endverbatim
 *
 *  <b> Return Value </b>   
 *  CPSW3G_INVALID_PARAM  -   Returned on BD allocation error 
 *  CPSW3G_SUCCESS      -   On Success 
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b>
 *  @n  Sets up the Rx Buffer descriptors. Rx channel ready for receive.
 *
 *  @b Example
    @endverbatim
 * ============================================================================
 */
static Uint32 cpsw3g_InitRxChannel(Cpsw3gChInfo *chInfo)
{
    CpdmaObj*       dmaObj = &localDev.cpdma;
    Cpsw3gInitConfig*   cpsw3gCfg = &localDev.Config;
    Cpsw3gRxCppiCh* rxChan = &dmaObj->rxCppi[chInfo->chNum];
    CPSW_Desc       *pDesc;
    CPSW_Pkt*		pPkt;

    /* zero init the book keeping structure */
    memset(rxChan, 0, sizeof(Cpsw3gRxCppiCh));

    /* store pointer to channel info structure */
    rxChan->chInfo = chInfo;

    /*
     * Setup Receive Buffers
     */

    /*
     * We give the first descriptors to RX. The rest of the descriptors
     * will be divided evenly among the TX channels. Odds are this
     * will leave TX with a very large number of TX descriptors, but
     * we'll only use what we need (driven from the application send
     * requests). The RX descriptors are always kept fully populated.
     */

    /* Pointer to first descriptor to use on RX */
	if (localDev.Config.DescBase == CPSW_DESC_BASE_CPPI)
		pDesc = (CPSW_Desc *)(cpsw3gCfg->baseConfig.cppi_ram_base);
	else {
		return (CPSW3G_INVALID_PARAM);
	}

    pDesc += cpswNumBdsAllocated; /* advance to next free BD */

    if( (cpswNumBdsAllocated + chInfo->numBD) > (_CPSW_DSC_ENTRY_COUNT))
    {
        /* not enough room for the requested number of BDs, fail request */
        info_printf("InitRx Channel : Unable to allocate %d BDs for channel %d.%d BDs already in use\n",
                chInfo->numBD,chInfo->chNum,cpswNumBdsAllocated);
        return CPSW3G_INVALID_PARAM;
    }    
   
    /* Init the Rx channel */
    rxChan->pd         = &localDev;
	rxChan->DescMax    = chInfo->numBD;
	rxChan->pDescFirst = pDesc;
	rxChan->pDescLast  = pDesc + (chInfo->numBD - 1);
	rxChan->pDescRead  = pDesc;
	rxChan->pDescWrite = pDesc;
	/* Fill the descriptor table */
	emacEnqueueRx(rxChan, 0);
	
    if (rxChan->DescCount < (chInfo->numBD)) 
    {
	    /* Free all RX descriptors */
		while (pPkt = pqPop( &rxChan->DescQueue))
		    (*localDev.Config.pfcbFreePacket)(localDev.hApplication, pPkt);

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

    /* clear the teardown pending flag */
    dmaObj->tdPending[CPSW_NET_CH_DIR_RX][chInfo->chNum] = FALSE;
    cpswNumBdsAllocated += chInfo->numBD;
    
    dmaObj->chIsInit[CPSW_NET_CH_DIR_RX][chInfo->chNum] = TRUE;

   return (CPSW3G_SUCCESS);
}

/** ============================================================================
 *  @n@b cpsw3g_UnInitTxChannel()
 *
 *  @b Description
 *  @n This function frees up the enqueued Transmit Buffer descriptors and the 
 *  packets held in any of its queues.
 *
 *  @b Arguments
 *  @verbatim
 *      chInfo              Channel object
    @endverbatim
 *
 *  <b> Return Value </b>   
 *  Always returns CPSW3G_SUCCESS
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b> None
 *
 *  @b Example
    @endverbatim
 * ============================================================================
 */
static Uint32 cpsw3g_UnInitTxChannel(Cpsw3gChInfo *chInfo)
{
	CpdmaObj*       dmaObj = &localDev.cpdma;
	Cpsw3gRxCppiCh* txChan = &dmaObj->txCppi[chInfo->chNum];
	CPSW_Pkt*       pPkt;

    while (pPkt = pqPop( &txChan->DescQueue ))
	    (localDev.Config.pfcbFreePacket)(localDev.hApplication, pPkt);
    while (pPkt = pqPop( &txChan->WaitQueue ))
	    (localDev.Config.pfcbFreePacket)(localDev.hApplication, pPkt);

	dmaObj->chIsInit[CPSW_NET_CH_DIR_TX][chInfo->chNum] = FALSE;

    return (CPSW3G_SUCCESS);
}

/** ============================================================================
 *  @n@b cpsw3g_UnInitRxChannel()
 *
 *  @b Description
 *  @n This function frees up the enqueued Receive Buffer descriptors and any
 *  packets held in the Rx queue.
 *
 *  @b Arguments
 *  @verbatim
 *      chInfo              Channel object
    @endverbatim
 *
 *  <b> Return Value </b>   
 *  Always returns CPSW3G_SUCCESS
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b> None
 *
 *  @b Example
    @endverbatim
 * ============================================================================
 */
static Uint32 cpsw3g_UnInitRxChannel(Cpsw3gChInfo *chInfo)
{
	CpdmaObj*       dmaObj = &localDev.cpdma;
	Cpsw3gRxCppiCh* rxChan = &dmaObj->rxCppi[chInfo->chNum];
	CPSW_Pkt*       pPkt;

    while (pPkt = pqPop( &rxChan->DescQueue ))
	    (localDev.Config.pfcbFreePacket)(localDev.hApplication, pPkt);

	dmaObj->chIsInit[CPSW_NET_CH_DIR_RX][chInfo->chNum] = FALSE;

    return (CPSW3G_SUCCESS);
}

/** ============================================================================
 *  @n@b cpsw3g_NetChOpen()
 *
 *  @b Description
 *  @n This function opens a data channel on the CPPI DMA engine.
 *
 *  @b Arguments
 *  @verbatim
 *      chInfo              Channel object to setup.
    @endverbatim
 *
 *  <b> Return Value </b>   
 *  CPSW3G_SUCCESS          - Channel setup successful
 *  CPSW3G_ERR_CH_ALREADY_INIT  - Channel already initialized
 *  Other error values if Channel init failed.
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b> None
 *
 *  @b Example
    @endverbatim
 * ============================================================================
 */
static Uint32 cpsw3g_NetChOpen(Cpsw3gChInfo *chInfo)
{
    Cpsw3gInitConfig*   cpsw3gCfg = &localDev.Config;
    Uint32 retVal;

    /* Perform sanity checks on input params */
    if( chInfo->chNum >= cpsw3gCfg->dmaInitCfg.numChannels[chInfo->chDir])
    {
        info_printf("NetChOpen: Channel number invalid \n");
    	return (CPSW3G_ERR_CH_INVALID);
    }
    if(localDev.cpdma.chIsInit[chInfo->chDir][chInfo->chNum] == TRUE)
    {
        info_printf("NetChOpen: %s Channel %d already initialized\n",
	        ((chInfo->chDir == CPSW_NET_CH_DIR_TX) ? "TX" : "RX"), chInfo->chNum);
        return (CPSW3G_ERR_CH_ALREADY_INIT);
	}

    /* Perform book keeping for indv channel */
	if (chInfo->chDir == CPSW_NET_CH_DIR_TX)
	{
        retVal = cpsw3g_InitTxChannel(chInfo);
	}
	else
	{
        retVal = cpsw3g_InitRxChannel( chInfo);
	}

	if (retVal != CPSW3G_SUCCESS)
	{
        info_printf("NetChOpen: Error in initializing %s channel %d",
	        ((chInfo->chDir == CPSW_NET_CH_DIR_TX) ? "TX" : "RX"), chInfo->chNum);
        return (retVal);
	}

	/**CHECK : if device already opened then enable ?? */
	/* Enable this channel for use */
    retVal = cpsw3g_EnableChannel(chInfo->chNum, chInfo->chDir);
	if (retVal != CPSW3G_SUCCESS)
    {
		info_printf("NetChOpen: Error enabling channel %d in %d direction\n",
            chInfo->chNum, chInfo->chDir);
        return (retVal);
    }

 	return (CPSW3G_SUCCESS);
}

/** ============================================================================
 *  @n@b cpsw3g_NetChClose()
 *
 *  @b Description
 *  @n This function closes a previously open data channel on the CPPI DMA engine
 *  and frees up any memory held associated with it.
 *
 *  @b Arguments
 *  @verbatim
 *      chInfo              Channel object to clean up.
    @endverbatim
 *
 *  <b> Return Value </b>   
 *  Always returns CPSW3G_SUCCESS
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b> None
 *
 *  @b Example
    @endverbatim
 * ============================================================================
 */
static Uint32 cpsw3g_NetChClose(Cpsw3gChInfo *chInfo)
{
	CpdmaObj *dmaObj = &localDev.cpdma;

	if(dmaObj->chIsOpen[chInfo->chDir][chInfo->chNum]  == TRUE)
    {
	    cpsw3g_DisableChannel(chInfo->chNum, chInfo->chDir);
	}
	if(dmaObj->chIsInit[chInfo->chDir][chInfo->chNum] == TRUE)
	{
	    if(chInfo->chDir == CPSW_NET_CH_DIR_TX)
		{
		    cpsw3g_UnInitTxChannel(chInfo);
		}
		else
		{
		    cpsw3g_UnInitRxChannel(chInfo);
		}
    }

	return (CPSW3G_SUCCESS);
}

/** ============================================================================
 *  @n@b cpgmacMacOpen()
 *
 *  @b Description
 *  @n This function opens and sets up a MAC port for communication.
 *
 *  @b Arguments
 *  @verbatim
 *      hPort               Handle to the Port object to setup
    @endverbatim
 *
 *  <b> Return Value </b>   None
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b> None
 *
 *  @b Example
    @endverbatim
 * ============================================================================
 */
static void cpgmacMacOpen(Cpsw3gPort *hPort)
{
    Cpsw3gInitConfig*	cpsw3gCfg = &localDev.Config;
    Uint32 				instId = hPort->portNum -1 ;//idk:port0-cpdma,port1&2-SL
    CpgmacMacConfig*	macInitCfg = &cpsw3gCfg->macInitCfg[instId];
    CpgmacObj*			gmacObject = &localDev.cpgmacMac[instId];
	int				    index;
	CPSW_AddrConfig*	tmp;

    /* Do a soft reset of the module */
	CPSWSlReset(cpsw3gCfg->baseConfig.port[instId].sliver_base);

    /* Set MacControl Register */
    cpsw3g_SetMacCfg(hPort);

    /* Configure Mac Address */
	for (index = 0; (Uint8)index < CPSW_NUMBER_OF_MAC_ADDRESS; index++)
	{
        tmp = cpsw3gCfg->MacAddr[index];

		/* set MAC hardware address */
		CPSWPortSrcAddrSet(cpsw3gCfg->baseConfig.port[instId].port_base, tmp->Addr);
    }    
    /**
     * For Dual Mac mode, configure port0 and port1 for one VLAN ID;
     * port0 and port2 for a different VLAN ID. Here we choose the
     * port number as VLAN ID.
     */
    CPSWPortVLANConfig(cpsw3gCfg->baseConfig.port[instId].port_base, instId + 1, 0, 0);

    /* write rx maxlen register */
    CPSWSlRxMaxLenSet(cpsw3gCfg->baseConfig.port[instId].sliver_base, localDev.PktMTU/* + 4 */);

    /*Kick Start MDIO , auto-negn */
    memset(&gmacObject->PhyDev, 0, sizeof(CPSW_PHY_DEVICE));

    cpsw_MDIO_Init(&gmacObject->PhyDev, CPSW0_MDIO_REGS, instId, macInitCfg->PhyMask,
              macInitCfg->MLinkMask, 0,cpsw3gCfg->baseConfig.port[instId].phy_addr, 0,
              MDIO_FREQ_INPUT, MDIO_FREQ_OUTPUT, 0);

    if(mac_configuration.tlk110Flag ==1)
    	tlkNLPFix(CPSW0_MDIO_REGS,cpsw3gCfg->baseConfig.port[instId].phy_addr);

    /* set the Phy to given mode based on Config Params */
    cpsw3g_SetPhyMode(gmacObject,instId);
   
    /* Finally Set the Mac Control register. Enable MII */
    CPSWSlGMIIEnable(cpsw3gCfg->baseConfig.port[instId].sliver_base);
}

/** ============================================================================
 *  @n@b cpgmacMacClose()
 *
 *  @b Description
 *  @n This function closes and de-initializes the MAC port.
 *
 *  @b Arguments
 *  @verbatim
 *      hPort               Handle to the Port object to setup
    @endverbatim
 *
 *  <b> Return Value </b>   None
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b> None
 *
 *  @b Example
    @endverbatim
 * ============================================================================
 */
static void cpgmacMacClose(Cpsw3gPort *hPort)
{
    Uint32 instId = hPort->portNum - 1;

    /* soft reset */
    CPSWSlReset(localDev.Config.baseConfig.port[instId].sliver_base);

    return;
}

/** ============================================================================
 *  @n@b cpdmaOpen()
 *
 *  @b Description
 *  @n This function opens and sets up the DMA port and channel for communication.
 *
 *  @b Arguments
 *  @verbatim
 *      hPort               Handle to the Port object to setup
    @endverbatim
 *
 *  <b> Return Value </b>   
 *      CPSWG3_SUCCESS      DMA open successful
 *      error value         DMA open failed
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b> None
 *
 *  @b Example
    @endverbatim
 * ============================================================================
 */
static Uint32 cpdmaOpen(Cpsw3gPort *hPort)
{
    Cpsw3gInitConfig*   cpsw3gCfg = &localDev.Config;
    Uint32              retVal;
    CpdmaConfig*        dmaInitCfg = &cpsw3gCfg->dmaInitCfg;
    CpdmaObj*           dmaObj = &localDev.cpdma;
    Uint32              channel, dir;

    CPSWCPDMAReset(cpsw3gCfg->baseConfig.cpdma_base);
    /* Enable Opened TX Channels */
    for (dir = CPSW_NET_CH_DIR_TX; dir <= CPSW_NET_CH_DIR_RX; dir ++)
    {
        for (channel = 0; channel < CPDMA_MAX_CHANNELS; channel++)
	    {
	        /**CHECK: Normal scenario channel wont be init at this stage */
	        if (dmaObj->chIsInit[dir][channel] == TRUE)
	        {
	            retVal = cpsw3g_EnableChannel(channel, dir);
	            if (retVal != CPSW3G_SUCCESS)
		        {
	            	info_printf("\nERROR:cpdmaOpen: Error enabling channel %d", channel);
		            return (retVal);
		        }
	        }
	    }/* end of for channel loop */
    }/* end of for loop over dir */
    

    CPSWCPDMARxBufOffsetSet(cpsw3gCfg->baseConfig.cpdma_base, dmaInitCfg->rxBufferOffset);

    CPSWCPDMATxIntDisable(cpsw3gCfg->baseConfig.cpdma_base, 0);
    CPSWCPDMARxIntDisable(cpsw3gCfg->baseConfig.cpdma_base, 0);

    /* Acknowledge receive and transmit interrupts for proper interrupt pulsing*/
    CPSWCPDMAEndOfIntVectorWrite(cpsw3gCfg->baseConfig.cpdma_base, CPSW_EOI_TX_PULSE);
    CPSWCPDMAEndOfIntVectorWrite(cpsw3gCfg->baseConfig.cpdma_base, CPSW_EOI_RX_PULSE);

    CPSWCPDMATxEnable(cpsw3gCfg->baseConfig.cpdma_base);
    CPSWCPDMARxEnable(cpsw3gCfg->baseConfig.cpdma_base);

    /* Enable Adapter check interrupts - enable stats interupt */
    CPSWCPDMADMAIntEnable(cpsw3gCfg->baseConfig.cpdma_base,
    		CPSW_CPDMA_DMA_INTMASK_SET_HOST_ERR_INT_MASK |CPSW_CPDMA_DMA_INTMASK_SET_STAT_INT_MASK);

    /* enable host,stats interrupt in cpsw_3gss_s wrapper */
    CPSWWrCoreMiscIntEnable(cpsw3gCfg->baseConfig.wrpr_base, 0,
    		CPSW3G_ECTL_HOSTERR_INTMASK | CPSW3G_ECTL_STATPEND_INTMASK);

#ifdef CPSW3G_USE_INTERRUPT_PACING
		/* enable Interrupt Pacing Logic in the Wrapper */
	CPSWWrSetRxIntPerSec(cpsw3gCfg->baseConfig.wrpr_base, 0, 2);
	CPSWWrSetIntPacingEnable(cpsw3gCfg->baseConfig.wrpr_base,  CSL_ECTL_INT_CONTROL_INT_PACE_EN_C0_RX);
	CPSWWrSetIntPrescaler(cpsw3gCfg->baseConfig.wrpr_base, 0x370);
#endif
    return (CPSW3G_SUCCESS);
}

/** ============================================================================
 *  @n@b cpdmaClose()
 *
 *  @b Description
 *  @n This function closes and de-initializes up the DMA port and channels.
 *
 *  @b Arguments
 *  @verbatim
 *      hPort               Handle to the Port object to close
    @endverbatim
 *
 *  <b> Return Value </b>   
 *      CPSWG3_SUCCESS      DMA close successful
 *      error value         DMA close failed
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b> None
 *
 *  @b Example
    @endverbatim
 * ============================================================================
 */
static Uint32 cpdmaClose(Cpsw3gPort* hPort)
{
    Uint32 retVal=CPSW3G_SUCCESS;
    Uint32 channel;

    (void)hPort;/*to suppress warning */

    /* Close TX Channels */
    for (channel = 0; channel < CPDMA_MAX_CHANNELS; channel++)
    {
        retVal = cpsw3g_NetChClose(&localDev.Config.chInfo[CPSW_NET_CH_DIR_TX][channel]);
    }

    /* Close RX Channels */
    for (channel = 0; channel < CPDMA_MAX_CHANNELS; channel++)
    {
     	retVal = cpsw3g_NetChClose(&localDev.Config.chInfo[CPSW_NET_CH_DIR_RX][channel]);

	}

    /* Disable TX/RX DMA */
    CPSWCPDMATxDisable(localDev.Config.baseConfig.cpdma_base);
    CPSWCPDMARxDisable(localDev.Config.baseConfig.cpdma_base);
 
    /* Disable Adapter check interrupts - Disable stats interupt */
    CPSWCPDMADMAIntDisable(localDev.Config.baseConfig.cpdma_base,
    		CPSW_CPDMA_DMA_INTMASK_SET_HOST_ERR_INT_MASK |
    					CPSW_CPDMA_DMA_INTMASK_SET_STAT_INT_MASK);


    /* Disable host,stats interrupt in cpsw_3gss_s wrapper */
    CPSWWrCoreMiscIntDisable(localDev.Config.baseConfig.wrpr_base, 0,
    		~( CPSW3G_ECTL_HOSTERR_INTMASK |
    		    						CPSW3G_ECTL_STATPEND_INTMASK));
    /* soft reset */
    CPSWCPDMAReset(localDev.Config.baseConfig.cpdma_base);


    return (retVal);
}

/** ============================================================================
 *  @n@b cpsw3g_port_close()
 *
 *  @b Description
 *  @n This function calls the appropriate functions for closing the port and 
 *  cleaning up the associated channels.
 *
 *  @b Arguments
 *  @verbatim
 *      hPort               Handle to the Port object to setup
    @endverbatim
 *
 *  <b> Return Value </b>   
 *      CPSWG3_SUCCESS      port open successful
 *      error value         port open failed
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b> None
 *
 *  @b Example
    @endverbatim
 * ============================================================================
 */
static int cpsw3g_port_close(Cpsw3gPort* hPort)
{
    if(hPort->portNum == 0)
    {
	    /* handle DMA port cleanup here */
	    cpdmaClose(hPort);
	}
	else
	{
	    cpgmacMacClose(hPort);
	}

    return (CPSW3G_SUCCESS);
}


/** ============================================================================
 *  @n@b cpsw3g_port_open()
 *
 *  @b Description
 *  @n This function opens and sets up the port and channel for communication.
 *
 *  @b Arguments
 *  @verbatim
 *      hPort               Handle to the Port object to setup
    @endverbatim
 *
 *  <b> Return Value </b>   
 *      CPSWG3_SUCCESS      port open successful
 *      error value         port open failed
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b> None
 *
 *  @b Example
    @endverbatim
 * ============================================================================
 */
static int cpsw3g_port_open(Cpsw3gPort *hPort)
{
    Cpsw3gInitConfig*   cpsw3gCfg = &localDev.Config;

    /* Open DDC */
    if(hPort->portNum > 0)
    {
	    /* Ports 1 & 2 are CPGMAC_SL */
	    cpgmacMacOpen(hPort);
    }
    else
    {
	    cpdmaOpen(hPort);
    }

    /**CHECK  sequence here */

    /*Program the CPSW_Control register */
    cpsw3g_SetCpswCfg();

    /* Program the ALE Control register */
    cpsw3g_SetAleCfg();

    /* Configure ALE Port Control Register */
    cpsw3g_SetAlePortCfg(hPort);

    /**CHECK: kick start any timers here */

    /**Port num 0: Program DMA channels here */
    if (hPort->portNum == 0)
    {
        Uint32 dir,ch,retCode;
        for (dir = CPSW_NET_CH_DIR_TX; dir <= CPSW_NET_CH_DIR_RX; dir ++)
        {
            for (ch = 0; ch < cpsw3gCfg->dmaInitCfg.numChannels[dir]; ch++)
            {
                /*Create a channel */
                retCode = cpsw3g_NetChOpen( &localDev.Config.chInfo[dir][ch]);
                if (retCode != CPSW3G_SUCCESS)
                {
                    return (-1);
                }
            }/* end of for loop over ch */
        }/*end of for loop over dir*/
    }
    return (CPSW3G_SUCCESS);
}

static Uint32 cpsw3g_Control(Uint32 cmd, void *cmdArg, void *param)
{
    switch(cmd)
    {
        case CPSW3G_IOCTL_PORT_STATISTICS_ENABLE:
        {
     		{    /* clear old all old stats */
    			Uint32 statClearVal;

				/* if atleast one port is enabled, all values are write to clear hence 
			  	 * we write all FFs to clear, else write zero to set value 
			  	 */
				if (cmdArg == 0) 
				{
					statClearVal = 0 ;
				}
				else
				{
					statClearVal = CPSW3G_STAT_CLEAR;
				}

				CPSWSTATSClear(localDev.Config.baseConfig.stat_base,statClearVal);

    		}
    		/* update our s/w stat counters also to zero */
    		memset(&localDev.Stats, 0, sizeof(localDev.Stats));
    		break;
        }
	    default:
        {
		    break;
        }
    }

    /** second argument param added for future extensibility, since it is not being
     * used, add dummy to suppress warning*/
    (void)param;

    return CPSW3G_SUCCESS;
}


/*-----------------------------------------------------------------------*\
 * STANDARD API FUNCTIONS
 *
 * Note on Exclusion (Serialization):
 * The application is charged with verifying that only one of the
 * following API calls may only be executing at a given time across
 * all threads and all interrupt functions.
 *
 *-----------------------------------------------------------------------*/


/** ============================================================================
 *  @n@b  CPSW_enumerate()
 *
 *  @b Description
 *  @n Enumerates the EMAC peripherals installed in the system and returns an
 *     integer count. The EMAC devices are enumerated in a consistent
 *     fashion so that each device can be later referenced by its physical
 *     index value ranging from "1" to "n" where "n" is the count returned
 *     by this function.
 *
 *  <b> Return Value </b>  Uint32
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b>
 *  @n  None
 *
 *  @b Example
 *  @verbatim
        EMAC_enumerate( );
    @endverbatim
 * ============================================================================
 */
Uint32 CPSW_enumerate(void)
{
    return (1);
}


/** ============================================================================
 *  @n@b  CPSW_open()
 *
 *  @b Description
 *  @n Opens the EMAC peripheral at the given physical index and initializes
 *     it to an embryonic state.
 *
 *     The calling application must supply a operating configuration that
 *     includes a callback function table. Data from this config structure is
 *     copied into the device's internal instance structure so the structure
 *     may be discarded after CPSW_open() returns. In order to change an item
 *     in the configuration, the EMAC device must be closed and then
 *     re-opened with the new configuration.
 *
 *     The application layer may pass in an hApplication callback handle,
 *     that will be supplied by the EMAC device when making calls to the
 *     application callback functions.
 *
 *     An EMAC device handle is written to phEMAC. This handle must be saved
 *     by the caller and then passed to other EMAC device functions.
 *
 *     The default receive filter prevents normal packets from being received
 *     until the receive filter is specified by calling EMAC_receiveFilter().
 *
 *     A device reset is achieved by calling CPSW_close() followed by CPSW_open().
 *
 *     The function returns zero on success, or an error code on failure.
 *
 *     Possible error codes include:
 *       CPSW3G_ERR_DEV_ALREADY_OPEN   - The device is already open
 *       CPSW3G_INVALID_PARAM   - A calling parameter is invalid
 *
 *  @b Arguments
 *  @verbatim
        physicalIndex   physical index
        hApplication    application handle
        pEMACConfig     EMAC's configuration structure
        phEMAC          handle to the EMAC device
    @endverbatim
 *
 *
 *  <b> Return Value </b>  Success (0)
 *  @n     CPSW3G_INVALID_PARAM   - A calling parameter is invalid
 *  @n     CPSW3G_ERR_DEV_ALREADY_OPEN   - The device is already open
 *
 *  <b> Pre Condition </b>
 *  @n  None
 *
 *  <b> Post Condition </b>
 *  @n  Opens the EMAC peripheral at the given physical index and initializes it.
 *
 *  @b Example
 *  @verbatim
    @endverbatim
 * ============================================================================
 */
Uint32 CPSW_open(int physicalIndex, Handle hApplication,
                 Cpsw3gInitConfig *pEMACConfig, Handle *phEMAC)
{
    int              i, index;
    CPSW_AddrConfig  *tmp;


    /* We only handle a single instance */
    if (physicalIndex != 1)
        return (CPSW3G_INVALID_PARAM);

    /* If the device is alread open, return an error */
    if (openFlag)
        return( CPSW3G_ERR_DEV_ALREADY_OPEN );

    /*
     *  Validate the supplied configuration structure
     */
    if (!pEMACConfig || !phEMAC)
        return (CPSW3G_INVALID_PARAM);

    /* MAC address must be supplied and not a multicast address */
	for (index=0; (Uint8)index<(pEMACConfig->TotalNumOfMacAddrs); index++){
		tmp = pEMACConfig->MacAddr[index];
    	if(tmp->Addr[0] & 1 )
        	return( CPSW3G_INVALID_PARAM );
	    for (i = 0; (i < 6) && (!(tmp->Addr[i])); i++)
    	if (i == 6)
        	return (CPSW3G_INVALID_PARAM);
	}

    /* Callback functions must be supplied */
    if (!pEMACConfig->pfcbGetPacket || !pEMACConfig->pfcbFreePacket ||
            !pEMACConfig->pfcbRxPacket)
        return (CPSW3G_INVALID_PARAM);

    /*
     * Init the instance structure
     */

    /* Default everything in our instance structure to zero */
    memset(&localDev, 0, sizeof(Cpsw3gDevice));

    /* Set the hApplication and RxFilter */
    localDev.hApplication = hApplication;

    /* Setup the new configuration */
    localDev.Config = *pEMACConfig;

    /* there are soft resets in indv. modules, and one from LPSC */
    /* order of reset CPDMA->SL0->SL1->3G->SG0->SG1->3Gss */

    /* Reset the different modules */
    Cpsw3gInitConfig*   cpsw3gCfg = &localDev.Config;
    CPSWCPDMAReset(cpsw3gCfg->baseConfig.cpdma_base);
    for(i=0; i<cpsw_num_mac_ports; i++)
    	CPSWSlReset(cpsw3gCfg->baseConfig.port[i].sliver_base);
    CPSWWrReset(cpsw3gCfg->baseConfig.wrpr_base);
    CPSWSSReset(cpsw3gCfg->baseConfig.ss_base);

    /* Open all ports */
    	for(i=0;i<cpsw_num_ports; i++)
    	{
	    	localDev.cpsw3gPort[i].portNum = i;
	    	localDev.cpsw3gPort[i].chNum = i;
	    	{
	    		cpsw3g_port_open(&localDev.cpsw3gPort[i]);
	    	}
	    	
    	}/* end of for loop over PORTS */



     /*Creates the task for TLK 110 Fix*/
     if(mac_configuration.tlk110Flag ==1)
        	tlkMDIXFixinit(CPSW0_MDIO_REGS);

    /* Activate the ALE ageout timer here */
    localDev.Config.aleTimerActive = 1;
    
	/* Validate the device handle */
    localDev.DevMagic = CPSW_DEVMAGIC;

    /* Set the open flag */
    openFlag = 1;

    /* Give a handle back to the caller */
    *phEMAC = &localDev;

    /* Return Success */
    return( CPSW3G_SUCCESS );
}


/** ============================================================================
 *  @n@b  CPSW_close()
 *
 *  @b Description
 *  @n Closed the EMAC peripheral indicated by the supplied instance handle.
 *     When called, the EMAC device will shutdown both send and receive
 *     operations, and free all pending transmit and receive packets.
 *
 *     The function returns zero on success, or an error code on failure.
 *
 *     Possible error code include:
 *         CPSW3G_INVALID_PARAM   - A calling parameter is invalid
 *
 *  @b Arguments
 *  @verbatim
        hEMAC   handle to opened the EMAC device
    @endverbatim
 *
 *  <b> Return Value </b>  Success (0)
 *  @n      CPSW3G_INVALID_PARAM   - A calling parameter is invalid
 *
 *  <b> Pre Condition </b>
 *  @n  CPSW_open function must be called before calling this API.
 *
 *  <b> Post Condition </b>
 *  @n  The EMAC device will shutdown both send and receive
 *      operations, and free all pending transmit and receive packets.
 *
 *  @b Example
 *  @verbatim
        Cpsw3gInitConfig  ecfg;
        Handle       hEMAC = 0;
        //Open the EMAC peripheral
        CPSW_open(1, (Handle)ICSS_HANDLE_VALUE, &ecfg, &hEMAC);

        //Close the EMAC peripheral
        CPSW_close( hEMAC );
    @endverbatim
 * ============================================================================
 */
Uint32 CPSW_close(Handle hEMAC)
{
	Cpsw3gDevice    *pd = (Cpsw3gDevice *)hEMAC;
    Uint32          index;


    /* Validate our handle */
    if (!pd || pd->DevMagic != CPSW_DEVMAGIC)
        return (CPSW3G_INVALID_PARAM);

    /* Close all ports */
   	for(index=0;index<cpsw_num_ports; index++)
    {
     	cpsw3g_port_close(&pd->cpsw3gPort[index]);
    }/* end of for loop over PORTS */

    /*Deletes the task for TLK 110 Fix*/
    if(mac_configuration.tlk110Flag ==1)
    	tlkMDIXFixDeinit();

    /* De-Activate the ALE ageout timer here */
    pd->Config.aleTimerActive = 0;    

    /* Invalidate the EMAC handle */
    pd->DevMagic = 0;

    /* Clear the open flag */
    openFlag = 0;

    /* Exit with interrupts still disabled in the wrapper */
    return (CPSW3G_SUCCESS);
}

/** ============================================================================
 *  @n@b  CPSW_getStatistics()
 *
 *  @b Description
 *  @n Called to get the current device statistics. The statistics structure
 *     contains a collection of event counts for various packet sent and
 *     receive properties. Reading the statistics also clears the current
 *     statistic counters, so the values read represent a delta from the last
 *     call.
 *
 *     The statistics information is copied into the structure pointed to
 *     by the pStatistics argument.
 *
 *     The function returns zero on success, or an error code on failure.
 *
 *     Possible error code include:
 *      CPSW3G_INVALID_PARAM   - A calling parameter is invalid
 *
 *  @b Arguments
 *  @verbatim
        hEMAC       handle to the opened EMAC device
        pStatistics Get the device statistics
    @endverbatim
 *
 *  <b> Return Value </b>  Success (0)
 *  @n      CPSW3G_INVALID_PARAM   - A calling parameter is invalid
 *
 *  <b> Pre Condition </b>
 *  @n  EMAC peripheral instance must be opened before calling this API
 *
 *  <b> Post Condition </b>
 *      -# Statistics are read for various packects sent and received.
        -# Reading the statistics also clears the current
           statistic counters, so the values read represent a delta from the
           last call.
 *
 *  @b Example
 *  @verbatim
        Cpsw3gInitConfig      ecfg;
        Handle           hEMAC = 0;
        CPSW_Statistics  pStatistics;

        CPSW_open(1, (Handle)ICSS_HANDLE_VALUE, &ecfg, &hEMAC);

        CPSW_getStatistics(hEMAC, &pStatistics );
    @endverbatim
 * ============================================================================
 */
Uint32 CPSW_getStatistics(Handle hEMAC, Cpsw3gStatistics *pStatistics)
{
    Cpsw3gDevice  *pd = (Cpsw3gDevice *)hEMAC;

    /* Validate our handle */
    if(!pd || pd->DevMagic != CPSW_DEVMAGIC || !pStatistics)
        return (CPSW3G_INVALID_PARAM);

    /* Update the stats */
    emacUpdateStats(pd);

    return (0);
}

/** ============================================================================
 *  @n@b  CPSW_setConfig()
 *
 *  @b Description
 *  @n This function is called to perform various get/set/dump operations on the
 *     EMAC ALE table, statistics counters etc.
 *
 *     The function returns zero on success, or an error code on failure.
 *
 *     Possible error code include:
 *       CPSW3G_INVALID_PARAM   - A calling parameter is invalid
 *
 *  @b Arguments
 *  @verbatim
        hEMAC       handle to the opened EMAC device
        pBuf        pointer to the buffer that holds the configuration
                    command and any data required.
        size        size of the buffer
    @endverbatim
 *
 *
 *  <b> Return Value </b>  Success (0)
 *  @n      CPSW3G_INVALID_PARAM   - A calling parameter is invalid
 *
 *  <b> Pre Condition </b>
 *  @n  EMAC peripheral instance must be opened.
 *
 *  <b> Post Condition </b> None
 *
 *  @b Example
 *  @verbatim
    @endverbatim
 * ============================================================================
 */
Uint32 CPSW_setConfig(Handle hEMAC, void* pBuf, Uint32 size)
{
    Cpsw3gDevice*       pd = (Cpsw3gDevice *)hEMAC;
    SwitchConsCmd*      swConsCommand = NULL;
    Cpsw3gInitConfig*   cfgPtr  = &pd->Config;
    Int32               ret_val = CPSW3G_SUCCESS;
    Uint32              port = 0;
    Uint32              cpsw3g_statistics = 0;

    /* Validate our handle */
    if (!pd || pd->DevMagic != CPSW_DEVMAGIC || !size || !pBuf)
        return (CPSW3G_INVALID_PARAM);

    swConsCommand = (SwitchConsCmd *)pBuf;

    switch(swConsCommand->opcode)
    {
        case CPSW3G_IOCTL_PORT_STATISTICS_ENABLE:
        {
            PORT_CMD *lpPortCmd = &swConsCommand->PortCmd;
            if((lpPortCmd->value < 2) && (lpPortCmd->ml < 2) && (lpPortCmd->bl < 2))
            {
                if(lpPortCmd->value)
           			CPSWStatisticsEnable(localDev.Config.baseConfig.ss_base);

                cpsw3g_statistics = (lpPortCmd->bl << 2) | (lpPortCmd->ml << 1) | (lpPortCmd->value);


                if(cpsw3g_Control(CPSW3G_IOCTL_PORT_STATISTICS_ENABLE,(Ptr)cpsw3g_statistics,NULL)!=CPSW3G_SUCCESS)
                {
                	info_printf("Error enabling statistics for port %d\n",lpPortCmd->value);
                }
            }
            else
            {
            	info_printf("PORT_STATISTICS_ENABLE:Invalid Arguments\n");
            }

            break;
        }

        case CPSW3G_IOCTL_SET_PORT_CONFIG:
        {
            PORT_CMD *lpPortCmd = &swConsCommand->PortCmd;
            Uint32 fault = 0u;
        
            if( (lpPortCmd->port < 2) && (lpPortCmd->value < 1001) && (lpPortCmd->EnDis < 2))
            {
                switch(lpPortCmd->value)
                {
                    case 0:  
                    {
                        if(pd->cpgmacMac[lpPortCmd->port].intPhy == 0)
                        {
                            cfgPtr->macInitCfg[lpPortCmd->port].phyMode = NWAY_AUTO|NWAY_FD1000|NWAY_FD100|
                                                                          NWAY_FD10|NWAY_HD100|NWAY_HD10;                                                                         
                        }
                        else
                        {
                            cfgPtr->macInitCfg[lpPortCmd->port].phyMode = NWAY_FD100|NWAY_FD10|NWAY_HD100|NWAY_HD10|NWAY_AUTO;
                        }

                        break; 
                    }
                    case 10: 
                    {
                        if(lpPortCmd->EnDis ==1)
                        {
                            cfgPtr->macInitCfg[lpPortCmd->port].phyMode = NWAY_FD10;
                        }
                        else
                        {
                            if(lpPortCmd->EnDis ==0)   
                            {
                                cfgPtr->macInitCfg[lpPortCmd->port].phyMode = NWAY_HD10;
                            }
                            else
                            {
                                cfgPtr->macInitCfg[lpPortCmd->port].phyMode = NWAY_HD10|NWAY_FD10;
                            }
                        }
                        
                        break;
                    }
                    case 100: 
                    {
                        if(lpPortCmd->EnDis ==1)
                        {
                            cfgPtr->macInitCfg[lpPortCmd->port].phyMode = NWAY_FD100;
                        }
                        else
                        {
                            if(lpPortCmd->EnDis ==0)
                            {
                                cfgPtr->macInitCfg[lpPortCmd->port].phyMode = NWAY_HD100;
                            }
                            else
                            {
                                cfgPtr->macInitCfg[lpPortCmd->port].phyMode = NWAY_HD100|NWAY_FD100;
                            }
                         }

                         break;
                    }
                    case 1000: 
                    {
                        if(pd->cpgmacMac[lpPortCmd->port].intPhy == 0)                
                        {
                            cfgPtr->macInitCfg[lpPortCmd->port].phyMode = NWAY_FD1000;
                            if(lpPortCmd->EnDis ==0)      
                            {
                                info_printf("Half duplex is not supported with 1000Mbps\n");
                                fault = 1u;
                            }
                        }
                        else
                        {
                        	info_printf("1000Mbps is not supported with internal phy\n");
                            fault = 1u;
                        }
                                    
                        break;
                    }
				    default:
                    {
				        break;
                    }
                }/* end of switch construct  */
                            
                if(!fault)
                {
                    cpsw3g_SetPhyMode(&pd->cpgmacMac[lpPortCmd->port],lpPortCmd->port); 
                }
            }
            else
            {
            	info_printf("SET_PORT_CONFIG:Invalid Arguments\n");
            } 

            break;
        }
        case CPSW3G_IOCTL_GET_PORT_CONFIG:
        {
            PORT_CMD *lpPortCmd = &swConsCommand->PortCmd;

            if(lpPortCmd->port < 2)
            {
                port  = lpPortCmd->port;
                lpPortCmd->ml    = port;      
                lpPortCmd->port  = pd->cpgmacMac[port].PhyLinked; 
                lpPortCmd->value = pd->Config.linkSpeed[port];
                lpPortCmd->EnDis = pd->Config.linkMode[port];
                lpPortCmd->linkStat =  pd->Config.linkStatus[port];
            }
            else
            {
            	info_printf("GET_PORT_CONFIG:Invalid Arguments\n");
            }

            break;
        }
        default:
        {
            break;
        }
    }/* end of switch construct */

    swConsCommand->ret_type = ret_val;

    return ret_val;
}


/** ============================================================================
 *  @n@b  CPSW_sendPacket()
 *
 *  @b Description
 *  @n Sends a Ethernet data packet out the EMAC device. On a non-error return,
 *     the EMAC device takes ownership of the packet. The packet is returned
 *     to the application's free pool once it has been transmitted.
 *
 *     The function returns zero on success, or an error code on failure.
 *     When an error code is returned, the EMAC device has not taken ownership
 *     of the packet.
 *
 *     Possible error codes include:
 *       CPSW3G_INVALID_PARAM   - A calling parameter is invalid
 *       CPSW3G_ERR_BADPACKET - The packet structure is invalid
 *
 *  @b Arguments
 *  @verbatim
        hEMAC       handle to the opened EMAC device
        pPkt        EMAC packet structure
    @endverbatim
 *  <b> Return Value </b>  Success (0)
 *  @n      CPSW3G_INVALID_PARAM   - A calling parameter is invalid
 *  @n      CPSW3G_ERR_BADPACKET - The packet structure is invalid
 *
 *  <b> Pre Condition </b>
 *  @n  EMAC peripheral instance must be opened and get a packet
 *      buffer from private queue
 *
 *  <b> Post Condition </b>
 *  @n  Sends a ethernet data packet out the EMAC device and is returned to the
 *      application,s free pool once it has been transmitted.
 *
 *  @b Example
 *  @verbatim
        #define EMAC_RXFILTER_DIRECT       1
        #define EMAC_PKT_FLAGS_SOP         0x80000000u
        #define EMAC_PKT_FLAGS_EOP         0x40000000u

        Cpsw3gInitConfig ecfg;
        EMAC_Pkt    *pPkt;
        Handle      hEMAC = 0;
        Uint32      size, TxCount = 0;

        //open the EMAC device
        CPSW_open( 1, (Handle)ICSS_HANDLE_VALUE, &ecfg, &hEMAC );

        //set the receive filter
        CPSW_setReceiveFilter( hEMAC, EMAC_RXFILTER_DIRECT );

        //Fill the packet options fields
        size = TxCount + 60;
        pPkt->Flags      = EMAC_PKT_FLAGS_SOP | EMAC_PKT_FLAGS_EOP;
        pPkt->ValidLen   = size;
        pPkt->DataOffset = 0;
        pPkt->PktChannel = 0;
        pPkt->PktLength  = size;
        pPkt->PktFrags   = 1;

        CPSW_sendPacket( hEMAC, pPkt );

    @endverbatim
 * ============================================================================
 */


Uint32 CPSW_sendPacket(Handle hEMAC, CPSW_Pkt *pPkt)
{
    Cpsw3gDevice    *pd = (Cpsw3gDevice *)hEMAC;
    Uint32          fragcnt,pktlen;
    CPSW_Pkt        *pPktLast;
    CPSW_DescCh     *pdc;
	CpdmaObj*       dmaObj;
    Cpsw3gChInfo*   txChan;


    /* Validate our handle */
    if (!pd || pd->DevMagic != CPSW_DEVMAGIC || !pPkt)
        return (CPSW3G_INVALID_PARAM);

    /* Do some packet validation */
    if (!(pPkt->Flags & CPDMA_BUF_DESC_SOP))
        return (CPSW3G_ERR_BADPACKET);

    dmaObj = &pd->cpdma;
    txChan = &pd->Config.chInfo[CPSW_NET_CH_DIR_TX][pPkt->PktChannel];

    if (pPkt->PktLength < 14 || pPkt->PktLength > pd->PktMTU)
        return (CPSW3G_ERR_BADPACKET);

    /* Count the number of frags in this packet */
    fragcnt = 1;
    pktlen  = pPkt->PktLength;

    pPktLast = pPkt;
    while (!(pPktLast->Flags & CPDMA_BUF_DESC_EOP))
    {
        if (!pPktLast->pNext)
            return (CPSW3G_INVALID_PARAM);
        pktlen -= pPktLast->ValidLen;
        pPktLast = pPktLast->pNext;
        fragcnt++;

        /* At this point we can't have another SOP */
        if (pPktLast->Flags & CPDMA_BUF_DESC_SOP)
            return (CPSW3G_INVALID_PARAM);
    }


    /* Make sure PktLength and ValidLen agree */
    if (pktlen != pPktLast->ValidLen)
        return (CPSW3G_ERR_BADPACKET);

    /* The final packet frag must be the last in the list */
    if (pPktLast->pNext)
        return (CPSW3G_ERR_BADPACKET);

    /* The frag count must be correct */
    if (fragcnt != pPkt->PktFrags)
        return (CPSW3G_ERR_BADPACKET);

    /* Now pad for 60 byte min size. We only pad the last fragment */
    if (pPkt->PktLength < 60)
    {
        pktlen = 60 - pPkt->PktLength;
        pPkt->PktLength = 60;
        pPktLast->ValidLen += pktlen;
    }

    /* Get a local pointer to the descriptor channel */
    pdc = &(dmaObj->txCppi[pPkt->PktChannel]);
    pdc->chInfo = txChan;

    /* Make sure this packet does not have too many frags to fit */
    if (fragcnt > pdc->DescMax)
        return (CPSW3G_ERR_BADPACKET);


    if(cpsw_tx_packet_exception_callback != NULL)
    {
    	if(cpsw_tx_packet_exception_callback ((Uint16*)(pPkt->pDataBuffer + pPkt->DataOffset),NULL))
		{
			return (1);
		}
    }


    /*
     * Queue and packet and service transmitter
     */
    pqPushChain(&pdc->WaitQueue, pPkt, pPktLast, fragcnt);
    emacEnqueueTx(pdc);	
    return (0);
}


/** ============================================================================
 *  @n@b  CPSW_RxServiceCheck()
 *
 *  @b Description
 *  @n This function should be called every time there is an EMAC device Rx
 *     interrupt. It maintains the status the EMAC.
 *
 *     Note that the application has the responsibility for mapping the
 *     physical device index to the correct EMAC_serviceCheck() function. If
 *     more than one EMAC device is on the same interrupt, the function must be
 *     called for each device.
 *
 *     Possible error codes include:
 *       CPSW3G_INVALID_PARAM   - A calling parameter is invalid
 *       CPSW3G_ERR_MACFATAL  - Fatal error in the MAC - Call CPSW_close()
 *
 *  @b Arguments
 *  @verbatim
        hEMAC       handle to the opened EMAC device
    @endverbatim
 *  <b> Return Value </b>  Success (0)
 *  @n     CPSW3G_INVALID_PARAM   - A calling parameter is invalid
 *  @n     CPSW3G_ERR_MACFATAL  - Fatal error in the MAC - Call CPSW_close()
 *
 *  <b> Pre Condition </b>
 *  @n  CPSW_open function must be called before calling this API.
 *
 *  <b> Post Condition </b>
 *  @n  None
 *
 *  @b Example
 *  @verbatim
        static CSL_IntcContext context;
        static CSL_IntcEventHandlerRecord Record[13];
        static CSL_IntcObj intcEMACRx;
        static CSL_IntcHandle hIntcEMACRx;

        //CSL_IntcParam vectId1;
        CSL_IntcParam vectId2;

        CSL_IntcGlobalEnableState state;

        // Setup the global Interrupt
        context.numEvtEntries = 13;
        context.eventhandlerRecord = Record;

        // VectorID for the Event
        vectId2 = CSL_INTC_VECTID_6;

        CSL_intcInit(&context);
        // Enable NMIs
        CSL_intcGlobalNmiEnable();
        // Enable Global Interrupts
        CSL_intcGlobalEnable(&state);

        // Opening a handle for EMAC Rx interrupt
        hIntcEMACRx=CSL_intcOpen(&intcEMACRx,CSL_INTC_EVENTID_MACRXINT,&vectId2,NULL);

        //Hook the ISRs
        CSL_intcHookIsr(vectId2,&HwRxInt);

        CSL_intcHwControl(hIntcEMACRx, CSL_INTC_CMD_EVTENABLE, NULL);

        // This function is called when Rx interrupt occurs
        Void HwRxInt (void)
        {
	        // Note : get the Emac Handle(hEMAC) by calling CPSW_open function
            CPSW_RxServiceCheck(hEMAC);
        }


    Fix: April - 1 by vinoth 
    Issue: While iterating the status of RX interrupt in the each DMA channel, the *rxChan been initalized only there is an interrupt
             but Re-fill RX buffer queue get processed without checking the status of interrupt flag. It would cause null pointer exception if rxchan is not initialized             

	    if (rxChan->DescCount != rxChan->DescMax)
		    emacEnqueueRx(rxChan, 1);

    MadeFix: Do the Enqueue only if intflag is true
    @endverbatim
 * ============================================================================
 */
Uint32 CPSW_RxServiceCheck(Handle hEMAC)
{
	Cpsw3gDevice    *pd = (Cpsw3gDevice *)hEMAC;
	Uint32          Desc;
	int             i;
	Cpsw3gRxCppiCh  *rxChan;

	/* Validate our handle */
	if (!pd || pd->DevMagic != CPSW_DEVMAGIC)
		return (CPSW3G_INVALID_PARAM);
	i=0;
	Desc = CPSWCPDMARxCPGet(pd->Config.baseConfig.cpdma_base, i);
	rxChan = &pd->cpdma.rxCppi[i];
#ifdef DEBUG_STATS
	cpsw_raweth_stat.cslRxCnt++;
#endif
	emacDequeueRx(rxChan, (CPSW_Desc *)Desc);

	/* Re-fill Rx buffer queue if needed */
	if (rxChan->DescCount != rxChan->DescMax)
		emacEnqueueRx(rxChan, 1);
	CPSWCPDMARxCPWrite(pd->Config.baseConfig.cpdma_base, i, (unsigned int)Desc);
	
    return(0);
}

/** ============================================================================
 *  @n@b  CPSW_TxServiceCheck()
 *
 *  @b Description
 *  @n This function should be called every time there is an EMAC device Tx
 *     interrupt. It maintains the status the EMAC.
 *
 *     Note that the application has the responsibility for mapping the
 *     physical device index to the correct EMAC_serviceCheck() function. If
 *     more than one EMAC device is on the same interrupt, the function must be
 *     called for each device.
 *
 *     Possible error codes include:
 *       CPSW3G_INVALID_PARAM   - A calling parameter is invalid
 *       CPSW3G_ERR_MACFATAL  - Fatal error in the MAC - Call CPSW_close()
 *
 *  @b Arguments
 *  @verbatim
        hEMAC       handle to the opened EMAC device
    @endverbatim
 *  <b> Return Value </b>  Success (0)
 *  @n     CPSW3G_INVALID_PARAM   - A calling parameter is invalid
 *  @n     CPSW3G_ERR_MACFATAL  - Fatal error in the MAC - Call CPSW_close()
 *
 *  <b> Pre Condition </b>
 *  @n CPSW_open function must be called before calling this API.
 *
 *  <b> Post Condition </b>
 *  @n  None
 *
 *  @b Example
 *  @verbatim
        static CSL_IntcContext context;
        static CSL_IntcEventHandlerRecord Record[13];
        static CSL_IntcObj intcEMACTx;
        static CSL_IntcHandle hIntcEMACTx;

        //CSL_IntcParam vectId1;
        CSL_IntcParam vectId2;

        CSL_IntcGlobalEnableState state;

        // Setup the global Interrupt
        context.numEvtEntries = 13;
        context.eventhandlerRecord = Record;

        // VectorID for the Event
        vectId2 = CSL_INTC_VECTID_6;

        CSL_intcInit(&context);
        // Enable NMIs
        CSL_intcGlobalNmiEnable();
        // Enable Global Interrupts
        CSL_intcGlobalEnable(&state);

        // Opening a handle for EMAC Tx interrupt
        hIntcEMACTx=CSL_intcOpen(&intcEMACTx,CSL_INTC_EVENTID_MACTXINT,&vectId2,NULL);

        //Hook the ISRs
        CSL_intcHookIsr(vectId2,&HwTxInt);

        CSL_intcHwControl(hIntcEMACTx, CSL_INTC_CMD_EVTENABLE, NULL);

        // This function is called when Rx interrupt occurs
        Void HwTxInt (void)
        {
	        // Note : get the Emac Handle(hEMAC) by calling CPSW_open function
            CPSW_TxServiceCheck(hEMAC);
        }

    @endverbatim
 * ============================================================================
 */
Uint32 CPSW_TxServiceCheck(Handle hEMAC)
{
    Cpsw3gDevice    *pd = (Cpsw3gDevice *)hEMAC;
    Uint32          Desc;
	Uint32          i;

    /* Validate our handle */
    if (!pd || pd->DevMagic != CPSW_DEVMAGIC)
        return (CPSW3G_INVALID_PARAM);

    i = 0;
    /* find out if interrupt happend */
    Cpsw3gTxCppiCh *txChan;
    Desc = CPSWCPDMATxCPGet(pd->Config.baseConfig.cpdma_base, i);
	txChan = &(pd->cpdma.txCppi[i]);
	emacDequeueTx(txChan, (CPSW_Desc *)Desc);
    CPSWCPDMATxCPWrite(pd->Config.baseConfig.cpdma_base, 0, (Uint32)Desc);
    return (0);
}

void CPSW_rxEoiWrite ()
{
	CPSWCPDMAEndOfIntVectorWrite(localDev.Config.baseConfig.cpdma_base, CPSW_EOI_RX_PULSE);
}

void CPSW_txEoiWrite()
{
	CPSWCPDMAEndOfIntVectorWrite(localDev.Config.baseConfig.cpdma_base, CPSW_EOI_TX_PULSE);
}

