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.

QMSS, CPPI, PA Setup

My goal is to use the QMSS, CPPI and PA to handle as much of my specific network traffic as possible. I have two UDP ports that will be used. One port to send and receive packets, and the other port just to receive a continuous packet stream. 

I started with the PA Multicore Example. It was easy enough to take it and reconfigure so my rx/tx port worked within my app. However getting the second port, the receive data stream port, running has been a little tricky. 

What I did on the second port: I copied the Add_Port() function and modified it for my desired port number and changed the Rx queue destination setup

/* Setup the Rx queue as destination for the packets */
rxQInfo = Qmss_getQueueNumber (g_imagerx_qhnd);
routeInfo.queue = rxQInfo.qNum;
routeInfo.flowId = (uint8_t)Cppi_getFlowId(g_imagerx_flowhnd);

This is a fairly minor change and I 'feel' the problem must be with my new mem region, descriptor config, or rx flow configuration. I basically copied the setup for the multicore demo but changed the buffer sizes/locations. Also I do not need EPIB or PS info.

The configuration successfully completes but none of the stream packets are received, the FDQ is always full and RxQueue is always empty on this port! 

Also, one minor thing I found, and maybe it is because I have done something incorrectly, is if you configure the linkram as follows (which is like the QMMS InfrastructureMode example) :

/* Use internal linking RAM */
qmssInitConfig.linkingRAM0Base = (UInt32)&g_image_lram[0];
qmssInitConfig.linkingRAM0Size = ((NUM_HOST_DESC + NUM_IMAGE_HOST_DESC));
qmssInitConfig.linkingRAM1Base = 0;
qmssInitConfig.maxDescNum = (NUM_HOST_DESC + NUM_IMAGE_HOST_DESC);

But if ((NUM_HOST_DESC + NUM_IMAGE_HOST_DESC)) is greater than the internal link ram size it will error out. Even though I am using an external mem region. In qmmss_drv, function Qmss_init(), this is the line causing the problem:

/* Check if LinkingRAM0 can hold all the descriptors if LinkingRAM1 is NULL */
if (initCfg->linkingRAM1Base == 0)

So I just set 

qmssInitConfig.linkingRAM1Base = 1;

and it is happy. 

Reading the linkram memory area that pertains to the NUM_IMAGE_HOST_DESC (my stream port config), the index entries all have a value of 0x80000 + index. I was wondering if that 0x80000 indicates some configuration issue?

  • I have my attached my modified cppi_qmss_mgmt.c file

  • /**  
     * @file cppi_qmss_mgmt.c
     *
     * @brief 
     *  This file holds all the APIs required to configure CPPI/QMSS LLDs and 
     *  to send/receive data using PA/QM.
     *
     *  \par
     *  ============================================================================
     *  @n   (C) Copyright 2009, Texas Instruments, Inc.
     * 
     *  Redistribution and use in source and binary forms, with or without 
     *  modification, are permitted provided that the following conditions 
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright 
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the 
     *    documentation and/or other materials provided with the   
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
    */
    #include "multicore_example.h"
    #include <ti/drv/qmss/qmss_firmware.h>
    /* QMSS device specific configuration */
    extern Qmss_GlobalConfigParams  qmssGblCfgParams;
    /* CPPI device specific configuration */
    extern Cppi_GlobalConfigParams  cppiGblCfgParams;
    
    extern paMacAddr_t g_mac_address_port0;
    
    //#define _LITTLE_ENDIAN
    
    //#if ( !defined( _LITTLE_ENDIAN ) && !defined( _BIG_ENDIAN ) ) \
    //||  ( defined(_LITTLE_ENDIAN ) && defined( _BIG_ENDIAN ) )
    //#error either _LITTLE_ENDIAN or _BIG_ENDIAN must be defined
    //#endif
    
    
    /* Number of Tx Free descriptors to allocate */
    #define     NUM_TX_DESC                 NUM_HOST_DESC/2
    
    /* Number of Rx Free descriptors to allocate */
    #define     NUM_RX_DESC                 NUM_HOST_DESC/2
    
    /* Buffer sizes configured for 
     * -  maximum command size to PA 
     * -  Maximum size of the control messages
     *    from DSP
     * - Maximum size of the packets being transmitted
     */
    //#define TX_BUF_SIZE 		(((300+15)/16)*16)
    #define TX_BUF_SIZE 		(512)
    #define RX_BUF_SIZE 		TX_BUF_SIZE  
    
    #define IMAGE_RX_BUF_SZ		1500 //max ethernet fram size
    
    
    #pragma DATA_SECTION(g_image_lram, ".sharedDDR")
    #pragma DATA_ALIGN (g_image_lram, 16)
    UInt32 far g_image_lram[(((NUM_HOST_DESC + NUM_IMAGE_HOST_DESC) * 2) + 1)];
    
    /* Image Host Descriptor Region - [Size of descriptor * Number of descriptors]
     *
     * MUST be 16 byte aligned.
     */
    
    /* Host Descriptor Region - [Size of descriptor * Number of descriptors] 
     *
     * MUST be 16 byte aligned.
     */
    #pragma DATA_SECTION(gHostDesc, ".sharedDDR")
    #pragma DATA_ALIGN (gHostDesc, 64)
    UInt8 far gHostDesc[SIZE_HOST_DESC * NUM_HOST_DESC];
    
    /* Buffers to be used for TX */
    #pragma DATA_SECTION (cppiMemTX, ".cppiMemTX");
    #pragma DATA_ALIGN(cppiMemTX, 16)
    Uint8 far cppiMemTX[NUM_TX_DESC][TX_BUF_SIZE];
    
    /* Buffers to be used for RX */
    #pragma DATA_SECTION (cppiMemRX, ".cppiMemRX");
    #pragma DATA_ALIGN(cppiMemRX, 16)
    Uint8 far cppiMemRX[NUM_RX_DESC][RX_BUF_SIZE];
    
    /* QMSS queue handles */
    
    /* Queue with free descriptors */
    #pragma DATA_SECTION(gGlobalFreeQHnd, ".sharedDDR")
    Qmss_QueueHnd    far                       gGlobalFreeQHnd;
    
    /* TX queues used to send data to PA PDSP/CPSW.*/
    #pragma DATA_ALIGN   (gPaTxQHnd, 128)
    #pragma DATA_SECTION(gPaTxQHnd, ".sharedDDR")
    Qmss_QueueHnd     far                      gPaTxQHnd [NUM_PA_TX_QUEUES];
    
    /* TX queue with free decriptors attached to data buffers for transmission.*/
    #pragma DATA_ALIGN   (gTxFreeQHnd, 128)
    #pragma DATA_SECTION(gTxFreeQHnd, ".sharedDDR")
    Qmss_QueueHnd      far                     gTxFreeQHnd;
    
    /* RX queue with free decriptors attached to data buffers to be used
       by the PASS CPDMA to hold the received data.*/
    #pragma DATA_ALIGN   (gRxFreeQHnd, 128)
    #pragma DATA_SECTION(gRxFreeQHnd, ".sharedDDR")
    Qmss_QueueHnd       far                    gRxFreeQHnd;
    
    /* RX queue used by the application to receive packets from PASS/CPSW.
       Each core has an independent RX queue. */
    #pragma DATA_SECTION(gRxQHnd, ".sharedDDR")
    Qmss_QueueHnd           far                gRxQHnd[NUM_CORES];
    
    
    /* CPPI Handles used by the application */
    #pragma DATA_SECTION(gCpdmaHnd, ".sharedDDR")
    Cppi_Handle           far                  gCpdmaHnd;
    
    #pragma DATA_SECTION(gCpdmaTxChanHnd, ".sharedDDR")
    Cppi_ChHnd           far                   gCpdmaTxChanHnd [NUM_PA_TX_QUEUES];
    
    #pragma DATA_SECTION(gCpdmaRxChanHnd, ".sharedDDR")
    Cppi_ChHnd          far                    gCpdmaRxChanHnd [NUM_PA_RX_CHANNELS];
    
    Cppi_FlowHnd                            gRxFlowHnd;
    
    #pragma DATA_SECTION(g_image_hdesc, ".sharedDDR")
    #pragma DATA_ALIGN (g_image_hdesc, 16)
    UInt8 far g_image_hdesc[IMAGE_HOST_DESC_SZ * (NUM_IMAGE_HOST_DESC + 1)];
    
    /* Buffers to be used for Image RX */
    #pragma DATA_SECTION (cppi_mem_image_rx, ".cppiMemImageRX");
    #pragma DATA_ALIGN(cppi_mem_image_rx, 16)
    Uint8 far cppi_mem_image_rx[NUM_IMAGE_HOST_DESC][IMAGE_RX_BUF_SZ];
    
    /* Queue with free descriptors */
    #pragma DATA_SECTION(g_image_freeqhnd, ".sharedDDR")
    Qmss_QueueHnd    far                       g_image_freeqhnd;
    
    /* RX queue with free decriptors attached to data buffers to be used
       by the PASS CPDMA to hold the received data.*/
    #pragma DATA_ALIGN   (g_imagerx_freeqhnd, 128)
    #pragma DATA_SECTION(g_imagerx_freeqhnd, ".sharedDDR")
    Qmss_QueueHnd       far                    g_imagerx_freeqhnd;
    
    /* RX queue used by the application to receive packets from PASS/CPSW.
       Each core has an independent RX queue. */
    #pragma DATA_SECTION(g_imagerx_qhnd, ".sharedDDR")
    Qmss_QueueHnd           far                g_imagerx_qhnd;
    
    
    #pragma DATA_SECTION(g_cpdma_imagerx_chanhnd, ".sharedDDR")
    Cppi_ChHnd          far                    g_cpdma_imagerx_chanhnd [NUM_PA_RX_CHANNELS];
    
    Cppi_FlowHnd                            g_imagerx_flowhnd;
    
    /* Constructed data packet to send. 
       Each core will have a slightly modified version
       of this packet which is stored in the core's local memory. */
    #define PACKET_UDP_DEST_PORT_SHIFT  36
    #define PACKET_PAYLOAD_SHIFT        42
    #pragma DATA_ALIGN(pktMatch, 16)
    UInt8 pktMatch[] = {
    							0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,                      /* Dest MAC */
                                0x40, 0x54, 0xc2, 0xc9, 0x29, 0x2F,                      /* Src MAC  */
                                0x08, 0x00,                                              /* Ethertype = IPv4 */
                                0x45, 0x00, 0x00, 0x24,                                  /* IP version, services, total length */
                                0x00, 0x00, 0x40, 0x00,                                  /* IP ID, flags, fragment offset */
                                0x80, 0x11, 0x32, 0x26,                                  /* IP ttl, protocol (UDP), header checksum */
                                0xc0, 0xa8, 0x00, 0x67,                                  /* Source IP address */
                                0xFF, 0xFF, 0xFF, 0xFF,                                  /* Destination IP address */
                                0xD9, 0x7E, 0x0F, 0x74,                                  /* UDP source port, dest port */
                                0x00, 0x10, 0x00, 0x00,                                  /* UDP len, UDP checksum */
                                0x42, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01,          /* 80 bytes of payload data */
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0x00, 0x00  };
    /*
    UInt8 pktMatch[] = {
    							0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,                      // Dest MAC
                                0x40, 0x5F, 0xC2, 0xC9, 0x29, 0x2F,                      // Src MAC
                                0x08, 0x00,                                              // Ethertype = IPv4
                                0x45, 0x00, 0x00, 0x24,                                  // IP version, services, total length
                                0x00, 0x00, 0x40, 0x00,                                  // IP ID, flags, fragment offset
                                0x80, 0x11, 0x39, 0xBA,                                  // IP ttl, protocol (UDP), header checksum
                                0xc0, 0xa8, 0x00, 0x67,                                  // Source IP address
                                0xFF, 0xFF, 0xFF, 0xFF,                                  // Destination IP address
                                0xD9, 0xE7, 0x0F, 0x74,                                  // UDP source port, dest port
                                0x00, 0x10, 0x00, 0x00,                                  // UDP len, UDP checksum
                                0x42, 0x01, 0x00, 0x02,
    							0x00, 0x00, 0x00, 0x01};
    */
    /* Tx/Rx packet counters */
    volatile UInt32						gTxCounter = 0, gRxCounter = 0;
    
    /* High Priority Accumulation Interrupt Service Handler for this application */
    Void Cpsw_RxISR (Void);
    
    
    
    /** ============================================================================
     *   @n@b Init_Qmss
     *
     *   @b Description
     *   @n This API initializes the QMSS LLD on core 0 only.
     *
     *   @param[in]  
     *   @n None
     * 
     *   @return    Int32
     *              -1      -   Error
     *              0       -   Success
     * =============================================================================
     */
    Int32 Init_Qmss (Void)
    {
        Int32                       result;
        Qmss_MemRegInfo             memCfg;
        Qmss_MemRegInfo             image_memcfg;
        Qmss_InitCfg                qmssInitConfig;
        Cppi_DescCfg                cppiDescCfg;
        Cppi_DescCfg                cppi_imageDescCfg;
        UInt32                      numAllocated;
    
        /* Initialize QMSS */
        memset (&qmssInitConfig, 0, sizeof (Qmss_InitCfg));
    
        /* Set up QMSS configuration */
    
        /* Use internal linking RAM */
        qmssInitConfig.linkingRAM0Base  =   (UInt32)&g_image_lram[0];
        qmssInitConfig.linkingRAM0Size  =   ((NUM_HOST_DESC + NUM_IMAGE_HOST_DESC));
        qmssInitConfig.linkingRAM1Base  =   1;
        qmssInitConfig.maxDescNum       =   (NUM_HOST_DESC + NUM_IMAGE_HOST_DESC);
        //qmssInitConfig.maxDescNum       =   NUM_HOST_DESC;
        
        qmssInitConfig.pdspFirmware[0].pdspId = Qmss_PdspId_PDSP1;
    #ifdef _LITTLE_ENDIAN    
        qmssInitConfig.pdspFirmware[0].firmware = (void *) &acc48_le;
        qmssInitConfig.pdspFirmware[0].size = sizeof (acc48_le);
    #else
        qmssInitConfig.pdspFirmware[0].firmware = (void *) &acc48_be;
        qmssInitConfig.pdspFirmware[0].size = sizeof (acc48_be);
    #endif    
    
    	(*(volatile UInt32 *)(MSGREG + 4)) = 0xcab00;
        /* Initialize the Queue Manager */
        result = Qmss_init (&qmssInitConfig, &qmssGblCfgParams);
        if (result != QMSS_SOK)
        {
            System_printf ("Error initializing Queue Manager SubSystem, Error code : %d\n", result);
        	(*(volatile UInt32 *)(MSGREG + 8)) = result;
           return -1;
        }
    
    	(*(volatile UInt32 *)(MSGREG + 4)) = 0xcab01;
    
        /* Start Queue manager on this core */
        Qmss_start ();
    
    	////////////////////////////////////////////////////////////////////////////
    
    	/* Initialize and setup CPSW Host Descriptors required for example */
    	memset (gHostDesc, 0, SIZE_HOST_DESC * NUM_HOST_DESC);
    	memCfg.descBase             =   (UInt32 *) gHostDesc;
    	memCfg.descSize             =   SIZE_HOST_DESC;
    	memCfg.descNum              =   NUM_HOST_DESC;
    	memCfg.manageDescFlag       =   Qmss_ManageDesc_MANAGE_DESCRIPTOR;
    	memCfg.memRegion            =   Qmss_MemRegion_MEMORY_REGION0;
    	memCfg.startIndex           =   0;
    
    	(*(volatile UInt32 *)(MSGREG + 4)) = 0xcab02;
    	/* Insert Host Descriptor memory region */
    	result = Qmss_insertMemoryRegion(&memCfg);
    	if (result == QMSS_MEMREGION_ALREADY_INITIALIZED)
    	{
    		System_printf ("Memory Region %d already Initialized \n", memCfg.memRegion);
    	}
    	else if (result < QMSS_SOK)
    	{
    		System_printf ("Error: Inserting memory region %d, Error code : %d\n", memCfg.memRegion, result);
    		return -1;
    	}
    
        ////////////////////////////////////////////////////////////////////////////
    	/* Setup the descriptor memory regions.
    	 *
    	 * The Descriptor base addresses MUST be global addresses and
    	 * all memory regions MUST be setup in ascending order of the
    	 * descriptor base addresses.
    	 */
    	/* Initialize and setup Image Host Descriptors required for example */
    
    	memset (g_image_hdesc, 0, IMAGE_HOST_DESC_SZ * NUM_IMAGE_HOST_DESC);
    	image_memcfg.descBase             =   (UInt32 *) g_image_hdesc;
    	image_memcfg.descSize             =   IMAGE_HOST_DESC_SZ;
    	image_memcfg.descNum              =   NUM_IMAGE_HOST_DESC;
    	image_memcfg.manageDescFlag       =   Qmss_ManageDesc_MANAGE_DESCRIPTOR; //Who manages the descriptors: user or LLD.
    //	image_memcfg.memRegion            =   Qmss_MemRegion_MEMORY_REGION_NOT_SPECIFIED;
    	image_memcfg.memRegion            =   Qmss_MemRegion_MEMORY_REGION2;
    	image_memcfg.startIndex           =   NUM_HOST_DESC;
    
    	(*(volatile UInt32 *)(MSGREG + 4)) = 0xcab03;
    	// Insert Image Host Descriptor memory region
    	result = Qmss_insertMemoryRegion(&image_memcfg);
    	if (result == QMSS_MEMREGION_ALREADY_INITIALIZED)
    	{
    		System_printf ("Memory Region %d already Initialized \n", memCfg.memRegion);
    	}
    	else if (result < QMSS_SOK)
    	{
    		System_printf ("Error: Inserting memory region %d, Error code : %d\n", memCfg.memRegion, result);
    		return -1;
    	}
    
    
    ////////////////////////////////////////////////////////////////////////////
    
        /* Initialize all the descriptors we just allocated on the
         * memory region above. Setup the descriptors with some well
         * known values before we use them for data transfers.
         */
        memset (&cppiDescCfg, 0, sizeof (cppiDescCfg));
        cppiDescCfg.memRegion       =   Qmss_MemRegion_MEMORY_REGION0;
        cppiDescCfg.descNum         =   NUM_HOST_DESC;
        cppiDescCfg.destQueueNum    =   QMSS_PARAM_NOT_SPECIFIED;     
        cppiDescCfg.queueType       =   Qmss_QueueType_GENERAL_PURPOSE_QUEUE;
        cppiDescCfg.initDesc        =   Cppi_InitDesc_INIT_DESCRIPTOR;
        cppiDescCfg.descType        =   Cppi_DescType_HOST;
        
        /* By default:
         *      (1) Return descriptors to tail of queue 
         *      (2) Always return entire packet to this free queue
         *      (3) Set that PS Data is always present in start of SOP buffer
         *      (4) Configure free q num < 4K, hence qMgr = 0
         *      (5) Recycle back to the same Free queue by default.
         */
        cppiDescCfg.returnPushPolicy            =   Qmss_Location_TAIL;    
        cppiDescCfg.cfg.host.returnPolicy       =   Cppi_ReturnPolicy_RETURN_ENTIRE_PACKET;    
        cppiDescCfg.cfg.host.psLocation         =   Cppi_PSLoc_PS_IN_DESC;         
        cppiDescCfg.returnQueue.qMgr            =   0;    
        cppiDescCfg.returnQueue.qNum            =   QMSS_PARAM_NOT_SPECIFIED; 
        cppiDescCfg.epibPresent                 =   Cppi_EPIB_EPIB_PRESENT;
        
    	(*(volatile UInt32 *)(MSGREG + 4)) = 0xcab04;
        /* Initialize the descriptors, create a free queue and push descriptors to a global free queue */
        if ((gGlobalFreeQHnd = Cppi_initDescriptor (&cppiDescCfg, &numAllocated)) <= 0)
        {
            System_printf ("Error Initializing Free Descriptors, Error: %d \n", gGlobalFreeQHnd);
            return -1;
        }
        else
        {
            System_printf ("Initializing Free Descriptors. \n");
        }        
    
        ////////////////////////////////////////////////////////////////////////////
            /* Initialize all the descriptors we just allocated on the
              * memory region above. Setup the descriptors with some well
              * known values before we use them for data transfers.
              */
    	memset (&cppi_imageDescCfg, 0, sizeof (cppi_imageDescCfg));
    	cppi_imageDescCfg.memRegion       =   Qmss_MemRegion_MEMORY_REGION2;
    	cppi_imageDescCfg.descNum         =   NUM_IMAGE_HOST_DESC;
    	cppi_imageDescCfg.destQueueNum    =   QMSS_PARAM_NOT_SPECIFIED;
    	cppi_imageDescCfg.queueType       =   Qmss_QueueType_GENERAL_PURPOSE_QUEUE;
    	cppi_imageDescCfg.initDesc        =   Cppi_InitDesc_INIT_DESCRIPTOR;
    	cppi_imageDescCfg.descType        =   Cppi_DescType_HOST;
    
    	cppi_imageDescCfg.returnPushPolicy            =   Qmss_Location_TAIL;
    	cppi_imageDescCfg.cfg.host.returnPolicy       =   Cppi_ReturnPolicy_RETURN_ENTIRE_PACKET;
    	cppi_imageDescCfg.cfg.host.psLocation         =   Cppi_PSLoc_PS_IN_DESC;
    	cppi_imageDescCfg.returnQueue.qMgr            =   0;
    	cppi_imageDescCfg.returnQueue.qNum            =   QMSS_PARAM_NOT_SPECIFIED;
    	cppi_imageDescCfg.epibPresent                 =   Cppi_EPIB_NO_EPIB_PRESENT;
    
    	(*(volatile UInt32 *)(MSGREG + 4)) = 0xcab05;
    	// Initialize the descriptors, create a free queue and push descriptors to a global free queue
    	if ((g_image_freeqhnd = Cppi_initDescriptor (&cppi_imageDescCfg, &numAllocated)) <= 0)
    	{
    	 System_printf ("Error Initializing Free Descriptors, Error: %d \n", g_image_freeqhnd);
    	 return -1;
    	}
    	else
    	{
    	 System_printf ("Initializing Free Descriptors. \n");
    	(*(volatile UInt32 *)(MSGREG + 8)) = numAllocated;
    	}
    
    	/* Queue Manager Initialization Done */
        return 0;
    }
    
    
    /** ============================================================================
     *   @n@b Init_Qmss_Local
     *
     *   @b Description
     *   @n This API initializes the QMSS LLD in cores other than core 0.
     *
     *   @param[in]  
     *   @n None
     * 
     *   @return    Int32
     *              -1      -   Error
     *              0       -   Success
     * =============================================================================
     */
    Int32 Init_Qmss_Local (Void)
    {
      Int32            result;
    
      while(1)
      {
          /* Block until Qmss_init() has completed by core 0 */
          result = Qmss_start();
          if(result == QMSS_NOT_INITIALIZED)
          {
              System_printf ("QMSS Not yet Initialized\n");
              continue;
          }
          else if (result != QMSS_SOK)  {
            System_printf ("Qmss_start failed with error code %d\n", result);
            return (-1);
          }
    
          if (result == QMSS_SOK) 
          {
              break;
          }
      }
    
      return 0;
    }
    
    
    /** ============================================================================
     *   @n@b Init_Cppi
     *
     *   @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
     *              -1      -   Error
     *              0       -   Success
     * =============================================================================
     */
    Int32 Init_Cppi (Void)
    {
        Int32                       result, i;        
        Cppi_CpDmaInitCfg           cpdmaCfg;
        UInt8                       isAllocated;        
        Cppi_TxChInitCfg            txChCfg;
        Cppi_RxChInitCfg            rxChInitCfg;
    
        /* Initialize CPPI LLD */
        result = Cppi_init (&cppiGblCfgParams);
        if (result != CPPI_SOK)
        {
            System_printf ("Error initializing CPPI LLD, Error code : %d\n", result);
            return -1;
        }
    
        /* Initialize PASS CPDMA */
        memset (&cpdmaCfg, 0, sizeof (Cppi_CpDmaInitCfg));
        cpdmaCfg.dmaNum     = Cppi_CpDma_PASS_CPDMA;
        if ((gCpdmaHnd = Cppi_open (&cpdmaCfg)) == NULL)
        {
            System_printf ("Error initializing CPPI for PASS CPDMA %d \n", cpdmaCfg.dmaNum);
            return -1;
        }    
    
        /* Open all CPPI Tx Channels. These will be used to send data to PASS/CPSW */             
        for (i = 0; i < NUM_PA_TX_QUEUES; i ++)
        {
            txChCfg.channelNum      =   i;       /* CPPI channels are mapped one-one to the PA Tx queues */
            txChCfg.txEnable        =   Cppi_ChState_CHANNEL_DISABLE;  /* Disable the channel for now. */
            txChCfg.filterEPIB      =   0;
            txChCfg.filterPS        =   0;
            txChCfg.aifMonoMode     =   0;
            txChCfg.priority        =   2;
            if ((gCpdmaTxChanHnd[i] = Cppi_txChannelOpen (gCpdmaHnd, &txChCfg, &isAllocated)) == NULL)
            {
                System_printf ("Error opening Tx channel %d\n", txChCfg.channelNum);
                return -1;
            }
    
            Cppi_channelEnable (gCpdmaTxChanHnd[i]);
        }
    
        /* Open all CPPI Rx channels. These will be used by PA to stream data out. */
        for (i = 0; i < NUM_PA_RX_CHANNELS; i++)
        {
            /* Open a CPPI Rx channel that will be used by PA to stream data out. */
            rxChInitCfg.channelNum  =   i; 
            rxChInitCfg.rxEnable    =   Cppi_ChState_CHANNEL_DISABLE; 
            if ((gCpdmaRxChanHnd[i] = Cppi_rxChannelOpen (gCpdmaHnd, &rxChInitCfg, &isAllocated)) == NULL)
            {
                System_printf ("Error opening Rx channel: %d \n", rxChInitCfg.channelNum);
                return -1;
            }
    
            /* Also enable Rx Channel */
            Cppi_channelEnable (gCpdmaRxChanHnd[i]);    
        }
        
        /* Clear CPPI Loobpack bit in PASS CDMA Global Emulation Control Register */
        Cppi_setCpdmaLoopback(gCpdmaHnd, 0);
    
        /* CPPI Init Done. Return success */
        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
     *              -1      -   Error
     *              0       -   Success
     * =============================================================================
     */
    Int32 Setup_Tx (Void)
    {
        UInt8                       isAllocated, i;        
        Qmss_Queue                  qInfo;
        Ptr                   		pCppiDesc;
    
        /* 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)
            {
                System_printf ("Error opening PA Tx queue \n");
                return -1;
            }            
        }
        
        SYS_CACHE_WB ((void *)gPaTxQHnd, 128, CACHE_WAIT);
        
    
        /* 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)
        {
            System_printf ("Error opening Tx Free descriptor queue \n");
            return -1;
        }    
        
        SYS_CACHE_WB ((void *)&gTxFreeQHnd, 128, CACHE_WAIT);
                
    
        qInfo = Qmss_getQueueNumber (gTxFreeQHnd);
    
        /* Attach some free descriptors to the Tx free queue we just opened. */
        for (i = 0; i < NUM_TX_DESC; i++)
        {
            /* Get a free descriptor from the global free queue we setup 
             * during initialization.
             */
            if ((pCppiDesc = Qmss_queuePop (gGlobalFreeQHnd)) == NULL)
            {
                break;                
            }
    
            /* The descriptor address returned from the hardware has the 
             * 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) pCppiDesc & 0xFFFFFFF0);
    
            /* Populate the Tx free descriptor with the buffer. */
            Cppi_setData (Cppi_DescType_HOST, pCppiDesc, (Uint8 *)(&cppiMemTX[i]), TX_BUF_SIZE);
    
            /* Save original buffer information */
            Cppi_setOriginalBufInfo (Cppi_DescType_HOST, pCppiDesc, (Uint8 *)(&cppiMemTX[i]), TX_BUF_SIZE);
    
            /* 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) Cppi_DescType_HOST, pCppiDesc, qInfo);
    
            Cppi_setPacketLen    (Cppi_DescType_HOST, pCppiDesc, TX_BUF_SIZE);
            
            SYS_CACHE_WB (pCppiDesc, SIZE_HOST_DESC, CACHE_FENCE_WAIT);
    
            /* Push descriptor to Tx free queue */
            Qmss_queuePushDescSize (gTxFreeQHnd, pCppiDesc, SIZE_HOST_DESC);           
        }
        if (i != NUM_TX_DESC)
        {
            System_printf ("Error allocating Tx 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. 
     *
     *   @param[in]  
     *   @n None
     * 
     *   @return    Int32
     *              -1      -   Error
     *              0       -   Success
     * =============================================================================
     */
    Int32 Setup_Rx (Void)
    {
        UInt8                       isAllocated, i;        
        Qmss_Queue                  rxFreeQInfo, rxQInfo;
        Ptr                   		pCppiDesc;
        Cppi_RxFlowCfg              rxFlowCfg;
        Ptr                         pDataBuffer;
        Uint32                      mySWInfo[] = {0x11112222, 0x33334444};
    	UInt32                      coreNum;
    
        /* Get the core number. */
        coreNum = CSL_chipReadReg(CSL_CHIP_DNUM); 
        
        /* Open a Receive (Rx) queue. 
         *
         * This queue will be used to hold all the packets received by PASS/CPSW
         *
         */
        if ((gRxQHnd[coreNum] = Qmss_queueOpen (Qmss_QueueType_GENERAL_PURPOSE_QUEUE, RX_QUEUE_NUM_INIT+coreNum, &isAllocated)) < 0)
        {
            System_printf ("Error opening gRxQHnd queue \n");
            return -1;
        }            
        rxQInfo = Qmss_getQueueNumber (gRxQHnd[coreNum]);
    
        /* The following RX queues are shared between cores, so their
           initialization is done by core zero only*/
        if(!coreNum)
        {   
            /* Open a Rx Free Descriptor Queue (Rx FDQ). 
             *
             * This queue will hold all the Rx free decriptors. 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)
            {
                System_printf ("Error opening Rx Free descriptor queue \n");
                return -1;
            }            
            
            SYS_CACHE_WB ((void *)&gRxFreeQHnd, 128, CACHE_WAIT);
            
            rxFreeQInfo = Qmss_getQueueNumber (gRxFreeQHnd);
    
            /* Attach some free descriptors to the Rx free queue we just opened. */
            for (i = 0; i < NUM_RX_DESC; i++)
            {
                /* Get a free descriptor from the global free queue we setup 
                 * during initialization.
                 */
                if ((pCppiDesc = Qmss_queuePop (gGlobalFreeQHnd)) == NULL)
                {
                    System_printf ("Error poping descriptor.\n");
                    break;                
                }
    
                /* The descriptor address returned from the hardware has the 
                 * 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) pCppiDesc & 0xFFFFFFF0);
                
                pDataBuffer = (Uint8 *)(&cppiMemRX[i]);
                /* Populate the Rx free descriptor with the buffer we just allocated. */
                Cppi_setData (Cppi_DescType_HOST, pCppiDesc, (UInt8 *)pDataBuffer, RX_BUF_SIZE);
    
                /* Save original buffer information */
                Cppi_setOriginalBufInfo (Cppi_DescType_HOST, pCppiDesc, (UInt8 *)pDataBuffer, RX_BUF_SIZE);
                
    
                /* 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 *) mySWInfo);
    
                Cppi_setPacketLen    (Cppi_DescType_HOST, pCppiDesc, RX_BUF_SIZE);
                
                SYS_CACHE_WB (pCppiDesc, SIZE_HOST_DESC, CACHE_FENCE_WAIT);
                
                /* Push descriptor to Tx free queue */
                Qmss_queuePushDescSize (gRxFreeQHnd, pCppiDesc, SIZE_HOST_DESC);           
            }        
            if (i != NUM_RX_DESC)
            {
                System_printf ("Error allocating Rx free descriptors \n");
                return -1;
            }
        }
        
        /* Setup a Rx Flow on each core. The only difference among the cores is the rxQInfo.
         *
         * A Rx flow encapsulates all relevant data properties that CPDMA would
         * have to know in order to succefully receive data.
         */
        /* Initialize the flow configuration */
        memset (&rxFlowCfg, 0, sizeof(Cppi_RxFlowCfg));
        rxFreeQInfo = Qmss_getQueueNumber (gRxFreeQHnd);
    
        /* 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 (gCpdmaHnd, &rxFlowCfg, &isAllocated)) == NULL)
        {
            System_printf ("Error configuring Rx flow \n");
            return -1;
        }
    
        /* All done with Rx configuration. Return success. */
        return 0;
    }
    
    /** ============================================================================
     *   @n@b setup_imagerx
     *
     *   @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.
     *
     *   @param[in]
     *   @n None
     *
     *   @return    Int32
     *              -1      -   Error
     *              0       -   Success
     * =============================================================================
     */
    Int32 setup_imagerx (void)
    {
        UInt8                       isAllocated;
        Qmss_Queue                  rxFreeQInfo, rxQInfo;
        Ptr                   		pCppiDesc;
        Cppi_RxFlowCfg              rxFlowCfg;
        Ptr                         pDataBuffer;
        Uint32                      mySWInfo[] = {0x11112222, 0x33334444};
    	UInt32                      coreNum, i;
    
        /* Get the core number. */
        coreNum = CSL_chipReadReg(CSL_CHIP_DNUM);
    
    	(*(volatile UInt32 *)(MSGREG + 4)) = 0xDEAD00;
        /* Open a Receive (Rx) queue.
         *
         * This queue will be used to hold all the packets received by PASS/CPSW
         *
         */
        if ((g_imagerx_qhnd = Qmss_queueOpen (Qmss_QueueType_GENERAL_PURPOSE_QUEUE, IMAGERX_QUEUE_NUM_INIT, &isAllocated)) < 0)
        {
            System_printf ("Error opening gRxQHnd queue \n");
            return -1;
        }
        rxQInfo = Qmss_getQueueNumber (g_imagerx_qhnd);
    
    	(*(volatile UInt32 *)(MSGREG + 4)) = 0xDEAD01;
        /* The following RX queues are shared between cores, so their
           initialization is done by core zero only*/
        if(!coreNum)
        {
            /* Open a Rx Free Descriptor Queue (Rx FDQ).
             *
             * This queue will hold all the Rx free decriptors. These descriptors will be
             * used by the PASS CPDMA to hold data received via CPSW.
             */
            if ((g_imagerx_freeqhnd = Qmss_queueOpen (Qmss_QueueType_STARVATION_COUNTER_QUEUE, QMSS_PARAM_NOT_SPECIFIED, &isAllocated)) < 0)
            {
                System_printf ("Error opening Rx Free descriptor queue \n");
                return -1;
            }
        	(*(volatile UInt32 *)(MSGREG + 8)) = isAllocated;
    
            SYS_CACHE_WB ((void *)&g_imagerx_freeqhnd, 128, CACHE_WAIT);
    
            rxFreeQInfo = Qmss_getQueueNumber (g_imagerx_freeqhnd);
    
        	(*(volatile UInt32 *)(MSGREG + 4)) = 0xDEAD02;
    
    
        	(*(volatile UInt32 *)(MSGREG + 0xC)) = Qmss_getQueueEntryCount(g_image_freeqhnd);
        	/* Attach some free descriptors to the Rx free queue we just opened. */
            for (i = 0; i < NUM_IMAGE_HOST_DESC; i++)
            {
                /* Get a free descriptor from the global free queue we setup
                 * during initialization.
                 */
                if ((pCppiDesc = Qmss_queuePop (g_image_freeqhnd)) == NULL)
                {
                    System_printf ("Error poping descriptor.\n");
                    break;
                }
            	(*(volatile UInt32 *)(MSGREG + 4)) = 0xDEAD03;
    
                /* The descriptor address returned from the hardware has the
                 * 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) pCppiDesc & 0xFFFFFFF0);
    
                pDataBuffer = (Uint8 *)(&cppi_mem_image_rx[i]);
                /* Populate the Rx free descriptor with the buffer we just allocated. */
                Cppi_setData (Cppi_DescType_HOST, pCppiDesc, (UInt8 *)pDataBuffer, IMAGE_RX_BUF_SZ);
    
                /* Save original buffer information */
                Cppi_setOriginalBufInfo (Cppi_DescType_HOST, pCppiDesc, (UInt8 *)pDataBuffer, IMAGE_RX_BUF_SZ);
    
            	(*(volatile UInt32 *)(MSGREG + 4)) = 0xDEAD04;
    
                /* 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 *) mySWInfo);
    
                Cppi_setPacketLen    (Cppi_DescType_HOST, pCppiDesc, IMAGE_RX_BUF_SZ);
    
                SYS_CACHE_WB (pCppiDesc, IMAGE_HOST_DESC_SZ, CACHE_FENCE_WAIT);
    
                /* Push descriptor to Tx free queue */
                Qmss_queuePushDescSize (g_imagerx_freeqhnd, pCppiDesc, IMAGE_HOST_DESC_SZ);
            }
            if (i != NUM_IMAGE_HOST_DESC)
            {
                System_printf ("Error allocating Rx free descriptors \n");
            	(*(volatile UInt32 *)(MSGREG + 4)) = ((0xDEAD << 16) + i);
                return -1;
            }
        }
    
    	(*(volatile UInt32 *)(MSGREG + 4)) = 0xDEAD06;
        /* Setup a Rx Flow on each core. The only difference among the cores is the rxQInfo.
         *
         * A Rx flow encapsulates all relevant data properties that CPDMA would
         * have to know in order to succefully receive data.
         */
        /* Initialize the flow configuration */
        memset (&rxFlowCfg, 0, sizeof(Cppi_RxFlowCfg));
        rxFreeQInfo = Qmss_getQueueNumber (g_imagerx_freeqhnd);
    
        /* 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_SOP;
        rxFlowCfg.rx_psinfo_present     =   0;    /* Enable PS info */
    
        rxFlowCfg.rx_error_handling     =   0;    /* Drop the packet, do not retry on starvation by default */
        rxFlowCfg.rx_einfo_present      =   0;    /* 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;
    
    	(*(volatile UInt32 *)(MSGREG + 4)) = 0xDEAD06;
        /* Configure the Rx flow */
        if ((g_imagerx_flowhnd = Cppi_configureRxFlow (gCpdmaHnd, &rxFlowCfg, &isAllocated)) == NULL)
        {
            System_printf ("Error configuring Rx flow \n");
        	(*(volatile UInt32 *)(MSGREG + 4)) = 0xDEAD07;
            return -1;
        }
    
        /* All done with Rx configuration. Return success. */
        return 0;
    }
    
    /** ============================================================================
     *   @n@b SendPacket
     *
     *   @b Description
     *   @n This API is called to actually send out data onto wire using ethernet.
     *      On success, this API increments a global Tx counter to indicate the same.
     *
     *   @param[in]  
     *   @n None
     * 
     *   @return    Int32
     *              -1      -   Error
     *              0       -   Success
     * =============================================================================
     */
    int sendpacket (UInt32 s, UInt32 len, char *pckt)
    {
        Cppi_HostDesc*  pCppiDesc;
        char            psFlags = (cpswSimTest)?pa_EMAC_PORT_0:pa_EMAC_PORT_1;
        int i;
    
        /* Get a free descriptor from the global free queue we setup 
         * during initialization.
         */
        if ((pCppiDesc = Qmss_queuePop (gTxFreeQHnd)) == NULL)
        {
            System_printf ("No Tx free descriptor. Cant run send/rcv test \n");
            return -1;
        }
        
        /* The descriptor address returned from the hardware has the 
         * 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) pCppiDesc & 0xFFFFFFF0);
    
        //memset(pktMatch, 0 , sizeof(pktMatch));
        //for (i=0; i<len; i++)
        	//pktMatch[i] = pckt[i];
    
        /* Disable Interrupts */
        //key = Hwi_disable();
    
         /* Get the hardware semaphore.
         *
         * Acquire Multi core CPPI synchronization lock
         */
        while ((CSL_semAcquireDirect (PLATFORM_CPPI_HW_SEM)) == 0);
    
        /* Cleanup the prefetch buffer also. */
        CSL_XMC_invalidatePrefetchBuffer();
        
        SYS_CACHE_INV (pCppiDesc, SIZE_HOST_DESC, CACHE_FENCE_WAIT);
        
        Cppi_setData (  Cppi_DescType_HOST, 
                        (Cppi_Desc *) pCppiDesc, 
                        (UInt8 *) Convert_CoreLocal2GlobalAddr((UInt32)pckt),
                        len
                     );
        Cppi_setPacketLen (Cppi_DescType_HOST, (Cppi_Desc *)pCppiDesc, len);
    
        
        if (cpswLpbkMode != CPSW_LOOPBACK_NONE)
        {
            /* Force the packet to specific EMAC port if loopback is enabled */
            Cppi_setPSFlags(Cppi_DescType_HOST, (Cppi_Desc *)pCppiDesc, psFlags);
        }
        else
        {
            Cppi_setPSFlags(Cppi_DescType_HOST, (Cppi_Desc *)pCppiDesc, pa_EMAC_PORT_0);
        }
        
        /* Clear PS Data */
        Cppi_setPSLen (Cppi_DescType_HOST, (Cppi_Desc *)pCppiDesc, 0);
      
        SYS_CACHE_WB (pCppiDesc, SIZE_HOST_DESC, CACHE_FENCE_WAIT);
      
        /* Reenable Interrupts. */
        //Hwi_restore(key);
    
        /* Send the packet out the mac. It will loop back to PA if the mac/switch 
         * have been configured properly 
         */  
        Qmss_queuePushDescSize (gPaTxQHnd[8], pCppiDesc, SIZE_HOST_DESC);
    
        /* Release the hardware semaphore
         *
         * Release multi-core lock.
         */
        CSL_semReleaseSemaphore (PLATFORM_CPPI_HW_SEM);  
    
        /* Increment the application transmit counter */
        gTxCounter ++;
    
        /* Give some time for the PA to process the packet */
        //CycleDelay (10000);
    
        return 0; 
    }
    
    /** ============================================================================
     *   @n@b ReceivePacket
     *
     *   @b Description
     *   @n This API is called to Receive packets.
     *
     *   @param[in]  
     *   @n None
     * 
     *   @return    Int32
     *              -1      -   Error
     *              0       -   Success
     * =============================================================================
     */
    int ReceivePacket (UInt32 *buf, UInt32 *len)
    {
    	Cppi_Desc     *hd;
    	Cppi_HostDesc               *pHostDesc;
    	Int            j;
    	UInt32         coreNum;
        Int32          status=0;
    
        /* Get the core number. */
        coreNum = CSL_chipReadReg(CSL_CHIP_DNUM); 
    	
    	/* Wait for a data packet from PA */
        for (j = 0; j < 60000; j++)
        {
        	(*(volatile UInt32 *)(MSGREG + 0x4)) = 0xCAB1 + (j<<16);
          CycleDelay (1000);
          if (Qmss_getQueueEntryCount (gRxQHnd[coreNum]) > 0)   
          {
    
      	    hd = (Cppi_Desc *)(((UInt32)Qmss_queuePop (gRxQHnd[coreNum])) & ~0xf);
            pHostDesc = (Cppi_HostDesc *)hd;
            *buf = (UInt32)pHostDesc->buffPtr;
            *len = pHostDesc->buffLen;
            //memcpy(buf, pHostDesc->buffPtr, len);
            if(VerifyPacket(hd) != 0) {
                status=-1;
          	    (*(volatile UInt32 *)(MSGREG + 0x4)) = 0xDEADBEEF;
            }
            return (1);
          }
        } 
        
        return (status);
    }
    
    /** ============================================================================
     *   @n@b VerifyPacket
     *
     *   @b Description
     *   @n This API verifies a packet received against the expected data and 
     *      returns 0 to inidcate success and -1 to indicate a mismatch.
     *
     *   @param[in]  
     *   @n pCppiDesc           Packet descriptor received.
     * 
     *   @return    Int32
     *              -1      -   Error
     *              0       -   Success
     * =============================================================================
     */
    Int32 VerifyPacket (Cppi_Desc* pCppiDesc)
    {
    	Cppi_HostDesc               *pHostDesc;
    	UInt8                       *pDataBuffer;
    	Int32                       i;
    	
        pHostDesc = (Cppi_HostDesc *)pCppiDesc;
        
        /* Cleanup the prefetch buffer also. */
        CSL_XMC_invalidatePrefetchBuffer();
    
        SYS_CACHE_INV (pHostDesc, SIZE_HOST_DESC, CACHE_FENCE_WAIT);
        
        SYS_CACHE_INV ((Ptr)(pHostDesc->buffPtr), pHostDesc->buffLen, CACHE_FENCE_WAIT);
        
        /* Verify the application software info we received is same
         * as what we had sent earlier.
         */
        if (pHostDesc->softwareInfo0 != 0xaaaaaaaa)  
        {
            System_printf ("VerifyPacket: Found an entry in receive queue with swinfo0 = 0x%08x, expected 0x%08x\n", 
                            pHostDesc->softwareInfo0, 0xaaaaaaaa);
                       
            pHostDesc->buffLen = pHostDesc->origBufferLen;
            SYS_CACHE_WB (pHostDesc, SIZE_HOST_DESC, CACHE_FENCE_WAIT);
            Qmss_queuePush (gRxFreeQHnd, (Ptr)pHostDesc, pHostDesc->buffLen, SIZE_HOST_DESC, Qmss_Location_TAIL);
              
            return -1;
        }
    
        /* Increment Rx counter to indicate the number of successfully
         * received packets by the example app.
         */
        gRxCounter ++;
    
        /* Reset the buffer length and put the descriptor back on the free queue */
        pHostDesc->buffLen = pHostDesc->origBufferLen;
        SYS_CACHE_WB (pHostDesc, SIZE_HOST_DESC, CACHE_FENCE_WAIT);
        Qmss_queuePush (gRxFreeQHnd, (Ptr)pHostDesc, pHostDesc->buffLen, SIZE_HOST_DESC, Qmss_Location_TAIL);
    
        /* Verify packet done. Return success. */
    	return 0;
    }
    	
    /** ============================================================================
     *   @n@b ModifyPacket
     *
     *   @b Description
     *   @n This API modifies the data packet as a function on the core number.
     *      Each core will be associated with a different UDP port.
     *
     *   @param[in]  
     *   @n None
     * 
     *   @return    Int32
     *              -1      -   Error
     *              0       -   Success
     * =============================================================================
     */
    Void ModifyPacket (Void)
    {
    	UInt32 coreNum;
    
        /* Get the core number. */
        coreNum = CSL_chipReadReg(CSL_CHIP_DNUM);
        
        /* Modify UDP destination port so that the packet is
           routed to the correct core*/
        pktMatch[PACKET_UDP_DEST_PORT_SHIFT+1] += coreNum;   
           
        /* Modify first byte of the packet payload to have
           an unique packet payload per core */    
        pktMatch[PACKET_PAYLOAD_SHIFT] += coreNum;  
        
    }