PROCESSOR-SDK-J784S4: FreeRTOS enet examples enet_loopback_test 5ms Freeze every 2-5 million send frames

Part Number: PROCESSOR-SDK-J784S4
Other Parts Discussed in Thread: J784S4XEVM

Tool/software:

Dear FreeRTOS Enet driver Team,

I ported my application to J784S4XEVM with FreeRTOS on R5f and try to send and receive an Ethernet frame every 250µs

My Ethernet settings are based on the enet_loopback_test  example for MCU2_1 core. Except for the following issue it's working well.

In my application every ~1.8 Million frames, some microseconds after send, the system freezes for about 5.2 ms.

I only know that during this freeze the system does not call FreeRtos Idle function, global breakpoints can't stop the R5f core and the timer isr function isn't called.

I reproduced this issue with the enet_loopback_test  example from pdk_j784s4_08_06_01_03 and from the latest pdk_j784s4_09_02_00_30.

I had to make some changes

- to avoid loopback in mac or phy,

- to avoid delays by  EnetLpbk_retrieveFreeTxPkts() and Tx Semaphore

- and I also added my CCNT Time measurement.

In my last test I got this freeze 12 Times in 50 Million send frames, it always occurs in the 200µs after EnetDma_submitTxPktQ().

Hopefully some of you can look at my attached modified example and check if I made something wrong.

Best Regards

Daniel

enet_loopback_test.zip

  • Hi,

    Can you see any drop packets during that time, if descriptors are not available packets will not be received.

    I only know that during this freeze the system does not call FreeRtos Idle function

    May I know where the Program counter pointing to during this freeze time.

    Best Regards,
    Sudheer

  • Hi,

    I didn't see any lost frames.

    and I fortunately have no idea where the Programm Counter is at this time and what the core actually does.

    Best Regards

    Daniel

  • Hi,

    and I fortunately have no idea where the Programm Counter is at this time and what the core actually does.

    You can add prints and trace, where it was struck.

    I didn't see any lost frames.

    If TDA4 is sender, It could be due to no buffers available at UDMA to transmit the frames. 
    After transfer completion, the descriptors will be freed and refilled with new frames information.

    How you identified the freeze for few msec?

    Best Regards,
    Sudheer

  • Hi,

    Sorry I thought to complex about where the Programm Counter is, my application it's in the loop after EnetDma_submitTxPktQ()

    (but actually to to the scheduler or an interrupt it is far far away.) So EnetDma_submitTxPktQ always was finished successfully.

    I measure the time with the CCNT counter and  there's a 5ms gap in the Wireshark recording.

    Best Regards

    Daniel

  • Hi,

    Sorry I thought to complex about where the Programm Counter is, my application it's in the loop after EnetDma_submitTxPktQ()

    (but actually to to the scheduler or an interrupt it is far far away.) So EnetDma_submitTxPktQ always was finished successfully.

    I don't know how you have modified loopback example as you required.

    Default SDK has semaphore and waiting for it for sending the packet, semaphore is posted in interrupt.
    Also, we are checking if any descriptors available or not, if not waiting for some time and then filling the queue/descriptor.

    There could be possibility that HW is busy after so many packets, so you are observing the delay in the packets.

    Until the call trace it is hard to find where it was struck.

    Best Regards,
    Sudheer

  • Hi,

    can you please look at my attached files?

    Best Regards

    Daniel

  • Hi,

    can you please look at my attached files?

    If "WFI" is  executing, ARM counters will not increment. 

    I could find you using ARM counters and performing some calculations, as stated above if  "WFI" is executed it will impact your calculations.
    Also, I think the counter is 32bit counter. Please check your calculations taken care of overflow if exceeding 32bit counter value.

    Please add prints in loops and check where it was struck.

    Best Regards,
    Sudheer

  • Hi,

    I now about the CCNT issues.

    I replaced WFI with NOP and the counter overflow is handled in the code.

    You can't print if you want to send at least 10 Million frames.

    I measured the average and max time value in the different send steps.

    """

    Time 3168 s, Frames 10000000
    times more than; 100us 9999100; 1000us 1; 1500us 0; 5000us 2;
    all in us: min: 0010, avg: 0316, max 5771
    prepare1 in us: min: 0002, avg: 0002, max 0205
    prepare2 in us: min: 0000, avg: 0000, max 0034
    send in us: min: 0003, avg: 0005, max 0805
    semaphore in us: min: 0010, avg: 0306, max 5761

    Time 6336 s, Frames 20000000
    times more than; 100us 9999100; 1000us 1; 1500us 0; 5000us 2;
    all in us: min: 0010, avg: 0317, max 5783
    prepare1 in us: min: 0002, avg: 0002, max 0171
    prepare2 in us: min: 0000, avg: 0000, max 0033
    send in us: min: 0003, avg: 0005, max 0742
    semaphore in us: min: 0010, avg: 0307, max 5771

    Time 9505 s, Frames 30000000
    times more than; 100us 9999099; 1000us 1; 1500us 0; 5000us 3;
    all in us: min: 0010, avg: 0316, max 5796
    prepare1 in us: min: 0002, avg: 0002, max 0166
    prepare2 in us: min: 0000, avg: 0000, max 0046
    send in us: min: 0003, avg: 0005, max 0730
    semaphore in us: min: 0010, avg: 0306, max 5785
    Received 5002 packets

    Time 12673 s, Frames 40000000
    times more than; 100us 9999100; 1000us 1; 1500us 0; 5000us 2;
    all in us: min: 0010, avg: 0316, max 5779
    prepare1 in us: min: 0002, avg: 0002, max 0171
    prepare2 in us: min: 0000, avg: 0000, max 0033
    send in us: min: 0003, avg: 0005, max 0752
    semaphore in us: min: 0010, avg: 0306, max 5768


    Time 15842 s, Frames 50000000
    times more than; 100us 9999099; 1000us 1; 1500us 0; 5000us 3;
    all in us: min: 0010, avg: 0316, max 5778
    prepare1 in us: min: 0002, avg: 0002, max 0168
    prepare2 in us: min: 0000, avg: 0000, max 0034
    send in us: min: 0003, avg: 0005, max 0732
    semaphore in us: min: 0010, avg: 0306, max 5769

    Transmitted 50000000 packets

    """

    in my loop after EnetDma_submitTxPktQ (and only in this loop) I get a 5,2ms delay

                    qwTickPoint3 = OsMeasGetCounterTicks();
    #if 0
         /* can send frames even faster but it looks like there is sometimes an addtional delay */
                    SemaphoreP_pend(gEnetLpbk.hTxSem, SemaphoreP_WAIT_FOREVER);
    #elif 0
        /* too slow */
                    EnetAppUtils_wait(1);
    #else
                    for (int i =0; i < dwTicks1u * 60; i++) /* about 250us */
                        __asm__ volatile ("nop");
    #endif
                    qwTickPoint4 = OsMeasGetCounterTicks();

    If I use EnetAppUtils_wait(1); instead of the loop it happens too.

    Best Regards

    Daniel

  • sorry Semaphore is the name of this block

    semaphore in us: min: 0010, avg: 0306, max 5761

  • Hi,

    I now about the CCNT issues.

    May I know what issue your are observing with ARM counters.

    is the delay is same what you observer after submit packet? i.e. for get the transfer completion.

    Best Regards,
    Sudheer

  • Hi,

    Sorry this was a typo "know" not "now"

    There now no Problem left, I trust my time measurement.

    I get this delay in my wait loop after EnetDma_submitTxPktQ() and especially in my application I can proof that the delay is real.

    Best Regards

    Daniel

  • Hi,

    I get this delay in my wait loop after EnetDma_submitTxPktQ() and especially in my application I can proof that the delay is real.

    As mentioned above, if buffer are not available and H/W is busy in transmitting the frames submitted you will go for wait.
    Please refer to comments in SDK example.

    Best Regards,
    Sudheer

  • Hi,

    I think the delay you mean is inside EnetDma_submitTxPktQ() 

    And I determine it in the block

    send in us: min: 0003, avg: 0005, max 0730

    in my measurement.

    the my delay is in the next block when EnetDma_submitTxPktQ()  is successfully finished.
    semaphore in us: min: 0010, avg: 0306, max 5785

    Best Regards

    Daniel

  • Hi,

    I think the delay you mean is inside EnetDma_submitTxPktQ() 

    I could not find the submitTxPktQ in your loopback.c file. I am not sure whether the above shares one is latest or not.

    From Tx Task , I could understand you are filling the Queues, but no where checking for Tx completion or not, Usually by semaphore in TI SDK.

    If you have utilized all the queue elements, you will not have any empty queues to submit your Tx packet. If H/W is busy in sending the data submitted before and not freed/empty the Queue you can't push further data.

    Please check is time delay is because of this Queue element is not available or not? as you are not using DMA notification for the indication of Tx completion.

    Best Regards,
    Sudheer

  • Hi,

    please search for EnetDma_submitTxPktQ without brackets.

    The semaphore belongs to the send interrupt, in Linux driver code and I think here too, it's for the cleanup in the retrieve function.

    My tests are at less than 1 % of the send capabilities of the cpsw (less the 10% of 100Mbit, of possible 1Gbit). so the hardware can't be very busy.

    Best Regards

    Daniel

  • Hi,

    It seems like the Transmission sequence was modified by you.

    Compared to TI SDK, we are checking all the packets filled in Queue and submitting all to DMA but, in your application you are not looping for all filled queue elements and submit to DMA.

    Until to check step by step debug or debug logs,  it could be very difficulty to confirm the delay is from where?

    Please add some debug points for the whole Tx process (Filing Queues with data, fetching and submit to DMA, getting the completion status if not getting check whether queue is available or not for next packet queuing)

    Best Regards,
    Sudheer

  • Hi Sudheer,

    I made test with a Beckhoff ET2000 .

    Till frame n everything is good and all frames are send successfully also frame n

    After Frame n  in my loop of asm("nop") the system freeze more than 5ms and then continue sending.

    #Relative No. Time timestamp (ET2000) Protocol Source Frame Idx Diff to previous (ET2000)
    Frame n-4 4146515 979.3640990 0x000001f3eaa37610 0x88b5 TexasIns_1d:92:c1 0x62 -
    Frame n-3 4146516 979.364099 0x000001f3eaa6fa10 0x88b5 TexasIns_1d:92:c1 0x63 230400 ns
    Frame n-2 4146517 979.364333 0x000001f3eaaa8b30 0x88b5 TexasIns_1d:92:c1 0x64 233760 ns
    Frame n-1 4146518 979.364565 0x000001f3eaae1700 0x88b5 TexasIns_1d:92:c1 0x65 232400 ns
    Frame n 4146519 979.364796 0x000001f3eab19ba0 0x88b5 TexasIns_1d:92:c1 0x66 230560 ns
    Frame n+1 4146520 979.370117 0x000001f3eb027598 0x88b5 TexasIns_1d:92:c1 0x67 5298680 ns

    With this result (and the fact I  didn't change there anything) would assume there is no problem in getting buffers and send.

    But maybe the state of the Tx Cleanup ring or the state of some other things behind the EnetLpbk_retrieveFreeTxPkts() function is bad before if try to send Frame n.

    What state information shall I collect?

    Or what shall I change around Sematphore and EnetLpbk_retrieveFreeTxPkts() to make it safe but still fast?

    Best Regards

    Daniel

  • Hi,

    But maybe the state of the Tx Cleanup ring or the state of some other things behind the EnetLpbk_retrieveFreeTxPkts() function is bad before if try to send Frame n.

    Can you check is there delay addition by "EnetLpbk_retrieveFreeTxPkts" API or not? by reading the time before and after.

    Best Regards,
    Sudheer

  • Hi,

    When do you mean in the cycle of the freeze but after the freeze, in the cycle before or in the cycle after?

    The average is 7µs (all - prepare1 - prepare2 - send - semaphore)

    Best Regards

    Daniel

  • Hi,

    When do you mean in the cycle of the freeze but after the freeze, in the cycle before or in the cycle after?

    I mean, check is the freeze is because of "EnetLpbk_retrieveFreeTxPkts" call or not?

    Best Regards,
    Sudheer

  • Hi Sudheer,

    I made a new measurement.

    EnetLpbk_retrieveFreeTxPkts() takes never more then 67µs, the measurement is from Point4 to end.

    The freeze is always during my nop-loop.

    Time 2679 s, Frames 10000000
    times more than; 100us 9999115; 1000us 0; 1500us 1; 5000us 2;
    all in us: min: 0010, avg: 0267, max 5835
    prepare1 in us: min: 0002, avg: 0003, max 0224
    prepare2 in us: min: 0000, avg: 0000, max 0053
    send in us: min: 0005, avg: 0007, max 1063
    smphr/wait in us: min: 0010, avg: 0253, max 5820
    retrieve in us: min: 0001, avg: 0002, max 0065

    Time 5349 s, Frames 20000000
    times more than; 100us 9999117; 1000us 1; 1500us 0; 5000us 2;
    all in us: min: 0010, avg: 0267, max 5822
    prepare1 in us: min: 0002, avg: 0003, max 0176
    prepare2 in us: min: 0000, avg: 0000, max 0052
    send in us: min: 0004, avg: 0008, max 0942
    smphr/wait in us: min: 0010, avg: 0253, max 5808
    retrieve in us: min: 0001, avg: 0002, max 0062

    Time 8025 s, Frames 30000000
    times more than; 100us 9999115; 1000us 1; 1500us 0; 5000us 3;
    all in us: min: 0010, avg: 0267, max 5818
    prepare1 in us: min: 0002, avg: 0003, max 0187
    prepare2 in us: min: 0000, avg: 0000, max 0054
    send in us: min: 0005, avg: 0007, max 0929
    smphr/wait in us: min: 0010, avg: 0253, max 5802
    retrieve in us: min: 0001, avg: 0002, max 0067

    Best Regards

    Daniel

  • Hi Sudheer,

    I turned on the original retrieve loop. And tested it with my nop-wait-loop.

    The is still a freeze in the first 250µs after send, once after each 4 million frames.

                //while (0U != EnetQueue_getQCount(&txSubmitQ))
                if (0U != EnetQueue_getQCount(&txSubmitQ))
                {
                    uint32_t txCnt = EnetQueue_getQCount(&txSubmitQ);
                    status = EnetDma_submitTxPktQ(gEnetLpbk.hTxCh,
                                                       &txSubmitQ);
                    qwTickPoint3 = OsMeasGetCounterTicks();
    
                    for (int i =0; i < dwTicks1u * 60; i++) /* about 250us */
                        __asm__ volatile ("nop");
                    qwTickPoint4 = OsMeasGetCounterTicks();
    
                    SemaphoreP_pend(gEnetLpbk.hTxSem, SemaphoreP_WAIT_FOREVER);
    
                    /* Retrieve TX free packets */
                    if (status == ENET_SOK)
                    {
                        txCnt            = txCnt - EnetQueue_getQCount(&txSubmitQ);
                        txRetrievePktCnt = 0U;
                        while (txRetrievePktCnt != txCnt)
                        {
                            /* This is not failure as HW is busy sending packets, we
                             * need to wait and again call retrieve packets */
                            EnetAppUtils_wait(1);
                            txRetrievePktCnt += EnetLpbk_retrieveFreeTxPkts();
                        }
                    }
                    //else
                    //{
                    //    break;
                    //}
                }

    Time 10939 s, Frames 10000000
    times more than; 100us 0; 1000us 9998998; 1500us 1; 5000us 9;
    all in us: min: 0010, avg: 1094, max 6571
    prepare1 in us: min: 0002, avg: 0003, max 0222
    prepare2 in us: min: 0000, avg: 0000, max 0017
    send in us: min: 0005, avg: 0009, max 1131
    wait in us: min: 0010, avg: 0252, max 5864
    smphr/retrieve in us: min: 0010, avg: 0828, max 5315

    Best Regards

    Daniel

  • Hi,

    The is still a freeze in the first 250µs after send, once after each 4 million frames.

    The 250usec will be due to your NOP wait loop.

    for (int i =0; i < dwTicks1u * 60; i++) /* about 250us */
        __asm__ volatile ("nop");


    You can remove this loop, as semaphore is already present next to your wait loop.

    Best Regards,
    Sudheer

  • Hi,

    But I don't want it to happen in SemaphoreP_pend,

    I need to the freeze to disappear.

    I think this shows that send can leave time delayed bombs.

    Best Regards

    Daniel

  • Hi,

    I think this shows that send can leave time delayed bombs.

    You need to handle the freeing of Queues (descriptors) and submit back after transmission success.

    In SDK, it was based on ISR, and Semaphore based handled the same.

    But I don't want it to happen in SemaphoreP_pend,

    I need to the freeze to disappear.

    May be create a Task & try to free all completed Queues and in other thread fill the descriptors and submit the packets.

    Even in above case also, if queues are not freed, send will freeze some time until the empty queue is found.

    Other above, there is no other possibility for handling the send without semaphore/interrupt.

    Best Regards,
    Sudheer

  • Hi Sudheer,

    I ensured it's only one frame send each cycle,

    I added a thread with a bit higher priority which runs SemaphoreP_pend and EnetLpbk_retrieveFreeTxPkts.

    After send I sleep 1 ms and then I check if the package was retrieved.

    static void EnetLpbk_txTaskCleanup(void* a0,
                                void* a1)
    {
        uint32_t txRetrievePktCnt = 0;
    
        uint32_t *pdwTxRetrieveTotal = (uint32_t *)a1;
        MutexP_Handle mutexHandle = (MutexP_Handle)a0;
    
        while (1)
        {
            SemaphoreP_pend(gEnetLpbk.hTxSem, SemaphoreP_WAIT_FOREVER);
    
            /* Retrieve TX free packets */
            txRetrievePktCnt = EnetLpbk_retrieveFreeTxPkts();
    
            MutexP_lock(mutexHandle, MutexP_WAIT_FOREVER);
            *pdwTxRetrieveTotal = *pdwTxRetrieveTotal + txRetrievePktCnt;
            MutexP_unlock(mutexHandle);
        }
    }

    So there is nothing left in the queues, but still there is the same freeze each 4.5 million frames.

    Time 11098 s, Frames 10000000
    times more than; 100us 2; 1000us 9999996; 1500us 0; 5000us 2;
    dwCntTxRetrieveDelayed 0; dwTxRetrieveTotal 10000000; pktCnt 10000000;
    all        in us: avg: 1109, max 5728
    prepare1   in us: avg: 0003, max 0080
    prepare2   in us: avg: 0000, max 0017
    send       in us: avg: 0010, max 0113
    wait       in us: avg: 1095, max 5713
    
    Time 22197 s, Frames 20000000
    times more than; 100us 2; 1000us 9999996; 1500us 0; 5000us 2;
    dwCntTxRetrieveDelayed 0; dwTxRetrieveTotal 10000000; pktCnt 10000000;
    all        in us: avg: 1109, max 5707
    prepare1   in us: avg: 0003, max 0021
    prepare2   in us: avg: 0000, max 0017
    send       in us: avg: 0010, max 0031
    wait       in us: avg: 1094, max 5693
    
    Time 33297 s, Frames 30000000
    times more than; 100us 3; 1000us 9999994; 1500us 0; 5000us 3;
    dwCntTxRetrieveDelayed 0; dwTxRetrieveTotal 10000000; pktCnt 10000000;
    all        in us: avg: 1109, max 5698
    prepare1   in us: avg: 0003, max 0021
    prepare2   in us: avg: 0000, max 0017
    send       in us: avg: 0011, max 0031
    wait       in us: avg: 1094, max 5681
    
    Time 44396 s, Frames 40000000
    times more than; 100us 2; 1000us 9999996; 1500us 0; 5000us 2;
    dwCntTxRetrieveDelayed 0; dwTxRetrieveTotal 10000000; pktCnt 10000000;
    all        in us: avg: 1109, max 5698
    prepare1   in us: avg: 0003, max 0021
    prepare2   in us: avg: 0000, max 0017
    send       in us: avg: 0010, max 0031
    wait       in us: avg: 1094, max 5684

    Best Regards

    Daniel

    enet_loopback.c
    /*
     *  Copyright (c) Texas Instruments Incorporated 2020-2021
     *
     *  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  enet_loopback.c
     *
     * \brief This file contains the implementation of the Enet loopback example.
     */
    
    /* ========================================================================== */
    /*                             Include Files                                  */
    /* ========================================================================== */
    
    #include <stdint.h>
    #include <string.h>
    #include <assert.h>
    
    #include <ti/osal/osal.h>
    #include <ti/osal/TaskP.h>
    #include <ti/osal/SemaphoreP.h>
    #include <ti/osal/ClockP.h>
    
    #include <ti/board/board.h>
    #include <ti/drv/pm/pmlib.h>
    #include <ti/drv/sciclient/sciclient.h>
    #include <ti/drv/enet/enet.h>
    #include <ti/drv/enet/enet_cfg.h>
    #include <ti/drv/enet/include/core/enet_dma.h>
    #include <ti/drv/enet/include/per/cpsw.h>
    
    #include <ti/drv/enet/examples/utils/include/enet_apputils.h>
    #include <ti/drv/enet/examples/utils/include/enet_apputils_rtos.h>
    #include <ti/drv/enet/examples/utils/include/enet_appmemutils.h>
    #include <ti/drv/enet/examples/utils/include/enet_appmemutils_cfg.h>
    #include <ti/drv/enet/examples/utils/include/enet_apputils_rtos.h>
    #include <ti/drv/enet/examples/utils/include/enet_board.h>
    
    #include "test_config.h"
    
    /* ========================================================================== */
    /*                           Macros & Typedefs                                */
    /* ========================================================================== */
    
    /* Loopback test iteration count */
    #ifndef SIM_BUILD
    #define ENETLPBK_NUM_ITERATION                     (5U)
    #else
    #define ENETLPBK_NUM_ITERATION                     (2U)
    #endif
    
    /* 100-ms periodic tick */
    #define ENETLPBK_PERIODIC_TICK_MS                  (100U)
    
    /* Task stack size */
    #if defined(SAFERTOS)
    #define ENETLPBK_TASK_STACK_SZ                     (16U * 1024U)
    #define ENETLPBK_TASK_STACK_ALIGN                  ENETLPBK_TASK_STACK_SZ
    #else
    #define ENETLPBK_TASK_STACK_SZ                     (10U * 1024U)
    #define ENETLPBK_TASK_STACK_ALIGN                  (32U)
    #endif
    
    #ifndef SIM_BUILD
    #define ENETLPBK_TEST_PKT_NUM                      (1000U)
    #else
    #define ENETLPBK_TEST_PKT_NUM                      (20U)
    #endif
    
    #define ENETLPBK_TEST_PKT_LEN                      (500U)
    
    #define ENETLPBK_SCATTER_GATHER_ENABLE_TX          (0U)//(1U)
    #define ENETLPBK_SCATTER_GATHER_ENABLE_RX          (0U)//(1U)
    
    /* ========================================================================== */
    /*                         Structure Declarations                             */
    /* ========================================================================== */
    
    typedef struct EnetLpbk_Obj_s
    {
        /* Enet driver */
        Enet_Handle hEnet;
        Enet_Type enetType;
        uint32_t instId;
        uint32_t coreId;
        uint32_t coreKey;
        uint32_t boardId;
        uint32_t expPort;
        Enet_MacPort macPort;
        emac_mode macMode;      /* MAC mode (defined in board library) */
    
        /* UDMA driver handle */
        Udma_DrvHandle hUdmaDrv;
        uint32_t rxFlowIdx;
        uint32_t rxStartFlowIdx;
        EnetDma_RxChHandle hRxCh;
        EnetDma_PktQ rxFreeQ;
        EnetDma_PktQ rxReadyQ;
        EnetDma_TxChHandle hTxCh;
        EnetDma_PktQ txFreePktInfoQ;
        uint32_t txChNum;
        uint8_t hostMacAddr[ENET_MAC_ADDR_LEN];
    
        /* Test config params */
        bool testExtLoopback;   /* TODO: replace testPhyLoopback as testLoopBackType (MAC, PHY and External) */
        bool testPhyLoopback;   /* PHY loopback or MAC loopback? */
        bool printFrame;        /* Print received Ethernet frames? */
    
        /* Test runtime params */
        volatile bool exitFlag; /* Exit test? */
    
    
        /* Periodic tick */
        ClockP_Handle hTickTimer;
        TaskP_Handle hTickTask;
        SemaphoreP_Handle hTimerSem;
    
        /* Packet transmission */
        TaskP_Handle hTxTask;
        TaskP_Handle hTxTaskCleanup;
        SemaphoreP_Handle hTxSem;
        SemaphoreP_Handle hTxDoneSem;
        uint32_t totalTxCnt;
    
        /* Packet reception */
        TaskP_Handle hRxTask;
        SemaphoreP_Handle hRxSem;
        SemaphoreP_Handle hRxDoneSem;
        uint32_t totalRxCnt;
    } EnetLpbk_Obj;
    
    /* ========================================================================== */
    /*                          Function Declarations                             */
    /* ========================================================================== */
    
    static void EnetLpbk_mainTask(void* a0, void* a1);
    
    static void EnetLpbk_createClock(void);
    
    static void EnetLpbk_deleteClock(void);
    
    static void EnetLpbk_timerCallback(void* arg);
    
    static void EnetLpbk_tickTask(void* a0, void* a1);
    
    static void EnetLpbk_txTask(void* a0, void* a1);
    
    static void EnetLpbk_txTaskCleanup(void* a0, void* a1);
    
    static void EnetLpbk_rxTask(void* a0, void* a1);
    
    static void EnetLpbk_createRxTxTasks(void);
    
    static void EnetLpbk_deleteRxTxTasks(void);
    
    static int32_t EnetLpbk_loopbackTest(void);
    
    static void EnetLpbk_initCpswCfg(Cpsw_Cfg *cpswCfg);
    
    static int32_t EnetLpbk_setupCpswAle(void);
    
    static int32_t EnetLpbk_openEnet(void);
    
    static void EnetLpbk_closeEnet(void);
    
    static int32_t EnetLpbk_showAlivePhys(void);
    
    static int32_t EnetLpbk_waitForLinkUp(void);
    
    static void EnetLpbk_showCpswStats(void);
    
    #if 0 //TODO - NEED TO BE PORTED
    static uint32_t EnetLpbk_getSystemHeapFreeSpace(void);
    #endif
    
    void EnetLpbk_waitForDebugger(void);
    
    int32_t EnetLpbk_openDma();
    
    void EnetLpbk_closeDma();
    
    Udma_DrvHandle EnetLpbkUtils_udmaOpen(Enet_Type enetType,
                                          Udma_InitPrms *pInitPrms);
    
    /* ========================================================================== */
    /*                            Global Variables                                */
    /* ========================================================================== */
    
    /* Enet loopback test object */
    EnetLpbk_Obj gEnetLpbk;
    
    /* Test application stack */
    static uint8_t gEnetLpbkTaskStackMain[ENETLPBK_TASK_STACK_SZ] __attribute__((aligned(ENETLPBK_TASK_STACK_ALIGN)));
    static uint8_t gEnetLpbkTaskStackTick[ENETLPBK_TASK_STACK_SZ] __attribute__((aligned( ENETLPBK_TASK_STACK_ALIGN)));
    static uint8_t gEnetLpbkTaskStackTx[ENETLPBK_TASK_STACK_SZ] __attribute__((aligned( ENETLPBK_TASK_STACK_ALIGN)));
    static uint8_t gEnetLpbkTaskStackTxCleanup[ENETLPBK_TASK_STACK_SZ] __attribute__((aligned( ENETLPBK_TASK_STACK_ALIGN)));
    static uint8_t gEnetLpbkTaskStackRx[ENETLPBK_TASK_STACK_SZ] __attribute__((aligned( ENETLPBK_TASK_STACK_ALIGN)));
    
    uint32_t txScatterSegments[] = 
    {
    
    #if (ENETLPBK_SCATTER_GATHER_ENABLE_TX != 1U)
        [0] = (ENETLPBK_TEST_PKT_LEN + sizeof(EthFrameHeader)),
    #else
        [0] = sizeof(EthFrameHeader),
        [1] = (ENETLPBK_TEST_PKT_LEN / 3),
        [2] = (ENETLPBK_TEST_PKT_LEN / 3),
        [3] = ((ENETLPBK_TEST_PKT_LEN / 3) + (ENETLPBK_TEST_PKT_LEN % 3)),
    #endif
    };
    
    uint32_t rxScatterSegments[] = 
    {
    
    #if (ENETLPBK_SCATTER_GATHER_ENABLE_RX != 1U)
        [0] = (ENETLPBK_TEST_PKT_LEN + sizeof(EthFrameHeader)),
    #else
        [0] = (ENETLPBK_TEST_PKT_LEN + sizeof(EthFrameHeader)),
        [1] = (ENETLPBK_TEST_PKT_LEN / 3),
        [2] = (ENETLPBK_TEST_PKT_LEN / 3),
        [3] = ((ENETLPBK_TEST_PKT_LEN / 3) + (ENETLPBK_TEST_PKT_LEN % 3) + 32),
    #endif
    };
    
    /* ========================================================================== */
    /*                          Function Definitions                              */
    /* ========================================================================== */
    
    int main(void)
    {
        TaskP_Handle hTask;
        TaskP_Params params;
    
        OS_init();
    
        /* Initialize loopback test config */
        memset(&gEnetLpbk, 0, sizeof(gEnetLpbk));
        gEnetLpbk.exitFlag = false;
    
        /* Initialize the main task params */
        TaskP_Params_init(&params);
        params.priority       = 2U;
        params.stack          = gEnetLpbkTaskStackMain;
        params.stacksize      = sizeof(gEnetLpbkTaskStackMain);
        params.name           = (const char *)"Loopback main task";
    
        hTask = TaskP_create(&EnetLpbk_mainTask, &params);
        if (hTask == NULL)
        {
            EnetAppUtils_print("main() failed to create main task\n");
            OS_stop();
        }
    
        /* Does not return */
        OS_start();
    
        return 0;
    }
    
    static void EnetLpbk_mainTask(void* a0,
                                  void* a1)
    {
    #if 0 //TODO - NEED TO BE PORTED
        uint32_t freeSize0, freeSize1;
    #endif
        uint32_t i;
        int32_t status;
    
        EnetBoard_init();
    
        EnetLpbk_getTestConfig(&gEnetLpbk.enetType,
                               &gEnetLpbk.instId,
                               &gEnetLpbk.testPhyLoopback,
                               &gEnetLpbk.macPort,
                               &gEnetLpbk.macMode,
                               &gEnetLpbk.boardId,
                               &gEnetLpbk.expPort);
    
        for (i = 0U; i < ENETLPBK_NUM_ITERATION; i++)
        {
    #if 0 //TODO - NEED TO BE PORTED
            freeSize0 = EnetLpbk_getSystemHeapFreeSpace();
    #endif
    
            /* Note: Clock create/delete must be done per iteration to account for
             * memory allocation (from heap) done in snprintf for code reentrancy.
             * Moving this out will result in heap memory leak error in external
             * loopback mode on A72. */
            EnetLpbk_createClock();
    
            EnetAppUtils_print("=============================\n");
            EnetAppUtils_print(" Enet Loopback: Iteration %u \n", i + 1);
            EnetAppUtils_print("=============================\n");
    
            /* Run the loopback test */
            status = EnetLpbk_loopbackTest();
    
            EnetLpbk_deleteClock();
    
    #if 0 //TODO - NEED TO BE PORTED
            freeSize1 = EnetLpbk_getSystemHeapFreeSpace();
    
            EnetAppUtils_assert(freeSize0 == freeSize1);
    #endif
            /* Sleep at end of each iteration to allow idle task to delete all terminated tasks */
            TaskP_sleep(1000);
        }
    
        if (status == ENET_SOK)
        {
            EnetAppUtils_print("All tests have passed\n");
        }
        else
        {
            EnetAppUtils_print("Loopback application failed to complete\n");
        }
    
        EnetBoard_deinit();
    }
    
    static void EnetLpbk_createClock(void)
    {
        TaskP_Params taskParams;
        SemaphoreP_Params semParams;
        ClockP_Params clkParams;
    
        /* Initialize timer semaphore params */
        SemaphoreP_Params_init(&semParams);
        semParams.mode = SemaphoreP_Mode_COUNTING;
    
        /* Create timer semaphore */
        gEnetLpbk.hTimerSem = SemaphoreP_create(0, &semParams);
    
        /* Reset the exitFlag */
        gEnetLpbk.exitFlag = false;
    
        /* Initialize the periodic tick task params */
        TaskP_Params_init(&taskParams);
        taskParams.priority       = 7U;
        taskParams.stack          = gEnetLpbkTaskStackTick;
        taskParams.stacksize      = sizeof(gEnetLpbkTaskStackTick);
        taskParams.arg0           = (void*)gEnetLpbk.hTimerSem;
        taskParams.name           = (const char *)"Periodic tick task";
    
        /* Create periodic tick task */
        gEnetLpbk.hTickTask = TaskP_create(&EnetLpbk_tickTask, &taskParams);
        if (gEnetLpbk.hTickTask == NULL)
        {
            EnetAppUtils_print("EnetLpbk_createClock() failed to create tick task\n");
            OS_stop();
        }
    
        ClockP_Params_init(&clkParams);
        clkParams.startMode = ClockP_StartMode_USER;
        clkParams.period    = ENETLPBK_PERIODIC_TICK_MS;
        clkParams.runMode   = ClockP_RunMode_CONTINUOUS;
        clkParams.arg       = (void*)gEnetLpbk.hTimerSem;
    
        /* Creating timer and setting timer callback function*/
        gEnetLpbk.hTickTimer = ClockP_create(EnetLpbk_timerCallback, &clkParams);
        if (gEnetLpbk.hTickTimer == NULL)
        {
            EnetAppUtils_print("EnetLpbk_createClock() failed to create clock\n");
            OS_stop();
        }
    }
    
    static void EnetLpbk_deleteClock(void)
    {
        gEnetLpbk.exitFlag = true;
    
        /* Delete periodic tick timer */
        if (gEnetLpbk.hTickTimer != NULL)
        {
            ClockP_delete(gEnetLpbk.hTickTimer);
            gEnetLpbk.hTickTimer = NULL;
        }
    
        /* Delete periodic tick task */
        if (gEnetLpbk.hTickTask != NULL)
        {
    #if !defined (FREERTOS)
            TaskP_delete(&gEnetLpbk.hTickTask);
    #endif
            gEnetLpbk.hTickTask = NULL;
        }
    
        /* Delete periodic tick timer */
        if (gEnetLpbk.hTimerSem != NULL)
        {
            SemaphoreP_delete(gEnetLpbk.hTimerSem);
            gEnetLpbk.hTimerSem = NULL;
        }
    }
    
    static void EnetLpbk_timerCallback(void* arg)
    {
        SemaphoreP_Handle hSem = (SemaphoreP_Handle)arg;
    
        /* Tick! */
        SemaphoreP_post(hSem);
    }
    
    static void EnetLpbk_tickTask(void* a0,
                                  void* a1)
    {
        SemaphoreP_Handle hSem = (SemaphoreP_Handle)a0;
    
        while (!gEnetLpbk.exitFlag)
        {
            SemaphoreP_pend(hSem, SemaphoreP_WAIT_FOREVER);
    
            /* PeriodicTick should be called from non-ISR context */
            Enet_periodicTick(gEnetLpbk.hEnet);
        }
        EnetAppUtils_print("EnetLpbk_tickTask() exiting..\n");
    }
    
    static void EnetLpbk_createRxTxTasks(void)
    {
        TaskP_Params params;
    
        TaskP_Params_init(&params);
        params.priority       = 2U;
        params.stack          = gEnetLpbkTaskStackTx;
        params.stacksize      = sizeof(gEnetLpbkTaskStackTx);
        params.name           = (const char *)"Tx Task";
    
        gEnetLpbk.hTxTask = TaskP_create(&EnetLpbk_txTask, &params);
        if (gEnetLpbk.hTxTask == NULL)
        {
            EnetAppUtils_print("EnetLpbk_createRxTxTasks() failed to create tx task\n");
            OS_stop();
        }
    
        TaskP_Params_init(&params);
        params.priority       = 3U;
        params.stack          = gEnetLpbkTaskStackRx;
        params.stacksize      = sizeof(gEnetLpbkTaskStackRx);
        params.name           = (const char *)"Rx Task";
    
        gEnetLpbk.hRxTask = TaskP_create(&EnetLpbk_rxTask, &params);
        if (gEnetLpbk.hRxTask == NULL)
        {
            EnetAppUtils_print("EnetLpbk_createRxTxTasks() failed to create rx task\n");
            OS_stop();
        }
    }
    
    static void EnetLpbk_deleteRxTxTasks(void)
    {
        if (gEnetLpbk.hTxTask != NULL)
        {
    #if !defined (FREERTOS)
            EnetAppUtils_assert(TaskP_isTerminated(gEnetLpbk.hTxTask) == 1);
            TaskP_delete(&gEnetLpbk.hTxTask);
    #endif
            gEnetLpbk.hTxTask = NULL;
        }
    
        if (gEnetLpbk.hRxTask != NULL)
        {
    #if !defined (FREERTOS)
            EnetAppUtils_assert(TaskP_isTerminated(gEnetLpbk.hRxTask) == 1);
            TaskP_delete(&gEnetLpbk.hRxTask);
    #endif
            gEnetLpbk.hRxTask = NULL;
        }
        EnetAppUtils_print("EnetLpbk_deleteRxTxTasks() done..\n");
    }
    
    
    uint32_t EnetLpbk_retrieveFreeTxPkts(void)
    {
        EnetDma_PktQ txFreeQ;
        EnetDma_Pkt *pktInfo;
        int32_t status;
        uint32_t txFreeQCnt = 0U;
    
        EnetQueue_initQ(&txFreeQ);
    
        /* Retrieve any CPSW packets that may be free now */
        status = EnetDma_retrieveTxPktQ(gEnetLpbk.hTxCh, &txFreeQ);
        if (status == ENET_SOK)
        {
            txFreeQCnt = EnetQueue_getQCount(&txFreeQ);
    
            pktInfo = (EnetDma_Pkt *)EnetQueue_deq(&txFreeQ);
            while (NULL != pktInfo)
            {
                EnetDma_checkPktState(&pktInfo->pktState,
                                        ENET_PKTSTATE_MODULE_APP,
                                        ENET_PKTSTATE_APP_WITH_DRIVER,
                                        ENET_PKTSTATE_APP_WITH_FREEQ);
    
                EnetQueue_enq(&gEnetLpbk.txFreePktInfoQ, &pktInfo->node);
                pktInfo = (EnetDma_Pkt *)EnetQueue_deq(&txFreeQ);
            }
        }
        else
        {
            EnetAppUtils_print("retrieveFreeTxPkts() failed to retrieve pkts: %d\n",
                               status);
        }
    
        return txFreeQCnt;
    }
    
    void EnableCCNT(void)
    {
        /* Make CCNT accessible from usermode */
        __asm__ volatile ("mcr p15, 0, %0, c9, c14, 0"::"r"(1));
        /* Disable counter flow interrupt */
        __asm__ volatile ("mcr p15, 0, %0, c9, c14, 2"::"r"(0x8000000f));
        /* Initialize CCNT */
        __asm__ volatile ("mcr p15, 0, %0, c9, c12, 0"::"r"(5));
        /* Start CCNT */
        __asm__ volatile ("mcr p15, 0, %0, c9, c12, 1"::"r"(0x80000000));
    }
    
    /***************************************************************************************************/
    /**
    @brief  OsMeasGetCounterTicks
    
    @return the current TSC count [EC_T_UINT64]
    */
    typedef unsigned int    EC_T_DWORD;     /**< Double word, unsigned integer 32 bit */
    typedef unsigned long long  EC_T_UINT64;
    typedef signed long long    EC_T_INT64;
    #define EC_MAKEQWORD(hi, lo)    ((EC_T_UINT64)(((EC_T_DWORD)(lo)) | ((EC_T_UINT64)((EC_T_DWORD)(hi))) << 32))
    #define EC_LODWORD(qw)          ((EC_T_DWORD)((EC_T_UINT64)(qw) & 0xFFFFFFFF))
    #define EC_HIDWORD(qw)          ((EC_T_DWORD)(((EC_T_UINT64)(qw) >> 32) & 0xFFFFFFFF))
    
    EC_T_UINT64 OsMeasGetCounterTicks(void)
    {
    
        static EC_T_DWORD dwLastCount   = 0;
        static EC_T_DWORD dwCountHi     = 0;
        EC_T_DWORD dwCountLo    = 0;
    
        __asm__ volatile ("mrc p15, 0, %0, c9, c13, 0" : "=r" (dwCountLo));
    
        if (dwLastCount > dwCountLo) dwCountHi++;
    
        dwLastCount = dwCountLo;
        //EnetAppUtils_print("%x\n", dwCountLo);
        return EC_MAKEQWORD(dwCountHi, dwCountLo);
    }
    
    void TrackTimeSegments(unsigned long long data[3], unsigned long long qwTime)
    {
        if (data[2] < qwTime)
        {
            data[2] = qwTime;
        }
        data[1] = ((data[1]*99 + qwTime)/100);
    }
    
    void ResetTrackTimeSegments(unsigned long long data[3])
    {
        data[0] = 9999;
        data[1] = 0;
        data[2] = 0;
    }
    
    void PrintTrackedTimeSegments(unsigned long long data[3], unsigned long long dwFactor, char * szName )
    {
        EnetAppUtils_print("%s: avg: %04d, max %04d\n", szName, (unsigned int)(data[1]/dwFactor), (unsigned int)(data[2]/dwFactor));
    }
    
    
    static void EnetLpbk_txTaskCleanup(void* a0,
                                void* a1)
    {
        uint32_t txRetrievePktCnt = 0;
    
        uint32_t *pdwTxRetrieveTotal = (uint32_t *)a1;
        MutexP_Handle mutexHandle = (MutexP_Handle)a0;
    
        while (1)
        {
            SemaphoreP_pend(gEnetLpbk.hTxSem, SemaphoreP_WAIT_FOREVER);
    
            /* Retrieve TX free packets */
            txRetrievePktCnt = EnetLpbk_retrieveFreeTxPkts();
    
            MutexP_lock(mutexHandle, MutexP_WAIT_FOREVER);
            *pdwTxRetrieveTotal = *pdwTxRetrieveTotal + txRetrievePktCnt;
            MutexP_unlock(mutexHandle);
        }
    }
    
    static void EnetLpbk_txTask(void* a0,
                                void* a1)
    {
        EnetDma_PktQ txSubmitQ;
        EnetDma_Pkt *pktInfo;
        EthFrame *frame;
        uint32_t txRetrievePktCnt;
        uint32_t loopCnt, pktCnt;
        int32_t status = ENET_SOK;
        uint8_t bcastAddr[ENET_MAC_ADDR_LEN] = {0xffU, 0xffU, 0xffU, 0xffU, 0xffU, 0xffU};
    
        /* time measurement */
        EC_T_UINT64 qwLastTick = 0;
        uint32_t dwTicks1u = 0;
        uint32_t dwCnt100us = 0;
        uint32_t dwCnt1000us = 0;
        uint32_t dwCnt1500us = 0;
        uint32_t dwCnt5000us = 0;
        EC_T_UINT64 qwTickPoint1 = 0;
        EC_T_UINT64 qwTickPoint2 = 0;
        EC_T_UINT64 qwTickPoint3 = 0;
    
        unsigned long long aSegmentAll[3];
        unsigned long long aSegment1[3];
        unsigned long long aSegment2[3];
        unsigned long long aSegment3[3];
        unsigned long long aSegment4[3];
    
        /* thread communication */
        uint32_t dwTxRetrieveTotal = 0;
        MutexP_Object mutexObj;
        MutexP_Handle mutexHandle;
        mutexHandle = MutexP_create(&mutexObj);
        uint32_t dwCntTxRetrieveDelayed = 0;
    
    
        /* calibration */
        EnableCCNT();
        qwLastTick = OsMeasGetCounterTicks();
        {
            EC_T_UINT64 qwTick = 0;
            EnetAppUtils_wait(1);
            qwTick = OsMeasGetCounterTicks();
            dwTicks1u = (qwTick - qwLastTick)/1000;
        }
    
        /* start cleanup task */
        {
            TaskP_Params params;
    
            TaskP_Params_init(&params);
            params.priority       =3U;
            params.stack          = gEnetLpbkTaskStackTxCleanup;
            params.stacksize      = sizeof(gEnetLpbkTaskStackTxCleanup);
            params.name           = (const char *)"Tx Task Cleanup";
            params.arg0           = mutexHandle;
            params.arg1           = &dwTxRetrieveTotal;
    
            gEnetLpbk.hTxTaskCleanup = TaskP_create(&EnetLpbk_txTaskCleanup, &params);
            if (gEnetLpbk.hTxTaskCleanup == NULL)
            {
                EnetAppUtils_print("EnetLpbk_createRxTxTasks() failed to create tx task Cleanup\n");
                OS_stop();
            }
        }
    
    
        gEnetLpbk.totalTxCnt = 0U;
        for (loopCnt = 0U; loopCnt < ENETLPBK_NUM_ITERATION; loopCnt++)
        {
            qwLastTick = OsMeasGetCounterTicks();
            dwCnt100us = 0;
            dwCnt1000us = 0;
            dwCnt1500us = 0;
            dwCnt5000us = 0;
            ResetTrackTimeSegments(aSegmentAll);
            ResetTrackTimeSegments(aSegment1);
            ResetTrackTimeSegments(aSegment2);
            ResetTrackTimeSegments(aSegment3);
            ResetTrackTimeSegments(aSegment4);
            dwCntTxRetrieveDelayed = 0;
            MutexP_lock(mutexHandle, MutexP_WAIT_FOREVER);
            dwTxRetrieveTotal = 0;
            MutexP_unlock(mutexHandle);
    
            pktCnt = 0U;
            while (pktCnt < 10*1000*1000 )
            {
                /* Transmit a single packet */
                EnetQueue_initQ(&txSubmitQ);
    
                /* Dequeue one free TX Eth packet */
                pktInfo = (EnetDma_Pkt *)EnetQueue_deq(&gEnetLpbk.txFreePktInfoQ);
    
                while (NULL != pktInfo)
                {
                    pktCnt++;
    
                    /* Fill the TX Eth frame with test content */
                    frame = (EthFrame *)pktInfo->sgList.list[0U].bufPtr;
                    memcpy(frame->hdr.dstMac, bcastAddr, ENET_MAC_ADDR_LEN);
                    memcpy(frame->hdr.srcMac, &gEnetLpbk.hostMacAddr[0U], ENET_MAC_ADDR_LEN);
                    frame->hdr.etherType = Enet_htons(ETHERTYPE_EXPERIMENTAL1);
                    if (pktInfo->sgList.numScatterSegments == 1)
                    {
                        EnetAppUtils_assert(pktInfo->sgList.list[0U].segmentAllocLen >= (ENETLPBK_TEST_PKT_LEN + sizeof(EthFrameHeader)));
                        memset(&frame->payload[0U], (uint8_t)(0xA5 + pktCnt), ENETLPBK_TEST_PKT_LEN);
                        pktInfo->sgList.list[0U].segmentFilledLen = sizeof(EthFrameHeader) + ENETLPBK_TEST_PKT_LEN;
                    }
                    else
                    {
                        uint32_t segmentFillLength;
                        uint32_t i;
                        uint32_t payloadSegmentLen;
                        uint32_t payloadRemainLength;
    
                        EnetAppUtils_assert(pktInfo->sgList.numScatterSegments > 1);
                        segmentFillLength = (ENETLPBK_TEST_PKT_LEN / (pktInfo->sgList.numScatterSegments - 1));
    
                        pktInfo->sgList.list[0U].segmentFilledLen = sizeof(EthFrameHeader);
                        payloadRemainLength = ENETLPBK_TEST_PKT_LEN;
                        for (i = 1; i < pktInfo->sgList.numScatterSegments; i++)
                        {
                            payloadSegmentLen = EnetUtils_min(segmentFillLength, pktInfo->sgList.list[i].segmentAllocLen);
                            memset(pktInfo->sgList.list[i].bufPtr,
                                   (uint8_t)(0xA5 + pktCnt),
                                   payloadSegmentLen);
                            pktInfo->sgList.list[i].segmentFilledLen = payloadSegmentLen;
                            payloadRemainLength -= payloadSegmentLen;
                        }
                        if (payloadRemainLength)
                        {
                            uint32_t lastSegmentIndex = pktInfo->sgList.numScatterSegments - 1;
                            uint32_t lastSegmentBufOffset = pktInfo->sgList.list[lastSegmentIndex].segmentFilledLen;
    
                            EnetAppUtils_assert(pktInfo->sgList.list[lastSegmentIndex].segmentAllocLen >= (lastSegmentBufOffset + payloadRemainLength));
                            memset(&pktInfo->sgList.list[lastSegmentIndex].bufPtr[lastSegmentBufOffset], (uint8_t)(0xA5 + pktCnt), payloadRemainLength);
                            pktInfo->sgList.list[lastSegmentIndex].segmentFilledLen += payloadRemainLength;
                        }
                    }
                    qwTickPoint1 = OsMeasGetCounterTicks();
                    pktInfo->appPriv    = &gEnetLpbk;
                    pktInfo->chkSumInfo = 0U;
                    pktInfo->txPortNum  = ENET_MAC_PORT_INV;
                    pktInfo->tsInfo.enableHostTxTs = false;
                    EnetDma_checkPktState(&pktInfo->pktState,
                                            ENET_PKTSTATE_MODULE_APP,
                                            ENET_PKTSTATE_APP_WITH_FREEQ,
                                            ENET_PKTSTATE_APP_WITH_DRIVER);
    
                    /* Enqueue the packet for later transmission */
                    EnetQueue_enq(&txSubmitQ, &pktInfo->node);
    
    
                    /* only one frame! */
                    //if (pktCnt >= ENETLPBK_TEST_PKT_NUM)
                    {
                        break;
                    }
    
                    /* Dequeue one free TX Eth packet */
                    pktInfo = (EnetDma_Pkt *)EnetQueue_deq(&gEnetLpbk.txFreePktInfoQ);
                }
                qwTickPoint2 = OsMeasGetCounterTicks();
    
                if (0U != EnetQueue_getQCount(&txSubmitQ))
                {
                    uint32_t txCnt = EnetQueue_getQCount(&txSubmitQ);
                    status = EnetDma_submitTxPktQ(gEnetLpbk.hTxCh,
                                                       &txSubmitQ);
    
                    qwTickPoint3 = OsMeasGetCounterTicks();
                    EnetAppUtils_wait(1);
    
                    /* retrieve in thread */
    
                    MutexP_lock(mutexHandle, MutexP_WAIT_FOREVER);
                    if (dwTxRetrieveTotal < pktCnt)
                        dwCntTxRetrieveDelayed ++;
                    MutexP_unlock(mutexHandle);
                }
    
                /* track time measurements */
                {
                    EC_T_UINT64 qwTick = OsMeasGetCounterTicks();
                    EC_T_UINT64 qwTickDiff = qwTick - qwLastTick;
                    {
                        if(qwTickDiff/dwTicks1u > 5000)
                            dwCnt5000us++;
                        else if(qwTickDiff/dwTicks1u > 1500)
                            dwCnt1500us++;
                        else if(qwTickDiff/dwTicks1u > 1000)
                            dwCnt1000us++;
                        else if(qwTickDiff/dwTicks1u > 100)
                            dwCnt100us++;
    
                        TrackTimeSegments(aSegmentAll, qwTickDiff);
                        TrackTimeSegments(aSegment1, (qwTickPoint1 - qwLastTick));
                        TrackTimeSegments(aSegment2, (qwTickPoint2 - qwTickPoint1));
                        TrackTimeSegments(aSegment3, (qwTickPoint3 - qwTickPoint2));
                        TrackTimeSegments(aSegment4, (qwTick       - qwTickPoint3));
                    }
                    qwLastTick = (qwTick);
              }
            }
    
            gEnetLpbk.totalTxCnt += pktCnt;
    
            /* print time measurements per iteration */
            EnetAppUtils_print("\nTime %d s, Frames %d \n", (uint32_t)(qwLastTick/dwTicks1u/1000/1000), gEnetLpbk.totalTxCnt);
            EnetAppUtils_print("times more than; 100us %d; 1000us %d; 1500us %d; 5000us %d; \n", dwCnt100us, dwCnt1000us, dwCnt1500us, dwCnt5000us);
            MutexP_lock(mutexHandle, MutexP_WAIT_FOREVER);
            EnetAppUtils_print("dwCntTxRetrieveDelayed %d; dwTxRetrieveTotal %d; pktCnt %d;\n", dwCntTxRetrieveDelayed, dwTxRetrieveTotal, pktCnt);
            MutexP_unlock(mutexHandle);
            PrintTrackedTimeSegments(aSegmentAll, dwTicks1u, "all        in us" );
            PrintTrackedTimeSegments(aSegment1, dwTicks1u,   "prepare1   in us" );
            PrintTrackedTimeSegments(aSegment2, dwTicks1u,   "prepare2   in us" );
            PrintTrackedTimeSegments(aSegment3, dwTicks1u,   "send       in us" );
            PrintTrackedTimeSegments(aSegment4, dwTicks1u,   "wait       in us" );
        }
    
        EnetAppUtils_print("Transmitted %d packets \n", gEnetLpbk.totalTxCnt);
        MutexP_delete(mutexHandle);
        SemaphoreP_post(gEnetLpbk.hTxDoneSem);
    }
    
    uint32_t EnetLpbk_receivePkts(void)
    {
        EnetDma_PktQ rxReadyQ;
        EnetDma_Pkt *pktInfo;
        int32_t status;
        uint32_t rxReadyCnt = 0U;
    
        EnetQueue_initQ(&rxReadyQ);
    
        /* Retrieve any CPSW packets which are ready */
        status = EnetDma_retrieveRxPktQ(gEnetLpbk.hRxCh, &rxReadyQ);
        if (status == ENET_SOK)
        {
            rxReadyCnt = EnetQueue_getQCount(&rxReadyQ);
    
            /* Queue the received packet to rxReadyQ and pass new ones from rxFreeQ
            **/
            pktInfo = (EnetDma_Pkt *)EnetQueue_deq(&rxReadyQ);
            while (pktInfo != NULL)
            {
                EnetDma_checkPktState(&pktInfo->pktState,
                                        ENET_PKTSTATE_MODULE_APP,
                                        ENET_PKTSTATE_APP_WITH_DRIVER,
                                        ENET_PKTSTATE_APP_WITH_READYQ);
    
                EnetQueue_enq(&gEnetLpbk.rxReadyQ, &pktInfo->node);
                pktInfo = (EnetDma_Pkt *)EnetQueue_deq(&rxReadyQ);
            }
        }
        else
        {
            EnetAppUtils_print("receivePkts() failed to retrieve pkts: %d\n",
                               status);
        }
    
        return rxReadyCnt;
    }
    
    static bool EnetLpbk_verifyRxFrame(EnetDma_Pkt *pktInfo, uint8_t rxCnt)
    {
        uint8_t *rxPayload;
        EthFrame *rxframe;
        uint8_t verifyRxpkt = 0xA5+rxCnt;
        bool retval = false;
        uint32_t i,j;
        uint32_t segmentLen, headerLen;
        bool incorrectPayload = false;
    
        rxframe = (EthFrame *)pktInfo->sgList.list[0U].bufPtr;
        rxPayload = rxframe->payload;
    
        if (pktInfo->sgList.numScatterSegments == 1)
        {
            for (i = 0; i < ENETLPBK_TEST_PKT_LEN; i++)
            {
                if((rxPayload[i] != verifyRxpkt))
                {
                    retval = false;
                    break;
                }
                retval = true;
            }
        }
        else
        {
            headerLen = rxPayload - pktInfo->sgList.list[0U].bufPtr;
            for (i = 0; i < pktInfo->sgList.numScatterSegments; i++)
            {
                segmentLen = pktInfo->sgList.list[i].segmentFilledLen;
                if(i == 0)
                {
                    segmentLen -= headerLen;
                }
                else
                {
                    rxPayload = pktInfo->sgList.list[i].bufPtr;
                }
                for (j = 0; j < segmentLen; j++)
                {
                    if((rxPayload[j] != verifyRxpkt))
                    {
                        retval = false;
                        incorrectPayload = true;
                        break;
                    }
                    retval = true;
                }
                if(incorrectPayload == true)
                {
                    break;
                }
            }
        }
    
        return retval;
    }
    
    static void EnetLpbk_rxTask(void* a0,
                                void* a1)
    {
        EnetDma_Pkt *pktInfo;
        uint32_t rxReadyCnt;
        uint32_t loopCnt, loopRxPktCnt;
        uint32_t i;
        uint8_t *payload;
        uint32_t len;
        int32_t status = ENET_SOK;
        uint32_t rxPktCnt;
    
        gEnetLpbk.totalRxCnt = 0U;
    
        for (loopCnt = 0U; loopCnt < ENETLPBK_NUM_ITERATION; loopCnt++)
        {
            loopRxPktCnt = 0U;
            rxPktCnt = 0;
            /* Wait for packet reception */
            do
            {
                SemaphoreP_pend(gEnetLpbk.hRxSem, SemaphoreP_WAIT_FOREVER);
                /* Get the packets received so far */
                rxReadyCnt = EnetLpbk_receivePkts();
                if (rxReadyCnt > 0U)
                {
                    /* Consume the received packets and release them */
                    pktInfo = (EnetDma_Pkt *)EnetQueue_deq(&gEnetLpbk.rxReadyQ);
                    while (NULL != pktInfo)
                    {
                        rxPktCnt++;
                        EnetDma_checkPktState(&pktInfo->pktState,
                                                ENET_PKTSTATE_MODULE_APP,
                                                ENET_PKTSTATE_APP_WITH_READYQ,
                                                ENET_PKTSTATE_APP_WITH_FREEQ);
    
                        /* Consume the packet by just printing its content */
                        if (gEnetLpbk.printFrame)
                        {
                            EnetAppUtils_printSGFrame(pktInfo);
                        }
                        //EnetAppUtils_assert(EnetLpbk_verifyRxFrame(pktInfo, rxPktCnt) == true);
                        /* Release the received packet */
                        EnetQueue_enq(&gEnetLpbk.rxFreeQ, &pktInfo->node);
                        pktInfo = (EnetDma_Pkt *)EnetQueue_deq(&gEnetLpbk.rxReadyQ);
                    }
    
                    /*Submit now processed buffers */
                    if (status == ENET_SOK)
                    {
                        EnetAppUtils_validatePacketState(&gEnetLpbk.rxFreeQ,
                                                         ENET_PKTSTATE_APP_WITH_FREEQ,
                                                         ENET_PKTSTATE_APP_WITH_DRIVER);
    
                        EnetDma_submitRxPktQ(gEnetLpbk.hRxCh,
                                             &gEnetLpbk.rxFreeQ);
                    }
                }
    
                loopRxPktCnt += rxReadyCnt;
            }
            while (loopRxPktCnt < ENETLPBK_TEST_PKT_NUM);
    
            gEnetLpbk.totalRxCnt += loopRxPktCnt;
        }
    
        if (status != ENET_SOK)
        {
            EnetAppUtils_print("Failed to transmit/receive packets: %d, transmitted: %d \n", ENETLPBK_TEST_PKT_NUM, gEnetLpbk.totalRxCnt);
        }
        else
        {
            EnetAppUtils_print("Received %d packets\n", gEnetLpbk.totalRxCnt);
        }
    
        SemaphoreP_post(gEnetLpbk.hRxDoneSem);
    }
    
    static int32_t EnetLpbk_loopbackTest(void)
    {
        EnetOsal_Cfg osalCfg;
        EnetUtils_Cfg utilsCfg;
        Enet_IoctlPrms prms;
        SemaphoreP_Params params;
        int32_t status;
    
        EnetAppUtils_enableClocks(gEnetLpbk.enetType, gEnetLpbk.instId);
    
        /* Create TX/RX semaphores */
        SemaphoreP_Params_init(&params);
        params.mode = SemaphoreP_Mode_BINARY;
    
        gEnetLpbk.hRxSem = SemaphoreP_create(0, &params);
        EnetAppUtils_assert(gEnetLpbk.hRxSem != NULL);
    
        gEnetLpbk.hTxSem = SemaphoreP_create(0, &params);
        EnetAppUtils_assert(gEnetLpbk.hTxSem != NULL);
    
        gEnetLpbk.hTxDoneSem = SemaphoreP_create(0, &params);
        EnetAppUtils_assert(gEnetLpbk.hTxDoneSem != NULL);
    
        gEnetLpbk.hRxDoneSem = SemaphoreP_create(0, &params);
        EnetAppUtils_assert(gEnetLpbk.hRxDoneSem != NULL);
    
        /* Local core id */
        gEnetLpbk.coreId = EnetSoc_getCoreId();
    
        /* Initialize Enet driver (use default OSAL and utils) */
        Enet_initOsalCfg(&osalCfg);
        Enet_initUtilsCfg(&utilsCfg);
        Enet_init(&osalCfg, &utilsCfg);
    
        /* Open Enet driver */
        status = EnetLpbk_openEnet();
        if (status != ENET_SOK)
        {
            EnetAppUtils_print("Failed to open Enet driver: %d\n", status);
        }
    
        if (status == ENET_SOK)
        {
            /* Attach the core with RM */
            uint32_t coreId;
            EnetPer_AttachCoreOutArgs attachCoreOutArgs;
            coreId = gEnetLpbk.coreId;
    
            ENET_IOCTL_SET_INOUT_ARGS(&prms, &coreId, &attachCoreOutArgs);
            status = Enet_ioctl(gEnetLpbk.hEnet, gEnetLpbk.coreId, ENET_PER_IOCTL_ATTACH_CORE, &prms);
            if (status != ENET_SOK)
            {
                EnetAppUtils_print("EnetLpbk_loopbackTest failed ENET_PER_IOCTL_ATTACH_CORE: %d\n", status);
            }
            else
            {
                gEnetLpbk.coreKey = attachCoreOutArgs.coreKey;
            }
        }
    
        if (status == ENET_SOK)
        {
            /* memutils open should happen after Cpsw is opened as it uses CpswUtils_Q
             * functions */
            status = EnetMem_init();
            EnetAppUtils_assert(ENET_SOK == status);
        }
    
        /* Open DMA driver */
        if (status == ENET_SOK)
        {
            status = EnetLpbk_openDma();
            if (status != ENET_SOK)
            {
                EnetAppUtils_print("Failed to open DMA: %d\n", status);
            }
        }
    
        /* Enable host port */
        if (status == ENET_SOK)
        {
            if (Enet_isCpswFamily(gEnetLpbk.enetType))
            {
                status = EnetLpbk_setupCpswAle();
                if (status != ENET_SOK)
                {
                    EnetAppUtils_print("Failed to setup CPSW ALE: %d\n", status);
                }
            }
    
            if (status == ENET_SOK)
            {
                ENET_IOCTL_SET_NO_ARGS(&prms);
                status = Enet_ioctl(gEnetLpbk.hEnet, gEnetLpbk.coreId, ENET_HOSTPORT_IOCTL_ENABLE, &prms);
                if (status != ENET_SOK)
                {
                    EnetAppUtils_print("Failed to enable host port: %d\n", status);
                }
            }
        }
    
        /* Show alive PHYs */
        if (status == ENET_SOK)
        {
            status = EnetLpbk_showAlivePhys();
        }
    
        /* Start timer */
        ClockP_start(gEnetLpbk.hTickTimer);
    
        /* Wait for link up */
        if ((status == ENET_SOK) && gEnetLpbk.testPhyLoopback)
        {
            status = EnetLpbk_waitForLinkUp();
        }
    
        /* Do packet transmission and reception */
        if (status == ENET_SOK)
        {
            EnetLpbk_createRxTxTasks();
    
            SemaphoreP_pend(gEnetLpbk.hTxDoneSem, SemaphoreP_WAIT_FOREVER);
            SemaphoreP_pend(gEnetLpbk.hRxDoneSem, SemaphoreP_WAIT_FOREVER);
        }
    
        /* Print network statistics */
        if (status == ENET_SOK)
        {
            if (Enet_isCpswFamily(gEnetLpbk.enetType))
            {
                EnetLpbk_showCpswStats();
            }
        }
    
        /* Disable host port */
        if (status == ENET_SOK)
        {
            ENET_IOCTL_SET_NO_ARGS(&prms);
            status = Enet_ioctl(gEnetLpbk.hEnet, gEnetLpbk.coreId, ENET_HOSTPORT_IOCTL_DISABLE, &prms);
            if (status != ENET_SOK)
            {
                EnetAppUtils_print("Failed to disable host port: %d\n", status);
            }
        }
    
        /* Stop periodic tick timer */
        ClockP_stop(gEnetLpbk.hTickTimer);
    
        /* Print DMA statistics */
        if (status == ENET_SOK)
        {
            EnetAppUtils_showRxChStats(gEnetLpbk.hRxCh);
            EnetAppUtils_showTxChStats(gEnetLpbk.hTxCh);
        }
    
        /* Show stack usage statistics */
        if (status == ENET_SOK)
        {
            EnetAppUtils_printTaskStackUsage();
        }
    
        /* Close Enet DMA driver */
        EnetLpbk_closeDma();
    
        /* Close Enet driver */
        EnetLpbk_closeEnet();
    
        /* Disable peripheral clocks */
        EnetAppUtils_disableClocks(gEnetLpbk.enetType, gEnetLpbk.instId);
    
        /* Delete RX and TX tasks */
        EnetLpbk_deleteRxTxTasks();
    
        /* Deinit Enet driver */
        Enet_deinit();
    
        /* Delete all TX/RX semaphores */
        SemaphoreP_delete(gEnetLpbk.hRxDoneSem);
        gEnetLpbk.hRxDoneSem = NULL;
        SemaphoreP_delete(gEnetLpbk.hTxDoneSem);
        gEnetLpbk.hTxDoneSem = NULL;
        SemaphoreP_delete(gEnetLpbk.hTxSem);
        gEnetLpbk.hTxSem = NULL;
        SemaphoreP_delete(gEnetLpbk.hRxSem);
        gEnetLpbk.hRxSem = NULL;
    
        EnetAppUtils_print("Test complete: %s\n", (status == ENET_SOK) ? "PASS" : "FAIL");
    
        return status;
    }
    
    static void EnetLpbk_initCpswCfg(Cpsw_Cfg *cpswCfg)
    {
        CpswHostPort_Cfg *hostPortCfg = &cpswCfg->hostPortCfg;
        CpswAle_Cfg *aleCfg = &cpswCfg->aleCfg;
        CpswCpts_Cfg *cptsCfg = &cpswCfg->cptsCfg;
    
        /* Set initial config */
        Enet_initCfg(gEnetLpbk.enetType, gEnetLpbk.instId, cpswCfg, sizeof(*cpswCfg));
    
        /* Peripheral config */
        cpswCfg->vlanCfg.vlanAware = false;
    
        /* Host port config */
        hostPortCfg->removeCrc      = true;
        hostPortCfg->padShortPacket = true;
        hostPortCfg->passCrcErrors  = true;
    
        /* ALE config */
        aleCfg->modeFlags                          = CPSW_ALE_CFG_MODULE_EN;
        aleCfg->agingCfg.autoAgingEn               = true;
        aleCfg->agingCfg.agingPeriodInMs           = 1000;
        aleCfg->nwSecCfg.vid0ModeEn                = true;
        aleCfg->vlanCfg.aleVlanAwareMode           = false;
        aleCfg->vlanCfg.cpswVlanAwareMode          = false;
        aleCfg->vlanCfg.unknownUnregMcastFloodMask = CPSW_ALE_ALL_PORTS_MASK;
        aleCfg->vlanCfg.unknownRegMcastFloodMask   = CPSW_ALE_ALL_PORTS_MASK;
        aleCfg->vlanCfg.unknownVlanMemberListMask  = CPSW_ALE_ALL_PORTS_MASK;
    
        /* CPTS config */
        /* Note: Timestamping and MAC loopback are not supported together because of
         * IP limitation, so disabling timestamping for this application */
        cptsCfg->hostRxTsEn = false;
    
        EnetAppUtils_initResourceConfig(gEnetLpbk.enetType, gEnetLpbk.instId, gEnetLpbk.coreId, &cpswCfg->resCfg);
    }
    
    static int32_t EnetLpbk_setupCpswAle(void)
    {
        Enet_IoctlPrms prms;
        CpswAle_SetPortStateInArgs setPortStateInArgs;
        CpswAle_SetUcastEntryInArgs setUcastInArgs;
        uint32_t entryIdx;
        int32_t status;
    
        /* ALE entry with "secure" bit cleared is required for loopback */
        setUcastInArgs.addr.vlanId  = 0U;
        setUcastInArgs.info.portNum = CPSW_ALE_HOST_PORT_NUM;
        setUcastInArgs.info.blocked = false;
        setUcastInArgs.info.secure  = false;
        setUcastInArgs.info.super   = false;
        setUcastInArgs.info.ageable = false;
        setUcastInArgs.info.trunk   = false;
        EnetUtils_copyMacAddr(&setUcastInArgs.addr.addr[0U], gEnetLpbk.hostMacAddr);
        ENET_IOCTL_SET_INOUT_ARGS(&prms, &setUcastInArgs, &entryIdx);
    
        status = Enet_ioctl(gEnetLpbk.hEnet, gEnetLpbk.coreId, CPSW_ALE_IOCTL_ADD_UCAST, &prms);
        if (status != ENET_SOK)
        {
            EnetAppUtils_print("Failed to add ucast entry: %d\n", status);
        }
    
        /* Set host port to 'forwarding' state */
        if (status == ENET_SOK)
        {
            setPortStateInArgs.portNum   = CPSW_ALE_HOST_PORT_NUM;
            setPortStateInArgs.portState = CPSW_ALE_PORTSTATE_FORWARD;
            ENET_IOCTL_SET_IN_ARGS(&prms, &setPortStateInArgs);
    
            status = Enet_ioctl(gEnetLpbk.hEnet, gEnetLpbk.coreId, CPSW_ALE_IOCTL_SET_PORT_STATE, &prms);
            if (status != ENET_SOK)
            {
                EnetAppUtils_print("Failed to set ALE port state: %d\n", status);
            }
        }
    
        return status;
    }
    
    static int32_t EnetLpbk_openEnet(void)
    {
        Cpsw_Cfg cpswCfg;
        EnetUdma_Cfg dmaCfg;
        Enet_IoctlPrms prms;
        EnetPer_PortLinkCfg portLinkCfg;
        CpswMacPort_Cfg macCfg;
        int32_t status = ENET_SOK;
    
        cpswCfg.dmaCfg = &dmaCfg;
    
        /* Initialize peripheral config */
        EnetLpbk_initCpswCfg(&cpswCfg);
    
        if (gEnetLpbk.enetType == ENET_CPSW_9G)
        {
            EnetAppUtils_print("CPSW_9G Test on MAIN NAVSS\n");
        }
        else if (gEnetLpbk.enetType == ENET_CPSW_5G)
        {
            EnetAppUtils_print("CPSW_5G Test on MAIN NAVSS\n");
        }
        else if (gEnetLpbk.enetType == ENET_CPSW_2G)
        {
            if (gEnetLpbk.instId == 0)
            {
                EnetAppUtils_print("CPSW_2G Test on MCU NAVSS\n");
            }
            else if (gEnetLpbk.instId == 1)
            {
                EnetAppUtils_print("CPSW_2G Test on MAIN NAVSS\n");
            }
        }
    
        dmaCfg.rxChInitPrms.dmaPriority = UDMA_DEFAULT_RX_CH_DMA_PRIORITY;
    
        /* App should open UDMA first as UDMA handle is needed to initialize
         * CPSW RX channel */
        gEnetLpbk.hUdmaDrv = EnetAppUtils_udmaOpen(gEnetLpbk.enetType, NULL);
        EnetAppUtils_assert(NULL != gEnetLpbk.hUdmaDrv);
    
        dmaCfg.hUdmaDrv = gEnetLpbk.hUdmaDrv;
    
        /* Set Enet global runtime log level */
        Enet_setTraceLevel(ENET_TRACE_DEBUG);
    
        /* Open the Enet driver */
        gEnetLpbk.hEnet = Enet_open(gEnetLpbk.enetType, gEnetLpbk.instId, &cpswCfg, sizeof(cpswCfg));
        if (gEnetLpbk.hEnet == NULL)
        {
            EnetAppUtils_print("Failed to open Enet driver\n");
            status = ENET_EFAIL;
        }
    
        /* Setup port link open parameters */
        if (status == ENET_SOK)
        {
            EnetBoard_EthPort ethPort;
            EnetMacPort_LinkCfg *linkCfg = &portLinkCfg.linkCfg;
            EnetMacPort_Interface *mii = &portLinkCfg.mii;
            EnetPhy_Cfg *phyCfg = &portLinkCfg.phyCfg;
            EnetPhy_Mii phyMii;
    
            /* Setup board for requested Ethernet port */
            ethPort.macPort  = gEnetLpbk.macPort;
            ethPort.boardId  = gEnetLpbk.boardId;
            ethPort.expPort  = gEnetLpbk.expPort;
            EnetLpbk_macMode2MacMii(gEnetLpbk.macMode, &ethPort.mii);
    
            status = EnetBoard_setupPorts(gEnetLpbk.enetType, gEnetLpbk.instId, &ethPort, 1U);
            EnetAppUtils_assert(status == ENET_SOK);
    
            /* Set port link params */
            portLinkCfg.macPort = gEnetLpbk.macPort;
            portLinkCfg.macCfg = &macCfg;
    
            CpswMacPort_initCfg(&macCfg);
            EnetLpbk_macMode2MacMii(gEnetLpbk.macMode, mii);
    
            if (gEnetLpbk.testPhyLoopback)
            {
                const EnetBoard_PortCfg *portCfg = NULL;
    
                /* Set PHY configuration params */
                EnetPhy_initCfg(phyCfg);
                status = EnetLpbk_macMode2PhyMii(gEnetLpbk.macMode, &phyMii);
    
                if (status == ENET_SOK)
                {
                    portCfg = EnetBoard_getPortCfg(gEnetLpbk.enetType, gEnetLpbk.instId, &ethPort);
                    if (portCfg != NULL)
                    {
                        phyCfg->phyAddr     = portCfg->phyCfg.phyAddr;
                        phyCfg->isStrapped  = portCfg->phyCfg.isStrapped;
                        phyCfg->skipExtendedCfg = portCfg->phyCfg.skipExtendedCfg;
                        phyCfg->extendedCfgSize = portCfg->phyCfg.extendedCfgSize;
                        memcpy(phyCfg->extendedCfg, portCfg->phyCfg.extendedCfg, phyCfg->extendedCfgSize);
    
                        macCfg.sgmiiMode = portCfg->sgmiiMode;
                    }
                    else
                    {
                        EnetAppUtils_print("Port info not found\n");
                        EnetAppUtils_assert(false);
                    }
    
                    if ((phyMii == ENETPHY_MAC_MII_MII) ||
                        (phyMii == ENETPHY_MAC_MII_RMII))
                    {
                        linkCfg->speed = ENET_SPEED_100MBIT;
                    }
                    else
                    {
                        linkCfg->speed = ENET_SPEED_1GBIT;
                    }
    
                    linkCfg->duplexity = ENET_DUPLEX_FULL;
    
                    linkCfg->speed = ENET_SPEED_AUTO;
                    linkCfg->duplexity = ENET_DUPLEX_AUTO;
                }
            }
            else
            {
                phyCfg->phyAddr = ENETPHY_INVALID_PHYADDR;
                if (mii->layerType == ENET_MAC_LAYER_MII)
                {
                    linkCfg->speed = ENET_SPEED_100MBIT;
                }
                else
                {
                    linkCfg->speed = ENET_SPEED_1GBIT;
                }
    
                linkCfg->duplexity = ENET_DUPLEX_FULL;
    
                if (EnetMacPort_isSgmii(mii))
                {
                    macCfg.sgmiiMode = ENET_MAC_SGMIIMODE_SGMII_FORCEDLINK;
                }
            }
    
            /* MAC and PHY loopbacks are mutually exclusive */
            phyCfg->loopbackEn  = false;// = gEnetLpbk.testPhyLoopback && !gEnetLpbk.testExtLoopback;
            macCfg.loopbackEn = false;//!gEnetLpbk.testPhyLoopback;
        }
    
        /* Open port link */
        if (status == ENET_SOK)
        {
            ENET_IOCTL_SET_IN_ARGS(&prms, &portLinkCfg);
    
            status = Enet_ioctl(gEnetLpbk.hEnet, gEnetLpbk.coreId, ENET_PER_IOCTL_OPEN_PORT_LINK, &prms);
            if (status != ENET_SOK)
            {
                EnetAppUtils_print("Failed to open port link: %d\n", status);
            }
        }
    
        return status;
    }
    
    static void EnetLpbk_closeEnet(void)
    {
        Enet_IoctlPrms prms;
        int32_t status;
    
        /* Close port link */
        ENET_IOCTL_SET_IN_ARGS(&prms, &gEnetLpbk.macPort);
    
        status = Enet_ioctl(gEnetLpbk.hEnet, gEnetLpbk.coreId, ENET_PER_IOCTL_CLOSE_PORT_LINK, &prms);
        if (status != ENET_SOK)
        {
            EnetAppUtils_print("Failed to close port link: %d\n", status);
        }
    
        /* Detach core */
        if (status == ENET_SOK)
        {
            ENET_IOCTL_SET_IN_ARGS(&prms, &gEnetLpbk.coreKey);
    
            status = Enet_ioctl(gEnetLpbk.hEnet, gEnetLpbk.coreId, ENET_PER_IOCTL_DETACH_CORE, &prms);
            if (status != ENET_SOK)
            {
                EnetAppUtils_print("Failed to detach core key %u: %d\n", gEnetLpbk.coreKey, status);
            }
        }
    
        /* Close Enet driver */
        Enet_close(gEnetLpbk.hEnet);
    
        /* Close UDMA */
        EnetAppUtils_udmaclose(gEnetLpbk.hUdmaDrv);
    
        gEnetLpbk.hEnet = NULL;
    }
    
    static int32_t EnetLpbk_showAlivePhys(void)
    {
        Enet_IoctlPrms prms;
        bool alive = false;
        int8_t i;
        int32_t status;
    
        for (i = 0U; i < ENET_MDIO_PHY_CNT_MAX; i++)
        {
            ENET_IOCTL_SET_INOUT_ARGS(&prms, &i, &alive);
    
            status = Enet_ioctl(gEnetLpbk.hEnet, gEnetLpbk.coreId, ENET_MDIO_IOCTL_IS_ALIVE, &prms);
            if (status == ENET_SOK)
            {
                if (alive == true)
                {
                    EnetAppUtils_print("PHY %u is alive\n", i);
                }
            }
            else
            {
                EnetAppUtils_print("Failed to get PHY %u alive status: %d\n", i, status);
            }
        }
    
        return status;
    }
    
    static int32_t EnetLpbk_waitForLinkUp(void)
    {
        Enet_IoctlPrms prms;
        bool linked = false;
        int32_t status = ENET_SOK;
    
        ENET_IOCTL_SET_INOUT_ARGS(&prms, &gEnetLpbk.macPort, &linked);
    
        while (!linked)
        {
            status = Enet_ioctl(gEnetLpbk.hEnet, gEnetLpbk.coreId, ENET_PER_IOCTL_IS_PORT_LINK_UP, &prms);
            if (status != ENET_SOK)
            {
                EnetAppUtils_print("Failed to get port %u's link status: %d\n",
                                ENET_MACPORT_ID(gEnetLpbk.macPort), status);
                linked = false;
                break;
            }
    
            if (!linked)
            {
                EnetUtils_delay(10U);
            }
        }
    
        return status;
    }
    
    static void EnetLpbk_showCpswStats(void)
    {
        Enet_IoctlPrms prms;
        CpswStats_PortStats portStats;
        int32_t status;
    
        /* Show host port statistics */
        ENET_IOCTL_SET_OUT_ARGS(&prms, &portStats);
        status = Enet_ioctl(gEnetLpbk.hEnet, gEnetLpbk.coreId, ENET_STATS_IOCTL_GET_HOSTPORT_STATS, &prms);
        if (status == ENET_SOK)
        {
            EnetAppUtils_print("\n Port 0 Statistics\n");
            EnetAppUtils_print("-----------------------------------------\n");
            EnetAppUtils_printHostPortStats2G((CpswStats_HostPort_2g *)&portStats);
            EnetAppUtils_print("\n");
        }
        else
        {
            EnetAppUtils_print("Failed to get host stats: %d\n", status);
        }
    
        /* Show MAC port statistics */
        if (status == ENET_SOK)
        {
            ENET_IOCTL_SET_INOUT_ARGS(&prms, &gEnetLpbk.macPort, &portStats);
            status = Enet_ioctl(gEnetLpbk.hEnet, gEnetLpbk.coreId, ENET_STATS_IOCTL_GET_MACPORT_STATS, &prms);
            if (status == ENET_SOK)
            {
                EnetAppUtils_print("\n Port 1 Statistics\n");
                EnetAppUtils_print("-----------------------------------------\n");
                EnetAppUtils_printMacPortStats2G((CpswStats_MacPort_2g *)&portStats);
                EnetAppUtils_print("\n");
            }
            else
            {
                EnetAppUtils_print("Failed to get MAC stats: %d\n", status);
            }
        }
    }
    
    #if 0 //TODO - NEED TO BE PORTED
    static uint32_t EnetLpbk_getSystemHeapFreeSpace(void)
    {
        Memory_Stats stats;
        HeapMem_Object *obj = NULL;
        HeapMem_Object *nextObj = NULL;
        HeapMem_Object *currObj = NULL;
        uint32_t totalFreeSize = 0U;
        uint32_t totalFreeSizeStatic = 0U;
        uint32_t totalFreeSizeDynamic = 0U;
        uint32_t i;
    
        for (i = 0U; i < HeapMem_Object_count(); i++)
        {
            obj = HeapMem_Object_get(NULL, i);
            if (NULL != obj)
            {
                HeapMem_getStats(obj, &stats);
                totalFreeSizeStatic += stats.totalFreeSize;
            }
        }
    
        nextObj = HeapMem_Object_first();
        do
        {
            currObj = nextObj;
            if (NULL != currObj)
            {
                HeapMem_getStats(currObj, &stats);
                totalFreeSizeDynamic += stats.totalFreeSize;
    
                nextObj = HeapMem_Object_next(currObj);
            }
        }
        while (nextObj != NULL);
    
        totalFreeSize = totalFreeSizeStatic + totalFreeSizeDynamic;
    
        return totalFreeSize;
    }
    #endif
    
    void EnetLpbk_waitForDebugger(void)
    {
        /* Set ccsHaltFlag to 1 for halting core for CCS connection */
        volatile bool ccsHalt = true;
    
        while (ccsHalt)
        {
            /* Do nothing */
        }
    }
    
    void EnetLpbk_rxIsrFxn(void *appData)
    {
        SemaphoreP_post(gEnetLpbk.hRxSem);
    }
    
    void EnetLpbk_txIsrFxn(void *appData)
    {
        SemaphoreP_post(gEnetLpbk.hTxSem);
    }
    
    void EnetLpbk_initTxFreePktQ(void)
    {
        EnetDma_Pkt *pPktInfo;
        uint32_t i;
    
        /* Initialize all queues */
        EnetQueue_initQ(&gEnetLpbk.txFreePktInfoQ);
    
        /* Initialize TX EthPkts and queue them to txFreePktInfoQ */
        for (i = 0U; i < ENET_MEM_NUM_TX_PKTS; i++)
        {
            pPktInfo = EnetMem_allocEthPkt(&gEnetLpbk,
                                           ENETDMA_CACHELINE_ALIGNMENT,
                                           ENET_ARRAYSIZE(txScatterSegments),
                                           txScatterSegments);
            EnetAppUtils_assert(pPktInfo != NULL);
            ENET_UTILS_SET_PKT_APP_STATE(&pPktInfo->pktState, ENET_PKTSTATE_APP_WITH_FREEQ);
            EnetQueue_enq(&gEnetLpbk.txFreePktInfoQ, &pPktInfo->node);
        }
    
        EnetAppUtils_print("initQs() txFreePktInfoQ initialized with %d pkts\n",
                           EnetQueue_getQCount(&gEnetLpbk.txFreePktInfoQ));
    }
    
    void EnetLpbk_initRxReadyPktQ(void)
    {
        EnetDma_PktQ rxReadyQ;
        EnetDma_Pkt *pPktInfo;
        int32_t status;
        uint32_t i;
    
        EnetQueue_initQ(&gEnetLpbk.rxFreeQ);
        EnetQueue_initQ(&gEnetLpbk.rxReadyQ);
        EnetQueue_initQ(&rxReadyQ);
    
        for (i = 0U; i < ENET_MEM_NUM_RX_PKTS; i++)
        {
            pPktInfo = EnetMem_allocEthPkt(&gEnetLpbk,
                                           ENETDMA_CACHELINE_ALIGNMENT,
                                           ENET_ARRAYSIZE(rxScatterSegments),
                                           rxScatterSegments);
            EnetAppUtils_assert(pPktInfo != NULL);
            ENET_UTILS_SET_PKT_APP_STATE(&pPktInfo->pktState, ENET_PKTSTATE_APP_WITH_FREEQ);
            EnetQueue_enq(&gEnetLpbk.rxFreeQ, &pPktInfo->node);
        }
    
        /* Retrieve any CPSW packets which are ready */
        status = EnetDma_retrieveRxPktQ(gEnetLpbk.hRxCh, &rxReadyQ);
        EnetAppUtils_assert(status == ENET_SOK);
        /* There should not be any packet with DMA during init */
        EnetAppUtils_assert(EnetQueue_getQCount(&rxReadyQ) == 0U);
    
        EnetAppUtils_validatePacketState(&gEnetLpbk.rxFreeQ,
                                         ENET_PKTSTATE_APP_WITH_FREEQ,
                                         ENET_PKTSTATE_APP_WITH_DRIVER);
    
        EnetDma_submitRxPktQ(gEnetLpbk.hRxCh,
                             &gEnetLpbk.rxFreeQ);
    
        /* Assert here as during init no. of DMA descriptors should be equal to
         * no. of free Ethernet buffers available with app */
    
        EnetAppUtils_assert(0U == EnetQueue_getQCount(&gEnetLpbk.rxFreeQ));
    }
    
    int32_t EnetLpbk_openDma()
    {
        int32_t status = ENET_SOK;
        EnetUdma_OpenRxFlowPrms rxChCfg;
        EnetUdma_OpenTxChPrms   txChCfg;
    
        /* Open the CPSW TX channel  */
        if (status == ENET_SOK)
        {
            EnetDma_initTxChParams(&txChCfg);
    
            txChCfg.hUdmaDrv = gEnetLpbk.hUdmaDrv;
            txChCfg.cbArg    = &gEnetLpbk;
            txChCfg.notifyCb = EnetLpbk_txIsrFxn;
    
            EnetAppUtils_setCommonTxChPrms(&txChCfg);
    
            EnetAppUtils_openTxCh(gEnetLpbk.hEnet,
                                  gEnetLpbk.coreKey,
                                  gEnetLpbk.coreId,
                                  &gEnetLpbk.txChNum,
                                  &gEnetLpbk.hTxCh,
                                  &txChCfg);
    
            EnetLpbk_initTxFreePktQ();
    
            if (NULL != gEnetLpbk.hTxCh)
            {
                status = EnetDma_enableTxEvent(gEnetLpbk.hTxCh);
                if (ENET_SOK != status)
                {
    #if FIX_RM
                    /* Free the Ch Num if enable event failed */
                    EnetAppUtils_freeTxCh(gEnetLpbk.hEnet,
                                          gEnetLpbk.coreKey,
                                          gEnetLpbk.coreId,
                                          gEnetLpbk.txChNum);
    #endif
                    EnetAppUtils_print("EnetUdma_startTxCh() failed: %d\n", status);
                    status = ENET_EFAIL;
                }
            }
            else
            {
    #if FIX_RM
                /* Free the Ch Num if open Tx Ch failed */
                EnetAppUtils_freeTxCh(gEnetLpbk.hEnet,
                                      gEnetLpbk.coreKey,
                                      gEnetLpbk.coreId,
                                      gEnetLpbk.txChNum);
    #endif
                EnetAppUtils_print("EnetDma_openTxCh() failed to open: %d\n",
                                   status);
                status = ENET_EFAIL;
            }
        }
    
        /* Open the CPSW RX flow  */
        if (status == ENET_SOK)
        {
            EnetDma_initRxChParams(&rxChCfg);
    
            rxChCfg.hUdmaDrv = gEnetLpbk.hUdmaDrv;
            rxChCfg.notifyCb = EnetLpbk_rxIsrFxn;
            rxChCfg.cbArg   = &gEnetLpbk;
    
            EnetAppUtils_setCommonRxFlowPrms(&rxChCfg);
            EnetAppUtils_openRxFlow(gEnetLpbk.enetType,
                                    gEnetLpbk.hEnet,
                                    gEnetLpbk.coreKey,
                                    gEnetLpbk.coreId,
                                    true,
                                    &gEnetLpbk.rxStartFlowIdx,
                                    &gEnetLpbk.rxFlowIdx,
                                    &gEnetLpbk.hostMacAddr[0U],
                                    &gEnetLpbk.hRxCh,
                                    &rxChCfg);
            if (NULL == gEnetLpbk.hRxCh)
            {
                EnetAppUtils_print("EnetDma_openRxCh() failed to open: %d\n",
                                   status);
                EnetAppUtils_assert(NULL != gEnetLpbk.hRxCh);
            }
            else
            {
                EnetAppUtils_print("Host MAC address: ");
                EnetAppUtils_printMacAddr(gEnetLpbk.hostMacAddr);
                /* Submit all ready RX buffers to DMA.*/
                EnetLpbk_initRxReadyPktQ();
            }
        }
    
        return status;
    }
    
    void EnetLpbk_closeDma()
    {
        EnetDma_PktQ fqPktInfoQ;
        EnetDma_PktQ cqPktInfoQ;
    
        EnetQueue_initQ(&fqPktInfoQ);
        EnetQueue_initQ(&cqPktInfoQ);
    
        /* There should not be any ready packet */
        EnetAppUtils_assert(0U == EnetQueue_getQCount(&gEnetLpbk.rxReadyQ));
    
        /* Close RX channel */
        EnetAppUtils_closeRxFlow(gEnetLpbk.enetType,
                                 gEnetLpbk.hEnet,
                                 gEnetLpbk.coreKey,
                                 gEnetLpbk.coreId,
                                 true,
                                 &fqPktInfoQ,
                                 &cqPktInfoQ,
                                 gEnetLpbk.rxStartFlowIdx,
                                 gEnetLpbk.rxFlowIdx,
                                 gEnetLpbk.hostMacAddr,
                                 gEnetLpbk.hRxCh);
    
        EnetAppUtils_freePktInfoQ(&fqPktInfoQ);
        EnetAppUtils_freePktInfoQ(&cqPktInfoQ);
    
        /* Close TX channel */
        EnetQueue_initQ(&fqPktInfoQ);
        EnetQueue_initQ(&cqPktInfoQ);
    
        EnetAppUtils_closeTxCh(gEnetLpbk.hEnet,
                               gEnetLpbk.coreKey,
                               gEnetLpbk.coreId,
                               &fqPktInfoQ,
                               &cqPktInfoQ,
                               gEnetLpbk.hTxCh,
                               gEnetLpbk.txChNum);
        EnetAppUtils_freePktInfoQ(&fqPktInfoQ);
        EnetAppUtils_freePktInfoQ(&cqPktInfoQ);
    
        EnetAppUtils_freePktInfoQ(&gEnetLpbk.rxFreeQ);
        EnetAppUtils_freePktInfoQ(&gEnetLpbk.txFreePktInfoQ);
    
        EnetMem_deInit();
    }
    

  • Hi,

    Let us check in TI SDK in next week and update you.
    Kindly wait for response.

    Best Regards,
    Sudheer