This thread has been locked.

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

EmacBenchmark example project fails to get SGMII LINK

Other Parts Discussed in Thread: TMS320C6657

HI

I am trying to get the EMACBenchmark_ExampleProject to run on my custom board, which have a C6655 DSP and an Alaska Marvel 88E1512 PHY. I know that TI does not support other PHYs than the one on the EVM, but my problem is more related to the emac_drv than to the configuration and operation of the PHY.

I connect the ethernet port on my board directly to my PC and can see that the netcard in the PC detetct my board as a 1Gb Full duplex link. I have tested the example project out-of-the-box on the EVM and here it works perfectly and I can se on my PC that the EVM transmits alot of packets.

I have made a small modification to the example code from TI pdk_C6657_1_1_2_6. Instead of using the EVM value APP_PORT0_PHY_ADDR =24 I have changed this to APP_PORT0_PHY_ADDR = 1, which is what the PHY on my board have been configured to by HW.

I have also changed the destination MAC address to match the netcard on my PC so I can see if the board sends any packets.

When I run the code the app_send_task calls emac_open with these parameters

 

And inside emac_open the function SGMII_config is called with this config

I have also tried with masterEn=1 but that did not change anything

After calling sgmii_config the code waits for SGMII_STATUS.LINK to be 0

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

But that never happens so the program never returns from emac_open.

When I look at the registers in the SGMII modules I see the following values

this clearly shows that bit 0 in SGMII->status is not set, so SGMII does not detect that the link is up.

If I look in the registers from the MDIO module I see these values

which shows that the MDIO module have detected that there is a PHY on address 1 that have Link up.

So the question is

How come the SGMII module does not see the Link is up, when the MDIO module detects a PHY with link up?

I hope somebody can explain me how to modify the example so the SGMII detects that the link is up.

Best

Jens

  • Jens,

    We have discussed in the below E2E thread for your custom board, which is using different Phy and how it configure.
    http://e2e.ti.com/support/dsp/c6000_multi-core_dsps/f/639/t/367396.aspx

    Did you try SGMII configure as a master mode?
    SGMII_CONTROL->MASTER = 0x21 // master mode, auto-negotiation enable
    The below E2E thread will be useful for SGMII,
    http://e2e.ti.com/support/dsp/c6000_multi-core_dsps/f/639/p/379471/1352734.aspx#1352734
    Meantime, I will check your SGMII module register value with the datasheet.

  • HI

    I think the problem is related to the configuration of the SGMII_Serdes registers.

    On the EVM I need to initialize the board using the evmc6657l.gel file otherwise no data is transmitted. If I try to call the same GEL file ion my board it will fail when it enters the configSGMIISerdes() part, because it does not lock the PLL so it stays in this loop for a long time

    /* waitforclock() */
    for(i = 0; i < 10000; i++) {
    if (SGMII_SERDES_STS & 0x01)
    break;
    Wait_Soft(1000);
    }

    In my real code I do not use the GEL file, instead I have tried using the platform_init function to initialize the SGMII_serdes. I can see that it does excactly the same as the gel file. 

    The platform_init writes the following values to the SGMII_SERDES (evmc665x_phy.c)

    void configSerdes()
    {
    	int i;
        /* Unlock the chip configuration registers to allow SGMII SERDES registers to
        * be written */
        CSL_BootCfgUnlockKicker();
    
        /* Configure the SERDES */
        /* Multiply to be 8 with Quarter Rate in the Rx registers */
        CSL_BootCfgSetSGMIIConfigPLL (0x00000051);
    
    	platform_delaycycles(100);
    
        //31:25    Reserved    0000000
        //23:24    LOOPBACK    00
        //   22    ENOC        1
        //21:18    EQ          0001
        //17:15    CDR         001 -- first order threshold of 17
        //14:12    LOS         000 -- tie off
        //11:10    ALIGN       01  -- Comma Aligned
        //09:07    TERM        100 -- tie off (100)
        //   06    INVPAIR     0
        //05:04    RATE        01  -- tie off (10)  //00 = Full Rate, 01 = Half Rate (*0.5), 10 = Quarter Rate (*0.25)
        //03:01    BUSWIDTH    000 -- tie off
        //   00    ENRX        1
        // 0000 0000 0100 0100 0000 0010 0001 0001 = 0x0044_0211 -- My estimated value
        // 0000 0000 0100 0100 0000 0100 0001 0001 = 0x0044_0411 -- New DV value
        // 0000 0000 0000 1000 0000 1000 0100 0001 = 0x0008_0841 -- Original DV value
    
        CSL_BootCfgSetSGMIIRxConfig (0, 0x00700621);
    
        //31:22    Reserved    0
        //21:20    LOOPBACK    00
        //19:18    RDTCT       00  -- tie off
        //   17    ENIDL       0   -- tie off
        //   16    MYSNC       1   -- tie off
        //15:12    DEMPHASIS   ???? - 0001 Lets give some de-emphasis
        //11:08    SWING       ????
        //   07    CM          1   -- tie off
        //   06    INVPAIR     0
        //05:04    RATE        01  -- tie off
        //03:01    BUSWIDTH    000 -- tie off
        //   00    ENTX        1
        // 0000 0000 0011 0001 ???? ???? 1001 0001 = 0x0031_1E91 -- My estimated value
        // 0000 0000 0000 0001 0000 1111 0001 0001 = 0x0001_0F11 -- New DV value
        // 0000 0000 0100 0000 0001 1110 0100 0001 = 0x0040_1e41 -- Original DV value
        CSL_BootCfgSetSGMIITxConfig (0, 0x000108A1);
    
        /* Poll the SGMII0 lock bit to confirm that the sgmii module has recognized
        that the SERDES PLL has locked */
        /*
        do
        {
            CSL_SGMII_getStatus(0, &sgmii_status);
        } while (sgmii_status.bIsLocked != 1);
    	*/
        for(i = 0; i < 10000; i++)
        {
        	if (SGMII_SERDES_STS & 0x01)
        		break;
        	platform_delay(1000);
        }
        /* All done with configuration. Return Now. */
        return;
    }
    

    On my board the SGMII_SERDES_STS register remains 0x00 which means that the PLL have not locked.

    Do you have any idea what can cause the PLL not to lock?

    According to the datasheet for the PHY, it seems that the PHY have a 1.25GHz SERDES interface, that by default is as an SGMII to be hooked up to a MAC.

    Jens

  • Jens,

    Please can you try to run the EmacLoopbackTest on your custom board. This will validate there is no issue on the EMAC. I will check your PLL lock issue.

    Note:
    The TX/RX ports should be connected via a local Ethernet switch, no other network (LANs or PCs) should be connected to the switch.

    The test result on the console, find the below for EmacLoopbackTest,

    [C66xx_0] TMS320C6657: EMAC Driver Revision: 01.00.03.00
    EMAC loopback test application initialization
    emac_init: core 0, port 0, total number of channels/MAC addresses: 8/32
    MAC addresses configured for channel 0:
    00-01-02-03-04-05
    00-01-02-03-04-15
    00-01-02-03-04-25
    00-01-02-03-04-35
    MAC addresses configured for channel 1:
    00-01-02-03-14-05
    00-01-02-03-14-15
    00-01-02-03-14-25
    00-01-02-03-14-35
    MAC addresses configured for channel 2:
    00-01-02-03-24-05
    00-01-02-03-24-15
    00-01-02-03-24-25
    00-01-02-03-24-35
    MAC addresses configured for channel 3:
    00-01-02-03-34-05
    00-01-02-03-34-15
    00-01-02-03-34-25
    00-01-02-03-34-35
    MAC addresses configured for channel 4:
    00-01-02-03-44-05
    00-01-02-03-44-15
    00-01-02-03-44-25
    00-01-02-03-44-35
    MAC addresses configured for channel 5:
    00-01-02-03-54-05
    00-01-02-03-54-15
    00-01-02-03-54-25
    00-01-02-03-54-35
    MAC addresses configured for channel 6:
    00-01-02-03-64-05
    00-01-02-03-64-15
    00-01-02-03-64-25
    00-01-02-03-64-35
    MAC addresses configured for channel 7:
    00-01-02-03-74-05
    00-01-02-03-74-15
    00-01-02-03-74-25
    00-01-02-03-74-35
    emac_open core 0 port 0 successfully
    Sent 4096 received & verified 4094 pkts on Core 0 Port 0 Channel 0
    Sent 4096 received & verified 4094 pkts on Core 0 Port 0 Channel 1
    Sent 4096 received & verified 4094 pkts on Core 0 Port 0 Channel 2
    Sent 4096 received & verified 4094 pkts on Core 0 Port 0 Channel 3
    Sent 4096 received & verified 4094 pkts on Core 0 Port 0 Channel 4
    Sent 4096 received & verified 4094 pkts on Core 0 Port 0 Channel 5
    Sent 4096 received & verified 4094 pkts on Core 0 Port 0 Channel 6
    Sent 4096 received & verified 4094 pkts on Core 0 Port 0 Channel 7
    Sent 8192 received & verified 8190 pkts on Core 0 Port 0 Channel 0
    Sent 8192 received & verified 8190 pkts on Core 0 Port 0 Channel 1
    Sent 8192 received & verified 8190 pkts on Core 0 Port 0 Channel 2
    Sent 8192 received & verified 8190 pkts on Core 0 Port 0 Channel 3
    Sent 8192 received & verified 8190 pkts on Core 0 Port 0 Channel 4
    Sent 8192 received & verified 8190 pkts on Core 0 Port 0 Channel 5
    Sent 8192 received & verified 8190 pkts on Core 0 Port 0 Channel 6
    Sent 8192 received & verified 8190 pkts on Core 0 Port 0 Channel 7
    Loopback Test completed successfully on core 0
    Total TX packets 81920, RX packets 81920

  • Hi Pubesh

    I just ran the EMACloopbacktest on my custom board, and it gave excactly the same result as you got.

    If I change the benchmark test to to have emac loopback 

    open_cfg.master_core_flag = TRUE;
    open_cfg.mdio_flag = TRUE;
    open_cfg.loop_back = TRUE;

    Then the sender task works perfectly and I get this output

    [C66xx_0] TMS320C6657: EMAC Driver Revision: 01.00.03.00
    EMAC Benchmark test application initialization
    Running send task on core 0 port 0 channel 0
    emac_init: core 0, port 0, total number of channels/MAC addresses: 1/1
    MAC addresses configured for channel 0:
    BA-98-76-54-32-10
    emac_open core 0 port 0 successfully
    Sending packets on core 0 port 0 channel 0
    ------------------------------------------------
    Total Data Sent : 1510000000 bytes
    Start Time : 6 msec
    End Time : 18617 msec
    Total Time expired : 18611 msec
    Sent Throughput : 649 Mb/s
    ------------------------------------------------
    Benchmark Send Packet Test completed successfully on core 0 port 0 channel 0

    I was wondering abot this SERDES setting, and PLL not locking: Should I in some way take the distance between the DSP and the PHY in to account? On my custom board the distance is about 25cm and it goes through a connector (my DSP is on a daughter-board and the PHY is on the main board)

    Best

    Jens

    Jens

  • Jens,

    Jens: said:
    I was wondering abot this SERDES setting, and PLL not locking: Should I in some way take the distance between the DSP and the PHY in to account? On my custom board the distance is about 25cm and it goes through a connector (my DSP is on a daughter-board and the PHY is on the main board)

    I have requested the expert to clarify your query. Please wait some more time.

  • OK that would be nice.

    In the mean time I have discovered why the SERDED did nock lock the PLL. It was because the clock generator had not been enabled so there was no clock signal for the PLL to lock on to.

    After getting the HW guys to enable this clock signal I get a 200MHz clock as input to the SRIOSGMII_CLK input, which is not the same as on the EVM but I think it should be possible to use this signal right? I am not sure why The Clock generator gives 200MHz instead of 250MHz as on the EVM, but we will have to go with that for a while.

    I have changed the PLL multiplyer for the SERDES from  10 to 12,5 by writing 0x65 to the SGMIIConfigPLL register, and after doing that SGMII_SERDES_STS becomes 0x01 indicating that the PLL have locked.

    So that is good, but unfortunately the SGMII->STATUS.LINK still remains 0 indicating that the SGMII does not get link up.

    I can see that in the last part of the function SGMII_config() the code writes to three registers

    SGMII_REGS->AUX_CFG = config->auxConfig;

    /* wait for 2 usfor PLL to lock */

    for(val = 0; val < 1000; val++) asm(" NOP 5 ");

       SGMII_REGS->TX_CFG = config->txConfig;

    /* Toggle ENFTP bit */

    //SGMII_REGS->TX_CFG = config->txConfig | 0x1000;

    for(val = 0; val < 10; val++) asm(" NOP 5 ");

    //SGMII_REGS->TX_CFG = config->txConfig & (~(1 << 12));

       SGMII_REGS->RX_CFG = config->rxConfig;

    If I look in the debugger these registers are located at

    TX_CFG unsigned int 0x000108A1 (Hex) 0x02C08930
    RX_CFG unsigned int 0x00700621 (Hex) 0x02C08934
    AUX_CFG unsigned int 0x00000051 (Hex) 0x02C08938
    But According to the Gigabit Ethernet Switch Subsystem manual  http://www.ti.com/lit/ug/sprugv9d/sprugv9d.pdf page 96
    These adresses are in a reserved area???
    The "funny" thing is that the waluse written to these registers are the same as the values that were written to SGMII_SERDES_CFGPLL,  SGMII_SERDES_CFGRX0, and SGMII_SERDES_CFGTX0.
    Can you explain what the three SGMII_REGS should be set to and what the purpose of these registers are?
    best
    Jens

     

  • Jens,

    Apologize for the late reponse. Please refer the following thread for SGMII config, this will be useful.
    http://e2e.ti.com/support/dsp/c6000_multi-core_dsps/f/639/p/244293/869498

    We need to double check with you about the following sequence,
    “AUX_CFG unsigned int 0x00000051 (Hex) 0x02C08938”
    Are you expecting this to read 0x65?

    And aslo you are using platform.lib in your testing test code, If yes, in this case, wouldn’t the below function (line number 60) of evmc665x_phy.c affect the SGMII­_PLL config?

        /* Configure the SERDES */
        /* Multiply to be 8 with Quarter Rate in the Rx registers */
        CSL_BootCfgSetSGMIIConfigPLL (0x00000051);
     
    If you are modified the source code for platform_lib, you will need to rebuild the C6657 platform_lib, and then build your project so that the changes will take hold.

  • Hi Pubesh

    The thread you refer to explains hte usage of the three registers in the SGMII module - They have no influence in Keystone devices since the SerDes is set up in the bootcfg instead.

    I use the platform_lib as well as the drivers from the PDK, so I rebuild these components before I rebuild my application. I have checked using the debugger that the changes I make are in fact included in my application.

    As I mentioned we are using a 200MHz clock signal for the SRIOSGMII_CLK, and therefore I have changed the configuration of the SERDES PLL to

        /* Configure the SERDES */
        /* Multiply to be 12.5 with Quarter Rate in the Rx registers */
        /* Input clk is 200 MHz target clk is 1250 MHz                 */
        CSL_BootCfgSetSGMIIConfigPLL (0x00000065);
    

    In the debugger I can see that the register Gets the right value

    SGMII_CFGPLL unsigned int Value:0x00000065 (Hex) addr: 0x02620340

    I have also tried playing with the SGMII Rx and Tx configuration so now I am using 

        CSL_BootCfgSetSGMIIRxConfig (0, 0x00708621); // was 0x00700621
        CSL_BootCfgSetSGMIITxConfig (0, 0x00010FA1); // was 0x000108A1
    

    In the RxConfig I tried changing CDR to 001 - First order, threshold of 17.

    In the TxConfig I have tried increasing the voltage level by setting SWING = 1111

    11-8 SWING Output swing. Selects one of 16 output amplitude settings between 110 and 1310mVdfpp. Reducing the output amplitude
    decreases the current drawn in direct proportion to the reduction in swing, thereby saving power. See Table 3-178 for
    selectable values. It is recommended to start by setting this field to 1111. Whenever the SWING is reduced to a level below the
    maximum value, the link should be re-validated.

    But these changes have not helped. 

    I still have not found any explanation of what is required for the SGMII->STATUS.link bit to be set. If I knew which conditions that are required for the SGMII module to link, then it might be possible to figure out which of these conditions that are not fulfiled.

    Best

    Jens

  • Jens,

    Recently, We have the 88E1514 implemented on the K2E EVM(Keystone II based device). But it is functional through Linux. On K2E EVM, It must be enabled through MDIO before it can be used. Older EVMs used PHYs of the 88E11xx family which have more pin configuration which allows for booting without MDIO interaction.
    We are assuming that the ‘1512 and ‘1514 are sister devices but cannot provide this without seeing a ‘1514 datasheet which is protested by NDA which we do not have with Marvell. Perhaps,You can confirm or refute this assertion.
     
    We assume that the SGMII PLL will work with a 200MHz reference clock. We only qualified this PLL at 156.25, 250 and 312.5MHz.  There should not be any need to adjust the SGMII SERDES TX settings like Swing.

  • HI

    You are right in your assumption, det 1512 and 1515 are sister devices and they share the same datasheet.

    Could you share some more info on the board with the 1514, and how linux setup the up the PHY via MDIO? Then maybe I can figure out which register in the PHY that I need to adjust.

    Jens

  • Jens,


    Please refer the K2E GEL, this will be helpful you to get a clue on the MDIO setup since K2E uses the 1514 PHY.
    C:\ti\ccsv5\ccs_base\emulation\boards\evmk2e\gel\evmk2e.gel
      


    The similar discussion held on the following E2E post for how MDIO configured in the keystone II based device(K2E EVM).
    http://e2e.ti.com/support/dsp/c6000_multi-core_dsps/f/639/p/379471/1352734#1352734

  • Hi Jens,

    Please take a look at the K2E GEL to get some guidance on the MDIO setup. The GEL should be on your PC under this path:
    C:\ti\ccsv5\ccs_base\emulation\boards\evmk2e\gel\evmk2e.gel.

    You can also see the K2E schematic at https://www.einfochips.com/images/texas_instrument/K2EEVM/K2E_EVM_SCH_16_00175_02.pdf

    Also, I believe Pubesh had referenced this thread previously, but please take a look in case there is something else there to help.
    http://e2e.ti.com/support/dsp/c6000_multi-core_dsps/f/639/p/379471/1338213

    Lali
  • Hi

    I do not have the gel file for the K2E on my PC, but I have tried setting up the PHY in the same way as the previous post from Pubesh. In fact this is the setup I was using initially - and that I would expect to work.

    At the moment I am suspecting the SERDES interface between the DSP and the PHY, so I have asked the HW group to do some simulations on these signals.

    To verify that the problem is indeed in the electrical interface, I would like to set the SERDES in loopback mode to verify that the SGMII module then gets a link up status, but for some reason I do not see that happening, so I was hoping that you could explain how to use the SERDES loopback.

    What I have done is to set SGMII_SERDES_CGFTX0.LOOPBACK = 10b (also tried 11b) to enable loopback in the SERDES layer.

    I have also tried setting SGMII_SERDES_CGFRX0.LOOPBACK = 11b to see if that had any influence.

    I have tried all combinations of SGMII_SERDES_CGFTX0.LOOPBACK and SGMII_SERDES_CGFRX0.LOOPBACK but no matter how I setup the SERDES loopback I do not get SGMII->STATUS.LINK = 1.

    I still have not recieved an answer to my question: "What is required for the SGMII_STATUS.LINK to be set?"  

    thanks

    Jens

  • Jens,
    As far as I know, once the PLL is locked & MDIO enabled (for 1512 PHY) the link should come up. Assuming there aren't any hardware problems with the PCB.

    For the SERDES loopback, I'm working on trying some experiments to see if its just a matter of setting those bits for SERDES loopback. I initially tried this by manually setting those bits in the GEL and the SGMII_STATUS.LINK seemed to come up. I will get back to you with what I find.

    For the K2E GEL, you can install the KS2 emupack from the link below which will have the GEL.
    http://software-dl.ti.com/sdoemb/sdoemb_public_sw/mcsdk/latest/index_FDS.html

    Lali
  • Hi Jens,

    For SERDES loopback, are you using the KICK mechanism to unlock the registers? I think this is the reason LINK is not coming up after setting the SERDES loopback. Please take a look at http://www.ti.com/lit/ds/symlink/tms320c6657.pdf pg 72 which talks about the kicker mechanism. Also, http://www.ti.com/lit/ug/spruhh1/spruhh1.pdf (top of pg 2-56) says that the SGMII_SERDES registers must be unlocked prior to writing.

    I tried some tests on my C6657 EVM and here’s what I observed. This was using the C6657 GEL ( If you don’t have it, you can get the latest GEL from the KS1 emupack http://tigt_qa.gt.design.ti.com/qacm/test_area/TI_EMUPACK_KEYSTONE1/1_0_9_0/index_FDS.html)

    The below 2 values :

    SGMII_SERDES_CFGRX0.LOOPBACK=11
    SGMII_SERDES_CFGTX0. LOOPBACK=11

    Which translates to the register vals (in GEL):

    SGMII_SERDES_CFGRX0 = 0x1F00621;
    SGMII_SERDES_CFGTX0 = 0x3108A1;

    I connected to Core0 on CCS and loaded the GEL. Following this, the register showed that the LINK is UP.
    0x2c08914 = 0x31

    To experiment, I tried to create a scenario that the LINK would not come up. For this, the KICK0 = KICK0_UNLOCK & KICK0 = KICK0_UNLOCK were removed from the SERDES section in the GEL; essentailly leaving it LOCKED and not having access to the registers. This yielded the following which showed the LINK is DOWN.
    0x2c08914 = 0x30

    To bring it back up, I physically wrote the following sequence in CCS where each value was written into memory (1 at a time) by hand using the CCS memory browser:

    UNLOCK KICK0 and KICK1:
    mem location- 0x2620038
    val- 0x83E70B13

    mem location- 0x262003C
    val- 0x95A4F1E0

    Write to SGMII_SERDES_ CFGTX0 and RX0 registers:
    mem location- 0x2620344
    val- 0x1F00621

    mem location- 0x2620348
    val- 0x3108A1

    Immediately following this, the LINK came up:
    0x2c08914 = 0x31

    Hope this helps.
    Lali

  • Hi Lali

    When I initialize the SERDES, I call the platform function configSerdes() (in evmc665x_phy.c) and this function calls CSL_BootCfgUnlockKicker(), which writes the same values as you do in the KICK0 and KICK1 registers.

    I am not sure what I did wrong when I tried to enable SERDES loopback, but when I use the values you propose in  SGMII_SERDES_ CFGTX0 and RX0 registers, I also get SGMII.STATUS = 0x31 so that is good.

    I still do not get SGMII Link when I run without the SERDES loopback, so I suspect that the problem is somewhere in the routing of the SERDES PCB tracks, but this will require some more investigation and simulation of my Board

    Now that I have enabled SERDES loopback, I would expect that my application should recieve the packets that I transmit, but for some reason I do not see any packets being recieved.

    The aim is to transmit on channel 0 MAC:80-81-82-83-84-85 and recieve on channel 1 MAC: 00-01-02-03-04-05

    This should be a mix of the EMAC loopback example project and the EMAC benchmark example project.

    I have pasted the source code for my loopback test so maybe you can see what I am doing wrong?

    The task that I initiate is app_send_and_receive_task

    Best

    Jens

    /*
     * 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 Loopback 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/family/c64p/eventcombiner.h>
    #include <ti/sysbios/knl/Clock.h>
    #include <xdc/cfg/global.h>
    
    #define C665x
    #define C6657
    /* CSL Chip Functional Layer */
    #include <ti/csl/csl_chip.h>
    #include <ti/csl/csl_cache.h>
    #include <ti/csl/csl_mdio.h>
    #include <ti/csl/cslr_emac.h>
    #include <ti/csl/csl_mdio.h>
    
    #include <ti/csl/csl_gpio.h>
    #include <ti/csl/csl_gpioAux.h>
    
    /* Platform utilities include */
    #include <ti/platform/platform.h>
    
    /* 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>
    #include <ti/csl/cslr_sgmii.h>
    #include <ti/csl/cslr_bootcfg.h>
    
    /* Test application local header file */
    #include "emac_test_loc.h"
    #include "framework.h"
    #include "GlobalDataSpace/GlobalDataSpace.h"
    
    typedef struct
    {
      volatile int32* total_tx_count;
      volatile int32* total_rx_count;
      volatile int32* total_rx_error_count;
      volatile int32* link_state;
    } EMAC_TEST_STATUS_STRUCT;
    
    EMAC_TEST_STATUS_STRUCT _stEmacTest;
    
    #define NR_OF_PHY_PAGES 19
    #define NR_OF_PHY_REGS  29
    uint16 phyregs[NR_OF_PHY_PAGES][NR_OF_PHY_REGS];
    uint16 scan_phy_reg = 0;
    
    void phy_reg_scan(void);
    void emac_test_status_config(void);
    
    typedef struct
    {
      uint16 page;
      uint16 reg;
      uint16 new_val;
      uint16 write;
    } PHY_REG_STRUCT;
    
    volatile PHY_REG_STRUCT phy_reg_debug_write = {0, 0, 0, 0};
    
    /**********************************************************************
     ************************** Global Variables **************************
     ********************** ************************************************/
    //extern CSL_GpioHandle hGpio;
    
    /* Memory allocated for the packet buffer. This is 128 bytes aligned. */
    /* 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)
    volatile CSL_SgmiiRegs* SgmiiRegs = (CSL_SgmiiRegs*)0x2c08900;
    volatile CSL_MdioRegs * MdioRegs  = (CSL_MdioRegs *)0x02C08800;
    volatile CSL_BootcfgRegs* BootcfgRegs = (CSL_BootcfgRegs*)0x02620000;
    
    /* Memory allocated for the application control block */
    APP_EMAC_MCB_T   app_mcb;
    #pragma DATA_SECTION(app_mcb, ".far:APP_EMAC")
    
    int stop_test = TRUE;
    static PM_HPerFunc hemac_testScan100ms = NULL;
    
    /**********************************************************************
     ****************** Test Configuration Variables **********************
     **********************************************************************/
    /* Single core device receive flag,
       TRUE: running receive task on the core;
       FALSE: running send task on the core */
    Bool    single_core_receive = FALSE;
    
    Bool linkup = FALSE;
    
    /* 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   rx_mac_addr[EMAC_MAC_ADDR_LENTH] = {0xD8, 0xEB, 0x97, 0xB0, 0x77, 0x50};
    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;
    
    void writePhyReg(Uint32 phynum, Uint32 regnum, Uint16 data);
    Uint16 readPhyReg(Uint32 phynum, Uint32 regnum);
    
    Uint32 tx_count = 0;
    Uint32 rx_count = 0;
    Uint32 rx_error_count = 0;
    
    /**********************************************************************
     ************************ EMAC TEST FUNCTIONS *************************
     **********************************************************************/
    void phy_reg_scan(void)
    {
    #define PRINT_PHY_REGS
    
      int page = 0;
      int regnum = 0;
      int regvalue = 0;
    
      for (page = 0; page < NR_OF_PHY_PAGES; page++)
      {
        writePhyReg(APP_PORT0_PHY_ADDR, 22, page);
    
        for (regnum = 0; regnum < NR_OF_PHY_REGS; regnum++)
        {
          regvalue = readPhyReg(APP_PORT0_PHY_ADDR, regnum);
    
          if (regvalue != phyregs[page][regnum])
          {
            phyregs[page][regnum] = regvalue;
    #ifdef PRINT_PHY_REGS
            if (page != 6) /* filter some pages from print */
            {
              System_printf("\nreadPhyReg page %d, regnum %d = 0x%x", page, regnum, regvalue);
            }
    #endif
          }
        }
      }
    
      writePhyReg(APP_PORT0_PHY_ADDR, 22, 0); /* reset page */
    
    
    }
    
    /**
     *  @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);
    }
    
    /******************************************************************************
     *
     * 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
    }
    
    #define SET_PHYPAGE(X) writePhyReg(APP_PORT0_PHY_ADDR, 22, X)
    
    /******************************************************************************
     *
     * 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 phyReset(void)
    {
      int regval;
      int page;
    
      page = readPhyReg(APP_PORT0_PHY_ADDR, 22);
      //SET_PHYPAGE(0); /* set phy page to 0 */
      //regval = readPhyReg(APP_PORT0_PHY_ADDR, 0);
      //writePhyReg(APP_PORT0_PHY_ADDR, 0, regval | (1<<9));  /* restart copper negotiation*/
    
      SET_PHYPAGE(18); /* set phy page to 18 */
      regval = readPhyReg(APP_PORT0_PHY_ADDR, 20);
      writePhyReg(APP_PORT0_PHY_ADDR, 20, regval | 0x8001);  /* set mode to 1 and request SW reset of PHY*/
      SET_PHYPAGE(page);
    
    }
    
    /******************************************************************************
     *
     * 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)
    {
      int regval;
    //  int page;
      // Enable MDIO interface
      MDIOR->CONTROL = 0x400000A5;
    
      SET_PHYPAGE(0x00ff);	/* reg page 0xff */
      writePhyReg(APP_PORT0_PHY_ADDR, 17, 0x214B);
      writePhyReg(APP_PORT0_PHY_ADDR, 16, 0x2144);
      writePhyReg(APP_PORT0_PHY_ADDR, 17, 0x0C28);
      writePhyReg(APP_PORT0_PHY_ADDR, 16, 0x2146);
      writePhyReg(APP_PORT0_PHY_ADDR, 17, 0xB233);
      writePhyReg(APP_PORT0_PHY_ADDR, 16, 0x214D);
      writePhyReg(APP_PORT0_PHY_ADDR, 17, 0xCC0C);
      writePhyReg(APP_PORT0_PHY_ADDR, 16, 0x2159);
      SET_PHYPAGE(0);
    
      SET_PHYPAGE(1);
      writePhyReg(APP_PORT0_PHY_ADDR, 26, 0x47);  /* Ste PHY SWING to max, allowed to bypass serial AN, must be followed by reset*/
    //  regval = readPhyReg(APP_PORT0_PHY_ADDR, 0);
    //  regval |= ((1 << 15) | (1<<9)); /* reset and restart Auto Negotiation SGMII*/
    //  writePhyReg(APP_PORT0_PHY_ADDR, 0, regval);
    
    //  SET_PHYPAGE(2);
    //  writePhyReg(APP_PORT0_PHY_ADDR, 16, 0x5449);  /* Ste PHY SWING to max, not allowed to bypass serial AN, must be followed by reset*/
    
    //  SET_PHYPAGE(0);
      writePhyReg(APP_PORT0_PHY_ADDR, 9, 0x1800);  /* Set PHY to MASTER */
    //  writePhyReg(APP_PORT0_PHY_ADDR, 9, 0x1000);  /* Set PHY to SLAVE do not advertise 1000BASE*/
    
      SET_PHYPAGE(18);
      writePhyReg(APP_PORT0_PHY_ADDR, 20, 0x1);  /* set mode to 1 and request SW reset of PHY*/
      writePhyReg(APP_PORT0_PHY_ADDR, 20, 0x8201);  /* set mode to 1 and request SW reset of PHY*/
    
    //  regval = readPhyReg(APP_PORT0_PHY_ADDR, 0);
    //  regval |= ((1 << 15)); /* reset and restart Auto Negotiation copper*/
    //  writePhyReg(APP_PORT0_PHY_ADDR, 0, regval);
    
      SET_PHYPAGE(0);
      do
      {
        regval = readPhyReg(APP_PORT0_PHY_ADDR, 1);
      }
      while ((regval >> 5) & 0x1 == 0);
    
    }
    
    /**
     *  @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 emac_test_phy_init (void)
    {
      phyInit(NORMAL_PHY_MODE);
    }
    
    
    /**
     *  @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[p_pkt_enq->PktChannel],
                     (EMAC_PKT_DESC_T *)p_pkt_enq);
    }
    
    /**
     *  @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
    emac_testScan100ms
    (
      void
    )
    {
      EMAC_LINK_INFO_T        link_info;
      int port_num = 0;
    
      if (scan_phy_reg)
      {
        phy_reg_scan();
        if (scan_phy_reg == 1)
        {
          scan_phy_reg = 0;
        }
      }
    
      if (phy_reg_debug_write.write)
      {
        uint16 old_page = readPhyReg(APP_PORT0_PHY_ADDR, 22);
        phy_reg_debug_write.write = 0;
        writePhyReg(APP_PORT0_PHY_ADDR, 22, phy_reg_debug_write.page);
        writePhyReg(APP_PORT0_PHY_ADDR, phy_reg_debug_write.reg,  phy_reg_debug_write.new_val);
        writePhyReg(APP_PORT0_PHY_ADDR, 22, old_page);
      }
    
    //  if (app_mcb.emac_pcb[port_num].emac_state != APP_EMAC_PORT_STATE_CLOSE)
      {
        if (emac_poll(port_num, &link_info) == EMAC_DRV_RESULT_OK)
        {
          *_stEmacTest.link_state           = link_info.link_status;
          if (link_info.link_status_change)
          {
            if (link_info.link_status == EMAC_LINKSTATUS_NOLINK)
            {
              app_mcb.emac_pcb[port_num].emac_state = APP_EMAC_PORT_STATE_LINKDN;
            }
            else
            {
              app_mcb.emac_pcb[port_num].emac_state = APP_EMAC_PORT_STATE_LINKUP;
            }
            //app_display_linkstatus(port_num, link_info.link_status);
          }
        }
      }
    }
    
    /**
     *  @b app_verify_packet
     *  @n
     *      Perform a sanity check validation on the packet received
     *
     *  @retval
     *      True on success or False on failure
     */
    /**
     *  @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 != 1)
      {
        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);
    }
    
    /**
     *  @b app_rx0_int
     *  @n
     *      Receive Packet ISR for port 0
     *
     *  @param[in]  void
     *
     *  @retval
     *      void
     */
    void app_rx0_int()
    {
      /* 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
     */
    void
    app_tx0_int()
    {
      /* Call the EMAC driver TX interrupt service function for port 0 */
      emac_int_service(0, FALSE);
    }
    
    /**
     *  @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;
      EMAC_PKT_DESC_T*            p_pkt_desc;
      Uint32                      start_time, end_time, tx_time;
    
    
      /******************** 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
      ******************************************************************************/
      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;
      }
    
      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)
      {
        app_mcb.emac_pcb[port_num].emac_state = APP_EMAC_PORT_STATE_OPEN;
        /* 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)
      {
        if (app_mcb.emac_pcb[port_num].emac_state==APP_EMAC_PORT_STATE_LINKUP)
        {
          /* 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;
            }
          }
        }
      } /* 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");
    
      /* 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;
      EMAC_PKT_DESC_T*            p_pkt_desc;
      Uint32                      start_time, end_time, rx_time;
      Uint8                       mcast_list[2*EMAC_MAC_ADDR_LENTH];
    
      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;
      }
    
      /* 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;
    
      /* 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();
    }
    
    static Void app_send_and_receive_task(UArg arg0, UArg arg1)
    {
      EMAC_OPEN_CONFIG_INFO_T     open_cfg;
      EMAC_CHAN_MAC_ADDR_T        chan_cfg[2];
      EMAC_MAC_ADDR_T             mac_addr[2];
      EMAC_CONFIG_INFO_T          emac_cfg;
      Uint32                      port_num = 0;
      Uint32                      chan_num = 0;
      EMAC_PKT_DESC_T*            p_pkt_desc;
      Uint8                       mcast_list[2*EMAC_MAC_ADDR_LENTH];
    
      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;
      }
    
      /* Set the Tx channel configuration */
      chan_cfg[0].chan_num               = 0;
      chan_cfg[0].num_of_mac_addrs       = APP_EMAC_NUM_MACADDRS_PER_CHAN;
      memcpy(mac_addr[0].addr, tx_mac_addr, EMAC_MAC_ADDR_LENTH);
      chan_cfg[0].p_mac_addr             = &mac_addr[0];
    
      /* Set the Rx channel configuration */
      chan_cfg[1].chan_num               = 1;
      chan_cfg[1].num_of_mac_addrs       = APP_EMAC_NUM_MACADDRS_PER_CHAN;
      memcpy(mac_addr[1].addr, rx_mac_addr, EMAC_MAC_ADDR_LENTH);
      chan_cfg[1].p_mac_addr             = &mac_addr[1];
    
      /* Always open the channel 0 on port 0 for receive task */
      if (emac_open(port_num, &open_cfg) == EMAC_DRV_RESULT_OK)
      {
        app_mcb.emac_pcb[port_num].emac_state = APP_EMAC_PORT_STATE_OPEN;
    
        /* 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);
      }
    
      while (stop_test == FALSE)
      {
        OS_TaskSleep(1);
    	/* First get a packet descriptor from the free queue */
        if (app_mcb.emac_pcb[port_num].emac_state==APP_EMAC_PORT_STATE_LINKUP)
        {
    		chan_num = 0;
    		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);
    		  tx_count++;
    		}
    
    		chan_num = 1;
    		/* 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)
    		{
    		  /* 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);
    			rx_error_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 );
    	    }
    
    	  *_stEmacTest.total_tx_count       = tx_count;
    	  *_stEmacTest.total_rx_count       = rx_count;
    	  *_stEmacTest.total_rx_error_count = rx_error_count;
        }
      } /* End of while(TRUE) */
      Task_exit();
    }
    
    /**
     *  @b app_interrupt_init
     *  @n
     *      Registering Interrupts and Enabling global interrupts.
     *
     *  @param[in]  void
     *
     *  @retval
     *      void
     */
    static void
    app_interrupt_init
    (
      Uint32          port_num
    )
    {
      EventCombiner_dispatchPlug(APP_EMAC0_RX_INT_EV, (EventCombiner_FuncPtr)app_rx0_int, 0, TRUE);
      EventCombiner_dispatchPlug(APP_EMAC0_TX_INT_EV, (EventCombiner_FuncPtr)app_tx0_int, 0, TRUE);
    #if 0
      Hwi_Params      hwi_params;
      Error_Block     eb;
      static Bool     port0Init   = FALSE;
      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);
        }
      }
    
    #endif
    }
    
    /**
     *  @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;
    
      System_printf ("%s\n", emac_get_version());
      System_printf ("EMAC loopback test application initialization\n");
    
      /* 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);
      }
    
      else
      {
        pktbuf_ptr = (Uint8 *) ((Uint32) app_pkt_buffer | 0x10000000);
      }
    
      /* 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;
        }
    
        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);
      }
    }
    
    
    void emac_testScan100ms(void);
    
    /**
     *  @b Description
     *  @n
     *      Entry point for the application test code.
     *
     *  @retval
     *      None.
     */
    void emac_test_start(int transmit)
    {
      static int first = 1;
      Task_Params     taskParams;
    
      CSL_GPIO_setOutputData(hGpio, 15);
      app_init();
      stop_test = FALSE;
    
      if (first)
      {
        //emac_test_phy_init();
        emac_test_status_config();
        /* Create the UnitTest Task.*/
        hemac_testScan100ms = PM_InstallFunc("emac_testScan100ms", (PM_function_t) emac_testScan100ms, PM_RepTime_100ms, PM_EXECUTION_ORDER_FIRST, NULL, TRUE);
        first = 0;
      }
      Task_Params_init(&taskParams);
      taskParams.stackSize = 4096;
      taskParams.priority = 2;
      if (transmit == 1)
      {
        Task_create(app_send_and_receive_task, &taskParams, NULL);
      }
      else if (transmit == 2)
      {
        Task_create(app_send_task, &taskParams, NULL);
      }
      else if (transmit == 3)
      {
        Task_create(app_receive_task, &taskParams, NULL);
      }
    }
    
    void emac_test_stop(void)
    {
      /* The stop / restart functionality is not working properly - JEPBI 23-09-2014*/
      stop_test = TRUE;
      CSL_GPIO_clearOutputData(hGpio, 15);
    }
    
    void emac_test_status_config(void)
    {
      _stEmacTest.total_tx_count       = GlobalDataSpaceGetIntPtr(ENUM_EMAC_TEST_TOTAL_TX_COUNT);
      _stEmacTest.total_rx_count       = GlobalDataSpaceGetIntPtr(ENUM_EMAC_TEST_TOTAL_RX_COUNT);
      _stEmacTest.total_rx_error_count = GlobalDataSpaceGetIntPtr(ENUM_EMAC_TEST_TOTAL_RX_ERROR_COUNT);
      _stEmacTest.link_state           = GlobalDataSpaceGetIntPtr(ENUM_EMAC_TEST_LINK_STATE);
    
    }
    

  • Hi Jens,
    I don't know why your code might be failing, but I did try the EMAC loopback test with the SERDES loopback enabled. The test seemed to pass. I kept the 6657 EVM RJ45 physically connected to the LAN when I executed the test. Does this work for you in SERDES loopback mode?

    mem location- 0x2620344
    val- 0x1F00621

    mem location- 0x2620348
    val- 0x3108A1

    [C66xx_0] TMS320C6657: EMAC Driver Revision: 01.00.03.00
    EMAC loopback test application initialization
    emac_init: core 0, port 0, total number of channels/MAC addresses: 8/32
    MAC addresses configured for channel 0:
    00-01-02-03-04-05
    00-01-02-03-04-15
    00-01-02-03-04-25
    00-01-02-03-04-35
    MAC addresses configured for channel 1:
    00-01-02-03-14-05
    00-01-02-03-14-15
    00-01-02-03-14-25
    00-01-02-03-14-35
    MAC addresses configured for channel 2:
    00-01-02-03-24-05
    00-01-02-03-24-15
    00-01-02-03-24-25
    00-01-02-03-24-35
    MAC addresses configured for channel 3:
    00-01-02-03-34-05
    00-01-02-03-34-15
    00-01-02-03-34-25
    00-01-02-03-34-35
    MAC addresses configured for channel 4:
    00-01-02-03-44-05
    00-01-02-03-44-15
    00-01-02-03-44-25
    00-01-02-03-44-35
    MAC addresses configured for channel 5:
    00-01-02-03-54-05
    00-01-02-03-54-15
    00-01-02-03-54-25
    00-01-02-03-54-35
    MAC addresses configured for channel 6:
    00-01-02-03-64-05
    00-01-02-03-64-15
    00-01-02-03-64-25
    00-01-02-03-64-35
    MAC addresses configured for channel 7:
    00-01-02-03-74-05
    00-01-02-03-74-15
    00-01-02-03-74-25
    00-01-02-03-74-35
    emac_open core 0 port 0 successfully
    Sent 4096 received & verified 4094 pkts on Core 0 Port 0 Channel 0
    Sent 4096 received & verified 4094 pkts on Core 0 Port 0 Channel 1
    Sent 4096 received & verified 4094 pkts on Core 0 Port 0 Channel 2
    Sent 4096 received & verified 4094 pkts on Core 0 Port 0 Channel 3
    Sent 4096 received & verified 4094 pkts on Core 0 Port 0 Channel 4
    Sent 4096 received & verified 4094 pkts on Core 0 Port 0 Channel 5
    Sent 4096 received & verified 4094 pkts on Core 0 Port 0 Channel 6
    Sent 4096 received & verified 4094 pkts on Core 0 Port 0 Channel 7
    Sent 8192 received & verified 8190 pkts on Core 0 Port 0 Channel 0
    Sent 8192 received & verified 8190 pkts on Core 0 Port 0 Channel 1
    Sent 8192 received & verified 8190 pkts on Core 0 Port 0 Channel 2
    Sent 8192 received & verified 8190 pkts on Core 0 Port 0 Channel 3
    Sent 8192 received & verified 8190 pkts on Core 0 Port 0 Channel 4
    Sent 8192 received & verified 8190 pkts on Core 0 Port 0 Channel 5
    Sent 8192 received & verified 8190 pkts on Core 0 Port 0 Channel 6
    Sent 8192 received & verified 8190 pkts on Core 0 Port 0 Channel 7
    Loopback Test completed successfully on core 0
    Total TX packets 81920, RX packets 81920

    Lali

  • Hi Lali

    I can see from your console dump that you did not initialize the SGMII so I guess that your test code runs with EMAC loopback instead og SERDES loopback?

    I think you need to modify test_main.c change the EMACLoopback test project

    Instead of
    open_cfg.loop_back = TRUE;

    You must use
    open_cfg.loop_back = FALSE;

    This way the loopback does not happen in the EMAC layer, instead it happens in the SERDES layer which is what we want.

    If I run the EMACLoopback test project without this modification I get the same output as you do, but if I modify open_cfg.loop_back and run the test project with I get the following output (when I run it on the EVM6657)

    TMS320C6657: EMAC Driver Revision: 01.00.03.00
    EMAC loopback test application initialization
    emac_init: core 0, port 0, total number of channels/MAC addresses: 8/32
    MAC addresses configured for channel 0:
    00-01-02-03-04-05
    00-01-02-03-04-15
    00-01-02-03-04-25
    00-01-02-03-04-35
    MAC addresses configured for channel 1:
    00-01-02-03-14-05
    00-01-02-03-14-15
    00-01-02-03-14-25
    00-01-02-03-14-35
    MAC addresses configured for channel 2:
    00-01-02-03-24-05
    00-01-02-03-24-15
    00-01-02-03-24-25
    00-01-02-03-24-35
    MAC addresses configured for channel 3:
    00-01-02-03-34-05
    00-01-02-03-34-15
    00-01-02-03-34-25
    00-01-02-03-34-35
    MAC addresses configured for channel 4:
    00-01-02-03-44-05
    00-01-02-03-44-15
    00-01-02-03-44-25
    00-01-02-03-44-35
    MAC addresses configured for channel 5:
    00-01-02-03-54-05
    00-01-02-03-54-15
    00-01-02-03-54-25
    00-01-02-03-54-35
    MAC addresses configured for channel 6:
    00-01-02-03-64-05
    00-01-02-03-64-15
    00-01-02-03-64-25
    00-01-02-03-64-35
    MAC addresses configured for channel 7:
    00-01-02-03-74-05
    00-01-02-03-74-15
    00-01-02-03-74-25
    00-01-02-03-74-35
    SGMII reset successful........
    SGMII config successful........
    emac_open core 0 port 0 successfully
    Loopback Test failed on core 0
    Packets TX/RX on port 0:
    Channel 0 TX pkts 8, RX pkts 0
    Channel 1 TX pkts 8, RX pkts 0
    Channel 2 TX pkts 8, RX pkts 0
    Channel 3 TX pkts 8, RX pkts 0
    Channel 4 TX pkts 8, RX pkts 0
    Channel 5 TX pkts 8, RX pkts 0
    Channel 6 TX pkts 8, RX pkts 0
    Channel 7 TX pkts 8, RX pkts 0

    I use GEL file to set up the SERDES on the emulator
    /* Multiply to be 8 with Quarter Rate in the Rx registers */
    SGMII_SERDES_CFGPLL = 0x00000051; /* EVM SGMII @250Mhz */

    /* Wait */
    Wait_Soft(100);

    SGMII_SERDES_CFGRX0 = 0x01F00621; /* serdes loopback */
    // SGMII_SERDES_CFGRX0 = 0x00700621; /* normal operation */

    SGMII_SERDES_CFGTX0 = 0x003108A1; /* serdes loopback */
    // SGMII_SERDES_CFGTX0 = 0x000108A1; /* normal operation */

    /* waitforclock() */

    Any idea what is wrong, or how I can use the SERDES loopback?

    Best
    Jens