O-RAN E Maintenance Release contribution for ODULOW
[o-du/phy.git] / wls_lib / testapp / testapp.c
1 /******************************************************************************
2 *
3 *   Copyright (c) 2021 Intel.
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 *
17 *******************************************************************************/
18
19 /**
20  * WLS interface test application
21  * (contains functional unit tests and diagnostics to test wls
22  *  supported by WLS interface)
23  */
24
25 #ifndef _GNU_SOURCE
26 #define _GNU_SOURCE
27 #endif
28
29 #include <stdio.h>   // for printf
30 #include <string.h>  // for memset
31 #include <signal.h>  // for SIGINT
32 #include <unistd.h>  // for usleep
33 #include <stdlib.h>  // for rand
34 #include <getopt.h>  // for getopt
35 #include <sys/time.h>
36 #include <pthread.h>
37 #include <sched.h>
38 #include "ttypes.h"
39 #include "wls_lib.h"
40 #include "pool.h"
41 #include <rte_config.h>
42 #include <rte_common.h>
43 #include <rte_eal.h>
44
45
46 #define HANDLE  PVOID
47
48
49 #define K                       1024
50 #define M                       (K*K)
51
52 #define   DEFAULT_TEST_MEMORY_SIZE      256*M
53 #define   DEFAUTL_TEST_BLOCK_SIZE       16*K
54
55 #define   DEFAULT_MESSAGE_COUNT_PER_MS  10
56 #define   DEFAULT_MAX_MESSAGE_SIZE      2000
57 #define   DEFUALT_MIN_MESSAGE_SIZE      100
58
59 #define   APP_QUEUE_SIZE   255   /* number of elements each queue of the WLS  being registered will have */
60 #define   MAX_MESSAGES  1000   /* per ms */
61
62 U32 nCRC_Fail = 0;
63 U32 nCRC_Pass = 0;
64
65 #ifndef TRUE
66 #define TRUE  1
67 #endif
68
69 #ifndef FALSE
70 #define FALSE 0
71 #endif
72
73 typedef enum {
74     APP_TC_SANITY_TEST = 0,
75 } APP_TEST_CASES;
76
77 typedef struct tagAPP_PARAMS {
78     char *wls_dev_name;
79     int aff_core;
80     int test_id;
81     int rx_id;
82     int tx_id;
83     int n_messages;
84     int max_size;
85     int min_size;
86     int interface_count;
87     U8 master;
88     U8 debug;
89     U8 crc;
90     U8 trusted;
91 } APP_PARAMS, *PAPP_PARAMS;
92
93 typedef struct tagAPP_MESSAGE {
94     U32 id;
95 } APP_MESSAGE, *PAPP_MESSAGE;
96
97 typedef struct tagAPP_CONTEXT {
98     V32 ExitStatus;
99     HANDLE hWls;
100
101     U32 master;
102
103     PVOID shm_memory;
104
105     POOL Pool; // The pool descriptor
106     void* PoolStrPtr; // The pool storage pointer to keep indexes
107
108     U16 RxID;
109     U16 TxID;
110
111     U16 nInterfaces; // number of RX identifiers used by the APP
112     //
113     U16 InitQueueSize; // for invalid messages test (to trigger WLS  blocking)
114
115     //
116     U32 MsgPerMs;
117     U32 MaxMsgSize;
118     U32 MinMsgSize;
119
120     U32 TxCnt;
121     U32 RxCnt;
122
123     U64 nTxMsgs; // Messages transmitted
124     U64 nTxOctets; // Octets transmitted
125     U64 nRxMsgs; // Messages received
126     U64 nRxOcters; // Octets received
127     U64 Cycles; // number of 1ms cycles
128
129     int AppSanityMsgSize; // 4 or 8 depending on CRC feature
130     U8 Debug; // when TRUE app cycle is 1 sec, otherwise 1ms
131     U8 TrustedDataSource; // for trusted data sources ICC service removes msg validity checking.
132
133     void (*Receive)(HANDLE h);
134     void (*Transmit)(HANDLE h);
135
136     void (*ThreadReceive)(HANDLE h);
137     void (*ThreadTransmit)(HANDLE h);
138
139     int (*wls_put)(void* h, unsigned long long pMsg, unsigned int MsgSize, unsigned short MsgTypeID, unsigned short Flags);
140     unsigned long long (*wls_get)(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags);
141     unsigned long long (*wls_wget)(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags);
142
143     U8 *pLastRx; // used for scatter-gather test
144     U32 LastRxSize; // used for scatter-gather test
145
146     U32 *pServiceBuffer;
147
148     U32 TxMsgCnt;
149     PVOID TxMessages[MAX_MESSAGES];
150     U32 TxMessageSizes[MAX_MESSAGES]; // <-- required for Ping-Pong test to store received sizes
151     int core;
152
153 } APP_CONTEXT, *PAPP_CONTEXT;
154
155 APP_CONTEXT AppContext;
156
157 static int pool_alloc = 0;
158 static int pool_free = 0;
159
160 static void ShowData(void* ptr, unsigned int size)
161 {
162     U8 *d = ptr;
163     unsigned int i;
164
165     for (i = 0; i < size; i++) {
166         if (!(i & 0xf))
167             printf("\n");
168         printf("%02x ", d[i]);
169     }
170     printf("\n");
171 }
172
173 static void App_SigExitCallback(int signum)
174 {
175     (void) signum;
176     AppContext.ExitStatus = TRUE;
177 }
178
179 static void* WlsVaToPa(void * ptr)
180 {
181     PAPP_CONTEXT pCtx = &AppContext;
182     return (void*) WLS_VA2PA(pCtx->hWls, ptr);
183 }
184
185 static void* WlsPaToVa(void * ptr)
186 {
187     PAPP_CONTEXT pCtx = &AppContext;
188     return (void*) WLS_PA2VA(pCtx->hWls, (U64) ptr);
189 }
190
191 static void* App_Alloc(void* h, unsigned long size)
192 {
193     (void) h;
194     (void) size;
195     void * retval = NULL;
196     if (AppContext.master) {
197         retval = PoolAlloc(&(AppContext.Pool));
198         //printf("pPool->FreeGet  %d == pPool->FreePut %d\n", AppContext.Pool.FreeGet, AppContext.Pool.FreePut);
199     } else {
200         retval = (void*) WLS_DequeueBlock(AppContext.hWls);
201         if (retval)
202             retval = (void*) WlsPaToVa(retval);
203         else
204             printf("WLS_DequeueBlock returned null\n");
205     }
206
207     if (retval == NULL) {
208         printf("no memory %d %d\n", pool_alloc, pool_free);
209         exit(-1);
210     } else
211         pool_alloc++;
212
213     return retval;
214 }
215
216 static int App_Free(void* h, void* pMsg)
217 {
218     (void) h;
219     if (AppContext.master)
220         if (pMsg) {
221             pool_free++;
222             return (PoolFree(&(AppContext.Pool), pMsg) == 1 ? 0 : -1);
223         } else {
224             printf("Free Null pointer\n");
225             exit(-1);
226         } else
227         return 0;
228 }
229
230 static int App_MemoryInit(void* h, unsigned long size, U32 BlockSize)
231 {
232     int ret = 0;
233     unsigned long long* pUsed;
234     unsigned long long* pFree;
235     PAPP_CONTEXT pCtx = &AppContext;
236     U32 nBlocksSlave = 0;
237
238     U32 nElmNum = size / BlockSize - 1;
239
240     // We need to allocate the memory for indexes and to initialize the
241     // pool descriptor, (x+1) is used to prevent queues overflow
242
243     pCtx->PoolStrPtr = malloc((nElmNum + 1) * 4 * sizeof (unsigned long long));
244
245     if (pCtx->PoolStrPtr == NULL)
246         return -1;
247
248     pFree = (unsigned long long*) pCtx->PoolStrPtr;
249     pUsed = pFree + (nElmNum + 1);
250
251     ret = PoolInit(&pCtx->Pool, h, nElmNum, BlockSize, pFree, pUsed);
252
253     if (ret == 0) {
254
255         if (AppContext.master) {
256             int res = TRUE;
257             /* allocate blocks for Slave to Master transmittion */
258             while (res) {
259                 void* pBlock = App_Alloc(AppContext.hWls, DEFAUTL_TEST_BLOCK_SIZE);
260                 if (pBlock) {
261                     res = WLS_EnqueueBlock(AppContext.hWls, (U64) WlsVaToPa(pBlock));
262                     if (res)
263                         nBlocksSlave++;
264                     else
265                         App_Free(AppContext.hWls, pBlock);
266                 } else
267                     res = FALSE;
268             }
269             printf("Slave has %d free blocks\n", nBlocksSlave);
270         }
271     }
272
273     return ret;
274 }
275
276 /********************************/
277
278 const U8 mb_table_level1[] = {
279     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
280     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
281     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
282     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
283     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
284     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
285     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
286     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
287     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
288     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
289     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
290     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
291     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
292     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
293     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
294     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
295     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
296     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
297     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
298     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
299     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
300     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
301     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
302     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
303     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
304     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
305     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
306     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
307     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
308     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
309     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
310     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
311 };
312
313 const U8 mb_table_level2[] = {
314     0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2,
315     0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04,
316     0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
317     0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8,
318     0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
319     0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
320     0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6,
321     0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10,
322     0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
323     0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
324     0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE,
325     0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
326     0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA,
327     0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C,
328     0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
329     0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0,
330     0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62,
331     0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
332     0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE,
333     0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
334     0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
335     0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C,
336     0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76,
337     0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
338     0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
339     0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54,
340     0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
341     0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98,
342     0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A,
343     0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
344     0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86,
345     0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40
346 };
347
348 #define CRC32_INIT_VAL  0xFFFFFFFF
349 #define CRC32_DIVISOR   0xA0000001
350
351 static U32 ICC_CRC32(U8 *pData, U32 size)
352 {
353     U32 retval = CRC32_INIT_VAL;
354     U8 i, tmp;
355
356     if (!size)
357         return CRC32_INIT_VAL; // mean CRC error
358     do {
359         retval ^= *pData++;
360         for (i = 8; i > 0; --i) {
361             tmp = retval & 0x01;
362             retval >>= 1;
363             if (tmp) {
364                 retval ^= CRC32_DIVISOR;
365             }
366         }
367     } while (--size);
368     return retval;
369 }
370
371
372 static int app_PutMessageCRC(void* h, unsigned long long pMsg, unsigned int MsgSize, unsigned short MsgTypeID, unsigned short Flags)
373 {
374     U8 *p;
375     U64 pMsgVa = (U64) WlsPaToVa((void*) pMsg);
376
377     if (pMsgVa == 0)
378     {
379         return 0;
380     }
381     p = (U8 *) pMsgVa;
382
383     U32 crc = ICC_CRC32((U8 *) pMsgVa, MsgSize - sizeof (crc));
384
385     // CRC32
386     p[MsgSize - 4] = (crc >> 0) & 0xff;
387     p[MsgSize - 3] = (crc >> 8) & 0xff;
388     p[MsgSize - 2] = (crc >> 16) & 0xff;
389     p[MsgSize - 1] = (crc >> 24) & 0xff;
390
391     return WLS_Put(h, (unsigned long long) pMsg, MsgSize, MsgTypeID, Flags);
392 }
393
394 static unsigned long long app_GetMessageCRC(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags)
395 {
396     U64 pMsgPa = WLS_Get(h, MsgSize, MsgTypeID, Flags);
397
398     if (pMsgPa) {
399     U64 pMsg = (U64) WlsPaToVa((void*) pMsgPa);
400
401     if (pMsg) {
402         U32 size = *MsgSize;
403         U32 crc = ICC_CRC32((U8*) pMsg, size);
404
405         if (crc != 0) {
406                 nCRC_Fail++;
407             printf("CRC error detected for message %p, size_%lu\n", (void*) pMsg, (long) size);
408             ShowData((U8*) pMsg, size);
409         }
410             else {
411                 if (nCRC_Pass == 0) {
412                     printf("Example of Msg Size and Content being sent: %d\n", size);
413                     ShowData((U8*) pMsg, size);
414                 }
415                 nCRC_Pass++;
416             }
417         }
418     }
419     return pMsgPa;
420 }
421
422 static unsigned long long app_WGetMessageCRC(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags)
423 {
424     U64 pMsgPa = WLS_WGet(h, MsgSize, MsgTypeID, Flags);
425
426     if (pMsgPa) {
427     U64 pMsg = (U64) WlsPaToVa((void*) pMsgPa);
428
429     if (pMsg) {
430         U32 size = *MsgSize;
431         U32 crc = ICC_CRC32((U8*) pMsg, size);
432
433         if (crc != 0) {
434                 nCRC_Fail++;
435             printf("CRC error detected for message %p, size_%lu\n", (void*) pMsg, (long) size);
436             ShowData((U8*) pMsg, size);
437         }
438             else {
439                 if (nCRC_Pass == 0) {
440                     printf("Example of Msg Size and Content being sent: %d\n", size);
441                     ShowData((U8*) pMsg, size);
442                 }
443                 nCRC_Pass++;
444             }
445         }
446     }
447     return pMsgPa;
448 }
449
450 static void CreateMessage(PAPP_MESSAGE p, U32 size)
451 {
452     (void) size;
453     p->id = AppContext.TxCnt++;
454 }
455
456 static void CheckMessage(PAPP_MESSAGE p, U32 size)
457 {
458     if (AppContext.RxCnt && p->id != AppContext.RxCnt) {
459         //              char buf[8*K];
460         printf("rx message(id_%llu)_%lx error expected_%lu, received_%lu\n", (long long) AppContext.nRxMsgs, (U64) p, (long) AppContext.RxCnt, (long) p->id);
461         ShowData(p, size);
462         //              if (TL_GetStatistics(AppContext.hWls, buf, sizeof(buf)))
463         //              printf("%s", buf);
464     }
465
466     AppContext.RxCnt = p->id;
467     AppContext.RxCnt += 1;
468 }
469
470 /**
471  *******************************************************************************
472  *
473  * @fn    app_AllocMultiple
474  * @brief used to allocate multiple blocks of the same size from the WLS
475  *
476  * @param[h]  hWls - app thread WLS  handle
477  * @param[o]  pMsgs - ptr to beginning of array of points to allocated blocks
478  * @param[o]  pMsgSizes - array to write size for each allocated blocks
479  * @param[i]  nMsgs - number of blocks to allocate
480  * @return    U32 - number of allocated blocks
481  *
482  * @description
483  *    The routine is used allocate multiple blocks from the ICC service,
484  * the blocks are supposed to be same size blocks, satisfying
485  * appContext.MaxMsgSize parameter.
486  *    In case the service is unable to provide requested number of blocks,
487  * smaller count is allocated. The routine returns actual number of allocated
488  * blocks
489  *
490  * @references
491  * MS-111070-SP
492  *
493  * @ingroup icc_service_unit_test
494  *
495  ******************************************************************************/
496 static U32 app_AllocMultiple(HANDLE hWls, PVOID *pMsgs, U32 *pMsgSizes, U32 nMsgs)
497 {
498     unsigned n = 0;
499     unsigned i, j;
500
501     memset(pMsgs, 0x00, sizeof (PVOID) * nMsgs);
502
503     while (nMsgs--) {
504         pMsgs[n] = App_Alloc(hWls, AppContext.MaxMsgSize);
505         pMsgSizes[n] = AppContext.MaxMsgSize;
506         if (!pMsgs[n]) {
507             printf("empty pool allocated_%u out of %lu\n", n, (long) AppContext.MsgPerMs);
508             break;
509         }
510         n += 1;
511     }
512
513     // check for duplicated pointers
514     for (i = 0; i < n; i++) {
515         for (j = i + 1; j < n; j++) {
516             if (pMsgs[i] == pMsgs[j]) {
517                 printf("duplicated pointer %p (msg_id1_%u, msg_id2_%u)\n", pMsgs[i], i, j);
518                 break;
519             }
520         }
521     }
522
523     return n;
524     //ShowData(TxMessages, sizeof(TxMessages));
525 }
526
527 /**
528  *******************************************************************************
529  *
530  * @fn    app_SanityTestTransmitter
531  * @brief transmitter of default test case (0).
532  *
533  * @param[h]  hWls - app thread WLS  handle
534  * @return    void
535  *
536  * @description
537  *    The routine is used in test case 0 (non-blocking sanity unit test)
538  * The transmitter does allocate multiple blocks of the same size from the ICC
539  * service. Then it fills each block with incremental counter and transfers
540  * to other application specified by parameter TxID.
541  *
542  * @references
543  * MS-111070-SP
544  *
545  * @ingroup icc_service_unit_test
546  *
547  ******************************************************************************/
548 static void app_SanityTestTransmitter(HANDLE hWls)
549 {
550     U8 *pMsg;
551     unsigned n = app_AllocMultiple(hWls, AppContext.TxMessages, AppContext.TxMessageSizes, AppContext.MsgPerMs);
552     unsigned fn = n;
553     unsigned cnt = 0;
554     unsigned k = 0;
555     unsigned alloc = n;
556
557     // lets transmit some message for test
558     while (n--) {
559         pMsg = AppContext.TxMessages[cnt++];
560         if (pMsg) {
561             U32 size = (rand() % AppContext.MaxMsgSize);
562
563             if (size < AppContext.MinMsgSize)
564                 size = AppContext.MinMsgSize;
565
566             memset(pMsg, cnt, size);
567             CreateMessage((PAPP_MESSAGE) pMsg, size);
568             if ((AppContext.wls_put(hWls, (U64) WlsVaToPa(pMsg), size, AppContext.TxID, 0) != 0)) {
569                 printf("could not send the message_%p\n", pMsg);
570                 break;
571             } else {
572                 k++;
573             }
574             AppContext.nTxOctets += size;
575             AppContext.nTxMsgs += 1;
576         }
577     }
578
579     if (alloc != k)
580         printf("inorrect sent %d alloc %d \n", k, alloc);
581
582     cnt = 0;
583     while (fn--) {
584         pMsg = AppContext.TxMessages[cnt++];
585         if (pMsg) {
586             if (App_Free(hWls, pMsg) != 0)
587                 printf("could not release the message_%p\n", pMsg);
588         } else
589             printf("pMsg is NULL [%d]\n", cnt);
590     }
591     if (cnt != k) {
592         printf("inorrect free sent %d free %d \nQuiting...\n", k, cnt);
593         AppContext.ExitStatus = 1;
594     }
595 }
596
597
598 /**
599  *******************************************************************************
600  *
601  * @fn    app_SanityTestReceiver
602  * @brief default sanity checking receiver used in multiple tests.
603  *
604  * @param[h]  hWls - app thread WLS  handle
605  * @return    void
606  *
607  * @description
608  *    The routine takes received messages and checks the sanity incremental
609  * counter to confirm the order. In case the counter does not correspond to
610  * expected counter (misordered message or incorrect message) an error is
611  * printed to STDOUT.
612  *
613  * @references
614  * MS-111070-SP
615  *
616  * @ingroup icc_service_unit_test
617  *
618  ******************************************************************************/
619 static void app_SanityTestReceiver(HANDLE hWls)
620 {
621     (void) hWls;
622     U32 MsgSize;
623     U8 *pMsg;
624     U8 *pMsgPa;
625     U8 *pMsgVa;
626     U8 TempBuf[16 * K];
627     unsigned short MsgTypeID;
628     unsigned short Flags;
629     U32 nBlocksSlave = 0;
630
631     // handle RX receiver
632     while (((pMsgPa = (U8 *) AppContext.wls_get(AppContext.hWls, &MsgSize, &MsgTypeID, &Flags)) != NULL)) {
633         pMsgVa = (U8 *) WlsPaToVa(pMsgPa);
634
635         if (pMsgVa == NULL) {
636             printf("va: %lx pa: %lx\n", (long) pMsgVa, (long) pMsgPa);
637             continue;
638         }
639
640         pMsg = pMsgVa;
641
642         if (((U64) pMsg & 0x3) == 0) {
643             // aligned message
644             CheckMessage((PAPP_MESSAGE) pMsg, MsgSize);
645         } else {
646             // misaligned message
647             printf("Unaligned message\n");
648             MsgSize = (MsgSize > sizeof (TempBuf)) ? sizeof (TempBuf) : MsgSize;
649             memcpy(TempBuf, pMsg, MsgSize);
650             // handle received message
651             CheckMessage((PAPP_MESSAGE) TempBuf, MsgSize);
652         }
653         App_Free(AppContext.hWls, pMsg);
654         AppContext.nRxOcters += MsgSize;
655         AppContext.nRxMsgs += 1;
656
657         if (AppContext.master) {
658             int res = TRUE;
659             /* allocate blocks for Slave to Master transmittion */
660             while (res) {
661                 void* pBlock = App_Alloc(AppContext.hWls, DEFAUTL_TEST_BLOCK_SIZE);
662                 if (pBlock) {
663                     res = WLS_EnqueueBlock(AppContext.hWls, (U64) WlsVaToPa(pBlock));
664                     if (res)
665                         nBlocksSlave++;
666                     else
667                         App_Free(AppContext.hWls, pBlock);
668                 } else
669                     res = FALSE;
670             }
671         }
672
673     }
674 }
675
676
677 /******************************************************************************
678  *                                                                             *
679  *                       Application common routines                           *
680  *                                                                             *
681  ******************************************************************************/
682
683 /**
684  *******************************************************************************
685  *
686  * @fn    app_UpdateStatistics
687  * @brief is used to update RX and TX statistics
688  *
689  * @param[n]  void
690  * @return    void
691  *
692  * @description
693  *    The routine prints out the statistics of received and transmitted
694  * messages.
695  *
696  * @references
697  * MS-111070-SP
698  *
699  * @ingroup icc_service_unit_test
700  *
701  ******************************************************************************/
702
703 static void app_UpdateStatistics(void)
704 {
705     AppContext.Cycles += 1;
706
707     if (AppContext.Debug || AppContext.Cycles % 1000 == 0) {
708         printf("Rx(id_%u) (%llu) - (%llu KiB)\n", AppContext.RxID, (long long) AppContext.nRxMsgs, (long long) AppContext.nRxOcters >> 10);
709         printf("Tx(id_%u) (%llu) - (%llu KiB)\n", AppContext.TxID, (long long) AppContext.nTxMsgs, (long long) AppContext.nTxOctets >> 10);
710     }
711
712 }
713
714 /**
715  *******************************************************************************
716  *
717  * @fn    app_Help
718  * @brief prints app help content
719  *
720  * @param[n]  void
721  * @return    void
722  *
723  * @description
724  *    The routine is used to print help content to stdout.
725  *
726  * @references
727  * MS-111070-SP
728  *
729  * @ingroup icc_service_unit_test
730  *
731  ******************************************************************************/
732 static void app_Help(void)
733 {
734     char help_content[] =  \
735                         "WLS test application\n\n"\
736                         "Usage: testapp [-c <test>] [-r <rxid>] [-t <txid>] [-n <msgcount>]\n\n"\
737                         "supports the following parameters:\n\n"
738                         "-c | --testcase <test number>     0 - default sanity test\n"\
739                         "                                  1 - misaligned pointers test\n"\
740                         "                                  2 - aligned 4 pointers test\n"\
741                         "                                  3 - random pools test\n"\
742                         "                                  4 - ping-pong (ZBC test)\n"\
743                         "                                  5 - invalid messages test\n\n"\
744                         "--trusted                    switches WLS  to trusted mode\n"\
745                         "-r | --rxid <id>             used to specify RxTypeID\n"\
746                         "-t | --txid <id>             used to specify TxTypeID\n"\
747                         "-n | --msgcount <count>      used to specify number of messages per timeframe\n"\
748                         "-l | --minsize  <size>       specifies MIN message size in bytes\n"\
749                         "-s | --maxsize  <size>       specifies MAX message size in bytes\n"\
750                         "--crc                        enables CRC generation and checking\n"\
751                         "--debug                      increases sleep interval to 1 second\n"\
752                         "-m | --master                set predefined rxid and txid\n";
753
754     printf("%s", help_content);
755 }
756
757 /**
758  *******************************************************************************
759  *
760  * @fn    app_ParseArgs
761  * @brief is used to parse incoming app args
762  *
763  * @param[i]  argc - app arg count
764  * @param[i]  argv - array of args
765  * @param[o]  params - app startup params filled basing on args parse
766  * @return    number of parsed args
767  *
768  * @description
769  *    The routine is parse input args and convert them into app startup params
770  *
771  * @references
772  * MS-111070-SP
773  *
774  * @ingroup icc_service_unit_test
775  *
776  ******************************************************************************/
777 static int app_ParseArgs(int argc, char ** argv, PAPP_PARAMS params)
778 {
779     int c;
780     int *pInt;
781     int cnt = 0;
782
783     struct option long_options[] = {
784         {"wlsdev", required_argument, 0, 'w'},
785         {"affinity", required_argument, 0, 'a'},
786         {"testcase", required_argument, 0, 'c'},
787         {"rxid", required_argument, 0, 'r'},
788         {"txid", required_argument, 0, 't'},
789         {"msgcount", required_argument, 0, 'n'},
790         {"maxsize", required_argument, 0, 's'},
791         {"minsize", required_argument, 0, 'l'},
792         {"master", no_argument, 0, 'm'},
793         {"debug", no_argument, 0, 'd'}, /* slow down the app cycle from 1ms to 1s*/
794         {"icount", required_argument, 0, 'i'},
795         {"crc", no_argument, 0, 1},
796         {"trusted", no_argument, 0, 2},
797         {"help", no_argument, 0, 'h'},
798         {0, 0, 0, 0}
799     };
800
801     memset(params, 0, sizeof (*params));
802
803     // set default values here
804     params->interface_count = 1;
805
806     while (1) {
807         //int this_option_optind = optind ? optind : 1;
808         int option_index = 0;
809
810         c = getopt_long(argc, argv, "a:w:c:r:t:n:s:l:mdi:h", long_options, &option_index);
811
812         if (c == -1)
813             break;
814
815         cnt += 1;
816         pInt = NULL;
817
818         switch (c) {
819             case 'a': // test Case selection
820                 pInt = &params->aff_core;
821                 break;
822             case 'c': // test Case selection
823                 pInt = &params->test_id;
824                 break;
825             case 'r': // rx id selection
826                 pInt = &params->rx_id;
827                 break;
828             case 't': // tx id selection
829                 pInt = &params->tx_id;
830                 break;
831             case 's': // select message size
832                 pInt = &params->max_size;
833                 break;
834             case 'l': // select message size
835                 pInt = &params->min_size;
836                 break;
837             case 'n': // select number of messages
838                 pInt = &params->n_messages;
839                 break;
840             case 'i': // select number of interfaces to register
841                 pInt = &params->interface_count;
842                 break;
843             case 'm':
844                 params->master = TRUE;
845                 break;
846             case 'd':
847                 params->debug = TRUE;
848                 break;
849             case 'w':
850                 params->wls_dev_name = optarg;
851                 break;
852             case 'h':
853                 app_Help();
854                 exit(0);
855             case 2:
856                 params->trusted = TRUE;
857                 break;
858             case 1: // crc checking enabled
859                 params->crc = TRUE;
860                 break;
861         }
862
863         if (pInt && optarg) {
864             // get int arg
865             if (optarg[0] == '0' && (optarg[1] == 'x' || optarg[1] == 'X')) {
866                 sscanf(optarg, "%x", (unsigned *) pInt);
867             } else {
868                 *pInt = atoi(optarg);
869             }
870         }
871     }
872     return cnt;
873 }
874
875 static int app_set_affinity(int coreNum)
876 {
877     cpu_set_t cpuset;
878     int i, rc;
879
880     /* set main thread affinity mask to CPU7 */
881
882     CPU_ZERO(&cpuset);
883     CPU_SET(coreNum, &cpuset);
884
885     rc = pthread_setaffinity_np(pthread_self(), sizeof (cpu_set_t), &cpuset);
886     if (rc) {
887         perror("pthread_setaffinity_np failed");
888         printf("pthread_setaffinity_np failed: %d", rc);
889     }
890
891     /* check the actual affinity mask assigned to the thread */
892
893     CPU_ZERO(&cpuset);
894
895     rc = pthread_getaffinity_np(pthread_self(), sizeof (cpu_set_t), &cpuset);
896
897     if (rc) {
898         perror("pthread_getaffinity_np failed");
899         printf("pthread_getaffinity_np failed: %d", rc);
900     }
901
902     printf("set affinity: ");
903     for (i = 0; i < CPU_SETSIZE; i++)
904         if (CPU_ISSET(i, &cpuset))
905             printf("    CPU %d\n", i);
906
907     if (!CPU_ISSET(coreNum, &cpuset)) {
908         printf("affinity failed");
909     }
910
911     /**
912        A new thread created by pthread_create(3) inherits a copy of its
913        creator's CPU affinity mask. */
914
915     return rc;
916 }
917
918 /**
919  *******************************************************************************
920  *
921  * @fn    app_ApplyParams
922  * @brief is used to apply application startup parameters
923  *
924  * @param[i]  params - app startup params
925  * @return    void
926  *
927  * @description
928  *    The applies startup parameters
929  *
930  * @references
931  * MS-111070-SP
932  *
933  * @ingroup icc_service_unit_test
934  *
935  ******************************************************************************/
936 static void app_ApplyParams(PAPP_PARAMS params)
937 {
938     // apply parameters
939     printf("selected test case %d - ", params->test_id);
940     switch (params->test_id) {
941         case APP_TC_SANITY_TEST:
942         default:
943             printf("NON-BLOCKING SANITY TEST\n");
944             AppContext.Receive = app_SanityTestReceiver;
945             AppContext.Transmit = app_SanityTestTransmitter;
946             break;
947     }
948
949     AppContext.wls_put = WLS_Put;
950     AppContext.wls_get = WLS_Get;
951     AppContext.wls_wget = WLS_WGet;
952
953     AppContext.MsgPerMs = DEFAULT_MESSAGE_COUNT_PER_MS;
954     AppContext.MaxMsgSize = DEFAULT_MAX_MESSAGE_SIZE;
955     AppContext.MinMsgSize = DEFUALT_MIN_MESSAGE_SIZE;
956     AppContext.AppSanityMsgSize = sizeof (APP_MESSAGE);
957
958     if (params->master) {
959         printf("WLS test app (supposed to run as MEMORY MASTER)\n");
960         AppContext.master = TRUE;
961         AppContext.RxID = 1;
962         AppContext.TxID = 2;
963     } else {
964         AppContext.master = FALSE;
965         AppContext.RxID = 2;
966         AppContext.TxID = 1;
967     }
968
969     if (params->rx_id)
970         AppContext.RxID = params->rx_id;
971
972     if (params->tx_id)
973         AppContext.TxID = params->tx_id;
974
975     if (params->n_messages && params->n_messages < MAX_MESSAGES)
976         AppContext.MsgPerMs = params->n_messages;
977
978     if (params->min_size && params->min_size >= 4)
979         AppContext.MinMsgSize = params->min_size;
980
981     // default is 1 RX interface
982     printf("if count = %u\n", params->interface_count);
983     AppContext.nInterfaces = 1;
984     if (params->interface_count == 0) {
985         printf("WLS test app started as simple data source, no RX ID will be specified\n");
986         AppContext.nInterfaces = 0;
987         AppContext.RxID = 0; // override RxID
988     } else if (params->interface_count <= 7) {
989         AppContext.nInterfaces = params->interface_count;
990     }
991
992
993     AppContext.TrustedDataSource = params->trusted;
994
995     if (params->crc) {
996         if (AppContext.MinMsgSize < 8)
997             AppContext.MinMsgSize = 8;
998
999         AppContext.wls_put = app_PutMessageCRC;
1000         AppContext.wls_get = app_GetMessageCRC;
1001         AppContext.wls_wget = app_WGetMessageCRC;
1002
1003         AppContext.AppSanityMsgSize += 4; // + sizeof CRC
1004     }
1005
1006     if (params->max_size && params->max_size <= 16 * K)
1007         AppContext.MaxMsgSize = params->max_size;
1008
1009     if (params->max_size < params->min_size)
1010         params->max_size = params->min_size;
1011
1012     AppContext.Debug = params->debug;
1013
1014     if (params->aff_core) {
1015         AppContext.core = params->aff_core;
1016         app_set_affinity(AppContext.core);
1017     }
1018
1019     printf("The application started with:\n");
1020     printf("Core ................ %d\n", AppContext.core);
1021     printf("Rx interface count .. %d\n", AppContext.nInterfaces);
1022     printf("RxID ................ %d\n", AppContext.RxID);
1023     printf("TxID ................ %d\n", AppContext.TxID);
1024     if (AppContext.Debug)
1025         printf("Generating .......... %lu Messages per second (DEBUG MODE)\n", (long) AppContext.MsgPerMs);
1026     else
1027         printf("Generating .......... %lu Messages per ms\n", (long) AppContext.MsgPerMs);
1028     printf("Max Message Size .... %lu bytes\n", (long) AppContext.MaxMsgSize);
1029     printf("Min Message Size .... %lu bytes\n", (long) AppContext.MinMsgSize);
1030     printf("Number of threads ... 1\n");
1031     printf("CRC checking ........ ");
1032     if (params->crc)
1033         printf("ENABLED\n");
1034     else
1035         printf("DISABLED\n");
1036 }
1037
1038 /**
1039  *******************************************************************************
1040  *
1041  * @fn    app_ReleaseAllocatedBuffers
1042  * @brief releases ICC buffers allocated by the application
1043  *
1044  * @param[n]  void
1045  * @return    void
1046  *
1047  * @description
1048  *    In process of making some tests when signal to close the application
1049  * happens the app may keep some allocated buffers from the ICC pools. This
1050  * routine does release these buffers back to ICC.
1051  *
1052  * @references
1053  * MS-111070-SP
1054  *
1055  * @ingroup icc_service_unit_test
1056  *
1057  ******************************************************************************/
1058 static void app_ReleaseAllocatedBuffers(void)
1059 {
1060     if (AppContext.TxMsgCnt && AppContext.master)
1061         do {
1062             AppContext.TxMsgCnt -= 1;
1063             App_Free(AppContext.hWls, AppContext.TxMessages[ AppContext.TxMsgCnt ]);
1064         } while (AppContext.TxMsgCnt != 0);
1065 }
1066
1067 /**
1068  *******************************************************************************
1069  *
1070  * @fn    main
1071  * @brief ICC test application main routine
1072  *
1073  * @param[n]  void
1074  * @return    void
1075  *
1076  * @description
1077  *    Contains logic of the test (one RX/TX thread)
1078  *
1079  * @references
1080  * MS-111070-SP
1081  *
1082  * @ingroup icc_service_unit_test
1083  *
1084  ****************************************************************************/
1085 int main(int argc, char* argv[])
1086 {
1087     int retval = 0;
1088     APP_PARAMS params;
1089     uint64_t nWlsMacMemorySize = DEFAULT_TEST_MEMORY_SIZE, nWlsPhyMemorySize = 0;
1090     uint32_t nLoop = 30000;
1091     uint32_t nNumBlks = 0;
1092
1093     signal(SIGINT, App_SigExitCallback);
1094
1095     memset(&AppContext, 0, sizeof (AppContext));
1096     memset(&params, 0, sizeof (params));
1097
1098     nCRC_Fail = 0;
1099     nCRC_Pass = 0;
1100
1101     int ret = rte_eal_init(argc, argv);
1102     if (ret < 0)
1103         rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
1104
1105     argc -= ret;
1106     argv += ret;
1107
1108     app_ParseArgs(argc, argv, &params);
1109     app_ApplyParams(&params);
1110
1111     AppContext.InitQueueSize = APP_QUEUE_SIZE;
1112
1113     AppContext.hWls = WLS_Open(params.wls_dev_name, !AppContext.master, &nWlsMacMemorySize, &nWlsPhyMemorySize);
1114
1115     if (!AppContext.hWls) {
1116         printf("could not register WLS client\n");
1117         return 1;
1118     } else {
1119         printf("WLS has been registered\n");
1120     }
1121
1122     WLS_SetMode(AppContext.hWls, AppContext.master);
1123     AppContext.shm_memory = WLS_Alloc(AppContext.hWls, DEFAULT_TEST_MEMORY_SIZE);
1124
1125     if (AppContext.shm_memory == NULL) {
1126         if (AppContext.master)
1127             printf("could not create WLS shared memory\n");
1128         else
1129             printf("could not attach WLS shared memory\n");
1130
1131         return -1;
1132     }
1133
1134     if (AppContext.master) {
1135         if (App_MemoryInit(AppContext.shm_memory, DEFAULT_TEST_MEMORY_SIZE, DEFAUTL_TEST_BLOCK_SIZE) != 0) {
1136             WLS_Free(AppContext.hWls, AppContext.shm_memory);
1137             WLS_Close(AppContext.hWls);
1138             exit(1);
1139         }
1140
1141     }
1142
1143     ret = WLS_Ready(AppContext.hWls);
1144     if (ret) {
1145         printf("wls not ready\n");
1146         return -1;
1147     }
1148
1149     nNumBlks = WLS_Check(AppContext.hWls);
1150     printf("There are %d blocks in queue from WLS_Check\n", nNumBlks);
1151
1152     nNumBlks = WLS_NumBlocks(AppContext.hWls);
1153     printf("There are %d blocks in queue from WLS_NumBlocks\n", nNumBlks);
1154
1155     // APPLICATION MAIN LOOP
1156     while (!AppContext.ExitStatus && (AppContext.Receive || AppContext.Transmit) && nLoop) {
1157         if (AppContext.Receive)
1158             AppContext.Receive(AppContext.hWls);
1159
1160         if (AppContext.Debug)
1161             //usleep(10000); // 1 sec delay
1162             sleep(1); // 1 sec delay
1163         else
1164             usleep(1000); // 1 ms delay
1165
1166         if (AppContext.Transmit)
1167             AppContext.Transmit(AppContext.hWls);
1168
1169         app_UpdateStatistics();
1170         nLoop--;
1171     }
1172
1173     app_ReleaseAllocatedBuffers();
1174     printf("deregistering WLS  (TxTotal_%lld, RxTotal_%lld)\n", (long long) AppContext.nTxMsgs, (long long) AppContext.nRxMsgs);
1175     if (params.crc)
1176     {
1177         printf("Number of CRC Pass %d\n", nCRC_Pass);
1178         printf("Number of CRC Fail %d\n", nCRC_Fail);
1179         printf("Total Message sent: %d\n", (nCRC_Pass + nCRC_Fail));
1180     }
1181     WLS_Free(AppContext.hWls, AppContext.shm_memory);
1182     WLS_Close(AppContext.hWls);
1183     return retval;
1184 }