@@ -1546,6 +1546,11 @@ M: Chenbo Xia <chenbo.xia@intel.com>
M: Xiuchun Lu <xiuchun.lu@intel.com>
F: lib/librte_vfio_user/
+Emudev - EXPERIMENTAL
+M: Chenbo Xia <chenbo.xia@intel.com>
+M: Xiuchun Lu <xiuchun.lu@intel.com>
+F: lib/librte_emudev/
+
Test Applications
-----------------
new file mode 100644
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2020 Intel Corporation
+
+sources = files('rte_emudev.c')
+headers = files('rte_emudev.h', 'rte_emudev_vdev.h')
new file mode 100644
@@ -0,0 +1,502 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <string.h>
+
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+
+#include "rte_emudev.h"
+
+#define RTE_MAX_EMU_DEV 1024
+struct rte_emudev rte_emu_devices[RTE_MAX_EMU_DEV];
+
+static struct rte_emudev_global emu_dev_globals = {
+ .nb_devs = 0
+};
+
+static inline uint16_t
+rte_emu_alloc_dev_id(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < RTE_MAX_EMU_DEV; i++) {
+ if (rte_emu_devices[i].name[0] == '\0')
+ return i;
+ }
+ return RTE_MAX_EMU_DEV;
+}
+
+uint8_t
+rte_emudev_count(void)
+{
+ return emu_dev_globals.nb_devs;
+}
+
+int
+rte_emudev_get_dev_id(const char *name)
+{
+ uint16_t i;
+
+ if (!name) {
+ RTE_EMUDEV_LOG(ERR, "Failed to get device ID: "
+ "NULL device name\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < emu_dev_globals.nb_devs; i++)
+ if (!strncmp(rte_emu_devices[i].name, name,
+ RTE_EMU_NAME_MAX_LEN))
+ return i;
+
+ return -ENODEV;
+}
+
+struct rte_emudev *
+rte_emudev_allocate(const char *name)
+{
+ uint16_t dev_id;
+ struct rte_emudev *emu_dev = NULL;
+ size_t name_len;
+
+ if (!name) {
+ RTE_EMUDEV_LOG(ERR, "Failed to allocate emudev: "
+ "NULL device name\n");
+ return NULL;
+ }
+
+ name_len = strnlen(name, RTE_EMU_NAME_MAX_LEN);
+ if (!name_len) {
+ RTE_EMUDEV_LOG(ERR, "Emulated device name has zero length\n");
+ return NULL;
+ }
+
+ if (name_len >= RTE_EMU_NAME_MAX_LEN) {
+ RTE_EMUDEV_LOG(ERR, "Emulated device name too long\n");
+ return NULL;
+ }
+
+ if (rte_emudev_allocated(name) != NULL) {
+ RTE_EMUDEV_LOG(ERR,
+ "Emulated device with name %s already exists\n",
+ name);
+ return NULL;
+ }
+
+ dev_id = rte_emu_alloc_dev_id();
+ if (dev_id == RTE_MAX_EMU_DEV) {
+ RTE_EMUDEV_LOG(ERR, "Reached max number of Emulated device\n");
+ return NULL;
+ }
+
+ emu_dev = &rte_emu_devices[dev_id];
+ strncpy(emu_dev->name, name, sizeof(emu_dev->name));
+ emu_dev->dev_id = dev_id;
+ emu_dev_globals.nb_devs++;
+
+ return emu_dev;
+}
+
+int
+rte_emudev_release(struct rte_emudev *dev)
+{
+ if (!dev)
+ return -EINVAL;
+
+ if (dev->priv_data) {
+ rte_free(dev->priv_data);
+ dev->priv_data = NULL;
+ }
+
+ memset(dev, 0, sizeof(*dev));
+ emu_dev_globals.nb_devs--;
+ return 0;
+}
+
+struct rte_emudev *
+rte_emudev_allocated(const char *name)
+{
+ unsigned int i;
+
+ if (!name) {
+ RTE_EMUDEV_LOG(ERR, "Failed to find emudev: "
+ "NULL device name\n");
+ return NULL;
+ }
+
+ for (i = 0; i < RTE_MAX_EMU_DEV; i++) {
+ if (rte_emu_devices[i].dev_ops != NULL &&
+ strcmp(rte_emu_devices[i].device->name, name) == 0)
+ return &rte_emu_devices[i];
+ }
+ return NULL;
+}
+
+int
+rte_emudev_is_valid_id(uint16_t dev_id)
+{
+ if (dev_id >= RTE_MAX_EMU_DEV ||
+ rte_emu_devices[dev_id].name[0] == '\0')
+ return 0;
+ else
+ return 1;
+}
+
+int
+rte_emudev_selftest(uint16_t dev_id)
+{
+ RTE_EMU_CHECK_VALID_DEVID_ERR(dev_id);
+
+ struct rte_emudev *dev = &rte_emu_devices[dev_id];
+
+ RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_selftest, -ENOTSUP);
+
+ return (*dev->dev_ops->dev_selftest)(dev_id);
+}
+
+
+int
+rte_emudev_start(uint16_t dev_id)
+{
+ struct rte_emudev *dev;
+ int ret;
+
+ RTE_EMU_CHECK_VALID_DEVID_ERR(dev_id);
+
+ dev = &rte_emu_devices[dev_id];
+
+ if (dev->started) {
+ RTE_EMUDEV_LOG(ERR, "Device %u already started\n", dev_id);
+ return 0;
+ }
+
+ RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_start, -ENOTSUP);
+
+ ret = (*dev->dev_ops->dev_start)(dev);
+ if (ret)
+ return ret;
+
+ dev->started = 1;
+ return 0;
+}
+
+void
+rte_emudev_stop(uint16_t dev_id)
+{
+ struct rte_emudev *dev;
+
+ RTE_EMU_CHECK_VALID_DEVID(dev_id);
+
+ dev = &rte_emu_devices[dev_id];
+
+ if (!dev->started) {
+ RTE_EMUDEV_LOG(ERR, "Device %u already stopped\n", dev_id);
+ return;
+ }
+
+ RTE_FUNC_PTR_OR_RET(*dev->dev_ops->dev_stop);
+
+ (*dev->dev_ops->dev_stop)(dev);
+
+ dev->started = 0;
+}
+
+int
+rte_emudev_configure(uint16_t dev_id, struct rte_emudev_info *dev_conf)
+{
+ struct rte_emudev *dev;
+
+ RTE_EMU_CHECK_VALID_DEVID_ERR(dev_id);
+
+ dev = &rte_emu_devices[dev_id];
+
+ if (!dev_conf)
+ return -EINVAL;
+
+ if (dev->started) {
+ RTE_EMUDEV_LOG(ERR, "Device %u must be stopped "
+ "before configure\n", dev_id);
+ return -EBUSY;
+ }
+
+ RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_configure, -ENOTSUP);
+
+ if (strcmp(dev_conf->dev_type, dev->dev_info.dev_type)) {
+ RTE_EMUDEV_LOG(ERR, "Wrong device type to configure"
+ " for device %u\n", dev_id);
+ return -EINVAL;
+ }
+
+ return (*dev->dev_ops->dev_configure)(dev, dev_conf);
+}
+
+int
+rte_emudev_close(uint16_t dev_id)
+{
+ struct rte_emudev *dev;
+
+ RTE_EMU_CHECK_VALID_DEVID_ERR(dev_id);
+
+ dev = &rte_emu_devices[dev_id];
+
+ if (dev->started) {
+ RTE_EMUDEV_LOG(ERR, "Device %u must be stopped "
+ "before close\n", dev_id);
+ return -EBUSY;
+ }
+
+ RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_close, -ENOTSUP);
+
+ (*dev->dev_ops->dev_close)(dev);
+
+ rte_emudev_release(dev);
+ return 0;
+}
+
+int
+rte_emudev_subscribe_event(uint16_t dev_id,
+ const rte_emudev_event_chnl_t ev_chnl)
+{
+ struct rte_emudev *dev;
+
+ RTE_EMU_CHECK_VALID_DEVID_ERR(dev_id);
+
+ if (!ev_chnl) {
+ RTE_EMUDEV_LOG(ERR, "Failed to subscribe because of NULL"
+ " event channel for device %u\n", dev_id);
+ return -EINVAL;
+ }
+
+ dev = &rte_emu_devices[dev_id];
+
+ RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->subscribe_event, -ENOTSUP);
+
+ return (*dev->dev_ops->subscribe_event)(dev, ev_chnl);
+}
+
+int
+rte_emudev_unsubscribe_event(uint16_t dev_id,
+ const rte_emudev_event_chnl_t ev_chnl)
+{
+ struct rte_emudev *dev;
+
+ RTE_EMU_CHECK_VALID_DEVID_ERR(dev_id);
+
+ if (!ev_chnl) {
+ RTE_EMUDEV_LOG(ERR, "Failed to unsubscribe because of NULL"
+ " event channel for device %u\n", dev_id);
+ return -EINVAL;
+ }
+
+ dev = &rte_emu_devices[dev_id];
+
+ RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->unsubscribe_event, -ENOTSUP);
+
+ return (*dev->dev_ops->unsubscribe_event)(dev, ev_chnl);
+}
+
+int
+rte_emudev_get_dev_info(uint16_t dev_id, struct rte_emudev_info *info)
+{
+ struct rte_emudev *dev;
+ struct rte_emudev_info *dev_info;
+
+ RTE_EMU_CHECK_VALID_DEVID_ERR(dev_id);
+
+ if (!info) {
+ RTE_EMUDEV_LOG(ERR, "NULL device info for device %u\n",
+ dev_id);
+ return -EINVAL;
+ }
+
+ dev = &rte_emu_devices[dev_id];
+ dev_info = &dev->dev_info;
+
+ strcpy(info->dev_type, dev_info->dev_type);
+ info->max_qp_num = dev_info->max_qp_num;
+ info->region_num = dev_info->region_num;
+
+ RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_info_get, -ENOTSUP);
+
+ return (*dev->dev_ops->dev_info_get)(dev, info->dev_priv);
+}
+
+int
+rte_emudev_get_mem_table(uint16_t dev_id, rte_emudev_mem_table_t *tb)
+{
+ struct rte_emudev *dev;
+
+ RTE_EMU_CHECK_VALID_DEVID_ERR(dev_id);
+
+ if (!tb) {
+ RTE_EMUDEV_LOG(ERR, "NULL memory table for device %u\n",
+ dev_id);
+ return -EINVAL;
+ }
+
+ dev = &rte_emu_devices[dev_id];
+
+ RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_mem_table, -ENOTSUP);
+
+ return (*dev->dev_ops->get_mem_table)(dev, tb);
+}
+
+int
+rte_emudev_get_queue_info(uint16_t dev_id, uint32_t queue,
+ struct rte_emudev_q_info *info)
+{
+ struct rte_emudev *dev;
+
+ RTE_EMU_CHECK_VALID_DEVID_ERR(dev_id);
+
+ if (!info) {
+ RTE_EMUDEV_LOG(ERR, "NULL queue info for queue %d"
+ " of device %u\n", queue, dev_id);
+ return -EINVAL;
+ }
+
+ dev = &rte_emu_devices[dev_id];
+
+ if (queue >= dev->dev_info.max_qp_num * 2) {
+ RTE_EMUDEV_LOG(ERR, "Queue index of device %u exceeds max\n",
+ dev_id);
+ return -EINVAL;
+ }
+
+ RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_queue_info, -ENOTSUP);
+
+ memset(info, 0, sizeof(*info));
+
+ return (*dev->dev_ops->get_queue_info)(dev, queue, info);
+}
+
+int
+rte_emudev_get_irq_info(uint16_t dev_id, uint32_t vector,
+ struct rte_emudev_irq_info *info)
+{
+ struct rte_emudev *dev;
+
+ RTE_EMU_CHECK_VALID_DEVID_ERR(dev_id);
+
+ if (!info) {
+ RTE_EMUDEV_LOG(ERR, "NULL irq info for vector %u"
+ " of device %u\n", vector, dev_id);
+ return -EINVAL;
+ }
+
+ dev = &rte_emu_devices[dev_id];
+
+ RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_irq_info, -ENOTSUP);
+
+ memset(info, 0, sizeof(*info));
+
+ return (*dev->dev_ops->get_irq_info)(dev, vector, info);
+}
+
+int
+rte_emudev_get_db_info(uint16_t dev_id, uint32_t doorbell,
+ struct rte_emudev_db_info *info)
+{
+ struct rte_emudev *dev;
+
+ RTE_EMU_CHECK_VALID_DEVID_ERR(dev_id);
+
+ if (!info) {
+ RTE_EMUDEV_LOG(ERR, "NULL doorbell info of device %u"
+ " for id %u\n", dev_id, doorbell);
+ return -EINVAL;
+ }
+
+ dev = &rte_emu_devices[dev_id];
+
+ RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_db_info, -ENOTSUP);
+
+ memset(info, 0, sizeof(*info));
+
+ return (*dev->dev_ops->get_db_info)(dev, doorbell, info);
+}
+
+int
+rte_emudev_set_attr(uint16_t dev_id, const char *attr_name,
+ rte_emudev_attr_t attr)
+{
+ struct rte_emudev *dev;
+
+ RTE_EMU_CHECK_VALID_DEVID_ERR(dev_id);
+
+ if (!attr_name) {
+ RTE_EMUDEV_LOG(ERR, "NULL attribute name of device %u "
+ "for set\n", dev_id);
+ return -EINVAL;
+ }
+
+ if (!attr) {
+ RTE_EMUDEV_LOG(ERR, "NULL attribute of device %u "
+ "for set_attr\n", dev_id);
+ return -EINVAL;
+ }
+
+ dev = &rte_emu_devices[dev_id];
+
+ RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_attr, -ENOTSUP);
+
+ return (*dev->dev_ops->set_attr)(dev, attr_name, attr);
+}
+
+int
+rte_emudev_get_attr(uint16_t dev_id, const char *attr_name,
+ rte_emudev_attr_t attr)
+{
+ struct rte_emudev *dev;
+
+ RTE_EMU_CHECK_VALID_DEVID_ERR(dev_id);
+
+ if (!attr_name) {
+ RTE_EMUDEV_LOG(ERR, "NULL attribute name of device %u "
+ "for get\n", dev_id);
+ return -EINVAL;
+ }
+
+ if (!attr) {
+ RTE_EMUDEV_LOG(ERR, "NULL attribute of device %u "
+ "for get_attr\n", dev_id);
+ return -EINVAL;
+ }
+
+ dev = &rte_emu_devices[dev_id];
+
+ RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_attr, -ENOTSUP);
+
+ return (*dev->dev_ops->get_attr)(dev, attr_name, attr);
+}
+
+int
+rte_emudev_region_map(uint16_t dev_id, uint32_t index,
+ uint64_t *region_size, uint64_t *base_addr)
+{
+ struct rte_emudev *dev;
+
+ RTE_EMU_CHECK_VALID_DEVID_ERR(dev_id);
+
+ if (!region_size || !base_addr)
+ return -EINVAL;
+
+ dev = &rte_emu_devices[dev_id];
+
+ if (index >= dev->dev_info.region_num) {
+ RTE_EMUDEV_LOG(ERR, "Wrong region index for device %u\n",
+ dev_id);
+ return -EINVAL;
+ }
+
+ RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->region_map, -ENOTSUP);
+
+ memset(region_size, 0, sizeof(*region_size));
+ memset(base_addr, 0, sizeof(*base_addr));
+
+ return (*dev->dev_ops->region_map)(dev, index, region_size,
+ base_addr);
+}
+
+RTE_LOG_REGISTER(rte_emudev_logtype, lib.emudev, INFO);
new file mode 100644
@@ -0,0 +1,431 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_EMUDEV_H_
+#define _RTE_EMUDEV_H_
+
+#include <rte_config.h>
+#include <rte_dev.h>
+#include <rte_compat.h>
+
+#define RTE_EMU_NAME_MAX_LEN RTE_DEV_NAME_MAX_LEN
+
+extern int rte_emudev_logtype;
+
+#define RTE_EMUDEV_LOG(level, ...) \
+ rte_log(RTE_LOG_ ## level, rte_emudev_logtype, "" __VA_ARGS__)
+
+/* Macros to check for valid dev id */
+#define RTE_EMU_CHECK_VALID_DEVID_ERR(dev_id) do { \
+ if (!rte_emudev_is_valid_id(dev_id)) { \
+ RTE_EMUDEV_LOG(ERR, "Invalid dev_id=%u\n", dev_id); \
+ return -ENODEV; \
+ } \
+} while (0)
+
+#define RTE_EMU_CHECK_VALID_DEVID(dev_id) do { \
+ if (!rte_emudev_is_valid_id(dev_id)) { \
+ RTE_EMUDEV_LOG(ERR, "Invalid dev_id=%u\n", dev_id); \
+ return; \
+ } \
+} while (0)
+
+typedef void *rte_emudev_obj_t;
+typedef void *rte_emudev_attr_t;
+typedef void *rte_emudev_mem_table_t;
+typedef void *rte_emudev_event_chnl_t;
+
+struct rte_emudev;
+
+/**
+ * Global structure used for maintaining state
+ * of allocated emu devices
+ */
+struct rte_emudev_global {
+ uint8_t nb_devs; /**< Number of devices found */
+};
+
+struct rte_emudev_info {
+ char dev_type[RTE_EMU_NAME_MAX_LEN];
+ uint32_t region_num;
+ uint32_t max_qp_num;
+ rte_emudev_obj_t dev_priv;
+};
+
+struct rte_emudev_q_info {
+ uint64_t base;
+ uint64_t size;
+ int doorbell_id;
+ int irq_vector;
+};
+
+struct rte_emudev_irq_info {
+ uint32_t vector;
+ bool enable;
+ int eventfd;
+};
+
+struct rte_emudev_db_info {
+ uint32_t id;
+ uint32_t flag;
+#define RTE_EMUDEV_DB_FD (0x1 << 0)
+#define RTE_EMUDEV_DB_MEM (0x1 << 1)
+ union {
+ int eventfd;
+ struct {
+ uint64_t base;
+ uint64_t size;
+ } mem;
+ } data;
+};
+
+struct rte_emudev_ops {
+ int (*dev_start)(struct rte_emudev *dev);
+ void (*dev_stop)(struct rte_emudev *dev);
+ int (*dev_configure)(struct rte_emudev *dev,
+ struct rte_emudev_info *conf);
+ int (*dev_close)(struct rte_emudev *dev);
+ int (*dev_info_get)(struct rte_emudev *dev, rte_emudev_obj_t info);
+ int (*subscribe_event)(struct rte_emudev *dev,
+ rte_emudev_event_chnl_t ev_chnl);
+ int (*unsubscribe_event)(struct rte_emudev *dev,
+ rte_emudev_event_chnl_t ev_chnl);
+ int (*get_mem_table)(struct rte_emudev *dev,
+ rte_emudev_mem_table_t *tb);
+ int (*get_queue_info)(struct rte_emudev *dev, uint32_t queue,
+ struct rte_emudev_q_info *info);
+ int (*get_irq_info)(struct rte_emudev *dev, uint32_t vector,
+ struct rte_emudev_irq_info *info);
+ int (*get_db_info)(struct rte_emudev *dev, uint32_t doorbell,
+ struct rte_emudev_db_info *info);
+ int (*get_attr)(struct rte_emudev *dev, const char *attr_name,
+ rte_emudev_attr_t attr);
+ int (*set_attr)(struct rte_emudev *dev, const char *attr_name,
+ rte_emudev_attr_t attr);
+ int (*region_map)(struct rte_emudev *dev, uint32_t index,
+ uint64_t *region_size, uint64_t *base_addr);
+ int (*dev_selftest)(uint16_t dev_id);
+};
+
+struct rte_emudev {
+ char name[RTE_EMU_NAME_MAX_LEN];
+ uint16_t dev_id;
+ int numa_node;
+ int started;
+ struct rte_device *device;
+ struct rte_emudev_info dev_info;
+ const struct rte_emudev_ops *dev_ops;
+ void *priv_data;
+ void *backend_priv;
+} __rte_cache_aligned;
+
+/**
+ * Note that 'rte_emudev_allocate', 'rte_emudev_release' and
+ * 'rte_emudev_allocated' should be called by emulated device
+ * provider.
+ */
+
+/**
+ * Allocate a new emudev for an emulation device and returns the pointer
+ * to the emudev.
+ *
+ * @param name
+ * Name of the emudev
+ * @return
+ * Pointer to rte_emudev on success, NULL on failure
+ */
+__rte_experimental
+struct rte_emudev *
+rte_emudev_allocate(const char *name);
+
+/**
+ * Release the emudev.
+ *
+ * @param dev
+ * The emulated device
+ * @return
+ * - 0: Success, device release
+ * - <0: Failure on release
+ */
+__rte_experimental
+int
+rte_emudev_release(struct rte_emudev *dev);
+
+/**
+ * Find an emudev using name.
+ *
+ * @param name
+ * Name of the emudev
+ * @return
+ * Pointer to rte_emudev on success, NULL on failure
+ */
+__rte_experimental
+struct rte_emudev *
+rte_emudev_allocated(const char *name);
+
+/**
+ * Start an emulation device.
+ *
+ * @param dev_id
+ * Device ID of emudev
+ * @return
+ * - 0: Success, device start
+ * - <0: Failure on start
+ */
+__rte_experimental
+int
+rte_emudev_start(uint16_t dev_id);
+
+/**
+ * Stop an emulation device.
+ *
+ * @param dev_id
+ * Device ID of emudev
+ */
+__rte_experimental
+void
+rte_emudev_stop(uint16_t dev_id);
+
+/**
+ * Configure an emulation device.
+ *
+ * @param dev_id
+ * Device ID of emudev
+ * @param dev_conf
+ * Device configure info
+ * @return
+ * - 0: Success, device configured
+ * - <0: Failure on configure
+ */
+__rte_experimental
+int
+rte_emudev_configure(uint16_t dev_id, struct rte_emudev_info *dev_conf);
+
+/**
+ * Close an emulation device.
+ *
+ * @param dev_id
+ * Device ID of emudev
+ * @return
+ * - 0: Success, device close
+ * - <0: Failure on close
+ */
+__rte_experimental
+int
+rte_emudev_close(uint16_t dev_id);
+
+/* Note that below APIs should only be called by back-end (data path) driver */
+
+/**
+ * Back-end driver subscribes events of the emulated device.
+ *
+ * @param dev_id
+ * Device ID of emudev
+ * @param ev_chnl
+ * Event channel that events should be passed to
+ * @return
+ * - 0: Success, event subscribed
+ * - <0: Failure on subscribe
+ */
+__rte_experimental
+int
+rte_emudev_subscribe_event(uint16_t dev_id,
+ const rte_emudev_event_chnl_t ev_chnl);
+
+/**
+ * Back-end driver unsubscribes events of the emulated device.
+ *
+ * @param dev_id
+ * Device ID of emudev
+ * @param set
+ * Event channel that events should be passed to
+ * @return
+ * - 0: Success, event unsubscribed
+ * - <0: Failure on unsubscribe
+ */
+__rte_experimental
+int
+rte_emudev_unsubscribe_event(uint16_t dev_id,
+ const rte_emudev_event_chnl_t ev_chnl);
+
+/**
+ * Get the total number of emulated devices that have been
+ * successfully initialised.
+ *
+ * @return
+ * The total number of usable emudev.
+ */
+__rte_experimental
+uint8_t
+rte_emudev_count(void);
+
+/**
+ * Get the device identifier for the named emulated device.
+ *
+ * @param name
+ * Emulated device name to select the device identifier.
+ *
+ * @return
+ * - 0: Success, emulated device identifier returned
+ * - <0: Failure on unsubscribe
+ */
+__rte_experimental
+int
+rte_emudev_get_dev_id(const char *name);
+
+/**
+ * Back-end driver gets the device info of the emulated device.
+ *
+ * @param dev_id
+ * Device ID of emudev
+ * @return
+ * - 0: Success, emulated device info updated
+ * - <0: Failure on get device information
+ */
+__rte_experimental
+int
+rte_emudev_get_dev_info(uint16_t dev_id, struct rte_emudev_info *info);
+
+/**
+ * Get the memory table content and operations of the emulated device.
+ *
+ * @param dev_id
+ * Device ID of emudev
+ * @return
+ * - 0: Success, memory table of emulated device updated
+ * - <0: Failure on get memory table
+ */
+__rte_experimental
+int
+rte_emudev_get_mem_table(uint16_t dev_id, rte_emudev_mem_table_t *tb);
+
+/**
+ * Get queue info of the emudev.
+ *
+ * @param dev_id
+ * Device ID of emudev
+ * @param queue
+ * Queue ID of emudev
+ * @return
+ * - 0: Success, queue information of emulated device updated
+ * - <0: Failure on get queue information
+ */
+__rte_experimental
+int
+rte_emudev_get_queue_info(uint16_t dev_id, uint32_t queue,
+ struct rte_emudev_q_info *info);
+
+/**
+ * Get irq info of the emudev.
+ *
+ * @param dev_id
+ * Device ID of emudev
+ * @param vector
+ * Interrupt vector
+ * @return
+ * - 0: Success, irq information of emulated device updated
+ * - <0: Failure on get irq information
+ */
+__rte_experimental
+int
+rte_emudev_get_irq_info(uint16_t dev_id, uint32_t vector,
+ struct rte_emudev_irq_info *info);
+
+/**
+ * Get doorbell info of the emudev.
+ *
+ * @param dev_id
+ * Device ID of emudev
+ * @param doorbell
+ * Doorbell ID
+ * @return
+ * - 0: Success, doorbell information of emulated device updated
+ * - <0: Failure on get doorbell information
+ */
+__rte_experimental
+int
+rte_emudev_get_db_info(uint16_t dev_id, uint32_t doorbell,
+ struct rte_emudev_db_info *info);
+
+/**
+ * Set attribute of the emudev.
+ *
+ * @param dev_id
+ * Device ID of emudev
+ * @param attr_name
+ * Opaque object representing an attribute in implementation.
+ * @param attr
+ * Pointer to attribute
+ * @return
+ * - 0: Success, attribute set
+ * - <0: Failure on attribute set
+ */
+__rte_experimental
+int
+rte_emudev_set_attr(uint16_t dev_id, const char *attr_name,
+ rte_emudev_attr_t attr);
+
+/**
+ * Get attribute of the emudev.
+ *
+ * @param dev_id
+ * Device ID of emudev
+ * @param attr_name
+ * Opaque object representing an attribute in implementation.
+ * @return
+ * - 0: Success, attribute of emulated device updated
+ * - <0: Failure on attribute get
+ */
+__rte_experimental
+int
+rte_emudev_get_attr(uint16_t dev_id, const char *attr_name,
+ rte_emudev_attr_t attr);
+
+/**
+ * Back-end driver maps a region to the emulated device.
+ * Region name identifies the meaning of the region and the emulated
+ * device and the back-end driver should have the same definition of
+ * region name and its meaning.
+ *
+ * @param dev_id
+ * Device ID of emudev
+ * @param index
+ * Region index
+ * @param attr
+ * Pointer to attribute
+ * @return
+ * - 0: Success, region mapped
+ * - <0: Failure on region map
+ */
+__rte_experimental
+int
+rte_emudev_region_map(uint16_t dev_id, uint32_t index,
+ uint64_t *region_size, uint64_t *base_addr);
+
+/**
+ * Trigger the emudev self test.
+ *
+ * @param dev_id
+ * The identifier of the device
+ * @return
+ * - 0: Selftest successful
+ * - <0: Failure on selftest
+ */
+__rte_experimental
+int
+rte_emudev_selftest(uint16_t dev_id);
+
+/**
+ * Check if an emudev device ID is valid.
+ *
+ * @param dev_id
+ * The identifier of the device
+ * @return
+ * 0 on failure, 1 on success
+ */
+__rte_experimental
+int
+rte_emudev_is_valid_id(uint16_t dev_id);
+
+#endif /* _RTE_EMUDEV_H_ */
new file mode 100644
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_EMUDEV_VDEV_H_
+#define _RTE_EMUDEV_VDEV_H_
+
+#include <rte_bus_vdev.h>
+#include <rte_malloc.h>
+
+#include "rte_emudev.h"
+
+/**
+ * @internal
+ * Allocates a new emudev instance for an emulated device and
+ * returns the pointer to that instance for the driver to use.
+ *
+ * @param dev
+ * Pointer to virtual device
+ *
+ * @param private_data_size
+ * Size of private data structure
+ *
+ * @return
+ * A pointer to a rte_emudev or NULL if allocation failed.
+ */
+static inline struct rte_emudev *
+rte_emu_vdev_allocate(struct rte_vdev_device *dev, size_t private_data_size)
+{
+ struct rte_emudev *emu_dev;
+ const char *name = rte_vdev_device_name(dev);
+
+ emu_dev = rte_emudev_allocate(name);
+ if (!emu_dev)
+ return NULL;
+
+ if (private_data_size) {
+ emu_dev->priv_data = rte_zmalloc_socket(name,
+ private_data_size, RTE_CACHE_LINE_SIZE,
+ dev->device.numa_node);
+ if (!emu_dev->priv_data) {
+ rte_emudev_release(emu_dev);
+ return NULL;
+ }
+ }
+
+ emu_dev->device = &dev->device;
+ emu_dev->numa_node = dev->device.numa_node;
+
+ return emu_dev;
+}
+
+#endif /* _RTE_EMUDEV_VDEV_H_ */
new file mode 100644
@@ -0,0 +1,27 @@
+EXPERIMENTAL {
+ global:
+
+ rte_emudev_allocate;
+ rte_emudev_release;
+ rte_emudev_allocated;
+ rte_emudev_start;
+ rte_emudev_stop;
+ rte_emudev_configure;
+ rte_emudev_close;
+ rte_emudev_subscribe_event;
+ rte_emudev_unsubscribe_event;
+ rte_emudev_count;
+ rte_emudev_get_dev_id;
+ rte_emudev_get_dev_info;
+ rte_emudev_get_mem_table;
+ rte_emudev_get_queue_info;
+ rte_emudev_get_irq_info;
+ rte_emudev_get_db_info;
+ rte_emudev_set_attr;
+ rte_emudev_get_attr;
+ rte_emudev_region_map;
+ rte_emudev_selftest;
+ rte_emudev_is_valid_id;
+
+ local: *;
+};
@@ -28,7 +28,7 @@ libraries = [
'rib', 'reorder', 'sched', 'security', 'stack', 'vhost',
# ipsec lib depends on net, crypto and security
'ipsec',
- 'vfio_user',
+ 'vfio_user', 'emudev',
#fib lib depends on rib
'fib',
# add pkt framework libs which use other libs from above