/*
 * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *    Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the
 *    distribution.
 *
 *    Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

/**
 *   @file  test_main.c
 *
 *   @brief
 *      This is the Benchmark test code for the EMAC Driver. The test code uses
 *      XDC/BIOS and showcases usage of the EMAC Driver exported API
 *      for sending/receiving Ethernet packets.
 */
#include <string.h>

#include <xdc/std.h>
#include <xdc/runtime/IHeap.h>
#include <xdc/runtime/System.h>
#include <xdc/runtime/Error.h>
#include <xdc/runtime/Memory.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/heaps/HeapBuf.h>
#include <ti/sysbios/heaps/HeapMem.h>
#include <ti/sysbios/hal/Hwi.h>
#include <ti/sysbios/knl/Clock.h>

#include <xdc/cfg/global.h>

/* CSL Chip Functional Layer */
#include <ti/csl/csl_chip.h>
#include <ti/csl/csl_chipAux.h>
#include <ti/csl/csl_cache.h>
#ifndef C6657
#include <ti/csl/cslr_ddr2.h>
#endif
#include <ti/csl/csl_mdio.h>
#ifdef C6474
#include <ti/csl/csl_sem.h>
#endif

/* EMAC Driver Header File. */
#include <ti/drv/emac/emac_hwcfg.h>
#include <ti/drv/emac/emac_drv.h>

/* OSAL Include Files. */
#include <ti/drv/emac/emac_osal.h>

/* Test application local header file */
#include "test_loc.h"

#define APP_DEBUG 0

#if APP_DEBUG
extern cregister volatile unsigned int TSCL;
#endif

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

/* Memory allocated for the packet buffer. This is 128 bytes aligned. */
Uint8   app_pkt_buffer[APP_TOTAL_PKTBUF_SIZE];
#pragma DATA_SECTION(app_pkt_buffer, ".far:PKTBUF_L2MEM")
//#pragma DATA_SECTION(app_pkt_buffer, "msmc")
#pragma DATA_ALIGN(app_pkt_buffer, CACHE_L2_LINESIZE)

/* Memory allocated for the application control block */
APP_EMAC_MCB_T   app_mcb;
#pragma DATA_SECTION(app_mcb, ".far:APP_EMAC")

/**********************************************************************
 ****************** Test Configuration Variables **********************
 **********************************************************************/
#ifdef MULTI_CORE_DEV
/* Multi core device receive flag,
   TRUE: running receive task on the core;
   FALSE: running send task on the core */
Bool    multi_core_receive = TRUE;
#else
/* Single core device receive flag,
   TRUE: running receive task on the core;
   FALSE: running send task on the core */
Bool    single_core_receive = FALSE;
#endif

/* Copy data flag
   TRUE: Both send/receive tasks copy the data for every packet sent/received
   FALSE: Send/receive tasks do not copy the data for every packet sent/received */
Bool    copy_data = FALSE;

/* Unicast RX channel MAC address */
Uint8   rx_mac_addr[EMAC_MAC_ADDR_LENTH] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
//Uint8   tx_mac_addr[EMAC_MAC_ADDR_LENTH] = {0x80, 0x81, 0x82, 0x83, 0x84, 0x85};
Uint8   tx_mac_addr[EMAC_MAC_ADDR_LENTH] = {0xba,0x98,0x76,0x54,0x32,0x10};

/* Multicast flag */
Bool    multicast = FALSE;
Uint8   mcast_mac_addr0[EMAC_MAC_ADDR_LENTH] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x00};
Uint8   mcast_mac_addr1[EMAC_MAC_ADDR_LENTH] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x08};

/* Broadcast flag */
Bool    broadcast = FALSE;

/* Packet buffer allocated in external memory flag */
Bool    pktbuf_extmem = FALSE;

/**********************************************************************
 ************************ EMAC TEST FUNCTIONS *************************
 **********************************************************************/

/**
 *  @b app_queue_pop
 *  @n
 *      Dequeues a packet descriptor from an app queue.
 *
 *  @param[in]  pq
 *      Packet queue of type APP_PKT_QUEUE_T .
 *
 *  @retval
 *      EMAC_Pkt popped from the queue.
 */
static EMAC_PKT_DESC_T*
app_queue_pop
(
    Uint32              port_num,
    APP_PKT_QUEUE_T*    pq
)
{
    EMAC_PKT_DESC_T*    pPktHdr;

    if (!pq->Count)
    {
        return 0;
    }

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

    return( pPktHdr );
}

/**
 *  @b app_queue_push
 *  @n
 *      Enqueues a packet in EMAC_Pkt queue.
 *
 *  @param[in]  pq
 *      Packet queue of type EMAC_PKT_QUEUE_T .
 *  @param[in]  pPktHdr
 *      EMAC_PKT_DESC_T type packet to push.
 *
 *  @retval
 *      void
 */
static void
app_queue_push
(
    Uint32              port_num,
    APP_PKT_QUEUE_T*    pq,
    EMAC_PKT_DESC_T*    pPktHdr
)
{
    Emac_osalEnterSingleCoreCriticalSection(port_num);
    pPktHdr->pNext = 0;

    if( !pq->pHead )
    {
        /* Queue is empty - Initialize it with this one packet */
        pq->pHead = pPktHdr;
        pq->pTail = pPktHdr;
    }
    else
    {
        /* Queue is not empty - Push onto end */
        pq->pTail->pNext = pPktHdr;
        pq->pTail        = pPktHdr;
    }
    pq->Count++;
    Emac_osalExitSingleCoreCriticalSection(port_num);
}

void
DDR2Init
(
    void
)
{
#ifdef C6472
    // DDR2 init here
    /* Configure DDR for 533MHz operation (sequence is order dependent) */
    DDR2C->SDCFG        = 0x00538832; /* Unlock boot + timing, 32bit wide */
    DDR2C->SDRFC        = 0x0000073B; /* Refresh 533Mhz */
    DDR2C->SDTIM1       = 0x47245BD2; /* Timing 1 */
    DDR2C->SDTIM2       = 0x0125DC44; /* Timing 2 */
    DDR2C->DMCCTL       = 0x50001906; /* PHY read latency for CAS 5 is 5 + 2 - 1 */
    DDR2C->SDCFG        = 0x00530832; /* Lock, 32bit wide */
#endif

#ifdef C6457
    // Setup DDR2 timings @ 660.0 / 2 MHz (External clock * 10 / 2)
    DDR2C->SDCFG        =   0x00D38A32; // Unlock boot + timing, 32bit wide CAS: 5
    DDR2C->SDRFC        =   0x00000A0E; // (ddr2_freq / 2) * 7.8e-6 : ddr2_freq=660MHz
    DDR2C->SDTIM1       =   0x832474DA; // Timing 1
    DDR2C->SDTIM2       =   0x3D44C742; // Timing 2

    // PHY read	latency	for	CAS	5
    DDR2C->DMCCTL       =   (DDR2C->DMCCTL & 0xFFFFFFF8) | ( 5 + 1);
    DDR2C->SDCFG        =   0x00530A32; /* Lock, 32bit wide	*/
#endif

#ifdef C6474
    // Setup DDR2 timings @ 660.0 / 2 MHz (External clock * 10 / 2)
    DDR2C->SDCFG        =   0x00D38A32; // Unlock boot + timing, 32bit wide CAS: 5
    DDR2C->SDRFC        =   0x00000a29; // (ddr2_freq / 2) * 7.8e-6 : ddr2_freq=660MHz
    DDR2C->SDTIM1       =   0x4D246C9A; // Timing 1
    DDR2C->SDTIM2       =   0x00993c42; // Timing 2
    // PHY read latency for CAS 5
    DDR2C->DMCCTL       =   0x50001906;
    DDR2C->SDCFG        =   0x00538A32; /* Lock, 32bit wide */
#endif
}

/**
 *  @b EVM_pllc_init
 *  @n
 *     Configure PLL1, PLL2, PLL3.
 *
 *  @param[in]  count
 *           PLL multiplier
 *
 *  @retval
 *      void
 */
void EVM_pllc_init(int count)
{
    int i;
    /* Multiplier value */
    int PLLM_val = count;
    /* TPCC, TPTC, DMA SCR, CFG SCR, Boot, Bridges, Peripherals */
    int PLLDIV7_val = 3;
    /* PSC and SYSCLKOUT */
    int PLLDIV8_val = 4;
    /* SMC and memory */
    int PLLDIV9_val = 2;
    /* GEM trace logic */
    int PLLDIV10_val = 3;

    /** PLL 1 configuration *****************************************/

    /* In PLLCTL, write PLLENSRC = 0 (enable PLLEN bit).*/
    *(int *)PLLCTL_1 &= ~(0x00000020);
    /* In PLLCTL, write PLLEN = 0 (bypass mode).*/
    *(int *)PLLCTL_1 &= ~(0x00000001);
    /* Wait 4 cycles of the slowest of PLLOUT or reference clock source (CLKIN).*/
    for (i=0 ; i<100 ; i++);
    /*In PLLCTL, write PLLRST = 1 (PLL is reset).*/
    *(int *)PLLCTL_1 |= 0x00000008;
    /*If necessary, program PREDIV and PLLM.*/
    *(int *)PLLM_1 = PLLM_val - 1;

    /* Check that the GOSTAT bit in PLLSTAT is cleared to show that no GO
    operation is currently in progress.*/
    while( (*(int *)PLLSTAT_1) & 0x00000001);

    /* Program the RATIO field in PLLDIVn to the desired new divide-down rate.
    If the RATIO field changed, the PLL controller will flag the change
    in the corresponding bit of DCHANGE.*/
    *(int *)PLLDIV7_1 = (PLLDIV7_val - 1) | 0x8000;
    *(int *)PLLDIV8_1 = (PLLDIV8_val - 1) | 0x8000;
    *(int *)PLLDIV9_1 = (PLLDIV9_val - 1) | 0x8000;
    *(int *)PLLDIV10_1 = (PLLDIV10_val - 1) | 0x8000;

    /* Set the GOSET bit in PLLCMD to initiate the GO operation to change
    the divide values and align the SYSCLKs as programmed.*/
    *(int *)PLLCMD_1 |= 0x00000001;

    /* Read the GOSTAT bit in PLLSTAT to make sure the bit returns to 0
    to indicate that the GO operation has completed.*/
    while( (*(int *)PLLSTAT_1) & 0x00000001);

    /* Wait for PLL to properly reset.(128 CLKIN1 cycles).*/
    for (i=0 ; i<1000 ; i++);

    /* In PLLCTL, write PLLRST = 0 to bring PLL out of reset.*/
    *(int *)PLLCTL_1 &= ~(0x00000008);

    /* Wait for PLL to lock (2000 CLKIN1 cycles). */
    for (i=0 ; i<4000 ; i++);

    /* In PLLCTL, write PLLEN = 1 to enable PLL mode. */
    *(int *)PLLCTL_1 |= (0x00000001);


    /* PLL2 configuration (EMAC) */

    /* In PLLCTL, write PLLENSRC = 0 (enable PLLEN bit).*/
    *(int *)PLLCTL_2 &= ~(0x00000020);
    /* In PLLCTL, write PLLEN = 0 (bypass mode).*/
    *(int *)PLLCTL_2 &= ~(0x00000001);
    /* Wait 4 cycles of the slowest of PLLOUT or reference clock source (CLKIN).*/
    for (i=0 ; i<100 ; i++);
    /*In PLLCTL, write PLLRST = 1 (PLL is reset).*/
    *(int *)PLLCTL_2 |= 0x00000008;

    /* Wait for PLL to properly reset.*/
    for (i=0 ; i<4000 ; i++);

    /* In PLLCTL, write PLLRST = 0 to bring PLL out of reset.*/
    *(int *)PLLCTL_2 &= ~(0x00000008);

    /* Wait for PLL to lock */
    for (i=0 ; i<4000 ; i++);

    /* In PLLCTL, write PLLEN = 1 to enable PLL mode. */
    *(int *)PLLCTL_2 |= (0x00000001);

    for (i=0 ; i<10000 ; i++);


    /** PLL 3 configuration (DDR2) *****************************************/

    /* In PLLCTL, write PLLEN = 0 (bypass mode).*/
    *(int *)PLLCTL_3 &= ~(0x00000001);
    /* Wait 4 cycles of the slowest of PLLOUT or reference clock source (CLKIN).*/
    for (i=0 ; i<100 ; i++);
    /*In PLLCTL, write PLLRST = 1 (PLL is reset).*/
    *(int *)PLLCTL_3 |= 0x00000008;
    /*If necessary, program PREDIV and PLLM.*/
    *(int *)PLLM_3 = PLLM_val - 1;

    /* Check that the GOSTAT bit in PLLSTAT is cleared to show that no GO
    operation is currently in progress.*/
    while( (*(int *)PLLSTAT_3) & 0x00000001);

    /* Set the GOSET bit in PLLCMD to initiate the GO operation to change
    the divide values and align the SYSCLKs as programmed.*/
    *(int *)PLLCMD_3 |= 0x00000001;

    /* Read the GOSTAT bit in PLLSTAT to make sure the bit returns to 0
    to indicate that the GO operation has completed.*/
    while( (*(int *)PLLSTAT_3) & 0x00000001);

    /* Wait for PLL to properly reset.(128 CLKIN1 cycles).*/
    for (i=0 ; i<1000 ; i++);

    /* In PLLCTL, write PLLRST = 0 to bring PLL out of reset.*/
    *(int *)PLLCTL_3 &= ~(0x00000008);

    /* Wait for PLL to lock (2000 CLKIN1 cycles). */
    for (i=0 ; i<4000 ; i++);

    /* In PLLCTL, write PLLEN = 1 to enable PLL mode. */
    *(int *)PLLCTL_3 |= (0x00000001);

}

#if defined(C6457) || defined(C6474) || defined(C6657)
/******************************************************************************
*
* Function:	readPhyReg
*
* Description:	Reads the phy register.
*
* Parameters:	Uint32 phynum - Address of the phy
*              Uint32 regnum - Phy register number
*
* Return Value: Uint16 - Register value read
******************************************************************************/
Uint16 readPhyReg(Uint32 phynum, Uint32 regnum)
{
    Uint16 value;

    MDIOR->USERACCESS0 = 0                  // Read Phy Id 1
        | ( 1 << 31 )                       // [31] Go
        | ( 0 << 30 )                       // [30] Read
        | ( 0 << 29 )                       // [29] Ack
        | (regnum << 21 )                   // [25-21] PHY register address
        | (phynum << 16 )                   // [20-16] PHY address
        | ( 0 << 0 )                        // [15-0] Data
        ;

    while( MDIOR->USERACCESS0 & 0x80000000 ); // Wait for Results

    value = MDIOR->USERACCESS0;

    return value;
}

/******************************************************************************
*
* Function:	writePhyReg
*
* Description:	Writes to the phy register.
*
* Parameters:	Uint32 phynum - Address of the phy
*              Uint32 regnum - Phy register number
*              Uint16 data   - Data to be written to register
*
* Return Value: void
******************************************************************************/
void writePhyReg(Uint32 phynum, Uint32 regnum, Uint16 data)
{
    MDIOR->USERACCESS0 = 0                  // Read Phy Id 1
        | ( 1 << 31 )                       // [31] Go
        | ( 1 << 30 )                       // [30] Write
        | ( 0 << 29 )                       // [29] Ack
        | (regnum << 21 )                   // [25-21] PHY register address
        | (phynum << 16 )                   // [20-16] PHY address
        | ( data << 0 );                    // [15-0] Data

    while( MDIOR->USERACCESS0 & 0x80000000 ); // Wait for Results
}

#if APP_DEBUG
void
phyEnableDebugCount
(
    Bool enable
)
{
    Uint16   reg_value;

    /* Enable Page 6 of phy register */
    writePhyReg(1, 22, 6);

    /* Read test mode select register */
    reg_value = readPhyReg(1, 16);

    if (enable)
    {
        /* Enable CRC error and frame count */
        writePhyReg(1, 16, reg_value | 0x10);
    }
    else
    {
        /* Disable CRC error and frame count */
        writePhyReg(1, 16, reg_value & (~0x10));
    }
}

void
phyGetDebugCount
(
    Uint32*     p_crc_cnt,
    Uint32*     p_rcv_err
)
{
    Uint16   reg_value;

    /* Enable Page 6 of phy register */

    /* Read CRC error count register */
    writePhyReg(1, 22, 6);
    reg_value = readPhyReg(1, 17);
    *p_crc_cnt = reg_value;

    /* Read receive error count register */
    writePhyReg(1, 22, 0);
    reg_value = readPhyReg(1, 21);
    *p_rcv_err = reg_value;
}
#endif


/******************************************************************************
*
* Function:	phyInit
*
* Description:	Initialize the phy in loopback mode
*
* Parameters:	uiLoopback - 0 - Phy loopback on port 6
* 						   - 1 - RJ45 loopback enable port 1
*						   - 2 - SGMII loopback on AMC edge
* Return Value: void
******************************************************************************/
void phyInit(Uint32 uiLoopback)
{
    // Enable MDIO interface
    MDIOR->CONTROL = 0x400000A5;
#ifndef C6657
    // Turn PPU off to make copper PHY visible at SMI address 0x01
    writePhyReg(27, 4, 0x0081);

    // Configure Marvell 88E6122 PHY
    writePhyReg(0xe, 26, 0x47);    	// Set PHY port 6 SERDES to 0.7V swing
    writePhyReg(0x0e, 0, 0x8140);  	// Configure PHY port 6 SERDES --> C6474 1 at 1000mpbs, full duplex
    writePhyReg(0x16, 0x1, 0x043e); // Force internal switch --> port 6 SERDES to 1000MBPS, full Duplex

    if (uiLoopback == PHY_LOOPBACK)
    {
        // Force 1000mps at port 6 SERDES, line loopback
        writePhyReg(0x0e, 16, 0x106b); 	// 1000mbps

    }
    else if (uiLoopback == COPPER_LOOPBACK)
    {
        // Force 1000mps at copper PHY - port 1, disable auto-negotiate
        writePhyReg(1, 0, 0x8100); 		// 0x8100 = 1000mbps

        //power down port 4
        writePhyReg(0x0c, 0, 0x0800);
    }
    else if (uiLoopback == AMC_MODE)
    {
        // Power down port 1
        writePhyReg(1,0, 0x0800);
        writePhyReg(1, 16, 0x0040);

        // configure port 4
        writePhyReg(0xc, 26, 0x47);    	// Set PHY port 4 SERDES to 0.7V swing
        writePhyReg(0x0c, 0, 0x8140);  	// Configure PHY port 4 SERDES --> AMC port at 1000mbps, full duplex
        writePhyReg(0x14, 0x1, 0x043e); // Force internal switch --> port 4 SERDES to 1000MBPS, full Duplex
    }
    else
    {
        /* Force the PHY to negotiate at 100Mbps link speed */
#ifdef PHY_MODE_1000MBPS
        // Force 1000mps at copper PHY, disable auto-negotiate
        writePhyReg(1, 0, 0x8140); // 0x8140 = 1000mbps
#else
#ifdef PHY_MODE_100MBPS
        //Force 100mps at copper PHY, disable auto-negotiate
        writePhyReg(1, 0, 0xa100); // 0xa100 = 100mbps
#else
        // Enable auto-negotiate
        writePhyReg(1, 0, 0x9140);
#endif
#endif
    }

#if APP_DEBUG
    phyEnableDebugCount(FALSE);
    phyEnableDebugCount(TRUE);
#endif

#endif
}
#endif /* defined(C6457) || defined(C6474) */

/**
 *  @b Description
 *  @n
 *      Utility function that is required by the IPC module to set the proc Id.
 *      The proc Id is set via this function instead of hard coding it in the .cfg file
 *
 *  @retval
 *      Not Applicable.
 */
Void myStartupFxn (Void)
{
#if defined(C6474) | defined(C6472) | defined(C6457)
    DDR2Init();
#endif

    /* Initialize the EMAC clock */
#ifdef C6472
    EVM_pllc_init(28);
#endif

#ifdef C6457
    EVM_pllc_init(16);
    phyInit(NORMAL_PHY_MODE);
#endif

#ifdef C6474
    EVM_pllc_init(20);
    //phyInit(NORMAL_PHY_MODE);
    phyInit(PHY_LOOPBACK);
#endif

#ifndef C6657
    CACHE_setL1dSize(CACHE_L1_32KCACHE);
    CACHE_setL2Size(CACHE_256KCACHE);
#endif

#ifdef C6657
    phyInit(NORMAL_PHY_MODE);
#endif

}


/**
 *  @b Description
 *  @n
 *      Call back function provided by application for EMAC driver
 *      to allocate a packet descriptor.
 *
 *  @retval
 *      pointer to the allocated packet descriptor.
 */
static EMAC_PKT_DESC_T*
app_alloc_pkt
(
    Uint32              port_num,
    Uint32              pkt_size
)
{
    EMAC_PKT_DESC_T*    p_pkt_desc = NULL;

    if (pkt_size < APP_EMAC_MAX_PKT_SIZE)
    {
        /* Get a packet descriptor from the free queue */
        p_pkt_desc              = app_queue_pop(port_num, &app_mcb.emac_pcb[port_num].freeQueue);
        p_pkt_desc->AppPrivate  = (Uint32)p_pkt_desc;
        p_pkt_desc->BufferLen   = pkt_size;
        p_pkt_desc->DataOffset  = 0;
    }
    else
    {
        System_printf ("app_alloc_pkt on port %d failed, packet size %d is too big\n", port_num, pkt_size);
    }

    return p_pkt_desc;
}

/**
 *  @b Description
 *  @n
 *      Call back function provided by application for EMAC driver
 *      to free a packet descriptor.
 *
 *  @retval
 *      None.
 */
static void
app_free_pkt
(
    Uint32              port_num,
    EMAC_PKT_DESC_T*    p_pkt_desc
)
{
    /* Free a packet descriptor to the free queue */
    app_queue_push(port_num, &app_mcb.emac_pcb[port_num].freeQueue,
                   (EMAC_PKT_DESC_T *)p_pkt_desc->AppPrivate);
}

/**
 *  @b Description
 *  @n
 *      Call back function provided by application for EMAC driver
 *      to report a received packet descriptor.
 *
 *  @retval
 *      None.
 */
static void
app_rx_pkt
(
    Uint32              port_num,
    EMAC_PKT_DESC_T*    p_pkt_desc
)
{
    EMAC_PKT_DESC_T*    p_pkt_enq;

    p_pkt_enq = (EMAC_PKT_DESC_T *)p_pkt_desc->AppPrivate;
    memcpy(p_pkt_enq, p_pkt_desc, sizeof(EMAC_PKT_DESC_T));

    /* enqueue the received packet descriptor to the channel specific RX queue */
    app_queue_push(port_num, &app_mcb.emac_pcb[port_num].rxQueue[0],
                  (EMAC_PKT_DESC_T *)p_pkt_enq);
}


/**
 *  @b app_verify_packet
 *  @n
 *      Perform a sanity check validation on the packet received
 *
 *  @retval
 *      True on success or False on failure
 */
static Bool
app_verify_packet
(
    EMAC_PKT_DESC_T*    p_pkt_desc,
    Bool                copy_data
)
{
    if( (p_pkt_desc->Flags & (EMAC_PKT_FLAG_SOP | EMAC_PKT_FLAG_EOP)) !=
        (EMAC_PKT_FLAG_SOP | EMAC_PKT_FLAG_EOP) )
    {
        System_printf("Verify: Bad Flags %08x\n", p_pkt_desc->Flags);
        return(FALSE);
    }

    if(p_pkt_desc->ValidLen != APP_EMAC_TEST_TX_PKT_SIZE)
    {
        System_printf("Verify: Bad ValidLen %d %d\n",p_pkt_desc->ValidLen);
        return(FALSE);
    }

    if(p_pkt_desc->DataOffset != 0)
    {
        System_printf("Verify: Bad DataOffset %d\n",p_pkt_desc->DataOffset);
        return(FALSE);
    }

    if(p_pkt_desc->PktChannel != 0)
    {
        System_printf("Verify: Bad Channel %d\n",p_pkt_desc->PktChannel);
        return(FALSE);
    }

    if(p_pkt_desc->PktLength != APP_EMAC_TEST_TX_PKT_SIZE)
    {
        System_printf("Verify: Bad PktLength %d\n",p_pkt_desc->PktLength);
        return(FALSE);
    }

    if(p_pkt_desc->PktFrags != 1)
    {
        System_printf("Verify: Bad Frag Count %d\n",p_pkt_desc->PktFrags);
        return(FALSE);
    }

    if (copy_data)
    {
        /* Invalidate cache if data in external memory */
        Osal_emacBeginMemAccess(p_pkt_desc->pDataBuffer, APP_EMAC_TEST_TX_PKT_SIZE);

        /* copy the packet data */
        memcpy (app_mcb.test_pkt_buf, p_pkt_desc->pDataBuffer, APP_EMAC_TEST_TX_PKT_SIZE);
    }

    return(TRUE);
}

#if APP_DEBUG
/******************************************************************************
 *
 * Function:	app_delay
 *
 * Description:	This function implements a delay loop in CPU clocks
 *
 * Parameters:	delay - delay in CPU clocks
 *
 * Return Value: void
 *
 *****************************************************************************/
void app_delay(Uint32 delay)
{
	Uint32 t;
	TSCL = 1;

	t = TSCL;
	while(TSCL < (t + delay));
}
#endif

/**
 *  @b app_send_task
 *  @n
 *      This is the Benchmark test task for receiving packets.
 *
 *  @retval
 *      Not Applicable.
 */
static Void app_send_task(UArg arg0, UArg arg1)
{
    EMAC_OPEN_CONFIG_INFO_T     open_cfg;
    EMAC_CHAN_MAC_ADDR_T        chan_cfg;
    EMAC_MAC_ADDR_T             mac_addr;
    Uint32                      port_num = 0;
    Uint32                      chan_num = 0;
    Uint32                      tx_count = 0;
    EMAC_PKT_DESC_T*            p_pkt_desc;
    Uint32                      start_time, end_time, tx_time;
#if APP_DEBUG
#if defined(C6457) || defined(C6474)
    Uint32                      crc_err_cnt, rx_err_cnt;
#endif
#endif

    /******************** Set the emac_open configuration ************************
     * For one port device (C6457 or C6474):
     *     Send task needs to be run on a separate device, using port 0 channel 0
     *
     * For Mulit cores and two port device (C6472):
     *     Send task needs to be run on non-master core 1, using port 1 channel 0
     ******************************************************************************/
#ifdef TWO_PORT_DEV
    port_num                        = 1;
#endif
    open_cfg.master_core_flag       = TRUE;
    open_cfg.mdio_flag              = TRUE;
    open_cfg.loop_back              = FALSE;
    open_cfg.num_of_tx_pkt_desc     = APP_EMAC_INIT_TX_PKTS;
    open_cfg.num_of_rx_pkt_desc     = APP_EMAC_INIT_RX_PKTS;
    open_cfg.max_pkt_size           = APP_EMAC_INIT_PKT_SIZE;
    open_cfg.num_of_chans           = APP_EMAC_NUM_CHANS_PER_CORE;
    open_cfg.p_chan_mac_addr        = &chan_cfg;
    open_cfg.rx_pkt_cb              = app_rx_pkt;
    open_cfg.alloc_pkt_cb           = app_alloc_pkt;
    open_cfg.free_pkt_cb            = app_free_pkt;

    if (port_num == 0)
    {
        open_cfg.phy_addr           = APP_PORT0_PHY_ADDR;
    }
#ifdef TWO_PORT_DEV
    else
    {
        open_cfg.phy_addr           = APP_PORT1_PHY_ADDR;
    }
#endif

    System_printf ("Running send task on core %d port %d channel %d\n",
                   app_mcb.core_num, port_num, chan_num);

    /* Set the channel configuration */
    chan_cfg.chan_num               = chan_num;
    chan_cfg.num_of_mac_addrs       = APP_EMAC_NUM_MACADDRS_PER_CHAN;
    memcpy(mac_addr.addr, tx_mac_addr, EMAC_MAC_ADDR_LENTH);
    chan_cfg.p_mac_addr             = &mac_addr;

    /* Always open the channel 0 on port 0 for receive task */
    if (emac_open(port_num, &open_cfg) == EMAC_DRV_RESULT_OK)
    {
        /* Enable RX/TX interrupt */
        Osal_emacExitSingleCoreCriticalSection(port_num);
    }
    else
    {
        System_printf ("Application open EMAC port %d error \n", port_num);
    }

    System_printf ("Sending packets on core %d port %d channel %d\n",
                   app_mcb.core_num, port_num, chan_num);

    start_time = Clock_getTicks();
    while (TRUE)
    {
        /* First get a packet descriptor from the free queue */
        p_pkt_desc = app_queue_pop(port_num, &app_mcb.emac_pcb[port_num].freeQueue);
        if(p_pkt_desc)
        {
            p_pkt_desc->AppPrivate   = (Uint32)p_pkt_desc;
            p_pkt_desc->Flags        = EMAC_PKT_FLAG_SOP | EMAC_PKT_FLAG_EOP;
            p_pkt_desc->ValidLen     = APP_EMAC_TEST_TX_PKT_SIZE;
            p_pkt_desc->DataOffset   = 0;
            p_pkt_desc->PktChannel   = chan_num;
            p_pkt_desc->PktLength    = APP_EMAC_TEST_TX_PKT_SIZE;
            p_pkt_desc->PktFrags     = 1;

            if (multicast)
            {
                /* Fill in the multicast destination address */
                if (tx_count & 0x1)
                {
                    memcpy(p_pkt_desc->pDataBuffer, mcast_mac_addr1, EMAC_MAC_ADDR_LENTH);
                }
                else
                {
                    memcpy(p_pkt_desc->pDataBuffer, mcast_mac_addr0, EMAC_MAC_ADDR_LENTH);
                }
            }
            else if (broadcast)
            {
                /* Fill in the broadcast destination address */
                memset(p_pkt_desc->pDataBuffer, 0xff, EMAC_MAC_ADDR_LENTH);
            }
            else
            {
                /* Fill in the unitcast destination address */
                memcpy(p_pkt_desc->pDataBuffer, rx_mac_addr, EMAC_MAC_ADDR_LENTH);
            }

            /* Fill in the source address */
            memcpy(&p_pkt_desc->pDataBuffer[EMAC_MAC_ADDR_LENTH], tx_mac_addr, EMAC_MAC_ADDR_LENTH);

            if(copy_data)
            {
                /* Fill in the Ether Type and Payload */
                memcpy(&p_pkt_desc->pDataBuffer[2*EMAC_MAC_ADDR_LENTH],
                       app_mcb.test_pkt_buf,
                       APP_EMAC_TEST_TX_PKT_SIZE-2*EMAC_MAC_ADDR_LENTH);
            }
            /* Write back cache to memory if data in external memory */
            Osal_emacEndMemAccess(p_pkt_desc->pDataBuffer, APP_EMAC_TEST_TX_PKT_SIZE);

            emac_send(port_num, p_pkt_desc);

            /* Increment the TX count */
            tx_count++;
            if (tx_count == APP_NUM_TEST_SEND_PKTS)
            {
                end_time = Clock_getTicks();
                break;
            }
        }
#if APP_DEBUG
        app_delay(4000);
#endif
    } /* End of while(TRUE) */

    tx_time = end_time-start_time;

    /* Print out the Receive Results. */
    System_printf ("------------------------------------------------\n");
    System_printf ("Total Data Sent    : %d bytes\n", tx_count*APP_EMAC_TEST_TX_PKT_SIZE);
    System_printf ("Start Time         : %d msec\n", start_time);
    System_printf ("End   Time         : %d msec\n", end_time);
    System_printf ("Total Time expired : %d msec\n", tx_time);
    System_printf ("Sent Throughput    : %u Mb/s \n", (((tx_count*APP_EMAC_TEST_TX_PKT_SIZE/tx_time)*1000)*8)/1000000);
    System_printf ("------------------------------------------------\n");

#if APP_DEBUG
#if defined(C6457) || defined(C6474)
    phyGetDebugCount(&crc_err_cnt, &rx_err_cnt);
    System_printf ("Benchmark Send Packet Test Phy crc err count 0x%x, rx err count 0x%x\n",
                   crc_err_cnt, rx_err_cnt);
#endif
#endif

    /* All the tests passed. */
    System_printf ("Benchmark Send Packet Test completed successfully on core %d port %d channel %d\n",
                   app_mcb.core_num, port_num, chan_num);
    Task_exit();
}

/**
 *  @b app_receive_task
 *  @n
 *      This is the Benchmark test task for receiving packets.
 *
 *  @retval
 *      Not Applicable.
 */
static Void app_receive_task(UArg arg0, UArg arg1)
{

    EMAC_OPEN_CONFIG_INFO_T     open_cfg;
    EMAC_CHAN_MAC_ADDR_T        chan_cfg;
    EMAC_MAC_ADDR_T             mac_addr;
    EMAC_CONFIG_INFO_T          emac_cfg;
    Uint32                      port_num = 0;
    Uint32                      chan_num = 0;
    Uint32                      rx_count = 0;
    EMAC_PKT_DESC_T*            p_pkt_desc;
    Uint32                      start_time, end_time, rx_time;
    Uint8                       mcast_list[2*EMAC_MAC_ADDR_LENTH];
#if APP_DEBUG
#if defined(C6457) || defined(C6474)
    Uint32                      crc_err_cnt, rx_err_cnt;
#endif
#endif

    System_printf ("Running receive task on core %d port %d channel %d\n",
                   app_mcb.core_num, port_num, chan_num);

    /******************** Set the emac_open configuration ************************
     * For all the devices:
     *     Receive task needs to be run on master core 0, using port 0 channel 0
     ******************************************************************************/
    open_cfg.master_core_flag       = TRUE;
    open_cfg.mdio_flag              = TRUE;
    open_cfg.num_of_tx_pkt_desc     = APP_EMAC_INIT_TX_PKTS;
    open_cfg.num_of_rx_pkt_desc     = APP_EMAC_INIT_RX_PKTS;
    open_cfg.loop_back              = FALSE;
    open_cfg.max_pkt_size           = APP_EMAC_INIT_PKT_SIZE;
    open_cfg.num_of_chans           = APP_EMAC_NUM_CHANS_PER_CORE;
    open_cfg.p_chan_mac_addr        = &chan_cfg;
    open_cfg.rx_pkt_cb              = app_rx_pkt;
    open_cfg.alloc_pkt_cb           = app_alloc_pkt;
    open_cfg.free_pkt_cb            = app_free_pkt;

    if (port_num == 0)
    {
        open_cfg.phy_addr           = APP_PORT0_PHY_ADDR;
    }
#ifdef TWO_PORT_DEV
    else
    {
        open_cfg.phy_addr           = APP_PORT1_PHY_ADDR;
    }
#endif

    /* Set the channel configuration */
    chan_cfg.chan_num               = chan_num;
    chan_cfg.num_of_mac_addrs       = APP_EMAC_NUM_MACADDRS_PER_CHAN;
    memcpy(mac_addr.addr, rx_mac_addr, EMAC_MAC_ADDR_LENTH);
    chan_cfg.p_mac_addr             = &mac_addr;

    /* Always open the channel 0 on port 0 for receive task */
    if (emac_open(port_num, &open_cfg) == EMAC_DRV_RESULT_OK)
    {
        /* Set the 'initial' Receive Filter */
        if (multicast)
        {
            /*
             * Multicast address list is:
             * 0x01, 0x80, 0xC2, 0x00, 0x00, 0x00
             * 0x01, 0x80, 0xC2, 0x00, 0x00, 0x08
             */
            memcpy (mcast_list, mcast_mac_addr0, EMAC_MAC_ADDR_LENTH);
            memcpy (&mcast_list[EMAC_MAC_ADDR_LENTH], mcast_mac_addr1, EMAC_MAC_ADDR_LENTH);
            emac_cfg.mcast_cnt       = 2;
            emac_cfg.p_mcast_list    = mcast_list;
        }
        else
        {
            emac_cfg.mcast_cnt       = 0;
            emac_cfg.p_mcast_list    = NULL;
        }

        emac_cfg.rx_filter       = EMAC_PKTFLT_MULTICAST;
        emac_config(port_num, &emac_cfg);

        /* Enable RX/TX interrupt */
        Osal_emacExitSingleCoreCriticalSection(port_num);
    }
    else
    {
        System_printf ("Application open EMAC port %d error \n", port_num);
    }

    System_printf ("Receiving packets on core %d port %d channel %d\n",
                   app_mcb.core_num, port_num, chan_num);

    while (TRUE)
    {
        /* Check if we received a packet */
        p_pkt_desc = app_queue_pop(port_num, &app_mcb.emac_pcb[port_num].rxQueue[chan_num]);
        if(p_pkt_desc)
        {
            if (rx_count == 0)
            {
                start_time = Clock_getTicks();
            }

            /* Validate this packet */
            if(!app_verify_packet(p_pkt_desc, copy_data))
            {
                System_printf("ERROR: Core %d Port %d Channel %d verify failure on received packet %d\n",
                    app_mcb.core_num, port_num, chan_num, rx_count);
            }
            else
            {
            /* Increment the RX count */
                rx_count++;
            }

            /* Free the packet */
            app_queue_push(port_num, &app_mcb.emac_pcb[port_num].freeQueue, p_pkt_desc );
        }

        if (rx_count == APP_NUM_TEST_RECEIVE_PKTS)
        {
            end_time = Clock_getTicks();
            break;
        }

    } /* End of while(TRUE) */

    rx_time = end_time-start_time;
#if APP_DEBUG
#if defined(C6457) || defined(C6474)
    phyGetDebugCount(&crc_err_cnt, &rx_err_cnt);
    System_printf ("Benchmark Receive Packet Test Phy crc err count 0x%x, rx err count 0x%x\n",
                   crc_err_cnt, rx_err_cnt);
#endif
#endif

    /* Print out the Receive Results. */
    System_printf ("------------------------------------------------\n");
    System_printf ("Total Data received : %d bytes\n", rx_count*APP_EMAC_TEST_TX_PKT_SIZE);
    System_printf ("Start Time          : %d msec\n", start_time);
    System_printf ("End   Time          : %d msec\n", end_time);
    System_printf ("Total Time expired  : %d msec\n", rx_time);
    System_printf ("Receive Throughput  : %u Mb/s \n", (((rx_count*APP_EMAC_TEST_TX_PKT_SIZE/rx_time)*1000)*8)/1000000);
    System_printf ("------------------------------------------------\n");

    /* All the tests passed. */
    System_printf ("Benchmark Receive Packet Test completed successfully on core %d port %d channel %d\n",
                   app_mcb.core_num, port_num, chan_num);
    Task_exit();
}



/**
 *  @b app_rx0_int
 *  @n
 *      Receive Packet ISR for port 0
 *
 *  @param[in]  void
 *
 *  @retval
 *      void
 */
static void
app_rx0_int
(
    void
)
{
    /* Call the EMAC driver RX interrupt service function for port 0 */
    emac_int_service(0, TRUE);
}

/**
 *  @b app_tx0_int
 *  @n
 *      Transmit Complete ISR.for port 0
 *
 *  @param[in]  void
 *
 *  @retval
 *      void
 */
static void
app_tx0_int
(
    void
)
{
    /* Call the EMAC driver TX interrupt service function for port 0 */
    emac_int_service(0, FALSE);
}

#ifdef TWO_PORT_DEV
/**
 *  @b app_rx1_int
 *  @n
 *      Receive Packet ISR for port 1
 *
 *  @param[in]  void
 *
 *  @retval
 *      void
 */
static void
app_rx1_int
(
    void
)
{
    /* Call the EMAC driver RX interrupt service function for port 1 */
    emac_int_service(1, TRUE);
}

/**
 *  @b app_tx1_int
 *  @n
 *      Transmit Complete ISR.for port 1
 *
 *  @param[in]  void
 *
 *  @retval
 *      void
 */
static void
app_tx1_int
(
    void
)
{
    /* Call the EMAC driver TX interrupt service function for port 1 */
    emac_int_service(1, FALSE);
}
#endif

/**
 *  @b app_interrupt_init
 *  @n
 *      Registering Interrupts and Enabling global interrupts.
 *
 *  @param[in]  void
 *
 *  @retval
 *      void
 */
static void
app_interrupt_init
(
    Uint32          port_num
)
{
    Hwi_Params      hwi_params;
    Error_Block     eb;
    static Bool     port0Init   = FALSE;
#ifdef TWO_PORT_DEV
    static Bool     port1Init   = FALSE;
#endif
    Bool            error_flag;

    if ((!port0Init) && (port_num==0))
    {
        error_flag = FALSE;

        /* Initialize the error block. */
        Error_init(&eb);
        Hwi_Params_init (&hwi_params);

        /*
         * Setup RX Int using BIOS6 Hwi module
         */
        hwi_params.arg          = (UArg) 0;
        hwi_params.enableInt    = 1;
        hwi_params.eventId      = APP_EMAC0_RX_INT_EV;
        hwi_params.maskSetting  = ti_sysbios_hal_Hwi_MaskingOption_SELF;

        if (Hwi_create (APP_EMAC0_RXINT_ID, (ti_sysbios_hal_Hwi_FuncPtr) &app_rx0_int, &hwi_params, &eb) == NULL)
        {
            System_printf("app_interrupt_init(): could not configure the RX interrupt for port %d", port_num);
            error_flag = TRUE;
        }

        /*
         * Setup TX Int using BIOS6 Hwi module
         */
        hwi_params.eventId      = APP_EMAC0_TX_INT_EV;

        if (Hwi_create (APP_EMAC0_TXINT_ID, (ti_sysbios_hal_Hwi_FuncPtr) &app_tx0_int, &hwi_params, &eb) == NULL)
        {
            System_printf("app_interrupt_init(): could not configure the TX interrupt for port %d", port_num);
            error_flag = TRUE;
        }

        if(!error_flag)
        {
            port0Init = TRUE;
            Osal_emacEnterSingleCoreCriticalSection(0);
        }
    }

#ifdef TWO_PORT_DEV
    if ((!port1Init) && (port_num==1))
    {
        error_flag = FALSE;

        /* Initialize the error block. */
        Error_init(&eb);
        Hwi_Params_init (&hwi_params);

        /*
         * Setup RX Int using BIOS6 Hwi module
         */
        hwi_params.arg          = (UArg) 0;
        hwi_params.enableInt    = 1;
        hwi_params.eventId      = APP_EMAC1_RX_INT_EV;
        hwi_params.maskSetting  = ti_sysbios_hal_Hwi_MaskingOption_SELF;

        if (Hwi_create (APP_EMAC1_RXINT_ID, (ti_sysbios_hal_Hwi_FuncPtr) &app_rx1_int, &hwi_params, &eb) == NULL)
        {
            System_printf("app_interrupt_init(): could not configure the RX interrupt for port %d", port_num);
            error_flag = TRUE;
        }

        /*
         * Setup TX Int using BIOS6 Hwi module
         */
        hwi_params.eventId      = APP_EMAC1_TX_INT_EV;

        if (Hwi_create (APP_EMAC1_TXINT_ID, (ti_sysbios_hal_Hwi_FuncPtr) &app_tx1_int, &hwi_params, &eb) == NULL)
        {
            System_printf("app_interrupt_init(): could not configure the TX interrupt for port %d", port_num);
            error_flag = TRUE;
        }

        if(!error_flag)
        {
            port1Init = TRUE;
            Osal_emacEnterSingleCoreCriticalSection(1);
        }
    }
#endif
}

Uint32 Convert_CoreLocal2GlobalAddr (Uint32  addr)
{
    Uint32 coreNum;

    /* Get the core number. */
    coreNum = CSL_chipReadDNUM();
    /* Check if the address is a valid Local L2 address to convert */
    if ( (addr >= (uint32_t) 0x800000) &&
         (addr <  (uint32_t) 0x880000) ) {
         /* Compute the global address. */
         return ((1 << 28) | (coreNum << 24) | (addr & 0x00ffffff));
    }
    else {
        return (addr);
    }
}

/**
*  @b Description
*  @n
*      Intialize the application control block, free/rx packet queue.
*
*  @retval
*      None.
*/
void
app_init
(
    void
)
{
    Uint32              i, j;
    EMAC_PKT_DESC_T*    p_pkt_desc;
    Uint8*              pktbuf_ptr;
#ifdef C6474
    CSL_SemContext      mem_sem_context;
    CSL_Status          mem_sem_stat;
    CSL_SemParam        mem_sem_param;
#endif

    System_printf ("%s\n", emac_get_version());
    System_printf ("EMAC Benchmark test application initialization\n");

#if APP_DEBUG
    TSCL =  0;
#endif

    /* Reset application control block */
    memset(&app_mcb, 0, sizeof (APP_EMAC_MCB_T));

    app_mcb.core_num = CSL_chipReadReg (CSL_CHIP_DNUM);

    if (pktbuf_extmem)
    {
        /* If packet buffer stored in external memory */
        pktbuf_ptr = (Uint8 *)(APP_EXTMEM+app_mcb.core_num*APP_TOTAL_PKTBUF_SIZE);
#ifdef C6474
        /* C6474 does not have shared internal memory, the first 0x2000 bytes of
        exteral memory is reserved for shared data structure used by EMAC driver */
        pktbuf_ptr += 0x2000;
#endif
    }
    else
    {
    	//pktbuf_ptr = (Uint8 *) ((Uint32) app_pkt_buffer | 0x10000000);
    	pktbuf_ptr = (Uint8 *)Convert_CoreLocal2GlobalAddr((Uint32)app_pkt_buffer);
    }

    /* Initialize the free packet queue */
    for (i=0; i<MAX_NUM_EMAC_PORTS; i++)
    {
        if (i == 0)
        {
            app_mcb.emac_pcb[0].phy_addr   = APP_PORT0_PHY_ADDR;
        }
#ifdef TWO_PORT_DEV
        else
        {
            app_mcb.emac_pcb[1].phy_addr   = APP_PORT1_PHY_ADDR;
        }
#endif

        for (j=0; j<APP_MAX_PKTS; j++)
        {
            p_pkt_desc               = &app_mcb.emac_pcb[i].pkt_desc[j];
            p_pkt_desc->pDataBuffer  = pktbuf_ptr;
            p_pkt_desc->BufferLen    = APP_EMAC_MAX_PKT_SIZE;
            app_queue_push( i, &app_mcb.emac_pcb[i].freeQueue, p_pkt_desc );
            pktbuf_ptr += APP_EMAC_MAX_PKT_SIZE;
        }
        /* Initialize the EMAC interrupts */
        app_interrupt_init(i);

#ifdef C6474
        /* Do semaphore module Initialization for shared data used by EMAC driver */
        CSL_semInit(&mem_sem_context);

        /* Open a Module specific Handle*/
        mem_sem_param.flags                 = APP_MEM_SEM_NUM;
        app_mcb.emac_pcb[i].mem_sem_handle  = CSL_semOpen(&app_mcb.emac_pcb[i].mem_sem_obj,CSL_SEM,&mem_sem_param,&mem_sem_stat);
        if (app_mcb.emac_pcb[i].mem_sem_handle == NULL)
        {
            System_printf ("app_init core %d port %d shared memory access semaphore open error \n",
                           app_mcb.core_num, i);
            return;
        }
#endif
    }
}

/**
 *  @b app_display_linkstatus
 *  @n
 *      This function is called whenever there is a change in link state on
 *      master core.
 *
 *  @param[in]  port_num
 *      EMAC port number.
 *  @param[in]  link_status
 *      Status of the link.
 *
 *  @retval
 *      void
 */
void
app_display_linkstatus
(
    Uint32              port_num,
    Uint32              link_status
)
{
    /* This string array corresponds to link state as defined in csl_mdio.h */
    char *LinkStr[] = { "No Link",
                        "10Mb/s Half Duplex",
                        "10Mb/s Full Duplex",
                        "100Mb/s Half Duplex",
                        "100Mb/s Full Duplex",
                        "1000Mb/s Full Duplex" };

    if (app_mcb.core_num == APP_MASTER_CORE_NUM)
    {
        System_printf("Port %d Link Status: %s on PHY %d\n",
                      port_num, LinkStr[link_status],
                      app_mcb.emac_pcb[port_num].phy_addr);
    }
}

/**
 *  @b Description
 *  @n
 *     This timer function polls the EMAC ports every 100 msec, it is called from a DSP/BIOS
 *     clock module, see evmc6472.cfg
 *
 *  @retval
 *      Not Applicable.
 */
void
app_timer
(
    void
)
{
/*    EMAC_LINK_INFO_T        link_info;

    if (emac_poll(0, &link_info) == EMAC_DRV_RESULT_OK)
    {
        if (link_info.link_status_change)
        {
            app_display_linkstatus(0, link_info.link_status);
            linkup = TRUE;
        }
    }
*/
}


/**
*  @b Description
*  @n
*      Entry point for the application test code.
*
*  @retval
*      None.
*/
void main(void)
{
    Task_Params     taskParams;

    app_init();

    /* Create the UnitTest Task.*/
    Task_Params_init(&taskParams);
    if (app_mcb.core_num == APP_MASTER_CORE_NUM)
    {
#ifdef MULTI_CORE_DEV
        /*
         * For multi core device, user can change the multi_core_receive
         * variable to select to run send or receive task on the master core
         */
        if (multi_core_receive)
        {
            Task_create(app_receive_task, &taskParams, NULL);
        }
        else
        {
            Task_create(app_send_task, &taskParams, NULL);
        }
#else
        /*
         * For single core device, user can change the single_core_receive
         * variable to select to run send or receive task on the core
         */
        if (single_core_receive)
        {
            Task_create(app_receive_task, &taskParams, NULL);
        }
        else
        {
            Task_create(app_send_task, &taskParams, NULL);
        }
#endif
    }
    else
    {
        /* For multi core device, always run send task on non-master core */
        Task_create(app_send_task, &taskParams, NULL);
    }


    /* Start BIOS */
    BIOS_start();
}

