NETAPI net test application updates
[keystone-rtos/netapi.git] / ti / runtime / netapi / test / ifdma_test.c
1 /******************************************\r
2  * File: ifdma-test.c\r
3  * Purpose: test of infrastructure dma mode\r
4  **************************************************************\r
5  * FILE:  ifdma-test.c\r
6  * \r
7  * DESCRIPTION:  netapi user space transport\r
8  *               library  test application\r
9  * \r
10  * REVISION HISTORY:  rev 0.0.1 \r
11  *\r
12  *  Copyright (c) Texas Instruments Incorporated 2010-2011\r
13  * \r
14  *  Redistribution and use in source and binary forms, with or without \r
15  *  modification, are permitted provided that the following conditions \r
16  *  are met:\r
17  *\r
18  *    Redistributions of source code must retain the above copyright \r
19  *    notice, this list of conditions and the following disclaimer.\r
20  *\r
21  *    Redistributions in binary form must reproduce the above copyright\r
22  *    notice, this list of conditions and the following disclaimer in the \r
23  *    documentation and/or other materials provided with the   \r
24  *    distribution.\r
25  *\r
26  *    Neither the name of Texas Instruments Incorporated nor the names of\r
27  *    its contributors may be used to endorse or promote products derived\r
28  *    from this software without specific prior written permission.\r
29  *\r
30  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \r
31  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT \r
32  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
33  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT \r
34  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, \r
35  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT \r
36  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
37  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
38  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT \r
39  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE \r
40  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
41 \r
42  *****************************************/\r
43 \r
44 #include <stdio.h>\r
45 #include <stdlib.h>\r
46 #include <unistd.h>\r
47 #include <string.h>\r
48 #include <signal.h>\r
49 #include <pthread.h>\r
50 #include <sched.h>\r
51 \r
52 #include "trie.h"\r
53 #include "string.h"\r
54 #include "netapi.h"\r
55 #include "pktio.h"\r
56 #include "net_test.h"\r
57 #include <ti/drv/sa/salld.h>\r
58 \r
59 \r
60 //turn this off to use packets received from Network instead of self generated ones\r
61 #define INTERNAL_PACKETS\r
62 static int scnt=0;\r
63 static int QUIT=0;\r
64 __thread int our_core;\r
65 \r
66 \r
67 #define IFDMA_FLOW_INDEX 33\r
68 #define IFMDA_HEAP_SIZE 200\r
69 #define IFDMA_MAX_NUM_HEAPS 2\r
70 #define IFDMA_MAX_HEAP_PKTS 128\r
71 //sig handler\r
72 void netTest_utilMySig(int x)\r
73 {\r
74   QUIT=1;\r
75   scnt+=1;\r
76   printf(">ifdma-test: recv'd signal %d cnt=%d\n",x,scnt);\r
77   if (scnt > 10) {printf(">ifdma-test: WARNING EXITING WITH PROPER SHUTDOWN, LUTS LEFT ACTIVE\n");exit(1);}\r
78 \r
79 }\r
80 void recv_cb_net(struct PKTIO_HANDLE_Tag * channel, Ti_Pkt* p_recv[],\r
81                          PKTIO_METADATA_T meta[], int n_pkts,\r
82                          uint64_t ts );\r
83 void recv_cb_consumer(struct PKTIO_HANDLE_Tag * channel, Ti_Pkt* p_recv[],\r
84                          PKTIO_METADATA_T meta[], int n_pkts,\r
85                          uint64_t ts );\r
86 \r
87 \r
88 /*************debug********************/\r
89 void netTest_utilDumpDescr(unsigned long *p, int n)\r
90 {\r
91    printf("--------dump of descriptor %d %x\n", n, (int) p);\r
92    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
93    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
94    printf("-----------------------------\n");\r
95 }\r
96 void netTest_utilDumpHeader(unsigned long *p, int n, int a, int r)\r
97 {\r
98    printf("--------dump of header %d %x appID=%x flag1=%x\n", n, (int) p,a,r);\r
99    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
100    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
101    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
102    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
103    printf("-----------------------------\n");\r
104 }\r
105 /*****************************************/\r
106 \r
107 \r
108 \r
109 \r
110 \r
111 \r
112 \r
113 /*******************************************\r
114  *************NETAPI OBJECTS***************\r
115  *****************************************/\r
116 static NETAPI_CFG_T our_netapi_default_cfg=\r
117 {\r
118 TUNE_NETAPI_PERM_MEM_SZ,\r
119 128,  //start of packet offset for hw to place data on rx for default flow\r
120 TUNE_NETAPI_QM_CONFIG_MAX_DESC_NUM, //max number of descriptors in system\r
121 TUNE_NETAPI_NUM_GLOBAL_DESC,        //total we will use\r
122 TUNE_NETAPI_DEFAULT_NUM_BUFFERS,   //#descriptors+buffers in default heap\r
123 64, //#descriptors w/o buffers in default heap\r
124 TUNE_NETAPI_DEFAULT_BUFFER_SIZE+128+128,  //size of buffers in default heap\r
125 128   ,  //tail room\r
126 256      //extra room \r
127 };\r
128 \r
129 Pktlib_HeapHandle OurHeap;     //default heap, used by producer\r
130 Pktlib_HeapHandle consumerHeap; //for consumer\r
131 PKTIO_HANDLE_T * rx_chan;  //for consumer\r
132 PKTIO_HANDLE_T * tx_chan;  // for producer\r
133 PKTIO_CFG_T rx_chan_cfg={PKTIO_RX|PKTIO_TX, PKTIO_GLOBAL, PKTIO_Q_ANY, 8};\r
134 PKTIO_CFG_T tx_chan_cfg={PKTIO_TX, PKTIO_GLOBAL|PKTIO_IFDMA, /*PKTIO_Q_ANY*/ 820, 8};\r
135 PKTIO_CFG_T netcp_rx_cfg={PKTIO_RX, PKTIO_NA, PKTIO_NA, 8};\r
136 PKTIO_HANDLE_T * netcp_rx_chan;\r
137 NETAPI_T netapi_handle;\r
138 NETCP_CFG_FLOW_HANDLE_T specialFlow;  //for consumer.  Producer uses the "flowid" in this handle as meta data when he sends data\r
139 \r
140 PKTIO_CONTROL_T zap_channel_control={PKTIO_CLEAR, NULL};\r
141 \r
142 NETCP_CFG_ROUTE_T  test_route=\r
143 {\r
144 NULL, NULL  //* to be filled in\r
145 };\r
146 \r
147 \r
148 /*************************END NETAPI OBJECTS***********************/\r
149 \r
150 static unsigned char all_mac[]={0,0,0,0,0,0};\r
151 \r
152 \r
153 #define IFDMA_PKT_LEN 100\r
154 \r
155 //stats\r
156 int pkt_rx=0; \r
157 int pkt_tx=0;\r
158 \r
159 //***************************\r
160 //consumer thread \r
161 //**************************\r
162 void consumer_thread(int coreid)\r
163 {\r
164 int err;\r
165 int np;\r
166 cpu_set_t cpu_set;\r
167 \r
168     CPU_ZERO( &cpu_set);\r
169     CPU_SET( 1, &cpu_set);\r
170     hplib_utilSetupThread(1, &cpu_set);\r
171 \r
172      for(;!((volatile)QUIT);)\r
173      {\r
174          np = netapi_pktioPoll(rx_chan,NULL,&err);\r
175          pkt_rx+=np;\r
176      }\r
177      printf("IFDMA-TEST: CONSUMER DONE %d packets received\n", pkt_rx);\r
178 }\r
179 \r
180 \r
181 //**********************************\r
182 //producer thread\r
183 //*********************************\r
184 void producer_thread(int coreid)\r
185 {\r
186 int err;\r
187 int i;\r
188 Ti_Pkt * tip;\r
189 unsigned char * pData;\r
190 int len;\r
191 PKTIO_METADATA_T meta = {PKTIO_META_IFDMA_TX,{0},0};\r
192 int np;\r
193 cpu_set_t cpu_set;\r
194 \r
195 \r
196     CPU_ZERO( &cpu_set);\r
197     CPU_SET( 2, &cpu_set);\r
198     hplib_utilSetupThread(2, &cpu_set);\r
199 \r
200 #ifdef INTERNAL_PACKETS\r
201       //generate packets internally by allocating from OurHeap (the NETAPI \r
202       //default) and send to receiver via ifdma pktio channel\r
203       sleep(5);\r
204       for(i=0;!((volatile) QUIT);i++)\r
205       {\r
206           tip=Pktlib_allocPacket(OurHeap,IFDMA_PKT_LEN);\r
207           if (!tip) \r
208           {\r
209               sleep(1); //out of buffers, let consumer catch up\r
210               continue;\r
211            }\r
212            Pktlib_getDataBuffer(tip,&pData,&len);\r
213            sprintf(pData,"this is packet %d", pkt_tx);\r
214            Cppi_setData (Cppi_DescType_HOST, (Cppi_Desc *) tip, pData,IFDMA_PKT_LEN);\r
215            Pktlib_setPacketLen(tip,IFDMA_PKT_LEN);\r
216            meta.u.tx_ifdma_dest=((NETCP_CFG_FLOW_T*)specialFlow)->flowid;\r
217            netapi_pktioSend(tx_chan,tip,&meta,&err);\r
218            pkt_tx+=1;\r
219            if(!(pkt_tx % 128)) sched_yield(); //give consumer a chance\r
220       }\r
221 #else\r
222      //relay packets from network.  recv_cb registered when we created\r
223      //netcp_rx_chan will do this relay via the ifdma pktio channel\r
224      //so we poll the default pktio channel for pkts from net\r
225       for(i=0;!((volatile) QUIT);i++)\r
226       {\r
227         np = netapi_pktioPoll(netcp_rx_chan,NULL,&err);\r
228         if (!np) sched_yield();\r
229 \r
230       }\r
231 #endif\r
232       printf("IFDMA-TEST: PRODUCER  DONE %d pkts sent\n", pkt_tx);\r
233 }\r
234 \r
235 \r
236 //******************************\r
237 //  main program\r
238 //*****************************\r
239 int main(int argc, char **argv)\r
240 {\r
241     int err,i;\r
242     int32_t             errCode;\r
243     Pktlib_HeapIfTable*  pPktifTable;\r
244     Pktlib_HeapCfg heapCfg;\r
245     long t1, t2 ;\r
246     cpu_set_t cpu_set;\r
247 \r
248 \r
249      //install signal handler for ^c\r
250     signal(SIGINT,netTest_utilMySig);\r
251     CPU_ZERO( &cpu_set);\r
252     CPU_SET( 0, &cpu_set);\r
253     hplib_utilSetupThread(0, &cpu_set);\r
254 \r
255 \r
256     /*******************************************/\r
257     /*************NETAPI STARTUP****************/\r
258     /*******************************************/\r
259 \r
260     /* create netapi */\r
261     netapi_handle = netapi_init(NETAPI_SYS_MASTER, &our_netapi_default_cfg);\r
262 \r
263     /* open the main heap */\r
264     OurHeap = Pktlib_findHeapByName("netapi");\r
265     if (!OurHeap) {printf("findheapbyname fail\n"); exit(1);}\r
266 \r
267     //create a receive queue for consumer\r
268     rx_chan=netapi_pktioCreate(netapi_handle,"ourrxq",(PKTIO_CB) recv_cb_consumer, &rx_chan_cfg,&err);\r
269     if (!rx_chan) {printf("pktio create failed err=%d\n",err); exit(1);}\r
270 \r
271 \r
272 #ifndef INTERNAL_PACKETS\r
273     //if we want to relay network packets, we create a handle to the \r
274     //default netcp receive queue here\r
275     netcp_rx_chan= netapi_pktioOpen(netapi_handle, NETCP_RX, (PKTIO_CB) recv_cb_net, &netcp_rx_cfg,  &err);\r
276     if (!netcp_rx_chan) {printf("pktio open RX failed err=%d\n",err); exit(1);}\r
277 #endif\r
278 \r
279 //********************************\r
280 //create a consumer heap\r
281 //**********************************\r
282 \r
283     /* Initialize the heap configuration. */\r
284     memset ((void *)&heapCfg, 0, sizeof(Pktlib_HeapCfg));\r
285 \r
286     pPktifTable = netapi_getPktlibIfTable();\r
287 \r
288     /* Populate the heap configuration */\r
289     heapCfg.name                = "netapi-consumer";\r
290     heapCfg.memRegion           = NETAPI_GLOBAL_REGION;\r
291     heapCfg.sharedHeap          = 1;\r
292     heapCfg.useStarvationQueue  = 0;\r
293     heapCfg.dataBufferSize      = TUNE_NETAPI_DEFAULT_BUFFER_SIZE;\r
294     heapCfg.numPkts             = IFDMA_MAX_HEAP_PKTS;\r
295     heapCfg.numZeroBufferPackets= 0;\r
296     heapCfg.heapInterfaceTable.data_malloc  = pPktifTable->data_malloc;\r
297     heapCfg.heapInterfaceTable.data_free    = pPktifTable->data_free;\r
298     heapCfg.dataBufferPktThreshold   = 0;\r
299     heapCfg.zeroBufferPktThreshold   = 0;\r
300     consumerHeap = Pktlib_createHeap(&heapCfg, &errCode);\r
301 \r
302     //by registering the heap, netapi will take care of\r
303     //cleaning it up @ shutdown..\r
304     netapi_registerHeap(netapi_handle, consumerHeap);  //register heap.\r
305 \r
306     //**************************************************\r
307     //create a FLOW for consumer RX. Note this is created\r
308     //in the QMSS (INFRASTRUCTURE) CPPI DMA ENGINE\r
309     // todo:  flowindex should be passed in or got\r
310     //        from resource manager\r
311     //*************************************************\r
312     {\r
313     Pktlib_HeapHandle heaps[2];\r
314     int sizes[2];\r
315 #define SPECIAL_SOP_OFF 0\r
316     NETCP_CFG_FLOW_CONFIG_T flow_config={IFDMA_FLOW_INDEX,\r
317                                          NETAPI_DMA_INFRASTRUCTURE,\r
318                                          SPECIAL_SOP_OFF,\r
319                                          NETAPI_FLOW_BLOCK };\r
320     heaps[0]= consumerHeap;\r
321     sizes[0]=IFMDA_HEAP_SIZE;\r
322     heaps[1]= consumerHeap;\r
323     sizes[1]=TUNE_NETAPI_DEFAULT_BUFFER_SIZE - SPECIAL_SOP_OFF;\r
324     flow_config.p_dest_q = rx_chan; // send pkts to rx_chan \r
325 \r
326     //specialFlow handle will hold "magic" flowid that producer needs to\r
327     //include in his pkto_send meta data\r
328     specialFlow = netapi_netcpCfgAddFlow( netapi_handle,\r
329                                     IFDMA_MAX_NUM_HEAPS,  //1 heap defined\r
330                                     heaps,\r
331                                     sizes,\r
332                                     &flow_config,  //offset to start rx is 128 \r
333                                     &err);\r
334     if (err) {printf("add flow failed\n", err); exit(1);}\r
335 }\r
336 \r
337 //************************************************************\r
338 //create the IDMA channel:  this is used by producer to either\r
339 //send generated packets or relay received packets from net\r
340 //***************************************************************\r
341 tx_chan=netapi_pktioCreate(netapi_handle,"ourtxq",NULL, &tx_chan_cfg,&err);\r
342 if (!tx_chan) {printf("pktio create failed err=%d\n",err); exit(1);}\r
343 \r
344 #ifndef INTERNAL_PACKETS \r
345 //if we want to relay packets, creaate a simple netcp rule\r
346 //to get a lot of packets\r
347 netapi_netcpCfgCreateMacInterface(\r
348                   netapi_handle,\r
349                   &all_mac[0],\r
350                   0,0,\r
351                   (NETCP_CFG_ROUTE_HANDLE_T)  NULL, \r
352                   (NETCP_CFG_VLAN_T ) NULL ,  //future\r
353                   1,\r
354                   &err);\r
355 #endif\r
356 \r
357 /*********************************************/\r
358 /*****************end NETAPI STARTUP**********/\r
359 /*********************************************/\r
360 \r
361 \r
362 //**************************************\r
363 //Create a consumer and producer thread\r
364 //***************************************\r
365 {\r
366         pthread_t *thrs;\r
367         int procs =2; \r
368         char c;\r
369         thrs = malloc( sizeof( pthread_t ) * procs );\r
370         if (thrs == NULL)\r
371         {\r
372                 perror( "malloc" );\r
373                 return -1;\r
374         }\r
375         printf( "ifdma-test: Starting %d threads...\n", procs );\r
376 \r
377         if (pthread_create( &thrs[0], NULL, (void*)consumer_thread,\r
378                         (void *)0 ))\r
379         {\r
380                         perror( "pthread_create" );\r
381                         exit(1);\r
382         }\r
383         if (pthread_create( &thrs[1], NULL, (void*)producer_thread,\r
384                         (void *)1 ))\r
385         {\r
386                         perror( "pthread_create" );\r
387                         exit(1);\r
388         }\r
389         //this thread of execution (main) now just waits on user input\r
390         for(;;)\r
391         {\r
392            printf(">");\r
393            c=getchar();\r
394            if (c=='q') {QUIT=1;break;}\r
395            else if (c=='s') printf(">IFDMA-TEST STATS:   %d sent, %d received\n",pkt_tx, pkt_rx);\r
396            else if (c=='h') printf("> 'q' to quit,  's' for stats,  'h' for help\n");\r
397         }\r
398 \r
399         //wait for completion \r
400         printf("main task now pending on thread completion\n");\r
401         for (i = 0; i < procs; i++)\r
402                 pthread_join( thrs[i], NULL );\r
403 \r
404         free( thrs );\r
405       \r
406 }\r
407 \r
408 /*************************************************\r
409  ************CLEAN UP****************************\r
410  ************************************************/\r
411 #ifndef INTERNAL_PACKETS\r
412 //get rid of rule, in the case that we are relaying packets\r
413 //also close our netcp rx channel\r
414 netapi_netcpCfgDelMac(netapi_handle,0,&err);\r
415 netapi_pktioClose(netcp_rx_chan,&err);\r
416 #endif\r
417 \r
418 //close pktio channels we opened\r
419 netapi_pktioDelete(tx_chan ,&err);\r
420 netapi_pktioDelete(rx_chan ,&err);\r
421 \r
422 //close flow\r
423 netapi_netcpCfgDelFlow(netapi_handle, specialFlow, &err);\r
424 \r
425 //done\r
426 netapi_shutdown(netapi_handle);\r
427 \r
428 \r
429 //!finished!\r
430 }\r
431 \r
432 \r
433 //receive callback for packets from net (for consumer)\r
434 // this is used for case where we want to relay packets from\r
435 // network, instead of internally generating them\r
436 void recv_cb_net(struct PKTIO_HANDLE_Tag * channel, Ti_Pkt* p_recv[],\r
437                          PKTIO_METADATA_T meta[], int n_pkts,\r
438                          uint64_t ts )\r
439 {\r
440 int i;\r
441 PKTIO_METADATA_T meta2 = {PKTIO_META_TX,{0},0};\r
442 Ti_Pkt * tip;\r
443 int err;\r
444 \r
445 for(i=0;i<n_pkts;i++)\r
446 {\r
447     tip = p_recv[i];\r
448     meta2.u.tx_ifdma_dest=((NETCP_CFG_FLOW_T*)specialFlow)->flowid;\r
449     netapi_pktioSend(tx_chan,tip,&meta2,&err);\r
450     pkt_tx+=1;\r
451     if(!(pkt_tx % 128)) sched_yield(); //give consumer a chance\r
452 }\r
453 \r
454 \r
455 }\r
456 \r
457 \r
458 //receive callback for consumer (registered when we create pktio channel)\r
459 void recv_cb_consumer(struct PKTIO_HANDLE_Tag * channel, Ti_Pkt* p_recv[],\r
460                          PKTIO_METADATA_T meta[], int n_pkts,\r
461                          uint64_t ts )\r
462 {\r
463 int i;\r
464 int len;\r
465 Ti_Pkt * tip;\r
466 unsigned int templen;\r
467 char * p_pkt;\r
468 \r
469 for(i=0;i<n_pkts;i++)\r
470 {\r
471         tip = p_recv[i];\r
472         Pktlib_getDataBuffer(tip,(uint8_t**)&p_pkt,&templen);//ignore templen\r
473         len = Pktlib_getPacketLen(tip);\r
474         Pktlib_freePacket((Ti_Pkt*)tip);\r
475 }\r
476 return;\r
477 }\r
478 \r
479 \r
480 \r
481 \r
482 \r