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