a0fbd1775294c3e6b9693e2e26a7acfcdc827408
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 "ti/runtime/netapi/netapi.h"
55 #include "ti/runtime/netapi/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");
104 }
105 void netTest_utilDumpHeader(unsigned long *p, int n, int a, int r)
106 {
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");
113 }
114 /*****************************************/
122 /*******************************************
123 *************NETAPI OBJECTS***************
124 *****************************************/
125 static NETAPI_CFG_T our_netapi_default_cfg=
126 {
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 };
138 Pktlib_HeapHandle OurHeap; //default heap, used by producer
139 Pktlib_HeapHandle consumerHeap; //for consumer
140 PKTIO_HANDLE_T * rx_chan; //for consumer
141 PKTIO_HANDLE_T * tx_chan; // for producer
142 PKTIO_CFG_T rx_chan_cfg={PKTIO_RX|PKTIO_TX, PKTIO_GLOBAL, PKTIO_Q_ANY, 8};
143 PKTIO_CFG_T tx_chan_cfg={PKTIO_TX, PKTIO_GLOBAL|PKTIO_IFDMA, /*PKTIO_Q_ANY*/ 820, 8};
144 PKTIO_CFG_T netcp_rx_cfg={PKTIO_RX, PKTIO_NA, PKTIO_NA, 8};
145 PKTIO_HANDLE_T * netcp_rx_chan;
146 NETAPI_T netapi_handle;
147 NETCP_CFG_FLOW_HANDLE_T specialFlow; //for consumer. Producer uses the "flowid" in this handle as meta data when he sends data
149 PKTIO_CONTROL_T zap_channel_control={PKTIO_CLEAR, NULL};
151 NETCP_CFG_ROUTE_T test_route=
152 {
153 NULL, NULL //* to be filled in
154 };
157 /*************************END NETAPI OBJECTS***********************/
159 static unsigned char all_mac[]={0,0,0,0,0,0};
162 #define IFDMA_PKT_LEN 100
164 //stats
165 int pkt_rx=0;
166 int pkt_tx=0;
167 int pkt_stall=0;
169 //***************************
170 //consumer thread
171 //**************************
172 void consumer_thread(int coreid)
173 {
174 int err;
175 int np;
176 cpu_set_t cpu_set;
178 CPU_ZERO( &cpu_set);
179 CPU_SET( 1, &cpu_set);
180 hplib_utilSetupThread(1, &cpu_set);
182 for(;!((volatile)QUIT);)
183 {
184 np = netapi_pktioPoll(rx_chan,NULL,&err);
185 pkt_rx+=np;
186 }
187 printf("IFDMA-TEST: CONSUMER DONE %d packets received\n", pkt_rx);
188 }
191 //**********************************
192 //producer thread
193 //*********************************
194 void producer_thread(int coreid)
195 {
196 int err;
197 int i;
198 Ti_Pkt * tip;
199 unsigned char * pData;
200 int len;
201 PKTIO_METADATA_T meta = {PKTIO_META_IFDMA_TX,{0},0};
202 int np;
203 cpu_set_t cpu_set;
206 CPU_ZERO( &cpu_set);
207 CPU_SET( 2, &cpu_set);
208 hplib_utilSetupThread(2, &cpu_set);
210 #ifdef INTERNAL_PACKETS
211 //generate packets internally by allocating from OurHeap (the NETAPI
212 //default) and send to receiver via ifdma pktio channel
213 sleep(5);
214 for(i=0;!((volatile) QUIT);i++)
215 {
216 tip=Pktlib_allocPacket(OurHeap,IFDMA_PKT_LEN);
217 if (!tip)
218 {
219 pkt_stall+=1;
220 sleep(1); //out of buffers, let consumer catch up
221 continue;
222 }
223 Pktlib_getDataBuffer(tip,&pData,&len);
224 sprintf(pData,"this is packet %d", pkt_tx);
225 Cppi_setData (Cppi_DescType_HOST, (Cppi_Desc *) tip, pData,IFDMA_PKT_LEN);
226 Pktlib_setPacketLen(tip,IFDMA_PKT_LEN);
227 meta.u.tx_ifdma_dest=((NETCP_CFG_FLOW_T*)specialFlow)->flowid;
228 netapi_pktioSend(tx_chan,tip,&meta,&err);
229 pkt_tx+=1;
230 if(!(pkt_tx % 64)) sched_yield(); //give consumer a chance
231 }
232 #else
233 //relay packets from network. recv_cb registered when we created
234 //netcp_rx_chan will do this relay via the ifdma pktio channel
235 //so we poll the default pktio channel for pkts from net
236 for(i=0;!((volatile) QUIT);i++)
237 {
238 np = netapi_pktioPoll(netcp_rx_chan,NULL,&err);
239 if (!np) sched_yield();
241 }
242 #endif
243 printf("IFDMA-TEST: PRODUCER DONE %d pkts sent (stalls=%d)\n", pkt_tx,pkt_stall);
244 }
247 //******************************
248 // main program
249 //*****************************
250 int main(int argc, char **argv)
251 {
252 int err,i;
253 int32_t errCode;
254 Pktlib_HeapIfTable* pPktifTable;
255 Pktlib_HeapCfg heapCfg;
256 long t1, t2 ;
257 cpu_set_t cpu_set;
260 //install signal handler for ^c
261 signal(SIGINT,netTest_utilMySig);
262 CPU_ZERO( &cpu_set);
263 CPU_SET( 0, &cpu_set);
264 hplib_utilSetupThread(0, &cpu_set);
267 /*******************************************/
268 /*************NETAPI STARTUP****************/
269 /*******************************************/
271 /* create netapi */
272 netapi_handle = netapi_init(NETAPI_SYS_MASTER, &our_netapi_default_cfg);
273 printf("main: returned from netapi_init\n");
275 /* Un-configure rules for execption packet handling */
276 netapi_netcpCfgExceptions(netapi_handle,
277 NETCP_CFG_ALL_EXCEPTIONS,
278 NETCP_CFG_ACTION_DISCARD,
279 (NETCP_CFG_ROUTE_HANDLE_T) NULL);
280 /* open the main heap */
281 OurHeap = Pktlib_findHeapByName("netapi");
282 if (!OurHeap) {printf("findheapbyname fail\n"); exit(1);}
284 //create a receive queue for consumer
285 rx_chan=netapi_pktioCreate(netapi_handle,"ourrxq",(PKTIO_CB) recv_cb_consumer, &rx_chan_cfg,&err);
286 if (!rx_chan) {printf("pktio create failed err=%d\n",err); exit(1);}
289 #ifndef INTERNAL_PACKETS
290 //if we want to relay network packets, we create a handle to the
291 //default netcp receive queue here
292 netcp_rx_chan= netapi_pktioOpen(netapi_handle, NETCP_RX, (PKTIO_CB) recv_cb_net, &netcp_rx_cfg, &err);
293 if (!netcp_rx_chan) {printf("pktio open RX failed err=%d\n",err); exit(1);}
294 #endif
296 //********************************
297 //create a consumer heap
298 //**********************************
300 /* Initialize the heap configuration. */
301 memset ((void *)&heapCfg, 0, sizeof(Pktlib_HeapCfg));
303 pPktifTable = netapi_getPktlibIfTable();
305 /* Populate the heap configuration */
306 heapCfg.name = "netapi-consumer";
307 heapCfg.memRegion = NETAPI_GLOBAL_REGION;
308 heapCfg.sharedHeap = 1;
309 heapCfg.useStarvationQueue = 0;
310 heapCfg.dataBufferSize = TUNE_NETAPI_DEFAULT_BUFFER_SIZE;
311 heapCfg.numPkts = IFDMA_MAX_HEAP_PKTS;
312 heapCfg.numZeroBufferPackets= 0;
313 heapCfg.heapInterfaceTable.data_malloc = pPktifTable->data_malloc;
314 heapCfg.heapInterfaceTable.data_free = pPktifTable->data_free;
315 heapCfg.dataBufferPktThreshold = 0;
316 heapCfg.zeroBufferPktThreshold = 0;
317 consumerHeap = Pktlib_createHeap(&heapCfg, &errCode);
319 //by registering the heap, netapi will take care of
320 //cleaning it up @ shutdown..
321 netapi_registerHeap(netapi_handle, consumerHeap); //register heap.
323 //**************************************************
324 //create a FLOW for consumer RX. Note this is created
325 //in the QMSS (INFRASTRUCTURE) CPPI DMA ENGINE
326 // todo: flowindex should be passed in or got
327 // from resource manager
328 //*************************************************
329 {
330 Pktlib_HeapHandle heaps[2];
331 int sizes[2];
332 #define SPECIAL_SOP_OFF 0
333 NETCP_CFG_FLOW_CONFIG_T flow_config={IFDMA_FLOW_INDEX,
334 NETAPI_DMA_INFRASTRUCTURE,
335 SPECIAL_SOP_OFF,
336 NETAPI_FLOW_BLOCK };
337 heaps[0]= consumerHeap;
338 sizes[0]=IFMDA_HEAP_SIZE;
339 heaps[1]= consumerHeap;
340 sizes[1]=TUNE_NETAPI_DEFAULT_BUFFER_SIZE - SPECIAL_SOP_OFF;
341 flow_config.p_dest_q = rx_chan; // send pkts to rx_chan
343 //specialFlow handle will hold "magic" flowid that producer needs to
344 //include in his pkto_send meta data
345 specialFlow = netapi_netcpCfgAddFlow( netapi_handle,
346 IFDMA_MAX_NUM_HEAPS, //1 heap defined
347 heaps,
348 sizes,
349 &flow_config, //offset to start rx is 128
350 &err);
351 if (err) {printf("add flow failed\n", err); exit(1);}
352 }
354 //************************************************************
355 //create the IDMA channel: this is used by producer to either
356 //send generated packets or relay received packets from net
357 //***************************************************************
358 tx_chan=netapi_pktioCreate(netapi_handle,"ourtxq",NULL, &tx_chan_cfg,&err);
359 if (!tx_chan) {printf("pktio create failed err=%d\n",err); exit(1);}
361 #ifndef INTERNAL_PACKETS
362 //if we want to relay packets, creaate a simple netcp rule
363 //to get a lot of packets
364 netapi_netcpCfgCreateMacInterface(
365 netapi_handle,
366 &all_mac[0],
367 0,0,
368 (NETCP_CFG_ROUTE_HANDLE_T) NULL,
369 (NETCP_CFG_VLAN_T ) NULL , //future
370 1,
371 &err);
372 #endif
374 /*********************************************/
375 /*****************end NETAPI STARTUP**********/
376 /*********************************************/
378 #if 1
379 //sonme benchmarks
380 benchmarks();
381 #endif
382 //**************************************
383 //Create a consumer and producer thread
384 //***************************************
385 {
386 pthread_t *thrs;
387 int procs =2;
388 char c;
389 thrs = malloc( sizeof( pthread_t ) * procs );
390 if (thrs == NULL)
391 {
392 perror( "malloc" );
393 return -1;
394 }
395 printf( "ifdma-test: Starting %d threads...\n", procs );
397 if (pthread_create( &thrs[0], NULL, (void*)consumer_thread,
398 (void *)0 ))
399 {
400 perror( "pthread_create" );
401 exit(1);
402 }
403 if (pthread_create( &thrs[1], NULL, (void*)producer_thread,
404 (void *)1 ))
405 {
406 perror( "pthread_create" );
407 exit(1);
408 }
409 //this thread of execution (main) now just waits on user input
410 for(;;)
411 {
412 printf(">");
413 c=getchar();
414 if (c=='q') {QUIT=1;break;}
415 else if (c=='s') printf(">IFDMA-TEST STATS: %d sent, %d received stall=%d \n",pkt_tx, pkt_rx,pkt_stall);
416 else if (c=='h') printf("> 'q' to quit, 's' for stats, 'h' for help\n");
417 }
419 //wait for completion
420 printf("main task now pending on thread completion\n");
421 for (i = 0; i < procs; i++)
422 pthread_join( thrs[i], NULL );
424 free( thrs );
426 }
428 /*************************************************
429 ************CLEAN UP****************************
430 ************************************************/
431 #ifndef INTERNAL_PACKETS
432 //get rid of rule, in the case that we are relaying packets
433 //also close our netcp rx channel
434 netapi_netcpCfgDelMac(netapi_handle,0,&err);
435 netapi_pktioClose(netcp_rx_chan,&err);
436 #endif
438 //close pktio channels we opened
439 netapi_pktioDelete(tx_chan ,&err);
440 netapi_pktioDelete(rx_chan ,&err);
442 //close flow
443 netapi_netcpCfgDelFlow(netapi_handle, specialFlow, &err);
445 //done
446 netapi_shutdown(netapi_handle);
449 //!finished!
450 }
453 //receive callback for packets from net (for consumer)
454 // this is used for case where we want to relay packets from
455 // network, instead of internally generating them
456 void recv_cb_net(struct PKTIO_HANDLE_Tag * channel, Ti_Pkt* p_recv[],
457 PKTIO_METADATA_T meta[], int n_pkts,
458 uint64_t ts )
459 {
460 int i;
461 PKTIO_METADATA_T meta2 = {PKTIO_META_TX,{0},0};
462 Ti_Pkt * tip;
463 int err;
465 for(i=0;i<n_pkts;i++)
466 {
467 tip = p_recv[i];
468 meta2.u.tx_ifdma_dest=((NETCP_CFG_FLOW_T*)specialFlow)->flowid;
469 netapi_pktioSend(tx_chan,tip,&meta2,&err);
470 pkt_tx+=1;
471 if(!(pkt_tx % 128)) sched_yield(); //give consumer a chance
472 }
475 }
478 //receive callback for consumer (registered when we create pktio channel)
479 void recv_cb_consumer(struct PKTIO_HANDLE_Tag * channel, Ti_Pkt* p_recv[],
480 PKTIO_METADATA_T meta[], int n_pkts,
481 uint64_t ts )
482 {
483 int i;
484 int len;
485 Ti_Pkt * tip;
486 unsigned int templen;
487 char * p_pkt;
489 for(i=0;i<n_pkts;i++)
490 {
491 tip = p_recv[i];
492 Pktlib_getDataBuffer(tip,(uint8_t**)&p_pkt,&templen);//ignore templen
493 len = Pktlib_getPacketLen(tip);
494 Pktlib_freePacket((Ti_Pkt*)tip);
495 }
496 return;
497 }
502 //SOME BENCHMARKS
503 //sonme benchmarks
504 void benchmarks(void)
505 {
506 int i,j;
507 unsigned long v1pop;
508 unsigned long v2pop;
509 unsigned long v1push;
510 unsigned long v2push;
511 unsigned long v1read;
512 unsigned long v2read;
513 unsigned long v1write;
514 unsigned long v2write;
515 unsigned long v1read2;
516 unsigned long v2read2;
517 #define N 100
518 Ti_Pkt pkts[N];
519 unsigned char * p_pkt;
520 int len;
521 int sum=0;
522 int sum2=0;
523 char *p=(char *) malloc(1000);
525 //queue pop
526 v1pop=netapi_timing_start();
527 for(i=0;i<N;i++) pkts[i]= Pktlib_allocPacket(OurHeap,1000);
528 v2pop = netapi_timing_start();
530 //write access
531 Pktlib_getDataBuffer(pkts[0],(uint8_t**)&p_pkt,&len);
532 v1write=netapi_timing_start();
533 for(i=0;i<1000;i++) p_pkt[i]=i;
534 v2write=netapi_timing_start();
536 // access
538 v1read=netapi_timing_start();
539 for(j=0;j<10;j++)
540 for(i=0;i<1000;i++) sum+=p_pkt[i];
541 v2read=netapi_timing_start();
543 // access (from malloc)
544 v1read2=netapi_timing_start();
545 for(i=0;i<1000;i++) sum2+=p[i];
546 v2read2=netapi_timing_start();
548 //queue push
549 v1push=netapi_timing_start();
550 for(i=0;i<N;i++) Pktlib_freePacket(pkts[i]);
551 v2push = netapi_timing_start();
553 //resutls
554 printf("allocs= %d free=%d write=%d read=%d read-malloc=%d (sum=%d %d)\n",
555 (v2pop-v1pop)/N, (v2push-v1push)/N, (v2write-v1write)/1000, (v2read-v1read)/10000,
556 (v2read2-v1read2)/1000,sum,sum2);
558 }