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.

How to Use 6678 eth0 and eth1 with different MAC simultaneously

Hi All

I have a customized board with 6678 processor.

Need to use Core 0 with eth port 0 with unique Mac and Core 1 with eth port 1 with its unique MAC Simultaneously

( eth0 and eth1 with same MAC -mirror mode is working .. but we need unique mac for each eth port)

How to achieve it ?

Please help

PS:

Using 2 eth ports simultaneously with different MAC is hot topic discussed in Forum ... But TI has not come with a solution yet ?

  • Are you trying to run the NDK stack on both cores?  This is not supported at this time.  If you are only trying to use raw ethernet, I think this can be supported, but I'll ask one of our experts to chime in.  We have an example in the MCSDK that uses multiple cores, but it uses one port and mac address.

    Travis

  • hi,

    i'm also looking forward to use 2 ndk stack on 2 differnet cores, each ndk stack connected too a mac and an ip.

    please help

  • Hi, We also tried to do the same on our custom board but it didn't worked as the present is SDK supports either one of the port. When TI will update the SDK for simultaneous usage of both ports. This functionality is very much required for us to demonstrate to our customer.

    Regards,

    Senthil

  • Hi All,


    We are currently working on the customized board. In the customized board we have to DSP C6678 processors. There are totaly (8cores for DSP1 + 8cores for DSP2)

    16 cores. In the customized board we have two ethernet port's. We are trying to enable ethernet port1 for core0 of DSP1 with a Seperate MAC Address and IP Address.

    We are also trying to enable ethernet port2 for core1 of DSP1 with a Seperate MAC Address and IP Address.

    The image given bellow clearly explain what I am trying to do.

    1. How to assign 2 different MAC Address and 2 different IP Address for Core0 and Core1 of same DSP?

    Regards,

    Avinash N

  • Hi Travis

    Yes Iam trying to run NDK stack on both cores.

    If I need to run like this , I thought I need to do code level changes in PDK only.

    Do I need to do code level changes in NDK level also ?

    Please help to sort this issue soon..

    PS:

    I browsed in forum and found out lot of people need solution for two ethernet with independent MAC.

    Please provide some solution

  • We believe the NDK software supports it, and that the limitation is to the NIMU driver within the PDK.  There are TI folks looking into it, though I can't currently give you a schedule. Stay tuned...

    Regards,

    Travis

  • Thanks for this and Iour team also need this solution on the NIMU hardware but two different NDK stacks on two different chips of C6670.

    Can Ti support this?

    Alan

  • Hi Travis,

    We believe that existing NDK package  and NIMU driver if modified supports simultaneous usage of Both EMAC ports.

    From the link,

    http://e2e.ti.com/support/dsp/c6000_multi-core_dsps/f/439/t/136841.aspx

    it seems the NDK for 6472 doesn't support on Multicores.

    Is NDK for 6678 also not support running NDK's on different cores.

    Regards,

    Senthil

  • Senthil,

    I just checked and the current effort underway is to make the needed modifications to NIMU to support one NDK running on a single core, but using both ethernet ports simultaneously.  Each port has it's own IP address and own MAC address.  As mentioned above in this thread, running two copies of NDK on different cores is not currently supported either, I've requested that this be looked at as well.

    Regards,

    Travis

  • Hi Travis,

    We have modified nimu_eth to enable both EMAC ports with different IP address on Core0.

    We are able ping both the IP's from the external world. But the ping is happening only for sometime. If we assign both IP's in same subnet, duplicate IP binding issue is coming from NDK.

    C66xx_0] max_num_desc (256)
    [C66xx_0] p_qmss_cfg (256)
    [C66xx_0] QMSS successfully initialized
    [C66xx_0] CPPI successfully initialized
    [C66xx_0] PA successfully initialized
    [C66xx_0]
    [C66xx_0] TCP/IP Stack 'Hello World!' Application
    [C66xx_0]
    [C66xx_0]
    [C66xx_0] TCP/IP Stack 'Hello World!' Application
    [C66xx_0]
    [C66xx_0] EMACInit_Core: Efuse MAC- 00-17-EA-CD-CE-2D
    [C66xx_0] PASS successfully initialized
    [C66xx_0] Init_Cpsw: Configure MAC- 00-17-EA-CD-CE-2D
    [C66xx_0] Ethernet subsystem successfully initialized
    [C66xx_0] Setup_Rx: H.P queue 0 704
    [C66xx_0] Ethernet eventId : 48 and vectId (Interrupt) : 7
    [C66xx_0] Verify_Init: Expected 0 entry count for Queue number = 897, found 129 entries
    [C66xx_0] Registration of the EMAC Successful, waiting for link up ..
    [C66xx_0] I2_EMACInit_Core: Efuse MAC- 10-11-12-13-14-15
    [C66xx_0] PASS successfully initialized
    [C66xx_0] Init_Cpsw: Configure MAC- 10-11-12-13-14-15
    [C66xx_0] Ethernet subsystem successfully initialized
    [C66xx_0] I2_EmacStart:  MAC- 10-11-12-13-14-15
    [C66xx_0] I2_Setup_Rx: H.P queue 0 712
    [C66xx_0] Ethernet eventId : 49 and vectId (Interrupt) : 8
    [C66xx_0] Verify_Init: Expected 0 entry count for Queue number = 897, found 2 entries
    [C66xx_0] Registration of the EMAC Successful, waiting for link up ..
    [C66xx_0] Network Added: If-1:172.17.10.183
    [C66xx_0] Network Added: If-2:192.168.10.183

    On debug, we observed the interrupt from the accumulator is not rising when the ping is not happening, so that EmacRxPktISR is not called to receive the packets.
    The statistics shows that no update on PortA Rx side. Means packets are going inside the switch but not coming out?

    How to check the statistics for PDSP0, so that we can debug further whether the packets are forwarded to host or dropped.

    Snapshot: Ping is not happening at this point.
    C66xx_0: GEL Output: -----------------------------------------------
    C66xx_0: GEL Output: Ethernet Statistics A.
    C66xx_0: GEL Output: -----------------------------------------------
    C66xx_0: GEL Output: RX Good Frames ................ 0x0x00000098
    C66xx_0: GEL Output: RX Broadcast Frames ........... 0x0x00000004
    C66xx_0: GEL Output: RX Multicast Frames ........... 0x0x00000000
    C66xx_0: GEL Output: RX Pause Frames ............... 0x0x00000000
    C66xx_0: GEL Output: RX CRC Errors ................. 0x0x00000000
    C66xx_0: GEL Output: RX Align/Code Errors .......... 0x0x00000000
    C66xx_0: GEL Output: RX Oversized Frames ........... 0x0x00000000
    C66xx_0: GEL Output: RX Jabber Frames .............. 0x0x00000000
    C66xx_0: GEL Output: RX Undersized Frames .......... 0x0x00000000
    C66xx_0: GEL Output: RX Fragments .................. 0x0x00000000
    C66xx_0: GEL Output: RX Octets ..................... 0x0x00002E28
    C66xx_0: GEL Output: TX Good Frames ................ 0x0x00000DEA
    C66xx_0: GEL Output: TX Broadcast Frames ........... 0x0x00000622
    C66xx_0: GEL Output: TX Multicast Frames ........... 0x0x000006F0
    C66xx_0: GEL Output: TX Pause Frames ............... 0x0x00000000
    C66xx_0: GEL Output: TX Deferred Frames ............ 0x0x00000000
    C66xx_0: GEL Output: TX Collision Frames ........... 0x0x00000000
    C66xx_0: GEL Output: TX Single Collision Frames .... 0x0x00000000
    C66xx_0: GEL Output: TX Multiple Collision Frames .. 0x0x00000000
    C66xx_0: GEL Output: TX Excessive Collision Frames . 0x0x00000000
    C66xx_0: GEL Output: TX Late Collisions ............ 0x0x00000000
    C66xx_0: GEL Output: TX Underrun ................... 0x0x00000000
    C66xx_0: GEL Output: TX Carrier Sense Errors ....... 0x0x00000000
    C66xx_0: GEL Output: TX Octets ..................... 0x0x000862D3
    C66xx_0: GEL Output: 64 Byte Octet Frames .......... 0x0x000002B4
    C66xx_0: GEL Output: 65 to 127 Byte Octet Frames ... 0x0x000007F9
    C66xx_0: GEL Output: 128 to 255 Byte Octet Frames .. 0x0x0000019B
    C66xx_0: GEL Output: 256 to 511 Byte Octet Frames .. 0x0x0000019A
    C66xx_0: GEL Output: 512 to 1024 Byte Octet Frames . 0x0x0000008C
    C66xx_0: GEL Output: Over   1024 Byte Octet Frames . 0x0x00000018
    C66xx_0: GEL Output: Net Octets .................... 0x0x0008913B
    C66xx_0: GEL Output: RX Start of Frame Overruns .... 0x0x00000000
    C66xx_0: GEL Output: RX Middle of Frame Overruns ... 0x0x00000000
    C66xx_0: GEL Output: RX DMA Overruns ............... 0x0x00000000
    C66xx_0: GEL Output: -----------------------------------------------

    C66xx_0: GEL Output: -----------------------------------------------
    C66xx_0: GEL Output: Ethernet Statistics B.
    C66xx_0: GEL Output: -----------------------------------------------
    C66xx_0: GEL Output: RX Good Frames ................ 0x0x000010E8
    C66xx_0: GEL Output: RX Broadcast Frames ........... 0x0x00000626
    C66xx_0: GEL Output: RX Multicast Frames ........... 0x0x000006F0
    C66xx_0: GEL Output: RX Pause Frames ............... 0x0x00000000
    C66xx_0: GEL Output: RX CRC Errors ................. 0x0x00000000
    C66xx_0: GEL Output: RX Align/Code Errors .......... 0x0x00000000
    C66xx_0: GEL Output: RX Oversized Frames ........... 0x0x00000000
    C66xx_0: GEL Output: RX Jabber Frames .............. 0x0x00000000
    C66xx_0: GEL Output: RX Undersized Frames .......... 0x0x00000000
    C66xx_0: GEL Output: RX Fragments .................. 0x0x00000000
    C66xx_0: GEL Output: RX Octets ..................... 0x0x000D1477
    C66xx_0: GEL Output: TX Good Frames ................ 0x0x000010A8
    C66xx_0: GEL Output: TX Broadcast Frames ........... 0x0x0000062B
    C66xx_0: GEL Output: TX Multicast Frames ........... 0x0x000006F0
    C66xx_0: GEL Output: TX Pause Frames ............... 0x0x00000000
    C66xx_0: GEL Output: TX Deferred Frames ............ 0x0x00000000
    C66xx_0: GEL Output: TX Collision Frames ........... 0x0x00000000
    C66xx_0: GEL Output: TX Single Collision Frames .... 0x0x00000000
    C66xx_0: GEL Output: TX Multiple Collision Frames .. 0x0x00000000
    C66xx_0: GEL Output: TX Excessive Collision Frames . 0x0x00000000
    C66xx_0: GEL Output: TX Late Collisions ............ 0x0x00000000
    C66xx_0: GEL Output: TX Underrun ................... 0x0x00000000
    C66xx_0: GEL Output: TX Carrier Sense Errors ....... 0x0x00000000
    C66xx_0: GEL Output: TX Octets ..................... 0x0x000D1160
    C66xx_0: GEL Output: 64 Byte Octet Frames .......... 0x0x000007BE
    C66xx_0: GEL Output: 65 to 127 Byte Octet Frames ... 0x0x0000100B
    C66xx_0: GEL Output: 128 to 255 Byte Octet Frames .. 0x0x00000372
    C66xx_0: GEL Output: 256 to 511 Byte Octet Frames .. 0x0x000003AA
    C66xx_0: GEL Output: 512 to 1024 Byte Octet Frames . 0x0x0000016A
    C66xx_0: GEL Output: Over   1024 Byte Octet Frames . 0x0x0000015A
    C66xx_0: GEL Output: Net Octets .................... 0x0x001A369A
    C66xx_0: GEL Output: RX Start of Frame Overruns .... 0x0x00000000
    C66xx_0: GEL Output: RX Middle of Frame Overruns ... 0x0x00000000
    C66xx_0: GEL Output: RX DMA Overruns ............... 0x0x00000000
    C66xx_0: GEL Output: -----------------------------------------------

    Snapshot after some time duration.


    C66xx_0: GEL Output: -----------------------------------------------
    C66xx_0: GEL Output: Ethernet Statistics A.
    C66xx_0: GEL Output: -----------------------------------------------
    C66xx_0: GEL Output: RX Good Frames ................ 0x0x00000098
    C66xx_0: GEL Output: RX Broadcast Frames ........... 0x0x00000004
    C66xx_0: GEL Output: RX Multicast Frames ........... 0x0x00000000
    C66xx_0: GEL Output: RX Pause Frames ............... 0x0x00000000
    C66xx_0: GEL Output: RX CRC Errors ................. 0x0x00000000
    C66xx_0: GEL Output: RX Align/Code Errors .......... 0x0x00000000
    C66xx_0: GEL Output: RX Oversized Frames ........... 0x0x00000000
    C66xx_0: GEL Output: RX Jabber Frames .............. 0x0x00000000
    C66xx_0: GEL Output: RX Undersized Frames .......... 0x0x00000000
    C66xx_0: GEL Output: RX Fragments .................. 0x0x00000000
    C66xx_0: GEL Output: RX Octets ..................... 0x0x00002E28
    C66xx_0: GEL Output: TX Good Frames ................ 0x0x00001116
    C66xx_0: GEL Output: TX Broadcast Frames ........... 0x0x00000797
    C66xx_0: GEL Output: TX Multicast Frames ........... 0x0x00000878
    C66xx_0: GEL Output: TX Pause Frames ............... 0x0x00000000
    C66xx_0: GEL Output: TX Deferred Frames ............ 0x0x00000000
    C66xx_0: GEL Output: TX Collision Frames ........... 0x0x00000000
    C66xx_0: GEL Output: TX Single Collision Frames .... 0x0x00000000
    C66xx_0: GEL Output: TX Multiple Collision Frames .. 0x0x00000000
    C66xx_0: GEL Output: TX Excessive Collision Frames . 0x0x00000000
    C66xx_0: GEL Output: TX Late Collisions ............ 0x0x00000000
    C66xx_0: GEL Output: TX Underrun ................... 0x0x00000000
    C66xx_0: GEL Output: TX Carrier Sense Errors ....... 0x0x00000000
    C66xx_0: GEL Output: TX Octets ..................... 0x0x000A4784
    C66xx_0: GEL Output: 64 Byte Octet Frames .......... 0x0x0000039C
    C66xx_0: GEL Output: 65 to 127 Byte Octet Frames ... 0x0x00000941
    C66xx_0: GEL Output: 128 to 255 Byte Octet Frames .. 0x0x000001EF
    C66xx_0: GEL Output: 256 to 511 Byte Octet Frames .. 0x0x00000223
    C66xx_0: GEL Output: 512 to 1024 Byte Octet Frames . 0x0x000000A7
    C66xx_0: GEL Output: Over   1024 Byte Octet Frames . 0x0x00000018
    C66xx_0: GEL Output: Net Octets .................... 0x0x000A75EC
    C66xx_0: GEL Output: RX Start of Frame Overruns .... 0x0x00000000
    C66xx_0: GEL Output: RX Middle of Frame Overruns ... 0x0x00000000
    C66xx_0: GEL Output: RX DMA Overruns ............... 0x0x00000000
    C66xx_0: GEL Output: -----------------------------------------------

    C66xx_0: GEL Output: -----------------------------------------------
    C66xx_0: GEL Output: Ethernet Statistics B.
    C66xx_0: GEL Output: -----------------------------------------------
    C66xx_0: GEL Output: RX Good Frames ................ 0x0x00001436
    C66xx_0: GEL Output: RX Broadcast Frames ........... 0x0x00000798
    C66xx_0: GEL Output: RX Multicast Frames ........... 0x0x00000878
    C66xx_0: GEL Output: RX Pause Frames ............... 0x0x00000000
    C66xx_0: GEL Output: RX CRC Errors ................. 0x0x00000000
    C66xx_0: GEL Output: RX Align/Code Errors .......... 0x0x00000000
    C66xx_0: GEL Output: RX Oversized Frames ........... 0x0x00000000
    C66xx_0: GEL Output: RX Jabber Frames .............. 0x0x00000000
    C66xx_0: GEL Output: RX Undersized Frames .......... 0x0x00000000
    C66xx_0: GEL Output: RX Fragments .................. 0x0x00000000
    C66xx_0: GEL Output: RX Octets ..................... 0x0x000F03F2
    C66xx_0: GEL Output: TX Good Frames ................ 0x0x000013C7
    C66xx_0: GEL Output: TX Broadcast Frames ........... 0x0x0000079C
    C66xx_0: GEL Output: TX Multicast Frames ........... 0x0x00000878
    C66xx_0: GEL Output: TX Pause Frames ............... 0x0x00000000
    C66xx_0: GEL Output: TX Deferred Frames ............ 0x0x00000000
    C66xx_0: GEL Output: TX Collision Frames ........... 0x0x00000000
    C66xx_0: GEL Output: TX Single Collision Frames .... 0x0x00000000
    C66xx_0: GEL Output: TX Multiple Collision Frames .. 0x0x00000000
    C66xx_0: GEL Output: TX Excessive Collision Frames . 0x0x00000000
    C66xx_0: GEL Output: TX Late Collisions ............ 0x0x00000000
    C66xx_0: GEL Output: TX Underrun ................... 0x0x00000000
    C66xx_0: GEL Output: TX Carrier Sense Errors ....... 0x0x00000000
    C66xx_0: GEL Output: TX Octets ..................... 0x0x000EE214
    C66xx_0: GEL Output: 64 Byte Octet Frames .......... 0x0x000009A2
    C66xx_0: GEL Output: 65 to 127 Byte Octet Frames ... 0x0x000012A9
    C66xx_0: GEL Output: 128 to 255 Byte Octet Frames .. 0x0x0000041A
    C66xx_0: GEL Output: 256 to 511 Byte Octet Frames .. 0x0x000004A4
    C66xx_0: GEL Output: 512 to 1024 Byte Octet Frames . 0x0x000001A0
    C66xx_0: GEL Output: Over   1024 Byte Octet Frames . 0x0x0000015A
    C66xx_0: GEL Output: Net Octets .................... 0x0x001DE806
    C66xx_0: GEL Output: RX Start of Frame Overruns .... 0x0x00000000
    C66xx_0: GEL Output: RX Middle of Frame Overruns ... 0x0x00000000
    C66xx_0: GEL Output: RX DMA Overruns ............... 0x0x00000000
    C66xx_0: GEL Output: -----------------------------------------------

  • Senthil,

    I've asked another TI engineer to chime in here.  My understanding is that you do need separate sub-nets for the two ports, but I'll let others comment.

    Regards,

    Travis

  • Senthil:

    I am currently working through the exact same issue you are experiencing.  The insight I can provide you right now is that the IPs should be on different subnets in order to avoid address resolution problems.  In regards to the ISR not being triggered, I believe you must change which accChannelNum is being used for the second interface in the setupRx function.  For instance, my code initializes accChannelNum to be PA_ACC_CHANNEL_NUM for the first interface, and PA_ACC_CHANNEL_NUM + 8 for the second interface.  This 8 stems from usable accumulator channels on 6678 core 0.  If you are using say, a 6670, use + 4.   Additionally, I believe you have to set a different event ID for the other interface and register the ISR handle with this event as well.  I simply chose the eventId to be PLATFORM_ETH_EVENTID+1. 

    I have not had a chance to properly test this but I believe it is in the right direction.  I should have more information in the next several days.

    Sincerely,

    John Demery

  • Hi John,

    For the second interface, i am using Accumulator channel number 8, event id 49 and interrupt 8. I am able to ping both IP address means interrupt is getting triggered for both ports but it is happening only for few minutes. After that ping is not happening as interrupt is not raised from the accumulator.

    Regards,

    Senthil

  • Senthil:

    Are you using the same ISR for each interface?  If so, have you modified the Qmss_ackInterrupt and Qmss_setEoiVector calls to accurately reflect which accumulator channel you are using?  I haven't had the opportunity to test this yet but I think it's a good avenue to go down.   Is the amount of time it works for consistent?

    Sincerely,

    John Demery

  • Hi John,

    I have configured the 48 event id and vector no 7 for port 0 and 49 event id and vector no 8 for port 1. But if read the interrupt map register using shannon_interrrupt gel it seems both accumulator queue 704 and 712 are mapped to event id 1 and vector no 7. Configured Qmss_ackInterrupt and Qmss_setEoiVector calls for port 1 to accumulator channel 8.

    When its the ping happens i am checking gRxFreeQHnd entry count  using Qmss_getQueueEntryCount in the ISR. Its value is keep increasing and when it reaches 221 the ping is not happening and ISR is not raising. The values 221 arrives as i have increased NIMU_NUM_RX_DESC to 222. I don't know whether free descriptor are emptied as i may not be properly configured the return queue properly in rxflow.

    Regards,

    Senthil

  • Senthil:

    I have currently not run my test that far.  Let me see what I can figure out on your issue and I'll get back to you as soon as I know something.

    Sincerely,

    John Demery

  • Hi, John

         I encountered the same problem with Senthil‘s, is there any progress in it?

         Liu

  • Liu and all:

    In my investigations I have found that this loss of network functionality is due to one of the interfaces running out of free descriptors in its free descriptor queue.

    I assume that you have separate free descriptor queues for each interface, correct?  For some reason, all of the free descriptors from both interfaces seem to be getting recycled to a queue only associated with one interface.  I am in the process of figuring out what is going on here and am aiming to have an answer for you by the end of the week.

    If you get a chance, could you log or print out the free descriptors in your RxFreeQHnd (receive free queues)?  I would like to see that your issue is stemming from the same problem.

    Thanks,

    John Demery

  • John and All

      I found the cause of the problem: Ping is a broadcast packet !

      I do have separate rx queues and Rx free descriptor queues for each interface, and I find that all of the free descriptors from both interfaces are get recycled to a queue only associated with the interface 0.   

      In the file resourcemgr.c, the function res_mgr_init_pass() has

                   "paCfg.initDefaultRoute = TRUE",

      which means that packets received by both interfaces will be first sent to PA PDSP0 for processing.   

      In the file nimu_eth.c, the function EmacStart() uses function Add_MACAddress() to  set up the MAC Address LUT , which will be used by PDSP0 to transmit packets to PKTDMA Rx channel. 

      By defaulte, broadcast MAC address is added to LUT with the Rx Flow Id=0, and Rx flow 0 will only use gRxFreeQHnd and gRxQHnd.   

      Generally speaking, Ping request is broadcast packet. No matter from which interface, the Ping packet will be processed with Rx Flow 0. While in the ISR for interface 1, I return the Desc to the free queue for interface 1.

      Therefore, all of the Descs would be freed back to the Rx FDQ forinterface 0 !

               Liu

  • Hi, 

    My name is Ryan.

    I have still this problem. have you gotten any solution?

    Please tell me about this more detaily. 

    Thanks, Ryan.

  • Hi, 

    My name is Ryan.

    I have had problem with using dual port at the same time. 

    So, Would you mind share your code? because until now  I don't understand this clearly.

    Please help me out if you don't mind.

    Thanks, Ryan.

  • Ryan:

    I am attaching updated NIMU code that allows usage of both interfaces at the same time as well as a brief document describing the changes that were made.

    Please note that both this document and code are not formal.  You may discover issues with them but they are certainly a step in the right direction.  The code is cleaner than the documentation and was updated more recently.

    Lastly, I have heard that in some cases both interfaces will crash due to free descriptors not returning to the proper queue.  If you run into this issue, try the following.change in EmacStart

    if( pdi.PhysIdx == 0)
       routeInfo.flowId = Cppi_getFlowId(gRxFlowHnd[0])

    if( pdi.PhysIdx == 1)
       routeInfo.flowId = Cppi_getFlowId(gRxFlowHnd[1])

    I have not tested this fix yet though.

     

    I hope this helps!

     

    7142.Code Changes to NIMU and Explanation.docx1325.NIMU2Port6678.zip

  • Hi, John.

    Thank you for your help.

    And, I tried to change my nimu code to your code you sent me.

    But , I got this debug message. 

    Please check it out again.

    PHY = SGMII port 0
    PASS successfully initialized
    Ethernet subsystem successfully initialized
    Ethernet eventId : 48 and vectId (Interrupt) : 7
    gTxFlowHnd=0xc007660
    Verify_Init: Expected 16 entry count for gTxFreeQHnd queue 0, found 0 entries
    Verify_Init: Expected 110 entry count for gRxFreeQHnd queue 0, found 0 entries
    Verify_Init: Expected 0 entry count for Queue number = 736, found 16 entries
    Verify_Init: Expected 0 entry count for Queue number = 737, found 2 entries
    Verify_Init: Expected 0 entry count for Queue number = 738, found 110 entries
    Warning:Queue handler Verification failed
    Registration of the EMAC Successful, waiting for link up ..
    Error: Unable to find a TX EMAC port
    Network Added: If-1:192.168.20.7
    Service Status: Telnet : Enabled : : 000

    Thanks, Ryan.

  • I did what you recommanded way.

    But I got some problem like here. 

    After I added this code you gave me to my project I just changed like below one thing more to avoid the fail concerned with descriptor.

    #define NIMU_NUM_TX_DESC 16u /**< Maximum number of TX descriptors used by NIMU */
    #define NIMU_NUM_RX_DESC 110u /**< Maximum number of RX descriptors used by NIMU */
    #define NIMU_MAX_NUM_TX_CMD_DESC 2u /**< Maximum number of TX Command descriptors used by NIMU */

    //#define MAX_NUM_NIMU_DESC (NIMU_NUM_TX_DESC + NIMU_NUM_RX_DESC + NIMU_MAX_NUM_TX_CMD_DESC) /**< Maximum number of descriptors used by NIMU */
    //#define MAX_NUM_DESC (MAX_NUM_NIMU_DESC) /**< Maximum number of descriptors used by all the modules */
    #define MAX_NUM_NIMU_DESC 256 /**< Maximum number of descriptors used by NIMU */
    #define MAX_NUM_DESC 256 /**< Maximum number of descriptors used by all the modules */
    //#define MAX_DESC_SIZE 128 /**< Maximum size of descriptor in bytes */
    #define MAX_DESC_SIZE 512 /**< Maximum size of descriptor in bytes */


    So, I got console message like this.

    ---------------------------------------------------------------------

    PHY = ptr_pvt_data->pdi.PhysIdx 0 
    PHY = SGMII port 0 mode 1 
    PHY = SGMII port 0
    PASS successfully initialized 
    Ethernet subsystem successfully initialized 
    Ethernet eventId : 48 and vectId (Interrupt) : 7 
    gTxFlowHnd=0xc007660
    Verify_Init: Expected 0 entry count for Queue number = 897, found 128 entries
    Verify_Init: Expected 16 entry count for gTxFreeQHnd queue 0, found 0 entries
    Verify_Init: Expected 110 entry count for gRxFreeQHnd queue 0, found 0 entries
    Verify_Init: Expected 0 entry count for Queue number = 736, found 16 entries
    Verify_Init: Expected 0 entry count for Queue number = 737, found 2 entries
    Verify_Init: Expected 0 entry count for Queue number = 738, found 110 entries
    Verify_Init: Expected 0 entry count for Queue number = 897, found 128 entries
    Warning:Queue handler Verification failed 
    Registration of the EMAC Successful, waiting for link up ..
    PHY = ptr_pvt_data->pdi.PhysIdx 1 
    PHY = SGMII port 0 mode 1 
    AMC = SGMII port 0
    Ethernet eventId : 49 and vectId (Interrupt) : 8 
    gTxFlowHnd=0xc007640
    Verify_Init: Expected 110 entry count for gRxFreeQHnd queue 738, found 108 entries
    Verify_Init: Expected 0 entry count for Queue number = 739, found 16 entries
    Verify_Init: Expected 0 entry count for Queue number = 740, found 2 entries
    Verify_Init: Expected 0 entry count for Queue number = 741, found 112 entries
    Verify_Init: Expected 110 entry count for gRxFreeQHnd queue 741, found 112 entries
    Verify_Init: Expected 0 entry count for Queue number = 736, found 16 entries
    Verify_Init: Expected 0 entry count for Queue number = 737, found 2 entries
    Verify_Init: Expected 0 entry count for Queue number = 738, found 108 entries
    Warning:Queue handler Verification failed 
    Registration of the EMAC Successful, waiting for link up ..
    Network Added: If-1:192.168.20.7
    Network Added: If-2:192.168.10.2

    ---------------------------------------------------------------------

    But, when I try to do ping test between my pc and target board(c6671). It doesn't work properly.

    just one port can success ping test several time. that's it.

    After more then 1minute would fail the ping test again.

    And the ping test can success just one port at a time not two ports at the same time.

    If you need more information about this I can give to you. 

    Please help me.

    Thanks, Ryan.

  • And, I have a question about that because I changed the define of descriptor.

    Before

    #define NIMU_NUM_TX_DESC 16u /**< Maximum number of TX descriptors used by NIMU */
    #define NIMU_NUM_RX_DESC 110u /**< Maximum number of RX descriptors used by NIMU */
    #define NIMU_MAX_NUM_TX_CMD_DESC 2u /**< Maximum number of TX Command descriptors used by NIMU */

    #define MAX_NUM_NIMU_DESC (NIMU_NUM_TX_DESC + NIMU_NUM_RX_DESC + NIMU_MAX_NUM_TX_CMD_DESC) /**< Maximum number of descriptors used by NIMU */
    #define MAX_NUM_DESC (MAX_NUM_NIMU_DESC) /**< Maximum number of descriptors used by all the modules */
    #define MAX_DESC_SIZE 128 /**< Maximum size of descriptor in bytes */


    After

    #define NIMU_NUM_TX_DESC 16u /**< Maximum number of TX descriptors used by NIMU */
    #define NIMU_NUM_RX_DESC 110u /**< Maximum number of RX descriptors used by NIMU */
    #define NIMU_MAX_NUM_TX_CMD_DESC 2u /**< Maximum number of TX Command descriptors used by NIMU */

    #define MAX_NUM_NIMU_DESC 256
    #define MAX_NUM_DESC 256
    #define MAX_DESC_SIZE 512 /**< Maximum size of descriptor in bytes */


    Because by the time I changed it like After. I could see the fail message like below.

    So I changed this in my way.

    As a result eth0 works fine when just ping to eth0 only.

    But when I ping eth1 only with eth0 ping test, the connection is unstable like disconnecting after 1 minute.

    Am I wrong? Please check it out for me.


    PHY = ptr_pvt_data->pdi.PhysIdx 0 
    PHY = SGMII port 0 mode 1 
    PHY = SGMII port 0
    PASS successfully initialized 
    Ethernet subsystem successfully initialized 
    Ethernet eventId : 48 and vectId (Interrupt) : 7 
    gTxFlowHnd=0xc007660
    Verify_Init: Expected 16 entry count for gTxFreeQHnd queue 0, found 0 entries
    Verify_Init: Expected 110 entry count for gRxFreeQHnd queue 0, found 0 entries
    Verify_Init: Expected 0 entry count for Queue number = 736, found 16 entries
    Verify_Init: Expected 0 entry count for Queue number = 737, found 2 entries
    Verify_Init: Expected 0 entry count for Queue number = 738, found 110 entries
    Warning:Queue handler Verification failed 
    Registration of the EMAC Successful, waiting for link up ..
    PHY = ptr_pvt_data->pdi.PhysIdx 1 
    PHY = SGMII port 0 mode 1 
    PHY = SGMII port 1 mode 2 
    AMC = SGMII port 1
    Error allocating Tx free descriptors 
    Tx setup failed 
    Error: Unable to register the EMAC
    Network Added: If-1:192.168.20.7

    Thanks, Ryan.

  • As a test what i did i would rearrange the talk again.

     

    I think, I set two mac and ip address up successfully.

    But the ping test for eth1 port doesn't work now, I could see the 50 times success ping test then fail the ping(approximately 1 minute).

    And eth0 is fine, it works with ping test But, in this case when I plug eth1 in again, the ping test with eth0 broken again.

    That means, just eth0 is ok, eth1 have some problem and doesn't work eth0 and eth1 at the same time.

    Oh my god.

    Have you had this kinds of problem?

    Please help me.

     

    Thanks, Ryan.

  • changed nimu_eth.c like below.

    So, I just can use two port at the same time.

    But I couldn't set the mac address at each port individually.

    So I just thought like this. Just using this code and set the mac address at each port using vlan function.

    But I am not sure it is possible or not setting mac addres using vlan each port.

    Do you know about this?

    As you can see until now I couldn't solve the problem which is disconnecting eth1 ping test after around 40 times.

    Please look at "ETH1_4_GIGABITETHERNET" define code.

    It is for just dual port not dual network. :)

    * @brief
    * Ethernet Packet Driver rewritten using the NIMU Packet
    * Architecture guidelines.
    *
    * Note: The NDK nimu driver interface is built based on the examples from the
    * PDK. Please refer to PDK examples
    * (<pdk_install_dir>\packages\ti\drv\pa\example\emacExample) directory to get
    * the knowledge on the QMSS, CPPI, PA LLD configurations/programs.
    *
    */
    #include <ti/platform/platform.h>
    #include "resource_mgr.h"

    #include <nimu_eth.h>
    #include <include/nimu_internal.h>
    #include <ti/csl/csl_cpsgmiiAux.h>
    #include <ti/csl/cslr_cpsgmii.h>

    /* The following code and define is used for code timing measurements of the Tx and Rx routines */
    #ifdef TIMING
    #include <ti/csl/csl_tsc.h>
    #define MAX_TIMING_PACKETS 1000
    #endif

    #define MAX_CORES 8
    uint32_t coreKey [MAX_CORES];

    /* Enable the eth1 for gigabit ethernet */
    #define ETH1_4_GIGABITETHERNET

    /**
    * @brief
    * NIMUDeviceTable
    *
    * @details
    * This is the NIMU Device Table for the Platform.
    * This should be defined for each platform. Since the current platform
    * has a single network Interface; this has been defined here. If the
    * platform supports more than one network interface this should be
    * defined to have a list of "initialization" functions for each of the
    * interfaces.
    */

    NIMU_DEVICE_TABLE_ENTRY NIMUDeviceTable[] =
    {
    /**
    * @brief EmacInit for the platform
    */
    EmacInit,
    NULL
    };

    /**
    * @b EmacStart
    * @n
    * The function is used to initialize and start the EMAC
    * controller and device.
    *
    * @param[in] ptr_net_device
    * NETIF_DEVICE structure pointer.
    *
    * @retval
    * Success - 0
    * @retval
    * Error - <0
    */
    static int EmacStart
    (
    NETIF_DEVICE* ptr_net_device
    )
    {

    EMAC_DATA* ptr_pvt_data;
    paMacAddr_t broadcast_mac_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
    paEthInfo_t ethInfo = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* Src mac = dont care */
    { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 }, /* Default Dest mac */
    0, /* vlan = dont care */
    0, /* ignore ether type */
    0 /* MPLS tag = don't care */
    };
    paRouteInfo_t routeInfo = { pa_DEST_HOST, /* Route a match to the host */
    0, /* Flow ID 0 */
    0, /* Destination queue */
    -1, /* Multi route disabled */
    0xaaaaaaaa, /* SwInfo 0 */
    0, /* SwInfo 1 is dont care */
    0, /* customType = pa_CUSTOM_TYPE_NONE */ \
    0, /* customIndex: not used */ \
    0, /* pkyType: for SRIO only */ \
    NULL /* No commands */
    };

    /* Get the pointer to the private data */
    ptr_pvt_data = (EMAC_DATA *)ptr_net_device->pvt_data;

    /* Setup Tx */
    if (Setup_Tx () != 0)
    {
    platform_write ("Tx setup failed \n");
    return -1;
    }

    /* Setup Rx */
    if (Setup_Rx (ptr_net_device) != 0)
    {
    platform_write ("Rx setup failed \n");
    return -1;
    }

    memcpy (&ethInfo.dst[0], ptr_pvt_data->pdi.bMacAddr, sizeof(paMacAddr_t));

    /* Set up the MAC Address LUT*/
    if (Add_MACAddress (&ethInfo, &routeInfo) != 0)
    {
    platform_write ("Add_MACAddress failed \n");
    return -1;
    }

    memcpy (&ethInfo.dst[0], broadcast_mac_addr, sizeof(paMacAddr_t));
    /* Set up the MAC Address LUT for Broadcast */
    if (Add_MACAddress (&ethInfo, &routeInfo) != 0)
    {
    platform_write ("Add_MACAddress failed \n");
    return -1;
    }
    /* Verify the Tx and Rx Initializations */
    if (Verify_Init () != 0)
    {
    platform_write ("Warning:Queue handler Verification failed \n");
    }

    /* Copy the MAC Address into the network interface object here. */
    mmCopy(&ptr_net_device->mac_address[0], &ptr_pvt_data->pdi.bMacAddr[0], 6);

    /* Set the 'initial' Receive Filter */
    ptr_pvt_data->pdi.Filter = ETH_PKTFLT_MULTICAST;

    ptr_pvt_data->pdi.TxFree = 1;

    return 0;
    }


    /**
    * @b EmacStop
    * @n
    * The function is used to de-initialize and stop the EMAC
    * controller and device.
    *
    * @param[in] ptr_net_device
    * NETIF_DEVICE structure pointer.
    *
    * @retval
    * Success - 0
    * @retval
    * Error - <0
    */
    static int
    EmacStop
    (
    NETIF_DEVICE* ptr_net_device
    )
    {
    EMAC_DATA* ptr_pvt_data;
    uint16_t count, i;
    Cppi_Desc* pCppiDesc;
    uint8_t* bufaddr;
    uint32_t bufLen;

    /* Disable event, interrupt */
    EventCombiner_disableEvent(PLATFORM_ETH_EVENTID);
    Hwi_disableInterrupt(PLATFORM_ETH_INTERRUPT);

    /* Get the pointer to the private data */
    ptr_pvt_data = (EMAC_DATA *)ptr_net_device->pvt_data;
    Osal_nimuFree((Ptr)ptr_pvt_data, platform_roundup(sizeof(EMAC_DATA), PLATFORM_CACHE_LINE_SIZE));

    count = Qmss_getQueueEntryCount(gRxQHnd);

    /* Free the packet data buffer associated with the Rx Descriptor */
    for (i=0; i < count; i++) {
    /* Need to free up the PBM handle */
    /* free the PBM packet */

    /* Get a free descriptor from the global free queue we setup
    * during initialization.
    */
    if ((QMSS_QPOP (gRxQHnd, QHANDLER_QPOP_FDQ_ATTACHEDBUF, (Cppi_HostDesc **)&pCppiDesc)) != NULL)
    {
    return -1;
    }

    /* Get the Address and Length for Free */
    Cppi_getOriginalBufInfo(Cppi_DescType_HOST, pCppiDesc, &bufaddr, &bufLen);
    Osal_nimuFree((Ptr)bufaddr, bufLen);
    }

    count = Qmss_getQueueEntryCount(gRxFreeQHnd);
    /* Free the packet data buffer associated with the Rx Descriptor */
    for (i=0; i < count; i++) {
    /* Need to free up the PBM handle */
    /* free the PBM packet */

    /* Get a free descriptor from the global free queue we setup
    * during initialization.
    */
    if ((QMSS_QPOP (gRxFreeQHnd, QHANDLER_QPOP_FDQ_ATTACHEDBUF, (Cppi_HostDesc **)&pCppiDesc)) != NULL)
    {
    return -1;
    }

    /* Get the Address and Length for Free */
    Cppi_getOriginalBufInfo(Cppi_DescType_HOST, pCppiDesc, &bufaddr, &bufLen);
    Osal_nimuFree ((Ptr)bufaddr, bufLen);
    }


    /* tear down queues and dmas */
    res_mgr_stop_qmss();
    Qmss_queueClose (gPaCfgCmdRespQHnd);
    Qmss_queueClose (gTxFreeQHnd);
    Qmss_queueClose (gRxFreeQHnd);
    Qmss_queueClose (gRxQHnd);
    Qmss_queueClose (gTxReturnQHnd);

    for (i = 0; i < NUM_PA_TX_QUEUES; i++)
    Qmss_queueClose (gPaTxQHnd[i]);

    res_mgr_stop_cppi(CPPI_CFG_PASS);

    /* EMAC Controller has been stopped. */
    return 0;
    }
    #ifndef SIMULATOR_SUPPORT
    /**
    * @b emac_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
    emac_display_linkstatus
    (
    uint32_t port_num,
    uint32_t 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" };

    platform_write("Port %d Link Status: %s on PHY %d\n",
    port_num, LinkStr[link_status],
    platform_get_phy_addr(port_num));
    }
    #endif

    /**
    * @b EmacPoll
    * @n
    * The function is used to poll the EMAC controller to check
    * if there has been any activity
    *
    * @param[in] ptr_net_device
    * NETIF_DEVICE structure pointer.
    * @param[in] timer_tick
    * Flag to poll the driver.
    *
    * @retval
    * void
    */
    static void EmacPoll (NETIF_DEVICE* ptr_net_device, uint timer_tick)
    {
    return;
    }

    /*
    * Routine to debug transmit descriptors
    */
    #define DEBUG_TX_DESC 0
    #if DEBUG_TX_DESC
    #pragma DATA_SECTION(TxDescArray, ".DbgSection");
    Cppi_HostDesc TxDescArray[NUM_TX_DESC];
    int TxDescArrayIndex = 0;
    int gtotal_pkts_freed = 0;
    #pragma DATA_SECTION(DescIndexArray, ".DbgSection");
    int32_t DescIndexArray[NIMU_NUM_TX_DESC];
    int32_t gDescTest = 0;
    printHostDesc (Cppi_HostDesc* pHostDesc)
    {
    platform_write (" pHostDesc->buffLen =%ld \n" , pHostDesc->buffLen );
    platform_write (" pHostDesc->buffPtr =%ld \n" , pHostDesc->buffPtr );
    platform_write (" pHostDesc->descInfo =%ld \n" , pHostDesc->descInfo );
    platform_write (" pHostDesc->nextBDPtr =%ld \n" , pHostDesc->nextBDPtr );
    platform_write (" pHostDesc->origBufferLen =%ld \n" , pHostDesc->origBufferLen);
    platform_write (" pHostDesc->origBuffPtr =%ld \n" , pHostDesc->origBuffPtr );
    platform_write (" pHostDesc->packetInfo =%ld \n" , pHostDesc->packetInfo );
    platform_write (" pHostDesc->psData =%ld \n" , pHostDesc->psData );
    platform_write (" pHostDesc->softwareInfo0 =%ld \n" , pHostDesc->softwareInfo0);
    platform_write (" pHostDesc->softwareInfo1 =%ld \n" , pHostDesc->softwareInfo1);
    platform_write (" pHostDesc->softwareInfo2 =%ld \n" , pHostDesc->softwareInfo2);
    platform_write (" pHostDesc->tagInfo =%ld \n" , pHostDesc->tagInfo );
    platform_write (" pHostDesc->timeStamp =%ld \n" , pHostDesc->timeStamp );
    }
    #endif


    /**
    * @b EmacSend
    * @n
    * The function is the interface routine invoked by the NDK stack to
    * pass packets to the driver.
    *
    * @param[in] ptr_net_device
    * NETIF_DEVICE structure pointer.
    * @param[in] hPkt
    * Packet to be sent out on wire.
    *
    * @retval
    * Success - 0
    * @retval
    * Error - <0
    */

    #ifdef TIMING
    #pragma DATA_SECTION(txisr_time, ".TimingSection");
    uint32_t txisr_time[MAX_TIMING_PACKETS];
    #pragma DATA_SECTION(txisr_time_idx, ".TimingSection");
    uint32_t txisr_time_idx = 0;
    #pragma DATA_SECTION(txisr_free_count, ".TimingSection");
    uint32_t txisr_free_count[MAX_TIMING_PACKETS];
    #endif

    static int
    EmacSend (NETIF_DEVICE* ptr_net_device, PBM_Handle hPkt)
    {
    EMAC_DATA* ptr_pvt_data;
    Cppi_Desc* pCppiDesc;
    uint32_t dataBufferSize, i, count=0;
    register uint8_t* buffer;
    register uint32_t length;
    Cppi_HostDesc* pHostDesc;
    uint32_t coreNum;
    Ptr key;
    #ifdef TIMING
    CSL_Uint64 st,et;
    #endif

    #ifdef TIMING
    st = 0;
    et = 0;
    #endif

    #ifdef TIMING_TX
    /* record start time */
    if (txisr_time_idx < MAX_TIMING_PACKETS) {
    st = CSL_tscRead();
    }
    #endif

    /* Begin Critical Section before accessing shared resources. */
    key = Osal_cppiCsEnter();

    /* Get the core number. */
    coreNum = platform_get_coreid();

    count = Qmss_getQueueEntryCount (gTxReturnQHnd);


    /* Check if we got to free up any PBM handles? */
    #ifdef TIMING_FREE
    if (txisr_time_idx < MAX_TIMING_PACKETS) {
    st = CSL_tscRead();
    txisr_free_count[txisr_time_idx] = count;
    }
    #endif

    for (i = 0; i < count; i++) {
    PBM_Handle hPkt_to_free;

    /* Need to free up the PBM handle */
    /* free the PBM packet */

    /* Get a free descriptor from the global free queue we setup
    * during initialization.
    */
    if ((QMSS_QPOP (gTxReturnQHnd, QHANDLER_QPOP_FDQ_ATTACHEDBUF, (Cppi_HostDesc **)&pCppiDesc)) != NULL)
    {
    goto error_cond;
    }
    pHostDesc = (Cppi_HostDesc *)pCppiDesc;

    /* Software info is intended to hold the PBM Pkt Handle for buffer management */
    hPkt_to_free = (PBM_Handle ) pHostDesc->softwareInfo0;

    /* Clear the PBM Handle set in the descriptor */
    pHostDesc->softwareInfo0 = NULL;

    /* Push descriptor to Tx free queue */
    QMSS_QPUSH (gTxFreeQHnd, (Ptr)pHostDesc, pHostDesc->buffLen, SIZE_HOST_DESC, Qmss_Location_TAIL);

    PBM_free( (PBM_Handle) hPkt_to_free);

    }

    #ifdef TIMING_FREE
    /* record end time */
    if (txisr_time_idx < MAX_TIMING_PACKETS) {
    et = CSL_tscRead();
    txisr_time[txisr_time_idx++] = (uint32_t) (et - st);
    }
    #endif

    /* Get the pointer to the private data */
    ptr_pvt_data = (EMAC_DATA *)ptr_net_device->pvt_data;

    /* Make sure the driver does not transmit packet less than min. as per the
    * Ethernet standards. */
    if( PBM_getValidLen(hPkt) < 60 )
    PBM_setValidLen (hPkt, 64 );

    /* We do not do any packet size checks here. If the packet
    * is too big to fit in the MTU configured on the peripheral,
    * then the driver/CSL layer should catch the error.
    */
    if(1)
    {
    /* Peek into the packet to check out if any
    * prioritization is needed.
    *
    * All raw Ethernet packets are tagged with the EMAC
    * channel number onto which they need to be sent out
    * in the PktPriority field.
    */
    if (((PBM_Pkt *)hPkt)->PktPriority != PRIORITY_UNDEFINED)
    {
    /* PktPriority contains the EMAC channel number on which
    * the packet needs to be txed.
    */
    ptr_pvt_data->pdi.PhysIdx = (((PBM_Pkt *)hPkt)->PktPriority);
    }
    else
    {
    /* This is just a normal IP packet. Enqueue the packet in the
    * Tx queue and send it for transmission.
    * We are assuming here that the IP packets are transmitted
    * on Channel 0 -> Core 0; Channel 1 --> Core 1; Channel 2 --> Core 2.
    * and that the Raw packets can be transmitted on any channel.
    */
    ptr_pvt_data->pdi.PhysIdx = coreNum;
    }

    /* Pass the packet to the controller if the transmitter is free. */
    if(ptr_pvt_data->pdi.TxFree )
    {
    buffer = PBM_getDataBuffer(hPkt) + PBM_getDataOffset(hPkt);
    length = PBM_getValidLen(hPkt);
    /* Clean the cache for external/L2 addresses */
    if( ((uint32_t)buffer & EMAC_EXTMEM ) ||
    ((uint32_t)buffer & EMAC_LL2SRAM ) ) {
    OEMCacheClean( (void *)buffer, length );
    }

    /* Get a free descriptor from the global free queue we setup
    * during initialization.
    */
    if ((QMSS_QPOP (gTxFreeQHnd, QHANDLER_QPOP_FDQ_NO_ATTACHEDBUF, (Cppi_HostDesc **)&pCppiDesc)) != NULL)
    {
    gTxDropCounter++;
    goto error_cond;
    }

    pHostDesc = (Cppi_HostDesc *)pCppiDesc;

    pHostDesc->softwareInfo0 = (uint32_t) hPkt;

    dataBufferSize = length;
    Cppi_setData ( Cppi_DescType_HOST,
    (Cppi_Desc *) pCppiDesc,
    (uint8_t *) Convert_CoreLocal2GlobalAddr((uint32_t)buffer),
    dataBufferSize
    );
    Cppi_setPacketLen (Cppi_DescType_HOST, (Cppi_Desc *)pCppiDesc, dataBufferSize);

    count = Qmss_getQueueEntryCount (gTxReturnQHnd);

    #ifdef PA_LOOPBACK
    QMSS_QPUSH (gPaTxQHnd[0], pCppiDesc, dataBufferSize, SIZE_HOST_DESC, Qmss_Location_TAIL);
    #else
    #ifdef ETH1_4_GIGABITETHERNET
    #else
    Cppi_setPSFlags (Cppi_DescType_HOST, (Cppi_Desc *)pCppiDesc, (1<<gTxPort));
    #endif
    /* Send the packet out the mac. It will loop back to PA if the mac/switch
    * have been configured properly
    */
    QMSS_QPUSH (gPaTxQHnd[8], pCppiDesc, dataBufferSize, SIZE_HOST_DESC, Qmss_Location_TAIL);
    #endif

    /* Increment the application transmit counter */
    gTxCounter ++;
    }

    /* Packet has been successfully transmitted. */
    /* End Critical Section */
    Osal_cppiCsExit (key);

    #ifdef TIMING_TX
    /* record end time */
    if (txisr_time_idx < MAX_TIMING_PACKETS) {
    et = CSL_tscRead();
    txisr_time[txisr_time_idx++] = (uint32_t) (et - st);
    }
    #endif
    return 0;
    }

    error_cond:
    {

    /* End Critical Section */
    Osal_cppiCsExit (key);

    #ifdef TIMING_TX
    /* record end time */
    if (txisr_time_idx < MAX_TIMING_PACKETS) {
    et = CSL_tscRead();
    txisr_time[txisr_time_idx++] = (uint32_t) (et - st);
    }

    #endif
    return -1;
    }
    }

    /**
    * @b Description
    * @n
    * Call back function provided by application for EMAC driver
    * to report a received packet descriptor.
    *
    * @retval
    * None.
    */
    static Bool gIsPingListUsed = 0;

    #ifdef TIMING
    #pragma DATA_SECTION(rxisr_time, ".TimingSection");
    uint32_t rxisr_time[MAX_TIMING_PACKETS]; /* hold start time, end time, start time, end time, etc */
    #pragma DATA_SECTION(rxisr_time_idx, ".TimingSection");
    uint32_t rxisr_time_idx;
    #pragma DATA_SECTION(rxisr_pktcount, ".TimingSection");
    uint32_t rxisr_pktcount;
    #endif

    void
    EmacRxPktISR
    (
    NETIF_DEVICE* ptr_net_device
    )
    {
    uint32_t protocol, pktLen;
    uint8_t* pBuffer;
    Cppi_HostDesc* pHostDesc;
    PBM_Handle hPkt;
    Cppi_Desc* pCppiDesc;
    uint32_t count, i;
    uint32_t* ListAddress;
    EMAC_DATA* ptr_pvt_data;
    PBM_Pkt* rx_pbm_pkt;
    void* key;
    void* accum_list_ptr;
    #ifdef TIMING
    CSL_Uint64 st, et;
    #endif

    #ifdef TIMING
    /* record start time */
    if (rxisr_pktcount < MAX_TIMING_PACKETS) {
    st = CSL_tscRead();
    }
    #endif

    /* Disable the interrupt */
    coreKey [CSL_chipReadReg (CSL_CHIP_DNUM)] = Hwi_disableInterrupt(PLATFORM_ETH_INTERRUPT); //Hwi_disable();

    /* Begin Critical Section before accessing shared resources. */
    key = Osal_qmssCsEnter ();

    /* Get the pointer to the private data */
    ptr_pvt_data = (EMAC_DATA *)ptr_net_device->pvt_data;

    if (!gIsPingListUsed){
    accum_list_ptr = (void *)&gHiPriAccumList[0];
    }
    else {
    accum_list_ptr = (void *)&gHiPriAccumList[MAX_HI_PRI_ACCUM_LIST_SIZE];
    }


    /* Invalidate cache if needed --
    * if accumulator is in DDR then INV L2.
    * if accumulator is in shared RAM (MSMC) invalidate L1
    */
    if((uint32_t)(gHiPriAccumList) & EMAC_EXTMEM ){
    CACHE_invL2(accum_list_ptr, sizeof(gHiPriAccumList)/2, CACHE_WAIT);
    }

    if ((uint32_t)(gHiPriAccumList) & EMAC_MSMCSRAM ) {
    CACHE_invL1d(accum_list_ptr, sizeof(gHiPriAccumList)/2, CACHE_WAIT);
    }

    i = MAX_HI_PRI_ACCUM_LIST_SIZE - 1 - (RX_INT_THRESHOLD);
    ListAddress = (uint32_t* )Convert_CoreLocal2GlobalAddr((uint32_t) &gHiPriAccumList[i]);

    /* Process ISR.
    *
    * Get the number of entries in accumulator list.
    * The hardware enqueues data alternatively to Ping/Pong buffer lists in
    * the accumulator. Hence, we need to track which list (Ping/Pong)
    * we serviced the last time and accordingly process the other one
    * this time around.
    */
    if (!gIsPingListUsed)
    {
    /* Serviced Pong list last time. So read off the Ping list now */
    count = ListAddress[0];
    }
    else
    {
    /* Serviced Pong list last time. So read off the Ping list now */
    count = ListAddress[RX_INT_THRESHOLD + 1];
    }

    /* Nothing to receive, so return... */
    if (count == 0) {
    /* End Critical Section */
    Osal_qmssCsExit (key);
    Hwi_restoreInterrupt(PLATFORM_ETH_INTERRUPT, coreKey [CSL_chipReadReg (CSL_CHIP_DNUM)]);
    /* Clear INTD */
    Qmss_ackInterrupt(PA_ACC_CHANNEL_NUM, 1);
    Qmss_setEoiVector(Qmss_IntdInterruptType_HIGH, PA_ACC_CHANNEL_NUM);
    return ; /* Not enough packets are received */
    }

    /* Process all the Results received
    *
    * Skip the first entry in the list that contains the
    * entry count and proceed processing results.
    */
    for (i = 1; i <= count; i ++)
    {

    gRxCounter ++;

    /* Get the result descriptor.
    *
    * The hardware enqueues data alternatively to Ping/Pong buffer lists in
    * the accumulator. Hence, we need to track which list (Ping/Pong)
    * we serviced the last time and accordingly process the other one
    * this time around.
    */
    if (!gIsPingListUsed)
    {
    /* Serviced Pong list last time. So read off the Ping list now */
    pCppiDesc = (Cppi_Desc *) ListAddress [i];
    }
    else
    {
    /* Serviced Ping list last time. So read off the Pong list now
    *
    * Skip over Ping list length to arrive at Pong list start.
    */
    pCppiDesc = (Cppi_Desc *) ListAddress [i + RX_INT_THRESHOLD + 1];
    }

    /* Descriptor size appended to the address in the last 4 bits.
    *
    * To get the true descriptor size, always mask off the last
    * 4 bits of the address.
    */
    pCppiDesc = (Ptr) ((uint32_t) pCppiDesc & 0xFFFFFFF0);
    pHostDesc = (Cppi_HostDesc *)pCppiDesc;

    /* Invalidate cache based on where the memory is */
    if((uint32_t)(pHostDesc) & EMAC_EXTMEM ){
    CACHE_invL2((void *) pHostDesc, sizeof(Cppi_HostDesc), CACHE_WAIT);
    }

    if ((uint32_t)(pHostDesc) & EMAC_MSMCSRAM ) {
    CACHE_invL1d((void *)pHostDesc, sizeof(Cppi_HostDesc), CACHE_WAIT);
    }

    if((uint32_t)(pHostDesc->buffPtr) & EMAC_EXTMEM ){
    CACHE_invL2((void *) pHostDesc->buffPtr, pHostDesc->buffLen, CACHE_WAIT);
    }

    if ((uint32_t)(pHostDesc->buffPtr) & EMAC_MSMCSRAM ) {
    CACHE_invL1d((void *)pHostDesc->buffPtr, pHostDesc->buffLen, CACHE_WAIT);
    }

    /*
    * We should not see packets too large but check anyways ...
    * Note that we are subtracting off the FCS the switch added to the frame.
    * If its too large then return it to the free queue.
    */
    if ((pHostDesc->buffLen-4) > (ptr_net_device->mtu + ETHHDR_SIZE)) {
    /* lets try the next one... we should record this as a too large.... */
    gRxDropCounter++;
    pHostDesc->buffLen = pHostDesc->origBufferLen;
    QMSS_QPUSH (gRxFreeQHnd, (Ptr)pHostDesc, pHostDesc->buffLen, SIZE_HOST_DESC, Qmss_Location_TAIL);
    continue;
    }

    /* Allocate the PBM packet for the Max MTU size*/
    if (NULL == (hPkt = PBM_alloc(1514))) {
    /* could not get a free NDK packet, maybe the next time around we can... */
    gRxDropCounter++;
    pHostDesc->buffLen = pHostDesc->origBufferLen;
    QMSS_QPUSH (gRxFreeQHnd, (Ptr)pHostDesc, pHostDesc->buffLen, SIZE_HOST_DESC, Qmss_Location_TAIL);
    continue;
    }

    rx_pbm_pkt = (PBM_Pkt *) hPkt;

    PBM_setDataOffset((PBM_Handle) hPkt, 0);

    /* removing the FCS length the EMAC switch adds here */
    pktLen = (pHostDesc->buffLen-4);

    /* Set to minimum packet size */
    if (pktLen < 60) {
    pktLen = 64;
    }

    PBM_setValidLen((PBM_Handle) hPkt, pktLen);

    /* Handle raw frames separately, i.e. check the
    * Ethernet Protocol type in this packet and see
    * if its a well known ether type. If so, this is normal
    * IP stream, enqueue this is in usual Rx queue and let the
    * stack know that a packet has arrived for it. However, if
    * the Ethernet type in the packet is not a well known one,
    * this could be a custom raw Ethernet packet, enqueue it
    * separately in the Raw Rx queue and notify stack. The Raw
    * Ethernet packets when being handed over are given
    * preferential treatment and are serviced before the normal
    * IP traffic. Hence the 2 queues.
    */
    pBuffer = (uint8_t* )Convert_CoreLocal2GlobalAddr((uint32_t) pHostDesc->buffPtr);

    /* Extract the Ethernet type from the packet. */
    protocol = ( pBuffer[12] << 8) | pBuffer[13] ;
    protocol = (protocol & 0xFFFFu);

    PBM_setIFRx((PBM_Handle) hPkt, (HANDLE) protocol );

    /* Copy the data buffer received to the allocated PBM packet */
    mmCopy((uint8_t* )rx_pbm_pkt->pDataBuffer, (uint8_t* )pBuffer, pktLen) ;

    /* Is it a standard ethernet type? */
    if (protocol != ETHERTYPE_IP && protocol != ETHERTYPE_IPv6 && protocol != ETHERTYPE_VLAN
    && protocol != ETHERTYPE_PPPOECTL && protocol != ETHERTYPE_PPPOEDATA )
    {
    /* This is a raw packet, enqueue in Raw Rx Queue */
    PBMQ_enq( &ptr_pvt_data->pdi.PBMQ_rawrx, (PBM_Handle) hPkt);
    }
    else
    { /* This is a normal IP packet. Enqueue in Rx Queue */
    PBMQ_enq( &ptr_pvt_data->pdi.PBMQ_rx, (PBM_Handle) hPkt );
    }

    /* Free the packet back to the Rx FDQ */
    pHostDesc->buffLen = pHostDesc->origBufferLen;
    QMSS_QPUSH (gRxFreeQHnd, (Ptr)pHostDesc, pHostDesc->buffLen, SIZE_HOST_DESC, Qmss_Location_TAIL);
    }

    ListAddress = (uint32_t *) Convert_CoreLocal2GlobalAddr((uint32_t) &gHiPriAccumList[0]);

    /* Clear the accumulator list and save whether we used Ping/Pong
    * list information for next time around.
    */
    if (!gIsPingListUsed)
    {
    /* Just processed Ping list */
    gIsPingListUsed = 1;

    i = sizeof (gHiPriAccumList)/2;

    /* Clear the accumulator list after processing */
    memset ((Void *) &gHiPriAccumList[0], 0, i);

    if(
    ((uint32_t)(&gHiPriAccumList[0]) & EMAC_EXTMEM ) ||
    ((uint32_t)(&gHiPriAccumList[0]) & EMAC_MSMCSRAM )
    )
    {
    /* This needs to be enabled if gHiPriAccumList is in External Memory or MSMCMEM */
    CACHE_wbL2 ((void *)&gHiPriAccumList[0], i, CACHE_WAIT);
    }
    }
    else
    {
    /* Just processed Pong list */
    gIsPingListUsed = 0;
    i = sizeof (gHiPriAccumList)/2;

    /* Clear the accumulator list after processing */
    memset ((Void *) &gHiPriAccumList[MAX_HI_PRI_ACCUM_LIST_SIZE], 0, i);

    if(
    ((uint32_t)(&gHiPriAccumList[MAX_HI_PRI_ACCUM_LIST_SIZE]) & EMAC_EXTMEM ) ||
    ((uint32_t)(&gHiPriAccumList[MAX_HI_PRI_ACCUM_LIST_SIZE]) & EMAC_MSMCSRAM )
    )
    {
    /* This needs to be enabled if gHiPriAccumList is in External Memory or MSMCMEM */
    CACHE_wbL2((void *) &gHiPriAccumList[MAX_HI_PRI_ACCUM_LIST_SIZE], i, CACHE_WAIT);
    }
    }

    /* Notify NDK stack of pending Rx Ethernet packet */
    STKEVENT_signal( ptr_pvt_data->pdi.hEvent, STKEVENT_ETHERNET, 1 );

    /* End Critical Section */
    Osal_qmssCsExit (key);
    Hwi_restoreInterrupt(PLATFORM_ETH_INTERRUPT, coreKey [CSL_chipReadReg (CSL_CHIP_DNUM)]);

    #ifdef TIMING
    /* record end time */
    if (rxisr_pktcount < MAX_TIMING_PACKETS) {
    et = CSL_tscRead();
    rxisr_time[rxisr_time_idx++] = (uint32_t) (et-st);
    rxisr_pktcount += count;
    }
    #endif

    /* Clear INTD */
    Qmss_ackInterrupt(PA_ACC_CHANNEL_NUM, 1);
    Qmss_setEoiVector(Qmss_IntdInterruptType_HIGH, PA_ACC_CHANNEL_NUM);

    return;
    }

    /**
    * @b EmacPktService
    * @n
    * The function is called by the NDK core stack to receive any packets
    * from the driver.
    *
    * @param[in] ptr_net_device
    * NETIF_DEVICE structure pointer.
    *
    * @retval
    * void
    */
    static void EmacPktService (NETIF_DEVICE* ptr_net_device)
    {
    EMAC_DATA* ptr_pvt_data;
    PBM_Handle hPacket;

    /* Get the pointer to the private data */
    ptr_pvt_data = (EMAC_DATA *)ptr_net_device->pvt_data;

    /* Give all queued Raw packets first to the Ether module */
    while (PBMQ_count(&ptr_pvt_data->pdi.PBMQ_rawrx))
    {
    /* Dequeue a packet from the driver's Raw receive queue. */
    hPacket = PBMQ_deq(&ptr_pvt_data->pdi.PBMQ_rawrx);

    /* Prepare the packet so that it can be passed up the networking stack.
    * If this 'step' is not done the fields in the packet are not correct
    * and the packet will eventually be dropped. */
    PBM_setIFRx (hPacket, ptr_net_device);

    /* Pass the packet to the NDK Core stack. */
    NIMUReceivePacket(hPacket);
    }

    /* Give all queued IP packets to the Ether module */
    while (PBMQ_count(&ptr_pvt_data->pdi.PBMQ_rx))
    {
    /* Dequeue a packet from the driver receive queue. */
    hPacket = PBMQ_deq(&ptr_pvt_data->pdi.PBMQ_rx);

    /* Prepare the packet so that it can be passed up the networking stack.
    * If this 'step' is not done the fields in the packet are not correct
    * and the packet will eventually be dropped. */
    PBM_setIFRx (hPacket, ptr_net_device);

    /* Pass the packet to the NDK Core stack. */
    NIMUReceivePacket(hPacket);
    }

    /* Work has been completed; the receive queue is empty... */
    return;
    }


    /**
    * @b Emacioctl
    * @n
    * The function is called by the NDK core stack to configure the
    * driver
    *
    * @param[in] ptr_net_device
    * NETIF_DEVICE structure pointer.
    * @param[in] cmd
    * Ioctl command.
    * @param[in] pBuf
    * Mac address to be added or deleted.
    * @param[in] size
    * Size of Mac Address.
    *
    * @retval
    * Success - 0
    * @retval
    * Error - <0
    */
    static int Emacioctl (NETIF_DEVICE* ptr_net_device, uint cmd, void* pBuf, uint size)
    {
    switch(cmd)
    {
    case NIMU_ADD_MULTICAST_ADDRESS:
    /*
    caller: ptr_device->ioctl (ptr_device, NIMU_ADD_MULTICAST_ADDRESS, (void *)&bMacAddr[0], 6) (ndk_2_21_01_38/packages/ti/ndk/stack/igmp/igmp.c)
    */
    {
    paEthInfo_t ethInfo = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* Src mac = dont care */
    { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 }, /* Default Dest mac */
    0, /* vlan = dont care */
    0, /* ignore ether type */
    0 /* MPLS tag = don't care */
    };
    paRouteInfo_t routeInfo = { pa_DEST_HOST, /* Route a match to the host */
    0, /* Flow ID 0 */
    0, /* Destination queue */
    -1, /* Multi route disabled */
    0xaaaaaaaa, /* SwInfo 0 */
    0, /* SwInfo 1 is dont care */
    0, /* customType = pa_CUSTOM_TYPE_NONE */ \
    0, /* customIndex: not used */ \
    0, /* pkyType: for SRIO only */ \
    NULL /* No commands */
    };

    memcpy (&ethInfo.dst[0], pBuf, size);
    /* Set up the MAC Address LUT for Broadcast */
    if (Add_MACAddress (&ethInfo, &routeInfo) != 0)
    {
    platform_write ("Add_MACAddress failed \n");
    return -1;
    }
    platform_write ("Add_MACAddress success\n");

    }
    break;

    //Todo
    case NIMU_DEL_MULTICAST_ADDRESS:

    break;
    default:
    break;
    }
    return 0;
    }


    /**
    * @b EmacInit
    * @n
    * The function is used to initialize and register the EMAC
    * with the Network Interface Management Unit (NIMU)
    *
    * @param[in] hEvent
    * Stack Event Handle.
    *
    * @retval
    * Success - 0
    * @retval
    * Error - <0
    */
    static int EmacInit (STKEVENT_Handle hEvent)
    {
    EMACInit_Core(hEvent);

    return 0;
    }

    static int EMACInit_Core (STKEVENT_Handle hEvent)
    {
    NETIF_DEVICE* ptr_device;
    EMAC_DATA* ptr_pvt_data;
    char names[6][5]={"eth0","eth1","eth2","eth3","eth4","eth5"};
    uint32_t coreNum, i;
    PLATFORM_EMAC_EXT_info emac_info;

    /* Get the core number. */
    coreNum = platform_get_coreid();

    /* Allocate memory for the private data */
    ptr_pvt_data = Osal_nimuMalloc (platform_roundup(sizeof(EMAC_DATA), PLATFORM_CACHE_LINE_SIZE), PLATFORM_CACHE_LINE_SIZE);

    if (ptr_pvt_data == NULL)
    {
    platform_write ("Error: Unable to allocate private memory data\n");
    return -1;
    }

    /* Initialize the allocated memory block. */
    mmZeroInit (ptr_pvt_data, sizeof(EMAC_DATA));

    /* Initialize the RX Queue */
    PBMQ_init(&ptr_pvt_data->pdi.PBMQ_rx);
    PBMQ_init(&ptr_pvt_data->pdi.PBMQ_rawrx);

    /* Initialize the private data */
    mmZeroInit(&ptr_pvt_data->pdi, sizeof(PDINFO));

    /* Set physical index */
    ptr_pvt_data->pdi.PhysIdx = coreNum;
    ptr_pvt_data->pdi.hEvent = hEvent;

    /* MCast List is EMPTY */
    ptr_pvt_data->pdi.MCastCnt = 0;

    #ifndef SIMULATOR_SUPPORT
    #ifdef ETH1_4_GIGABITETHERNET
    platform_get_emac_info(0, &emac_info);
    memcpy(ptr_pvt_data->pdi.bMacAddr, emac_info.mac_address, 6);
    #else
    for (i = 0; i < PLATFORM_MAX_EMAC_PORT_NUM; i++)
    {
    platform_get_emac_info (i, &emac_info);
    if (emac_info.mode == PLATFORM_EMAC_PORT_MODE_PHY)
    {
    break;
    }
    }
    if (i < PLATFORM_MAX_EMAC_PORT_NUM)
    {
    gTxPort = emac_info.port_num;
    memcpy(ptr_pvt_data->pdi.bMacAddr, emac_info.mac_address, 6);
    }
    else
    {
    platform_write ("Error: Unable to find a TX EMAC port\n");
    return -1;
    }
    #endif
    #else
    {
    gTxPort = 1;
    platform_get_emac_info (1, &emac_info);
    memcpy(ptr_pvt_data->pdi.bMacAddr, emac_info.mac_address, 6);
    }
    #endif

    /* Init Logical Device */
    /* ptr_pvt_data->pdi.hEther = hEther; */

    /* Allocate memory for the EMAC. */
    /* ptr_device needs to be allocated via mmAlloc since NDK frees it during shutdown */
    ptr_device = mmAlloc(sizeof(NETIF_DEVICE));

    if (ptr_device == NULL)
    {
    platform_write ("Error: Unable to allocate memory for the EMAC\n");
    return -1;
    }

    /* Initialize the allocated memory block. */
    mmZeroInit (ptr_device, sizeof(NETIF_DEVICE));

    /* Populate the Network Interface Object. */
    strcpy (ptr_device->name, names[coreNum]);
    ptr_device->mtu = ETH_MAX_PAYLOAD - ETHHDR_SIZE;
    ptr_device->pvt_data = (void *)ptr_pvt_data;

    /* Populate the Driver Interface Functions. */
    ptr_device->start = EmacStart;
    ptr_device->stop = EmacStop;
    ptr_device->poll = EmacPoll;
    ptr_device->send = EmacSend;
    ptr_device->pkt_service = EmacPktService;
    ptr_device->ioctl = Emacioctl;
    ptr_device->add_header = NIMUAddEthernetHeader;

    /* Init PA LLD */
    if (Init_PASS () != 0)
    {
    platform_write ("PASS init failed \n");
    return -1;
    }
    else
    {
    platform_write ("PASS successfully initialized \n");
    }

    /* Initialize the CPSW switch */
    if (Init_Cpsw ((uint32_t) ptr_device->mtu, ptr_pvt_data->pdi.bMacAddr) != 0)
    {
    platform_write ("Ethernet subsystem init failed \n");
    return -1;
    }
    else
    {
    platform_write ("Ethernet subsystem successfully initialized \n");
    }

    /* Register the device with NIMU */
    if (NIMURegister (ptr_device) < 0)
    {
    platform_write ("Error: Unable to register the EMAC\n");
    return -1;
    }

    platform_write ("Registration of the EMAC Successful, waiting for link up ..\n");
    return 0;

    }


    /** ============================================================================
    * @n@b Setup_Tx
    *
    * @b Description
    * @n This API sets up all relevant data structures and configuration required
    * for sending data to PASS/Ethernet. It sets up a Tx free descriptor queue,
    * PASS Tx queues required for send.
    *
    * @param[in]
    * @n None
    *
    * @return int32_t
    * -1 - Error
    * 0 - Success
    * =============================================================================
    */
    int32_t Setup_Tx (Void)
    {
    uint8_t isAllocated, i;
    Qmss_Queue qRetInfo;
    Ptr pCppiDesc;
    uint32_t mySWInfo[] = {0x00000000, 0x00000000, 0x00000000};

    /* Open all Transmit (Tx) queues.
    *
    * These queues are used to send data to PA PDSP/CPSW.
    */
    for (i = 0; i < NUM_PA_TX_QUEUES; i ++)
    {

    if ((gPaTxQHnd[i] = Qmss_queueOpen (Qmss_QueueType_PASS_QUEUE, QMSS_PARAM_NOT_SPECIFIED, &isAllocated)) < 0)
    {
    platform_write ("Error opening PA Tx queue \n");
    return -1;
    }
    }

    /* Open a Tx Free Descriptor Queue (Tx FDQ).
    *
    * This queue will be used to hold Tx free decriptors that can be filled
    * later with data buffers for transmission onto wire.
    */
    if ((gTxFreeQHnd = Qmss_queueOpen (Qmss_QueueType_STARVATION_COUNTER_QUEUE, QMSS_PARAM_NOT_SPECIFIED, &isAllocated)) < 0)
    {
    platform_write ("Error opening Tx Free descriptor queue \n");
    return -1;
    }

    /* Open a Tx Return Descriptor Queue (Tx Transmit CompletionQ).
    *
    * This queue will be used to hold Tx completed decriptors that can be filled
    * later with data buffers for transmission onto wire.
    */
    if ((gTxReturnQHnd = Qmss_queueOpen (Qmss_QueueType_GENERAL_PURPOSE_QUEUE, QMSS_PARAM_NOT_SPECIFIED, &isAllocated)) < 0)
    {
    platform_write ("Error opening Tx Return descriptor queue \n");
    return -1;
    }

    qRetInfo = Qmss_getQueueNumber (gTxReturnQHnd);

    /* Attach some free descriptors to the Tx free queue we just opened. */
    for (i = 0; i < NIMU_NUM_TX_DESC; i++)
    {
    /* Get a free descriptor from the global free queue we setup
    * during initialization.
    */
    if ((QMSS_QPOP (res_mgr_qmss_get_freeq(), QHANDLER_QPOP_FDQ_NO_ATTACHEDBUF, (Cppi_HostDesc **)&pCppiDesc )) != NULL)
    {
    break;
    }

    /* Setup the Completion queue:
    *
    * Setup the return policy for this desc to return to the completion q we just
    * setup instead of the global free queue.
    */
    Cppi_setReturnQueue ((Cppi_DescType) Cppi_DescType_HOST, pCppiDesc, qRetInfo);

    /* Software info is inteded to hold the PBM Pkt Handle for buffer management */
    mySWInfo[1] = i;
    Cppi_setSoftwareInfo (Cppi_DescType_HOST, pCppiDesc, (uint8_t *) mySWInfo);

    /* Push descriptor to Tx free queue */
    QMSS_QPUSHDESCSIZE (gTxFreeQHnd, pCppiDesc, SIZE_HOST_DESC);
    }
    if (i != NIMU_NUM_TX_DESC)
    {
    platform_write ("Error allocating Tx free descriptors \n");
    return -1;
    }

    /* Open a Tx Command Free Descriptor Queue (Tx CMD FDQ).
    *
    * This queue will be used to hold Tx Command free decriptors
    */
    if ((gTxCmdFreeQHnd = Qmss_queueOpen (Qmss_QueueType_STARVATION_COUNTER_QUEUE, QMSS_PARAM_NOT_SPECIFIED, &isAllocated)) < 0)
    {
    platform_write ("Error opening Tx Cmd Free descriptor queue \n");
    return -1;
    }

    /* Open a Tx Cmd Return Descriptor Queue (Tx Cmd Completion Queue).
    *
    * This queue will be used to hold Tx command completed decriptors
    */
    if ((gTxCmdReturnQHnd = Qmss_queueOpen (Qmss_QueueType_GENERAL_PURPOSE_QUEUE, QMSS_PARAM_NOT_SPECIFIED, &isAllocated)) < 0)
    {
    platform_write ("Error opening Tx Return descriptor queue \n");
    return -1;
    }

    qRetInfo = Qmss_getQueueNumber (gTxCmdReturnQHnd);

    /* Attach some free descriptors to the Tx CMD free queue we just opened. */
    for (i = 0; i < NIMU_MAX_NUM_TX_CMD_DESC; i++)
    {
    /* Get a free descriptor from the global free queue we setup
    * during initialization.
    */
    if ((QMSS_QPOP (res_mgr_qmss_get_freeq(), QHANDLER_QPOP_FDQ_NO_ATTACHEDBUF, (Cppi_HostDesc **)&pCppiDesc )) != NULL)
    {
    break;
    }

    /* Setup the Completion queue:
    *
    * Setup the return policy for this desc to return to the completion q we just
    * setup instead of the global free queue.
    */
    Cppi_setReturnQueue ((Cppi_DescType) Cppi_DescType_HOST, pCppiDesc, qRetInfo);


    /* Push descriptor to Tx free queue */
    QMSS_QPUSHDESCSIZE (gTxCmdFreeQHnd, pCppiDesc, SIZE_HOST_DESC);
    }
    if (i != NIMU_MAX_NUM_TX_CMD_DESC)
    {
    platform_write ("Error allocating Tx Command free descriptors \n");
    return -1;
    }

    /* All done with Rx configuration. Return success. */
    return 0;
    }

    /** ============================================================================
    * @n@b Setup_Rx
    *
    * @b Description
    * @n This API sets up all relevant data structures and configuration required
    * for receiving data from PASS/Ethernet. It sets up a Rx free descriptor queue
    * with some empty pre-allocated buffers to receive data, and an Rx queue
    * to which the Rxed data is streamed for the example application. This API
    * also sets up the QM high priority accumulation interrupts required to
    * receive data from the Rx queue.
    *
    * @param[in]
    * @n None
    *
    * @return int32_t
    * -1 - Error
    * 0 - Success
    * =============================================================================
    */
    int32_t Setup_Rx (NETIF_DEVICE* ptr_net_device)
    {
    int32_t result, vectId;
    uint8_t isAllocated, accChannelNum, i;
    uint16_t numAccEntries, intThreshold, pktLen;
    Qmss_Queue rxFreeQInfo, rxQInfo;
    Ptr pCppiDesc;
    Qmss_AccCmdCfg accCfg;
    Cppi_RxFlowCfg rxFlowCfg;
    int16_t eventId;
    Ptr pDataBuffer;
    uint32_t mySWInfo[] = {0x11112222, 0x33334444};
    uint32_t ListAddress;

    pktLen = ptr_net_device->mtu + ETHHDR_SIZE + 4; /* ETh Header + 4 bytes of FCS */

    i = MAX_HI_PRI_ACCUM_LIST_SIZE - 1 - (RX_INT_THRESHOLD);
    ListAddress = Convert_CoreLocal2GlobalAddr((uint32_t) &gHiPriAccumList[i]);

    /* Open a Receive (Rx) queue.
    *
    * This queue will be used to hold all the packets received by PASS/CPSW
    *
    * Open the next available High Priority Accumulation queue for Rx.
    */
    if ((gRxQHnd = Qmss_queueOpen (Qmss_QueueType_HIGH_PRIORITY_QUEUE, QMSS_PARAM_NOT_SPECIFIED, &isAllocated)) < 0)
    {
    platform_write ("Error opening a High Priority Accumulation Rx queue \n");
    return -1;
    }

    rxQInfo = Qmss_getQueueNumber (gRxQHnd);

    /* Setup high priority accumulation interrupts on the Rx queue.
    *
    * Let's configure the accumulator with the following settings:
    * (1) Interrupt pacing disabled.
    * (2) Interrupt on every received packet
    */
    intThreshold = RX_INT_THRESHOLD;
    numAccEntries = (intThreshold + 1) * 2;
    accChannelNum = PA_ACC_CHANNEL_NUM;

    /* Initialize the accumulator list memory */
    memset ((Void *) ListAddress, 0, numAccEntries * 4);

    /* Ensure that the accumulator channel we are programming is not
    * in use currently.
    */
    result = Qmss_disableAccumulator (Qmss_PdspId_PDSP1, accChannelNum);
    if (result != QMSS_ACC_SOK && result != QMSS_ACC_CHANNEL_NOT_ACTIVE)
    {
    platform_write ("Error Disabling high priority accumulator for channel : %d error code: %d\n",
    accChannelNum, result);
    return -1;
    }

    /* Setup the accumulator settings */
    accCfg.channel = accChannelNum;
    accCfg.command = Qmss_AccCmd_ENABLE_CHANNEL;
    accCfg.queueEnMask = 0;
    accCfg.listAddress = ListAddress;
    accCfg.queMgrIndex = gRxQHnd;
    accCfg.maxPageEntries = (intThreshold + 1); /* Add an extra entry for holding the entry count */
    accCfg.timerLoadCount = 40;
    accCfg.interruptPacingMode = Qmss_AccPacingMode_LAST_INTERRUPT;
    accCfg.listEntrySize = Qmss_AccEntrySize_REG_D;
    accCfg.listCountMode = Qmss_AccCountMode_ENTRY_COUNT;
    accCfg.multiQueueMode = Qmss_AccQueueMode_SINGLE_QUEUE;

    /* Program the accumulator */
    if ((result = Qmss_programAccumulator (Qmss_PdspId_PDSP1, &accCfg)) != QMSS_ACC_SOK)
    {
    platform_write ("Error Programming high priority accumulator for channel : %d queue : %d error code : %d\n",
    accCfg.channel, accCfg.queMgrIndex, result);
    return -1;
    }

    /* Register interrupts for the system event corresponding to the
    * accumulator channel we are using.
    */
    /* System event n - Accumulator Channel 0 */
    eventId = PLATFORM_ETH_EVENTID;

    /* Pick a interrupt vector id to use */
    vectId = PLATFORM_ETH_INTERRUPT;

    platform_write ("Ethernet eventId : %d and vectId (Interrupt) : %d \n", eventId, vectId);

    /* Register our ISR handle for this event */
    EventCombiner_dispatchPlug (eventId, (EventCombiner_FuncPtr)EmacRxPktISR, (UArg)ptr_net_device, TRUE);
    EventCombiner_enableEvent(eventId);

    /* Map the event id to hardware interrupt 7. */
    Hwi_eventMap(vectId, eventId >> 5);

    /* Enable interrupt */
    Hwi_enableInterrupt(vectId);

    /* Open a Rx Free Descriptor Queue (Rx FDQ).
    *
    * This queue will hold all the Rx free descriptors. These descriptors will be
    * used by the PASS CPDMA to hold data received via CPSW.
    */
    if ((gRxFreeQHnd = Qmss_queueOpen (Qmss_QueueType_STARVATION_COUNTER_QUEUE, QMSS_PARAM_NOT_SPECIFIED, &isAllocated)) < 0)
    {
    platform_write ("Error opening Rx Free descriptor queue \n");
    return -1;
    }
    rxFreeQInfo = Qmss_getQueueNumber (gRxFreeQHnd);

    /* Attach some free descriptors to the Rx free queue we just opened. */
    for (i = 0; i < NIMU_NUM_RX_DESC; i++)
    {
    /* Get a free descriptor from the global free queue we setup
    * during initialization.
    */
    if ((QMSS_QPOP (res_mgr_qmss_get_freeq(), QHANDLER_QPOP_FDQ_NO_ATTACHEDBUF, (Cppi_HostDesc **)&pCppiDesc)) != NULL)
    {
    break;
    }

    pktLen = platform_roundup(pktLen, PLATFORM_CACHE_LINE_SIZE);
    if ((pDataBuffer = Osal_nimuMalloc (pktLen, PLATFORM_CACHE_LINE_SIZE)) == NULL)
    {
    platform_write ("Error allocating memory for Rx data buffer \n");
    break;
    }

    /* Populate the Rx free descriptor with the buffer we just allocated. */
    Cppi_setData (Cppi_DescType_HOST, pCppiDesc, (uint8_t *)Convert_CoreLocal2GlobalAddr((uint32_t)pDataBuffer), pktLen);

    /* Save original buffer information */
    Cppi_setOriginalBufInfo (Cppi_DescType_HOST, pCppiDesc, (uint8_t *)Convert_CoreLocal2GlobalAddr((uint32_t)pDataBuffer), pktLen);

    /* Setup the Completion queue:
    *
    * Setup the return policy for this desc to return to the free q we just
    * setup instead of the global free queue.
    */
    Cppi_setReturnQueue (Cppi_DescType_HOST, pCppiDesc, rxFreeQInfo);

    Cppi_setSoftwareInfo (Cppi_DescType_HOST, pCppiDesc, (uint8_t *) mySWInfo);

    Cppi_setPacketLen (Cppi_DescType_HOST, pCppiDesc, pktLen);

    /* Push descriptor to Rx free queue */
    QMSS_QPUSHDESCSIZE (gRxFreeQHnd, pCppiDesc, SIZE_HOST_DESC);
    }
    if (i != NIMU_NUM_RX_DESC)
    {
    platform_write ("Error allocating Rx free descriptors \n");
    return -1;
    }

    /* Setup a Rx Flow.
    *
    * A Rx flow encapsulates all relevant data properties that CPDMA would
    * have to know in order to successfully receive data.
    */
    /* Initialize the flow configuration */
    memset (&rxFlowCfg, 0, sizeof(Cppi_RxFlowCfg));

    /* Let CPPI pick the next available flow */
    rxFlowCfg.flowIdNum = CPPI_PARAM_NOT_SPECIFIED;

    rxFlowCfg.rx_dest_qmgr = rxQInfo.qMgr;
    rxFlowCfg.rx_dest_qnum = rxQInfo.qNum;
    rxFlowCfg.rx_desc_type = Cppi_DescType_HOST;

    rxFlowCfg.rx_ps_location = Cppi_PSLoc_PS_IN_DESC;
    rxFlowCfg.rx_psinfo_present = 1; /* Enable PS info */

    rxFlowCfg.rx_error_handling = 0; /* Drop the packet, do not retry on starvation by default */
    rxFlowCfg.rx_einfo_present = 1; /* EPIB info present */

    rxFlowCfg.rx_dest_tag_lo_sel = 0; /* Disable tagging */
    rxFlowCfg.rx_dest_tag_hi_sel = 0;
    rxFlowCfg.rx_src_tag_lo_sel = 0;
    rxFlowCfg.rx_src_tag_hi_sel = 0;

    rxFlowCfg.rx_size_thresh0_en = 0; /* By default, we disable Rx Thresholds */
    rxFlowCfg.rx_size_thresh1_en = 0; /* By default, we disable Rx Thresholds */
    rxFlowCfg.rx_size_thresh2_en = 0; /* By default, we disable Rx Thresholds */
    rxFlowCfg.rx_size_thresh0 = 0x0;
    rxFlowCfg.rx_size_thresh1 = 0x0;
    rxFlowCfg.rx_size_thresh2 = 0x0;

    rxFlowCfg.rx_fdq0_sz0_qmgr = rxFreeQInfo.qMgr; /* Setup the Receive free queue for the flow */
    rxFlowCfg.rx_fdq0_sz0_qnum = rxFreeQInfo.qNum;
    rxFlowCfg.rx_fdq0_sz1_qnum = 0x0;
    rxFlowCfg.rx_fdq0_sz1_qmgr = 0x0;
    rxFlowCfg.rx_fdq0_sz2_qnum = 0x0;
    rxFlowCfg.rx_fdq0_sz2_qmgr = 0x0;
    rxFlowCfg.rx_fdq0_sz3_qnum = 0x0;
    rxFlowCfg.rx_fdq0_sz3_qmgr = 0x0;

    rxFlowCfg.rx_fdq1_qnum = rxFreeQInfo.qNum; /* Use the Rx Queue to pick descriptors */
    rxFlowCfg.rx_fdq1_qmgr = rxFreeQInfo.qMgr;
    rxFlowCfg.rx_fdq2_qnum = rxFreeQInfo.qNum; /* Use the Rx Queue to pick descriptors */
    rxFlowCfg.rx_fdq2_qmgr = rxFreeQInfo.qMgr;
    rxFlowCfg.rx_fdq3_qnum = rxFreeQInfo.qNum; /* Use the Rx Queue to pick descriptors */
    rxFlowCfg.rx_fdq3_qmgr = rxFreeQInfo.qMgr;

    /* Configure the Rx flow */
    if ((gRxFlowHnd = Cppi_configureRxFlow (res_mgr_cppi_get_passhandle(), &rxFlowCfg, &isAllocated)) == NULL)
    {
    platform_write ("Error configuring Rx flow \n");
    return -1;
    }

    /* All done with Rx configuration. Return success. */
    return 0;
    }

    /** ============================================================================
    * @n@b Init_MAC
    *
    * @b Description
    * @n This API initializes the CPGMAC Sliver (MAC Port) port.
    *
    * @param[in]
    * @n macPortNum MAC port number for which the initialization must be done.
    *
    * @param[in]
    * @n macAddress MAC address to configure on this port.
    *
    * @param[in]
    * @n mtu Maximum Frame length to configure on this port.
    *
    * @return
    * @n None
    * =============================================================================
    */
    Void Init_MAC (uint32_t macPortNum, uint8_t macAddress[6], uint32_t mtu)
    {
    /* Reset MAC Sliver 0 */
    CSL_CPGMAC_SL_resetMac (macPortNum);
    while (CSL_CPGMAC_SL_isMACResetDone (macPortNum) != TRUE);

    /* Setup the MAC Control Register for this port:
    * (1) Enable Full duplex
    * (2) Enable GMII
    * (3) Enable Gigabit
    * (4) Enable External Configuration. This enables
    * the "Full duplex" and "Gigabit" settings to be
    * controlled externally from SGMII
    * (5) Don't Enable any control/error frames
    * (6) Enable short frames
    */
    CSL_CPGMAC_SL_enableFullDuplex (macPortNum);
    CSL_CPGMAC_SL_enableGMII (macPortNum);
    CSL_CPGMAC_SL_enableGigabit (macPortNum);
    CSL_CPGMAC_SL_enableExtControl (macPortNum);

    /* Adding these configurations to allow the switch not to ignore any packets */
    CSL_CPGMAC_SL_enableRxCSF(macPortNum);

    /* Configure the MAC address for this port */
    CSL_CPSW_3GF_setPortMACAddress (macPortNum, macAddress);

    /* Configure VLAN ID/CFI/Priority.
    *
    * For now, we are not using VLANs so just configure them
    * to all zeros.
    */
    CSL_CPSW_3GF_setPortVlanReg (macPortNum, 0, 0, 0);

    /* Configure the Receive Maximum length on this port,
    * i.e., the maximum size the port can receive without
    * any errors.
    *
    * Set the Rx Max length to the MTU configured for the
    * interface.
    */
    CSL_CPGMAC_SL_setRxMaxLen (macPortNum, mtu);

    /* Done setting up the MAC port */
    return;
    }

    /** ============================================================================
    * @n@b Init_MDIO
    *
    * @b Description
    * @n Not supported at moment. MDIO is not simulated yet.
    *
    * @param[in]
    * @n None
    *
    * @return
    * @n None
    * =============================================================================
    */
    Void Init_MDIO (Void)
    {
    /* There is nothing to be done for C6678 EVM */
    return;
    }

    /** ============================================================================
    * @n@b Init_Switch
    *
    * @b Description
    * @n This API sets up the ethernet switch subsystem and its Address Lookup
    * Engine (ALE) in "Switch" mode.
    *
    * @param[in]
    * @n mtu Maximum Frame length to configure on the switch.
    *
    * @return
    * @n None
    * =============================================================================
    */
    Void Init_Switch (uint32_t mtu)
    {
    CSL_CPSW_3GF_PORTSTAT portStatCfg;
    uint32_t rx_max_len = mtu + ETHHDR_SIZE + 4; /* 4 bytes of FCS */

    /* Enable the CPPI port, i.e., port 0 that does all
    * the data streaming in/out of EMAC.
    */
    CSL_CPSW_3GF_enablePort0 ();
    CSL_CPSW_3GF_disableVlanAware ();
    CSL_CPSW_3GF_setPort0VlanReg (0, 0, 0);
    CSL_CPSW_3GF_setPort0RxMaxLen (rx_max_len);

    /* Enable statistics on both the port groups:
    *
    * MAC Sliver ports - Port 1, Port 2
    * CPPI Port - Port 0
    */
    portStatCfg.p0AStatEnable = 1;
    portStatCfg.p0BStatEnable = 1;
    portStatCfg.p1StatEnable = 1;
    portStatCfg.p2StatEnable = 1;
    CSL_CPSW_3GF_setPortStatsEnableReg (&portStatCfg);

    /* Setup the Address Lookup Engine (ALE) Configuration:
    * (1) Enable ALE.
    * (2) Clear stale ALE entries.
    * (3) Disable VLAN Aware lookups in ALE since
    * we are not using VLANs by default.
    * (4) No Flow control
    * (5) Configure the Unknown VLAN processing
    * properties for the switch, i.e., which
    * ports to send the packets to.
    */
    CSL_CPSW_3GF_enableAle ();
    CSL_CPSW_3GF_clearAleTable ();
    CSL_CPSW_3GF_disableAleVlanAware ();
    CSL_CPSW_3GF_disableAleTxRateLimit ();

    /* Setting the Switch MTU Size to more than needed */
    CSL_CPGMAC_SL_setRxMaxLen(0, rx_max_len);
    CSL_CPGMAC_SL_setRxMaxLen(1, rx_max_len);

    //#ifdef SIMULATOR_SUPPORT
    CSL_CPSW_3GF_enableAleBypass();
    //#endif
    /* Done with switch configuration */
    #ifdef ETH1_4_GIGABITETHERNET
    // Configure "Learning"/"Forward" state for all 3 ports
    int portNum;
    for (portNum=0; portNum<3; portNum++)
    {
    CSL_CPSW_3GF_ALE_PORTCONTROL alePortControlCfg;
    alePortControlCfg.portState = ALE_PORTSTATE_FORWARD;
    alePortControlCfg.dropUntaggedEnable = 0;
    alePortControlCfg.vidIngressCheckEnable = 0;
    alePortControlCfg.noLearnModeEnable = 0;
    alePortControlCfg.mcastLimit = 0;
    alePortControlCfg.bcastLimit = 0;
    CSL_CPSW_3GF_setAlePortControlReg (portNum, &alePortControlCfg);
    }
    #endif
    return;
    }


    /** ============================================================================
    * @n@b Switch_update_addr
    *
    * @b Description
    * @n This API add/delete entries in the Address Lookup Engine (ALE) in "Switch" mode.
    *
    * @param[in]
    * @n portNum Switch port number.

    * @param[in]
    * @n macAddress MAC address to configure on the switch.
    *
    * @param[in]
    * @n add 0:add; 1:delete.
    *
    * @return
    * @n None
    *
    * @Note It supports "add" operation only now.
    * =============================================================================
    */
    int Switch_update_addr (uint32_t portNum, uint8_t macAddress[6], Uint16 add)
    {
    CSL_CPSW_3GF_ALE_PORTCONTROL alePortControlCfg;
    #ifdef SIMULATOR_SUPPORT
    uint32_t i;
    CSL_CPSW_3GF_ALE_UNICASTADDR_ENTRY ucastAddrCfg;
    #endif


    /* Configure the address in "Learning"/"Forward" state */
    alePortControlCfg.portState = ALE_PORTSTATE_FORWARD;
    alePortControlCfg.dropUntaggedEnable = 0;
    alePortControlCfg.vidIngressCheckEnable = 0;
    alePortControlCfg.noLearnModeEnable = 0;
    alePortControlCfg.mcastLimit = 0;
    alePortControlCfg.bcastLimit = 0;

    CSL_CPSW_3GF_setAlePortControlReg (portNum, &alePortControlCfg);

    #ifdef SIMULATOR_SUPPORT
    /* Program the ALE with the MAC address.
    *
    * The ALE entries determine the switch port to which any
    * matching received packet must be forwarded to.
    */
    /* Get the next free ALE entry to program */
    for (i = 0; i < CSL_CPSW_3GF_NUMALE_ENTRIES; i++)
    {
    if (CSL_CPSW_3GF_getALEEntryType (i) == ALE_ENTRYTYPE_FREE)
    {
    /* Found a free entry */
    break;
    }
    }
    if (i == CSL_CPSW_3GF_NUMALE_ENTRIES)
    {
    /* No free ALE entry found. return error. */
    return -1;
    }
    else
    {
    /* Found a free ALE entry to program our MAC address */
    memcpy (ucastAddrCfg.macAddress, macAddress, 6); // Set the MAC address
    ucastAddrCfg.ucastType = ALE_UCASTTYPE_UCAST_NOAGE; // Add a permanent unicast address entryALE_UCASTTYPE_UCAST_NOAGE.
    ucastAddrCfg.secureEnable = FALSE;
    ucastAddrCfg.blockEnable = FALSE;
    ucastAddrCfg.portNumber = portNum; // Add the ALE entry for this port

    /* Setup the ALE entry for this port's MAC address */
    CSL_CPSW_3GF_setAleUnicastAddrEntry (i, &ucastAddrCfg);
    }
    #endif
    /* Done with upading address */
    return 0;
    }

    /** ============================================================================
    * @n@b Verify_Init
    *
    * @b Description
    * @n This API initializes the CPPI LLD, opens the PASS CPDMA and opens up
    * the Tx, Rx channels required for data transfers.
    *
    * @param[in]
    * @n None
    *
    * @return int32_t
    * -1 - Error
    * 0 - Success
    * =============================================================================
    */
    int32_t Verify_Init (Void)
    {
    int32_t count, returnVal = 0, i;
    int32_t num_tx_desc = NIMU_NUM_TX_DESC;
    int32_t num_rx_desc = NIMU_NUM_RX_DESC;
    int32_t max_queue_number = QMSS_MAX_LOW_PRIORITY_QUEUE +
    QMSS_MAX_PASS_QUEUE +
    QMSS_MAX_LOW_PRIORITY_QUEUE +
    QMSS_MAX_PASS_QUEUE +
    QMSS_MAX_INTC_QUEUE +
    QMSS_MAX_SRIO_QUEUE +
    QMSS_MAX_HIGH_PRIORITY_QUEUE +
    QMSS_MAX_STARVATION_COUNTER_QUEUE +
    QMSS_MAX_INFRASTRUCTURE_QUEUE +
    QMSS_MAX_TRAFFIC_SHAPING_QUEUE +
    QMSS_MAX_GENERAL_PURPOSE_QUEUE ;

    /*Verify if we got NIMU_NUM_TX_DESC Tx Free Q*/
    if ((count = Qmss_getQueueEntryCount (gTxFreeQHnd)) != num_tx_desc) {
    platform_write ("Verify_Init: Expected %d entry count for gTxFreeQHnd queue %d, found %d entries\n", num_tx_desc, gTxFreeQHnd, count);
    returnVal = -1;
    }

    /* Verify if we got NIMU_NUM_RX_DESC Rx FDQ */
    if ((count = Qmss_getQueueEntryCount (gRxFreeQHnd)) != num_rx_desc) {
    platform_write ("Verify_Init: Expected %d entry count for gRxFreeQHnd queue %d, found %d entries\n", num_rx_desc, gRxFreeQHnd, count);
    returnVal = -1;
    }

    /* Verify if we got empty Tx completion Q*/
    if ((count = Qmss_getQueueEntryCount (gTxReturnQHnd)) != 0) {
    platform_write ("Verify_Init: Expected 0 entry count for gTxReturnQHnd queue %d, found %d entries\n", gTxReturnQHnd, count);
    returnVal = -1;
    }

    /* Verify if we got NIMU_NUM_RX_DESC Rx FDQ */
    if ((count = Qmss_getQueueEntryCount (gRxQHnd)) != 0) {
    platform_write ("Verify_Init: Expected 0 entry count for gRxQHnd= %d, found %d entries\n", gRxQHnd, count);
    returnVal = -1;
    }

    for (i = 0; i < max_queue_number; i++ ) {
    if ( (i == gRxFreeQHnd) || (i == gTxFreeQHnd) || (i == gTxCmdFreeQHnd))
    continue;

    count = Qmss_getQueueEntryCount (i);
    if (count != 0) {
    platform_write ("Verify_Init: Expected 0 entry count for Queue number = %d, found %d entries\n", i, count);
    }
    }

    /* Verify_Init Done. Return success */
    return (returnVal);
    }

    /** ============================================================================
    * @n@b Init_Cpsw
    *
    * @b Description
    * @n This API sets up the entire ethernet subsystem and all its associated
    * components.
    *
    * @param[in]
    * @n None
    *
    * @return
    * @n None
    * =============================================================================
    */
    int32_t Init_Cpsw (uint32_t mtu, uint8_t* myMACAddress)
    {
    #ifdef ETH1_4_GIGABITETHERNET
    uint8_t portMac[6] = {0x1, 0x1, 0x1, 0x1, 0x1, 0x1};
    Init_MAC(0, portMac, mtu);

    portMac[0] = 2;
    Init_MAC(1, portMac, mtu);

    /* Setup the Phys by initializing the MDIO - not needed for Simulator*/
    Init_MDIO();

    /* Setup the Ethernet switch finally. */
    Init_Switch(mtu);
    /* CPSW subsystem setup done. Return success */
    return 0;
    #else
    #ifdef SIMULATOR_SUPPORT

    uint8_t bcMACAddress[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
    extern uint8_t clientMACAddress [6];

    /* Initialize the SGMII/Sliver submodules for the MAC port. */
    Init_SGMII (0);
    Init_MAC (0, myMACAddress, mtu);

    Init_SGMII (1);
    Init_MAC (1, myMACAddress, mtu);

    /* Setup the Ethernet switch finally. */
    Init_Switch (mtu);


    /* Update the ALE Entries and ensure that these are correctly configured.
    * There are 2 Entries created here:
    * Entry1: My OWN MAC Address goes to Port 0
    * Entry2: Destination MAC Address is forwarded to Port1
    * If there are more destination MAC Addresses to which packets need to be sent
    * than additional entries need to be configured. */

    /* This is needed only for testing in Simulator*/
    Switch_update_addr(0, myMACAddress, 0);
    Switch_update_addr(1, clientMACAddress, 0);
    Switch_update_addr(1, myMACAddress, 0); // testing a hybrid between cooked up ping and the original app (cooked up raw message)

    // checking out if adding bc message still work for unicast
    Switch_update_addr(1, bcMACAddress, 0); // verified needed for BCAST tx

    // add this to see if BC packet response can come into the PA
    Switch_update_addr(0, bcMACAddress, 0); // verfied needed for BCast Rx

    #else

    uint32_t i;
    uint8_t backplaneMac[6] = {0x1, 0x1, 0x1, 0x1, 0x1, 0x1}; /* Mask for creating mac address by flipping LSB */
    uint8_t cppiMac [6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05}; /* MAC address for (CPPI) Port 0 - we made it up*/


    /* we need to create a mac address for the Backplane Ethernet port
    * using the Ethernet MAC Adress
    */
    for (i=0; i < 6; i++) {
    backplaneMac[i] |= myMACAddress[i];
    }
    Init_MAC (0, backplaneMac, mtu);

    /* set the silver port to the stacks ethernet address */
    Init_MAC (1, myMACAddress, mtu);

    /* Setup the Phys by initializing the MDIO - not needed for Simulator*/
    Init_MDIO ();

    /* Setup the Ethernet switch finally. */
    Init_Switch (mtu);

    /* This is a little confusing but different APIs use different numbering */
    Switch_update_addr(0, cppiMac, 0);
    Switch_update_addr(1, backplaneMac, 0);
    Switch_update_addr(2, myMACAddress, 0);
    #endif

    /* CPSW subsystem setup done. Return success */
    return 0;
    #endif
    }

    /* ============================================================================
    * @n@b Init_PASS
    *
    * @b Description
    * @n This API initializes the PASS/PDSP and opens a queue that the application
    * can use to receive command responses from the PASS.
    *
    * @param[in]
    * @n None
    *
    * @return int32_t
    * -1 - Error
    * 0 - Success
    * =============================================================================
    */
    int32_t Init_PASS (Void)
    {
    uint8_t isAllocated;

    /* Open a PA Command Response Queue.
    *
    * This queue will be used to hold responses from the PA PDSP for all the
    * commands issued by NIMU.
    *
    * This queue is used only when configuring the PA PDSP. We will use it when adding our mac address.
    */
    if ((gPaCfgCmdRespQHnd = Qmss_queueOpen (Qmss_QueueType_GENERAL_PURPOSE_QUEUE, QMSS_PARAM_NOT_SPECIFIED, &isAllocated)) < 0)
    {
    platform_write ("Error opening a PA Command Response queue \n");
    return -1;
    }

    /* Init done. Return success. */
    return 0;
    }


    /** ============================================================================
    * @n@b Add_MACAddress
    *
    * @b Description
    * @n This API adds the switch MAC address to the PA PDSP Lookup table. This
    * ensures that all packets destined for this MAC address get processed
    * for forwarding to the host.
    *
    * @param[in]
    * @n ethInfo Pointer to PA Ethernet Info table.
    *
    * @param[in]
    * @n routeInfo Pointer to PA Route Info table.
    *
    * @n None
    *
    * @return int32_t
    * -1 - Error
    * 0 - Success
    * =============================================================================
    */
    int32_t
    Add_MACAddress
    (
    paEthInfo_t *ethInfo,
    paRouteInfo_t *routeInfo
    )
    {
    int32_t j;
    uint16_t cmdSize;
    Qmss_Queue cmdReplyQInfo;

    paRouteInfo_t nFailInfo = { pa_DEST_DISCARD, /* Toss the packet */
    0, /* Flow Id = dont care */
    0, /* queue = dont care */
    0, /* mutli route = dont care */
    0, /* swinfo0 = dont care */
    0, /* swinfo1 = dont care */
    0, /* customType = pa_CUSTOM_TYPE_NONE */ \
    0, /* customIndex: not used */ \
    0, /* pkyType: for SRIO only */ \
    NULL /* No commands */
    };
    paCmdReply_t cmdReplyInfo = { pa_DEST_HOST, /* Replies go to the host */
    0, /* User chosen ID to go to swinfo0 */
    0, /* Destination queue */
    0 /* Flow ID */
    };
    paReturn_t retVal;
    paEntryHandle_t retHandle;
    int32_t handleType, cmdDest;
    uint32_t psCmd = ((uint32_t)(4 << 5) << 24);
    uint32_t myswinfo[] = {0x11112222, 0x33334444};
    uint32_t myswinfo_orig[] = {0x00000000, 0x00000000, 0x00000000};;
    uint8_t* pCmdDataBuffer;
    Cppi_HostDesc* pHostDesc = NULL;
    Qmss_Queue rxQInfo;
    uint32_t count, cmdbuf_len = 320;
    int32_t ret_val = 0;

    /* Get a Tx free descriptor to send a command to the PA PDSP */
    if ((QMSS_QPOP (gTxCmdFreeQHnd, QHANDLER_QPOP_FDQ_NO_ATTACHEDBUF, (Cppi_HostDesc **)&pHostDesc )) != NULL)
    {
    platform_write ("Error obtaining a Tx free descriptor \n");
    return -1;
    }

    /* Allocate a Tx buffer and attach the command info to it. */
    cmdbuf_len = platform_roundup(cmdbuf_len, PLATFORM_CACHE_LINE_SIZE);
    if ((pCmdDataBuffer = (Ptr) Osal_nimuMalloc (cmdbuf_len, PLATFORM_CACHE_LINE_SIZE)) == NULL)
    {
    platform_write ("Error allocating memory for PA Command data buffer \n");
    return -1;
    }

    /* Populate the Tx free descriptor with the buffer we just allocated. */
    Cppi_setData (Cppi_DescType_HOST, (Cppi_Desc *)pHostDesc, (uint8_t *)Convert_CoreLocal2GlobalAddr((uint32_t)pCmdDataBuffer), cmdbuf_len);

    /* Save original buffer information */
    Cppi_setOriginalBufInfo (Cppi_DescType_HOST, (Cppi_Desc *)pHostDesc, (uint8_t *)Convert_CoreLocal2GlobalAddr((uint32_t)pCmdDataBuffer), cmdbuf_len);

    cmdSize = pHostDesc->buffLen;
    cmdReplyInfo.replyId = 0x11111111; /* unique for each add mac command */

    /* Get the PA response queue number and populate the destination queue number
    * in the PA response configuration.
    */
    cmdReplyQInfo = Qmss_getQueueNumber (gPaCfgCmdRespQHnd);
    cmdReplyInfo.queue = cmdReplyQInfo.qNum;

    /* Setup the Rx queue as destination for the packets */
    rxQInfo = Qmss_getQueueNumber (gRxQHnd);
    routeInfo->queue = rxQInfo.qNum;

    retVal = Pa_addMac (res_mgr_get_painstance(),
    pa_LUT1_INDEX_NOT_SPECIFIED,
    ethInfo,
    routeInfo,
    &nFailInfo,
    &gPaL2Handles[0],
    (paCmd_t) pHostDesc->buffPtr,
    &cmdSize,
    &cmdReplyInfo,
    &cmdDest);
    if (retVal != pa_OK)
    {
    platform_write ("Pa_addMac returned error %d\n", retVal);
    ret_val = -1;
    goto return_fail;
    }


    /* This sets the extended info for descriptors, and this is required so PS info
    * goes to the right spot
    */
    Cppi_setSoftwareInfo (Cppi_DescType_HOST, (Cppi_Desc *)pHostDesc, (uint8_t *)myswinfo);

    /* Set the buffer length to the size used. It will be restored when the descriptor
    * is returned
    */
    Cppi_setPacketLen (Cppi_DescType_HOST, (Cppi_Desc *)pHostDesc, cmdSize);
    pHostDesc->buffLen = cmdSize;

    /* Mark the packet as a configuration packet */
    Cppi_setPSData (Cppi_DescType_HOST, (Cppi_Desc *)pHostDesc, (uint8_t *)&psCmd, 4);

    /* Send the command to the PA and wait for the return */
    QMSS_QPUSH (gPaTxQHnd[cmdDest - pa_CMD_TX_DEST_0],
    pHostDesc,
    pHostDesc->buffLen,
    SIZE_HOST_DESC,
    Qmss_Location_TAIL
    );

    /* Poll on the PA response queue to see if response from PA has come */
    for (j = 0; j < 100; j++)
    {
    platform_delaycycles (1000);

    /* Verify if we got empty Tx completion Q*/
    count = Qmss_getQueueEntryCount (gTxCmdReturnQHnd);

    if (count != 0) {

    if ((QMSS_QPOP (gTxCmdReturnQHnd, QHANDLER_QPOP_FDQ_ATTACHEDBUF, (Cppi_HostDesc **)&pHostDesc)) != NULL)
    {
    ret_val = -1;
    goto return_fail;
    }

    /* Restore the states */
    Cppi_setSoftwareInfo(Cppi_DescType_HOST, (Cppi_Desc *)pHostDesc, (uint8_t *)myswinfo_orig);
    Cppi_setPSData (Cppi_DescType_HOST, (Cppi_Desc *)pHostDesc, NULL, NULL);
    Cppi_setData (Cppi_DescType_HOST, (Cppi_Desc *)pHostDesc, NULL, NULL);
    Cppi_setOriginalBufInfo (Cppi_DescType_HOST, (Cppi_Desc *)pHostDesc, NULL, NULL);
    Cppi_setPacketLen (Cppi_DescType_HOST, (Cppi_Desc *)pHostDesc, NULL);
    pHostDesc->buffLen = 0;

    QMSS_QPUSHDESCSIZE (gTxCmdFreeQHnd, pHostDesc, SIZE_HOST_DESC);
    }

    if (Qmss_getQueueEntryCount (gPaCfgCmdRespQHnd) > 0)
    {

    /* We have a response from PA PDSP for the command we submitted earlier for
    * MAC address addition.
    */
    if ((QMSS_QPOP (gPaCfgCmdRespQHnd, QHANDLER_QPOP_FDQ_NO_ATTACHEDBUF, (Cppi_HostDesc **)&pHostDesc)) != NULL)
    {
    ret_val = -1;
    goto return_fail;
    }

    if (pHostDesc->softwareInfo0 != cmdReplyInfo.replyId)
    {
    platform_write ("Found an entry in PA response queue with swinfo0 = 0x%08x, expected 0x%08x\n",
    pHostDesc->softwareInfo0, cmdReplyInfo.replyId);
    pHostDesc->buffLen = pHostDesc->origBufferLen;
    QMSS_QPUSH (gTxCmdFreeQHnd, pHostDesc, pHostDesc->buffLen, SIZE_HOST_DESC, Qmss_Location_TAIL);
    ret_val = -1;
    goto return_fail;

    }

    retVal = Pa_forwardResult (res_mgr_get_painstance(), (Ptr)pHostDesc->buffPtr, &retHandle, &handleType, &cmdDest);
    if (retVal != pa_OK)
    {
    platform_write ("PA sub-system rejected Pa_addMac command\n");
    ret_val = -1;
    goto return_fail;
    }

    /* Reset the buffer length and put the descriptor back on the Rx free queue */
    pHostDesc->buffLen = pHostDesc->origBufferLen;
    QMSS_QPUSH (gRxFreeQHnd, pHostDesc, pHostDesc->buffLen, SIZE_HOST_DESC, Qmss_Location_TAIL);
    break;
    }
    }

    if (j == 100)
    {
    platform_write ("Timeout waiting for reply from PA to Pa_addMac command\n");
    Osal_nimuFree (pCmdDataBuffer, cmdbuf_len);
    ret_val = -1;
    }

    return_fail:

    Osal_nimuFree (pCmdDataBuffer, cmdbuf_len);

    return (ret_val);
    }

    /**
    * @b Description
    * @n
    * Returns the number of received packet drops, most likely due to NDK buffer starvation.
    *
    * @retval
    * None.
    */
    uint32_t nimu_getrxdrops(void) {
    return gRxDropCounter;
    }

    /**
    * @b Description
    * @n
    * Returns the number of transmit packet drops due to Tx descriptor starvation.
    *
    * @retval
    * None.
    */
    uint32_t nimu_gettxdrops(void) {
    return gTxDropCounter;
    }


    #ifdef TIMING
    /*
    * Routine to print out timing measurements.. meant to be called from application as we dont
    * want to print in an interrupt context.
    */
    void print_nimu_timing(void) {
    uint32_t avg_rxisr, avg_txisr, max_rxisr, min_rxisr, max_txisr, min_txisr;
    uint32_t total_rx, total_tx;
    uint32_t i, x, n;
    void* key;

    /* Begin Critical Section before accessing shared resources. */
    key = Osal_qmssCsEnter ();

    /* Calculate min, max, avg times for display */
    avg_rxisr = 0;
    avg_txisr = 0;
    max_rxisr = 0;
    min_rxisr = (uint32_t) (rxisr_time[0]); /* seed the value */
    max_txisr = 0;
    min_txisr = (uint32_t) (txisr_time[0]); /* seed the value */
    total_rx = 0;
    total_tx = 0;

    for (i=0, n=0; i < MAX_TIMING_PACKETS; i++) {

    x = (uint32_t) (rxisr_time[i]);

    if (rxisr_time[i] != 0) {
    n++;
    if (min_rxisr > x) {
    min_rxisr = x;
    }

    if ( max_rxisr < x) {
    max_rxisr = x;
    }
    total_rx += x;
    }

    x = (uint32_t) (txisr_time[i]);

    if (txisr_time[i] != 0) {
    if ( min_txisr > x && x > 0) {
    min_txisr = x;
    }
    if ( max_txisr < x) {
    max_txisr = x;
    }
    total_tx += x;
    }
    }
    /* End Critical Section */
    Osal_qmssCsExit (key);

    avg_rxisr = total_rx / n; /* have to avg over number of times it was called */
    avg_txisr = total_tx / MAX_TIMING_PACKETS;

    platform_write ("NIMU Rx (%d Packets): Total = %d Min = %d Max = %d Avg = %d \n", MAX_TIMING_PACKETS, total_rx, min_rxisr, max_rxisr, avg_rxisr);
    platform_write ("NIMU Tx (%d Packets): Total = %d Min = %d Max = %d Avg = %d \n", MAX_TIMING_PACKETS, total_tx, min_txisr, max_txisr, avg_txisr);


    }

    /* reset timing counters */
    void reset_nimu_timing(void) {
    void* key;

    /* Begin Critical Section before accessing shared resources. */
    key = Osal_qmssCsEnter ();

    memset (&rxisr_time[0], 0, MAX_TIMING_PACKETS);
    memset (&txisr_time[0], 0, MAX_TIMING_PACKETS);

    rxisr_time_idx = 0; txisr_time_idx = 0;
    rxisr_pktcount = 0;

    /* End Critical Section */
    Osal_qmssCsExit (key);
    }

    #endif

  • Ryan:

    I am slightly confused.  Does the code you uploaded allow for simultaneous use of both network interfaces without crashing?

    The code I uploaded allows for simultaneous usage of both network interfaces - but not using ping.  I simply used small messages to test it. My code also allowed for separate MAC addresses for each interface.  The reason ping crashes is because it is treated as a broadcast packet, which all descriptors get recycled to the same queue (thus one interface runs out, eventually crashing the communication).  This is addressed in Liu's post several above ours.

    Could you elaborate on where you stand right now?

    Sincerely,

    John Demery

  • Thank you for your response.

    And, the code I uploaded is not for simultaneous use of both network interfaces exactly.

    Because, the code can't set separate MAC addresses for each interface up, just with ONE MAC address and using ports. That's it.

    As you know, I want to use separate MAC addresses for each interface, so the code you gave me is right direction for me.

    Here is I stand today.

    I tested ping several times even many many times for several days. :)

    So, I got this information.

    First of all, just eth0 : only eth0 is OK with ping tests.

                                eth1 : I checked the count of ISR for eth1.

                                           Usually after 101 times later it would be crashed. that means isr function doesn't be called anymore.(sometimes after 108 but usually after 101 times...)

    So, I can tell you carefully like this. just eth1 is problem. not a hardware problem because I switched the port between eth0 and eth1 physically.

    then, just eth1 is always a problem.

    Please help me and check it out for me. 

    Thanks, Ryan.

  • And, one more I have a question.

    Would you mind asking you how can i debug in this case? I means what can I do in order to solve this problem?

    Just I lost my way now. so I need you guys help.

  • Hi John,

    as I was skipping through your code i've met with unknown identifiers PLATFORM_AMC_INTERRUPT and PLATFORM_AMC_EVENTID. Would you give me a hint what should it be ?

    Thanks,

    BS.

  • add like below

    #define PLATFORM_AMC_EVENTID 49 /**< Ethernet Switch event - Used by NIMU library */
    #define PLATFORM_AMC_INTERRUPT 8 /**< Ethernet Switch Interrupt - Used by NIMU library */

    Thanks.

  • Hi, John.

    Eventually, I just success the ping test.

    But, now I have another problem concerned with multicast.

    just eth0 works fine but the1 doesn't work now.

    So you have any solution for me???

    Please help me.

    Thanks, Ryan.

  • I found another clue.

    which is even though I sent the multicast message to eth1, trigering just eth0 isr now.

    So, I can I solve this problem?

    And, one thing more.

    Here is I added for multicast join.

    Please check this code for me.

    ----------------------------------------------------------------------------------------------------------------------------

    static int Emacioctl (NETIF_DEVICE* ptr_net_device, uint cmd, void* pBuf, uint size)
    {

    EMAC_DATA* ptr_pvt_data;

    switch(cmd)
    {
    case NIMU_ADD_MULTICAST_ADDRESS:
    /*
    caller: ptr_device->ioctl (ptr_device, NIMU_ADD_MULTICAST_ADDRESS, (void *)&bMacAddr[0], 6) (ndk_2_21_01_38/packages/ti/ndk/stack/igmp/igmp.c)
    */
    {
    paEthInfo_t ethInfo = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* Src mac = dont care */
    { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 }, /* Default Dest mac */
    0, /* vlan = dont care */
    0, /* ignore ether type */
    0 /* MPLS tag = don't care */
    };
    paRouteInfo_t routeInfo = { pa_DEST_HOST, /* Route a match to the host */
    0, /* Flow ID 0 */
    0, /* Destination queue */
    2, /* Multi route disabled */
    0xaaaaaaaa, /* SwInfo 0 */
    0, /* SwInfo 1 is dont care */
    0, /* customType = pa_CUSTOM_TYPE_NONE */ \
    0, /* customIndex: not used */ \
    0, /* pkyType: for SRIO only */ \
    NULL /* No commands */
    };

    /* Get the pointer to the private data */
    ptr_pvt_data = (EMAC_DATA *)ptr_net_device->pvt_data;


    memcpy (&ethInfo.dst[0], pBuf, size);

    if( ptr_pvt_data->pdi.PhysIdx == 0) {
    routeInfo.flowId = Cppi_getFlowId(gRxFlowHnd[0]);
    platform_write (" routeInfo.flowId 0 : %d \n", routeInfo.flowId);
    //inc++;
    // ethInfo.dst[6] = ethInfo.dst[6] + inc;
    }

    if( ptr_pvt_data->pdi.PhysIdx == 1) {
    routeInfo.flowId = Cppi_getFlowId(gRxFlowHnd[1]);
    platform_write (" routeInfo.flowId 1 : %d \n", routeInfo.flowId);
    //inc++;
    //ethInfo.dst[5] = ethInfo.dst[5] + 2;
    }

    platform_write (" ==============mmc %x:%x:%x:%x:%x \n", ethInfo.dst[0], ethInfo.dst[1], ethInfo.dst[2], ethInfo.dst[3], ethInfo.dst[4], ethInfo.dst[5]);
    /* Set up the MAC Address LUT for Broadcast */
    if (Add_MACAddress (&ethInfo, &routeInfo) != 0)
    {
    platform_write ("Add_MACAddress failed \n");
    //return -1;
    }
    platform_write ("Add_MACAddress success\n");

    }
    break;

    //Todo
    case NIMU_DEL_MULTICAST_ADDRESS:

    break;
    default:
    break;
    }

    return 0;
    }

  • Hi,

    I eventually success porting dual port ethernet a week ago.

    Becuase you guys helped me a lot like above.

    If anyone need my help to use dual port gbe, I can help you.

    But, I met another problem when I test the network founction.

    That is when I sent multicaste messages every 1ms, It becomes back out. i mean die.

    But every 100ms is OK with my borad.

    Our spec of this :

    1. get multicast messages every 1ms from linux server (40Byte)

    2. assemble the data around 126Byte and send back to linux server.

    I don't know what do I have to do now. Just I am doing changing all of variable which I think concerned with this problem.

    But as I mentioned it doesn't work.

    Please help me.

    Thanks, Ryan.

  • Hi, John Demery.

    I eventually success the use of dual port ethernet a week ago.

    Because you help. Thanks a lot.

    But, I met another problem nowadays.

    That is when I sent multicaste messages every 1ms, It becomes back out. i mean die the whole system.

    But every 100ms is OK with my borad.

    Our spec of this :

    1. get multicast messages every 1ms from linux server (40Byte)

    2. assemble the data around 126Byte and send back to linux server.

    I don't know what do I have to do now. Just I am doing changing all of variable which I think concerned with this problem.

    But as I mentioned it doesn't work.

    Please help me.

  • I make progress here a little bit.

    Actually  it's not a progress, :) just I check one thing more.

    That is just eth0 works fine but eth1 doesn't work with 1ms multicast receive but it works with 100ms muticast recevie.

    Just I think It doesn't work with accumulator when it set up in Setup_Rx in numu_eth.c.

    Anybody have any ideas? Please tell me someone who have any idea about this.

    Thanks, Ryan

  • I make progress here a little bit.

    Actually  it's not a progress, :) just I check one thing more.

    That is just eth0 works fine but eth1 doesn't work with 1ms multicast receive but it works with 100ms muticast recevie.

    Just I think It doesn't work with accumulator when it set up in Setup_Rx in numu_eth.c.

    Anybody have any ideas? Please tell me someone who have any idea about this.

    Thanks, Ryan.

  • Hi, ryan. After reading your post, I think you have already used eth0 and eth1 successfully. I have downloaded files to change NIMU. Can you tell me how to change HelloWorld.c in order to use both the eth? I have no idea now. thanks very much.
  • Hi, John 
    I tried your code of NIMU. Now I want to use it on my board of c6678. I am using the example project HelloWorld. which part of the code in HelloWorld.c should I changed to initilize eth0 and eth0. Now in HelloWorld.c, it is only init eth1.
    Can I just add the code of configuring IP for eth0 as the following for configuring eth1:
    // Setup manual IP address
    bzero( &NA, sizeof(NA) );
    NA.IPAddr = inet_addr(LocalIPAddr);
    NA.IPMask = inet_addr(LocalIPMask);
    strcpy( NA.Domain, DomainName );
    NA.NetType = 0;

    // Add the address to interface 1
    CfgAddEntry( hCfg, CFGTAG_IPNET, 1, 0,
    sizeof(CI_IPNET), (UINT8 *)&NA, 0 );

    // Add the default gateway. Since it is the default, the
    // destination address and mask are both zero (we go ahead
    // and show the assignment for clarity).
    bzero( &RT, sizeof(RT) );
    RT.IPDestAddr = 0;
    RT.IPDestMask = 0;
    RT.IPGateAddr = inet_addr(GatewayIP);

    thanks.

  • Hi. GANG ZHANG48047

    I've followed the John's guideline(word documentation) to use simultaneous two Ethernet ports, and I've met the below error case :<

    ================

    TCP/IP Stack 'Hello World!' Application

    StackTest: using dhcp
    EMACInit_Core port:1
    Setup_Tx port:1
    Setup_Rx port:1
    Add_MACAddress port:1
    Add_MACAddress port:1
    Registration of the EMAC Successful, waiting for link up ..  <-- might 1st port init success

    EMACInit_Core port:1
    Setup_Tx port:1
    Error opening PA Tx queue, i:0       <-- might 2nd port init fail
    Tx setup failed

    ====================

    So, I am now studying QMSS module hardly.

    Could you attach the nimu_eth.c file for me(or other people), please......:).

    It really helpful for many guys  -_- b

  • Hi, SungBum
    The nimu_eth.c file I use is exactly the same posted by John Demery in this post. But I dont use dhcp, instead I use static IP. You can try static IP. another tip is that you need to change the parameter for port 2 as followings:
    // Add the address to interface 2
    CfgAddEntry( hCfg, CFGTAG_IPNET, 2, 0,
    sizeof(CI_IPNET), (UINT8 *)&NA, 0 );
  • Hi. GANG ZHANG48047
    Opssss. I've downloaded just docx file.
    I'll check the zip file, too.
    Really thank you so much.
  • Yes,  you are right. I did it successfully. If you need anything concerned this ask me with little more details. I think i can help you with my experience.

  • Hi, Ryan.

    Thank you for your consideration.

    Actually, I am using the EVMK2H (evaluation) board. So, the source code which you modified is different of mine.

    (For example, my nimu_eth.c is under pdk_k2hk_4_0_2\packages\ti\transport\ndk\nimu\src\v2\nimu_eth.c).

    Therefore, I am modifying the nimu_eth.c with referencing of yours. :)

    Anyway, If I have any questions, please help me ^^

  • Hi. Ryan.

    After changing follow your comment(chnage the MAX_NUM_NIMU_DESC,MAX_NUM_DESC,MAX_DESC_SIZE to 256,256,512),
    I have met the exactly same fail message like yours during 2nd port "Verify_init" code. (The local variable 'j' means 2nd port)

    However, the 2nd port pings success even it fails the init. Ula~~~

    Would you guide a bit more about the "Error allocating Tx free descriptors " message?

    ===================log start=====================
    EMACInit_Core port:0
    PHY = SGMII port 0
    PASS successfully initialized
    SGMII Serdes Lanes Init Complete
    Ethernet subsystem successfully initialized
    Add_MACAddress port:0
    Add_MACAddress port:0
    Verify_Init: Expected 16 entry count for gTxFreeQHnd queue 0, found 0 entries, j:1
    Verify_Init: Expected 110 entry count for gRxFreeQHnd queue 0, found 0 entries, j:1
    Warning:Queue handler Verification failed
    Registration of the EMAC Successful, waiting for link up ..
    EmacInit
    EMACInit_Core port:1
    AMC = SGMII port 1
    Error allocating Tx free descriptors
    Tx setup failed
    Error: Unable to register the EMAC
    ...
    ===================log end=====================

    -> Error message is shown because I did not change the MAX_NUM_NIMU_DESC, MAX_NUM_DESC and MAX_DESC_SIZE at nimu_cppi_qmss_iface.h

    (I only changed at nimu_internal.h)

    After changing 3 define macro, to 256,256 and 512, both EMACs are inited successfully.

    I am really appreciate your help, Ryan.

    God blessing you~~:)