/* ======================================================================
 *   Copyright (C) 2022 Texas Instruments Incorporated
 *
 *   All rights reserved. Property of Texas Instruments Incorporated.
 *   Restricted rights to use, duplicate or disclose this code are
 *   granted through contract.
 *
 *   The program may not be used without the written permission
 *   of Texas Instruments Incorporated or against the terms and conditions
 *   stipulated in the agreement under which this program has been
 *   supplied.
 * ==================================================================== */

/**
 *  \file     Eth_Priv.c
 *
 *  \brief    This file contains ETH MCAL driver
 *
 */

/* ========================================================================== */
/*                             Include Files                                  */
/* ========================================================================== */

#include "Std_Types.h"
#include "string.h"
/* There are static inline functions in hw_types.h file. Map them as well */
#define ETH_START_SEC_CODE
/* MISRAC_2012_R.20.1
  * "Reason - This is the format to use for specifying memory sections " */
#include "Eth_MemMap.h"
#include "hw_types.h"
#define ETH_STOP_SEC_CODE
/* MISRAC_2012_R.20.1
  * "Reason - This is the format to use for specifying memory sections " */
#include "Eth_MemMap.h"

#include "Dem.h"
#include "Os.h"
#include "soc.h"
#include "hw_ctrl_core.h"
#include "Eth.h"
#include "SchM_Eth.h"
#include "Eth_Irq.h"
#include "EthIf_Cbk.h"
#include "cpsw.h"
#include "cpsw_ale.h"
#include "Eth_Priv.h"
#include "cpsw_priv.h"
#include "cpsw_stats.h"
#include "cpsw_cpts.h"
#include "hw_cpsw_mdio.h"
#include "hw_cpsw_ss.h"
#include "hw_cpsw_port.h"
#include "hw_cpsw_cpdma.h"
/* ========================================================================== */
/*                           Macros & Typedefs                                */
/* ========================================================================== */
/** \brief Declaration for Port Obj pointer type */
typedef Eth_PortObject * Eth_PortObjectPtrType;

/* Default frame type for receive and transmit */
#define ETH_FRAME_DEFAULT_TYPE  (0x0800U)

/* VLAN ID ZERO - no VLAN */
#define ETH_NOVLAN_ID                    (0U)
/* ========================================================================== */
/*                         Structures and Enums                               */
/* ========================================================================== */

/* None */

/* ========================================================================== */
/*                 Internal Function Declarations                             */
/* ========================================================================== */
static void Eth_waitLoop(uint32 count);
static Eth_BufObjType *Eth_rxBufAlloc(uint8 ctrlIdx);
static void Eth_updateGiiModeVal(const Eth_MacConfigType *pMACConfig,
                                 uint32                  *pGmiiModeVal);

static void Eth_updateMacControlVal(Eth_MacConfigType *pMACConfig,
                                    uint32            *pMacControlVal);

static void Eth_updateGmiiField(uint32 macNum, uint32 gmiiModeVal);
static void CPSWInitPortAndEnableIntr(uint32 baseAddr);

static void EthRxChTearDown(uint8 ctrlIdx, uint32 chNum);

static void EthRxCompleteXfer(uint8 ctrlIdx, uint32 chNum,
                       uint32 packetCount, Eth_CpdmaBuffDescType *pLastBuffDesc);
static void EthRxProcessPacket(uint8 ctrlIdx,
                               Eth_CpdmaBuffDescType *pCurrRxBuffDesc);
static void
   Eth_configureSwitch(uint8 CtrlIdx, const uint8 macAddr[]);
static Std_ReturnType Eth_allowReception
     (uint8 CtrlIdx, uint8 currPort, P2VAR(uint8, AUTOMATIC, ETH_APPL_DATA)
	                                                             PhysAddrPtr);
static void
    Eth_enableControllerToTransmitAndReceiveBuffers(
    Eth_CpdmaConfigType *pCpdmaConfig);
static BufReq_ReturnType  Eth_checkBuffLen
    ( uint16 *allocBuffLen,
      P2VAR(Eth_BufIdxType, AUTOMATIC, ETH_APPL_DAT)BufIdxPtr,
      uint32 maxBuffIdx,
      uint16 maxBuffLen);
static inline Eth_PortObjectPtrType Eth_getCurrPortObj(void);
static uint64 CSL_locToGlobAddr(uintptr_t locAddr);
static uintptr_t CSL_globToLocAddr(uint64 globAddr64);
static void Eth_delay(uint32 delay);
/* ========================================================================== */
/*                            Global Variables                                */
/* ========================================================================== */
#define ETH_START_SEC_VAR_NO_INIT_UNSPECIFIED
/* MISRAC_2012_R.20.1
  * "Reason - This is the format to use for specifying memory sections " */
#include "Eth_MemMap.h"
/** \brief Ethernet driver object */
    VAR(Eth_DrvObject, ETH_VAR_ZERO_INIT) gEthDrvObj;
#define ETH_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
/* MISRAC_2012_R.20.1
  * "Reason - This is the format to use for specifying memory sections " */
#include "Eth_MemMap.h"

    static uint8 gTxPacketMemoryPool[ETH_MAX_FRAME_LEN * ETH_NUM_RX_BUFFERS];

    static uint8 gRxPacketMemoryPool[ETH_MAX_FRAME_LEN * ETH_NUM_RX_BUFFERS];

    uint8 gEthDescMem[CPDMA_DESC_MEM_SIZE] __attribute__(( aligned(128), 
	                                   section(".bss:ENET_CPPI_DESC") ));
	
    Eth_BufObjType  *pBufObj __attribute__ ((aligned(32)));
    /**< Associated buffer descriptor(mostly used for Transmit logging */

#define ETH_START_SEC_VAR_INIT_32
/* MISRAC_2012_R.20.1
  * "Reason - This is the format to use for specifying memory sections " */
#include "Eth_MemMap.h"
 static uint32 gCpdmaRxChTornFlag = (uint32) FALSE;
 static uint32 gCpdmaTxChTornFlag = (uint32) FALSE;
#define ETH_STOP_SEC_VAR_INIT_32
/* MISRAC_2012_R.20.1
  * "Reason - This is the format to use for specifying memory sections " */
#include "Eth_MemMap.h"

#define ETH_START_SEC_CONST_8
/* MISRAC_2012_R.20.1
  * "Reason - This is the format to use for specifying memory sections " */
#include "Eth_MemMap.h"
    static const uint8 gBcastAddr[ETH_MAC_ADDR_LEN] =
        {0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU};

    static const uint8 gPtpMcastAddr[ETH_MAC_ADDR_LEN] =
        {0x01U,0x1BU,0x19U,0x00U,0x00U,0x0U};
#define ETH_STOP_SEC_CONST_8
/* MISRAC_2012_R.20.1
  * "Reason - This is the format to use for specifying memory sections " */
#include "Eth_MemMap.h"

#define ETH_START_SEC_CONST_UNSPECIFIED
/* MISRAC_2012_R.20.1
  * "Reason - This is the format to use for specifying memory sections " */
#include "Eth_MemMap.h"
    static const cpswAleMcastConfigParams_t gMulticastParams =
    {(uint32) 3U, (uint32) FALSE};

    static const cpswAleUcastConfigParams_t gUnicastParams =
    {
        (uint32) CPSW_ALE_TBL_UNICAST_TYPE_NOT_AGEABLE,
        (uint32) FALSE,
        (uint32) FALSE,
        (uint32) FALSE
    };
#define ETH_STOP_SEC_CONST_UNSPECIFIED
/* MISRAC_2012_R.20.1
  * "Reason - This is the format to use for specifying memory sections " */
#include "Eth_MemMap.h"

#define ETH_START_SEC_VAR_INIT_32
/* MISRAC_2012_R.20.1
  * "Reason - This is the format to use for specifying memory sections " */
#include "Eth_MemMap.h"
    volatile uint32 gEthControllerModeChangeFlag = (uint32) FALSE;
#define ETH_STOP_SEC_VAR_INIT_32
/* MISRAC_2012_R.20.1
  * "Reason - This is the format to use for specifying memory sections " */
#include "Eth_MemMap.h"

/* ========================================================================== */
/*                          Function Definitions                              */
/* ========================================================================== */
#define ETH_START_SEC_CODE
/* MISRAC_2012_R.20.1
  * "Reason - This is the format to use for specifying memory sections " */
#include "Eth_MemMap.h"

FUNC(Std_ReturnType, ETH_CODE) Eth_HwInit(const Eth_ConfigType *CfgPtr)
{
    uint16 i = 0;
    uint8  portIdx = 0U;
    uint32 currPort = 0U;
    uint32 packetMtu = 0U;
    Eth_PortObject           *portObj = NULL_PTR;
    const Eth_PortConfigType *portCfg = NULL_PTR;
    //const Eth_ConfigType *CfgPtr = NULL_PTR;

    //CfgPtr =(const Eth_ConfigType *) &EthConfigSet_EthCtrlConfig_0;

    EthResetDrvObj(&gEthDrvObj);
    /* store instance specific parameters */
	gEthDrvObj.ctrlIdx = CfgPtr->ctrlIdx;
    EthCpswifInstConfig((uint32) gEthDrvObj.ctrlIdx);
    /* Copy controller configuration into driver object*/
	portIdx = CfgPtr->portIdx;
    portObj = &gEthDrvObj.portObj;
    portCfg = &CfgPtr->portCfg;
	  
    /* Reset the different modules */
      CPSWEnetReset(gEthDrvObj.baseAddr, portIdx);
      CPSWCpdmaReset(gEthDrvObj.baseAddr);
    (void) memcpy(&gEthDrvObj.ethConfig,
                  CfgPtr, sizeof (Eth_ConfigType));
				  
    /* Each port is considered as one controller */
      

            gEthDrvObj.enableCacheOps     = CfgPtr->enableCacheOps;
            gEthDrvObj.cacheFlushFnPtr      = CfgPtr->cacheFlushOps;
            gEthDrvObj.cacheInvalidateFnPtr = CfgPtr->cacheInvalidateOps;

            /* Copy port configuration into driver object */
            portObj->portNum = portIdx; /* External port starts with 1 */
            (void) memcpy(&portObj->portCfg,
                          portCfg,
                          sizeof (Eth_PortConfigType));

            /* Copy TX buffer information into driver object */
            for (i = 0; i < ETH_NUM_TX_BUFFERS; i++)
            {
                portObj->txBufObjArray[i].bufIdx  = i;
                portObj->txBufObjArray[i].payload =
                                &gTxPacketMemoryPool[i * ETH_MAX_FRAME_LEN];
                portObj->txBufObjArray[i].len =  ETH_MAX_FRAME_LEN;
                portObj->txBufObjArray[i].type =  ETH_FRAME_DEFAULT_TYPE;
                portObj->txBufObjArray[i].bufState       = ETH_BUF_STATE_FREE;
                portObj->txBufObjArray[i].txConfirmation = (boolean) FALSE;
            }

            /* Copy RX buffer information into driver object */
            for (i = 0; i < ETH_NUM_RX_BUFFERS; i++)
            {
                portObj->rxBufObjArray[i].bufIdx  = i;
                portObj->rxBufObjArray[i].payload =
                                &gRxPacketMemoryPool[i * ETH_MAX_FRAME_LEN];
                portObj->rxBufObjArray[i].len =   ETH_MAX_FRAME_LEN;
                portObj->rxBufObjArray[i].type =  ETH_FRAME_DEFAULT_TYPE;
                portObj->rxBufObjArray[i].bufState       = ETH_BUF_STATE_FREE;
                portObj->rxBufObjArray[i].txConfirmation = (boolean) FALSE;
            }

            currPort = gEthDrvObj.portObj.portNum;

            /* Initialize CPSW */
            EthCpswInstInit(currPort);

            /* configure switch for speed, duplex mode etc.*/
            Eth_MacConfigType *pMACConfig  =
                            &gEthDrvObj.portObj.portCfg.macCfg;

            /* PHY found at address pMACConfig->phyAddr */            
            Eth_macSetConfig(portObj->portNum, pMACConfig);

            /* write rx maxlen register */
            if ((pMACConfig->macModeFlags & MAC_CONFIG_MODEFLG_RXCRC) != 0U)
            {
                packetMtu = ETH_BUF_LEN_BYTE + 4U;
            }
            else
            {
                packetMtu = ETH_BUF_LEN_BYTE;
            }

            CPSWSetRxMaxLen(gEthDrvObj.baseAddr, portIdx, packetMtu);

#if ((ETH_GETETHERSTATS_API == STD_ON) || \
     (ETH_GET_DROPCOUNT_API == STD_ON) || \
     (ETH_GETTXERROR_COUNTERVALUES_API == STD_ON) || \
     (ETH_GETTX_STATS_API   == STD_ON))
            /* Enable statistics for port */
            gEthDrvObj.statsObj.enableStatistics = (uint32) TRUE;
            /*Stats Enable for Port 0 and 1*/
            HW_WR_REG32(gEthDrvObj.baseAddr + CPSW_STAT_PORT_EN_REG,
														(0x1U | (1<<portIdx)));
#else
            gEthDrvObj.statsObj.enableStatistics = (uint32) FALSE;
#endif
return E_OK;
}

/**
 * \brief Initializes driver object for the CPSW instance
 *
 * \param  instNum   Pointer to  CPSW driver object to be initialised.
 */
FUNC(void, ETH_CODE) EthResetDrvObj(Eth_DrvObject *pEthDrvObj)
{
    /* Always one controller */
    pEthDrvObj->ctrlIdx  = (uint32) 0U;
    pEthDrvObj->ctrlMode = ETH_MODE_DOWN;
    /* clear MDIO config structure */
    (void) memset(&(pEthDrvObj->ethConfig), 0, sizeof (Eth_ConfigType));

    /* clear port object structure */
    (void) memset(&(pEthDrvObj->portObj), 0, sizeof (pEthDrvObj->portObj));
    /* clear CPDMA config structure */
    (void) memset(&(pEthDrvObj->rxDescRing), 0, sizeof (pEthDrvObj->rxDescRing));
    /* clear CPDMA config structure */
    (void) memset(&(pEthDrvObj->txDescRing), 0, sizeof (pEthDrvObj->txDescRing));
    pEthDrvObj->maxTxBuffDesc = 0U;
    pEthDrvObj->maxRxBuffDesc = 0U;

    /* clear CPDMA config structure */
    (void) memset(&(pEthDrvObj->statsObj), 0, sizeof (pEthDrvObj->statsObj));

    pEthDrvObj->baseAddr           = 0U;
    pEthDrvObj->descMemBaseAddr    = 0U;
    pEthDrvObj->activeMACPortCount = 0x1U;
}

/**
 * \brief Configure driver.
 *
 * \param  instNum   The CPSW instance to be initialised
 */
FUNC(void, ETH_CODE)EthCpswifInstConfig(uint32 instNum)
{
    /**
     * Code is added for only instance 0. If more instances
     * are there, assign base addresses and phy info here.
     */
    if (0U == instNum)
    {
        gEthDrvObj.baseAddr           = SOC_MSS_CPSW_BASE;

        gEthDrvObj.descMemBaseAddr    = (uint32)gEthDescMem;

        gEthDrvObj.activeMACPortCount = 0x1U;
    }
	else if (1U == instNum)
    {
        gEthDrvObj.baseAddr           = SOC_MSS_CPSW_BASE;

        gEthDrvObj.descMemBaseAddr    = (uint32)gEthDescMem;

        gEthDrvObj.activeMACPortCount = 0x1U;
    }
}

/**
 * \brief Initializes the CPSW instance
 *
 * \param  instNum   The CPSW instance to be initialised
 */
FUNC(void, ETH_CODE) EthCpswInstInit(uint32 portNum)
{
    uint32 maskVar = 0U;

#if  (ETH_ENABLE_MII_API == STD_ON)
    Eth_MdioConfigType *pMdioCfg = NULL_PTR;

    /* Initialize MDIO */
    pMdioCfg = &(gEthDrvObj.ethConfig.mdioCfg);
    CPSWMdioInit(gEthDrvObj.baseAddr, pMdioCfg->mdioClockFreq,
                 pMdioCfg->mdioBusFreq);
#endif
    Eth_waitLoop(100U);

    CPSWAleInit(gEthDrvObj.baseAddr);

    /* Set the port 0 and app provided port to forward */
    CPSWAleSetPortState(gEthDrvObj.baseAddr, 0U,
                        (uint32) CPSW_ALE_PORT_STATE_FWD);

    /* Configure ALE & CPSW VLAN aware mode */
    CPSWAleVlanAwareEnable (gEthDrvObj.baseAddr, (uint32)TRUE );

    /* Enable ALE unknown VLAN member & registered multicast - port mask where
    *  unknown VLAN packets would be forwarded to  */
    uint32 tmpPortId, tmpCurrPort;

    tmpPortId = ((uint32)1U << ETH_HOST_PORT_ID);
    tmpCurrPort = ((uint32)1U << portNum);

    maskVar = (tmpPortId | tmpCurrPort);

    CPSWAleUnknownMemberListSet(gEthDrvObj.baseAddr, maskVar );
    CPSWAleUnknownRegFloodMaskSet(gEthDrvObj.baseAddr, maskVar );

    /* Set user enabled port to forwarding state */
    CPSWAleSetPortState(gEthDrvObj.baseAddr, portNum,
                    (uint32) CPSW_ALE_PORT_STATE_FWD);

    CPSWInitPortAndEnableIntr(gEthDrvObj.baseAddr);
#if (ETH_USR_MDIO_INTERRUPT == STD_ON)
    /* Enable the Misc. interrupt for MDIO events, error stats etc */
    CPSWMiscIntrEnable(gEthDrvObj.baseAddr,
                         (uint32) CPSW_SS_MISC_EN_MDIO_USER);
    /* Enable the interrupt in MDIO module */
    CPSWMDIOUsrIntrEnable(gEthDrvObj.baseAddr);
#endif
#if (ETH_HOST_ERROR_INTERRUPT == STD_ON)
    /* Enable the Misc. interrupt for MDIO events, error stats etc */
    CPSWMiscIntrEnable(gEthDrvObj.baseAddr,
                         (uint32) CPSW_SS_MISC_EN_HOST_PEND);
#endif
}

static void CPSWInitPortAndEnableIntr(uint32 baseAddr)
{
    /*
     *  Acknowledge receive and transmit interrupts for proper interrupt
     *  pulsing
     */
    CPSWCpdmaWriteEoiVector(baseAddr, (uint32) CPSW_WR_INTR_LINE_RX);
    CPSWCpdmaWriteEoiVector(baseAddr, (uint32) CPSW_WR_INTR_LINE_TX);

    /* Enable the interrupts for channel 0 and for control core 0 */
    CPSWCpdmaChIntrEnable(baseAddr,
                          ETH_CPDMA_DEFAULT_RX_CHANNEL_NUM,
                          (uint32) CPSW_CH_INTR_RX);
   CPSWChIntrEnable(baseAddr,
                       ETH_CPDMA_DEFAULT_RX_CHANNEL_NUM,
                       (uint32) CPSW_CH_INTR_RX);
    CPSWCpdmaChIntrEnable(baseAddr,
                          ETH_CPDMA_DEFAULT_TX_CHANNEL_NUM,
                          (uint32) CPSW_CH_INTR_TX);
   CPSWChIntrEnable(baseAddr,
                       ETH_CPDMA_DEFAULT_TX_CHANNEL_NUM,
                       (uint32) CPSW_CH_INTR_TX);

    return;
}

void Eth_macSetConfig( uint32 portNum,
                       Eth_MacConfigType *pMACConfig)
{
    uint32 macNum        = portNum;
    uint32 macControlVal = 0U;
    uint32 gmiiModeVal   = 0U;

    // /* Unlock the pertinent Control Module locks */
    // uint32 controlLockTemp0 = HW_RD_REG32(SOC_CONTROLSS_CTRL + MSS_IOCFGKICK0);
    // HW_WR_REG32((SOC_CONTROLSS_CTRL +MSS_IOCFGKICK0),KICK0_UNLOCK_VAL_MCU);
    
	// uint32 controlLockTemp1 = HW_RD_REG32(SOC_CONTROLSS_CTRL + MSS_IOCFGKICK1);
    // HW_WR_REG32((SOC_CONTROLSS_CTRL +MSS_IOCFGKICK1),KICK1_UNLOCK_VAL_MCU);
			
    // /* Update GMII_SEL in Control Module */
    Eth_updateGiiModeVal(pMACConfig, &gmiiModeVal);
    Eth_updateGmiiField(macNum, gmiiModeVal);

    // /* Lock the pertinent Control Module locks */
	// HW_WR_REG32((SOC_CONTROLSS_CTRL +MSS_IOCFGKICK0),controlLockTemp0);
    // HW_WR_REG32((SOC_CONTROLSS_CTRL +MSS_IOCFGKICK1),controlLockTemp1);
	
    /* If PASSCONTROL is set, enable control frames */
    if ((pMACConfig->macModeFlags & MAC_CONFIG_MODEFLG_PASSCONTROL) != 0U)
    {
        HW_SET_FIELD32(macControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_RX_CMF_EN, 1U);
    }
    if ((pMACConfig->macModeFlags & MAC_CONFIG_MODEFLG_PASSERROR) != 0U)
    {
        HW_SET_FIELD32(macControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_RX_CEF_EN, 1U);
        HW_SET_FIELD32(macControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_RX_CSF_EN, 1U);
    }
    if ((pMACConfig->macModeFlags & MAC_CONFIG_MODEFLG_CMDIDLE) != 0U)
    {
        HW_SET_FIELD32(macControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_CMD_IDLE, 1U);
    }
    if ((pMACConfig->macModeFlags & MAC_CONFIG_MODEFLG_TXSHORTGAPEN) != 0U)
    {
        HW_SET_FIELD32(macControlVal, 
		             CPSW_ETH_PN_MAC_CONTROL_REG_TX_SHORT_GAP_ENABLE, 1U);
    }
    if ((pMACConfig->macModeFlags & MAC_CONFIG_MODEFLG_TXPACE) != 0U)
    {
        HW_SET_FIELD32(macControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_TX_PACE, 1U);
    }
    if ((pMACConfig->macModeFlags & MAC_CONFIG_MODEFLG_TXFLOWCNTL) != 0U)
    {
        HW_SET_FIELD32(macControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_TX_FLOW_EN, 
		                                                                  1U);
    }
    if ((pMACConfig->macModeFlags & MAC_CONFIG_MODEFLG_RXBUFFERFLOWCNTL) != 0U)
    {
        HW_SET_FIELD32(macControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_RX_FLOW_EN,
                                                                  		1U);
    }
    if ((pMACConfig->macModeFlags & MAC_CONFIG_MODEFLG_MACLOOPBACK) != 0U)
    {
        HW_SET_FIELD32(macControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_LOOPBACK, 1U);
    }
	if (pMACConfig->macConnectionType == ETH_MAC_CONN_TYPE_RGMII_FORCE_1000)
    {
        HW_SET_FIELD32(macControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_GIG, 1U);
    }
    macControlVal |= CPSWSlGetMacCtrl(gEthDrvObj.baseAddr, portNum);

    CPSWSetMacCtrl(gEthDrvObj.baseAddr, portNum, macControlVal);

    Eth_updateMacControlVal(pMACConfig, &macControlVal);

    /* Update MACCONTROL with speed/duplex/type settings */
    CPSWSetMacCtrl(gEthDrvObj.baseAddr, portNum, macControlVal);
}

/*
 * \brief Mac configuration function.
 *
 * \param  pMACConfig - MAC configuration structure.
 *                      Refer #Eth_MacConfigType
 *
 * \return none
 */
 static void Eth_updateGiiModeVal(
    const Eth_MacConfigType *pMACConfig, uint32 *pGmiiModeVal)
{
    switch (pMACConfig-> macConnectionType)
    {
        case ETH_MAC_CONN_TYPE_MII_10:
        case ETH_MAC_CONN_TYPE_MII_100:
            /* MII modes */
            /* Eth mode select */
            *pGmiiModeVal = ETH_GMII_SEL_GMII_MODE;
            break;
        case ETH_MAC_CONN_TYPE_RMII_10:
        case ETH_MAC_CONN_TYPE_RMII_100:
            /* RMII modes */
            *pGmiiModeVal = ETH_GMII_SEL_RMII_MODE;
            break;
        case ETH_MAC_CONN_TYPE_RGMII_FORCE_100_HALF:
        case ETH_MAC_CONN_TYPE_RGMII_FORCE_100_FULL:
		case ETH_MAC_CONN_TYPE_RGMII_FORCE_1000:
        case ETH_MAC_CONN_TYPE_RGMII_DETECT_INBAND:
            /* RGMII modes */
            *pGmiiModeVal = ETH_GMII_SEL_RGMII_MODE;
            break;
        default:
            /* Wrong configuration */
            break;
    }

    return;
}

static void Eth_updateGmiiField(
     uint32 macNum, uint32 gmiiModeVal)
 {
     if (1U == macNum)
     {
         
         HW_WR_FIELD32(SOC_MSS_CTRL_BASE + MSS_CPSW_CONTROL_REG,
				 MSS_CPSW_CONTROL_REG_P1_MODE_SEL,(gmiiModeVal));
     }
	 else if (2U == macNum)
     {
         
         HW_WR_FIELD32(SOC_MSS_CTRL_BASE + MSS_CPSW_CONTROL_REG,
				 MSS_CPSW_CONTROL_REG_P2_MODE_SEL,(gmiiModeVal));
     }
     else
     {
        /* wrong port */
     }
     return;
 }

static void Eth_updateMacControlVal(
    Eth_MacConfigType *pMACConfig, uint32 *pMacControlVal)
{
    /*
     * We put this down here on its own since in DLB mode we have to
     * enable GMII_EN bit after enabling loop back mode. When not in
     * DLB mode, we can still do it here.
     */
	switch (pMACConfig->macConnectionType)
	{
		case ETH_MAC_CONN_TYPE_MII_10:
		case ETH_MAC_CONN_TYPE_MII_100:
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_CTL_EN, 0U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_GIG, 0U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_GIG_FORCE, 0U);
		  
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_FULLDUPLEX, 1U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_GMII_EN, 1U);
			break;
		  
		case ETH_MAC_CONN_TYPE_RMII_10:
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_CTL_EN, 0U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_GIG, 0U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_GIG_FORCE, 0U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_IFCTL_A, 0U);

			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_FULLDUPLEX, 1U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_GMII_EN, 1U);

			break;
		case ETH_MAC_CONN_TYPE_RMII_100:
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_CTL_EN, 0U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_GIG, 0U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_GIG_FORCE, 0U);

			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_FULLDUPLEX, 1U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_GMII_EN, 1U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_IFCTL_A, 1U);

			break;
		case ETH_MAC_CONN_TYPE_RGMII_FORCE_100_HALF:
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_CTL_EN, 0U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_GIG, 0U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_FULLDUPLEX, 0U);

			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_GIG_FORCE, 1U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_GMII_EN, 1U);

			break;
		case ETH_MAC_CONN_TYPE_RGMII_FORCE_100_FULL:
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_CTL_EN, 0U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_GIG, 0U);

			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_FULLDUPLEX, 1U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_GIG_FORCE, 1U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_GMII_EN, 1U);

			break;

		case ETH_MAC_CONN_TYPE_RGMII_FORCE_1000:
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_CTL_EN, 0U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_GIG, 1U);

			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_FULLDUPLEX, 1U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_GIG_FORCE, 1U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_GMII_EN, 1U);
			break;
			
		case ETH_MAC_CONN_TYPE_RGMII_DETECT_INBAND:
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_GIG_FORCE, 0U);

			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_CTL_EN, 1U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_GMII_EN, 1U);
			HW_SET_FIELD32(*pMacControlVal, CPSW_ETH_PN_MAC_CONTROL_REG_FULLDUPLEX, 1U);
			break;
		default:
		  /* MISRA Fix */
			break;
	}
    return;
}

Std_ReturnType Eth_cpswCheckHostErr(void)
{
    Std_ReturnType retVal = (Std_ReturnType) E_OK;
    if ((uint32) TRUE == CPSWCheckHostErr(gEthDrvObj.baseAddr))
    {
        /* Requirements: SWS_Eth_00039 */
        /*
         * check access to controller and report production error
         * ETH_E_ACCESS.
         */
#if (ETH_E_ACCESS != ETH_DEM_NO_EVENT)
            Dem_SetEventStatus(
                ETH_E_ACCESS,
                DEM_EVENT_STATUS_PREFAILED);
#endif
        retVal = (Std_ReturnType) E_NOT_OK;
    }

    return retVal;
}

FUNC(Std_ReturnType, ETH_CODE)Eth_HwSetControllerMode
(uint8 CtrlIdx, Eth_ModeType CtrlMode)
{
    Std_ReturnType retVal = E_NOT_OK;
    uint32         descStartAddr = 0U;
    uint32 rxChNum = ETH_CPDMA_DEFAULT_RX_CHANNEL_NUM;
    uint32 txChNum = ETH_CPDMA_DEFAULT_TX_CHANNEL_NUM;
	uint32 portIdx = gEthDrvObj.portObj.portNum;
    /*
         * Disable the Ethernet controller, reset all transmit & receive
         * buffers (i.e. ignore all pending transmission & reception
         * requests
         */
        if (ETH_MODE_DOWN == CtrlMode)
        {
            /*
             * Requirements: SWS_Eth_00137 (All pending transmit buffers
             * shall be released)
             */
            /*
             * Use channel Tear-down to clear all pending transmission and
             * reception requests.
             * Note: This is asynchronous call. Once teardown is complete it
             *       will issue interrupt with Tear-down bit set.
             */
            SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_0();

            /*
             * SWS_Eth_00137 - All locked transmit buffers shall be released if
             * the controller is disabled via Eth_SetControllerMod
             */
            
            Eth_PortObject *pPortObj = &gEthDrvObj.portObj;


            CPSWCpdmaChTearDown(gEthDrvObj.baseAddr,
                         (uint32) ETH_XFER_MODE_TX,
                         txChNum);
            CPSWCpdmaChTearDown(gEthDrvObj.baseAddr,
                         ETH_XFER_MODE_RX,
                         rxChNum);
            /* Disable the interrupts for channel 0 and for control core 0 */
            CPSWCpdmaChIntrDisable(gEthDrvObj.baseAddr,
                                  rxChNum,
                                  CPSW_CH_INTR_RX);
            CPSWCpdmaChIntrDisable(gEthDrvObj.baseAddr,
                                  txChNum,
                                  CPSW_CH_INTR_TX);

            /* Disable Rx threshold interrupt in CPDMA */
            CPSWCpdmaChIntrDisable(gEthDrvObj.baseAddr, rxChNum,
                                  CPSW_CH_INTR_RX_THR);

            Eth_freeBuffers(pPortObj->txBufObjArray, ETH_NUM_TX_BUFFERS);
            Eth_freeBuffers(pPortObj->rxBufObjArray, ETH_NUM_RX_BUFFERS);

            EthStatsDeInit(gEthDrvObj.baseAddr, &(gEthDrvObj.statsObj), CtrlIdx);
            EthStatsDeInit(gEthDrvObj.baseAddr, &(gEthDrvObj.statsObj), portIdx);

            Eth_cptsDeInit(&gEthDrvObj.cptsObj);

            /* Set controller mode to active */
            gEthDrvObj.ctrlMode          = ETH_MODE_DOWN;
            gEthControllerModeChangeFlag = (uint32) TRUE;

            SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_0();

            retVal = E_OK;
        }
        else
        {
            /*
             * Enable the Ethernet controller, enable all transmit and receive
             * buffers
             */
            SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_0();

            Eth_CpdmaConfigType *pCpdmaConfig = &(gEthDrvObj.ethConfig.cpdmaCfg);

            Eth_enableControllerToTransmitAndReceiveBuffers(pCpdmaConfig);

            if (pCpdmaConfig->rxThreshCount != 0U)
            {
                /*
                 * Reset the free buffer count for this channel
                 * (it is write to increment, force to rollover to zero)
                 */
                CPSWSetCpdmaNumFreeBuf(gEthDrvObj.baseAddr, rxChNum,
                           (gEthDrvObj.maxRxBuffDesc));
                /* Set the threshold for the RX_THRESH interrupt trigger */

                /* Enable Rx threshold interrupt in CPDMA */
                CPSWCpdmaChIntrEnable(gEthDrvObj.baseAddr, rxChNum,
                                      CPSW_CH_INTR_RX_THR);
            }
            /*
             * Currently no. of descriptors can not be more than
             * number of buffers
             */

                gEthDrvObj.maxTxBuffDesc = (uint32) ETH_NUM_TX_BUFFERS;

                gEthDrvObj.maxRxBuffDesc = (uint32) ETH_NUM_RX_BUFFERS;

            descStartAddr = ((uint32) (gEthDrvObj.descMemBaseAddr) + 
                            (gEthDrvObj.maxRxBuffDesc*sizeof (Eth_CpdmaBuffDescType)));
 
            EthBuffDescInit(gEthDrvObj.ctrlIdx,
                            &(gEthDrvObj.txDescRing),
                            (uint32) ETH_XFER_MODE_TX,
                            gEthDrvObj.maxTxBuffDesc,
                            descStartAddr);
            descStartAddr = (uint32) (gEthDrvObj.descMemBaseAddr);
            EthBuffDescInit(gEthDrvObj.ctrlIdx,
                            &(gEthDrvObj.rxDescRing),
                            ETH_XFER_MODE_RX,
                            gEthDrvObj.maxRxBuffDesc,
                            descStartAddr);
            /* Enable all transmit and receive buffers */
            
            CPSWCpdmaXferHdrDescPtrWrite(gEthDrvObj.baseAddr,
                ETH_XFER_MODE_RX,
                (Eth_CpdmaBuffDescType *)CSL_locToGlobAddr((uintptr_t)
			    gEthDrvObj.rxDescRing.pHead),
                rxChNum);
				
		    /* Enable the statistics */
            /* Open the stats module */
            retVal = EthStatsInit(gEthDrvObj.baseAddr,
                                  &(gEthDrvObj.statsObj),
                                  portIdx);

            #if (ETH_GLOBALTIMESUPPORT_API == STD_ON)
            /* Enable CPTS module */
            retVal += Eth_cptsInit( gEthDrvObj.baseAddr, &(gEthDrvObj.cptsObj),
                                    &(gEthDrvObj.ethConfig.cptsCfg), portIdx );
            #endif
			if ( (Std_ReturnType) E_NOT_OK != retVal)
            {

                /* Enable the transmission and reception */
                CPSWCpdmaXferEnable(gEthDrvObj.baseAddr, ETH_XFER_MODE_TX);
                CPSWCpdmaXferEnable(gEthDrvObj.baseAddr, ETH_XFER_MODE_RX);

                /* Set controller mode to active */
                gEthDrvObj.ctrlMode          = ETH_MODE_ACTIVE;
                gEthControllerModeChangeFlag = (uint32) TRUE;
		    }

            SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_0();
        }

    return retVal;
}

void Eth_HwSetPhysAddr(uint8 CtrlIdx, P2CONST(uint8, AUTOMATIC, ETH_APPL_DATA) 
     PhysAddrPtr)
{
    uint8  currPort = 0U;
    Eth_PortConfigType *pPortCfg = NULL_PTR;
	/* Each port is considered as one controller */
	pPortCfg = &gEthDrvObj.portObj.portCfg;
	currPort = gEthDrvObj.portObj.portNum;
	SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_0();
	Eth_configureSwitch(CtrlIdx, PhysAddrPtr);

	/* Copy MAC address to config structure */
	(void) memcpy((void *) &(pPortCfg->macCfg.macAddr[0U]),
				(const void *) PhysAddrPtr,
				 ETH_MAC_ADDR_LEN);

	/*   Configure Mac Address  for the port */
	CPSWSetPortSrcAddr(gEthDrvObj.baseAddr, currPort,
					   pPortCfg->macCfg.macAddr);
	
	SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_0();
}

Std_ReturnType Eth_HwUpdatePhysAddrFilter(
                        uint8 CtrlIdx,
                        P2VAR(uint8, AUTOMATIC,
                        ETH_APPL_DATA) PhysAddrPtr, Eth_FilterActionType Action)
{
    uint8          currPort = 0U;
    uint32         aleIdx = 0U;
    Std_ReturnType         retVal = E_NOT_OK;
 /* Each port is considered as one controller */
            currPort = gEthDrvObj.portObj.portNum;

            if (ETH_ADD_TO_FILTER == Action)
            {
                retVal = Eth_allowReception(CtrlIdx, currPort, PhysAddrPtr);
            }
            else
            {
               if ((uint32) TRUE ==
                 CPSWAleValidateMacAddr(PhysAddrPtr, ETH_MACADDR_TYPE_MULTICAST))
                {
                    aleIdx = CPSWAleMulticastEntryPortDel(gEthDrvObj.baseAddr,
                                                          PhysAddrPtr,
                                                          ETH_NOVLAN_ID,
                                                          ETH_HOST_PORT_ID);
					if (CPSW_ALE_ENTRY_MAX == aleIdx)
					{
						retVal = E_NOT_OK;
					}
					else
					{
						retVal = E_OK;
					}
                    aleIdx = CPSWAleMulticastEntryPortDel(gEthDrvObj.baseAddr,
                                                          PhysAddrPtr,
                                                          ETH_NOVLAN_ID,
                                                          currPort);
                }
                else
                {
                    aleIdx = CPSWAleUnicastEntryDel(gEthDrvObj.baseAddr,
                                                PhysAddrPtr,
                                                ETH_NOVLAN_ID,
                                                ETH_HOST_PORT_ID);
                }
                /* Check for error table entry is not free*/
                if ((CPSW_ALE_ENTRY_MAX == aleIdx) && (retVal != E_NOT_OK))
                {
                    retVal = E_NOT_OK;
                }
            }

    return (retVal);
}

static void
    Eth_configureSwitch(uint8 CtrlIdx, const uint8 macAddr[])
{
    uint32         currPort = 0U;
    uint32 flushOldAddrFlag = (uint32) FALSE;
    uint8  oldMacAddr[ETH_MAC_ADDR_LEN];


    /* Each port is considered as one controller */
    currPort = gEthDrvObj.portObj.portNum;


    /* Check if MAC address is already set(if this is update MAC
     * operation)
     * if yes, remove old MAC addr entries from ALE
     */
    if ((Std_ReturnType) E_OK ==
        CPSWGetPortSrcAddr(gEthDrvObj.baseAddr, currPort, oldMacAddr))
    {
        flushOldAddrFlag = (uint32) TRUE;
    }

    {
        uint32 portMask = 0U;
        uint32 tmpPortId = 0U, tmpCurrPort = 0U;

        /* For normal CPSW switch mode, set multicast entry. */
        /* Set portmask for all ports */
        tmpPortId = ((uint32)1U << ETH_HOST_PORT_ID);
        tmpCurrPort = ((uint32)1U << currPort);

        portMask = (tmpPortId | tmpCurrPort);

        (void) CPSWAleMulticastEntryAdd(gEthDrvObj.baseAddr, gBcastAddr,
                                    ETH_NOVLAN_ID, portMask, &gMulticastParams);
        (void) CPSWAleMulticastEntryAdd(gEthDrvObj.baseAddr, gPtpMcastAddr,
                                    ETH_NOVLAN_ID, portMask, &gMulticastParams);

        if (((uint32) TRUE) == flushOldAddrFlag)
        {
            (void) CPSWAleUnicastEntryDel(gEthDrvObj.baseAddr,
                                          oldMacAddr,
                                          ETH_NOVLAN_ID,
                                          ETH_HOST_PORT_ID);
        }

        (void) CPSWAleUnicastEntryAdd(gEthDrvObj.baseAddr,
                                      macAddr,
                                      ETH_NOVLAN_ID,
                                      ETH_HOST_PORT_ID,
                                      &gUnicastParams);
    }
}

static Std_ReturnType Eth_allowReception
     (uint8 CtrlIdx, uint8 currPort, 
	  P2VAR(uint8, AUTOMATIC, ETH_APPL_DATA)PhysAddrPtr)
 {
     uint32         aleIdx = 0U;
     Std_ReturnType retVal = (Std_ReturnType) E_OK;

     if ((uint32) TRUE == EthCheckNullMACAddr(PhysAddrPtr))
     {
         /*
          * Requirements SWS_Eth_00147
          * If the physical source address (MAC address) is set to
          * 00:00:00:00:00:00, this shall reduce the filter to the
          * controllers unique unicast MAC address and end
          * promiscuous mode if it was turned on.
          */
         /* Disable bypass mode */
         CPSWAleBypassEnable(gEthDrvObj.baseAddr, (uint32) FALSE);

         /* Get controllers unique unicast MAC address which was set earlier by
          * Eth_SetPhysAddr */
         Eth_PortConfigType *pPortCfg = &(gEthDrvObj.portObj.portCfg);
         /* Sets the ethernet address at the CPSW port  */
         if( (uint32) TRUE != EthCheckNullMACAddr(pPortCfg->macCfg.macAddr) )
         {
             Eth_configureSwitch(CtrlIdx, pPortCfg->macCfg.macAddr);
         }
         else
         {
             retVal = (Std_ReturnType) E_NOT_OK;
         }
     }
     /*
      * Requirements SWS_Eth_00144
      * If the physical source address (MAC address) is set to
      * FF:FF:FF:FF:FF:FF, this shall completely open the filter
      */
     else if ((uint32) TRUE ==
              CPSWAleValidateMacAddr(PhysAddrPtr, ETH_MACADDR_TYPE_BROADCAST))
     {
         /* Clear ALE table*/
         CPSWAleClearTable(gEthDrvObj.baseAddr);
         /* Bypass ALE to pass all data to host */
         CPSWAleBypassEnable(gEthDrvObj.baseAddr, (uint32) TRUE);
     }
     else
     {
         /* Disable bypass mode if it was enabled */
         CPSWAleBypassEnable(gEthDrvObj.baseAddr, (uint32) FALSE);

         if ((uint32) TRUE ==
               CPSWAleValidateMacAddr(PhysAddrPtr, ETH_MACADDR_TYPE_MULTICAST))
         {
             uint32 portMask = ( (1U << ETH_HOST_PORT_ID) |
                                 (1U << currPort) );
             aleIdx = CPSWAleMulticastEntryAdd(gEthDrvObj.baseAddr, PhysAddrPtr,
                                    ETH_NOVLAN_ID, portMask, &gMulticastParams);
             /* Check for error table entry is not free*/
             if (CPSW_ALE_ENTRY_MAX == aleIdx)
             {
                 retVal = (Std_ReturnType) E_NOT_OK;
             }
         }
         else
         {
             aleIdx = CPSWAleUnicastEntryAdd(gEthDrvObj.baseAddr,
                                             PhysAddrPtr,
                                             ETH_NOVLAN_ID,
                                             ETH_HOST_PORT_ID,
                                             &gUnicastParams);
             /* Check for error table entry is not free*/
             if (CPSW_ALE_ENTRY_MAX == aleIdx)
             {
                 retVal = (Std_ReturnType) E_NOT_OK;
             }
         }
     }
     return retVal;
 }

uint32 EthCheckNullMACAddr(
    const uint8 macAddr[ETH_MAC_ADDR_LEN])
{
    uint32 i      = 0U;
    uint32 retVal = (uint32) TRUE;

    for (i = 0U; i < ETH_MAC_ADDR_LEN; i++)
    {
        if (0U != macAddr[i])
        {
            retVal = (uint32) FALSE;
            break;
        }
    }
    return retVal;
}

void Eth_freeBuffers(Eth_BufObjType *bufObjArray,
                                           uint32 numBuffers)
{
    uint32 i = 0U;

    for (i = 0U; i < numBuffers; i++)
    {
        bufObjArray[i].bufState = ETH_BUF_STATE_FREE;
    }
}

static void
    Eth_enableControllerToTransmitAndReceiveBuffers(
    Eth_CpdmaConfigType *pCpdmaConfig)
{
    /*
     * ControllerInit function will enable packet receive, and after
     * enabling CPDMA receive this packet would be processed.
     * Resetting CPDMA to avoid these packet processing.
     */
    /* Enable the interrupts for channel 0 and for control core 0 */
    CPSWCpdmaChIntrEnable(gEthDrvObj.baseAddr, ETH_CPDMA_DEFAULT_RX_CHANNEL_NUM,
                          CPSW_CH_INTR_RX);
    CPSWCpdmaChIntrEnable(gEthDrvObj.baseAddr, ETH_CPDMA_DEFAULT_TX_CHANNEL_NUM,
                          CPSW_CH_INTR_TX);

#if (ETH_HOST_ERROR_INTERRUPT == STD_ON)
    /* Enable host port error interrupts */
    CPSWCpdmaDmaIntrEnable(gEthDrvObj.baseAddr, (uint32) CPSW_HOST_ERR_INT);
#endif
    /* Enable CPDMA Rx and/or Tx interrupt pacing */
    if ((pCpdmaConfig->rxInterruptPacingEnabled != 0U) ||
        (pCpdmaConfig->txInterruptPacingEnabled != 0U))
    {
        /*
         * Calculate prescale count to get 5us pulse from MAIN_CLK
         */
#if (1U)
        CPSWSetPrescale(gEthDrvObj.baseAddr,
                          ((pCpdmaConfig->pacingClkFreq *
                            (uint32) 5U) / (uint32) 1000000U));
#else
        CPSWWrSetPrescale(gEthDrvObj.baseAddr,
                          (uint32) ((pCpdmaConfig->pacingClkFreq *
                                     5.0F) / 1000000.0));
#endif

        if (pCpdmaConfig->rxInterruptPacingEnabled == (uint32) TRUE)
        {
            CPSWEnableIntrPacing(
                gEthDrvObj.baseAddr,
                CPSW_INTR_TYPE_RX,
                pCpdmaConfig->rxInterruptsPerMsec);
        }

        if (pCpdmaConfig->txInterruptPacingEnabled == (uint32) TRUE)
        {
            CPSWEnableIntrPacing(
                gEthDrvObj.baseAddr,
                CPSW_INTR_TYPE_TX,
                pCpdmaConfig->rxInterruptsPerMsec);
        }
    }

    return;
}

void EthBuffDescInit(uint8 ctrlIdx,
                     Eth_CpdmaBuffDescQueue *pRing,
                     uint32                xferType,
                     uint32                numBuffDesc,
                     uint32                startAddr)
{
    Eth_CpdmaBuffDescType *pCurrBuffDesc = NULL_PTR;
    Eth_CpdmaBuffDescType *pTempCurrBuffDesc = NULL_PTR;
    Eth_CpdmaBuffDescType *pLastBuffDesc = NULL_PTR;
    uint32           numBufDescCount = 0U;

    pRing->pFreeHead = (Eth_CpdmaBuffDescType *) startAddr;

    if (ETH_XFER_MODE_TX == (Eth_XferModeType)xferType)
    {
        pRing->pHead = pRing->pFreeHead;
        pRing->pTail = NULL;
    }

  pRing->freeBuffDesc = numBuffDesc;
  pCurrBuffDesc       = pRing->pFreeHead;
  pTempCurrBuffDesc   = pCurrBuffDesc;

    if (0U != numBuffDesc)
    {
        /* Number of buffer given to allocate are non-zero*/

        /* Create the rx ring of buffer descriptors */
        numBufDescCount = numBuffDesc;
        while (0U != numBufDescCount)
        {
            if ((uint32) ETH_XFER_MODE_RX == xferType)
            {
                if ((gEthDrvObj.enableCacheOps == (uint32) TRUE) &&
                    (gEthDrvObj.cacheFlushFnPtr != NULL))
                {
                    /* Double cast to avoid MISRA-C:2004 11.4 */
                  gEthDrvObj.cacheFlushFnPtr((uint8 *) ((void *) pCurrBuffDesc),
                                                     (uint32)1514);
                }
                pCurrBuffDesc =pTempCurrBuffDesc;
                pCurrBuffDesc->pNextBuffDesc   =  
				                (void *)(uintptr_t)CSL_locToGlobAddr((uintptr_t)
                                  pCurrBuffDesc+sizeof (Eth_CpdmaBuffDescType));

            }
            if ((uint32) ETH_XFER_MODE_TX == xferType)
            {
                pCurrBuffDesc->pNextBuffDesc     = pCurrBuffDesc + 0x1U;

            }
            pCurrBuffDesc->flagsAndPacketLength = 0U;
            
            /* if ((uint32) ETH_XFER_MODE_RX == xferType)
            {
                HW_SET_FIELD32(pCurrBuffDesc->flagsAndPacketLength, 
				               CPSW_CPDMA_WRD3_OWN,
                               CPSW_CPDMA_WRD3_OWN_ENABLE);
            } */
            pLastBuffDesc = pCurrBuffDesc;
            pCurrBuffDesc = pCurrBuffDesc->pNextBuffDesc;
            numBufDescCount--;
            pTempCurrBuffDesc++;
        }

        pLastBuffDesc->pNextBuffDesc = pRing->pFreeHead;
       
        if ((uint32) ETH_XFER_MODE_RX == xferType)
        {
            /* We are going to receive starting from the free head */
            pRing->pHead = pRing->pFreeHead;
            pRing->pTail = pLastBuffDesc;
            EthCpswRxBuffDescAllocate(ctrlIdx, pRing);

            /*
             * Close the ring to indicate end of buffer ring, when CPSW sees
             * 0x0 as next B.D it stops receiving packets as no buffer to store
             * data.
             */
            pLastBuffDesc->pNextBuffDesc = (struct Eth_CpdmaBuffDesc *) NULL_PTR;
        }
    }
}

void EthCpswRxBuffDescAllocate(
    uint8 ctrlIdx, Eth_CpdmaBuffDescQueue *pRing)
{
    Eth_CpdmaBuffDescType *pCurrRxBuffDesc = NULL_PTR;
    Eth_CpdmaBuffDescType *pLastRxBuffDesc = NULL_PTR;
    Eth_CpdmaBuffDescType *pHeadRxBuffDesc = NULL_PTR;
    Eth_BufObjType  *pEthBufObj = NULL_PTR;
    uint32           allocateFlag = (uint32) FALSE;

    /* Start from the free head of the chain */
   pCurrRxBuffDesc = pRing->pFreeHead;

    /* Note down the current positions */
    pHeadRxBuffDesc = pRing->pFreeHead;

    while (0U != pRing->freeBuffDesc)
    {
        /*
         * Try to get a ethFrame of max. length. This shall be cache line
         * aligned if cache is enabled.
         */
        pEthBufObj = Eth_rxBufAlloc(ctrlIdx);

        /*
         * Allocate bd's if p is not NULL. This allocation does not support
         * packet buffer chaining.
         */
        if (NULL_PTR != pEthBufObj)
        {
            /* Clear descriptor flags */
          Eth_CPDMABuffDescClearFlags(pCurrRxBuffDesc);

            /* Copy Data pointer into descriptor*/
        pCurrRxBuffDesc->pDataBuffer = (Eth_CpdmaBuffDescType *)
			CSL_locToGlobAddr((uintptr_t)pEthBufObj->payload);
			
			/*
             *  Copy buffer object info into buffer descriptor for buffer
             *  mgt(not needed by CPDMA)
             */
            pCurrRxBuffDesc->pBufObj   = pEthBufObj;

            HW_SET_FIELD32(pCurrRxBuffDesc->bufferOffsetAndLength,
                           CPSW_CPDMA_RX_WRD2_BUFF_LEN,
                           pEthBufObj->len);
            HW_SET_FIELD32(pCurrRxBuffDesc->flagsAndPacketLength, 
                           CPSW_CPDMA_WRD3_OWN, CPSW_CPDMA_WRD3_OWN_ENABLE);

            pLastRxBuffDesc = pCurrRxBuffDesc;
            pCurrRxBuffDesc = (Eth_CpdmaBuffDescType *)
			            CSL_globToLocAddr((uint64_t)(uintptr_t)pCurrRxBuffDesc);
            pCurrRxBuffDesc++;
            pRing->freeBuffDesc--;
            allocateFlag = (uint32) TRUE;
        }
        else
        {
            /* No buffer available */
            break;
        }
    }

    if (((uint32) TRUE) == allocateFlag)
    {
        /* Update tail desc next pointer */
        pRing->pTail->pNextBuffDesc = pHeadRxBuffDesc;

        /* Update head and tail pointers to newly allocated descriptors */

        pRing->pTail = pLastRxBuffDesc;

        /* Close the ring to prevent overwriting of ethFrame data. */
       
       
        pRing->pTail->pNextBuffDesc = (struct Eth_CpdmaBuffDesc *) NULL_PTR;
        /*
         * If the entire ring is traversed, curr_bd will be NULL. In that case,
         * write the Rx HDP in order to continue reception.
         */
        if (NULL_PTR != pCurrRxBuffDesc)
        {
            pRing->pFreeHead = pCurrRxBuffDesc;
        }
    }
}

/*
 * \brief Eth_rxBufAlloc function.
 *        Allocate receive buffer.
 *
 * \param  None
 *
 * \return Pointer to allocated packet buffer or Null.
 *         If no free buffers available, function will
 *         return null pointer.
 */

static Eth_BufObjType *Eth_rxBufAlloc(uint8 ctrlIdx)
{
    Eth_BufObjType *pBuffObjRing = NULL_PTR;
    uint32          bufIdx = 0U;

    for (bufIdx = 0U; bufIdx < ETH_NUM_RX_BUFFERS; bufIdx++)
    {
        pBuffObjRing = &gEthDrvObj.portObj.rxBufObjArray[bufIdx];
        if (ETH_BUF_STATE_FREE == pBuffObjRing->bufState)
        {
            pBuffObjRing->bufState = ETH_BUF_STATE_IN_USE;
#if (ETH_GLOBALTIMESUPPORT_API == STD_ON)
            pBuffObjRing->enableEgressTimeStamp = (boolean) FALSE;
#endif
            break;
        }
    }
    return pBuffObjRing;
}

/** Zero init the buffer descriptor */
void Eth_CPDMABuffDescClearFlags(
    Eth_CpdmaBuffDescType *pCPDMABuffDesc)
{
    pCPDMABuffDesc->pDataBuffer             = 0x00000000U;
    pCPDMABuffDesc->bufferOffsetAndLength   = 0x00000000U;
    pCPDMABuffDesc->flagsAndPacketLength    = 0x00000000U;
}

FUNC(BufReq_ReturnType, ETH_CODE) Eth_HwProvideTxBuffer(
                        VAR(uint8, AUTOMATIC)CtrlIdx,
                        VAR(uint8, AUTOMATIC)Priority,
                        P2VAR(Eth_BufIdxType,AUTOMATIC,ETH_APPL_DATA)BufIdxPtr,
                        P2VAR(uint8,AUTOMATIC,ETH_APPL_DATA)*BufPtr,
                        P2VAR(uint16,AUTOMATIC,ETH_APPL_DATA)LenBytePtr)
{
    uint16 reqBuffLen = 0U;
    BufReq_ReturnType retVal = BUFREQ_E_NOT_OK;
    Eth_PortObject      *pPortObj;
    uint32 maxBuffIdx   = 0U;
    uint16 allocBuffLen = 0xFFFFU, maxBuffLen = 0U;
    Eth_BufIdxType bufIdx;
    uint32 bufAvlblFlag = (uint32) FALSE;

    /* Each port is considered as one controller */
           pPortObj = &(gEthDrvObj.portObj);
           /* Make sure to get empty buffer to fit data and header */
           reqBuffLen = *LenBytePtr + ETH_HLEN;

           /*
            * check if transmit buffer descriptor is available for this buffer
            * request. As no. of buffers can be more than more than no. of bd's we
            * may encounter a case where buffer is available but not buffer
            * descriptor.
            */

           if (0U == gEthDrvObj.txDescRing.freeBuffDesc)
           {
               retVal = BUFREQ_E_BUSY;
           }
           else
           {
               for (bufIdx = 0U; bufIdx < ETH_NUM_TX_BUFFERS; bufIdx++)
               {
                   if (ETH_BUF_STATE_FREE ==
                       pPortObj->txBufObjArray[bufIdx].bufState)
                   {
                       /*
                        *  At least one buffer available, it may be not of
                        *  exact size requested
                        */
                       uint16 currBuffLen = pPortObj->txBufObjArray[bufIdx].len;
                       bufAvlblFlag = (uint32) TRUE;
                       if (currBuffLen > maxBuffLen)
                       {
                           maxBuffLen = currBuffLen;
                           maxBuffIdx = bufIdx;
                       }
                       /* find best fit buffer */
                       if ((reqBuffLen <= currBuffLen) &&
                           (allocBuffLen > currBuffLen))
                       {
                           *BufIdxPtr   = bufIdx;
                           allocBuffLen = pPortObj->txBufObjArray[bufIdx].len;
                       }
                   }
                   else
                   {
                       /* Do nothing */
                   }
               }

               if (((uint32) FALSE) == bufAvlblFlag)
               {
                   /* No buffer available */
                   retVal = BUFREQ_E_BUSY;
               }
               else
               {
                   retVal = Eth_checkBuffLen(&allocBuffLen, BufIdxPtr, maxBuffIdx,
                                             maxBuffLen);

                   /* Add Ethernet header length to BufPtr and return to
                    * application */
                   if (BUFREQ_E_BUSY != retVal)
                   {

                       if (BUFREQ_E_OVFL != retVal)
                       {
                         *BufPtr = (uint8 *) pPortObj->txBufObjArray
						                                 [maxBuffIdx].payload;

                          pPortObj->txBufObjArray[maxBuffIdx].bufState = 
						                                  ETH_BUF_STATE_IN_USE;

                            *BufPtr = *BufPtr + (uint8) ETH_HLEN;

                            /* Enter critical section */
                           SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_0();
                           /* Decrement free bds, since one is consumed */
                           gEthDrvObj.txDescRing.freeBuffDesc--;
                           /* Enter critical section */
                           SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_0();
                       }


                       if (*LenBytePtr > (allocBuffLen - ETH_HLEN))
                       {
                       /*
                        * [SWS_Eth_00079] If a buffer is requested with 
						*  Eth_ProvideTxBuffer that is larger than the available
                        *  buffer length, the buffer shall not be locked but 
                        *  return the available length and BUFREQ_E_OVFL.
                        */
                       /*
                       * Buffer available is smaller than (requested + Header)
                       * Subtract header length from allocated size
                       */
                           *LenBytePtr = (allocBuffLen - ETH_HLEN);
                       }


                   }
               }
           }
       return retVal;
}

static BufReq_ReturnType  Eth_checkBuffLen
    ( uint16 *allocBuffLen,
      P2VAR(Eth_BufIdxType, AUTOMATIC, ETH_APPL_DAT)BufIdxPtr,
      uint32 maxBuffIdx,
      uint16 maxBuffLen)
{
    BufReq_ReturnType retVal = BUFREQ_E_NOT_OK;

    if (0xFFFFU == *allocBuffLen)
    {
        /*No buffer of lenByte available, allocate best available*/
        if (maxBuffLen > ETH_HLEN)
        {
            retVal        = BUFREQ_E_OVFL;
            *BufIdxPtr    = maxBuffIdx;
            *allocBuffLen = maxBuffLen;
        }
        else
        {
            retVal = BUFREQ_E_BUSY;
        }
    }
    else
    {
        /* Buffer of requested size available */
        retVal = BUFREQ_OK;
    }
    return retVal;
}

FUNC(Std_ReturnType, ETH_CODE) Eth_HwTransmit(
                            VAR(uint8, AUTOMATIC) CtrlIdx,
                            VAR(Eth_BufIdxType,AUTOMATIC)BufIdx,
                            VAR(Eth_FrameType,AUTOMATIC) FrameType,
                            VAR(boolean,AUTOMATIC) TxConfirmation,
                            VAR(uint16,AUTOMATIC) LenByte,
                            P2CONST(uint8, AUTOMATIC,ETH_APPL_DATA) PhysAddrPtr)
{
    Std_ReturnType      retVal = (Std_ReturnType) E_OK;
    Eth_PortObject     *pPortObj = NULL_PTR;
    Eth_PortConfigType *pPortCfg = NULL_PTR;
    uint16 totalLen = 0U;

    /* Each port is considered as one controller */
    pPortObj = &(gEthDrvObj.portObj);
    pPortCfg = &pPortObj->portCfg;

    if ((ETH_BUF_STATE_FREE == pPortObj->txBufObjArray[BufIdx].bufState) ||
        (ETH_BUF_STATE_QUED == pPortObj->txBufObjArray[BufIdx].bufState))
    {
        /*
         * Buffer is not allocated through call to Eth_ProvideTxBuffer or
         * already qued for transmit.
         */
        retVal = (Std_ReturnType) E_NOT_OK;
    }
    else
    {

        Eth_FrameObjType *pDataBuffer;
        Eth_CpdmaBuffDescType *pXmitTxBuffDesc;
        Eth_BufObjType *pTempBufObj = &(pPortObj->txBufObjArray[BufIdx]);
        Eth_CpdmaBuffDescQueue *pTxDescRing = &(gEthDrvObj.txDescRing);

        /* Take packet from Tx Buffer ring using BufIdx */
        pDataBuffer = (Eth_FrameObjType *) pTempBufObj->payload;
        totalLen  = LenByte + ETH_HLEN;
        /*
         * Make sure the driver does not transmit packet less than min. as per the
         * Ethernet standards.
         */
        if (totalLen < (uint16)60U)
        {
            uint16 remLenInBytes = (60U - totalLen);
            /* Zero pad the packet data to at least 60 known bytes */
            
            memset ( ((void *)((uint32)pDataBuffer + totalLen)), 0, 
			          (size_t)remLenInBytes );
    /* With Ethernet FCS, total transmitted size will be the minimum 64 bytes */
            totalLen = (uint16)60U;
        }
		
#if (ETH_GLOBALTIMESUPPORT_API == STD_ON)
            if ((boolean)TRUE == pTempBufObj->enableEgressTimeStamp)
            {
                uint8 *msgtype;
                uint16 *seqid;

                msgtype = pDataBuffer->payload;
                /* Indicate the end of the packet */
                seqid = (uint16 *)(pDataBuffer->payload + 
				        (uint8)TIME_SYNC_OFFSET_PTP_SEQUENCE_ID);
                pTempBufObj->bufCptsEventInfo.messageType = 
				             (Eth_CptsMessageType) (*msgtype & (uint8)0xFU);
                pTempBufObj->bufCptsEventInfo.sequenceId = ntohs(*seqid);
            }
#endif
        /* set application callback flag */
        pTempBufObj->txConfirmation = TxConfirmation;

        (void) memcpy(pDataBuffer->header.srcMacAddr,
                      (void *) &(pPortCfg->macCfg.macAddr[0U]),
                       ETH_MAC_ADDR_LEN);
        (void) memcpy(pDataBuffer->header.dstMacAddr, (void *) (PhysAddrPtr),
                      ETH_MAC_ADDR_LEN);
        pDataBuffer->header.h_proto =
            ((FrameType & 0xFFU) << 8U) | ((FrameType & 0xFF00U) >> 8U);

        /* Flush buffers */
        
        if ((gEthDrvObj.enableCacheOps == (uint32) TRUE) &&
            (gEthDrvObj.cacheFlushFnPtr != NULL))
        {
            /* Double cast to avoid MISRA-C:2004 11.4 */
            gEthDrvObj.cacheFlushFnPtr((uint8 *) ((void *) pDataBuffer),
                                     (uint32)totalLen);
        }

        SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_0();

        /* Get the buffer descriptor which is free to transmit */
        pXmitTxBuffDesc = pTxDescRing->pFreeHead;

        
        Eth_CPDMABuffDescClearFlags(pXmitTxBuffDesc);

        HW_SET_FIELD32(pXmitTxBuffDesc->flagsAndPacketLength, 
		               CPSW_CPDMA_WRD3_PKT_LEN, totalLen);
        /* Indicate the start of the packet */
        HW_SET_FIELD32(pXmitTxBuffDesc->flagsAndPacketLength, 
		               CPSW_CPDMA_WRD3_SOP,
                       CPSW_CPDMA_WRD3_SOP_ENABLE);
        HW_SET_FIELD32(pXmitTxBuffDesc->flagsAndPacketLength, 
		               CPSW_CPDMA_WRD3_OWN,
                       CPSW_CPDMA_WRD3_OWN_ENABLE);

        /* Intialize the buffer pointer and length */
		pXmitTxBuffDesc->pDataBuffer  = (void *)(uintptr_t)
		                          CSL_locToGlobAddr((uintptr_t)pDataBuffer);

        HW_SET_FIELD32(pXmitTxBuffDesc->bufferOffsetAndLength,
                       CPSW_CPDMA_TX_WRD2_BUFF_LEN,
                       totalLen);

        /* Update Transmit ring head */
        pTxDescRing->pFreeHead = pXmitTxBuffDesc->pNextBuffDesc;

        /* Indicate the end of the packet */
        
        pXmitTxBuffDesc->pNextBuffDesc = (struct Eth_CpdmaBuffDesc *) NULL_PTR;
        HW_SET_FIELD32(pXmitTxBuffDesc->flagsAndPacketLength, CPSW_CPDMA_WRD3_EOP,
                       CPSW_CPDMA_WRD3_EOP_ENABLE);

        /* Copy buffer information into TX buffer descriptors */
        pXmitTxBuffDesc->pBufObj = pTempBufObj;
        /* Change buffer state to qued */
        pTempBufObj->bufState = ETH_BUF_STATE_QUED;

        /* For the first time, write the HDP with the filled bd */
        
        if (NULL_PTR == pTxDescRing->pTail)
        {
			Eth_delay(1000);
            CPSWCpdmaXferHdrDescPtrWrite(gEthDrvObj.baseAddr,
                                         ETH_XFER_MODE_TX,
               (Eth_CpdmaBuffDescType *)CSL_locToGlobAddr((uintptr_t)pXmitTxBuffDesc),
                                         ETH_CPDMA_DEFAULT_TX_CHANNEL_NUM);
        }
        else
        {
            /*
             * Chain the bd's. If the DMA engine, already reached the end of
             * the chain, the EOQ will be set. In that case, HDP shall be
             * written again.
             */
            /* Chain the bd's. */
            pTxDescRing->pTail->pNextBuffDesc = pXmitTxBuffDesc;


            if (CPSW_CPDMA_WRD3_EOQ_ENABLE ==
                (uint32) HW_GET_FIELD(pTxDescRing->pTail->flagsAndPacketLength,
                                      CPSW_CPDMA_WRD3_EOQ) )
            {
                HW_WR_FIELD32(&pTxDescRing->pTail->flagsAndPacketLength,
                                  CPSW_CPDMA_WRD3_EOQ,
                                  CPSW_CPDMA_WRD3_EOQ_DISABLE);

                /* Write the Header Descriptor Pointer and start DMA */
                CPSWCpdmaXferHdrDescPtrWrite(gEthDrvObj.baseAddr,
                (uint32) ETH_XFER_MODE_TX, (Eth_CpdmaBuffDescType *)
                CSL_locToGlobAddr((uintptr_t)pXmitTxBuffDesc),
                 ETH_CPDMA_DEFAULT_TX_CHANNEL_NUM);
           }
        }

        /* Tail describes last packet transferred */
        pTxDescRing->pTail = pXmitTxBuffDesc;
        gEthDrvObj.txDescRing.freeBuffDesc++;
        if (((boolean) FALSE) == pTempBufObj->txConfirmation)
        {
            /*
             * Requirements: SWS_Eth_00089 (If TxConfirmation is false, the
             * function shall release the buffer resource).
             */
            pTempBufObj->bufState = ETH_BUF_STATE_FREE;
        }
        SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_0();
    }
return (retVal);
}

uint64 CSL_locToGlobAddr(uintptr_t locAddr)
{
    uintptr_t globAddr = locAddr;

    if (locAddr < (SOC_MSS_TCMA_RAM_BASE + SOC_MSS_TCMA_RAM_SIZE))
    {
        /* TCMA: locAddr | 0x78000000) */
        globAddr = (locAddr | SOC_GLOB_MSS_TCMA_RAM_BASE);
    }
    else if ((locAddr >= SOC_MSS_TCMB_RAM_BASE) &&
             (locAddr < (SOC_MSS_TCMB_RAM_BASE + SOC_MSS_TCMB_RAM_SIZE)))
    {
        /* TCMB: (locAddr & 0xFFFF) | 0x78100000 */
        globAddr = ((locAddr & 0xFFFFU) | SOC_GLOB_MSS_TCMB_RAM_BASE);
    }

    return ((uint64) globAddr);
}

uintptr_t CSL_globToLocAddr(uint64_t globAddr64)
{
    uintptr_t globAddr = (uintptr_t) globAddr64;
    uint32_t locAddr = globAddr;

    if ((globAddr >= SOC_GLOB_MSS_TCMA_RAM_BASE) &&
        (globAddr < (SOC_GLOB_MSS_TCMA_RAM_BASE + SOC_MSS_TCMA_RAM_SIZE)))
    {
        /* TCMA: (globAddr & 0xFFFF) | 0x00020000U) */
        locAddr = ((globAddr & 0xFFFFU) | SOC_MSS_TCMA_RAM_BASE);
    }
    else if ((globAddr >= SOC_GLOB_MSS_TCMB_RAM_BASE) &&
             (globAddr < (SOC_GLOB_MSS_TCMB_RAM_BASE + SOC_MSS_TCMB_RAM_SIZE)))
    {
        /* TCMB: (globAddr & 0xFFFF) | 0x00080000U) */
        locAddr = ((globAddr & 0xFFFFU) | SOC_MSS_TCMB_RAM_BASE);
    }

    return (locAddr);
}

void CPSWCpdmaXferHdrDescPtrWrite(uint32 baseAddr,
                                  uint32                 xferMode,
                                  const Eth_CpdmaBuffDescType *descHdr,
                                  uint32                 chNum)
{
    if ((uint32)ETH_XFER_MODE_RX == xferMode)
    {  
        HW_WR_REG32(
            baseAddr + CPSW_CPDMA_TH_HDP_REG(chNum),
            descHdr);
    }
    else if ((uint32)ETH_XFER_MODE_TX == xferMode)
    {    
        HW_WR_REG32(
            baseAddr + CPSW_CPDMA_FH_HDP_REG(chNum),
            descHdr);
    }
    else
    {
        /* This error does not happen because of check done already */
    }

    return;
}

FUNC(void, ETH_CODE) Eth_HwReceive(
                 VAR(uint8, AUTOMATIC)CtrlIdx,
                 VAR(uint8, AUTOMATIC)FifoIdx,
                 P2VAR(Eth_RxStatusType,AUTOMATIC,ETH_APPL_DATA)RxStatusPtr)
{
    uint32 rxIntFlags = 0U, threshIntFlags = 0U;
    uint32 channelNum = 0U, channelMask = 0U;
    *RxStatusPtr = ETH_NOT_RECEIVED;

        rxIntFlags = CPSWChIntrStatus(gEthDrvObj.baseAddr,
                                      CPSW_CH_INTR_RX);

        threshIntFlags = CPSWChIntrStatus(gEthDrvObj.baseAddr,
                                               CPSW_CH_INTR_RX_THR);

    rxIntFlags |= threshIntFlags;

    /* Look for receive interrupts from across all CPDMA Rx Channels */
    while (0U != rxIntFlags)
    {
        channelMask = 0x1U << channelNum;

        if ((uint32) 0U != (uint32) (rxIntFlags & channelMask))
        {
            SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_0();

            *RxStatusPtr = EthRxBuffDescProcessSingle(gEthDrvObj.ctrlIdx,
                                                      channelNum);
            SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_0();
        }

        /* Clear the channel flag for the channel just handled */
        rxIntFlags &= ~channelMask;
        channelNum++;
    }

    if (ETH_NOT_RECEIVED != *RxStatusPtr)
    {
        if (0U != threshIntFlags)
        {
            /* All outstanding RX_THRESH interrupts were handled */
         CPSWCpdmaWriteEoiVector(gEthDrvObj.baseAddr, CPSW_WR_INTR_LINE_RX_THR);
        }
        /* Write the EOI register */
        CPSWCpdmaWriteEoiVector(gEthDrvObj.baseAddr, CPSW_WR_INTR_LINE_RX);
    }
return;

}

Eth_RxStatusType EthRxBuffDescProcessSingle(uint8 ctrlIdx, uint32 chNum)
{
    Eth_CpdmaBuffDescType      *pCurrRxBuffDesc = NULL_PTR;
	Eth_CpdmaBuffDescType      *pLastBuffDesc = NULL_PTR;
    Eth_CpdmaBuffDescQueue     *pRxDescRing = &(gEthDrvObj.rxDescRing);
    uint32                      cp = 0U, packetCount = 0U;
    Eth_RxStatusType            rxStatus = ETH_NOT_RECEIVED;

    CPSWCpdmaReadRxCP(gEthDrvObj.baseAddr, chNum, &cp);

    packetCount = 0u;

    /* Only do stuff if not a teardown request for this channel */
    if (CPSW_CPDMA_TEAR_DWN_ACK != cp)
    {
        /* Get the bd which contains the earliest filled data */
        pCurrRxBuffDesc = pRxDescRing->pHead;

        /*
         * Process the receive buffer descriptors. When the DMA completes
         * reception, OWNERSHIP flag will be cleared.
         */
        if ( CPSW_CPDMA_WRD3_OWN_DISABLE ==
                (uint32) HW_GET_FIELD(pCurrRxBuffDesc->flagsAndPacketLength,
                                      CPSW_CPDMA_WRD3_OWN) )
        {
            EthRxProcessPacket(ctrlIdx, pCurrRxBuffDesc);

#if (ETH_AUTO_BUFF_ROTATION == STD_ON)
            /*
             * Immediately mark current buffer as free so it can be reused.
             * This buffer will not be reused until all buffers older than
             * this is reused. Application should consume buffer before it is
             * reused.
             */
        pCurrRxBuffDesc->pBufObj->bufState = ETH_BUF_STATE_FREE;

#endif

            pLastBuffDesc = pCurrRxBuffDesc;
            if (NULL_PTR == pCurrRxBuffDesc->pNextBuffDesc)
            {
             pCurrRxBuffDesc = pCurrRxBuffDesc->pNextBuffDesc;
            }
            else
            {
            pCurrRxBuffDesc = (Eth_CpdmaBuffDescType *)
			                 CSL_globToLocAddr((uint64_t)(uintptr_t)
							 pCurrRxBuffDesc->pNextBuffDesc);
            }

            packetCount++;
            pRxDescRing->freeBuffDesc++;

            /*
             * If the DMA engine took the NULL pointer, we dont have any bd to
             * process until new bd's are allocated.
             */
            if (NULL_PTR == pCurrRxBuffDesc)
            {
                pRxDescRing->pHead = pRxDescRing->pFreeHead;
            }
            else
            {
                pRxDescRing->pHead = pCurrRxBuffDesc;
                if ( CPSW_CPDMA_WRD3_OWN_DISABLE ==
                    (uint32) HW_GET_FIELD(pCurrRxBuffDesc->flagsAndPacketLength,
                                          CPSW_CPDMA_WRD3_OWN) )
                {
                    /**< frame received, more frames are available */
                    rxStatus = ETH_RECEIVED_MORE_DATA_AVAILABLE;
                }
                else
                {
                    /**< frame received, no further frames available */
                    rxStatus = ETH_RECEIVED;
                }
            }
        }
        else
        {
            /**< frame not received, no further frames available */
            rxStatus = ETH_NOT_RECEIVED;
        }
    }
    else
    {
        EthRxChTearDown(ctrlIdx, chNum);
        /**< frame not received, no further frames available */
        rxStatus = ETH_NOT_RECEIVED;
    }

    if (0U != packetCount)
    {
        EthRxCompleteXfer(ctrlIdx, chNum, packetCount, pLastBuffDesc);
    }

    return rxStatus;

}

static void EthRxProcessPacket(uint8 ctrlIdx,
                               Eth_CpdmaBuffDescType *pCurrRxBuffDesc)
{
    uint16                      totLen = 0U , dataLen = 0U;
    uint8                       srcMacAddr[ETH_MAC_ADDR_LEN];
    boolean                     isBroadcast = FALSE;
    Eth_FrameType               frameType;
    Eth_FrameObjType           *pFrameBuffer = NULL_PTR;
	Eth_FrameObjType           *pFrameBuffer1 = NULL_PTR;
    uint8                       *frameDataPtr = NULL_PTR;

    /* Get the total length of the packet */
    /*
     * Buffer length field is 11 bit so typecasting to uint16
     * will not lose data.
     */
    totLen = (uint16) HW_GET_FIELD(pCurrRxBuffDesc->flagsAndPacketLength,
                                   CPSW_CPDMA_WRD3_PKT_LEN);

    /* Remove FCS/CRC (4 octets) from total size as CPDMA passes CRC along 
	   with data */
    totLen = totLen - 4U;

    pCurrRxBuffDesc = (Eth_CpdmaBuffDescType *)
	                  CSL_globToLocAddr((uint64_t)(uintptr_t)pCurrRxBuffDesc);

    /* Get the EthFrame which is associated with the current bd */
   pFrameBuffer = (Eth_FrameObjType *) CSL_globToLocAddr(
                           (uint64_t)(uintptr_t) pCurrRxBuffDesc->pDataBuffer);

    if ((gEthDrvObj.enableCacheOps == (uint32) TRUE) &&
        (gEthDrvObj.cacheInvalidateFnPtr != NULL))
    {
        gEthDrvObj.cacheInvalidateFnPtr(
            (uint8 *) ((const void *) pFrameBuffer), (uint32)totLen);
    }

    /* Process the packet */
    (void) memcpy(srcMacAddr,
                  (const void  *) &pFrameBuffer->header.srcMacAddr,
                   ETH_MAC_ADDR_LEN);
    /* Fetch information like frametype, Isbroadcast from packet */
    if ((uint32) TRUE == CPSWAleValidateMacAddr(pFrameBuffer->header.dstMacAddr, 
	        ETH_MACADDR_TYPE_BROADCAST))
    {
        isBroadcast = (boolean) TRUE;
    }
    else
    {
        isBroadcast = (boolean) FALSE;
    }
    frameType = ntohs((Eth_FrameType) pFrameBuffer->header.h_proto);

    frameDataPtr = pFrameBuffer->payload;
    dataLen = totLen - ((uint16) sizeof(Eth_FrameHeaderType));
#if (ETH_GLOBALTIMESUPPORT_API == STD_ON)
    /*
     * If timestamping is enabled then we check for CPTS event each
     * received packet.
     */
    if (0U != Eth_cptsEventPendStatus(gEthDrvObj.cptsObj.cpswBaseAddr))
    {
        /*
         * Pop the event into SW queue to be returned to when
         * Eth_GetIngressTimeStamp is called from EthIf_RxIndication
         */
        Eth_cptsHandleEvents(&gEthDrvObj.cptsObj);
    }
#endif
    
 EthIf_RxIndication(ctrlIdx,
                       frameType,
                       isBroadcast,
                       &srcMacAddr[0U],
                       (Eth_DataType *) frameDataPtr,
                       dataLen);
}

static void EthRxChTearDown(uint8 ctrlIdx, uint32 chNum)
{
        Eth_PortObject *pPortObj = NULL_PTR;

        /* Each port is considered as one controller */
        pPortObj = &gEthDrvObj.portObj;

        /* The software should acknowledge a teardown interrupt with a
         *FFFF_FFFCh Acknowledge value */
        CPSWCpdmaXferCpWrite(gEthDrvObj.baseAddr,
                             (uint32) ETH_XFER_MODE_RX,
                             chNum,
                             (uint32) CPSW_CPDMA_TEAR_DWN_ACK);
        CPSWCpdmaXferDisable(gEthDrvObj.baseAddr,
                             (uint32) ETH_XFER_MODE_RX);

        Eth_freeBuffers(pPortObj->rxBufObjArray, ETH_NUM_RX_BUFFERS);

        /*
         * Set Eth controller mode to disabled if both RX and TX
         * channels are torn. Else set this channel torn flag to TRUE so
         * when TX channel is torn it can use this for disabling
         * controller.
         */
        if (((uint32) TRUE) == gCpdmaTxChTornFlag)
        {
            gEthControllerModeChangeFlag = (uint32) TRUE;
            gCpdmaTxChTornFlag           = (uint32) FALSE;
            gEthDrvObj.ctrlMode          = ETH_MODE_DOWN;
        }
        else
        {
            gCpdmaRxChTornFlag = (uint32) TRUE;
        }
}

static void EthRxCompleteXfer(uint8 ctrlIdx, uint32 chNum,
                       uint32 packetCount, Eth_CpdmaBuffDescType *pLastBuffDesc)
{
    uint32           endOfQueueFlag = FALSE;
    Eth_CpdmaBuffDescQueue     *pRxDescRing = &(gEthDrvObj.rxDescRing);

    /*
     * Check if Receive threshold is enabled if yes write one to
     * increment number of buffers available(This is a write to
     * increment field).
     */
    if (0U != gEthDrvObj.ethConfig.cpdmaCfg.rxThreshCount)
    {
        CPSWSetCpdmaNumFreeBuf(gEthDrvObj.baseAddr, chNum, packetCount);
    }

    /*
     * If PHead descriptor is NULL means receive operation has stopped due
     * to unavailability of buffers. Now that some buffers are allocated by
     * application(in case of this function called by Eth_Receive) restart
     * receive operation by writing to RX HDP.
     */
    endOfQueueFlag = HW_GET_FIELD(pLastBuffDesc->flagsAndPacketLength,
                                CPSW_CPDMA_WRD3_EOQ);
  
    if (((uint32) TRUE) == endOfQueueFlag)
    {
         /* We got some bd's freed; Allocate them */
        EthBuffDescInit(gEthDrvObj.ctrlIdx,
                        &(gEthDrvObj.rxDescRing),
                        ETH_XFER_MODE_RX,
                        gEthDrvObj.maxRxBuffDesc,
                        (uint32) (gEthDrvObj.descMemBaseAddr));
        
        CPSWCpdmaXferHdrDescPtrWrite(gEthDrvObj.baseAddr,
                                            (uint32) ETH_XFER_MODE_RX,
                   (Eth_CpdmaBuffDescType *)CSL_locToGlobAddr((uintptr_t)
				                            (pRxDescRing->pHead)),                      
                                            ETH_CPDMA_DEFAULT_RX_CHANNEL_NUM);
    }

    /* Acknowledge latest processed descriptors */
    CPSWCpdmaXferCpWrite(gEthDrvObj.baseAddr,
                         ETH_XFER_MODE_RX, chNum,
                         (uint32) pLastBuffDesc);
}

void EthRxBuffDescProcess(uint8 ctrlIdx, uint32 chNum)
{
    Eth_CpdmaBuffDescType      *pCurrRxBuffDesc = NULL_PTR;
	Eth_CpdmaBuffDescType      *pLastBuffDesc = NULL_PTR;
    Eth_CpdmaBuffDescQueue     *pRxDescRing = &(gEthDrvObj.rxDescRing);
    uint32                      cp = 0U, packetCount = 0U;
    
    CPSWCpdmaReadRxCP(gEthDrvObj.baseAddr, chNum, &cp);

    /* Only do stuff if not a teardown request for this channel */
    if (CPSW_CPDMA_TEAR_DWN_ACK != cp)
    {
        /* Get the bd which contains the earliest filled data */
        pCurrRxBuffDesc = pRxDescRing->pHead;
        /*
         * Process the receive buffer descriptors. When the DMA completes
         * reception, OWNERSHIP flag will be cleared.
         */
        while ( CPSW_CPDMA_WRD3_OWN_DISABLE ==
                (uint32) HW_GET_FIELD(pCurrRxBuffDesc->flagsAndPacketLength,
                                      CPSW_CPDMA_WRD3_OWN) )
        {
            EthRxProcessPacket(ctrlIdx, pCurrRxBuffDesc);

#if (ETH_AUTO_BUFF_ROTATION == STD_ON)
            /*
             * Immediately mark current buffer as free so it can be reused.
             * This buffer will not be reused until all buffers older than
             * this is reused. Application should consume buffer before it is
             * reused.
             */ 
            pCurrRxBuffDesc->pBufObj->bufState = ETH_BUF_STATE_FREE;
#endif

            pLastBuffDesc = pCurrRxBuffDesc;
            if (NULL_PTR == pCurrRxBuffDesc->pNextBuffDesc)
            {
             pCurrRxBuffDesc = pCurrRxBuffDesc->pNextBuffDesc;
            }
            else
            {
            pCurrRxBuffDesc = (Eth_CpdmaBuffDescType *)
			                  CSL_globToLocAddr((uint64_t)(uintptr_t)
							  pCurrRxBuffDesc->pNextBuffDesc);
            }
            packetCount++;
            pRxDescRing->freeBuffDesc++;

            /*
             * If the DMA engine took the NULL pointer, we dont have any bd to
             * process until new bd's are allocated.
             */
            if (NULL_PTR == pCurrRxBuffDesc)
            {
                pRxDescRing->pHead = pRxDescRing->pFreeHead;
                break;
            }

            pRxDescRing->pHead = pCurrRxBuffDesc;
        }
    }
    else
    {
        EthRxChTearDown(ctrlIdx, chNum);
    }

    if (0U != packetCount)
    {
        EthRxCompleteXfer(ctrlIdx, chNum, packetCount, pLastBuffDesc);
        
    }

}

void EthTxBuffDescProcess(uint8 ctrlIdx, uint32 chNum)
{
    Eth_CpdmaBuffDescType      *pCurrTxBuffDesc = NULL_PTR; 
	Eth_CpdmaBuffDescType      *pLastBuffDesc = NULL_PTR;
    Eth_CpdmaBuffDescType      *pHeadTxBuffDesc = NULL_PTR;
    uint32                     cnt = 0xFFFFU, cp = 0U;
    uint32  packetProcessed = 0U;
    Eth_BufObjType *pTempBufObj = NULL_PTR;
    Eth_CpdmaBuffDescQueue *pTxDescRing = &(gEthDrvObj.txDescRing);

    pHeadTxBuffDesc = pTxDescRing->pHead;
    pCurrTxBuffDesc = pTxDescRing->pHead;

    CPSWCpdmaReadTxCP(gEthDrvObj.baseAddr, chNum, &cp);

    packetProcessed = 0U;
    /* Only do stuff if not a teardown request for this channel */
    if (CPSW_CPDMA_TEAR_DWN_ACK != cp)
    {
        /* Check for correct start of packet */
        while (CPSW_CPDMA_WRD3_SOP_ENABLE ==
               (uint32) HW_GET_FIELD(pCurrTxBuffDesc->flagsAndPacketLength,
                                     CPSW_CPDMA_WRD3_SOP))
        {
            while ((cnt != 0U) && (CPSW_CPDMA_WRD3_OWN_ENABLE ==
                                   (uint32) HW_GET_FIELD(pCurrTxBuffDesc->
                                                         flagsAndPacketLength,
                                                         CPSW_CPDMA_WRD3_OWN)))
            {
                /* Make sure that the transmission is over */
                cnt--;
            }

            if (0U == cnt)
            {
                break;
            }
            else
            {
                /* One buffer descriptor is free now */
                pTxDescRing->freeBuffDesc++;

                /* Traverse till the end of packet is reached */
                while (CPSW_CPDMA_WRD3_EOP_DISABLE ==
                    (uint32) HW_GET_FIELD(pCurrTxBuffDesc->flagsAndPacketLength,
                                             CPSW_CPDMA_WRD3_EOP))
                {
                    pCurrTxBuffDesc = pCurrTxBuffDesc->pNextBuffDesc;
                    /* As this bd is not the end, its free now */
                    pTxDescRing->freeBuffDesc++;

                    if (pTxDescRing->freeBuffDesc ==
                        ((CPDMA_DESC_MEM_SIZE >>
                          1U) / sizeof (Eth_CpdmaBuffDescType)))
                    {
                        break;
                    }
                }

                /*
                 * If there are no more data transmitted, the next interrupt
                 * shall happen with the ethFrame associated with the
                 * free_head
                 */
                if (pCurrTxBuffDesc->pNextBuffDesc == NULL_PTR)
                {
                    pTxDescRing->pHead = pTxDescRing->pFreeHead;
                }
                else
                {
                    pTxDescRing->pHead = pCurrTxBuffDesc->pNextBuffDesc;
                }
                 
				 pTempBufObj = pCurrTxBuffDesc->pBufObj;
#if (ETH_GLOBALTIMESUPPORT_API == STD_ON)
                /*
                 * If timestamping is enabled then we check CPTS event for
                 * each transmitted packet.
                 */
                if (0U != Eth_cptsEventPendStatus(gEthDrvObj.cptsObj.cpswBaseAddr))
                {
                    /*
                     * Pop the event into SW queue to be returned to when
                     * getEgressTimeStamp is called from EthIf_TxConfirmation
                     */
                    Eth_cptsHandleEvents(&gEthDrvObj.cptsObj);
                }
#endif
                if (((boolean) TRUE) == pTempBufObj->txConfirmation)
                {
                    EthIf_TxConfirmation((uint8) ctrlIdx,
                                         (Eth_BufIdxType) pTempBufObj->bufIdx);
#if (ETH_GLOBALTIMESUPPORT_API == STD_ON)
                    /*
                     * As Eth_GetEgressTimeStamp is only called from
                     * EthIf_TxConfirmation function, buffer timestamp is
                     * processed by now, hence clear flag
                     */
                    pTempBufObj->enableEgressTimeStamp = (boolean) FALSE;
#endif
               /*
                *  If TxConfirmation is FALSE buffer is freed in the Eth_Transmit
                */
                    pTempBufObj->bufState = ETH_BUF_STATE_FREE;
                }

                HW_SET_FIELD32(pHeadTxBuffDesc->flagsAndPacketLength,
                               CPSW_CPDMA_WRD3_SOP,
                               CPSW_CPDMA_WRD3_SOP_DISABLE);
                HW_SET_FIELD32(pCurrTxBuffDesc->flagsAndPacketLength,
                               CPSW_CPDMA_WRD3_EOP,
                               CPSW_CPDMA_WRD3_EOP_DISABLE);

             /* If this is last b.d. transmitted, then acknowledge using this */
                pLastBuffDesc = pCurrTxBuffDesc;

                pHeadTxBuffDesc = pTxDescRing->pHead;
                pCurrTxBuffDesc = pHeadTxBuffDesc;
                packetProcessed++;
            }
        }

        if(0U != packetProcessed)
        {
            /* Check for misqueued packet */
            if (CPSW_CPDMA_WRD3_EOQ_ENABLE == 
                (uint32) HW_GET_FIELD( pLastBuffDesc->flagsAndPacketLength,
                                      CPSW_CPDMA_WRD3_EOQ) )
            {
                if (NULL  != pLastBuffDesc->pNextBuffDesc)
                {
                /*
                 * The hardware set the EOQ flag, but our EOP descriptor points
                 * to another following descriptor in a new packet -> misqueued packet,
                 * so restart the channel transmission with that new packet.
                 */
                uint32 ownerFlag =
                    HW_GET_FIELD(pLastBuffDesc->pNextBuffDesc->flagsAndPacketLength,
                                   CPSW_CPDMA_WRD3_OWN);

                    if(CPSW_CPDMA_WRD3_OWN_ENABLE == ownerFlag)
                    {
                      HW_WR_FIELD32(&pLastBuffDesc->pNextBuffDesc->flagsAndPacketLength,
                                      CPSW_CPDMA_WRD3_EOQ,
                                      CPSW_CPDMA_WRD3_EOQ_DISABLE);
                      CPSWCpdmaXferHdrDescPtrWrite(gEthDrvObj.baseAddr,
                        (uint32) ETH_XFER_MODE_TX,
                        (Eth_CpdmaBuffDescType *)CSL_locToGlobAddr((uintptr_t)
						pLastBuffDesc->pNextBuffDesc),                              
                        ETH_CPDMA_DEFAULT_TX_CHANNEL_NUM);
                    }
                }
            }

            /* Acknowledge CPSW and free the corresponding ethFrame */
            CPSWCpdmaXferCpWrite(gEthDrvObj.baseAddr, ETH_XFER_MODE_TX,
                                 chNum,
                                 (uint32) pLastBuffDesc);
        }

    }
    else
    {
        /* Channel teardown */
        Eth_PortObject *portObj;

        /* Each port is considered as one controller */
        portObj = Eth_getCurrPortObj();
            /* "Reason - portObj cannot be NULL here as
            *  as it is ensured by DET error check before calling this func */
        /*
         * The software should acknowledge a teardown interrupt with a
         * FFFF_FFFCh Acknowledge value
         */
        CPSWCpdmaXferCpWrite(gEthDrvObj.baseAddr,
                             ETH_XFER_MODE_TX, chNum,
                             (uint32) CPSW_CPDMA_TEAR_DWN_ACK);
        CPSWCpdmaXferDisable(gEthDrvObj.baseAddr, ETH_XFER_MODE_TX);

        Eth_freeBuffers(portObj->txBufObjArray, ETH_NUM_TX_BUFFERS);

        /*
         * Set Eth controller mode to disabled if both RX and TX
         * channels are torn. Else set this channel torn flag to TRUE so
         * when RX channel is torn it can use this for disabling
         * controller.
         */
        if (((uint32) TRUE) == gCpdmaRxChTornFlag)
        {
            gEthControllerModeChangeFlag = (uint32) TRUE;
            gCpdmaRxChTornFlag           = (uint32) FALSE;
            gEthDrvObj.ctrlMode          = ETH_MODE_DOWN;
        }
        else
        {
            gCpdmaTxChTornFlag = (uint32) TRUE;
        }
    }
}

/* This API is to get address of current ETH port object */
static inline Eth_PortObjectPtrType
    Eth_getCurrPortObj()
{
    return (&gEthDrvObj.portObj);
}

static void Eth_waitLoop(uint32 count)
{
    uint32 loopCnt = count;
    while (loopCnt != (uint32) 0U)
    {
        loopCnt--;
        /* Wait */
    }
}

FUNC(void,ETH_CODE_FAST) Eth_HwGetRxStats(
                VAR(uint8,AUTOMATIC)CtrlIdx,
                P2VAR(Eth_RxStatsType,AUTOMATIC,ETH_APPL_DATA)RxStats)
{
	    Eth_StatsType  ethStats;
	    SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_0();

        EthGetStats(gEthDrvObj.baseAddr, &(gEthDrvObj.statsObj), &ethStats, 
													gEthDrvObj.portObj.portNum);

        SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_0();

	
    /* List of RxStats*/
    RxStats->RxStatsDropEvents= ethStats.ALE_DROP
	                          + ethStats.ALE_OVERRUN_DROP
							  + ethStats.PORTMASK_DROP
							  + ethStats.RX_TOP_OF_FIFO_DROP
							  + ethStats.RX_BOTTOM_OF_FIFO_DROP
							  + ethStats.ALE_RATE_LIMIT_DROP
							  + ethStats.ALE_VID_INGRESS_DROP
							  + ethStats.ALE_DA_EQ_SA_DROP
							  + ethStats.ALE_BLOCK_DROP
							  + ethStats.ALE_SECURE_DROP
							  + ethStats.ALE_AUTH_DROP;
							  
    RxStats->RxStatsOctets = ethStats.RXOCTETS;
    RxStats->RxStatsPkts = ethStats.RXGOODFRAMES
	                      + ethStats.RXBROADCASTFRAMES
						  + ethStats.RXMULTICASTFRAMES;
    RxStats->RxStatsBroadcastPkts = ethStats.RXBROADCASTFRAMES;
    RxStats->RxStatsMulticastPkts = ethStats.RXMULTICASTFRAMES;
    RxStats->RxStatsCrcAlignErrors = ethStats.RXCRCERRORS
	                                + ethStats.RXALIGNCODEERRORS;
    RxStats->RxStatsUndersizePkts = ethStats.RXUNDERSIZEDFRAMES;
    RxStats->RxStatsOversizePkts = ethStats.RXOVERSIZEDFRAMES;
    RxStats->RxStatsFragments = ethStats.RXFRAGMENTS;
    RxStats->RxStatsJabbers = ethStats.RXJABBERFRAMES;
    RxStats->RxStatsCollisions = 0xFFFFFFFFU;
    RxStats->RxStatsPkts64Octets = 0xFFFFFFFFU;
    RxStats->RxStatsPkts65to127Octets = 0xFFFFFFFFU;
    RxStats->RxStatsPkts128to255Octets = 0xFFFFFFFFU;
    RxStats->RxStatsPkts256to511Octets = 0xFFFFFFFFU;
    RxStats->RxStatsPkts512to1023Octets = 0xFFFFFFFFU;
    RxStats->RxStatsPkts1024to1518Octets = 0xFFFFFFFFU;
    RxStats->RxUnicastFrames = ethStats.RXGOODFRAMES
	                         - ethStats.RXBROADCASTFRAMES
							 - ethStats.RXMULTICASTFRAMES;
}

void Eth_HwGetCounterValues(
                VAR(uint8, AUTOMATIC)CtrlIdx,
                P2VAR(Eth_CounterType,AUTOMATIC,ETH_APPL_DATA)CounterPtr)
{
  	    Eth_StatsType  ethStats;
	    SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_0();
        EthGetStats(gEthDrvObj.baseAddr, &(gEthDrvObj.statsObj), &ethStats, 
													gEthDrvObj.portObj.portNum);
        SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_0();
		
    /* List of drop counter values */
    CounterPtr->DropPktBufOverrun = ethStats.RX_BOTTOM_OF_FIFO_DROP;
    CounterPtr->DropPktCrc  = ethStats.RXCRCERRORS;
    CounterPtr->UndersizePkt = ethStats.RXUNDERSIZEDFRAMES;
    CounterPtr->OversizePkt  = ethStats.RXOVERSIZEDFRAMES;
    CounterPtr->AlgnmtErr = ethStats.RXALIGNCODEERRORS;
    CounterPtr->SqeTestErr = 0xFFFFFFFFU;
    CounterPtr->DiscInbdPkt = 0xFFFFFFFFU;
    CounterPtr->ErrInbdPkt = ethStats.RXALIGNCODEERRORS
	                        + ethStats.RXOVERSIZEDFRAMES
							+ ethStats.RXUNDERSIZEDFRAMES
							+ ethStats.RXCRCERRORS;
    CounterPtr->DiscOtbdPkt = 0xFFFFFFFFU;
    CounterPtr->ErrOtbdPkt = ethStats.TXDEFERREDFRAMES
	                        + ethStats.TXCOLLISIONFRAMES
							+ ethStats.TXCARRIERSENSEERRORS;
    CounterPtr->SnglCollPkt = ethStats.TXSINGLECOLLFRAMES;
    CounterPtr->MultCollPkt = ethStats.TXMULTCOLLFRAMES;
    CounterPtr->DfrdPkt = ethStats.TXDEFERREDFRAMES;
    CounterPtr->LatCollPkt= ethStats.TXLATECOLLISIONS;
    CounterPtr->HwDepCtr0 = ethStats.TXEXCESSIVECOLLISIONS;
    CounterPtr->HwDepCtr1 = ethStats.TXCARRIERSENSEERRORS;
    CounterPtr->HwDepCtr2 = 0xFFFFFFFFU;
    CounterPtr->HwDepCtr3 = 0xFFFFFFFFU;
}

void Eth_HwGetTxStats(
                VAR(uint8,AUTOMATIC)CtrlIdx,
                P2VAR(Eth_TxStatsType,AUTOMATIC,ETH_APPL_DATA)TxStats)
{
  	    Eth_StatsType  ethStats;
	    SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_0();
        EthGetStats(gEthDrvObj.baseAddr, &(gEthDrvObj.statsObj), &ethStats, 
													gEthDrvObj.portObj.portNum);
        SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_0();
	
    /* List of TxStats*/	
    TxStats->TxNumberOfOctets = ethStats.TXOCTETS;
    TxStats->TxNUcastPkts = ethStats.TXBROADCASTFRAMES
	                       + ethStats.TXMULTICASTFRAMES;
    TxStats->TxUniCastPkts = ethStats.TXGOODFRAMES
	                       - ethStats.TXBROADCASTFRAMES
	                       - ethStats.TXMULTICASTFRAMES;
}

void Eth_HwGetTxErrorCounterValues(
    VAR(uint8, AUTOMATIC)CtrlIdx,
    P2VAR(Eth_TxErrorCounterValuesType,AUTOMATIC,ETH_APPL_DATA)
	                                      TxErrorCounterValues)
{
  	    Eth_StatsType  ethStats;
		uint32 i;
	    SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_0();
        EthGetStats(gEthDrvObj.baseAddr, &(gEthDrvObj.statsObj), &ethStats, 
													gEthDrvObj.portObj.portNum);
        SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_0();
		
    /* list of Transmission Error Counters */
    TxErrorCounterValues->TxDroppedNoErrorPkts = 0xFFFFFFFFU;
	
	    /* Check drop count for all 8 priorities levels */
    for (i = 0U; i < 8U; i++)
    {
        TxErrorCounterValues->TxDroppedErrorPkts += 
		                                   ethStats.ENET_PN_TX_PRI_DROP_REG[i];
    }
    TxErrorCounterValues->TxDeferredTrans = ethStats.TXDEFERREDFRAMES;
    TxErrorCounterValues->TxSingleCollision = ethStats.TXSINGLECOLLFRAMES;
    TxErrorCounterValues->TxMultipleCollision = ethStats.TXMULTCOLLFRAMES;
    TxErrorCounterValues->TxLateCollision = ethStats.TXLATECOLLISIONS;
    TxErrorCounterValues->TxExcessiveCollison = ethStats.TXEXCESSIVECOLLISIONS;
}

void Eth_HwGetEgressTimeStamp(
            VAR(uint8, AUTOMATIC)CtrlIdx,
            VAR(Eth_BufIdxType, AUTOMATIC)BufIdx,
            P2VAR(Eth_TimeStampQualType, AUTOMATIC,ETH_APPL_DATA)timeQualPtr,
            P2VAR(Eth_TimeStampType,AUTOMATIC,ETH_APPL_DATA)timeStampPtr)
{
	    Std_ReturnType retVal = E_NOT_OK;
        uint64 nsec =0U;
        Eth_CptsStateObj *pCptsStateObj = &(gEthDrvObj.cptsObj);
        Eth_CptsEvent      eventTemplate;
        Eth_PortObject     *pPortObj = NULL_PTR;
        pPortObj = &(gEthDrvObj.portObj);
        Eth_BufObjType *pTempBufObj = &(pPortObj->txBufObjArray[BufIdx]);


        /* We set timeStampPtr to zero so if TS read fails it returns zero */
        memset(timeStampPtr, 0, sizeof (Eth_TimeStampType));

        eventTemplate.eventType = CPTS_EVENT_ETHERNET_TRANSMIT;
#if (ETH_GLOBALTIMESUPPORT_API == STD_ON)
        /*
         * Taking message and sequence details from the earlier transmitted
         * buffer. This was set in Eth_Transmit call
         */
        eventTemplate.messageType = pTempBufObj->bufCptsEventInfo.messageType;
        eventTemplate.sequenceId = pTempBufObj->bufCptsEventInfo.sequenceId;
#endif
        retVal = Eth_cptsCounterReadEthEvent( pCptsStateObj, &nsec, &eventTemplate);

        if ((Std_ReturnType)E_NOT_OK != retVal)
        {
            Eth_cptsGetSysTime(pCptsStateObj, &nsec, timeStampPtr);
            /* Quality information not supported, the value always Valid. */
            *timeQualPtr = ETH_VALID;
        }
    }


void Eth_HwGetIngressTimeStamp(
            VAR(uint8, AUTOMATIC)CtrlIdx,
            P2CONST(Eth_DataType,AUTOMATIC,ETH_APPL_DATA)DataPtr,
            P2VAR(Eth_TimeStampQualType,AUTOMATIC,ETH_APPL_DATA)timeQualPtr,
            P2VAR(Eth_TimeStampType ,AUTOMATIC,ETH_APPL_DATA)timeStampPtr)
{
      Std_ReturnType retVal = E_NOT_OK;
        uint64 nsec;
        Eth_CptsStateObj *pCptsStateObj = &(gEthDrvObj.cptsObj);
        const Eth_DataType *msgtype = NULL_PTR;
        Eth_CptsEvent      eventTemplate;
        uint16 *seqid = NULL_PTR;

        /* We set timeStampPtr to zero so if TS read fails it returns zero */
        memset(timeStampPtr, 0, sizeof (Eth_TimeStampType));

        msgtype = DataPtr;

        seqid = (uint16 *)( (uint8 *) DataPtr + TIME_SYNC_OFFSET_PTP_SEQUENCE_ID );

        eventTemplate.eventType = CPTS_EVENT_ETHERNET_RECEIVE;
        eventTemplate.messageType = (Eth_CptsMessageType) 
		                            (*msgtype & (uint8) 0xFU);
        eventTemplate.sequenceId = ntohs(*seqid);

        retVal = Eth_cptsCounterReadEthEvent(pCptsStateObj, &nsec, 
		                                                    &eventTemplate );

        if ((Std_ReturnType)E_NOT_OK != retVal)
        {
            Eth_cptsGetSysTime(pCptsStateObj, &nsec, timeStampPtr);
            /* Quality information not supported, the value always Valid. */
            *timeQualPtr = ETH_VALID;
        }

    }	


void Eth_HwcheckCtrlrErrors(void)
{
    Eth_StatsType ethStats;

    (void) memset(&ethStats, 0, sizeof (ethStats));

    SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_0();

    EthGetStats(gEthDrvObj.baseAddr, &(gEthDrvObj.statsObj), &ethStats, 
													gEthDrvObj.portObj.portNum);

    SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_0();

    /*
     * Check for controller errors (e.g. CRC errors). If the check
     * fails the function shall raise the extended production error.
     */
    if (0U != ethStats.RXCRCERRORS)
    {
#if (ETH_E_CRC != ETH_DEM_NO_EVENT)
        Dem_SetEventStatus(ETH_E_CRC,
                              DEM_EVENT_STATUS_PREFAILED);
#endif
    }
    else if (0U != ethStats.RX_BOTTOM_OF_FIFO_DROP)
    {
#if (ETH_E_RX_FRAMES_LOST != ETH_DEM_NO_EVENT)
        Dem_SetEventStatus(ETH_E_RX_FRAMES_LOST,
                              DEM_EVENT_STATUS_PREFAILED);
#endif
    }
    else if (0U != ethStats.RXUNDERSIZEDFRAMES)
    {
#if (ETH_E_UNDERSIZEFRAME != ETH_DEM_NO_EVENT)
        Dem_SetEventStatus(ETH_E_UNDERSIZEFRAME,
                              DEM_EVENT_STATUS_PREFAILED);
#endif
    }
    else if (0U != ethStats.RXOVERSIZEDFRAMES)
    {
#if (ETH_E_OVERSIZEFRAME != ETH_DEM_NO_EVENT)
        Dem_SetEventStatus(ETH_E_OVERSIZEFRAME,
                              DEM_EVENT_STATUS_PREFAILED);
#endif
    }
    else if (0U != ethStats.RXALIGNCODEERRORS)
    {
#if (ETH_E_ALIGNMENT != ETH_DEM_NO_EVENT)
        Dem_SetEventStatus(ETH_E_ALIGNMENT,
                              DEM_EVENT_STATUS_PREFAILED);
#endif
    }
    else if (0U != ethStats.TXSINGLECOLLFRAMES)
    {
#if (ETH_E_SINGLECOLLISION != ETH_DEM_NO_EVENT)
        Dem_SetEventStatus(ETH_E_SINGLECOLLISION,
                              DEM_EVENT_STATUS_PREFAILED);
#endif
    }
    else if (0U != ethStats.TXMULTCOLLFRAMES)
    {
#if (ETH_E_MULTIPLECOLLISION != ETH_DEM_NO_EVENT)
        Dem_SetEventStatus(ETH_E_MULTIPLECOLLISION,
                              DEM_EVENT_STATUS_PREFAILED);
#endif
    }
    else if (0U != ethStats.TXLATECOLLISIONS)
    {
#if (ETH_E_LATECOLLISION != ETH_DEM_NO_EVENT)
        Dem_SetEventStatus(ETH_E_LATECOLLISION,
                              DEM_EVENT_STATUS_PREFAILED);
#endif
    }
    else
    {
        /* No error detected */
    }

    return;
}

static void Eth_delay(uint32 delay)
{
    volatile uint32 i = delay;

    while (i > 0U)
    {
        i = i - 1U;
    }
}

#define ETH_STOP_SEC_CODE
#include "Eth_MemMap.h"
