Changes to compile with devkit
[keystone-rtos/netapi.git] / ti / runtime / netapi / test / ifdma_test.c
index 8df5fbbcd85fb15d3252d0a302c7c69a8db22224..505decf0811ad54811c1fb2c8126878d6d81507b 100755 (executable)
-/******************************************\r
- * File: ifdma-test.c\r
- * Purpose: test of infrastructure dma mode\r
- **************************************************************\r
- * FILE:  ifdma-test.c\r
- * \r
- * DESCRIPTION:  netapi user space transport\r
- *               library  test application\r
- * \r
- * REVISION HISTORY:  rev 0.0.1 \r
- *\r
- *  Copyright (c) Texas Instruments Incorporated 2010-2011\r
- * \r
- *  Redistribution and use in source and binary forms, with or without \r
- *  modification, are permitted provided that the following conditions \r
- *  are met:\r
- *\r
- *    Redistributions of source code must retain the above copyright \r
- *    notice, this list of conditions and the following disclaimer.\r
- *\r
- *    Redistributions in binary form must reproduce the above copyright\r
- *    notice, this list of conditions and the following disclaimer in the \r
- *    documentation and/or other materials provided with the   \r
- *    distribution.\r
- *\r
- *    Neither the name of Texas Instruments Incorporated nor the names of\r
- *    its contributors may be used to endorse or promote products derived\r
- *    from this software without specific prior written permission.\r
- *\r
- *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \r
- *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT \r
- *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
- *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT \r
- *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, \r
- *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT \r
- *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
- *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
- *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT \r
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE \r
- *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
-\r
- *****************************************/\r
-\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <unistd.h>\r
-#include <string.h>\r
-#include <signal.h>\r
-#include <pthread.h>\r
-\r
-#include "trie.h"\r
-#include "string.h"\r
-#include "netapi.h"\r
-#include "pktio.h"\r
-#include "net_test.h"\r
-#include <ti/drv/sa/salld.h>\r
-\r
-\r
-//turn this off to use packets received from Network instead of self generated ones\r
-#define INTERNAL_PACKETS\r
-static int scnt=0;\r
-static int QUIT=0;\r
-__thread int our_core;\r
-\r
-\r
-#define IFDMA_FLOW_INDEX 33\r
-#define IFMDA_HEAP_SIZE 200\r
-#define IFDMA_MAX_NUM_HEAPS 2\r
-#define IFDMA_MAX_HEAP_PKTS 128\r
-//sig handler\r
-void netTest_utilMySig(int x)\r
-{\r
-  QUIT=1;\r
-  scnt+=1;\r
-  printf(">ifdma-test: recv'd signal %d cnt=%d\n",x,scnt);\r
-  if (scnt > 10) {printf(">ifdma-test: WARNING EXITING WITH PROPER SHUTDOWN, LUTS LEFT ACTIVE\n");exit(1);}\r
-\r
-}\r
-void recv_cb_net(struct PKTIO_HANDLE_Tag * channel, Ti_Pkt* p_recv[],\r
-                         PKTIO_METADATA_T meta[], int n_pkts,\r
-                         uint64_t ts );\r
-void recv_cb_consumer(struct PKTIO_HANDLE_Tag * channel, Ti_Pkt* p_recv[],\r
-                         PKTIO_METADATA_T meta[], int n_pkts,\r
-                         uint64_t ts );\r
-\r
-\r
-/*************debug********************/\r
-void netTest_utilDumpDescr(unsigned long *p, int n)\r
-{\r
-   printf("--------dump of descriptor %d %x\n", n, (int) p);\r
-   printf("> %x %x %x %x %x %x %x %x\n",p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7]);\r
-   printf("> %x %x %x %x %x %x %x %x\n",p[8],p[9],p[10],p[11],p[12],p[13],p[14],p[15]);\r
-   printf("-----------------------------\n");\r
-}\r
-void netTest_utilDumpHeader(unsigned long *p, int n, int a, int r)\r
-{\r
-   printf("--------dump of header %d %x appID=%x flag1=%x\n", n, (int) p,a,r);\r
-   printf("> %x %x %x %x %x %x %x %x\n",p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7]);\r
-   printf("> %x %x %x %x %x %x %x %x\n",p[8],p[9],p[10],p[11],p[12],p[13],p[14],p[15]);\r
-   printf("> %x %x %x %x %x %x %x %x\n",p[16],p[17],p[18],p[19],p[20],p[21],p[22],p[23]);\r
-   printf("> %x %x %x %x %x %x %x %x\n",p[24],p[25],p[26],p[27],p[28],p[29],p[30],p[31]);\r
-   printf("-----------------------------\n");\r
-}\r
-/*****************************************/\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-/*******************************************\r
- *************NETAPI OBJECTS***************\r
- *****************************************/\r
-static NETAPI_CFG_T our_netapi_default_cfg=\r
-{\r
-TUNE_NETAPI_PERM_MEM_SZ,\r
-128,  //start of packet offset for hw to place data on rx for default flow\r
-TUNE_NETAPI_QM_CONFIG_MAX_DESC_NUM, //max number of descriptors in system\r
-TUNE_NETAPI_NUM_GLOBAL_DESC,        //total we will use\r
-TUNE_NETAPI_DEFAULT_NUM_BUFFERS,   //#descriptors+buffers in default heap\r
-64, //#descriptors w/o buffers in default heap\r
-TUNE_NETAPI_DEFAULT_BUFFER_SIZE+128+128,  //size of buffers in default heap\r
-128   ,  //tail room\r
-256      //extra room \r
-};\r
-\r
-Pktlib_HeapHandle OurHeap;     //default heap, used by producer\r
-Pktlib_HeapHandle consumerHeap; //for consumer\r
-PKTIO_HANDLE_T * rx_chan;  //for consumer\r
-PKTIO_HANDLE_T * tx_chan;  // for producer\r
-PKTIO_CFG_T rx_chan_cfg={PKTIO_RX|PKTIO_TX, PKTIO_GLOBAL, PKTIO_Q_ANY, 8};\r
-PKTIO_CFG_T tx_chan_cfg={PKTIO_TX, PKTIO_GLOBAL|PKTIO_IFDMA, /*PKTIO_Q_ANY*/ 820, 8};\r
-PKTIO_CFG_T netcp_rx_cfg={PKTIO_RX, PKTIO_NA, PKTIO_NA, 8};\r
-PKTIO_HANDLE_T * netcp_rx_chan;\r
-NETAPI_T netapi_handle;\r
-NETCP_CFG_FLOW_HANDLE_T specialFlow;  //for consumer.  Producer uses the "flowid" in this handle as meta data when he sends data\r
-\r
-PKTIO_CONTROL_T zap_channel_control={PKTIO_CLEAR, NULL};\r
-\r
-NETCP_CFG_ROUTE_T  test_route=\r
-{\r
-NULL, NULL  //* to be filled in\r
-};\r
-\r
-\r
-/*************************END NETAPI OBJECTS***********************/\r
-\r
-static unsigned char all_mac[]={0,0,0,0,0,0};\r
-\r
-\r
-#define IFDMA_PKT_LEN 100\r
-\r
-//stats\r
-int pkt_rx=0; \r
-int pkt_tx=0;\r
-\r
-//***************************\r
-//consumer thread \r
-//**************************\r
-void consumer_thread(int coreid)\r
-{\r
-int err;\r
-int np;\r
-     for(;!((volatile)QUIT);)\r
-     {\r
-         np = netapi_pktioPoll(rx_chan,NULL,&err);\r
-         pkt_rx+=np;\r
-     }\r
-     printf("IFDMA-TEST: CONSUMER DONE %d packets received\n", pkt_rx);\r
-}\r
-\r
-\r
-//**********************************\r
-//producer thread\r
-//*********************************\r
-void producer_thread(int coreid)\r
-{\r
-int err;\r
-int i;\r
-Ti_Pkt * tip;\r
-unsigned char * pData;\r
-int len;\r
-PKTIO_METADATA_T meta = {PKTIO_META_IFDMA_TX,{0},0};\r
-int np;\r
-#ifdef INTERNAL_PACKETS\r
-      //generate packets internally by allocating from OurHeap (the NETAPI \r
-      //default) and send to receiver via ifdma pktio channel\r
-      sleep(5);\r
-      for(i=0;!((volatile) QUIT);i++)\r
-      {\r
-          tip=Pktlib_allocPacket(OurHeap,IFDMA_PKT_LEN);\r
-          if (!tip) \r
-          {\r
-             sleep(1); //out of buffers, let consumer catch up\r
-              continue;\r
-           }\r
-           Pktlib_getDataBuffer(tip,&pData,&len);\r
-           sprintf(pData,"this is packet %d", pkt_tx);\r
-           Cppi_setData (Cppi_DescType_HOST, (Cppi_Desc *) tip, pData,IFDMA_PKT_LEN);\r
-           Pktlib_setPacketLen(tip,IFDMA_PKT_LEN);\r
-           meta.u.tx_ifdma_dest=((NETCP_CFG_FLOW_T*)specialFlow)->flowid;\r
-           netapi_pktioSend(tx_chan,tip,&meta,&err);\r
-           pkt_tx+=1;\r
-           if(!(pkt_tx % 128)) sched_yield(); //give consumer a chance\r
-      }\r
-#else\r
-     //relay packets from network.  recv_cb registered when we created\r
-     //netcp_rx_chan will do this relay via the ifdma pktio channel\r
-     //so we poll the default pktio channel for pkts from net\r
-      for(i=0;!((volatile) QUIT);i++)\r
-      {\r
-        np = netapi_pktioPoll(netcp_rx_chan,NULL,&err);\r
-       if (!np) sched_yield();\r
-\r
-      }\r
-#endif\r
-      printf("IFDMA-TEST: PRODUCER  DONE %d pkts sent\n", pkt_tx);\r
-}\r
-\r
-\r
-//******************************\r
-//  main program\r
-//*****************************\r
-int main(int argc, char **argv)\r
-{\r
-    int err,i;\r
-    int32_t             errCode;\r
-    Pktlib_HeapIfTable*  pPktifTable;\r
-    Pktlib_HeapCfg heapCfg;\r
-    long t1, t2 ;\r
-\r
-     //install signal handler for ^c\r
-    signal(SIGINT,netTest_utilMySig);\r
-\r
-\r
-    /*******************************************/\r
-    /*************NETAPI STARTUP****************/\r
-    /*******************************************/\r
-\r
-    /* create netapi */\r
-    netapi_handle = netapi_init(NETAPI_SYS_MASTER, &our_netapi_default_cfg);\r
-\r
-    /* open the main heap */\r
-    OurHeap = Pktlib_findHeapByName("netapi");\r
-    if (!OurHeap) {printf("findheapbyname fail\n"); exit(1);}\r
-\r
-    //create a receive queue for consumer\r
-    rx_chan=netapi_pktioCreate(netapi_handle,"ourrxq",(PKTIO_CB) recv_cb_consumer, &rx_chan_cfg,&err);\r
-    if (!rx_chan) {printf("pktio create failed err=%d\n",err); exit(1);}\r
-\r
-\r
-#ifndef INTERNAL_PACKETS\r
-    //if we want to relay network packets, we create a handle to the \r
-    //default netcp receive queue here\r
-    netcp_rx_chan= netapi_pktioOpen(netapi_handle, NETCP_RX, (PKTIO_CB) recv_cb_net, &netcp_rx_cfg,  &err);\r
-    if (!netcp_rx_chan) {printf("pktio open RX failed err=%d\n",err); exit(1);}\r
-#endif\r
-\r
-//********************************\r
-//create a consumer heap\r
-//**********************************\r
-\r
-    /* Initialize the heap configuration. */\r
-    memset ((void *)&heapCfg, 0, sizeof(Pktlib_HeapCfg));\r
-\r
-    pPktifTable = netapi_getPktlibIfTable();\r
-\r
-    /* Populate the heap configuration */\r
-    heapCfg.name                = "netapi-consumer";\r
-    heapCfg.memRegion           = NETAPI_GLOBAL_REGION;\r
-    heapCfg.sharedHeap          = 1;\r
-    heapCfg.useStarvationQueue  = 0;\r
-    heapCfg.dataBufferSize      = TUNE_NETAPI_DEFAULT_BUFFER_SIZE;\r
-    heapCfg.numPkts             = IFDMA_MAX_HEAP_PKTS;\r
-    heapCfg.numZeroBufferPackets= 0;\r
-    heapCfg.heapInterfaceTable.data_malloc  = pPktifTable->data_malloc;\r
-    heapCfg.heapInterfaceTable.data_free    = pPktifTable->data_free;\r
-    heapCfg.dataBufferPktThreshold   = 0;\r
-    heapCfg.zeroBufferPktThreshold   = 0;\r
-    consumerHeap = Pktlib_createHeap(&heapCfg, &errCode);\r
-\r
-    //by registering the heap, netapi will take care of\r
-    //cleaning it up @ shutdown..\r
-    netapi_registerHeap(netapi_handle, consumerHeap);  //register heap.\r
-\r
-    //**************************************************\r
-    //create a FLOW for consumer RX. Note this is created\r
-    //in the QMSS (INFRASTRUCTURE) CPPI DMA ENGINE\r
-    // todo:  flowindex should be passed in or got\r
-    //        from resource manager\r
-    //*************************************************\r
-    {\r
-    Pktlib_HeapHandle heaps[2];\r
-    int sizes[2];\r
-#define SPECIAL_SOP_OFF 0\r
-    NETCP_CFG_FLOW_CONFIG_T flow_config={IFDMA_FLOW_INDEX,\r
-                                         NETAPI_DMA_INFRASTRUCTURE,\r
-                                         SPECIAL_SOP_OFF,\r
-                                         NETAPI_FLOW_BLOCK };\r
-    heaps[0]= consumerHeap;\r
-    sizes[0]=IFMDA_HEAP_SIZE;\r
-    heaps[1]= consumerHeap;\r
-    sizes[1]=TUNE_NETAPI_DEFAULT_BUFFER_SIZE - SPECIAL_SOP_OFF;\r
-    flow_config.p_dest_q = rx_chan; // send pkts to rx_chan \r
-\r
-    //specialFlow handle will hold "magic" flowid that producer needs to\r
-    //include in his pkto_send meta data\r
-    specialFlow = netapi_netcpCfgAddFlow( netapi_handle,\r
-                                    IFDMA_MAX_NUM_HEAPS,  //1 heap defined\r
-                                    heaps,\r
-                                    sizes,\r
-                                    &flow_config,  //offset to start rx is 128 \r
-                                    &err);\r
-    if (err) {printf("add flow failed\n", err); exit(1);}\r
-}\r
-\r
-//************************************************************\r
-//create the IDMA channel:  this is used by producer to either\r
-//send generated packets or relay received packets from net\r
-//***************************************************************\r
-tx_chan=netapi_pktioCreate(netapi_handle,"ourtxq",NULL, &tx_chan_cfg,&err);\r
-if (!tx_chan) {printf("pktio create failed err=%d\n",err); exit(1);}\r
-\r
-#ifndef INTERNAL_PACKETS \r
-//if we want to relay packets, creaate a simple netcp rule\r
-//to get a lot of packets\r
-netapi_netcpCfgCreateMacInterface(\r
-                  netapi_handle,\r
-                  &all_mac[0],\r
-                  0,0,\r
-                  (NETCP_CFG_ROUTE_HANDLE_T)  NULL, \r
-                  (NETCP_CFG_VLAN_T ) NULL ,  //future\r
-                  1,\r
-                  &err);\r
-#endif\r
-\r
-/*********************************************/\r
-/*****************end NETAPI STARTUP**********/\r
-/*********************************************/\r
-\r
-\r
-//**************************************\r
-//Create a consumer and producer thread\r
-//***************************************\r
-{\r
-       pthread_t *thrs;\r
-        int procs =2; \r
-        char c;\r
-        thrs = malloc( sizeof( pthread_t ) * procs );\r
-        if (thrs == NULL)\r
-        {\r
-                perror( "malloc" );\r
-                return -1;\r
-        }\r
-        printf( "ifdma-test: Starting %d threads...\n", procs );\r
-\r
-        if (pthread_create( &thrs[0], NULL, (void*)consumer_thread,\r
-                        (void *)0 ))\r
-        {\r
-                        perror( "pthread_create" );\r
-                        exit(1);\r
-        }\r
-        if (pthread_create( &thrs[1], NULL, (void*)producer_thread,\r
-                        (void *)1 ))\r
-        {\r
-                        perror( "pthread_create" );\r
-                        exit(1);\r
-        }\r
-        //this thread of execution (main) now just waits on user input\r
-        for(;;)\r
-        {\r
-           printf(">");\r
-           c=getchar();\r
-           if (c=='q') {QUIT=1;break;}\r
-           else if (c=='s') printf(">IFDMA-TEST STATS:   %d sent, %d received\n",pkt_tx, pkt_rx);\r
-           else if (c=='h') printf("> 'q' to quit,  's' for stats,  'h' for help\n");\r
-        }\r
-\r
-        //wait for completion \r
-        printf("main task now pending on thread completion\n");\r
-        for (i = 0; i < procs; i++)\r
-                pthread_join( thrs[i], NULL );\r
-\r
-        free( thrs );\r
-      \r
-}\r
-\r
-/*************************************************\r
- ************CLEAN UP****************************\r
- ************************************************/\r
-#ifndef INTERNAL_PACKETS\r
-//get rid of rule, in the case that we are relaying packets\r
-//also close our netcp rx channel\r
-netapi_netcpCfgDelMac(netapi_handle,0,&err);\r
-netapi_pktioClose(netcp_rx_chan,&err);\r
-#endif\r
-\r
-//close pktio channels we opened\r
-netapi_pktioDelete(tx_chan ,&err);\r
-netapi_pktioDelete(rx_chan ,&err);\r
-\r
-//close flow\r
-netapi_netcpCfgDelFlow(netapi_handle, specialFlow, &err);\r
-\r
-//done\r
-netapi_shutdown(netapi_handle);\r
-\r
-\r
-//!finished!\r
-}\r
-\r
-\r
-//receive callback for packets from net (for consumer)\r
-// this is used for case where we want to relay packets from\r
-// network, instead of internally generating them\r
-void recv_cb_net(struct PKTIO_HANDLE_Tag * channel, Ti_Pkt* p_recv[],\r
-                         PKTIO_METADATA_T meta[], int n_pkts,\r
-                         uint64_t ts )\r
-{\r
-int i;\r
-PKTIO_METADATA_T meta2 = {PKTIO_META_TX,{0},0};\r
-Ti_Pkt * tip;\r
-int err;\r
-\r
-for(i=0;i<n_pkts;i++)\r
-{\r
-    tip = p_recv[i];\r
-    meta2.u.tx_ifdma_dest=((NETCP_CFG_FLOW_T*)specialFlow)->flowid;\r
-    netapi_pktioSend(tx_chan,tip,&meta2,&err);\r
-    pkt_tx+=1;\r
-    if(!(pkt_tx % 128)) sched_yield(); //give consumer a chance\r
-}\r
-\r
-\r
-}\r
-\r
-\r
-//receive callback for consumer (registered when we create pktio channel)\r
-void recv_cb_consumer(struct PKTIO_HANDLE_Tag * channel, Ti_Pkt* p_recv[],\r
-                         PKTIO_METADATA_T meta[], int n_pkts,\r
-                         uint64_t ts )\r
-{\r
-int i;\r
-int len;\r
-Ti_Pkt * tip;\r
-unsigned int templen;\r
-char * p_pkt;\r
-\r
-for(i=0;i<n_pkts;i++)\r
-{\r
-        tip = p_recv[i];\r
-        Pktlib_getDataBuffer(tip,(uint8_t**)&p_pkt,&templen);//ignore templen\r
-        len = Pktlib_getPacketLen(tip);\r
-        Pktlib_freePacket((Ti_Pkt*)tip);\r
-}\r
-return;\r
-}\r
-\r
-\r
-\r
-\r
-\r
+/******************************************
+ * File: ifdma-test.c
+ * Purpose: test of infrastructure dma mode
+ **************************************************************
+ * FILE:  ifdma-test.c
+ * 
+ * DESCRIPTION:  netapi user space transport
+ *               library  test application
+ * 
+ * REVISION HISTORY:  rev 0.0.1 
+ *
+ *  Copyright (c) Texas Instruments Incorporated 2010-2011
+ * 
+ *  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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <pthread.h>
+#include <sched.h>
+
+#include "trie.h"
+#include "string.h"
+#include "ti/runtime/netapi/netapi.h"
+#include "ti/runtime/netapi/pktio.h"
+#include "net_test.h"
+#include <ti/drv/sa/salld.h>
+
+
+void benchmarks(void);
+static inline unsigned long netapi_timing_start(void)
+{
+        volatile int vval;
+        //read clock
+        asm volatile("mrc p15, 0, %0, c9, c13, 0" :  "=r"(vval));
+        return vval;
+}
+
+//turn this off to use packets received from Network instead of self generated ones
+#define INTERNAL_PACKETS
+static int scnt=0;
+static int QUIT=0;
+__thread int our_core;
+
+
+#define IFDMA_FLOW_INDEX 33
+#define IFMDA_HEAP_SIZE 200
+#define IFDMA_MAX_NUM_HEAPS 2
+#define IFDMA_MAX_HEAP_PKTS 128
+//sig handler
+void netTest_utilMySig(int x)
+{
+  QUIT=1;
+  scnt+=1;
+  printf(">ifdma-test: recv'd signal %d cnt=%d\n",x,scnt);
+  if (scnt > 10) {printf(">ifdma-test: WARNING EXITING WITH PROPER SHUTDOWN, LUTS LEFT ACTIVE\n");exit(1);}
+
+}
+void recv_cb_net(struct PKTIO_HANDLE_Tag * channel, Ti_Pkt* p_recv[],
+                         PKTIO_METADATA_T meta[], int n_pkts,
+                         uint64_t ts );
+void recv_cb_consumer(struct PKTIO_HANDLE_Tag * channel, Ti_Pkt* p_recv[],
+                         PKTIO_METADATA_T meta[], int n_pkts,
+                         uint64_t ts );
+
+
+/*************debug********************/
+void netTest_utilDumpDescr(unsigned long *p, int n)
+{
+   printf("--------dump of descriptor %d %x\n", n, (int) p);
+   printf("> %x %x %x %x %x %x %x %x\n",p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7]);
+   printf("> %x %x %x %x %x %x %x %x\n",p[8],p[9],p[10],p[11],p[12],p[13],p[14],p[15]);
+   printf("-----------------------------\n");
+}
+void netTest_utilDumpHeader(unsigned long *p, int n, int a, int r)
+{
+   printf("--------dump of header %d %x appID=%x flag1=%x\n", n, (int) p,a,r);
+   printf("> %x %x %x %x %x %x %x %x\n",p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7]);
+   printf("> %x %x %x %x %x %x %x %x\n",p[8],p[9],p[10],p[11],p[12],p[13],p[14],p[15]);
+   printf("> %x %x %x %x %x %x %x %x\n",p[16],p[17],p[18],p[19],p[20],p[21],p[22],p[23]);
+   printf("> %x %x %x %x %x %x %x %x\n",p[24],p[25],p[26],p[27],p[28],p[29],p[30],p[31]);
+   printf("-----------------------------\n");
+}
+/*****************************************/
+
+
+
+
+
+
+
+/*******************************************
+ *************NETAPI OBJECTS***************
+ *****************************************/
+static NETAPI_CFG_T our_netapi_default_cfg=
+{
+TUNE_NETAPI_PERM_MEM_SZ,
+128,  //start of packet offset for hw to place data on rx for default flow
+TUNE_NETAPI_QM_CONFIG_MAX_DESC_NUM, //max number of descriptors in system
+TUNE_NETAPI_NUM_GLOBAL_DESC,        //total we will use
+TUNE_NETAPI_DEFAULT_NUM_BUFFERS,   //#descriptors+buffers in default heap
+64, //#descriptors w/o buffers in default heap
+TUNE_NETAPI_DEFAULT_BUFFER_SIZE+128+128,  //size of buffers in default heap
+128   ,  //tail room
+256      //extra room 
+};
+
+Pktlib_HeapHandle OurHeap;     //default heap, used by producer
+Pktlib_HeapHandle consumerHeap; //for consumer
+PKTIO_HANDLE_T * rx_chan;  //for consumer
+PKTIO_HANDLE_T * tx_chan;  // for producer
+PKTIO_CFG_T rx_chan_cfg={PKTIO_RX|PKTIO_TX, PKTIO_GLOBAL, PKTIO_Q_ANY, 8};
+PKTIO_CFG_T tx_chan_cfg={PKTIO_TX, PKTIO_GLOBAL|PKTIO_IFDMA, /*PKTIO_Q_ANY*/ 820, 8};
+PKTIO_CFG_T netcp_rx_cfg={PKTIO_RX, PKTIO_NA, PKTIO_NA, 8};
+PKTIO_HANDLE_T * netcp_rx_chan;
+NETAPI_T netapi_handle;
+NETCP_CFG_FLOW_HANDLE_T specialFlow;  //for consumer.  Producer uses the "flowid" in this handle as meta data when he sends data
+
+PKTIO_CONTROL_T zap_channel_control={PKTIO_CLEAR, NULL};
+
+NETCP_CFG_ROUTE_T  test_route=
+{
+NULL, NULL  //* to be filled in
+};
+
+
+/*************************END NETAPI OBJECTS***********************/
+
+static unsigned char all_mac[]={0,0,0,0,0,0};
+
+
+#define IFDMA_PKT_LEN 100
+
+//stats
+int pkt_rx=0; 
+int pkt_tx=0;
+int pkt_stall=0;
+
+//***************************
+//consumer thread 
+//**************************
+void consumer_thread(int coreid)
+{
+int err;
+int np;
+cpu_set_t cpu_set;
+
+    CPU_ZERO( &cpu_set);
+    CPU_SET( 1, &cpu_set);
+    hplib_utilSetupThread(1, &cpu_set);
+
+     for(;!((volatile)QUIT);)
+     {
+         np = netapi_pktioPoll(rx_chan,NULL,&err);
+         pkt_rx+=np;
+     }
+     printf("IFDMA-TEST: CONSUMER DONE %d packets received\n", pkt_rx);
+}
+
+
+//**********************************
+//producer thread
+//*********************************
+void producer_thread(int coreid)
+{
+int err;
+int i;
+Ti_Pkt * tip;
+unsigned char * pData;
+int len;
+PKTIO_METADATA_T meta = {PKTIO_META_IFDMA_TX,{0},0};
+int np;
+cpu_set_t cpu_set;
+
+
+    CPU_ZERO( &cpu_set);
+    CPU_SET( 2, &cpu_set);
+    hplib_utilSetupThread(2, &cpu_set);
+
+#ifdef INTERNAL_PACKETS
+      //generate packets internally by allocating from OurHeap (the NETAPI 
+      //default) and send to receiver via ifdma pktio channel
+      sleep(5);
+      for(i=0;!((volatile) QUIT);i++)
+      {
+          tip=Pktlib_allocPacket(OurHeap,IFDMA_PKT_LEN);
+          if (!tip) 
+          {
+              pkt_stall+=1;
+             sleep(1); //out of buffers, let consumer catch up
+              continue;
+           }
+           Pktlib_getDataBuffer(tip,&pData,&len);
+           sprintf(pData,"this is packet %d", pkt_tx);
+           Cppi_setData (Cppi_DescType_HOST, (Cppi_Desc *) tip, pData,IFDMA_PKT_LEN);
+           Pktlib_setPacketLen(tip,IFDMA_PKT_LEN);
+           meta.u.tx_ifdma_dest=((NETCP_CFG_FLOW_T*)specialFlow)->flowid;
+           netapi_pktioSend(tx_chan,tip,&meta,&err);
+           pkt_tx+=1;
+           if(!(pkt_tx % 64)) sched_yield(); //give consumer a chance
+      }
+#else
+     //relay packets from network.  recv_cb registered when we created
+     //netcp_rx_chan will do this relay via the ifdma pktio channel
+     //so we poll the default pktio channel for pkts from net
+      for(i=0;!((volatile) QUIT);i++)
+      {
+        np = netapi_pktioPoll(netcp_rx_chan,NULL,&err);
+       if (!np) sched_yield();
+
+      }
+#endif
+      printf("IFDMA-TEST: PRODUCER  DONE %d pkts sent (stalls=%d)\n", pkt_tx,pkt_stall);
+}
+
+
+//******************************
+//  main program
+//*****************************
+int main(int argc, char **argv)
+{
+    int err,i;
+    int32_t             errCode;
+    Pktlib_HeapIfTable*  pPktifTable;
+    Pktlib_HeapCfg heapCfg;
+    long t1, t2 ;
+    cpu_set_t cpu_set;
+
+
+     //install signal handler for ^c
+    signal(SIGINT,netTest_utilMySig);
+    CPU_ZERO( &cpu_set);
+    CPU_SET( 0, &cpu_set);
+    hplib_utilSetupThread(0, &cpu_set);
+
+
+    /*******************************************/
+    /*************NETAPI STARTUP****************/
+    /*******************************************/
+
+    /* create netapi */
+    netapi_handle = netapi_init(NETAPI_SYS_MASTER, &our_netapi_default_cfg);
+    printf("main: returned from netapi_init\n");
+    /* open the main heap */
+    OurHeap = Pktlib_findHeapByName("netapi");
+    if (!OurHeap) {printf("findheapbyname fail\n"); exit(1);}
+
+    //create a receive queue for consumer
+    rx_chan=netapi_pktioCreate(netapi_handle,"ourrxq",(PKTIO_CB) recv_cb_consumer, &rx_chan_cfg,&err);
+    if (!rx_chan) {printf("pktio create failed err=%d\n",err); exit(1);}
+
+
+#ifndef INTERNAL_PACKETS
+    //if we want to relay network packets, we create a handle to the 
+    //default netcp receive queue here
+    netcp_rx_chan= netapi_pktioOpen(netapi_handle, NETCP_RX, (PKTIO_CB) recv_cb_net, &netcp_rx_cfg,  &err);
+    if (!netcp_rx_chan) {printf("pktio open RX failed err=%d\n",err); exit(1);}
+#endif
+
+//********************************
+//create a consumer heap
+//**********************************
+
+    /* Initialize the heap configuration. */
+    memset ((void *)&heapCfg, 0, sizeof(Pktlib_HeapCfg));
+
+    pPktifTable = netapi_getPktlibIfTable();
+
+    /* Populate the heap configuration */
+    heapCfg.name                = "netapi-consumer";
+    heapCfg.memRegion           = NETAPI_GLOBAL_REGION;
+    heapCfg.sharedHeap          = 1;
+    heapCfg.useStarvationQueue  = 0;
+    heapCfg.dataBufferSize      = TUNE_NETAPI_DEFAULT_BUFFER_SIZE;
+    heapCfg.numPkts             = IFDMA_MAX_HEAP_PKTS;
+    heapCfg.numZeroBufferPackets= 0;
+    heapCfg.heapInterfaceTable.data_malloc  = pPktifTable->data_malloc;
+    heapCfg.heapInterfaceTable.data_free    = pPktifTable->data_free;
+    heapCfg.dataBufferPktThreshold   = 0;
+    heapCfg.zeroBufferPktThreshold   = 0;
+    consumerHeap = Pktlib_createHeap(&heapCfg, &errCode);
+
+    //by registering the heap, netapi will take care of
+    //cleaning it up @ shutdown..
+    netapi_registerHeap(netapi_handle, consumerHeap);  //register heap.
+
+    //**************************************************
+    //create a FLOW for consumer RX. Note this is created
+    //in the QMSS (INFRASTRUCTURE) CPPI DMA ENGINE
+    // todo:  flowindex should be passed in or got
+    //        from resource manager
+    //*************************************************
+    {
+    Pktlib_HeapHandle heaps[2];
+    int sizes[2];
+#define SPECIAL_SOP_OFF 0
+    NETCP_CFG_FLOW_CONFIG_T flow_config={IFDMA_FLOW_INDEX,
+                                         NETAPI_DMA_INFRASTRUCTURE,
+                                         SPECIAL_SOP_OFF,
+                                         NETAPI_FLOW_BLOCK };
+    heaps[0]= consumerHeap;
+    sizes[0]=IFMDA_HEAP_SIZE;
+    heaps[1]= consumerHeap;
+    sizes[1]=TUNE_NETAPI_DEFAULT_BUFFER_SIZE - SPECIAL_SOP_OFF;
+    flow_config.p_dest_q = rx_chan; // send pkts to rx_chan 
+
+    //specialFlow handle will hold "magic" flowid that producer needs to
+    //include in his pkto_send meta data
+    specialFlow = netapi_netcpCfgAddFlow( netapi_handle,
+                                    IFDMA_MAX_NUM_HEAPS,  //1 heap defined
+                                    heaps,
+                                    sizes,
+                                    &flow_config,  //offset to start rx is 128 
+                                    &err);
+    if (err) {printf("add flow failed\n", err); exit(1);}
+}
+
+//************************************************************
+//create the IDMA channel:  this is used by producer to either
+//send generated packets or relay received packets from net
+//***************************************************************
+tx_chan=netapi_pktioCreate(netapi_handle,"ourtxq",NULL, &tx_chan_cfg,&err);
+if (!tx_chan) {printf("pktio create failed err=%d\n",err); exit(1);}
+
+#ifndef INTERNAL_PACKETS 
+//if we want to relay packets, creaate a simple netcp rule
+//to get a lot of packets
+netapi_netcpCfgCreateMacInterface(
+                  netapi_handle,
+                  &all_mac[0],
+                  0,0,
+                  (NETCP_CFG_ROUTE_HANDLE_T)  NULL, 
+                  (NETCP_CFG_VLAN_T ) NULL ,  //future
+                  1,
+                  &err);
+#endif
+
+/*********************************************/
+/*****************end NETAPI STARTUP**********/
+/*********************************************/
+
+#if 1
+//sonme benchmarks
+benchmarks();
+#endif
+//**************************************
+//Create a consumer and producer thread
+//***************************************
+{
+       pthread_t *thrs;
+        int procs =2; 
+        char c;
+        thrs = malloc( sizeof( pthread_t ) * procs );
+        if (thrs == NULL)
+        {
+                perror( "malloc" );
+                return -1;
+        }
+        printf( "ifdma-test: Starting %d threads...\n", procs );
+
+        if (pthread_create( &thrs[0], NULL, (void*)consumer_thread,
+                        (void *)0 ))
+        {
+                        perror( "pthread_create" );
+                        exit(1);
+        }
+        if (pthread_create( &thrs[1], NULL, (void*)producer_thread,
+                        (void *)1 ))
+        {
+                        perror( "pthread_create" );
+                        exit(1);
+        }
+        //this thread of execution (main) now just waits on user input
+        for(;;)
+        {
+           printf(">");
+           c=getchar();
+           if (c=='q') {QUIT=1;break;}
+           else if (c=='s') printf(">IFDMA-TEST STATS:   %d sent, %d received stall=%d \n",pkt_tx, pkt_rx,pkt_stall);
+           else if (c=='h') printf("> 'q' to quit,  's' for stats,  'h' for help\n");
+        }
+
+        //wait for completion 
+        printf("main task now pending on thread completion\n");
+        for (i = 0; i < procs; i++)
+                pthread_join( thrs[i], NULL );
+
+        free( thrs );
+      
+}
+
+/*************************************************
+ ************CLEAN UP****************************
+ ************************************************/
+#ifndef INTERNAL_PACKETS
+//get rid of rule, in the case that we are relaying packets
+//also close our netcp rx channel
+netapi_netcpCfgDelMac(netapi_handle,0,&err);
+netapi_pktioClose(netcp_rx_chan,&err);
+#endif
+
+//close pktio channels we opened
+netapi_pktioDelete(tx_chan ,&err);
+netapi_pktioDelete(rx_chan ,&err);
+
+//close flow
+netapi_netcpCfgDelFlow(netapi_handle, specialFlow, &err);
+
+//done
+netapi_shutdown(netapi_handle);
+
+
+//!finished!
+}
+
+
+//receive callback for packets from net (for consumer)
+// this is used for case where we want to relay packets from
+// network, instead of internally generating them
+void recv_cb_net(struct PKTIO_HANDLE_Tag * channel, Ti_Pkt* p_recv[],
+                         PKTIO_METADATA_T meta[], int n_pkts,
+                         uint64_t ts )
+{
+int i;
+PKTIO_METADATA_T meta2 = {PKTIO_META_TX,{0},0};
+Ti_Pkt * tip;
+int err;
+
+for(i=0;i<n_pkts;i++)
+{
+    tip = p_recv[i];
+    meta2.u.tx_ifdma_dest=((NETCP_CFG_FLOW_T*)specialFlow)->flowid;
+    netapi_pktioSend(tx_chan,tip,&meta2,&err);
+    pkt_tx+=1;
+    if(!(pkt_tx % 128)) sched_yield(); //give consumer a chance
+}
+
+
+}
+
+
+//receive callback for consumer (registered when we create pktio channel)
+void recv_cb_consumer(struct PKTIO_HANDLE_Tag * channel, Ti_Pkt* p_recv[],
+                         PKTIO_METADATA_T meta[], int n_pkts,
+                         uint64_t ts )
+{
+int i;
+int len;
+Ti_Pkt * tip;
+unsigned int templen;
+char * p_pkt;
+
+for(i=0;i<n_pkts;i++)
+{
+        tip = p_recv[i];
+        Pktlib_getDataBuffer(tip,(uint8_t**)&p_pkt,&templen);//ignore templen
+        len = Pktlib_getPacketLen(tip);
+        Pktlib_freePacket((Ti_Pkt*)tip);
+}
+return;
+}
+
+
+
+
+//SOME BENCHMARKS
+//sonme benchmarks
+void benchmarks(void)
+{
+int i,j;
+unsigned long v1pop;
+unsigned long v2pop;
+unsigned long v1push;
+unsigned long v2push;
+unsigned long v1read;
+unsigned long v2read;
+unsigned long v1write;
+unsigned long v2write;
+unsigned long v1read2;
+unsigned long v2read2;
+#define N 100
+Ti_Pkt  pkts[N];
+unsigned char * p_pkt;
+int len;
+int sum=0;
+int sum2=0;
+char *p=(char *) malloc(1000);
+
+//queue pop
+v1pop=netapi_timing_start();
+for(i=0;i<N;i++)   pkts[i]= Pktlib_allocPacket(OurHeap,1000);
+v2pop = netapi_timing_start();
+
+//write access
+Pktlib_getDataBuffer(pkts[0],(uint8_t**)&p_pkt,&len);
+v1write=netapi_timing_start();
+for(i=0;i<1000;i++) p_pkt[i]=i;
+v2write=netapi_timing_start();
+
+// access
+
+v1read=netapi_timing_start();
+for(j=0;j<10;j++)
+for(i=0;i<1000;i++) sum+=p_pkt[i];
+v2read=netapi_timing_start();
+
+// access (from malloc)
+v1read2=netapi_timing_start();
+for(i=0;i<1000;i++) sum2+=p[i];
+v2read2=netapi_timing_start();
+
+//queue push
+v1push=netapi_timing_start();
+for(i=0;i<N;i++)   Pktlib_freePacket(pkts[i]);
+v2push = netapi_timing_start();
+
+//resutls
+printf("allocs= %d  free=%d   write=%d  read=%d read-malloc=%d (sum=%d %d)\n",
+        (v2pop-v1pop)/N, (v2push-v1push)/N,  (v2write-v1write)/1000, (v2read-v1read)/10000,
+        (v2read2-v1read2)/1000,sum,sum2);
+
+}