app/testbbdev: add test application for bbdev
authorAmr Mokhtar <amr.mokhtar@intel.com>
Thu, 11 Jan 2018 19:23:21 +0000 (19:23 +0000)
committerThomas Monjalon <thomas@monjalon.net>
Fri, 19 Jan 2018 00:44:25 +0000 (01:44 +0100)
- full test suite for bbdev
- test App works seamlessly on all PMDs registered with bbdev
 framework
- a python script is provided to make our life easier
- supports execution of tests by parsing Test Vector files
- test Vectors can be added/deleted/modified with no need for
 re-compilation
- various tests can be executed:
 (a) Throughput test
 (b) Offload latency test
 (c) Operation latency test
 (d) Validation test
 (c) Sanity checks

Signed-off-by: Amr Mokhtar <amr.mokhtar@intel.com>
16 files changed:
MAINTAINERS
app/Makefile
app/test-bbdev/Makefile [new file with mode: 0644]
app/test-bbdev/main.c [new file with mode: 0644]
app/test-bbdev/main.h [new file with mode: 0644]
app/test-bbdev/test-bbdev.py [new file with mode: 0755]
app/test-bbdev/test_bbdev.c [new file with mode: 0644]
app/test-bbdev/test_bbdev_perf.c [new file with mode: 0644]
app/test-bbdev/test_bbdev_vector.c [new file with mode: 0644]
app/test-bbdev/test_bbdev_vector.h [new file with mode: 0644]
app/test-bbdev/test_vectors/bbdev_vector_null.data [new file with mode: 0644]
app/test-bbdev/test_vectors/bbdev_vector_td_default.data [new file with mode: 0644]
app/test-bbdev/test_vectors/bbdev_vector_te_default.data [new file with mode: 0644]
config/common_base
doc/guides/tools/index.rst
doc/guides/tools/testbbdev.rst [new file with mode: 0644]

index 03222ce..f6a607e 100644 (file)
@@ -270,6 +270,8 @@ F: lib/librte_bbdev/
 F: doc/guides/prog_guide/bbdev.rst
 F: drivers/bbdev/
 F: doc/guides/bbdevs/
+F: app/test-bbdev/
+F: doc/guides/tools/testbbdev.rst
 
 Crypto API
 M: Declan Doherty <declan.doherty@intel.com>
index aa44827..0eaed53 100644 (file)
@@ -7,6 +7,10 @@ DIRS-$(CONFIG_RTE_TEST_PMD) += test-pmd
 DIRS-$(CONFIG_RTE_PROC_INFO) += proc_info
 DIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += pdump
 
+ifeq ($(CONFIG_RTE_LIBRTE_BBDEV),y)
+DIRS-$(CONFIG_RTE_TEST_BBDEV) += test-bbdev
+endif
+
 ifeq ($(CONFIG_RTE_LIBRTE_CRYPTODEV),y)
 DIRS-$(CONFIG_RTE_APP_CRYPTO_PERF) += test-crypto-perf
 endif
diff --git a/app/test-bbdev/Makefile b/app/test-bbdev/Makefile
new file mode 100644 (file)
index 0000000..5a6e36a
--- /dev/null
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2017 Intel Corporation
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+APP = testbbdev
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+#
+# all sources are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_TEST_BBDEV) += main.c
+SRCS-$(CONFIG_RTE_TEST_BBDEV) += test_bbdev.c
+SRCS-$(CONFIG_RTE_TEST_BBDEV) += test_bbdev_perf.c
+SRCS-$(CONFIG_RTE_TEST_BBDEV) += test_bbdev_vector.c
+
+include $(RTE_SDK)/mk/rte.app.mk
diff --git a/app/test-bbdev/main.c b/app/test-bbdev/main.c
new file mode 100644 (file)
index 0000000..3f542a8
--- /dev/null
@@ -0,0 +1,325 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Intel Corporation
+ */
+
+#include <getopt.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <rte_eal.h>
+#include <rte_common.h>
+#include <rte_string_fns.h>
+#include <rte_cycles.h>
+#include <rte_lcore.h>
+
+#include "main.h"
+
+/* Defines how many testcases can be specified as cmdline args */
+#define MAX_CMDLINE_TESTCASES 8
+
+static const char tc_sep = ',';
+
+static struct test_params {
+       struct test_command *test_to_run[MAX_CMDLINE_TESTCASES];
+       unsigned int num_tests;
+       unsigned int num_ops;
+       unsigned int burst_sz;
+       unsigned int num_lcores;
+       char test_vector_filename[PATH_MAX];
+} test_params;
+
+static struct test_commands_list commands_list =
+       TAILQ_HEAD_INITIALIZER(commands_list);
+
+void
+add_test_command(struct test_command *t)
+{
+       TAILQ_INSERT_TAIL(&commands_list, t, next);
+}
+
+int
+unit_test_suite_runner(struct unit_test_suite *suite)
+{
+       int test_result = TEST_SUCCESS;
+       unsigned int total = 0, skipped = 0, succeeded = 0, failed = 0;
+       uint64_t start, end;
+
+       printf(
+                       "\n + ------------------------------------------------------- +\n");
+       printf(" + Starting Test Suite : %s\n", suite->suite_name);
+
+       start = rte_rdtsc_precise();
+
+       if (suite->setup) {
+               test_result = suite->setup();
+               if (test_result == TEST_FAILED) {
+                       printf(" + Test suite setup %s failed!\n",
+                                       suite->suite_name);
+                       printf(
+                                       " + ------------------------------------------------------- +\n");
+                       return 1;
+               }
+               if (test_result == TEST_SKIPPED) {
+                       printf(" + Test suite setup %s skipped!\n",
+                                       suite->suite_name);
+                       printf(
+                                       " + ------------------------------------------------------- +\n");
+                       return 0;
+               }
+       }
+
+       while (suite->unit_test_cases[total].testcase) {
+               if (suite->unit_test_cases[total].setup)
+                       test_result = suite->unit_test_cases[total].setup();
+
+               if (test_result == TEST_SUCCESS)
+                       test_result = suite->unit_test_cases[total].testcase();
+
+               if (suite->unit_test_cases[total].teardown)
+                       suite->unit_test_cases[total].teardown();
+
+               if (test_result == TEST_SUCCESS) {
+                       succeeded++;
+                       printf(" + TestCase [%2d] : %s passed\n", total,
+                                       suite->unit_test_cases[total].name);
+               } else if (test_result == TEST_SKIPPED) {
+                       skipped++;
+                       printf(" + TestCase [%2d] : %s skipped\n", total,
+                                       suite->unit_test_cases[total].name);
+               } else {
+                       failed++;
+                       printf(" + TestCase [%2d] : %s failed\n", total,
+                                       suite->unit_test_cases[total].name);
+               }
+
+               total++;
+       }
+
+       /* Run test suite teardown */
+       if (suite->teardown)
+               suite->teardown();
+
+       end = rte_rdtsc_precise();
+
+       printf(" + ------------------------------------------------------- +\n");
+       printf(" + Test Suite Summary : %s\n", suite->suite_name);
+       printf(" + Tests Total :       %2d\n", total);
+       printf(" + Tests Skipped :     %2d\n", skipped);
+       printf(" + Tests Passed :      %2d\n", succeeded);
+       printf(" + Tests Failed :      %2d\n", failed);
+       printf(" + Tests Lasted :       %lg ms\n",
+                       ((end - start) * 1000) / (double)rte_get_tsc_hz());
+       printf(" + ------------------------------------------------------- +\n");
+
+       return (failed > 0) ? 1 : 0;
+}
+
+const char *
+get_vector_filename(void)
+{
+       return test_params.test_vector_filename;
+}
+
+unsigned int
+get_num_ops(void)
+{
+       return test_params.num_ops;
+}
+
+unsigned int
+get_burst_sz(void)
+{
+       return test_params.burst_sz;
+}
+
+unsigned int
+get_num_lcores(void)
+{
+       return test_params.num_lcores;
+}
+
+static void
+print_usage(const char *prog_name)
+{
+       struct test_command *t;
+
+       printf("Usage: %s [EAL params] [-- [-n/--num-ops NUM_OPS]\n"
+                       "\t[-b/--burst-size BURST_SIZE]\n"
+                       "\t[-v/--test-vector VECTOR_FILE]\n"
+                       "\t[-c/--test-cases TEST_CASE[,TEST_CASE,...]]]\n",
+                       prog_name);
+
+       printf("Available testcases: ");
+       TAILQ_FOREACH(t, &commands_list, next)
+               printf("%s ", t->command);
+       printf("\n");
+}
+
+static int
+parse_args(int argc, char **argv, struct test_params *tp)
+{
+       int opt, option_index;
+       unsigned int num_tests = 0;
+       bool test_cases_present = false;
+       bool test_vector_present = false;
+       struct test_command *t;
+       char *tokens[MAX_CMDLINE_TESTCASES];
+       int tc, ret;
+
+       static struct option lgopts[] = {
+               { "num-ops", 1, 0, 'n' },
+               { "burst-size", 1, 0, 'b' },
+               { "test-cases", 1, 0, 'c' },
+               { "test-vector", 1, 0, 'v' },
+               { "lcores", 1, 0, 'l' },
+               { "help", 0, 0, 'h' },
+               { NULL,  0, 0, 0 }
+       };
+
+       while ((opt = getopt_long(argc, argv, "hn:b:c:v:l:", lgopts,
+                       &option_index)) != EOF)
+               switch (opt) {
+               case 'n':
+                       TEST_ASSERT(strlen(optarg) > 0,
+                                       "Num of operations is not provided");
+                       tp->num_ops = strtol(optarg, NULL, 10);
+                       break;
+               case 'b':
+                       TEST_ASSERT(strlen(optarg) > 0,
+                                       "Burst size is not provided");
+                       tp->burst_sz = strtol(optarg, NULL, 10);
+                       TEST_ASSERT(tp->burst_sz <= MAX_BURST,
+                                       "Burst size mustn't be greater than %u",
+                                       MAX_BURST);
+                       break;
+               case 'c':
+                       TEST_ASSERT(test_cases_present == false,
+                                       "Test cases provided more than once");
+                       test_cases_present = true;
+
+                       ret = rte_strsplit(optarg, strlen(optarg),
+                                       tokens, MAX_CMDLINE_TESTCASES, tc_sep);
+
+                       TEST_ASSERT(ret <= MAX_CMDLINE_TESTCASES,
+                                       "Too many test cases (max=%d)",
+                                       MAX_CMDLINE_TESTCASES);
+
+                       for (tc = 0; tc < ret; ++tc) {
+                               /* Find matching test case */
+                               TAILQ_FOREACH(t, &commands_list, next)
+                                       if (!strcmp(tokens[tc], t->command))
+                                               tp->test_to_run[num_tests] = t;
+
+                               TEST_ASSERT(tp->test_to_run[num_tests] != NULL,
+                                               "Unknown test case: %s",
+                                               tokens[tc]);
+                               ++num_tests;
+                       }
+                       break;
+               case 'v':
+                       TEST_ASSERT(test_vector_present == false,
+                                       "Test vector provided more than once");
+                       test_vector_present = true;
+
+                       TEST_ASSERT(strlen(optarg) > 0,
+                                       "Config file name is null");
+
+                       strncpy(tp->test_vector_filename, optarg,
+                                       sizeof(tp->test_vector_filename));
+                       break;
+               case 'l':
+                       TEST_ASSERT(strlen(optarg) > 0,
+                                       "Num of lcores is not provided");
+                       tp->num_lcores = strtol(optarg, NULL, 10);
+                       TEST_ASSERT(tp->num_lcores <= RTE_MAX_LCORE,
+                                       "Num of lcores mustn't be greater than %u",
+                                       RTE_MAX_LCORE);
+                       break;
+               case 'h':
+                       print_usage(argv[0]);
+                       return 0;
+               default:
+                       printf("ERROR: Unknown option: -%c\n", opt);
+                       return -1;
+               }
+
+       if (tp->num_ops == 0) {
+               printf(
+                       "WARNING: Num of operations was not provided or was set 0. Set to default (%u)\n",
+                       DEFAULT_OPS);
+               tp->num_ops = DEFAULT_OPS;
+       }
+       if (tp->burst_sz == 0) {
+               printf(
+                       "WARNING: Burst size was not provided or was set 0. Set to default (%u)\n",
+                       DEFAULT_BURST);
+               tp->burst_sz = DEFAULT_BURST;
+       }
+       if (tp->num_lcores == 0) {
+               printf(
+                       "WARNING: Num of lcores was not provided or was set 0. Set to value from RTE config (%u)\n",
+                       rte_lcore_count());
+               tp->num_lcores = rte_lcore_count();
+       }
+
+       TEST_ASSERT(tp->burst_sz <= tp->num_ops,
+                       "Burst size (%u) mustn't be greater than num ops (%u)",
+                       tp->burst_sz, tp->num_ops);
+
+       tp->num_tests = num_tests;
+       return 0;
+}
+
+static int
+run_all_tests(void)
+{
+       int ret = TEST_SUCCESS;
+       struct test_command *t;
+
+       TAILQ_FOREACH(t, &commands_list, next)
+               ret |= t->callback();
+
+       return ret;
+}
+
+static int
+run_parsed_tests(struct test_params *tp)
+{
+       int ret = TEST_SUCCESS;
+       unsigned int i;
+
+       for (i = 0; i < tp->num_tests; ++i)
+               ret |= tp->test_to_run[i]->callback();
+
+       return ret;
+}
+
+int
+main(int argc, char **argv)
+{
+       int ret;
+
+       /* Init EAL */
+       ret = rte_eal_init(argc, argv);
+       if (ret < 0)
+               return 1;
+       argc -= ret;
+       argv += ret;
+
+       /* Parse application arguments (after the EAL ones) */
+       ret = parse_args(argc, argv, &test_params);
+       if (ret < 0) {
+               print_usage(argv[0]);
+               return 1;
+       }
+
+       rte_log_set_global_level(RTE_LOG_INFO);
+
+       /* If no argument provided - run all tests */
+       if (test_params.num_tests == 0)
+               return run_all_tests();
+       else
+               return run_parsed_tests(&test_params);
+}
diff --git a/app/test-bbdev/main.h b/app/test-bbdev/main.h
new file mode 100644 (file)
index 0000000..20a55ef
--- /dev/null
@@ -0,0 +1,120 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Intel Corporation
+ */
+
+#ifndef _MAIN_H_
+#define _MAIN_H_
+
+#include <stddef.h>
+#include <sys/queue.h>
+
+#include <rte_common.h>
+#include <rte_hexdump.h>
+#include <rte_log.h>
+
+#define TEST_SUCCESS    0
+#define TEST_FAILED     -1
+#define TEST_SKIPPED    1
+
+#define MAX_BURST 512U
+#define DEFAULT_BURST 32U
+#define DEFAULT_OPS 64U
+
+#define TEST_ASSERT(cond, msg, ...) do {  \
+               if (!(cond)) {  \
+                       printf("TestCase %s() line %d failed: " \
+                               msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+                       return TEST_FAILED;  \
+               } \
+} while (0)
+
+/* Compare two buffers (length in bytes) */
+#define TEST_ASSERT_BUFFERS_ARE_EQUAL(a, b, len, msg, ...) do { \
+       if (memcmp((a), (b), len)) { \
+               printf("TestCase %s() line %d failed: " \
+                       msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+               rte_memdump(stdout, "Buffer A", (a), len); \
+               rte_memdump(stdout, "Buffer B", (b), len); \
+               return TEST_FAILED; \
+       } \
+} while (0)
+
+#define TEST_ASSERT_SUCCESS(val, msg, ...) do { \
+               typeof(val) _val = (val); \
+               if (!(_val == 0)) { \
+                       printf("TestCase %s() line %d failed (err %d): " \
+                               msg "\n", __func__, __LINE__, _val, \
+                               ##__VA_ARGS__); \
+                       return TEST_FAILED; \
+               } \
+} while (0)
+
+#define TEST_ASSERT_FAIL(val, msg, ...) \
+       TEST_ASSERT_SUCCESS(!(val), msg, ##__VA_ARGS__)
+
+#define TEST_ASSERT_NOT_NULL(val, msg, ...) do { \
+               if ((val) == NULL) { \
+                       printf("TestCase %s() line %d failed (null): " \
+                               msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+                       return TEST_FAILED;  \
+               } \
+} while (0)
+
+struct unit_test_case {
+       int (*setup)(void);
+       void (*teardown)(void);
+       int (*testcase)(void);
+       const char *name;
+};
+
+#define TEST_CASE(testcase) {NULL, NULL, testcase, #testcase}
+
+#define TEST_CASE_ST(setup, teardown, testcase) \
+               {setup, teardown, testcase, #testcase}
+
+#define TEST_CASES_END() {NULL, NULL, NULL, NULL}
+
+struct unit_test_suite {
+       const char *suite_name;
+       int (*setup)(void);
+       void (*teardown)(void);
+       struct unit_test_case unit_test_cases[];
+};
+
+int unit_test_suite_runner(struct unit_test_suite *suite);
+
+typedef int (test_callback)(void);
+TAILQ_HEAD(test_commands_list, test_command);
+struct test_command {
+       TAILQ_ENTRY(test_command) next;
+       const char *command;
+       test_callback *callback;
+};
+
+void add_test_command(struct test_command *t);
+
+/* Register a test function */
+#define REGISTER_TEST_COMMAND(name, testsuite) \
+       static int test_func_##name(void) \
+       { \
+               return unit_test_suite_runner(&testsuite); \
+       } \
+       static struct test_command test_struct_##name = { \
+               .command = RTE_STR(name), \
+               .callback = test_func_##name, \
+       }; \
+       static void __attribute__((constructor, used)) \
+       test_register_##name(void) \
+       { \
+               add_test_command(&test_struct_##name); \
+       }
+
+const char *get_vector_filename(void);
+
+unsigned int get_num_ops(void);
+
+unsigned int get_burst_sz(void);
+
+unsigned int get_num_lcores(void);
+
+#endif
diff --git a/app/test-bbdev/test-bbdev.py b/app/test-bbdev/test-bbdev.py
new file mode 100755 (executable)
index 0000000..ce78149
--- /dev/null
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2017 Intel Corporation
+
+import sys
+import os
+import argparse
+import subprocess
+import shlex
+
+from threading import Timer
+
+def kill(process):
+    print "ERROR: Test app timed out"
+    process.kill()
+
+if "RTE_SDK" in os.environ:
+    dpdk_path = os.environ["RTE_SDK"]
+else:
+    dpdk_path = "../.."
+
+if "RTE_TARGET" in os.environ:
+    dpdk_target = os.environ["RTE_TARGET"]
+else:
+    dpdk_target = "x86_64-native-linuxapp-gcc"
+
+parser = argparse.ArgumentParser(
+                    description='BBdev Unit Test Application',
+                    formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+parser.add_argument("-p", "--testapp-path",
+                    help="specifies path to the bbdev test app",
+                    default=dpdk_path + "/" + dpdk_target + "/app/testbbdev")
+parser.add_argument("-e", "--eal-params",
+                    help="EAL arguments which are passed to the test app",
+                    default="--vdev=bbdev_null0")
+parser.add_argument("-t", "--timeout",
+                    type=int,
+                    help="Timeout in seconds",
+                    default=300)
+parser.add_argument("-c", "--test-cases",
+                    nargs="+",
+                    help="Defines test cases to run. Run all if not specified")
+parser.add_argument("-v", "--test-vector",
+                    nargs="+",
+                    help="Specifies paths to the test vector files.",
+                    default=[dpdk_path +
+                    "/app/test-bbdev/test_vectors/bbdev_vector_null.data"])
+parser.add_argument("-n", "--num-ops",
+                    type=int,
+                    help="Number of operations to process on device.",
+                    default=32)
+parser.add_argument("-b", "--burst-size",
+                    nargs="+",
+                    type=int,
+                    help="Operations enqueue/dequeue burst size.",
+                    default=[32])
+parser.add_argument("-l", "--num-lcores",
+                    type=int,
+                    help="Number of lcores to run.",
+                    default=16)
+
+args = parser.parse_args()
+
+if not os.path.exists(args.testapp_path):
+    print "No such file: " + args.testapp_path
+    sys.exit(1)
+
+params = [args.testapp_path]
+if args.eal_params:
+    params.extend(shlex.split(args.eal_params))
+
+params.extend(["--"])
+
+if args.num_ops:
+    params.extend(["-n", str(args.num_ops)])
+
+if args.num_lcores:
+    params.extend(["-l", str(args.num_lcores)])
+
+if args.test_cases:
+    params.extend(["-c"])
+    params.extend([",".join(args.test_cases)])
+
+exit_status = 0
+for vector in args.test_vector:
+    for burst_size in args.burst_size:
+        call_params = params[:]
+        call_params.extend(["-v", vector])
+        call_params.extend(["-b", str(burst_size)])
+        params_string = " ".join(call_params)
+
+        print("Executing: {}".format(params_string))
+        app_proc = subprocess.Popen(call_params)
+        if args.timeout > 0:
+            timer = Timer(args.timeout, kill, [app_proc])
+            timer.start()
+
+        try:
+            app_proc.communicate()
+        except:
+            print("Error: failed to execute: {}".format(params_string))
+        finally:
+            timer.cancel()
+
+        if app_proc.returncode != 0:
+            exit_status = 1
+            print("ERROR TestCase failed. Failed test for vector {}. Return code: {}".format(
+                vector, app_proc.returncode))
+
+sys.exit(exit_status)
diff --git a/app/test-bbdev/test_bbdev.c b/app/test-bbdev/test_bbdev.c
new file mode 100644 (file)
index 0000000..10579ea
--- /dev/null
@@ -0,0 +1,1378 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Intel Corporation
+ */
+
+#include <rte_common.h>
+#include <rte_hexdump.h>
+#include <rte_mbuf.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_cycles.h>
+
+#include <rte_bus_vdev.h>
+
+#include <rte_bbdev.h>
+#include <rte_bbdev_op.h>
+#include <rte_bbdev_pmd.h>
+
+#include "main.h"
+
+
+#define BBDEV_NAME_NULL          ("bbdev_null")
+
+struct bbdev_testsuite_params {
+       struct rte_bbdev_queue_conf qconf;
+};
+
+static struct bbdev_testsuite_params testsuite_params;
+
+static uint8_t null_dev_id;
+
+static int
+testsuite_setup(void)
+{
+       uint8_t nb_devs;
+       int ret;
+       char buf[RTE_BBDEV_NAME_MAX_LEN];
+
+       /* Create test device */
+       snprintf(buf, sizeof(buf), "%s_unittest", BBDEV_NAME_NULL);
+       ret = rte_vdev_init(buf, NULL);
+       TEST_ASSERT(ret == 0, "Failed to create instance of pmd: %s", buf);
+
+       nb_devs = rte_bbdev_count();
+       TEST_ASSERT(nb_devs != 0, "No devices found");
+
+       /* Most recently created device is our device */
+       null_dev_id = nb_devs - 1;
+
+       return TEST_SUCCESS;
+}
+
+static void
+testsuite_teardown(void)
+{
+       char buf[RTE_BBDEV_NAME_MAX_LEN];
+
+       snprintf(buf, sizeof(buf), "%s_unittest", BBDEV_NAME_NULL);
+       rte_vdev_uninit(buf);
+}
+
+static int
+ut_setup(void)
+{
+       struct bbdev_testsuite_params *ts_params = &testsuite_params;
+       uint8_t num_queues;
+
+       /* Valid queue configuration */
+       ts_params->qconf.priority = 0;
+       ts_params->qconf.socket = SOCKET_ID_ANY;
+       ts_params->qconf.deferred_start = 1;
+
+       num_queues = 1;
+       TEST_ASSERT_SUCCESS(rte_bbdev_setup_queues(null_dev_id, num_queues,
+                       SOCKET_ID_ANY), "Failed to setup queues for bbdev %u",
+                       0);
+
+       /* Start the device */
+       TEST_ASSERT_SUCCESS(rte_bbdev_start(null_dev_id),
+                       "Failed to start bbdev %u", 0);
+
+       return TEST_SUCCESS;
+}
+
+static void
+ut_teardown(void)
+{
+       rte_bbdev_close(null_dev_id);
+}
+
+static int
+test_bbdev_configure_invalid_dev_id(void)
+{
+       uint8_t dev_id;
+       uint8_t num_queues;
+
+       num_queues = 1;
+       for (dev_id = 0; dev_id < RTE_BBDEV_MAX_DEVS; dev_id++) {
+               if (!rte_bbdev_is_valid(dev_id)) {
+                       TEST_ASSERT_FAIL(rte_bbdev_setup_queues(dev_id,
+                                       num_queues, SOCKET_ID_ANY),
+                                       "Failed test for rte_bbdev_setup_queues: "
+                                       "invalid dev_num %u", dev_id);
+                       TEST_ASSERT(rte_bbdev_intr_enable(dev_id) == -ENODEV,
+                                       "Failed test for rte_bbdev_intr_enable: "
+                                       "invalid dev_num %u", dev_id);
+                       break;
+               }
+       }
+
+       return TEST_SUCCESS;
+}
+
+static int
+test_bbdev_configure_invalid_num_queues(void)
+{
+       struct rte_bbdev_info info;
+       uint8_t dev_id, num_devs;
+       uint8_t num_queues;
+       int return_value;
+
+       TEST_ASSERT((num_devs = rte_bbdev_count()) >= 1,
+                       "Need at least %d devices for test", 1);
+
+       /* valid num_queues values */
+       num_queues = 8;
+
+       /* valid dev_id values */
+       dev_id = null_dev_id;
+
+       /* Stop the device in case it's started so it can be configured */
+       rte_bbdev_stop(dev_id);
+
+       TEST_ASSERT_FAIL(rte_bbdev_setup_queues(dev_id, 0, SOCKET_ID_ANY),
+                       "Failed test for rte_bbdev_setup_queues: "
+                       "invalid num_queues %d", 0);
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_setup_queues(dev_id, num_queues,
+                       SOCKET_ID_ANY),
+                       "Failed test for rte_bbdev_setup_queues: "
+                       "invalid dev_num %u", dev_id);
+
+       TEST_ASSERT_FAIL(return_value = rte_bbdev_info_get(dev_id, NULL),
+                        "Failed test for rte_bbdev_info_get: "
+                        "returned value:%i", return_value);
+
+       TEST_ASSERT_SUCCESS(return_value = rte_bbdev_info_get(dev_id, &info),
+                       "Failed test for rte_bbdev_info_get: "
+                       "invalid return value:%i", return_value);
+
+       TEST_ASSERT(info.num_queues == num_queues,
+                       "Failed test for rte_bbdev_info_get: "
+                       "invalid num_queues:%u", info.num_queues);
+
+       num_queues = info.drv.max_num_queues;
+       TEST_ASSERT_SUCCESS(rte_bbdev_setup_queues(dev_id, num_queues,
+                       SOCKET_ID_ANY),
+                       "Failed test for rte_bbdev_setup_queues: "
+                       "invalid num_queues: %u", num_queues);
+
+       num_queues++;
+       TEST_ASSERT_FAIL(rte_bbdev_setup_queues(dev_id, num_queues,
+                       SOCKET_ID_ANY),
+                       "Failed test for rte_bbdev_setup_queues: "
+                       "invalid num_queues: %u", num_queues);
+
+       return TEST_SUCCESS;
+}
+
+static int
+test_bbdev_configure_stop_device(void)
+{
+       struct rte_bbdev_info info;
+       uint8_t dev_id;
+       int return_value;
+
+       /* valid dev_id values */
+       dev_id = null_dev_id;
+
+       /* Stop the device so it can be configured */
+       rte_bbdev_stop(dev_id);
+
+       TEST_ASSERT_SUCCESS(return_value = rte_bbdev_info_get(dev_id, &info),
+                       "Failed test for rte_bbdev_info_get: "
+                       "invalid return value from "
+                       "rte_bbdev_info_get function: %i", return_value);
+
+       TEST_ASSERT_SUCCESS(info.started, "Failed test for rte_bbdev_info_get: "
+                       "started value: %u", info.started);
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_setup_queues(dev_id,
+                       info.drv.max_num_queues, SOCKET_ID_ANY),
+                       "Failed test for rte_bbdev_setup_queues: "
+                       "device should be stopped, dev_id: %u", dev_id);
+
+       return_value = rte_bbdev_intr_enable(dev_id);
+       TEST_ASSERT(return_value != -EBUSY,
+                       "Failed test for rte_bbdev_intr_enable: device should be stopped, dev_id: %u",
+                       dev_id);
+
+       /* Start the device so it cannot be configured */
+       TEST_ASSERT_FAIL(rte_bbdev_start(RTE_BBDEV_MAX_DEVS),
+                       "Failed to start bbdev %u", dev_id);
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_start(dev_id),
+                       "Failed to start bbdev %u", dev_id);
+
+       TEST_ASSERT_SUCCESS(return_value = rte_bbdev_info_get(dev_id, &info),
+                       "Failed test for rte_bbdev_info_get: "
+                       "invalid return value from "
+                       "rte_bbdev_info_get function: %i", return_value);
+
+       TEST_ASSERT_FAIL(info.started, "Failed test for rte_bbdev_info_get: "
+                       "started value: %u", info.started);
+
+       TEST_ASSERT_FAIL(rte_bbdev_setup_queues(dev_id,
+                       info.drv.max_num_queues, SOCKET_ID_ANY),
+                       "Failed test for rte_bbdev_setup_queues: "
+                       "device should be started, dev_id: %u", dev_id);
+
+       return_value = rte_bbdev_intr_enable(dev_id);
+       TEST_ASSERT(return_value == -EBUSY,
+                       "Failed test for rte_bbdev_intr_enable: device should be started, dev_id: %u",
+                       dev_id);
+
+       /* Stop again the device so it can be once again configured */
+       TEST_ASSERT_FAIL(rte_bbdev_stop(RTE_BBDEV_MAX_DEVS),
+                       "Failed to start bbdev %u", dev_id);
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_stop(dev_id), "Failed to stop bbdev %u",
+                       dev_id);
+
+       TEST_ASSERT_SUCCESS(return_value = rte_bbdev_info_get(dev_id, &info),
+                       "Failed test for rte_bbdev_info_get: "
+                       "invalid return value from "
+                       "rte_bbdev_info_get function: %i", return_value);
+
+       TEST_ASSERT_SUCCESS(info.started, "Failed test for rte_bbdev_info_get: "
+                       "started value: %u", info.started);
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_setup_queues(dev_id,
+                       info.drv.max_num_queues, SOCKET_ID_ANY),
+                       "Failed test for rte_bbdev_setup_queues: "
+                       "device should be stopped, dev_id: %u", dev_id);
+
+       return_value = rte_bbdev_intr_enable(dev_id);
+       TEST_ASSERT(return_value != -EBUSY,
+                       "Failed test for rte_bbdev_intr_enable: device should be stopped, dev_id: %u",
+                       dev_id);
+
+       return TEST_SUCCESS;
+}
+
+static int
+test_bbdev_configure_stop_queue(void)
+{
+       struct bbdev_testsuite_params *ts_params = &testsuite_params;
+       struct rte_bbdev_info info;
+       struct rte_bbdev_queue_info qinfo;
+       uint8_t dev_id;
+       uint16_t queue_id;
+       int return_value;
+
+       /* Valid dev_id values */
+       dev_id = null_dev_id;
+
+       /* Valid queue_id values */
+       queue_id = 0;
+
+       rte_bbdev_stop(dev_id);
+       TEST_ASSERT_SUCCESS(return_value = rte_bbdev_info_get(dev_id, &info),
+                       "Failed test for rte_bbdev_info_get: "
+                       "invalid return value:%i", return_value);
+
+       /* Valid queue configuration */
+       ts_params->qconf.queue_size = info.drv.queue_size_lim;
+       ts_params->qconf.priority = info.drv.max_queue_priority;
+
+       /* Device - started; queue - started */
+       rte_bbdev_start(dev_id);
+
+       TEST_ASSERT_FAIL(rte_bbdev_queue_configure(dev_id, queue_id,
+                       &ts_params->qconf),
+                       "Failed test for rte_bbdev_queue_configure: "
+                       "queue:%u on device:%u should be stopped",
+                        queue_id, dev_id);
+
+       /* Device - stopped; queue - started */
+       rte_bbdev_stop(dev_id);
+
+       TEST_ASSERT_FAIL(rte_bbdev_queue_configure(dev_id, queue_id,
+                       &ts_params->qconf),
+                       "Failed test for rte_bbdev_queue_configure: "
+                       "queue:%u on device:%u should be stopped",
+                        queue_id, dev_id);
+
+       TEST_ASSERT_FAIL(rte_bbdev_queue_stop(RTE_BBDEV_MAX_DEVS, queue_id),
+                       "Failed test for rte_bbdev_queue_stop "
+                       "invalid dev_id ");
+
+       TEST_ASSERT_FAIL(rte_bbdev_queue_stop(dev_id, RTE_MAX_QUEUES_PER_PORT),
+                       "Failed test for rte_bbdev_queue_stop "
+                       "invalid queue_id ");
+
+       /* Device - stopped; queue - stopped */
+       rte_bbdev_queue_stop(dev_id, queue_id);
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_queue_configure(dev_id, queue_id,
+                       &ts_params->qconf),
+                       "Failed test for rte_bbdev_queue_configure: "
+                       "queue:%u on device:%u should be stopped", queue_id,
+                       dev_id);
+
+       TEST_ASSERT_SUCCESS(return_value = rte_bbdev_queue_info_get(dev_id,
+                       queue_id, &qinfo),
+                       "Failed test for rte_bbdev_info_get: "
+                       "invalid return value from "
+                       "rte_bbdev_queue_info_get function: %i", return_value);
+
+       TEST_ASSERT(qinfo.conf.socket == ts_params->qconf.socket,
+                       "Failed test for rte_bbdev_queue_info_get: "
+                       "invalid queue_size:%u", qinfo.conf.socket);
+
+       TEST_ASSERT(qinfo.conf.queue_size == ts_params->qconf.queue_size,
+                       "Failed test for rte_bbdev_queue_info_get: "
+                       "invalid queue_size:%u", qinfo.conf.queue_size);
+
+       TEST_ASSERT(qinfo.conf.priority == ts_params->qconf.priority,
+                       "Failed test for rte_bbdev_queue_info_get: "
+                       "invalid queue_size:%u", qinfo.conf.priority);
+
+       TEST_ASSERT(qinfo.conf.deferred_start ==
+                       ts_params->qconf.deferred_start,
+                       "Failed test for rte_bbdev_queue_info_get: "
+                       "invalid queue_size:%u", qinfo.conf.deferred_start);
+
+       /* Device - started; queue - stopped */
+       rte_bbdev_start(dev_id);
+       rte_bbdev_queue_stop(dev_id, queue_id);
+
+       TEST_ASSERT_FAIL(rte_bbdev_queue_configure(dev_id, queue_id,
+                       &ts_params->qconf),
+                       "Failed test for rte_bbdev_queue_configure: "
+                       "queue:%u on device:%u should be stopped", queue_id,
+                       dev_id);
+
+       rte_bbdev_stop(dev_id);
+
+       /* After rte_bbdev_start(dev_id):
+        * - queue should be still stopped if deferred_start ==
+        */
+       rte_bbdev_start(dev_id);
+
+       TEST_ASSERT_SUCCESS(return_value = rte_bbdev_queue_info_get(dev_id,
+                       queue_id, &qinfo),
+                       "Failed test for rte_bbdev_info_get: "
+                       "invalid return value from "
+                       "rte_bbdev_queue_info_get function: %i", return_value);
+
+       TEST_ASSERT(qinfo.started == 0,
+                       "Failed test for rte_bbdev_queue_info_get: "
+                       "invalid value for qinfo.started:%u", qinfo.started);
+
+       rte_bbdev_stop(dev_id);
+
+       /* After rte_bbdev_start(dev_id):
+        * - queue should be started if deferred_start ==
+        */
+       ts_params->qconf.deferred_start = 0;
+       rte_bbdev_queue_configure(dev_id, queue_id, &ts_params->qconf);
+       rte_bbdev_start(dev_id);
+
+       TEST_ASSERT_SUCCESS(return_value = rte_bbdev_queue_info_get(dev_id,
+                       queue_id, &qinfo),
+                       "Failed test for rte_bbdev_info_get: "
+                       "invalid return value from "
+                       "rte_bbdev_queue_info_get function: %i", return_value);
+
+       TEST_ASSERT(qinfo.started == 1,
+                       "Failed test for rte_bbdev_queue_info_get: "
+                       "invalid value for qinfo.started:%u", qinfo.started);
+
+       return TEST_SUCCESS;
+}
+
+static int
+test_bbdev_configure_invalid_queue_configure(void)
+{
+       struct bbdev_testsuite_params *ts_params = &testsuite_params;
+       int return_value;
+       struct rte_bbdev_info info;
+       uint8_t dev_id;
+       uint16_t queue_id;
+
+       /* Valid dev_id values */
+       dev_id = null_dev_id;
+
+       /* Valid queue_id values */
+       queue_id = 0;
+
+       rte_bbdev_stop(dev_id);
+
+       TEST_ASSERT_SUCCESS(return_value = rte_bbdev_info_get(dev_id, &info),
+                       "Failed test for rte_bbdev_info_get: "
+                       "invalid return value:%i", return_value);
+
+       rte_bbdev_queue_stop(dev_id, queue_id);
+
+       ts_params->qconf.queue_size = info.drv.queue_size_lim + 1;
+       TEST_ASSERT_FAIL(rte_bbdev_queue_configure(dev_id, queue_id,
+                       &ts_params->qconf),
+                       "Failed test for rte_bbdev_queue_configure: "
+                       "invalid value qconf.queue_size: %u",
+                       ts_params->qconf.queue_size);
+
+       ts_params->qconf.queue_size = info.drv.queue_size_lim;
+       ts_params->qconf.priority = info.drv.max_queue_priority + 1;
+       TEST_ASSERT_FAIL(rte_bbdev_queue_configure(dev_id, queue_id,
+                       &ts_params->qconf),
+                       "Failed test for rte_bbdev_queue_configure: "
+                       "invalid value qconf.queue_size: %u",
+                       ts_params->qconf.queue_size);
+
+       ts_params->qconf.priority = info.drv.max_queue_priority;
+       queue_id = info.num_queues;
+       TEST_ASSERT_FAIL(rte_bbdev_queue_configure(dev_id, queue_id,
+                       &ts_params->qconf),
+                       "Failed test for rte_bbdev_queue_configure: "
+                       "invalid value queue_id: %u", queue_id);
+
+       queue_id = 0;
+       TEST_ASSERT_SUCCESS(rte_bbdev_queue_configure(dev_id, queue_id, NULL),
+                       "Failed test for rte_bbdev_queue_configure: "
+                       "NULL qconf structure ");
+
+       ts_params->qconf.socket = RTE_MAX_NUMA_NODES;
+       TEST_ASSERT_FAIL(rte_bbdev_queue_configure(dev_id, queue_id,
+                       &ts_params->qconf),
+                       "Failed test for rte_bbdev_queue_configure: "
+                       "invalid socket number ");
+
+       ts_params->qconf.socket = SOCKET_ID_ANY;
+       TEST_ASSERT_SUCCESS(rte_bbdev_queue_configure(dev_id, queue_id,
+                       &ts_params->qconf),
+                       "Failed test for rte_bbdev_queue_configure: "
+                       "invalid value qconf.queue_size: %u",
+                       ts_params->qconf.queue_size);
+
+       TEST_ASSERT_FAIL(rte_bbdev_queue_configure(RTE_BBDEV_MAX_DEVS, queue_id,
+                       &ts_params->qconf),
+                       "Failed test for rte_bbdev_queue_configure: "
+                       "invalid dev_id");
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_queue_configure(dev_id, queue_id, NULL),
+                       "Failed test for rte_bbdev_queue_configure: "
+                       "invalid value qconf.queue_size: %u",
+                       ts_params->qconf.queue_size);
+
+       return TEST_SUCCESS;
+}
+
+static int
+test_bbdev_op_pool(void)
+{
+       struct rte_mempool *mp;
+
+       unsigned int dec_size = sizeof(struct rte_bbdev_dec_op);
+       unsigned int enc_size = sizeof(struct rte_bbdev_enc_op);
+
+       const char *pool_dec = "Test_DEC";
+       const char *pool_enc = "Test_ENC";
+
+       /* Valid pool configuration */
+       uint32_t size = 256;
+       uint32_t cache_size = 128;
+
+       TEST_ASSERT(rte_bbdev_op_pool_create(NULL,
+                       RTE_BBDEV_OP_TURBO_DEC, size, cache_size, 0) == NULL,
+                       "Failed test for rte_bbdev_op_pool_create: "
+                       "NULL name parameter");
+
+       TEST_ASSERT((mp = rte_bbdev_op_pool_create(pool_dec,
+                       RTE_BBDEV_OP_TURBO_DEC, size, cache_size, 0)) != NULL,
+                       "Failed test for rte_bbdev_op_pool_create: "
+                       "returned value is empty");
+
+       TEST_ASSERT(mp->size == size,
+                       "Failed test for rte_bbdev_op_pool_create: "
+                       "invalid size of the mempool, mp->size: %u", mp->size);
+
+       TEST_ASSERT(mp->cache_size == cache_size,
+                       "Failed test for rte_bbdev_op_pool_create: "
+                       "invalid size of the mempool, mp->size: %u",
+                       mp->cache_size);
+
+       TEST_ASSERT_SUCCESS(strcmp(mp->name, pool_dec),
+                       "Failed test for rte_bbdev_op_pool_create: "
+                       "invalid name of mempool, mp->name: %s", mp->name);
+
+       TEST_ASSERT(mp->elt_size == dec_size,
+                       "Failed test for rte_bbdev_op_pool_create: "
+                       "invalid element size for RTE_BBDEV_OP_TURBO_DEC, "
+                       "mp->elt_size: %u", mp->elt_size);
+
+       rte_mempool_free(mp);
+
+       TEST_ASSERT((mp = rte_bbdev_op_pool_create(pool_enc,
+                       RTE_BBDEV_OP_TURBO_ENC, size, cache_size, 0)) != NULL,
+                        "Failed test for rte_bbdev_op_pool_create: "
+                       "returned value is empty");
+
+       TEST_ASSERT(mp->elt_size == enc_size,
+                       "Failed test for rte_bbdev_op_pool_create: "
+                       "invalid element size for RTE_BBDEV_OP_TURBO_ENC, "
+                       "mp->elt_size: %u", mp->elt_size);
+
+       rte_mempool_free(mp);
+
+       TEST_ASSERT((mp = rte_bbdev_op_pool_create("Test_NONE",
+                       RTE_BBDEV_OP_NONE, size, cache_size, 0)) != NULL,
+                       "Failed test for rte_bbdev_op_pool_create: "
+                       "returned value is empty for RTE_BBDEV_OP_NONE");
+
+       TEST_ASSERT(mp->elt_size == (enc_size > dec_size ? enc_size : dec_size),
+                       "Failed test for rte_bbdev_op_pool_create: "
+                       "invalid  size for RTE_BBDEV_OP_NONE, mp->elt_size: %u",
+                       mp->elt_size);
+
+       rte_mempool_free(mp);
+
+       TEST_ASSERT((mp = rte_bbdev_op_pool_create("Test_INV",
+                       RTE_BBDEV_OP_TYPE_COUNT, size, cache_size, 0)) == NULL,
+                       "Failed test for rte_bbdev_op_pool_create: "
+                       "returned value is not NULL for invalid type");
+
+       /* Invalid pool configuration */
+       size = 128;
+       cache_size = 256;
+
+       TEST_ASSERT((mp = rte_bbdev_op_pool_create("Test_InvSize",
+                       RTE_BBDEV_OP_NONE, size, cache_size, 0)) == NULL,
+                       "Failed test for rte_bbdev_op_pool_create: "
+                       "returned value should be empty "
+                       "because size of per-lcore local cache "
+                       "is greater than size of the mempool.");
+
+       return TEST_SUCCESS;
+}
+
+/**
+ *  Create pool of OP types RTE_BBDEV_OP_NONE, RTE_BBDEV_OP_TURBO_DEC and
+ *  RTE_BBDEV_OP_TURBO_ENC and check that only ops of that type can be
+ *  allocated
+ */
+static int
+test_bbdev_op_type(void)
+{
+       struct rte_mempool *mp_dec;
+
+       const unsigned int OPS_COUNT = 32;
+       struct rte_bbdev_dec_op *dec_ops_arr[OPS_COUNT];
+       struct rte_bbdev_enc_op *enc_ops_arr[OPS_COUNT];
+
+       const char *pool_dec = "Test_op_dec";
+
+       /* Valid pool configuration */
+       uint32_t num_elements = 256;
+       uint32_t cache_size = 128;
+
+       /* mempool type : RTE_BBDEV_OP_TURBO_DEC */
+       mp_dec = rte_bbdev_op_pool_create(pool_dec,
+                       RTE_BBDEV_OP_TURBO_DEC, num_elements, cache_size, 0);
+       TEST_ASSERT(mp_dec != NULL, "Failed to create %s mempool", pool_dec);
+
+       TEST_ASSERT(rte_bbdev_dec_op_alloc_bulk(mp_dec, dec_ops_arr, 1) == 0,
+                       "Failed test for rte_bbdev_op_alloc_bulk TURBO_DEC: "
+                       "OPs type: RTE_BBDEV_OP_TURBO_DEC");
+
+       TEST_ASSERT(rte_bbdev_enc_op_alloc_bulk(mp_dec, enc_ops_arr, 1) != 0,
+                       "Failed test for rte_bbdev_op_alloc_bulk TURBO_DEC: "
+                       "OPs type: RTE_BBDEV_OP_TURBO_ENC");
+
+       rte_mempool_free(mp_dec);
+
+       return TEST_SUCCESS;
+}
+
+static int
+test_bbdev_op_pool_size(void)
+{
+       struct rte_mempool *mp_none;
+
+       const unsigned int OPS_COUNT = 128;
+       struct rte_bbdev_enc_op *ops_enc_arr[OPS_COUNT];
+       struct rte_bbdev_enc_op *ops_ext_arr[OPS_COUNT];
+       struct rte_bbdev_enc_op *ops_ext2_arr[OPS_COUNT];
+
+       const char *pool_none = "Test_pool_size";
+
+       /* Valid pool configuration */
+       uint32_t num_elements = 256;
+       uint32_t cache_size = 0;
+
+       /* Create mempool type : RTE_BBDEV_OP_TURBO_ENC, size : 256 */
+       mp_none = rte_bbdev_op_pool_create(pool_none, RTE_BBDEV_OP_TURBO_ENC,
+                       num_elements, cache_size, 0);
+       TEST_ASSERT(mp_none != NULL, "Failed to create %s mempool", pool_none);
+
+       /* Add 128 RTE_BBDEV_OP_TURBO_ENC ops */
+       rte_bbdev_enc_op_alloc_bulk(mp_none, ops_enc_arr, OPS_COUNT);
+
+       /* Add 128 RTE_BBDEV_OP_TURBO_ENC ops */
+       TEST_ASSERT(rte_bbdev_enc_op_alloc_bulk(mp_none, ops_ext_arr,
+                       OPS_COUNT) == 0,
+                       "Failed test for allocating bbdev ops: "
+                       "Mempool size: 256, Free : 128, Attempted to add: 128");
+
+       /* Try adding 128 more RTE_BBDEV_OP_TURBO_ENC ops, this should fail */
+       TEST_ASSERT(rte_bbdev_enc_op_alloc_bulk(mp_none, ops_ext2_arr,
+                       OPS_COUNT) != 0,
+                       "Failed test for allocating bbdev ops: "
+                       "Mempool size: 256, Free : 0, Attempted to add: 128");
+
+       /* Free-up 128 RTE_BBDEV_OP_TURBO_ENC ops */
+       rte_bbdev_enc_op_free_bulk(ops_enc_arr, OPS_COUNT);
+
+       /* Try adding 128 RTE_BBDEV_OP_TURBO_DEC ops, this should succeed */
+       /* Cache size > 0 causes reallocation of ops size > 127 fail */
+       TEST_ASSERT(rte_bbdev_enc_op_alloc_bulk(mp_none, ops_ext2_arr,
+                       OPS_COUNT) == 0,
+                       "Failed test for allocating ops after mempool freed:  "
+                       "Mempool size: 256, Free : 128, Attempted to add: 128");
+
+       rte_mempool_free(mp_none);
+
+       return TEST_SUCCESS;
+}
+
+static int
+test_bbdev_count(void)
+{
+       uint8_t num_devs, num_valid_devs = 0;
+
+       for (num_devs = 0; num_devs < RTE_BBDEV_MAX_DEVS; num_devs++) {
+               if (rte_bbdev_is_valid(num_devs))
+                       num_valid_devs++;
+       }
+
+       num_devs = rte_bbdev_count();
+       TEST_ASSERT(num_valid_devs == num_devs,
+                       "Failed test for rte_bbdev_is_valid: "
+                       "invalid num_devs %u ", num_devs);
+
+       return TEST_SUCCESS;
+}
+
+static int
+test_bbdev_stats(void)
+{
+       uint8_t dev_id = null_dev_id;
+       uint16_t queue_id = 0;
+       struct rte_bbdev_dec_op *dec_ops[4096] = { 0 };
+       struct rte_bbdev_dec_op *dec_proc_ops[4096] = { 0 };
+       struct rte_bbdev_enc_op *enc_ops[4096] = { 0 };
+       struct rte_bbdev_enc_op *enc_proc_ops[4096] = { 0 };
+       uint16_t num_ops = 236;
+       struct rte_bbdev_stats stats;
+       struct bbdev_testsuite_params *ts_params = &testsuite_params;
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_queue_stop(dev_id, queue_id),
+                       "Failed to stop queue %u on device %u ", queue_id,
+                       dev_id);
+       TEST_ASSERT_SUCCESS(rte_bbdev_stop(dev_id),
+                       "Failed to stop bbdev %u ", dev_id);
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_queue_configure(dev_id, queue_id,
+                       &ts_params->qconf),
+                       "Failed to configure queue %u on device %u ",
+                       queue_id, dev_id);
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_start(dev_id),
+                       "Failed to start bbdev %u ", dev_id);
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_queue_start(dev_id, queue_id),
+                       "Failed to start queue %u on device %u ", queue_id,
+                       dev_id);
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_queue_start(dev_id, queue_id),
+                       "Failed to start queue %u on device %u ", queue_id,
+                       dev_id);
+
+       /* Tests after enqueue operation */
+       rte_bbdev_enqueue_enc_ops(dev_id, queue_id, enc_ops, num_ops);
+       rte_bbdev_enqueue_dec_ops(dev_id, queue_id, dec_ops, num_ops);
+
+       TEST_ASSERT_FAIL(rte_bbdev_stats_get(RTE_BBDEV_MAX_DEVS, &stats),
+                       "Failed test for rte_bbdev_stats_get on device %u ",
+                       dev_id);
+
+       TEST_ASSERT_FAIL(rte_bbdev_stats_get(dev_id, NULL),
+                       "Failed test for rte_bbdev_stats_get on device %u ",
+                       dev_id);
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_stats_get(dev_id, &stats),
+                       "Failed test for rte_bbdev_stats_get on device %u ",
+                       dev_id);
+
+       TEST_ASSERT(stats.enqueued_count == 2 * num_ops,
+                       "Failed test for rte_bbdev_enqueue_ops: "
+                       "invalid enqueued_count %" PRIu64 " ",
+                       stats.enqueued_count);
+
+       TEST_ASSERT(stats.dequeued_count == 0,
+                       "Failed test for rte_bbdev_stats_reset: "
+                       "invalid dequeued_count %" PRIu64 " ",
+                       stats.dequeued_count);
+
+       /* Tests after dequeue operation */
+       rte_bbdev_dequeue_enc_ops(dev_id, queue_id, enc_proc_ops, num_ops);
+       rte_bbdev_dequeue_dec_ops(dev_id, queue_id, dec_proc_ops, num_ops);
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_stats_get(dev_id, &stats),
+                       "Failed test for rte_bbdev_stats_get on device %u ",
+                       dev_id);
+
+       TEST_ASSERT(stats.dequeued_count == 2 * num_ops,
+                       "Failed test for rte_bbdev_dequeue_ops: "
+                       "invalid enqueued_count %" PRIu64 " ",
+                       stats.dequeued_count);
+
+       TEST_ASSERT(stats.enqueue_err_count == 0,
+                       "Failed test for rte_bbdev_stats_reset: "
+                       "invalid enqueue_err_count %" PRIu64 " ",
+                       stats.enqueue_err_count);
+
+       TEST_ASSERT(stats.dequeue_err_count == 0,
+                       "Failed test for rte_bbdev_stats_reset: "
+                       "invalid dequeue_err_count %" PRIu64 " ",
+                       stats.dequeue_err_count);
+
+       /* Tests after reset operation */
+       TEST_ASSERT_FAIL(rte_bbdev_stats_reset(RTE_BBDEV_MAX_DEVS),
+                       "Failed to reset statistic for device %u ", dev_id);
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_stats_reset(dev_id),
+                       "Failed to reset statistic for device %u ", dev_id);
+       TEST_ASSERT_SUCCESS(rte_bbdev_stats_get(dev_id, &stats),
+                       "Failed test for rte_bbdev_stats_get on device %u ",
+                       dev_id);
+
+       TEST_ASSERT(stats.enqueued_count == 0,
+                       "Failed test for rte_bbdev_stats_reset: "
+                       "invalid enqueued_count %" PRIu64 " ",
+                       stats.enqueued_count);
+
+       TEST_ASSERT(stats.dequeued_count == 0,
+                       "Failed test for rte_bbdev_stats_reset: "
+                       "invalid dequeued_count %" PRIu64 " ",
+                       stats.dequeued_count);
+
+       TEST_ASSERT(stats.enqueue_err_count == 0,
+                       "Failed test for rte_bbdev_stats_reset: "
+                       "invalid enqueue_err_count %" PRIu64 " ",
+                       stats.enqueue_err_count);
+
+       TEST_ASSERT(stats.dequeue_err_count == 0,
+                       "Failed test for rte_bbdev_stats_reset: "
+                       "invalid dequeue_err_count %" PRIu64 " ",
+                       stats.dequeue_err_count);
+
+       return TEST_SUCCESS;
+}
+
+static int
+test_bbdev_driver_init(void)
+{
+       struct rte_bbdev *dev1, *dev2;
+       const char *name = "dev_name";
+       char name_tmp[16];
+       int num_devs, num_devs_tmp;
+
+       dev1 = rte_bbdev_allocate(NULL);
+       TEST_ASSERT(dev1 == NULL,
+                       "Failed initialize bbdev driver with NULL name");
+
+       dev1 = rte_bbdev_allocate(name);
+       TEST_ASSERT(dev1 != NULL, "Failed to initialize bbdev driver");
+
+       dev2 = rte_bbdev_allocate(name);
+       TEST_ASSERT(dev2 == NULL,
+                       "Failed to initialize bbdev driver: "
+                       "driver with the same name has been initialized before");
+
+       num_devs = rte_bbdev_count() - 1;
+       num_devs_tmp = num_devs;
+
+       /* Initialize the maximum amount of devices */
+       do {
+               sprintf(name_tmp, "%s%i", "name_", num_devs);
+               dev2 = rte_bbdev_allocate(name_tmp);
+               TEST_ASSERT(dev2 != NULL,
+                               "Failed to initialize bbdev driver");
+               ++num_devs;
+       } while (num_devs < (RTE_BBDEV_MAX_DEVS - 1));
+
+       sprintf(name_tmp, "%s%i", "name_", num_devs);
+       dev2 = rte_bbdev_allocate(name_tmp);
+       TEST_ASSERT(dev2 == NULL, "Failed to initialize bbdev driver number %d "
+                       "more drivers than RTE_BBDEV_MAX_DEVS: %d ", num_devs,
+                       RTE_BBDEV_MAX_DEVS);
+
+       num_devs--;
+
+       while (num_devs >= num_devs_tmp) {
+               sprintf(name_tmp, "%s%i", "name_", num_devs);
+               dev2 = rte_bbdev_get_named_dev(name_tmp);
+               TEST_ASSERT_SUCCESS(rte_bbdev_release(dev2),
+                               "Failed to uninitialize bbdev driver %s ",
+                               name_tmp);
+               num_devs--;
+       }
+
+       TEST_ASSERT(dev1->data->dev_id < RTE_BBDEV_MAX_DEVS,
+                       "Failed test rte_bbdev_allocate: "
+                       "invalid dev_id %" PRIu8 ", max number of devices %d ",
+                       dev1->data->dev_id, RTE_BBDEV_MAX_DEVS);
+
+       TEST_ASSERT(dev1->state == RTE_BBDEV_INITIALIZED,
+                       "Failed test rte_bbdev_allocate: "
+                       "invalid state %d (0 - RTE_BBDEV_UNUSED, 1 - RTE_BBDEV_INITIALIZED",
+                       dev1->state);
+
+       TEST_ASSERT_FAIL(rte_bbdev_release(NULL),
+                       "Failed to uninitialize bbdev driver with NULL bbdev");
+
+       sprintf(name_tmp, "%s", "invalid_name");
+       dev2 = rte_bbdev_get_named_dev(name_tmp);
+       TEST_ASSERT_FAIL(rte_bbdev_release(dev2),
+                       "Failed to uninitialize bbdev driver with invalid name");
+
+       dev2 = rte_bbdev_get_named_dev(name);
+       TEST_ASSERT_SUCCESS(rte_bbdev_release(dev2),
+                       "Failed to uninitialize bbdev driver: %s ", name);
+
+       return TEST_SUCCESS;
+}
+
+static void
+event_callback(uint16_t dev_id, enum rte_bbdev_event_type type, void *param,
+               void *ret_param)
+{
+       RTE_SET_USED(dev_id);
+       RTE_SET_USED(ret_param);
+
+       if (param == NULL)
+               return;
+
+       if (type == RTE_BBDEV_EVENT_UNKNOWN ||
+                       type == RTE_BBDEV_EVENT_ERROR ||
+                       type == RTE_BBDEV_EVENT_MAX)
+               *(int *)param = type;
+}
+
+static int
+test_bbdev_callback(void)
+{
+       struct rte_bbdev *dev1, *dev2;
+       const char *name = "dev_name1";
+       const char *name2 = "dev_name2";
+       int event_status;
+       uint8_t invalid_dev_id = RTE_BBDEV_MAX_DEVS;
+       enum rte_bbdev_event_type invalid_event_type = RTE_BBDEV_EVENT_MAX;
+       uint8_t dev_id;
+
+       dev1 = rte_bbdev_allocate(name);
+       TEST_ASSERT(dev1 != NULL, "Failed to initialize bbdev driver");
+
+       /*
+        * RTE_BBDEV_EVENT_UNKNOWN - unregistered
+        * RTE_BBDEV_EVENT_ERROR - unregistered
+        */
+       event_status = -1;
+       rte_bbdev_pmd_callback_process(dev1, RTE_BBDEV_EVENT_UNKNOWN, NULL);
+       rte_bbdev_pmd_callback_process(dev1, RTE_BBDEV_EVENT_ERROR, NULL);
+       TEST_ASSERT(event_status == -1,
+                       "Failed test for rte_bbdev_pmd_callback_process: "
+                       "events were not registered ");
+
+       TEST_ASSERT_FAIL(rte_bbdev_callback_register(dev1->data->dev_id,
+                       RTE_BBDEV_EVENT_MAX, event_callback, NULL),
+                       "Failed to callback register for RTE_BBDEV_EVENT_MAX ");
+
+       TEST_ASSERT_FAIL(rte_bbdev_callback_unregister(dev1->data->dev_id,
+                       RTE_BBDEV_EVENT_MAX, event_callback, NULL),
+                       "Failed to unregister RTE_BBDEV_EVENT_MAX ");
+
+       /*
+        * RTE_BBDEV_EVENT_UNKNOWN - registered
+        * RTE_BBDEV_EVENT_ERROR - unregistered
+        */
+       TEST_ASSERT_SUCCESS(rte_bbdev_callback_register(dev1->data->dev_id,
+                       RTE_BBDEV_EVENT_UNKNOWN, event_callback, &event_status),
+                       "Failed to callback rgstr for RTE_BBDEV_EVENT_UNKNOWN");
+
+       rte_bbdev_pmd_callback_process(dev1, RTE_BBDEV_EVENT_UNKNOWN, NULL);
+       TEST_ASSERT(event_status == 0,
+                       "Failed test for rte_bbdev_pmd_callback_process "
+                       "for RTE_BBDEV_EVENT_UNKNOWN ");
+
+       rte_bbdev_pmd_callback_process(dev1, RTE_BBDEV_EVENT_ERROR, NULL);
+       TEST_ASSERT(event_status == 0,
+                       "Failed test for rte_bbdev_pmd_callback_process: "
+                       "event RTE_BBDEV_EVENT_ERROR was not registered ");
+
+       /*
+        * RTE_BBDEV_EVENT_UNKNOWN - registered
+        * RTE_BBDEV_EVENT_ERROR - registered
+        */
+       TEST_ASSERT_SUCCESS(rte_bbdev_callback_register(dev1->data->dev_id,
+                       RTE_BBDEV_EVENT_ERROR, event_callback, &event_status),
+                       "Failed to callback rgstr for RTE_BBDEV_EVENT_ERROR ");
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_callback_register(dev1->data->dev_id,
+                       RTE_BBDEV_EVENT_ERROR, event_callback, &event_status),
+                       "Failed to callback register for RTE_BBDEV_EVENT_ERROR"
+                       "(re-registration) ");
+
+       event_status = -1;
+       rte_bbdev_pmd_callback_process(dev1, RTE_BBDEV_EVENT_UNKNOWN, NULL);
+       TEST_ASSERT(event_status == 0,
+                       "Failed test for rte_bbdev_pmd_callback_process "
+                       "for RTE_BBDEV_EVENT_UNKNOWN ");
+
+       rte_bbdev_pmd_callback_process(dev1, RTE_BBDEV_EVENT_ERROR, NULL);
+       TEST_ASSERT(event_status == 1,
+                       "Failed test for rte_bbdev_pmd_callback_process "
+                       "for RTE_BBDEV_EVENT_ERROR ");
+
+       /*
+        * RTE_BBDEV_EVENT_UNKNOWN - registered
+        * RTE_BBDEV_EVENT_ERROR - unregistered
+        */
+       TEST_ASSERT_SUCCESS(rte_bbdev_callback_unregister(dev1->data->dev_id,
+                       RTE_BBDEV_EVENT_ERROR, event_callback, &event_status),
+                       "Failed to unregister RTE_BBDEV_EVENT_ERROR ");
+
+       event_status = -1;
+       rte_bbdev_pmd_callback_process(dev1, RTE_BBDEV_EVENT_UNKNOWN, NULL);
+       TEST_ASSERT(event_status == 0,
+                       "Failed test for rte_bbdev_pmd_callback_process "
+                       "for RTE_BBDEV_EVENT_UNKNOWN ");
+
+       rte_bbdev_pmd_callback_process(dev1, RTE_BBDEV_EVENT_ERROR, NULL);
+       TEST_ASSERT(event_status == 0,
+                       "Failed test for rte_bbdev_pmd_callback_process: "
+                       "event RTE_BBDEV_EVENT_ERROR was unregistered ");
+
+       /* rte_bbdev_callback_register with invalid inputs */
+       TEST_ASSERT_FAIL(rte_bbdev_callback_register(invalid_dev_id,
+                       RTE_BBDEV_EVENT_ERROR, event_callback, &event_status),
+                       "Failed test for rte_bbdev_callback_register "
+                       "for invalid_dev_id ");
+
+       TEST_ASSERT_FAIL(rte_bbdev_callback_register(dev1->data->dev_id,
+                       invalid_event_type, event_callback, &event_status),
+                       "Failed to callback register for invalid event type ");
+
+       TEST_ASSERT_FAIL(rte_bbdev_callback_register(dev1->data->dev_id,
+                       RTE_BBDEV_EVENT_ERROR, NULL, &event_status),
+                       "Failed to callback register - no callback function ");
+
+       /* The impact of devices on each other */
+       dev2 = rte_bbdev_allocate(name2);
+       TEST_ASSERT(dev2 != NULL,
+                       "Failed to initialize bbdev driver");
+
+       /*
+        * dev2:
+        * RTE_BBDEV_EVENT_UNKNOWN - unregistered
+        * RTE_BBDEV_EVENT_ERROR - unregistered
+        */
+       event_status = -1;
+       rte_bbdev_pmd_callback_process(dev2, RTE_BBDEV_EVENT_UNKNOWN, NULL);
+       rte_bbdev_pmd_callback_process(dev2, RTE_BBDEV_EVENT_ERROR, NULL);
+       TEST_ASSERT(event_status == -1,
+                       "Failed test for rte_bbdev_pmd_callback_process: "
+                       "events were not registered ");
+
+       /*
+        * dev1: RTE_BBDEV_EVENT_ERROR - unregistered
+        * dev2: RTE_BBDEV_EVENT_ERROR - registered
+        */
+       TEST_ASSERT_SUCCESS(rte_bbdev_callback_register(dev2->data->dev_id,
+                       RTE_BBDEV_EVENT_ERROR, event_callback, &event_status),
+                       "Failed to callback rgstr for RTE_BBDEV_EVENT_ERROR");
+
+       rte_bbdev_pmd_callback_process(dev1, RTE_BBDEV_EVENT_ERROR, NULL);
+       TEST_ASSERT(event_status == -1,
+               "Failed test for rte_bbdev_pmd_callback_process in dev1 "
+               "for RTE_BBDEV_EVENT_ERROR ");
+
+       rte_bbdev_pmd_callback_process(dev2, RTE_BBDEV_EVENT_ERROR, NULL);
+       TEST_ASSERT(event_status == 1,
+               "Failed test for rte_bbdev_pmd_callback_process in dev2 "
+               "for RTE_BBDEV_EVENT_ERROR ");
+
+       /*
+        * dev1: RTE_BBDEV_EVENT_UNKNOWN - registered
+        * dev2: RTE_BBDEV_EVENT_UNKNOWN - unregistered
+        */
+       TEST_ASSERT_SUCCESS(rte_bbdev_callback_register(dev2->data->dev_id,
+                       RTE_BBDEV_EVENT_UNKNOWN, event_callback, &event_status),
+                       "Failed to callback register for RTE_BBDEV_EVENT_UNKNOWN "
+                       "in dev 2 ");
+
+       rte_bbdev_pmd_callback_process(dev2, RTE_BBDEV_EVENT_UNKNOWN, NULL);
+       TEST_ASSERT(event_status == 0,
+                       "Failed test for rte_bbdev_pmd_callback_process in dev2"
+                       " for RTE_BBDEV_EVENT_UNKNOWN ");
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_callback_unregister(dev2->data->dev_id,
+                       RTE_BBDEV_EVENT_UNKNOWN, event_callback, &event_status),
+                       "Failed to unregister RTE_BBDEV_EVENT_UNKNOWN ");
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_callback_unregister(dev2->data->dev_id,
+                       RTE_BBDEV_EVENT_UNKNOWN, event_callback, &event_status),
+                       "Failed to unregister RTE_BBDEV_EVENT_UNKNOWN : "
+                       "unregister function called once again ");
+
+       event_status = -1;
+       rte_bbdev_pmd_callback_process(dev2, RTE_BBDEV_EVENT_UNKNOWN, NULL);
+       TEST_ASSERT(event_status == -1,
+                       "Failed test for rte_bbdev_pmd_callback_process in dev2"
+               " for RTE_BBDEV_EVENT_UNKNOWN ");
+
+       rte_bbdev_pmd_callback_process(dev1, RTE_BBDEV_EVENT_UNKNOWN, NULL);
+       TEST_ASSERT(event_status == 0,
+                       "Failed test for rte_bbdev_pmd_callback_process in dev2 "
+                       "for RTE_BBDEV_EVENT_UNKNOWN ");
+
+       /* rte_bbdev_pmd_callback_process with invalid inputs */
+       rte_bbdev_pmd_callback_process(NULL, RTE_BBDEV_EVENT_UNKNOWN, NULL);
+
+       event_status = -1;
+       rte_bbdev_pmd_callback_process(dev1, invalid_event_type, NULL);
+       TEST_ASSERT(event_status == -1,
+                       "Failed test for rte_bbdev_pmd_callback_process: "
+                       "for invalid event type ");
+
+       /* rte_dev_callback_unregister with invalid inputs */
+       TEST_ASSERT_FAIL(rte_bbdev_callback_unregister(invalid_dev_id,
+                       RTE_BBDEV_EVENT_UNKNOWN, event_callback, &event_status),
+                       "Failed test for rte_dev_callback_unregister "
+                       "for invalid_dev_id ");
+
+       TEST_ASSERT_FAIL(rte_bbdev_callback_unregister(dev1->data->dev_id,
+                       invalid_event_type, event_callback, &event_status),
+                       "Failed rte_dev_callback_unregister "
+                       "for invalid event type ");
+
+       TEST_ASSERT_FAIL(rte_bbdev_callback_unregister(dev1->data->dev_id,
+                       invalid_event_type, NULL, &event_status),
+                       "Failed rte_dev_callback_unregister "
+                       "when no callback function ");
+
+       dev_id = dev1->data->dev_id;
+
+       rte_bbdev_release(dev1);
+       rte_bbdev_release(dev2);
+
+       TEST_ASSERT_FAIL(rte_bbdev_callback_register(dev_id,
+                       RTE_BBDEV_EVENT_ERROR, event_callback, &event_status),
+                       "Failed test for rte_bbdev_callback_register: "
+                       "function called after rte_bbdev_driver_uninit .");
+
+       TEST_ASSERT_FAIL(rte_bbdev_callback_unregister(dev_id,
+                       RTE_BBDEV_EVENT_ERROR, event_callback, &event_status),
+                       "Failed test for rte_dev_callback_unregister: "
+                       "function called after rte_bbdev_driver_uninit. ");
+
+       event_status = -1;
+       rte_bbdev_pmd_callback_process(dev1, RTE_BBDEV_EVENT_UNKNOWN, NULL);
+       rte_bbdev_pmd_callback_process(dev1, RTE_BBDEV_EVENT_ERROR, NULL);
+       rte_bbdev_pmd_callback_process(dev2, RTE_BBDEV_EVENT_UNKNOWN, NULL);
+       rte_bbdev_pmd_callback_process(dev2, RTE_BBDEV_EVENT_ERROR, NULL);
+       TEST_ASSERT(event_status == -1,
+                       "Failed test for rte_bbdev_pmd_callback_process: "
+                       "callback function was called after rte_bbdev_driver_uninit");
+
+       return TEST_SUCCESS;
+}
+
+static int
+test_bbdev_invalid_driver(void)
+{
+       struct rte_bbdev dev1, *dev2;
+       uint8_t dev_id = null_dev_id;
+       uint16_t queue_id = 0;
+       struct rte_bbdev_stats stats;
+       struct bbdev_testsuite_params *ts_params = &testsuite_params;
+       struct rte_bbdev_queue_info qinfo;
+       struct rte_bbdev_ops dev_ops_tmp;
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_stop(dev_id), "Failed to stop bbdev %u ",
+                       dev_id);
+
+       dev1 = rte_bbdev_devices[dev_id];
+       dev2 = &rte_bbdev_devices[dev_id];
+
+       /* Tests for rte_bbdev_setup_queues */
+       dev2->dev_ops = NULL;
+       TEST_ASSERT_FAIL(rte_bbdev_setup_queues(dev_id, 1, SOCKET_ID_ANY),
+                       "Failed test for rte_bbdev_setup_queues: "
+                       "NULL dev_ops structure ");
+       dev2->dev_ops = dev1.dev_ops;
+
+       dev_ops_tmp = *dev2->dev_ops;
+       dev_ops_tmp.info_get = NULL;
+       dev2->dev_ops = &dev_ops_tmp;
+       TEST_ASSERT_FAIL(rte_bbdev_setup_queues(dev_id, 1, SOCKET_ID_ANY),
+                       "Failed test for rte_bbdev_setup_queues: "
+                       "NULL info_get ");
+       dev2->dev_ops = dev1.dev_ops;
+
+       dev_ops_tmp = *dev2->dev_ops;
+       dev_ops_tmp.queue_release = NULL;
+       dev2->dev_ops = &dev_ops_tmp;
+       TEST_ASSERT_FAIL(rte_bbdev_setup_queues(dev_id, 1, SOCKET_ID_ANY),
+                       "Failed test for rte_bbdev_setup_queues: "
+                       "NULL queue_release ");
+       dev2->dev_ops = dev1.dev_ops;
+
+       dev2->data->socket_id = SOCKET_ID_ANY;
+       TEST_ASSERT_SUCCESS(rte_bbdev_setup_queues(dev_id, 1,
+                       SOCKET_ID_ANY), "Failed to configure bbdev %u", dev_id);
+
+       /* Test for rte_bbdev_queue_configure */
+       dev2->dev_ops = NULL;
+       TEST_ASSERT_FAIL(rte_bbdev_queue_configure(dev_id, queue_id,
+                       &ts_params->qconf),
+                       "Failed to configure queue %u on device %u "
+                       "with NULL dev_ops structure ", queue_id, dev_id);
+       dev2->dev_ops = dev1.dev_ops;
+
+       dev_ops_tmp = *dev2->dev_ops;
+       dev_ops_tmp.queue_setup = NULL;
+       dev2->dev_ops = &dev_ops_tmp;
+       TEST_ASSERT_FAIL(rte_bbdev_queue_configure(dev_id, queue_id,
+                       &ts_params->qconf),
+                       "Failed to configure queue %u on device %u "
+                       "with NULL queue_setup ", queue_id, dev_id);
+       dev2->dev_ops = dev1.dev_ops;
+
+       dev_ops_tmp = *dev2->dev_ops;
+       dev_ops_tmp.info_get = NULL;
+       dev2->dev_ops = &dev_ops_tmp;
+       TEST_ASSERT_FAIL(rte_bbdev_queue_configure(dev_id, queue_id,
+                       &ts_params->qconf),
+                       "Failed to configure queue %u on device %u "
+                       "with NULL info_get ", queue_id, dev_id);
+       dev2->dev_ops = dev1.dev_ops;
+
+       TEST_ASSERT_FAIL(rte_bbdev_queue_configure(RTE_BBDEV_MAX_DEVS,
+                       queue_id, &ts_params->qconf),
+                       "Failed to configure queue %u on device %u ",
+                       queue_id, dev_id);
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_queue_configure(dev_id, queue_id,
+                       &ts_params->qconf),
+                       "Failed to configure queue %u on device %u ",
+                       queue_id, dev_id);
+
+       /* Test for rte_bbdev_queue_info_get */
+       dev2->dev_ops = NULL;
+       TEST_ASSERT_SUCCESS(rte_bbdev_queue_info_get(dev_id, queue_id, &qinfo),
+                       "Failed test for rte_bbdev_info_get: "
+                       "NULL dev_ops structure  ");
+       dev2->dev_ops = dev1.dev_ops;
+
+       TEST_ASSERT_FAIL(rte_bbdev_queue_info_get(RTE_BBDEV_MAX_DEVS,
+                       queue_id, &qinfo),
+                       "Failed test for rte_bbdev_info_get: "
+                       "invalid dev_id ");
+
+       TEST_ASSERT_FAIL(rte_bbdev_queue_info_get(dev_id,
+                       RTE_MAX_QUEUES_PER_PORT, &qinfo),
+                       "Failed test for rte_bbdev_info_get: "
+                       "invalid queue_id ");
+
+       TEST_ASSERT_FAIL(rte_bbdev_queue_info_get(dev_id, queue_id, NULL),
+                       "Failed test for rte_bbdev_info_get: "
+                       "invalid dev_info ");
+
+       /* Test for rte_bbdev_start */
+       dev2->dev_ops = NULL;
+       TEST_ASSERT_FAIL(rte_bbdev_start(dev_id),
+                       "Failed to start bbdev %u "
+                       "with NULL dev_ops structure ", dev_id);
+       dev2->dev_ops = dev1.dev_ops;
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_start(dev_id),
+                       "Failed to start bbdev %u ", dev_id);
+
+       /* Test for rte_bbdev_queue_start */
+       dev2->dev_ops = NULL;
+       TEST_ASSERT_FAIL(rte_bbdev_queue_start(dev_id, queue_id),
+                       "Failed to start queue %u on device %u: "
+                       "NULL dev_ops structure", queue_id, dev_id);
+       dev2->dev_ops = dev1.dev_ops;
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_queue_start(dev_id, queue_id),
+                       "Failed to start queue %u on device %u ", queue_id,
+                       dev_id);
+
+       /* Tests for rte_bbdev_stats_get */
+       dev2->dev_ops = NULL;
+       TEST_ASSERT_FAIL(rte_bbdev_stats_get(dev_id, &stats),
+                       "Failed test for rte_bbdev_stats_get on device %u ",
+                       dev_id);
+       dev2->dev_ops = dev1.dev_ops;
+
+       dev_ops_tmp = *dev2->dev_ops;
+       dev_ops_tmp.stats_reset = NULL;
+       dev2->dev_ops = &dev_ops_tmp;
+       TEST_ASSERT_SUCCESS(rte_bbdev_stats_get(dev_id, &stats),
+                       "Failed test for rte_bbdev_stats_get: "
+                       "NULL stats_get ");
+       dev2->dev_ops = dev1.dev_ops;
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_stats_get(dev_id, &stats),
+                       "Failed test for rte_bbdev_stats_get on device %u ",
+                       dev_id);
+
+       /*
+        * Tests for:
+        * rte_bbdev_callback_register,
+        * rte_bbdev_pmd_callback_process,
+        * rte_dev_callback_unregister
+        */
+       dev2->dev_ops = NULL;
+       TEST_ASSERT_SUCCESS(rte_bbdev_callback_register(dev_id,
+                       RTE_BBDEV_EVENT_UNKNOWN, event_callback, NULL),
+                       "Failed to callback rgstr for RTE_BBDEV_EVENT_UNKNOWN");
+       rte_bbdev_pmd_callback_process(dev2, RTE_BBDEV_EVENT_UNKNOWN, NULL);
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_callback_unregister(dev_id,
+                       RTE_BBDEV_EVENT_UNKNOWN, event_callback, NULL),
+                       "Failed to unregister RTE_BBDEV_EVENT_ERROR ");
+       dev2->dev_ops = dev1.dev_ops;
+
+       /* Tests for rte_bbdev_stats_reset */
+       dev2->dev_ops = NULL;
+       TEST_ASSERT_FAIL(rte_bbdev_stats_reset(dev_id),
+                       "Failed to reset statistic for device %u ", dev_id);
+       dev2->dev_ops = dev1.dev_ops;
+
+       dev_ops_tmp = *dev2->dev_ops;
+       dev_ops_tmp.stats_reset = NULL;
+       dev2->dev_ops = &dev_ops_tmp;
+       TEST_ASSERT_SUCCESS(rte_bbdev_stats_reset(dev_id),
+                       "Failed test for rte_bbdev_stats_reset: "
+                       "NULL stats_reset ");
+       dev2->dev_ops = dev1.dev_ops;
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_stats_reset(dev_id),
+                       "Failed to reset statistic for device %u ", dev_id);
+
+       /* Tests for rte_bbdev_queue_stop */
+       dev2->dev_ops = NULL;
+       TEST_ASSERT_FAIL(rte_bbdev_queue_stop(dev_id, queue_id),
+                       "Failed to stop queue %u on device %u: "
+                       "NULL dev_ops structure", queue_id, dev_id);
+       dev2->dev_ops = dev1.dev_ops;
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_queue_stop(dev_id, queue_id),
+                       "Failed to stop queue %u on device %u ", queue_id,
+                       dev_id);
+
+       /* Tests for rte_bbdev_stop */
+       dev2->dev_ops = NULL;
+       TEST_ASSERT_FAIL(rte_bbdev_stop(dev_id),
+                       "Failed to stop bbdev %u with NULL dev_ops structure ",
+                       dev_id);
+       dev2->dev_ops = dev1.dev_ops;
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_stop(dev_id),
+                       "Failed to stop bbdev %u ", dev_id);
+
+       /* Tests for rte_bbdev_close */
+       TEST_ASSERT_FAIL(rte_bbdev_close(RTE_BBDEV_MAX_DEVS),
+                       "Failed to close bbdev with invalid dev_id");
+
+       dev2->dev_ops = NULL;
+       TEST_ASSERT_FAIL(rte_bbdev_close(dev_id),
+                       "Failed to close bbdev %u with NULL dev_ops structure ",
+                       dev_id);
+       dev2->dev_ops = dev1.dev_ops;
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_close(dev_id),
+                       "Failed to close bbdev %u ", dev_id);
+
+       return TEST_SUCCESS;
+}
+
+static int
+test_bbdev_get_named_dev(void)
+{
+       struct rte_bbdev *dev, *dev_tmp;
+       const char *name = "name";
+
+       dev = rte_bbdev_allocate(name);
+       TEST_ASSERT(dev != NULL, "Failed to initialize bbdev driver");
+
+       dev_tmp = rte_bbdev_get_named_dev(NULL);
+       TEST_ASSERT(dev_tmp == NULL, "Failed test for rte_bbdev_get_named_dev: "
+                       "function called with NULL parameter");
+
+       dev_tmp = rte_bbdev_get_named_dev(name);
+
+       TEST_ASSERT(dev == dev_tmp, "Failed test for rte_bbdev_get_named_dev: "
+                       "wrong device was returned ");
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_release(dev),
+                       "Failed to uninitialize bbdev driver %s ", name);
+
+       return TEST_SUCCESS;
+}
+
+static struct unit_test_suite bbdev_null_testsuite = {
+       .suite_name = "BBDEV NULL Unit Test Suite",
+       .setup = testsuite_setup,
+       .teardown = testsuite_teardown,
+       .unit_test_cases = {
+
+               TEST_CASE(test_bbdev_configure_invalid_dev_id),
+
+               TEST_CASE_ST(ut_setup, ut_teardown,
+                               test_bbdev_configure_invalid_num_queues),
+
+               TEST_CASE_ST(ut_setup, ut_teardown,
+                               test_bbdev_configure_stop_device),
+
+               TEST_CASE_ST(ut_setup, ut_teardown,
+                               test_bbdev_configure_stop_queue),
+
+               TEST_CASE_ST(ut_setup, ut_teardown,
+                               test_bbdev_configure_invalid_queue_configure),
+
+               TEST_CASE_ST(ut_setup, ut_teardown,
+                               test_bbdev_op_pool),
+
+               TEST_CASE_ST(ut_setup, ut_teardown,
+                               test_bbdev_op_type),
+
+               TEST_CASE_ST(ut_setup, ut_teardown,
+                               test_bbdev_op_pool_size),
+
+               TEST_CASE_ST(ut_setup, ut_teardown,
+                               test_bbdev_stats),
+
+               TEST_CASE_ST(ut_setup, ut_teardown,
+                               test_bbdev_driver_init),
+
+               TEST_CASE_ST(ut_setup, ut_teardown,
+                               test_bbdev_callback),
+
+               TEST_CASE_ST(ut_setup, ut_teardown,
+                               test_bbdev_invalid_driver),
+
+               TEST_CASE_ST(ut_setup, ut_teardown,
+                               test_bbdev_get_named_dev),
+
+               TEST_CASE(test_bbdev_count),
+
+               TEST_CASES_END() /**< NULL terminate unit test array */
+       }
+};
+
+REGISTER_TEST_COMMAND(unittest, bbdev_null_testsuite);
diff --git a/app/test-bbdev/test_bbdev_perf.c b/app/test-bbdev/test_bbdev_perf.c
new file mode 100644 (file)
index 0000000..f7b51ca
--- /dev/null
@@ -0,0 +1,2136 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Intel Corporation
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <rte_eal.h>
+#include <rte_common.h>
+#include <rte_dev.h>
+#include <rte_launch.h>
+#include <rte_bbdev.h>
+#include <rte_cycles.h>
+#include <rte_lcore.h>
+#include <rte_malloc.h>
+#include <rte_random.h>
+#include <rte_hexdump.h>
+
+#include "main.h"
+#include "test_bbdev_vector.h"
+
+#define GET_SOCKET(socket_id) (((socket_id) == SOCKET_ID_ANY) ? 0 : (socket_id))
+
+#define MAX_QUEUES RTE_MAX_LCORE
+
+#define OPS_CACHE_SIZE 256U
+#define OPS_POOL_SIZE_MIN 511U /* 0.5K per queue */
+
+#define SYNC_WAIT 0
+#define SYNC_START 1
+
+#define INVALID_QUEUE_ID -1
+
+static struct test_bbdev_vector test_vector;
+
+/* Switch between PMD and Interrupt for throughput TC */
+static bool intr_enabled;
+
+/* Represents tested active devices */
+static struct active_device {
+       const char *driver_name;
+       uint8_t dev_id;
+       uint16_t supported_ops;
+       uint16_t queue_ids[MAX_QUEUES];
+       uint16_t nb_queues;
+       struct rte_mempool *ops_mempool;
+       struct rte_mempool *in_mbuf_pool;
+       struct rte_mempool *hard_out_mbuf_pool;
+       struct rte_mempool *soft_out_mbuf_pool;
+} active_devs[RTE_BBDEV_MAX_DEVS];
+
+static uint8_t nb_active_devs;
+
+/* Data buffers used by BBDEV ops */
+struct test_buffers {
+       struct rte_bbdev_op_data *inputs;
+       struct rte_bbdev_op_data *hard_outputs;
+       struct rte_bbdev_op_data *soft_outputs;
+};
+
+/* Operation parameters specific for given test case */
+struct test_op_params {
+       struct rte_mempool *mp;
+       struct rte_bbdev_dec_op *ref_dec_op;
+       struct rte_bbdev_enc_op *ref_enc_op;
+       uint16_t burst_sz;
+       uint16_t num_to_process;
+       uint16_t num_lcores;
+       int vector_mask;
+       rte_atomic16_t sync;
+       struct test_buffers q_bufs[RTE_MAX_NUMA_NODES][MAX_QUEUES];
+};
+
+/* Contains per lcore params */
+struct thread_params {
+       uint8_t dev_id;
+       uint16_t queue_id;
+       uint64_t start_time;
+       double mops;
+       double mbps;
+       rte_atomic16_t nb_dequeued;
+       rte_atomic16_t processing_status;
+       struct test_op_params *op_params;
+};
+
+typedef int (test_case_function)(struct active_device *ad,
+               struct test_op_params *op_params);
+
+static inline void
+set_avail_op(struct active_device *ad, enum rte_bbdev_op_type op_type)
+{
+       ad->supported_ops |= (1 << op_type);
+}
+
+static inline bool
+is_avail_op(struct active_device *ad, enum rte_bbdev_op_type op_type)
+{
+       return ad->supported_ops & (1 << op_type);
+}
+
+static inline bool
+flags_match(uint32_t flags_req, uint32_t flags_present)
+{
+       return (flags_req & flags_present) == flags_req;
+}
+
+static void
+clear_soft_out_cap(uint32_t *op_flags)
+{
+       *op_flags &= ~RTE_BBDEV_TURBO_SOFT_OUTPUT;
+       *op_flags &= ~RTE_BBDEV_TURBO_POS_LLR_1_BIT_SOFT_OUT;
+       *op_flags &= ~RTE_BBDEV_TURBO_NEG_LLR_1_BIT_SOFT_OUT;
+}
+
+static int
+check_dev_cap(const struct rte_bbdev_info *dev_info)
+{
+       unsigned int i;
+       unsigned int nb_inputs, nb_soft_outputs, nb_hard_outputs;
+       const struct rte_bbdev_op_cap *op_cap = dev_info->drv.capabilities;
+
+       nb_inputs = test_vector.entries[DATA_INPUT].nb_segments;
+       nb_soft_outputs = test_vector.entries[DATA_SOFT_OUTPUT].nb_segments;
+       nb_hard_outputs = test_vector.entries[DATA_HARD_OUTPUT].nb_segments;
+
+       for (i = 0; op_cap->type != RTE_BBDEV_OP_NONE; ++i, ++op_cap) {
+               if (op_cap->type != test_vector.op_type)
+                       continue;
+
+               if (op_cap->type == RTE_BBDEV_OP_TURBO_DEC) {
+                       const struct rte_bbdev_op_cap_turbo_dec *cap =
+                                       &op_cap->cap.turbo_dec;
+                       /* Ignore lack of soft output capability, just skip
+                        * checking if soft output is valid.
+                        */
+                       if ((test_vector.turbo_dec.op_flags &
+                                       RTE_BBDEV_TURBO_SOFT_OUTPUT) &&
+                                       !(cap->capability_flags &
+                                       RTE_BBDEV_TURBO_SOFT_OUTPUT)) {
+                               printf(
+                                       "WARNING: Device \"%s\" does not support soft output - soft output flags will be ignored.\n",
+                                       dev_info->dev_name);
+                               clear_soft_out_cap(
+                                       &test_vector.turbo_dec.op_flags);
+                       }
+
+                       if (!flags_match(test_vector.turbo_dec.op_flags,
+                                       cap->capability_flags))
+                               return TEST_FAILED;
+                       if (nb_inputs > cap->num_buffers_src) {
+                               printf("Too many inputs defined: %u, max: %u\n",
+                                       nb_inputs, cap->num_buffers_src);
+                               return TEST_FAILED;
+                       }
+                       if (nb_soft_outputs > cap->num_buffers_soft_out &&
+                                       (test_vector.turbo_dec.op_flags &
+                                       RTE_BBDEV_TURBO_SOFT_OUTPUT)) {
+                               printf(
+                                       "Too many soft outputs defined: %u, max: %u\n",
+                                               nb_soft_outputs,
+                                               cap->num_buffers_soft_out);
+                               return TEST_FAILED;
+                       }
+                       if (nb_hard_outputs > cap->num_buffers_hard_out) {
+                               printf(
+                                       "Too many hard outputs defined: %u, max: %u\n",
+                                               nb_hard_outputs,
+                                               cap->num_buffers_hard_out);
+                               return TEST_FAILED;
+                       }
+                       if (intr_enabled && !(cap->capability_flags &
+                                       RTE_BBDEV_TURBO_DEC_INTERRUPTS)) {
+                               printf(
+                                       "Dequeue interrupts are not supported!\n");
+                               return TEST_FAILED;
+                       }
+
+                       return TEST_SUCCESS;
+               } else if (op_cap->type == RTE_BBDEV_OP_TURBO_ENC) {
+                       const struct rte_bbdev_op_cap_turbo_enc *cap =
+                                       &op_cap->cap.turbo_enc;
+
+                       if (!flags_match(test_vector.turbo_enc.op_flags,
+                                       cap->capability_flags))
+                               return TEST_FAILED;
+                       if (nb_inputs > cap->num_buffers_src) {
+                               printf("Too many inputs defined: %u, max: %u\n",
+                                       nb_inputs, cap->num_buffers_src);
+                               return TEST_FAILED;
+                       }
+                       if (nb_hard_outputs > cap->num_buffers_dst) {
+                               printf(
+                                       "Too many hard outputs defined: %u, max: %u\n",
+                                       nb_hard_outputs, cap->num_buffers_src);
+                               return TEST_FAILED;
+                       }
+                       if (intr_enabled && !(cap->capability_flags &
+                                       RTE_BBDEV_TURBO_ENC_INTERRUPTS)) {
+                               printf(
+                                       "Dequeue interrupts are not supported!\n");
+                               return TEST_FAILED;
+                       }
+
+                       return TEST_SUCCESS;
+               }
+       }
+
+       if ((i == 0) && (test_vector.op_type == RTE_BBDEV_OP_NONE))
+               return TEST_SUCCESS; /* Special case for NULL device */
+
+       return TEST_FAILED;
+}
+
+/* calculates optimal mempool size not smaller than the val */
+static unsigned int
+optimal_mempool_size(unsigned int val)
+{
+       return rte_align32pow2(val + 1) - 1;
+}
+
+/* allocates mbuf mempool for inputs and outputs */
+static struct rte_mempool *
+create_mbuf_pool(struct op_data_entries *entries, uint8_t dev_id,
+               int socket_id, unsigned int mbuf_pool_size,
+               const char *op_type_str)
+{
+       unsigned int i;
+       uint32_t max_seg_sz = 0;
+       char pool_name[RTE_MEMPOOL_NAMESIZE];
+
+       /* find max input segment size */
+       for (i = 0; i < entries->nb_segments; ++i)
+               if (entries->segments[i].length > max_seg_sz)
+                       max_seg_sz = entries->segments[i].length;
+
+       snprintf(pool_name, sizeof(pool_name), "%s_pool_%u", op_type_str,
+                       dev_id);
+       return rte_pktmbuf_pool_create(pool_name, mbuf_pool_size, 0, 0,
+                       RTE_MAX(max_seg_sz + RTE_PKTMBUF_HEADROOM,
+                       (unsigned int)RTE_MBUF_DEFAULT_BUF_SIZE), socket_id);
+}
+
+static int
+create_mempools(struct active_device *ad, int socket_id,
+               enum rte_bbdev_op_type op_type, uint16_t num_ops)
+{
+       struct rte_mempool *mp;
+       unsigned int ops_pool_size, mbuf_pool_size = 0;
+       char pool_name[RTE_MEMPOOL_NAMESIZE];
+       const char *op_type_str;
+
+       struct op_data_entries *in = &test_vector.entries[DATA_INPUT];
+       struct op_data_entries *hard_out =
+                       &test_vector.entries[DATA_HARD_OUTPUT];
+       struct op_data_entries *soft_out =
+                       &test_vector.entries[DATA_SOFT_OUTPUT];
+
+       /* allocate ops mempool */
+       ops_pool_size = optimal_mempool_size(RTE_MAX(
+                       /* Ops used plus 1 reference op */
+                       RTE_MAX((unsigned int)(ad->nb_queues * num_ops + 1),
+                       /* Minimal cache size plus 1 reference op */
+                       (unsigned int)(1.5 * rte_lcore_count() *
+                                       OPS_CACHE_SIZE + 1)),
+                       OPS_POOL_SIZE_MIN));
+
+       op_type_str = rte_bbdev_op_type_str(op_type);
+       TEST_ASSERT_NOT_NULL(op_type_str, "Invalid op type: %u", op_type);
+
+       snprintf(pool_name, sizeof(pool_name), "%s_pool_%u", op_type_str,
+                       ad->dev_id);
+       mp = rte_bbdev_op_pool_create(pool_name, op_type,
+                       ops_pool_size, OPS_CACHE_SIZE, socket_id);
+       TEST_ASSERT_NOT_NULL(mp,
+                       "ERROR Failed to create %u items ops pool for dev %u on socket %u.",
+                       ops_pool_size,
+                       ad->dev_id,
+                       socket_id);
+       ad->ops_mempool = mp;
+
+       /* Inputs */
+       mbuf_pool_size = optimal_mempool_size(ops_pool_size * in->nb_segments);
+       mp = create_mbuf_pool(in, ad->dev_id, socket_id, mbuf_pool_size, "in");
+       TEST_ASSERT_NOT_NULL(mp,
+                       "ERROR Failed to create %u items input pktmbuf pool for dev %u on socket %u.",
+                       mbuf_pool_size,
+                       ad->dev_id,
+                       socket_id);
+       ad->in_mbuf_pool = mp;
+
+       /* Hard outputs */
+       mbuf_pool_size = optimal_mempool_size(ops_pool_size *
+                       hard_out->nb_segments);
+       mp = create_mbuf_pool(hard_out, ad->dev_id, socket_id, mbuf_pool_size,
+                       "hard_out");
+       TEST_ASSERT_NOT_NULL(mp,
+                       "ERROR Failed to create %u items hard output pktmbuf pool for dev %u on socket %u.",
+                       mbuf_pool_size,
+                       ad->dev_id,
+                       socket_id);
+       ad->hard_out_mbuf_pool = mp;
+
+       if (soft_out->nb_segments == 0)
+               return TEST_SUCCESS;
+
+       /* Soft outputs */
+       mbuf_pool_size = optimal_mempool_size(ops_pool_size *
+                       soft_out->nb_segments);
+       mp = create_mbuf_pool(soft_out, ad->dev_id, socket_id, mbuf_pool_size,
+                       "soft_out");
+       TEST_ASSERT_NOT_NULL(mp,
+                       "ERROR Failed to create %uB soft output pktmbuf pool for dev %u on socket %u.",
+                       mbuf_pool_size,
+                       ad->dev_id,
+                       socket_id);
+       ad->soft_out_mbuf_pool = mp;
+
+       return 0;
+}
+
+static int
+add_bbdev_dev(uint8_t dev_id, struct rte_bbdev_info *info,
+               struct test_bbdev_vector *vector)
+{
+       int ret;
+       unsigned int queue_id;
+       struct rte_bbdev_queue_conf qconf;
+       struct active_device *ad = &active_devs[nb_active_devs];
+       unsigned int nb_queues;
+       enum rte_bbdev_op_type op_type = vector->op_type;
+
+       nb_queues = RTE_MIN(rte_lcore_count(), info->drv.max_num_queues);
+       /* setup device */
+       ret = rte_bbdev_setup_queues(dev_id, nb_queues, info->socket_id);
+       if (ret < 0) {
+               printf("rte_bbdev_setup_queues(%u, %u, %d) ret %i\n",
+                               dev_id, nb_queues, info->socket_id, ret);
+               return TEST_FAILED;
+       }
+
+       /* configure interrupts if needed */
+       if (intr_enabled) {
+               ret = rte_bbdev_intr_enable(dev_id);
+               if (ret < 0) {
+                       printf("rte_bbdev_intr_enable(%u) ret %i\n", dev_id,
+                                       ret);
+                       return TEST_FAILED;
+               }
+       }
+
+       /* setup device queues */
+       qconf.socket = info->socket_id;
+       qconf.queue_size = info->drv.default_queue_conf.queue_size;
+       qconf.priority = 0;
+       qconf.deferred_start = 0;
+       qconf.op_type = op_type;
+
+       for (queue_id = 0; queue_id < nb_queues; ++queue_id) {
+               ret = rte_bbdev_queue_configure(dev_id, queue_id, &qconf);
+               if (ret != 0) {
+                       printf(
+                                       "Allocated all queues (id=%u) at prio%u on dev%u\n",
+                                       queue_id, qconf.priority, dev_id);
+                       qconf.priority++;
+                       ret = rte_bbdev_queue_configure(ad->dev_id, queue_id,
+                                       &qconf);
+               }
+               if (ret != 0) {
+                       printf("All queues on dev %u allocated: %u\n",
+                                       dev_id, queue_id);
+                       break;
+               }
+               ad->queue_ids[queue_id] = queue_id;
+       }
+       TEST_ASSERT(queue_id != 0,
+                       "ERROR Failed to configure any queues on dev %u",
+                       dev_id);
+       ad->nb_queues = queue_id;
+
+       set_avail_op(ad, op_type);
+
+       return TEST_SUCCESS;
+}
+
+static int
+add_active_device(uint8_t dev_id, struct rte_bbdev_info *info,
+               struct test_bbdev_vector *vector)
+{
+       int ret;
+
+       active_devs[nb_active_devs].driver_name = info->drv.driver_name;
+       active_devs[nb_active_devs].dev_id = dev_id;
+
+       ret = add_bbdev_dev(dev_id, info, vector);
+       if (ret == TEST_SUCCESS)
+               ++nb_active_devs;
+       return ret;
+}
+
+static uint8_t
+populate_active_devices(void)
+{
+       int ret;
+       uint8_t dev_id;
+       uint8_t nb_devs_added = 0;
+       struct rte_bbdev_info info;
+
+       RTE_BBDEV_FOREACH(dev_id) {
+               rte_bbdev_info_get(dev_id, &info);
+
+               if (check_dev_cap(&info)) {
+                       printf(
+                               "Device %d (%s) does not support specified capabilities\n",
+                                       dev_id, info.dev_name);
+                       continue;
+               }
+
+               ret = add_active_device(dev_id, &info, &test_vector);
+               if (ret != 0) {
+                       printf("Adding active bbdev %s skipped\n",
+                                       info.dev_name);
+                       continue;
+               }
+               nb_devs_added++;
+       }
+
+       return nb_devs_added;
+}
+
+static int
+read_test_vector(void)
+{
+       int ret;
+
+       memset(&test_vector, 0, sizeof(test_vector));
+       printf("Test vector file = %s\n", get_vector_filename());
+       ret = test_bbdev_vector_read(get_vector_filename(), &test_vector);
+       TEST_ASSERT_SUCCESS(ret, "Failed to parse file %s\n",
+                       get_vector_filename());
+
+       return TEST_SUCCESS;
+}
+
+static int
+testsuite_setup(void)
+{
+       TEST_ASSERT_SUCCESS(read_test_vector(), "Test suite setup failed\n");
+
+       if (populate_active_devices() == 0) {
+               printf("No suitable devices found!\n");
+               return TEST_SKIPPED;
+       }
+
+       return TEST_SUCCESS;
+}
+
+static int
+interrupt_testsuite_setup(void)
+{
+       TEST_ASSERT_SUCCESS(read_test_vector(), "Test suite setup failed\n");
+
+       /* Enable interrupts */
+       intr_enabled = true;
+
+       /* Special case for NULL device (RTE_BBDEV_OP_NONE) */
+       if (populate_active_devices() == 0 ||
+                       test_vector.op_type == RTE_BBDEV_OP_NONE) {
+               intr_enabled = false;
+               printf("No suitable devices found!\n");
+               return TEST_SKIPPED;
+       }
+
+       return TEST_SUCCESS;
+}
+
+static void
+testsuite_teardown(void)
+{
+       uint8_t dev_id;
+
+       /* Unconfigure devices */
+       RTE_BBDEV_FOREACH(dev_id)
+               rte_bbdev_close(dev_id);
+
+       /* Clear active devices structs. */
+       memset(active_devs, 0, sizeof(active_devs));
+       nb_active_devs = 0;
+}
+
+static int
+ut_setup(void)
+{
+       uint8_t i, dev_id;
+
+       for (i = 0; i < nb_active_devs; i++) {
+               dev_id = active_devs[i].dev_id;
+               /* reset bbdev stats */
+               TEST_ASSERT_SUCCESS(rte_bbdev_stats_reset(dev_id),
+                               "Failed to reset stats of bbdev %u", dev_id);
+               /* start the device */
+               TEST_ASSERT_SUCCESS(rte_bbdev_start(dev_id),
+                               "Failed to start bbdev %u", dev_id);
+       }
+
+       return TEST_SUCCESS;
+}
+
+static void
+ut_teardown(void)
+{
+       uint8_t i, dev_id;
+       struct rte_bbdev_stats stats;
+
+       for (i = 0; i < nb_active_devs; i++) {
+               dev_id = active_devs[i].dev_id;
+               /* read stats and print */
+               rte_bbdev_stats_get(dev_id, &stats);
+               /* Stop the device */
+               rte_bbdev_stop(dev_id);
+       }
+}
+
+static int
+init_op_data_objs(struct rte_bbdev_op_data *bufs,
+               struct op_data_entries *ref_entries,
+               struct rte_mempool *mbuf_pool, const uint16_t n,
+               enum op_data_type op_type, uint16_t min_alignment)
+{
+       int ret;
+       unsigned int i, j;
+
+       for (i = 0; i < n; ++i) {
+               char *data;
+               struct op_data_buf *seg = &ref_entries->segments[0];
+               struct rte_mbuf *m_head = rte_pktmbuf_alloc(mbuf_pool);
+               TEST_ASSERT_NOT_NULL(m_head,
+                               "Not enough mbufs in %d data type mbuf pool (needed %u, available %u)",
+                               op_type, n * ref_entries->nb_segments,
+                               mbuf_pool->size);
+
+               bufs[i].data = m_head;
+               bufs[i].offset = 0;
+               bufs[i].length = 0;
+
+               if (op_type == DATA_INPUT) {
+                       data = rte_pktmbuf_append(m_head, seg->length);
+                       TEST_ASSERT_NOT_NULL(data,
+                                       "Couldn't append %u bytes to mbuf from %d data type mbuf pool",
+                                       seg->length, op_type);
+
+                       TEST_ASSERT(data == RTE_PTR_ALIGN(data, min_alignment),
+                                       "Data addr in mbuf (%p) is not aligned to device min alignment (%u)",
+                                       data, min_alignment);
+                       rte_memcpy(data, seg->addr, seg->length);
+                       bufs[i].length += seg->length;
+
+
+                       for (j = 1; j < ref_entries->nb_segments; ++j) {
+                               struct rte_mbuf *m_tail =
+                                               rte_pktmbuf_alloc(mbuf_pool);
+                               TEST_ASSERT_NOT_NULL(m_tail,
+                                               "Not enough mbufs in %d data type mbuf pool (needed %u, available %u)",
+                                               op_type,
+                                               n * ref_entries->nb_segments,
+                                               mbuf_pool->size);
+                               seg += 1;
+
+                               data = rte_pktmbuf_append(m_tail, seg->length);
+                               TEST_ASSERT_NOT_NULL(data,
+                                               "Couldn't append %u bytes to mbuf from %d data type mbuf pool",
+                                               seg->length, op_type);
+
+                               TEST_ASSERT(data == RTE_PTR_ALIGN(data,
+                                               min_alignment),
+                                               "Data addr in mbuf (%p) is not aligned to device min alignment (%u)",
+                                               data, min_alignment);
+                               rte_memcpy(data, seg->addr, seg->length);
+                               bufs[i].length += seg->length;
+
+                               ret = rte_pktmbuf_chain(m_head, m_tail);
+                               TEST_ASSERT_SUCCESS(ret,
+                                               "Couldn't chain mbufs from %d data type mbuf pool",
+                                               op_type);
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int
+allocate_buffers_on_socket(struct rte_bbdev_op_data **buffers, const int len,
+               const int socket)
+{
+       int i;
+
+       *buffers = rte_zmalloc_socket(NULL, len, 0, socket);
+       if (*buffers == NULL) {
+               printf("WARNING: Failed to allocate op_data on socket %d\n",
+                               socket);
+               /* try to allocate memory on other detected sockets */
+               for (i = 0; i < socket; i++) {
+                       *buffers = rte_zmalloc_socket(NULL, len, 0, i);
+                       if (*buffers != NULL)
+                               break;
+               }
+       }
+
+       return (*buffers == NULL) ? TEST_FAILED : TEST_SUCCESS;
+}
+
+static int
+fill_queue_buffers(struct test_op_params *op_params,
+               struct rte_mempool *in_mp, struct rte_mempool *hard_out_mp,
+               struct rte_mempool *soft_out_mp, uint16_t queue_id,
+               uint16_t min_alignment, const int socket_id)
+{
+       int ret;
+       enum op_data_type type;
+       const uint16_t n = op_params->num_to_process;
+
+       struct rte_mempool *mbuf_pools[DATA_NUM_TYPES] = {
+               in_mp,
+               soft_out_mp,
+               hard_out_mp,
+       };
+
+       struct rte_bbdev_op_data **queue_ops[DATA_NUM_TYPES] = {
+               &op_params->q_bufs[socket_id][queue_id].inputs,
+               &op_params->q_bufs[socket_id][queue_id].soft_outputs,
+               &op_params->q_bufs[socket_id][queue_id].hard_outputs,
+       };
+
+       for (type = DATA_INPUT; type < DATA_NUM_TYPES; ++type) {
+               struct op_data_entries *ref_entries =
+                               &test_vector.entries[type];
+               if (ref_entries->nb_segments == 0)
+                       continue;
+
+               ret = allocate_buffers_on_socket(queue_ops[type],
+                               n * sizeof(struct rte_bbdev_op_data),
+                               socket_id);
+               TEST_ASSERT_SUCCESS(ret,
+                               "Couldn't allocate memory for rte_bbdev_op_data structs");
+
+               ret = init_op_data_objs(*queue_ops[type], ref_entries,
+                               mbuf_pools[type], n, type, min_alignment);
+               TEST_ASSERT_SUCCESS(ret,
+                               "Couldn't init rte_bbdev_op_data structs");
+       }
+
+       return 0;
+}
+
+static void
+free_buffers(struct active_device *ad, struct test_op_params *op_params)
+{
+       unsigned int i, j;
+
+       rte_mempool_free(ad->ops_mempool);
+       rte_mempool_free(ad->in_mbuf_pool);
+       rte_mempool_free(ad->hard_out_mbuf_pool);
+       rte_mempool_free(ad->soft_out_mbuf_pool);
+
+       for (i = 0; i < rte_lcore_count(); ++i) {
+               for (j = 0; j < RTE_MAX_NUMA_NODES; ++j) {
+                       rte_free(op_params->q_bufs[j][i].inputs);
+                       rte_free(op_params->q_bufs[j][i].hard_outputs);
+                       rte_free(op_params->q_bufs[j][i].soft_outputs);
+               }
+       }
+}
+
+static void
+copy_reference_dec_op(struct rte_bbdev_dec_op **ops, unsigned int n,
+               unsigned int start_idx,
+               struct rte_bbdev_op_data *inputs,
+               struct rte_bbdev_op_data *hard_outputs,
+               struct rte_bbdev_op_data *soft_outputs,
+               struct rte_bbdev_dec_op *ref_op)
+{
+       unsigned int i;
+       struct rte_bbdev_op_turbo_dec *turbo_dec = &ref_op->turbo_dec;
+
+       for (i = 0; i < n; ++i) {
+               if (turbo_dec->code_block_mode == 0) {
+                       ops[i]->turbo_dec.tb_params.ea =
+                                       turbo_dec->tb_params.ea;
+                       ops[i]->turbo_dec.tb_params.eb =
+                                       turbo_dec->tb_params.eb;
+                       ops[i]->turbo_dec.tb_params.k_pos =
+                                       turbo_dec->tb_params.k_pos;
+                       ops[i]->turbo_dec.tb_params.k_neg =
+                                       turbo_dec->tb_params.k_neg;
+                       ops[i]->turbo_dec.tb_params.c =
+                                       turbo_dec->tb_params.c;
+                       ops[i]->turbo_dec.tb_params.c_neg =
+                                       turbo_dec->tb_params.c_neg;
+                       ops[i]->turbo_dec.tb_params.cab =
+                                       turbo_dec->tb_params.cab;
+               } else {
+                       ops[i]->turbo_dec.cb_params.e = turbo_dec->cb_params.e;
+                       ops[i]->turbo_dec.cb_params.k = turbo_dec->cb_params.k;
+               }
+
+               ops[i]->turbo_dec.ext_scale = turbo_dec->ext_scale;
+               ops[i]->turbo_dec.iter_max = turbo_dec->iter_max;
+               ops[i]->turbo_dec.iter_min = turbo_dec->iter_min;
+               ops[i]->turbo_dec.op_flags = turbo_dec->op_flags;
+               ops[i]->turbo_dec.rv_index = turbo_dec->rv_index;
+               ops[i]->turbo_dec.num_maps = turbo_dec->num_maps;
+               ops[i]->turbo_dec.code_block_mode = turbo_dec->code_block_mode;
+
+               ops[i]->turbo_dec.hard_output = hard_outputs[start_idx + i];
+               ops[i]->turbo_dec.input = inputs[start_idx + i];
+               if (soft_outputs != NULL)
+                       ops[i]->turbo_dec.soft_output =
+                               soft_outputs[start_idx + i];
+       }
+}
+
+static void
+copy_reference_enc_op(struct rte_bbdev_enc_op **ops, unsigned int n,
+               unsigned int start_idx,
+               struct rte_bbdev_op_data *inputs,
+               struct rte_bbdev_op_data *outputs,
+               struct rte_bbdev_enc_op *ref_op)
+{
+       unsigned int i;
+       struct rte_bbdev_op_turbo_enc *turbo_enc = &ref_op->turbo_enc;
+       for (i = 0; i < n; ++i) {
+               if (turbo_enc->code_block_mode == 0) {
+                       ops[i]->turbo_enc.tb_params.ea =
+                                       turbo_enc->tb_params.ea;
+                       ops[i]->turbo_enc.tb_params.eb =
+                                       turbo_enc->tb_params.eb;
+                       ops[i]->turbo_enc.tb_params.k_pos =
+                                       turbo_enc->tb_params.k_pos;
+                       ops[i]->turbo_enc.tb_params.k_neg =
+                                       turbo_enc->tb_params.k_neg;
+                       ops[i]->turbo_enc.tb_params.c =
+                                       turbo_enc->tb_params.c;
+                       ops[i]->turbo_enc.tb_params.c_neg =
+                                       turbo_enc->tb_params.c_neg;
+                       ops[i]->turbo_enc.tb_params.cab =
+                                       turbo_enc->tb_params.cab;
+                       ops[i]->turbo_enc.tb_params.ncb_pos =
+                                       turbo_enc->tb_params.ncb_pos;
+                       ops[i]->turbo_enc.tb_params.ncb_neg =
+                                       turbo_enc->tb_params.ncb_neg;
+                       ops[i]->turbo_enc.tb_params.r = turbo_enc->tb_params.r;
+               } else {
+                       ops[i]->turbo_enc.cb_params.e = turbo_enc->cb_params.e;
+                       ops[i]->turbo_enc.cb_params.k = turbo_enc->cb_params.k;
+                       ops[i]->turbo_enc.cb_params.ncb =
+                                       turbo_enc->cb_params.ncb;
+               }
+               ops[i]->turbo_enc.rv_index = turbo_enc->rv_index;
+               ops[i]->turbo_enc.op_flags = turbo_enc->op_flags;
+               ops[i]->turbo_enc.code_block_mode = turbo_enc->code_block_mode;
+
+               ops[i]->turbo_enc.output = outputs[start_idx + i];
+               ops[i]->turbo_enc.input = inputs[start_idx + i];
+       }
+}
+
+static int
+check_dec_status_and_ordering(struct rte_bbdev_dec_op *op,
+               unsigned int order_idx, const int expected_status)
+{
+       TEST_ASSERT(op->status == expected_status,
+                       "op_status (%d) != expected_status (%d)",
+                       op->status, expected_status);
+
+       TEST_ASSERT((void *)(uintptr_t)order_idx == op->opaque_data,
+                       "Ordering error, expected %p, got %p",
+                       (void *)(uintptr_t)order_idx, op->opaque_data);
+
+       return TEST_SUCCESS;
+}
+
+static int
+check_enc_status_and_ordering(struct rte_bbdev_enc_op *op,
+               unsigned int order_idx, const int expected_status)
+{
+       TEST_ASSERT(op->status == expected_status,
+                       "op_status (%d) != expected_status (%d)",
+                       op->status, expected_status);
+
+       TEST_ASSERT((void *)(uintptr_t)order_idx == op->opaque_data,
+                       "Ordering error, expected %p, got %p",
+                       (void *)(uintptr_t)order_idx, op->opaque_data);
+
+       return TEST_SUCCESS;
+}
+
+static inline int
+validate_op_chain(struct rte_bbdev_op_data *op,
+               struct op_data_entries *orig_op)
+{
+       uint8_t i;
+       struct rte_mbuf *m = op->data;
+       uint8_t nb_dst_segments = orig_op->nb_segments;
+
+       TEST_ASSERT(nb_dst_segments == m->nb_segs,
+                       "Number of segments differ in original (%u) and filled (%u) op",
+                       nb_dst_segments, m->nb_segs);
+
+       for (i = 0; i < nb_dst_segments; ++i) {
+               /* Apply offset to the first mbuf segment */
+               uint16_t offset = (i == 0) ? op->offset : 0;
+               uint16_t data_len = m->data_len - offset;
+
+               TEST_ASSERT(orig_op->segments[i].length == data_len,
+                               "Length of segment differ in original (%u) and filled (%u) op",
+                               orig_op->segments[i].length, data_len);
+               TEST_ASSERT_BUFFERS_ARE_EQUAL(orig_op->segments[i].addr,
+                               rte_pktmbuf_mtod_offset(m, uint32_t *, offset),
+                               data_len,
+                               "Output buffers (CB=%u) are not equal", i);
+               m = m->next;
+       }
+
+       return TEST_SUCCESS;
+}
+
+static int
+validate_dec_buffers(struct rte_bbdev_dec_op *ref_op, struct test_buffers *bufs,
+               const uint16_t num_to_process)
+{
+       int i;
+
+       struct op_data_entries *hard_data_orig =
+                       &test_vector.entries[DATA_HARD_OUTPUT];
+       struct op_data_entries *soft_data_orig =
+                       &test_vector.entries[DATA_SOFT_OUTPUT];
+
+       for (i = 0; i < num_to_process; i++) {
+               TEST_ASSERT_SUCCESS(validate_op_chain(&bufs->hard_outputs[i],
+                               hard_data_orig),
+                               "Hard output buffers are not equal");
+               if (ref_op->turbo_dec.op_flags &
+                               RTE_BBDEV_TURBO_SOFT_OUTPUT)
+                       TEST_ASSERT_SUCCESS(validate_op_chain(
+                                       &bufs->soft_outputs[i],
+                                       soft_data_orig),
+                                       "Soft output buffers are not equal");
+       }
+
+       return TEST_SUCCESS;
+}
+
+static int
+validate_enc_buffers(struct test_buffers *bufs, const uint16_t num_to_process)
+{
+       int i;
+
+       struct op_data_entries *hard_data_orig =
+                       &test_vector.entries[DATA_HARD_OUTPUT];
+
+       for (i = 0; i < num_to_process; i++)
+               TEST_ASSERT_SUCCESS(validate_op_chain(&bufs->hard_outputs[i],
+                               hard_data_orig), "");
+
+       return TEST_SUCCESS;
+}
+
+static int
+validate_dec_op(struct rte_bbdev_dec_op **ops, const uint16_t n,
+               struct rte_bbdev_dec_op *ref_op, const int vector_mask)
+{
+       unsigned int i;
+       int ret;
+       struct op_data_entries *hard_data_orig =
+                       &test_vector.entries[DATA_HARD_OUTPUT];
+       struct op_data_entries *soft_data_orig =
+                       &test_vector.entries[DATA_SOFT_OUTPUT];
+       struct rte_bbdev_op_turbo_dec *ops_td;
+       struct rte_bbdev_op_data *hard_output;
+       struct rte_bbdev_op_data *soft_output;
+       struct rte_bbdev_op_turbo_dec *ref_td = &ref_op->turbo_dec;
+
+       for (i = 0; i < n; ++i) {
+               ops_td = &ops[i]->turbo_dec;
+               hard_output = &ops_td->hard_output;
+               soft_output = &ops_td->soft_output;
+
+               if (vector_mask & TEST_BBDEV_VF_EXPECTED_ITER_COUNT)
+                       TEST_ASSERT(ops_td->iter_count <= ref_td->iter_count,
+                                       "Returned iter_count (%d) > expected iter_count (%d)",
+                                       ops_td->iter_count, ref_td->iter_count);
+               ret = check_dec_status_and_ordering(ops[i], i, ref_op->status);
+               TEST_ASSERT_SUCCESS(ret,
+                               "Checking status and ordering for decoder failed");
+
+               TEST_ASSERT_SUCCESS(validate_op_chain(hard_output,
+                               hard_data_orig),
+                               "Hard output buffers (CB=%u) are not equal",
+                               i);
+
+               if (ref_op->turbo_dec.op_flags & RTE_BBDEV_TURBO_SOFT_OUTPUT)
+                       TEST_ASSERT_SUCCESS(validate_op_chain(soft_output,
+                                       soft_data_orig),
+                                       "Soft output buffers (CB=%u) are not equal",
+                                       i);
+       }
+
+       return TEST_SUCCESS;
+}
+
+static int
+validate_enc_op(struct rte_bbdev_enc_op **ops, const uint16_t n,
+               struct rte_bbdev_enc_op *ref_op)
+{
+       unsigned int i;
+       int ret;
+       struct op_data_entries *hard_data_orig =
+                       &test_vector.entries[DATA_HARD_OUTPUT];
+
+       for (i = 0; i < n; ++i) {
+               ret = check_enc_status_and_ordering(ops[i], i, ref_op->status);
+               TEST_ASSERT_SUCCESS(ret,
+                               "Checking status and ordering for encoder failed");
+               TEST_ASSERT_SUCCESS(validate_op_chain(
+                               &ops[i]->turbo_enc.output,
+                               hard_data_orig),
+                               "Output buffers (CB=%u) are not equal",
+                               i);
+       }
+
+       return TEST_SUCCESS;
+}
+
+static void
+create_reference_dec_op(struct rte_bbdev_dec_op *op)
+{
+       unsigned int i;
+       struct op_data_entries *entry;
+
+       op->turbo_dec = test_vector.turbo_dec;
+       entry = &test_vector.entries[DATA_INPUT];
+       for (i = 0; i < entry->nb_segments; ++i)
+               op->turbo_dec.input.length +=
+                               entry->segments[i].length;
+}
+
+static void
+create_reference_enc_op(struct rte_bbdev_enc_op *op)
+{
+       unsigned int i;
+       struct op_data_entries *entry;
+
+       op->turbo_enc = test_vector.turbo_enc;
+       entry = &test_vector.entries[DATA_INPUT];
+       for (i = 0; i < entry->nb_segments; ++i)
+               op->turbo_enc.input.length +=
+                               entry->segments[i].length;
+}
+
+static int
+init_test_op_params(struct test_op_params *op_params,
+               enum rte_bbdev_op_type op_type, const int expected_status,
+               const int vector_mask, struct rte_mempool *ops_mp,
+               uint16_t burst_sz, uint16_t num_to_process, uint16_t num_lcores)
+{
+       int ret = 0;
+       if (op_type == RTE_BBDEV_OP_TURBO_DEC)
+               ret = rte_bbdev_dec_op_alloc_bulk(ops_mp,
+                               &op_params->ref_dec_op, 1);
+       else
+               ret = rte_bbdev_enc_op_alloc_bulk(ops_mp,
+                               &op_params->ref_enc_op, 1);
+
+       TEST_ASSERT_SUCCESS(ret, "rte_bbdev_op_alloc_bulk() failed");
+
+       op_params->mp = ops_mp;
+       op_params->burst_sz = burst_sz;
+       op_params->num_to_process = num_to_process;
+       op_params->num_lcores = num_lcores;
+       op_params->vector_mask = vector_mask;
+       if (op_type == RTE_BBDEV_OP_TURBO_DEC)
+               op_params->ref_dec_op->status = expected_status;
+       else if (op_type == RTE_BBDEV_OP_TURBO_ENC)
+               op_params->ref_enc_op->status = expected_status;
+
+       return 0;
+}
+
+static int
+run_test_case_on_device(test_case_function *test_case_func, uint8_t dev_id,
+               struct test_op_params *op_params)
+{
+       int t_ret, f_ret, socket_id = SOCKET_ID_ANY;
+       unsigned int i;
+       struct active_device *ad;
+       unsigned int burst_sz = get_burst_sz();
+       enum rte_bbdev_op_type op_type = test_vector.op_type;
+
+       ad = &active_devs[dev_id];
+
+       /* Check if device supports op_type */
+       if (!is_avail_op(ad, test_vector.op_type))
+               return TEST_SUCCESS;
+
+       struct rte_bbdev_info info;
+       rte_bbdev_info_get(ad->dev_id, &info);
+       socket_id = GET_SOCKET(info.socket_id);
+
+       if (op_type == RTE_BBDEV_OP_NONE)
+               op_type = RTE_BBDEV_OP_TURBO_ENC;
+       f_ret = create_mempools(ad, socket_id, op_type,
+                       get_num_ops());
+       if (f_ret != TEST_SUCCESS) {
+               printf("Couldn't create mempools");
+               goto fail;
+       }
+
+       f_ret = init_test_op_params(op_params, test_vector.op_type,
+                       test_vector.expected_status,
+                       test_vector.mask,
+                       ad->ops_mempool,
+                       burst_sz,
+                       get_num_ops(),
+                       get_num_lcores());
+       if (f_ret != TEST_SUCCESS) {
+               printf("Couldn't init test op params");
+               goto fail;
+       }
+
+       if (test_vector.op_type == RTE_BBDEV_OP_TURBO_DEC)
+               create_reference_dec_op(op_params->ref_dec_op);
+       else if (test_vector.op_type == RTE_BBDEV_OP_TURBO_ENC)
+               create_reference_enc_op(op_params->ref_enc_op);
+
+       for (i = 0; i < ad->nb_queues; ++i) {
+               f_ret = fill_queue_buffers(op_params,
+                               ad->in_mbuf_pool,
+                               ad->hard_out_mbuf_pool,
+                               ad->soft_out_mbuf_pool,
+                               ad->queue_ids[i],
+                               info.drv.min_alignment,
+                               socket_id);
+               if (f_ret != TEST_SUCCESS) {
+                       printf("Couldn't init queue buffers");
+                       goto fail;
+               }
+       }
+
+       /* Run test case function */
+       t_ret = test_case_func(ad, op_params);
+
+       /* Free active device resources and return */
+       free_buffers(ad, op_params);
+       return t_ret;
+
+fail:
+       free_buffers(ad, op_params);
+       return TEST_FAILED;
+}
+
+/* Run given test function per active device per supported op type
+ * per burst size.
+ */
+static int
+run_test_case(test_case_function *test_case_func)
+{
+       int ret = 0;
+       uint8_t dev;
+
+       /* Alloc op_params */
+       struct test_op_params *op_params = rte_zmalloc(NULL,
+                       sizeof(struct test_op_params), RTE_CACHE_LINE_SIZE);
+       TEST_ASSERT_NOT_NULL(op_params, "Failed to alloc %zuB for op_params",
+                       RTE_ALIGN(sizeof(struct test_op_params),
+                               RTE_CACHE_LINE_SIZE));
+
+       /* For each device run test case function */
+       for (dev = 0; dev < nb_active_devs; ++dev)
+               ret |= run_test_case_on_device(test_case_func, dev, op_params);
+
+       rte_free(op_params);
+
+       return ret;
+}
+
+static void
+dequeue_event_callback(uint16_t dev_id,
+               enum rte_bbdev_event_type event, void *cb_arg,
+               void *ret_param)
+{
+       int ret;
+       uint16_t i;
+       uint64_t total_time;
+       uint16_t deq, burst_sz, num_to_process;
+       uint16_t queue_id = INVALID_QUEUE_ID;
+       struct rte_bbdev_dec_op *dec_ops[MAX_BURST];
+       struct rte_bbdev_enc_op *enc_ops[MAX_BURST];
+       struct test_buffers *bufs;
+       struct rte_bbdev_info info;
+
+       /* Input length in bytes, million operations per second,
+        * million bits per second.
+        */
+       double in_len;
+
+       struct thread_params *tp = cb_arg;
+
+       RTE_SET_USED(ret_param);
+       queue_id = tp->queue_id;
+
+       /* Find matching thread params using queue_id */
+       for (i = 0; i < MAX_QUEUES; ++i, ++tp)
+               if (tp->queue_id == queue_id)
+                       break;
+
+       if (i == MAX_QUEUES) {
+               printf("%s: Queue_id from interrupt details was not found!\n",
+                               __func__);
+               return;
+       }
+
+       if (unlikely(event != RTE_BBDEV_EVENT_DEQUEUE)) {
+               rte_atomic16_set(&tp->processing_status, TEST_FAILED);
+               printf(
+                       "Dequeue interrupt handler called for incorrect event!\n");
+               return;
+       }
+
+       burst_sz = tp->op_params->burst_sz;
+       num_to_process = tp->op_params->num_to_process;
+
+       if (test_vector.op_type == RTE_BBDEV_OP_TURBO_DEC)
+               deq = rte_bbdev_dequeue_dec_ops(dev_id, queue_id, dec_ops,
+                               burst_sz);
+       else
+               deq = rte_bbdev_dequeue_enc_ops(dev_id, queue_id, enc_ops,
+                               burst_sz);
+
+       if (deq < burst_sz) {
+               printf(
+                       "After receiving the interrupt all operations should be dequeued. Expected: %u, got: %u\n",
+                       burst_sz, deq);
+               rte_atomic16_set(&tp->processing_status, TEST_FAILED);
+               return;
+       }
+
+       if (rte_atomic16_read(&tp->nb_dequeued) + deq < num_to_process) {
+               rte_atomic16_add(&tp->nb_dequeued, deq);
+               return;
+       }
+
+       total_time = rte_rdtsc_precise() - tp->start_time;
+
+       rte_bbdev_info_get(dev_id, &info);
+
+       bufs = &tp->op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id];
+
+       ret = TEST_SUCCESS;
+       if (test_vector.op_type == RTE_BBDEV_OP_TURBO_DEC)
+               ret = validate_dec_buffers(tp->op_params->ref_dec_op, bufs,
+                               num_to_process);
+       else if (test_vector.op_type == RTE_BBDEV_OP_TURBO_ENC)
+               ret = validate_enc_buffers(bufs, num_to_process);
+
+       if (ret) {
+               printf("Buffers validation failed\n");
+               rte_atomic16_set(&tp->processing_status, TEST_FAILED);
+       }
+
+       switch (test_vector.op_type) {
+       case RTE_BBDEV_OP_TURBO_DEC:
+               in_len = tp->op_params->ref_dec_op->turbo_dec.input.length;
+               break;
+       case RTE_BBDEV_OP_TURBO_ENC:
+               in_len = tp->op_params->ref_enc_op->turbo_enc.input.length;
+               break;
+       case RTE_BBDEV_OP_NONE:
+               in_len = 0.0;
+               break;
+       default:
+               printf("Unknown op type: %d\n", test_vector.op_type);
+               rte_atomic16_set(&tp->processing_status, TEST_FAILED);
+               return;
+       }
+
+       tp->mops = ((double)num_to_process / 1000000.0) /
+                       ((double)total_time / (double)rte_get_tsc_hz());
+       tp->mbps = ((double)num_to_process * in_len * 8 / 1000000.0) /
+                       ((double)total_time / (double)rte_get_tsc_hz());
+
+       rte_atomic16_add(&tp->nb_dequeued, deq);
+}
+
+static int
+throughput_intr_lcore_dec(void *arg)
+{
+       struct thread_params *tp = arg;
+       unsigned int enqueued;
+       struct rte_bbdev_dec_op *ops[MAX_BURST];
+       const uint16_t queue_id = tp->queue_id;
+       const uint16_t burst_sz = tp->op_params->burst_sz;
+       const uint16_t num_to_process = tp->op_params->num_to_process;
+       struct test_buffers *bufs = NULL;
+       unsigned int allocs_failed = 0;
+       struct rte_bbdev_info info;
+       int ret;
+
+       TEST_ASSERT_SUCCESS((burst_sz > MAX_BURST),
+                       "BURST_SIZE should be <= %u", MAX_BURST);
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_queue_intr_enable(tp->dev_id, queue_id),
+                       "Failed to enable interrupts for dev: %u, queue_id: %u",
+                       tp->dev_id, queue_id);
+
+       rte_bbdev_info_get(tp->dev_id, &info);
+       bufs = &tp->op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id];
+
+       rte_atomic16_clear(&tp->processing_status);
+       rte_atomic16_clear(&tp->nb_dequeued);
+
+       while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT)
+               rte_pause();
+
+       tp->start_time = rte_rdtsc_precise();
+       for (enqueued = 0; enqueued < num_to_process;) {
+
+               uint16_t num_to_enq = burst_sz;
+
+               if (unlikely(num_to_process - enqueued < num_to_enq))
+                       num_to_enq = num_to_process - enqueued;
+
+               ret = rte_bbdev_dec_op_alloc_bulk(tp->op_params->mp, ops,
+                               num_to_enq);
+               if (ret != 0) {
+                       allocs_failed++;
+                       continue;
+               }
+
+               if (test_vector.op_type != RTE_BBDEV_OP_NONE)
+                       copy_reference_dec_op(ops, num_to_enq, enqueued,
+                                       bufs->inputs,
+                                       bufs->hard_outputs,
+                                       bufs->soft_outputs,
+                                       tp->op_params->ref_dec_op);
+
+               enqueued += rte_bbdev_enqueue_dec_ops(tp->dev_id, queue_id, ops,
+                               num_to_enq);
+
+               rte_bbdev_dec_op_free_bulk(ops, num_to_enq);
+       }
+
+       if (allocs_failed > 0)
+               printf("WARNING: op allocations failed: %u times\n",
+                               allocs_failed);
+
+       return TEST_SUCCESS;
+}
+
+static int
+throughput_intr_lcore_enc(void *arg)
+{
+       struct thread_params *tp = arg;
+       unsigned int enqueued;
+       struct rte_bbdev_enc_op *ops[MAX_BURST];
+       const uint16_t queue_id = tp->queue_id;
+       const uint16_t burst_sz = tp->op_params->burst_sz;
+       const uint16_t num_to_process = tp->op_params->num_to_process;
+       struct test_buffers *bufs = NULL;
+       unsigned int allocs_failed = 0;
+       struct rte_bbdev_info info;
+       int ret;
+
+       TEST_ASSERT_SUCCESS((burst_sz > MAX_BURST),
+                       "BURST_SIZE should be <= %u", MAX_BURST);
+
+       TEST_ASSERT_SUCCESS(rte_bbdev_queue_intr_enable(tp->dev_id, queue_id),
+                       "Failed to enable interrupts for dev: %u, queue_id: %u",
+                       tp->dev_id, queue_id);
+
+       rte_bbdev_info_get(tp->dev_id, &info);
+       bufs = &tp->op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id];
+
+       rte_atomic16_clear(&tp->processing_status);
+       rte_atomic16_clear(&tp->nb_dequeued);
+
+       while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT)
+               rte_pause();
+
+       tp->start_time = rte_rdtsc_precise();
+       for (enqueued = 0; enqueued < num_to_process;) {
+
+               uint16_t num_to_enq = burst_sz;
+
+               if (unlikely(num_to_process - enqueued < num_to_enq))
+                       num_to_enq = num_to_process - enqueued;
+
+               ret = rte_bbdev_enc_op_alloc_bulk(tp->op_params->mp, ops,
+                               num_to_enq);
+               if (ret != 0) {
+                       allocs_failed++;
+                       continue;
+               }
+
+               if (test_vector.op_type != RTE_BBDEV_OP_NONE)
+                       copy_reference_enc_op(ops, num_to_enq, enqueued,
+                                       bufs->inputs,
+                                       bufs->hard_outputs,
+                                       tp->op_params->ref_enc_op);
+
+               enqueued += rte_bbdev_enqueue_enc_ops(tp->dev_id, queue_id, ops,
+                               num_to_enq);
+
+               rte_bbdev_enc_op_free_bulk(ops, num_to_enq);
+       }
+
+       if (allocs_failed > 0)
+               printf("WARNING: op allocations failed: %u times\n",
+                               allocs_failed);
+
+       return TEST_SUCCESS;
+}
+
+static int
+throughput_pmd_lcore_dec(void *arg)
+{
+       struct thread_params *tp = arg;
+       unsigned int enqueued, dequeued;
+       struct rte_bbdev_dec_op *ops_enq[MAX_BURST], *ops_deq[MAX_BURST];
+       uint64_t total_time, start_time;
+       const uint16_t queue_id = tp->queue_id;
+       const uint16_t burst_sz = tp->op_params->burst_sz;
+       const uint16_t num_to_process = tp->op_params->num_to_process;
+       struct rte_bbdev_dec_op *ref_op = tp->op_params->ref_dec_op;
+       struct test_buffers *bufs = NULL;
+       unsigned int allocs_failed = 0;
+       int ret;
+       struct rte_bbdev_info info;
+
+       /* Input length in bytes, million operations per second, million bits
+        * per second.
+        */
+       double in_len;
+
+       TEST_ASSERT_SUCCESS((burst_sz > MAX_BURST),
+                       "BURST_SIZE should be <= %u", MAX_BURST);
+
+       rte_bbdev_info_get(tp->dev_id, &info);
+       bufs = &tp->op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id];
+
+       while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT)
+               rte_pause();
+
+       start_time = rte_rdtsc_precise();
+       for (enqueued = 0, dequeued = 0; dequeued < num_to_process;) {
+               uint16_t deq;
+
+               if (likely(enqueued < num_to_process)) {
+
+                       uint16_t num_to_enq = burst_sz;
+
+                       if (unlikely(num_to_process - enqueued < num_to_enq))
+                               num_to_enq = num_to_process - enqueued;
+
+                       ret = rte_bbdev_dec_op_alloc_bulk(tp->op_params->mp,
+                                       ops_enq, num_to_enq);
+                       if (ret != 0) {
+                               allocs_failed++;
+                               goto do_dequeue;
+                       }
+
+                       if (test_vector.op_type != RTE_BBDEV_OP_NONE)
+                               copy_reference_dec_op(ops_enq, num_to_enq,
+                                               enqueued,
+                                               bufs->inputs,
+                                               bufs->hard_outputs,
+                                               bufs->soft_outputs,
+                                               ref_op);
+
+                       enqueued += rte_bbdev_enqueue_dec_ops(tp->dev_id,
+                                       queue_id, ops_enq, num_to_enq);
+               }
+do_dequeue:
+               deq = rte_bbdev_dequeue_dec_ops(tp->dev_id, queue_id, ops_deq,
+                               burst_sz);
+               dequeued += deq;
+               rte_bbdev_dec_op_free_bulk(ops_enq, deq);
+       }
+       total_time = rte_rdtsc_precise() - start_time;
+
+       if (allocs_failed > 0)
+               printf("WARNING: op allocations failed: %u times\n",
+                               allocs_failed);
+
+       TEST_ASSERT(enqueued == dequeued, "enqueued (%u) != dequeued (%u)",
+                       enqueued, dequeued);
+
+       if (test_vector.op_type != RTE_BBDEV_OP_NONE) {
+               ret = validate_dec_buffers(ref_op, bufs, num_to_process);
+               TEST_ASSERT_SUCCESS(ret, "Buffers validation failed");
+       }
+
+       in_len = ref_op->turbo_dec.input.length;
+       tp->mops = ((double)num_to_process / 1000000.0) /
+                       ((double)total_time / (double)rte_get_tsc_hz());
+       tp->mbps = ((double)num_to_process * in_len * 8 / 1000000.0) /
+                       ((double)total_time / (double)rte_get_tsc_hz());
+
+       return TEST_SUCCESS;
+}
+
+static int
+throughput_pmd_lcore_enc(void *arg)
+{
+       struct thread_params *tp = arg;
+       unsigned int enqueued, dequeued;
+       struct rte_bbdev_enc_op *ops_enq[MAX_BURST], *ops_deq[MAX_BURST];
+       uint64_t total_time, start_time;
+       const uint16_t queue_id = tp->queue_id;
+       const uint16_t burst_sz = tp->op_params->burst_sz;
+       const uint16_t num_to_process = tp->op_params->num_to_process;
+       struct rte_bbdev_enc_op *ref_op = tp->op_params->ref_enc_op;
+       struct test_buffers *bufs = NULL;
+       unsigned int allocs_failed = 0;
+       int ret;
+       struct rte_bbdev_info info;
+
+       /* Input length in bytes, million operations per second, million bits
+        * per second.
+        */
+       double in_len;
+
+       TEST_ASSERT_SUCCESS((burst_sz > MAX_BURST),
+                       "BURST_SIZE should be <= %u", MAX_BURST);
+
+       rte_bbdev_info_get(tp->dev_id, &info);
+       bufs = &tp->op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id];
+
+       while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT)
+               rte_pause();
+
+       start_time = rte_rdtsc_precise();
+       for (enqueued = 0, dequeued = 0; dequeued < num_to_process;) {
+               uint16_t deq;
+
+               if (likely(enqueued < num_to_process)) {
+
+                       uint16_t num_to_enq = burst_sz;
+
+                       if (unlikely(num_to_process - enqueued < num_to_enq))
+                               num_to_enq = num_to_process - enqueued;
+
+                       ret = rte_bbdev_enc_op_alloc_bulk(tp->op_params->mp,
+                                       ops_enq, num_to_enq);
+                       if (ret != 0) {
+                               allocs_failed++;
+                               goto do_dequeue;
+                       }
+
+                       if (test_vector.op_type != RTE_BBDEV_OP_NONE)
+                               copy_reference_enc_op(ops_enq, num_to_enq,
+                                               enqueued,
+                                               bufs->inputs,
+                                               bufs->hard_outputs,
+                                               ref_op);
+
+                       enqueued += rte_bbdev_enqueue_enc_ops(tp->dev_id,
+                                       queue_id, ops_enq, num_to_enq);
+               }
+do_dequeue:
+               deq = rte_bbdev_dequeue_enc_ops(tp->dev_id, queue_id, ops_deq,
+                               burst_sz);
+               dequeued += deq;
+               rte_bbdev_enc_op_free_bulk(ops_enq, deq);
+       }
+       total_time = rte_rdtsc_precise() - start_time;
+
+       if (allocs_failed > 0)
+               printf("WARNING: op allocations failed: %u times\n",
+                               allocs_failed);
+
+       TEST_ASSERT(enqueued == dequeued, "enqueued (%u) != dequeued (%u)",
+                       enqueued, dequeued);
+
+       if (test_vector.op_type != RTE_BBDEV_OP_NONE) {
+               ret = validate_enc_buffers(bufs, num_to_process);
+               TEST_ASSERT_SUCCESS(ret, "Buffers validation failed");
+       }
+
+       in_len = ref_op->turbo_enc.input.length;
+
+       tp->mops = ((double)num_to_process / 1000000.0) /
+                       ((double)total_time / (double)rte_get_tsc_hz());
+       tp->mbps = ((double)num_to_process * in_len * 8 / 1000000.0) /
+                       ((double)total_time / (double)rte_get_tsc_hz());
+
+       return TEST_SUCCESS;
+}
+static void
+print_throughput(struct thread_params *t_params, unsigned int used_cores)
+{
+       unsigned int lcore_id, iter = 0;
+       double total_mops = 0, total_mbps = 0;
+
+       RTE_LCORE_FOREACH(lcore_id) {
+               if (iter++ >= used_cores)
+                       break;
+               printf("\tlcore_id: %u, throughput: %.8lg MOPS, %.8lg Mbps\n",
+               lcore_id, t_params[lcore_id].mops, t_params[lcore_id].mbps);
+               total_mops += t_params[lcore_id].mops;
+               total_mbps += t_params[lcore_id].mbps;
+       }
+       printf(
+               "\n\tTotal stats for %u cores: throughput: %.8lg MOPS, %.8lg Mbps\n",
+               used_cores, total_mops, total_mbps);
+}
+
+/*
+ * Test function that determines how long an enqueue + dequeue of a burst
+ * takes on available lcores.
+ */
+static int
+throughput_test(struct active_device *ad,
+               struct test_op_params *op_params)
+{
+       int ret;
+       unsigned int lcore_id, used_cores = 0;
+       struct thread_params t_params[MAX_QUEUES];
+       struct rte_bbdev_info info;
+       lcore_function_t *throughput_function;
+       struct thread_params *tp;
+       uint16_t num_lcores;
+       const char *op_type_str;
+
+       rte_bbdev_info_get(ad->dev_id, &info);
+
+       op_type_str = rte_bbdev_op_type_str(test_vector.op_type);
+       TEST_ASSERT_NOT_NULL(op_type_str, "Invalid op type: %u",
+                       test_vector.op_type);
+
+       printf(
+               "Throughput test: dev: %s, nb_queues: %u, burst size: %u, num ops: %u, num_lcores: %u, op type: %s, int mode: %s, GHz: %lg\n",
+                       info.dev_name, ad->nb_queues, op_params->burst_sz,
+                       op_params->num_to_process, op_params->num_lcores,
+                       op_type_str,
+                       intr_enabled ? "Interrupt mode" : "PMD mode",
+                       (double)rte_get_tsc_hz() / 1000000000.0);
+
+       /* Set number of lcores */
+       num_lcores = (ad->nb_queues < (op_params->num_lcores))
+                       ? ad->nb_queues
+                       : op_params->num_lcores;
+
+       if (intr_enabled) {
+               if (test_vector.op_type == RTE_BBDEV_OP_TURBO_DEC)
+                       throughput_function = throughput_intr_lcore_dec;
+               else
+                       throughput_function = throughput_intr_lcore_enc;
+
+               /* Dequeue interrupt callback registration */
+               rte_bbdev_callback_register(ad->dev_id, RTE_BBDEV_EVENT_DEQUEUE,
+                               dequeue_event_callback,
+                               &t_params);
+       } else {
+               if (test_vector.op_type == RTE_BBDEV_OP_TURBO_DEC)
+                       throughput_function = throughput_pmd_lcore_dec;
+               else
+                       throughput_function = throughput_pmd_lcore_enc;
+       }
+
+       rte_atomic16_set(&op_params->sync, SYNC_WAIT);
+
+       t_params[rte_lcore_id()].dev_id = ad->dev_id;
+       t_params[rte_lcore_id()].op_params = op_params;
+       t_params[rte_lcore_id()].queue_id =
+                       ad->queue_ids[used_cores++];
+
+       RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+               if (used_cores >= num_lcores)
+                       break;
+
+               t_params[lcore_id].dev_id = ad->dev_id;
+               t_params[lcore_id].op_params = op_params;
+               t_params[lcore_id].queue_id = ad->queue_ids[used_cores++];
+
+               rte_eal_remote_launch(throughput_function, &t_params[lcore_id],
+                               lcore_id);
+       }
+
+       rte_atomic16_set(&op_params->sync, SYNC_START);
+       ret = throughput_function(&t_params[rte_lcore_id()]);
+
+       /* Master core is always used */
+       used_cores = 1;
+       RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+               if (used_cores++ >= num_lcores)
+                       break;
+
+               ret |= rte_eal_wait_lcore(lcore_id);
+       }
+
+       /* Return if test failed */
+       if (ret)
+               return ret;
+
+       /* Print throughput if interrupts are disabled and test passed */
+       if (!intr_enabled) {
+               if (test_vector.op_type != RTE_BBDEV_OP_NONE)
+                       print_throughput(t_params, num_lcores);
+               return ret;
+       }
+
+       /* In interrupt TC we need to wait for the interrupt callback to deqeue
+        * all pending operations. Skip waiting for queues which reported an
+        * error using processing_status variable.
+        * Wait for master lcore operations.
+        */
+       tp = &t_params[rte_lcore_id()];
+       while ((rte_atomic16_read(&tp->nb_dequeued) <
+                       op_params->num_to_process) &&
+                       (rte_atomic16_read(&tp->processing_status) !=
+                       TEST_FAILED))
+               rte_pause();
+
+       ret |= rte_atomic16_read(&tp->processing_status);
+
+       /* Wait for slave lcores operations */
+       used_cores = 1;
+       RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+               tp = &t_params[lcore_id];
+               if (used_cores++ >= num_lcores)
+                       break;
+
+               while ((rte_atomic16_read(&tp->nb_dequeued) <
+                               op_params->num_to_process) &&
+                               (rte_atomic16_read(&tp->processing_status) !=
+                               TEST_FAILED))
+                       rte_pause();
+
+               ret |= rte_atomic16_read(&tp->processing_status);
+       }
+
+       /* Print throughput if test passed */
+       if (!ret && test_vector.op_type != RTE_BBDEV_OP_NONE)
+               print_throughput(t_params, num_lcores);
+
+       return ret;
+}
+
+static int
+operation_latency_test_dec(struct rte_mempool *mempool,
+               struct test_buffers *bufs, struct rte_bbdev_dec_op *ref_op,
+               int vector_mask, uint16_t dev_id, uint16_t queue_id,
+               const uint16_t num_to_process, uint16_t burst_sz,
+               uint64_t *total_time)
+{
+       int ret = TEST_SUCCESS;
+       uint16_t i, j, dequeued;
+       struct rte_bbdev_dec_op *ops_enq[MAX_BURST], *ops_deq[MAX_BURST];
+       uint64_t start_time = 0;
+
+       for (i = 0, dequeued = 0; dequeued < num_to_process; ++i) {
+               uint16_t enq = 0, deq = 0;
+               bool first_time = true;
+
+               if (unlikely(num_to_process - dequeued < burst_sz))
+                       burst_sz = num_to_process - dequeued;
+
+               rte_bbdev_dec_op_alloc_bulk(mempool, ops_enq, burst_sz);
+               if (test_vector.op_type != RTE_BBDEV_OP_NONE)
+                       copy_reference_dec_op(ops_enq, burst_sz, dequeued,
+                                       bufs->inputs,
+                                       bufs->hard_outputs,
+                                       bufs->soft_outputs,
+                                       ref_op);
+
+               /* Set counter to validate the ordering */
+               for (j = 0; j < burst_sz; ++j)
+                       ops_enq[j]->opaque_data = (void *)(uintptr_t)j;
+
+               start_time = rte_rdtsc_precise();
+
+               enq = rte_bbdev_enqueue_dec_ops(dev_id, queue_id, &ops_enq[enq],
+                               burst_sz);
+               TEST_ASSERT(enq == burst_sz,
+                               "Error enqueueing burst, expected %u, got %u",
+                               burst_sz, enq);
+
+               /* Dequeue */
+               do {
+                       deq += rte_bbdev_dequeue_dec_ops(dev_id, queue_id,
+                                       &ops_deq[deq], burst_sz - deq);
+                       if (likely(first_time && (deq > 0))) {
+                               *total_time += rte_rdtsc_precise() - start_time;
+                               first_time = false;
+                       }
+               } while (unlikely(burst_sz != deq));
+
+               if (test_vector.op_type != RTE_BBDEV_OP_NONE) {
+                       ret = validate_dec_op(ops_deq, burst_sz, ref_op,
+                                       vector_mask);
+                       TEST_ASSERT_SUCCESS(ret, "Validation failed!");
+               }
+
+               rte_bbdev_dec_op_free_bulk(ops_enq, deq);
+               dequeued += deq;
+       }
+
+       return i;
+}
+
+static int
+operation_latency_test_enc(struct rte_mempool *mempool,
+               struct test_buffers *bufs, struct rte_bbdev_enc_op *ref_op,
+               uint16_t dev_id, uint16_t queue_id,
+               const uint16_t num_to_process, uint16_t burst_sz,
+               uint64_t *total_time)
+{
+       int ret = TEST_SUCCESS;
+       uint16_t i, j, dequeued;
+       struct rte_bbdev_enc_op *ops_enq[MAX_BURST], *ops_deq[MAX_BURST];
+       uint64_t start_time = 0;
+
+       for (i = 0, dequeued = 0; dequeued < num_to_process; ++i) {
+               uint16_t enq = 0, deq = 0;
+               bool first_time = true;
+
+               if (unlikely(num_to_process - dequeued < burst_sz))
+                       burst_sz = num_to_process - dequeued;
+
+               rte_bbdev_enc_op_alloc_bulk(mempool, ops_enq, burst_sz);
+               if (test_vector.op_type != RTE_BBDEV_OP_NONE)
+                       copy_reference_enc_op(ops_enq, burst_sz, dequeued,
+                                       bufs->inputs,
+                                       bufs->hard_outputs,
+                                       ref_op);
+
+               /* Set counter to validate the ordering */
+               for (j = 0; j < burst_sz; ++j)
+                       ops_enq[j]->opaque_data = (void *)(uintptr_t)j;
+
+               start_time = rte_rdtsc_precise();
+
+               enq = rte_bbdev_enqueue_enc_ops(dev_id, queue_id, &ops_enq[enq],
+                               burst_sz);
+               TEST_ASSERT(enq == burst_sz,
+                               "Error enqueueing burst, expected %u, got %u",
+                               burst_sz, enq);
+
+               /* Dequeue */
+               do {
+                       deq += rte_bbdev_dequeue_enc_ops(dev_id, queue_id,
+                                       &ops_deq[deq], burst_sz - deq);
+                       if (likely(first_time && (deq > 0))) {
+                               *total_time += rte_rdtsc_precise() - start_time;
+                               first_time = false;
+                       }
+               } while (unlikely(burst_sz != deq));
+
+               if (test_vector.op_type != RTE_BBDEV_OP_NONE) {
+                       ret = validate_enc_op(ops_deq, burst_sz, ref_op);
+                       TEST_ASSERT_SUCCESS(ret, "Validation failed!");
+               }
+
+               rte_bbdev_enc_op_free_bulk(ops_enq, deq);
+               dequeued += deq;
+       }
+
+       return i;
+}
+
+static int
+operation_latency_test(struct active_device *ad,
+               struct test_op_params *op_params)
+{
+       int iter;
+       uint16_t burst_sz = op_params->burst_sz;
+       const uint16_t num_to_process = op_params->num_to_process;
+       const enum rte_bbdev_op_type op_type = test_vector.op_type;
+       const uint16_t queue_id = ad->queue_ids[0];
+       struct test_buffers *bufs = NULL;
+       struct rte_bbdev_info info;
+       uint64_t total_time = 0;
+       const char *op_type_str;
+
+       TEST_ASSERT_SUCCESS((burst_sz > MAX_BURST),
+                       "BURST_SIZE should be <= %u", MAX_BURST);
+
+       rte_bbdev_info_get(ad->dev_id, &info);
+       bufs = &op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id];
+
+       op_type_str = rte_bbdev_op_type_str(op_type);
+       TEST_ASSERT_NOT_NULL(op_type_str, "Invalid op type: %u", op_type);
+
+       printf(
+               "Validation/Latency test: dev: %s, burst size: %u, num ops: %u, op type: %s\n",
+                       info.dev_name, burst_sz, num_to_process, op_type_str);
+
+       if (op_type == RTE_BBDEV_OP_TURBO_DEC)
+               iter = operation_latency_test_dec(op_params->mp, bufs,
+                               op_params->ref_dec_op, op_params->vector_mask,
+                               ad->dev_id, queue_id, num_to_process,
+                               burst_sz, &total_time);
+       else
+               iter = operation_latency_test_enc(op_params->mp, bufs,
+                               op_params->ref_enc_op, ad->dev_id, queue_id,
+                               num_to_process, burst_sz, &total_time);
+
+       if (iter < 0)
+               return TEST_FAILED;
+
+       printf("\toperation avg. latency: %lg cycles, %lg us\n",
+                       (double)total_time / (double)iter,
+                       (double)(total_time * 1000000) / (double)iter /
+                       (double)rte_get_tsc_hz());
+
+       return TEST_SUCCESS;
+}
+
+static int
+offload_latency_test_dec(struct rte_mempool *mempool, struct test_buffers *bufs,
+               struct rte_bbdev_dec_op *ref_op, uint16_t dev_id,
+               uint16_t queue_id, const uint16_t num_to_process,
+               uint16_t burst_sz, uint64_t *enq_total_time,
+               uint64_t *deq_total_time)
+{
+       int i, dequeued;
+       struct rte_bbdev_dec_op *ops_enq[MAX_BURST], *ops_deq[MAX_BURST];
+       uint64_t enq_start_time, deq_start_time;
+
+       for (i = 0, dequeued = 0; dequeued < num_to_process; ++i) {
+               uint16_t enq = 0, deq = 0;
+
+               if (unlikely(num_to_process - dequeued < burst_sz))
+                       burst_sz = num_to_process - dequeued;
+
+               rte_bbdev_dec_op_alloc_bulk(mempool, ops_enq, burst_sz);
+               if (test_vector.op_type != RTE_BBDEV_OP_NONE)
+                       copy_reference_dec_op(ops_enq, burst_sz, dequeued,
+                                       bufs->inputs,
+                                       bufs->hard_outputs,
+                                       bufs->soft_outputs,
+                                       ref_op);
+
+               /* Start time measurment for enqueue function offload latency */
+               enq_start_time = rte_rdtsc();
+               do {
+                       enq += rte_bbdev_enqueue_dec_ops(dev_id, queue_id,
+                                       &ops_enq[enq], burst_sz - enq);
+               } while (unlikely(burst_sz != enq));
+               *enq_total_time += rte_rdtsc() - enq_start_time;
+
+               /* ensure enqueue has been completed */
+               rte_delay_ms(10);
+
+               /* Start time measurment for dequeue function offload latency */
+               deq_start_time = rte_rdtsc();
+               do {
+                       deq += rte_bbdev_dequeue_dec_ops(dev_id, queue_id,
+                                       &ops_deq[deq], burst_sz - deq);
+               } while (unlikely(burst_sz != deq));
+               *deq_total_time += rte_rdtsc() - deq_start_time;
+
+               rte_bbdev_dec_op_free_bulk(ops_enq, deq);
+               dequeued += deq;
+       }
+
+       return i;
+}
+
+static int
+offload_latency_test_enc(struct rte_mempool *mempool, struct test_buffers *bufs,
+               struct rte_bbdev_enc_op *ref_op, uint16_t dev_id,
+               uint16_t queue_id, const uint16_t num_to_process,
+               uint16_t burst_sz, uint64_t *enq_total_time,
+               uint64_t *deq_total_time)
+{
+       int i, dequeued;
+       struct rte_bbdev_enc_op *ops_enq[MAX_BURST], *ops_deq[MAX_BURST];
+       uint64_t enq_start_time, deq_start_time;
+
+       for (i = 0, dequeued = 0; dequeued < num_to_process; ++i) {
+               uint16_t enq = 0, deq = 0;
+
+               if (unlikely(num_to_process - dequeued < burst_sz))
+                       burst_sz = num_to_process - dequeued;
+
+               rte_bbdev_enc_op_alloc_bulk(mempool, ops_enq, burst_sz);
+               if (test_vector.op_type != RTE_BBDEV_OP_NONE)
+                       copy_reference_enc_op(ops_enq, burst_sz, dequeued,
+                                       bufs->inputs,
+                                       bufs->hard_outputs,
+                                       ref_op);
+
+               /* Start time measurment for enqueue function offload latency */
+               enq_start_time = rte_rdtsc();
+               do {
+                       enq += rte_bbdev_enqueue_enc_ops(dev_id, queue_id,
+                                       &ops_enq[enq], burst_sz - enq);
+               } while (unlikely(burst_sz != enq));
+               *enq_total_time += rte_rdtsc() - enq_start_time;
+
+               /* ensure enqueue has been completed */
+               rte_delay_ms(10);
+
+               /* Start time measurment for dequeue function offload latency */
+               deq_start_time = rte_rdtsc();
+               do {
+                       deq += rte_bbdev_dequeue_enc_ops(dev_id, queue_id,
+                                       &ops_deq[deq], burst_sz - deq);
+               } while (unlikely(burst_sz != deq));
+               *deq_total_time += rte_rdtsc() - deq_start_time;
+
+               rte_bbdev_enc_op_free_bulk(ops_enq, deq);
+               dequeued += deq;
+       }
+
+       return i;
+}
+
+static int
+offload_latency_test(struct active_device *ad,
+               struct test_op_params *op_params)
+{
+       int iter;
+       uint64_t enq_total_time = 0, deq_total_time = 0;
+       uint16_t burst_sz = op_params->burst_sz;
+       const uint16_t num_to_process = op_params->num_to_process;
+       const enum rte_bbdev_op_type op_type = test_vector.op_type;
+       const uint16_t queue_id = ad->queue_ids[0];
+       struct test_buffers *bufs = NULL;
+       struct rte_bbdev_info info;
+       const char *op_type_str;
+
+       TEST_ASSERT_SUCCESS((burst_sz > MAX_BURST),
+                       "BURST_SIZE should be <= %u", MAX_BURST);
+
+       rte_bbdev_info_get(ad->dev_id, &info);
+       bufs = &op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id];
+
+       op_type_str = rte_bbdev_op_type_str(op_type);
+       TEST_ASSERT_NOT_NULL(op_type_str, "Invalid op type: %u", op_type);
+
+       printf(
+               "Offload latency test: dev: %s, burst size: %u, num ops: %u, op type: %s\n",
+                       info.dev_name, burst_sz, num_to_process, op_type_str);
+
+       if (op_type == RTE_BBDEV_OP_TURBO_DEC)
+               iter = offload_latency_test_dec(op_params->mp, bufs,
+                               op_params->ref_dec_op, ad->dev_id, queue_id,
+                               num_to_process, burst_sz, &enq_total_time,
+                               &deq_total_time);
+       else
+               iter = offload_latency_test_enc(op_params->mp, bufs,
+                               op_params->ref_enc_op, ad->dev_id, queue_id,
+                               num_to_process, burst_sz, &enq_total_time,
+                               &deq_total_time);
+
+       if (iter < 0)
+               return TEST_FAILED;
+
+       printf("\tenq offload avg. latency: %lg cycles, %lg us\n",
+                       (double)enq_total_time / (double)iter,
+                       (double)(enq_total_time * 1000000) / (double)iter /
+                       (double)rte_get_tsc_hz());
+
+       printf("\tdeq offload avg. latency: %lg cycles, %lg us\n",
+                       (double)deq_total_time / (double)iter,
+                       (double)(deq_total_time * 1000000) / (double)iter /
+                       (double)rte_get_tsc_hz());
+
+       return TEST_SUCCESS;
+}
+
+static int
+offload_latency_empty_q_test_dec(uint16_t dev_id, uint16_t queue_id,
+               const uint16_t num_to_process, uint16_t burst_sz,
+               uint64_t *deq_total_time)
+{
+       int i, deq_total;
+       struct rte_bbdev_dec_op *ops[MAX_BURST];
+       uint64_t deq_start_time;
+
+       /* Test deq offload latency from an empty queue */
+       deq_start_time = rte_rdtsc_precise();
+       for (i = 0, deq_total = 0; deq_total < num_to_process;
+                       ++i, deq_total += burst_sz) {
+               if (unlikely(num_to_process - deq_total < burst_sz))
+                       burst_sz = num_to_process - deq_total;
+               rte_bbdev_dequeue_dec_ops(dev_id, queue_id, ops, burst_sz);
+       }
+       *deq_total_time = rte_rdtsc_precise() - deq_start_time;
+
+       return i;
+}
+
+static int
+offload_latency_empty_q_test_enc(uint16_t dev_id, uint16_t queue_id,
+               const uint16_t num_to_process, uint16_t burst_sz,
+               uint64_t *deq_total_time)
+{
+       int i, deq_total;
+       struct rte_bbdev_enc_op *ops[MAX_BURST];
+       uint64_t deq_start_time;
+
+       /* Test deq offload latency from an empty queue */
+       deq_start_time = rte_rdtsc_precise();
+       for (i = 0, deq_total = 0; deq_total < num_to_process;
+                       ++i, deq_total += burst_sz) {
+               if (unlikely(num_to_process - deq_total < burst_sz))
+                       burst_sz = num_to_process - deq_total;
+               rte_bbdev_dequeue_enc_ops(dev_id, queue_id, ops, burst_sz);
+       }
+       *deq_total_time = rte_rdtsc_precise() - deq_start_time;
+
+       return i;
+}
+
+static int
+offload_latency_empty_q_test(struct active_device *ad,
+               struct test_op_params *op_params)
+{
+       int iter;
+       uint64_t deq_total_time = 0;
+       uint16_t burst_sz = op_params->burst_sz;
+       const uint16_t num_to_process = op_params->num_to_process;
+       const enum rte_bbdev_op_type op_type = test_vector.op_type;
+       const uint16_t queue_id = ad->queue_ids[0];
+       struct rte_bbdev_info info;
+       const char *op_type_str;
+
+       TEST_ASSERT_SUCCESS((burst_sz > MAX_BURST),
+                       "BURST_SIZE should be <= %u", MAX_BURST);
+
+       rte_bbdev_info_get(ad->dev_id, &info);
+
+       op_type_str = rte_bbdev_op_type_str(op_type);
+       TEST_ASSERT_NOT_NULL(op_type_str, "Invalid op type: %u", op_type);
+
+       printf(
+               "Offload latency empty dequeue test: dev: %s, burst size: %u, num ops: %u, op type: %s\n",
+                       info.dev_name, burst_sz, num_to_process, op_type_str);
+
+       if (op_type == RTE_BBDEV_OP_TURBO_DEC)
+               iter = offload_latency_empty_q_test_dec(ad->dev_id, queue_id,
+                               num_to_process, burst_sz, &deq_total_time);
+       else
+               iter = offload_latency_empty_q_test_enc(ad->dev_id, queue_id,
+                               num_to_process, burst_sz, &deq_total_time);
+
+       if (iter < 0)
+               return TEST_FAILED;
+
+       printf("\tempty deq offload avg. latency: %lg cycles, %lg us\n",
+                       (double)deq_total_time / (double)iter,
+                       (double)(deq_total_time * 1000000) / (double)iter /
+                       (double)rte_get_tsc_hz());
+
+       return TEST_SUCCESS;
+}
+
+static int
+throughput_tc(void)
+{
+       return run_test_case(throughput_test);
+}
+
+static int
+offload_latency_tc(void)
+{
+       return run_test_case(offload_latency_test);
+}
+
+static int
+offload_latency_empty_q_tc(void)
+{
+       return run_test_case(offload_latency_empty_q_test);
+}
+
+static int
+operation_latency_tc(void)
+{
+       return run_test_case(operation_latency_test);
+}
+
+static int
+interrupt_tc(void)
+{
+       return run_test_case(throughput_test);
+}
+
+static struct unit_test_suite bbdev_throughput_testsuite = {
+       .suite_name = "BBdev Throughput Tests",
+       .setup = testsuite_setup,
+       .teardown = testsuite_teardown,
+       .unit_test_cases = {
+               TEST_CASE_ST(ut_setup, ut_teardown, throughput_tc),
+               TEST_CASES_END() /**< NULL terminate unit test array */
+       }
+};
+
+static struct unit_test_suite bbdev_validation_testsuite = {
+       .suite_name = "BBdev Validation Tests",
+       .setup = testsuite_setup,
+       .teardown = testsuite_teardown,
+       .unit_test_cases = {
+               TEST_CASE_ST(ut_setup, ut_teardown, operation_latency_tc),
+               TEST_CASES_END() /**< NULL terminate unit test array */
+       }
+};
+
+static struct unit_test_suite bbdev_latency_testsuite = {
+       .suite_name = "BBdev Latency Tests",
+       .setup = testsuite_setup,
+       .teardown = testsuite_teardown,
+       .unit_test_cases = {
+               TEST_CASE_ST(ut_setup, ut_teardown, offload_latency_tc),
+               TEST_CASE_ST(ut_setup, ut_teardown, offload_latency_empty_q_tc),
+               TEST_CASE_ST(ut_setup, ut_teardown, operation_latency_tc),
+               TEST_CASES_END() /**< NULL terminate unit test array */
+       }
+};
+
+static struct unit_test_suite bbdev_interrupt_testsuite = {
+       .suite_name = "BBdev Interrupt Tests",
+       .setup = interrupt_testsuite_setup,
+       .teardown = testsuite_teardown,
+       .unit_test_cases = {
+               TEST_CASE_ST(ut_setup, ut_teardown, interrupt_tc),
+               TEST_CASES_END() /**< NULL terminate unit test array */
+       }
+};
+
+REGISTER_TEST_COMMAND(throughput, bbdev_throughput_testsuite);
+REGISTER_TEST_COMMAND(validation, bbdev_validation_testsuite);
+REGISTER_TEST_COMMAND(latency, bbdev_latency_testsuite);
+REGISTER_TEST_COMMAND(interrupt, bbdev_interrupt_testsuite);
diff --git a/app/test-bbdev/test_bbdev_vector.c b/app/test-bbdev/test_bbdev_vector.c
new file mode 100644 (file)
index 0000000..2d0852c
--- /dev/null
@@ -0,0 +1,937 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Intel Corporation
+ */
+
+#ifdef RTE_EXEC_ENV_BSDAPP
+       #define _WITH_GETLINE
+#endif
+#include <stdio.h>
+#include <stdbool.h>
+#include <rte_malloc.h>
+
+#include "test_bbdev_vector.h"
+
+#define VALUE_DELIMITER ","
+#define ENTRY_DELIMITER "="
+
+const char *op_data_prefixes[] = {
+       "input",
+       "soft_output",
+       "hard_output",
+};
+
+/* trim leading and trailing spaces */
+static void
+trim_space(char *str)
+{
+       char *start, *end;
+
+       for (start = str; *start; start++) {
+               if (!isspace((unsigned char) start[0]))
+                       break;
+       }
+
+       for (end = start + strlen(start); end > start + 1; end--) {
+               if (!isspace((unsigned char) end[-1]))
+                       break;
+       }
+
+       *end = 0;
+
+       /* Shift from "start" to the beginning of the string */
+       if (start > str)
+               memmove(str, start, (end - start) + 1);
+}
+
+static bool
+starts_with(const char *str, const char *pre)
+{
+       return strncmp(pre, str, strlen(pre)) == 0;
+}
+
+/* tokenization test values separated by a comma */
+static int
+parse_values(char *tokens, uint32_t **data, uint32_t *data_length)
+{
+       uint32_t n_tokens = 0;
+       uint32_t data_size = 32;
+
+       uint32_t *values, *values_resized;
+       char *tok, *error = NULL;
+
+       tok = strtok(tokens, VALUE_DELIMITER);
+       if (tok == NULL)
+               return -1;
+
+       values = (uint32_t *)
+                       rte_zmalloc(NULL, sizeof(uint32_t) * data_size, 0);
+       if (values == NULL)
+               return -1;
+
+       while (tok != NULL) {
+               values_resized = NULL;
+
+               if (n_tokens >= data_size) {
+                       data_size *= 2;
+
+                       values_resized = (uint32_t *) rte_realloc(values,
+                               sizeof(uint32_t) * data_size, 0);
+                       if (values_resized == NULL) {
+                               rte_free(values);
+                               return -1;
+                       }
+                       values = values_resized;
+               }
+
+               values[n_tokens] = (uint32_t) strtoul(tok, &error, 0);
+               if ((error == NULL) || (*error != '\0')) {
+                       printf("Failed with convert '%s'\n", tok);
+                       rte_free(values);
+                       return -1;
+               }
+
+               *data_length = *data_length + (strlen(tok) - strlen("0x"))/2;
+
+               tok = strtok(NULL, VALUE_DELIMITER);
+               if (tok == NULL)
+                       break;
+
+               n_tokens++;
+       }
+
+       values_resized = (uint32_t *) rte_realloc(values,
+               sizeof(uint32_t) * (n_tokens + 1), 0);
+
+       if (values_resized == NULL) {
+               rte_free(values);
+               return -1;
+       }
+
+       *data = values_resized;
+
+       return 0;
+}
+
+/* convert turbo decoder flag from string to unsigned long int*/
+static int
+op_decoder_flag_strtoul(char *token, uint32_t *op_flag_value)
+{
+       if (!strcmp(token, "RTE_BBDEV_TURBO_SUBBLOCK_DEINTERLEAVE"))
+               *op_flag_value = RTE_BBDEV_TURBO_SUBBLOCK_DEINTERLEAVE;
+       else if (!strcmp(token, "RTE_BBDEV_TURBO_CRC_TYPE_24B"))
+               *op_flag_value = RTE_BBDEV_TURBO_CRC_TYPE_24B;
+       else if (!strcmp(token, "RTE_BBDEV_TURBO_EQUALIZER"))
+               *op_flag_value = RTE_BBDEV_TURBO_EQUALIZER;
+       else if (!strcmp(token, "RTE_BBDEV_TURBO_SOFT_OUT_SATURATE"))
+               *op_flag_value = RTE_BBDEV_TURBO_SOFT_OUT_SATURATE;
+       else if (!strcmp(token, "RTE_BBDEV_TURBO_HALF_ITERATION_EVEN"))
+               *op_flag_value = RTE_BBDEV_TURBO_HALF_ITERATION_EVEN;
+       else if (!strcmp(token, "RTE_BBDEV_TURBO_CONTINUE_CRC_MATCH"))
+               *op_flag_value = RTE_BBDEV_TURBO_CONTINUE_CRC_MATCH;
+       else if (!strcmp(token, "RTE_BBDEV_TURBO_SOFT_OUTPUT"))
+               *op_flag_value = RTE_BBDEV_TURBO_SOFT_OUTPUT;
+       else if (!strcmp(token, "RTE_BBDEV_TURBO_EARLY_TERMINATION"))
+               *op_flag_value = RTE_BBDEV_TURBO_EARLY_TERMINATION;
+       else if (!strcmp(token, "RTE_BBDEV_TURBO_POS_LLR_1_BIT_IN"))
+               *op_flag_value = RTE_BBDEV_TURBO_POS_LLR_1_BIT_IN;
+       else if (!strcmp(token, "RTE_BBDEV_TURBO_NEG_LLR_1_BIT_IN"))
+               *op_flag_value = RTE_BBDEV_TURBO_NEG_LLR_1_BIT_IN;
+       else if (!strcmp(token, "RTE_BBDEV_TURBO_POS_LLR_1_BIT_SOFT_OUT"))
+               *op_flag_value = RTE_BBDEV_TURBO_POS_LLR_1_BIT_SOFT_OUT;
+       else if (!strcmp(token, "RTE_BBDEV_TURBO_NEG_LLR_1_BIT_SOFT_OUT"))
+               *op_flag_value = RTE_BBDEV_TURBO_NEG_LLR_1_BIT_SOFT_OUT;
+       else if (!strcmp(token, "RTE_BBDEV_TURBO_MAP_DEC"))
+               *op_flag_value = RTE_BBDEV_TURBO_MAP_DEC;
+       else if (!strcmp(token, "RTE_BBDEV_TURBO_DEC_SCATTER_GATHER"))
+               *op_flag_value = RTE_BBDEV_TURBO_DEC_SCATTER_GATHER;
+       else {
+               printf("The given value is not a turbo decoder flag\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+/* convert turbo encoder flag from string to unsigned long int*/
+static int
+op_encoder_flag_strtoul(char *token, uint32_t *op_flag_value)
+{
+       if (!strcmp(token, "RTE_BBDEV_TURBO_RV_INDEX_BYPASS"))
+               *op_flag_value = RTE_BBDEV_TURBO_RV_INDEX_BYPASS;
+       else if (!strcmp(token, "RTE_BBDEV_TURBO_RATE_MATCH"))
+               *op_flag_value = RTE_BBDEV_TURBO_RATE_MATCH;
+       else if (!strcmp(token, "RTE_BBDEV_TURBO_CRC_24B_ATTACH"))
+               *op_flag_value = RTE_BBDEV_TURBO_CRC_24B_ATTACH;
+       else if (!strcmp(token, "RTE_BBDEV_TURBO_CRC_24A_ATTACH"))
+               *op_flag_value = RTE_BBDEV_TURBO_CRC_24A_ATTACH;
+       else if (!strcmp(token, "RTE_BBDEV_TURBO_ENC_SCATTER_GATHER"))
+               *op_flag_value = RTE_BBDEV_TURBO_ENC_SCATTER_GATHER;
+       else {
+               printf("The given value is not a turbo encoder flag\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+/* tokenization turbo decoder/encoder flags values separated by a comma */
+static int
+parse_turbo_flags(char *tokens, uint32_t *op_flags,
+               enum rte_bbdev_op_type op_type)
+{
+       char *tok = NULL;
+       uint32_t op_flag_value = 0;
+
+       tok = strtok(tokens, VALUE_DELIMITER);
+       if (tok == NULL)
+               return -1;
+
+       while (tok != NULL) {
+               trim_space(tok);
+               if (op_type == RTE_BBDEV_OP_TURBO_DEC) {
+                       if (op_decoder_flag_strtoul(tok, &op_flag_value) == -1)
+                               return -1;
+               } else if (op_type == RTE_BBDEV_OP_TURBO_ENC) {
+                       if (op_encoder_flag_strtoul(tok, &op_flag_value) == -1)
+                               return -1;
+               } else {
+                       return -1;
+               }
+
+               *op_flags = *op_flags | op_flag_value;
+
+               tok = strtok(NULL, VALUE_DELIMITER);
+               if (tok == NULL)
+                       break;
+       }
+
+       return 0;
+}
+
+/* convert turbo encoder/decoder op_type from string to enum*/
+static int
+op_turbo_type_strtol(char *token, enum rte_bbdev_op_type *op_type)
+{
+       trim_space(token);
+       if (!strcmp(token, "RTE_BBDEV_OP_TURBO_DEC"))
+               *op_type = RTE_BBDEV_OP_TURBO_DEC;
+       else if (!strcmp(token, "RTE_BBDEV_OP_TURBO_ENC"))
+               *op_type = RTE_BBDEV_OP_TURBO_ENC;
+       else if (!strcmp(token, "RTE_BBDEV_OP_NONE"))
+               *op_type = RTE_BBDEV_OP_NONE;
+       else {
+               printf("Not valid turbo op_type: '%s'\n", token);
+               return -1;
+       }
+
+       return 0;
+}
+
+/* tokenization expected status values separated by a comma */
+static int
+parse_expected_status(char *tokens, int *status, enum rte_bbdev_op_type op_type)
+{
+       char *tok = NULL;
+       bool status_ok = false;
+
+       tok = strtok(tokens, VALUE_DELIMITER);
+       if (tok == NULL)
+               return -1;
+
+       while (tok != NULL) {
+               trim_space(tok);
+               if (!strcmp(tok, "OK"))
+                       status_ok = true;
+               else if (!strcmp(tok, "DMA"))
+                       *status = *status | (1 << RTE_BBDEV_DRV_ERROR);
+               else if (!strcmp(tok, "FCW"))
+                       *status = *status | (1 << RTE_BBDEV_DATA_ERROR);
+               else if (!strcmp(tok, "CRC")) {
+                       if (op_type == RTE_BBDEV_OP_TURBO_DEC)
+                               *status = *status | (1 << RTE_BBDEV_CRC_ERROR);
+                       else {
+                               printf(
+                                               "CRC is only a valid value for turbo decoder\n");
+                               return -1;
+                       }
+               } else {
+                       printf("Not valid status: '%s'\n", tok);
+                       return -1;
+               }
+
+               tok = strtok(NULL, VALUE_DELIMITER);
+               if (tok == NULL)
+                       break;
+       }
+
+       if (status_ok && *status != 0) {
+               printf(
+                               "Not valid status values. Cannot be OK and ERROR at the same time.\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+/* parse ops data entry (there can be more than 1 input entry, each will be
+ * contained in a separate op_data_buf struct)
+ */
+static int
+parse_data_entry(const char *key_token, char *token,
+               struct test_bbdev_vector *vector, enum op_data_type type,
+               const char *prefix)
+{
+       int ret;
+       uint32_t data_length = 0;
+       uint32_t *data = NULL;
+       unsigned int id;
+       struct op_data_buf *op_data;
+       unsigned int *nb_ops;
+
+       if (type > DATA_NUM_TYPES) {
+               printf("Unknown op type: %d!\n", type);
+               return -1;
+       }
+
+       op_data = vector->entries[type].segments;
+       nb_ops = &vector->entries[type].nb_segments;
+
+       if (*nb_ops >= RTE_BBDEV_MAX_CODE_BLOCKS) {
+               printf("Too many segments (code blocks defined): %u, max %d!\n",
+                               *nb_ops, RTE_BBDEV_MAX_CODE_BLOCKS);
+               return -1;
+       }
+
+       if (sscanf(key_token + strlen(prefix), "%u", &id) != 1) {
+               printf("Missing ID of %s\n", prefix);
+               return -1;
+       }
+       if (id != *nb_ops) {
+               printf(
+                       "Please order data entries sequentially, i.e. %s0, %s1, ...\n",
+                               prefix, prefix);
+               return -1;
+       }
+
+       /* Clear new op data struct */
+       memset(op_data + *nb_ops, 0, sizeof(struct op_data_buf));
+
+       ret = parse_values(token, &data, &data_length);
+       if (!ret) {
+               op_data[*nb_ops].addr = data;
+               op_data[*nb_ops].length = data_length;
+               ++(*nb_ops);
+       }
+
+       return ret;
+}
+
+/* parses turbo decoder parameters and assigns to global variable */
+static int
+parse_decoder_params(const char *key_token, char *token,
+               struct test_bbdev_vector *vector)
+{
+       int ret = 0, status = 0;
+       uint32_t op_flags = 0;
+       char *err = NULL;
+
+       struct rte_bbdev_op_turbo_dec *turbo_dec = &vector->turbo_dec;
+
+       /* compare keys */
+       if (starts_with(key_token, op_data_prefixes[DATA_INPUT]))
+               ret = parse_data_entry(key_token, token, vector,
+                               DATA_INPUT, op_data_prefixes[DATA_INPUT]);
+
+       else if (starts_with(key_token, op_data_prefixes[DATA_SOFT_OUTPUT]))
+               ret = parse_data_entry(key_token, token, vector,
+                               DATA_SOFT_OUTPUT,
+                               op_data_prefixes[DATA_SOFT_OUTPUT]);
+
+       else if (starts_with(key_token, op_data_prefixes[DATA_HARD_OUTPUT]))
+               ret = parse_data_entry(key_token, token, vector,
+                               DATA_HARD_OUTPUT,
+                               op_data_prefixes[DATA_HARD_OUTPUT]);
+       else if (!strcmp(key_token, "e")) {
+               vector->mask |= TEST_BBDEV_VF_E;
+               turbo_dec->cb_params.e = (uint32_t) strtoul(token, &err, 0);
+       } else if (!strcmp(key_token, "ea")) {
+               vector->mask |= TEST_BBDEV_VF_EA;
+               turbo_dec->tb_params.ea = (uint32_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "eb")) {
+               vector->mask |= TEST_BBDEV_VF_EB;
+               turbo_dec->tb_params.eb = (uint32_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "k")) {
+               vector->mask |= TEST_BBDEV_VF_K;
+               turbo_dec->cb_params.k = (uint16_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "k_pos")) {
+               vector->mask |= TEST_BBDEV_VF_K_POS;
+               turbo_dec->tb_params.k_pos = (uint16_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "k_neg")) {
+               vector->mask |= TEST_BBDEV_VF_K_NEG;
+               turbo_dec->tb_params.k_neg = (uint16_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "c")) {
+               vector->mask |= TEST_BBDEV_VF_C;
+               turbo_dec->tb_params.c = (uint16_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "c_neg")) {
+               vector->mask |= TEST_BBDEV_VF_C_NEG;
+               turbo_dec->tb_params.c_neg = (uint16_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "cab")) {
+               vector->mask |= TEST_BBDEV_VF_CAB;
+               turbo_dec->tb_params.cab = (uint8_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "rv_index")) {
+               vector->mask |= TEST_BBDEV_VF_RV_INDEX;
+               turbo_dec->rv_index = (uint8_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "iter_max")) {
+               vector->mask |= TEST_BBDEV_VF_ITER_MAX;
+               turbo_dec->iter_max = (uint8_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "iter_min")) {
+               vector->mask |= TEST_BBDEV_VF_ITER_MIN;
+               turbo_dec->iter_min = (uint8_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "expected_iter_count")) {
+               vector->mask |= TEST_BBDEV_VF_EXPECTED_ITER_COUNT;
+               turbo_dec->iter_count = (uint8_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "ext_scale")) {
+               vector->mask |= TEST_BBDEV_VF_EXT_SCALE;
+               turbo_dec->ext_scale = (uint8_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "num_maps")) {
+               vector->mask |= TEST_BBDEV_VF_NUM_MAPS;
+               turbo_dec->num_maps = (uint8_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "code_block_mode")) {
+               vector->mask |= TEST_BBDEV_VF_CODE_BLOCK_MODE;
+               turbo_dec->code_block_mode = (uint8_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "op_flags")) {
+               vector->mask |= TEST_BBDEV_VF_OP_FLAGS;
+               ret = parse_turbo_flags(token, &op_flags,
+                       vector->op_type);
+               if (!ret)
+                       turbo_dec->op_flags = op_flags;
+       } else if (!strcmp(key_token, "expected_status")) {
+               vector->mask |= TEST_BBDEV_VF_EXPECTED_STATUS;
+               ret = parse_expected_status(token, &status, vector->op_type);
+               if (!ret)
+                       vector->expected_status = status;
+       } else {
+               printf("Not valid dec key: '%s'\n", key_token);
+               return -1;
+       }
+
+       if (ret != 0) {
+               printf("Failed with convert '%s\t%s'\n", key_token, token);
+               return -1;
+       }
+
+       return 0;
+}
+
+/* parses turbo encoder parameters and assigns to global variable */
+static int
+parse_encoder_params(const char *key_token, char *token,
+               struct test_bbdev_vector *vector)
+{
+       int ret = 0, status = 0;
+       uint32_t op_flags = 0;
+       char *err = NULL;
+
+
+       struct rte_bbdev_op_turbo_enc *turbo_enc = &vector->turbo_enc;
+
+       if (starts_with(key_token, op_data_prefixes[DATA_INPUT]))
+               ret = parse_data_entry(key_token, token, vector,
+                               DATA_INPUT, op_data_prefixes[DATA_INPUT]);
+       else if (starts_with(key_token, "output"))
+               ret = parse_data_entry(key_token, token, vector,
+                               DATA_HARD_OUTPUT, "output");
+       else if (!strcmp(key_token, "e")) {
+               vector->mask |= TEST_BBDEV_VF_E;
+               turbo_enc->cb_params.e = (uint32_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "ea")) {
+               vector->mask |= TEST_BBDEV_VF_EA;
+               turbo_enc->tb_params.ea = (uint32_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "eb")) {
+               vector->mask |= TEST_BBDEV_VF_EB;
+               turbo_enc->tb_params.eb = (uint32_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "k")) {
+               vector->mask |= TEST_BBDEV_VF_K;
+               turbo_enc->cb_params.k = (uint16_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "k_neg")) {
+               vector->mask |= TEST_BBDEV_VF_K_NEG;
+               turbo_enc->tb_params.k_neg = (uint16_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "k_pos")) {
+               vector->mask |= TEST_BBDEV_VF_K_POS;
+               turbo_enc->tb_params.k_pos = (uint16_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "c_neg")) {
+               vector->mask |= TEST_BBDEV_VF_C_NEG;
+               turbo_enc->tb_params.c_neg = (uint8_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "c")) {
+               vector->mask |= TEST_BBDEV_VF_C;
+               turbo_enc->tb_params.c = (uint8_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "cab")) {
+               vector->mask |= TEST_BBDEV_VF_CAB;
+               turbo_enc->tb_params.cab = (uint8_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "rv_index")) {
+               vector->mask |= TEST_BBDEV_VF_RV_INDEX;
+               turbo_enc->rv_index = (uint8_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "ncb")) {
+               vector->mask |= TEST_BBDEV_VF_NCB;
+               turbo_enc->cb_params.ncb = (uint16_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "ncb_neg")) {
+               vector->mask |= TEST_BBDEV_VF_NCB_NEG;
+               turbo_enc->tb_params.ncb_neg =
+                               (uint16_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "ncb_pos")) {
+               vector->mask |= TEST_BBDEV_VF_NCB_POS;
+               turbo_enc->tb_params.ncb_pos =
+                               (uint16_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "r")) {
+               vector->mask |= TEST_BBDEV_VF_R;
+               turbo_enc->tb_params.r = (uint8_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "code_block_mode")) {
+               vector->mask |= TEST_BBDEV_VF_CODE_BLOCK_MODE;
+               turbo_enc->code_block_mode = (uint8_t) strtoul(token, &err, 0);
+               ret = ((err == NULL) || (*err != '\0')) ? -1 : 0;
+       } else if (!strcmp(key_token, "op_flags")) {
+               vector->mask |= TEST_BBDEV_VF_OP_FLAGS;
+               ret = parse_turbo_flags(token, &op_flags,
+                               vector->op_type);
+               if (!ret)
+                       turbo_enc->op_flags = op_flags;
+       } else if (!strcmp(key_token, "expected_status")) {
+               vector->mask |= TEST_BBDEV_VF_EXPECTED_STATUS;
+               ret = parse_expected_status(token, &status, vector->op_type);
+               if (!ret)
+                       vector->expected_status = status;
+       } else {
+               printf("Not valid enc key: '%s'\n", key_token);
+               return -1;
+       }
+
+       if (ret != 0) {
+               printf("Failed with convert '%s\t%s'\n", key_token, token);
+               return -1;
+       }
+
+       return 0;
+}
+
+/* checks the type of key and assigns data */
+static int
+parse_entry(char *entry, struct test_bbdev_vector *vector)
+{
+       int ret = 0;
+       char *token, *key_token;
+       enum rte_bbdev_op_type op_type = RTE_BBDEV_OP_NONE;
+
+       if (entry == NULL) {
+               printf("Expected entry value\n");
+               return -1;
+       }
+
+       /* get key */
+       token = strtok(entry, ENTRY_DELIMITER);
+       key_token = token;
+       /* get values for key */
+       token = strtok(NULL, ENTRY_DELIMITER);
+
+       if (key_token == NULL || token == NULL) {
+               printf("Expected 'key = values' but was '%.40s'..\n", entry);
+               return -1;
+       }
+       trim_space(key_token);
+
+       /* first key_token has to specify type of operation */
+       if (vector->op_type == RTE_BBDEV_OP_NONE) {
+               if (!strcmp(key_token, "op_type")) {
+                       ret = op_turbo_type_strtol(token, &op_type);
+                       if (!ret)
+                               vector->op_type = op_type;
+                       return (!ret) ? 0 : -1;
+               }
+               printf("First key_token (%s) does not specify op_type\n",
+                               key_token);
+               return -1;
+       }
+
+       /* compare keys */
+       if (vector->op_type == RTE_BBDEV_OP_TURBO_DEC) {
+               if (parse_decoder_params(key_token, token, vector) == -1)
+                       return -1;
+       } else if (vector->op_type == RTE_BBDEV_OP_TURBO_ENC) {
+               if (parse_encoder_params(key_token, token, vector) == -1)
+                       return -1;
+       }
+
+       return 0;
+}
+
+static int
+check_decoder_segments(struct test_bbdev_vector *vector)
+{
+       unsigned char i;
+       struct rte_bbdev_op_turbo_dec *turbo_dec = &vector->turbo_dec;
+
+       if (vector->entries[DATA_INPUT].nb_segments == 0)
+               return -1;
+
+       for (i = 0; i < vector->entries[DATA_INPUT].nb_segments; i++)
+               if (vector->entries[DATA_INPUT].segments[i].addr == NULL)
+                       return -1;
+
+       if (vector->entries[DATA_HARD_OUTPUT].nb_segments == 0)
+               return -1;
+
+       for (i = 0; i < vector->entries[DATA_HARD_OUTPUT].nb_segments;
+                       i++)
+               if (vector->entries[DATA_HARD_OUTPUT].segments[i].addr == NULL)
+                       return -1;
+
+       if ((turbo_dec->op_flags & RTE_BBDEV_TURBO_SOFT_OUTPUT) &&
+                       (vector->entries[DATA_SOFT_OUTPUT].nb_segments == 0))
+               return -1;
+
+       for (i = 0; i < vector->entries[DATA_SOFT_OUTPUT].nb_segments;
+                       i++)
+               if (vector->entries[DATA_SOFT_OUTPUT].segments[i].addr == NULL)
+                       return -1;
+
+       return 0;
+}
+
+static int
+check_decoder_llr_spec(struct test_bbdev_vector *vector)
+{
+       struct rte_bbdev_op_turbo_dec *turbo_dec = &vector->turbo_dec;
+
+       /* Check input LLR sign formalism specification */
+       if ((turbo_dec->op_flags & RTE_BBDEV_TURBO_POS_LLR_1_BIT_IN) &&
+                       (turbo_dec->op_flags &
+                       RTE_BBDEV_TURBO_NEG_LLR_1_BIT_IN)) {
+               printf(
+                       "Both positive and negative LLR input flags were set!\n");
+               return -1;
+       }
+       if (!(turbo_dec->op_flags & RTE_BBDEV_TURBO_POS_LLR_1_BIT_IN) &&
+                       !(turbo_dec->op_flags &
+                       RTE_BBDEV_TURBO_NEG_LLR_1_BIT_IN)) {
+               printf(
+                       "WARNING: input LLR sign formalism was not specified and will be set to negative LLR for '1' bit\n");
+               turbo_dec->op_flags |= RTE_BBDEV_TURBO_NEG_LLR_1_BIT_IN;
+       }
+
+       if (!(turbo_dec->op_flags & RTE_BBDEV_TURBO_SOFT_OUTPUT))
+               return 0;
+
+       /* Check output LLR sign formalism specification */
+       if ((turbo_dec->op_flags & RTE_BBDEV_TURBO_POS_LLR_1_BIT_SOFT_OUT) &&
+                       (turbo_dec->op_flags &
+                       RTE_BBDEV_TURBO_NEG_LLR_1_BIT_SOFT_OUT)) {
+               printf(
+                       "Both positive and negative LLR output flags were set!\n");
+               return -1;
+       }
+       if (!(turbo_dec->op_flags & RTE_BBDEV_TURBO_POS_LLR_1_BIT_SOFT_OUT) &&
+                       !(turbo_dec->op_flags &
+                       RTE_BBDEV_TURBO_NEG_LLR_1_BIT_SOFT_OUT)) {
+               printf(
+                       "WARNING: soft output LLR sign formalism was not specified and will be set to negative LLR for '1' bit\n");
+               turbo_dec->op_flags |=
+                               RTE_BBDEV_TURBO_NEG_LLR_1_BIT_SOFT_OUT;
+       }
+
+       return 0;
+}
+
+/* checks decoder parameters */
+static int
+check_decoder(struct test_bbdev_vector *vector)
+{
+       struct rte_bbdev_op_turbo_dec *turbo_dec = &vector->turbo_dec;
+       const int mask = vector->mask;
+
+       if (check_decoder_segments(vector) < 0)
+               return -1;
+
+       if (check_decoder_llr_spec(vector) < 0)
+               return -1;
+
+       /* Check which params were set */
+       if (!(mask & TEST_BBDEV_VF_CODE_BLOCK_MODE)) {
+               printf(
+                       "WARNING: code_block_mode was not specified in vector file and will be set to 1 (0 - TB Mode, 1 - CB mode)\n");
+               turbo_dec->code_block_mode = 1;
+       }
+       if (turbo_dec->code_block_mode == 0) {
+               if (!(mask & TEST_BBDEV_VF_EA))
+                       printf(
+                               "WARNING: ea was not specified in vector file and will be set to 0\n");
+               if (!(mask & TEST_BBDEV_VF_EB))
+                       printf(
+                               "WARNING: eb was not specified in vector file and will be set to 0\n");
+               if (!(mask & TEST_BBDEV_VF_K_NEG))
+                       printf(
+                               "WARNING: k_neg was not specified in vector file and will be set to 0\n");
+               if (!(mask & TEST_BBDEV_VF_K_POS))
+                       printf(
+                               "WARNING: k_pos was not specified in vector file and will be set to 0\n");
+               if (!(mask & TEST_BBDEV_VF_C_NEG))
+                       printf(
+                               "WARNING: c_neg was not specified in vector file and will be set to 0\n");
+               if (!(mask & TEST_BBDEV_VF_C)) {
+                       printf(
+                               "WARNING: c was not specified in vector file and will be set to 1\n");
+                       turbo_dec->tb_params.c = 1;
+               }
+               if (!(mask & TEST_BBDEV_VF_CAB))
+                       printf(
+                               "WARNING: cab was not specified in vector file and will be set to 0\n");
+       } else {
+               if (!(mask & TEST_BBDEV_VF_E))
+                       printf(
+                               "WARNING: e was not specified in vector file and will be set to 0\n");
+               if (!(mask & TEST_BBDEV_VF_K))
+                       printf(
+                               "WARNING: k was not specified in vector file and will be set to 0\n");
+       }
+       if (!(mask & TEST_BBDEV_VF_RV_INDEX))
+               printf(
+                       "WARNING: rv_index was not specified in vector file and will be set to 0\n");
+       if (!(mask & TEST_BBDEV_VF_ITER_MIN))
+               printf(
+                       "WARNING: iter_min was not specified in vector file and will be set to 0\n");
+       if (!(mask & TEST_BBDEV_VF_ITER_MAX))
+               printf(
+                       "WARNING: iter_max was not specified in vector file and will be set to 0\n");
+       if (!(mask & TEST_BBDEV_VF_EXPECTED_ITER_COUNT))
+               printf(
+                       "WARNING: expected_iter_count was not specified in vector file and iter_count will not be validated\n");
+       if (!(mask & TEST_BBDEV_VF_EXT_SCALE))
+               printf(
+                       "WARNING: ext_scale was not specified in vector file and will be set to 0\n");
+       if (!(mask & TEST_BBDEV_VF_OP_FLAGS)) {
+               printf(
+                       "WARNING: op_flags was not specified in vector file and capabilities will not be validated\n");
+               turbo_dec->num_maps = 0;
+       } else if (!(turbo_dec->op_flags & RTE_BBDEV_TURBO_MAP_DEC) &&
+                       mask & TEST_BBDEV_VF_NUM_MAPS) {
+               printf(
+                       "WARNING: RTE_BBDEV_TURBO_MAP_DEC was not set in vector file and num_maps will be set to 0\n");
+               turbo_dec->num_maps = 0;
+       }
+       if (!(mask & TEST_BBDEV_VF_EXPECTED_STATUS))
+               printf(
+                       "WARNING: expected_status was not specified in vector file and will be set to 0\n");
+       return 0;
+}
+
+/* checks encoder parameters */
+static int
+check_encoder(struct test_bbdev_vector *vector)
+{
+       unsigned char i;
+       const int mask = vector->mask;
+
+       if (vector->entries[DATA_INPUT].nb_segments == 0)
+               return -1;
+
+       for (i = 0; i < vector->entries[DATA_INPUT].nb_segments; i++)
+               if (vector->entries[DATA_INPUT].segments[i].addr == NULL)
+                       return -1;
+
+       if (vector->entries[DATA_HARD_OUTPUT].nb_segments == 0)
+               return -1;
+
+       for (i = 0; i < vector->entries[DATA_HARD_OUTPUT].nb_segments; i++)
+               if (vector->entries[DATA_HARD_OUTPUT].segments[i].addr == NULL)
+                       return -1;
+
+       if (!(mask & TEST_BBDEV_VF_CODE_BLOCK_MODE)) {
+               printf(
+                       "WARNING: code_block_mode was not specified in vector file and will be set to 1\n");
+               vector->turbo_enc.code_block_mode = 1;
+       }
+       if (vector->turbo_enc.code_block_mode == 0) {
+               if (!(mask & TEST_BBDEV_VF_EA) && (vector->turbo_enc.op_flags &
+                               RTE_BBDEV_TURBO_RATE_MATCH))
+                       printf(
+                               "WARNING: ea was not specified in vector file and will be set to 0\n");
+               if (!(mask & TEST_BBDEV_VF_EB) && (vector->turbo_enc.op_flags &
+                               RTE_BBDEV_TURBO_RATE_MATCH))
+                       printf(
+                               "WARNING: eb was not specified in vector file and will be set to 0\n");
+               if (!(mask & TEST_BBDEV_VF_K_NEG))
+                       printf(
+                               "WARNING: k_neg was not specified in vector file and will be set to 0\n");
+               if (!(mask & TEST_BBDEV_VF_K_POS))
+                       printf(
+                               "WARNING: k_pos was not specified in vector file and will be set to 0\n");
+               if (!(mask & TEST_BBDEV_VF_C_NEG))
+                       printf(
+                               "WARNING: c_neg was not specified in vector file and will be set to 0\n");
+               if (!(mask & TEST_BBDEV_VF_C)) {
+                       printf(
+                               "WARNING: c was not specified in vector file and will be set to 1\n");
+                       vector->turbo_enc.tb_params.c = 1;
+               }
+               if (!(mask & TEST_BBDEV_VF_CAB) && (vector->turbo_enc.op_flags &
+                               RTE_BBDEV_TURBO_RATE_MATCH))
+                       printf(
+                               "WARNING: cab was not specified in vector file and will be set to 0\n");
+               if (!(mask & TEST_BBDEV_VF_NCB_NEG))
+                       printf(
+                               "WARNING: ncb_neg was not specified in vector file and will be set to 0\n");
+               if (!(mask & TEST_BBDEV_VF_NCB_POS))
+                       printf(
+                               "WARNING: ncb_pos was not specified in vector file and will be set to 0\n");
+               if (!(mask & TEST_BBDEV_VF_R))
+                       printf(
+                               "WARNING: r was not specified in vector file and will be set to 0\n");
+       } else {
+               if (!(mask & TEST_BBDEV_VF_E) && (vector->turbo_enc.op_flags &
+                               RTE_BBDEV_TURBO_RATE_MATCH))
+                       printf(
+                               "WARNING: e was not specified in vector file and will be set to 0\n");
+               if (!(mask & TEST_BBDEV_VF_K))
+                       printf(
+                               "WARNING: k was not specified in vector file and will be set to 0\n");
+               if (!(mask & TEST_BBDEV_VF_NCB))
+                       printf(
+                               "WARNING: ncb was not specified in vector file and will be set to 0\n");
+       }
+       if (!(mask & TEST_BBDEV_VF_RV_INDEX))
+               printf(
+                       "WARNING: rv_index was not specified in vector file and will be set to 0\n");
+       if (!(mask & TEST_BBDEV_VF_OP_FLAGS))
+               printf(
+                       "WARNING: op_flags was not specified in vector file and capabilities will not be validated\n");
+       if (!(mask & TEST_BBDEV_VF_EXPECTED_STATUS))
+               printf(
+                       "WARNING: expected_status was not specified in vector file and will be set to 0\n");
+
+       return 0;
+}
+
+static int
+bbdev_check_vector(struct test_bbdev_vector *vector)
+{
+       if (vector->op_type == RTE_BBDEV_OP_TURBO_DEC) {
+               if (check_decoder(vector) == -1)
+                       return -1;
+       } else if (vector->op_type == RTE_BBDEV_OP_TURBO_ENC) {
+               if (check_encoder(vector) == -1)
+                       return -1;
+       } else if (vector->op_type != RTE_BBDEV_OP_NONE) {
+               printf("Vector was not filled\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+int
+test_bbdev_vector_read(const char *filename,
+               struct test_bbdev_vector *vector)
+{
+       int ret = 0;
+       size_t len = 0;
+
+       FILE *fp = NULL;
+       char *line = NULL;
+       char *entry = NULL;
+
+       fp = fopen(filename, "r");
+       if (fp == NULL) {
+               printf("File %s does not exist\n", filename);
+               return -1;
+       }
+
+       while (getline(&line, &len, fp) != -1) {
+
+               /* ignore comments and new lines */
+               if (line[0] == '#' || line[0] == '/' || line[0] == '\n'
+                       || line[0] == '\r')
+                       continue;
+
+               trim_space(line);
+
+               /* buffer for multiline */
+               entry = realloc(entry, strlen(line) + 1);
+               if (entry == NULL) {
+                       printf("Fail to realloc %zu bytes\n", strlen(line) + 1);
+                       ret = -ENOMEM;
+                       goto exit;
+               }
+
+               memset(entry, 0, strlen(line) + 1);
+               strncpy(entry, line, strlen(line));
+
+               /* check if entry ends with , or = */
+               if (entry[strlen(entry) - 1] == ','
+                       || entry[strlen(entry) - 1] == '=') {
+                       while (getline(&line, &len, fp) != -1) {
+                               trim_space(line);
+
+                               /* extend entry about length of new line */
+                               char *entry_extended = realloc(entry,
+                                               strlen(line) +
+                                               strlen(entry) + 1);
+
+                               if (entry_extended == NULL) {
+                                       printf("Fail to allocate %zu bytes\n",
+                                                       strlen(line) +
+                                                       strlen(entry) + 1);
+                                       ret = -ENOMEM;
+                                       goto exit;
+                               }
+
+                               entry = entry_extended;
+                               strncat(entry, line, strlen(line));
+
+                               if (entry[strlen(entry) - 1] != ',')
+                                       break;
+                       }
+               }
+               ret = parse_entry(entry, vector);
+               if (ret != 0) {
+                       printf("An error occurred while parsing!\n");
+                       goto exit;
+               }
+       }
+       ret = bbdev_check_vector(vector);
+       if (ret != 0)
+               printf("An error occurred while checking!\n");
+
+exit:
+       fclose(fp);
+       free(line);
+       free(entry);
+
+       return ret;
+}
diff --git a/app/test-bbdev/test_bbdev_vector.h b/app/test-bbdev/test_bbdev_vector.h
new file mode 100644 (file)
index 0000000..476aae1
--- /dev/null
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Intel Corporation
+ */
+
+#ifndef TEST_BBDEV_VECTOR_H_
+#define TEST_BBDEV_VECTOR_H_
+
+#include <rte_bbdev_op.h>
+
+/* Flags which are set when specific parameter is define in vector file */
+enum {
+       TEST_BBDEV_VF_E = (1ULL << 0),
+       TEST_BBDEV_VF_EA = (1ULL << 1),
+       TEST_BBDEV_VF_EB = (1ULL << 2),
+       TEST_BBDEV_VF_K = (1ULL << 3),
+       TEST_BBDEV_VF_K_NEG = (1ULL << 4),
+       TEST_BBDEV_VF_K_POS = (1ULL << 5),
+       TEST_BBDEV_VF_C_NEG = (1ULL << 6),
+       TEST_BBDEV_VF_C = (1ULL << 7),
+       TEST_BBDEV_VF_CAB = (1ULL << 8),
+       TEST_BBDEV_VF_RV_INDEX = (1ULL << 9),
+       TEST_BBDEV_VF_ITER_MAX = (1ULL << 10),
+       TEST_BBDEV_VF_ITER_MIN = (1ULL << 11),
+       TEST_BBDEV_VF_EXPECTED_ITER_COUNT = (1ULL << 12),
+       TEST_BBDEV_VF_EXT_SCALE = (1ULL << 13),
+       TEST_BBDEV_VF_NUM_MAPS = (1ULL << 14),
+       TEST_BBDEV_VF_NCB = (1ULL << 15),
+       TEST_BBDEV_VF_NCB_NEG = (1ULL << 16),
+       TEST_BBDEV_VF_NCB_POS = (1ULL << 17),
+       TEST_BBDEV_VF_R = (1ULL << 18),
+       TEST_BBDEV_VF_CODE_BLOCK_MODE = (1ULL << 19),
+       TEST_BBDEV_VF_OP_FLAGS = (1ULL << 20),
+       TEST_BBDEV_VF_EXPECTED_STATUS = (1ULL << 21),
+};
+
+enum op_data_type {
+       DATA_INPUT = 0,
+       DATA_SOFT_OUTPUT,
+       DATA_HARD_OUTPUT,
+       DATA_NUM_TYPES,
+};
+
+struct op_data_buf {
+       uint32_t *addr;
+       uint32_t length;
+};
+
+struct op_data_entries {
+       struct op_data_buf segments[RTE_BBDEV_MAX_CODE_BLOCKS];
+       unsigned int nb_segments;
+};
+
+struct test_bbdev_vector {
+       enum rte_bbdev_op_type op_type;
+       int expected_status;
+       int mask;
+       union {
+               struct rte_bbdev_op_turbo_dec turbo_dec;
+               struct rte_bbdev_op_turbo_enc turbo_enc;
+       };
+       /* Additional storage for op data entries */
+       struct op_data_entries entries[DATA_NUM_TYPES];
+};
+
+/* fills test vector parameters based on test file */
+int
+test_bbdev_vector_read(const char *filename,
+               struct test_bbdev_vector *vector);
+
+
+#endif /* TEST_BBDEV_VECTOR_H_ */
diff --git a/app/test-bbdev/test_vectors/bbdev_vector_null.data b/app/test-bbdev/test_vectors/bbdev_vector_null.data
new file mode 100644 (file)
index 0000000..c9a9abe
--- /dev/null
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2017 Intel Corporation
+
+op_type =
+RTE_BBDEV_OP_NONE
\ No newline at end of file
diff --git a/app/test-bbdev/test_vectors/bbdev_vector_td_default.data b/app/test-bbdev/test_vectors/bbdev_vector_td_default.data
new file mode 100644 (file)
index 0000000..b5c3027
--- /dev/null
@@ -0,0 +1,54 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2017 Intel Corporation
+
+op_type =
+RTE_BBDEV_OP_TURBO_DEC
+
+input0 =
+0x7f007f00, 0x7f817f00, 0x767f8100, 0x817f8100, 0x81008100, 0x7f818100, 0x81817f00, 0x7f818100,
+0x86007f00, 0x7f818100, 0x887f8100, 0x81815200, 0x81008100, 0x817f7f00, 0x7f7f8100, 0x9e817f00,
+0x7f7f0000, 0xb97f0000, 0xa7810000, 0x7f7f4a7f, 0x7f810000, 0x7f7f7f7f, 0x81720000, 0x40658181,
+0x84810000, 0x817f0000, 0x81810000, 0x7f818181, 0x7f810000, 0x81815a81, 0x817f0000, 0x7a867f7b,
+0x817f0000, 0x6b7f0000, 0x7f810000, 0x81818181, 0x817f0000, 0x7f7f817f, 0x7f7f0000, 0xab7f4f7f,
+0x817f0000, 0x817f6c00, 0x81810000, 0x817f8181, 0x7f810000, 0x81816981, 0x7f7f0000, 0x007f8181
+
+hard_output0 =
+0xa7d6732e, 0x61
+
+soft_output0 =
+0x7f7f7f7f, 0x81817f7f, 0x7f817f81, 0x817f7f81, 0x81817f81, 0x81817f81, 0x8181817f, 0x7f81817f,
+0x7f81817f, 0x7f817f7f, 0x81817f7f, 0x817f8181, 0x81818181, 0x817f7f7f, 0x7f818181, 0x817f817f,
+0x81818181, 0x81817f7f, 0x7f817f81, 0x7f81817f, 0x817f7f7f, 0x817f7f7f, 0x7f81817f, 0x817f817f,
+0x81817f7f, 0x81817f7f, 0x81817f7f, 0x7f817f7f, 0x817f7f81, 0x7f7f8181, 0x81817f81, 0x817f7f7f,
+0x7f7f8181
+
+e =
+17280
+
+k =
+40
+
+rv_index =
+1
+
+iter_max =
+8
+
+iter_min =
+4
+
+expected_iter_count =
+8
+
+ext_scale =
+15
+
+num_maps =
+0
+
+op_flags =
+RTE_BBDEV_TURBO_SOFT_OUTPUT, RTE_BBDEV_TURBO_SUBBLOCK_DEINTERLEAVE, RTE_BBDEV_TURBO_NEG_LLR_1_BIT_IN,
+RTE_BBDEV_TURBO_NEG_LLR_1_BIT_SOFT_OUT
+
+expected_status =
+OK
diff --git a/app/test-bbdev/test_vectors/bbdev_vector_te_default.data b/app/test-bbdev/test_vectors/bbdev_vector_te_default.data
new file mode 100644 (file)
index 0000000..883a76c
--- /dev/null
@@ -0,0 +1,33 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2017 Intel Corporation
+
+op_type =
+RTE_BBDEV_OP_TURBO_ENC
+
+input0 =
+0x11d2bcac, 0x4d
+
+output0 =
+0xd2399179, 0x640eb999, 0x2cbaf577, 0xaf224ae2, 0x9d139927, 0xe6909b29, 0xa25b7f47, 0x2aa224ce,
+0x79f2
+
+e =
+272
+
+k =
+40
+
+ncb =
+192
+
+rv_index =
+0
+
+code_block_mode =
+1
+
+op_flags =
+RTE_BBDEV_TURBO_RATE_MATCH
+
+expected_status =
+OK
index fe0bbc2..7afd2c3 100644 (file)
@@ -811,6 +811,11 @@ CONFIG_RTE_TEST_PMD=y
 CONFIG_RTE_TEST_PMD_RECORD_CORE_CYCLES=n
 CONFIG_RTE_TEST_PMD_RECORD_BURST_STATS=n
 
+#
+# Compile the bbdev test application
+#
+CONFIG_RTE_TEST_BBDEV=y
+
 #
 # Compile the crypto performance application
 #
index c9133ec..a6e2c4c 100644 (file)
@@ -39,5 +39,6 @@ DPDK Tools User Guides
     pdump
     pmdinfo
     devbind
+    testbbdev
     cryptoperf
     testeventdev
diff --git a/doc/guides/tools/testbbdev.rst b/doc/guides/tools/testbbdev.rst
new file mode 100644 (file)
index 0000000..c7aac49
--- /dev/null
@@ -0,0 +1,538 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright(c) 2017 Intel Corporation
+
+dpdk-test-bbdev Application
+===========================
+
+The ``dpdk-test-bbdev`` tool is a Data Plane Development Kit (DPDK) utility that
+allows measuring performance parameters of PMDs available in the bbdev framework.
+Available tests available for execution are: latency, throughput, validation and
+sanity tests. Execution of tests can be customized using various parameters
+passed to a python running script.
+
+Compiling the Application
+-------------------------
+
+**Step 1: PMD setting**
+
+The ``dpdk-test-bbdev`` tool depends on crypto device drivers PMD which
+are disabled by default in the build configuration file ``common_base``.
+The bbdevice drivers PMD which should be tested can be enabled by setting
+
+   ``CONFIG_RTE_LIBRTE_PMD_<name>=y``
+
+Setting example for (*turbo_sw*) PMD
+
+   ``CONFIG_RTE_LIBRTE_PMD_BBDEV_TURBO_SW=y``
+
+**Step 2: Build the application**
+
+Execute the ``dpdk-setup.sh`` script to build the DPDK library together with the
+``dpdk-test-bbdev`` application.
+
+Initially, the user must select a DPDK target to choose the correct target type
+and compiler options to use when building the libraries.
+The user must have all libraries, modules, updates and compilers installed
+in the system prior to this, as described in the earlier chapters in this
+Getting Started Guide.
+
+Running the Application
+-----------------------
+
+The tool application has a number of command line options:
+
+.. code-block:: console
+
+  python test-bbdev.py [-h] [-p TESTAPP_PATH] [-e EAL_PARAMS] [-t TIMEOUT]
+                       [-c TEST_CASE [TEST_CASE ...]]
+                       [-v TEST_VECTOR [TEST_VECTOR...]] [-n NUM_OPS]
+                       [-b BURST_SIZE [BURST_SIZE ...]] [-l NUM_LCORES]
+
+command-line Options
+~~~~~~~~~~~~~~~~~~~~
+
+The following are the command-line options:
+
+``-h, --help``
+ Shows help message and exit.
+
+``-p TESTAPP_PATH, --testapp_path TESTAPP_PATH``
+ Indicates the path to the bbdev test app. If not specified path is set based
+ on *$RTE_SDK* environment variable concatenated with "*/build/app/testbbdev*".
+
+``-e EAL_PARAMS, --eal_params EAL_PARAMS``
+ Specifies EAL arguments which are passed to the test app. For more details,
+ refer to DPDK documentation at http://dpdk.org/doc.
+
+``-t TIMEOUT, --timeout TIMEOUT``
+ Specifies timeout in seconds. If not specified timeout is set to 300 seconds.
+
+``-c TEST_CASE [TEST_CASE ...], --test_cases TEST_CASE [TEST_CASE ...]``
+ Defines test cases to run. If not specified all available tests are run.
+
+ The following tests can be run:
+  * unittest
+     Small unit tests witch check basic functionality of bbdev library.
+  * latency
+     Test calculates three latency metrics:
+      * offload_latency_tc
+         measures the cost of offloading enqueue and dequeue operations.
+      * offload_latency_empty_q_tc
+         measures the cost of offloading a dequeue operation from an empty queue.
+         checks how long last dequeueing if there is no operations to dequeue
+      * operation_latency_tc
+         measures the time difference from the first attempt to enqueue till the
+         first successful dequeue.
+  * validation
+     Test do enqueue on given vector and compare output after dequeueing.
+  * throughput
+     Test measures the achieved throughput on the available lcores.
+     Results are printed in million operations per second and million bits per second.
+  * interrupt
+     The same test as 'throughput' but uses interrupts instead of PMD to perform
+     the dequeue.
+
+ **Example usage:**
+
+ ``./test-bbdev.py -c validation``
+  Runs validation test suite
+
+ ``./test-bbdev.py -c latency throughput``
+  Runs latency and throughput test suites
+
+``-v TEST_VECTOR [TEST_VECTOR ...], --test_vector TEST_VECTOR [TEST_VECTOR ...]``
+ Specifies paths to the test vector files. If not specified path is set based
+ on *$RTE_SDK* environment variable concatenated with
+ "*/app/test-bbdev/test_vectors/bbdev_vector_null.data*" and indicates default
+ data file.
+
+ **Example usage:**
+
+ ``./test-bbdev.py -v app/test-bbdev/test_vectors/bbdev_vector_td_test1.data``
+  Fills vector based on bbdev_vector_td_test1.data file and runs all tests
+
+ ``./test-bbdev.py -v bbdev_vector_td_test1.data bbdev_vector_te_test2.data``
+  The bbdev test app is executed twice. First time vector is filled based on
+  *bbdev_vector_td_test1.data* file and second time based on
+  *bbdev_vector_te_test2.data* file. For both executions all tests are run.
+
+``-n NUM_OPS, --num_ops NUM_OPS``
+ Specifies number of operations to process on device. If not specified num_ops
+ is set to 32 operations.
+
+``-l NUM_LCORES, --num_lcores NUM_LCORES``
+ Specifies number of lcores to run. If not specified num_lcores is set
+ according to value from RTE configuration (EAL coremask)
+
+``-b BURST_SIZE [BURST_SIZE ...], --burst-size BURST_SIZE [BURST_SIZE ...]``
+ Specifies operations enqueue/dequeue burst size. If not specified burst_size is
+ set to 32. Maximum is 512.
+
+
+Parameter globbing
+~~~~~~~~~~~~~~~~~~
+
+Thanks to the globbing functionality in python test-bbdev.py script allows to
+run tests with different set of vector files without giving all of them explicitly.
+
+**Example usage:**
+
+.. code-block:: console
+
+  ./test-bbdev.py -v app/test-bbdev/test_vectors/bbdev_vector_*.data
+
+It runs all tests with following vectors:
+
+- ``bbdev_vector_null.data``
+
+- ``bbdev_vector_td_default.data``
+
+- ``bbdev_vector_te_default.data``
+
+
+.. code-block:: console
+
+  ./test-bbdev.py -v app/test-bbdev/test_vectors/bbdev_vector_t?_default.data
+
+It runs all tests with "default" vectors:
+
+- ``bbdev_vector_te_default.data``
+
+- ``bbdev_vector_td_default.data``
+
+
+Running Tests
+-------------
+
+Shortened tree of isg_cid-wireless_dpdk_ae with dpdk compiled for
+x86_64-native-linuxapp-icc target:
+
+::
+
+ |-- app
+     |-- test-bbdev
+         |-- test_vectors
+             |-- bbdev_vector_null.data
+             |-- bbdev_vector_td_default.data
+             |-- bbdev_vector_te_default.data
+
+ |-- x86_64-native-linuxapp-icc
+     |-- app
+         |-- testbbdev
+
+All bbdev devices
+~~~~~~~~~~~~~~~~~
+
+.. code-block:: console
+
+  ./test-bbdev.py -p ../../x86_64-native-linuxapp-icc/app/testbbdev
+  -v ./test_vectors/bbdev_vector_td_default.data
+
+It runs all available tests using the test vector filled based on
+*bbdev_vector_td_default.data* file.
+By default number of operations to process on device is set to 32, timeout is
+set to 300s and operations enqueue/dequeue burst size is set to 32.
+Moreover a bbdev (*bbdev_null*) device will be created.
+
+bbdev turbo_sw device
+~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: console
+
+  ./test-bbdev.py -p ../../x86_64-native-linuxapp-icc/app/testbbdev
+  -e="--vdev=turbo_sw" -t 120 -c validation
+  -v ./test_vectors/bbdev_vector_t?_default.data -n 64 -b 8 32
+
+It runs **validation** test for each vector file that matches the given pattern.
+Number of operations to process on device is set to 64 and operations timeout is
+set to 120s and enqueue/dequeue burst size is set to 8 and to 32.
+Moreover a bbdev (*turbo_sw*) device will be created.
+
+
+bbdev null device
+~~~~~~~~~~~~~~~~~
+
+Executing bbdev null device with *bbdev_vector_null.data* helps in measuring the
+overhead introduced by the bbdev framework.
+
+.. code-block:: console
+
+  ./test-bbdev.py -e="--vdev=bbdev_null0"
+  -v ./test_vectors/bbdev_vector_null.data
+
+**Note:**
+
+bbdev_null device does not have to be defined explicitly as it is created by default.
+
+
+
+Test Vector files
+=================
+
+Test Vector files contain the data which is used to set turbo decoder/encoder
+parameters and buffers for validation purpose. New test vector files should be
+stored in ``app/test-bbdev/test_vectors/`` directory. Detailed description of
+the syntax of the test vector files is in the following section.
+
+
+Basic principles for test vector files
+--------------------------------------
+Line started with ``#`` is treated as a comment and is ignored.
+
+If variable is a chain of values, values should be separated by a comma. If
+assignment is split into several lines, each line (except the last one) has to
+be ended with a comma.
+There is no comma after last value in last line. Correct assignment should
+look like the following:
+
+.. parsed-literal::
+
+ variable =
+ value, value, value, value,
+ value, value
+
+In case where variable is a single value correct assignment looks like the
+following:
+
+.. parsed-literal::
+
+ variable =
+ value
+
+Length of chain variable is calculated by parser. Can not be defined
+explicitly.
+
+Variable op_type has to be defined as a first variable in file. It specifies
+what type of operations will be executed. For decoder op_type has to be set to
+``RTE_BBDEV_OP_TURBO_DEC`` and for encoder to ``RTE_BBDEV_OP_TURBO_ENC``.
+
+Full details of the meaning and valid values for the below fields are
+documented in *rte_bbdev_op.h*
+
+
+Turbo decoder test vectors template
+-----------------------------------
+
+For turbo decoder it has to be always set to ``RTE_BBDEV_OP_TURBO_DEC``
+
+.. parsed-literal::
+
+    op_type =
+    RTE_BBDEV_OP_TURBO_DEC
+
+Chain of uint32_t values. Note that it is possible to define more than one
+input/output entries which will result in chaining two or more data structures
+for *segmented Transport Blocks*
+
+.. parsed-literal::
+
+    input0 =
+    0x00000000, 0x7f817f00, 0x7f7f8100, 0x817f8100, 0x81008100, 0x7f818100, 0x81817f00, 0x7f818100,
+    0x81007f00, 0x7f818100, 0x817f8100, 0x81817f00, 0x81008100, 0x817f7f00, 0x7f7f8100, 0x81817f00
+
+Chain of uint32_t values
+
+.. parsed-literal::
+
+    input1 =
+    0x7f7f0000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
+
+Chain of uint32_t values
+
+.. parsed-literal::
+
+    input2 =
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
+
+Chain of uint32_t values
+
+.. parsed-literal::
+
+    hard_output0 =
+    0xa7d6732e
+
+Chain of uint32_t values
+
+.. parsed-literal::
+
+    hard_output1 =
+    0xa61
+
+Chain of uint32_t values
+
+.. parsed-literal::
+
+    soft_output0 =
+    0x817f817f, 0x7f817f7f, 0x81818181, 0x817f7f81, 0x7f818181, 0x8181817f, 0x817f817f, 0x8181817f
+
+Chain of uint32_t values
+
+.. parsed-literal::
+
+    soft_output1 =
+    0x817f7f81, 0x7f7f7f81, 0x7f7f8181
+
+uint32_t value
+
+.. parsed-literal::
+
+    e =
+    44
+
+uint16_t value
+
+.. parsed-literal::
+
+    k =
+    40
+
+uint8_t value
+
+.. parsed-literal::
+
+    rv_index =
+    0
+
+uint8_t value
+
+.. parsed-literal::
+
+    iter_max =
+    8
+
+uint8_t value
+
+.. parsed-literal::
+
+    iter_min =
+    4
+
+uint8_t value
+
+.. parsed-literal::
+
+    expected_iter_count =
+    8
+
+uint8_t value
+
+.. parsed-literal::
+
+    ext_scale =
+    15
+
+uint8_t value
+
+.. parsed-literal::
+
+    num_maps =
+    0
+
+Chain of flags for turbo decoder operation. Following flags can be used:
+
+- ``RTE_BBDEV_TURBO_SUBBLOCK_DEINTERLEAVE``
+
+- ``RTE_BBDEV_TURBO_CRC_TYPE_24B``
+
+- ``RTE_BBDEV_TURBO_EQUALIZER``
+
+- ``RTE_BBDEV_TURBO_SOFT_OUT_SATURATE``
+
+- ``RTE_BBDEV_TURBO_HALF_ITERATION_EVEN``
+
+- ``RTE_BBDEV_TURBO_CONTINUE_CRC_MATCH``
+
+- ``RTE_BBDEV_TURBO_SOFT_OUTPUT``
+
+- ``RTE_BBDEV_TURBO_EARLY_TERMINATION``
+
+- ``RTE_BBDEV_TURBO_DEC_INTERRUPTS``
+
+- ``RTE_BBDEV_TURBO_POS_LLR_1_BIT_IN``
+
+- ``RTE_BBDEV_TURBO_NEG_LLR_1_BIT_IN``
+
+- ``RTE_BBDEV_TURBO_POS_LLR_1_BIT_SOFT_OUT``
+
+- ``RTE_BBDEV_TURBO_NEG_LLR_1_BIT_SOFT_OUT``
+
+- ``RTE_BBDEV_TURBO_MAP_DEC``
+
+Example:
+
+    .. parsed-literal::
+
+        op_flags =
+        RTE_BBDEV_TURBO_SUBBLOCK_DEINTERLEAVE, RTE_BBDEV_TURBO_EQUALIZER,
+        RTE_BBDEV_TURBO_SOFT_OUTPUT
+
+Chain of operation statuses that are expected after operation is performed.
+Following statuses can be used:
+
+- ``DMA``
+
+- ``FCW``
+
+- ``CRC``
+
+- ``OK``
+
+``OK`` means no errors are expected. Cannot be used with other values.
+
+.. parsed-literal::
+
+    expected_status =
+    FCW, CRC
+
+
+Turbo encoder test vectors template
+-----------------------------------
+
+For turbo encoder it has to be always set to ``RTE_BBDEV_OP_TURBO_ENC``
+
+.. parsed-literal::
+
+    op_type =
+    RTE_BBDEV_OP_TURBO_ENC
+
+Chain of uint32_t values
+
+.. parsed-literal::
+
+    input0 =
+    0x11d2bcac, 0x4d
+
+Chain of uint32_t values
+
+.. parsed-literal::
+
+    output0 =
+    0xd2399179, 0x640eb999, 0x2cbaf577, 0xaf224ae2, 0x9d139927, 0xe6909b29,
+    0xa25b7f47, 0x2aa224ce, 0x79f2
+
+uint32_t value
+
+.. parsed-literal::
+
+    e =
+    272
+
+uint16_t value
+
+.. parsed-literal::
+
+    k =
+    40
+
+uint16_t value
+
+.. parsed-literal::
+
+    ncb =
+    192
+
+uint8_t value
+
+.. parsed-literal::
+
+    rv_index =
+    0
+
+Chain of flags for turbo encoder operation. Following flags can be used:
+
+- ``RTE_BBDEV_TURBO_RV_INDEX_BYPASS``
+
+- ``RTE_BBDEV_TURBO_RATE_MATCH``
+
+- ``RTE_BBDEV_TURBO_CRC_24B_ATTACH``
+
+- ``RTE_BBDEV_TURBO_CRC_24A_ATTACH``
+
+- ``RTE_BBDEV_TURBO_ENC_SCATTER_GATHER``
+
+``RTE_BBDEV_TURBO_ENC_SCATTER_GATHER`` is used to indicate the parser to
+force the input data to be memory split and formed as a segmented mbuf.
+
+
+.. parsed-literal::
+
+    op_flags =
+    RTE_BBDEV_TURBO_RATE_MATCH
+
+Chain of operation statuses that are expected after operation is performed.
+Following statuses can be used:
+
+- ``DMA``
+
+- ``FCW``
+
+- ``OK``
+
+``OK`` means no errors are expected. Cannot be used with other values.
+
+.. parsed-literal::
+
+    expected_status =
+    OK