* [dpdk-dev] [PATCH v3 2/5] bbdev: PMD drivers (null/turbo_sw)
2017-12-07 21:40 [dpdk-dev] [PATCH v3 1/5] bbdev: librte_bbdev library Amr Mokhtar
@ 2017-12-07 21:40 ` Amr Mokhtar
2017-12-11 19:00 ` Ferruh Yigit
2017-12-07 21:40 ` [dpdk-dev] [PATCH v3 3/5] bbdev: test applications Amr Mokhtar
` (4 subsequent siblings)
5 siblings, 1 reply; 16+ messages in thread
From: Amr Mokhtar @ 2017-12-07 21:40 UTC (permalink / raw)
To: dev
Cc: thomas, anatoly.burakov, pablo.de.lara.guarch, niall.power,
chris.macnamara, Amr Mokhtar
- bbdev 'null' PMD enabled by default
- bbdev 'turbo_sw' PMD disabled by default
- 'turbo_sw' requires the external FLEXRAN SDK libraries
Signed-off-by: Amr Mokhtar <amr.mokhtar@intel.com>
---
drivers/Makefile | 2 +
drivers/bbdev/Makefile | 41 +
drivers/bbdev/null/Makefile | 51 +
drivers/bbdev/null/bbdev_null.c | 385 ++++++
drivers/bbdev/null/rte_pmd_bbdev_null_version.map | 3 +
drivers/bbdev/turbo_sw/Makefile | 68 ++
drivers/bbdev/turbo_sw/bbdev_turbo_software.c | 1226 ++++++++++++++++++++
.../turbo_sw/rte_pmd_bbdev_turbo_sw_version.map | 3 +
8 files changed, 1779 insertions(+)
create mode 100644 drivers/bbdev/Makefile
create mode 100644 drivers/bbdev/null/Makefile
create mode 100644 drivers/bbdev/null/bbdev_null.c
create mode 100644 drivers/bbdev/null/rte_pmd_bbdev_null_version.map
create mode 100644 drivers/bbdev/turbo_sw/Makefile
create mode 100644 drivers/bbdev/turbo_sw/bbdev_turbo_software.c
create mode 100644 drivers/bbdev/turbo_sw/rte_pmd_bbdev_turbo_sw_version.map
diff --git a/drivers/Makefile b/drivers/Makefile
index db0cd76..eb9a1f8 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -40,5 +40,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += crypto
DEPDIRS-crypto := bus mempool
DIRS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += event
DEPDIRS-event := bus mempool net
+DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) += bbdev
+DEPDIRS-bbdev := bus mempool
include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/drivers/bbdev/Makefile b/drivers/bbdev/Makefile
new file mode 100644
index 0000000..c70cd06
--- /dev/null
+++ b/drivers/bbdev/Makefile
@@ -0,0 +1,41 @@
+# BSD LICENSE
+#
+# Copyright(c) 2017 Intel Corporation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+core-libs := librte_eal librte_mbuf librte_mempool librte_ring
+core-libs += librte_bbdev librte_kvargs librte_cfgfile
+
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_BBDEV_NULL) += null
+DEPDIRS-null = $(core-libs)
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_BBDEV_TURBO_SW) += turbo_sw
+DEPDIRS-turbo_sw = $(core-libs)
+
+include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/drivers/bbdev/null/Makefile b/drivers/bbdev/null/Makefile
new file mode 100644
index 0000000..2b51b02
--- /dev/null
+++ b/drivers/bbdev/null/Makefile
@@ -0,0 +1,51 @@
+# BSD LICENSE
+#
+# Copyright(c) 2017 Intel Corporation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+# library name
+LIB = librte_pmd_bbdev_null.a
+
+# build flags
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring -lrte_kvargs
+LDLIBS += -lrte_bbdev
+LDLIBS += -lrte_bus_vdev
+
+# versioning export map
+EXPORT_MAP := rte_pmd_bbdev_null_version.map
+
+# library version
+LIBABIVER := 1
+
+# library source files
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_BBDEV_NULL) += bbdev_null.c
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/bbdev/null/bbdev_null.c b/drivers/bbdev/null/bbdev_null.c
new file mode 100644
index 0000000..4e5e360
--- /dev/null
+++ b/drivers/bbdev/null/bbdev_null.c
@@ -0,0 +1,385 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_bus_vdev.h>
+#include <rte_malloc.h>
+#include <rte_ring.h>
+#include <rte_kvargs.h>
+
+#include <rte_bbdev.h>
+#include <rte_bbdev_pmd.h>
+
+#define DRIVER_NAME bbdev_null
+
+/* Initialisation params structure that can be used by null BBDEV driver */
+struct bbdev_null_params {
+ int socket_id; /*< Null BBDEV socket */
+ uint16_t queues_num; /*< Null BBDEV queues number */
+};
+
+/* Accecptable params for null BBDEV devices */
+#define BBDEV_NULL_MAX_NB_QUEUES_ARG "max_nb_queues"
+#define BBDEV_NULL_SOCKET_ID_ARG "socket_id"
+
+static const char * const bbdev_null_valid_params[] = {
+ BBDEV_NULL_MAX_NB_QUEUES_ARG,
+ BBDEV_NULL_SOCKET_ID_ARG
+};
+
+/* private data structure */
+struct bbdev_private {
+ unsigned int max_nb_queues; /**< Max number of queues */
+};
+
+/* queue */
+struct bbdev_queue {
+ struct rte_ring *processed_pkts; /* Ring for processed packets */
+} __rte_cache_aligned;
+
+/* Get device info */
+static void
+info_get(struct rte_bbdev *dev, struct rte_bbdev_driver_info *dev_info)
+{
+ struct bbdev_private *internals = dev->data->dev_private;
+
+ static const struct rte_bbdev_op_cap bbdev_capabilities[] = {
+ RTE_BBDEV_END_OF_CAPABILITIES_LIST(),
+ };
+
+ static struct rte_bbdev_queue_conf default_queue_conf = {
+ .queue_size = RTE_BBDEV_QUEUE_SIZE_LIMIT,
+ };
+
+ default_queue_conf.socket = dev->data->socket_id;
+
+ dev_info->driver_name = RTE_STR(DRIVER_NAME);
+ dev_info->max_num_queues = internals->max_nb_queues;
+ dev_info->queue_size_lim = RTE_BBDEV_QUEUE_SIZE_LIMIT;
+ dev_info->hardware_accelerated = false;
+ dev_info->max_queue_priority = 0;
+ dev_info->default_queue_conf = default_queue_conf;
+ dev_info->capabilities = bbdev_capabilities;
+ dev_info->cpu_flag_reqs = NULL;
+ dev_info->min_alignment = 0;
+
+ rte_bbdev_log_debug("got device info from %u", dev->data->dev_id);
+}
+
+/* Release queue */
+static int
+q_release(struct rte_bbdev *dev, uint16_t q_id)
+{
+ struct bbdev_queue *q = dev->data->queues[q_id].queue_private;
+
+ if (q != NULL) {
+ rte_ring_free(q->processed_pkts);
+ rte_free(q);
+ dev->data->queues[q_id].queue_private = NULL;
+ }
+
+ rte_bbdev_log_debug("released device queue %u:%u",
+ dev->data->dev_id, q_id);
+ return 0;
+}
+
+/* Setup a queue */
+static int
+q_setup(struct rte_bbdev *dev, uint16_t q_id,
+ const struct rte_bbdev_queue_conf *queue_conf)
+{
+ struct bbdev_queue *q;
+ char ring_name[RTE_RING_NAMESIZE];
+ snprintf(ring_name, RTE_RING_NAMESIZE, RTE_STR(DRIVER_NAME) "%u:%u",
+ dev->data->dev_id, q_id);
+
+ /* Allocate the queue data structure. */
+ q = rte_zmalloc_socket(RTE_STR(DRIVER_NAME), sizeof(*q),
+ RTE_CACHE_LINE_SIZE, queue_conf->socket);
+ if (q == NULL) {
+ rte_bbdev_log(ERR, "Failed to allocate queue memory");
+ return -ENOMEM;
+ }
+
+ q->processed_pkts = rte_ring_create(ring_name, queue_conf->queue_size,
+ queue_conf->socket, RING_F_SP_ENQ | RING_F_SC_DEQ);
+ if (q->processed_pkts == NULL) {
+ rte_bbdev_log(ERR, "Failed to create ring");
+ goto free_q;
+ }
+
+ dev->data->queues[q_id].queue_private = q;
+ rte_bbdev_log_debug("setup device queue %s", ring_name);
+ return 0;
+
+free_q:
+ rte_free(q);
+ return -EFAULT;
+}
+
+static const struct rte_bbdev_ops pmd_ops = {
+ .setup_queues = NULL,
+ .intr_enable = NULL,
+ .start = NULL,
+ .stop = NULL,
+ .close = NULL,
+ .info_get = info_get,
+ .stats_get = NULL,
+ .stats_reset = NULL,
+ .queue_setup = q_setup,
+ .queue_release = q_release,
+ .queue_start = NULL,
+ .queue_stop = NULL,
+ .queue_intr_enable = NULL,
+ .queue_intr_disable = NULL
+};
+
+/* Enqueue decode burst */
+static uint16_t
+enqueue_dec_ops(struct rte_bbdev_queue_data *q_data,
+ struct rte_bbdev_dec_op **ops, uint16_t nb_ops)
+{
+ struct bbdev_queue *q = q_data->queue_private;
+ uint16_t nb_enqueued = rte_ring_enqueue_burst(q->processed_pkts,
+ (void **)ops, nb_ops, NULL);
+
+ q_data->queue_stats.enqueue_err_count += nb_ops - nb_enqueued;
+ q_data->queue_stats.enqueued_count += nb_enqueued;
+
+ return nb_enqueued;
+}
+
+/* Enqueue encode burst */
+static uint16_t
+enqueue_enc_ops(struct rte_bbdev_queue_data *q_data,
+ struct rte_bbdev_enc_op **ops, uint16_t nb_ops)
+{
+ struct bbdev_queue *q = q_data->queue_private;
+ uint16_t nb_enqueued = rte_ring_enqueue_burst(q->processed_pkts,
+ (void **)ops, nb_ops, NULL);
+
+ q_data->queue_stats.enqueue_err_count += nb_ops - nb_enqueued;
+ q_data->queue_stats.enqueued_count += nb_enqueued;
+
+ return nb_enqueued;
+}
+
+/* Dequeue decode burst */
+static uint16_t
+dequeue_dec_ops(struct rte_bbdev_queue_data *q_data,
+ struct rte_bbdev_dec_op **ops, uint16_t nb_ops)
+{
+ struct bbdev_queue *q = q_data->queue_private;
+ uint16_t nb_dequeued = rte_ring_dequeue_burst(q->processed_pkts,
+ (void **)ops, nb_ops, NULL);
+ q_data->queue_stats.dequeued_count += nb_dequeued;
+
+ return nb_dequeued;
+}
+
+/* Dequeue encode burst */
+static uint16_t
+dequeue_enc_ops(struct rte_bbdev_queue_data *q_data,
+ struct rte_bbdev_enc_op **ops, uint16_t nb_ops)
+{
+ struct bbdev_queue *q = q_data->queue_private;
+ uint16_t nb_dequeued = rte_ring_dequeue_burst(q->processed_pkts,
+ (void **)ops, nb_ops, NULL);
+ q_data->queue_stats.dequeued_count += nb_dequeued;
+
+ return nb_dequeued;
+}
+
+/* Parse 16bit integer from string argument */
+static inline int
+parse_u16_arg(const char *key, const char *value, void *extra_args)
+{
+ uint16_t *u16 = extra_args;
+ unsigned int long result;
+
+ if ((value == NULL) || (extra_args == NULL))
+ return -EINVAL;
+ errno = 0;
+ result = strtoul(value, NULL, 0);
+ if ((result >= (1 << 16)) || (errno != 0)) {
+ rte_bbdev_log(ERR, "Invalid value %lu for %s", result, key);
+ return -ERANGE;
+ }
+ *u16 = (uint16_t)result;
+ return 0;
+}
+
+/* Parse parameters used to create device */
+static int
+parse_bbdev_null_params(struct bbdev_null_params *params,
+ const char *input_args)
+{
+ struct rte_kvargs *kvlist = NULL;
+ int ret = 0;
+
+ if (params == NULL)
+ return -EINVAL;
+ if (input_args) {
+ kvlist = rte_kvargs_parse(input_args, bbdev_null_valid_params);
+ if (kvlist == NULL)
+ return -EFAULT;
+
+ ret = rte_kvargs_process(kvlist, bbdev_null_valid_params[0],
+ &parse_u16_arg, ¶ms->queues_num);
+ if (ret < 0)
+ goto exit;
+
+ ret = rte_kvargs_process(kvlist, bbdev_null_valid_params[1],
+ &parse_u16_arg, ¶ms->socket_id);
+ if (ret < 0)
+ goto exit;
+
+ if (params->socket_id >= RTE_MAX_NUMA_NODES) {
+ rte_bbdev_log(ERR, "Invalid socket, must be < %u",
+ RTE_MAX_NUMA_NODES);
+ goto exit;
+ }
+ }
+
+exit:
+ if (kvlist)
+ rte_kvargs_free(kvlist);
+ return ret;
+}
+
+/* Create device */
+static int
+null_bbdev_create(struct rte_vdev_device *vdev,
+ struct bbdev_null_params *init_params)
+{
+ struct rte_bbdev *bbdev;
+ const char *name = rte_vdev_device_name(vdev);
+
+ bbdev = rte_bbdev_allocate(name);
+ if (bbdev == NULL)
+ return -ENODEV;
+
+ bbdev->data->dev_private = rte_zmalloc_socket(name,
+ sizeof(struct bbdev_private), RTE_CACHE_LINE_SIZE,
+ init_params->socket_id);
+ if (bbdev->data->dev_private == NULL) {
+ rte_bbdev_release(bbdev);
+ return -ENOMEM;
+ }
+
+ bbdev->dev_ops = &pmd_ops;
+ bbdev->device = &vdev->device;
+ bbdev->data->socket_id = init_params->socket_id;
+ bbdev->intr_handle = NULL;
+
+ /* register rx/tx burst functions for data path */
+ bbdev->dequeue_enc_ops = dequeue_enc_ops;
+ bbdev->dequeue_dec_ops = dequeue_dec_ops;
+ bbdev->enqueue_enc_ops = enqueue_enc_ops;
+ bbdev->enqueue_dec_ops = enqueue_dec_ops;
+ ((struct bbdev_private *) bbdev->data->dev_private)->max_nb_queues =
+ init_params->queues_num;
+
+ return 0;
+}
+
+/* Initialise device */
+static int
+null_bbdev_probe(struct rte_vdev_device *vdev)
+{
+ struct bbdev_null_params init_params = {
+ rte_socket_id(),
+ RTE_BBDEV_DEFAULT_MAX_NB_QUEUES
+ };
+ const char *name;
+ const char *input_args;
+
+ if (vdev == NULL)
+ return -EINVAL;
+
+ name = rte_vdev_device_name(vdev);
+ if (name == NULL)
+ return -EINVAL;
+
+ input_args = rte_vdev_device_args(vdev);
+ parse_bbdev_null_params(&init_params, input_args);
+
+ rte_bbdev_log_debug("Init %s on NUMA node %d with max queues: %d",
+ name, init_params.socket_id, init_params.queues_num);
+
+ return null_bbdev_create(vdev, &init_params);
+}
+
+/* Uninitialise device */
+static int
+null_bbdev_remove(struct rte_vdev_device *vdev)
+{
+ struct rte_bbdev *bbdev;
+ const char *name;
+
+ if (vdev == NULL)
+ return -EINVAL;
+
+ name = rte_vdev_device_name(vdev);
+ if (name == NULL)
+ return -EINVAL;
+
+ bbdev = rte_bbdev_get_named_dev(name);
+ if (bbdev == NULL)
+ return -EINVAL;
+
+ rte_free(bbdev->data->dev_private);
+
+ return rte_bbdev_release(bbdev);
+}
+
+static struct rte_vdev_driver bbdev_null_pmd_drv = {
+ .probe = null_bbdev_probe,
+ .remove = null_bbdev_remove
+};
+
+RTE_PMD_REGISTER_VDEV(DRIVER_NAME, bbdev_null_pmd_drv);
+RTE_PMD_REGISTER_ALIAS(DRIVER_NAME, bbdev_null_pmd);
+RTE_PMD_REGISTER_PARAM_STRING(DRIVER_NAME,
+ BBDEV_NULL_MAX_NB_QUEUES_ARG"=<int> "
+ BBDEV_NULL_SOCKET_ID_ARG"=<int>");
+
+int bbdev_logtype;
+RTE_INIT(null_bbdev_init_log);
+static void
+null_bbdev_init_log(void)
+{
+ bbdev_logtype = rte_log_register("pmd.null_bbdev");
+ if (bbdev_logtype >= 0)
+ rte_log_set_level(bbdev_logtype, RTE_LOG_NOTICE);
+}
diff --git a/drivers/bbdev/null/rte_pmd_bbdev_null_version.map b/drivers/bbdev/null/rte_pmd_bbdev_null_version.map
new file mode 100644
index 0000000..58b9427
--- /dev/null
+++ b/drivers/bbdev/null/rte_pmd_bbdev_null_version.map
@@ -0,0 +1,3 @@
+DPDK_18.02 {
+ local: *;
+};
diff --git a/drivers/bbdev/turbo_sw/Makefile b/drivers/bbdev/turbo_sw/Makefile
new file mode 100644
index 0000000..5564f1c
--- /dev/null
+++ b/drivers/bbdev/turbo_sw/Makefile
@@ -0,0 +1,68 @@
+# BSD LICENSE
+#
+# Copyright(c) 2017 Intel Corporation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifeq ($(FLEXRAN_SDK),)
+$(error "Please define FLEXRAN_SDK environment variable")
+endif
+
+# library name
+LIB = librte_pmd_bbdev_turbo_sw.a
+
+# build flags
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring -lrte_kvargs
+LDLIBS += -lrte_bbdev
+LDLIBS += -lrte_bus_vdev
+
+# versioning export map
+EXPORT_MAP := rte_pmd_bbdev_turbo_sw_version.map
+
+# external library dependencies
+CFLAGS += -I$(FLEXRAN_SDK)/lib_common
+CFLAGS += -I$(FLEXRAN_SDK)/lib_turbo
+CFLAGS += -I$(FLEXRAN_SDK)/lib_crc
+CFLAGS += -I$(FLEXRAN_SDK)/lib_rate_matching
+
+LDLIBS += -L$(FLEXRAN_SDK)/lib_common -lcommon
+LDLIBS += -L$(FLEXRAN_SDK)/lib_crc -lcrc
+LDLIBS += -L$(FLEXRAN_SDK)/lib_turbo -lturbo
+LDLIBS += -L$(FLEXRAN_SDK)/lib_rate_matching -lrate_matching
+LDLIBS += -lstdc++ -lirc -limf -lipps
+
+# library version
+LIBABIVER := 1
+
+# library source files
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_BBDEV_TURBO_SW) += bbdev_turbo_software.c
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/bbdev/turbo_sw/bbdev_turbo_software.c b/drivers/bbdev/turbo_sw/bbdev_turbo_software.c
new file mode 100644
index 0000000..f7c028c
--- /dev/null
+++ b/drivers/bbdev/turbo_sw/bbdev_turbo_software.c
@@ -0,0 +1,1226 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_bus_vdev.h>
+#include <rte_malloc.h>
+#include <rte_ring.h>
+#include <rte_kvargs.h>
+
+#include <rte_bbdev.h>
+#include <rte_bbdev_pmd.h>
+
+#include <phy_turbo.h>
+#include <phy_crc.h>
+#include <phy_rate_match.h>
+#include <divide.h>
+
+#define DRIVER_NAME turbo_sw
+
+/* Number of columns in sub-block interleaver (36.212, section 5.1.4.1.1) */
+#define C_SUBBLOCK 32
+#define MAX_TB_SIZE (391656)
+#define MAX_CB_SIZE (6144)
+#define MAX_NCB ((MAX_CB_SIZE + 4) * 3)
+
+/* private data structure */
+struct bbdev_private {
+ unsigned int max_nb_queues; /**< Max number of queues */
+};
+
+/* Initialisation params structure that can be used by Turbo SW driver */
+struct turbo_sw_params {
+ int socket_id; /*< Turbo SW device socket */
+ uint16_t queues_num; /*< Turbo SW device queues number */
+};
+
+/* Accecptable params for Turbo SW devices */
+#define TURBO_SW_MAX_NB_QUEUES_ARG "max_nb_queues"
+#define TURBO_SW_SOCKET_ID_ARG "socket_id"
+
+static const char * const turbo_sw_valid_params[] = {
+ TURBO_SW_MAX_NB_QUEUES_ARG,
+ TURBO_SW_SOCKET_ID_ARG
+};
+
+/* queue */
+struct turbo_sw_queue {
+ /* Ring for processed (encoded/decoded) operations which are ready to
+ * be dequeued.
+ */
+ struct rte_ring *processed_pkts;
+ /* Stores input for turbo encoder (used when CRC attachment is
+ * performed
+ */
+ uint8_t *enc_in;
+ /* Stores output from turbo encoder */
+ uint8_t *enc_out;
+ /* Alpha gamma buf for bblib_turbo_decoder() function */
+ int8_t *ag;
+ /* Temp buf for bblib_turbo_decoder() function */
+ uint16_t *code_block;
+ /* Input buf for bblib_rate_dematching_lte() function */
+ uint8_t *deint_input;
+ /* Output buf for bblib_rate_dematching_lte() function */
+ uint8_t *deint_output;
+ /* Output buf for bblib_turbodec_adapter_lte() function */
+ uint8_t *adapter_output;
+ /* Operation type of this queue */
+ enum rte_bbdev_op_type type;
+} __rte_cache_aligned;
+
+/* Calculate index based on Table 5.1.3-3 from TS34.212 */
+static inline int32_t
+compute_idx(uint16_t k)
+{
+ int32_t result = 0;
+
+ if (k < 40 || k > MAX_CB_SIZE)
+ return -1;
+
+ if (k > 2048) {
+ if ((k - 2048) % 64 != 0)
+ result = -1;
+
+ result = 124 + (k - 2048) / 64;
+ } else if (k <= 512) {
+ if ((k - 40) % 8 != 0)
+ result = -1;
+
+ result = (k - 40) / 8 + 1;
+ } else if (k <= 1024) {
+ if ((k - 512) % 16 != 0)
+ result = -1;
+
+ result = 60 + (k - 512) / 16;
+ } else { /* 1024 < k <= 2048 */
+ if ((k - 1024) % 32 != 0)
+ result = -1;
+
+ result = 92 + (k - 1024) / 32;
+ }
+
+ return result;
+}
+
+/* Read flag value 0/1 from bitmap */
+static inline bool
+check_bit(uint32_t bitmap, uint32_t bitmask)
+{
+ return bitmap & bitmask;
+}
+
+/* Get device info */
+static void
+info_get(struct rte_bbdev *dev, struct rte_bbdev_driver_info *dev_info)
+{
+ struct bbdev_private *internals = dev->data->dev_private;
+
+ static const struct rte_bbdev_op_cap bbdev_capabilities[] = {
+ {
+ .type = RTE_BBDEV_OP_TURBO_DEC,
+ .cap.turbo_dec = {
+ .capability_flags =
+ RTE_BBDEV_TURBO_SUBBLOCK_DEINTERLEAVE |
+ RTE_BBDEV_TURBO_POS_LLR_1_BIT_IN |
+ RTE_BBDEV_TURBO_NEG_LLR_1_BIT_IN |
+ RTE_BBDEV_TURBO_CRC_TYPE_24B,
+ .num_buffers_src = RTE_BBDEV_MAX_CODE_BLOCKS,
+ .num_buffers_hard_out =
+ RTE_BBDEV_MAX_CODE_BLOCKS,
+ .num_buffers_soft_out = 0,
+ }
+ },
+ {
+ .type = RTE_BBDEV_OP_TURBO_ENC,
+ .cap.turbo_enc = {
+ .capability_flags =
+ RTE_BBDEV_TURBO_CRC_24B_ATTACH |
+ RTE_BBDEV_TURBO_CRC_24A_ATTACH |
+ RTE_BBDEV_TURBO_RATE_MATCH |
+ RTE_BBDEV_TURBO_RV_INDEX_BYPASS,
+ .num_buffers_src = RTE_BBDEV_MAX_CODE_BLOCKS,
+ .num_buffers_dst = RTE_BBDEV_MAX_CODE_BLOCKS,
+ }
+ },
+ RTE_BBDEV_END_OF_CAPABILITIES_LIST()
+ };
+
+ static struct rte_bbdev_queue_conf default_queue_conf = {
+ .queue_size = RTE_BBDEV_QUEUE_SIZE_LIMIT,
+ };
+
+ static const enum rte_cpu_flag_t cpu_flag = RTE_CPUFLAG_SSE4_2;
+
+ default_queue_conf.socket = dev->data->socket_id;
+
+ dev_info->driver_name = RTE_STR(DRIVER_NAME);
+ dev_info->max_num_queues = internals->max_nb_queues;
+ dev_info->queue_size_lim = RTE_BBDEV_QUEUE_SIZE_LIMIT;
+ dev_info->hardware_accelerated = false;
+ dev_info->max_queue_priority = 0;
+ dev_info->default_queue_conf = default_queue_conf;
+ dev_info->capabilities = bbdev_capabilities;
+ dev_info->cpu_flag_reqs = &cpu_flag;
+ dev_info->min_alignment = 64;
+
+ rte_bbdev_log_debug("got device info from %u\n", dev->data->dev_id);
+}
+
+/* Release queue */
+static int
+q_release(struct rte_bbdev *dev, uint16_t q_id)
+{
+ struct turbo_sw_queue *q = dev->data->queues[q_id].queue_private;
+
+ if (q != NULL) {
+ rte_ring_free(q->processed_pkts);
+ rte_free(q->enc_out);
+ rte_free(q->enc_in);
+ rte_free(q->ag);
+ rte_free(q->code_block);
+ rte_free(q->deint_input);
+ rte_free(q->deint_output);
+ rte_free(q->adapter_output);
+ rte_free(q);
+ dev->data->queues[q_id].queue_private = NULL;
+ }
+
+ rte_bbdev_log_debug("released device queue %u:%u",
+ dev->data->dev_id, q_id);
+ return 0;
+}
+
+/* Setup a queue */
+static int
+q_setup(struct rte_bbdev *dev, uint16_t q_id,
+ const struct rte_bbdev_queue_conf *queue_conf)
+{
+ int ret;
+ struct turbo_sw_queue *q;
+ char name[RTE_RING_NAMESIZE];
+
+ /* Allocate the queue data structure. */
+ q = rte_zmalloc_socket(RTE_STR(DRIVER_NAME), sizeof(*q),
+ RTE_CACHE_LINE_SIZE, queue_conf->socket);
+ if (q == NULL) {
+ rte_bbdev_log(ERR, "Failed to allocate queue memory");
+ return -ENOMEM;
+ }
+
+ /* Allocate memory for encoder output. */
+ ret = snprintf(name, RTE_RING_NAMESIZE, RTE_STR(DRIVER_NAME)"_enc_out%u:%u",
+ dev->data->dev_id, q_id);
+ if ((ret < 0) || (ret >= (int)RTE_RING_NAMESIZE)) {
+ rte_bbdev_log(ERR,
+ "Creating queue name for device %u queue %u failed",
+ dev->data->dev_id, q_id);
+ return -ENAMETOOLONG;
+ }
+ q->enc_out = rte_zmalloc_socket(name,
+ ((MAX_TB_SIZE >> 3) + 3) * sizeof(*q->enc_out) * 3,
+ RTE_CACHE_LINE_SIZE, queue_conf->socket);
+ if (q->enc_out == NULL) {
+ rte_bbdev_log(ERR,
+ "Failed to allocate queue memory for %s", name);
+ goto free_q;
+ }
+
+ /* Allocate memory for rate matching output. */
+ ret = snprintf(name, RTE_RING_NAMESIZE,
+ RTE_STR(DRIVER_NAME)"_enc_in%u:%u", dev->data->dev_id,
+ q_id);
+ if ((ret < 0) || (ret >= (int)RTE_RING_NAMESIZE)) {
+ rte_bbdev_log(ERR,
+ "Creating queue name for device %u queue %u failed",
+ dev->data->dev_id, q_id);
+ return -ENAMETOOLONG;
+ }
+ q->enc_in = rte_zmalloc_socket(name,
+ (MAX_CB_SIZE >> 3) * sizeof(*q->enc_in),
+ RTE_CACHE_LINE_SIZE, queue_conf->socket);
+ if (q->enc_in == NULL) {
+ rte_bbdev_log(ERR,
+ "Failed to allocate queue memory for %s", name);
+ goto free_q;
+ }
+
+ /* Allocate memory for Aplha Gamma temp buffer. */
+ ret = snprintf(name, RTE_RING_NAMESIZE, RTE_STR(DRIVER_NAME)"_ag%u:%u",
+ dev->data->dev_id, q_id);
+ if ((ret < 0) || (ret >= (int)RTE_RING_NAMESIZE)) {
+ rte_bbdev_log(ERR,
+ "Creating queue name for device %u queue %u failed",
+ dev->data->dev_id, q_id);
+ return -ENAMETOOLONG;
+ }
+ q->ag = rte_zmalloc_socket(name,
+ MAX_CB_SIZE * 10 * sizeof(*q->ag),
+ RTE_CACHE_LINE_SIZE, queue_conf->socket);
+ if (q->ag == NULL) {
+ rte_bbdev_log(ERR,
+ "Failed to allocate queue memory for %s", name);
+ goto free_q;
+ }
+
+ /* Allocate memory for code block temp buffer. */
+ ret = snprintf(name, RTE_RING_NAMESIZE, RTE_STR(DRIVER_NAME)"_cb%u:%u",
+ dev->data->dev_id, q_id);
+ if ((ret < 0) || (ret >= (int)RTE_RING_NAMESIZE)) {
+ rte_bbdev_log(ERR,
+ "Creating queue name for device %u queue %u failed",
+ dev->data->dev_id, q_id);
+ return -ENAMETOOLONG;
+ }
+ q->code_block = rte_zmalloc_socket(name,
+ (6144 >> 3) * sizeof(*q->code_block),
+ RTE_CACHE_LINE_SIZE, queue_conf->socket);
+ if (q->code_block == NULL) {
+ rte_bbdev_log(ERR,
+ "Failed to allocate queue memory for %s", name);
+ goto free_q;
+ }
+
+ /* Allocate memory for Deinterleaver input. */
+ ret = snprintf(name, RTE_RING_NAMESIZE,
+ RTE_STR(DRIVER_NAME)"_deint_input%u:%u",
+ dev->data->dev_id, q_id);
+ if ((ret < 0) || (ret >= (int)RTE_RING_NAMESIZE)) {
+ rte_bbdev_log(ERR,
+ "Creating queue name for device %u queue %u failed",
+ dev->data->dev_id, q_id);
+ return -ENAMETOOLONG;
+ }
+ q->deint_input = rte_zmalloc_socket(name,
+ MAX_NCB * sizeof(*q->deint_input),
+ RTE_CACHE_LINE_SIZE, queue_conf->socket);
+ if (q->deint_input == NULL) {
+ rte_bbdev_log(ERR,
+ "Failed to allocate queue memory for %s", name);
+ goto free_q;
+ }
+
+ /* Allocate memory for Deinterleaver output. */
+ ret = snprintf(name, RTE_RING_NAMESIZE,
+ RTE_STR(DRIVER_NAME)"_deint_output%u:%u",
+ dev->data->dev_id, q_id);
+ if ((ret < 0) || (ret >= (int)RTE_RING_NAMESIZE)) {
+ rte_bbdev_log(ERR,
+ "Creating queue name for device %u queue %u failed",
+ dev->data->dev_id, q_id);
+ return -ENAMETOOLONG;
+ }
+ q->deint_output = rte_zmalloc_socket(NULL,
+ MAX_NCB * sizeof(*q->deint_output),
+ RTE_CACHE_LINE_SIZE, queue_conf->socket);
+ if (q->deint_output == NULL) {
+ rte_bbdev_log(ERR,
+ "Failed to allocate queue memory for %s", name);
+ goto free_q;
+ }
+
+ /* Allocate memory for Adapter output. */
+ ret = snprintf(name, RTE_RING_NAMESIZE,
+ RTE_STR(DRIVER_NAME)"_adapter_output%u:%u",
+ dev->data->dev_id, q_id);
+ if ((ret < 0) || (ret >= (int)RTE_RING_NAMESIZE)) {
+ rte_bbdev_log(ERR,
+ "Creating queue name for device %u queue %u failed",
+ dev->data->dev_id, q_id);
+ return -ENAMETOOLONG;
+ }
+ q->adapter_output = rte_zmalloc_socket(NULL,
+ MAX_CB_SIZE * 6 * sizeof(*q->adapter_output),
+ RTE_CACHE_LINE_SIZE, queue_conf->socket);
+ if (q->adapter_output == NULL) {
+ rte_bbdev_log(ERR,
+ "Failed to allocate queue memory for %s", name);
+ goto free_q;
+ }
+
+ /* Create ring for packets awaiting to be dequeued. */
+ ret = snprintf(name, RTE_RING_NAMESIZE, RTE_STR(DRIVER_NAME)"%u:%u",
+ dev->data->dev_id, q_id);
+ if ((ret < 0) || (ret >= (int)RTE_RING_NAMESIZE)) {
+ rte_bbdev_log(ERR,
+ "Creating queue name for device %u queue %u failed",
+ dev->data->dev_id, q_id);
+ return -ENAMETOOLONG;
+ }
+ q->processed_pkts = rte_ring_create(name, queue_conf->queue_size,
+ queue_conf->socket, RING_F_SP_ENQ | RING_F_SC_DEQ);
+ if (q->processed_pkts == NULL) {
+ rte_bbdev_log(ERR, "Failed to create ring for %s", name);
+ goto free_q;
+ }
+
+ q->type = queue_conf->op_type;
+
+ dev->data->queues[q_id].queue_private = q;
+ rte_bbdev_log_debug("setup device queue %s", name);
+ return 0;
+
+free_q:
+ rte_ring_free(q->processed_pkts);
+ rte_free(q->enc_out);
+ rte_free(q->enc_in);
+ rte_free(q->ag);
+ rte_free(q->code_block);
+ rte_free(q->deint_input);
+ rte_free(q->deint_output);
+ rte_free(q->adapter_output);
+ rte_free(q);
+ return -EFAULT;
+}
+
+static const struct rte_bbdev_ops pmd_ops = {
+ .setup_queues = NULL,
+ .intr_enable = NULL,
+ .start = NULL,
+ .stop = NULL,
+ .close = NULL,
+ .info_get = info_get,
+ .stats_get = NULL,
+ .stats_reset = NULL,
+ .queue_setup = q_setup,
+ .queue_release = q_release,
+ .queue_start = NULL,
+ .queue_stop = NULL,
+ .queue_intr_enable = NULL,
+ .queue_intr_disable = NULL
+};
+
+/* Checks if the encoder input buffer is correct.
+ * Returns 0 if it's valid, -1 otherwise.
+ */
+static inline int
+is_enc_input_valid(const uint16_t k, const int32_t k_idx,
+ const uint16_t in_length)
+{
+ if (k_idx < 0) {
+ rte_bbdev_log(ERR, "K Index is invalid");
+ return -1;
+ }
+
+ if (in_length - (k >> 3) < 0) {
+ rte_bbdev_log(ERR,
+ "Mismatch between input length (%u bytes) and K (%u bits)",
+ in_length, k);
+ return -1;
+ }
+
+ if (k > MAX_CB_SIZE) {
+ rte_bbdev_log(ERR, "CB size (%u) is too big, max: %d",
+ k, MAX_CB_SIZE);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Checks if the decoder input buffer is correct.
+ * Returns 0 if it's valid, -1 otherwise.
+ */
+static inline int
+is_dec_input_valid(int32_t k_idx, uint16_t in_length)
+{
+ if (k_idx < 0) {
+ rte_bbdev_log(ERR, "K index is invalid");
+ return -1;
+ }
+
+ if (in_length > MAX_NCB) {
+ rte_bbdev_log(ERR, "Input length (%u) is too big, max: %d",
+ in_length, MAX_NCB);
+ return -1;
+ }
+
+ return 0;
+}
+
+static inline void
+process_enc_cb(struct turbo_sw_queue *q, struct rte_bbdev_enc_op *op,
+ uint8_t cb_idx, uint8_t c, uint16_t k, uint16_t ncb,
+ uint32_t e, struct rte_mbuf *m_in, struct rte_mbuf *m_out,
+ uint16_t in_offset, uint16_t out_offset, uint16_t total_left)
+{
+ int ret;
+ int16_t k_idx;
+ uint16_t m;
+ uint8_t *in, *out0, *out1, *out2, *tmp_out, *rm_out;
+ struct rte_bbdev_op_turbo_enc *enc = &op->turbo_enc;
+ struct bblib_crc_request crc_req;
+ struct bblib_turbo_encoder_request turbo_req;
+ struct bblib_turbo_encoder_response turbo_resp;
+ struct bblib_rate_match_dl_request rm_req;
+ struct bblib_rate_match_dl_response rm_resp;
+
+ k_idx = compute_idx(k);
+ in = rte_pktmbuf_mtod_offset(m_in, uint8_t *, in_offset);
+
+ /* CRC24A (for TB) */
+ if ((enc->op_flags & RTE_BBDEV_TURBO_CRC_24A_ATTACH) &&
+ (enc->code_block_mode == 1)) {
+ ret = is_enc_input_valid(k - 24, k_idx, total_left);
+ if (ret != 0) {
+ op->status |= 1 << RTE_BBDEV_DATA_ERROR;
+ return;
+ }
+ /* copy the input to the temporary buffer to be able to extend
+ * it by 3 CRC bytes
+ */
+ rte_memcpy(q->enc_in, in, (k - 24) >> 3);
+ crc_req.data = q->enc_in;
+ crc_req.len = (k - 24) >> 3;
+ if (bblib_lte_crc24a_gen(&crc_req) == -1) {
+ op->status |= 1 << RTE_BBDEV_CRC_ERROR;
+ rte_bbdev_log(ERR, "CRC24a generation failed");
+ return;
+ }
+ in = q->enc_in;
+ } else if (enc->op_flags & RTE_BBDEV_TURBO_CRC_24B_ATTACH) {
+ /* CRC24B */
+ ret = is_enc_input_valid(k - 24, k_idx, total_left);
+ if (ret != 0) {
+ op->status |= 1 << RTE_BBDEV_DATA_ERROR;
+ return;
+ }
+ /* copy the input to the temporary buffer to be able to extend
+ * it by 3 CRC bytes
+ */
+ rte_memcpy(q->enc_in, in, (k - 24) >> 3);
+ crc_req.data = q->enc_in;
+ crc_req.len = (k - 24) >> 3;
+ if (bblib_lte_crc24b_gen(&crc_req) == -1) {
+ op->status |= 1 << RTE_BBDEV_CRC_ERROR;
+ rte_bbdev_log(ERR, "CRC24b generation failed");
+ return;
+ }
+ in = q->enc_in;
+ } else {
+ ret = is_enc_input_valid(k, k_idx, total_left);
+ if (ret != 0) {
+ op->status |= 1 << RTE_BBDEV_DATA_ERROR;
+ return;
+ }
+ }
+
+ /* Turbo encoder */
+
+ /* Each bit layer output from turbo encoder is (k+4) bits long, i.e.
+ * input length + 4 tail bits. That's (k/8) + 1 bytes after rounding up.
+ * So dst_data's length should be 3*(k/8) + 3 bytes.
+ */
+ out0 = q->enc_out;
+ out1 = RTE_PTR_ADD(out0, (k >> 3) + 1);
+ out2 = RTE_PTR_ADD(out1, (k >> 3) + 1);
+
+ turbo_req.case_id = k_idx;
+ turbo_req.input_win = in;
+ turbo_req.length = k >> 3;
+ turbo_resp.output_win_0 = out0;
+ turbo_resp.output_win_1 = out1;
+ turbo_resp.output_win_2 = out2;
+ if (bblib_turbo_encoder(&turbo_req, &turbo_resp) != 0) {
+ op->status |= 1 << RTE_BBDEV_DRV_ERROR;
+ rte_bbdev_log(ERR, "Turbo Encoder failed");
+ return;
+ }
+
+ /* Rate-matching */
+ if (enc->op_flags & RTE_BBDEV_TURBO_RATE_MATCH) {
+ /* get output data starting address */
+ rm_out = (uint8_t *)rte_pktmbuf_append(m_out, (e >> 3));
+ if (rm_out == NULL) {
+ op->status |= 1 << RTE_BBDEV_DATA_ERROR;
+ rte_bbdev_log(ERR,
+ "Too little space in output mbuf");
+ return;
+ }
+ /* rte_bbdev_op_data.offset can be different than the offset
+ * of the appended bytes
+ */
+ rm_out = rte_pktmbuf_mtod_offset(m_out, uint8_t *, out_offset);
+
+ /* index of current code block */
+ rm_req.r = cb_idx;
+ /* total number of code block */
+ rm_req.C = c;
+ /* For DL - 1, UL - 0 */
+ rm_req.direction = 1;
+ /* According to 3ggp 36.212 Spec 5.1.4.1.2 section Nsoft, KMIMO
+ * and MDL_HARQ are used for Ncb calculation. As Ncb is already
+ * known we can adjust those parameteres
+ */
+ rm_req.Nsoft = ncb * rm_req.C;
+ rm_req.KMIMO = 1;
+ rm_req.MDL_HARQ = 1;
+ /* According to 3ggp 36.212 Spec 5.1.4.1.2 section Nl, Qm and G
+ * are used for E calculation. As E is already known we can
+ * adjust those parameteres
+ */
+ rm_req.NL = e;
+ rm_req.Qm = 1;
+ rm_req.G = rm_req.NL * rm_req.Qm * rm_req.C;
+
+ rm_req.rvidx = enc->rv_index;
+ rm_req.Kidx = k_idx - 1;
+ rm_req.nLen = k + 4;
+ rm_req.tin0 = out0;
+ rm_req.tin1 = out1;
+ rm_req.tin2 = out2;
+ rm_resp.output = rm_out;
+ rm_resp.OutputLen = (e >> 3);
+ if (enc->op_flags & RTE_BBDEV_TURBO_RV_INDEX_BYPASS)
+ rm_req.bypass_rvidx = 1;
+ else
+ rm_req.bypass_rvidx = 0;
+
+ if (bblib_rate_match_dl(&rm_req, &rm_resp) != 0) {
+ op->status |= 1 << RTE_BBDEV_DRV_ERROR;
+ rte_bbdev_log(ERR, "Rate matching failed");
+ return;
+ }
+ enc->output.length += rm_resp.OutputLen;
+ } else {
+ /* Rate matching is bypassed */
+
+ /* Completing last byte of out0 (where 4 tail bits are stored)
+ * by moving first 4 bits from out1
+ */
+ tmp_out = (uint8_t *) --out1;
+ *tmp_out = *tmp_out | ((*(tmp_out + 1) & 0xF0) >> 4);
+ tmp_out++;
+ /* Shifting out1 data by 4 bits to the left */
+ for (m = 0; m < k >> 3; ++m) {
+ uint8_t *first = tmp_out;
+ uint8_t second = *(tmp_out + 1);
+ *first = (*first << 4) | ((second & 0xF0) >> 4);
+ tmp_out++;
+ }
+ /* Shifting out2 data by 8 bits to the left */
+ for (m = 0; m < (k >> 3) + 1; ++m) {
+ *tmp_out = *(tmp_out + 1);
+ tmp_out++;
+ }
+ *tmp_out = 0;
+
+ /* copy shifted output to turbo_enc entity */
+ out0 = (uint8_t *)rte_pktmbuf_append(m_out,
+ (k >> 3) * 3 + 2);
+ if (out0 == NULL) {
+ op->status |= 1 << RTE_BBDEV_DATA_ERROR;
+ rte_bbdev_log(ERR,
+ "Too little space in output mbuf");
+ return;
+ }
+ enc->output.length += (k >> 3) * 3 + 2;
+ /* rte_bbdev_op_data.offset can be different than the
+ * offset of the appended bytes
+ */
+ out0 = rte_pktmbuf_mtod_offset(m_out, uint8_t *,
+ out_offset);
+ rte_memcpy(out0, q->enc_out, (k >> 3) * 3 + 2);
+ }
+}
+
+static inline void
+enqueue_enc_one_op(struct turbo_sw_queue *q, struct rte_bbdev_enc_op *op)
+{
+ uint8_t c, r, crc24_bits = 0;
+ uint16_t k, ncb;
+ uint32_t e;
+ struct rte_bbdev_op_turbo_enc *enc = &op->turbo_enc;
+ uint16_t in_offset = enc->input.offset;
+ uint16_t out_offset = enc->output.offset;
+ struct rte_mbuf *m_in = enc->input.data;
+ struct rte_mbuf *m_out = enc->output.data;
+ uint16_t total_left = enc->input.length - in_offset;
+
+ /* Clear op status */
+ op->status = 0;
+
+ if (total_left > MAX_TB_SIZE >> 3) {
+ rte_bbdev_log(ERR, "TB size (%u) is too big, max: %d",
+ total_left, MAX_TB_SIZE);
+ op->status = 1 << RTE_BBDEV_DATA_ERROR;
+ return;
+ }
+
+ if (m_in == NULL || m_out == NULL) {
+ rte_bbdev_log(ERR, "Invalid mbuf pointer");
+ op->status = 1 << RTE_BBDEV_DATA_ERROR;
+ return;
+ }
+
+ if ((enc->op_flags & RTE_BBDEV_TURBO_CRC_24B_ATTACH) ||
+ (enc->op_flags & RTE_BBDEV_TURBO_CRC_24A_ATTACH))
+ crc24_bits = 24;
+
+ if (enc->code_block_mode == 0) { /* For Transport Block mode */
+ c = enc->tb_params.c;
+ r = enc->tb_params.r;
+
+ } else {/* For Code Block mode */
+ c = 1;
+ r = 0;
+ }
+
+ while (total_left > 0 && r < c) {
+ if (enc->code_block_mode == 0) {
+ k = (r < enc->tb_params.c_neg) ?
+ enc->tb_params.k_neg : enc->tb_params.k_pos;
+ ncb = (r < enc->tb_params.c_neg) ?
+ enc->tb_params.ncb_neg : enc->tb_params.ncb_pos;
+ e = (r < enc->tb_params.cab) ?
+ enc->tb_params.ea : enc->tb_params.eb;
+ } else {
+ k = enc->cb_params.k;
+ ncb = enc->cb_params.ncb;
+ e = enc->cb_params.e;
+ }
+
+ process_enc_cb(q, op, r, c, k, ncb, e, m_in,
+ m_out, in_offset, out_offset, total_left);
+ /* Update total_left */
+ total_left -= (k - crc24_bits) >> 3;
+ /* Update offsets for next CBs (if exist) */
+ in_offset += (k - crc24_bits) >> 3;
+ if (enc->op_flags & RTE_BBDEV_TURBO_RATE_MATCH)
+ out_offset += e >> 3;
+ else
+ out_offset += (k >> 3) * 3 + 2;
+ r++;
+ }
+
+ /* check if all input data was processed */
+ if (total_left != 0) {
+ op->status |= 1 << RTE_BBDEV_DATA_ERROR;
+ rte_bbdev_log(ERR,
+ "Mismatch between mbuf length and included CBs sizes");
+ }
+}
+
+static inline uint16_t
+enqueue_enc_all_ops(struct turbo_sw_queue *q, struct rte_bbdev_enc_op **ops,
+ uint16_t nb_ops)
+{
+ uint16_t i;
+
+ for (i = 0; i < nb_ops; ++i)
+ enqueue_enc_one_op(q, ops[i]);
+
+ return rte_ring_enqueue_burst(q->processed_pkts, (void **)ops, nb_ops,
+ NULL);
+}
+
+/* Remove the padding bytes from a cyclic buffer.
+ * The input buffer is a data stream wk as described in 3GPP TS 36.212 section
+ * 5.1.4.1.2 starting from w0 and with length Ncb bytes.
+ * The output buffer is a data stream wk with pruned padding bytes. It's length
+ * is 3*D bytes and the order of non-padding bytes is preserved.
+ */
+static inline void
+remove_nulls_from_circular_buf(const uint8_t *in, uint8_t *out, uint16_t k,
+ uint16_t ncb)
+{
+ uint32_t in_idx, out_idx, c_idx;
+ const uint32_t d = k + 4;
+ const uint32_t kw = (ncb / 3);
+ const uint32_t nd = kw - d;
+ const uint32_t r_subblock = kw / C_SUBBLOCK;
+ /* Inter-column permutation pattern */
+ const uint32_t P[C_SUBBLOCK] = {0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10,
+ 26, 6, 22, 14, 30, 1, 17, 9, 25, 5, 21, 13, 29, 3, 19,
+ 11, 27, 7, 23, 15, 31};
+ in_idx = 0;
+ out_idx = 0;
+
+ /* The padding bytes are at the first Nd positions in the first row. */
+ for (c_idx = 0; in_idx < kw; in_idx += r_subblock, ++c_idx) {
+ if (P[c_idx] < nd) {
+ rte_memcpy(&out[out_idx], &in[in_idx + 1],
+ r_subblock - 1);
+ out_idx += r_subblock - 1;
+ } else {
+ rte_memcpy(&out[out_idx], &in[in_idx], r_subblock);
+ out_idx += r_subblock;
+ }
+ }
+
+ /* First and second parity bits sub-blocks are interlaced. */
+ for (c_idx = 0; in_idx < ncb - 2 * r_subblock;
+ in_idx += 2 * r_subblock, ++c_idx) {
+ uint32_t second_block_c_idx = P[c_idx];
+ uint32_t third_block_c_idx = P[c_idx] + 1;
+
+ if (second_block_c_idx < nd && third_block_c_idx < nd) {
+ rte_memcpy(&out[out_idx], &in[in_idx + 2],
+ 2 * r_subblock - 2);
+ out_idx += 2 * r_subblock - 2;
+ } else if (second_block_c_idx >= nd &&
+ third_block_c_idx >= nd) {
+ rte_memcpy(&out[out_idx], &in[in_idx], 2 * r_subblock);
+ out_idx += 2 * r_subblock;
+ } else if (second_block_c_idx < nd) {
+ out[out_idx++] = in[in_idx];
+ in_idx += 2;
+ rte_memcpy(&out[out_idx], &in[in_idx],
+ 2 * r_subblock - 2);
+ out_idx += 2 * r_subblock - 2;
+ } else {
+ ++in_idx;
+ rte_memcpy(&out[out_idx], &in[in_idx],
+ 2 * r_subblock - 1);
+ out_idx += 2 * r_subblock - 1;
+ }
+ }
+
+ /* Last interlaced row is different - its last byte is the only padding
+ * byte. We can have from 2 up to 26 padding bytes (Nd) per sub-block.
+ * After interlacing the 1st and 2nd parity sub-blocks we can have 0, 1
+ * or 2 padding bytes each time we make a step of 2 * R_SUBBLOCK bytes
+ * (moving to another column). 2nd parity sub-block uses the same
+ * inter-column permutation pattern as the systematic and 1st parity
+ * sub-blocks but it adds '1' to the resulting index and calculates the
+ * modulus of the result and Kw. Last column is mapped to itself (id 31)
+ * so the first byte taken from the 2nd parity sub-block will be the
+ * 32nd (31+1) byte, then 64th etc. (step is C_SUBBLOCK == 32) and the
+ * last byte will be the first byte from the sub-block:
+ * (32 + 32 * (R_SUBBLOCK-1)) % Kw == Kw % Kw == 0. Nd can't be smaller
+ * than 2 so we know that bytes with ids 0 and 1 must be the padding
+ * bytes. The bytes from the 1st parity sub-block are the bytes from the
+ * 31st column - Nd can't be greater than 26 so we are sure that there
+ * are no padding bytes in 31st column.
+ */
+ rte_memcpy(&out[out_idx], &in[in_idx], 2 * r_subblock - 1);
+}
+
+static inline void
+process_dec_cb(struct turbo_sw_queue *q, struct rte_bbdev_dec_op *op,
+ uint8_t c, uint16_t k, struct rte_mbuf *m_in,
+ struct rte_mbuf *m_out, uint16_t in_offset, uint16_t out_offset,
+ bool check_crc_24b, uint16_t *total_left)
+{
+ int ret;
+ int32_t k_idx;
+ uint16_t in_length;
+ int32_t iter_cnt;
+ uint8_t *in, *out, *adapter_input;
+ int32_t ncb, ncb_without_null;
+ struct bblib_turbo_adapter_ul_response adapter_resp;
+ struct bblib_turbo_adapter_ul_request adapter_req;
+ struct bblib_turbo_decoder_request turbo_req;
+ struct bblib_turbo_decoder_response turbo_resp;
+ struct rte_bbdev_op_turbo_dec *dec = &op->turbo_dec;
+
+ k_idx = compute_idx(k);
+
+ in_length = (*total_left >= (m_in->data_len - in_offset)) ?
+ m_in->data_len - in_offset : *total_left;
+ *total_left -= in_length;
+
+ ret = is_dec_input_valid(k_idx, in_length);
+ if (ret != 0) {
+ op->status |= 1 << RTE_BBDEV_DATA_ERROR;
+ return;
+ }
+
+ in = rte_pktmbuf_mtod_offset(m_in, uint8_t *, in_offset);
+ adapter_input = in;
+ ncb = ncb_without_null = in_length;
+
+ if (check_bit(dec->op_flags, RTE_BBDEV_TURBO_SUBBLOCK_DEINTERLEAVE)) {
+ struct bblib_deinterleave_ul_request deint_req;
+ struct bblib_deinterleave_ul_response deint_resp;
+
+ /* SW decoder accpets only a circular buffer without NULL bytes
+ * so the input needs to be converted.
+ */
+ remove_nulls_from_circular_buf(in, q->deint_input, k, ncb);
+
+ ncb_without_null = (k + 4) * 3;
+ deint_req.pharqbuffer = q->deint_input;
+ deint_req.ncb = ncb_without_null;
+ deint_resp.pinteleavebuffer = q->deint_output;
+ bblib_deinterleave_ul(&deint_req, &deint_resp);
+ adapter_input = q->deint_output;
+ }
+
+ if (dec->op_flags & RTE_BBDEV_TURBO_POS_LLR_1_BIT_IN)
+ adapter_req.isinverted = 1;
+ else if (dec->op_flags & RTE_BBDEV_TURBO_NEG_LLR_1_BIT_IN)
+ adapter_req.isinverted = 0;
+ else {
+ op->status |= 1 << RTE_BBDEV_DRV_ERROR;
+ rte_bbdev_log(ERR, "LLR format wasn't specified");
+ return;
+ }
+
+ adapter_req.ncb = ncb_without_null;
+ adapter_req.pinteleavebuffer = adapter_input;
+ adapter_resp.pharqout = q->adapter_output;
+ bblib_turbo_adapter_ul(&adapter_req, &adapter_resp);
+
+ out = (uint8_t *)rte_pktmbuf_append(m_out, (k >> 3));
+ if (out == NULL) {
+ op->status |= 1 << RTE_BBDEV_DATA_ERROR;
+ rte_bbdev_log(ERR, "Too little space in output mbuf");
+ return;
+ }
+ /* rte_bbdev_op_data.offset can be different than the offset of the
+ * appended bytes
+ */
+ out = rte_pktmbuf_mtod_offset(m_out, uint8_t *, out_offset);
+ if (check_crc_24b)
+ turbo_req.c = c + 1;
+ else
+ turbo_req.c = c;
+ turbo_req.input = (int8_t *)q->adapter_output;
+ turbo_req.k = k;
+ turbo_req.k_idx = k_idx;
+ turbo_req.max_iter_num = dec->iter_max;
+ turbo_req.early_term_disable = !check_bit(dec->op_flags,
+ RTE_BBDEV_TURBO_EARLY_TERMINATION);
+ turbo_resp.ag_buf = q->ag;
+ turbo_resp.cb_buf = q->code_block;
+ turbo_resp.output = out;
+ iter_cnt = bblib_turbo_decoder(&turbo_req, &turbo_resp);
+
+ dec->hard_output.length += (k >> 3);
+
+ if (iter_cnt > 0)
+ dec->iter_count = RTE_MAX(iter_cnt, dec->iter_count);
+ else {
+ op->status |= 1 << RTE_BBDEV_DATA_ERROR;
+ rte_bbdev_log(ERR, "Turbo Decoder failed");
+ return;
+ }
+}
+
+static inline void
+enqueue_dec_one_op(struct turbo_sw_queue *q, struct rte_bbdev_dec_op *op)
+{
+ uint8_t cb_idx = 0;
+ uint8_t cb_total, c_neg;
+ uint16_t k_pos, k_neg, k;
+ struct rte_bbdev_op_turbo_dec *dec = &op->turbo_dec;
+ struct rte_mbuf *m_in = dec->input.data;
+ struct rte_mbuf *m_out = dec->hard_output.data;
+ struct rte_mbuf *m_out_next;
+ uint16_t total_left = dec->input.length;
+ uint16_t in_offset = dec->input.offset;
+ uint16_t out_offset = dec->hard_output.offset;
+
+ if (dec->code_block_mode == 0) { /* For Transport Block mode */
+ k_pos = dec->tb_params.k_pos;
+ k_neg = dec->tb_params.k_neg;
+ cb_total = dec->tb_params.c;
+ c_neg = dec->tb_params.c_neg;
+ k = (cb_idx < c_neg) ? k_neg : k_pos;
+ } else { /* For Code Block mode */
+ k = dec->cb_params.k;
+ cb_total = 1;
+ }
+
+ /* Clear op status */
+ op->status = 0;
+
+ if (m_in == NULL || m_out == NULL) {
+ rte_bbdev_log(ERR, "Invalid mbuf pointer");
+ op->status = 1 << RTE_BBDEV_DATA_ERROR;
+ return;
+ }
+
+ process_dec_cb(q, op, cb_total, k, m_in, m_out, in_offset, out_offset,
+ check_bit(dec->op_flags, RTE_BBDEV_TURBO_CRC_TYPE_24B),
+ &total_left);
+
+ for (cb_idx = 1; cb_idx < cb_total; ++cb_idx) {
+ k = (cb_idx < c_neg) ? k_neg : k_pos;
+
+ m_in = m_in->next;
+ m_out_next = rte_pktmbuf_alloc(m_out->pool);
+ if (m_in == NULL || m_out_next == NULL) {
+ rte_bbdev_log(ERR, "Invalid mbuf pointer");
+ op->status |= 1 << RTE_BBDEV_DATA_ERROR;
+ return;
+ }
+ rte_pktmbuf_chain(m_out, m_out_next);
+
+ process_dec_cb(q, op, cb_total, k, m_in, m_out_next, in_offset,
+ out_offset, check_bit(dec->op_flags,
+ RTE_BBDEV_TURBO_CRC_TYPE_24B), &total_left);
+ }
+ if (total_left != 0) {
+ op->status |= 1 << RTE_BBDEV_DATA_ERROR;
+ rte_bbdev_log(ERR,
+ "Mismatch between rte_bbdev_op_data.length and mbuf data");
+ }
+}
+
+static inline uint16_t
+enqueue_dec_all_ops(struct turbo_sw_queue *q, struct rte_bbdev_dec_op **ops,
+ uint16_t nb_ops)
+{
+ uint16_t i;
+
+ for (i = 0; i < nb_ops; ++i)
+ enqueue_dec_one_op(q, ops[i]);
+
+ return rte_ring_enqueue_burst(q->processed_pkts, (void **)ops, nb_ops,
+ NULL);
+}
+
+/* Enqueue burst */
+static uint16_t
+enqueue_enc_ops(struct rte_bbdev_queue_data *q_data,
+ struct rte_bbdev_enc_op **ops, uint16_t nb_ops)
+{
+ void *queue = q_data->queue_private;
+ struct turbo_sw_queue *q = queue;
+ uint16_t nb_enqueued = 0;
+
+ nb_enqueued = enqueue_enc_all_ops(q, ops, nb_ops);
+
+ q_data->queue_stats.enqueue_err_count += nb_ops - nb_enqueued;
+ q_data->queue_stats.enqueued_count += nb_enqueued;
+
+ return nb_enqueued;
+}
+
+/* Enqueue burst */
+static uint16_t
+enqueue_dec_ops(struct rte_bbdev_queue_data *q_data,
+ struct rte_bbdev_dec_op **ops, uint16_t nb_ops)
+{
+ void *queue = q_data->queue_private;
+ struct turbo_sw_queue *q = queue;
+ uint16_t nb_enqueued = 0;
+
+ nb_enqueued = enqueue_dec_all_ops(q, ops, nb_ops);
+
+ q_data->queue_stats.enqueue_err_count += nb_ops - nb_enqueued;
+ q_data->queue_stats.enqueued_count += nb_enqueued;
+
+ return nb_enqueued;
+}
+
+/* Dequeue decode burst */
+static uint16_t
+dequeue_dec_ops(struct rte_bbdev_queue_data *q_data,
+ struct rte_bbdev_dec_op **ops, uint16_t nb_ops)
+{
+ struct turbo_sw_queue *q = q_data->queue_private;
+ uint16_t nb_dequeued = rte_ring_dequeue_burst(q->processed_pkts,
+ (void **)ops, nb_ops, NULL);
+ q_data->queue_stats.dequeued_count += nb_dequeued;
+
+ return nb_dequeued;
+}
+
+/* Dequeue encode burst */
+static uint16_t
+dequeue_enc_ops(struct rte_bbdev_queue_data *q_data,
+ struct rte_bbdev_enc_op **ops, uint16_t nb_ops)
+{
+ struct turbo_sw_queue *q = q_data->queue_private;
+ uint16_t nb_dequeued = rte_ring_dequeue_burst(q->processed_pkts,
+ (void **)ops, nb_ops, NULL);
+ q_data->queue_stats.dequeued_count += nb_dequeued;
+
+ return nb_dequeued;
+}
+
+/* Parse 16bit integer from string argument */
+static inline int
+parse_u16_arg(const char *key, const char *value, void *extra_args)
+{
+ uint16_t *u16 = extra_args;
+ unsigned int long result;
+
+ if ((value == NULL) || (extra_args == NULL))
+ return -EINVAL;
+ errno = 0;
+ result = strtoul(value, NULL, 0);
+ if ((result >= (1 << 16)) || (errno != 0)) {
+ rte_bbdev_log(ERR, "Invalid value %lu for %s", result, key);
+ return -ERANGE;
+ }
+ *u16 = (uint16_t)result;
+ return 0;
+}
+
+/* Parse parameters used to create device */
+static int
+parse_turbo_sw_params(struct turbo_sw_params *params, const char *input_args)
+{
+ struct rte_kvargs *kvlist = NULL;
+ int ret = 0;
+
+ if (params == NULL)
+ return -EINVAL;
+ if (input_args) {
+ kvlist = rte_kvargs_parse(input_args, turbo_sw_valid_params);
+ if (kvlist == NULL)
+ return -EFAULT;
+
+ ret = rte_kvargs_process(kvlist, turbo_sw_valid_params[0],
+ &parse_u16_arg, ¶ms->queues_num);
+ if (ret < 0)
+ goto exit;
+
+ ret = rte_kvargs_process(kvlist, turbo_sw_valid_params[1],
+ &parse_u16_arg, ¶ms->socket_id);
+ if (ret < 0)
+ goto exit;
+
+ if (params->socket_id >= RTE_MAX_NUMA_NODES) {
+ rte_bbdev_log(ERR, "Invalid socket, must be < %u",
+ RTE_MAX_NUMA_NODES);
+ goto exit;
+ }
+ }
+
+exit:
+ if (kvlist)
+ rte_kvargs_free(kvlist);
+ return ret;
+}
+
+/* Create device */
+static int
+turbo_sw_bbdev_create(struct rte_vdev_device *vdev,
+ struct turbo_sw_params *init_params)
+{
+ struct rte_bbdev *bbdev;
+ const char *name = rte_vdev_device_name(vdev);
+
+ bbdev = rte_bbdev_allocate(name);
+ if (bbdev == NULL)
+ return -ENODEV;
+
+ bbdev->data->dev_private = rte_zmalloc_socket(name,
+ sizeof(struct bbdev_private), RTE_CACHE_LINE_SIZE,
+ init_params->socket_id);
+ if (bbdev->data->dev_private == NULL) {
+ rte_bbdev_release(bbdev);
+ return -ENOMEM;
+ }
+
+ bbdev->dev_ops = &pmd_ops;
+ bbdev->device = &vdev->device;
+ bbdev->data->socket_id = init_params->socket_id;
+ bbdev->intr_handle = NULL;
+
+ /* register rx/tx burst functions for data path */
+ bbdev->dequeue_enc_ops = dequeue_enc_ops;
+ bbdev->dequeue_dec_ops = dequeue_dec_ops;
+ bbdev->enqueue_enc_ops = enqueue_enc_ops;
+ bbdev->enqueue_dec_ops = enqueue_dec_ops;
+ ((struct bbdev_private *) bbdev->data->dev_private)->max_nb_queues =
+ init_params->queues_num;
+
+ return 0;
+}
+
+/* Initialise device */
+static int
+turbo_sw_bbdev_probe(struct rte_vdev_device *vdev)
+{
+ struct turbo_sw_params init_params = {
+ rte_socket_id(),
+ RTE_BBDEV_DEFAULT_MAX_NB_QUEUES
+ };
+ const char *name;
+ const char *input_args;
+
+ if (vdev == NULL)
+ return -EINVAL;
+
+ name = rte_vdev_device_name(vdev);
+ if (name == NULL)
+ return -EINVAL;
+ input_args = rte_vdev_device_args(vdev);
+ parse_turbo_sw_params(&init_params, input_args);
+
+ rte_bbdev_log_debug(
+ "Initialising %s on NUMA node %d with max queues: %d\n",
+ name, init_params.socket_id, init_params.queues_num);
+
+ return turbo_sw_bbdev_create(vdev, &init_params);
+}
+
+/* Uninitialise device */
+static int
+turbo_sw_bbdev_remove(struct rte_vdev_device *vdev)
+{
+ struct rte_bbdev *bbdev;
+ const char *name;
+
+ if (vdev == NULL)
+ return -EINVAL;
+
+ name = rte_vdev_device_name(vdev);
+ if (name == NULL)
+ return -EINVAL;
+
+ bbdev = rte_bbdev_get_named_dev(name);
+ if (bbdev == NULL)
+ return -EINVAL;
+
+ rte_free(bbdev->data->dev_private);
+
+ return rte_bbdev_release(bbdev);
+}
+
+static struct rte_vdev_driver bbdev_turbo_sw_pmd_drv = {
+ .probe = turbo_sw_bbdev_probe,
+ .remove = turbo_sw_bbdev_remove
+};
+
+RTE_PMD_REGISTER_VDEV(DRIVER_NAME, bbdev_turbo_sw_pmd_drv);
+RTE_PMD_REGISTER_ALIAS(DRIVER_NAME, bbdev_turbo_sw_pmd);
+RTE_PMD_REGISTER_PARAM_STRING(DRIVER_NAME,
+ TURBO_SW_MAX_NB_QUEUES_ARG"=<int> "
+ TURBO_SW_SOCKET_ID_ARG"=<int>");
+
+int bbdev_logtype;
+RTE_INIT(null_bbdev_init_log);
+static void
+null_bbdev_init_log(void)
+{
+ bbdev_logtype = rte_log_register("pmd.turbo_sw");
+ if (bbdev_logtype >= 0)
+ rte_log_set_level(bbdev_logtype, RTE_LOG_NOTICE);
+}
diff --git a/drivers/bbdev/turbo_sw/rte_pmd_bbdev_turbo_sw_version.map b/drivers/bbdev/turbo_sw/rte_pmd_bbdev_turbo_sw_version.map
new file mode 100644
index 0000000..58b9427
--- /dev/null
+++ b/drivers/bbdev/turbo_sw/rte_pmd_bbdev_turbo_sw_version.map
@@ -0,0 +1,3 @@
+DPDK_18.02 {
+ local: *;
+};
--
2.7.4
^ permalink raw reply [flat|nested] 16+ messages in thread
* [dpdk-dev] [PATCH v3 3/5] bbdev: test applications
2017-12-07 21:40 [dpdk-dev] [PATCH v3 1/5] bbdev: librte_bbdev library Amr Mokhtar
2017-12-07 21:40 ` [dpdk-dev] [PATCH v3 2/5] bbdev: PMD drivers (null/turbo_sw) Amr Mokhtar
@ 2017-12-07 21:40 ` Amr Mokhtar
2017-12-11 19:01 ` Ferruh Yigit
2017-12-07 21:40 ` [dpdk-dev] [PATCH v3 4/5] bbdev: sample app Amr Mokhtar
` (3 subsequent siblings)
5 siblings, 1 reply; 16+ messages in thread
From: Amr Mokhtar @ 2017-12-07 21:40 UTC (permalink / raw)
To: dev
Cc: thomas, anatoly.burakov, pablo.de.lara.guarch, niall.power,
chris.macnamara, Amr Mokhtar
- 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>
---
app/Makefile | 4 +
app/test-bbdev/Makefile | 53 +
app/test-bbdev/main.c | 353 ++++
app/test-bbdev/main.h | 148 ++
app/test-bbdev/test-bbdev.py | 139 ++
app/test-bbdev/test_bbdev.c | 1406 +++++++++++++
app/test-bbdev/test_bbdev_perf.c | 2193 ++++++++++++++++++++
app/test-bbdev/test_bbdev_vector.c | 963 +++++++++
app/test-bbdev/test_bbdev_vector.h | 99 +
app/test-bbdev/test_vectors/bbdev_vector_null.data | 32 +
.../test_vectors/bbdev_vector_td_default.data | 81 +
.../test_vectors/bbdev_vector_te_default.data | 60 +
12 files changed, 5531 insertions(+)
create mode 100644 app/test-bbdev/Makefile
create mode 100644 app/test-bbdev/main.c
create mode 100644 app/test-bbdev/main.h
create mode 100755 app/test-bbdev/test-bbdev.py
create mode 100644 app/test-bbdev/test_bbdev.c
create mode 100644 app/test-bbdev/test_bbdev_perf.c
create mode 100644 app/test-bbdev/test_bbdev_vector.c
create mode 100644 app/test-bbdev/test_bbdev_vector.h
create mode 100644 app/test-bbdev/test_vectors/bbdev_vector_null.data
create mode 100644 app/test-bbdev/test_vectors/bbdev_vector_td_default.data
create mode 100644 app/test-bbdev/test_vectors/bbdev_vector_te_default.data
diff --git a/app/Makefile b/app/Makefile
index 7ea02b0..6b0ed67 100644
--- a/app/Makefile
+++ b/app/Makefile
@@ -43,4 +43,8 @@ ifeq ($(CONFIG_RTE_LIBRTE_EVENTDEV),y)
DIRS-$(CONFIG_RTE_APP_EVENTDEV) += test-eventdev
endif
+ifeq ($(CONFIG_RTE_LIBRTE_BBDEV),y)
+DIRS-$(CONFIG_RTE_TEST_BBDEV) += test-bbdev
+endif
+
include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/app/test-bbdev/Makefile b/app/test-bbdev/Makefile
new file mode 100644
index 0000000..29c9be5
--- /dev/null
+++ b/app/test-bbdev/Makefile
@@ -0,0 +1,53 @@
+# BSD LICENSE
+#
+# Copyright(c) 2017 Intel Corporation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifeq ($(CONFIG_RTE_TEST_BBDEV),y)
+
+#
+# library name
+#
+APP = testbbdev
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+#
+# all sources are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_BBDEV) += main.c
+SRCS-$(CONFIG_RTE_LIBRTE_BBDEV) += test_bbdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_BBDEV) += test_bbdev_perf.c
+SRCS-$(CONFIG_RTE_LIBRTE_BBDEV) += test_bbdev_vector.c
+
+include $(RTE_SDK)/mk/rte.app.mk
+
+endif
diff --git a/app/test-bbdev/main.c b/app/test-bbdev/main.c
new file mode 100644
index 0000000..d3e07a6
--- /dev/null
+++ b/app/test-bbdev/main.c
@@ -0,0 +1,353 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#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
index 0000000..6c60759
--- /dev/null
+++ b/app/test-bbdev/main.h
@@ -0,0 +1,148 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#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
index 0000000..cf7d619
--- /dev/null
+++ b/app/test-bbdev/test-bbdev.py
@@ -0,0 +1,139 @@
+#!/usr/bin/env python
+
+# BSD LICENSE
+#
+# Copyright(c) 2017 Intel Corporation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+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
index 0000000..b4cd67e
--- /dev/null
+++ b/app/test-bbdev/test_bbdev.c
@@ -0,0 +1,1406 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#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 = 7;
+ 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
index 0000000..e46540e
--- /dev/null
+++ b/app/test-bbdev/test_bbdev_perf.c
@@ -0,0 +1,2193 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#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>
+
+#ifdef RTE_LIBRTE_PMD_TIP
+#include <rte_tip_pmd.h>
+#endif
+
+#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
+
+#ifdef RTE_LIBRTE_PMD_TIP
+#define TIPPF_DRIVER_NAME ("intel_tip_pf")
+#define TIPVF_DRIVER_NAME ("intel_tip_vf")
+#define CFG_FILE_NAME ("tip_config.cfg")
+#define RTE_TIP_CONFIG_FILE "RTE_TIP_CONFIG_FILE"
+#endif
+
+#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];
+
+ 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));
+ snprintf(pool_name, sizeof(pool_name), "%s_pool_%u",
+ rte_bbdev_op_type_str(op_type), 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;
+
+#ifdef RTE_LIBRTE_PMD_TIP
+ if (!strcmp(info->drv.driver_name, TIPPF_DRIVER_NAME)) {
+ struct rte_tip_conf tip_conf;
+ const char *cfg_file_name = getenv(RTE_TIP_CONFIG_FILE);
+
+ if (cfg_file_name == NULL) {
+ cfg_file_name = CFG_FILE_NAME;
+ printf(
+ "RTE_TIP_CONFIG_FILE was not set. %s will be used\n",
+ cfg_file_name);
+ }
+ ret = rte_tip_parse_conf_file(cfg_file_name, &tip_conf);
+ TEST_ASSERT_SUCCESS(ret, "Failed to parse TIP config file");
+
+ /* setup TIP PF */
+ ret = rte_tip_configure(info->dev_name, &tip_conf);
+ TEST_ASSERT_SUCCESS(ret,
+ "Failed to configure TIP PF for TIP bbdev %s",
+ info->dev_name);
+
+ /* re-get info after it is updated */
+ rte_bbdev_info_get(dev_id, info);
+
+ /* re-check device capabilities - some options are disabled
+ * after device configuration
+ */
+ if (check_dev_cap(info)) {
+ printf(
+ "Device %d (%s) does not support specified capabilities\n",
+ dev_id, info->dev_name);
+ return -1;
+ }
+ }
+#endif
+
+ 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;
+
+#ifdef RTE_LIBRTE_PMD_TIP
+ struct rte_tip_deq_intr_details *intr_det = ret_param;
+ queue_id = intr_det->queue_id;
+#else
+ RTE_SET_USED(ret_param);
+#endif
+
+ /* 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[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, 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, 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, num_to_enq);
+ }
+do_dequeue:
+ deq = rte_bbdev_dequeue_dec_ops(tp->dev_id, queue_id, ops,
+ burst_sz);
+ dequeued += deq;
+ rte_bbdev_dec_op_free_bulk(ops, 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[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, 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, num_to_enq, enqueued,
+ bufs->inputs,
+ bufs->hard_outputs,
+ ref_op);
+
+ enqueued += rte_bbdev_enqueue_enc_ops(tp->dev_id,
+ queue_id, ops, num_to_enq);
+ }
+do_dequeue:
+ deq = rte_bbdev_dequeue_enc_ops(tp->dev_id, queue_id, ops,
+ burst_sz);
+ dequeued += deq;
+ rte_bbdev_enc_op_free_bulk(ops, 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;
+
+ rte_bbdev_info_get(ad->dev_id, &info);
+
+ 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,
+ rte_bbdev_op_type_str(test_vector.op_type),
+ 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[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, burst_sz);
+ if (test_vector.op_type != RTE_BBDEV_OP_NONE)
+ copy_reference_dec_op(ops, 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[j]->opaque_data = (void *)(uintptr_t)j;
+
+ start_time = rte_rdtsc_precise();
+
+ enq = rte_bbdev_enqueue_dec_ops(dev_id, queue_id, &ops[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], 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, burst_sz, ref_op,
+ vector_mask);
+ TEST_ASSERT_SUCCESS(ret, "Validation failed!");
+ }
+
+ rte_bbdev_dec_op_free_bulk(ops, 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[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, burst_sz);
+ if (test_vector.op_type != RTE_BBDEV_OP_NONE)
+ copy_reference_enc_op(ops, burst_sz, dequeued,
+ bufs->inputs,
+ bufs->hard_outputs,
+ ref_op);
+
+ /* Set counter to validate the ordering */
+ for (j = 0; j < burst_sz; ++j)
+ ops[j]->opaque_data = (void *)(uintptr_t)j;
+
+ start_time = rte_rdtsc_precise();
+
+ enq = rte_bbdev_enqueue_enc_ops(dev_id, queue_id, &ops[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], 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, burst_sz, ref_op);
+ TEST_ASSERT_SUCCESS(ret, "Validation failed!");
+ }
+
+ rte_bbdev_enc_op_free_bulk(ops, 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;
+
+ 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];
+
+ printf(
+ "Validation/Latency test: dev: %s, burst size: %u, num ops: %u, op type: %s\n",
+ info.dev_name, burst_sz, num_to_process,
+ rte_bbdev_op_type_str(op_type));
+
+ 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[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, burst_sz);
+ if (test_vector.op_type != RTE_BBDEV_OP_NONE)
+ copy_reference_dec_op(ops, 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], 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], burst_sz - deq);
+ } while (unlikely(burst_sz != deq));
+ *deq_total_time += rte_rdtsc() - deq_start_time;
+
+ rte_bbdev_dec_op_free_bulk(ops, 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[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, burst_sz);
+ if (test_vector.op_type != RTE_BBDEV_OP_NONE)
+ copy_reference_enc_op(ops, 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], 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], burst_sz - deq);
+ } while (unlikely(burst_sz != deq));
+ *deq_total_time += rte_rdtsc() - deq_start_time;
+
+ rte_bbdev_enc_op_free_bulk(ops, 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;
+
+ 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];
+
+ printf(
+ "Offload latency test: dev: %s, burst size: %u, num ops: %u, op type: %s\n",
+ info.dev_name, burst_sz, num_to_process,
+ rte_bbdev_op_type_str(op_type));
+
+ 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;
+
+ TEST_ASSERT_SUCCESS((burst_sz > MAX_BURST),
+ "BURST_SIZE should be <= %u", MAX_BURST);
+
+ rte_bbdev_info_get(ad->dev_id, &info);
+
+ 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,
+ rte_bbdev_op_type_str(op_type));
+
+ 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
index 0000000..8d8596b
--- /dev/null
+++ b/app/test-bbdev/test_bbdev_vector.c
@@ -0,0 +1,963 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#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 {
+ 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
index 0000000..7f41d20
--- /dev/null
+++ b/app/test-bbdev/test_bbdev_vector.h
@@ -0,0 +1,99 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#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
index 0000000..91aea62
--- /dev/null
+++ b/app/test-bbdev/test_vectors/bbdev_vector_null.data
@@ -0,0 +1,32 @@
+# BSD LICENSE
+#
+# Copyright(c) 2017 Intel Corporation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+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
index 0000000..d69ca6b
--- /dev/null
+++ b/app/test-bbdev/test_vectors/bbdev_vector_td_default.data
@@ -0,0 +1,81 @@
+# BSD LICENSE
+#
+# Copyright(c) 2017 Intel Corporation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+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
index 0000000..b5cecf4
--- /dev/null
+++ b/app/test-bbdev/test_vectors/bbdev_vector_te_default.data
@@ -0,0 +1,60 @@
+# BSD LICENSE
+#
+# Copyright(c) 2017 Intel Corporation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+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
--
2.7.4
^ permalink raw reply [flat|nested] 16+ messages in thread
* [dpdk-dev] [PATCH v3 4/5] bbdev: sample app
2017-12-07 21:40 [dpdk-dev] [PATCH v3 1/5] bbdev: librte_bbdev library Amr Mokhtar
2017-12-07 21:40 ` [dpdk-dev] [PATCH v3 2/5] bbdev: PMD drivers (null/turbo_sw) Amr Mokhtar
2017-12-07 21:40 ` [dpdk-dev] [PATCH v3 3/5] bbdev: test applications Amr Mokhtar
@ 2017-12-07 21:40 ` Amr Mokhtar
2017-12-07 21:40 ` [dpdk-dev] [PATCH v3 5/5] bbdev: documentation Amr Mokhtar
` (2 subsequent siblings)
5 siblings, 0 replies; 16+ messages in thread
From: Amr Mokhtar @ 2017-12-07 21:40 UTC (permalink / raw)
To: dev
Cc: thomas, anatoly.burakov, pablo.de.lara.guarch, niall.power,
chris.macnamara, Amr Mokhtar
- Sample application performing a loop-back over ethernet using
a bbbdev device
- A packet is received on an Rx ethdev port -> enqueued for baseband
operation -> dequeued -> looped-back to a Tx ethdev port
- 'Turbo_sw' PMD must be enabled for the app to be functional
Signed-off-by: Amr Mokhtar <amr.mokhtar@intel.com>
---
examples/Makefile | 1 +
examples/bbdev_app/Makefile | 50 ++
examples/bbdev_app/main.c | 1452 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 1503 insertions(+)
create mode 100644 examples/bbdev_app/Makefile
create mode 100644 examples/bbdev_app/main.c
diff --git a/examples/Makefile b/examples/Makefile
index 9f7974a..26bf256 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -61,6 +61,7 @@ ifneq ($(PQOS_INSTALL_PATH),)
DIRS-y += l2fwd-cat
endif
DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += l2fwd-crypto
+DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) += bbdev_app
DIRS-$(CONFIG_RTE_LIBRTE_JOBSTATS) += l2fwd-jobstats
DIRS-y += l2fwd-keepalive
DIRS-y += l2fwd-keepalive/ka-agent
diff --git a/examples/bbdev_app/Makefile b/examples/bbdev_app/Makefile
new file mode 100644
index 0000000..1583251
--- /dev/null
+++ b/examples/bbdev_app/Makefile
@@ -0,0 +1,50 @@
+# BSD LICENSE
+#
+# Copyright(c) 2017 Intel Corporation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overridden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = bbdev
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/bbdev_app/main.c b/examples/bbdev_app/main.c
new file mode 100644
index 0000000..9343e95
--- /dev/null
+++ b/examples/bbdev_app/main.c
@@ -0,0 +1,1452 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/unistd.h>
+#include <sys/queue.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <assert.h>
+#include <getopt.h>
+#include <signal.h>
+#include <inttypes.h>
+
+#include "rte_common.h"
+#include "rte_eal.h"
+#include "rte_cycles.h"
+#include "rte_eal.h"
+#include "rte_ether.h"
+#include "rte_ethdev.h"
+#include "rte_ip.h"
+#include "rte_lcore.h"
+#include "rte_malloc.h"
+#include "rte_mbuf.h"
+#include "rte_memory.h"
+#include "rte_mempool.h"
+#include "rte_log.h"
+#include "rte_bbdev.h"
+#include "rte_bbdev_op.h"
+
+#define MAX_PKT_BURST 32
+#define NB_MBUF 8163
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_LCORE 16
+#define MEMPOOL_CACHE_SIZE 256
+
+/*Configurable number of RX/TX ring descriptors */
+#define RTE_TEST_RX_DESC_DEFAULT 128
+#define RTE_TEST_TX_DESC_DEFAULT 512
+
+#define BBDEV_ASSERT(a) do { \
+ if (!(a)) { \
+ usage(prgname); \
+ return -1; \
+ } \
+} while (0)
+
+static struct rte_mempool *ethdev_mbuf_mempool;
+
+struct dev_qs {
+ unsigned int port_id;
+ unsigned int queues_list[RTE_MAX_QUEUES_PER_PORT];
+ unsigned int queues;
+};
+
+static struct rte_mempool *bbdev_op_pool[RTE_BBDEV_OP_TYPE_COUNT];
+
+/**all lcores used*/
+struct lcore_setup {
+ unsigned int rxte_lcores;
+ unsigned int rxte_lcore_list[RTE_MAX_LCORE];
+ unsigned int tetx_lcores;
+ unsigned int tetx_lcore_list[RTE_MAX_LCORE];
+ unsigned int rxtd_lcores;
+ unsigned int rxtd_lcore_list[RTE_MAX_LCORE];
+ unsigned int tdtx_lcores;
+ unsigned int tdtx_lcore_list[RTE_MAX_LCORE];
+};
+
+/** each lcore configuration */
+struct lcore_queue_conf {
+ unsigned int nb_ports;
+ struct dev_qs port_list[RTE_MAX_ETHPORTS];
+ /* ethernet addresses of ports */
+ struct ether_addr ports_eth_addr[RTE_MAX_ETHPORTS];
+
+ unsigned int bbdev_id;
+
+ unsigned int bbdev_qs[128];
+ unsigned int nb_bbdev_qs;
+
+ struct rte_mempool *mbuf_pool;
+} __rte_cache_aligned;
+
+static struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+
+static const struct rte_eth_conf port_conf = {
+ .rxmode = {
+ .mq_mode = ETH_MQ_RX_NONE,
+ .max_rx_pkt_len = ETHER_MAX_LEN,
+ .split_hdr_size = 0,
+ .header_split = 0, /**< Header Split disabled */
+ .hw_ip_checksum = 0, /**< IP checksum offload disabled */
+ .hw_vlan_filter = 0, /**< VLAN filtering disabled */
+ .jumbo_frame = 0, /**< Jumbo Frame Support disabled */
+ .hw_strip_crc = 0, /**< CRC stripped by hardware */
+ },
+ .txmode = {
+ .mq_mode = ETH_MQ_TX_NONE,
+ },
+};
+
+struct rte_bbdev_op_turbo_enc def_op_enc = {
+ /* These values are arbitrarily put, and does not map to the real
+ * values for the data received from ethdev ports
+ */
+ .rv_index = 0,
+ .code_block_mode = 1,
+ .cb_params = {
+ .e = 272,
+ .ncb = 192
+ },
+ .op_flags = RTE_BBDEV_TURBO_CRC_24B_ATTACH
+};
+
+struct rte_bbdev_op_turbo_dec def_op_dec = {
+ /* These values are arbitrarily put, and does not map to the real
+ * values for the data received from ethdev ports
+ */
+ .cb_params.e = 44,
+ .rv_index = 0,
+ .iter_max = 8,
+ .iter_min = 4,
+ .ext_scale = 15,
+ .num_maps = 0,
+ .op_flags = RTE_BBDEV_TURBO_SUBBLOCK_DEINTERLEAVE |
+ RTE_BBDEV_TURBO_EQUALIZER | RTE_BBDEV_TURBO_SOFT_OUTPUT
+};
+
+struct bbdev_config_params {
+ uint8_t downlink_lcores;
+ uint8_t uplink_lcores;
+
+ uint8_t downlink_rx_ports;
+ uint8_t downlink_tx_ports;
+
+ uint8_t uplink_rx_ports;
+ uint8_t uplink_tx_ports;
+
+ unsigned int rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+ unsigned int tx_port_list[MAX_TX_QUEUE_PER_LCORE];
+};
+
+struct lcore_statistics {
+ unsigned int enqueued;
+ unsigned int dequeued;
+ unsigned int lost_packets;
+} __rte_cache_aligned;
+
+static struct lcore_statistics lcore_stats[RTE_MAX_LCORE];
+
+static volatile int global_exit_flag;
+
+struct port_queues {
+ unsigned int nb_rx_qs;
+ unsigned int nb_tx_qs;
+};
+
+static struct port_queues ports_qs[RTE_MAX_ETHPORTS];
+
+/* display usage */
+static inline void
+usage(const char *prgname)
+{
+ printf("%s [EAL options] "
+ " --\n"
+ " --downlink_cores - downlink cores mask\n"
+ " --uplink_cores - uplink cores mask\n"
+ " --downlink_rx_ports - downlink Rx ports mask\n"
+ " --downlink_tx_ports - downlink Tx ports mask\n"
+ " --uplink_tx_ports -uplink Tx ports mask\n"
+ " --uplink_rx_ports -uplink Rx ports msk\n"
+ "\n", prgname);
+}
+
+/* parse port or core mask */
+static inline
+uint8_t bbdev_parse_mask(const char *mask)
+{
+ char *end = NULL;
+ unsigned long pm;
+
+ /* parse hexadecimal string */
+ pm = strtoul(mask, &end, 16);
+ if ((mask[0] == '\0') || (end == NULL) || (*end != '\0'))
+ return 0;
+
+ if (pm == 0)
+ return 0;
+
+ return pm;
+}
+
+static int
+bbdev_parse_args(int argc, char **argv,
+ struct bbdev_config_params *bbdev_params)
+{
+ int optind = 0;
+ int opt;
+ int opt_indx = 0;
+ char *prgname = argv[0];
+
+ memset(bbdev_params, 0, sizeof(*bbdev_params));
+
+ static struct option lgopts[] = {
+ { "downlink_cores", required_argument, 0, 'c' },
+ { "uplink_cores", required_argument, 0, 'C' },
+ { "downlink_rx_ports", required_argument, 0, 'r' },
+ { "downlink_tx_ports", required_argument, 0, 't' },
+ { "uplink_rx_ports", required_argument, 0, 'R' },
+ { "uplink_tx_ports", required_argument, 0, 'T' },
+ { NULL, 0, 0, 0 }
+ };
+
+ BBDEV_ASSERT(argc != 0);
+ BBDEV_ASSERT(argv != NULL);
+ BBDEV_ASSERT(bbdev_params != NULL);
+
+ while ((opt = getopt_long(argc, argv, "c:C:r:t:R:T:", lgopts,
+ &opt_indx)) != EOF) {
+
+ switch (opt) {
+ case 'c':
+ bbdev_params->downlink_lcores =
+ bbdev_parse_mask(optarg);
+ if (bbdev_params->downlink_lcores == 0) {
+ usage(prgname);
+ return -1;
+ }
+ break;
+
+ case 'C':
+ bbdev_params->uplink_lcores =
+ bbdev_parse_mask(optarg);
+ if (bbdev_params->uplink_lcores == 0) {
+ usage(prgname);
+ return -1;
+ }
+ break;
+
+ case 'r':
+ bbdev_params->downlink_rx_ports =
+ bbdev_parse_mask(optarg);
+ if (bbdev_params->downlink_rx_ports == 0) {
+ usage(prgname);
+ return -1;
+ }
+ break;
+
+ case 't':
+ bbdev_params->downlink_tx_ports =
+ bbdev_parse_mask(optarg);
+ if (bbdev_params->downlink_tx_ports == 0) {
+ usage(prgname);
+ return -1;
+ }
+ break;
+
+ case 'R':
+ bbdev_params->uplink_rx_ports =
+ bbdev_parse_mask(optarg);
+ if (bbdev_params->uplink_rx_ports == 0) {
+ usage(prgname);
+ return -1;
+ }
+ break;
+
+ case 'T':
+ bbdev_params->uplink_tx_ports =
+ bbdev_parse_mask(optarg);
+ if (bbdev_params->uplink_tx_ports == 0) {
+ usage(prgname);
+ return -1;
+ }
+ break;
+
+ default:
+ usage(prgname);
+ return -1;
+ }
+ }
+ optind = 0;
+ return optind;
+}
+
+static void
+signal_handler(int signum)
+{
+ printf("\nSignal %d received", signum);
+ global_exit_flag = 1;
+}
+
+static void
+print_mac(unsigned int portid, struct ether_addr *bbdev_ports_eth_address)
+{
+ printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n",
+ (unsigned int) portid,
+ bbdev_ports_eth_address[portid].addr_bytes[0],
+ bbdev_ports_eth_address[portid].addr_bytes[1],
+ bbdev_ports_eth_address[portid].addr_bytes[2],
+ bbdev_ports_eth_address[portid].addr_bytes[3],
+ bbdev_ports_eth_address[portid].addr_bytes[4],
+ bbdev_ports_eth_address[portid].addr_bytes[5]);
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+ uint8_t portid, count, all_ports_up, print_flag = 0;
+ struct rte_eth_link link;
+
+ printf("\nChecking link status");
+ fflush(stdout);
+
+ for (count = 0; count <= MAX_CHECK_TIME; count++) {
+ all_ports_up = 1;
+ for (portid = 0; portid < port_num; portid++) {
+ if ((port_mask & (1 << portid)) == 0)
+ continue;
+ memset(&link, 0, sizeof(link));
+ rte_eth_link_get_nowait(portid, &link);
+ /* print link status if flag set */
+ if (print_flag == 1) {
+ if (link.link_status) {
+ const char *dp = (link.link_duplex ==
+ ETH_LINK_FULL_DUPLEX) ?
+ "full-duplex" :
+ "half-duplex";
+ printf("Port %u Link Up - speed %u Mbps"
+ " - %s\n", portid,
+ link.link_speed,
+ dp);
+ } else
+ printf("Port %d Link Down\n", portid);
+ continue;
+ }
+ /* clear all_ports_up flag if any link down */
+ if (link.link_status == 0) {
+ all_ports_up = 0;
+ break;
+ }
+ }
+ /* after finally printing all link status, get out */
+ if (print_flag == 1)
+ break;
+
+ if (all_ports_up == 0) {
+ printf(".");
+ fflush(stdout);
+ rte_delay_ms(CHECK_INTERVAL);
+ }
+
+ /* set the print_flag if all ports up or timeout */
+ if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+ print_flag = 1;
+ printf("done\n");
+ }
+ }
+}
+
+static void
+update_pkt_mac(uint16_t n, struct rte_mbuf *pkts_burst[],
+ struct ether_addr *addr, unsigned int dest_portid)
+{
+ struct ether_hdr *eth;
+ void *tmp;
+ uint16_t i;
+
+ for (i = 0; i < n; i++) {
+ eth = rte_pktmbuf_mtod(pkts_burst[i], struct ether_hdr *);
+ /* 02:00:00:00:00:xx */
+ tmp = ð->d_addr.addr_bytes[0];
+ *((uint64_t *)tmp) = 0x000000000002 +
+ ((uint64_t)dest_portid << 40);
+ /* src addr */
+ ether_addr_copy(addr, ð->s_addr);
+ }
+}
+
+static int
+initialize_ports(uint8_t ports_mask, char link, char port_type,
+ uint32_t *bbdev_enabled_port_mask)
+{
+ uint8_t portid;
+ unsigned int enabled_portcount = 0, q;
+ int ret;
+ struct port_queues *port_qs;
+ /* ethernet addresses of ports */
+ struct ether_addr bbdev_dl_ports_eth_addr[RTE_MAX_ETHPORTS];
+ struct ether_addr bbdev_ul_ports_eth_addr[RTE_MAX_ETHPORTS];
+
+ uint8_t nb_ports = rte_eth_dev_count();
+ if (nb_ports == 0) {
+ printf("No Ethernet ports available\n");
+ return -1;
+ }
+
+ for (portid = 0; portid < nb_ports; portid++) {
+
+ /* Skip ports that are not enabled */
+ if ((ports_mask & (1 << portid)) == 0)
+ continue;
+
+ port_qs = &ports_qs[portid];
+ /* initialize ports */
+ printf("\nInitializing %cx port %u... ",
+ port_type, portid);
+ fflush(stdout);
+ ret = rte_eth_dev_configure(portid, port_qs->nb_rx_qs,
+ port_qs->nb_tx_qs, &port_conf);
+
+ if (ret < 0) {
+ printf("Cannot configure device: err=%d, port=%u\n",
+ ret, portid);
+ return -1;
+ }
+ fflush(stdout);
+
+ /* initialize one RX or TX queue on each port*/
+ if (port_type == 'R')
+ for (q = 0; q < port_qs->nb_rx_qs; q++)
+ ret = rte_eth_rx_queue_setup(portid, q,
+ RTE_TEST_RX_DESC_DEFAULT,
+ rte_eth_dev_socket_id(portid),
+ NULL, ethdev_mbuf_mempool);
+ else if (port_type == 'T')
+ for (q = 0; q < port_qs->nb_rx_qs; q++)
+ ret = rte_eth_tx_queue_setup(portid, q,
+ RTE_TEST_TX_DESC_DEFAULT,
+ rte_eth_dev_socket_id(portid),
+ NULL);
+
+ if (ret < 0) {
+ printf("%cL rte_eth_%cx_queue_setup:err=%d, port=%u\n",
+ port_type, link, ret,
+ (unsigned int) portid);
+ return -1;
+ }
+
+ rte_eth_promiscuous_enable(portid);
+
+ if (link == 'D') {
+ rte_eth_macaddr_get(portid,
+ &bbdev_dl_ports_eth_addr[portid]);
+ print_mac(portid, bbdev_dl_ports_eth_addr);
+ } else {
+ rte_eth_macaddr_get(portid,
+ &bbdev_ul_ports_eth_addr[portid]);
+ print_mac(portid, bbdev_ul_ports_eth_addr);
+ }
+
+ *bbdev_enabled_port_mask |= (1 << portid);
+ enabled_portcount++;
+ }
+ return enabled_portcount;
+}
+
+static int
+start_ethdev_ports(uint8_t nb_ports, uint32_t bbdev_enabled_port_mask)
+{
+ unsigned int portid;
+ int ret, ports_started = 0;
+
+ for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+
+ if ((bbdev_enabled_port_mask & (uint32_t)(1 << portid)) == 0)
+ continue;
+ ret = rte_eth_dev_start(portid);
+ if (ret < 0) {
+ printf("rte_eth_dev_start:err=%d, port=%u\n", ret,
+ (unsigned int) portid);
+ return -1;
+ }
+
+ ports_started++;
+ if (ports_started == nb_ports)
+ break;
+ }
+ return ports_started;
+}
+
+static int
+lcore_queue_init(uint8_t nb_ports, struct bbdev_config_params *bbdev_params,
+ struct lcore_setup *l_setup)
+{
+ uint16_t port;
+ unsigned int lcore;
+ int lcount, total_count = 0;
+ struct lcore_queue_conf *qconf;
+
+ /*
+ * for each core in the uplink populate the array of ports (rx or tx).
+ * core with odd id receives rx ports, core with even id receives all
+ * tx ports.
+ */
+ for (lcore = 0, lcount = 0; lcore < sizeof(int) * 8; lcore++) {
+
+ /* get the lcore_id */
+ if ((bbdev_params->downlink_lcores & (1 << lcore)) == 0)
+ continue;
+
+ lcount++;
+ for (port = 0; port <= nb_ports; port++) {
+ if ((lcount & 1) == 1) {
+ if (port < nb_ports) {
+ /*get the port id*/
+ if ((bbdev_params->downlink_rx_ports &
+ (1 << port)) == 0)
+ continue;
+
+ l_setup->rxte_lcore_list[
+ l_setup->rxte_lcores] =
+ lcore;
+ printf("Lcore %d: DL RX port %d\n",
+ lcore, port);
+ } else {
+ l_setup->rxte_lcores++;
+ continue;
+ }
+
+ } else {
+ if (port < nb_ports) {
+ if ((bbdev_params->downlink_tx_ports &
+ (1 << port)) == 0)
+ continue;
+
+ l_setup->tetx_lcore_list[
+ l_setup->tetx_lcores] =
+ lcore;
+ printf("Lcore %d: DL TX port %d\n",
+ lcore, port);
+ } else {
+ l_setup->tetx_lcores++;
+ continue;
+ }
+ }
+ qconf = &lcore_queue_conf[lcore];
+ qconf->port_list[qconf->nb_ports].queues++;
+ qconf->port_list[qconf->nb_ports].port_id = port;
+ rte_eth_macaddr_get(port,
+ &qconf->ports_eth_addr
+ [qconf->nb_ports]);
+ qconf->nb_ports++;
+ }
+ }
+
+ if (lcount % 2) {
+ printf("\nNumber of DL lcores is not an even number");
+ return -1;
+ }
+
+ total_count += lcount;
+
+ /*
+ * for each core in the downlink populate the array of ports (rx or tx).
+ * core with odd id receives rx ports, core with even id receives all
+ * tx ports
+ */
+ for (lcore = 0, lcount = 0; lcore < (sizeof(int) * 8); lcore++) {
+ if ((bbdev_params->uplink_lcores & (1 << lcore)) == 0)
+ continue;
+
+ lcount++;
+ for (port = 0; port <= nb_ports; port++) {
+
+ if ((lcount & 1) == 1) {
+ if (port < nb_ports) {
+ if ((bbdev_params->uplink_rx_ports &
+ (1 << port)) == 0)
+ continue;
+
+ l_setup->rxtd_lcore_list[
+ l_setup->rxtd_lcores] =
+ lcore;
+ printf("Lcore %u: UL RX port %u\n",
+ lcore, port);
+ } else {
+ l_setup->rxtd_lcores++;
+ continue;
+ }
+
+ } else {
+ if (port < nb_ports) {
+ if ((bbdev_params->uplink_tx_ports &
+ (1 << port)) == 0)
+ continue;
+
+ l_setup->tdtx_lcore_list[
+ l_setup->tdtx_lcores] =
+ lcore;
+ printf("Lcore %d: UL TX port %d\n",
+ lcore, port);
+ } else {
+ l_setup->tdtx_lcores++;
+ continue;
+ }
+ }
+ qconf = &lcore_queue_conf[lcore];
+ qconf->port_list[qconf->nb_ports].queues++;
+ qconf->port_list[qconf->nb_ports].port_id = port;
+ rte_eth_macaddr_get(port,
+ &qconf->ports_eth_addr
+ [qconf->nb_ports]);
+ qconf->nb_ports++;
+ }
+ }
+ if (lcount % 2) {
+ printf("\nNumber of DL lcores is not an even number");
+ return -1;
+ }
+ total_count += lcount;
+ /*return number of lcores processed*/
+ return total_count;
+}
+
+static void
+bbdev_dequeue_dec(void)
+{
+ struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+ struct rte_bbdev_dec_op *ops_burst[MAX_PKT_BURST];
+ unsigned int i, j, portid, nb_tx, lcoreid, qid = 0, q, nb_tx_sent = 0;
+ struct lcore_queue_conf *qconf;
+ struct lcore_statistics *lcore_stat;
+
+ lcoreid = rte_lcore_id();
+ lcore_stat = &lcore_stats[lcoreid];
+ qconf = &lcore_queue_conf[lcoreid];
+
+ if (qconf->nb_ports == 0)
+ return;
+
+ while (!global_exit_flag) {
+ for (i = 0; i < qconf->nb_ports; i++) {
+ portid = qconf->port_list[i].port_id;
+
+ for (q = 0; q < qconf->port_list[i].queues; q++) {
+ qid = qconf->port_list[i].queues_list[q];
+ /* Dequeue packets from bbdev device*/
+ nb_tx = rte_bbdev_dequeue_dec_ops(
+ qconf->bbdev_id,
+ qconf->bbdev_qs[q], ops_burst,
+ MAX_PKT_BURST);
+
+ if (!nb_tx)
+ continue;
+
+ lcore_stat->dequeued += nb_tx;
+
+ for (j = 0; j < nb_tx; j++) {
+ pkts_burst[j] =
+ ops_burst[j]->turbo_dec.hard_output.data;
+ /* input mbufs are no longer needed,
+ * release!
+ */
+ rte_pktmbuf_free(
+ ops_burst[j]->turbo_dec.input.data);
+ }
+
+ rte_bbdev_dec_op_free_bulk(ops_burst, nb_tx);
+
+ update_pkt_mac(nb_tx, pkts_burst,
+ &(qconf->ports_eth_addr
+ [portid]),
+ portid);
+
+ /*Enqueue packets to ethdev*/
+ nb_tx_sent = rte_eth_tx_burst(
+ (uint8_t)portid, qid,
+ pkts_burst, nb_tx);
+ if (unlikely(nb_tx_sent < nb_tx)) {
+ lcore_stat->lost_packets +=
+ nb_tx - nb_tx_sent;
+ for (j = nb_tx_sent; j < nb_tx; j++)
+ rte_pktmbuf_free(pkts_burst[j]);
+ }
+ }
+ }
+ }
+}
+
+static void
+bbdev_dequeue_enc(void)
+{
+ struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+ struct rte_bbdev_enc_op *ops_burst[MAX_PKT_BURST];
+ unsigned int i, j, portid, nb_tx, lcoreid, qid = 0, q, nb_tx_sent = 0;
+ struct lcore_queue_conf *qconf;
+ struct lcore_statistics *lcore_stat;
+
+ lcoreid = rte_lcore_id();
+ lcore_stat = &lcore_stats[lcoreid];
+ qconf = &lcore_queue_conf[lcoreid];
+
+ if (qconf->nb_ports == 0)
+ return;
+
+ while (!global_exit_flag) {
+ for (i = 0; i < qconf->nb_ports; i++) {
+ portid = qconf->port_list[i].port_id;
+
+ for (q = 0; q < qconf->port_list[i].queues; q++) {
+ qid = qconf->port_list[i].queues_list[q];
+ /* Dequeue packets from bbdev device*/
+ nb_tx = rte_bbdev_dequeue_enc_ops(
+ qconf->bbdev_id,
+ qconf->bbdev_qs[q], ops_burst,
+ MAX_PKT_BURST);
+
+ if (!nb_tx)
+ continue;
+
+ lcore_stat->dequeued += nb_tx;
+
+ for (j = 0; j < nb_tx; j++) {
+ pkts_burst[j] =
+ ops_burst[j]->turbo_enc.output.data;
+ /* input mbufs are no longer needed,
+ * release!
+ */
+ rte_pktmbuf_free(
+ ops_burst[j]->turbo_enc.input.data);
+ }
+
+ rte_bbdev_enc_op_free_bulk(ops_burst, nb_tx);
+
+ update_pkt_mac(nb_tx, pkts_burst,
+ &(qconf->ports_eth_addr
+ [portid]), portid);
+
+ /*Enqueue packets to ethdev*/
+ nb_tx_sent = rte_eth_tx_burst(
+ (uint8_t)portid, qid,
+ pkts_burst, nb_tx);
+ if (unlikely(nb_tx_sent < nb_tx)) {
+ lcore_stat->lost_packets +=
+ nb_tx - nb_tx_sent;
+ for (j = nb_tx_sent; j < nb_tx; j++)
+ rte_pktmbuf_free(pkts_burst[j]);
+ }
+ }
+ }
+ }
+}
+
+static void
+bbdev_enqueue_dec(void)
+{
+ unsigned int i, portid, nb_rx = 0, j, lcoreid, q, qid = 0;
+ int ret;
+ struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+ struct rte_mbuf *bbdev_pkts[MAX_PKT_BURST];
+ struct rte_bbdev_dec_op *ops_burst[MAX_PKT_BURST];
+ struct lcore_statistics *lcore_stat;
+ struct lcore_queue_conf *qconf = &lcore_queue_conf[rte_lcore_id()];
+
+ if (qconf->nb_ports == 0)
+ return;
+
+ lcoreid = rte_lcore_id();
+ lcore_stat = &lcore_stats[lcoreid];
+
+ /* Read packet from RX queues*/
+ while (!global_exit_flag) {
+
+ for (i = 0; i < qconf->nb_ports; i++) {
+ portid = qconf->port_list[i].port_id;
+
+ for (q = 0; q < qconf->port_list[i].queues; q++) {
+
+ qid = qconf->port_list[i].queues_list[q];
+ /* Dequeue packets from ethdev */
+ nb_rx = rte_eth_rx_burst((uint8_t) portid, qid,
+ pkts_burst, MAX_PKT_BURST);
+
+ if (!nb_rx)
+ continue;
+
+ if (rte_bbdev_dec_op_alloc_bulk(
+ bbdev_op_pool
+ [RTE_BBDEV_OP_TURBO_DEC],
+ ops_burst, nb_rx) != 0)
+ continue;
+
+ ret = rte_pktmbuf_alloc_bulk(qconf->mbuf_pool,
+ bbdev_pkts, MAX_PKT_BURST);
+ if (ret < 0)
+ continue;
+
+ for (j = 0; j < nb_rx; j++) {
+ struct rte_bbdev_op_turbo_dec *td;
+ /* append the size of the etherneit
+ * header
+ */
+ rte_pktmbuf_append(bbdev_pkts[j],
+ sizeof(struct ether_hdr));
+ /* copy the ethernet header */
+ void *in_buf = rte_pktmbuf_mtod(
+ pkts_burst[j], void *);
+ void *out_buf = rte_pktmbuf_mtod(
+ bbdev_pkts[j], void *);
+ rte_memcpy(out_buf, in_buf,
+ sizeof(struct ether_hdr));
+ /* set op */
+ ops_burst[j]->turbo_dec = def_op_dec;
+ td = &ops_burst[j]->turbo_dec;
+ td->cb_params.k =
+ rte_pktmbuf_pkt_len(
+ bbdev_pkts[j])
+ * 8;
+ td->input.offset =
+ sizeof(
+ struct
+ ether_hdr);
+ td->input.length =
+ rte_pktmbuf_pkt_len(
+ bbdev_pkts[j]);
+ td->input.data =
+ pkts_burst[j];
+ td->hard_output.offset =
+ sizeof(
+ struct
+ ether_hdr);
+ td->hard_output.data =
+ bbdev_pkts[j];
+ }
+
+ /* Enqueue packets on BBDEV device */
+ nb_rx = rte_bbdev_enqueue_dec_ops(
+ qconf->bbdev_id,
+ qconf->bbdev_qs[q], ops_burst,
+ nb_rx);
+ lcore_stat->enqueued += nb_rx;
+ }
+ }
+ }
+}
+
+static void
+bbdev_enqueue_enc(void)
+{
+ unsigned int i, portid, nb_rx = 0, j, lcoreid, q, qid = 0;
+ int ret;
+ struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+ struct rte_mbuf *bbdev_pkts[MAX_PKT_BURST];
+ struct rte_bbdev_enc_op *ops_burst[MAX_PKT_BURST];
+ struct lcore_statistics *lcore_stat;
+ struct lcore_queue_conf *qconf = &lcore_queue_conf[rte_lcore_id()];
+
+ lcoreid = rte_lcore_id();
+ lcore_stat = &lcore_stats[lcoreid];
+
+ /* Read packet from RX queues*/
+ while (!global_exit_flag) {
+
+ for (i = 0; i < qconf->nb_ports; i++) {
+ portid = qconf->port_list[i].port_id;
+
+ for (q = 0; q < qconf->port_list[i].queues; q++) {
+
+ qid = qconf->port_list[i].queues_list[q];
+ /* Dequeue packets from ethdev */
+ nb_rx = rte_eth_rx_burst((uint8_t)portid, qid,
+ pkts_burst, MAX_PKT_BURST);
+
+ if (!nb_rx)
+ continue;
+
+ if (rte_bbdev_enc_op_alloc_bulk(
+ bbdev_op_pool
+ [RTE_BBDEV_OP_TURBO_ENC],
+ ops_burst, nb_rx) != 0)
+ continue;
+
+ ret = rte_pktmbuf_alloc_bulk(qconf->mbuf_pool,
+ bbdev_pkts, MAX_PKT_BURST);
+ if (ret < 0)
+ continue;
+
+ for (j = 0; j < nb_rx; j++) {
+ /* append the size of the ethernet
+ * header
+ */
+ rte_pktmbuf_append(bbdev_pkts[j],
+ sizeof(
+ struct
+ ether_hdr));
+ /* copy the ethernet header */
+ void *in_buf = rte_pktmbuf_mtod(
+ pkts_burst[j], void *);
+ void *out_buf = rte_pktmbuf_mtod(
+ bbdev_pkts[j], void *);
+ rte_memcpy(out_buf, in_buf,
+ sizeof(
+ struct
+ ether_hdr));
+ /* set op */
+ ops_burst[j]->turbo_enc = def_op_enc;
+ ops_burst[j]->turbo_enc.cb_params.k =
+ rte_pktmbuf_pkt_len(
+ bbdev_pkts[j])
+ * 8;
+ ops_burst[j]->turbo_enc.input.offset =
+ 0;
+ ops_burst[j]->turbo_enc.input.length =
+ rte_pktmbuf_pkt_len(
+ pkts_burst[j]);
+ ops_burst[j]->turbo_enc.input.data =
+ pkts_burst[j];
+ ops_burst[j]->turbo_enc.output.offset =
+ sizeof(
+ struct
+ ether_hdr);
+ ops_burst[j]->turbo_enc.output.data =
+ bbdev_pkts[j];
+ }
+
+ /* Enqueue packets on BBDEV device */
+ nb_rx = rte_bbdev_enqueue_enc_ops(
+ qconf->bbdev_id,
+ qconf->bbdev_qs[q], ops_burst,
+ nb_rx);
+ lcore_stat->enqueued += nb_rx;
+ }
+ }
+ }
+}
+
+static void
+print_lcore_stats(unsigned int lcore_id)
+{
+ struct lcore_statistics *lcore_stat;
+ static const char *stats_border = "_______";
+
+ lcore_stat = &lcore_stats[lcore_id];
+ printf("\nLcore %d: %s enqueued count:\t\t%u\n",
+ lcore_id, stats_border, lcore_stat->enqueued);
+ printf("Lcore %d: %s dequeued count:\t\t%u\n",
+ lcore_id, stats_border, lcore_stat->dequeued);
+}
+
+static void
+print_stats(struct lcore_setup *lcore_setup)
+{
+ unsigned int l_id, dev_id;
+ unsigned char x, nb_ports;
+ int len, ret, i;
+
+ struct rte_eth_xstat *xstats;
+ struct rte_eth_xstat_name *xstats_names;
+ struct rte_bbdev_stats bbstats;
+ static const char *stats_border = "_______";
+
+ const char clr[] = { 27, '[', '2', 'J', '\0' };
+ const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
+
+ /* Clear screen and move to top left */
+ printf("%s%s", clr, topLeft);
+
+ nb_ports = rte_eth_dev_count();
+ printf("PORT STATISTICS:\n================\n");
+ for (x = 0; x < nb_ports; x++) {
+
+ len = rte_eth_xstats_get(x, NULL, 0);
+ if (len < 0)
+ rte_exit(EXIT_FAILURE,
+ "rte_eth_xstats_get(%hhu) failed: %d",
+ x, len);
+
+ xstats = calloc(len, sizeof(*xstats));
+ if (xstats == NULL)
+ rte_exit(EXIT_FAILURE,
+ "Failed to calloc memory for xstats");
+
+ ret = rte_eth_xstats_get(x, xstats, len);
+ if (ret < 0 || ret > len)
+ rte_exit(EXIT_FAILURE,
+ "rte_eth_xstats_get(%hhu) len%i failed: %d",
+ x, len, ret);
+
+ xstats_names = calloc(len, sizeof(*xstats_names));
+ if (xstats_names == NULL)
+ rte_exit(EXIT_FAILURE,
+ "Failed to calloc memory for xstats_names");
+
+ ret = rte_eth_xstats_get_names(x, xstats_names, len);
+ if (ret < 0 || ret > len)
+ rte_exit(EXIT_FAILURE,
+ "rte_eth_xstats_get_names(%hhu) len%i failed: %d",
+ x, len, ret);
+
+ for (i = 0; i < len; i++) {
+ if (xstats[i].value > 0)
+ printf("Port %u: %s %s:\t\t%"PRIu64"\n",
+ x, stats_border,
+ xstats_names[i].name,
+ xstats[i].value);
+ }
+ }
+
+ printf("\nBBDEV STATISTICS:\n=================\n");
+ RTE_BBDEV_FOREACH(dev_id) {
+ rte_bbdev_stats_get(dev_id, &bbstats);
+ printf("BBDEV %u: %s enqueue count:\t\t%"PRIu64"\n",
+ dev_id, stats_border,
+ bbstats.enqueued_count);
+ printf("BBDEV %u: %s dequeue count:\t\t%"PRIu64"\n",
+ dev_id, stats_border,
+ bbstats.dequeued_count);
+ printf("BBDEV %u: %s enqueue error count:\t\t%"PRIu64"\n",
+ dev_id, stats_border,
+ bbstats.enqueue_err_count);
+ printf("BBDEV %u: %s dequeue error count:\t\t%"PRIu64"\n\n",
+ dev_id, stats_border,
+ bbstats.dequeue_err_count);
+ }
+
+ printf("LCORE STATISTICS:\n=================\n");
+ for (l_id = 0; l_id < lcore_setup->tdtx_lcores; l_id++)
+ print_lcore_stats(lcore_setup->tdtx_lcore_list[l_id]);
+ for (l_id = 0; l_id < lcore_setup->tetx_lcores; l_id++)
+ print_lcore_stats(lcore_setup->tetx_lcore_list[l_id]);
+ for (l_id = 0; l_id < lcore_setup->rxtd_lcores; l_id++)
+ print_lcore_stats(lcore_setup->rxtd_lcore_list[l_id]);
+ for (l_id = 0; l_id < lcore_setup->rxte_lcores; l_id++)
+ print_lcore_stats(lcore_setup->rxte_lcore_list[l_id]);
+}
+
+static void
+qs_to_lcores(unsigned int nb_lcores, unsigned int lcores[])
+{
+ unsigned int port = 0, lcore, nb_ports = 0, q_id;
+ unsigned int l = 0, y, x;
+ struct lcore_queue_conf *qconf;
+ struct dev_qs temp[RTE_MAX_LCORE];
+ int count = 0;
+ struct dev_qs *p;
+ struct port_queues *port_qs;
+
+ /*
+ * for each core copy array of ports (holding all ports available to
+ * this lcore) from qconf into temp array and empty the one in qconf
+ */
+ for (x = 0; x < nb_lcores; x++) {
+
+ lcore = lcores[x];
+ qconf = &lcore_queue_conf[lcore];
+ nb_ports = qconf->nb_ports;
+ qconf->nb_ports = 0;
+ p = qconf->port_list;
+
+ for (y = 0; y < nb_ports; y++, p++) {
+ temp[y] = *p;
+ p->port_id = 0;
+ }
+ }
+ /*
+ * re-populate array of ports and queues in qconf according to number
+ * of available lcores, ports, and queues so only the required ports
+ * and queues stay in the configuration of each particular lcore
+ */
+ while (port < nb_ports || l < nb_lcores) {
+
+ if (port < nb_ports && l == nb_lcores) {
+ l = 0;
+ count++;
+ }
+ if (port == nb_ports && l < nb_lcores)
+ port = 0;
+
+ lcore = lcores[l];
+ qconf = &lcore_queue_conf[lcore];
+ port_qs = &ports_qs[temp[port].port_id];
+
+ if ((lcore & 1) == 1) {
+ qconf->port_list[count].port_id =
+ temp[port].port_id;
+
+ for (q_id = 0; q_id < qconf->port_list[count].queues;
+ q_id++) {
+ qconf->port_list[count].queues_list[q_id] =
+ port_qs->nb_tx_qs;
+ port_qs->nb_tx_qs++;
+ }
+
+ qconf->nb_ports++;
+ } else {
+ qconf->port_list[count].port_id =
+ temp[port].port_id;
+ for (q_id = 0; q_id < qconf->port_list[count].queues;
+ q_id++) {
+ qconf->port_list[count].queues_list[q_id] =
+ port_qs->nb_rx_qs;
+ port_qs->nb_rx_qs++;
+ }
+ qconf->nb_ports++;
+ }
+ printf("Lcore: %u connected to port: %u\n",
+ lcores[l], temp[port].port_id);
+ port++;
+ l++;
+ }
+}
+
+static void
+main_loop(struct lcore_setup *lcore_setup)
+{
+ unsigned int i = 0, this_lcore;
+ this_lcore = rte_lcore_id();
+
+ /* print stats on master core */
+ if (rte_get_master_lcore() == this_lcore) {
+ while (!global_exit_flag) {
+ print_stats(lcore_setup);
+ rte_delay_ms(500);
+ }
+ }
+
+ for (i = 0; i < lcore_setup->rxte_lcores; i++) {
+ if (lcore_setup->rxte_lcore_list[i] == this_lcore)
+ bbdev_enqueue_enc();
+ }
+
+ for (i = 0; i < lcore_setup->tetx_lcores; i++) {
+ if (lcore_setup->tetx_lcore_list[i] == this_lcore)
+ bbdev_dequeue_enc();
+ }
+
+ for (i = 0; i < lcore_setup->rxtd_lcores; i++) {
+ if (lcore_setup->rxtd_lcore_list[i] == this_lcore)
+ bbdev_enqueue_dec();
+ }
+
+ for (i = 0; i < lcore_setup->tdtx_lcores; i++) {
+ if (lcore_setup->tdtx_lcore_list[i] == this_lcore)
+ bbdev_dequeue_dec();
+ }
+}
+
+static int
+launch_one_lcore(void *arg)
+{
+ main_loop((struct lcore_setup *)arg);
+ return 0;
+}
+
+static int
+prepare_bbdev_device(unsigned int dev_id, struct rte_bbdev_info *info,
+ uint16_t dec_qs_nb, uint16_t enc_qs_nb)
+{
+ int ret;
+ unsigned int q_id;
+ struct rte_bbdev_queue_conf qconf = {0};
+ uint16_t tot_qs = dec_qs_nb + enc_qs_nb;
+
+ ret = rte_bbdev_setup_queues(dev_id, tot_qs, info->socket_id);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE,
+ "ERROR(%d): BBDEV %u not configured properly\n",
+ ret, dev_id);
+
+ /* setup device DEC queues */
+ qconf.socket = info->socket_id;
+ qconf.queue_size = info->drv.queue_size_lim;
+ qconf.op_type = RTE_BBDEV_OP_TURBO_DEC;
+
+ for (q_id = 0; q_id < dec_qs_nb; q_id++) {
+ ret = rte_bbdev_queue_configure(dev_id, q_id, &qconf);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE,
+ "ERROR(%d): BBDEV %u DEC queue %u not configured properly\n",
+ ret, dev_id, q_id);
+ }
+
+ /* setup device ENC queues */
+ qconf.op_type = RTE_BBDEV_OP_TURBO_ENC;
+
+ for (q_id = dec_qs_nb; q_id < tot_qs; q_id++) {
+ ret = rte_bbdev_queue_configure(dev_id, q_id, &qconf);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE,
+ "ERROR(%d): BBDEV %u ENC queue %u not configured properly\n",
+ ret, dev_id, q_id);
+ }
+
+ ret = rte_bbdev_start(dev_id);
+
+ if (ret != 0)
+ rte_exit(EXIT_FAILURE, "ERROR(%d): BBDEV %u not started\n",
+ ret, dev_id);
+
+ printf("BBdev %u started\n", dev_id);
+
+ return 0;
+}
+
+static unsigned int
+enable_bbdev(unsigned int lcores[], unsigned int nb_lcores, unsigned int dev_id,
+ const char *type)
+{
+ unsigned int i, nb_qs, tot_nb_bbdev_qs = 0, lcore, lcoreid;
+ struct lcore_queue_conf *qconf, *qconf_next;
+ unsigned int nb_bbdev_qs = 0;
+ char pool_name[RTE_MEMPOOL_NAMESIZE];
+
+ /* set num of port queues and bbdev queues for each lcore on the link */
+ for (lcore = 0; lcore < nb_lcores; lcore++) {
+ nb_qs = 0;
+ lcoreid = lcores[lcore];
+ qconf = &lcore_queue_conf[lcoreid];
+
+ for (i = 0; i < qconf->nb_ports; i++)
+ nb_qs += qconf->port_list->queues;
+
+ for (i = 0; i < nb_qs; i++) {
+ qconf->bbdev_qs[i] = nb_bbdev_qs;
+ nb_bbdev_qs++;
+ }
+
+ /* create the mbuf mempool for ethdev pkts */
+ snprintf(pool_name, sizeof(pool_name), "bbdev%d_mbuf_pool%d_%s",
+ dev_id, lcore, type);
+ qconf->mbuf_pool = rte_pktmbuf_pool_create(pool_name,
+ NB_MBUF, MEMPOOL_CACHE_SIZE, 0,
+ RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
+ if (qconf->mbuf_pool == NULL)
+ rte_exit(EXIT_FAILURE,
+ "Unable to create '%s' pool\n",
+ pool_name);
+
+ qconf->nb_bbdev_qs = nb_qs;
+ qconf->bbdev_id = dev_id;
+ printf("BBdev: %u, lcore %u\n", dev_id, lcoreid);
+
+ qconf_next = &lcore_queue_conf[lcoreid + 1];
+ qconf_next->bbdev_id = dev_id;
+
+ for (i = 0; i < nb_qs; i++)
+ qconf_next->bbdev_qs[i] = qconf->bbdev_qs[i];
+
+ qconf_next->nb_bbdev_qs = nb_qs;
+ printf("BBdev: %u, lcore %u\n", dev_id, lcoreid + 1);
+ }
+
+ /* count the number of queues needed on the bbdev device on this link */
+ for (lcore = 0; lcore < nb_lcores; lcore++) {
+ qconf = &lcore_queue_conf[lcoreid];
+ tot_nb_bbdev_qs += qconf->nb_bbdev_qs;
+ }
+
+ return tot_nb_bbdev_qs;
+}
+
+static void
+enable_bbdevs(struct lcore_setup *lcore_setup, uint16_t nb_bbdevs)
+{
+ struct rte_bbdev_info dev_info;
+ const struct rte_bbdev_op_cap *op_cap;
+ uint16_t dev_id, enc_dev = 0, dec_dev = 0;
+ uint16_t enc_qs = 0, dec_qs = 0;
+
+ for (dev_id = 0; dev_id < nb_bbdevs; ++dev_id) {
+ rte_bbdev_info_get(dev_id, &dev_info);
+ op_cap = dev_info.drv.capabilities;
+
+ while (op_cap->type != RTE_BBDEV_OP_NONE) {
+ if (op_cap->type == RTE_BBDEV_OP_TURBO_ENC) {
+ /*start DL bbdev device*/
+ if (lcore_setup->rxte_lcores) {
+ unsigned int *rxte_cs_l =
+ lcore_setup->rxte_lcore_list;
+ unsigned int rxte_cs =
+ lcore_setup->rxte_lcores;
+ enc_qs = enable_bbdev(rxte_cs_l,
+ rxte_cs,
+ dev_id, "ENC");
+ enc_dev++;
+ }
+ }
+
+ if (op_cap->type == RTE_BBDEV_OP_TURBO_DEC) {
+ /*start UL bbdev device*/
+ if (lcore_setup->rxtd_lcores) {
+ unsigned int *rxtd_cs_l =
+ lcore_setup->rxtd_lcore_list;
+ unsigned int rxtd_cs =
+ lcore_setup->rxtd_lcores;
+ dec_qs = enable_bbdev(rxtd_cs_l,
+ rxtd_cs,
+ dev_id, "DEC");
+ dec_dev++;
+ }
+ }
+
+ op_cap++;
+ }
+
+ prepare_bbdev_device(dev_id, &dev_info, dec_qs, enc_qs);
+ }
+
+ if (enc_dev == 0 && dec_dev == 0)
+ rte_exit(EXIT_FAILURE,
+ "No decoder and encoder devices were configured!\n");
+
+ printf("%d encoder and %d decoder devices were configured\n",
+ enc_dev, dec_dev);
+}
+
+int
+main(int argc, char **argv)
+{
+ int ret, nb_bbdevs, nb_ports;
+ int enabled_portcount = 0;
+ uint8_t lcore_id;
+ char rx = 'R', tx = 'T', up_link = 'U', down_link = 'D';
+ void *sigret;
+ uint32_t bbdev_enabled_port_mask = 0;
+ struct lcore_setup lcore_setup = { 0 };
+ struct bbdev_config_params bbdev_params = { 0 };
+
+ sigret = signal(SIGTERM, signal_handler);
+ if (sigret == SIG_ERR)
+ rte_exit(EXIT_FAILURE, "signal(%d, ...) failed", SIGTERM);
+
+ sigret = signal(SIGINT, signal_handler);
+ if (sigret == SIG_ERR)
+ rte_exit(EXIT_FAILURE, "signal(%d, ...) failed", SIGINT);
+
+ ret = rte_eal_init(argc, argv);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+
+ argc -= ret;
+ argv += ret;
+
+ /* parse application arguments (after the EAL ones) */
+ ret = bbdev_parse_args(argc, argv, &bbdev_params);
+
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Invalid BBDEV arguments\n");
+
+ /* Get number of available bbdev devices */
+ nb_bbdevs = rte_bbdev_count();
+ if (nb_bbdevs == 0)
+ rte_exit(EXIT_FAILURE, "No bbdevs detected!\n");
+ printf("Number of bbdevs detected: %d\n", nb_bbdevs);
+
+ /* Get number of available ethdev devices */
+ nb_ports = rte_eth_dev_count();
+ /* Initialize the port/queue configuration of each logical core */
+ ret = lcore_queue_init(nb_ports, &bbdev_params, &lcore_setup);
+ if (ret < nb_bbdevs * 2)
+ rte_exit(EXIT_FAILURE, "Failed to initialize queues.\n");
+
+ /* reconfigure ports to lcores assignment to allow for multiple lcores
+ * usage
+ */
+ qs_to_lcores(lcore_setup.rxte_lcores, lcore_setup.rxte_lcore_list);
+ qs_to_lcores(lcore_setup.rxtd_lcores, lcore_setup.rxtd_lcore_list);
+ qs_to_lcores(lcore_setup.tdtx_lcores, lcore_setup.tdtx_lcore_list);
+ qs_to_lcores(lcore_setup.tetx_lcores, lcore_setup.tetx_lcore_list);
+
+ /* create the mbuf mempool for ethdev pkts */
+ ethdev_mbuf_mempool = rte_pktmbuf_pool_create("ethdev_mbuf_pool",
+ NB_MBUF, MEMPOOL_CACHE_SIZE, 0,
+ RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
+ if (ethdev_mbuf_mempool == NULL)
+ rte_exit(EXIT_FAILURE, "Cannot create ethdev mbuf mempool\n");
+
+ /*initialize ports*/
+ enabled_portcount = initialize_ports(bbdev_params.downlink_rx_ports,
+ down_link, rx, &bbdev_enabled_port_mask);
+ enabled_portcount += initialize_ports(bbdev_params.downlink_tx_ports,
+ down_link, tx, &bbdev_enabled_port_mask);
+ enabled_portcount += initialize_ports(bbdev_params.uplink_rx_ports,
+ up_link, rx, &bbdev_enabled_port_mask);
+ enabled_portcount += initialize_ports(bbdev_params.uplink_tx_ports,
+ up_link, tx, &bbdev_enabled_port_mask);
+
+ if (enabled_portcount < 1)
+ rte_exit(EXIT_FAILURE, "Failed to initialize Ethernet ports\n");
+
+ /*start Ethernet devices*/
+ ret = start_ethdev_ports(nb_ports, bbdev_enabled_port_mask);
+ if (ret <= 0)
+ rte_exit(EXIT_FAILURE,
+ "Failed to start Ethernet devices on ports\n");
+ check_all_ports_link_status(nb_ports, bbdev_enabled_port_mask);
+
+ /*create bbdev op pools*/
+ bbdev_op_pool[RTE_BBDEV_OP_TURBO_DEC] =
+ rte_bbdev_op_pool_create("bbdev_op_pool_dec",
+ RTE_BBDEV_OP_TURBO_DEC, NB_MBUF, 128, rte_socket_id());
+ bbdev_op_pool[RTE_BBDEV_OP_TURBO_ENC] =
+ rte_bbdev_op_pool_create("bbdev_op_pool_enc",
+ RTE_BBDEV_OP_TURBO_ENC, NB_MBUF, 128, rte_socket_id());
+
+ if ((bbdev_op_pool[RTE_BBDEV_OP_TURBO_DEC] == NULL) ||
+ (bbdev_op_pool[RTE_BBDEV_OP_TURBO_ENC] == NULL))
+ rte_exit(EXIT_FAILURE, "Cannot create bbdev op pools\n");
+
+ /*start DL and UL bbdev device*/
+ enable_bbdevs(&lcore_setup, nb_bbdevs);
+
+ /*launch per-lcore init on every lcore*/
+ rte_eal_mp_remote_launch(launch_one_lcore, (void *)&lcore_setup,
+ CALL_MASTER);
+
+ RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+ if (rte_eal_wait_lcore(lcore_id) < 0)
+ return -1;
+ }
+
+ return 0;
+}
--
2.7.4
^ permalink raw reply [flat|nested] 16+ messages in thread