8df5fbbcd85fb15d3252d0a302c7c69a8db22224
[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 \r
51 #include "trie.h"\r
52 #include "string.h"\r
53 #include "netapi.h"\r
54 #include "pktio.h"\r
55 #include "net_test.h"\r
56 #include <ti/drv/sa/salld.h>\r
57 \r
58 \r
59 //turn this off to use packets received from Network instead of self generated ones\r
60 #define INTERNAL_PACKETS\r
61 static int scnt=0;\r
62 static int QUIT=0;\r
63 __thread int our_core;\r
64 \r
65 \r
66 #define IFDMA_FLOW_INDEX 33\r
67 #define IFMDA_HEAP_SIZE 200\r
68 #define IFDMA_MAX_NUM_HEAPS 2\r
69 #define IFDMA_MAX_HEAP_PKTS 128\r
70 //sig handler\r
71 void netTest_utilMySig(int x)\r
72 {\r
73   QUIT=1;\r
74   scnt+=1;\r
75   printf(">ifdma-test: recv'd signal %d cnt=%d\n",x,scnt);\r
76   if (scnt > 10) {printf(">ifdma-test: WARNING EXITING WITH PROPER SHUTDOWN, LUTS LEFT ACTIVE\n");exit(1);}\r
77 \r
78 }\r
79 void recv_cb_net(struct PKTIO_HANDLE_Tag * channel, Ti_Pkt* p_recv[],\r
80                          PKTIO_METADATA_T meta[], int n_pkts,\r
81                          uint64_t ts );\r
82 void recv_cb_consumer(struct PKTIO_HANDLE_Tag * channel, Ti_Pkt* p_recv[],\r
83                          PKTIO_METADATA_T meta[], int n_pkts,\r
84                          uint64_t ts );\r
85 \r
86 \r
87 /*************debug********************/\r
88 void netTest_utilDumpDescr(unsigned long *p, int n)\r
89 {\r
90    printf("--------dump of descriptor %d %x\n", n, (int) p);\r
91    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
92    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
93    printf("-----------------------------\n");\r
94 }\r
95 void netTest_utilDumpHeader(unsigned long *p, int n, int a, int r)\r
96 {\r
97    printf("--------dump of header %d %x appID=%x flag1=%x\n", n, (int) p,a,r);\r
98    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
99    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
100    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
101    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
102    printf("-----------------------------\n");\r
103 }\r
104 /*****************************************/\r
105 \r
106 \r
107 \r
108 \r
109 \r
110 \r
111 \r
112 /*******************************************\r
113  *************NETAPI OBJECTS***************\r
114  *****************************************/\r
115 static NETAPI_CFG_T our_netapi_default_cfg=\r
116 {\r
117 TUNE_NETAPI_PERM_MEM_SZ,\r
118 128,  //start of packet offset for hw to place data on rx for default flow\r
119 TUNE_NETAPI_QM_CONFIG_MAX_DESC_NUM, //max number of descriptors in system\r
120 TUNE_NETAPI_NUM_GLOBAL_DESC,        //total we will use\r
121 TUNE_NETAPI_DEFAULT_NUM_BUFFERS,   //#descriptors+buffers in default heap\r
122 64, //#descriptors w/o buffers in default heap\r
123 TUNE_NETAPI_DEFAULT_BUFFER_SIZE+128+128,  //size of buffers in default heap\r
124 128   ,  //tail room\r
125 256      //extra room \r
126 };\r
127 \r
128 Pktlib_HeapHandle OurHeap;     //default heap, used by producer\r
129 Pktlib_HeapHandle consumerHeap; //for consumer\r
130 PKTIO_HANDLE_T * rx_chan;  //for consumer\r
131 PKTIO_HANDLE_T * tx_chan;  // for producer\r
132 PKTIO_CFG_T rx_chan_cfg={PKTIO_RX|PKTIO_TX, PKTIO_GLOBAL, PKTIO_Q_ANY, 8};\r
133 PKTIO_CFG_T tx_chan_cfg={PKTIO_TX, PKTIO_GLOBAL|PKTIO_IFDMA, /*PKTIO_Q_ANY*/ 820, 8};\r
134 PKTIO_CFG_T netcp_rx_cfg={PKTIO_RX, PKTIO_NA, PKTIO_NA, 8};\r
135 PKTIO_HANDLE_T * netcp_rx_chan;\r
136 NETAPI_T netapi_handle;\r
137 NETCP_CFG_FLOW_HANDLE_T specialFlow;  //for consumer.  Producer uses the "flowid" in this handle as meta data when he sends data\r
138 \r
139 PKTIO_CONTROL_T zap_channel_control={PKTIO_CLEAR, NULL};\r
140 \r
141 NETCP_CFG_ROUTE_T  test_route=\r
142 {\r
143 NULL, NULL  //* to be filled in\r
144 };\r
145 \r
146 \r
147 /*************************END NETAPI OBJECTS***********************/\r
148 \r
149 static unsigned char all_mac[]={0,0,0,0,0,0};\r
150 \r
151 \r
152 #define IFDMA_PKT_LEN 100\r
153 \r
154 //stats\r
155 int pkt_rx=0; \r
156 int pkt_tx=0;\r
157 \r
158 //***************************\r
159 //consumer thread \r
160 //**************************\r
161 void consumer_thread(int coreid)\r
162 {\r
163 int err;\r
164 int np;\r
165      for(;!((volatile)QUIT);)\r
166      {\r
167          np = netapi_pktioPoll(rx_chan,NULL,&err);\r
168          pkt_rx+=np;\r
169      }\r
170      printf("IFDMA-TEST: CONSUMER DONE %d packets received\n", pkt_rx);\r
171 }\r
172 \r
173 \r
174 //**********************************\r
175 //producer thread\r
176 //*********************************\r
177 void producer_thread(int coreid)\r
178 {\r
179 int err;\r
180 int i;\r
181 Ti_Pkt * tip;\r
182 unsigned char * pData;\r
183 int len;\r
184 PKTIO_METADATA_T meta = {PKTIO_META_IFDMA_TX,{0},0};\r
185 int np;\r
186 #ifdef INTERNAL_PACKETS\r
187       //generate packets internally by allocating from OurHeap (the NETAPI \r
188       //default) and send to receiver via ifdma pktio channel\r
189       sleep(5);\r
190       for(i=0;!((volatile) QUIT);i++)\r
191       {\r
192           tip=Pktlib_allocPacket(OurHeap,IFDMA_PKT_LEN);\r
193           if (!tip) \r
194           {\r
195               sleep(1); //out of buffers, let consumer catch up\r
196               continue;\r
197            }\r
198            Pktlib_getDataBuffer(tip,&pData,&len);\r
199            sprintf(pData,"this is packet %d", pkt_tx);\r
200            Cppi_setData (Cppi_DescType_HOST, (Cppi_Desc *) tip, pData,IFDMA_PKT_LEN);\r
201            Pktlib_setPacketLen(tip,IFDMA_PKT_LEN);\r
202            meta.u.tx_ifdma_dest=((NETCP_CFG_FLOW_T*)specialFlow)->flowid;\r
203            netapi_pktioSend(tx_chan,tip,&meta,&err);\r
204            pkt_tx+=1;\r
205            if(!(pkt_tx % 128)) sched_yield(); //give consumer a chance\r
206       }\r
207 #else\r
208      //relay packets from network.  recv_cb registered when we created\r
209      //netcp_rx_chan will do this relay via the ifdma pktio channel\r
210      //so we poll the default pktio channel for pkts from net\r
211       for(i=0;!((volatile) QUIT);i++)\r
212       {\r
213         np = netapi_pktioPoll(netcp_rx_chan,NULL,&err);\r
214         if (!np) sched_yield();\r
215 \r
216       }\r
217 #endif\r
218       printf("IFDMA-TEST: PRODUCER  DONE %d pkts sent\n", pkt_tx);\r
219 }\r
220 \r
221 \r
222 //******************************\r
223 //  main program\r
224 //*****************************\r
225 int main(int argc, char **argv)\r
226 {\r
227     int err,i;\r
228     int32_t             errCode;\r
229     Pktlib_HeapIfTable*  pPktifTable;\r
230     Pktlib_HeapCfg heapCfg;\r
231     long t1, t2 ;\r
232 \r
233      //install signal handler for ^c\r
234     signal(SIGINT,netTest_utilMySig);\r
235 \r
236 \r
237     /*******************************************/\r
238     /*************NETAPI STARTUP****************/\r
239     /*******************************************/\r
240 \r
241     /* create netapi */\r
242     netapi_handle = netapi_init(NETAPI_SYS_MASTER, &our_netapi_default_cfg);\r
243 \r
244     /* open the main heap */\r
245     OurHeap = Pktlib_findHeapByName("netapi");\r
246     if (!OurHeap) {printf("findheapbyname fail\n"); exit(1);}\r
247 \r
248     //create a receive queue for consumer\r
249     rx_chan=netapi_pktioCreate(netapi_handle,"ourrxq",(PKTIO_CB) recv_cb_consumer, &rx_chan_cfg,&err);\r
250     if (!rx_chan) {printf("pktio create failed err=%d\n",err); exit(1);}\r
251 \r
252 \r
253 #ifndef INTERNAL_PACKETS\r
254     //if we want to relay network packets, we create a handle to the \r
255     //default netcp receive queue here\r
256     netcp_rx_chan= netapi_pktioOpen(netapi_handle, NETCP_RX, (PKTIO_CB) recv_cb_net, &netcp_rx_cfg,  &err);\r
257     if (!netcp_rx_chan) {printf("pktio open RX failed err=%d\n",err); exit(1);}\r
258 #endif\r
259 \r
260 //********************************\r
261 //create a consumer heap\r
262 //**********************************\r
263 \r
264     /* Initialize the heap configuration. */\r
265     memset ((void *)&heapCfg, 0, sizeof(Pktlib_HeapCfg));\r
266 \r
267     pPktifTable = netapi_getPktlibIfTable();\r
268 \r
269     /* Populate the heap configuration */\r
270     heapCfg.name                = "netapi-consumer";\r
271     heapCfg.memRegion           = NETAPI_GLOBAL_REGION;\r
272     heapCfg.sharedHeap          = 1;\r
273     heapCfg.useStarvationQueue  = 0;\r
274     heapCfg.dataBufferSize      = TUNE_NETAPI_DEFAULT_BUFFER_SIZE;\r
275     heapCfg.numPkts             = IFDMA_MAX_HEAP_PKTS;\r
276     heapCfg.numZeroBufferPackets= 0;\r
277     heapCfg.heapInterfaceTable.data_malloc  = pPktifTable->data_malloc;\r
278     heapCfg.heapInterfaceTable.data_free    = pPktifTable->data_free;\r
279     heapCfg.dataBufferPktThreshold   = 0;\r
280     heapCfg.zeroBufferPktThreshold   = 0;\r
281     consumerHeap = Pktlib_createHeap(&heapCfg, &errCode);\r
282 \r
283     //by registering the heap, netapi will take care of\r
284     //cleaning it up @ shutdown..\r
285     netapi_registerHeap(netapi_handle, consumerHeap);  //register heap.\r
286 \r
287     //**************************************************\r
288     //create a FLOW for consumer RX. Note this is created\r
289     //in the QMSS (INFRASTRUCTURE) CPPI DMA ENGINE\r
290     // todo:  flowindex should be passed in or got\r
291     //        from resource manager\r
292     //*************************************************\r
293     {\r
294     Pktlib_HeapHandle heaps[2];\r
295     int sizes[2];\r
296 #define SPECIAL_SOP_OFF 0\r
297     NETCP_CFG_FLOW_CONFIG_T flow_config={IFDMA_FLOW_INDEX,\r
298                                          NETAPI_DMA_INFRASTRUCTURE,\r
299                                          SPECIAL_SOP_OFF,\r
300                                          NETAPI_FLOW_BLOCK };\r
301     heaps[0]= consumerHeap;\r
302     sizes[0]=IFMDA_HEAP_SIZE;\r
303     heaps[1]= consumerHeap;\r
304     sizes[1]=TUNE_NETAPI_DEFAULT_BUFFER_SIZE - SPECIAL_SOP_OFF;\r
305     flow_config.p_dest_q = rx_chan; // send pkts to rx_chan \r
306 \r
307     //specialFlow handle will hold "magic" flowid that producer needs to\r
308     //include in his pkto_send meta data\r
309     specialFlow = netapi_netcpCfgAddFlow( netapi_handle,\r
310                                     IFDMA_MAX_NUM_HEAPS,  //1 heap defined\r
311                                     heaps,\r
312                                     sizes,\r
313                                     &flow_config,  //offset to start rx is 128 \r
314                                     &err);\r
315     if (err) {printf("add flow failed\n", err); exit(1);}\r
316 }\r
317 \r
318 //************************************************************\r
319 //create the IDMA channel:  this is used by producer to either\r
320 //send generated packets or relay received packets from net\r
321 //***************************************************************\r
322 tx_chan=netapi_pktioCreate(netapi_handle,"ourtxq",NULL, &tx_chan_cfg,&err);\r
323 if (!tx_chan) {printf("pktio create failed err=%d\n",err); exit(1);}\r
324 \r
325 #ifndef INTERNAL_PACKETS \r
326 //if we want to relay packets, creaate a simple netcp rule\r
327 //to get a lot of packets\r
328 netapi_netcpCfgCreateMacInterface(\r
329                   netapi_handle,\r
330                   &all_mac[0],\r
331                   0,0,\r
332                   (NETCP_CFG_ROUTE_HANDLE_T)  NULL, \r
333                   (NETCP_CFG_VLAN_T ) NULL ,  //future\r
334                   1,\r
335                   &err);\r
336 #endif\r
337 \r
338 /*********************************************/\r
339 /*****************end NETAPI STARTUP**********/\r
340 /*********************************************/\r
341 \r
342 \r
343 //**************************************\r
344 //Create a consumer and producer thread\r
345 //***************************************\r
346 {\r
347         pthread_t *thrs;\r
348         int procs =2; \r
349         char c;\r
350         thrs = malloc( sizeof( pthread_t ) * procs );\r
351         if (thrs == NULL)\r
352         {\r
353                 perror( "malloc" );\r
354                 return -1;\r
355         }\r
356         printf( "ifdma-test: Starting %d threads...\n", procs );\r
357 \r
358         if (pthread_create( &thrs[0], NULL, (void*)consumer_thread,\r
359                         (void *)0 ))\r
360         {\r
361                         perror( "pthread_create" );\r
362                         exit(1);\r
363         }\r
364         if (pthread_create( &thrs[1], NULL, (void*)producer_thread,\r
365                         (void *)1 ))\r
366         {\r
367                         perror( "pthread_create" );\r
368                         exit(1);\r
369         }\r
370         //this thread of execution (main) now just waits on user input\r
371         for(;;)\r
372         {\r
373            printf(">");\r
374            c=getchar();\r
375            if (c=='q') {QUIT=1;break;}\r
376            else if (c=='s') printf(">IFDMA-TEST STATS:   %d sent, %d received\n",pkt_tx, pkt_rx);\r
377            else if (c=='h') printf("> 'q' to quit,  's' for stats,  'h' for help\n");\r
378         }\r
379 \r
380         //wait for completion \r
381         printf("main task now pending on thread completion\n");\r
382         for (i = 0; i < procs; i++)\r
383                 pthread_join( thrs[i], NULL );\r
384 \r
385         free( thrs );\r
386       \r
387 }\r
388 \r
389 /*************************************************\r
390  ************CLEAN UP****************************\r
391  ************************************************/\r
392 #ifndef INTERNAL_PACKETS\r
393 //get rid of rule, in the case that we are relaying packets\r
394 //also close our netcp rx channel\r
395 netapi_netcpCfgDelMac(netapi_handle,0,&err);\r
396 netapi_pktioClose(netcp_rx_chan,&err);\r
397 #endif\r
398 \r
399 //close pktio channels we opened\r
400 netapi_pktioDelete(tx_chan ,&err);\r
401 netapi_pktioDelete(rx_chan ,&err);\r
402 \r
403 //close flow\r
404 netapi_netcpCfgDelFlow(netapi_handle, specialFlow, &err);\r
405 \r
406 //done\r
407 netapi_shutdown(netapi_handle);\r
408 \r
409 \r
410 //!finished!\r
411 }\r
412 \r
413 \r
414 //receive callback for packets from net (for consumer)\r
415 // this is used for case where we want to relay packets from\r
416 // network, instead of internally generating them\r
417 void recv_cb_net(struct PKTIO_HANDLE_Tag * channel, Ti_Pkt* p_recv[],\r
418                          PKTIO_METADATA_T meta[], int n_pkts,\r
419                          uint64_t ts )\r
420 {\r
421 int i;\r
422 PKTIO_METADATA_T meta2 = {PKTIO_META_TX,{0},0};\r
423 Ti_Pkt * tip;\r
424 int err;\r
425 \r
426 for(i=0;i<n_pkts;i++)\r
427 {\r
428     tip = p_recv[i];\r
429     meta2.u.tx_ifdma_dest=((NETCP_CFG_FLOW_T*)specialFlow)->flowid;\r
430     netapi_pktioSend(tx_chan,tip,&meta2,&err);\r
431     pkt_tx+=1;\r
432     if(!(pkt_tx % 128)) sched_yield(); //give consumer a chance\r
433 }\r
434 \r
435 \r
436 }\r
437 \r
438 \r
439 //receive callback for consumer (registered when we create pktio channel)\r
440 void recv_cb_consumer(struct PKTIO_HANDLE_Tag * channel, Ti_Pkt* p_recv[],\r
441                          PKTIO_METADATA_T meta[], int n_pkts,\r
442                          uint64_t ts )\r
443 {\r
444 int i;\r
445 int len;\r
446 Ti_Pkt * tip;\r
447 unsigned int templen;\r
448 char * p_pkt;\r
449 \r
450 for(i=0;i<n_pkts;i++)\r
451 {\r
452         tip = p_recv[i];\r
453         Pktlib_getDataBuffer(tip,(uint8_t**)&p_pkt,&templen);//ignore templen\r
454         len = Pktlib_getPacketLen(tip);\r
455         Pktlib_freePacket((Ti_Pkt*)tip);\r
456 }\r
457 return;\r
458 }\r
459 \r
460 \r
461 \r
462 \r
463 \r