[dpdk-dev] [PATCH 1/8] lib: introduce emudev library

Chenbo Xia chenbo.xia at intel.com
Fri Dec 18 08:47:29 CET 2020


This patch introduces the emudev library. Emudev library is used
to abstract an emulated device, whose type could be general
(e.g., network, crypto and etc.). Several device-level APIs are
implemented to use or manipulate the device. It can be attached
to another data path driver (e.g., ethdev driver) to plug in its
high performance data path.

Signed-off-by: Chenbo Xia <chenbo.xia at intel.com>
Signed-off-by: Xiuchun Lu <xiuchun.lu at intel.com>
Signed-off-by: Miao Li <miao.li at intel.com>
---
 MAINTAINERS                         |   5 +
 lib/librte_emudev/meson.build       |   5 +
 lib/librte_emudev/rte_emudev.c      | 486 ++++++++++++++++++++++++++++
 lib/librte_emudev/rte_emudev.h      | 410 +++++++++++++++++++++++
 lib/librte_emudev/rte_emudev_vdev.h |  53 +++
 lib/librte_emudev/version.map       |  27 ++
 lib/meson.build                     |   2 +-
 7 files changed, 987 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_emudev/meson.build
 create mode 100644 lib/librte_emudev/rte_emudev.c
 create mode 100644 lib/librte_emudev/rte_emudev.h
 create mode 100644 lib/librte_emudev/rte_emudev_vdev.h
 create mode 100644 lib/librte_emudev/version.map

diff --git a/MAINTAINERS b/MAINTAINERS
index 5fb4880758..1b395e181d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1545,6 +1545,11 @@ M: Chenbo Xia <chenbo.xia at intel.com>
 M: Xiuchun Lu <xiuchun.lu at intel.com>
 F: lib/librte_vfio_user/
 
+Emudev - EXPERIMENTAL
+M: Chenbo Xia <chenbo.xia at intel.com>
+M: Xiuchun Lu <xiuchun.lu at intel.com>
+F: lib/librte_emudev/
+
 Test Applications
 -----------------
 
diff --git a/lib/librte_emudev/meson.build b/lib/librte_emudev/meson.build
new file mode 100644
index 0000000000..4e16cecbaf
--- /dev/null
+++ b/lib/librte_emudev/meson.build
@@ -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')
diff --git a/lib/librte_emudev/rte_emudev.c b/lib/librte_emudev/rte_emudev.c
new file mode 100644
index 0000000000..2bbf3970d8
--- /dev/null
+++ b/lib/librte_emudev/rte_emudev.c
@@ -0,0 +1,486 @@
+/* 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);
diff --git a/lib/librte_emudev/rte_emudev.h b/lib/librte_emudev/rte_emudev.h
new file mode 100644
index 0000000000..df31c631b7
--- /dev/null
+++ b/lib/librte_emudev/rte_emudev.h
@@ -0,0 +1,410 @@
+/* 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_ */
diff --git a/lib/librte_emudev/rte_emudev_vdev.h b/lib/librte_emudev/rte_emudev_vdev.h
new file mode 100644
index 0000000000..85f534b4bd
--- /dev/null
+++ b/lib/librte_emudev/rte_emudev_vdev.h
@@ -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_ */
diff --git a/lib/librte_emudev/version.map b/lib/librte_emudev/version.map
new file mode 100644
index 0000000000..f800b4c21c
--- /dev/null
+++ b/lib/librte_emudev/version.map
@@ -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: *;
+};
diff --git a/lib/meson.build b/lib/meson.build
index b7fbfcc95b..6dd07fb73e 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -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
-- 
2.17.1



More information about the dev mailing list