diff options
Diffstat (limited to 'drivers/raw')
-rw-r--r-- | drivers/raw/Makefile | 9 | ||||
-rw-r--r-- | drivers/raw/skeleton_rawdev/Makefile | 29 | ||||
-rw-r--r-- | drivers/raw/skeleton_rawdev/rte_pmd_skeleton_rawdev_version.map | 4 | ||||
-rw-r--r-- | drivers/raw/skeleton_rawdev/skeleton_rawdev.c | 755 | ||||
-rw-r--r-- | drivers/raw/skeleton_rawdev/skeleton_rawdev.h | 136 | ||||
-rw-r--r-- | drivers/raw/skeleton_rawdev/skeleton_rawdev_test.c | 450 |
6 files changed, 1383 insertions, 0 deletions
diff --git a/drivers/raw/Makefile b/drivers/raw/Makefile new file mode 100644 index 00000000..da7c8b44 --- /dev/null +++ b/drivers/raw/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2017 NXP + +include $(RTE_SDK)/mk/rte.vars.mk + +# DIRS-$(<configuration>) += <directory> +DIRS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += skeleton_rawdev + +include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/drivers/raw/skeleton_rawdev/Makefile b/drivers/raw/skeleton_rawdev/Makefile new file mode 100644 index 00000000..bacc66dd --- /dev/null +++ b/drivers/raw/skeleton_rawdev/Makefile @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2017 NXP + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_pmd_skeleton_rawdev.a + +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +LDLIBS += -lrte_eal +LDLIBS += -lrte_rawdev +LDLIBS += -lrte_bus_vdev +LDLIBS += -lrte_kvargs + +EXPORT_MAP := rte_pmd_skeleton_rawdev_version.map + +LIBABIVER := 1 + +# +# all source are stored in SRCS-y +# +SRCS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += skeleton_rawdev.c +SRCS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += skeleton_rawdev_test.c + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/raw/skeleton_rawdev/rte_pmd_skeleton_rawdev_version.map b/drivers/raw/skeleton_rawdev/rte_pmd_skeleton_rawdev_version.map new file mode 100644 index 00000000..179140fb --- /dev/null +++ b/drivers/raw/skeleton_rawdev/rte_pmd_skeleton_rawdev_version.map @@ -0,0 +1,4 @@ +DPDK_18.02 { + + local: *; +}; diff --git a/drivers/raw/skeleton_rawdev/skeleton_rawdev.c b/drivers/raw/skeleton_rawdev/skeleton_rawdev.c new file mode 100644 index 00000000..6bdbbb50 --- /dev/null +++ b/drivers/raw/skeleton_rawdev/skeleton_rawdev.c @@ -0,0 +1,755 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright 2017 NXP + */ + +#include <assert.h> +#include <stdio.h> +#include <stdbool.h> +#include <errno.h> +#include <stdint.h> +#include <inttypes.h> +#include <string.h> + +#include <rte_byteorder.h> +#include <rte_common.h> +#include <rte_debug.h> +#include <rte_dev.h> +#include <rte_eal.h> +#include <rte_kvargs.h> +#include <rte_log.h> +#include <rte_malloc.h> +#include <rte_memory.h> +#include <rte_memcpy.h> +#include <rte_lcore.h> +#include <rte_bus_vdev.h> + +#include <rte_rawdev.h> +#include <rte_rawdev_pmd.h> + +#include "skeleton_rawdev.h" + +/* Dynamic log type identifier */ +int skeleton_pmd_logtype; + +/* Count of instances */ +uint16_t skeldev_init_once; + +/**< Rawdev Skeleton dummy driver name */ +#define SKELETON_PMD_RAWDEV_NAME rawdev_skeleton + +/**< Skeleton rawdev driver object */ +static struct rte_vdev_driver skeleton_pmd_drv; + +struct queue_buffers { + void *bufs[SKELETON_QUEUE_MAX_DEPTH]; +}; + +static struct queue_buffers queue_buf[SKELETON_MAX_QUEUES] = {}; +static void clear_queue_bufs(int queue_id); + +static void skeleton_rawdev_info_get(struct rte_rawdev *dev, + rte_rawdev_obj_t dev_info) +{ + struct skeleton_rawdev *skeldev; + struct skeleton_rawdev_conf *skeldev_conf; + + SKELETON_PMD_FUNC_TRACE(); + + if (!dev_info) { + SKELETON_PMD_ERR("Invalid request"); + return; + } + + skeldev = skeleton_rawdev_get_priv(dev); + + skeldev_conf = dev_info; + + skeldev_conf->num_queues = skeldev->num_queues; + skeldev_conf->capabilities = skeldev->capabilities; + skeldev_conf->device_state = skeldev->device_state; + skeldev_conf->firmware_state = skeldev->fw.firmware_state; +} + +static int skeleton_rawdev_configure(const struct rte_rawdev *dev, + rte_rawdev_obj_t config) +{ + struct skeleton_rawdev *skeldev; + struct skeleton_rawdev_conf *skeldev_conf; + + SKELETON_PMD_FUNC_TRACE(); + + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); + + if (!config) { + SKELETON_PMD_ERR("Invalid configuration"); + return -EINVAL; + } + + skeldev_conf = config; + skeldev = skeleton_rawdev_get_priv(dev); + + if (skeldev_conf->num_queues <= SKELETON_MAX_QUEUES) + skeldev->num_queues = skeldev_conf->num_queues; + else + return -EINVAL; + + skeldev->capabilities = skeldev_conf->capabilities; + skeldev->num_queues = skeldev_conf->num_queues; + + return 0; +} + +static int skeleton_rawdev_start(struct rte_rawdev *dev) +{ + int ret = 0; + struct skeleton_rawdev *skeldev; + enum skeleton_firmware_state fw_state; + enum skeleton_device_state device_state; + + SKELETON_PMD_FUNC_TRACE(); + + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); + + skeldev = skeleton_rawdev_get_priv(dev); + + fw_state = skeldev->fw.firmware_state; + device_state = skeldev->device_state; + + if (fw_state == SKELETON_FW_LOADED && + device_state == SKELETON_DEV_STOPPED) { + skeldev->device_state = SKELETON_DEV_RUNNING; + } else { + SKELETON_PMD_ERR("Device not ready for starting"); + ret = -EINVAL; + } + + return ret; +} + +static void skeleton_rawdev_stop(struct rte_rawdev *dev) +{ + struct skeleton_rawdev *skeldev; + + SKELETON_PMD_FUNC_TRACE(); + + if (dev) { + skeldev = skeleton_rawdev_get_priv(dev); + skeldev->device_state = SKELETON_DEV_STOPPED; + } +} + +static void +reset_queues(struct skeleton_rawdev *skeldev) +{ + int i; + + for (i = 0; i < SKELETON_MAX_QUEUES; i++) { + skeldev->queues[i].depth = SKELETON_QUEUE_DEF_DEPTH; + skeldev->queues[i].state = SKELETON_QUEUE_DETACH; + } +} + +static void +reset_attribute_table(struct skeleton_rawdev *skeldev) +{ + int i; + + for (i = 0; i < SKELETON_MAX_ATTRIBUTES; i++) { + if (skeldev->attr[i].name) { + free(skeldev->attr[i].name); + skeldev->attr[i].name = NULL; + } + } +} + +static int skeleton_rawdev_close(struct rte_rawdev *dev) +{ + int ret = 0, i; + struct skeleton_rawdev *skeldev; + enum skeleton_firmware_state fw_state; + enum skeleton_device_state device_state; + + SKELETON_PMD_FUNC_TRACE(); + + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); + + skeldev = skeleton_rawdev_get_priv(dev); + + fw_state = skeldev->fw.firmware_state; + device_state = skeldev->device_state; + + reset_queues(skeldev); + reset_attribute_table(skeldev); + + switch (fw_state) { + case SKELETON_FW_LOADED: + if (device_state == SKELETON_DEV_RUNNING) { + SKELETON_PMD_ERR("Cannot close running device"); + ret = -EINVAL; + } else { + /* Probably call fw reset here */ + skeldev->fw.firmware_state = SKELETON_FW_READY; + } + break; + case SKELETON_FW_READY: + case SKELETON_FW_ERROR: + default: + SKELETON_PMD_DEBUG("Device already in stopped state"); + ret = -EINVAL; + break; + } + + /* Clear all allocated queues */ + for (i = 0; i < SKELETON_MAX_QUEUES; i++) + clear_queue_bufs(i); + + return ret; +} + +static int skeleton_rawdev_reset(struct rte_rawdev *dev) +{ + struct skeleton_rawdev *skeldev; + + SKELETON_PMD_FUNC_TRACE(); + + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); + + skeldev = skeleton_rawdev_get_priv(dev); + + SKELETON_PMD_DEBUG("Resetting device"); + skeldev->fw.firmware_state = SKELETON_FW_READY; + + return 0; +} + +static void skeleton_rawdev_queue_def_conf(struct rte_rawdev *dev, + uint16_t queue_id, + rte_rawdev_obj_t queue_conf) +{ + struct skeleton_rawdev *skeldev; + struct skeleton_rawdev_queue *skelq; + + SKELETON_PMD_FUNC_TRACE(); + + if (!dev || !queue_conf) + return; + + skeldev = skeleton_rawdev_get_priv(dev); + skelq = &skeldev->queues[queue_id]; + + if (queue_id < SKELETON_MAX_QUEUES) + rte_memcpy(queue_conf, skelq, + sizeof(struct skeleton_rawdev_queue)); +} + +static void +clear_queue_bufs(int queue_id) +{ + int i; + + /* Clear buffers for queue_id */ + for (i = 0; i < SKELETON_QUEUE_MAX_DEPTH; i++) + queue_buf[queue_id].bufs[i] = NULL; +} + +static int skeleton_rawdev_queue_setup(struct rte_rawdev *dev, + uint16_t queue_id, + rte_rawdev_obj_t queue_conf) +{ + int ret = 0; + struct skeleton_rawdev *skeldev; + struct skeleton_rawdev_queue *q; + + SKELETON_PMD_FUNC_TRACE(); + + if (!dev || !queue_conf) + return -EINVAL; + + skeldev = skeleton_rawdev_get_priv(dev); + q = &skeldev->queues[queue_id]; + + if (skeldev->num_queues > queue_id && + q->depth < SKELETON_QUEUE_MAX_DEPTH) { + rte_memcpy(q, queue_conf, + sizeof(struct skeleton_rawdev_queue)); + clear_queue_bufs(queue_id); + } else { + SKELETON_PMD_ERR("Invalid queue configuration"); + ret = -EINVAL; + } + + return ret; +} + +static int skeleton_rawdev_queue_release(struct rte_rawdev *dev, + uint16_t queue_id) +{ + int ret = 0; + struct skeleton_rawdev *skeldev; + + SKELETON_PMD_FUNC_TRACE(); + + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); + + skeldev = skeleton_rawdev_get_priv(dev); + + if (skeldev->num_queues > queue_id) { + skeldev->queues[queue_id].state = SKELETON_QUEUE_DETACH; + skeldev->queues[queue_id].depth = SKELETON_QUEUE_DEF_DEPTH; + clear_queue_bufs(queue_id); + } else { + SKELETON_PMD_ERR("Invalid queue configuration"); + ret = -EINVAL; + } + + return ret; +} + +static int skeleton_rawdev_get_attr(struct rte_rawdev *dev, + const char *attr_name, + uint64_t *attr_value) +{ + int i; + uint8_t done = 0; + struct skeleton_rawdev *skeldev; + + SKELETON_PMD_FUNC_TRACE(); + + if (!dev || !attr_name || !attr_value) { + SKELETON_PMD_ERR("Invalid arguments for getting attributes"); + return -EINVAL; + } + + skeldev = skeleton_rawdev_get_priv(dev); + + for (i = 0; i < SKELETON_MAX_ATTRIBUTES; i++) { + if (!skeldev->attr[i].name) + continue; + + if (!strncmp(skeldev->attr[i].name, attr_name, + SKELETON_ATTRIBUTE_NAME_MAX)) { + *attr_value = skeldev->attr[i].value; + done = 1; + SKELETON_PMD_DEBUG("Attribute (%s) Value (%" PRIu64 ")", + attr_name, *attr_value); + break; + } + } + + if (done) + return 0; + + /* Attribute not found */ + return -EINVAL; +} + +static int skeleton_rawdev_set_attr(struct rte_rawdev *dev, + const char *attr_name, + const uint64_t attr_value) +{ + int i; + uint8_t done = 0; + struct skeleton_rawdev *skeldev; + + SKELETON_PMD_FUNC_TRACE(); + + if (!dev || !attr_name) { + SKELETON_PMD_ERR("Invalid arguments for setting attributes"); + return -EINVAL; + } + + skeldev = skeleton_rawdev_get_priv(dev); + + /* Check if attribute already exists */ + for (i = 0; i < SKELETON_MAX_ATTRIBUTES; i++) { + if (!skeldev->attr[i].name) + break; + + if (!strncmp(skeldev->attr[i].name, attr_name, + SKELETON_ATTRIBUTE_NAME_MAX)) { + /* Update value */ + skeldev->attr[i].value = attr_value; + done = 1; + break; + } + } + + if (!done) { + if (i < (SKELETON_MAX_ATTRIBUTES - 1)) { + /* There is still space to insert one more */ + skeldev->attr[i].name = strdup(attr_name); + if (!skeldev->attr[i].name) + return -ENOMEM; + + skeldev->attr[i].value = attr_value; + return 0; + } + } + + return -EINVAL; +} + +static int skeleton_rawdev_enqueue_bufs(struct rte_rawdev *dev, + struct rte_rawdev_buf **buffers, + unsigned int count, + rte_rawdev_obj_t context) +{ + unsigned int i; + uint16_t q_id; + RTE_SET_USED(dev); + + /* context is essentially the queue_id which is + * transferred as opaque object through the library layer. This can + * help in complex implementation which require more information than + * just an integer - for example, a queue-pair. + */ + q_id = *((int *)context); + + for (i = 0; i < count; i++) + queue_buf[q_id].bufs[i] = buffers[i]->buf_addr; + + return i; +} + +static int skeleton_rawdev_dequeue_bufs(struct rte_rawdev *dev, + struct rte_rawdev_buf **buffers, + unsigned int count, + rte_rawdev_obj_t context) +{ + unsigned int i; + uint16_t q_id; + RTE_SET_USED(dev); + + /* context is essentially the queue_id which is + * transferred as opaque object through the library layer. This can + * help in complex implementation which require more information than + * just an integer - for example, a queue-pair. + */ + q_id = *((int *)context); + + for (i = 0; i < count; i++) + buffers[i]->buf_addr = queue_buf[q_id].bufs[i]; + + return i; +} + +static int skeleton_rawdev_dump(struct rte_rawdev *dev, FILE *f) +{ + RTE_SET_USED(dev); + RTE_SET_USED(f); + + return 0; +} + +static int skeleton_rawdev_firmware_status_get(struct rte_rawdev *dev, + rte_rawdev_obj_t status_info) +{ + struct skeleton_rawdev *skeldev; + + SKELETON_PMD_FUNC_TRACE(); + + skeldev = skeleton_rawdev_get_priv(dev); + + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); + + if (status_info) + memcpy(status_info, &skeldev->fw.firmware_state, + sizeof(enum skeleton_firmware_state)); + + return 0; +} + + +static int skeleton_rawdev_firmware_version_get( + struct rte_rawdev *dev, + rte_rawdev_obj_t version_info) +{ + struct skeleton_rawdev *skeldev; + struct skeleton_firmware_version_info *vi; + + SKELETON_PMD_FUNC_TRACE(); + + skeldev = skeleton_rawdev_get_priv(dev); + vi = version_info; + + vi->major = skeldev->fw.firmware_version.major; + vi->minor = skeldev->fw.firmware_version.minor; + vi->subrel = skeldev->fw.firmware_version.subrel; + + return 0; +} + +static int skeleton_rawdev_firmware_load(struct rte_rawdev *dev, + rte_rawdev_obj_t firmware_buf) +{ + struct skeleton_rawdev *skeldev; + + SKELETON_PMD_FUNC_TRACE(); + + skeldev = skeleton_rawdev_get_priv(dev); + + /* firmware_buf is a mmaped, possibly DMA'able area, buffer. Being + * dummy, all this does is check if firmware_buf is not NULL and + * sets the state of the firmware. + */ + if (!firmware_buf) + return -EINVAL; + + skeldev->fw.firmware_state = SKELETON_FW_LOADED; + + return 0; +} + +static int skeleton_rawdev_firmware_unload(struct rte_rawdev *dev) +{ + struct skeleton_rawdev *skeldev; + + SKELETON_PMD_FUNC_TRACE(); + + skeldev = skeleton_rawdev_get_priv(dev); + + skeldev->fw.firmware_state = SKELETON_FW_READY; + + return 0; +} + +static const struct rte_rawdev_ops skeleton_rawdev_ops = { + .dev_info_get = skeleton_rawdev_info_get, + .dev_configure = skeleton_rawdev_configure, + .dev_start = skeleton_rawdev_start, + .dev_stop = skeleton_rawdev_stop, + .dev_close = skeleton_rawdev_close, + .dev_reset = skeleton_rawdev_reset, + + .queue_def_conf = skeleton_rawdev_queue_def_conf, + .queue_setup = skeleton_rawdev_queue_setup, + .queue_release = skeleton_rawdev_queue_release, + + .attr_get = skeleton_rawdev_get_attr, + .attr_set = skeleton_rawdev_set_attr, + + .enqueue_bufs = skeleton_rawdev_enqueue_bufs, + .dequeue_bufs = skeleton_rawdev_dequeue_bufs, + + .dump = skeleton_rawdev_dump, + + .xstats_get = NULL, + .xstats_get_names = NULL, + .xstats_get_by_name = NULL, + .xstats_reset = NULL, + + .firmware_status_get = skeleton_rawdev_firmware_status_get, + .firmware_version_get = skeleton_rawdev_firmware_version_get, + .firmware_load = skeleton_rawdev_firmware_load, + .firmware_unload = skeleton_rawdev_firmware_unload, + + .dev_selftest = test_rawdev_skeldev, +}; + +static int +skeleton_rawdev_create(const char *name, + struct rte_vdev_device *vdev, + int socket_id) +{ + int ret = 0, i; + struct rte_rawdev *rawdev = NULL; + struct skeleton_rawdev *skeldev = NULL; + + if (!name) { + SKELETON_PMD_ERR("Invalid name of the device!"); + ret = -EINVAL; + goto cleanup; + } + + /* Allocate device structure */ + rawdev = rte_rawdev_pmd_allocate(name, sizeof(struct skeleton_rawdev), + socket_id); + if (rawdev == NULL) { + SKELETON_PMD_ERR("Unable to allocate rawdevice"); + ret = -EINVAL; + goto cleanup; + } + + rawdev->dev_ops = &skeleton_rawdev_ops; + rawdev->device = &vdev->device; + rawdev->driver_name = vdev->device.driver->name; + + skeldev = skeleton_rawdev_get_priv(rawdev); + + skeldev->device_id = SKELETON_DEVICE_ID; + skeldev->vendor_id = SKELETON_VENDOR_ID; + skeldev->capabilities = SKELETON_DEFAULT_CAPA; + + memset(&skeldev->fw, 0, sizeof(struct skeleton_firmware)); + + skeldev->fw.firmware_state = SKELETON_FW_READY; + skeldev->fw.firmware_version.major = SKELETON_MAJOR_VER; + skeldev->fw.firmware_version.minor = SKELETON_MINOR_VER; + skeldev->fw.firmware_version.subrel = SKELETON_SUB_VER; + + skeldev->device_state = SKELETON_DEV_STOPPED; + + /* Reset/set to default queue configuration for this device */ + for (i = 0; i < SKELETON_MAX_QUEUES; i++) { + skeldev->queues[i].state = SKELETON_QUEUE_DETACH; + skeldev->queues[i].depth = SKELETON_QUEUE_DEF_DEPTH; + } + + /* Clear all allocated queue buffers */ + for (i = 0; i < SKELETON_MAX_QUEUES; i++) + clear_queue_bufs(i); + + return ret; + +cleanup: + if (rawdev) + rte_rawdev_pmd_release(rawdev); + + return ret; +} + +static int +skeleton_rawdev_destroy(const char *name) +{ + int ret; + struct rte_rawdev *rdev; + + if (!name) { + SKELETON_PMD_ERR("Invalid device name"); + return -EINVAL; + } + + rdev = rte_rawdev_pmd_get_named_dev(name); + if (!rdev) { + SKELETON_PMD_ERR("Invalid device name (%s)", name); + return -EINVAL; + } + + /* rte_rawdev_close is called by pmd_release */ + ret = rte_rawdev_pmd_release(rdev); + if (ret) + SKELETON_PMD_DEBUG("Device cleanup failed"); + + return 0; +} + +static int +skeldev_get_selftest(const char *key __rte_unused, + const char *value, + void *opaque) +{ + int *flag = opaque; + *flag = atoi(value); + return 0; +} + +static int +skeldev_parse_vdev_args(struct rte_vdev_device *vdev) +{ + int selftest = 0; + const char *name; + const char *params; + + static const char *const args[] = { + SKELETON_SELFTEST_ARG, + NULL + }; + + name = rte_vdev_device_name(vdev); + + params = rte_vdev_device_args(vdev); + if (params != NULL && params[0] != '\0') { + struct rte_kvargs *kvlist = rte_kvargs_parse(params, args); + + if (!kvlist) { + SKELETON_PMD_INFO( + "Ignoring unsupported params supplied '%s'", + name); + } else { + int ret = rte_kvargs_process(kvlist, + SKELETON_SELFTEST_ARG, + skeldev_get_selftest, &selftest); + if (ret != 0 || (selftest < 0 || selftest > 1)) { + SKELETON_PMD_ERR("%s: Error in parsing args", + name); + rte_kvargs_free(kvlist); + ret = -1; /* enforce if selftest is invalid */ + return ret; + } + } + + rte_kvargs_free(kvlist); + } + + return selftest; +} + +static int +skeleton_rawdev_probe(struct rte_vdev_device *vdev) +{ + const char *name; + int selftest = 0, ret = 0; + + + name = rte_vdev_device_name(vdev); + /* More than one instance is not supported */ + if (skeldev_init_once) { + SKELETON_PMD_ERR("Multiple instance not supported for %s", + name); + return -EINVAL; + } + + SKELETON_PMD_INFO("Init %s on NUMA node %d", name, rte_socket_id()); + + selftest = skeldev_parse_vdev_args(vdev); + /* In case of invalid argument, selftest != 1; ignore other values */ + + ret = skeleton_rawdev_create(name, vdev, rte_socket_id()); + if (!ret) { + /* In case command line argument for 'selftest' was passed; + * if invalid arguments were passed, execution continues but + * without selftest. + */ + if (selftest == 1) + test_rawdev_skeldev(); + } + + /* Device instance created; Second instance not possible */ + skeldev_init_once = 1; + + return ret; +} + +static int +skeleton_rawdev_remove(struct rte_vdev_device *vdev) +{ + const char *name; + int ret; + + name = rte_vdev_device_name(vdev); + + SKELETON_PMD_INFO("Closing %s on NUMA node %d", name, rte_socket_id()); + + ret = skeleton_rawdev_destroy(name); + if (!ret) + skeldev_init_once = 0; + + return ret; +} + +static struct rte_vdev_driver skeleton_pmd_drv = { + .probe = skeleton_rawdev_probe, + .remove = skeleton_rawdev_remove +}; + +RTE_PMD_REGISTER_VDEV(SKELETON_PMD_RAWDEV_NAME, skeleton_pmd_drv); + +RTE_INIT(skeleton_pmd_init_log); + +static void +skeleton_pmd_init_log(void) +{ + skeleton_pmd_logtype = rte_log_register("rawdev.skeleton"); + if (skeleton_pmd_logtype >= 0) + rte_log_set_level(skeleton_pmd_logtype, RTE_LOG_INFO); +} diff --git a/drivers/raw/skeleton_rawdev/skeleton_rawdev.h b/drivers/raw/skeleton_rawdev/skeleton_rawdev.h new file mode 100644 index 00000000..5045b592 --- /dev/null +++ b/drivers/raw/skeleton_rawdev/skeleton_rawdev.h @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright 2017 NXP + */ + +#ifndef __SKELETON_RAWDEV_H__ +#define __SKELETON_RAWDEV_H__ + +#include <rte_rawdev.h> + +extern int skeleton_pmd_logtype; + +#define SKELETON_PMD_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, skeleton_pmd_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define SKELETON_PMD_FUNC_TRACE() SKELETON_PMD_LOG(DEBUG, ">>") + +#define SKELETON_PMD_DEBUG(fmt, args...) \ + SKELETON_PMD_LOG(DEBUG, fmt, ## args) +#define SKELETON_PMD_INFO(fmt, args...) \ + SKELETON_PMD_LOG(INFO, fmt, ## args) +#define SKELETON_PMD_ERR(fmt, args...) \ + SKELETON_PMD_LOG(ERR, fmt, ## args) +#define SKELETON_PMD_WARN(fmt, args...) \ + SKELETON_PMD_LOG(WARNING, fmt, ## args) +/* Macros for self test application */ +#define SKELETON_TEST_INFO SKELETON_PMD_INFO +#define SKELETON_TEST_DEBUG SKELETON_PMD_DEBUG +#define SKELETON_TEST_ERR SKELETON_PMD_ERR +#define SKELETON_TEST_WARN SKELETON_PMD_WARN + +#define SKELETON_SELFTEST_ARG ("selftest") + +#define SKELETON_VENDOR_ID 0x10 +#define SKELETON_DEVICE_ID 0x01 + +#define SKELETON_MAJOR_VER 1 +#define SKELETON_MINOR_VER 0 +#define SKELETON_SUB_VER 0 + +#define SKELETON_MAX_QUEUES 1 + +enum skeleton_firmware_state { + SKELETON_FW_READY, + SKELETON_FW_LOADED, + SKELETON_FW_ERROR +}; + +enum skeleton_device_state { + SKELETON_DEV_RUNNING, + SKELETON_DEV_STOPPED +}; + +enum skeleton_queue_state { + SKELETON_QUEUE_DETACH, + SKELETON_QUEUE_ATTACH +}; + +#define SKELETON_QUEUE_DEF_DEPTH 10 +#define SKELETON_QUEUE_MAX_DEPTH 25 + +struct skeleton_firmware_version_info { + uint8_t major; + uint8_t minor; + uint8_t subrel; +}; + +struct skeleton_firmware { + /**< Device firmware information */ + struct skeleton_firmware_version_info firmware_version; + /**< Device state */ + enum skeleton_firmware_state firmware_state; + +}; + +#define SKELETON_MAX_ATTRIBUTES 10 +#define SKELETON_ATTRIBUTE_NAME_MAX 20 + +struct skeleton_rawdev_attributes { + /**< Name of the attribute */ + char *name; + /**< Value or reference of value of attribute */ + uint64_t value; +}; + +/**< Device supports firmware loading/unloading */ +#define SKELETON_CAPA_FW_LOAD 0x0001 +/**< Device supports firmware reset */ +#define SKELETON_CAPA_FW_RESET 0x0002 +/**< Device support queue based communication */ +#define SKELETON_CAPA_QUEUES 0x0004 +/**< Default Capabilities: FW_LOAD, FW_RESET, QUEUES */ +#define SKELETON_DEFAULT_CAPA 0x7 + +struct skeleton_rawdev_queue { + uint8_t state; + uint32_t depth; +}; + +struct skeleton_rawdev { + uint16_t device_id; + uint16_t vendor_id; + uint16_t num_queues; + /**< One of SKELETON_CAPA_* */ + uint16_t capabilities; + /**< State of device; linked to firmware state */ + enum skeleton_device_state device_state; + /**< Firmware configuration */ + struct skeleton_firmware fw; + /**< Collection of all communication channels - which can be referred + * to as queues. + */ + struct skeleton_rawdev_queue queues[SKELETON_MAX_QUEUES]; + /**< Global table containing various pre-defined and user-defined + * attributes. + */ + struct skeleton_rawdev_attributes attr[SKELETON_MAX_ATTRIBUTES]; + struct rte_device *device; +}; + +struct skeleton_rawdev_conf { + uint16_t num_queues; + unsigned int capabilities; + enum skeleton_device_state device_state; + enum skeleton_firmware_state firmware_state; +}; + +static inline struct skeleton_rawdev * +skeleton_rawdev_get_priv(const struct rte_rawdev *rawdev) +{ + return rawdev->dev_private; +} + +int test_rawdev_skeldev(void); + +#endif /* __SKELETON_RAWDEV_H__ */ diff --git a/drivers/raw/skeleton_rawdev/skeleton_rawdev_test.c b/drivers/raw/skeleton_rawdev/skeleton_rawdev_test.c new file mode 100644 index 00000000..795f24bc --- /dev/null +++ b/drivers/raw/skeleton_rawdev/skeleton_rawdev_test.c @@ -0,0 +1,450 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright 2017 NXP + */ + +#include <rte_common.h> +#include <rte_mbuf.h> +#include <rte_malloc.h> +#include <rte_memcpy.h> +#include <rte_dev.h> +#include <rte_rawdev.h> +#include <rte_bus_vdev.h> +#include <rte_test.h> + +/* Using relative path as skeleton_rawdev is not part of exported headers */ +#include "skeleton_rawdev.h" + +#define TEST_DEV_ID 0 +#define TEST_DEV_NAME "rawdev_skeleton" + +#define SKELDEV_LOGS(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, skeleton_pmd_logtype, fmt "\n", \ + ##args) + +#define SKELDEV_TEST_INFO(fmt, args...) \ + SKELDEV_LOGS(INFO, fmt, ## args) +#define SKELDEV_TEST_DEBUG(fmt, args...) \ + SKELDEV_LOGS(DEBUG, fmt, ## args) + +#define SKELDEV_TEST_RUN(setup, teardown, test) \ + skeldev_test_run(setup, teardown, test, #test) + +#define TEST_SUCCESS 0 +#define TEST_FAILED -1 + +static int total; +static int passed; +static int failed; +static int unsupported; + +static int +testsuite_setup(void) +{ + uint8_t count; + count = rte_rawdev_count(); + if (!count) { + SKELDEV_TEST_INFO("\tNo existing rawdev; " + "Creating 'skeldev_rawdev'"); + return rte_vdev_init(TEST_DEV_NAME, NULL); + } + + return TEST_SUCCESS; +} + +static void local_teardown(void); + +static void +testsuite_teardown(void) +{ + local_teardown(); +} + +static void +local_teardown(void) +{ + rte_vdev_uninit(TEST_DEV_NAME); +} + +static int +test_rawdev_count(void) +{ + uint8_t count; + count = rte_rawdev_count(); + RTE_TEST_ASSERT(count > 0, "Invalid rawdev count %" PRIu8, count); + return TEST_SUCCESS; +} + +static int +test_rawdev_get_dev_id(void) +{ + int ret; + ret = rte_rawdev_get_dev_id("invalid_rawdev_device"); + RTE_TEST_ASSERT_FAIL(ret, "Expected <0 for invalid dev name ret=%d", + ret); + return TEST_SUCCESS; +} + +static int +test_rawdev_socket_id(void) +{ + int socket_id; + socket_id = rte_rawdev_socket_id(TEST_DEV_ID); + RTE_TEST_ASSERT(socket_id != -EINVAL, + "Failed to get socket_id %d", socket_id); + socket_id = rte_rawdev_socket_id(RTE_RAWDEV_MAX_DEVS); + RTE_TEST_ASSERT(socket_id == -EINVAL, + "Expected -EINVAL %d", socket_id); + + return TEST_SUCCESS; +} + +static int +test_rawdev_info_get(void) +{ + int ret; + struct rte_rawdev_info rdev_info = {0}; + struct skeleton_rawdev_conf skel_conf = {0}; + + ret = rte_rawdev_info_get(TEST_DEV_ID, NULL); + RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret); + + rdev_info.dev_private = &skel_conf; + + ret = rte_rawdev_info_get(TEST_DEV_ID, &rdev_info); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get raw dev info"); + + return TEST_SUCCESS; +} + +static int +test_rawdev_configure(void) +{ + int ret; + struct rte_rawdev_info rdev_info = {0}; + struct skeleton_rawdev_conf rdev_conf_set = {0}; + struct skeleton_rawdev_conf rdev_conf_get = {0}; + + /* Check invalid configuration */ + ret = rte_rawdev_configure(TEST_DEV_ID, NULL); + RTE_TEST_ASSERT(ret == -EINVAL, + "Null configure; Expected -EINVAL, got %d", ret); + + /* Valid configuration test */ + rdev_conf_set.num_queues = 1; + rdev_conf_set.capabilities = SKELETON_CAPA_FW_LOAD | + SKELETON_CAPA_FW_RESET; + + rdev_info.dev_private = &rdev_conf_set; + ret = rte_rawdev_configure(TEST_DEV_ID, + (rte_rawdev_obj_t)&rdev_info); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure rawdev (%d)", ret); + + rdev_info.dev_private = &rdev_conf_get; + ret = rte_rawdev_info_get(TEST_DEV_ID, + (rte_rawdev_obj_t)&rdev_info); + RTE_TEST_ASSERT_SUCCESS(ret, + "Failed to obtain rawdev configuration (%d)", + ret); + + RTE_TEST_ASSERT_EQUAL(rdev_conf_set.num_queues, + rdev_conf_get.num_queues, + "Configuration test failed; num_queues (%d)(%d)", + rdev_conf_set.num_queues, + rdev_conf_get.num_queues); + RTE_TEST_ASSERT_EQUAL(rdev_conf_set.capabilities, + rdev_conf_get.capabilities, + "Configuration test failed; capabilities"); + + return TEST_SUCCESS; +} + +static int +test_rawdev_queue_default_conf_get(void) +{ + int ret, i; + struct rte_rawdev_info rdev_info = {0}; + struct skeleton_rawdev_conf rdev_conf_get = {0}; + struct skeleton_rawdev_queue q = {0}; + + /* Get the current configuration */ + rdev_info.dev_private = &rdev_conf_get; + ret = rte_rawdev_info_get(TEST_DEV_ID, + (rte_rawdev_obj_t)&rdev_info); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain rawdev configuration (%d)", + ret); + + /* call to test_rawdev_configure would have set the num_queues = 1 */ + RTE_TEST_ASSERT_SUCCESS(!(rdev_conf_get.num_queues > 0), + "Invalid number of queues (%d). Expected 1", + rdev_conf_get.num_queues); + /* All queues by default should have state = DETACH and + * depth = DEF_DEPTH + */ + for (i = 0; i < rdev_conf_get.num_queues; i++) { + rte_rawdev_queue_conf_get(TEST_DEV_ID, i, &q); + RTE_TEST_ASSERT_EQUAL(q.depth, SKELETON_QUEUE_DEF_DEPTH, + "Invalid default depth of queue (%d)", + q.depth); + RTE_TEST_ASSERT_EQUAL(q.state, SKELETON_QUEUE_DETACH, + "Invalid default state of queue (%d)", + q.state); + } + + return TEST_SUCCESS; +} + +static int +test_rawdev_queue_setup(void) +{ + int ret; + struct rte_rawdev_info rdev_info = {0}; + struct skeleton_rawdev_conf rdev_conf_get = {0}; + struct skeleton_rawdev_queue qset = {0}; + struct skeleton_rawdev_queue qget = {0}; + + /* Get the current configuration */ + rdev_info.dev_private = &rdev_conf_get; + ret = rte_rawdev_info_get(TEST_DEV_ID, + (rte_rawdev_obj_t)&rdev_info); + RTE_TEST_ASSERT_SUCCESS(ret, + "Failed to obtain rawdev configuration (%d)", + ret); + + /* call to test_rawdev_configure would have set the num_queues = 1 */ + RTE_TEST_ASSERT_SUCCESS(!(rdev_conf_get.num_queues > 0), + "Invalid number of queues (%d). Expected 1", + rdev_conf_get.num_queues); + + /* Modify the queue depth for Queue 0 and attach it */ + qset.depth = 15; + qset.state = SKELETON_QUEUE_ATTACH; + ret = rte_rawdev_queue_setup(TEST_DEV_ID, 0, &qset); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup queue (%d)", ret); + + /* Now, fetching the queue 0 should show depth as 15 */ + ret = rte_rawdev_queue_conf_get(TEST_DEV_ID, 0, &qget); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get queue config (%d)", ret); + + RTE_TEST_ASSERT_EQUAL(qset.depth, qget.depth, + "Failed to set queue depth: Need(%d), has(%d)", + qset.depth, qget.depth); + + return TEST_SUCCESS; +} + +/* After executing test_rawdev_queue_setup, queue_id=0 would have depth as 15. + * Releasing should set it back to default. state would set to DETACH + */ +static int +test_rawdev_queue_release(void) +{ + int ret; + struct skeleton_rawdev_queue qget = {0}; + + /* Now, fetching the queue 0 should show depth as 100 */ + ret = rte_rawdev_queue_release(TEST_DEV_ID, 0); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to release queue 0; (%d)", ret); + + /* Now, fetching the queue 0 should show depth as default */ + ret = rte_rawdev_queue_conf_get(TEST_DEV_ID, 0, &qget); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get queue config (%d)", ret); + + RTE_TEST_ASSERT_EQUAL(qget.depth, SKELETON_QUEUE_DEF_DEPTH, + "Release of Queue 0 failed; (depth)"); + + RTE_TEST_ASSERT_EQUAL(qget.state, SKELETON_QUEUE_DETACH, + "Release of Queue 0 failed; (state)"); + + return TEST_SUCCESS; +} + +static int +test_rawdev_attr_set_get(void) +{ + int ret; + int *dummy_value; + uint64_t ret_value; + + /* Set an attribute and fetch it */ + ret = rte_rawdev_set_attr(TEST_DEV_ID, "Test1", 100); + RTE_TEST_ASSERT(!ret, "Unable to set an attribute (Test1)"); + + dummy_value = malloc(sizeof(int)); + if (!dummy_value) + RTE_TEST_ASSERT(1, "Unable to allocate memory (dummy_value)"); + + *dummy_value = 200; + ret = rte_rawdev_set_attr(TEST_DEV_ID, "Test2", (uintptr_t)dummy_value); + + /* Check if attributes have been set */ + ret = rte_rawdev_get_attr(TEST_DEV_ID, "Test1", &ret_value); + RTE_TEST_ASSERT_EQUAL(ret_value, 100, + "Attribute (Test1) not set correctly (%" PRIu64 ")", + ret_value); + + ret_value = 0; + ret = rte_rawdev_get_attr(TEST_DEV_ID, "Test2", &ret_value); + RTE_TEST_ASSERT_EQUAL(*((int *)(uintptr_t)ret_value), 200, + "Attribute (Test2) not set correctly (%" PRIu64 ")", + ret_value); + + return TEST_SUCCESS; +} + +static int +test_rawdev_start_stop(void) +{ + int ret; + struct rte_rawdev_info rdev_info = {0}; + struct skeleton_rawdev_conf rdev_conf_get = {0}; + char *dummy_firmware = NULL; + + /* Get the current configuration */ + rdev_info.dev_private = &rdev_conf_get; + + /* Load a firmware using a dummy address area */ + dummy_firmware = rte_zmalloc("RAWDEV SKELETON", sizeof(int) * 10, 0); + RTE_TEST_ASSERT(dummy_firmware != NULL, + "Failed to create firmware memory backing"); + + ret = rte_rawdev_firmware_load(TEST_DEV_ID, dummy_firmware); + RTE_TEST_ASSERT_SUCCESS(ret, "Firmware loading failed (%d)", ret); + + /* Skeleton doesn't do anything with the firmware area - that is dummy + * and can be removed. + */ + rte_free(dummy_firmware); + dummy_firmware = NULL; + + rte_rawdev_start(TEST_DEV_ID); + ret = rte_rawdev_info_get(TEST_DEV_ID, (rte_rawdev_obj_t)&rdev_info); + RTE_TEST_ASSERT_SUCCESS(ret, + "Failed to obtain rawdev configuration (%d)", + ret); + RTE_TEST_ASSERT_EQUAL(rdev_conf_get.device_state, SKELETON_DEV_RUNNING, + "Device start failed. State is (%d)", + rdev_conf_get.device_state); + + rte_rawdev_stop(TEST_DEV_ID); + ret = rte_rawdev_info_get(TEST_DEV_ID, (rte_rawdev_obj_t)&rdev_info); + RTE_TEST_ASSERT_SUCCESS(ret, + "Failed to obtain rawdev configuration (%d)", + ret); + RTE_TEST_ASSERT_EQUAL(rdev_conf_get.device_state, SKELETON_DEV_STOPPED, + "Device stop failed. State is (%d)", + rdev_conf_get.device_state); + + /* Unloading the firmware once device is stopped */ + ret = rte_rawdev_firmware_unload(TEST_DEV_ID); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to unload firmware (%d)", ret); + + return TEST_SUCCESS; +} + +static int +test_rawdev_enqdeq(void) +{ + int ret; + unsigned int count = 1; + uint16_t queue_id = 0; + struct rte_rawdev_buf buffers[1]; + struct rte_rawdev_buf *deq_buffers = NULL; + + buffers[0].buf_addr = malloc(strlen(TEST_DEV_NAME) + 3); + if (!buffers[0].buf_addr) + goto cleanup; + snprintf(buffers[0].buf_addr, strlen(TEST_DEV_NAME) + 2, "%s%d", + TEST_DEV_NAME, 0); + + ret = rte_rawdev_enqueue_buffers(TEST_DEV_ID, + (struct rte_rawdev_buf **)&buffers, + count, &queue_id); + RTE_TEST_ASSERT_EQUAL((unsigned int)ret, count, + "Unable to enqueue buffers"); + + deq_buffers = malloc(sizeof(struct rte_rawdev_buf) * count); + if (!deq_buffers) + goto cleanup; + + ret = rte_rawdev_dequeue_buffers(TEST_DEV_ID, + (struct rte_rawdev_buf **)&deq_buffers, + count, &queue_id); + RTE_TEST_ASSERT_EQUAL((unsigned int)ret, count, + "Unable to dequeue buffers"); + + if (deq_buffers) + free(deq_buffers); + + return TEST_SUCCESS; +cleanup: + if (buffers[0].buf_addr) + free(buffers[0].buf_addr); + if (deq_buffers) + free(deq_buffers); + + return TEST_FAILED; +} + +static void skeldev_test_run(int (*setup)(void), + void (*teardown)(void), + int (*test)(void), + const char *name) +{ + int ret = 0; + + if (setup) { + ret = setup(); + if (ret < 0) { + SKELDEV_TEST_INFO("Error setting up test %s", name); + unsupported++; + } + } + + if (test) { + ret = test(); + if (ret < 0) { + failed++; + SKELDEV_TEST_INFO("%s Failed", name); + } else { + passed++; + SKELDEV_TEST_DEBUG("%s Passed", name); + } + } + + if (teardown) + teardown(); + + total++; +} + +int +test_rawdev_skeldev(void) +{ + testsuite_setup(); + + SKELDEV_TEST_RUN(NULL, NULL, test_rawdev_count); + SKELDEV_TEST_RUN(NULL, NULL, test_rawdev_get_dev_id); + SKELDEV_TEST_RUN(NULL, NULL, test_rawdev_socket_id); + SKELDEV_TEST_RUN(NULL, NULL, test_rawdev_info_get); + SKELDEV_TEST_RUN(NULL, NULL, test_rawdev_configure); + SKELDEV_TEST_RUN(test_rawdev_configure, NULL, + test_rawdev_queue_default_conf_get); + SKELDEV_TEST_RUN(test_rawdev_configure, NULL, test_rawdev_queue_setup); + SKELDEV_TEST_RUN(test_rawdev_queue_setup, NULL, + test_rawdev_queue_release); + SKELDEV_TEST_RUN(NULL, NULL, test_rawdev_attr_set_get); + SKELDEV_TEST_RUN(NULL, NULL, test_rawdev_start_stop); + SKELDEV_TEST_RUN(test_rawdev_queue_setup, NULL, test_rawdev_enqdeq); + + testsuite_teardown(); + + SKELDEV_TEST_INFO("Total tests : %d", total); + SKELDEV_TEST_INFO("Passed : %d", passed); + SKELDEV_TEST_INFO("Failed : %d", failed); + SKELDEV_TEST_INFO("Not supported : %d", unsupported); + + if (failed) + return -1; + + return 0; +}; |