FAPI TM, WLS_LIB and ODULOW documentation
* Additional ODU-Low components for Bronze Rel
* 5G Fapi Translator Module
* Wireless Services library based on DPDK
* Full ODULOW Documentation set
Issue-Id: ODULOW-2
Change-Id: I3d0df696286ad50798ccd0765f809fb04629b660
Signed-off-by: Luis Farias <luis.farias@intel.com>
diff --git a/wls_lib/Makefile b/wls_lib/Makefile
new file mode 100644
index 0000000..865c618
--- /dev/null
+++ b/wls_lib/Makefile
@@ -0,0 +1,69 @@
+###############################################################################
+#
+# Copyright (c) 2019 Intel.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###############################################################################
+
+ifdef DPDK_WLS
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+# Default target, can be overridden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-icc
+RTE_OUTPUT = ${PWD}
+
+include $(RTE_SDK)/mk/rte.vars.mk
+SRCS-y := wls_lib_dpdk.c syslib.c
+SHARED = libwls.so
+#CFLAGS +=-Wall -wd9 -DDPDK_WLS
+CFLAGS +=-Wall -DDPDK_WLS -fstack-protector
+EXTRA_CFLAGS +=-g
+include $(RTE_SDK)/mk/rte.extshared.mk
+
+else
+
+obj-m := wls.o
+wls-objs :=syslib.o \
+ wls_drv.o
+
+INSTALL_MOD_DIR ?=/lib/modules/`uname -r`/updates/drivers/intel/wls
+cmd_depmod = /sbin/depmod -a
+EXTRA_CFLAGS +=-g -Wall
+SRC := $(shell pwd)
+
+all:
+ $(MAKE) -C $(KERNEL_SRC) $(EXTRA_CFLAGS) M=$(SRC)
+
+modules_install:
+ $(MAKE) -C $(KERNEL_SRC) $(EXTRA_CFLAGS) M=$(SRC) modules_install
+
+wls_lib.o: wls_lib.c
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -D_GNU_SOURCE -g -fPIC -o $@ -c $<
+
+syslib_user.o: syslib.c
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -g -fPIC -o $@ -c $<
+
+libwls.so: wls_lib.o syslib_user.o
+ $(CC) $(LDFLAGS) -g -shared -fPIC -Wl,-soname,libwls.so -o $@ wls_lib.o syslib_user.o
+
+install:
+ [ -d "${INSTALL_MOD_DIR}" ] || mkdir -p ${INSTALL_MOD_DIR}
+ cp ./wls.ko ${INSTALL_MOD_DIR}
+ $(call cmd_depmod)
+clean:
+ rm -f *.o *~ core .depend .*.cmd *.ko *.so *.mod.c
+ rm -f Module.markers Module.symvers modules.order
+ rm -rf .tmp_versions Modules.symvers
+endif
diff --git a/wls_lib/build.sh b/wls_lib/build.sh
new file mode 100644
index 0000000..30a0c2a
--- /dev/null
+++ b/wls_lib/build.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+###############################################################################
+#
+# Copyright (c) 2019 Intel.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###############################################################################
+#
+# File: build.sh
+# Build script to comapile kernel module, library and test application.
+#
+
+#if [ "$1" = "dpdk_wls" ]; then
+ echo "Building dpdk based wls library"
+ make DPDK_WLS=1 ${*:2}
+ cd testapp
+ make DPDK_WLS=1 ${*:2}
+#else
+# echo "Building driver based wls library"
+# make -C /lib/modules/`uname -r`/build M=$PWD $*
+# make libwls.so $*
+# cd testapp
+# make $*
+#fi
diff --git a/wls_lib/syslib.c b/wls_lib/syslib.c
new file mode 100644
index 0000000..3bedeed
--- /dev/null
+++ b/wls_lib/syslib.c
@@ -0,0 +1,408 @@
+/******************************************************************************
+*
+* Copyright (c) 2019 Intel.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*******************************************************************************/
+#ifdef __KERNEL__
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#else
+#include <stdio.h>
+#include <string.h>
+#endif
+#include "syslib.h"
+#include "wls.h"
+
+#ifdef __KERNEL__
+#ifdef _DEBUG_
+#define PRINT_DEBUG(format, args...) \
+do { \
+ printk(KERN_INFO "wls debug: " format,##args); \
+}while(0)
+#else
+#define PRINT_DEBUG(x, args...) do { } while(0)
+#endif
+#else
+#ifdef _DEBUG_
+#define PRINT_DEBUG(x, args...) printf("wls_lib debug: "x, ## args);
+#else
+#define PRINT_DEBUG(x, args...) do { } while(0)
+#endif
+#endif
+
+
+
+#define SFL_memcpy memcpy
+/******************************************************************************
+* *
+* Generic fast queue that operates with pointers (derived from ICC) *
+* *
+******************************************************************************/
+
+int SFL_WlsEnqueue(PFASTQUEUE pq, U64 pData, wls_us_addr_conv change_addr, void* hWls)
+{
+ U32 put = pq->put;
+ U32 new_put = put + 1;
+
+ PRINT_DEBUG("off %lx put %d get %d size %d storage %lx\n",(unsigned long)pq - (unsigned long) hWls, pq->put, pq->get, pq->size, pq->pStorage);
+
+ if (new_put >= pq->size)
+ new_put = 0;
+
+ if (new_put != pq->get)
+ { // the queue is not full
+
+ U64* pLocalStorage = (U64*) pq->pStorage; // kernel VA
+ if (change_addr)
+ pLocalStorage = (U64*)change_addr(hWls, (U64)pq->pStorage); // user VA
+
+ PRINT_DEBUG("pLocalStorage %lx\n", (U64)pLocalStorage);
+
+ pLocalStorage[put] = pData;
+
+ DSB();
+ pq->put = new_put;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+U64 SFL_WlsDequeue(PFASTQUEUE pq,
+ wls_us_addr_conv change_addr,
+ void *hWls)
+{
+ U64 p;
+ U32 get = pq->get;
+
+ if ((pq->put - get) != 0)
+ {
+ U64* pLocalStorage = (U64*) pq->pStorage; // kernel VA
+
+ DSB();
+ if (change_addr)
+ pLocalStorage = (U64 *)change_addr(hWls, (U64)pLocalStorage); //convert to user VA
+
+ p = pLocalStorage[get++];
+ if (get >= pq->size)
+ get = 0;
+
+ pq->get = get;
+ return p;
+ }
+ return 0;
+}
+
+/*
+int SFL_Enqueue_NoSync(PFASTQUEUE pq, PVOID pData)
+{
+ U32 put = pq->put;
+ U32 new_put = put + 1;
+ if (new_put >= pq->size)
+ new_put = 0;
+
+ if (new_put != pq->get)
+ { // the queue is not full
+ pq->pStorage[ put ] = pData;
+ pq->put = new_put;
+ return TRUE;
+ }
+ return FALSE;
+}*/
+
+/*
+PVOID SFL_Dequeue_NoSync(PFASTQUEUE pq)
+{
+ PVOID p;
+ U32 get = pq->get;
+
+ if ((pq->put - get) != 0)
+ {
+ p = pq->pStorage[get++];
+ if (get >= pq->size)
+ get = 0;
+ pq->get = get;
+ return p;
+ }
+ return NULL;
+}*/
+
+void SFL_DefQueue(PFASTQUEUE pq, void *pStorage, int StorageSize)
+{
+ memset( (void*) pq, 0x00, sizeof( FASTQUEUE) );
+ // always define storage as U64 []
+ pq->size = StorageSize >> 3;
+ pq->pStorage = (U64)pStorage;
+
+ PRINT_DEBUG("put %d get %d size %d pq->pStorage %lx\n",pq->put, pq->get, pq->size, pq->pStorage);
+
+}
+
+static U32 sfl_SafeQueueLevel(U32 put, U32 get, U32 size)
+{
+ U32 nItems;
+
+ if (put >= get)
+ nItems = put - get;
+ else
+ nItems = size + put - get;
+
+ return nItems;
+}
+
+U32 WLS_GetNumItemsInTheQueue(PWLS_MSG_QUEUE fpq)
+{
+ return sfl_SafeQueueLevel(fpq->put, fpq->get, fpq->size);
+}
+
+U32 SFL_GetNumItemsInTheQueue(FASTQUEUE *fpq)
+{
+ return sfl_SafeQueueLevel(fpq->put, fpq->get, fpq->size);
+}
+
+/*
+
+U32 SFL_Queue_BatchRead( PFASTQUEUE pq, unsigned long *pDestArr, U32 Count)
+{
+ if (Count)
+ {
+ U32 write_index = 0;
+ U32 nReads = 0;
+ //U32 iMask = SFL_IDisable();
+ U32 put = pq->put; // fetch the put atomicly (as app may change it!)
+ U32 get = pq->get; // cache the volatile "get index"
+
+ //printf("nItems_%d ", SFL_GetNumItemsInTheQueue(pq));
+
+ if ( (nReads = sfl_SafeQueueLevel(put, get, pq->size)) < Count )
+ Count = nReads;
+ else
+ nReads = Count;
+
+ if (Count >= pq->size - get)
+ {
+ U32 n = pq->size - get;
+ SFL_memcpy( pDestArr, &pq->pStorage[get], sizeof(pDestArr[0]) * n);
+ get = 0;
+ Count -= n;
+ write_index += n;
+ }
+
+ if (Count)
+ {
+ SFL_memcpy( &pDestArr[write_index], &pq->pStorage[get], sizeof(pDestArr[0]) * Count);
+ get += Count;
+ }
+
+ DSB();
+ pq->get = get;
+
+ //printf("nItems_%d ", SFL_GetNumItemsInTheQueue(pq));
+
+ //SFL_IControl(iMask);
+
+ return nReads;
+ }
+ return FALSE;
+}
+
+
+// the routine does not keep the fifo order (it is used to take items away from the queue)
+U32 SFL_Queue_BatchUnload(PFASTQUEUE pq, unsigned long* pDestArr, U32 Count)
+{
+ if (Count)
+ {
+ U32 write_index = 0;
+ U32 nReads = 0;
+ //U32 iMask = SFL_IDisable();
+ U32 put = pq->put; // lets cache the volatile "put index"
+ U32 get = pq->get; // fetch the get index atomicly (as app may change it)
+
+ //printf("nItems_%d ", SFL_GetNumItemsInTheQueue(pq));
+
+ nReads = sfl_SafeQueueLevel(put, get, pq->size);
+ if (nReads)
+ nReads -= 1; // decrement is used to cover the case when a reader already started reading from head
+
+ if ( nReads < Count )
+ Count = nReads;
+ else
+ nReads = Count;
+
+ if (!put)
+ put = pq->size;
+
+ if (Count >= put)
+ {
+ U32 n = put;
+ SFL_memcpy( pDestArr, &pq->pStorage[0], sizeof(pDestArr[0]) * n);
+ put = pq->size;
+ Count -= n;
+ write_index += n;
+ }
+
+ if (Count)
+ {
+ put -= Count;
+ SFL_memcpy( &pDestArr[write_index], &pq->pStorage[put], sizeof(pDestArr[0]) * Count);
+ }
+
+ if (put >= pq->size)
+ put = 0;
+
+ DSB();
+ pq->put = put;
+
+ //printf("nItems_%d ", SFL_GetNumItemsInTheQueue(pq));
+
+ //SFL_IControl(iMask);
+
+ return nReads;
+ }
+ return FALSE;
+}
+
+
+U32 SFL_Queue_BatchWrite( PFASTQUEUE pq, unsigned long *pSrcArr, U32 Count)
+{
+
+ U32 nWrites = Count;
+
+ if (Count)
+ {
+ U32 read_index = 0;
+ U32 put = pq->put;
+ //U32 iMask = SFL_IDisable();
+
+ if (pq->size - put <= Count)
+ {
+ U32 n = pq->size - put;
+ SFL_memcpy( &pq->pStorage[put], pSrcArr, sizeof(pSrcArr[0]) * n);
+ put = 0;
+ Count -= n;
+ read_index += n;
+ }
+
+ if (Count)
+ {
+ SFL_memcpy( &pq->pStorage[put], &pSrcArr[read_index], sizeof(pSrcArr[0]) * Count);
+ put += Count;
+ }
+
+ DSB();
+ pq->put = put;
+
+ //SFL_IControl(iMask);
+ return nWrites;
+ }
+ return 0;
+}
+*/
+void WLS_MsgDefineQueue(
+ PWLS_MSG_QUEUE pq,
+ PWLS_MSG_HANDLE pStorage,
+ U32 size,
+ U32 sema)
+{
+ memset( pq, 0x00, sizeof(WLS_MSG_QUEUE));
+ pq->pStorage = (U64) pStorage;
+ pq->get = 0;
+ pq->put = 0;
+ pq->size = size; // number of items
+ pq->sema = sema;
+}
+
+U32 WLS_MsgEnqueue(
+ PWLS_MSG_QUEUE pq,
+ U64 pIaPaMsg,
+ U32 MsgSize,
+ U16 TypeID,
+ U16 flags,
+ wls_us_addr_conv change_addr,
+ void *hWls)
+{
+ U32 rc = 0;
+ // below is protected section.
+ U32 put = pq->put;
+ U32 put_new = put + 1;
+
+ if (put_new >= pq->size)
+ put_new = 0;
+
+ if (put_new != pq->get)
+ {
+ PWLS_MSG_HANDLE pLocalStorage = (PWLS_MSG_HANDLE)pq->pStorage; // kernel VA
+ PWLS_MSG_HANDLE pItem;
+
+ PRINT_DEBUG("Kernel VA pq->pStorage %lx put [%d] %d %d\n", pq->pStorage, put_new, pq->get, pq->size);
+
+ if (change_addr)
+ pLocalStorage = (PWLS_MSG_HANDLE)change_addr(hWls, (U64)pq->pStorage);
+
+ pItem = &pLocalStorage[put];
+
+ pItem->pIaPaMsg = pIaPaMsg;
+ pItem->MsgSize = MsgSize;
+ pItem->TypeID = TypeID;
+ pItem->flags = flags;
+ DSB();
+ pq->put = put_new;
+ rc = 1;
+ }
+
+ return rc;
+}
+
+int WLS_MsgDequeue(
+ PWLS_MSG_QUEUE pq,
+ PWLS_MSG_HANDLE pDestItem,
+ wls_us_addr_conv change_addr,
+ void *hWls)
+{
+ int retval = FALSE;
+ U32 get = pq->get;
+ PWLS_MSG_HANDLE pLocalStorage;
+
+ if (!pDestItem)
+ return retval;
+
+ if (get >= pq->size)
+ {
+
+ PRINT_DEBUG("error WLS_MsgDequeue get %d size %d\n", get, pq->size);
+
+ return retval;
+ }
+
+ pLocalStorage = (PWLS_MSG_HANDLE) pq->pStorage; // kernel VA
+ PRINT_DEBUG("WLS_MsgDequeue with pq->pStorage %lX\n",pq->pStorage);
+ if (pq->put != get)
+ {
+
+ DSB();
+ if (change_addr)
+ pLocalStorage = (PWLS_MSG_HANDLE)change_addr(hWls, (U64) pq->pStorage); //convert to user VA
+
+ *pDestItem = pLocalStorage[get];
+
+ if (++get == pq->size)
+ get = 0;
+
+ pq->get = get;
+ retval = TRUE;
+ }
+
+ return retval;
+}
diff --git a/wls_lib/syslib.h b/wls_lib/syslib.h
new file mode 100644
index 0000000..1b52470
--- /dev/null
+++ b/wls_lib/syslib.h
@@ -0,0 +1,131 @@
+/******************************************************************************
+*
+* Copyright (c) 2019 Intel.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*******************************************************************************/
+
+#ifndef __SYSLIB_H__
+#define __SYSLIB_H__
+
+typedef unsigned char U8; /* unsigned 8-bit integer */
+typedef unsigned short U16; /* unsigned 16-bit integer */
+typedef unsigned int U32; /* unsigned 32-bit integer */
+#ifdef __x86_64__
+typedef unsigned long U64; /* unsigned 64-bit integer */
+#else
+typedef unsigned long long U64; /* unsigned 64-bit integer */
+#endif
+
+typedef volatile unsigned char V8;
+typedef volatile unsigned short V16;
+typedef volatile unsigned int V32;
+typedef volatile unsigned long V4;
+
+typedef signed char S8; /* 8-bit signed integer */
+typedef signed short S16; /* 16-bit signed integer */
+typedef signed int S32; /* 32-bit signed integer */
+
+#ifdef __x86_64__
+typedef signed long S64; /* unsigned 64-bit integer */
+#else
+typedef signed long long S64; /* unsigned 64-bit integer */
+#endif
+
+#ifndef _PVOID_
+#define _PVOID_
+typedef void *PVOID;
+#endif
+
+typedef U64 (*wls_us_addr_conv)(void*, U64);
+
+
+#define K 1024
+#define M (K*K)
+#define KHZ 1000
+#define MHZ (KHZ * KHZ)
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+#ifndef NULL
+#define NULL ((PVOID)(0))
+#endif
+#define HANDLE PVOID
+
+#ifdef __KERNEL__
+#define DSB() smp_mb()
+#define DMB() smp_wmb()
+#else
+#define DSB() __asm__ __volatile__("mfence": : :"memory")
+#define DMB() __asm__ __volatile__("sfence": : :"memory")
+#endif
+
+typedef struct tagWLS_MSG_HANDLE
+{
+ U64 pIaPaMsg;
+ U32 pWlsPaMsg;
+ U32 MsgSize;
+ U16 TypeID; // used to identify destination
+ U16 flags;
+ U32 res1;
+} WLS_MSG_HANDLE, *PWLS_MSG_HANDLE; /* 4 x QW */
+
+typedef struct tagFASTQUEUE {
+ U64 pStorage;
+ U32 BlockSize;
+ U32 sema;
+ V32 get;
+ V32 put;
+ U32 size;
+ U32 res;
+} FASTQUEUE, *PFASTQUEUE;
+
+typedef struct tagWLS_MSG_QUEUE {
+ U64 pStorage;
+ U32 sema;
+ V32 get;
+ V32 put;
+ U32 size;
+} WLS_MSG_QUEUE, *PWLS_MSG_QUEUE;
+
+#define COUNT(some_array) ( sizeof(some_array)/sizeof((some_array)[0]) )
+
+void SFL_DefQueue(PFASTQUEUE pq, void *pStorage, int StorageSize);
+int SFL_WlsEnqueue(PFASTQUEUE pq, U64 pData, wls_us_addr_conv change_addr, void* hWls);
+int SFL_Enqueue_NoSync(PFASTQUEUE pq, PVOID pData);
+U64 SFL_WlsDequeue(PFASTQUEUE pq, wls_us_addr_conv change_addr, void *hWls);
+
+PVOID SFL_Dequeue_NoSync(PFASTQUEUE pq);
+U32 SFL_Queue_BatchRead( PFASTQUEUE pq, unsigned long *pDestArr, U32 Count);
+U32 SFL_Queue_BatchWrite( PFASTQUEUE pq, unsigned long *pSrcArr, U32 Count);
+
+void WLS_MsgDefineQueue(PWLS_MSG_QUEUE pq, PWLS_MSG_HANDLE pStorage, U32 size, U32 sema);
+U32 WLS_MsgEnqueue(PWLS_MSG_QUEUE pq, U64 pIaPaMsg, U32 MsgSize, U16 TypeID, U16 flags, wls_us_addr_conv change_addr, void* h);
+int WLS_MsgDequeue(PWLS_MSG_QUEUE pq, PWLS_MSG_HANDLE pDestItem, wls_us_addr_conv change_addr, void *hWls);
+U32 WLS_GetNumItemsInTheQueue(PWLS_MSG_QUEUE fpq);
+U32 SFL_GetNumItemsInTheQueue(FASTQUEUE *fpq);
+
+
+
+
+
+#endif // __SYSLIB_H__
+
+
diff --git a/wls_lib/test/bin/fapi/fapi.sh b/wls_lib/test/bin/fapi/fapi.sh
new file mode 100644
index 0000000..d5a72fa
--- /dev/null
+++ b/wls_lib/test/bin/fapi/fapi.sh
@@ -0,0 +1,30 @@
+#######################################################################
+#
+# <COPYRIGHT_TAG>
+#
+#######################################################################
+export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$DIR_WIRELESS_WLS
+
+MACHINE_TYPE=`uname -m`
+
+if [ ${MACHINE_TYPE} == 'x86_64' ]; then
+
+ ulimit -c unlimited
+ echo 1 > /proc/sys/kernel/core_uses_pid
+
+ sysctl -w kernel.sched_rt_runtime_us=-1
+ sysctl -w kernel.shmmax=2147483648
+ sysctl -w kernel.shmall=2147483648
+ chkconfig --level 12345 irqbalance off
+ echo 0 > /proc/sys/kernel/nmi_watchdog
+ echo 1 > /sys/module/rcupdate/parameters/rcu_cpu_stall_suppress
+
+fi
+
+echo start WLS PHY Process
+if [ "$1" = "-g" ]; then
+ shift
+ taskset -c 16 gdb-ia --args ./fapi_app $@
+else
+ taskset -c 16 ./fapi_app $@
+fi
diff --git a/wls_lib/test/bin/mac/mac.sh b/wls_lib/test/bin/mac/mac.sh
new file mode 100644
index 0000000..9b0b4e4
--- /dev/null
+++ b/wls_lib/test/bin/mac/mac.sh
@@ -0,0 +1,31 @@
+#######################################################################
+#
+# <COPYRIGHT_TAG>
+#
+#######################################################################
+export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$DIR_WIRELESS_WLS
+
+MACHINE_TYPE=`uname -m`
+
+if [ ${MACHINE_TYPE} == 'x86_64' ]; then
+
+ ulimit -c unlimited
+ echo 1 > /proc/sys/kernel/core_uses_pid
+
+ sysctl -w kernel.sched_rt_runtime_us=-1
+ sysctl -w kernel.shmmax=2147483648
+ sysctl -w kernel.shmall=2147483648
+ chkconfig --level 12345 irqbalance off
+ echo 0 > /proc/sys/kernel/nmi_watchdog
+ echo 1 > /sys/module/rcupdate/parameters/rcu_cpu_stall_suppress
+
+fi
+
+echo start WLS PHY Process
+if [ "$1" = "-g" ]; then
+ shift
+ taskset -c 17 gdb-ia --args ./mac_app $@
+else
+ taskset -c 17 ./mac_app $@
+fi
+
diff --git a/wls_lib/test/bin/phy/phy.sh b/wls_lib/test/bin/phy/phy.sh
new file mode 100644
index 0000000..41c1ea8
--- /dev/null
+++ b/wls_lib/test/bin/phy/phy.sh
@@ -0,0 +1,30 @@
+#######################################################################
+#
+# <COPYRIGHT_TAG>
+#
+#######################################################################
+export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$DIR_WIRELESS_WLS
+
+MACHINE_TYPE=`uname -m`
+
+if [ ${MACHINE_TYPE} == 'x86_64' ]; then
+
+ ulimit -c unlimited
+ echo 1 > /proc/sys/kernel/core_uses_pid
+
+ sysctl -w kernel.sched_rt_runtime_us=-1
+ sysctl -w kernel.shmmax=2147483648
+ sysctl -w kernel.shmall=2147483648
+ chkconfig --level 12345 irqbalance off
+ echo 0 > /proc/sys/kernel/nmi_watchdog
+ echo 1 > /sys/module/rcupdate/parameters/rcu_cpu_stall_suppress
+
+fi
+
+echo start WLS PHY Process
+if [ "$1" = "-g" ]; then
+ shift
+ taskset -c 15 gdb-ia --args ./phy_app $@
+else
+ taskset -c 15 ./phy_app $@
+fi
diff --git a/wls_lib/test/build.sh b/wls_lib/test/build.sh
new file mode 100644
index 0000000..2f4e455
--- /dev/null
+++ b/wls_lib/test/build.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+###############################################################################
+#
+# Copyright (c) 2019 Intel.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###############################################################################
+
+make -C ./mac --no-print-directory -f ./makefile $* PLATFORM=X86_64BIT
+make -C ./fapi --no-print-directory -f ./makefile $* PLATFORM=X86_64BIT
+make -C ./phy --no-print-directory -f ./makefile $* PLATFORM=X86_64BIT
diff --git a/wls_lib/test/build/fapi/dep_file b/wls_lib/test/build/fapi/dep_file
new file mode 100644
index 0000000..d72bb47
--- /dev/null
+++ b/wls_lib/test/build/fapi/dep_file
@@ -0,0 +1,27 @@
+../build/fapi//home/Luis/Integration/oran_wls_lib/test/fapi/fapi_main.o: \
+ /home/Luis/Integration/oran_wls_lib/test/fapi/fapi_main.c \
+ /usr/include/stdc-predef.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_eal.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_config.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_compat.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_common.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_per_lcore.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_bus.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_log.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_dev.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_pci_dev_feature_defs.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_cfgfile.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_string_fns.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_lcore.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_launch.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_debug.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_branch_prediction.h \
+ /home/Luis/Integration/oran_wls_lib/wls.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_atomic.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/generic/rte_atomic.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_atomic_64.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_memzone.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_memory.h \
+ /home/Luis/Integration/oran_wls_lib/ttypes.h \
+ /home/Luis/Integration/oran_wls_lib/syslib.h \
+ /home/Luis/Integration/oran_wls_lib/wls_lib.h
diff --git a/wls_lib/test/build/mac/dep_file b/wls_lib/test/build/mac/dep_file
new file mode 100644
index 0000000..31f7627
--- /dev/null
+++ b/wls_lib/test/build/mac/dep_file
@@ -0,0 +1,34 @@
+../build/mac//home/Luis/Integration/oran_wls_lib/test/mac/mac_main.o: \
+ /home/Luis/Integration/oran_wls_lib/test/mac/mac_main.c \
+ /usr/include/stdc-predef.h /home/Luis/Integration/oran_wls_lib/wls_lib.h \
+ /home/Luis/Integration/oran_wls_lib/test/mac/mac_wls.h \
+ /home/Luis/Integration/oran_5g_fapi/include/fapi_interface.h
+../build/mac//home/Luis/Integration/oran_wls_lib/test/mac/mac_wls.o: \
+ /home/Luis/Integration/oran_wls_lib/test/mac/mac_wls.c \
+ /usr/include/stdc-predef.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_eal.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_config.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_compat.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_common.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_per_lcore.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_bus.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_log.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_dev.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_pci_dev_feature_defs.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_cfgfile.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_string_fns.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_lcore.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_launch.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_debug.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_branch_prediction.h \
+ /home/Luis/Integration/oran_wls_lib/wls.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_atomic.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/generic/rte_atomic.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_atomic_64.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_memzone.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_memory.h \
+ /home/Luis/Integration/oran_wls_lib/ttypes.h \
+ /home/Luis/Integration/oran_wls_lib/syslib.h \
+ /home/Luis/Integration/oran_wls_lib/wls_lib.h \
+ /home/Luis/Integration/oran_wls_lib/test/mac/mac_wls.h \
+ /home/Luis/Integration/oran_5g_fapi/include/fapi_interface.h
diff --git a/wls_lib/test/build/phy/dep_file b/wls_lib/test/build/phy/dep_file
new file mode 100644
index 0000000..7a11259
--- /dev/null
+++ b/wls_lib/test/build/phy/dep_file
@@ -0,0 +1,19 @@
+../build/phy//home/Luis/Integration/oran_wls_lib/test/phy/phy_main.o: \
+ /home/Luis/Integration/oran_wls_lib/test/phy/phy_main.c \
+ /usr/include/stdc-predef.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_eal.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_config.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_compat.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_common.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_per_lcore.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_bus.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_log.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_dev.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_pci_dev_feature_defs.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_cfgfile.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_string_fns.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_lcore.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_launch.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_debug.h \
+ /home/samuelwo/dpdk-18.08/x86_64-native-linuxapp-icc/include/rte_branch_prediction.h \
+ /home/Luis/Integration/oran_wls_lib/wls_lib.h
diff --git a/wls_lib/test/fapi/fapi_main.c b/wls_lib/test/fapi/fapi_main.c
new file mode 100644
index 0000000..7c1a14a
--- /dev/null
+++ b/wls_lib/test/fapi/fapi_main.c
@@ -0,0 +1,649 @@
+/******************************************************************************
+*
+* Copyright (c) 2019 Intel.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*******************************************************************************/
+
+/**
+ * @brief This file is test FAPI wls lib main process
+ * @file fapi_main.c
+ * @ingroup group_testfapiwls
+ * @author Intel Corporation
+ **/
+
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <rte_eal.h>
+#include <rte_cfgfile.h>
+#include <rte_string_fns.h>
+#include <rte_common.h>
+#include <rte_string_fns.h>
+#include <rte_lcore.h>
+#include <rte_debug.h>
+#include <rte_launch.h>
+
+#define DPDK_WLS
+#include "wls.h"
+#include "wls_lib.h"
+
+#define NR5G_FAPI2PHY_WLS_INST 0
+#define NR5G_FAPI2MAC_WLS_INST 1
+#define SUCCESS 0
+#define FAILURE 1
+#define WLS_TEST_DEV_NAME "wls"
+#define WLS_TEST_MSG_ID 1
+#define WLS_TEST_MSG_SIZE 100
+#define WLS_TEST_MEM_SIZE 2126512128
+#define ALLOC_TRACK_SIZE 16384
+#define MIN_UL_BUF_LOCATIONS 50
+#define MIN_DL_BUF_LOCATIONS 50
+#define MAX_UL_BUF_LOCATIONS 50
+#define MAX_DL_BUF_LOCATIONS 50
+#define NUM_WLS_INSTANCES 2
+#define WLS_HUGE_DEF_PAGE_SIZEA 0x40000000LL
+#define MSG_MAXSIZE1 (16*16384)
+#define NUM_TEST_MSGS 16
+
+
+
+
+typedef void* WLS_HANDLE;
+typedef struct wls_fapi_mem_array
+{
+ void **ppFreeBlock;
+ void *pStorage;
+ void *pEndOfStorage;
+ uint32_t nBlockSize;
+ uint32_t nBlockCount;
+} WLS_FAPI_MEM_STRUCT, *PWLS_FAPI_MEM_STRUCT;
+
+// WLS context structure
+typedef struct _nr5g_fapi_wls_context {
+ void *shmem; // shared memory region.
+ uint64_t shmem_size; // shared memory region size.
+ WLS_FAPI_MEM_STRUCT sWlsStruct;
+ WLS_HANDLE h_wls[NUM_WLS_INSTANCES]; // WLS context handle
+ void *pWlsMemBase;
+ uint32_t nTotalMemorySize;
+ uint32_t nTotalBlocks;
+ uint32_t nAllocBlocks;
+ uint32_t nTotalAllocCnt;
+ uint32_t nTotalFreeCnt;
+ uint32_t nTotalUlBufAllocCnt;
+ uint32_t nTotalUlBufFreeCnt;
+ uint32_t nTotalDlBufAllocCnt;
+ uint32_t nTotalDlBufFreeCnt;
+ uint32_t nPartitionMemSize;
+ void *pPartitionMemBase;
+ volatile pthread_mutex_t lock;
+ volatile pthread_mutex_t lock_alloc;
+} nr5g_fapi_wls_context_t, *p_nr5g_fapi_wls_context_t;
+
+nr5g_fapi_wls_context_t g_wls_ctx;
+typedef void* WLS_HANDLE;
+static uint8_t alloc_track[ALLOC_TRACK_SIZE];
+void *g_shmem;
+uint32_t g_shmem_size=0;
+uint32_t g_nTotalAllocCnt=0;
+uint32_t g_nAllocBlocks=0;
+uint32_t gwls_fapi_ready=0;
+WLS_FAPI_MEM_STRUCT g_MemArray;
+nr5g_fapi_wls_context_t g_wls_ctx;
+uint32_t g_nTotalDlBufAllocCnt=0;
+uint32_t g_nTotalUlBufAllocCnt=0;
+
+wls_us_ctx_t gphy_wls;
+wls_us_ctx_t gfapi_wls;
+
+WLS_HANDLE g_phy_wls = &gphy_wls;
+WLS_HANDLE g_fapi_wls = &gfapi_wls;
+
+uint8_t fapi_dpdk_init(void);
+uint8_t fapi_wls_init(const char *dev_name, unsigned long long mem_size);
+uint64_t fapi_mac_recv();
+uint8_t fapi_phy_send();
+uint64_t fapi_phy_recv();
+uint8_t fapi_mac_send();
+uint8_t fapi2Phy_wls_init(p_nr5g_fapi_wls_context_t pwls);
+uint8_t wls_fapi_create_partition(p_nr5g_fapi_wls_context_t pWls);
+uint32_t wls_fapi_alloc_mem_array(PWLS_FAPI_MEM_STRUCT pMemArray, void **ppBlock);
+uint32_t wls_fapi_create_mem_array(PWLS_FAPI_MEM_STRUCT pMemArray, void *pMemArrayMemory, uint32_t totalSize, uint32_t nBlockSize);
+
+uint64_t nr5g_fapi_wls_va_to_pa(WLS_HANDLE h_wls, void *ptr)
+{
+ return ((uint64_t)WLS_VA2PA(h_wls, ptr));
+}
+
+inline p_nr5g_fapi_wls_context_t nr5g_fapi_wls_context()
+{
+ return &g_wls_ctx;
+}
+
+static inline WLS_HANDLE nr5g_fapi_fapi2mac_wls_instance()
+{
+ p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
+
+ return p_wls_ctx->h_wls[NR5G_FAPI2MAC_WLS_INST];
+}
+
+static inline WLS_HANDLE nr5g_fapi_fapi2phy_wls_instance()
+{
+ p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
+ return p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST];
+}
+void *wls_fapi_alloc_buffer(uint32_t size, uint32_t loc)
+{
+ void *pBlock = NULL;
+ p_nr5g_fapi_wls_context_t pWls = nr5g_fapi_wls_context();
+ PWLS_FAPI_MEM_STRUCT pMemArray = &pWls->sWlsStruct;
+
+ pthread_mutex_lock((pthread_mutex_t *)&pWls->lock_alloc);
+
+ if (wls_fapi_alloc_mem_array(&pWls->sWlsStruct, &pBlock) != SUCCESS)
+ {
+ printf("wls_fapi_alloc_buffer alloc error size[%d] loc[%d]\n", size, loc);
+
+ exit(-1);
+ }
+ else
+ {
+ pWls->nAllocBlocks++;
+ }
+
+ //printf("----------------wls_fapi_alloc_buffer: size[%d] loc[%d] buf[%p] nAllocBlocks[%d]\n", size, loc, pBlock, pWls->nAllocBlocks);
+
+ //printf("[%p]\n", pBlock);
+
+ pWls->nTotalAllocCnt++;
+ if (loc < MAX_DL_BUF_LOCATIONS)
+ pWls->nTotalDlBufAllocCnt++;
+ else if (loc < MAX_UL_BUF_LOCATIONS)
+ pWls->nTotalUlBufAllocCnt++;
+
+ pthread_mutex_unlock((pthread_mutex_t *)&pWls->lock_alloc);
+ return pBlock;
+}
+
+uint32_t wls_fapi_create_mem_array(PWLS_FAPI_MEM_STRUCT pMemArray, void *pMemArrayMemory, uint32_t totalSize, uint32_t nBlockSize)
+{
+
+ int numBlocks = totalSize / nBlockSize;
+ void **ptr;
+ uint32_t i;
+
+ printf("wls_fapi_create_mem_array: pMemArray[%p] pMemArrayMemory[%p] totalSize[%d] nBlockSize[%d] numBlocks[%d]\n",
+ pMemArray, pMemArrayMemory, totalSize, nBlockSize, numBlocks);
+
+ // Can't be less than pointer size
+ if (nBlockSize < sizeof(void *))
+ {
+ return FAILURE;
+ }
+
+ // Can't be less than one block
+ if (totalSize < sizeof(void *))
+ {
+ return FAILURE;
+ }
+
+ pMemArray->ppFreeBlock = (void **)pMemArrayMemory;
+ pMemArray->pStorage = pMemArrayMemory;
+ pMemArray->pEndOfStorage = ((unsigned long*)pMemArrayMemory) + numBlocks * nBlockSize / sizeof(unsigned long);
+ pMemArray->nBlockSize = nBlockSize;
+ pMemArray->nBlockCount = numBlocks;
+
+ // Initialize single-linked list of free blocks;
+ ptr = (void **)pMemArrayMemory;
+ for (i = 0; i < pMemArray->nBlockCount; i++)
+ {
+#ifdef MEMORY_CORRUPTION_DETECT
+ // Fill with some pattern
+ uint8_t *p = (uint8_t *)ptr;
+ uint32_t j;
+
+ p += (nBlockSize - 16);
+ for (j = 0; j < 16; j++)
+ {
+ p[j] = MEMORY_CORRUPTION_DETECT_FLAG;
+ }
+#endif
+
+ if (i == pMemArray->nBlockCount - 1)
+ {
+ *ptr = NULL; // End of list
+ }
+ else
+ {
+ // Points to the next block
+ *ptr = (void **)(((uint8_t*)ptr) + nBlockSize);
+ ptr += nBlockSize / sizeof(unsigned long);
+ }
+ }
+
+ memset(alloc_track, 0, sizeof(uint8_t) * ALLOC_TRACK_SIZE);
+
+ return SUCCESS;
+}
+
+uint32_t wls_fapi_alloc_mem_array(PWLS_FAPI_MEM_STRUCT pMemArray, void **ppBlock)
+{
+ int idx;
+
+ if (pMemArray->ppFreeBlock == NULL)
+ {
+ printf("wls_fapi_alloc_mem_array pMemArray->ppFreeBlock = NULL\n");
+ return FAILURE;
+ }
+
+ // FIXME: Remove after debugging
+ if (((void *) pMemArray->ppFreeBlock < pMemArray->pStorage) ||
+ ((void *) pMemArray->ppFreeBlock >= pMemArray->pEndOfStorage))
+ {
+ printf("wls_fapi_alloc_mem_array ERROR: Corrupted MemArray;Arr=%p,Stor=%p,Free=%p\n",
+ pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock);
+ return FAILURE;
+ }
+
+ pMemArray->ppFreeBlock = (void **)((unsigned long)pMemArray->ppFreeBlock & 0xFFFFFFFFFFFFFFF0);
+ *pMemArray->ppFreeBlock = (void **)((unsigned long)*pMemArray->ppFreeBlock & 0xFFFFFFFFFFFFFFF0);
+
+ if ((*pMemArray->ppFreeBlock != NULL) &&
+ (((*pMemArray->ppFreeBlock) < pMemArray->pStorage) ||
+ ((*pMemArray->ppFreeBlock) >= pMemArray->pEndOfStorage)))
+ {
+ fprintf(stderr, "ERROR: Corrupted MemArray;Arr=%p,Stor=%p,Free=%p,Curr=%p\n",
+ pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock,
+ *pMemArray->ppFreeBlock);
+ return FAILURE;
+ }
+
+ *ppBlock = (void *) pMemArray->ppFreeBlock;
+ pMemArray->ppFreeBlock = (void **) (*pMemArray->ppFreeBlock);
+
+ idx = (((uint64_t)*ppBlock - (uint64_t)pMemArray->pStorage)) / pMemArray->nBlockSize;
+ if (alloc_track[idx])
+ {
+ printf("wls_fapi_alloc_mem_array Double alloc Arr=%p,Stor=%p,Free=%p,Curr=%p\n",
+ pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock,
+ *pMemArray->ppFreeBlock);
+ }
+ else
+ {
+#ifdef MEMORY_CORRUPTION_DETECT
+ uint32_t nBlockSize = pMemArray->nBlockSize, i;
+ uint8_t *p = (uint8_t *)*ppBlock;
+
+ p += (nBlockSize - 16);
+ for (i = 0; i < 16; i++)
+ {
+ p[i] = MEMORY_CORRUPTION_DETECT_FLAG;
+ }
+#endif
+ alloc_track[idx] = 1;
+ }
+
+ //printf("Block allocd [%p,%p]\n", pMemArray, *ppBlock);
+
+ return SUCCESS;
+}
+
+
+
+uint8_t wls_fapi_create_partition(p_nr5g_fapi_wls_context_t pWls)
+{
+static long hugePageSize = WLS_HUGE_DEF_PAGE_SIZEA;
+ void *pPartitionMemBase;
+ uint32_t nPartitionMemSize;
+ uint32_t nTotalBlocks;
+
+ pWls->pPartitionMemBase = pWls->pWlsMemBase + hugePageSize;
+ pWls->nPartitionMemSize = (pWls->nTotalMemorySize - hugePageSize);
+
+ pWls->nTotalBlocks = pWls->nPartitionMemSize / MSG_MAXSIZE1;
+
+ return wls_fapi_create_mem_array(&pWls->sWlsStruct, pWls->pPartitionMemBase, pWls->nPartitionMemSize, MSG_MAXSIZE1);
+}
+
+uint8_t nr5g_fapi2Phy_wls_init(p_nr5g_fapi_wls_context_t pWls)
+{
+ int nBlocks = 0;
+ uint8_t retval = SUCCESS;
+
+
+ WLS_HANDLE h_wls = pWls->h_wls[NR5G_FAPI2PHY_WLS_INST];
+ pthread_mutex_init((pthread_mutex_t *)&pWls->lock, NULL);
+ pthread_mutex_init((pthread_mutex_t *)&pWls->lock_alloc, NULL);
+
+ pWls->nTotalAllocCnt = 0;
+ pWls->nTotalFreeCnt = 0;
+ pWls->nTotalUlBufAllocCnt = 0;
+ pWls->nTotalUlBufFreeCnt = 0;
+ pWls->nTotalDlBufAllocCnt = 0;
+ pWls->nTotalDlBufFreeCnt = 0;
+ // Need to add wls_fapi_create_partition
+ retval = wls_fapi_create_partition(pWls);
+ if (retval == SUCCESS)
+ {
+ gwls_fapi_ready = 1;
+ nBlocks = WLS_EnqueueBlock(h_wls, nr5g_fapi_wls_va_to_pa( h_wls, wls_fapi_alloc_buffer(0, MIN_UL_BUF_LOCATIONS+2)));
+ printf("WLS_EnqueueBlock [%d]\n", nBlocks);
+ // Allocate Blocks for UL Transmission
+ while(WLS_EnqueueBlock(h_wls, nr5g_fapi_wls_va_to_pa(h_wls,wls_fapi_alloc_buffer(0, MIN_UL_BUF_LOCATIONS+3))))
+ {
+ nBlocks++;
+ }
+ printf ("fapi2Phy UL Buffer Allocation completed\n");
+ }
+ else
+ {
+ printf ("can't create WLS FAPI2PHY partition \n");
+ return FAILURE;
+ }
+ return retval;
+}
+
+uint8_t nr5g_fapi_fapi2mac_wls_ready()
+{
+ int ret = SUCCESS;
+ ret = WLS_Ready1(nr5g_fapi_fapi2mac_wls_instance());
+ return ret;
+}
+
+
+inline uint8_t nr5g_fapi_fapi2phy_wls_ready()
+{
+ int ret = SUCCESS;
+ //NR5G_FAPI_LOG(TRACE_LOG, ("Waiting for L1 to respond in WLS Ready"));
+ ret = WLS_Ready(nr5g_fapi_fapi2phy_wls_instance());
+ return ret;
+}
+
+int main()
+{
+ uint8_t ret;
+ uint64_t p_msg;
+ uint8_t retval= FAILURE;
+ p_nr5g_fapi_wls_context_t pwls;
+
+ // DPDK init
+ ret = fapi_dpdk_init();
+ if (ret)
+ {
+ printf("\n[FAPI] DPDK Init - Failed\n");
+ return FAILURE;
+ }
+ printf("\n[FAPI] DPDK Init - Done\n");
+
+ // WLS init
+ ret = fapi_wls_init(WLS_TEST_DEV_NAME, WLS_TEST_MEM_SIZE);
+ if(ret)
+ {
+ printf("\n[FAPI] WLS Init - Failed\n");
+ return FAILURE;
+ }
+ // Need to check for L1 and L2 started before attempting partition creation
+ // First let's wait for the L1 and L2 to be present
+ while (retval)
+ {
+ retval = nr5g_fapi_fapi2phy_wls_ready();
+ }
+ // Now the L2 is up so let's make sure that the L1 was started first
+ retval=FAILURE;
+ while (retval)
+ {
+ retval = nr5g_fapi_fapi2mac_wls_ready();
+ }
+ // Now that the L2 is up and has completed the Common Memory initialization the FT needs to initialize the FAPI2PHY buffers
+ pwls = nr5g_fapi_wls_context();
+ usleep(1000000);
+ ret = nr5g_fapi2Phy_wls_init(pwls);
+ if(ret)
+ {
+ printf("\n[FAPI] 2Phy WLS Init - Failed\n");
+ return FAILURE;
+ }
+
+ printf("\n[FAPI] WLS Init - Done\n");
+
+ // Receive from MAC WLS
+ p_msg = fapi_mac_recv();
+ if (!p_msg)
+ {
+ printf("\n[FAPI] Receive from MAC - Failed\n");
+ return FAILURE;
+ }
+ printf("\n[FAPI] Receive from MAC - Done\n");
+
+ // Sent to PHY WLS
+ ret = fapi_phy_send();
+ if (ret)
+ {
+ printf("\n[FAPI] Send to PHY - Failed\n");
+ return FAILURE;
+ }
+ printf("\n[FAPI] Send to PHY - Done\n");
+
+ // Receive from PHY WLS
+ p_msg = fapi_phy_recv();
+ if (!p_msg)
+ {
+ printf("\n[FAPI] Receive from PHY - Failed\n");
+ return FAILURE;
+ }
+ printf("\n[FAPI] Receive from PHY - Done\n");
+
+ // Sent to MAC WLS
+ ret = fapi_mac_send();
+ if (ret)
+ {
+ printf("\n[FAPI] Send to MAC - Failed\n");
+ return FAILURE;
+ }
+ printf("\n[FAPI] Send to MAC - Done\n");
+
+
+ printf("\n[FAPI] Exiting...\n");
+
+ return SUCCESS;
+}
+
+uint8_t fapi_dpdk_init(void)
+{
+ char whitelist[32];
+ uint8_t i;
+
+ char *argv[] = {"fapi_app", "--proc-type=secondary",
+ "--file-prefix", "wls", whitelist};
+
+ int argc = RTE_DIM(argv);
+
+ /* initialize EAL first */
+ sprintf(whitelist, "-w %s", "0000:00:06.0");
+ printf("[FAPI] Calling rte_eal_init: ");
+
+ for (i = 0; i < RTE_DIM(argv); i++)
+ {
+ printf("%s ", argv[i]);
+ }
+ printf("\n");
+
+ if (rte_eal_init(argc, argv) < 0)
+ rte_panic("Cannot init EAL\n");
+
+ return SUCCESS;
+}
+
+uint8_t fapi_wls_init(const char *dev_name, unsigned long long mem_size)
+{
+ uint8_t *pMemZone;
+ static const struct rte_memzone *mng_memzone;
+ p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
+ wls_drv_ctx_t *pDrv_ctx;
+
+ p_wls_ctx->h_wls[NR5G_FAPI2MAC_WLS_INST] =
+ WLS_Open_Dual(dev_name, WLS_SLAVE_CLIENT, mem_size, &p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST]);
+ if((NULL == p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST]) &&
+ (NULL == p_wls_ctx->h_wls[NR5G_FAPI2MAC_WLS_INST]))
+ {
+ return FAILURE;
+ }
+ g_shmem_size = mem_size;
+ p_wls_ctx->shmem_size = mem_size;
+ // Issue WLS_Alloc() for FAPI2MAC
+ p_wls_ctx->shmem = WLS_Alloc(
+ p_wls_ctx->h_wls[NR5G_FAPI2MAC_WLS_INST],
+ p_wls_ctx->shmem_size);
+
+ if (NULL == p_wls_ctx->shmem)
+ {
+ printf("Unable to alloc WLS Memory for FAPI2MAC\n");
+ return FAILURE;
+ }
+ p_wls_ctx->shmem = WLS_Alloc(
+ p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST],
+ p_wls_ctx->shmem_size);
+ p_wls_ctx->pWlsMemBase = p_wls_ctx->shmem;
+ p_wls_ctx->nTotalMemorySize = p_wls_ctx->shmem_size;
+ if (NULL == p_wls_ctx->shmem)
+ {
+ printf("Unable to alloc WLS Memory for FAPI2PHY\n");
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
+
+uint64_t fapi_mac_recv()
+{
+ uint8_t num_blks = 0;
+ uint64_t p_msg;
+ uint32_t msg_size;
+ uint16_t msg_id;
+ uint16_t flags;
+ uint32_t i;
+
+ WLS_HANDLE wls= nr5g_fapi_fapi2mac_wls_instance();
+
+ for (i=0; i < NUM_TEST_MSGS; i++)
+ {
+ num_blks = WLS_Wait1(wls);
+
+ if (num_blks)
+ {
+ p_msg = WLS_Get1(wls, &msg_size, &msg_id, &flags);
+ }
+ else
+ {
+ printf("\n[FAPI] FAPI2MAC WLS wait returned 0 blocks\n");
+ }
+ if (p_msg)
+ {
+ printf("\n[FAPI] Receive from MAC Msg %d-\n", i);
+ }
+ }
+ return p_msg;
+}
+
+uint8_t fapi_phy_send()
+{
+ uint64_t pa_block = 0;
+ uint8_t ret = FAILURE;
+ uint32_t i;
+ WLS_HANDLE wls = nr5g_fapi_fapi2mac_wls_instance();
+ WLS_HANDLE wlsp = nr5g_fapi_fapi2phy_wls_instance();
+
+ for (i=0; i < NUM_TEST_MSGS; i++)
+ {
+ pa_block = (uint64_t) WLS_DequeueBlock((void*) wls);
+ if (!pa_block)
+ {
+ printf("\n[FAPI] FAPI2MAC WLS Dequeue block error %d\n",i);
+ return FAILURE;
+ }
+
+ ret = WLS_Put(wlsp, pa_block, WLS_TEST_MSG_SIZE, WLS_TEST_MSG_ID, (i== (NUM_TEST_MSGS-1))? WLS_TF_FIN:0);
+ if (ret)
+ {
+ printf("\n[FAPI] Send to PHY %d- Failed\n",i);
+ return FAILURE;
+ }
+ else
+ {
+ printf("\n[FAPI] Send to PHY %d done \n",i);
+ }
+ }
+ return ret;
+}
+
+uint64_t fapi_phy_recv()
+{
+ uint8_t num_blks = 0;
+ uint64_t p_msg;
+ uint32_t msg_size;
+ uint16_t msg_id;
+ uint16_t flags;
+ uint32_t i=0;
+ WLS_HANDLE wls = nr5g_fapi_fapi2phy_wls_instance();
+
+ while (1)
+ {
+ num_blks = WLS_Wait(wls);
+ printf("WLS_Wait returns %d\n",num_blks);
+
+ if (num_blks)
+ {
+ p_msg = WLS_Get(wls, &msg_size, &msg_id, &flags);
+ printf("\n[FAPI] FAPI2PHY Received Block %d \n", i);
+ i++;
+ if (flags & WLS_TF_FIN)
+ {
+ return p_msg;
+ }
+ }
+ else
+ {
+ printf("\n[FAPI] FAPI2MAC WLS wait returned 0 blocks\n");
+ }
+ }
+ return p_msg;
+}
+
+uint8_t fapi_mac_send()
+{
+ uint64_t pa_block = 0;
+ uint8_t ret = FAILURE;
+ uint32_t i;
+ WLS_HANDLE wls = nr5g_fapi_fapi2mac_wls_instance();
+ WLS_HANDLE wlsp = nr5g_fapi_fapi2phy_wls_instance();
+
+ for (i=0; i < NUM_TEST_MSGS; i++)
+ {
+ pa_block = (uint64_t) WLS_DequeueBlock((void*) wlsp);
+ if (!pa_block)
+ {
+ printf("\n[FAPI] FAPI2MAC WLS Dequeue block %d error\n",i);
+ return FAILURE;
+ }
+
+ ret = WLS_Put1(wls, pa_block, WLS_TEST_MSG_SIZE, WLS_TEST_MSG_ID, (i== (NUM_TEST_MSGS-1))? WLS_TF_FIN:0);
+ printf("\n[FAPI] FAPI2MAC WLS Put1 block %d\n",i);
+ }
+ return ret;
+}
diff --git a/wls_lib/test/fapi/makefile b/wls_lib/test/fapi/makefile
new file mode 100644
index 0000000..655de05
--- /dev/null
+++ b/wls_lib/test/fapi/makefile
@@ -0,0 +1,162 @@
+###############################################################################
+#
+# Copyright (c) 2019 Intel.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###############################################################################
+
+.SUFFIXES: .o .c .s .i .cpp
+
+# Makefile to build Testfapi application
+
+##############################################################
+# Tools configuration
+##############################################################
+CC := icc
+CPP := icpc
+AS := as
+AR := ar
+LD := icc
+OBJDUMP := objdump
+
+ifeq ($(SHELL),cmd.exe)
+MD := mkdir.exe -p
+RM := rm.exe -rf
+else
+MD := mkdir -p
+RM := rm -rf
+endif
+
+##############################################################
+# TARGET
+##############################################################
+ifeq ($(RTE_TARGET),)
+ RTE_TARGET :=x86_64-native-linuxapp-icc
+endif
+##############################################################
+# DPDK
+##############################################################
+ifeq ($(RTE_SDK),)
+$(info Please make sure RTE_SDK points to DPDK folder (current version of DPDK is 18.08))
+ RTE_SDK := /opt/dpdk-18.08
+endif
+
+##############################################################
+# Projects folders
+##############################################################
+WLSDIR := $(DIR_WIRELESS_WLS)
+BUILDDIR := ../build/fapi
+SRCDIR := $(CURDIR)
+
+wls_fapi_app_dep_file = $(BUILDDIR)/dep_file
+
+APP := ../bin/fapi/fapi_app
+
+INC := \
+ $(WLSDIR) \
+ $(SRCDIR) \
+ $(RTE_SDK)/$(RTE_TARGET)/include \
+
+INC := $(addprefix -I,$(INC))
+
+DEFS := USE_WO_LOCK _GNU_SOURCE NR5G
+
+ifneq ($(PRINTDBG),)
+DEFS := $(DEFS) PRINTF_DBG_OK
+endif
+
+ifeq ($(DEBUG_MODE),true)
+DEFS := $(DEFS) DEBUG_MODE
+endif
+
+DEFS := $(addprefix -D,$(DEFS))
+
+CFLAGS := -g -Wall -wd9 -Wno-deprecated-declarations -Wimplicit-function-declaration -fasm-blocks $(DEFS) $(INC)
+
+ifeq ($(PRINTDBG),)
+CFLAGS := $(CFLAGS) -Werror
+endif
+
+RTE_LIBS := -L$(RTE_SDK)/$(RTE_TARGET)/lib -Wl,--whole-archive -Wl,-lrte_distributor -Wl,-lrte_kni -Wl,-lrte_pipeline -Wl,-lrte_table -Wl,-lrte_port -Wl,-lrte_timer -Wl,-lrte_hash -Wl,-lrte_lpm -Wl,-lrte_power -Wl,-lrte_acl -Wl,-lrte_meter -Wl,-lrte_sched -Wl,-lm -Wl,-lrt -Wl,--start-group -Wl,-lrte_kvargs -Wl,-lrte_mbuf -Wl,-lrte_ip_frag -Wl,-lrte_ethdev -Wl,-lrte_mempool -Wl,-lrte_mempool_ring -Wl,-lrte_ring -Wl,-lrte_bus_pci -Wl,-lrte_bus_vdev -Wl,-lrte_pci -Wl,-lrte_net -Wl,-lrte_eal -Wl,-lrte_cmdline -Wl,-lrte_cfgfile -Wl,-lrte_pmd_bond -Wl,-lrte_pmd_vmxnet3_uio -Wl,-lrte_pmd_i40e -Wl,-lrte_pmd_ixgbe -Wl,-lrte_pmd_e1000 -Wl,-lrte_pmd_ring -Wl,-lrt -Wl,-lm -Wl,-ldl -Wl,--end-group -Wl,--no-whole-archive
+LDFLAGS := -g -Wl,-lrt -Wl,-lpthread -Wl,-lhugetlbfs -Wl,-lm -Wl,-lnuma -L $(WLSDIR) -lwls
+
+LINUX_WLS_FAPI_APP_SRC := \
+ $(SRCDIR)/fapi_main.c \
+
+OBJS := $(LINUX_WLS_FAPI_APP_SRC:.c=.o)
+
+PROJECT_OBJ_DIR = $(BUILDDIR)
+
+OBJS := $(addprefix $(PROJECT_OBJ_DIR)/,$(OBJS))
+
+DIRLIST := $(sort $(dir $(OBJS)))
+
+CC_DEPS := $(addprefix __dep__,$(LINUX_WLS_FAPI_APP_SRC))
+
+GEN_DEP :=
+ifeq ($(wildcard $(wls_fapi_app_dep_file)),)
+GEN_DEP := regenerate_dep
+endif
+
+.PHONY: $(APP)
+$(APP): $(DIRLIST) echo_options $(GEN_DEP) $(OBJS)
+ @echo [LD] $(APP)
+ @$(CC) -o $(APP) $(OBJS) $(RTE_LIBS) $(LDFLAGS)
+# $(OBJDUMP) -d $(APP) > $(APP).asm
+
+.PHONY : echo_options
+echo_options:
+ @echo [CFLAGS] $(CFLAGS)
+ @echo [LDFAGS] $(LDFLAGS)
+
+
+ifneq ($(wildcard $(wls_fapi_app_dep_file)),)
+include $(wls_fapi_app_dep_file)
+endif
+
+$(DIRLIST) :
+ -@$(MD) $@
+
+.PHONY : regenerate_dep
+regenerate_dep : clean_dep echo_regeenrate_dep $(CC_DEPS)
+
+.PHONY: clean_dep
+clean_dep:
+ $(RM) $(wls_fapi_app_dep_file)
+
+.PHONY : echo_regeenrate_dep
+echo_regeenrate_dep:
+ @echo regenerating dep files
+
+
+.PHONY : CC_DEPS
+$(CC_DEPS):
+ @$(CC) -MM $(subst __dep__,,$@) -MT $(addprefix $(PROJECT_OBJ_DIR)/,$(patsubst %.c,%.o,$(subst __dep__,,$@))) $(CFLAGS) >> $(wls_fapi_app_dep_file)
+
+$(OBJS) : $(PROJECT_OBJ_DIR)/%.o: %.c
+ @echo [CC] $(subst $(PROJECT_OBJ_DIR)/,,$@)
+ @$(CC) -c $(CFLAGS) -o"$@" $(patsubst %.o,%.c,$(subst $(PROJECT_OBJ_DIR)/,,$@))
+
+
+.PHONY: xclean
+xclean : clean_dep
+ @$(RM) $(OBJS)
+ @$(RM) $(APP)
+ @$(RM) $(BUILDDIR)
+
+.PHONY: clean
+clean :
+ @$(RM) $(OBJS)
+ @$(RM) $(APP)
+
diff --git a/wls_lib/test/mac/mac_main.c b/wls_lib/test/mac/mac_main.c
new file mode 100644
index 0000000..4d6c902
--- /dev/null
+++ b/wls_lib/test/mac/mac_main.c
@@ -0,0 +1,78 @@
+/******************************************************************************
+*
+* Copyright (c) 2019 Intel.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*******************************************************************************/
+
+/**
+ * @brief This file is test MAC wls lib main process
+ * @file mac_main.c
+ * @ingroup group_testmacwls
+ * @author Intel Corporation
+ **/
+
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "wls_lib.h"
+#include "mac_wls.h"
+
+#define WLS_TEST_DEV_NAME "wls"
+#define WLS_TEST_MSG_ID 1
+#define WLS_TEST_MSG_SIZE 100
+#define WLS_TEST_MEM_SIZE 2126512128
+
+#define N_MAC_MSGS 16
+
+int main()
+{
+ p_fapi_api_queue_elem_t p_list_elem;
+ unsigned int ret;
+ unsigned int n= N_MAC_MSGS;
+ unsigned int i;
+
+ // DPDK init
+ ret = mac_dpdk_init();
+ if (ret)
+ {
+ printf("\n[MAC] DPDK Init - Failed\n");
+ return FAILURE;
+ }
+ printf("\n[MAC] DPDK Init - Done\n");
+
+ wls_mac_init(WLS_TEST_DEV_NAME, WLS_TEST_MEM_SIZE);
+ printf("\n[MAC] WLS Init - Done\n");
+
+ for (i=0; i< N_MAC_MSGS; i++)
+ {
+ p_list_elem = wls_mac_create_elem(WLS_TEST_MSG_ID, WLS_TEST_MSG_SIZE, 1, 0);
+ printf("\n[MAC] MAC Create Element %d- Done\n", i);
+
+ if(p_list_elem)
+ {
+ wls_mac_send_msg_to_phy((void *)p_list_elem);
+ printf("\n[MAC] Send to FAPI %d- Done\n",i);
+ }
+ }
+
+ // Receive from FAPI WLS
+ wls_mac_rx_task();
+
+ printf("\n[MAC] Exiting...\n");
+
+ return SUCCESS;
+}
+
diff --git a/wls_lib/test/mac/mac_wls.c b/wls_lib/test/mac/mac_wls.c
new file mode 100644
index 0000000..3f69884
--- /dev/null
+++ b/wls_lib/test/mac/mac_wls.c
@@ -0,0 +1,1322 @@
+/******************************************************************************
+*
+* Copyright (c) 2019 Intel.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*******************************************************************************/
+
+/**
+ * @brief This file has Shared Memory interface functions between MAC and PHY
+ * @file testmac_wls.c
+ * @ingroup group_testmac
+ * @author Intel Corporation
+ **/
+
+
+#include <sys/ioctl.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sched.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <rte_eal.h>
+#include <rte_cfgfile.h>
+#include <rte_string_fns.h>
+#include <rte_common.h>
+#include <rte_string_fns.h>
+#include <rte_lcore.h>
+#include <rte_debug.h>
+#include <rte_launch.h>
+
+#define DPDK_WLS
+#include "wls.h"
+#include "wls_lib.h"
+#include "mac_wls.h"
+//#include "phy_printf.h"
+//#include "aux_sys.h"
+//#include "aux_timer.h"
+//#include "mlog_lnx.h"
+
+//#include "nr5g_testmac_config_test.h"
+//#include "nr5g_testmac_mac_phy_api_proc.h"
+
+
+#define MSG_MAXSIZE ( 16384 * 16 )
+
+
+#define TO_FREE_SIZE ( 10 )
+#define TOTAL_FREE_BLOCKS ( 50 * 12)
+#define ALLOC_TRACK_SIZE ( 16384 )
+
+#define MEMORY_CORRUPTION_DETECT
+#define MEMORY_CORRUPTION_DETECT_FLAG (0xAB)
+
+typedef struct wls_mac_mem_array
+{
+ void **ppFreeBlock;
+ void *pStorage;
+ void *pEndOfStorage;
+ uint32_t nBlockSize;
+ uint32_t nBlockCount;
+} WLS_MAC_MEM_SRUCT, *PWLS_MAC_MEM_SRUCT;
+
+typedef struct wls_mac_ctx
+{
+ void *hWls;
+ void *pWlsMemBase;
+ WLS_MAC_MEM_SRUCT sWlsStruct;
+
+ uint32_t nTotalMemorySize;
+ uint32_t nTotalBlocks;
+ uint32_t nAllocBlocks;
+ uint32_t nTotalAllocCnt;
+ uint32_t nTotalFreeCnt;
+ uint32_t nTotalUlBufAllocCnt;
+ uint32_t nTotalUlBufFreeCnt;
+ uint32_t nTotalDlBufAllocCnt;
+ uint32_t nTotalDlBufFreeCnt;
+// Support for FAPI Translator
+ uint32_t nPartitionMemSize;
+ void *pPartitionMemBase;
+
+ volatile pthread_mutex_t lock;
+ volatile pthread_mutex_t lock_alloc;
+} WLS_MAC_CTX, *PWLS_MAC_CTX;
+
+static pthread_t *pwls_testmac_thread = NULL;
+static WLS_MAC_CTX wls_mac_iface;
+static int gwls_mac_ready = 0;
+static pid_t gwls_pid = 0;
+static uint32_t gToFreeListCnt[TO_FREE_SIZE] = {0};
+static uint64_t gpToFreeList[TO_FREE_SIZE][TOTAL_FREE_BLOCKS] = {{0L}};
+static uint8_t alloc_track[ALLOC_TRACK_SIZE];
+static uint64_t gTotalTick = 0, gUsedTick = 0;
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param[in] ptr Pointer to display
+ * @param[in] size Size of data
+ *
+ * @return void
+ *
+ * @description
+ * This function displays content of Buffer - Used for debugging
+ *
+**/
+//-------------------------------------------------------------------------------------------
+void wls_mac_show_data(void* ptr, uint32_t size)
+{
+ uint8_t *d = ptr;
+ int i;
+
+ for(i = 0; i < size; i++)
+ {
+ if ( !(i & 0xf) )
+ printf("\n");
+ printf("%02x ", d[i]);
+ }
+ printf("\n");
+}
+
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param void
+ *
+ * @return Pointer to WLS_MAC_CTX stucture
+ *
+ * @description
+ * This function returns the WLS Local structure which has WLS related parameters
+ *
+**/
+//-------------------------------------------------------------------------------------------
+static PWLS_MAC_CTX wls_mac_get_ctx(void)
+{
+ return &wls_mac_iface;
+}
+
+void wls_mac_print_stats(void)
+{
+ PWLS_MAC_CTX pWls = wls_mac_get_ctx();
+
+ printf("wls_mac_free_list_all:\n");
+ printf(" nTotalBlocks[%d] nAllocBlocks[%d] nFreeBlocks[%d]\n", pWls->nTotalBlocks, pWls->nAllocBlocks, (pWls->nTotalBlocks- pWls->nAllocBlocks));
+ printf(" nTotalAllocCnt[%d] nTotalFreeCnt[%d] Diff[%d]\n", pWls->nTotalAllocCnt, pWls->nTotalFreeCnt, (pWls->nTotalAllocCnt- pWls->nTotalFreeCnt));
+ printf(" nDlBufAllocCnt[%d] nDlBufFreeCnt[%d] Diff[%d]\n", pWls->nTotalDlBufAllocCnt, pWls->nTotalDlBufFreeCnt, (pWls->nTotalDlBufAllocCnt- pWls->nTotalDlBufFreeCnt));
+ printf(" nUlBufAllocCnt[%d] nUlBufFreeCnt[%d] Diff[%d]\n\n", pWls->nTotalUlBufAllocCnt, pWls->nTotalUlBufFreeCnt, (pWls->nTotalUlBufAllocCnt- pWls->nTotalUlBufFreeCnt));
+}
+
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param[in] ptr Address to convert
+ *
+ * @return Converted address
+ *
+ * @description
+ * This function converts Virtual Address to Physical Address
+ *
+**/
+//-------------------------------------------------------------------------------------------
+uint64_t wls_mac_va_to_pa(void *ptr)
+{
+ PWLS_MAC_CTX pWls = wls_mac_get_ctx();
+ uint64_t ret = (uint64_t)WLS_VA2PA(pWls->hWls, ptr);
+
+ //printf("wls_mac_va_to_pa: %p ->%p\n", ptr, (void*)ret);
+
+ return ret;
+}
+
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param[in] ptr Address to convert
+ *
+ * @return Converted address
+ *
+ * @description
+ * This function converts Physical Address to Virtual Address
+ *
+**/
+//-------------------------------------------------------------------------------------------
+void *wls_mac_pa_to_va(uint64_t ptr)
+{
+ PWLS_MAC_CTX pWls = wls_mac_get_ctx();
+ void *ret = WLS_PA2VA(pWls->hWls, ptr);
+
+ //printf("wls_mac_pa_to_va: %p -> %p\n", (void*)ptr, ret);
+
+ return ret;
+}
+
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param[in] pMemArray Pointer to WLS Memory management structure
+ * @param[in] pMemArrayMemory Pointer to flat buffer that was allocated
+ * @param[in] totalSize Total Size of flat buffer allocated
+ * @param[in] nBlockSize Size of each block that needs to be partitioned by memory manager
+ *
+ * @return 0 if SUCCESS
+ *
+ * @description
+ * This function creates memory blocks from a flat buffer which will be used for communciation
+ * between MAC and PHY
+ *
+**/
+//-------------------------------------------------------------------------------------------
+uint32_t wls_mac_create_mem_array(PWLS_MAC_MEM_SRUCT pMemArray,
+ void *pMemArrayMemory,
+ uint32_t totalSize, uint32_t nBlockSize)
+{
+ int numBlocks = totalSize / nBlockSize;
+ void **ptr;
+ uint32_t i;
+
+ printf("wls_mac_create_mem_array: pMemArray[%p] pMemArrayMemory[%p] totalSize[%d] nBlockSize[%d] numBlocks[%d]\n",
+ pMemArray, pMemArrayMemory, totalSize, nBlockSize, numBlocks);
+
+ // Can't be less than pointer size
+ if (nBlockSize < sizeof(void *))
+ {
+ return FAILURE;
+ }
+
+ // Can't be less than one block
+ if (totalSize < sizeof(void *))
+ {
+ return FAILURE;
+ }
+
+ pMemArray->ppFreeBlock = (void **)pMemArrayMemory;
+ pMemArray->pStorage = pMemArrayMemory;
+ pMemArray->pEndOfStorage = ((unsigned long*)pMemArrayMemory) + numBlocks * nBlockSize / sizeof(unsigned long);
+ pMemArray->nBlockSize = nBlockSize;
+ pMemArray->nBlockCount = numBlocks;
+
+ // Initialize single-linked list of free blocks;
+ ptr = (void **)pMemArrayMemory;
+ for (i = 0; i < pMemArray->nBlockCount; i++)
+ {
+#ifdef MEMORY_CORRUPTION_DETECT
+ // Fill with some pattern
+ uint8_t *p = (uint8_t *)ptr;
+ uint32_t j;
+
+ p += (nBlockSize - 16);
+ for (j = 0; j < 16; j++)
+ {
+ p[j] = MEMORY_CORRUPTION_DETECT_FLAG;
+ }
+#endif
+
+ if (i == pMemArray->nBlockCount - 1)
+ {
+ *ptr = NULL; // End of list
+ }
+ else
+ {
+ // Points to the next block
+ *ptr = (void **)(((uint8_t*)ptr) + nBlockSize);
+ ptr += nBlockSize / sizeof(unsigned long);
+ }
+ }
+
+ memset(alloc_track, 0, sizeof(uint8_t) * ALLOC_TRACK_SIZE);
+
+ return SUCCESS;
+}
+
+
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param[in] pMemArray Pointer to WLS Memory management structure
+ * @param[out] ppBlock Pointer where allocated memory block is stored
+ *
+ * @return 0 if SUCCESS
+ *
+ * @description
+ * This function allocated a memory block from pool
+ *
+**/
+//-------------------------------------------------------------------------------------------
+uint32_t wls_mac_alloc_mem_array(PWLS_MAC_MEM_SRUCT pMemArray, void **ppBlock)
+{
+ int idx;
+
+ if (pMemArray->ppFreeBlock == NULL)
+ {
+ printf("wls_mac_alloc_mem_array pMemArray->ppFreeBlock = NULL\n");
+ return FAILURE;
+ }
+
+ // FIXME: Remove after debugging
+ if (((void *) pMemArray->ppFreeBlock < pMemArray->pStorage) ||
+ ((void *) pMemArray->ppFreeBlock >= pMemArray->pEndOfStorage))
+ {
+ printf("wls_mac_alloc_mem_array ERROR: Corrupted MemArray;Arr=%p,Stor=%p,Free=%p\n",
+ pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock);
+ return FAILURE;
+ }
+
+ pMemArray->ppFreeBlock = (void **)((unsigned long)pMemArray->ppFreeBlock & 0xFFFFFFFFFFFFFFF0);
+ *pMemArray->ppFreeBlock = (void **)((unsigned long)*pMemArray->ppFreeBlock & 0xFFFFFFFFFFFFFFF0);
+
+ if ((*pMemArray->ppFreeBlock != NULL) &&
+ (((*pMemArray->ppFreeBlock) < pMemArray->pStorage) ||
+ ((*pMemArray->ppFreeBlock) >= pMemArray->pEndOfStorage)))
+ {
+ fprintf(stderr, "ERROR: Corrupted MemArray;Arr=%p,Stor=%p,Free=%p,Curr=%p\n",
+ pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock,
+ *pMemArray->ppFreeBlock);
+ return FAILURE;
+ }
+
+ *ppBlock = (void *) pMemArray->ppFreeBlock;
+ pMemArray->ppFreeBlock = (void **) (*pMemArray->ppFreeBlock);
+
+ idx = (((uint64_t)*ppBlock - (uint64_t)pMemArray->pStorage)) / pMemArray->nBlockSize;
+ if (alloc_track[idx])
+ {
+ printf("wls_mac_alloc_mem_array Double alloc Arr=%p,Stor=%p,Free=%p,Curr=%p\n",
+ pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock,
+ *pMemArray->ppFreeBlock);
+ }
+ else
+ {
+#ifdef MEMORY_CORRUPTION_DETECT
+ uint32_t nBlockSize = pMemArray->nBlockSize, i;
+ uint8_t *p = (uint8_t *)*ppBlock;
+
+ p += (nBlockSize - 16);
+ for (i = 0; i < 16; i++)
+ {
+ p[i] = MEMORY_CORRUPTION_DETECT_FLAG;
+ }
+#endif
+ alloc_track[idx] = 1;
+ }
+
+ //printf("Block allocd [%p,%p]\n", pMemArray, *ppBlock);
+
+ return SUCCESS;
+}
+
+
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param[in] pMemArray Pointer to WLS Memory management structure
+ * @param[in] pBlock Pointer to block that needs to be added back to pool
+ *
+ * @return 0 if SUCCESS
+ *
+ * @description
+ * This function frees a WLS block of memory and adds it back to the pool
+ *
+**/
+//-------------------------------------------------------------------------------------------
+uint32_t wls_mac_free_mem_array(PWLS_MAC_MEM_SRUCT pMemArray, void *pBlock)
+{
+ int idx;
+ unsigned long mask = (((unsigned long)pMemArray->nBlockSize) - 1);
+
+ pBlock = (void *)((unsigned long)pBlock & ~mask);
+
+ if ((pBlock < pMemArray->pStorage) || (pBlock >= pMemArray->pEndOfStorage))
+ {
+ printf("wls_mac_free_mem_array WARNING: Trying to free foreign block;Arr=%p,Blk=%p pStorage [%p .. %p]\n",
+ pMemArray, pBlock, pMemArray->pStorage, pMemArray->pEndOfStorage);
+
+ return FAILURE;
+ }
+
+ idx = (int)(((uint64_t)pBlock - (uint64_t)pMemArray->pStorage)) / pMemArray->nBlockSize;
+
+ if (alloc_track[idx] == 0)
+ {
+ printf("wls_mac_free_mem_array ERROR: Double free Arr=%p,Stor=%p,Free=%p,Curr=%p\n",
+ pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock,
+ pBlock);
+
+ return SUCCESS;
+
+ }
+ else
+ {
+#ifdef MEMORY_CORRUPTION_DETECT
+ uint32_t nBlockSize = pMemArray->nBlockSize, i;
+ uint8_t *p = (uint8_t *)pBlock;
+
+ p += (nBlockSize - 16);
+ for (i = 0; i < 16; i++)
+ {
+ if (p[i] != MEMORY_CORRUPTION_DETECT_FLAG)
+ {
+ printf("ERROR: Corruption\n");
+ wls_mac_print_stats();
+ exit(-1);
+ }
+ }
+#endif
+ alloc_track[idx] = 0;
+ }
+
+ if (((void *) pMemArray->ppFreeBlock) == pBlock)
+ {
+ // Simple protection against freeing of already freed block
+ return SUCCESS;
+ }
+
+ // FIXME: Remove after debugging
+ if ((pMemArray->ppFreeBlock != NULL)
+ && (((void *) pMemArray->ppFreeBlock < pMemArray->pStorage)
+ || ((void *) pMemArray->ppFreeBlock >= pMemArray->pEndOfStorage)))
+ {
+ printf("wls_mac_free_mem_array ERROR: Corrupted MemArray;Arr=%p,Stor=%p,Free=%p\n",
+ pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock);
+ return FAILURE;
+ }
+
+ // FIXME: Remove after debugging
+ if ((pBlock < pMemArray->pStorage) ||
+ (pBlock >= pMemArray->pEndOfStorage))
+ {
+ printf("wls_mac_free_mem_array ERROR: Invalid block;Arr=%p,Blk=%p\n",
+ pMemArray, pBlock);
+ return FAILURE;
+ }
+
+ *((void **)pBlock) = (void **)((unsigned long)pMemArray->ppFreeBlock & 0xFFFFFFFFFFFFFFF0);
+ pMemArray->ppFreeBlock = (void **) ((unsigned long)pBlock & 0xFFFFFFFFFFFFFFF0);
+
+ //printf("Block freed [%p,%p]\n", pMemArray, pBlock);
+
+ return SUCCESS;
+}
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param void
+ *
+ * @return Pointer to the memory block
+ *
+ * @description
+ * This function allocates a block of memory from the pool
+ *
+**/
+//-------------------------------------------------------------------------------------------
+void *wls_mac_alloc_buffer(uint32_t size, uint32_t loc)
+{
+ void *pBlock = NULL;
+ PWLS_MAC_CTX pWls = wls_mac_get_ctx();
+ PWLS_MAC_MEM_SRUCT pMemArray = &pWls->sWlsStruct;
+
+ pthread_mutex_lock((pthread_mutex_t *)&pWls->lock_alloc);
+
+ if (wls_mac_alloc_mem_array(&pWls->sWlsStruct, &pBlock) != SUCCESS)
+ {
+ printf("wls_mac_alloc_buffer alloc error size[%d] loc[%d]\n", size, loc);
+ wls_mac_print_stats();
+ exit(-1);
+ }
+ else
+ {
+ pWls->nAllocBlocks++;
+ }
+
+ //printf("----------------wls_mac_alloc_buffer: size[%d] loc[%d] buf[%p] nAllocBlocks[%d]\n", size, loc, pBlock, pWls->nAllocBlocks);
+
+ //printf("[%p]\n", pBlock);
+
+ pWls->nTotalAllocCnt++;
+ if (loc < MAX_DL_BUF_LOCATIONS)
+ pWls->nTotalDlBufAllocCnt++;
+ else if (loc < MAX_UL_BUF_LOCATIONS)
+ pWls->nTotalUlBufAllocCnt++;
+
+ pthread_mutex_unlock((pthread_mutex_t *)&pWls->lock_alloc);
+
+ return pBlock;
+}
+
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param[in] *pMsg Pointer to free
+ *
+ * @return void
+ *
+ * @description
+ * This function frees a block of memory and adds it back to the pool
+ *
+**/
+//-------------------------------------------------------------------------------------------
+void wls_mac_free_buffer(void *pMsg, uint32_t loc)
+{
+ PWLS_MAC_CTX pWls = wls_mac_get_ctx();
+ PWLS_MAC_MEM_SRUCT pMemArray = &pWls->sWlsStruct;
+
+ pthread_mutex_lock((pthread_mutex_t *)&pWls->lock_alloc);
+
+ //printf("----------------wls_mac_free_buffer: buf[%p] loc[%d]\n", pMsg, loc);
+ if (wls_mac_free_mem_array(&pWls->sWlsStruct, (void *)pMsg) == SUCCESS)
+ {
+ pWls->nAllocBlocks--;
+ }
+ else
+ {
+ printf("wls_mac_free_buffer Free error\n");
+ wls_mac_print_stats();
+ exit(-1);
+ }
+
+ pWls->nTotalFreeCnt++;
+ if (loc < MAX_DL_BUF_LOCATIONS)
+ pWls->nTotalDlBufFreeCnt++;
+ else if (loc < MAX_UL_BUF_LOCATIONS)
+ pWls->nTotalUlBufFreeCnt++;
+
+ pthread_mutex_unlock((pthread_mutex_t *)&pWls->lock_alloc);
+}
+
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param void
+ *
+ * @return Number of free blocks
+ *
+ * @description
+ * This function queries the number of free blocks in the system
+ *
+**/
+//-------------------------------------------------------------------------------------------
+int wls_mac_num_free_blocks(void)
+{
+ PWLS_MAC_CTX pWls = wls_mac_get_ctx();
+
+ return (pWls->nTotalBlocks- pWls->nAllocBlocks);
+}
+
+
+
+void wls_mac_free_list_all(void)
+{
+ PWLS_MAC_CTX pWls = wls_mac_get_ctx();
+ uint32_t idx;
+
+ for (idx = 0; idx < TO_FREE_SIZE; idx++)
+ {
+ wls_mac_free_list(idx);
+ }
+
+ wls_mac_print_stats();
+}
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param[in] pWls Pointer to the WLS_MAC_CTX structure
+ *
+ * @return 0 if SUCCESS
+ *
+ * @description
+ * This function created a partition and blocks of WLS memory for API exchange between MAC and PHY
+ *
+**/
+//-------------------------------------------------------------------------------------------
+int wls_mac_create_partition(PWLS_MAC_CTX pWls)
+{
+ memset(pWls->pWlsMemBase, 0xCC, pWls->nTotalMemorySize);
+ pWls->pPartitionMemBase = pWls->pWlsMemBase;
+ pWls->nPartitionMemSize = pWls->nTotalMemorySize/2;
+ pWls->nTotalBlocks = pWls->nTotalMemorySize / MSG_MAXSIZE;
+ return wls_mac_create_mem_array(&pWls->sWlsStruct, pWls->pPartitionMemBase, pWls->nPartitionMemSize, MSG_MAXSIZE);
+}
+
+
+
+static volatile int gWlsMacPrintThreadInfo = 0;
+
+void wls_mac_print_thread_info(void)
+{
+ gWlsMacPrintThreadInfo = 1;
+
+ return;
+}
+
+void wls_mac_get_time_stats(uint64_t *pTotal, uint64_t *pUsed, uint32_t nClear)
+{
+ *pTotal = gTotalTick;
+ *pUsed = gUsedTick;
+
+ if (nClear)
+ {
+ gTotalTick = 0;
+ gUsedTick = 0;
+ }
+}
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param[in] pMsgHeader Pointer to TxSdu Message Block
+ * @param[in] count Location in Free List Array
+ * @param[in] pToFreeList Array where all the blocks to free are stored
+ *
+ * @return New Location in free list array
+ *
+ * @description
+ * This function adds all the messages in a subframe coming from L1 to L2 to a free array to be
+ * freed back to the queue at a later point in time.
+ *
+**/
+//-------------------------------------------------------------------------------------------
+int wls_mac_sdu_zbc_block_add_to_free(void* pMsgHeaderHead, int count, uint64_t *pToFreeList)
+{
+ fapi_msg_t *p_fapi_msg = (fapi_msg_t *) pMsgHeaderHead;
+
+ if (p_fapi_msg->msg_id == FAPI_TX_DATA_REQUEST)
+ {
+ fapi_tx_data_req_t *p_tx_data_req = (fapi_tx_data_req_t *) p_fapi_msg;
+ p_fapi_api_queue_elem_t p_list_elm = ((p_fapi_api_queue_elem_t) p_tx_data_req) - 1;
+ p_fapi_api_queue_elem_t p_sdu_elm = p_list_elm->p_tx_data_elm_list;
+ while(p_sdu_elm)
+ {
+ if (count < TOTAL_FREE_BLOCKS)
+ {
+ pToFreeList[count++] = (uint64_t) p_sdu_elm;
+ }
+ else
+ {
+ printf("wls_mac_sdu_zbc_block_add_to_free: ERROR: Reached max Number of Free Blocks\n");
+ return count;
+ }
+ p_sdu_elm = p_sdu_elm->p_next;
+ }
+ }
+
+ return count;
+}
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param[in] pListElem Pointer to List element header
+ * @param[in] idx Subframe Number
+ *
+ * @return Number of blocks freed
+ *
+ * @description
+ * This function Frees all the blocks in a List Element Linked List coming from L1 by storing
+ * them into an array to be freed at a later point in time.
+ *
+**/
+//-------------------------------------------------------------------------------------------
+int wls_mac_add_to_free(p_fapi_api_queue_elem_t pListElem, uint32_t idx)
+{
+ p_fapi_api_queue_elem_t pNextMsg = NULL;
+ void* pMsgHeader;
+ int count = gToFreeListCnt[idx], nZbcBlocks;
+
+ pNextMsg = pListElem;
+
+ while (pNextMsg)
+ {
+ if (count < TOTAL_FREE_BLOCKS)
+ {
+ gpToFreeList[idx][count] = (uint64_t)pNextMsg;
+ }
+ else
+ {
+ printf("wls_mac_add_to_free: ERROR: Reached max Number of Free Blocks\n");
+ return count;
+ }
+
+ if (pNextMsg->msg_type != FAPI_MSG_HEADER_IND)
+ {
+ pMsgHeader = (void *) (pNextMsg + 1);
+ count++;
+ count = wls_mac_sdu_zbc_block_add_to_free(pMsgHeader, count, gpToFreeList[idx]);
+ }
+
+ if (pNextMsg->p_next)
+ {
+ pNextMsg = (p_fapi_api_queue_elem_t)(pNextMsg->p_next);
+ }
+ else
+ {
+ pNextMsg = 0;
+ }
+ }
+
+ gpToFreeList[idx][count] = 0L;
+ gToFreeListCnt[idx] = count;
+
+ printf("To Free %d\n", count);
+
+ return count;
+}
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param[in] idx subframe Number
+ *
+ * @return Number of blocks freed
+ *
+ * @description
+ * This function frees all blocks that have been added to the free array
+ *
+**/
+//-------------------------------------------------------------------------------------------
+int wls_mac_free_list(uint32_t idx)
+{
+ p_fapi_api_queue_elem_t pNextMsg = NULL;
+ int count = 0;
+
+ if(idx >= TO_FREE_SIZE){
+ printf("Error idx %d\n", idx);
+ return 0;
+ }
+
+ pNextMsg = (p_fapi_api_queue_elem_t)gpToFreeList[idx][count];
+
+ while (pNextMsg)
+ {
+ wls_mac_free_buffer(pNextMsg, MIN_DL_BUF_LOCATIONS+0);
+ gpToFreeList[idx][count] = (uint64_t) NULL;
+ count++;
+ if (gpToFreeList[idx][count])
+ pNextMsg = (p_fapi_api_queue_elem_t)gpToFreeList[idx][count];
+ else
+ pNextMsg = 0;
+ }
+
+ printf("Free %d\n", count);
+ gToFreeListCnt[idx] = 0;
+
+ return count;
+}
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param void
+ *
+ * @return 0 if SUCCESS
+ *
+ * @description
+ * This function is called at WLS init and waits in an infinite for L1 to respond back with some information
+ * needed by the L2
+ *
+**/
+//-------------------------------------------------------------------------------------------
+int wls_mac_ready(void)
+{
+ int ret = 0;
+ PWLS_MAC_CTX pWls = wls_mac_get_ctx();
+ ret = WLS_Ready(pWls->hWls);
+
+ return ret;
+}
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param void
+ *
+ * @return Number of blocks of APIs received
+ *
+ * @description
+ * This functions waits in a infinite loop for L1 to send a list of APIs to MAC. This is called
+ * during runtime when L2 sends a API to L1 and then waits for response back.
+ *
+**/
+//-------------------------------------------------------------------------------------------
+int wls_mac_wait(void)
+{
+ int ret = 0;
+ PWLS_MAC_CTX pWls = wls_mac_get_ctx();
+
+ ret = WLS_Wait(pWls->hWls);
+
+ return ret;
+}
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param[out] data Location where First API from L1 is stored
+ *
+ * @return Size of Message sent from L1
+ *
+ * @description
+ * This function queries the APIs sent from L1 to L2 and gets the first pointer to the linked list
+ *
+**/
+//-------------------------------------------------------------------------------------------
+uint32_t wls_mac_recv(uint64_t *data, uint16_t *nFlags)
+{
+ PWLS_MAC_CTX pWls = wls_mac_get_ctx();
+ uint32_t msgSize = 0;
+ uint16_t msgType = 0;
+
+ *data = WLS_Get(pWls->hWls, &msgSize, &msgType, nFlags);
+
+ return msgSize;
+}
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param[in] pMsg Pointer to API block that needs to be sent to L1
+ * @param[in] MsgSize Size of Message
+ * @param[in] MsgTypeID Message Id
+ * @param[in] Flags Special Flags needed for WLS
+ *
+ * @return 0 if SUCCESS
+ *
+ * @description
+ * This function adds a block of API from L2 to L1 which will be sent later
+ *
+**/
+//-------------------------------------------------------------------------------------------
+int wls_mac_put(uint64_t pMsg, uint32_t MsgSize, uint16_t MsgTypeID, uint16_t Flags)
+{
+ int ret = 0;
+ PWLS_MAC_CTX pWls = wls_mac_get_ctx();
+
+ //printf("wls_mac_put: %p size: %d type: %d nFlags: %d\n", (void*)pMsg, MsgSize, MsgTypeID, Flags);
+ // wls_mac_show_data((void*)wls_alloc_buffer(pMsg), MsgSize);
+ ret = WLS_Put(pWls->hWls, pMsg, MsgSize, MsgTypeID, Flags);
+
+ return ret;
+}
+
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param[in] pMsgHeader Pointer to the TxSduReq Message block
+ * @param[in] nFlags Special nFlags needed for WLS
+ * @param[in] nZbcBlocks Number of ZBC blocks in list
+ *
+ * @return 0 if SUCCESS
+ *
+ * @description
+ * This function adds all the ZBC blocks in a TXSDU Message and prepares them to be sent to the L1
+ *
+**/
+//-------------------------------------------------------------------------------------------
+uint32_t wls_mac_send_zbc_blocks(void *pMsgHeaderHead, uint16_t nFlags, int *nZbcBlocks, uint32_t nFlagsUrllc)
+{
+ fapi_tx_data_req_t *p_tx_data_req = (fapi_tx_data_req_t *) pMsgHeaderHead;
+ p_fapi_api_queue_elem_t p_list_elm = ((p_fapi_api_queue_elem_t) p_tx_data_req) - 1;
+ p_list_elm = p_list_elm->p_tx_data_elm_list;
+
+ int ret = 0;
+ uint8_t nMsgType;
+ uint32_t isLast, nPduLen;
+ uint16_t list_flags = nFlags;
+ void *pPayload = NULL;
+
+ printf("wls_mac_put ZBC blocks: %d\n", nFlags);
+
+ while (p_list_elm)
+ {
+ nPduLen = p_list_elm->msg_len + sizeof(fapi_api_queue_elem_t);
+ pPayload = (void *) p_list_elm;
+ nMsgType = FAPI_MSG_PHY_ZBC_BLOCK_REQ;
+
+ if (p_list_elm->p_next)
+ isLast = 0;
+ else
+ isLast = 1;
+
+ if ((list_flags & WLS_TF_FIN) && isLast)
+ nFlags = WLS_SG_LAST; // TXSDU.req was last block in the list hence ZBC block is last
+ else
+ nFlags = WLS_SG_NEXT; // more blocks in the list
+
+ printf("wls_mac_put 0x%016lx msg type: %x nFlags %x\n", (uint64_t) pPayload, nMsgType, nFlags);
+ ret = wls_mac_put((uint64_t) pPayload, nPduLen, nMsgType, nFlags);
+ if (ret != 0)
+ {
+ printf("Error ZBC block 0x%016lx\n", (uint64_t) pPayload);
+ return FAILURE;
+ }
+ p_list_elm = p_list_elm->p_next;
+ }
+
+ return SUCCESS;
+}
+
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param[in] pMsgHeader Pointer to the TxSDuReq Message block
+ * @param[out] nZbcBlocks Number of ZBC blocks
+ *
+ * @return 1 if this block is a TxSduReq message. 0 else.
+ *
+ * @description
+ * This function checks if a block is a TxSduReq messages and counts the number of ZBC blocks in this
+ * API
+ *
+**/
+//-------------------------------------------------------------------------------------------
+int wls_mac_is_sdu_zbc_block(void* pMsgHeaderHead, int *nZbcBlocks)
+{
+ fapi_tx_data_req_t *p_tx_data_req = (fapi_tx_data_req_t *) pMsgHeaderHead;
+ p_fapi_api_queue_elem_t p_list_elm =
+ ((p_fapi_api_queue_elem_t) p_tx_data_req) - 1;
+ *nZbcBlocks = 0;
+
+ if (p_tx_data_req->header.msg_id == FAPI_TX_DATA_REQUEST &&
+ p_list_elm->p_tx_data_elm_list)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param[in] data Pointer to the Linked list header
+ *
+ * @return 0 if SUCCESS
+ *
+ * @description
+ * This function sends a list of APIs to the L1
+ *
+**/
+//-------------------------------------------------------------------------------------------
+uint32_t wls_mac_send_msg_to_phy(void *data)
+{
+ uint32_t ret = SUCCESS;
+ PWLS_MAC_CTX pWls = wls_mac_get_ctx();
+ PWLS_MAC_MEM_SRUCT pMemArray = &pWls->sWlsStruct;
+ p_fapi_api_queue_elem_t pCurrMsg = NULL;
+ p_fapi_api_queue_elem_t pListElem = NULL;
+ static uint32_t idx = 0;
+
+ fapi_msg_t *pMsgHeader;
+ uint16_t nFlags;
+ int nZbcBlocks = 0, isZbc = 0, count = 0;
+
+ printf("wls_mac_send_msg_to_phy\n");
+ printf("data (0x%lX) sending to phy...\n", (unsigned long)data);
+
+ pthread_mutex_lock((pthread_mutex_t *)&pWls->lock);
+
+ if (gwls_mac_ready)
+ {
+ pListElem = (p_fapi_api_queue_elem_t)data;
+ wls_mac_add_to_free(pListElem, idx);
+ count++;
+
+
+ ret = wls_mac_put(wls_mac_va_to_pa(pListElem),
+ pListElem->msg_len + sizeof(fapi_api_queue_elem_t),
+ pMsgHeader->msg_id, nFlags);
+ if (ret != 0)
+ {
+ printf("Error\n");
+ pthread_mutex_unlock((pthread_mutex_t *)&pWls->lock);
+ return FAILURE;
+ }
+ }
+
+ pthread_mutex_unlock((pthread_mutex_t *)&pWls->lock);
+ return ret;
+}
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param void
+ *
+ * @return Number of blocks added
+ *
+ * @description
+ * This function add WLS blocks to the L1 Array which will be used by L1 in every TTI to
+ * populate and send back APIs to the MAC
+ *
+**/
+//-------------------------------------------------------------------------------------------
+int wls_mac_add_blocks_to_ul(void)
+{
+ int ret = 0;
+ PWLS_MAC_CTX pWls = wls_mac_get_ctx();
+
+ void *pMsg = wls_mac_alloc_buffer(0, MIN_UL_BUF_LOCATIONS+0);
+
+ if(pMsg)
+ {
+ /* allocate blocks for UL transmittion */
+ while(WLS_EnqueueBlock(pWls->hWls,(uint64_t)wls_mac_va_to_pa(pMsg)))
+ {
+ ret++;
+ pMsg = wls_mac_alloc_buffer(0, MIN_UL_BUF_LOCATIONS+1);
+ if(WLS_EnqueueBlock(pWls->hWls,(uint64_t)wls_mac_va_to_pa(pMsg)))
+ {
+ ret++;
+ pMsg = wls_mac_alloc_buffer(0, MIN_UL_BUF_LOCATIONS+1);
+ }
+
+ if(!pMsg)
+ break;
+ }
+
+ // free not enqueued block
+ if(pMsg)
+ {
+ wls_mac_free_buffer(pMsg, MIN_UL_BUF_LOCATIONS+3);
+ }
+ }
+
+ return ret;
+}
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param[in] data Thread Local Context Structure Pointer
+ *
+ * @return NULL
+ *
+ * @description
+ * This is the WLS Receiver thread that is created at Testmac Init and is responsible for receiving
+ * APIs from L1 to MAC
+ *
+**/
+//-------------------------------------------------------------------------------------------
+void *wls_mac_rx_task()
+{
+ void* buffer_va = 0;
+ uint64_t buffer_pa = 0;
+ uint32_t get,i, rc = 0;
+
+ uint32_t size = 0;
+ uint64_t tWake = 0, tWakePrev = 0, tSleep = 0;
+ uint16_t nFlags;
+ p_fapi_api_queue_elem_t pElm = NULL;
+ p_fapi_api_queue_elem_t pFirst = NULL;
+ p_fapi_api_queue_elem_t pPrev = NULL;
+
+
+ usleep(1000);
+
+ wls_mac_ready();
+
+ while (1)
+ {
+ get = wls_mac_wait();
+
+ if (get == 0)
+ {
+ continue;
+ }
+ printf("Got %d messages from FAPI Translator\n", get);
+ while(get--)
+ {
+ size = wls_mac_recv((uint64_t *)&buffer_pa, &nFlags);
+ buffer_va = wls_mac_pa_to_va(buffer_pa);
+ pElm = (p_fapi_api_queue_elem_t) buffer_va;
+
+
+ if (pFirst == NULL)
+ pFirst = pElm;
+
+ if (nFlags != WLS_TF_FIN)
+ {
+ wls_mac_print_recv_list((p_fapi_api_queue_elem_t) pElm, i);
+ i++;
+ }
+ if(pPrev)
+ pPrev->p_next = pElm;
+
+ pPrev = pElm;
+
+ if ((nFlags & WLS_TF_FIN))
+ {
+ // send to MAC
+ if (pPrev)
+ {
+ pPrev->p_next = NULL;
+ }
+
+ wls_mac_print_recv_list((p_fapi_api_queue_elem_t) pFirst, i);
+
+ pFirst= NULL;
+ pPrev = NULL;
+ return NULL;
+ }
+ else
+ {
+ }
+ }
+ wls_mac_add_blocks_to_ul();
+
+ }
+
+ return NULL;
+}
+
+void wls_mac_print_recv_list(p_fapi_api_queue_elem_t list, uint32_t i)
+{
+ printf("\nMAC received response %d from FAPI\n",i);
+}
+
+p_fapi_api_queue_elem_t wls_mac_create_elem(uint16_t num_msg, uint32_t align_offset, uint32_t msg_type, uint32_t n_loc)
+{
+ p_fapi_api_queue_elem_t p_list_elem;
+
+ p_list_elem = (p_fapi_api_queue_elem_t)wls_mac_alloc_buffer(num_msg * align_offset + sizeof(fapi_api_queue_elem_t), n_loc);
+
+ //Fill header for link list of API messages
+ if (p_list_elem)
+ {
+ p_list_elem->msg_type = (uint8_t)msg_type;
+ p_list_elem->num_message_in_block = 1;
+ p_list_elem->align_offset = (uint16_t)align_offset;
+ p_list_elem->msg_len = num_msg * align_offset;
+ p_list_elem->p_next = NULL;
+ }
+
+ return p_list_elem;
+}
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param void
+ *
+ * @return 0 if SUCCESS
+ *
+ * @description
+ * This function initialized the WLS threads for the Testmac and allocates memory needed to
+ * exchange APIs between MAC and PHY
+ *
+**/
+//-------------------------------------------------------------------------------------------
+uint32_t wls_mac_init(char * wls_device_name, uint64_t nTotalMemorySize)
+{
+ uint32_t ret = FAILURE;
+ PWLS_MAC_CTX pWls = wls_mac_get_ctx();
+ uint8_t *pMemZone;
+ static const struct rte_memzone *mng_memzone;
+ wls_drv_ctx_t *pDrv_ctx;
+
+ sleep(1);
+
+ pthread_mutex_init((pthread_mutex_t *)&pWls->lock, NULL);
+ pthread_mutex_init((pthread_mutex_t *)&pWls->lock_alloc, NULL);
+
+ pWls->nTotalAllocCnt = 0;
+ pWls->nTotalFreeCnt = 0;
+ pWls->nTotalUlBufAllocCnt = 0;
+ pWls->nTotalUlBufFreeCnt = 0;
+ pWls->nTotalDlBufAllocCnt = 0;
+ pWls->nTotalDlBufFreeCnt = 0;
+
+ pWls->hWls = WLS_Open(wls_device_name, WLS_MASTER_CLIENT, nTotalMemorySize);
+ if (pWls->hWls)
+ {
+ /* allocate chuck of memory */
+ pWls->pWlsMemBase = WLS_Alloc(pWls->hWls, nTotalMemorySize);
+ if (pWls->pWlsMemBase)
+ {
+ pWls->nTotalMemorySize = (uint32_t) nTotalMemorySize;
+
+ ret = wls_mac_create_partition(pWls);
+
+ if (ret == SUCCESS)
+ {
+ int nBlocks = 0;
+ gwls_mac_ready = 1;
+
+ nBlocks = WLS_EnqueueBlock(pWls->hWls, wls_mac_va_to_pa(wls_mac_alloc_buffer(0, MIN_UL_BUF_LOCATIONS+2)));
+ /* allocate blocks for UL transmition */
+ while(WLS_EnqueueBlock(pWls->hWls, wls_mac_va_to_pa(wls_mac_alloc_buffer(0, MIN_UL_BUF_LOCATIONS+3))))
+ {
+ nBlocks++;
+ }
+
+ printf("WLS inited ok [%d]\n\n", nBlocks);
+ }
+ else
+ {
+ printf("can't create WLS Partition");
+ return FAILURE;
+ }
+
+ }
+ else
+ {
+ printf("can't allocate WLS memory");
+ return FAILURE;
+ }
+ }
+ else
+ {
+ printf("can't open WLS instance");
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup group_testmac
+ *
+ * @param void
+ *
+ * @return 0 if SUCCESS
+ *
+ * @description
+ * This function destroys the WLS layer for the testmac and de-allocates any memory used
+ *
+**/
+//-------------------------------------------------------------------------------------------
+uint32_t wls_mac_destroy(void)
+{
+ PWLS_MAC_CTX pWls = wls_mac_get_ctx();
+
+ if (pwls_testmac_thread)
+ {
+ pthread_cancel(*pwls_testmac_thread);
+
+ free(pwls_testmac_thread);
+ pwls_testmac_thread = NULL;
+
+ if(pWls->pWlsMemBase)
+ {
+ WLS_Free(pWls->hWls, pWls->pWlsMemBase);
+ }
+
+ WLS_Close(pWls->hWls);
+ printf("wls_mac_rx_task: [PID: %6d]... Stopping\n", gwls_pid);
+ }
+
+ return SUCCESS;
+}
+
+uint8_t mac_dpdk_init()
+{
+ uint8_t retval;
+ char whitelist[32];
+ uint8_t i;
+
+ char *argv[] = {"mac_app", "--proc-type=secondary",
+ "--file-prefix", "wls", whitelist};
+
+ int argc = RTE_DIM(argv);
+
+ /* initialize EAL first */
+ sprintf(whitelist, "-w %s", "0000:00:06.0");
+ printf("[MAC] Calling rte_eal_init: ");
+
+ for (i = 0; i < RTE_DIM(argv); i++)
+ {
+ printf("%s ", argv[i]);
+ }
+ printf("\n");
+
+ if (rte_eal_init(argc, argv) < 0)
+ rte_panic("Cannot init EAL\n");
+
+ return SUCCESS;
+}
diff --git a/wls_lib/test/mac/mac_wls.h b/wls_lib/test/mac/mac_wls.h
new file mode 100644
index 0000000..59a0855
--- /dev/null
+++ b/wls_lib/test/mac/mac_wls.h
@@ -0,0 +1,77 @@
+/******************************************************************************
+*
+* Copyright (c) 2019 Intel.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*******************************************************************************/
+
+/**
+ * @brief This file has Shared Memory interface functions between MAC and PHY
+ * @file testmac_wls.h
+ * @ingroup group_testmac
+ * @author Intel Corporation
+ **/
+
+#ifndef _TESTMAC_WLS_H_
+#define _TESTMAC_WLS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//#include "common_typedef.h"
+#include "fapi_interface.h"
+
+#define SUCCESS 0
+#define FAILURE 1
+
+#define MAX_NUM_LOCATIONS (50)
+
+#define MIN_DL_BUF_LOCATIONS (0) /* Used for stats collection 0-49 */
+#define MIN_UL_BUF_LOCATIONS (MIN_DL_BUF_LOCATIONS + MAX_NUM_LOCATIONS) /* Used for stats collection 50-99 */
+
+#define MAX_DL_BUF_LOCATIONS (MIN_DL_BUF_LOCATIONS + MAX_NUM_LOCATIONS) /* Used for stats collection 0-49 */
+#define MAX_UL_BUF_LOCATIONS (MIN_UL_BUF_LOCATIONS + MAX_NUM_LOCATIONS) /* Used for stats collection 50-99 */
+
+typedef struct tagZBC_LIST_ITEM
+{
+ uint64_t pMsg;
+ uint32_t MsgSize;
+} ZBC_LIST_ITEM, *PZBC_LIST_ITEM;
+
+
+uint32_t wls_mac_init(char * wls_device_name, uint64_t nWlsMemorySize);
+void wls_mac_print_thread_info(void);
+uint32_t wls_mac_destroy(void);
+void *wls_mac_alloc_buffer(uint32_t size, uint32_t loc);
+uint32_t wls_mac_send_msg_to_phy(void *data);
+uint64_t wls_mac_va_to_pa(void *ptr);
+void *wls_mac_pa_to_va(uint64_t ptr);
+void wls_mac_free_buffer(void *pMsg, uint32_t loc);
+void wls_mac_get_time_stats(uint64_t *pTotal, uint64_t *pUsed, uint32_t nClear);
+void wls_mac_free_list_all(void);
+int wls_mac_free_list(uint32_t idx);
+p_fapi_api_queue_elem_t wls_mac_create_elem(uint16_t num_msg, uint32_t align_offset, uint32_t msg_type, uint32_t n_loc);
+void wls_mac_print_recv_list(p_fapi_api_queue_elem_t list, uint32_t i);
+uint8_t mac_dpdk_init();
+void *wls_mac_rx_task();
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* #ifndef _TESTMAC_WLS_H_ */
+
+
diff --git a/wls_lib/test/mac/makefile b/wls_lib/test/mac/makefile
new file mode 100644
index 0000000..b6ba703
--- /dev/null
+++ b/wls_lib/test/mac/makefile
@@ -0,0 +1,172 @@
+###############################################################################
+#
+# Copyright (c) 2019 Intel.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###############################################################################
+
+.SUFFIXES: .o .c .s .i .cpp
+
+# Makefile to build TestMac application
+
+##############################################################
+# Tools configuration
+##############################################################
+CC := icc
+CPP := icpc
+AS := as
+AR := ar
+LD := icc
+OBJDUMP := objdump
+
+ifeq ($(SHELL),cmd.exe)
+MD := mkdir.exe -p
+RM := rm.exe -rf
+else
+MD := mkdir -p
+RM := rm -rf
+endif
+
+##############################################################
+# TARGET
+##############################################################
+ifeq ($(RTE_TARGET),)
+ RTE_TARGET :=x86_64-native-linuxapp-icc
+endif
+##############################################################
+# DPDK
+##############################################################
+ifeq ($(RTE_SDK),)
+$(info Please make sure RTE_SDK points to DPDK folder (current version of DPDK is 18.08))
+ RTE_SDK := /opt/dpdk-18.08
+endif
+
+##############################################################
+# Projects folders
+##############################################################
+ORANDIR := $(DIR_WIRELESS_ORAN)
+WLSDIR := $(DIR_WIRELESS_WLS)
+BUILDDIR := ../build/mac
+SRCDIR := $(CURDIR)
+
+wls_mac_app_dep_file = $(BUILDDIR)/dep_file
+
+APP := ../bin/mac/mac_app
+
+INC := \
+ $(WLSDIR) \
+ $(SRCDIR) \
+ $(RTE_SDK)/$(RTE_TARGET)/include \
+ $(ORANDIR)/include \
+ $(ORANDIR) \
+ #$(FLEXRANDIR)/source/nr5g/api \
+ #$(FLEXRANDIR)/source/common \
+
+INC := $(addprefix -I,$(INC))
+
+DEFS := USE_WO_LOCK _GNU_SOURCE NR5G
+
+ifneq ($(PRINTDBG),)
+DEFS := $(DEFS) PRINTF_DBG_OK
+endif
+
+ifeq ($(DEBUG_MODE),true)
+DEFS := $(DEFS) DEBUG_MODE
+endif
+
+DEFS := $(addprefix -D,$(DEFS))
+
+CFLAGS := -g -Wall -wd9 -Wno-deprecated-declarations -Wimplicit-function-declaration -fasm-blocks $(DEFS) $(INC)
+
+ifeq ($(PRINTDBG),)
+CFLAGS := $(CFLAGS) -Werror
+endif
+
+RTE_LIBS := -L$(RTE_SDK)/$(RTE_TARGET)/lib -Wl,--whole-archive -Wl,-lrte_distributor -Wl,-lrte_kni -Wl,-lrte_pipeline -Wl,-lrte_table -Wl,-lrte_port -Wl,-lrte_timer -Wl,-lrte_hash -Wl,-lrte_lpm -Wl,-lrte_power -Wl,-lrte_acl -Wl,-lrte_meter -Wl,-lrte_sched -Wl,-lm -Wl,-lrt -Wl,--start-group -Wl,-lrte_kvargs -Wl,-lrte_mbuf -Wl,-lrte_ip_frag -Wl,-lrte_ethdev -Wl,-lrte_mempool -Wl,-lrte_mempool_ring -Wl,-lrte_ring -Wl,-lrte_bus_pci -Wl,-lrte_bus_vdev -Wl,-lrte_pci -Wl,-lrte_net -Wl,-lrte_eal -Wl,-lrte_cmdline -Wl,-lrte_cfgfile -Wl,-lrte_pmd_bond -Wl,-lrte_pmd_vmxnet3_uio -Wl,-lrte_pmd_i40e -Wl,-lrte_pmd_ixgbe -Wl,-lrte_pmd_e1000 -Wl,-lrte_pmd_ring -Wl,-lrt -Wl,-lm -Wl,-ldl -Wl,--end-group -Wl,--no-whole-archive
+LDFLAGS := -g -Wl,-lrt -Wl,-lpthread -Wl,-lhugetlbfs -Wl,-lm -Wl,-lnuma -L $(WLSDIR) -lwls
+
+LINUX_WLS_MAC_APP_SRC := \
+ $(SRCDIR)/mac_main.c \
+ $(SRCDIR)/mac_wls.c \
+
+OBJS := $(LINUX_WLS_MAC_APP_SRC:.c=.o)
+
+PROJECT_OBJ_DIR = $(BUILDDIR)
+
+OBJS := $(addprefix $(PROJECT_OBJ_DIR)/,$(OBJS))
+
+DIRLIST := $(sort $(dir $(OBJS)))
+
+CC_DEPS := $(addprefix __dep__,$(LINUX_WLS_MAC_APP_SRC))
+
+GEN_DEP :=
+ifeq ($(wildcard $(wls_mac_app_dep_file)),)
+GEN_DEP := regenerate_dep
+endif
+
+.PHONY: $(APP)
+$(APP): $(DIRLIST) echo_options $(GEN_DEP) $(OBJS)
+ @echo [LD] $(APP)
+ @$(CC) -o $(APP) $(OBJS) $(RTE_LIBS) $(LDFLAGS)
+# $(OBJDUMP) -d $(APP) > $(APP).asm
+
+.PHONY : echo_options
+echo_options:
+ @echo [CFLAGS] $(CFLAGS)
+ @echo [LDFAGS] $(LDFLAGS)
+
+
+ifneq ($(wildcard $(wls_mac_app_dep_file)),)
+include $(wls_mac_app_dep_file)
+endif
+
+$(DIRLIST) :
+ -@$(MD) $@
+
+.PHONY : regenerate_dep
+regenerate_dep : clean_dep echo_regeenrate_dep $(CC_DEPS)
+
+.PHONY: clean_dep
+clean_dep:
+ $(RM) $(wls_mac_app_dep_file)
+
+.PHONY : echo_regeenrate_dep
+echo_regeenrate_dep:
+ @echo regenerating dep files
+
+
+.PHONY : CC_DEPS
+$(CC_DEPS):
+ @$(CC) -MM $(subst __dep__,,$@) -MT $(addprefix $(PROJECT_OBJ_DIR)/,$(patsubst %.c,%.o,$(subst __dep__,,$@))) $(CFLAGS) >> $(wls_mac_app_dep_file)
+
+$(OBJS) : $(PROJECT_OBJ_DIR)/%.o: %.c
+ @echo [CC] $(subst $(PROJECT_OBJ_DIR)/,,$@)
+ @echo "";echo $@
+ @echo "";echo $(subst $(PROJECT_OBJ_DIR)/,,$@)
+ @echo "";echo $(patsubst %.o,%.c,$(subst $(PROJECT_OBJ_DIR)/,,$@))
+ @echo ""
+ $(CC) -c $(CFLAGS) -o"$@" $(patsubst %.o,%.c,$(subst $(PROJECT_OBJ_DIR)/,,$@))
+
+
+.PHONY: xclean
+xclean : clean_dep
+ @$(RM) $(OBJS)
+ @$(RM) $(APP)
+ @$(RM) $(BUILDDIR)
+
+.PHONY: clean
+clean :
+ @$(RM) $(OBJS)
+ @$(RM) $(APP)
+
diff --git a/wls_lib/test/phy/makefile b/wls_lib/test/phy/makefile
new file mode 100644
index 0000000..f18d9d2
--- /dev/null
+++ b/wls_lib/test/phy/makefile
@@ -0,0 +1,162 @@
+###############################################################################
+#
+# Copyright (c) 2019 Intel.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###############################################################################
+
+.SUFFIXES: .o .c .s .i .cpp
+
+# Makefile to build Testphy application
+
+##############################################################
+# Tools configuration
+##############################################################
+CC := icc
+CPP := icpc
+AS := as
+AR := ar
+LD := icc
+OBJDUMP := objdump
+
+ifeq ($(SHELL),cmd.exe)
+MD := mkdir.exe -p
+RM := rm.exe -rf
+else
+MD := mkdir -p
+RM := rm -rf
+endif
+
+##############################################################
+# TARGET
+##############################################################
+ifeq ($(RTE_TARGET),)
+ RTE_TARGET :=x86_64-native-linuxapp-icc
+endif
+##############################################################
+# DPDK
+##############################################################
+ifeq ($(RTE_SDK),)
+$(info Please make sure RTE_SDK points to DPDK folder (current version of DPDK is 18.08))
+ RTE_SDK := /opt/dpdk-18.08
+endif
+
+##############################################################
+# Projects folders
+##############################################################
+WLSDIR := $(DIR_WIRELESS_WLS)
+BUILDDIR := ../build/phy
+SRCDIR := $(CURDIR)
+
+wls_phy_app_dep_file = $(BUILDDIR)/dep_file
+
+APP := ../bin/phy/phy_app
+
+INC := \
+ $(WLSDIR) \
+ $(SRCDIR) \
+ $(RTE_SDK)/$(RTE_TARGET)/include \
+
+INC := $(addprefix -I,$(INC))
+
+DEFS := USE_WO_LOCK _GNU_SOURCE NR5G
+
+ifneq ($(PRINTDBG),)
+DEFS := $(DEFS) PRINTF_DBG_OK
+endif
+
+ifeq ($(DEBUG_MODE),true)
+DEFS := $(DEFS) DEBUG_MODE
+endif
+
+DEFS := $(addprefix -D,$(DEFS))
+
+CFLAGS := -g -Wall -wd9 -Wno-deprecated-declarations -Wimplicit-function-declaration -fasm-blocks $(DEFS) $(INC)
+
+ifeq ($(PRINTDBG),)
+CFLAGS := $(CFLAGS) -Werror
+endif
+
+RTE_LIBS := -L$(RTE_SDK)/$(RTE_TARGET)/lib -Wl,--whole-archive -Wl,-lrte_distributor -Wl,-lrte_kni -Wl,-lrte_pipeline -Wl,-lrte_table -Wl,-lrte_port -Wl,-lrte_timer -Wl,-lrte_hash -Wl,-lrte_lpm -Wl,-lrte_power -Wl,-lrte_acl -Wl,-lrte_meter -Wl,-lrte_sched -Wl,-lm -Wl,-lrt -Wl,--start-group -Wl,-lrte_kvargs -Wl,-lrte_mbuf -Wl,-lrte_ip_frag -Wl,-lrte_ethdev -Wl,-lrte_mempool -Wl,-lrte_mempool_ring -Wl,-lrte_ring -Wl,-lrte_bus_pci -Wl,-lrte_bus_vdev -Wl,-lrte_pci -Wl,-lrte_net -Wl,-lrte_eal -Wl,-lrte_cmdline -Wl,-lrte_cfgfile -Wl,-lrte_pmd_bond -Wl,-lrte_pmd_vmxnet3_uio -Wl,-lrte_pmd_i40e -Wl,-lrte_pmd_ixgbe -Wl,-lrte_pmd_e1000 -Wl,-lrte_pmd_ring -Wl,-lrt -Wl,-lm -Wl,-ldl -Wl,--end-group -Wl,--no-whole-archive
+LDFLAGS := -g -Wl,-lrt -Wl,-lpthread -Wl,-lhugetlbfs -Wl,-lm -Wl,-lnuma -L $(WLSDIR) -lwls
+
+LINUX_WLS_PHY_APP_SRC := \
+ $(SRCDIR)/phy_main.c \
+
+OBJS := $(LINUX_WLS_PHY_APP_SRC:.c=.o)
+
+PROJECT_OBJ_DIR = $(BUILDDIR)
+
+OBJS := $(addprefix $(PROJECT_OBJ_DIR)/,$(OBJS))
+
+DIRLIST := $(sort $(dir $(OBJS)))
+
+CC_DEPS := $(addprefix __dep__,$(LINUX_WLS_PHY_APP_SRC))
+
+GEN_DEP :=
+ifeq ($(wildcard $(wls_phy_app_dep_file)),)
+GEN_DEP := regenerate_dep
+endif
+
+.PHONY: $(APP)
+$(APP): $(DIRLIST) echo_options $(GEN_DEP) $(OBJS)
+ @echo [LD] $(APP)
+ @$(CC) -o $(APP) $(OBJS) $(RTE_LIBS) $(LDFLAGS)
+# $(OBJDUMP) -d $(APP) > $(APP).asm
+
+.PHONY : echo_options
+echo_options:
+ @echo [CFLAGS] $(CFLAGS)
+ @echo [LDFAGS] $(LDFLAGS)
+
+
+ifneq ($(wildcard $(wls_phy_app_dep_file)),)
+include $(wls_phy_app_dep_file)
+endif
+
+$(DIRLIST) :
+ -@$(MD) $@
+
+.PHONY : regenerate_dep
+regenerate_dep : clean_dep echo_regeenrate_dep $(CC_DEPS)
+
+.PHONY: clean_dep
+clean_dep:
+ $(RM) $(wls_phy_app_dep_file)
+
+.PHONY : echo_regeenrate_dep
+echo_regeenrate_dep:
+ @echo regenerating dep files
+
+
+.PHONY : CC_DEPS
+$(CC_DEPS):
+ @$(CC) -MM $(subst __dep__,,$@) -MT $(addprefix $(PROJECT_OBJ_DIR)/,$(patsubst %.c,%.o,$(subst __dep__,,$@))) $(CFLAGS) >> $(wls_phy_app_dep_file)
+
+$(OBJS) : $(PROJECT_OBJ_DIR)/%.o: %.c
+ @echo [CC] $(subst $(PROJECT_OBJ_DIR)/,,$@)
+ @$(CC) -c $(CFLAGS) -o"$@" $(patsubst %.o,%.c,$(subst $(PROJECT_OBJ_DIR)/,,$@))
+
+
+.PHONY: xclean
+xclean : clean_dep
+ @$(RM) $(OBJS)
+ @$(RM) $(APP)
+ @$(RM) $(BUILDDIR)
+
+.PHONY: clean
+clean :
+ @$(RM) $(OBJS)
+ @$(RM) $(APP)
+
diff --git a/wls_lib/test/phy/phy_main.c b/wls_lib/test/phy/phy_main.c
new file mode 100644
index 0000000..cf3dd61
--- /dev/null
+++ b/wls_lib/test/phy/phy_main.c
@@ -0,0 +1,217 @@
+/******************************************************************************
+*
+* Copyright (c) 2019 Intel.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*******************************************************************************/
+
+/**
+ * @brief This file is test PHY wls lib main process
+ * @file phy_main.c
+ * @ingroup group_testphywls
+ * @author Intel Corporation
+ **/
+
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <rte_eal.h>
+#include <rte_cfgfile.h>
+#include <rte_string_fns.h>
+#include <rte_common.h>
+#include <rte_string_fns.h>
+#include <rte_lcore.h>
+#include <rte_debug.h>
+#include <rte_launch.h>
+
+#include "wls_lib.h"
+
+#define SUCCESS 0
+#define FAILURE 1
+#define WLS_TEST_DEV_NAME "wls"
+#define WLS_TEST_MSG_ID 1
+#define WLS_TEST_MSG_SIZE 100
+#define WLS_TEST_MEM_SIZE 2126512128
+#define NUM_PHY_MSGS 16
+
+typedef void* WLS_HANDLE;
+void *g_shmem;
+uint64_t g_shmem_size;
+
+WLS_HANDLE g_fapi_wls, g_phy_wls;
+
+uint8_t phy_dpdk_init(void);
+uint8_t phy_wls_init(const char *dev_name, unsigned long long mem_size);
+uint64_t phy_fapi_recv();
+uint8_t phy_fapi_send();
+
+int main()
+{
+ int64_t ret;
+ uint64_t p_msg;
+
+ // DPDK init
+ ret = phy_dpdk_init();
+ if (ret)
+ {
+ printf("\n[PHY] DPDK Init - Failed\n");
+ return FAILURE;
+ }
+ printf("\n[PHY] DPDK Init - Done\n");
+
+ // WLS init
+ ret = phy_wls_init(WLS_TEST_DEV_NAME, WLS_TEST_MEM_SIZE);
+ if(ret)
+ {
+ printf("\n[PHY] WLS Init - Failed\n");
+ return FAILURE;
+ }
+ printf("\n[PHY] WLS Init - Done\n");
+
+ // Receive from MAC WLS
+ p_msg = phy_fapi_recv();
+ if (!p_msg)
+ {
+ printf("\n[PHY] Receive from FAPI - Failed\n");
+ return FAILURE;
+ }
+ printf("\n[PHY] Receive from FAPI - Done\n");
+
+ // Sent to PHY WLS
+ ret = phy_fapi_send();
+ if (ret)
+ {
+ printf("\n[PHY] Send to FAPI - Failed\n");
+ return FAILURE;
+ }
+ printf("\n[PHY] Send to FAPI - Done\n");
+
+ printf("\n[PHY] Exiting...\n");
+
+ return SUCCESS;
+}
+
+uint8_t phy_dpdk_init(void)
+{
+ char whitelist[32];
+ uint8_t i;
+
+ char *argv[] = {"phy_app", "--proc-type=primary",
+ "--file-prefix", "wls", whitelist};
+
+ int argc = RTE_DIM(argv);
+
+ /* initialize EAL first */
+ sprintf(whitelist, "-w %s", "0000:00:06.0");
+ printf("[PHY] Calling rte_eal_init: ");
+
+ for (i = 0; i < RTE_DIM(argv); i++)
+ {
+ printf("%s ", argv[i]);
+ }
+ printf("\n");
+
+ if (rte_eal_init(argc, argv) < 0)
+ rte_panic("Cannot init EAL\n");
+
+ return SUCCESS;
+}
+
+uint8_t phy_wls_init(const char *dev_name, unsigned long long mem_size)
+{
+ g_phy_wls = WLS_Open(dev_name, WLS_SLAVE_CLIENT, mem_size);
+ if(NULL == g_phy_wls)
+ {
+ return FAILURE;
+ }
+ g_shmem_size = mem_size;
+
+ g_shmem = WLS_Alloc(g_phy_wls, g_shmem_size);
+ if (NULL == g_shmem)
+ {
+ printf("Unable to alloc WLS Memory\n");
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
+uint64_t phy_fapi_recv()
+{
+ uint8_t num_blks = 0;
+ uint64_t p_msg;
+ uint32_t msg_size;
+ uint16_t msg_id;
+ uint16_t flags;
+ uint32_t i=0;
+
+
+ while (1)
+ {
+ num_blks = WLS_Wait(g_phy_wls);
+ printf("WLS_Wait returns %d blocks\n",num_blks);
+
+ if (num_blks)
+ {
+ p_msg = WLS_Get(g_phy_wls, &msg_size, &msg_id, &flags);
+ if (p_msg)
+ {
+ printf("\n[PHY] FAPI2PHY WLS Received Block %d\n",i);
+ i++;
+ }
+ else
+ {
+ printf("\n[PHY] FAPI2PHY WLS Get Error for msg %d\n",i);
+ break;
+ }
+ if (flags & WLS_TF_FIN)
+ {
+ return p_msg;
+ }
+ }
+ else
+ {
+ printf("\n[PHY] FAPI2PHY WLS wait returned 0 blocks exiting \n");
+ return FAILURE;
+ }
+
+ }
+ return p_msg;
+}
+
+uint8_t phy_fapi_send()
+{
+ uint64_t pa_block = 0;
+ uint8_t ret = FAILURE;
+ uint32_t i;
+
+ for (i=0 ; i < NUM_PHY_MSGS; i++)
+ {
+
+ pa_block = (uint64_t) WLS_DequeueBlock((void*) g_phy_wls);
+ if (!pa_block)
+ {
+ printf("\n[PHY] FAPI2PHY WLS Dequeue block %d error\n",i);
+ return FAILURE;
+ }
+
+ ret = WLS_Put(g_phy_wls, pa_block, WLS_TEST_MSG_SIZE, WLS_TEST_MSG_ID, (i== (NUM_PHY_MSGS-1))? WLS_TF_FIN:0);
+ printf("\n[PHY] FAPI2PHY WLS Put Msg %d \n",i);
+ if (ret)
+ {
+ printf("\n[PHY] FAPI2PHY WLS Put Msg Error %d \n",i);
+ }
+ }
+ return ret;
+}
diff --git a/wls_lib/testapp/Makefile b/wls_lib/testapp/Makefile
new file mode 100644
index 0000000..6fcd6f6
--- /dev/null
+++ b/wls_lib/testapp/Makefile
@@ -0,0 +1,61 @@
+###############################################################################
+#
+# Copyright (c) 2019 Intel.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###############################################################################
+
+ifdef DPDK_WLS
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overridden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-icc
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = wls_test
+
+LDFLAGS += -L../.. -l wls -lpthread -lhugetlbfs
+
+# all source are stored in SRCS-y
+SRCS-y := pool.c testapp.c
+
+CFLAGS += $(WERROR_FLAGS) -I../.. -DDPDK_WLS
+EXTRA_CFLAGS += -g
+
+include $(RTE_SDK)/mk/rte.extapp.mk
+
+else
+
+#EXTRA_CFLAGS +=-g -Wall -wd9 -I../
+EXTRA_CFLAGS +=-g -Wall -I../
+LDFLAGS += -L../ -lwls
+
+# all source are stored in SRCS-y
+SRCS-y := pool.c testapp.c
+wls_test: testapp.o pool.o
+ $(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ testapp.o pool.o -L . -l wls -l pthread -l hugetlbfs
+
+CFLAGS += $(WERROR_FLAGS) -g -I../../
+testapp.o: testapp.c
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -o $@ -c $<
+
+pool.o: pool.c
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -o $@ -c $<
+
+clean:
+ rm -f *.o wls_test
+endif
diff --git a/wls_lib/testapp/pool.c b/wls_lib/testapp/pool.c
new file mode 100644
index 0000000..015c03b
--- /dev/null
+++ b/wls_lib/testapp/pool.c
@@ -0,0 +1,189 @@
+/******************************************************************************
+*
+* Copyright (c) 2019 Intel.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*******************************************************************************/
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#endif
+#include <string.h>
+#include <pthread.h>
+#include "pool.h"
+
+/*static void pool_mutex_destroy(pthread_mutex_t* pMutex)
+{
+ pthread_mutex_destroy(pMutex);
+}*/
+
+static void pool_mutex_init(pthread_mutex_t* pMutex)
+{
+ pthread_mutexattr_t prior;
+ pthread_mutexattr_init(&prior);
+ pthread_mutexattr_setprotocol(&prior, PTHREAD_PRIO_INHERIT);
+ pthread_mutex_init(pMutex, &prior);
+ pthread_mutexattr_destroy(&prior);
+}
+
+static void pool_mutex_lock(pthread_mutex_t* pMutex)
+{
+ pthread_mutex_lock(pMutex);
+}
+
+static void pool_mutex_unlock(pthread_mutex_t* pMutex)
+{
+ pthread_mutex_unlock(pMutex);
+}
+
+
+unsigned int PoolInit (PPOOL pPool, void * pStorage, unsigned int nBlockNum, unsigned int nBlockSize, unsigned long long* pFreePtr, unsigned long long* pUsedPtr)
+{
+ unsigned int i;
+
+ memset (pPool, 0, sizeof (*pPool));
+
+#ifdef __KERNEL__
+ mutex_init(&pPool->lock);
+#else
+ pool_mutex_init(&pPool->lock);
+#endif
+
+ pPool->StoragePtr = (unsigned char*)pStorage;
+ pPool->BlockSize = nBlockSize;
+ pPool->BlockNum = nBlockNum;
+
+ pPool->FreePtr = pFreePtr;
+ pPool->UsedPtr = pUsedPtr;
+
+ // to put the indexes to the free storage
+
+ i = 0;
+
+ while (i < nBlockNum)
+ {
+ PoolFree (pPool, pPool->StoragePtr + (pPool->BlockSize * i));
+ i++;
+ }
+
+ return 0;
+}
+
+void* PoolAlloc(PPOOL pPool)
+{
+ unsigned long long nIndex;
+ void* ret = NULL;
+
+#ifdef __KERNEL__
+ mutex_lock(&pPool->lock);
+#else
+ pool_mutex_lock(&pPool->lock);
+#endif
+
+ if (pPool->FreeGet == pPool->FreePut){
+#ifdef __KERNEL__
+ mutex_unlock(&pPool->lock);
+#else
+ pool_mutex_unlock(&pPool->lock);
+#endif
+ return ret;
+ }
+
+ nIndex = pPool->FreePtr[pPool->FreeGet++];
+
+ if (pPool->FreeGet >= (pPool->BlockNum+1))
+ pPool->FreeGet = 0;
+
+ ret = pPool->StoragePtr + (pPool->BlockSize * nIndex);
+
+#ifdef __KERNEL__
+ mutex_unlock(&pPool->lock);
+#else
+ pool_mutex_unlock(&pPool->lock);
+#endif
+
+ return ret;
+}
+
+unsigned int PoolFree(PPOOL pPool, void * pBlock)
+{
+ unsigned long long index;
+
+#ifdef __KERNEL__
+ mutex_lock(&pPool->lock);
+#else
+ pool_mutex_lock(&pPool->lock);
+#endif
+
+ index = (U64)((U64)pBlock - (U64)pPool->StoragePtr) / pPool->BlockSize;
+
+ pPool->FreePtr [pPool->FreePut ++] = index;
+
+ if (pPool->FreePut >= (pPool->BlockNum+1))
+ pPool->FreePut = 0;
+
+#ifdef __KERNEL__
+ mutex_unlock(&pPool->lock);
+#else
+ pool_mutex_unlock(&pPool->lock);
+#endif
+
+ return 1;
+}
+
+unsigned int PoolGetFreeNum(PPOOL pPool)
+{
+ unsigned int nCount;
+
+ if (pPool==NULL)
+ return 0;
+
+ if (pPool->FreePut >= pPool->FreeGet)
+ {
+ nCount = pPool->FreePut - pPool->FreeGet;
+ }
+ else
+ {
+ // the queue size is bigger on one element than a partition
+ // to prevent data loss
+
+ nCount = (pPool->BlockNum+1) - (pPool->FreeGet - pPool->FreePut);
+ }
+
+ return nCount;
+}
+
+unsigned int PoolGetAllocNum(PPOOL pPool)
+{
+ unsigned int nCount;
+
+ if (pPool==NULL)
+ return 0;
+
+ if (pPool->UsedPut >= pPool->UsedGet)
+ {
+ nCount = pPool->UsedPut - pPool->UsedGet;
+ }
+ else
+ {
+ // the queue size is bigger on one element than a partition
+ // to prevent data loss
+
+ nCount = (pPool->BlockNum+1) - (pPool->UsedGet - pPool->UsedPut);
+ }
+
+ return nCount;
+}
+
diff --git a/wls_lib/testapp/pool.h b/wls_lib/testapp/pool.h
new file mode 100644
index 0000000..bb1863e
--- /dev/null
+++ b/wls_lib/testapp/pool.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+*
+* Copyright (c) 2019 Intel.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*******************************************************************************/
+
+#ifndef _POOL_API_H_
+#define _POOL_API_H_
+
+#ifdef __KERNEL__
+#include <linux/mutex.h>
+#endif
+#include <pthread.h>
+#include "ttypes.h"
+
+
+typedef struct _POOL_
+{
+ unsigned char* StoragePtr; // The pointer to the storage where blocks are located
+ unsigned int BlockNum; // The number of blocks in storage
+ unsigned int BlockSize; // The size of block in bytes
+
+ unsigned long long* FreePtr; // The pointer to the storage with free object indexes
+ volatile unsigned long long FreePut; // PUT index used to put the new item to 'free' storage
+ volatile unsigned long long FreeGet; // GET index used to get the new free item from 'free' storage
+
+ unsigned long long* UsedPtr; // The pointer to the storage with 'Used' object indexes
+ volatile unsigned long long UsedPut; // PUT index used to put the new item to 'already used' storage
+ volatile unsigned long long UsedGet; // GET index used to get the item from 'already used' storage
+#ifdef __KERNEL__
+ struct mutex lock;
+#else
+ pthread_mutex_t lock;
+#endif
+}POOL, *PPOOL;
+
+
+unsigned int PoolInit (PPOOL pPool, void * pStorage, unsigned int nBlockNum, unsigned int nBlockSize, unsigned long long* pFreePtr, unsigned long long* pUsedPtr);
+void* PoolAlloc(PPOOL pPool);
+unsigned int PoolFree(PPOOL pPool, void * pBlock);
+unsigned int PoolGetFreeNum(PPOOL pPool);
+unsigned int PoolGetAllocNum(PPOOL pPool);
+
+#endif //_POOL_API_H_
diff --git a/wls_lib/testapp/testapp.c b/wls_lib/testapp/testapp.c
new file mode 100644
index 0000000..1bd9a84
--- /dev/null
+++ b/wls_lib/testapp/testapp.c
@@ -0,0 +1,1486 @@
+/******************************************************************************
+*
+* Copyright (c) 2019 Intel.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*******************************************************************************/
+
+/**
+ * WLS interface test application
+ * (contains functional unit tests and diagnostics to test wls
+ * supported by WLS interface)
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h> // for printf
+#include <string.h> // for memset
+#include <signal.h> // for SIGINT
+#include <unistd.h> // for usleep
+#include <stdlib.h> // for rand
+#include <getopt.h> // for getopt
+#include <sys/time.h>
+#include <pthread.h>
+#include <sched.h>
+#include "ttypes.h"
+#include "wls_lib.h"
+#include "pool.h"
+
+#define HANDLE PVOID
+
+
+#define K 1024
+#define M (K*K)
+
+#define DEFAULT_TEST_MEMORY_SIZE 256*M
+#define DEFAUTL_TEST_BLOCK_SIZE 16*K
+
+#define DEFAULT_MESSAGE_COUNT_PER_MS 10
+#define DEFAULT_MAX_MESSAGE_SIZE 2000
+#define DEFUALT_MIN_MESSAGE_SIZE 100
+
+#define APP_QUEUE_SIZE 255 /* number of elements each queue of the WLS being registered will have */
+#define MAX_MESSAGES 1000 /* per ms */
+
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+typedef enum {
+ APP_TC_SANITY_TEST = 0,
+} APP_TEST_CASES;
+
+typedef struct tagAPP_PARAMS {
+ char *wls_dev_name;
+ int aff_core;
+ int test_id;
+ int rx_id;
+ int tx_id;
+ int n_messages;
+ int max_size;
+ int min_size;
+ int interface_count;
+ U8 master;
+ U8 debug;
+ U8 crc;
+ U8 trusted;
+} APP_PARAMS, *PAPP_PARAMS;
+
+typedef struct tagAPP_MESSAGE {
+ U32 id;
+} APP_MESSAGE, *PAPP_MESSAGE;
+
+typedef struct tagAPP_CONTEXT {
+ V32 ExitStatus;
+ HANDLE hWls;
+
+ U32 master;
+
+ PVOID shm_memory;
+
+ POOL Pool; // The pool descriptor
+ void* PoolStrPtr; // The pool storage pointer to keep indexes
+
+ U16 RxID;
+ U16 TxID;
+
+ U16 nInterfaces; // number of RX identifiers used by the APP
+ //
+ U16 InitQueueSize; // for invalid messages test (to trigger WLS blocking)
+
+ //
+ U32 MsgPerMs;
+ U32 MaxMsgSize;
+ U32 MinMsgSize;
+
+ U32 TxCnt;
+ U32 RxCnt;
+
+ U64 nTxMsgs; // Messages transmitted
+ U64 nTxOctets; // Octets transmitted
+ U64 nRxMsgs; // Messages received
+ U64 nRxOcters; // Octets received
+ U64 Cycles; // number of 1ms cycles
+
+ int AppSanityMsgSize; // 4 or 8 depending on CRC feature
+ U8 Debug; // when TRUE app cycle is 1 sec, otherwise 1ms
+ U8 TrustedDataSource; // for trusted data sources ICC service removes msg validity checking.
+
+ void (*Receive)(HANDLE h);
+ void (*Transmit)(HANDLE h);
+
+ void (*ThreadReceive)(HANDLE h);
+ void (*ThreadTransmit)(HANDLE h);
+
+ int (*wls_put)(void* h, unsigned long long pMsg, unsigned int MsgSize, unsigned short MsgTypeID, unsigned short Flags);
+ unsigned long long (*wls_get)(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags);
+ unsigned long long (*wls_wget)(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags);
+
+ U8 *pLastRx; // used for scatter-gather test
+ U32 LastRxSize; // used for scatter-gather test
+
+ U32 *pServiceBuffer;
+
+ U32 TxMsgCnt;
+ PVOID TxMessages[MAX_MESSAGES];
+ U32 TxMessageSizes[MAX_MESSAGES]; // <-- required for Ping-Pong test to store received sizes
+ int core;
+
+} APP_CONTEXT, *PAPP_CONTEXT;
+
+APP_CONTEXT AppContext;
+
+static int pool_alloc = 0;
+static int pool_free = 0;
+
+static void ShowData(void* ptr, unsigned int size)
+{
+ U8 *d = ptr;
+ unsigned int i;
+
+ for (i = 0; i < size; i++) {
+ if (!(i & 0xf))
+ printf("\n");
+ printf("%02x ", d[i]);
+ }
+ printf("\n");
+}
+
+static void App_SigExitCallback(int signum)
+{
+ (void) signum;
+ AppContext.ExitStatus = TRUE;
+}
+
+static void* WlsVaToPa(void * ptr)
+{
+ PAPP_CONTEXT pCtx = &AppContext;
+ return (void*) WLS_VA2PA(pCtx->hWls, ptr);
+}
+
+static void* WlsPaToVa(void * ptr)
+{
+ PAPP_CONTEXT pCtx = &AppContext;
+ return (void*) WLS_PA2VA(pCtx->hWls, (U64) ptr);
+}
+
+static void* App_Alloc(void* h, unsigned long size)
+{
+ (void) h;
+ (void) size;
+ void * retval = NULL;
+ if (AppContext.master) {
+ retval = PoolAlloc(&(AppContext.Pool));
+ //printf("pPool->FreeGet %d == pPool->FreePut %d\n", AppContext.Pool.FreeGet, AppContext.Pool.FreePut);
+ } else {
+ retval = (void*) WLS_DequeueBlock(AppContext.hWls);
+ if (retval)
+ retval = (void*) WlsPaToVa(retval);
+ else
+ printf("WLS_DequeueBlock returned null\n");
+ }
+
+ if (retval == NULL) {
+ printf("no memory %d %d\n", pool_alloc, pool_free);
+ exit(-1);
+ } else
+ pool_alloc++;
+
+ return retval;
+}
+
+static int App_Free(void* h, void* pMsg)
+{
+ (void) h;
+ if (AppContext.master)
+ if (pMsg) {
+ pool_free++;
+ return (PoolFree(&(AppContext.Pool), pMsg) == 1 ? 0 : -1);
+ } else {
+ printf("Free Null pointer\n");
+ exit(-1);
+ } else
+ return 0;
+}
+
+static int App_MemoryInit(void* h, unsigned long size, U32 BlockSize)
+{
+ int ret = 0;
+ unsigned long long* pUsed;
+ unsigned long long* pFree;
+ PAPP_CONTEXT pCtx = &AppContext;
+ U32 nBlocksSlave = 0;
+
+ U32 nElmNum = size / BlockSize - 1;
+
+ // We need to allocate the memory for indexes and to initialize the
+ // pool descriptor, (x+1) is used to prevent queues overflow
+
+ pCtx->PoolStrPtr = malloc((nElmNum + 1) * 4 * sizeof (unsigned long long));
+
+ if (pCtx->PoolStrPtr == NULL)
+ return -1;
+
+ pFree = (unsigned long long*) pCtx->PoolStrPtr;
+ pUsed = pFree + (nElmNum + 1);
+
+ ret = PoolInit(&pCtx->Pool, h, nElmNum, BlockSize, pFree, pUsed);
+
+ if (ret == 0) {
+
+ if (AppContext.master) {
+ int res = TRUE;
+ /* allocate blocks for Slave to Master transmittion */
+ while (res) {
+ void* pBlock = App_Alloc(AppContext.hWls, DEFAUTL_TEST_BLOCK_SIZE);
+ if (pBlock) {
+ res = WLS_EnqueueBlock(AppContext.hWls, (U64) WlsVaToPa(pBlock));
+ if (res)
+ nBlocksSlave++;
+ else
+ App_Free(AppContext.hWls, pBlock);
+ } else
+ res = FALSE;
+ }
+ printf("Slave has %d free blocks\n", nBlocksSlave);
+ }
+ }
+
+ return ret;
+}
+
+/********************************/
+
+#define FAST_CRC16 1
+
+#if (FAST_CRC16)
+const U8 mb_table_level1[] = {
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
+};
+
+const U8 mb_table_level2[] = {
+ 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2,
+ 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04,
+ 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
+ 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8,
+ 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
+ 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
+ 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6,
+ 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10,
+ 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
+ 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
+ 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE,
+ 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
+ 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA,
+ 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C,
+ 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
+ 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0,
+ 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62,
+ 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
+ 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE,
+ 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
+ 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
+ 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C,
+ 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76,
+ 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
+ 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
+ 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54,
+ 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
+ 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98,
+ 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A,
+ 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
+ 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86,
+ 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40
+};
+
+#if 0
+// big endian CPU
+
+U16
+crc16(U16 crc, U8 data)
+{
+ U8 index;
+ U8 crc_Low = crc & 0xFF;
+ U8 crc_High = crc >> 8;
+
+ index = (crc_High ^ data) & 0xFF;
+ crc_High = crc_Low ^ mb_table_level1[ index ];
+ crc_Low = mb_table_level2[ index ];
+
+ return (crc_High << 8) | crc_Low;
+}
+#else
+// little endian CPU
+#if 0
+static U16 CRC16_Update(U16 crc, U8 data)
+{
+ U8 index;
+ U8 crc_High = crc >> 8;
+ U8 crc_Low = crc & 0xFF;
+
+ index = crc_Low ^ data;
+ crc_Low = crc_High ^ mb_table_level1[ index ];
+ crc_High = mb_table_level2[ index ];
+
+ return (crc_High << 8) | crc_Low;
+}
+#endif
+#endif
+
+#if 0
+/***********************************************
+ * CRC16 polynomial : X16 + X15 + X2 + 1 *
+ * FAST CRC16 routine *
+ * ---> pData - msg to be protected *
+ * ---> size - msg size in bytes *
+ * ---> aCRC - initializer (0xFFFF for 1st page)*
+ * <--- crc16 *
+ ***********************************************/
+static U16 CRC16_NoInit(U16 aCRC, U8 *pData, U16 size)
+{
+
+ if (!size)
+ return aCRC;
+ else {
+ U8 index;
+ U8 crc_High = aCRC >> 8;
+ U8 crc_Low = aCRC & 0xFF;
+
+ do {
+ index = crc_Low ^ *pData++;
+ crc_Low = crc_High ^ mb_table_level1[ index ];
+ crc_High = mb_table_level2[ index ];
+ } while (--size);
+
+ return (crc_High << 8) | crc_Low;
+ }
+}
+#endif
+
+#else // SLOW (canonic CRC16 calculation)
+
+/***********************************************
+ * CRC16 polynomial : X16 + X15 + X2 + 1 *
+ * ---> pData - msg to be protected *
+ * ---> size - msg size in bytes *
+ * ---> aCRC - initializer (0xFFFF for 1st page)*
+ * <--- crc16 *
+ ***********************************************/
+U16 CRC16_NoInit(U16 aCRC, U8 *pData, U16 size)
+{
+ U8 i, tmp;
+
+ if (!size)
+ return aCRC;
+
+ do {
+ aCRC ^= *pData++;
+ for (i = 0; i < 8; i++) {
+ tmp = aCRC & 0x01;
+ aCRC >>= 1;
+ if (tmp) {
+ aCRC ^= CRC16_DIVISOR;
+ }
+ }
+ } while (--size);
+ return aCRC;
+}
+
+#endif // FAST_CRC16
+
+
+#define CRC32_INIT_VAL 0xFFFFFFFF
+#define CRC32_DIVISOR 0xA0000001
+
+static U32 ICC_CRC32(U8 *pData, U32 size)
+{
+ U32 retval = CRC32_INIT_VAL;
+ U8 i, tmp;
+
+ if (!size)
+ return CRC32_INIT_VAL; // mean CRC error
+ do {
+ retval ^= *pData++;
+ for (i = 8; i > 0; --i) {
+ tmp = retval & 0x01;
+ retval >>= 1;
+ if (tmp) {
+ retval ^= CRC32_DIVISOR;
+ }
+ }
+ } while (--size);
+ return retval;
+}
+
+#if 0
+
+static U16 ICC_CRC16(U8 *pData, U16 size)
+{
+#define CRC16_ERROR (0xffff)
+ return CRC16_NoInit(CRC16_ERROR, pData, size); // use 0xFFFF as first initializer
+}
+#endif
+
+static int app_PutMessageCRC(void* h, unsigned long long pMsg, unsigned int MsgSize, unsigned short MsgTypeID, unsigned short Flags)
+{
+ U8 *p;
+ U64 pMsgVa = (U64) WlsPaToVa((void*) pMsg);
+
+ if (pMsgVa == 0)
+ {
+ return 0;
+ }
+ p = (U8 *) pMsgVa;
+#if 1
+ U32 crc = ICC_CRC32((U8 *) pMsgVa, MsgSize - sizeof (crc));
+ // CRC32
+ p[MsgSize - 4] = (crc >> 0) & 0xff;
+ p[MsgSize - 3] = (crc >> 8) & 0xff;
+ p[MsgSize - 2] = (crc >> 16) & 0xff;
+ p[MsgSize - 1] = (crc >> 24) & 0xff;
+#else
+ U16 crc = ICC_CRC16((U8 *) pMsg, MsgSize - sizeof (crc));
+ // CRC16
+ p[MsgSize - 2] = (crc >> 0) & 0xff;
+ p[MsgSize - 1] = (crc >> 8) & 0xff;
+#endif
+
+ return WLS_Put(h, (unsigned long long) pMsg, MsgSize, MsgTypeID, Flags);
+}
+
+static unsigned long long app_GetMessageCRC(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags)
+{
+ U64 pMsgPa = WLS_Get(h, MsgSize, MsgTypeID, Flags);
+ U64 pMsg = (U64) WlsPaToVa((void*) pMsgPa);
+
+ if (pMsg) {
+ U32 size = *MsgSize;
+#if 1
+ U32 crc = ICC_CRC32((U8*) pMsg, size);
+#else
+ U16 crc = ICC_CRC16((U8*) pMsg, size);
+#endif
+
+ if (crc != 0) {
+ printf("CRC error detected for message %p, size_%lu\n", (void*) pMsg, (long) size);
+ ShowData((U8*) pMsg, size);
+ }
+ }
+ return pMsgPa;
+}
+
+static unsigned long long app_WGetMessageCRC(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags)
+{
+ U64 pMsgPa = WLS_WGet(h, MsgSize, MsgTypeID, Flags);
+ U64 pMsg = (U64) WlsPaToVa((void*) pMsgPa);
+
+ if (pMsg) {
+ U32 size = *MsgSize;
+#if 1
+ U32 crc = ICC_CRC32((U8*) pMsg, size);
+#else
+ U16 crc = ICC_CRC16((U8*) pMsg, size);
+#endif
+
+ if (crc != 0) {
+ printf("CRC error detected for message %p, size_%lu\n", (void*) pMsg, (long) size);
+ ShowData((U8*) pMsg, size);
+ }
+ }
+ return pMsgPa;
+}
+
+static void CreateMessage(PAPP_MESSAGE p, U32 size)
+{
+ (void) size;
+ p->id = AppContext.TxCnt++;
+}
+
+static void CheckMessage(PAPP_MESSAGE p, U32 size)
+{
+ if (AppContext.RxCnt && p->id != AppContext.RxCnt) {
+ // char buf[8*K];
+ printf("rx message(id_%llu)_%lx error expected_%lu, received_%lu\n", (long long) AppContext.nRxMsgs, (U64) p, (long) AppContext.RxCnt, (long) p->id);
+ ShowData(p, size);
+ // if (TL_GetStatistics(AppContext.hWls, buf, sizeof(buf)))
+ // printf("%s", buf);
+ }
+
+ AppContext.RxCnt = p->id;
+ AppContext.RxCnt += 1;
+}
+
+/**
+ *******************************************************************************
+ *
+ * @fn app_AllocMultiple
+ * @brief used to allocate multiple blocks of the same size from the WLS
+ *
+ * @param[h] hWls - app thread WLS handle
+ * @param[o] pMsgs - ptr to beginning of array of points to allocated blocks
+ * @param[o] pMsgSizes - array to write size for each allocated blocks
+ * @param[i] nMsgs - number of blocks to allocate
+ * @return U32 - number of allocated blocks
+ *
+ * @description
+ * The routine is used allocate multiple blocks from the ICC service,
+ * the blocks are supposed to be same size blocks, satisfying
+ * appContext.MaxMsgSize parameter.
+ * In case the service is unable to provide requested number of blocks,
+ * smaller count is allocated. The routine returns actual number of allocated
+ * blocks
+ *
+ * @references
+ * MS-111070-SP
+ *
+ * @ingroup icc_service_unit_test
+ *
+ ******************************************************************************/
+static U32 app_AllocMultiple(HANDLE hWls, PVOID *pMsgs, U32 *pMsgSizes, U32 nMsgs)
+{
+ unsigned n = 0;
+ unsigned i, j;
+
+ memset(pMsgs, 0x00, sizeof (PVOID) * nMsgs);
+
+ while (nMsgs--) {
+ pMsgs[n] = App_Alloc(hWls, AppContext.MaxMsgSize);
+ pMsgSizes[n] = AppContext.MaxMsgSize;
+ if (!pMsgs[n]) {
+ printf("empty pool allocated_%u out of %lu\n", n, (long) AppContext.MsgPerMs);
+ break;
+ }
+ n += 1;
+ }
+
+ // check for duplicated pointers
+ for (i = 0; i < n; i++) {
+ for (j = i + 1; j < n; j++) {
+ if (pMsgs[i] == pMsgs[j]) {
+ printf("duplicated pointer %p (msg_id1_%u, msg_id2_%u)\n", pMsgs[i], i, j);
+ break;
+ }
+ }
+ }
+
+ return n;
+ //ShowData(TxMessages, sizeof(TxMessages));
+}
+
+/**
+ *******************************************************************************
+ *
+ * @fn app_SanityTestTransmitter
+ * @brief transmitter of default test case (0).
+ *
+ * @param[h] hWls - app thread WLS handle
+ * @return void
+ *
+ * @description
+ * The routine is used in test case 0 (non-blocking sanity unit test)
+ * The transmitter does allocate multiple blocks of the same size from the ICC
+ * service. Then it fills each block with incremental counter and transfers
+ * to other application specified by parameter TxID.
+ *
+ * @references
+ * MS-111070-SP
+ *
+ * @ingroup icc_service_unit_test
+ *
+ ******************************************************************************/
+static void app_SanityTestTransmitter(HANDLE hWls)
+{
+ U8 *pMsg;
+ unsigned n = app_AllocMultiple(hWls, AppContext.TxMessages, AppContext.TxMessageSizes, AppContext.MsgPerMs);
+ unsigned fn = n;
+ unsigned cnt = 0;
+ unsigned k = 0;
+ unsigned alloc = n;
+
+ // lets transmit some message for test
+ while (n--) {
+ pMsg = AppContext.TxMessages[cnt++];
+ if (pMsg) {
+ U32 size = (rand() % AppContext.MaxMsgSize);
+
+ if (size < AppContext.MinMsgSize)
+ size = AppContext.MinMsgSize;
+
+ memset(pMsg, cnt, size);
+ CreateMessage((PAPP_MESSAGE) pMsg, size);
+ if ((AppContext.wls_put(hWls, (U64) WlsVaToPa(pMsg), size, AppContext.TxID, 0) != 0)) {
+ printf("could not send the message_%p\n", pMsg);
+ break;
+ } else {
+ k++;
+ }
+ AppContext.nTxOctets += size;
+ AppContext.nTxMsgs += 1;
+ }
+ }
+
+ if (alloc != k)
+ printf("inorrect sent %d alloc %d \n", k, alloc);
+
+ cnt = 0;
+ while (fn--) {
+ pMsg = AppContext.TxMessages[cnt++];
+ if (pMsg) {
+ if (App_Free(hWls, pMsg) != 0)
+ printf("could not release the message_%p\n", pMsg);
+ } else
+ printf("pMsg is NULL [%d]\n", cnt);
+ }
+ if (cnt != k) {
+ printf("inorrect free sent %d free %d \nQuiting...\n", k, cnt);
+ AppContext.ExitStatus = 1;
+ }
+}
+
+#if 0
+/**
+ *******************************************************************************
+ *
+ * @fn app_ScatterGatherTransmitter
+ * @brief transmitter of default test case (15/16).
+ *
+ * @param[h] hWls - app thread WLS handle
+ * @return void
+ *
+ * @description
+ * The routine is used in test case 0 (non-blocking sanity unit test)
+ * The transmitter does allocate multiple blocks of the same size from the ICC
+ * service. Then it fills each block with incremental counter and transfers
+ * to other application specified by parameter TxID.
+ *
+ * @references
+ * MS-111070-SP
+ *
+ * @ingroup icc_service_unit_test
+ *
+ ******************************************************************************/
+static void app_ScatterGatherTransmitter(HANDLE hWls)
+{
+ U8 *pMsg;
+ unsigned n = app_AllocMultiple(hWls, AppContext.TxMessages, AppContext.TxMessageSizes, AppContext.MsgPerMs + 2);
+ unsigned i, cnt = 0, flags = 0;
+ U8 *p, *pOriginMsg = (U8 *)App_Alloc(hWls, AppContext.MaxMsgSize);
+ unsigned TotalSize = 0;
+
+ unsigned fn = n;
+ unsigned k = 0;
+ unsigned alloc = n;
+
+ if (!pOriginMsg) {
+ printf("No memory for App_Alloc()\n");
+ return;
+ }
+
+ flags = rand() & 0xff;
+
+ for(i = 0; i < AppContext.MaxMsgSize; i++)
+ pOriginMsg[i] = (flags + i) & 0xff;
+
+ // scatter original message among several blocks
+ for(i = 0; i < n; i++)
+ {
+ U32 size = (rand() % (AppContext.MaxMsgSize / n));
+
+ if (size < AppContext.MinMsgSize)
+ size = AppContext.MinMsgSize;
+
+ TotalSize += size;
+ AppContext.TxMessageSizes[i] = size;
+ //printf("size%d=%lu\n", i, size);
+ }
+
+ // adjust size of the last block
+ if (TotalSize < AppContext.MaxMsgSize)
+ {
+ AppContext.TxMessageSizes[n - 1] += AppContext.MaxMsgSize - TotalSize;
+ }
+ else if (TotalSize > AppContext.MaxMsgSize)
+ {
+ printf("error: size of the scatted blocks exceeding size of the original message\n");
+ }
+
+ p = pOriginMsg;
+ for(i = 0; i < n; i++)
+ {
+ // copy data into the scattered blocks
+ pMsg = AppContext.TxMessages[i];
+ memcpy(pMsg, p, AppContext.TxMessageSizes[i]);
+ p += AppContext.TxMessageSizes[i];
+ }
+
+ // transmit original message first
+ if (AppContext.wls_put(hWls, (U64)WlsVaToPa(pOriginMsg), AppContext.MaxMsgSize, AppContext.TxID, 0) != 0)
+ {
+ printf("could not send the message_%p\n", pOriginMsg);
+ if (App_Free(hWls, pOriginMsg) != 0)
+ printf("could not release the message_%p\n", pOriginMsg);
+ }
+ else
+ {
+ AppContext.nTxOctets += AppContext.MaxMsgSize;
+ AppContext.nTxMsgs += 1;
+ }
+
+ if(pOriginMsg){
+ if (App_Free(hWls, pOriginMsg) != 0)
+ printf("could not release the message_%p\n", pMsg);
+ }
+ else
+ printf("pOriginMsg is NULL \n");
+
+ // transmit scattered messages following their creation order
+ while (n--)
+ {
+ pMsg = AppContext.TxMessages[cnt];
+ if (!cnt)
+ flags = WLS_SG_FIRST;
+ else if (n == 0)
+ flags = WLS_SG_LAST;
+ else
+ flags = WLS_SG_NEXT;
+
+ if (AppContext.wls_put(hWls, (U64)WlsVaToPa(pMsg), AppContext.TxMessageSizes[cnt], AppContext.TxID, flags) != 0)
+ {
+ printf("could not send the message_%p\n", pMsg);
+ if (App_Free(hWls, pMsg) != 0)
+ printf("could not release the message_%p\n", pMsg);
+ }
+ else
+ k++;
+
+ AppContext.nTxOctets += AppContext.TxMessageSizes[cnt];
+ AppContext.nTxMsgs += 1;
+ cnt++;
+ }
+ if(alloc != k)
+ printf("inorrect sent %d alloc %d \n", k, alloc);
+
+ cnt = 0;
+ while (fn--)
+ {
+ pMsg = AppContext.TxMessages[cnt++];
+ if(pMsg){
+ if (App_Free(hWls, pMsg) != 0)
+ printf("could not release the message_%p\n", pMsg);
+ }
+ else
+ printf("pMsg is NULL [%d]\n", cnt);
+ }
+ if(cnt != k)
+ printf("inorrect free sent %d free %d \n", k, cnt);
+}
+#endif
+
+/**
+ *******************************************************************************
+ *
+ * @fn app_SanityTestReceiver
+ * @brief default sanity checking receiver used in multiple tests.
+ *
+ * @param[h] hWls - app thread WLS handle
+ * @return void
+ *
+ * @description
+ * The routine takes received messages and checks the sanity incremental
+ * counter to confirm the order. In case the counter does not correspond to
+ * expected counter (misordered message or incorrect message) an error is
+ * printed to STDOUT.
+ *
+ * @references
+ * MS-111070-SP
+ *
+ * @ingroup icc_service_unit_test
+ *
+ ******************************************************************************/
+static void app_SanityTestReceiver(HANDLE hWls)
+{
+ (void) hWls;
+ U32 MsgSize;
+ U8 *pMsg;
+ U8 *pMsgPa;
+ U8 *pMsgVa;
+ U8 TempBuf[16 * K];
+ unsigned short MsgTypeID;
+ unsigned short Flags;
+ U32 nBlocksSlave = 0;
+
+ // handle RX receiver
+ while (((pMsgPa = (U8 *) AppContext.wls_get(AppContext.hWls, &MsgSize, &MsgTypeID, &Flags)) != NULL)) {
+ pMsgVa = (U8 *) WlsPaToVa(pMsgPa);
+
+ if (pMsgVa == NULL) {
+ printf("va: %lx pa: %lx\n", (long) pMsgVa, (long) pMsgPa);
+ continue;
+ }
+
+ pMsg = pMsgVa;
+
+ if (((U64) pMsg & 0x3) == 0) {
+ // aligned message
+ CheckMessage((PAPP_MESSAGE) pMsg, MsgSize);
+ } else {
+ // misaligned message
+ printf("Unaligned message\n");
+ MsgSize = (MsgSize > sizeof (TempBuf)) ? sizeof (TempBuf) : MsgSize;
+ memcpy(TempBuf, pMsg, MsgSize);
+ // handle received message
+ CheckMessage((PAPP_MESSAGE) TempBuf, MsgSize);
+ }
+ App_Free(AppContext.hWls, pMsg);
+ AppContext.nRxOcters += MsgSize;
+ AppContext.nRxMsgs += 1;
+
+ if (AppContext.master) {
+ int res = TRUE;
+ /* allocate blocks for Slave to Master transmittion */
+ while (res) {
+ void* pBlock = App_Alloc(AppContext.hWls, DEFAUTL_TEST_BLOCK_SIZE);
+ if (pBlock) {
+ res = WLS_EnqueueBlock(AppContext.hWls, (U64) WlsVaToPa(pBlock));
+ if (res)
+ nBlocksSlave++;
+ else
+ App_Free(AppContext.hWls, pBlock);
+ } else
+ res = FALSE;
+ }
+ }
+
+ }
+}
+
+#if 0
+/**
+ *******************************************************************************
+ *
+ * @fn app_ScatterGatherReceiver
+ * @brief scatter gather test receiver
+ *
+ * @param[h] hWls - app thread WLS handle
+ * @return void
+ *
+ * @description
+ * The routine takes received messages and checks the sanity incremental
+ * counter to confirm the order. In case the counter does not correspond to
+ * expected counter (misordered message or incorrect message) an error is
+ * printed to STDOUT.
+ *
+ * @references
+ * MS-111070-SP
+ *
+ * @ingroup icc_service_unit_test
+ *
+ ******************************************************************************/
+static void app_ScatterGatherReceiver(HANDLE hWls)
+{
+ (void)hWls;
+ U32 MsgSize;
+ U8 *pMsg;
+ U8 *pMsgPa;
+ U8 *pMsgVa;
+ U32 size;
+ U8 err = 0;
+ unsigned short MsgTypeID;
+ unsigned short Flags;
+
+ // handle RX receiver
+ while ((pMsgPa = (U8*) AppContext.wls_get(AppContext.hWls, &MsgSize, &MsgTypeID, &Flags)) != NULL)
+ {
+ pMsgVa = (U8 *)WlsPaToVa(pMsgPa);
+
+ pMsg = pMsgVa;
+
+ AppContext.nRxOcters += MsgSize;
+ AppContext.nRxMsgs += 1;
+
+ if (!AppContext.pLastRx)
+ {
+ AppContext.pLastRx = pMsg;
+ AppContext.LastRxSize = MsgSize;
+ }
+ else // compare with received and release both
+ {
+ U32 i;
+ if (AppContext.LastRxSize != MsgSize)
+ printf("received wrong size, unsync? try to re-run app both clusters\n");
+
+ size = MsgSize;
+ if (size > AppContext.LastRxSize)
+ size = AppContext.LastRxSize;
+
+ for(i = 0; i < size; i++)
+ {
+ if (pMsg[i] != AppContext.pLastRx[i])
+ {
+ // error content doesn't match
+ err = TRUE;
+ break;
+ }
+ }
+
+ if (err)
+ {
+ printf("content verification failed, scatter-gather test FAIL\n");
+ // terminate
+ AppContext.Receive = NULL;
+ AppContext.Transmit = NULL;
+ App_Free(AppContext.hWls, pMsg);
+ App_Free(AppContext.hWls, AppContext.pLastRx);
+ return;
+ }
+
+ App_Free(AppContext.hWls, pMsg);
+ App_Free(AppContext.hWls, AppContext.pLastRx);
+ AppContext.pLastRx = NULL;
+ }
+
+ }
+}
+
+
+
+static U32 app_GetTime(void)
+{
+ struct timeval tv;
+ U32 time_ms = 0;
+ if (gettimeofday(&tv, NULL) == 0)
+ time_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+ return time_ms;
+}
+#endif
+
+/******************************************************************************
+ * *
+ * Application common routines *
+ * *
+ ******************************************************************************/
+
+/**
+ *******************************************************************************
+ *
+ * @fn app_UpdateStatistics
+ * @brief is used to update RX and TX statistics
+ *
+ * @param[n] void
+ * @return void
+ *
+ * @description
+ * The routine prints out the statistics of received and transmitted
+ * messages.
+ *
+ * @references
+ * MS-111070-SP
+ *
+ * @ingroup icc_service_unit_test
+ *
+ ******************************************************************************/
+
+static void app_UpdateStatistics(void)
+{
+ AppContext.Cycles += 1;
+
+ if (AppContext.Debug || AppContext.Cycles % 1000 == 0) {
+ printf("Rx(id_%u) (%llu) - (%llu KiB)\n", AppContext.RxID, (long long) AppContext.nRxMsgs, (long long) AppContext.nRxOcters >> 10);
+ printf("Tx(id_%u) (%llu) - (%llu KiB)\n", AppContext.TxID, (long long) AppContext.nTxMsgs, (long long) AppContext.nTxOctets >> 10);
+ }
+
+}
+
+/**
+ *******************************************************************************
+ *
+ * @fn app_Help
+ * @brief prints app help content
+ *
+ * @param[n] void
+ * @return void
+ *
+ * @description
+ * The routine is used to print help content to stdout.
+ *
+ * @references
+ * MS-111070-SP
+ *
+ * @ingroup icc_service_unit_test
+ *
+ ******************************************************************************/
+static void app_Help(void)
+{
+ char help_content[] = \
+ "WLS test application\n\n"\
+ "Usage: testapp [-c <test>] [-r <rxid>] [-t <txid>] [-n <msgcount>]\n\n"\
+ "supports the following parameters:\n\n"
+ "-c | --testcase <test number> 0 - default sanity test\n"\
+ " 1 - misaligned pointers test\n"\
+ " 2 - aligned 4 pointers test\n"\
+ " 3 - random pools test\n"\
+ " 4 - ping-pong (ZBC test)\n"\
+ " 5 - invalid messages test\n\n"\
+ "--trusted switches WLS to trusted mode\n"\
+ "-r | --rxid <id> used to specify RxTypeID\n"\
+ "-t | --txid <id> used to specify TxTypeID\n"\
+ "-n | --msgcount <count> used to specify number of messages per timeframe\n"\
+ "-l | --minsize <size> specifies MIN message size in bytes\n"\
+ "-s | --maxsize <size> specifies MAX message size in bytes\n"\
+ "--crc enables CRC generation and checking\n"\
+ "--debug increases sleep interval to 1 second\n"\
+ "-m | --master set predefined rxid and txid\n";
+
+ printf("%s", help_content);
+}
+
+/**
+ *******************************************************************************
+ *
+ * @fn app_ParseArgs
+ * @brief is used to parse incoming app args
+ *
+ * @param[i] argc - app arg count
+ * @param[i] argv - array of args
+ * @param[o] params - app startup params filled basing on args parse
+ * @return number of parsed args
+ *
+ * @description
+ * The routine is parse input args and convert them into app startup params
+ *
+ * @references
+ * MS-111070-SP
+ *
+ * @ingroup icc_service_unit_test
+ *
+ ******************************************************************************/
+static int app_ParseArgs(int argc, char ** argv, PAPP_PARAMS params)
+{
+ int c;
+ int *pInt;
+ int cnt = 0;
+
+ struct option long_options[] = {
+ {"wlsdev", required_argument, 0, 'w'},
+ {"affinity", required_argument, 0, 'a'},
+ {"testcase", required_argument, 0, 'c'},
+ {"rxid", required_argument, 0, 'r'},
+ {"txid", required_argument, 0, 't'},
+ {"msgcount", required_argument, 0, 'n'},
+ {"maxsize", required_argument, 0, 's'},
+ {"minsize", required_argument, 0, 'l'},
+ {"master", no_argument, 0, 'm'},
+ {"debug", no_argument, 0, 'd'}, /* slow down the app cycle from 1ms to 1s*/
+ {"icount", required_argument, 0, 'i'},
+ {"crc", no_argument, 0, 1},
+ {"trusted", no_argument, 0, 2},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+ };
+
+ memset(params, 0, sizeof (*params));
+
+ // set default values here
+ params->interface_count = 1;
+
+ while (1) {
+ //int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "a:w:c:r:t:n:s:l:mdi:h", long_options, &option_index);
+
+ if (c == -1)
+ break;
+
+ cnt += 1;
+ pInt = NULL;
+
+ switch (c) {
+ case 'a': // test Case selection
+ pInt = ¶ms->aff_core;
+ break;
+ case 'c': // test Case selection
+ pInt = ¶ms->test_id;
+ break;
+ case 'r': // rx id selection
+ pInt = ¶ms->rx_id;
+ break;
+ case 't': // tx id selection
+ pInt = ¶ms->tx_id;
+ break;
+ case 's': // select message size
+ pInt = ¶ms->max_size;
+ break;
+ case 'l': // select message size
+ pInt = ¶ms->min_size;
+ break;
+ case 'n': // select number of messages
+ pInt = ¶ms->n_messages;
+ break;
+ case 'i': // select number of interfaces to register
+ pInt = ¶ms->interface_count;
+ break;
+ case 'm':
+ params->master = TRUE;
+ break;
+ case 'd':
+ params->debug = TRUE;
+ break;
+ case 'w':
+ params->wls_dev_name = optarg;
+ break;
+ case 'h':
+ app_Help();
+ exit(0);
+ case 2:
+ params->trusted = TRUE;
+ break;
+ case 1: // crc checking enabled
+ params->crc = TRUE;
+ break;
+ }
+
+ if (pInt && optarg) {
+ // get int arg
+ if (optarg[0] == '0' && (optarg[1] == 'x' || optarg[1] == 'X')) {
+ sscanf(optarg, "%x", (unsigned *) pInt);
+ } else {
+ *pInt = atoi(optarg);
+ }
+ }
+ }
+ return cnt;
+}
+
+static int app_set_affinity(int coreNum)
+{
+ cpu_set_t cpuset;
+ int i, rc;
+
+ /* set main thread affinity mask to CPU7 */
+
+ CPU_ZERO(&cpuset);
+ CPU_SET(coreNum, &cpuset);
+
+ rc = pthread_setaffinity_np(pthread_self(), sizeof (cpu_set_t), &cpuset);
+ if (rc) {
+ perror("pthread_setaffinity_np failed");
+ printf("pthread_setaffinity_np failed: %d", rc);
+ }
+
+ /* check the actual affinity mask assigned to the thread */
+
+ CPU_ZERO(&cpuset);
+
+ rc = pthread_getaffinity_np(pthread_self(), sizeof (cpu_set_t), &cpuset);
+
+ if (rc) {
+ perror("pthread_getaffinity_np failed");
+ printf("pthread_getaffinity_np failed: %d", rc);
+ }
+
+ printf("set affinity: ");
+ for (i = 0; i < CPU_SETSIZE; i++)
+ if (CPU_ISSET(i, &cpuset))
+ printf(" CPU %d\n", i);
+
+ if (!CPU_ISSET(coreNum, &cpuset)) {
+ printf("affinity failed");
+ }
+
+ /**
+ A new thread created by pthread_create(3) inherits a copy of its
+ creator's CPU affinity mask. */
+
+ return rc;
+}
+
+/**
+ *******************************************************************************
+ *
+ * @fn app_ApplyParams
+ * @brief is used to apply application startup parameters
+ *
+ * @param[i] params - app startup params
+ * @return void
+ *
+ * @description
+ * The applies startup parameters
+ *
+ * @references
+ * MS-111070-SP
+ *
+ * @ingroup icc_service_unit_test
+ *
+ ******************************************************************************/
+static void app_ApplyParams(PAPP_PARAMS params)
+{
+ // apply parameters
+ printf("selected test case %d - ", params->test_id);
+ switch (params->test_id) {
+ case APP_TC_SANITY_TEST:
+ default:
+ printf("NON-BLOCKING SANITY TEST\n");
+ AppContext.Receive = app_SanityTestReceiver;
+ AppContext.Transmit = app_SanityTestTransmitter;
+ break;
+ }
+
+ AppContext.wls_put = WLS_Put;
+ AppContext.wls_get = WLS_Get;
+ AppContext.wls_wget = WLS_WGet;
+
+ AppContext.MsgPerMs = DEFAULT_MESSAGE_COUNT_PER_MS;
+ AppContext.MaxMsgSize = DEFAULT_MAX_MESSAGE_SIZE;
+ AppContext.MinMsgSize = DEFUALT_MIN_MESSAGE_SIZE;
+ AppContext.AppSanityMsgSize = sizeof (APP_MESSAGE);
+
+ if (params->master) {
+ printf("WLS test app (supposed to run as MEMORY MASTER)\n");
+ AppContext.master = TRUE;
+ AppContext.RxID = 1;
+ AppContext.TxID = 2;
+ } else {
+ AppContext.master = FALSE;
+ AppContext.RxID = 2;
+ AppContext.TxID = 1;
+ }
+
+ if (params->rx_id)
+ AppContext.RxID = params->rx_id;
+
+ if (params->tx_id)
+ AppContext.TxID = params->tx_id;
+
+ if (params->n_messages && params->n_messages < MAX_MESSAGES)
+ AppContext.MsgPerMs = params->n_messages;
+
+ if (params->min_size && params->min_size >= 4)
+ AppContext.MinMsgSize = params->min_size;
+
+ // default is 1 RX interface
+ printf("if count = %u\n", params->interface_count);
+ AppContext.nInterfaces = 1;
+ if (params->interface_count == 0) {
+ printf("WLS test app started as simple data source, no RX ID will be specified\n");
+ AppContext.nInterfaces = 0;
+ AppContext.RxID = 0; // override RxID
+ } else if (params->interface_count <= 7) {
+ AppContext.nInterfaces = params->interface_count;
+ }
+
+
+ AppContext.TrustedDataSource = params->trusted;
+
+ if (params->crc) {
+ if (AppContext.MinMsgSize < 8)
+ AppContext.MinMsgSize = 8;
+
+ AppContext.wls_put = app_PutMessageCRC;
+ AppContext.wls_get = app_GetMessageCRC;
+ AppContext.wls_wget = app_WGetMessageCRC;
+
+ AppContext.AppSanityMsgSize += 4; // + sizeof CRC
+ }
+
+ if (params->max_size && params->max_size <= 16 * K)
+ AppContext.MaxMsgSize = params->max_size;
+
+ if (params->max_size < params->min_size)
+ params->max_size = params->min_size;
+
+ AppContext.Debug = params->debug;
+
+ if (params->aff_core) {
+ AppContext.core = params->aff_core;
+ app_set_affinity(AppContext.core);
+ }
+
+ printf("The application started with:\n");
+ printf("Core ................ %d\n", AppContext.core);
+ printf("Rx interface count .. %d\n", AppContext.nInterfaces);
+ printf("RxID ................ %d\n", AppContext.RxID);
+ printf("TxID ................ %d\n", AppContext.TxID);
+ if (AppContext.Debug)
+ printf("Generating .......... %lu Messages per second (DEBUG MODE)\n", (long) AppContext.MsgPerMs);
+ else
+ printf("Generating .......... %lu Messages per ms\n", (long) AppContext.MsgPerMs);
+ printf("Max Message Size .... %lu bytes\n", (long) AppContext.MaxMsgSize);
+ printf("Min Message Size .... %lu bytes\n", (long) AppContext.MinMsgSize);
+ printf("Number of threads ... 1\n");
+ printf("CRC checking ........ ");
+ if (params->crc)
+ printf("ENABLED\n");
+ else
+ printf("DISABLED\n");
+}
+
+/**
+ *******************************************************************************
+ *
+ * @fn app_ReleaseAllocatedBuffers
+ * @brief releases ICC buffers allocated by the application
+ *
+ * @param[n] void
+ * @return void
+ *
+ * @description
+ * In process of making some tests when signal to close the application
+ * happens the app may keep some allocated buffers from the ICC pools. This
+ * routine does release these buffers back to ICC.
+ *
+ * @references
+ * MS-111070-SP
+ *
+ * @ingroup icc_service_unit_test
+ *
+ ******************************************************************************/
+static void app_ReleaseAllocatedBuffers(void)
+{
+ if (AppContext.TxMsgCnt && AppContext.master)
+ do {
+ AppContext.TxMsgCnt -= 1;
+ App_Free(AppContext.hWls, AppContext.TxMessages[ AppContext.TxMsgCnt ]);
+ } while (AppContext.TxMsgCnt != 0);
+}
+
+/**
+ *******************************************************************************
+ *
+ * @fn main
+ * @brief ICC test application main routine
+ *
+ * @param[n] void
+ * @return void
+ *
+ * @description
+ * Contains logic of the test (one RX/TX thread)
+ *
+ * @references
+ * MS-111070-SP
+ *
+ * @ingroup icc_service_unit_test
+ *
+ ****************************************************************************/
+int main(int argc, char* argv[])
+{
+ int retval = 0;
+ APP_PARAMS params;
+
+ signal(SIGINT, App_SigExitCallback);
+
+ memset(&AppContext, 0, sizeof (AppContext));
+ memset(¶ms, 0, sizeof (params));
+
+#ifdef DPDK_WLS
+ int ret = rte_eal_init(argc, argv);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
+
+ argc -= ret;
+ argv += ret;
+#endif
+
+ app_ParseArgs(argc, argv, ¶ms);
+ app_ApplyParams(¶ms);
+
+ AppContext.InitQueueSize = APP_QUEUE_SIZE;
+
+ AppContext.hWls = WLS_Open(params.wls_dev_name, AppContext.master, DEFAULT_TEST_MEMORY_SIZE);
+
+ if (!AppContext.hWls) {
+ printf("could not register WLS client\n");
+ return 1;
+ } else {
+ printf("WLS has been registered\n");
+ }
+
+ AppContext.shm_memory = WLS_Alloc(AppContext.hWls, DEFAULT_TEST_MEMORY_SIZE);
+
+ if (AppContext.shm_memory == NULL) {
+ if (AppContext.master)
+ printf("could not create WLS shared memory\n");
+ else
+ printf("could not attach WLS shared memory\n");
+
+ return -1;
+ }
+
+ if (AppContext.master) {
+ if (App_MemoryInit(AppContext.shm_memory, DEFAULT_TEST_MEMORY_SIZE, DEFAUTL_TEST_BLOCK_SIZE) != 0) {
+ WLS_Free(AppContext.hWls, AppContext.shm_memory);
+ WLS_Close(AppContext.hWls);
+ exit(1);
+ }
+
+ }
+
+ // APPLICATION MAIN LOOP
+ while (!AppContext.ExitStatus && (AppContext.Receive || AppContext.Transmit)) {
+ if (AppContext.Receive)
+ AppContext.Receive(AppContext.hWls);
+
+ if (AppContext.Debug)
+ //usleep(10000); // 1 sec delay
+ sleep(1); // 1 sec delay
+ else
+ usleep(1000); // 1 ms delay
+
+ if (AppContext.Transmit)
+ AppContext.Transmit(AppContext.hWls);
+
+ app_UpdateStatistics();
+ }
+
+ app_ReleaseAllocatedBuffers();
+ printf("deregistering WLS (TxTotal_%llu, RxTotal_%llu)\n", (long long) AppContext.nTxMsgs, (long long) AppContext.nRxMsgs);
+ WLS_Free(AppContext.hWls, AppContext.shm_memory);
+ WLS_Close(AppContext.hWls);
+ return retval;
+}
diff --git a/wls_lib/testapp/wls_test.sh b/wls_lib/testapp/wls_test.sh
new file mode 100644
index 0000000..79f154f
--- /dev/null
+++ b/wls_lib/testapp/wls_test.sh
@@ -0,0 +1,86 @@
+#!/bin/bash
+###############################################################################
+#
+# Copyright (c) 2019 Intel.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###############################################################################
+
+COREMASK=2
+SECONDARY=1
+FPREFIX="wls"
+DPDK_WLS=0
+
+while getopts ":mpa:w:" opt; do
+ case ${opt} in
+ m )
+ SECONDARY=0
+ ;;
+ a )
+ COREMASK=$((1 << $OPTARG))
+ ;;
+ : )
+ echo "Invalid option: $OPTARG requires a core number"
+ exit 1
+ ;;
+ w )
+ #replace / with _ for dpdk file prefix
+ FPREFIX=${OPTARG////_}
+ ;;
+ : )
+ echo "Invalid option: $OPTARG requires dev wls path"
+ exit 1
+ ;;
+ p )
+ DPDK_WLS=1
+ ;;
+ esac
+done
+
+wlsTestBinary="wls_test"
+if [ $DPDK_WLS -eq 1 ]; then
+ if [ $SECONDARY -eq 0 ]; then
+ wlsTestBinary="build/wls_test -c $COREMASK -n 4 "
+ wlsTestBinary+="--file-prefix=$FPREFIX --socket-mem=3072 --"
+ else
+ wlsTestBinary="build/wls_test -c $COREMASK -n 4 "
+ wlsTestBinary+="--proc-type=secondary --file-prefix=$FPREFIX --"
+ fi
+fi
+
+ulimit -c unlimited
+
+export RTE_WLS=$PWD/..
+
+MACHINE_TYPE=`uname -m`
+
+if [ ${MACHINE_TYPE} == 'x86_64' ]; then
+ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$RTE_WLS
+
+ grep Huge /proc/meminfo
+
+ ulimit -c unlimited
+ echo 1 > /proc/sys/kernel/core_uses_pid
+ sysctl -w kernel.sched_rt_runtime_us=-1
+ for c in $(ls -d /sys/devices/system/cpu/cpu[0-9]*); do echo performance >$c/cpufreq/scaling_governor; done
+ sysctl -w kernel.shmmax=2147483648
+ sysctl -w kernel.shmall=2147483648
+fi
+
+wlsCmd="./${wlsTestBinary} $*"
+echo "Running... ${wlsCmd}"
+
+eval $wlsCmd
+
+exit 0
diff --git a/wls_lib/ttypes.h b/wls_lib/ttypes.h
new file mode 100644
index 0000000..4130efc
--- /dev/null
+++ b/wls_lib/ttypes.h
@@ -0,0 +1,195 @@
+/******************************************************************************
+*
+* Copyright (c) 2019 Intel.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*******************************************************************************/
+
+#ifndef __TTYPES_H__
+#define __TTYPES_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif /*TRUE*/
+
+#ifndef FALSE
+#define FALSE 0
+#endif /*FALSE*/
+
+#ifndef NULL
+#define NULL (void*)0
+#endif /*NULL*/
+
+/************************************************************************/
+/* SINT64, SINT32, SINT16 and SINT8 definition */
+/************************************************************************/
+#ifndef _SINT64_
+#define _SINT64_
+typedef long long SINT64, *PSINT64;
+#endif /*_SINT64_*/
+
+#ifndef _SINT32_
+#define _SINT32_
+typedef int SINT32, *PSINT32;
+#endif /*_SINT32_*/
+
+#ifndef _SINT16_
+#define _SINT16_
+typedef short SINT16, *PSINT16;
+#endif /*_SINT16_*/
+
+#ifndef _SINT8_
+#define _SINT8_
+typedef char SINT8, *PSINT8;
+#endif /*_SINT8_*/
+
+#ifndef _PVOID_
+#define _PVOID_
+typedef void *PVOID;
+#endif /*_PVOID_*/
+
+#ifndef _BOOL_
+#define _BOOL_
+typedef unsigned char BOOL;
+#endif /*_BOOL_*/
+
+#ifndef _U8_
+typedef unsigned char U8; /* unsigned 8-bit integer */
+#define _U8_
+#endif
+
+#ifndef _U16_
+typedef unsigned short U16; /* unsigned 16-bit integer */
+#define _U16_
+#endif
+
+#ifndef _U32_
+typedef unsigned int U32; /* unsigned 32-bit integer */
+#define _U32_
+#endif
+
+#ifndef _U64_
+#ifdef __x86_64__
+typedef unsigned long U64; /* unsigned 64-bit integer */
+#else
+typedef unsigned long long U64; /* unsigned 64-bit integer */
+#endif
+#define _U64_
+#endif
+
+#ifndef _V8_
+typedef volatile unsigned char V8;
+#define _V8_
+#endif
+
+#ifndef _V16_
+typedef volatile unsigned short V16;
+#define _V16_
+#endif
+
+#ifndef _V32_
+typedef volatile unsigned int V32;
+#define _V32_
+#endif
+
+#ifndef _S8_
+typedef signed char S8; /* 8-bit signed integer */
+#define _S8_
+#endif
+
+#ifndef _S16_
+typedef signed short S16; /* 16-bit signed integer */
+#define _S16_
+#endif
+
+#ifndef _S32_
+typedef signed int S32; /* 32-bit signed integer */
+#define _S32_
+#endif
+
+#ifndef _S64_
+#ifdef __x86_64__
+typedef signed long S64; /* unsigned 64-bit integer */
+#else
+typedef signed long long S64; /* unsigned 64-bit integer */
+#endif
+#define _S64_
+#endif
+
+#ifndef _PVOID_
+#define _PVOID_
+typedef void *PVOID;
+#endif
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+#endif
+
+#define CONV_ENDIAN_32(v) ((v & 0xff) << 24 | (v >> 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8));
+
+
+#ifndef MAX
+#define MAX(x, y) ((x) >= (y) ? (x) : (y))
+#endif
+
+#ifndef MIN
+#define MIN(x, y) ((x) <= (y) ? (x) : (y))
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+typedef void (*VOIDCB)(void);
+
+typedef void (*CALLBACK)(PVOID);
+
+#define BCTRL_LEN_MASK 0x0000FFFF
+#define BCTRL_BLAST_MASK 0x00010000
+
+#define DMAFCTRL_IRQEN 0x00000001
+#define DMAFCTRL_INBOFF 0x0000FFF0
+
+#define ARRAY_COUNT(v) (sizeof(v)/sizeof(v[0]))
+
+#ifndef ROUND
+#define ROUND(x, dx) (((x) + ((dx) - 1) ) & ~((dx) - 1))
+#endif
+
+#define REG32CLR(addr, clr_mask) ( REG32(addr) = REG32(addr) & (~(clr_mask)) )
+#define REG32SET(addr, set_mask) ( REG32(addr) = REG32(addr) | (set_mask) )
+#define REG32UPD(addr, clr_mask, set_mask) ( REG32(addr) = (REG32(addr) & (~(clr_mask))) | (set_mask) )
+
+// Standard function return types
+#ifndef _RESULTCODE_
+#define _RESULTCODE_
+typedef unsigned int RESULTCODE;
+#endif
+
+typedef unsigned int RETURNVALUE;
+
+#define SUCCESS 0
+#define FAILURE 1
+#define EXPIRED 2 // Not an error - wait operation expired
+#define RESTART 3 // Not an error - indicate we need to restart process
+
+//#define _DEBUG_
+
+#endif /*__SYSTYPES_H__ */
+
diff --git a/wls_lib/wls.h b/wls_lib/wls.h
new file mode 100644
index 0000000..d711a62
--- /dev/null
+++ b/wls_lib/wls.h
@@ -0,0 +1,352 @@
+/******************************************************************************
+*
+* Copyright (c) 2019 Intel.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*******************************************************************************/
+
+#ifndef __WLS_H__
+#define __WLS_H__
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/ioctl.h>
+#include <linux/cdev.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#define MODNAME (KBUILD_MODNAME)
+#else /* __KERNEL__ */
+#include <sys/ioctl.h>
+#include <stdint.h>
+
+#ifdef DPDK_WLS
+#include <semaphore.h>
+#include <rte_common.h>
+#include <rte_atomic.h>
+#include <rte_memzone.h>
+#endif /* DPDK_WLS */
+
+#endif
+#include "ttypes.h"
+#include "syslib.h"
+
+#define WLS_PRINT(format, args...) printk(format, ##args)
+#define WLS_ERROR(format, args...) printk(KERN_ERR "wls err: " format,##args)
+
+#ifdef _DEBUG_
+#define WLS_DEBUG(format, args...) \
+do { \
+ printk(KERN_INFO "wls debug: " format,##args); \
+}while(0)
+#else /*_DEBUG_*/
+#define WLS_DEBUG(format, args...) do { } while(0)
+#endif /*_DEBUG_*/
+
+/******************************************************************************
+* Module error codes *
+******************************************************************************/
+#define WLS_RC_MDMA_ID_ERROR (-1)
+#define WLS_RC_MDMA_TASK_ERROR (-2)
+#define WLS_RC_ALLOC_DELAY_MEM_ERROR (-3)
+#define WLS_RC_ALLOC_BAR_MEM_ERROR (-4)
+#define WLS_RC_ALLOC_TAR_MEM_ERROR (-5)
+#define WLS_RC_PARAM_SIZE_ERROR (-6)
+#define WLS_RC_WLS_HEAP_ALLOC_ERROR (-7)
+#define WLS_RC_IRQ_ALLOC_ERROR (-8)
+#define WLS_RC_DMA_ALLOC_ERROR (-9)
+#define WLS_RC_TRANSACTION_ERROR (-10)
+#define WLS_RC_PHY_CTX_ERROR (-11)
+#define WLS_RC_KERNEL_HEAP_ALLOC_ERROR (-12)
+#define WLS_RC_CONFIGURATION_ERROR (-13)
+#define WLS_RC_THREAD_CREATION_ERROR (-14)
+
+#define WLS_IOC_MAGIC 'W'
+#define WLS_IOC_OPEN _IOWR(WLS_IOC_MAGIC, WLS_IOC_OPEN_NO, uint64_t)
+#define WLS_IOC_CLOSE _IOWR(WLS_IOC_MAGIC, WLS_IOC_CLOSE_NO, uint64_t)
+#define WLS_IOC_PUT _IOWR(WLS_IOC_MAGIC, WLS_IOC_PUT_NO, uint64_t)
+#define WLS_IOC_EVENT _IOWR(WLS_IOC_MAGIC, WLS_IOC_EVENT_NO, uint64_t)
+#define WLS_IOC_WAIT _IOWR(WLS_IOC_MAGIC, WLS_IOC_WAIT_NO, uint64_t)
+#define WLS_IOC_WAKE_UP _IOWR(WLS_IOC_MAGIC, WLS_IOC_WAKE_UP_NO, uint64_t)
+#define WLS_IOC_CONNECT _IOWR(WLS_IOC_MAGIC, WLS_IOC_CONNECT_NO, uint64_t)
+#define WLS_IOC_FILL _IOWR(WLS_IOC_MAGIC, WLS_IOC_FILL_NO, uint64_t)
+
+enum {
+ WLS_IOC_OPEN_NO = 1,
+ WLS_IOC_CLOSE_NO,
+ WLS_IOC_PUT_NO,
+ WLS_IOC_EVENT_NO,
+ WLS_IOC_WAIT_NO,
+ WLS_IOC_WAKE_UP_NO,
+ WLS_IOC_CONNECT_NO,
+ WLS_IOC_FILL_NO,
+ WLS_IOC_COUNT,
+};
+
+enum {
+ WLS_FILL_PUSH = 1,
+ WLS_FILL_PULL,
+ WLS_FILL_MAX,
+};
+
+
+#define WLS_US_CLIENTS_MAX 64
+
+#define CACHE_LINE_SIZE 64 /**< Cache line size. */
+#define CACHE_LINE_MASK (CACHE_LINE_SIZE-1) /**< Cache line mask. */
+
+#define CACHE_LINE_ROUNDUP(size) \
+ (CACHE_LINE_SIZE * ((size + CACHE_LINE_SIZE - 1) / CACHE_LINE_SIZE))
+
+#define DMA_ALIGNMENT_SIZE 256L
+
+// To make DMA we make sure that block starts on 256 bytes boundary
+#define DMA_ALIGNMENT_ROUNDUP(size) \
+ (DMA_ALIGNMENT_SIZE * ((size + DMA_ALIGNMENT_SIZE - 1) / DMA_ALIGNMENT_SIZE))
+
+/**< Return the first cache-aligned value greater or equal to size. */
+
+/**
+ * Force alignment to cache line.
+ */
+#define __wls_cache_aligned __attribute__((__aligned__(CACHE_LINE_SIZE)))
+
+#define WLS_HUGE_DEF_PAGE_SIZE 0x40000000LL
+#define WLS_IS_ONE_HUGE_PAGE(ptr, size, hp_size) ((((unsigned long long)ptr & (~(hp_size - 1)))\
+ == (((unsigned long long)ptr + size - 1) & (~(hp_size - 1)))) ? 1 : 0)
+
+typedef struct hugepage_tabl_s
+{
+ union {
+ void *pageVa;
+ uint64_t padding_pageVa;
+ };
+ uint64_t pagePa;
+}hugepage_tabl_t;
+
+#define DMA_MAP_MAX_BLOCK_SIZE 64*1024
+#define MAX_N_HUGE_PAGES 512
+#define UL_FREE_BLOCK_QUEUE_SIZE 384
+
+#define WLS_GET_QUEUE_N_ELEMENTS 384
+#define WLS_PUT_QUEUE_N_ELEMENTS 384
+
+#ifdef DPDK_WLS
+#define WLS_DEV_SHM_NAME_LEN RTE_MEMZONE_NAMESIZE
+#else
+#define WLS_DEV_SHM_NAME_LEN 256
+#endif
+
+#define FIFO_LEN 384
+
+typedef struct wls_wait_req_s {
+ uint64_t wls_us_kernel_va;
+ uint64_t start_time;
+ uint64_t ctx;
+ uint64_t action;
+ uint64_t nMsg;
+}wls_wait_req_t;
+
+#ifdef DPDK_WLS
+typedef struct wls_sema_priv_s
+{
+ sem_t sem;
+ rte_atomic16_t is_irq;
+ wls_wait_req_t drv_block[FIFO_LEN];
+ volatile unsigned int drv_block_put;
+ volatile unsigned int drv_block_get;
+} wls_sema_priv_t;
+
+typedef struct wls_us_priv_s
+{
+ wls_sema_priv_t sema;
+ U8 NeedToWakeUp;
+ U8 isWait;
+ volatile V32 pid;
+} wls_us_priv_t;
+
+#endif
+
+typedef struct wls_us_ctx_s
+{
+ union {
+ void * wls_us_user_space_va;
+ uint64_t padding_wls_us_user_space_va;
+ };
+
+ uint64_t wls_us_kernel_va;
+
+ uint64_t wls_us_pa;
+
+ uint32_t wls_us_ctx_size;
+ uint32_t HugePageSize;
+
+ union {
+ void* alloc_buffer;
+ uint64_t padding_alloc_buffer;
+ };
+
+ hugepage_tabl_t hugepageTbl [MAX_N_HUGE_PAGES];
+
+ FASTQUEUE ul_free_block_pq;
+ uint64_t ul_free_block_storage[UL_FREE_BLOCK_QUEUE_SIZE * sizeof(uint64_t)];
+
+ WLS_MSG_QUEUE get_queue;
+ WLS_MSG_HANDLE get_storage[WLS_GET_QUEUE_N_ELEMENTS];
+
+ WLS_MSG_QUEUE put_queue;
+ WLS_MSG_HANDLE put_storage[WLS_PUT_QUEUE_N_ELEMENTS];
+
+ uint64_t freePtrList[UL_FREE_BLOCK_QUEUE_SIZE * sizeof(uint64_t)];
+ uint32_t freeListIndex;
+ uint32_t dualMode;
+
+ // dst userspace context address (kernel va)
+ uint64_t dst_kernel_va;
+ // dst userspace context address (local user sapce va)
+
+ volatile uint64_t dst_user_va;
+ // dst userspace context address (local user sapce va)
+ volatile uint64_t dst_pa;
+
+ uint32_t alloc_size;
+#ifdef DPDK_WLS
+ wls_us_priv_t wls_us_private;
+#else
+ HANDLE wls_us_private;
+#endif
+ uint32_t mode;
+ uint32_t secmode;
+ char wls_dev_name[WLS_DEV_SHM_NAME_LEN];
+ char wls_shm_name[WLS_DEV_SHM_NAME_LEN];
+}wls_us_ctx_t;
+
+
+
+typedef struct wls_fill_req_s {
+ uint64_t wls_us_kernel_va;
+ uint64_t ctx;
+ uint64_t action;
+ uint64_t nMsg;
+}wls_fill_req_t;
+
+typedef struct wls_connect_req_s {
+ uint64_t wls_us_kernel_va;
+}wls_connect_req_t;
+
+#ifdef __KERNEL__
+
+typedef struct wls_sema_priv_s
+{
+ wait_queue_head_t queue;
+ atomic_t is_irq;
+ wls_wait_req_t drv_block[FIFO_LEN];
+ volatile unsigned int drv_block_put;
+ volatile unsigned int drv_block_get;
+}wls_sema_priv_t;
+
+typedef struct wls_drv_ctx_s
+{
+ uint32_t init_mask;
+ uint32_t us_ctx_cout;
+ wls_us_ctx_t* p_wls_us_ctx[WLS_US_CLIENTS_MAX];
+ wls_us_ctx_t* p_wls_us_pa_ctx[WLS_US_CLIENTS_MAX];
+ uint32_t nWlsClients;
+}wls_drv_ctx_t;
+
+#elif defined DPDK_WLS
+
+typedef struct wls_drv_ctx_s
+{
+ uint32_t init_mask;
+ uint32_t us_ctx_cout;
+ wls_us_ctx_t p_wls_us_ctx[WLS_US_CLIENTS_MAX];
+ wls_us_ctx_t p_wls_us_pa_ctx[WLS_US_CLIENTS_MAX];
+ uint32_t nWlsClients;
+ pthread_mutex_t mng_mutex;
+}wls_drv_ctx_t;
+
+#endif
+typedef struct wls_open_req_s {
+ uint64_t ctx;
+ uint64_t ctx_pa;
+ uint32_t size;
+}wls_open_req_t;
+
+typedef struct wls_close_req_s {
+ uint64_t ctx;
+ uint64_t ctx_pa;
+ uint32_t size;
+}wls_close_req_t;
+
+typedef enum wls_events_num_s {
+ WLS_EVENT_IA_READY = 0,
+ WLS_EVENT_IA_STOP,
+ WLS_EVENT_IA_ERROR,
+ WLS_EVENT_MAX
+}wls_events_num_t;
+
+typedef struct wls_event_req_s {
+ uint64_t wls_us_kernel_va;
+ uint64_t event_to_wls;
+ uint64_t event_param;
+}wls_event_req_t;
+
+typedef struct wls_put_req_s {
+ uint64_t wls_us_kernel_va;
+}wls_put_req_t;
+
+typedef struct wls_wake_up_req_s {
+ uint64_t wls_us_kernel_va;
+ uint32_t id;
+ uint64_t ctx;
+}wls_wake_up_req_t;
+
+
+#define SYS_CPU_CLOCK (2300000000L)
+#define CLOCK_PER_MS (SYS_CPU_CLOCK/1000)
+#define CLOCK_PER_US (SYS_CPU_CLOCK/1000000)
+
+static inline uint64_t
+wls_rdtsc(void)
+{
+ union {
+ uint64_t tsc_64;
+ struct {
+ uint32_t lo_32;
+ uint32_t hi_32;
+ };
+ } tsc;
+
+ asm volatile("rdtsc" :
+ "=a" (tsc.lo_32),
+ "=d" (tsc.hi_32));
+ return tsc.tsc_64;
+}
+
+static inline uint64_t rdtsc_ticks_diff(unsigned long curr, unsigned long prev)
+{
+ if (curr >= prev)
+ return (unsigned long)(curr - prev);
+ else
+ return (unsigned long)(0xFFFFFFFFFFFFFFFF - prev + curr);
+}
+
+void wls_show_data(void* ptr, unsigned int size);
+void *wls_get_sh_ctx(void);
+void *wls_get_sh_ctx_pa(void);
+
+#endif /* __WLS_H__*/
+
diff --git a/wls_lib/wls_debug.h b/wls_lib/wls_debug.h
new file mode 100644
index 0000000..98cb4e6
--- /dev/null
+++ b/wls_lib/wls_debug.h
@@ -0,0 +1,38 @@
+/******************************************************************************
+*
+* Copyright (c) 2019 Intel.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*******************************************************************************/
+
+#ifndef __WLS_DEBUG_H__
+#define __WLS_DEBUG_H__
+
+#include <linux/types.h>
+
+/* mlog specific defenitions */
+
+#define PID_WLS_DRV_IOC_WAIT_WAKE_UP 77000
+#define PID_WLS_DRV_IOC_WAIT_WAKE_ENTRY 77001
+#define PID_WLS_DRV_IOC_PUT 77002
+#define PID_WLS_DRV_ISR 77003
+#define PID_WLS_DRV_IOC_FILL 77004
+
+#define MLOG_VAR_MSG_BLOCK 0xDEAD7000
+#define MLOG_VAR_MSG_TIME_SYNC 0xDEAD7001
+#define MLOG_VAR_MSG_COPY_THREAD 0xDEAD7002
+
+
+#endif /* __WLS_DEBUG_H__*/
+
diff --git a/wls_lib/wls_drv.c b/wls_lib/wls_drv.c
new file mode 100644
index 0000000..8b7543c
--- /dev/null
+++ b/wls_lib/wls_drv.c
@@ -0,0 +1,856 @@
+/******************************************************************************
+*
+* Copyright (c) 2019 Intel.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*******************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/kthread.h>
+#include <linux/fs.h>
+#include <linux/wait.h>
+#include <asm/uaccess.h>
+
+#include "wls.h"
+#include "wls_drv.h"
+#include "wls_debug.h"
+
+#if defined(_MLOG_TRACE_)
+#include "mlog.h"
+#endif
+
+#define WLS_VERSION_X 0
+#define WLS_VERSION_Y 0
+#define WLS_VERSION_Z 3
+#define WLS_VERSION_RESERVED 0
+#define WLS_DRV_VERSION ((WLS_VERSION_X << 24) | (WLS_VERSION_Y << 16) | (WLS_VERSION_Z << 8) | WLS_VERSION_RESERVED)
+
+#define WLS_DRV_VERSION_FORMAT "%d.%d.%d"
+#define WLS_DEV_DEVICE_FORMAT "wls%d"
+
+
+#define WLS_SEMA_COUNT 32
+#define WLS_MAX_CLIENTS 8
+
+
+typedef struct wls_us_priv_s
+{
+ wls_sema_priv_t sema;
+
+ U8 NeedToWakeUp;
+ U8 isWait;
+
+ U32 pid;
+} wls_us_priv_t;
+
+char wls_driver_name[] = "wls";
+char wls_driver_version[10];
+char wls_dev_device_name[10];
+
+static long wls_ioctl(struct file * filp, unsigned int cmd, unsigned long arg);
+static int wls_open(struct inode * inode, struct file * filp);
+static int wls_release(struct inode * inode, struct file * filp);
+static int wls_mmap(struct file * filp, struct vm_area_struct * vma);
+static int wls_wait(wls_sema_priv_t *priv, unsigned long arg);
+static int wls_wake_up_user_thread(char *buf, wls_sema_priv_t *semap);
+
+static struct file_operations wls_fops = {
+ .owner = THIS_MODULE,
+ .open = wls_open,
+ .release = wls_release,
+ .unlocked_ioctl = wls_ioctl,
+ .compat_ioctl = wls_ioctl,
+ .mmap = wls_mmap,
+};
+
+static struct wls_dev_t* wls_dev[WLS_MAX_CLIENTS];
+static wls_drv_ctx_t wls_drv_ctx[WLS_MAX_CLIENTS];
+
+static struct class * wls_class;
+
+/**********************************************************************
+* Module Parameters *
+**********************************************************************/
+int wlsMaxClients = 1;
+
+
+/**********************************************************************/
+module_param(wlsMaxClients, int, S_IRUSR);
+
+/**********************************************************************/
+
+static wls_drv_ctx_t * wls_get_ctx(unsigned int id)
+{
+ if(id < WLS_MAX_CLIENTS)
+ return &wls_drv_ctx[id];
+ else
+ return NULL;
+}
+
+int wls_wake_up_user_thread(char *buf, wls_sema_priv_t *semap)
+{
+ if (likely(atomic_read(&semap->is_irq) < FIFO_LEN)) {
+ unsigned int put = semap->drv_block_put + 1;
+ if (put >= FIFO_LEN)
+ put = 0;
+ //copy data from user
+ memcpy(&semap->drv_block[put], buf, sizeof(wls_wait_req_t));
+
+ semap->drv_block_put = put;
+ atomic_inc(&semap->is_irq);
+#ifdef DEBUG
+ printk(KERN_INFO "[wls]:PUT: put=%d get=%d T=%lu is_irq=%d\n",
+ semap->drv_block_put, semap->drv_block_get,
+ semap->drv_block[put].start_time , atomic_read(&semap->is_irq));
+#endif /* DEBUG */
+ wake_up_interruptible(&semap->queue);
+ }
+
+ return 0;
+}
+
+void wls_show_data(void* ptr, unsigned int size)
+{
+ unsigned char *d = ptr;
+ int i;
+
+ for(i = 0; i < size; i++)
+ {
+ if ( !(i & 0xf) )
+ printk("\n");
+ printk("%02x ", d[i]);
+ }
+ printk("\n");
+}
+
+static int wls_open(struct inode * inode, struct file * filp)
+{
+ if((MINOR(inode->i_rdev ) >= 0) && (MINOR(inode->i_rdev) < wlsMaxClients) && (MINOR(inode->i_rdev ) < WLS_MAX_CLIENTS)){
+ filp->private_data = (void *)wls_dev[MINOR(inode->i_rdev)];
+ WLS_DEBUG("wls_open [%d] priv: 0x%p",MINOR(inode->i_rdev), filp->private_data);
+ WLS_DEBUG("wls_open PID [%d] ", current->pid);
+ } else {
+ WLS_ERROR("wls_open PID [%d] incorrect inode->i_rdev %d", current->pid, MINOR(inode->i_rdev));
+ }
+
+ return 0;
+}
+
+static int wls_release(struct inode * inode, struct file * filp)
+{
+ struct wls_dev_t* wls_loc = NULL;
+ wls_us_ctx_t* pUsCtx = NULL;
+ wls_us_priv_t* pUs_priv = NULL;
+ wls_drv_ctx_t* pDrv_ctx = NULL;
+ int i = 0;
+
+ WLS_DEBUG("priv: 0x%p", filp->private_data);
+ WLS_DEBUG("wls_release PID [%d] ",current->pid);
+
+ if((MINOR(inode->i_rdev ) >= 0) && (MINOR(inode->i_rdev) < wlsMaxClients) && (MINOR(inode->i_rdev ) < WLS_MAX_CLIENTS)){
+ if (filp->private_data != NULL) {
+ wls_loc = (struct wls_dev_t*)filp->private_data;
+ if((void *)wls_dev[MINOR(inode->i_rdev)] == (void *)wls_loc){
+ pDrv_ctx = (wls_drv_ctx_t*)wls_loc->pWlsDrvCtx;
+ if(pDrv_ctx){
+ for(i = 0; i < 2; i++ ){
+ pUsCtx = (wls_us_ctx_t*)pDrv_ctx->p_wls_us_ctx[i];
+ if(pUsCtx){
+ wls_us_ctx_t* dst = (wls_us_ctx_t*)pUsCtx->dst_kernel_va;
+ wls_wait_req_t drv_block;
+ if(dst){
+ wls_us_priv_t* pDstPriv = (wls_us_priv_t*)dst->wls_us_private;
+ if(pDstPriv){
+ drv_block.start_time = wls_rdtsc();
+ pDstPriv->NeedToWakeUp = 1;
+ wls_wake_up_user_thread((char *)&drv_block, &pDstPriv->sema);
+ }
+ }
+ //un-link ctx
+ pDrv_ctx->p_wls_us_ctx[i]->dst_kernel_va = (uint64_t)0;
+ pDrv_ctx->p_wls_us_ctx[i]->dst_user_va = (uint64_t)0;
+ pDrv_ctx->p_wls_us_ctx[i]->dst_pa = (uint64_t)0;
+ }
+ }
+
+ for(i = 0; i < 2; i++ ){
+ pUsCtx = (wls_us_ctx_t*)pDrv_ctx->p_wls_us_ctx[i];
+
+ if(pUsCtx){
+ pUs_priv = (wls_us_priv_t*)pUsCtx->wls_us_private;
+ if(pUs_priv){
+ if(pUs_priv->pid == current->pid){
+ if (pUs_priv->isWait == 0){
+ pUsCtx->wls_us_private = NULL;
+ kfree(pUs_priv);
+ pDrv_ctx->p_wls_us_ctx[i] = NULL;
+ dma_free_coherent(wls_loc->device, sizeof(wls_us_ctx_t),(void*)pUsCtx, (long)pDrv_ctx->p_wls_us_pa_ctx[i]);
+ pDrv_ctx->p_wls_us_pa_ctx[i] = NULL;
+ pDrv_ctx->nWlsClients--;
+ } else {
+ WLS_PRINT("Wait is in process\n");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ filp->private_data = NULL;
+ }
+ } else {
+ WLS_ERROR("wls_release PID [%d] incorrect inode->i_rdev %d", current->pid, MINOR(inode->i_rdev));
+ }
+
+ return 0;
+}
+
+static int wls_wait(wls_sema_priv_t *priv, unsigned long arg)
+{
+ char __user *buf = (char __user *)arg;
+
+ if (!likely(atomic_read(&priv->is_irq))) {
+ if (unlikely(wait_event_interruptible(priv->queue, atomic_read(&priv->is_irq)))) {
+ return -ERESTARTSYS;
+ }
+ }
+
+ atomic_dec(&priv->is_irq);
+
+ if (priv->drv_block_put != priv->drv_block_get) {
+ unsigned int get = priv->drv_block_get + 1;
+
+ if (get >= FIFO_LEN)
+ get = 0;
+
+ if (copy_to_user(buf, &priv->drv_block[get], sizeof(wls_wait_req_t))) {
+ return -EFAULT;
+ }
+
+ priv->drv_block_get = get;
+
+#ifdef DEBUG
+ printk(KERN_INFO "[wls]:GET: put=%d get=%d T=%lu is_irq=%d\n",
+ priv->drv_block_put, priv->drv_block_get,
+ priv->drv_block[get].start_time, atomic_read(&priv->is_irq));
+#endif /* DEBUG */
+
+ } else {
+#ifdef DEBUG
+ printk(KERN_ERR "[wls]: wrong computation of queueing\n");
+#endif /* DEBUG */
+ }
+
+ return 0;
+}
+
+static unsigned wls_is_us_opened(wls_open_req_t *param)
+{
+ // TODO: add check
+
+ return 0;
+}
+
+wls_us_ctx_t *wls_create_us_ctx(wls_open_req_t *param, struct wls_dev_t * wls_loc)
+{
+ wls_us_ctx_t* pUsCtx = NULL;
+ wls_drv_ctx_t* pDrv_ctx = wls_loc->pWlsDrvCtx;
+
+ // check if instance already registered
+ if(wls_is_us_opened(param))
+ goto err0;
+
+ // allocate memory for shared portion
+ pUsCtx = (wls_us_ctx_t*)dma_alloc_coherent(NULL, param->size, (dma_addr_t *)¶m->ctx_pa, GFP_KERNEL);
+ WLS_DEBUG("wls_create_us_ctx: pUsCtx 0x%016lx\n", (unsigned long)pUsCtx);
+ if (pUsCtx){
+ // allocate memory for private
+ wls_us_priv_t *pUs_priv = kmalloc(sizeof(wls_us_priv_t), GFP_KERNEL);
+
+ if(pUs_priv == NULL)
+ goto err1;
+ // init shared
+ memset (pUsCtx, 0, sizeof(wls_us_ctx_t));
+
+ SFL_DefQueue(&pUsCtx->ul_free_block_pq, pUsCtx->ul_free_block_storage, UL_FREE_BLOCK_QUEUE_SIZE * sizeof(void*));
+ WLS_PRINT("ul free: off %lx\n",((U64) &pUsCtx->ul_free_block_pq -(U64)pUsCtx));
+
+ WLS_MsgDefineQueue(&pUsCtx->get_queue, pUsCtx->get_storage, WLS_GET_QUEUE_N_ELEMENTS, 0);
+ WLS_PRINT("get_queue: off %lx\n",((U64) &pUsCtx->get_queue -(U64)pUsCtx));
+
+ WLS_MsgDefineQueue(&pUsCtx->put_queue, pUsCtx->put_storage, WLS_PUT_QUEUE_N_ELEMENTS, 0);
+ WLS_PRINT("put_queue: off %lx\n",((U64) &pUsCtx->put_queue -(U64)pUsCtx));
+
+ // init private
+ memset (pUs_priv, 0, sizeof(wls_us_priv_t));
+ init_waitqueue_head(&pUs_priv->sema.queue);
+ atomic_set(&pUs_priv->sema.is_irq, 0);
+
+ pUs_priv->pid = current->pid;
+
+ pUsCtx->wls_us_private = pUs_priv;
+ WLS_DEBUG("wls_create_us_ctx: pUsCtx->wls_us_private 0x%016lx\n", (unsigned long)pUsCtx->wls_us_private);
+ } else
+ goto err0;
+
+ pDrv_ctx->p_wls_us_ctx[pDrv_ctx->nWlsClients] = pUsCtx;
+ pDrv_ctx->p_wls_us_pa_ctx[pDrv_ctx->nWlsClients++] = (wls_us_ctx_t*)param->ctx_pa;
+
+ if(pDrv_ctx->p_wls_us_ctx[0] && pDrv_ctx->p_wls_us_ctx[1])
+ {
+ //link ctx
+ pDrv_ctx->p_wls_us_ctx[0]->dst_kernel_va = (uint64_t)pDrv_ctx->p_wls_us_ctx[1];
+ pDrv_ctx->p_wls_us_ctx[0]->dst_pa = (uint64_t) pDrv_ctx->p_wls_us_pa_ctx[1];
+
+ pDrv_ctx->p_wls_us_ctx[1]->dst_kernel_va = (uint64_t)pDrv_ctx->p_wls_us_ctx[0];
+ pDrv_ctx->p_wls_us_ctx[1]->dst_pa = (uint64_t) pDrv_ctx->p_wls_us_pa_ctx[0];
+
+ pDrv_ctx->p_wls_us_ctx[0]->dst_kernel_va = (uint64_t)pDrv_ctx->p_wls_us_ctx[1];
+ pDrv_ctx->p_wls_us_ctx[0]->dst_pa = (uint64_t) pDrv_ctx->p_wls_us_pa_ctx[1];
+ pDrv_ctx->p_wls_us_ctx[1]->dst_kernel_va = (uint64_t)pDrv_ctx->p_wls_us_ctx[0];
+ pDrv_ctx->p_wls_us_ctx[1]->dst_pa = (uint64_t) pDrv_ctx->p_wls_us_pa_ctx[0];
+
+ WLS_DEBUG("link: 0 <-> 1: 0: 0x%016lx 1: 0x%016lx\n", (long unsigned int)pDrv_ctx->p_wls_us_ctx[0]->dst_kernel_va,
+ (long unsigned int)pDrv_ctx->p_wls_us_ctx[1]->dst_kernel_va);
+ }
+
+ return pUsCtx;
+
+//err2:
+ kfree(pUsCtx->wls_us_private);
+err1:
+ dma_free_coherent(wls_loc->device, param->size, pUsCtx, param->ctx_pa);
+err0:
+ return NULL;
+}
+
+
+int wls_destroy_us_ctx(wls_close_req_t *param, struct wls_dev_t * wls_prv)
+{
+ wls_us_ctx_t* pUsCtx = NULL;
+ wls_us_priv_t* pUs_priv = NULL;
+
+ wls_drv_ctx_t* pDrv_ctx = wls_prv->pWlsDrvCtx;
+
+ if(pDrv_ctx->p_wls_us_ctx[0] && pDrv_ctx->p_wls_us_ctx[1])
+ {
+ //link ctx
+ pDrv_ctx->p_wls_us_ctx[0]->dst_kernel_va = (uint64_t)0;
+ pDrv_ctx->p_wls_us_ctx[1]->dst_kernel_va = (uint64_t)0;
+ pDrv_ctx->p_wls_us_ctx[0]->dst_user_va = (uint64_t)0;
+ pDrv_ctx->p_wls_us_ctx[1]->dst_user_va = (uint64_t)0;
+ pDrv_ctx->p_wls_us_ctx[0]->dst_pa = (uint64_t)0;
+ pDrv_ctx->p_wls_us_ctx[1]->dst_pa = (uint64_t)0;
+
+ WLS_DEBUG("un-link: 0 <-> 1: 0: 0x%016lx 1: 0x%016lx\n", (long unsigned int)pDrv_ctx->p_wls_us_ctx[0]->dst_kernel_va,
+ (long unsigned int)pDrv_ctx->p_wls_us_ctx[1]->dst_kernel_va);
+ }
+
+ pUsCtx = (wls_us_ctx_t*)param->ctx;
+
+ if(pUsCtx){
+ pUs_priv = (wls_us_priv_t*)pUsCtx->wls_us_private;
+ if(pUs_priv){
+ if (pUs_priv->isWait == 0){
+
+ pUsCtx->wls_us_private = NULL;
+ kfree(pUs_priv);
+ if(param->ctx_pa){
+ if( pDrv_ctx->p_wls_us_ctx[0] == pUsCtx){
+ pDrv_ctx->p_wls_us_ctx[0] = NULL;
+ pDrv_ctx->p_wls_us_pa_ctx[0] = NULL;
+ } else {
+ pDrv_ctx->p_wls_us_ctx[1] = NULL;
+ pDrv_ctx->p_wls_us_pa_ctx[1] = NULL;
+ }
+ pDrv_ctx->nWlsClients--;
+ dma_free_coherent(wls_prv->device, param->size, pUsCtx, param->ctx_pa);
+ }else{
+ WLS_ERROR("param->ctx_pa is NULL\n");
+ }
+ } else
+ WLS_PRINT("Wait is in process\n");
+ }
+ }
+
+ return 0;
+}
+
+static int wls_process_wait(wls_us_ctx_t* pUsCtx)
+{
+ int n = WLS_GetNumItemsInTheQueue(&pUsCtx->get_queue);
+
+ return n;
+}
+
+static int wls_process_put(wls_us_ctx_t *src, wls_us_ctx_t *dst)
+{
+ int ret = 0;
+ WLS_MSG_HANDLE hMsg;
+ int n = 0;
+
+ wls_us_priv_t* pDstPriv = NULL;
+ wls_wait_req_t drv_block;
+
+ WLS_DEBUG("offset get_queue %lx\n",(U64)&src->get_queue - (U64)src);
+
+ n = WLS_GetNumItemsInTheQueue(&src->put_queue);
+
+ while(n--)
+ {
+ if (WLS_MsgDequeue(&src->put_queue, &hMsg, NULL, (void*)src))
+ {
+ WLS_DEBUG("WLS_Get %lx %d type %d\n",(U64) hMsg.pIaPaMsg, hMsg.MsgSize, hMsg.TypeID);
+ if(WLS_MsgEnqueue(&dst->get_queue, hMsg.pIaPaMsg, hMsg.MsgSize, hMsg.TypeID, hMsg.flags, NULL, (void*)dst) == FALSE){ // try to send
+ if(WLS_MsgEnqueue(&src->put_queue, hMsg.pIaPaMsg, hMsg.MsgSize, hMsg.TypeID, hMsg.flags, NULL, (void*)src) == FALSE){ // return back
+ WLS_ERROR("wls_process_put: Cannot return block to back to queue \n");
+ ret = -1;
+ }
+ break;
+ }
+ }
+ else{
+ ret = -1;
+ break;
+ }
+
+ }
+
+ if(dst->wls_us_private){
+ pDstPriv = (wls_us_priv_t*)dst->wls_us_private;
+
+ drv_block.start_time = wls_rdtsc();
+ pDstPriv->NeedToWakeUp = 1;
+ wls_wake_up_user_thread((char *)&drv_block, &pDstPriv->sema);
+ }
+ else
+ ret = -1;
+
+ return ret;
+}
+
+static long wls_ioctl(struct file * filp, unsigned int cmd, unsigned long arg)
+{
+ struct wls_dev_t * wls_prv = (struct wls_dev_t *)filp->private_data;
+ void __user * to = (void __user *)arg;
+ const void __user * from = (const void __user *)arg;
+ long ret = 0;
+
+ WLS_DEBUG("wls_ioctl PID [%d] ", current->pid);
+
+ if (_IOC_TYPE(cmd) != WLS_IOC_MAGIC) {
+ return -ENOTTY;
+ }
+
+ if (_IOC_NR(cmd) >= WLS_IOC_COUNT) {
+ return -ENOTTY;
+ }
+
+ switch (cmd) {
+ case WLS_IOC_OPEN: {
+ wls_open_req_t param;
+
+ WLS_DEBUG("WLS_IOC_OPEN wls_us_ctx_t %ld\n", sizeof(wls_us_ctx_t));
+ ret = copy_from_user((void *)¶m, from, sizeof(param));
+ if (ret != 0) {
+ WLS_ERROR("could not copy %lu bytes from user 0x%08lx",
+ (unsigned long)ret, (unsigned long)from);
+ break;
+ }
+
+ if (sizeof(wls_drv_ctx_t) >= param.size){
+ WLS_ERROR("incorrect size %lu > %u\n", sizeof(wls_drv_ctx_t), param.size);
+ ret = -1;
+ break;
+ }
+
+ param.ctx = (uint64_t)wls_create_us_ctx(¶m, wls_prv);
+ if (param.ctx == 0) {
+ WLS_ERROR("could not copy %lu bytes to user 0x%08lx",
+ (unsigned long)ret, (unsigned long)from);
+ break;
+ }
+
+ WLS_DEBUG("WLS_IOC_OPEN: kva %lx pa %lx sz [%d]\n", (long unsigned int)param.ctx, (long unsigned int)param.ctx_pa, param.size);
+
+ ret = copy_to_user(to, (const void *)¶m, sizeof(wls_open_req_t));
+ if (ret != 0) {
+ WLS_ERROR("could not copy %lu bytes to user 0x%08lx",
+ (unsigned long)ret, (unsigned long)from);
+ break;
+ }
+ } break;
+ case WLS_IOC_CLOSE: {
+ wls_close_req_t param;
+
+ ret = copy_from_user((void *)¶m, from, sizeof(param));
+ if (ret != 0) {
+ WLS_ERROR("could not copy %lu bytes from user 0x%08lx",
+ (unsigned long)ret, (unsigned long)from);
+ break;
+ }
+ WLS_DEBUG("WLS_IOC_CLOSE: kva %lx pa %lx sz [%d]\n", (long unsigned int)param.ctx, (long unsigned int)param.ctx_pa, param.size);
+
+ ret = wls_destroy_us_ctx(¶m, wls_prv);
+
+ if (ret != 0) {
+ WLS_ERROR("could not copy %lu bytes from user 0x%08lx",
+ (unsigned long)ret, (unsigned long)from);
+ break;
+ }
+ } break;
+ case WLS_IOC_PUT: {
+ wls_put_req_t param;
+ wls_us_ctx_t* pUsCtx = NULL;
+
+#if defined(_MLOG_TRACE_)
+ unsigned long t = MLOG_GETTICK();
+#endif
+ ret = copy_from_user((void *)¶m, from, sizeof(param));
+ if (ret != 0) {
+ WLS_ERROR("could not copy %lu bytes from user 0x%08lx",
+ (unsigned long)ret, (unsigned long)from);
+ break;
+ }
+
+ pUsCtx = (wls_us_ctx_t*)param.wls_us_kernel_va;
+ if (pUsCtx == NULL) {
+ WLS_ERROR("Transaction failed %ld\n", (unsigned long)ret);
+ break;
+ }
+
+ if(pUsCtx->dst_kernel_va)
+ ret = wls_process_put(pUsCtx, (wls_us_ctx_t*)pUsCtx->dst_kernel_va);
+
+ if (ret != 0) {
+ WLS_ERROR("Transaction failed %ld\n", (unsigned long)ret);
+ break;
+ }
+
+ /* clean up for next time */
+#if defined(_MLOG_TRACE_)
+ MLogTask(PID_WLS_DRV_IOC_PUT, t, MLOG_GETTICK());
+#endif
+ } break;
+ case WLS_IOC_EVENT: {
+ wls_event_req_t param;
+
+ ret = copy_from_user((void *)¶m, from, sizeof(param));
+
+ if (ret != 0) {
+ WLS_ERROR("Event %ld failed %ld\n", (unsigned long)param.event_to_wls,
+ (unsigned long)ret);
+ break;
+ }
+ }break;
+ case WLS_IOC_WAIT: {
+ wls_wait_req_t param;
+ wls_us_ctx_t* pUsCtx = NULL;
+ wls_us_priv_t* pUsPriv = NULL;
+#if defined(_MLOG_TRACE_)
+ unsigned long t = MLOG_GETTICK();
+ MLogTask(PID_WLS_DRV_IOC_WAIT_WAKE_ENTRY, t, 1250+t);
+#endif
+ ret = copy_from_user((void *)¶m, from, sizeof(param));
+ if (ret != 0) {
+ WLS_ERROR("Wait failed %ld\n", (unsigned long)ret);
+ break;
+ }
+
+ WLS_DEBUG("Wait pUsCtx 0x%016lx\n", (unsigned long)param.wls_us_kernel_va);
+ pUsCtx = (wls_us_ctx_t*) param.wls_us_kernel_va;
+ if(pUsCtx == NULL) {
+ ret = -EINVAL;
+ WLS_ERROR("Wait failed on User context %ld\n", (unsigned long)ret);
+ break;
+ }
+
+ pUsPriv = (wls_us_priv_t*) pUsCtx->wls_us_private;
+ WLS_DEBUG("Wait pUsPriv 0x%016lx\n", (unsigned long)pUsPriv);
+
+ if(pUsPriv == NULL) {
+ ret = -EINVAL;
+ WLS_ERROR("Wait failed %ld\n", (unsigned long)ret);
+ break;
+ }
+ pUsPriv->isWait = 1;
+ wls_wait(&pUsPriv->sema, (unsigned long)from);
+ pUsPriv->isWait = 0;
+ memset(¶m, 0, sizeof(wls_wait_req_t));
+ param.nMsg = wls_process_wait(pUsCtx);
+
+#if defined(_MLOG_TRACE_)
+ t = MLOG_GETTICK();
+#endif
+ ret = copy_to_user(to, (const void *)¶m, sizeof(wls_wait_req_t));
+ if (ret != 0) {
+ WLS_ERROR("could not copy %lu bytes to user 0x%08lx",
+ (unsigned long)ret, (unsigned long)from);
+ break;
+ }
+#if defined(_MLOG_TRACE_)
+ MLogTask(PID_WLS_DRV_IOC_WAIT_WAKE_UP, t, MLOG_GETTICK());
+#endif
+ } break;
+ case WLS_IOC_WAKE_UP: {
+ wls_wait_req_t param;
+ wls_us_ctx_t* pUsCtx = NULL;
+ wls_us_priv_t* pUsPriv = NULL;
+ wls_wait_req_t drv_block;
+
+ ret = copy_from_user((void *)¶m, from, sizeof(param));
+ if (ret != 0) {
+ WLS_ERROR("WLS_IOC_WAKE_UP failed %ld\n",
+ (unsigned long)ret);
+ break;
+ }
+
+ WLS_DEBUG("Wait pUsCtx 0x%016lx\n", (unsigned long)param.wls_us_kernel_va);
+ pUsCtx = (wls_us_ctx_t*) param.wls_us_kernel_va;
+ if(pUsCtx == NULL) {
+ ret = -EINVAL;
+ WLS_ERROR("Wait failed on User context %ld\n", (unsigned long)ret);
+ break;
+ }
+
+ pUsPriv = (wls_us_priv_t*) pUsCtx->wls_us_private;
+ WLS_DEBUG("Wait pUsPriv 0x%016lx\n", (unsigned long)pUsPriv);
+
+ if(pUsPriv == NULL) {
+ ret = -EINVAL;
+ WLS_ERROR("Wait failed %ld\n", (unsigned long)ret);
+ break;
+ }
+
+ drv_block.start_time = wls_rdtsc();
+ wls_wake_up_user_thread((char *)&drv_block, &pUsPriv->sema);
+ } break;
+ case WLS_IOC_CONNECT: {
+ wls_connect_req_t param;
+ wls_us_priv_t* pUsPriv = NULL;
+ wls_wait_req_t drv_block;
+
+ ret = copy_from_user((void *)¶m, from, sizeof(param));
+ if (ret != 0) {
+ WLS_ERROR("WLS_IOC_WAKE_UP failed %ld\n",
+ (unsigned long)ret);
+ break;
+ }
+
+ pUsPriv = (wls_us_priv_t*)param.wls_us_kernel_va;
+ drv_block.start_time = wls_rdtsc();
+ wls_wake_up_user_thread((char *)&drv_block, &pUsPriv->sema);
+ } break;
+ default:{
+ WLS_ERROR("unknown ioctl cmd: '0x%08x'", cmd);
+ BUG();
+ } break;
+ }
+
+ if (ret != 0) {
+ WLS_ERROR("cmd_%x failed: %ld", cmd, ret);
+ }
+
+ return ret;
+}
+
+static int wls_mmap(struct file * filp, struct vm_area_struct * vma)
+{
+ struct wls_dev_t * wls = (struct wls_dev_t *)filp->private_data;
+
+ WLS_DEBUG("priv: 0x%p", filp->private_data);
+ WLS_DEBUG("WLS_mmap : mmap function called \n");
+ WLS_DEBUG("vma->start =%lx\n",vma->vm_start);
+ WLS_DEBUG("vma->end =%lx\n",vma->vm_end);
+
+ // non cached
+// vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ WLS_DEBUG("vma->pgoff =%lx\n",vma->vm_pgoff);
+
+ if (wls == NULL) {
+ WLS_ERROR("WLS is NULL");
+ return -EIO;
+ }
+
+ return remap_pfn_range(vma,vma->vm_start,vma->vm_pgoff,vma->vm_end-vma->vm_start,\
+ vma->vm_page_prot);
+}
+
+static int __init wls_init(void)
+{
+ struct wls_dev_t* wls_dev_loc = NULL;
+ int res = 0;
+ dev_t dev_no = 0;
+ int minor_no = 0;
+ int dev_cnt = 0;
+
+ memset(&wls_dev[0], 0, sizeof(struct wls_dev_t*) * WLS_MAX_CLIENTS);
+
+ snprintf(wls_driver_version, 10, WLS_DRV_VERSION_FORMAT, WLS_VERSION_X, WLS_VERSION_Y, WLS_VERSION_Z);
+
+ WLS_PRINT("Intel(R) Wireless Subsystem Communication interface - %s\n", wls_driver_version);
+ WLS_PRINT("Copyright(c) 2014 Intel Corporation.\n");
+ //WLS_PRINT("Build: Date: %s Time: %s\n", __DATE__, __TIME__);
+
+ if ((wlsMaxClients > WLS_MAX_CLIENTS) || (wlsMaxClients < 1))
+ {
+ WLS_ERROR("Invalid wlsMaxClients %d\n", wlsMaxClients);
+ wlsMaxClients = 1;
+ }
+ for (dev_cnt = 0; dev_cnt < wlsMaxClients; dev_cnt++){
+ wls_dev_loc = (struct wls_dev_t *)kzalloc(sizeof(struct wls_dev_t), GFP_KERNEL);
+ WLS_DEBUG("wls_dev_loc %d %p", dev_cnt, wls_dev_loc);
+
+ if (wls_dev_loc == NULL) {
+ WLS_ERROR("no free memory (wanted %ld bytes)", sizeof(struct wls_dev_t));
+ res = -ENOMEM;
+ goto err0;
+ }
+ wls_dev[dev_cnt] = wls_dev_loc;
+ WLS_DEBUG("wls_init [%d]: 0x%p",dev_cnt, wls_dev[dev_cnt]);
+ }
+
+ res = alloc_chrdev_region(&dev_no, minor_no, wlsMaxClients, MODNAME);
+ if (res < 0) {
+ WLS_ERROR("failed alloc char dev region: %d", res);
+ goto err0;
+ }
+
+ wls_class = class_create(THIS_MODULE, wls_driver_name);
+
+ wls_dev_loc = wls_dev[0];
+ wls_dev_loc->dev_no = dev_no;
+
+ cdev_init(&wls_dev_loc->cdev, &wls_fops);
+ wls_dev_loc->cdev.owner = THIS_MODULE;
+ wls_dev_loc->cdev.ops = &wls_fops;
+ res = cdev_add(&wls_dev_loc->cdev, dev_no, wlsMaxClients);
+
+ if (res) {
+ WLS_ERROR("failed add char dev: %d", res);
+ res = -1;
+ goto err2;
+ }
+
+ if (IS_ERR((void *)wls_class)) {
+ WLS_ERROR("failed create class");
+ res = -EIO;
+ goto err1;
+ }
+
+ for (dev_cnt = 0; dev_cnt < wlsMaxClients; dev_cnt++){
+ wls_dev_loc = wls_dev[dev_cnt];
+ if (wls_dev_loc == NULL ) {
+ WLS_ERROR("wls_dev_loc is NULL");
+ goto err2;
+ }
+
+ if(wlsMaxClients > 1){
+ snprintf(wls_dev_device_name, 10, WLS_DEV_DEVICE_FORMAT, dev_cnt);
+ } else {
+ snprintf(wls_dev_device_name, 10, "%s", MODNAME);
+ }
+
+ wls_dev_loc->dev_no = MKDEV(MAJOR(dev_no), dev_cnt);
+ wls_dev_loc->device = device_create(wls_class, NULL, wls_dev_loc->dev_no, NULL, wls_dev_device_name);
+
+ if (IS_ERR((void *)wls_dev_loc->device)) {
+ WLS_ERROR("failed create / device");
+ res = -2;
+ goto err2;
+ }
+
+ dev_info(wls_dev_loc->device, "Device: %s\n", wls_dev_device_name);
+ mutex_init(&wls_dev_loc->lock);
+
+ wls_dev_loc->pWlsDrvCtx = wls_get_ctx(dev_cnt);
+
+ if (wls_dev_loc->pWlsDrvCtx == NULL) {
+ WLS_ERROR("failed wls_get_ctx(%d)", dev_cnt);
+ res = -3;
+ goto err2;
+ }
+
+ //return res;
+// dev_no++;
+ continue;
+ }
+ WLS_PRINT("init %d /dev/wlsX communication devices [0-%d]\n", dev_cnt, dev_cnt-1);
+ return res;
+
+ err2:
+ for (dev_cnt = 0; dev_cnt < wlsMaxClients; dev_cnt++){
+ wls_dev_loc = wls_dev[dev_cnt];
+ if(wls_dev_loc){
+ device_destroy(wls_class, wls_dev_loc->dev_no);
+ cdev_del(&wls_dev_loc->cdev);
+ }
+ }
+ class_destroy(wls_class);
+ err1:
+ unregister_chrdev_region(wls_dev[0]->dev_no, wlsMaxClients);
+ err0:
+ for (dev_cnt = 0; dev_cnt < wlsMaxClients; dev_cnt++){
+ if(wls_dev[dev_cnt]){
+ kfree(wls_dev[dev_cnt]);
+ wls_dev[dev_cnt] = NULL;
+ }
+ }
+
+ WLS_ERROR("init failed");
+ return -1;
+}
+
+static void __exit wls_exit(void)
+{
+ struct wls_dev_t* wls_dev_loc = NULL;
+ int dev_cnt = 0;
+
+ if (wls_dev[0]) {
+ for (dev_cnt = 0; dev_cnt < wlsMaxClients; dev_cnt++){
+ wls_dev_loc = wls_dev[dev_cnt];
+ device_destroy(wls_class, wls_dev_loc->dev_no);
+ }
+ wls_dev_loc = wls_dev[0];
+
+ cdev_del(&wls_dev_loc->cdev);
+ class_destroy(wls_class);
+
+ unregister_chrdev_region(wls_dev[0]->dev_no, wlsMaxClients);
+
+ for (dev_cnt = 0; dev_cnt < wlsMaxClients; dev_cnt++){
+ if(wls_dev[dev_cnt]){
+ kfree(wls_dev[dev_cnt]);
+ wls_dev[dev_cnt] = NULL;
+ }
+ }
+ }
+
+ WLS_PRINT("Intel(R) Wireless Subsystem Communication interface - %s was removed\n", wls_driver_version);
+}
+
+MODULE_DESCRIPTION("Wirelsess Sybsytem Communication interface");
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("WLS_DRV_VERSION_FORMAT");
+
+module_init(wls_init);
+module_exit(wls_exit);
diff --git a/wls_lib/wls_drv.h b/wls_lib/wls_drv.h
new file mode 100644
index 0000000..24af067
--- /dev/null
+++ b/wls_lib/wls_drv.h
@@ -0,0 +1,44 @@
+/******************************************************************************
+*
+* Copyright (c) 2019 Intel.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*******************************************************************************/
+
+#ifndef __WLS_DRV_H__
+#define __WLS_DRV_H__
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/ioctl.h>
+#include <linux/cdev.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include "ttypes.h"
+
+struct wls_dev_t {
+ struct mutex lock;
+ dev_t dev_no;
+ struct class * class;
+ struct device * device;
+ struct cdev cdev;
+ wait_queue_head_t queue;
+ atomic_t qwake;
+ struct task_struct * thread;
+ wls_drv_ctx_t* pWlsDrvCtx;
+};
+
+#endif /* __WLS_DRC_H__*/
+
diff --git a/wls_lib/wls_lib.c b/wls_lib/wls_lib.c
new file mode 100644
index 0000000..83c82ff
--- /dev/null
+++ b/wls_lib/wls_lib.c
@@ -0,0 +1,836 @@
+/******************************************************************************
+*
+* Copyright (c) 2019 Intel.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*******************************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include "ttypes.h"
+#include "wls_lib.h"
+#include "wls.h"
+#include "syslib.h"
+
+#define WLS_MAP_SHM 1
+
+#define WLS_PHY_SHM_FILE_NAME "/tmp/phyappshm"
+
+#define HUGE_PAGE_FILE_NAME "/mnt/huge/page"
+
+#define DIV_ROUND_OFFSET(X,Y) ( X/Y + ((X%Y)?1:0) )
+
+#define WLS_LIB_USER_SPACE_CTX_SIZE DMA_MAP_MAX_BLOCK_SIZE
+
+#define PLIB_ERR(x, args...) printf("wls_lib: "x, ## args);
+#define PLIB_INFO(x, args...) printf("wls_lib: "x, ## args);
+
+#ifdef _DEBUG_
+#define PLIB_DEBUG(x, args...) printf("wls_lib debug: "x, ## args);
+#else
+#define PLIB_DEBUG(x, args...) do { } while(0)
+#endif
+
+#ifdef __x86_64__
+#define WLS_LIB_MMAP mmap
+#else
+#define WLS_LIB_MMAP mmap64
+#endif
+
+extern int gethugepagesizes(long pagesizes[], int n_elem);
+extern int hugetlbfs_unlinked_fd(void);
+
+
+static pthread_mutex_t wls_put_lock;
+static pthread_mutex_t wls_get_lock;
+
+static int wls_dev_fd = 0;
+static wls_us_ctx_t* wls_us_ctx = NULL;
+
+static uint64_t wls_kernel_va_to_user_va(void *pWls_us, uint64_t ptr);
+
+int ipc_file = 0;
+
+static int wls_VirtToPhys(void* virtAddr, uint64_t* physAddr)
+{
+ int mapFd;
+ uint64_t page;
+ unsigned int pageSize;
+ unsigned long virtualPageNumber;
+
+ mapFd = open ("/proc/self/pagemap" , O_RDONLY );
+ if (mapFd < 0 )
+ {
+ PLIB_ERR("Could't open pagemap file\n");
+ return -1;
+ }
+
+ /*get standard page size*/
+ pageSize = getpagesize();
+
+ virtualPageNumber = (unsigned long) virtAddr / pageSize ;
+
+ lseek(mapFd , virtualPageNumber * sizeof(uint64_t) , SEEK_SET );
+
+ if(read(mapFd ,&page , sizeof(uint64_t)) < 0 )
+ {
+ close(mapFd);
+ PLIB_ERR("Could't read pagemap file\n");
+ return -1;
+ }
+
+ *physAddr = (( page & 0x007fffffffffffffULL ) * pageSize );
+
+ close(mapFd);
+
+ return 0;
+}
+
+static void wls_mutex_destroy(pthread_mutex_t* pMutex)
+{
+ pthread_mutex_destroy(pMutex);
+}
+
+static void wls_mutex_init(pthread_mutex_t* pMutex)
+{
+ pthread_mutexattr_t prior;
+ pthread_mutexattr_init(&prior);
+ pthread_mutexattr_setprotocol(&prior, PTHREAD_PRIO_INHERIT);
+ pthread_mutex_init(pMutex, &prior);
+ pthread_mutexattr_destroy(&prior);
+}
+
+static void wls_mutex_lock(pthread_mutex_t* pMutex)
+{
+ pthread_mutex_lock(pMutex);
+}
+
+static void wls_mutex_unlock(pthread_mutex_t* pMutex)
+{
+ pthread_mutex_unlock(pMutex);
+}
+
+static uint64_t wls_kernel_va_to_user_va(void *pWls_us, uint64_t ptr)
+{
+ unsigned long ret = 0;
+ wls_us_ctx_t* pUs = (wls_us_ctx_t*)pWls_us;
+
+ uint64_t kva = (uint64_t) pUs->wls_us_kernel_va;
+ uint64_t uva = (uint64_t) pUs->wls_us_user_space_va;
+
+ ret = (uva + (ptr - kva));
+
+ PLIB_DEBUG("kva %lx to uva %lx [offset %d]\n",kva, ret, (kva - ret));
+ return ret;
+}
+
+static uint64_t wls_kernel_va_to_user_va_dest(void *pWls_us, uint64_t ptr)
+{
+ unsigned long ret = 0;
+ wls_us_ctx_t* pUs = (wls_us_ctx_t*)pWls_us;
+
+ uint64_t kva = (uint64_t) pUs->dst_kernel_va;
+ uint64_t uva = (uint64_t) pUs->dst_user_va;
+
+ ret = (uva + (ptr - kva));
+
+ PLIB_DEBUG("kva %lx to uva %lx [offset %d]\n",kva, ret, (kva - ret));
+ return ret;
+}
+
+
+void* WLS_Open(const char *ifacename, unsigned int mode, unsigned long long nWlsMemorySize)
+{
+ wls_us_ctx_t* pWls_us = NULL;
+ unsigned int ret = 0;
+ wls_open_req_t params;
+ int i, len;
+ char temp[WLS_DEV_SHM_NAME_LEN];
+
+#ifdef __x86_64__
+ params.ctx = 64L;
+#else
+ params.ctx = 32L;
+#endif
+
+ params.ctx_pa = 0;
+ params.size = WLS_LIB_USER_SPACE_CTX_SIZE;
+
+ if(sizeof(wls_us_ctx_t) >= 64*1024){
+ PLIB_ERR("WLS_Open %ld \n", sizeof(wls_us_ctx_t));
+ return NULL;
+ }
+
+ if (!wls_us_ctx) {
+ PLIB_INFO("Open %s 0x%08lx\n", ifacename, WLS_IOC_OPEN);
+
+ if ((wls_dev_fd = open(ifacename, O_RDWR | O_SYNC)) < 0){
+ PLIB_ERR("Open filed [%d]\n", wls_dev_fd);
+ return NULL;
+ }
+ /* allocate block in shared space */
+ if((ret = ioctl(wls_dev_fd, WLS_IOC_OPEN, ¶ms)) < 0) {
+ PLIB_ERR("Open filed [%d]\n", ret);
+ return NULL;
+ }
+
+ PLIB_DEBUG("params: kernel va 0x%016llx pa 0x%016llx size %ld\n",
+ params.ctx, params.ctx_pa, params.size);
+
+ if (params.ctx_pa) {
+ /* remap to user space the same block */
+ pWls_us = (wls_us_ctx_t*) WLS_LIB_MMAP(NULL,
+ params.size,
+ PROT_READ|PROT_WRITE ,
+ MAP_SHARED,
+ wls_dev_fd,
+ params.ctx_pa);
+
+ if( pWls_us == MAP_FAILED ){
+ PLIB_ERR("mmap has failed (%d:%s) 0x%016lx [size %d]\n", errno, strerror(errno),params.ctx_pa, params.size);
+ return NULL;
+ }
+
+ PLIB_DEBUG("Local: pWls_us 0x%016p\n", pWls_us);
+
+ PLIB_DEBUG("size wls_us_ctx_t %d\n", sizeof(wls_us_ctx_t));
+ PLIB_DEBUG(" ul free : off 0x%016lx\n",((unsigned long) &pWls_us->ul_free_block_pq -(unsigned long)pWls_us));
+ PLIB_DEBUG(" get_queue: off 0x%016lx\n",((unsigned long) &pWls_us->get_queue -(unsigned long)pWls_us));
+ PLIB_DEBUG(" put_queue: off 0x%016lx\n",((unsigned long) &pWls_us->put_queue -(unsigned long)pWls_us));
+
+ //memset(pWls_us, 0, params.size);
+
+ pWls_us->padding_wls_us_user_space_va = 0LL;
+
+ pWls_us->wls_us_user_space_va = pWls_us;
+
+ pWls_us->wls_us_kernel_va = (uint64_t) params.ctx;
+ pWls_us->wls_us_pa = (uint64_t) params.ctx_pa;
+ pWls_us->wls_us_ctx_size = params.size;
+
+ PLIB_INFO("User Space Lib Context: us va 0x%016lx kernel va 0x%016lx pa 0x%016lx size %d \n",
+ (uintptr_t)pWls_us->wls_us_user_space_va,
+ pWls_us->wls_us_kernel_va,
+ pWls_us->wls_us_pa,
+ pWls_us->wls_us_ctx_size);
+
+ wls_mutex_init(&wls_put_lock);
+ wls_mutex_init(&wls_get_lock);
+
+ pWls_us->mode = mode;
+ PLIB_INFO("\nMode %d\n", pWls_us->mode);
+
+ PLIB_INFO("\nWLS device %s [%d]\n", ifacename, (int)strlen(ifacename));
+ strncpy(temp, ifacename, WLS_DEV_SHM_NAME_LEN - 1);
+ len = strlen(ifacename);
+ if (len < WLS_DEV_SHM_NAME_LEN - 1)
+ strncpy(pWls_us->wls_dev_name, temp, len);
+ else
+ strncpy(pWls_us->wls_dev_name, temp, WLS_DEV_SHM_NAME_LEN - 1);
+ for(i = 0; i < MIN(strlen(pWls_us->wls_dev_name),WLS_DEV_SHM_NAME_LEN); i++)
+ if(pWls_us->wls_dev_name[i] != '/')
+ pWls_us->wls_shm_name[i] = pWls_us->wls_dev_name[i];
+ else
+ pWls_us->wls_shm_name[i] = '_';
+
+ wls_us_ctx = pWls_us;
+ }
+ else {
+ PLIB_ERR("Open filed: incorrect allocation \n");
+ return NULL;
+ }
+ }
+
+ return wls_us_ctx;
+}
+
+int WLS_Ready(void* h)
+{
+ int ret = 0;
+ wls_event_req_t params;
+
+ if (!wls_us_ctx || !wls_dev_fd){
+ PLIB_ERR("Library was not opened\n");
+ return -1;
+ }
+
+ params.event_to_wls = WLS_EVENT_IA_READY;
+ params.event_param = 0;
+
+ /* free block in shared space */
+ if((ret = ioctl(wls_dev_fd, WLS_IOC_EVENT, ¶ms)) < 0) {
+ PLIB_ERR("Event filed [%d]\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int WLS_Close(void* h)
+{
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t*)h;
+ wls_close_req_t params;
+ int ret = 0;
+
+ if (!wls_us_ctx || !wls_dev_fd){
+ PLIB_ERR("Library was not opened\n");
+ return -1;
+ }
+
+ if ((unsigned long)pWls_us != (unsigned long )wls_us_ctx){
+ PLIB_ERR("Incorret handle %lx [expected %lx]\n", (unsigned long)pWls_us, (unsigned long )wls_us_ctx);
+ return -1;
+ }
+
+ params.ctx = pWls_us->wls_us_kernel_va;
+ params.ctx_pa = pWls_us->wls_us_pa;
+ params.size = pWls_us->wls_us_ctx_size;
+
+ /* free block in shared space */
+ if((ret = ioctl(wls_dev_fd, WLS_IOC_CLOSE, ¶ms)) < 0) {
+ PLIB_ERR("Close filed [%d]\n", ret);
+ return 0;
+ }
+
+ /* unmap to user space */
+ munmap(pWls_us, pWls_us->wls_us_ctx_size);
+
+ wls_mutex_destroy(&wls_put_lock);
+ wls_mutex_destroy(&wls_get_lock);
+
+ close(wls_dev_fd);
+
+ wls_us_ctx = NULL;
+ wls_dev_fd = 0;
+
+ return 0;
+}
+
+
+void* WLS_Alloc(void* h, unsigned int size)
+{
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t* )h;
+
+ long pageSize[1];
+ long hugePageSize;
+ long nHugePage;
+
+ hugepage_tabl_t* pHugePageTlb = &pWls_us->hugepageTbl[0];
+
+ void* pvirtAddr = NULL;
+ int count;
+ int fd;
+
+ char shm_file_name[256];
+
+ fd = hugetlbfs_unlinked_fd();
+
+ if (fd < 0)
+ PLIB_ERR("Unable to open temp file in hugetlbfs (%s)", strerror(errno));
+
+ gethugepagesizes(pageSize,1);
+ hugePageSize = pageSize[0];
+
+ PLIB_INFO("hugePageSize on the system is %ld\n", hugePageSize);
+
+ /* calculate total number of hugepages */
+ nHugePage = DIV_ROUND_OFFSET(size, hugePageSize);
+
+ if (nHugePage >= MAX_N_HUGE_PAGES){
+ PLIB_INFO("not enough hugepages: need %ld system has %d\n", nHugePage, MAX_N_HUGE_PAGES);
+ return NULL;
+ }
+
+ if(pHugePageTlb == NULL )
+ {
+ PLIB_INFO("Table memory allocation failed\n");
+ return NULL;
+ }
+
+#if WLS_MAP_SHM
+{
+ snprintf(shm_file_name, WLS_DEV_SHM_NAME_LEN, "%s_%s", WLS_PHY_SHM_FILE_NAME, pWls_us->wls_shm_name);
+ PLIB_INFO("shm open %s\n", shm_file_name);
+ ipc_file = open(shm_file_name, O_CREAT); // | O_EXCL maybe sometimes in future.. ;-)
+ if(ipc_file == -1){
+ PLIB_ERR("open failed (%s)\n", strerror(errno) );
+ return NULL;
+ }
+
+ key_t key = ftok(shm_file_name, '4');
+ int shm_handle = shmget(key, size, SHM_HUGETLB|SHM_R|SHM_W);
+ if(shm_handle == -1){
+ PLIB_INFO("Create shared memory\n");
+ shm_handle = shmget(key, size, SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W);
+ }
+ else
+ PLIB_INFO("Attach to shared memory\n");
+
+ if(shm_handle == -1){
+ PLIB_ERR("shmget has failed (%s) [size %ld]\n", strerror(errno), nHugePage * hugePageSize);
+ return NULL;
+ }
+
+ pvirtAddr = shmat(shm_handle, 0, /*SHM_RND*/0);
+}
+#else
+ /* Allocate required number of pages */
+ pvirtAddr = mmap(0,(nHugePage * hugePageSize), (PROT_READ|PROT_WRITE), MAP_SHARED, fd,0);
+#endif
+ if(pvirtAddr == MAP_FAILED )
+ {
+ PLIB_ERR("mmap has failed (%s) [size %ld]\n", strerror(errno), nHugePage * hugePageSize);
+ return NULL;
+ }
+
+ PLIB_INFO("pvirtAddr 0x%016lx\n", (unsigned long)pvirtAddr);
+
+ for(count = 0 ; count < nHugePage ; count++ )
+ {
+ /*Incremented virtual address to next hugepage to create table*/
+ pHugePageTlb[count].pageVa = ((unsigned char*)pvirtAddr + \
+ ( count * hugePageSize ));
+ /*Creating dummy page fault in process for each page
+ inorder to get pagemap*/
+ *(unsigned char*)pHugePageTlb[count].pageVa = 1;
+
+ if(wls_VirtToPhys((uint64_t*) pHugePageTlb[count].pageVa,
+ &pHugePageTlb[count].pagePa ) == -1)
+ {
+ munmap(pvirtAddr, (nHugePage * hugePageSize));
+ PLIB_ERR("Virtual to physical conversion failed\n");
+ return NULL;
+ }
+
+ //PLIB_INFO("id %d va 0x%016p pa 0x%016llx [%ld]\n", count, (uintptr_t)pHugePageTlb[count].pageVa, (uint64_t) pHugePageTlb[count].pagePa, hugePageSize);
+ }
+
+ PLIB_INFO("WLS_Alloc: 0x%016lx [%d]\n", (unsigned long)pvirtAddr, size);
+
+ close(fd);
+
+ pWls_us->HugePageSize = (uint32_t)hugePageSize;
+ pWls_us->alloc_buffer = pvirtAddr;
+ pWls_us->alloc_size = (uint32_t)(nHugePage * hugePageSize);
+
+ if (pWls_us->mode == WLS_MASTER_CLIENT){
+ wls_us_ctx_t* pWls_usRem = NULL;
+ PLIB_INFO("Connecting to remote peer ...\n");
+ while (pWls_us->dst_pa == 0) // wait for slave
+ ;
+
+ /* remap to user space the same block */
+ pWls_usRem = (wls_us_ctx_t*) WLS_LIB_MMAP(NULL,
+ sizeof(wls_us_ctx_t),
+ PROT_READ|PROT_WRITE ,
+ MAP_SHARED,
+ wls_dev_fd,
+ pWls_us->dst_pa);
+
+ if( pWls_us == MAP_FAILED ){
+ PLIB_ERR("mmap has failed (%d:%s) 0x%016lx \n", errno, strerror(errno),pWls_us->dst_pa);
+ return NULL;
+ }
+
+ PLIB_INFO("Remote: pWls_us 0x%p\n", pWls_usRem);
+
+ PLIB_INFO("size wls_us_ctx_t %ld\n", sizeof(wls_us_ctx_t));
+ PLIB_INFO(" ul free : off 0x%016lx\n",((unsigned long) &pWls_usRem->ul_free_block_pq -(unsigned long)pWls_usRem));
+ PLIB_INFO(" get_queue: off 0x%016lx\n",((unsigned long) &pWls_usRem->get_queue -(unsigned long)pWls_usRem));
+ PLIB_INFO(" put_queue: off 0x%016lx\n",((unsigned long) &pWls_usRem->put_queue -(unsigned long)pWls_usRem));
+
+ pWls_us->dst_user_va = (uint64_t) pWls_usRem ;
+ }
+
+
+ return pvirtAddr;
+}
+
+int WLS_Free(void* h, PVOID pMsg)
+{
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t* )h;
+
+ if ((unsigned long)pMsg != (unsigned long)pWls_us->alloc_buffer) {
+ PLIB_ERR("incorrect pMsg %lx [expected %lx]\n", (unsigned long)pMsg ,(unsigned long)pWls_us->alloc_buffer);
+ return -1;
+ }
+
+ if (pWls_us->mode == WLS_MASTER_CLIENT){
+ if(pWls_us->dst_user_va){
+ munmap((void*)pWls_us->dst_user_va, sizeof(wls_us_ctx_t));
+ pWls_us->dst_user_va = 0;
+ }
+ }
+
+ PLIB_DEBUG("WLS_Free 0x%016lx", (unsigned long)pMsg);
+#if WLS_MAP_SHM
+ shmdt(pMsg);
+ close (ipc_file);
+#else
+ munmap(pMsg, pWls_us->alloc_size);
+#endif
+
+
+
+ return 0;
+}
+
+int WLS_Put(void* h, unsigned long long pMsg, unsigned int MsgSize, unsigned short MsgTypeID, unsigned short Flags)
+{
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t* )h;
+ int ret = 0;
+
+ if ((unsigned long)h != (unsigned long)wls_us_ctx) {
+ PLIB_ERR("Incorrect user space context %lx [%lx]\n", (unsigned long)h, (unsigned long)wls_us_ctx);
+ return -1;
+ }
+
+ if(!WLS_IS_ONE_HUGE_PAGE(pMsg, MsgSize, WLS_HUGE_DEF_PAGE_SIZE)) {
+ PLIB_ERR("WLS_Put input error: buffer is crossing 2MB page boundary 0x%016llx size %ld\n", pMsg, (unsigned long)MsgSize);
+ }
+
+ wls_mutex_lock(&wls_put_lock);
+
+ if ((WLS_FLAGS_MASK & Flags)){ // multi block transaction
+ if (Flags & WLS_TF_SYN){
+ PLIB_DEBUG("WLS_SG_FIRST\n");
+ if (WLS_MsgEnqueue(&pWls_us->put_queue, pMsg, MsgSize, MsgTypeID, Flags, wls_kernel_va_to_user_va, (void*)pWls_us))
+ {
+ PLIB_DEBUG("WLS_Get %lx %d type %d\n",(U64) pMsg, MsgSize, MsgTypeID);
+ }
+ } else if ((Flags & WLS_TF_SCATTER_GATHER) && !(Flags & WLS_TF_SYN) && !(Flags & WLS_TF_FIN)){
+ PLIB_DEBUG("WLS_SG_NEXT\n");
+ if (WLS_MsgEnqueue(&pWls_us->put_queue, pMsg, MsgSize, MsgTypeID, Flags, wls_kernel_va_to_user_va, (void*)pWls_us))
+ {
+ PLIB_DEBUG("WLS_Put %lx %d type %d\n",(U64) pMsg, MsgSize, MsgTypeID);
+ }
+ } else if (Flags & WLS_TF_FIN) {
+ wls_put_req_t params;
+ PLIB_DEBUG("WLS_SG_LAST\n");
+ params.wls_us_kernel_va = pWls_us->wls_us_kernel_va;
+ if (WLS_MsgEnqueue(&pWls_us->put_queue, pMsg, MsgSize, MsgTypeID, Flags, wls_kernel_va_to_user_va, (void*)pWls_us))
+ {
+ PLIB_DEBUG("WLS_Put %lx %d type %d\n",(U64) pMsg, MsgSize, MsgTypeID);
+ }
+
+ PLIB_DEBUG("List: call WLS_IOC_PUT\n");
+ if((ret = ioctl(wls_dev_fd, WLS_IOC_PUT, ¶ms)) < 0) {
+ PLIB_ERR("Put filed [%d]\n", ret);
+ wls_mutex_unlock(&wls_put_lock);
+ return -1;
+ }
+ } else
+ PLIB_ERR("unsaported flags %x\n", WLS_FLAGS_MASK & Flags);
+ } else { // one block transaction
+ wls_put_req_t params;
+ params.wls_us_kernel_va = pWls_us->wls_us_kernel_va;
+ if (WLS_MsgEnqueue(&pWls_us->put_queue, pMsg, MsgSize, MsgTypeID, Flags, wls_kernel_va_to_user_va, (void*)pWls_us))
+ {
+ PLIB_DEBUG("WLS_Put %lx %d type %d\n",(U64) pMsg, MsgSize, MsgTypeID);
+ }
+
+ PLIB_DEBUG("One block: call WLS_IOC_PUT\n");
+ if((ret = ioctl(wls_dev_fd, WLS_IOC_PUT, ¶ms)) < 0) {
+ PLIB_ERR("Put filed [%d]\n", ret);
+ wls_mutex_unlock(&wls_put_lock);
+ return -1;
+ }
+ }
+ wls_mutex_unlock(&wls_put_lock);
+
+ return 0;
+}
+
+int WLS_Check(void* h)
+{
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t* )h;
+
+ if ((unsigned long)h != (unsigned long)wls_us_ctx) {
+ PLIB_ERR("Incorrect user space context %lx [%lx]\n", (unsigned long)h, (unsigned long)wls_us_ctx);
+ return 0;
+ }
+
+ PLIB_DEBUG("offset get_queue %lx\n",(U64)&pWls_us->get_queue - (U64)pWls_us);
+
+ return WLS_GetNumItemsInTheQueue(&pWls_us->get_queue);
+}
+
+
+unsigned long long WLS_Get(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags)
+{
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t* )h;
+ WLS_MSG_HANDLE hMsg;
+ uint64_t pMsg = NULL;
+
+ if ((unsigned long)h != (unsigned long)wls_us_ctx) {
+ PLIB_ERR("Incorrect user space context %lx [%lx]\n", (unsigned long)h, (unsigned long)wls_us_ctx);
+ return 0;
+ }
+
+ PLIB_DEBUG("offset get_queue %lx\n",(U64)&pWls_us->get_queue - (U64)pWls_us);
+ wls_mutex_lock(&wls_get_lock);
+
+ if (WLS_MsgDequeue(&pWls_us->get_queue, &hMsg, wls_kernel_va_to_user_va, (void*)pWls_us))
+ {
+ PLIB_DEBUG("WLS_Get %lx %d type %d\n",(U64) hMsg.pIaPaMsg, hMsg.MsgSize, hMsg.TypeID);
+ pMsg = hMsg.pIaPaMsg;
+ *MsgSize = hMsg.MsgSize;
+ *MsgTypeID = hMsg.TypeID;
+ *Flags = hMsg.flags;
+ }
+
+ wls_mutex_unlock(&wls_get_lock);
+
+ return pMsg;
+}
+
+int WLS_WakeUp(void* h)
+{
+ int ret;
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t* )h;
+ wls_wake_up_req_t params;
+
+ if (!wls_us_ctx || !wls_dev_fd){
+ PLIB_ERR("Library was not opened\n");
+ return -1;
+ }
+
+ params.ctx = (uint64_t)pWls_us;
+ params.wls_us_kernel_va = (uint64_t)pWls_us->wls_us_kernel_va;
+
+ PLIB_DEBUG("WLS_WakeUp\n");
+
+ if((ret = ioctl(wls_dev_fd, WLS_IOC_WAKE_UP, ¶ms)) < 0) {
+ PLIB_ERR("Wake Up filed [%d]\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int WLS_Wait(void* h)
+{
+ int ret;
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t* )h;
+ wls_wait_req_t params;
+
+ if (!wls_us_ctx || !wls_dev_fd){
+ PLIB_ERR("Library was not opened\n");
+ return -1;
+ }
+
+ params.ctx = (uint64_t)pWls_us;
+ params.wls_us_kernel_va = (uint64_t)pWls_us->wls_us_kernel_va;
+ params.action = 0;
+ params.nMsg = 0;
+
+ PLIB_DEBUG("WLS_Wait\n");
+
+ if((ret = ioctl(wls_dev_fd, WLS_IOC_WAIT, ¶ms)) < 0) {
+ PLIB_ERR("Wait filed [%d]\n", ret);
+ return ret;
+ }
+
+ return params.nMsg;
+}
+
+unsigned long long WLS_WGet(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags)
+{
+ uint64_t pRxMsg = WLS_Get(h, MsgSize, MsgTypeID, Flags);
+
+ if (pRxMsg)
+ return pRxMsg;
+
+ WLS_Wait(h);
+ return WLS_Get(h, MsgSize, MsgTypeID, Flags);
+}
+
+unsigned long long WLS_VA2PA(void* h, PVOID pMsg)
+{
+ uint64_t ret = 0;
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t* )h;
+
+ unsigned long alloc_base;
+ hugepage_tabl_t* pHugePageTlb;
+ uint64_t hugePageBase;
+ uint64_t hugePageOffet;
+ unsigned int count = 0;
+
+ uint64_t HugePageMask = ((unsigned long)pWls_us->HugePageSize - 1);
+
+ if(pWls_us->alloc_buffer == NULL){
+ PLIB_ERR("WLS_VA2PA: nothing was allocated [%ld]\n", ret);
+ return (uint64_t)ret;
+ }
+
+ alloc_base = (unsigned long)pWls_us->alloc_buffer;
+
+ pHugePageTlb = &pWls_us->hugepageTbl[0];
+
+ hugePageBase = (uint64_t)pMsg & ~HugePageMask;
+ hugePageOffet = (uint64_t)pMsg & HugePageMask;
+
+ count = (hugePageBase - alloc_base) / pWls_us->HugePageSize;
+
+ PLIB_DEBUG("WLS_VA2PA %lx base %llx off %llx count %d\n", (unsigned long)pMsg,
+ (uint64_t)hugePageBase, (uint64_t)hugePageOffet, count);
+
+ ret = pHugePageTlb[count].pagePa + hugePageOffet;
+
+ return (uint64_t) ret;
+}
+
+void* WLS_PA2VA(void* h, unsigned long long pMsg)
+{
+ unsigned long ret = NULL;
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t* )h;
+
+ hugepage_tabl_t* pHugePageTlb;
+ uint64_t hugePageBase;
+ uint64_t hugePageOffet;
+ unsigned int count;
+ int i;
+ uint64_t HugePageMask = ((uint64_t)pWls_us->HugePageSize - 1);
+
+ if(pWls_us->alloc_buffer == NULL){
+ PLIB_ERR("WLS_PA2VA: nothing was allocated [%ld]\n", ret);
+ return (void*)ret;
+ }
+
+ pHugePageTlb = &pWls_us->hugepageTbl[0];
+
+ hugePageBase = (uint64_t)pMsg & ~HugePageMask;
+ hugePageOffet = (uint64_t)pMsg & HugePageMask;
+
+ count = pWls_us->alloc_size / pWls_us->HugePageSize;
+
+ PLIB_DEBUG("WLS_PA2VA %llx base %llx off %llx count %d\n", (uint64_t)pMsg,
+ (uint64_t)hugePageBase, (uint64_t)hugePageOffet, count);
+
+ for (i = 0; i < count; i++) {
+ if (pHugePageTlb[i].pagePa == hugePageBase)
+ {
+ ret = (unsigned long)pHugePageTlb[i].pageVa;
+ ret += hugePageOffet;
+ return (void*)ret;
+ }
+ }
+
+ return (void*) (ret);
+}
+
+int WLS_EnqueueBlock(void* h, unsigned long long pMsg)
+{
+ int ret = 0;
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t* )h;
+
+ if (!wls_us_ctx || !wls_dev_fd){
+ PLIB_ERR("Library was not opened\n");
+ return -1;
+ }
+
+ if(pWls_us->mode == WLS_SLAVE_CLIENT){
+ PLIB_ERR("Slave doesn't support memory allocation\n");
+ return -1;
+ }
+
+ if(pMsg == 0){
+ PLIB_ERR("WLS_EnqueueBlock: Null\n");
+ return -1;
+ }
+
+ if(pWls_us->dst_kernel_va){
+ if (pWls_us->dst_user_va)
+ {
+ wls_us_ctx_t* pDstWls_us = (wls_us_ctx_t* )pWls_us->dst_user_va;
+ ret = SFL_WlsEnqueue(&pDstWls_us->ul_free_block_pq, pMsg, wls_kernel_va_to_user_va_dest, pWls_us);
+ if(ret == 1){
+ unsigned long* ptr = (unsigned long*)WLS_PA2VA(pWls_us, pMsg);
+ if(ptr){
+ *ptr = 0xFFFFFFFFFFFFFFFF;
+ }
+ }
+ }
+ else
+ ret = -1;
+ }
+ else
+ ret = -1;
+
+ PLIB_DEBUG("SFL_WlsEnqueue %d\n", ret);
+ return ret;
+}
+
+unsigned long long WLS_DequeueBlock(void* h)
+{
+ unsigned long long retval = NULL;
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t* )h;
+
+ if(pWls_us->mode == WLS_SLAVE_CLIENT){
+ // local
+ retval = SFL_WlsDequeue(&pWls_us->ul_free_block_pq, wls_kernel_va_to_user_va, h );
+ } else if(pWls_us->dst_kernel_va) {
+ // remote
+ if (pWls_us->dst_user_va)
+ {
+ wls_us_ctx_t* pDstWls_us = (wls_us_ctx_t* )pWls_us->dst_user_va;
+ retval = SFL_WlsDequeue(&pDstWls_us->ul_free_block_pq, wls_kernel_va_to_user_va_dest, pWls_us);
+ if(retval){
+ unsigned long* ptr = (unsigned long*)WLS_PA2VA(pWls_us, retval);
+ if(ptr){
+ if(*ptr != 0xFFFFFFFFFFFFFFFF){
+ PLIB_ERR("WLS_EnqueueBlock: incorrect content pa: 0x%016lx: 0x%016lx\n", (unsigned long)retval, *ptr);
+ }
+ }
+ }
+ }
+ }
+
+ return retval;
+}
+
+int WLS_NumBlocks(void* h)
+{
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t* )h;
+ int n = 0;
+
+ if(pWls_us->mode == WLS_SLAVE_CLIENT){
+ // local
+ n = SFL_GetNumItemsInTheQueue(&pWls_us->ul_free_block_pq);
+ } else if(pWls_us->dst_kernel_va) {
+ // remote
+ if (pWls_us->dst_user_va)
+ {
+ wls_us_ctx_t* pDstWls_us = (wls_us_ctx_t* )pWls_us->dst_user_va;
+ n = SFL_GetNumItemsInTheQueue(&pDstWls_us->ul_free_block_pq);
+ }
+ }
+
+ return n;
+}
+
+
diff --git a/wls_lib/wls_lib.h b/wls_lib/wls_lib.h
new file mode 100644
index 0000000..e38ea43
--- /dev/null
+++ b/wls_lib/wls_lib.h
@@ -0,0 +1,482 @@
+/******************************************************************************
+*
+* Copyright (c) 2019 Intel.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*******************************************************************************/
+
+#ifndef _WLS_LIB_H_
+#define _WLS_LIB_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** WLS driver client operates as slave in terms of management of shared memory */
+#define WLS_SLAVE_CLIENT 0
+/** WLS driver client operates as master in terms of management of shared memory */
+#define WLS_MASTER_CLIENT 1
+/** WLS Open Dual Options */
+#define WLS_SEC_NA 0
+#define WLS_SEC_MASTER 1
+/** WLS Open Dual enabled */
+#define WLS_SINGLE_MODE 0
+#define WLS_DUAL_MODE 1
+
+
+/* definitions PUT/GET Flags */
+#define WLS_TF_SCATTER_GATHER (1 << 15)
+#define WLS_TF_URLLC (1 << 10)
+#define WLS_TF_SYN (1 << 9)
+#define WLS_TF_FIN (1 << 8)
+#define WLS_FLAGS_MASK (0xFF00)
+
+/** First block in Scatter/Gather sequence of blocks */
+#define WLS_SG_FIRST (WLS_TF_SCATTER_GATHER | WLS_TF_SYN)
+/** Next block in Scatter/Gather sequence of blocks */
+#define WLS_SG_NEXT (WLS_TF_SCATTER_GATHER)
+/** Last block in Scatter/Gather sequence of blocks */
+#define WLS_SG_LAST (WLS_TF_SCATTER_GATHER | WLS_TF_FIN)
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+ *
+ * @param[in] ifacename - pointer to string with device driver name (/dev/wls)
+ * @param[in] modef - mode of operation (Master or Slave)
+ *
+ * @return pointer to WLS handle
+ *
+ * @description
+ * Function opens the WLS interface and registers as instance in the kernel space driver.
+ * Control section of shared memory is mapped to application memory.
+ * pointer (handle) of WLS interface is returned for future use by WLS functions
+ *
+**/
+//-------------------------------------------------------------------------------------------
+void* WLS_Open(const char *ifacename, unsigned int mode, unsigned long long nWlsMemorySize);
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+ *
+ * @param[in] ifacename - pointer to string with device driver name (/dev/wls)
+ * @param[in] modef - mode of operation (Master or Slave)
+ *
+ * @return pointer to second WLS handle while first WLS_handle is returned to the argument handle1 location
+ *
+ * @description
+ * Function opens the WLS interface and registers two instances in the kernel space driver.
+ * Control section of shared memory is mapped to application memory.
+ * pointer (handle) of WLS interface is returned for future use by WLS functions
+ *
+**/
+//-------------------------------------------------------------------------------------------
+void* WLS_Open_Dual(const char *ifacename, unsigned int mode, unsigned long long nWlsMemorySize, void** handle1);
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+ *
+ * @param[in] h - handle of WLS interface to close
+ *
+ * @return 0 - in case of success
+ *
+ * @description
+ * Function closes the WLS interface and deregisters as instance in the kernel space driver.
+ * Control section of shared memory is unmapped form user space application
+ *
+**/
+//-------------------------------------------------------------------------------------------
+int WLS_Close(void* h);
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+ *
+ * @param[in] h - handle of second WLS interface within same app to close
+ *
+ * @return 0 - in case of success
+ *
+ * @description
+ * Function closes a second WLS interface open from a same process and deregisters as instance in the kernel space driver.
+ * Control section of shared memory is unmapped form user space application
+ *
+**/
+//-------------------------------------------------------------------------------------------
+int WLS_Close1(void* h);
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+ *
+ * @param[in] h - handle of WLS interface to check status
+ *
+ * @return 1 - in case of success
+ *
+ * @description
+ * Function checks state of remote peer of WLS interface and returns 1 if remote peer is available
+ * (one to one connection is established)
+ *
+**/
+//-------------------------------------------------------------------------------------------
+int WLS_Ready(void* h);
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+ *
+ * @param[in] h - handle of second WLS interface within the same app to check status
+ *
+ * @return 1 - in case of success
+ *
+ * @description
+ * Function checks state of remote peer of WLS interface and returns 1 if remote peer is available
+ * (one to one connection is established)
+ *
+**/
+//-------------------------------------------------------------------------------------------
+int WLS_Ready1(void* h);
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+ *
+ * @param[in] h - handle of WLS interface
+ * @param[in] size - size of memory block to allocate
+ *
+ * @return void* - pointer to allocated memory block or NULL if no memory available
+ *
+ * @description
+ * Function allocates memory block for data exchange shared memory. Memory block is backed
+ * by huge pages.
+ *
+**/
+//-------------------------------------------------------------------------------------------
+void* WLS_Alloc(void* h, unsigned int size);
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+*
+* @param[in] h - handle of WLS interface
+* @param[in] pMsg - pointer to WLS memory
+*
+* @return 0 - if operation is successful
+*
+* @description
+* Function frees memory block for data exchange shared memory. Memory block is backed
+* by huge pages
+*
+**/
+//-------------------------------------------------------------------------------------------
+int WLS_Free(void* h, void* pMsg);
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+ *
+ * @param[in] h - handle of WLS interface
+ * @param[in] pMsg - pointer to memory block (physical address) with data to be transfered to remote peer.
+ * pointer should belong to WLS memory allocated via WLS_Alloc()
+ * @param[in] MsgSize - size of memory block to send (should be less than 2 MB)
+ * @param[in] MsgTypeID - application specific identifier of message type
+ * @param[in] Flags - Scatter/Gather flag if memory block has multiple chunks
+ *
+ * @return 0 - if successful
+ * -1 - if error
+ *
+ * @description
+ * Function puts memory block (or group of blocks) allocated from WLS memory into interface
+ * for transfer to remote peer.
+ *
+**/
+//-------------------------------------------------------------------------------------------
+int WLS_Put(void* h, unsigned long long pMsg, unsigned int MsgSize, unsigned short MsgTypeID, unsigned short Flags);
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+ *
+ * @param[in] h - handle of second WLS interface within same app
+ * @param[in] pMsg - pointer to memory block (physical address) with data to be transfered to remote peer.
+ * pointer should belong to WLS memory allocated via WLS_Alloc()
+ * @param[in] MsgSize - size of memory block to send (should be less than 2 MB)
+ * @param[in] MsgTypeID - application specific identifier of message type
+ * @param[in] Flags - Scatter/Gather flag if memory block has multiple chunks
+ *
+ * @return 0 - if successful
+ * -1 - if error
+ *
+ * @description
+ * Function puts memory block (or group of blocks) allocated from WLS memory into interface
+ * for transfer to remote peer.
+ *
+**/
+//-------------------------------------------------------------------------------------------
+int WLS_Put1(void* h, unsigned long long pMsg, unsigned int MsgSize, unsigned short MsgTypeID, unsigned short Flags);
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+ *
+ * @param[in] h - handle of WLS interface
+ *
+ * @return number of blocks available
+ *
+ * @description
+ * Function checks if there are memory blocks with data from remote peer and returns number of blocks
+ * available for "get" operation
+ *
+**/
+//-------------------------------------------------------------------------------------------
+int WLS_Check(void* h);
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+ *
+ * @param[in] h - handle of second WLS interface within same app
+ *
+ * @return number of blocks available
+ *
+ * @description
+ * Function checks if there are memory blocks with data from remote peer and returns number of blocks
+ * available for "get" operation
+ *
+**/
+//-------------------------------------------------------------------------------------------
+int WLS_Check1(void* h);
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+*
+* @param[in] h - handle of WLS interface
+* @param[in] *MsgSize - pointer to set size of memory block
+* @param[in] *MsgTypeID - pointer to application specific identifier of message type
+* @param[in] *Flags - pointer to Scatter/Gather flag if memory block has multiple chunks
+*
+* @return pointer to memory block (physical address) with data received from remote peer
+* NULL - if error
+*
+* @description
+* Function gets memory block from interface received from remote peer. Function is non-blocking
+* operation and returns NULL if no blocks available
+*
+**/
+//-------------------------------------------------------------------------------------------
+unsigned long long WLS_Get(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags);
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+*
+* @param[in] h - handle of second WLS interface within same app
+* @param[in] *MsgSize - pointer to set size of memory block
+* @param[in] *MsgTypeID - pointer to application specific identifier of message type
+* @param[in] *Flags - pointer to Scatter/Gather flag if memory block has multiple chunks
+*
+* @return pointer to memory block (physical address) with data received from remote peer
+* NULL - if error
+*
+* @description
+* Function gets memory block from interface received from remote peer. Function is non-blocking
+* operation and returns NULL if no blocks available
+*
+**/
+//-------------------------------------------------------------------------------------------
+unsigned long long WLS_Get1(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags);
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+*
+* @param[in] h - handle of WLS interface
+*
+* @return number of blocks available for get
+*
+* @description
+* Function waits for new memory block from remote peer. Function is blocking call and returns number
+* of blocks received.
+*
+**/
+//-------------------------------------------------------------------------------------------
+int WLS_Wait(void* h);
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+*
+* @param[in] h - handle second of WLS interface within same app
+*
+* @return number of blocks available for get
+*
+* @description
+* Function waits for new memory block from remote peer. Function is blocking call and returns number
+* of blocks received.
+*
+**/
+//-------------------------------------------------------------------------------------------
+int WLS_Wait1(void* h);
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+*
+* @param[in] h - handle of WLS interface
+*
+* @return 0 - if successful
+*
+* @description
+* Function performs "wakeup" notification to remote peer to unblock "wait" operations pending
+*
+**/
+//-------------------------------------------------------------------------------------------
+int WLS_WakeUp(void* h);
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+*
+* @param[in] h - handle of second WLS interface within same app
+*
+* @return 0 - if successful
+*
+* @description
+* Function performs "wakeup" notification to remote peer to unblock "wait" operations pending
+*
+**/
+//-------------------------------------------------------------------------------------------
+int WLS_WakeUp1(void* h);
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+*
+* @param[in] h - handle of WLS interface
+* @param[in] *MsgSize - pointer to set size of memory block
+* @param[in] *MsgTypeID - pointer to application specific identifier of message type
+* @param[in] *Flags - pointer to Scatter/Gather flag if memory block has multiple chunks
+*
+* @return pointer to memory block (physical address) with data received from remote peer
+* NULL - if error
+*
+* @description
+* Function gets memory block from interface received from remote peer. Function is blocking
+* operation and waits till next memory block from remote peer.
+*
+**/
+//-------------------------------------------------------------------------------------------
+unsigned long long WLS_WGet(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags);
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+*
+* @param[in] h - handle of second WLS interface within the same app
+* @param[in] *MsgSize - pointer to set size of memory block
+* @param[in] *MsgTypeID - pointer to application specific identifier of message type
+* @param[in] *Flags - pointer to Scatter/Gather flag if memory block has multiple chunks
+*
+* @return pointer to memory block (physical address) with data received from remote peer
+* NULL - if error
+*
+* @description
+* Function gets memory block from interface received from remote peer. Function is blocking
+* operation and waits till next memory block from remote peer.
+*
+**/
+//-------------------------------------------------------------------------------------------
+unsigned long long WLS_WGet1(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags);
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+*
+* @param[in] h - handle of WLS interface
+* @param[in] pMsg - virtual address of WLS memory block.
+*
+* @return physical address of WLS memory block
+* NULL - if error
+*
+* @description
+* Function converts virtual address (VA) to physical address (PA)
+*
+**/
+//-------------------------------------------------------------------------------------------
+unsigned long long WLS_VA2PA(void* h, void* pMsg);
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+*
+* @param[in] h - handle of WLS interface
+* @param[in] pMsg - physical address of WLS memory block.
+*
+* @return virtual address of WLS memory block
+* NULL - if error
+*
+* @description
+* Function converts physical address (PA) to virtual address (VA)
+*
+**/
+//-------------------------------------------------------------------------------------------
+void* WLS_PA2VA(void* h, unsigned long long pMsg);
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+*
+* @param[in] h - handle of WLS interface
+* @param[in] pMsg - physical address of WLS memory block.
+*
+* @return 0 - if successful
+* -1 - if error
+*
+* @description
+* Function is used by master to provide memory blocks to slave for next slave to master transfer
+* of data.
+*
+**/
+//-------------------------------------------------------------------------------------------
+int WLS_EnqueueBlock(void* h, unsigned long long pMsg);
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+*
+* @param[in] h -- handle of second WLS interface within the same app
+* @param[in] pMsg - physical address of WLS memory block.
+*
+* @return 0 - if successful
+* -1 - if error
+*
+* @description
+* Function is used by master to provide memory blocks to slave for next slave to master transfer
+* of data.
+*
+**/
+//-------------------------------------------------------------------------------------------
+int WLS_EnqueueBlock1(void* h, unsigned long long pMsg);
+
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+*
+* @param[in] h - handle of WLS interface
+*
+* @return 0 - pointer (physical address) of WLS memory block
+* NULL - if error
+*
+* @description
+* Function is used by master and slave to get block from master to slave queue of available memory
+* blocks.
+*
+**/
+//-------------------------------------------------------------------------------------------
+unsigned long long WLS_DequeueBlock(void* h);
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup wls_mod
+*
+* @param[in] h - handle of WLS interface
+*
+* @return number of blocks in slave to master queue
+*
+* @description
+* Function returns number of current available block provided by master for new transfer
+* of data from slave.
+*
+**/
+//-------------------------------------------------------------------------------------------
+int WLS_NumBlocks(void* h);
+
+#ifdef __cplusplus
+}
+#endif
+#endif //_WLS_LIB_H_
diff --git a/wls_lib/wls_lib_dpdk.c b/wls_lib/wls_lib_dpdk.c
new file mode 100644
index 0000000..f05b12c
--- /dev/null
+++ b/wls_lib/wls_lib_dpdk.c
@@ -0,0 +1,1343 @@
+/******************************************************************************
+*
+* Copyright (c) 2019 Intel.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*******************************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include <rte_eal.h>
+#include <rte_errno.h>
+#include <rte_lcore.h>
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_branch_prediction.h>
+
+#include "ttypes.h"
+#include "wls_lib.h"
+#include "wls.h"
+#include "syslib.h"
+
+#define WLS_MAP_SHM 1
+
+#define WLS_PHY_SHM_FILE_NAME "hp_"
+
+#define HUGE_PAGE_FILE_NAME "/mnt/huge/page"
+
+#define DIV_ROUND_OFFSET(X,Y) ( X/Y + ((X%Y)?1:0) )
+
+#define WLS_LIB_USER_SPACE_CTX_SIZE DMA_MAP_MAX_BLOCK_SIZE
+
+#define PLIB_ERR(x, args...) printf("wls_lib: "x, ## args);
+#define PLIB_INFO(x, args...) printf("wls_lib: "x, ## args);
+
+#ifdef _DEBUG_
+#define PLIB_DEBUG(x, args...) printf("wls_lib debug: "x, ## args);
+#else
+#define PLIB_DEBUG(x, args...) do { } while(0)
+#endif
+
+extern int gethugepagesizes(long pagesizes[], int n_elem);
+
+
+static uint32_t get_hugepagesz_flag(uint64_t hugepage_sz)
+{
+ unsigned size_flag = 0;
+
+ switch (hugepage_sz) {
+ case RTE_PGSIZE_256K:
+ size_flag = RTE_MEMZONE_256KB;
+ break;
+ case RTE_PGSIZE_2M:
+ size_flag = RTE_MEMZONE_2MB;
+ break;
+ case RTE_PGSIZE_16M:
+ size_flag = RTE_MEMZONE_16MB;
+ break;
+ case RTE_PGSIZE_256M:
+ size_flag = RTE_MEMZONE_256MB;
+ break;
+ case RTE_PGSIZE_512M:
+ size_flag = RTE_MEMZONE_512MB;
+ break;
+ case RTE_PGSIZE_1G:
+ size_flag = RTE_MEMZONE_1GB;
+ break;
+ case RTE_PGSIZE_4G:
+ size_flag = RTE_MEMZONE_4GB;
+ break;
+ case RTE_PGSIZE_16G:
+ size_flag = RTE_MEMZONE_16GB;
+ break;
+ default:
+ PLIB_INFO("Unknown hugepage size %lu\n", hugepage_sz);
+ break;
+ }
+ return size_flag;
+}
+
+static pthread_mutex_t wls_put_lock;
+static pthread_mutex_t wls_get_lock;
+static pthread_mutex_t wls_put_lock1;
+static pthread_mutex_t wls_get_lock1;
+
+static wls_us_ctx_t* wls_us_ctx = NULL;
+static wls_us_ctx_t* wls_us_ctx1 = NULL;
+static const struct rte_memzone *hp_memzone = NULL;
+static long hugePageSize = WLS_HUGE_DEF_PAGE_SIZE;
+static uint64_t gWlsMemorySize = 0;
+
+static inline int wls_check_ctx(void *h)
+{
+ if (h != wls_us_ctx) {
+ PLIB_ERR("Incorrect user space context\n");
+ return -1;
+ }
+ return 0;
+}
+
+static inline int wls_check_ctx1(void *h)
+{
+ if (h != wls_us_ctx1) {
+ PLIB_ERR("Incorrect user space context1\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int wls_VirtToPhys(const void* virtAddr, uint64_t* physAddr)
+{
+ int mapFd;
+ uint64_t page;
+ unsigned int pageSize;
+ unsigned long virtualPageNumber;
+
+ mapFd = open("/proc/self/pagemap", O_RDONLY);
+ if (mapFd < 0) {
+ PLIB_ERR("Could't open pagemap file\n");
+ return -1;
+ }
+
+ /*get standard page size*/
+ pageSize = getpagesize();
+
+ virtualPageNumber = (unsigned long) virtAddr / pageSize;
+
+ lseek(mapFd, virtualPageNumber * sizeof (uint64_t), SEEK_SET);
+
+ if (read(mapFd, &page, sizeof (uint64_t)) < 0) {
+ close(mapFd);
+ PLIB_ERR("Could't read pagemap file\n");
+ return -1;
+ }
+
+ *physAddr = ((page & 0x007fffffffffffffULL) * pageSize);
+
+ close(mapFd);
+
+ return 0;
+}
+
+static void wls_mutex_destroy(pthread_mutex_t* pMutex)
+{
+ pthread_mutex_destroy(pMutex);
+}
+
+static void wls_mutex_init(pthread_mutex_t* pMutex)
+{
+ pthread_mutexattr_t prior;
+ pthread_mutexattr_init(&prior);
+ pthread_mutexattr_setprotocol(&prior, PTHREAD_PRIO_INHERIT);
+ pthread_mutex_init(pMutex, &prior);
+ pthread_mutexattr_destroy(&prior);
+}
+
+static void wls_mutex_lock(pthread_mutex_t* pMutex)
+{
+ pthread_mutex_lock(pMutex);
+}
+
+static void wls_mutex_unlock(pthread_mutex_t* pMutex)
+{
+ pthread_mutex_unlock(pMutex);
+}
+
+static int wls_initialize(const char *ifacename, uint64_t nWlsMemorySize)
+{
+ int ret;
+ pthread_mutexattr_t attr;
+
+ uint64_t nSize = nWlsMemorySize + sizeof(wls_drv_ctx_t);
+ uint8_t *pMemZone;
+ const struct rte_memzone *mng_ctx_memzone;
+ wls_drv_ctx_t *mng_ctx;
+
+ mng_ctx_memzone = rte_memzone_reserve_aligned(ifacename, nSize, rte_socket_id(), get_hugepagesz_flag(hugePageSize), hugePageSize);
+ if (mng_ctx_memzone == NULL) {
+ PLIB_ERR("Cannot reserve memory zone[%s]: %s\n", ifacename, rte_strerror(rte_errno));
+ return -1;
+ }
+
+ pMemZone = ((uint8_t *)mng_ctx_memzone->addr) + nWlsMemorySize;
+ memset(pMemZone, 0, sizeof(wls_drv_ctx_t));
+ mng_ctx = (wls_drv_ctx_t *)pMemZone;
+
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
+ if (ret = pthread_mutex_init(&mng_ctx->mng_mutex, &attr)) {
+ PLIB_ERR("Failed to initialize mng_mutex %d\n", ret);
+ pthread_mutexattr_destroy(&attr);
+ return ret;
+ }
+ pthread_mutexattr_destroy(&attr);
+ PLIB_DEBUG("Run wls_initialized\n");
+ return 0;
+}
+
+static wls_us_ctx_t* wls_create_us_ctx(wls_drv_ctx_t *pDrv_ctx)
+{
+ int idx;
+
+ wls_mutex_lock(&pDrv_ctx->mng_mutex);
+
+ if (unlikely(pDrv_ctx->nWlsClients >= WLS_US_CLIENTS_MAX)) {
+ PLIB_ERR("Maximum number of clients reached");
+ wls_mutex_unlock(&pDrv_ctx->mng_mutex);
+ return NULL;
+ }
+
+ wls_us_ctx_t *pUsCtx = &pDrv_ctx->p_wls_us_ctx[pDrv_ctx->nWlsClients];
+ wls_us_priv_t *pUs_priv = &pUsCtx->wls_us_private;
+
+ PLIB_DEBUG("wls_create_us_ctx for %d client\n", pDrv_ctx->nWlsClients);
+ memset(pUsCtx, 0, sizeof (wls_us_ctx_t));
+
+ SFL_DefQueue(&pUsCtx->ul_free_block_pq, pUsCtx->ul_free_block_storage,
+ UL_FREE_BLOCK_QUEUE_SIZE * sizeof (void*));
+ WLS_MsgDefineQueue(&pUsCtx->get_queue, pUsCtx->get_storage, WLS_GET_QUEUE_N_ELEMENTS, 0);
+ WLS_MsgDefineQueue(&pUsCtx->put_queue, pUsCtx->put_storage, WLS_PUT_QUEUE_N_ELEMENTS, 0);
+
+ memset(pUs_priv, 0, sizeof (wls_us_priv_t));
+ if (sem_init(&pUs_priv->sema.sem, 1, 0)) {
+ PLIB_ERR("Failed to initialize semaphore %s\n", strerror(errno));
+ memset(pUsCtx, 0, sizeof (wls_us_ctx_t));
+ wls_mutex_unlock(&pDrv_ctx->mng_mutex);
+ return NULL;
+ }
+ rte_atomic16_init(&pUs_priv->sema.is_irq);
+
+ idx = pDrv_ctx->nWlsClients;
+ pDrv_ctx->p_wls_us_ctx[idx].dst_user_va = (uint64_t) & pDrv_ctx->p_wls_us_ctx[idx ^ 1];
+ PLIB_INFO("link: %d <-> %d\n", idx, idx ^ 1);
+
+ pUs_priv->pid = getpid();
+ pDrv_ctx->nWlsClients++;
+
+ wls_mutex_unlock(&pDrv_ctx->mng_mutex);
+ return pUsCtx;
+}
+
+static int wls_destroy_us_ctx(wls_us_ctx_t *pUsCtx, wls_drv_ctx_t *pDrv_ctx)
+{
+ wls_us_priv_t* pUs_priv = NULL;
+
+ wls_mutex_lock(&pDrv_ctx->mng_mutex);
+ if (pDrv_ctx->p_wls_us_ctx[0].wls_us_private.pid
+ && pDrv_ctx->p_wls_us_ctx[1].wls_us_private.pid) {
+ PLIB_INFO("un-link: 0 <-> 1\n");
+ pDrv_ctx->p_wls_us_ctx[0].dst_user_va = 0ULL;
+ pDrv_ctx->p_wls_us_ctx[1].dst_user_va = 0ULL;
+ }
+
+
+ if (pUsCtx) {
+ pUs_priv = (wls_us_priv_t*) & pUsCtx->wls_us_private;
+ if (pUs_priv) {
+ sem_destroy(&pUs_priv->sema.sem);
+ memset(pUsCtx, 0, sizeof (wls_us_ctx_t));
+ pDrv_ctx->nWlsClients--;
+ }
+ }
+
+ wls_mutex_unlock(&pDrv_ctx->mng_mutex);
+ return 0;
+}
+
+static int wls_destroy_us_ctx1(wls_us_ctx_t *pUsCtx, wls_drv_ctx_t *pDrv_ctx)
+{
+ wls_us_priv_t* pUs_priv = NULL;
+
+ wls_mutex_lock(&pDrv_ctx->mng_mutex);
+ if (pDrv_ctx->p_wls_us_ctx[2].wls_us_private.pid
+ && pDrv_ctx->p_wls_us_ctx[3].wls_us_private.pid) {
+ PLIB_INFO("un-link: 2 <-> 3\n");
+ pDrv_ctx->p_wls_us_ctx[2].dst_user_va = 0ULL;
+ pDrv_ctx->p_wls_us_ctx[3].dst_user_va = 0ULL;
+ }
+
+
+ if (pUsCtx) {
+ pUs_priv = (wls_us_priv_t*) & pUsCtx->wls_us_private;
+ if (pUs_priv) {
+ sem_destroy(&pUs_priv->sema.sem);
+ memset(pUsCtx, 0, sizeof (wls_us_ctx_t));
+ pDrv_ctx->nWlsClients--;
+ }
+ }
+
+ wls_mutex_unlock(&pDrv_ctx->mng_mutex);
+ return 0;
+}
+
+static int wls_wake_up_user_thread(char *buf, wls_sema_priv_t *semap)
+{
+ if (unlikely(rte_atomic16_read(&semap->is_irq) >= FIFO_LEN))
+ return 0;
+
+ unsigned int put = semap->drv_block_put + 1;
+ if (put >= FIFO_LEN)
+ put = 0;
+ memcpy(&semap->drv_block[put], buf, sizeof (wls_wait_req_t));
+ semap->drv_block_put = put;
+ rte_atomic16_inc(&semap->is_irq);
+ PLIB_DEBUG("PUT: put=%d get=%d T=%lu is_irq=%d\n",
+ semap->drv_block_put, semap->drv_block_get,
+ semap->drv_block[put].start_time, rte_atomic16_read(&semap->is_irq));
+ sem_post(&semap->sem);
+ return 0;
+}
+
+static int wls_process_put(wls_us_ctx_t *src, wls_us_ctx_t *dst)
+{
+ int ret = 0;
+ WLS_MSG_HANDLE hMsg;
+ int n = 0;
+
+ wls_us_priv_t* pDstPriv = NULL;
+ wls_wait_req_t drv_block;
+
+ if (NULL == src || NULL == dst) {
+ PLIB_DEBUG("Bad input addresses\n");
+ return -1;
+ }
+
+ n = WLS_GetNumItemsInTheQueue(&src->put_queue);
+
+ while (n--) {
+ if (WLS_MsgDequeue(&src->put_queue, &hMsg, NULL, (void*) src) == FALSE) {
+ PLIB_ERR("WLS_MsgDequeue src failed\n");
+ ret = -1;
+ break;
+ }
+ PLIB_DEBUG("WLS_Get %lx %d type %d\n", (U64) hMsg.pIaPaMsg, hMsg.MsgSize, hMsg.TypeID);
+ if (WLS_MsgEnqueue(&dst->get_queue, hMsg.pIaPaMsg, hMsg.MsgSize, hMsg.TypeID,
+ hMsg.flags, NULL, (void*) dst) == FALSE) { // try to send
+ if (WLS_MsgEnqueue(&src->put_queue, hMsg.pIaPaMsg, hMsg.MsgSize, hMsg.TypeID,
+ hMsg.flags, NULL, (void*) src) == FALSE) { // return back
+ PLIB_ERR("wls_process_put: Cannot return block to back to queue \n");
+ ret = -1;
+ }
+ break;
+ }
+ }
+
+ if (dst->wls_us_private.pid) {
+ pDstPriv = (wls_us_priv_t*) & dst->wls_us_private;
+
+ drv_block.start_time = wls_rdtsc();
+ pDstPriv->NeedToWakeUp = 1;
+ wls_wake_up_user_thread((char *) &drv_block, &pDstPriv->sema);
+ } else
+ ret = -1;
+
+ return ret;
+}
+
+static int wls_process_wakeup(void* h)
+{
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t*) h;
+ int ret = 0;
+ wls_wait_req_t drv_block;
+ if (wls_check_ctx(h))
+ return -1;
+ if (!pWls_us->wls_us_private.pid) {
+ PLIB_ERR("wakeup failed");
+ return -1;
+ }
+ drv_block.start_time = wls_rdtsc();
+ wls_wake_up_user_thread((char *) &drv_block, &pWls_us->wls_us_private.sema);
+
+ return ret;
+}
+
+static int wls_process_wakeup1(void* h)
+{
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t*) h;
+ int ret = 0;
+ wls_wait_req_t drv_block;
+ if (wls_check_ctx1(h))
+ return -1;
+ if (!pWls_us->wls_us_private.pid) {
+ PLIB_ERR("wakeup failed");
+ return -1;
+ }
+ drv_block.start_time = wls_rdtsc();
+ wls_wake_up_user_thread((char *) &drv_block, &pWls_us->wls_us_private.sema);
+
+ return ret;
+}
+
+static int wls_wait(wls_sema_priv_t *priv)
+{
+ if (!rte_atomic16_read(&priv->is_irq)) {
+ if (sem_wait(&priv->sem) || !rte_atomic16_read(&priv->is_irq)) {
+ return -1;
+ }
+ }
+
+ rte_atomic16_dec(&priv->is_irq);
+
+ if (priv->drv_block_put != priv->drv_block_get) {
+ unsigned int get = priv->drv_block_get + 1;
+
+ if (get >= FIFO_LEN)
+ get = 0;
+
+ priv->drv_block_get = get;
+
+ PLIB_DEBUG("GET: put=%d get=%d T=%lu is_irq=%d\n",
+ priv->drv_block_put, priv->drv_block_get,
+ priv->drv_block[get].start_time, rte_atomic16_read(&priv->is_irq));
+ } else {
+ PLIB_DEBUG("[wrong computation of queueing\n");
+ }
+
+ return 0;
+}
+
+static int wls_process_wait(void* h)
+{
+ wls_us_ctx_t* pUsCtx = (wls_us_ctx_t*) h;
+
+ if (wls_check_ctx(h))
+ return -1;
+
+ if (pUsCtx == NULL) {
+ PLIB_ERR("Wait failed on User context");
+ return -1;
+ }
+
+
+ if (!pUsCtx->wls_us_private.pid) {
+ PLIB_ERR("Wait failed");
+ return -1;
+ }
+ pUsCtx->wls_us_private.isWait = 1;
+ wls_wait(&pUsCtx->wls_us_private.sema);
+ pUsCtx->wls_us_private.isWait = 0;
+ return WLS_GetNumItemsInTheQueue(&pUsCtx->get_queue);
+}
+
+static int wls_process_wait1(void* h)
+{
+ wls_us_ctx_t* pUsCtx = (wls_us_ctx_t*) h;
+
+ if (wls_check_ctx1(h))
+ return -1;
+
+ if (pUsCtx == NULL) {
+ PLIB_ERR("Wait failed on User context");
+ return -1;
+ }
+
+
+ if (!pUsCtx->wls_us_private.pid) {
+ PLIB_ERR("Wait failed");
+ return -1;
+ }
+ pUsCtx->wls_us_private.isWait = 1;
+ wls_wait(&pUsCtx->wls_us_private.sema);
+ pUsCtx->wls_us_private.isWait = 0;
+ return WLS_GetNumItemsInTheQueue(&pUsCtx->get_queue);
+}
+
+
+void* WLS_Open(const char *ifacename, unsigned int mode, unsigned long long nWlsMemorySize)
+{
+ wls_us_ctx_t* pWls_us = NULL;
+ int i, len;
+ char temp[WLS_DEV_SHM_NAME_LEN] = {0};
+ uint8_t *pMemZone;
+
+ gethugepagesizes(&hugePageSize, 1);
+
+ if (wls_us_ctx)
+ return wls_us_ctx;
+
+ strncpy(temp, ifacename, WLS_DEV_SHM_NAME_LEN - 1);
+ PLIB_INFO("Open %s (DPDK memzone)\n", temp);
+
+ static const struct rte_memzone *mng_memzone;
+ mng_memzone = rte_memzone_lookup(temp);
+ if ((mng_memzone == NULL)&&(RTE_PROC_PRIMARY==rte_eal_process_type())) {
+ wls_initialize(temp, nWlsMemorySize);
+ }
+
+ mng_memzone = rte_memzone_lookup(temp);
+ if (mng_memzone == NULL) {
+ PLIB_ERR("Cannot initialize wls shared memory: %s\n", temp);
+ return NULL;
+ }
+
+ pMemZone = ((uint8_t *)mng_memzone->addr) + nWlsMemorySize;
+
+ PLIB_INFO("WLS_Open %p\n", pMemZone);
+ if ((pWls_us = wls_create_us_ctx((wls_drv_ctx_t *)pMemZone)) == NULL) {
+ PLIB_ERR("WLS_Open failed to create context\n");
+ return NULL;
+ }
+
+ PLIB_DEBUG("Local: pWls_us %p\n", pWls_us);
+
+ pWls_us->padding_wls_us_user_space_va = 0LL;
+ pWls_us->wls_us_user_space_va = pWls_us;
+ pWls_us->wls_us_ctx_size = sizeof (*pWls_us);
+ gWlsMemorySize = nWlsMemorySize;
+
+ wls_mutex_init(&wls_put_lock);
+ wls_mutex_init(&wls_get_lock);
+
+ pWls_us->mode = mode;
+ pWls_us->secmode = WLS_SEC_NA;
+ pWls_us->dualMode = WLS_SINGLE_MODE;
+ PLIB_INFO("Mode %d\n", pWls_us->mode);
+
+ PLIB_INFO("WLS shared management memzone: %s\n", temp);
+ strncpy(pWls_us->wls_dev_name, temp, WLS_DEV_SHM_NAME_LEN - 1);
+ wls_us_ctx = pWls_us;
+
+ return wls_us_ctx;
+}
+
+void* WLS_Open_Dual(const char *ifacename, unsigned int mode, unsigned long long nWlsMemorySize, void** handle1)
+{
+ wls_us_ctx_t* pWls_us = NULL;
+ wls_us_ctx_t* pWls_us1 = NULL;
+ int i, len;
+ char temp[WLS_DEV_SHM_NAME_LEN] = {0};
+ uint8_t *pMemZone;
+
+ gethugepagesizes(&hugePageSize, 1);
+
+ if (wls_us_ctx)
+ return wls_us_ctx;
+
+ strncpy(temp, ifacename, WLS_DEV_SHM_NAME_LEN - 1);
+ PLIB_INFO("Open %s (DPDK memzone)\n", temp);
+
+ static const struct rte_memzone *mng_memzone;
+ mng_memzone = rte_memzone_lookup(temp);
+ if ((mng_memzone == NULL)&&(RTE_PROC_PRIMARY==rte_eal_process_type())) {
+ wls_initialize(temp, nWlsMemorySize);
+ }
+
+ mng_memzone = rte_memzone_lookup(temp);
+ if (mng_memzone == NULL) {
+ PLIB_ERR("Cannot initialize wls shared memory: %s\n", temp);
+ return NULL;
+ }
+
+ pMemZone = ((uint8_t *)mng_memzone->addr) + nWlsMemorySize;
+ PLIB_INFO("nWlsMemorySize is %llu\n", nWlsMemorySize);
+ PLIB_INFO("WLS_Open Dual 1 %p\n", pMemZone);
+ if ((pWls_us = wls_create_us_ctx((wls_drv_ctx_t *)pMemZone)) == NULL) {
+ PLIB_ERR("WLS_Open Dual 1 failed to create context\n");
+ return NULL;
+ }
+ else
+ {
+ PLIB_DEBUG("Local: pWls_us %p\n", pWls_us);
+
+ pWls_us->padding_wls_us_user_space_va = 0LL;
+ pWls_us->wls_us_user_space_va = pWls_us;
+ pWls_us->wls_us_ctx_size = sizeof (*pWls_us);
+ gWlsMemorySize = nWlsMemorySize;
+
+ wls_mutex_init(&wls_put_lock);
+ wls_mutex_init(&wls_get_lock);
+
+ pWls_us->mode = mode;
+ pWls_us->secmode = WLS_SEC_MASTER;
+ pWls_us->dualMode = WLS_DUAL_MODE;
+ PLIB_INFO("Mode %d SecMode %d \n", pWls_us->mode, pWls_us->secmode);
+
+ PLIB_INFO("WLS shared management memzone 1: %s\n", temp);
+ strncpy(pWls_us->wls_dev_name, temp, WLS_DEV_SHM_NAME_LEN - 1);
+ wls_us_ctx = pWls_us;
+ PLIB_INFO("pWLs_us is %p\n", wls_us_ctx);
+ *handle1 = pWls_us; // Now the first context is for L1-FT_iapi
+ }
+
+ // Create second context to support the second wls shared memory interface
+ if ((pWls_us1 = wls_create_us_ctx((wls_drv_ctx_t *)pMemZone)) == NULL) {
+ PLIB_ERR("WLS_Open Dual failed to create context 1\n");
+ return NULL;
+ }
+ else
+ {
+ PLIB_DEBUG("Local: pWls_us1 %p\n", pWls_us1);
+ pWls_us1->padding_wls_us_user_space_va = 0LL;
+ pWls_us1->wls_us_user_space_va = pWls_us1;
+ pWls_us1->wls_us_ctx_size = sizeof (*pWls_us1);
+ gWlsMemorySize = nWlsMemorySize;
+
+ wls_mutex_init(&wls_put_lock1);
+ wls_mutex_init(&wls_get_lock1);
+
+ pWls_us1->mode = mode;
+ pWls_us1->secmode = WLS_SEC_NA;
+ PLIB_INFO("Mode %d Secmode %d\n", pWls_us1->mode, pWls_us1->secmode);
+
+ PLIB_INFO("WLS shared management memzone 2: %s\n", temp);
+ strncpy(pWls_us1->wls_dev_name, temp, WLS_DEV_SHM_NAME_LEN - 1);
+ wls_us_ctx1 = pWls_us1; // Now the second context is for the L2-FT_fapi
+ PLIB_INFO("pWLs_us1 is %p\n", wls_us_ctx1);
+
+ }
+
+ return wls_us_ctx1; // returning second context preserves the L2 legacy code
+}
+
+int WLS_Ready(void* h)
+{
+ wls_us_ctx_t *pWls_us = (wls_us_ctx_t*) h;
+ wls_us_ctx_t *pWls_usRem = (wls_us_ctx_t*) pWls_us->dst_user_va;
+
+ if (!wls_us_ctx) {
+ PLIB_ERR("Library was not opened\n");
+ return -1;
+ }
+
+ if (pWls_usRem->wls_us_private.pid) {
+ return 0;
+ }
+ return -1;
+}
+
+int WLS_Ready1(void* h)
+{
+ wls_us_ctx_t *pWls_us = (wls_us_ctx_t*) h;
+ wls_us_ctx_t *pWls_usRem = (wls_us_ctx_t*) pWls_us->dst_user_va;
+
+ if (!wls_us_ctx1) {
+ PLIB_ERR("Library was not opened for Context 1\n");
+ return -1;
+ }
+
+ if (pWls_usRem->wls_us_private.pid) {
+ return 0;
+ }
+ return -1;
+}
+
+int WLS_Close(void* h)
+{
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t*) h;
+ int ret = 0;
+ uint8_t *pMemZone;
+ wls_drv_ctx_t *pDrv_ctx;
+
+ if (!wls_us_ctx) {
+ PLIB_ERR("Library was not opened\n");
+ return -1;
+ }
+
+ if (wls_check_ctx(h))
+ return -1;
+
+ static const struct rte_memzone *mng_memzone;
+ mng_memzone = rte_memzone_lookup(pWls_us->wls_dev_name);
+ if (mng_memzone == NULL) {
+ PLIB_ERR("Cannot find mng memzone: %s %s\n",
+ pWls_us->wls_dev_name, rte_strerror(rte_errno));
+ return -1;
+ }
+
+ pMemZone = ((uint8_t *)mng_memzone->addr) + gWlsMemorySize;
+ pDrv_ctx = (wls_drv_ctx_t *)pMemZone;
+
+ PLIB_INFO("WLS_Close\n");
+ if ((ret = wls_destroy_us_ctx(pWls_us, pDrv_ctx)) < 0) {
+ PLIB_ERR("Close failed [%d]\n", ret);
+ return ret;
+ }
+
+ wls_mutex_destroy(&wls_put_lock);
+ wls_mutex_destroy(&wls_get_lock);
+
+ wls_us_ctx = NULL;
+
+ if (0 == pDrv_ctx->nWlsClients) {
+ wls_mutex_destroy(&pDrv_ctx->mng_mutex);
+ rte_memzone_free(mng_memzone);
+ }
+ return 0;
+}
+
+int WLS_Close1(void* h)
+{
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t*) h;
+ int ret = 0;
+ uint8_t *pMemZone;
+ wls_drv_ctx_t *pDrv_ctx;
+
+ if (!wls_us_ctx1) {
+ PLIB_ERR("Library was not opened\n");
+ return -1;
+ }
+
+ if (wls_check_ctx1(h))
+ return -1;
+
+ static const struct rte_memzone *mng_memzone;
+ mng_memzone = rte_memzone_lookup(pWls_us->wls_dev_name);
+ if (mng_memzone == NULL) {
+ PLIB_ERR("Cannot find mng memzone: %s %s\n",
+ pWls_us->wls_dev_name, rte_strerror(rte_errno));
+ return -1;
+ }
+
+ pMemZone = ((uint8_t *)mng_memzone->addr) + gWlsMemorySize;
+ pDrv_ctx = (wls_drv_ctx_t *)pMemZone;
+
+ PLIB_INFO("WLS_Close1\n");
+ if ((ret = wls_destroy_us_ctx1(pWls_us, pDrv_ctx)) < 0) {
+ PLIB_ERR("Close failed [%d]\n", ret);
+ return ret;
+ }
+
+ wls_mutex_destroy(&wls_put_lock1);
+ wls_mutex_destroy(&wls_get_lock1);
+
+ wls_us_ctx1 = NULL;
+
+ if (0 == pDrv_ctx->nWlsClients) {
+ wls_mutex_destroy(&pDrv_ctx->mng_mutex);
+ rte_memzone_free(mng_memzone);
+ }
+ return 0;
+}
+
+void* WLS_Alloc(void* h, unsigned int size)
+{
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t*) h;
+ static const struct rte_memzone *mng_memzone;
+ long nHugePage;
+ void *pvirtAddr = NULL;
+ int count;
+
+ if ((NULL != hp_memzone)&&(pWls_us->dualMode != WLS_DUAL_MODE)) {
+ PLIB_ERR("Memory zone already reserved\n");
+ return hp_memzone->addr;
+ }
+
+ hugepage_tabl_t* pHugePageTlb = &pWls_us->hugepageTbl[0];
+ hugepage_tabl_t* pHugePageTlb1 = &pWls_us->hugepageTbl[1];
+ hugepage_tabl_t* pHugePageTlb2 = &pWls_us->hugepageTbl[2];
+
+ PLIB_INFO("hugePageSize on the system is %ld\n", hugePageSize);
+
+ /* calculate total number of hugepages */
+ nHugePage = DIV_ROUND_OFFSET(size, hugePageSize);
+
+ if (nHugePage >= MAX_N_HUGE_PAGES) {
+ PLIB_INFO("not enough hugepages: need %ld system has %d\n", nHugePage, MAX_N_HUGE_PAGES);
+ return NULL;
+ }
+
+ mng_memzone = rte_memzone_lookup(pWls_us->wls_dev_name);
+ if (mng_memzone == NULL) {
+ PLIB_ERR("Cannot initialize wls shared memory: %s\n", pWls_us->wls_dev_name);
+ return NULL;
+ }
+
+ hp_memzone = (struct rte_memzone *)mng_memzone;
+ pvirtAddr = (void *)hp_memzone->addr;
+ PLIB_DEBUG("pvirtAddr is %p\n", pvirtAddr);
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+ memset(pvirtAddr, 0, sizeof (wls_drv_ctx_t));
+ }
+
+ for (count = 0; count < nHugePage; count++) {
+ /*Increment virtual address to next hugepage to create table*/
+ pHugePageTlb[count].pageVa = ((unsigned char*) pvirtAddr + \
+ (count * hugePageSize));
+ /*Creating dummy page fault in process for each page
+ inorder to get pagemap*/
+ *(unsigned char*) pHugePageTlb[count].pageVa = 1;
+
+ if (wls_VirtToPhys((uint64_t*) pHugePageTlb[count].pageVa,
+ &pHugePageTlb[count].pagePa) == -1) {
+ PLIB_ERR("Virtual to physical conversion failed\n");
+ return NULL;
+ }
+ }
+
+ PLIB_DEBUG("count is %d, pHugePageTlb->pageVa is %p pHugePageTlb1->pageVa is %p pHugePageTlb2->pageVa is %p\n",count, pHugePageTlb->pageVa, pHugePageTlb1->pageVa, pHugePageTlb2->pageVa);
+ PLIB_INFO("WLS_Alloc [%d] bytes\n", size);
+
+ pWls_us->HugePageSize = (uint32_t) hugePageSize;
+ pWls_us->alloc_buffer = pvirtAddr;
+ pWls_us->alloc_size = (uint32_t) (nHugePage * hugePageSize);
+
+ if ((pWls_us->mode == WLS_MASTER_CLIENT)||(pWls_us->secmode == WLS_SEC_MASTER)) {
+ wls_us_ctx_t *pWls_usRem = (wls_us_ctx_t*) pWls_us->dst_user_va;
+ PLIB_INFO("Connecting to remote peer ...\n");
+ while (pWls_usRem->wls_us_private.pid == 0) { // wait for slave
+ }
+
+ PLIB_INFO("Connected to remote peer\n");
+ pWls_us->dst_user_va = (uint64_t) pWls_usRem;
+ }
+ return pvirtAddr;
+}
+
+int WLS_Free(void* h, PVOID pMsg)
+{
+ static const struct rte_memzone *mng_memzone;
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t*) h;
+ wls_drv_ctx_t *pDrv_ctx;
+
+ mng_memzone = rte_memzone_lookup(pWls_us->wls_dev_name);
+ if (mng_memzone == NULL) {
+ PLIB_ERR("Cannot find mng memzone: %s %s\n",
+ pWls_us->wls_dev_name, rte_strerror(rte_errno));
+ return -1;
+ }
+ pDrv_ctx = mng_memzone->addr;
+
+ if (pMsg != pWls_us->alloc_buffer) {
+ PLIB_ERR("incorrect pMsg %p [expected %p]\n", pMsg, pWls_us->alloc_buffer);
+ return -1;
+ }
+
+ if ((pWls_us->mode == WLS_MASTER_CLIENT)||(pWls_us->mode == WLS_SEC_MASTER)) {
+ if (pWls_us->dst_user_va) {
+ pWls_us->dst_user_va = 0;
+ }
+ }
+
+ PLIB_DEBUG("WLS_Free %s\n", shm_name);
+ if ( (1 == pDrv_ctx->nWlsClients) && hp_memzone)
+ hp_memzone = NULL;
+ return 0;
+}
+
+int WLS_Put(void *h, unsigned long long pMsg, unsigned int MsgSize, unsigned short MsgTypeID, unsigned short Flags)
+{
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t*) h;
+ int ret = 0;
+
+ if (wls_check_ctx(h))
+ return -1;
+
+ if (!WLS_IS_ONE_HUGE_PAGE(pMsg, MsgSize, hugePageSize)) {
+ PLIB_ERR("WLS_Put input error: buffer is crossing 2MB page boundary %lx size %u\n",
+ (U64) pMsg, MsgSize);
+ }
+
+ wls_mutex_lock(&wls_put_lock);
+
+ if ((WLS_FLAGS_MASK & Flags)) { // multi block transaction
+ if (Flags & WLS_TF_SYN) {
+ PLIB_DEBUG("WLS_SG_FIRST\n");
+ if (WLS_MsgEnqueue(&pWls_us->put_queue, pMsg, MsgSize, MsgTypeID,
+ Flags, NULL, (void*) pWls_us)) {
+ PLIB_DEBUG("WLS_Get %lx %d type %d\n", (U64) pMsg, MsgSize, MsgTypeID);
+ }
+ } else if ((Flags & WLS_TF_SCATTER_GATHER)
+ && !(Flags & WLS_TF_SYN)
+ && !(Flags & WLS_TF_FIN)) {
+ PLIB_DEBUG("WLS_SG_NEXT\n");
+ if (WLS_MsgEnqueue(&pWls_us->put_queue, pMsg, MsgSize, MsgTypeID,
+ Flags, NULL, (void*) pWls_us)) {
+ PLIB_DEBUG("WLS_Put %lx %d type %d\n", (U64) pMsg, MsgSize, MsgTypeID);
+ }
+ } else if (Flags & WLS_TF_FIN) {
+ if (WLS_MsgEnqueue(&pWls_us->put_queue, pMsg, MsgSize, MsgTypeID,
+ Flags, NULL, (void*) pWls_us)) {
+ PLIB_DEBUG("WLS_Put %lx %d type %d\n", (U64) pMsg, MsgSize, MsgTypeID);
+ }
+
+ PLIB_DEBUG("List: call wls_process_put\n");
+ if (pWls_us->dst_user_va) {
+ if ((ret = wls_process_put(pWls_us, (wls_us_ctx_t*) pWls_us->dst_user_va)) < 0) {
+ PLIB_ERR("Put failed [%d]\n", ret);
+ wls_mutex_unlock(&wls_put_lock);
+ return -1;
+ }
+ }
+ } else
+ PLIB_ERR("unsaported flags %x\n", WLS_FLAGS_MASK & Flags);
+ } else { // one block transaction
+ if (WLS_MsgEnqueue(&pWls_us->put_queue, pMsg, MsgSize, MsgTypeID,
+ Flags, NULL, (void*) pWls_us)) {
+ PLIB_DEBUG("WLS_Put %lx %d type %d\n", (U64) pMsg, MsgSize, MsgTypeID);
+ }
+
+ PLIB_DEBUG("One block: call wls_process_put\n");
+ if (likely(pWls_us->dst_user_va)) {
+ if ((ret = wls_process_put(pWls_us, (wls_us_ctx_t*) pWls_us->dst_user_va)) < 0) {
+ PLIB_ERR("Put failed [%d]\n", ret);
+ wls_mutex_unlock(&wls_put_lock);
+ return -1;
+ }
+ } else {
+ PLIB_ERR("Destination address is empty\n");
+ wls_mutex_unlock(&wls_put_lock);
+ return -1;
+ }
+ }
+ wls_mutex_unlock(&wls_put_lock);
+
+ return 0;
+}
+
+int WLS_Put1(void *h, unsigned long long pMsg, unsigned int MsgSize, unsigned short MsgTypeID, unsigned short Flags)
+{
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t*) h;
+ int ret = 0;
+
+ if (wls_check_ctx1(h))
+ return -1;
+
+ if (!WLS_IS_ONE_HUGE_PAGE(pMsg, MsgSize, hugePageSize)) {
+ PLIB_ERR("WLS_Put input error: buffer is crossing 2MB page boundary %lx size %u\n",
+ (U64) pMsg, MsgSize);
+ }
+
+ wls_mutex_lock(&wls_put_lock1);
+
+ if ((WLS_FLAGS_MASK & Flags)) { // multi block transaction
+ if (Flags & WLS_TF_SYN) {
+ PLIB_DEBUG("WLS_SG_FIRST\n");
+ if (WLS_MsgEnqueue(&pWls_us->put_queue, pMsg, MsgSize, MsgTypeID,
+ Flags, NULL, (void*) pWls_us)) {
+ PLIB_DEBUG("WLS_Get %lx %d type %d\n", (U64) pMsg, MsgSize, MsgTypeID);
+ }
+ } else if ((Flags & WLS_TF_SCATTER_GATHER)
+ && !(Flags & WLS_TF_SYN)
+ && !(Flags & WLS_TF_FIN)) {
+ PLIB_DEBUG("WLS_SG_NEXT\n");
+ if (WLS_MsgEnqueue(&pWls_us->put_queue, pMsg, MsgSize, MsgTypeID,
+ Flags, NULL, (void*) pWls_us)) {
+ PLIB_DEBUG("WLS_Put %lx %d type %d\n", (U64) pMsg, MsgSize, MsgTypeID);
+ }
+ } else if (Flags & WLS_TF_FIN) {
+ if (WLS_MsgEnqueue(&pWls_us->put_queue, pMsg, MsgSize, MsgTypeID,
+ Flags, NULL, (void*) pWls_us)) {
+ PLIB_DEBUG("WLS_Put %lx %d type %d\n", (U64) pMsg, MsgSize, MsgTypeID);
+ }
+
+ PLIB_DEBUG("List: call wls_process_put\n");
+ if (pWls_us->dst_user_va) {
+ if ((ret = wls_process_put(pWls_us, (wls_us_ctx_t*) pWls_us->dst_user_va)) < 0) {
+ PLIB_ERR("Put failed [%d]\n", ret);
+ wls_mutex_unlock(&wls_put_lock1);
+ return -1;
+ }
+ }
+ } else
+ PLIB_ERR("unsupported flags %x\n", WLS_FLAGS_MASK & Flags);
+ } else { // one block transaction
+ if (WLS_MsgEnqueue(&pWls_us->put_queue, pMsg, MsgSize, MsgTypeID,
+ Flags, NULL, (void*) pWls_us)) {
+ PLIB_DEBUG("WLS_Put %lx %d type %d\n", (U64) pMsg, MsgSize, MsgTypeID);
+ }
+
+ PLIB_DEBUG("One block: call wls_process_put\n");
+ if (likely(pWls_us->dst_user_va)) {
+ if ((ret = wls_process_put(pWls_us, (wls_us_ctx_t*) pWls_us->dst_user_va)) < 0) {
+ PLIB_ERR("Put failed [%d]\n", ret);
+ wls_mutex_unlock(&wls_put_lock1);
+ return -1;
+ }
+ } else {
+ PLIB_ERR("Destination address is empty\n");
+ wls_mutex_unlock(&wls_put_lock1);
+ return -1;
+ }
+ }
+ wls_mutex_unlock(&wls_put_lock1);
+
+ return 0;
+}
+
+int WLS_Check(void* h)
+{
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t*) h;
+
+ if (wls_check_ctx(h))
+ return 0;
+
+ return WLS_GetNumItemsInTheQueue(&pWls_us->get_queue);
+}
+
+int WLS_Check1(void* h)
+{
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t*) h;
+
+ if (wls_check_ctx1(h))
+ return 0;
+
+ return WLS_GetNumItemsInTheQueue(&pWls_us->get_queue);
+}
+
+unsigned long long WLS_Get(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags)
+{
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t*) h;
+ WLS_MSG_HANDLE hMsg;
+ uint64_t pMsg = (uint64_t) NULL;
+
+ if (wls_check_ctx(h))
+ {
+ PLIB_ERR("WLS_Get fails wls_check_ctx\n");
+ return 0;
+ }
+
+ wls_mutex_lock(&wls_get_lock);
+
+ if (WLS_MsgDequeue(&pWls_us->get_queue, &hMsg, NULL, (void*) pWls_us)) {
+ PLIB_DEBUG("WLS_Get %lx %d type %d\n", (U64) hMsg.pIaPaMsg, hMsg.MsgSize, hMsg.TypeID);
+ pMsg = hMsg.pIaPaMsg;
+ *MsgSize = hMsg.MsgSize;
+ *MsgTypeID = hMsg.TypeID;
+ *Flags = hMsg.flags;
+ }
+
+ wls_mutex_unlock(&wls_get_lock);
+
+ return pMsg;
+}
+
+unsigned long long WLS_Get1(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags)
+{
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t*) h;
+ WLS_MSG_HANDLE hMsg;
+ uint64_t pMsg = (uint64_t) NULL;
+
+ if (wls_check_ctx1(h))
+ return 0;
+
+ wls_mutex_lock(&wls_get_lock1);
+
+ if (WLS_MsgDequeue(&pWls_us->get_queue, &hMsg, NULL, (void*) pWls_us)) {
+ PLIB_DEBUG("WLS_Get %lx %d type %d\n", (U64) hMsg.pIaPaMsg, hMsg.MsgSize, hMsg.TypeID);
+ pMsg = hMsg.pIaPaMsg;
+ *MsgSize = hMsg.MsgSize;
+ *MsgTypeID = hMsg.TypeID;
+ *Flags = hMsg.flags;
+ }
+
+ wls_mutex_unlock(&wls_get_lock1);
+
+ return pMsg;
+}
+
+int WLS_WakeUp(void* h)
+{
+ if (!wls_us_ctx) {
+ PLIB_ERR("Library was not opened\n");
+ return -1;
+ }
+ if (wls_check_ctx(h))
+ return -1;
+
+ PLIB_DEBUG("WLS_WakeUp\n");
+
+ return wls_process_wakeup(h);
+
+
+ return 0;
+}
+
+int WLS_WakeUp1(void* h)
+{
+ if (!wls_us_ctx1) {
+ PLIB_ERR("Library was not opened\n");
+ return -1;
+ }
+ if (wls_check_ctx1(h))
+ return -1;
+
+ PLIB_DEBUG("WLS_WakeUp1\n");
+
+ return wls_process_wakeup1(h);
+
+
+ return 0;
+}
+
+int WLS_Wait(void* h)
+{
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t*) h;
+
+ if (!wls_us_ctx || (wls_us_ctx != pWls_us)) {
+ PLIB_ERR("Library was not opened\n");
+ return -1;
+ }
+
+ return wls_process_wait(h);
+}
+
+int WLS_Wait1(void* h)
+{
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t*) h;
+
+ if (!wls_us_ctx1 || (wls_us_ctx1 != pWls_us)) {
+ PLIB_ERR("Library was not opened\n");
+ return -1;
+ }
+
+ return wls_process_wait1(h);
+}
+
+unsigned long long WLS_WGet(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags)
+{
+ uint64_t pRxMsg = WLS_Get(h, MsgSize, MsgTypeID, Flags);
+
+ if (pRxMsg)
+ return pRxMsg;
+
+ WLS_Wait(h);
+ return WLS_Get(h, MsgSize, MsgTypeID, Flags);
+}
+
+unsigned long long WLS_WGet1(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags)
+{
+ uint64_t pRxMsg = WLS_Get1(h, MsgSize, MsgTypeID, Flags);
+
+ if (pRxMsg)
+ return pRxMsg;
+
+ WLS_Wait1(h);
+ return WLS_Get1(h, MsgSize, MsgTypeID, Flags);
+}
+
+unsigned long long WLS_VA2PA(void* h, PVOID pMsg)
+{
+ uint64_t ret = 0;
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t*) h;
+
+ unsigned long alloc_base;
+ hugepage_tabl_t* pHugePageTlb;
+ uint64_t hugePageBase;
+ uint64_t hugePageOffet;
+ unsigned int count = 0;
+
+ uint64_t HugePageMask = ((unsigned long) pWls_us->HugePageSize - 1);
+ if (pWls_us->alloc_buffer == NULL) {
+ PLIB_ERR("WLS_VA2PA: nothing was allocated [%ld]\n", ret);
+ return (uint64_t) ret;
+ }
+
+ alloc_base = (unsigned long) pWls_us->alloc_buffer;
+
+ pHugePageTlb = &pWls_us->hugepageTbl[0];
+
+ hugePageBase = (uint64_t) pMsg & ~HugePageMask;
+ hugePageOffet = (uint64_t) pMsg & HugePageMask;
+
+ count = (hugePageBase - alloc_base) / pWls_us->HugePageSize;
+ PLIB_DEBUG("WLS_VA2PA %lx base %llx off %llx count %u\n", (unsigned long) pMsg,
+ (uint64_t) hugePageBase, (uint64_t) hugePageOffet, count);
+
+ ret = pHugePageTlb[count].pagePa + hugePageOffet;
+
+ //printf(" WLS_VA2PA: %p -> %p HugePageSize[%d] HugePageMask[%p] count[%d] pagePa[%p] hugePageBase[%p] alloc_buffer[%p] hugePageOffet[%lld]\n",
+ // pMsg, (void*)ret, pWls_us->HugePageSize, (void*)HugePageMask, count, (void*)pHugePageTlb[count].pagePa, (void*)hugePageBase, pWls_us->alloc_buffer, hugePageOffet);
+
+ return (uint64_t) ret;
+}
+
+void* WLS_PA2VA(void* h, unsigned long long pMsg)
+{
+ unsigned long ret = 0;
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t*) h;
+
+ hugepage_tabl_t* pHugePageTlb;
+ uint64_t hugePageBase;
+ uint64_t hugePageOffet;
+ unsigned int count;
+ int i;
+ uint64_t HugePageMask = ((uint64_t) pWls_us->HugePageSize - 1);
+
+ if (pWls_us->alloc_buffer == NULL) {
+ PLIB_ERR("WLS_PA2VA: nothing was allocated [%ld]\n", ret);
+ return (void*) ret;
+ }
+
+ pHugePageTlb = &pWls_us->hugepageTbl[0];
+
+ hugePageBase = (uint64_t) pMsg & ~HugePageMask;
+ hugePageOffet = (uint64_t) pMsg & HugePageMask;
+
+ count = pWls_us->alloc_size / pWls_us->HugePageSize;
+
+ PLIB_DEBUG("WLS_PA2VA %llx base %llx off %llx count %d\n", (uint64_t) pMsg,
+ (uint64_t) hugePageBase, (uint64_t) hugePageOffet, count);
+
+ for (i = 0; i < count; i++) {
+ if (pHugePageTlb[i].pagePa == hugePageBase) {
+ ret = (unsigned long) pHugePageTlb[i].pageVa;
+ ret += hugePageOffet;
+ return (void*) ret;
+ }
+ }
+
+ //printf(" WLS_VA2PA: %p -> %p HugePageSize[%d] HugePageMask[%p] count[%d] pagePa[%p] hugePageBase[%p] alloc_buffer[%p] hugePageOffet[%lld]\n",
+ // (void*)pMsg, (void*)ret, pWls_us->HugePageSize, (void*)HugePageMask, count, (void*)pHugePageTlb[count].pagePa, (void*)hugePageBase, pWls_us->alloc_buffer, hugePageOffet);
+
+ return (void*) (ret);
+}
+
+int WLS_EnqueueBlock(void* h, unsigned long long pMsg)
+{
+ int ret = 0;
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t*) h;
+
+ if (!wls_us_ctx) {
+ PLIB_ERR("Library was not opened\n");
+ return -1;
+ }
+
+
+ if (pMsg == 0) {
+ PLIB_ERR("WLS_EnqueueBlock: Null\n");
+ return -1;
+ }
+
+ if (pWls_us->dst_user_va) {
+ wls_us_ctx_t* pDstWls_us = (wls_us_ctx_t*) pWls_us->dst_user_va;
+ ret = SFL_WlsEnqueue(&pDstWls_us->ul_free_block_pq, pMsg, NULL, pWls_us);
+ if (ret == 1) {
+ unsigned long* ptr = (unsigned long*) WLS_PA2VA(pWls_us, pMsg);
+ if (ptr) {
+ *ptr = 0xFFFFFFFFFFFFFFFF;
+ }
+ }
+ } else
+ ret = -1;
+
+ PLIB_DEBUG("SFL_WlsEnqueue %d\n", ret);
+ return ret;
+}
+
+int WLS_EnqueueBlock1(void* h, unsigned long long pMsg)
+{
+ int ret = 0;
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t*) h;
+
+ if (!wls_us_ctx1) {
+ PLIB_ERR("Library was not opened for a second context\n");
+ return -1;
+ }
+
+ if (pWls_us->mode == WLS_SLAVE_CLIENT) {
+ PLIB_ERR("Slave doesn't support memory allocation\n");
+ return -1;
+ }
+
+ if (pMsg == 0) {
+ PLIB_ERR("WLS_EnqueueBlock: Null\n");
+ return -1;
+ }
+
+ if (pWls_us->dst_user_va) {
+ wls_us_ctx_t* pDstWls_us = (wls_us_ctx_t*) pWls_us->dst_user_va;
+ ret = SFL_WlsEnqueue(&pDstWls_us->ul_free_block_pq, pMsg, NULL, pWls_us);
+ if (ret == 1) {
+ unsigned long* ptr = (unsigned long*) WLS_PA2VA(pWls_us, pMsg);
+ if (ptr) {
+ *ptr = 0xFFFFFFFFFFFFFFFF;
+ }
+ }
+ } else
+ ret = -1;
+
+ PLIB_DEBUG("SFL_WlsEnqueue %d\n", ret);
+ return ret;
+}
+
+
+unsigned long long WLS_DequeueBlock(void* h)
+{
+ unsigned long long retval = 0;
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t*) h;
+
+ if ((pWls_us->mode == WLS_SLAVE_CLIENT)&&(pWls_us->secmode==WLS_SEC_NA))
+ {
+ // local
+ return SFL_WlsDequeue(&pWls_us->ul_free_block_pq, NULL, h);
+ }
+ if (!pWls_us->dst_user_va)
+ {
+ return retval;
+ }
+ // remote
+ wls_us_ctx_t* pDstWls_us = (wls_us_ctx_t*) pWls_us->dst_user_va;
+ retval = SFL_WlsDequeue(&pDstWls_us->ul_free_block_pq, NULL, pDstWls_us);
+ if (retval) {
+ unsigned long* ptr = (unsigned long*) WLS_PA2VA(pWls_us, retval);
+ if (ptr) {
+ if (*ptr != 0xFFFFFFFFFFFFFFFF) {
+ PLIB_ERR("WLS_EnqueueBlock: incorrect content pa: 0x%016lx: 0x%016lx\n",
+ (unsigned long) retval, *ptr);
+ }
+ }
+ }
+
+ return retval;
+}
+
+int WLS_NumBlocks(void* h)
+{
+ wls_us_ctx_t* pWls_us = (wls_us_ctx_t*) h;
+ int n = 0;
+
+ if (pWls_us->mode == WLS_SLAVE_CLIENT) {
+ // local
+ n = SFL_GetNumItemsInTheQueue(&pWls_us->ul_free_block_pq);
+ } else if (pWls_us->dst_user_va) {
+ // remote
+ wls_us_ctx_t* pDstWls_us = (wls_us_ctx_t*) pWls_us->dst_user_va;
+ n = SFL_GetNumItemsInTheQueue(&pDstWls_us->ul_free_block_pq);
+ }
+
+ return n;
+}
diff --git a/wls_lib/wls_start.sh b/wls_lib/wls_start.sh
new file mode 100644
index 0000000..66ae2e6
--- /dev/null
+++ b/wls_lib/wls_start.sh
@@ -0,0 +1,65 @@
+#!/bin/bash
+###############################################################################
+#
+# Copyright (c) 2019 Intel.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###############################################################################
+#
+# File: wls_start.sh
+# Test script to load wls module.
+#
+
+export RTE_WLS=`pwd`
+
+#
+# Unloads wls.ko.
+#
+remove_wls_module()
+{
+ echo "Unloading WLS module"
+ /sbin/lsmod | grep -s wls > /dev/null
+ if [ $? -eq 0 ] ; then
+ sudo /sbin/rmmod wls
+ fi
+}
+
+#
+# Loads new wls.ko
+#
+load_wls_module()
+{
+ if [ ! -f $RTE_WLS/wls.ko ];then
+ echo "## ERROR: Folder does not have the WLS Kernel Module."
+ echo " To fix, please try to rebuild WLS"
+ return
+ fi
+
+ remove_wls_module
+
+ /sbin/lsmod | grep -s wls > /dev/null
+ if [ $? -eq 1 ] ; then
+ if [ -f /lib/modules/$(uname -r)/updates/drivers/intel/wls/wls.ko ] ; then
+ echo "Loading WLS module"
+ sudo /sbin/modprobe wls wlsMaxClients=4
+ else
+ echo "No module. WLS is not istalled? do 'make install'"
+ fi
+ fi
+}
+
+load_wls_module
+
+
+