From patchwork Sat Dec 19 06:27:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Chenbo Xia X-Patchwork-Id: 85489 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id D30BEA04B5; Sat, 19 Dec 2020 07:43:35 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 36EA5CB05; Sat, 19 Dec 2020 07:43:18 +0100 (CET) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id 3B77CCACA for ; Sat, 19 Dec 2020 07:43:15 +0100 (CET) IronPort-SDR: Tii5bxe0/qrnHtFVPWriqZgsgIawdj2P2d/SVOXvcMDS+lcbA8R+2DPa7RM6FpnGU3UMhK2ujJ dyUoK9nvJJ6Q== X-IronPort-AV: E=McAfee;i="6000,8403,9839"; a="163285186" X-IronPort-AV: E=Sophos;i="5.78,432,1599548400"; d="scan'208";a="163285186" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Dec 2020 22:43:14 -0800 IronPort-SDR: 3lAetFPIbCmAhxXLHmbjerLWKOMI8FTPZJsfHKL+F/wmBmUzR8FrP/BdLvEWuHFSEJBJCj1CzK M+x9AyT/t1wg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,432,1599548400"; d="scan'208";a="454449594" Received: from npg-dpdk-virtio-xiachenbo-nw.sh.intel.com ([10.67.119.123]) by fmsmga001.fm.intel.com with ESMTP; 18 Dec 2020 22:43:12 -0800 From: Chenbo Xia To: dev@dpdk.org, thomas@monjalon.net, david.marchand@redhat.com Cc: stephen@networkplumber.org, cunming.liang@intel.com, xiuchun.lu@intel.com, miao.li@intel.com, jingjing.wu@intel.com Date: Sat, 19 Dec 2020 14:27:59 +0800 Message-Id: <20201219062806.56477-2-chenbo.xia@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201219062806.56477-1-chenbo.xia@intel.com> References: <20201218074736.93999-1-chenbo.xia@intel.com> <20201219062806.56477-1-chenbo.xia@intel.com> MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH v2 1/8] lib: introduce emudev library X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" 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 Signed-off-by: Xiuchun Lu Signed-off-by: Miao Li --- 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 M: Xiuchun Lu F: lib/librte_vfio_user/ +Emudev - EXPERIMENTAL +M: Chenbo Xia +M: Xiuchun Lu +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 + +#include +#include + +#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 +#include +#include + +#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 +#include + +#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 From patchwork Sat Dec 19 06:28:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chenbo Xia X-Patchwork-Id: 85490 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 7C912A04B5; Sat, 19 Dec 2020 07:44:01 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 429DBCB3A; Sat, 19 Dec 2020 07:43:21 +0100 (CET) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id 92C6ACB12 for ; Sat, 19 Dec 2020 07:43:18 +0100 (CET) IronPort-SDR: TR2u0f/Wy1b/5/sanuaQQM9qVbVCwpexsREi0PnSBjMNo8rmnjpN5Lq49ibt0/MbJFt1Nqbehi SkygeObrhK2w== X-IronPort-AV: E=McAfee;i="6000,8403,9839"; a="163285188" X-IronPort-AV: E=Sophos;i="5.78,432,1599548400"; d="scan'208";a="163285188" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Dec 2020 22:43:18 -0800 IronPort-SDR: M+l78zg7O8LSfmi6CrAFZzq60xaEcind+xIPi9gHQl+1V0vWxaTQU38YFNpOAvLeKTnwQfkkMY o5rQDZ4Nbr0w== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,432,1599548400"; d="scan'208";a="454449603" Received: from npg-dpdk-virtio-xiachenbo-nw.sh.intel.com ([10.67.119.123]) by fmsmga001.fm.intel.com with ESMTP; 18 Dec 2020 22:43:15 -0800 From: Chenbo Xia To: dev@dpdk.org, thomas@monjalon.net, david.marchand@redhat.com Cc: stephen@networkplumber.org, cunming.liang@intel.com, xiuchun.lu@intel.com, miao.li@intel.com, jingjing.wu@intel.com Date: Sat, 19 Dec 2020 14:28:00 +0800 Message-Id: <20201219062806.56477-3-chenbo.xia@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201219062806.56477-1-chenbo.xia@intel.com> References: <20201218074736.93999-1-chenbo.xia@intel.com> <20201219062806.56477-1-chenbo.xia@intel.com> Subject: [dpdk-dev] [PATCH v2 2/8] doc: add emudev library guide X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add emudev library guide and update release notes. Signed-off-by: Chenbo Xia --- doc/guides/prog_guide/emudev.rst | 122 +++++++++++++++++++++++++ doc/guides/prog_guide/index.rst | 1 + doc/guides/rel_notes/release_21_02.rst | 12 +++ 3 files changed, 135 insertions(+) create mode 100644 doc/guides/prog_guide/emudev.rst diff --git a/doc/guides/prog_guide/emudev.rst b/doc/guides/prog_guide/emudev.rst new file mode 100644 index 0000000000..91ad520de7 --- /dev/null +++ b/doc/guides/prog_guide/emudev.rst @@ -0,0 +1,122 @@ +.. SPDX-License-Identifier: BSD-3-Clause + Copyright(c) 2020 Intel Corporation. + +Emulated Device Library +================= + +Introduction +------------ + +The DPDK Emudev library is an abstraction for emulated device. This library +provides a generic set of APIs for device provider, data path provider and +applications to use. + +A device provider could be implemented as a driver on vdev bus. It should +expose itself as an emudev for applications to use. It is responsible for the +device resource management and the device's internal logic. All specifics of a +device, except data path handling, should be implemented in the device +provider. The device provider uses emudev APIs mainly for create/destroy an +emudev instance. The device provider should also use a tranport to communicate +with device consumer (e.g., virtual machine monitor or container). A potential +choice could be vfio-user library, which implements the vfio-user protocol for +emulating devices outside of a virtual machine monitor. + +A data path provider could be implemented as any type of driver on vdev bus. +If the device you want to emulate is a network device, you could implement +it as an ethdev driver. It is responsible for all data path handling. The data +path provider uses emudev APIs mainly for getting device-related information +from the device provider. + +Applications uses emudev APIs for device lifecycle management and configuration. + +Design +------------ + +Some key objects are designed in emudev. + + ``Regions`` are the device layout exposed to the data path provider. + + ``Queues`` are the data path queues that the data path provider needs. Queue + information includes queue base address, queue size, queue-related doorbell + and interrupt information. + + ``Memory Table`` is the DMA mapping table. The data path provider could use + it to perform DMA read/write on device consumer's memory. + +Information of above key objects could be acquired through emudev APIs. The +following will introduce the emudev APIs which are used by data path provider +and applications. The APIs for device provider to use are allocate/release APIs +and will not be listed because it's similar to other device abstraction. + +There are five categories of APIs: + +1. Lifecycle management + +* ``rte_emu_dev_start(dev_id)`` +* ``rte_emu_dev_stop(dev_id)`` +* ``rte_emu_dev_configure(dev_id)`` +* ``rte_emu_dev_close(dev_id)`` + + Above APIs are respectively for device start/stop/configure/close and mainly + for applications to use. + + ``dev_id`` is the emudev device ID. + +2. Notification + +* ``rte_emu_subscribe_event(dev_id, ev_chnl)`` +* ``rte_emu_unsubscribe_event(dev_id, ev_chnl)`` + + Above APIs are for data path provider and applications to register events. + The mechanism of event notification could be different in different device + providers. A possbile implementation could be event callbacks. + + ``ev_chnl`` is the event channel pointer. The definition varies between + different devices. + +3. Region-related + +* ``rte_emu_region_map(dev_id, index, region_size, base_addr)`` +* ``rte_emu_get_attr(dev_id, attr_name, attr)`` +* ``rte_emu_set_attr(dev_id, attr_name, attr)`` + + Above APIs are for data path provider and applications to read/write regions. + ``rte_emu_region_map`` is for directly mapping the region and use the mapped + address to read/write it. ``rte_emu_get_attr`` and ``rte_emu_set_attr`` are + respectively for getting/setting certain attributes in all regions. + + Applications will set attributes or write regions for device configuration. + + In ``rte_emu_region_map``: + - ``index`` is the region index. + - ``region_size`` is for saving the size of mapped region. + - ``base_addr`` is for saving the address of mapped region. + + In ``rte_emu_get_attr`` and ``rte_emu_set_attr``: + - ``attr_name`` is the name of attribute. Note that attribute names are aligned + between device provider and data path provider for the same device. + - ``attr`` is the attribute value. + +4. Queue-related + +* ``rte_emu_get_queue_info(dev_id, queue, info)`` +* ``rte_emu_get_irq_info(dev_id, irq, info)`` +* ``rte_emu_get_db_info(dev_id, doorbell, info)`` + + Above APIs are for data path provider to get queue/interrupt/doorbell information. + + - ``queue``, ``irq`` and ``doorbell`` are respectively the queue/interrupt/doorbell + index. + - ``info`` is for saving the queue/interrupt/doorbell info. + +5. Direct Memory Access + +* ``rte_emu_get_mem_table(dev_id, tb)`` + + Above APIs are for data path provider to get the information of DMA memory table. + The memory table implementation varies between different devices and memory table + operations should better be helper functions exposed by device provider. Because + address translation make a difference in data path performance, the memory table + implementation should have high efficiency. + + ``tb`` is for saving the DMA memory table. diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst index f9847b1058..0ed15a0995 100644 --- a/doc/guides/prog_guide/index.rst +++ b/doc/guides/prog_guide/index.rst @@ -71,3 +71,4 @@ Programmer's Guide profile_app glossary vfio_user_lib + emudev diff --git a/doc/guides/rel_notes/release_21_02.rst b/doc/guides/rel_notes/release_21_02.rst index 6fbb6e8c39..3d26b6b580 100644 --- a/doc/guides/rel_notes/release_21_02.rst +++ b/doc/guides/rel_notes/release_21_02.rst @@ -67,6 +67,18 @@ New Features See :doc:`../prog_guide/vfio_user_lib` for more information. +* **Added emudev Library.** + + Added an experimental library ``librte_emudev`` to provide device abstraction + for an emulated device. + + The library abstracts an emulated device and provides several categories of + device-level APIs. The specific device type could be general (e.g, network, + crypto and etc.). It can be attached to another data path driver (e.g, ethdev + driver) to leverage the high performance of DPDK data path driver. + + See :doc:`../prog_guide/emudev` for more information. + Removed Items ------------- From patchwork Sat Dec 19 06:28:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chenbo Xia X-Patchwork-Id: 85491 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id B7976A04B5; Sat, 19 Dec 2020 07:44:20 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id D7A44CB46; Sat, 19 Dec 2020 07:43:23 +0100 (CET) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id 82531CB43 for ; Sat, 19 Dec 2020 07:43:21 +0100 (CET) IronPort-SDR: 2mpW8u5yFLcbS/HKtgdOxFDmXc3PkfipDOTwnY+jVF649RFYoNTHW9Hx/pk7M//EAcBu9ykuxc 6U7qleJYc4fg== X-IronPort-AV: E=McAfee;i="6000,8403,9839"; a="163285189" X-IronPort-AV: E=Sophos;i="5.78,432,1599548400"; d="scan'208";a="163285189" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Dec 2020 22:43:21 -0800 IronPort-SDR: T9g7uPbkxLZ45ZKjkJzf7a8YRZm7fWmEZwyje++yJ3pUIWhq57a18Rkp3NQHmEzTvQCJRz6QQB AiEajVhgtYoQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,432,1599548400"; d="scan'208";a="454449606" Received: from npg-dpdk-virtio-xiachenbo-nw.sh.intel.com ([10.67.119.123]) by fmsmga001.fm.intel.com with ESMTP; 18 Dec 2020 22:43:18 -0800 From: Chenbo Xia To: dev@dpdk.org, thomas@monjalon.net, david.marchand@redhat.com Cc: stephen@networkplumber.org, cunming.liang@intel.com, xiuchun.lu@intel.com, miao.li@intel.com, jingjing.wu@intel.com Date: Sat, 19 Dec 2020 14:28:01 +0800 Message-Id: <20201219062806.56477-4-chenbo.xia@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201219062806.56477-1-chenbo.xia@intel.com> References: <20201218074736.93999-1-chenbo.xia@intel.com> <20201219062806.56477-1-chenbo.xia@intel.com> Subject: [dpdk-dev] [PATCH v2 3/8] emu: introduce emulated iavf driver X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" This patch introduces emulated iavf driver. It is a vdev driver emulating all iavf device behavior except data path handling. Signed-off-by: Chenbo Xia Signed-off-by: Xiuchun Lu --- MAINTAINERS | 7 + drivers/emu/iavf/iavf_emu.c | 29 ++++ drivers/emu/iavf/iavf_emu_internal.h | 49 +++++++ drivers/emu/iavf/iavf_emudev.c | 207 +++++++++++++++++++++++++++ drivers/emu/iavf/meson.build | 8 ++ drivers/emu/iavf/rte_iavf_emu.h | 43 ++++++ drivers/emu/iavf/version.map | 3 + drivers/emu/meson.build | 6 + drivers/meson.build | 1 + 9 files changed, 353 insertions(+) create mode 100644 drivers/emu/iavf/iavf_emu.c create mode 100644 drivers/emu/iavf/iavf_emu_internal.h create mode 100644 drivers/emu/iavf/iavf_emudev.c create mode 100644 drivers/emu/iavf/meson.build create mode 100644 drivers/emu/iavf/rte_iavf_emu.h create mode 100644 drivers/emu/iavf/version.map create mode 100644 drivers/emu/meson.build diff --git a/MAINTAINERS b/MAINTAINERS index 1b395e181d..bca206ba8f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1275,6 +1275,13 @@ F: doc/guides/rawdevs/ntb.rst F: examples/ntb/ F: doc/guides/sample_app_ug/ntb.rst +Emudev Drivers +-------------- + +Intel iavf +M: Chenbo Xia +M: Xiuchun Lu +F: drivers/emulation/iavf/ Packet processing ----------------- diff --git a/drivers/emu/iavf/iavf_emu.c b/drivers/emu/iavf/iavf_emu.c new file mode 100644 index 0000000000..68d2c440e3 --- /dev/null +++ b/drivers/emu/iavf/iavf_emu.c @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Intel Corporation + */ + +#include "iavf_emu_internal.h" + +static int iavf_emu_dev_close(struct rte_emudev *dev) +{ + struct iavf_emudev *iavf; + + /* For now, we don't support device close when data + * path driver is attached + */ + if (dev->backend_priv) { + EMU_IAVF_LOG(ERR, "Close failed because of " + "data path attached\n"); + return -EPERM; + } + + iavf = (struct iavf_emudev *)dev->priv_data; + iavf_emu_uninit_device(iavf); + dev->priv_data = NULL; + + return 0; +} + +struct rte_emudev_ops emu_iavf_ops = { + .dev_close = iavf_emu_dev_close, +}; diff --git a/drivers/emu/iavf/iavf_emu_internal.h b/drivers/emu/iavf/iavf_emu_internal.h new file mode 100644 index 0000000000..a726bfe577 --- /dev/null +++ b/drivers/emu/iavf/iavf_emu_internal.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Intel Corporation + */ + +#ifndef _IAVF_EMU_ITNL_H +#define _IAVF_EMU_ITNL_H + +#include + +#include + +#include "rte_iavf_emu.h" + +extern struct rte_emudev_ops emu_iavf_ops; + +extern int emu_iavf_logtype; +#define EMU_IAVF_LOG(level, ...) \ + rte_log(RTE_LOG_ ## level, emu_iavf_logtype, "EMU_IAVF: " __VA_ARGS__) + +struct iavf_emu_intr_info { + int enable; + int fd; +}; + +struct iavf_emu_intr { + uint32_t intr_num; + struct iavf_emu_intr_info info[RTE_IAVF_EMU_MAX_INTR]; +}; + +struct iavf_emu_lanQ { + uint16_t db_size; + void *doorbell; +}; + +struct iavf_emudev { + struct rte_emudev *edev; + /* Maximum LANQ queue pair that this emulated iavf has */ + uint16_t max_lanqp; + /* Maximum LANQ queue pair number that back-end driver can use */ + uint16_t max_be_lanqp; + unsigned int numa_node; + char *sock_addr; + struct rte_iavf_emu_mem *mem; + struct iavf_emu_intr *intr; + struct iavf_emu_lanQ *lanq; +}; + +void iavf_emu_uninit_device(struct iavf_emudev *dev); +#endif diff --git a/drivers/emu/iavf/iavf_emudev.c b/drivers/emu/iavf/iavf_emudev.c new file mode 100644 index 0000000000..a4cd2deb06 --- /dev/null +++ b/drivers/emu/iavf/iavf_emudev.c @@ -0,0 +1,207 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Intel Corporation + */ + +#include +#include +#include + +#include "iavf_emu_internal.h" + +#define EMU_IAVF_SOCK_ARG "sock" +#define EMU_IAVF_QUEUES_ARG "queues" + +static const char * const emu_iavf_valid_arg[] = { + EMU_IAVF_SOCK_ARG, + EMU_IAVF_QUEUES_ARG, + NULL +}; + +static inline int +save_sockaddr(const char *key __rte_unused, const char *value, + void *extra_args) +{ + const char **sock_addr = extra_args; + + if (value == NULL) + return -1; + + *sock_addr = value; + + return 0; +} + +static inline int +save_int(const char *key __rte_unused, const char *value, void *extra_args) +{ + uint16_t *n = extra_args; + + if (value == NULL || extra_args == NULL) + return -EINVAL; + + *n = (uint16_t)strtoul(value, NULL, 0); + if (*n == USHRT_MAX && errno == ERANGE) + return -1; + + return 0; +} + +static int iavf_emu_init_device(struct iavf_emudev *dev, + char *sock_addr, uint16_t queues, unsigned int numa_node) +{ + dev->sock_addr = rte_malloc_socket("sock_addr", + strlen(sock_addr) + 1, 0, numa_node); + if (!dev->sock_addr) { + EMU_IAVF_LOG(ERR, "Failed to alloc sock addr\n"); + goto exit; + } + strcpy(dev->sock_addr, sock_addr); + + dev->mem = rte_zmalloc_socket("iavf_emu_mem", + sizeof(struct rte_iavf_emu_mem), + 0, numa_node); + if (!dev->mem) { + EMU_IAVF_LOG(ERR, "Unable to alloc iavf_emu_mem.\n"); + goto err_mem; + } + + dev->intr = rte_zmalloc_socket("iavf_emu_intr", + sizeof(struct iavf_emu_intr), + 0, numa_node); + if (!dev->intr) { + EMU_IAVF_LOG(ERR, "Unable to alloc iavf_emu_intr.\n"); + goto err_intr; + } + + dev->lanq = rte_zmalloc_socket("iavf_emu_lanQ", + sizeof(struct iavf_emu_lanQ) * queues * 2, + 0, numa_node); + if (!dev->lanq) { + EMU_IAVF_LOG(ERR, "Unable to alloc iavf_emu_lanQ.\n"); + goto err_lanq; + } + + dev->numa_node = numa_node; + + return 0; + +err_lanq: + rte_free(dev->lanq); +err_intr: + rte_free(dev->intr); +err_mem: + rte_free(dev->sock_addr); +exit: + return -1; +} + +void iavf_emu_uninit_device(struct iavf_emudev *dev) +{ + rte_free(dev->sock_addr); + rte_free(dev->mem); + rte_free(dev->intr); + rte_free(dev->lanq); +} + +static int +rte_emu_iavf_probe(struct rte_vdev_device *dev) +{ + struct rte_kvargs *kvlist = NULL; + struct rte_emudev *edev; + struct iavf_emudev *iavf; + char *sock_addr; + uint16_t queues; + int ret = 0; + + kvlist = rte_kvargs_parse(rte_vdev_device_args(dev), + emu_iavf_valid_arg); + if (kvlist == NULL) + return -1; + + if (rte_kvargs_count(kvlist, EMU_IAVF_SOCK_ARG) == 1) { + ret = rte_kvargs_process(kvlist, EMU_IAVF_SOCK_ARG, + &save_sockaddr, &sock_addr); + if (ret < 0) + goto err; + } else { + ret = -1; + goto err; + } + + if (rte_kvargs_count(kvlist, EMU_IAVF_QUEUES_ARG) == 1) { + ret = rte_kvargs_process(kvlist, EMU_IAVF_QUEUES_ARG, + &save_int, &queues); + if (ret < 0 || queues > RTE_MAX_QUEUES_PER_PORT || + queues > RTE_IAVF_EMU_MAX_QP_NUM) + goto err; + + } else + queues = 1; + + if (dev->device.numa_node == SOCKET_ID_ANY) + dev->device.numa_node = rte_socket_id(); + + edev = rte_emu_vdev_allocate(dev, sizeof(*iavf)); + if (!edev) { + EMU_IAVF_LOG(ERR, "Failed to allocate emu_vdev\n"); + ret = -1; + goto err; + } + edev->dev_ops = &emu_iavf_ops; + edev->dev_info.region_num = RTE_IAVF_EMU_MAPPABLE_REG_NUM; + edev->dev_info.max_qp_num = queues + RTE_IAVF_EMU_ADMINQ_NUM / 2; + + strcpy(edev->dev_info.dev_type, RTE_IAVF_EMUDEV_TYPE); + + iavf = (struct iavf_emudev *)edev->priv_data; + ret = iavf_emu_init_device(iavf, sock_addr, queues, + dev->device.numa_node); + if (ret) { + EMU_IAVF_LOG(ERR, "Failed to init new iavf device\n"); + ret = -1; + goto err_ndev; + } + + iavf->edev = edev; + /* If not configured, we assume back-end driver + * can use all queues of emulated iavf + */ + iavf->max_be_lanqp = queues; + iavf->max_lanqp = queues; + edev->priv_data = (void *)iavf; + + edev->started = 1; + rte_kvargs_free(kvlist); + return 0; + +err_ndev: + rte_emudev_release(edev); +err: + rte_kvargs_free(kvlist); + return ret; +} + +static int +rte_emu_iavf_remove(struct rte_vdev_device *dev) +{ + struct rte_emudev *emu_dev; + + /* Find the emudev entry */ + emu_dev = rte_emudev_allocated(rte_vdev_device_name(dev)); + if (!emu_dev) + return 0; + + return rte_emudev_close(emu_dev->dev_id); +} + +static struct rte_vdev_driver emu_iavf_drv = { + .probe = rte_emu_iavf_probe, + .remove = rte_emu_iavf_remove, +}; + +RTE_PMD_REGISTER_VDEV(emu_iavf, emu_iavf_drv); +RTE_PMD_REGISTER_PARAM_STRING(emu_iavf, + "sock= " + "queues= "); + +RTE_LOG_REGISTER(emu_iavf_logtype, emu.iavf, INFO); diff --git a/drivers/emu/iavf/meson.build b/drivers/emu/iavf/meson.build new file mode 100644 index 0000000000..58c2a90383 --- /dev/null +++ b/drivers/emu/iavf/meson.build @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2020 Intel Corporation + +sources = files('iavf_emu.c', 'iavf_emudev.c') + +deps += ['bus_vdev', 'emudev'] + +headers = files('rte_iavf_emu.h') diff --git a/drivers/emu/iavf/rte_iavf_emu.h b/drivers/emu/iavf/rte_iavf_emu.h new file mode 100644 index 0000000000..623c3c5d99 --- /dev/null +++ b/drivers/emu/iavf/rte_iavf_emu.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Intel Corporation + */ + +#ifndef _IAVF_EMU_H +#define _IAVF_EMU_H + +#include + +#include + +#define RTE_IAVF_EMUDEV_TYPE "iavf" +#define RTE_IAVF_EMU_MAX_MEM_REGIONS 256 +#define RTE_IAVF_EMU_MAX_QP_NUM 256 +#define RTE_IAVF_EMU_MAX_INTR 32 + +enum { + RTE_IAVF_EMU_ADMINQ_TXQ = 0, + RTE_IAVF_EMU_ADMINQ_RXQ = 1, + RTE_IAVF_EMU_ADMINQ_NUM = 2, +}; + +enum { + RTE_IAVF_EMU_MAPPABLE_REG_BAR0 = 0, + RTE_IAVF_EMU_MAPPABLE_REG_BAR3 = 1, + RTE_IAVF_EMU_MAPPABLE_REG_NUM = 2, +}; + +struct rte_iavf_emu_mem_reg { + uint64_t guest_phys_addr; + uint64_t host_user_addr; + uint64_t size; + void *mmap_addr; + uint64_t mmap_size; + int fd; +}; + +struct rte_iavf_emu_mem { + uint32_t region_num; + struct rte_iavf_emu_mem_reg regions[RTE_IAVF_EMU_MAX_MEM_REGIONS]; +}; + +#endif diff --git a/drivers/emu/iavf/version.map b/drivers/emu/iavf/version.map new file mode 100644 index 0000000000..4a76d1d52d --- /dev/null +++ b/drivers/emu/iavf/version.map @@ -0,0 +1,3 @@ +DPDK_21 { + local: *; +}; diff --git a/drivers/emu/meson.build b/drivers/emu/meson.build new file mode 100644 index 0000000000..acc8c395ef --- /dev/null +++ b/drivers/emu/meson.build @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2020 Intel Corporation + +drivers = ['iavf'] +std_deps = ['emudev'] +config_flag_fmt = 'RTE_LIBRTE_PMD_@0@_EMUDEV' diff --git a/drivers/meson.build b/drivers/meson.build index f9febc579e..64c34d2f9f 100644 --- a/drivers/meson.build +++ b/drivers/meson.build @@ -8,6 +8,7 @@ subdirs = [ 'common/mlx5', # depends on bus. 'common/qat', # depends on bus. 'mempool', # depends on common and bus. + 'emu', # depends on common and bus. 'net', # depends on common, bus, mempool 'raw', # depends on common, bus and net. 'crypto', # depends on common, bus and mempool (net in future). From patchwork Sat Dec 19 06:28:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chenbo Xia X-Patchwork-Id: 85492 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id D2A37A04B5; Sat, 19 Dec 2020 07:44:39 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 514D2CB69; Sat, 19 Dec 2020 07:43:27 +0100 (CET) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id F0A34CB69 for ; Sat, 19 Dec 2020 07:43:24 +0100 (CET) IronPort-SDR: VDnEzV2ElxaSjLEBmMgLWgEIek74cZ5PkMD3OLoWVSUD0P0Hb93RkLOkJZkXQ7anh1m0hM4/QG rwgvoHu7pBtQ== X-IronPort-AV: E=McAfee;i="6000,8403,9839"; a="163285190" X-IronPort-AV: E=Sophos;i="5.78,432,1599548400"; d="scan'208";a="163285190" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Dec 2020 22:43:24 -0800 IronPort-SDR: drW/qdCNskiFGR9DEHnOuzXzkOOR1NaSKGvHqKR1R7Z9tpfBAS0S43+2lDc4FQ1OUnOkTlWV1m wuwAz1KDI+Ng== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,432,1599548400"; d="scan'208";a="454449614" Received: from npg-dpdk-virtio-xiachenbo-nw.sh.intel.com ([10.67.119.123]) by fmsmga001.fm.intel.com with ESMTP; 18 Dec 2020 22:43:21 -0800 From: Chenbo Xia To: dev@dpdk.org, thomas@monjalon.net, david.marchand@redhat.com Cc: stephen@networkplumber.org, cunming.liang@intel.com, xiuchun.lu@intel.com, miao.li@intel.com, jingjing.wu@intel.com Date: Sat, 19 Dec 2020 14:28:02 +0800 Message-Id: <20201219062806.56477-5-chenbo.xia@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201219062806.56477-1-chenbo.xia@intel.com> References: <20201218074736.93999-1-chenbo.xia@intel.com> <20201219062806.56477-1-chenbo.xia@intel.com> Subject: [dpdk-dev] [PATCH v2 4/8] emu/iavf: add vfio-user device register and unregister X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" This patch adds vfio-user APIs call in driver probe and remove. rte_vfio_user_register() and rte_vfio_user_unregister() are called to create/destroy a vfio-user device. Notify callbacks that libvfio_user defines are also implemented. Signed-off-by: Chenbo Xia Signed-off-by: Miao Li --- drivers/emu/iavf/iavf_emu.c | 3 +- drivers/emu/iavf/iavf_emu_internal.h | 19 ++ drivers/emu/iavf/iavf_emudev.c | 12 +- drivers/emu/iavf/iavf_vfio_user.c | 384 +++++++++++++++++++++++++++ drivers/emu/iavf/iavf_vfio_user.h | 16 ++ drivers/emu/iavf/meson.build | 5 +- drivers/emu/iavf/rte_iavf_emu.h | 17 ++ 7 files changed, 452 insertions(+), 4 deletions(-) create mode 100644 drivers/emu/iavf/iavf_vfio_user.c create mode 100644 drivers/emu/iavf/iavf_vfio_user.h diff --git a/drivers/emu/iavf/iavf_emu.c b/drivers/emu/iavf/iavf_emu.c index 68d2c440e3..dfd9796920 100644 --- a/drivers/emu/iavf/iavf_emu.c +++ b/drivers/emu/iavf/iavf_emu.c @@ -2,7 +2,7 @@ * Copyright(c) 2020 Intel Corporation */ -#include "iavf_emu_internal.h" +#include "iavf_vfio_user.h" static int iavf_emu_dev_close(struct rte_emudev *dev) { @@ -18,6 +18,7 @@ static int iavf_emu_dev_close(struct rte_emudev *dev) } iavf = (struct iavf_emudev *)dev->priv_data; + iavf_emu_unregister_vfio_user(iavf); iavf_emu_uninit_device(iavf); dev->priv_data = NULL; diff --git a/drivers/emu/iavf/iavf_emu_internal.h b/drivers/emu/iavf/iavf_emu_internal.h index a726bfe577..10197c00ba 100644 --- a/drivers/emu/iavf/iavf_emu_internal.h +++ b/drivers/emu/iavf/iavf_emu_internal.h @@ -17,6 +17,13 @@ extern int emu_iavf_logtype; #define EMU_IAVF_LOG(level, ...) \ rte_log(RTE_LOG_ ## level, emu_iavf_logtype, "EMU_IAVF: " __VA_ARGS__) +struct iavf_emu_vfio_user { + int dev_id; + struct vfio_device_info *dev_info; + struct rte_vfio_user_regions *reg; + struct rte_vfio_user_irq_info *irq; +}; + struct iavf_emu_intr_info { int enable; int fd; @@ -27,6 +34,14 @@ struct iavf_emu_intr { struct iavf_emu_intr_info info[RTE_IAVF_EMU_MAX_INTR]; }; +struct iavf_emu_adminQ { + uint32_t *ring_addr_lo; + uint32_t *ring_addr_hi; + uint32_t *ring_sz; + uint16_t db_size; + void *doorbell; +}; + struct iavf_emu_lanQ { uint16_t db_size; void *doorbell; @@ -34,14 +49,18 @@ struct iavf_emu_lanQ { struct iavf_emudev { struct rte_emudev *edev; + struct iavf_emu_vfio_user *vfio; /* Maximum LANQ queue pair that this emulated iavf has */ uint16_t max_lanqp; /* Maximum LANQ queue pair number that back-end driver can use */ uint16_t max_be_lanqp; unsigned int numa_node; + int ready; char *sock_addr; + struct rte_iavf_emu_notify_ops *ops; struct rte_iavf_emu_mem *mem; struct iavf_emu_intr *intr; + struct iavf_emu_adminQ adq[RTE_IAVF_EMU_ADMINQ_NUM]; struct iavf_emu_lanQ *lanq; }; diff --git a/drivers/emu/iavf/iavf_emudev.c b/drivers/emu/iavf/iavf_emudev.c index a4cd2deb06..fbbe3d95a7 100644 --- a/drivers/emu/iavf/iavf_emudev.c +++ b/drivers/emu/iavf/iavf_emudev.c @@ -6,7 +6,7 @@ #include #include -#include "iavf_emu_internal.h" +#include "iavf_vfio_user.h" #define EMU_IAVF_SOCK_ARG "sock" #define EMU_IAVF_QUEUES_ARG "queues" @@ -170,10 +170,20 @@ rte_emu_iavf_probe(struct rte_vdev_device *dev) iavf->max_lanqp = queues; edev->priv_data = (void *)iavf; + ret = iavf_emu_register_vfio_user(iavf); + if (ret) { + EMU_IAVF_LOG(ERR, + "Emulated iavf failed to register vfio user.\n"); + ret = -1; + goto err_reg; + } + edev->started = 1; rte_kvargs_free(kvlist); return 0; +err_reg: + iavf_emu_uninit_device(iavf); err_ndev: rte_emudev_release(edev); err: diff --git a/drivers/emu/iavf/iavf_vfio_user.c b/drivers/emu/iavf/iavf_vfio_user.c new file mode 100644 index 0000000000..aae47de9f3 --- /dev/null +++ b/drivers/emu/iavf/iavf_vfio_user.c @@ -0,0 +1,384 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Intel Corporation + */ + +#include + +#include + +#include "iavf_vfio_user.h" +#include + +struct iavf_emu_sock_list { + TAILQ_ENTRY(iavf_emu_sock_list) next; + struct rte_emudev *emu_dev; +}; + +TAILQ_HEAD(iavf_emu_sock_list_head, iavf_emu_sock_list); + +static struct iavf_emu_sock_list_head sock_list = + TAILQ_HEAD_INITIALIZER(sock_list); + +static pthread_mutex_t sock_list_lock = PTHREAD_MUTEX_INITIALIZER; + +static int iavf_emu_setup_irq(struct iavf_emudev *dev) +{ + struct iavf_emu_intr *intr; + struct rte_vfio_user_irq_info *irq; + int *fds = NULL; + uint32_t i, count; + + irq = dev->vfio->irq; + if (!irq) + return -1; + + count = irq->irq_info[VFIO_PCI_MSIX_IRQ_INDEX].count; + if (count) { + fds = rte_zmalloc("irq_fds", sizeof(int) * count, 0); + if (!fds) { + EMU_IAVF_LOG(ERR, + "Failed to alloc irq fds.\n"); + return -1; + } + } + + if (rte_vfio_user_get_irq(dev->vfio->dev_id, + VFIO_PCI_MSIX_IRQ_INDEX, count, fds)) { + EMU_IAVF_LOG(ERR, "Failed to get irqfds from vfio-user.\n"); + return -1; + } + + intr = dev->intr; + intr->intr_num = irq->irq_info[VFIO_PCI_MSIX_IRQ_INDEX].count; + + for (i = 0; i < count; i++) { + intr->info[i].fd = fds[i]; + intr->info[i].enable = 0; + } + + rte_free(fds); + + return 0; +} + +static inline void iavf_emu_reset_irq(struct iavf_emudev *dev) +{ + struct iavf_emu_intr *intr = dev->intr; + uint32_t i; + + for (i = 0; i < intr->intr_num; i++) { + intr->info[i].enable = 0; + intr->info[i].fd = -1; + } +} + +static inline void iavf_emu_reset_regions(struct iavf_emudev *dev) +{ + struct rte_vfio_user_regions *reg = dev->vfio->reg; + struct rte_vfio_user_reg_info *vinfo; + uint32_t i; + + for (i = 0; i < reg->reg_num; i++) { + vinfo = ®->reg_info[i]; + if (vinfo->info->size && vinfo->base) + memset(vinfo->base, 0, vinfo->info->size); + } +} + +static int iavf_emu_setup_mem_table(struct iavf_emudev *dev) +{ + const struct rte_vfio_user_mem *vfio_mem; + const struct rte_vfio_user_mtb_entry *entry; + struct rte_iavf_emu_mem *mem; + uint32_t i; + + vfio_mem = rte_vfio_user_get_mem_table(dev->vfio->dev_id); + if (!vfio_mem) { + EMU_IAVF_LOG(ERR, "Unable to get vfio mem table.\n"); + return -1; + } + + mem = dev->mem; + + mem->region_num = vfio_mem->entry_num; + if (mem->region_num > RTE_IAVF_EMU_MAX_MEM_REGIONS) { + EMU_IAVF_LOG(ERR, "Failed to set up mem table," + "exceed max region num.\n"); + return -1; + } + + for (i = 0; i < vfio_mem->entry_num; i++) { + entry = &vfio_mem->entry[i]; + + mem->regions[i].guest_phys_addr = entry->gpa; + mem->regions[i].host_user_addr = entry->host_user_addr; + mem->regions[i].mmap_addr = entry->mmap_addr; + mem->regions[i].mmap_size = entry->mmap_size; + mem->regions[i].size = entry->size; + mem->regions[i].fd = entry->fd; + } + + return 0; +} + +static inline void iavf_emu_reset_mem_table(struct iavf_emudev *dev) +{ + struct rte_iavf_emu_mem *mem = dev->mem; + uint32_t i; + + for (i = 0; i < mem->region_num; i++) { + mem->regions[i].guest_phys_addr = 0; + mem->regions[i].host_user_addr = 0; + mem->regions[i].mmap_addr = 0; + mem->regions[i].mmap_size = 0; + mem->regions[i].size = 0; + mem->regions[i].fd = -1; + } +} + +static int iavf_emu_setup_queues(struct iavf_emudev *dev) +{ + struct iavf_emu_adminQ *asq, *arq; + struct rte_vfio_user_reg_info *info; + uint16_t i; + + info = &dev->vfio->reg->reg_info[0]; + asq = &dev->adq[RTE_IAVF_EMU_ADMINQ_TXQ]; + arq = &dev->adq[RTE_IAVF_EMU_ADMINQ_RXQ]; + + asq->doorbell = (uint8_t *)info->base + IAVF_VF_ATQT1; + asq->db_size = 4; + asq->ring_addr_lo = (uint32_t *)((uint8_t *)info->base + + IAVF_VF_ATQBAL1); + asq->ring_addr_hi = (uint32_t *)((uint8_t *)info->base + + IAVF_VF_ATQBAH1); + asq->ring_sz = (uint32_t *)((uint8_t *)info->base + IAVF_VF_ATQLEN1); + + arq->doorbell = (uint8_t *)info->base + IAVF_VF_ARQT1; + arq->db_size = 4; + arq->ring_addr_lo = (uint32_t *)((uint8_t *)info->base + + IAVF_VF_ARQBAL1); + arq->ring_addr_hi = (uint32_t *)((uint8_t *)info->base + + IAVF_VF_ARQBAH1); + arq->ring_sz = (uint32_t *)((uint8_t *)info->base + IAVF_VF_ARQLEN1); + + for (i = 0; i < dev->max_lanqp; i++) { + dev->lanq[i * 2].doorbell = (uint8_t *)info->base + + IAVF_QTX_TAIL1(i); + dev->lanq[i * 2].db_size = 4; + dev->lanq[i * 2 + 1].doorbell = (uint8_t *)info->base + + IAVF_QRX_TAIL1(i); + dev->lanq[i * 2 + 1].db_size = 4; + } + + return 0; +} + +static inline void iavf_emu_reset_queues(struct iavf_emudev *dev) +{ + memset(&dev->adq, 0, RTE_IAVF_EMU_ADMINQ_NUM * + sizeof(struct iavf_emu_adminQ)); + + memset(dev->lanq, 0, dev->max_lanqp * 2 * + sizeof(struct iavf_emu_lanQ)); +} + +static void iavf_emu_reset_all_resources(struct iavf_emudev *dev) +{ + iavf_emu_reset_mem_table(dev); + iavf_emu_reset_irq(dev); + iavf_emu_reset_queues(dev); + iavf_emu_reset_regions(dev); +} + +static inline struct iavf_emu_sock_list * +iavf_emu_find_sock_list(char *sock_addr) +{ + struct iavf_emu_sock_list *list; + struct iavf_emudev *dev; + int list_exist; + + if (!sock_addr) + return NULL; + + pthread_mutex_lock(&sock_list_lock); + + TAILQ_FOREACH(list, &sock_list, next) { + dev = (struct iavf_emudev *)list->emu_dev->priv_data; + + if (!strcmp(dev->sock_addr, sock_addr)) { + list_exist = 1; + break; + } + break; + } + + pthread_mutex_unlock(&sock_list_lock); + + if (!list_exist) + return NULL; + + return list; +} + +static struct iavf_emudev *find_iavf_with_dev_id(int vfio_dev_id) +{ + struct iavf_emu_sock_list *list; + char sock_addr[PATH_MAX]; + int ret; + + ret = rte_vfio_get_sock_addr(vfio_dev_id, sock_addr, + sizeof(sock_addr)); + if (ret) { + EMU_IAVF_LOG(ERR, "Can not find vfio device %d " + "sock_addr.\n", vfio_dev_id); + return NULL; + } + + list = iavf_emu_find_sock_list(sock_addr); + if (!list) { + EMU_IAVF_LOG(ERR, "Can not find sock list.\n"); + return NULL; + } + + return (struct iavf_emudev *)list->emu_dev->priv_data; +} + +static int iavf_emu_new_device(int vfio_dev_id) +{ + struct iavf_emudev *dev; + int ret; + + dev = find_iavf_with_dev_id(vfio_dev_id); + if (!dev) + return -1; + + dev->vfio->dev_id = vfio_dev_id; + + ret = iavf_emu_setup_mem_table(dev); + if (ret) { + EMU_IAVF_LOG(ERR, "Failed to set up memtable for " + "device %d", dev->vfio->dev_id); + return ret; + } + + ret = iavf_emu_setup_irq(dev); + if (ret) { + EMU_IAVF_LOG(ERR, "Failed to set up irq for " + "device %d", dev->vfio->dev_id); + return ret; + } + + ret = iavf_emu_setup_queues(dev); + if (ret) { + EMU_IAVF_LOG(ERR, "Failed to set up queues for " + "device %d", dev->vfio->dev_id); + return ret; + } + + ret = dev->ops->device_ready(dev->edev); + if (ret) + return ret; + + dev->ready = 1; + return 0; +} + +static void iavf_emu_destroy_device(int vfio_dev_id) +{ + struct iavf_emudev *dev; + + dev = find_iavf_with_dev_id(vfio_dev_id); + if (!dev) + return; + + iavf_emu_reset_all_resources(dev); + + dev->ops->device_destroy(dev->edev); +} + +static int iavf_emu_update_status(int vfio_dev_id) +{ + struct iavf_emudev *dev; + int ret; + + dev = find_iavf_with_dev_id(vfio_dev_id); + if (!dev) + return -1; + + ret = iavf_emu_setup_mem_table(dev); + if (ret) { + EMU_IAVF_LOG(ERR, "Failed to set up memtable for " + "device %d", dev->vfio->dev_id); + return ret; + } + + ret = iavf_emu_setup_irq(dev); + if (ret) { + EMU_IAVF_LOG(ERR, "Failed to set up irq for " + "device %d", dev->vfio->dev_id); + return ret; + } + + dev->ops->update_status(dev->edev); + + return 0; +} + +static int iavf_emu_lock_datapath(int vfio_dev_id, int lock) +{ + struct iavf_emudev *dev; + + dev = find_iavf_with_dev_id(vfio_dev_id); + if (!dev) + return -1; + + return dev->ops->lock_dp(dev->edev, lock); +} + +static int iavf_emu_reset_device(int vfio_dev_id) +{ + struct iavf_emudev *dev; + + dev = find_iavf_with_dev_id(vfio_dev_id); + if (!dev) + return -1; + + iavf_emu_reset_all_resources(dev); + + return dev->ops->reset_device(dev->edev); +} + +struct rte_vfio_user_notify_ops vfio_ops = { + .new_device = iavf_emu_new_device, + .destroy_device = iavf_emu_destroy_device, + .update_status = iavf_emu_update_status, + .lock_dp = iavf_emu_lock_datapath, + .reset_device = iavf_emu_reset_device, +}; + +int iavf_emu_register_vfio_user(struct iavf_emudev *dev) +{ + int ret; + + ret = rte_vfio_user_register(dev->sock_addr, &vfio_ops); + if (ret) { + EMU_IAVF_LOG(ERR, "Register vfio_user failed\n"); + return -1; + } + + return 0; +} + +int iavf_emu_unregister_vfio_user(struct iavf_emudev *dev) +{ + int ret; + + ret = rte_vfio_user_unregister(dev->sock_addr); + if (ret) { + EMU_IAVF_LOG(ERR, "Unregister vfio_user failed\n"); + return -1; + } + + return 0; +} diff --git a/drivers/emu/iavf/iavf_vfio_user.h b/drivers/emu/iavf/iavf_vfio_user.h new file mode 100644 index 0000000000..aa2f3edc87 --- /dev/null +++ b/drivers/emu/iavf/iavf_vfio_user.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Intel Corporation + */ + +#ifndef _IAVF_VFIO_USER_H +#define _IAVF_VFIO_USER_H + +#include + +#include "iavf_emu_internal.h" + +int iavf_emu_register_vfio_user(struct iavf_emudev *dev); + +int iavf_emu_unregister_vfio_user(struct iavf_emudev *dev); + +#endif diff --git a/drivers/emu/iavf/meson.build b/drivers/emu/iavf/meson.build index 58c2a90383..4f651258c2 100644 --- a/drivers/emu/iavf/meson.build +++ b/drivers/emu/iavf/meson.build @@ -1,8 +1,9 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2020 Intel Corporation -sources = files('iavf_emu.c', 'iavf_emudev.c') +sources = files('iavf_emu.c', 'iavf_vfio_user.c', + 'iavf_emudev.c') -deps += ['bus_vdev', 'emudev'] +deps += ['bus_vdev', 'emudev', 'vfio_user', 'common_iavf'] headers = files('rte_iavf_emu.h') diff --git a/drivers/emu/iavf/rte_iavf_emu.h b/drivers/emu/iavf/rte_iavf_emu.h index 623c3c5d99..6de0989f0b 100644 --- a/drivers/emu/iavf/rte_iavf_emu.h +++ b/drivers/emu/iavf/rte_iavf_emu.h @@ -40,4 +40,21 @@ struct rte_iavf_emu_mem { struct rte_iavf_emu_mem_reg regions[RTE_IAVF_EMU_MAX_MEM_REGIONS]; }; +struct rte_iavf_emu_notify_ops { + /* Device is ready */ + int (*device_ready)(struct rte_emudev *dev); + /* Device is destroyed */ + void (*device_destroy)(struct rte_emudev *dev); + /* Update device status */ + int (*update_status)(struct rte_emudev *dev); + /* Start device */ + int (*device_start)(struct rte_emudev *dev); + /* Stop device */ + int (*device_stop)(struct rte_emudev *dev); + /* Lock or unlock data path */ + int (*lock_dp)(struct rte_emudev *dev, int lock); + /* Reset device */ + int (*reset_device)(struct rte_emudev *dev); +}; + #endif From patchwork Sat Dec 19 06:28:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chenbo Xia X-Patchwork-Id: 85493 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id E0D90A04B5; Sat, 19 Dec 2020 07:45:01 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 63245CB85; Sat, 19 Dec 2020 07:43:30 +0100 (CET) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id D5F56CB79 for ; Sat, 19 Dec 2020 07:43:27 +0100 (CET) IronPort-SDR: nzAsIO4ajBoWZSgXEqOQzWEtTqlZ53MVbTu6TmytFcrmUATtw8ehQjwBXNJhEiqBPfdcKdAuJw rR1ZHJgHpLbw== X-IronPort-AV: E=McAfee;i="6000,8403,9839"; a="163285192" X-IronPort-AV: E=Sophos;i="5.78,432,1599548400"; d="scan'208";a="163285192" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Dec 2020 22:43:27 -0800 IronPort-SDR: nWmlL/aD0zaQdjH5nyKT4m7X9amt09nOkFLKvwq5AYAg3+aaArkzP9ZH9FhytyjpHdrSjzO7Ms 3CVhew+onXiw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,432,1599548400"; d="scan'208";a="454449619" Received: from npg-dpdk-virtio-xiachenbo-nw.sh.intel.com ([10.67.119.123]) by fmsmga001.fm.intel.com with ESMTP; 18 Dec 2020 22:43:25 -0800 From: Chenbo Xia To: dev@dpdk.org, thomas@monjalon.net, david.marchand@redhat.com Cc: stephen@networkplumber.org, cunming.liang@intel.com, xiuchun.lu@intel.com, miao.li@intel.com, jingjing.wu@intel.com Date: Sat, 19 Dec 2020 14:28:03 +0800 Message-Id: <20201219062806.56477-6-chenbo.xia@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201219062806.56477-1-chenbo.xia@intel.com> References: <20201218074736.93999-1-chenbo.xia@intel.com> <20201219062806.56477-1-chenbo.xia@intel.com> Subject: [dpdk-dev] [PATCH v2 5/8] emu/iavf: add resource management and internal logic of iavf X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" This patch adds the allocation and release of device resources. Device resources include PCI BARs' memory and interrupt related resources. Device internal logic is also added. Signed-off-by: Chenbo Xia Signed-off-by: Xiuchun Lu --- drivers/emu/iavf/iavf_emu.c | 1 + drivers/emu/iavf/iavf_emudev.c | 20 + drivers/emu/iavf/iavf_vfio_user.c | 669 ++++++++++++++++++++++++++++++ drivers/emu/iavf/iavf_vfio_user.h | 41 ++ drivers/emu/iavf/meson.build | 8 + 5 files changed, 739 insertions(+) diff --git a/drivers/emu/iavf/iavf_emu.c b/drivers/emu/iavf/iavf_emu.c index dfd9796920..c1a702d744 100644 --- a/drivers/emu/iavf/iavf_emu.c +++ b/drivers/emu/iavf/iavf_emu.c @@ -18,6 +18,7 @@ static int iavf_emu_dev_close(struct rte_emudev *dev) } iavf = (struct iavf_emudev *)dev->priv_data; + iavf_emu_uninit_vfio_user(iavf); iavf_emu_unregister_vfio_user(iavf); iavf_emu_uninit_device(iavf); dev->priv_data = NULL; diff --git a/drivers/emu/iavf/iavf_emudev.c b/drivers/emu/iavf/iavf_emudev.c index fbbe3d95a7..70cf558eef 100644 --- a/drivers/emu/iavf/iavf_emudev.c +++ b/drivers/emu/iavf/iavf_emudev.c @@ -178,10 +178,30 @@ rte_emu_iavf_probe(struct rte_vdev_device *dev) goto err_reg; } + ret = iavf_emu_init_vfio_user(iavf); + if (ret) { + EMU_IAVF_LOG(ERR, + "Emulated iavf failed to init vfio user.\n"); + ret = -1; + goto err_init; + } + + ret = iavf_emu_start_vfio_user(iavf); + if (ret) { + EMU_IAVF_LOG(ERR, + "Emulated iavf failed to start vfio user.\n"); + ret = -1; + goto err_start; + } + edev->started = 1; rte_kvargs_free(kvlist); return 0; +err_start: + iavf_emu_uninit_vfio_user(iavf); +err_init: + iavf_emu_unregister_vfio_user(iavf); err_reg: iavf_emu_uninit_device(iavf); err_ndev: diff --git a/drivers/emu/iavf/iavf_vfio_user.c b/drivers/emu/iavf/iavf_vfio_user.c index aae47de9f3..a4208de618 100644 --- a/drivers/emu/iavf/iavf_vfio_user.c +++ b/drivers/emu/iavf/iavf_vfio_user.c @@ -2,13 +2,36 @@ * Copyright(c) 2020 Intel Corporation */ +#include +#include +#include +#include +#include +#include +#include #include +#include #include +#include +#include #include "iavf_vfio_user.h" #include +#define STORE_LE16(addr, val) (*(__u16 *)addr = val) +#define STORE_LE32(addr, val) (*(__u32 *)addr = val) + +#define IAVF_EMU_BAR0_SIZE 0x10000 +#define IAVF_EMU_BAR3_SIZE 0x1000 +#define IAVF_EMU_BAR_SIZE_MASK 0xffffffff +#define IAVF_EMU_BAR_MASK(sz) (~(sz) + 1) +#define IAVF_EMU_MSIX_TABLE_SIZE 0x5 + +#define PCI_VENDOR_ID_INTEL 0x8086 +#define PCI_SUBDEVICE_ID 0x1100 +#define PCI_CLASS_ETHERNET 0x0200 + struct iavf_emu_sock_list { TAILQ_ENTRY(iavf_emu_sock_list) next; struct rte_emudev *emu_dev; @@ -174,6 +197,14 @@ static int iavf_emu_setup_queues(struct iavf_emudev *dev) return 0; } +static inline void iavf_emu_cleanup_queues(struct iavf_emudev *dev) +{ + memset(&dev->adq, 0, RTE_IAVF_EMU_ADMINQ_NUM * + sizeof(struct iavf_emu_adminQ)); + + rte_free(dev->lanq); +} + static inline void iavf_emu_reset_queues(struct iavf_emudev *dev) { memset(&dev->adq, 0, RTE_IAVF_EMU_ADMINQ_NUM * @@ -191,6 +222,576 @@ static void iavf_emu_reset_all_resources(struct iavf_emudev *dev) iavf_emu_reset_regions(dev); } +static int iavf_emu_init_dev(struct iavf_emudev *dev) +{ + struct iavf_emu_vfio_user *vfio; + struct vfio_device_info *dev_info; + struct rte_vfio_user_regions *reg; + struct rte_vfio_user_irq_info *irq; + struct vfio_region_info_cap_sparse_mmap *sparse; + int ret; + uint32_t i, j; + + vfio = rte_zmalloc_socket("vfio", sizeof(*vfio), 0, dev->numa_node); + if (!vfio) { + EMU_IAVF_LOG(ERR, "Failed to alloc iavf_emu_vfio_user\n"); + ret = -1; + goto exit; + } + + dev_info = rte_zmalloc_socket("vfio_dev_info", + sizeof(*dev_info), 0, dev->numa_node); + if (!dev_info) { + EMU_IAVF_LOG(ERR, "Failed to alloc vfio dev_info\n"); + ret = -1; + goto err_info; + } + dev_info->argsz = sizeof(*dev_info); + dev_info->flags = VFIO_DEVICE_FLAGS_PCI | VFIO_DEVICE_FLAGS_RESET; + dev_info->num_regions = VFIO_PCI_NUM_REGIONS; + dev_info->num_irqs = VFIO_PCI_NUM_IRQS; + + reg = rte_zmalloc_socket("vfio_user_regions", + sizeof(*reg) + dev_info->num_regions * + sizeof(struct rte_vfio_user_reg_info), 0, dev->numa_node); + if (!reg) { + EMU_IAVF_LOG(ERR, "Failed to alloc vfio_user_regions\n"); + ret = -1; + goto err_reg; + } + reg->reg_num = dev_info->num_regions; + + for (i = 0; i < reg->reg_num; i++) { + struct rte_vfio_user_reg_info *vinfo = ®->reg_info[i]; + size_t sz = sizeof(struct vfio_region_info); + + /* BAR0 has two sparse mmap area */ + if (i == VFIO_PCI_BAR0_REGION_INDEX) + sz += sizeof(*sparse) + 2 * sizeof(*sparse->areas); + + vinfo->info = rte_zmalloc_socket("vfio_region_info", + sz, 0, dev->numa_node); + if (!vinfo->info) { + EMU_IAVF_LOG(ERR, "Failed to alloc region info " + "for region %d\n", i); + ret = -1; + goto err_reg_alloc; + } + + vinfo->info->index = i; + + switch (i) { + case VFIO_PCI_CONFIG_REGION_INDEX: + vinfo->info->argsz = sz; + vinfo->info->offset = 0; + vinfo->info->size = IAVF_EMU_CFG_SPACE_SIZE; + vinfo->info->flags = VFIO_REGION_INFO_FLAG_READ | + VFIO_REGION_INFO_FLAG_WRITE; + break; + case VFIO_PCI_BAR0_REGION_INDEX: + vinfo->info->argsz = sz; + vinfo->info->offset = 0; + vinfo->info->size = IAVF_EMU_BAR0_SIZE; + vinfo->info->flags = VFIO_REGION_INFO_FLAG_READ | + VFIO_REGION_INFO_FLAG_WRITE | + VFIO_REGION_INFO_FLAG_MMAP | + VFIO_REGION_INFO_FLAG_CAPS; + vinfo->info->cap_offset = + sizeof(struct vfio_region_info); + + sparse = (struct vfio_region_info_cap_sparse_mmap *) + ((uint8_t *)vinfo->info + + vinfo->info->cap_offset); + sparse->header.id = VFIO_REGION_INFO_CAP_SPARSE_MMAP; + sparse->header.version = 1; + sparse->nr_areas = 2; + sparse->areas[0].offset = 0; + sparse->areas[0].size = 0x3000; + sparse->areas[1].offset = 0x6000; + sparse->areas[1].size = IAVF_EMU_BAR0_SIZE - 0x6000; + + break; + case VFIO_PCI_BAR3_REGION_INDEX: + vinfo->info->argsz = sz; + vinfo->info->offset = 0; + vinfo->info->size = IAVF_EMU_BAR3_SIZE; + vinfo->info->flags = VFIO_REGION_INFO_FLAG_READ | + VFIO_REGION_INFO_FLAG_WRITE | + VFIO_REGION_INFO_FLAG_MMAP; + break; + default: + vinfo->info->argsz = sz; + vinfo->info->offset = 0; + vinfo->info->size = 0; + vinfo->info->flags = 0; + } + } + + irq = rte_zmalloc_socket("vfio_user_irq_info", sizeof(*irq) + + VFIO_PCI_NUM_IRQS * sizeof(struct vfio_irq_info), + 0, dev->numa_node); + if (!irq) { + EMU_IAVF_LOG(ERR, "Failed to alloc vfio_user_irqs\n"); + ret = -1; + goto err_irq; + } + irq->irq_num = VFIO_PCI_NUM_IRQS; + + for (i = 0; i < VFIO_PCI_NUM_IRQS; i++) { + irq->irq_info[i].index = i; + irq->irq_info[i].flags = + VFIO_IRQ_INFO_EVENTFD | VFIO_IRQ_INFO_NORESIZE; + if (i == VFIO_PCI_MSIX_IRQ_INDEX) + irq->irq_info[i].count = + IAVF_EMU_MSIX_TABLE_SIZE + 1; + else if (i == VFIO_PCI_ERR_IRQ_INDEX) + irq->irq_info[i].count = 1; + else + irq->irq_info[i].count = 0; + } + + vfio->dev_info = dev_info; + vfio->reg = reg; + vfio->irq = irq; + dev->vfio = vfio; + + return 0; + +err_irq: +err_reg_alloc: + for (j = 0; j < i; j++) + rte_free(reg->reg_info[j].info); + rte_free(reg); +err_reg: + rte_free(dev_info); +err_info: + rte_free(vfio); +exit: + return ret; +} + +static int iavf_emu_uninit_dev(struct iavf_emudev *dev) +{ + struct iavf_emu_vfio_user *vfio; + struct rte_vfio_user_regions *reg; + uint32_t i; + + if (!dev->vfio) + return -1; + + vfio = dev->vfio; + rte_free(vfio->dev_info); + + reg = vfio->reg; + for (i = 0; i < reg->reg_num; i++) + rte_free(reg->reg_info[i].info); + rte_free(reg); + + rte_free(vfio->irq); + rte_free(vfio); + + return 0; +} + +static int handle_pci_cmd_write(struct iavf_emu_pci_hdr *hdr, + char *buf, size_t count) +{ + /* Below are all R/W bits in command register */ + uint16_t rw_bitmask = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | PCI_COMMAND_PARITY | + PCI_COMMAND_SERR | PCI_COMMAND_INTX_DISABLE; + uint16_t val; + + if (count != 2) { + EMU_IAVF_LOG(ERR, "Wrong write count (%lu) for PCI_COMMAND\n", + count); + return -1; + } + + val = *(uint16_t *)buf; + /* Only write the R/W bits */ + hdr->cmd = (rw_bitmask & val) | (~rw_bitmask & hdr->cmd); + + return 2; +} + +static int handle_pci_status_write(struct iavf_emu_pci_hdr *hdr, + char *buf, size_t count) +{ + /* Below are all write-1-to-clear bits in status register */ + uint16_t rw1c_bitmask = PCI_STATUS_PARITY | + PCI_STATUS_SIG_TARGET_ABORT | + PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT | + PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY; + uint16_t val; + + if (count != 2) { + EMU_IAVF_LOG(ERR, "Wrong write count (%lu) for PCI_STATUS\n", + count); + return -1; + } + + val = *(uint16_t *)buf; + /* Clear the write-1-to-clear bits*/ + hdr->status = ~(rw1c_bitmask & val) & hdr->status; + + return 2; +} + +static int handle_pci_bar_write(struct iavf_emu_pci_hdr *hdr, + char *buf, size_t count, loff_t pos) +{ + uint32_t val, size; + uint8_t idx; + + if (count != 4) { + EMU_IAVF_LOG(ERR, "Wrong write count (%lu) for " + "Base Address Register\n", + count); + return -1; + } + + val = *(uint32_t *)buf; + + if (pos == PCI_BASE_ADDRESS_0) + size = IAVF_EMU_BAR0_SIZE; + else if (pos == PCI_BASE_ADDRESS_3) + size = IAVF_EMU_BAR3_SIZE; + else + size = 0; + + if (val == IAVF_EMU_BAR_SIZE_MASK) + val &= IAVF_EMU_BAR_MASK(size); + + idx = (pos - PCI_BASE_ADDRESS_0) / 0x4; + hdr->bar[idx] |= val & ~PCI_BASE_ADDRESS_MEM_MASK; + + return 4; +} + +static int handle_cfg_write(struct iavf_emu_pci_hdr *hdr, + char *buf, size_t count, loff_t pos) +{ + int ret = count; + + switch (pos) { + case PCI_COMMAND: + ret = handle_pci_cmd_write(hdr, buf, count); + break; + case PCI_STATUS: + ret = handle_pci_status_write(hdr, buf, count); + break; + case PCI_INTERRUPT_LINE: + if (count != 1) { + EMU_IAVF_LOG(ERR, "Wrong write count (%lu)" + "for PCI_INTERRUPT_LINE\n", + count); + return -1; + } + hdr->intrl = *(uint8_t *)buf; + ret = 1; + break; + case PCI_BASE_ADDRESS_0: + /* FALLTHROUGH */ + case PCI_BASE_ADDRESS_1: + /* FALLTHROUGH */ + case PCI_BASE_ADDRESS_2: + /* FALLTHROUGH */ + case PCI_BASE_ADDRESS_3: + /* FALLTHROUGH */ + case PCI_BASE_ADDRESS_4: + /* FALLTHROUGH */ + case PCI_BASE_ADDRESS_5: + ret = handle_pci_bar_write(hdr, buf, count, pos); + break; + default: + EMU_IAVF_LOG(INFO, "Write request for cfg (pos: %ld) ignored\n", + pos); + break; + } + + return ret; +} + +static ssize_t iavf_emu_cfg_rw(struct rte_vfio_user_reg_info *reg, char *buf, + size_t count, loff_t pos, bool iswrite) +{ + struct iavf_emu_cfg_space *cfg; + char *reg_pos; + int ret = 0; + + if (!reg->base) { + EMU_IAVF_LOG(ERR, "Config space not exist\n"); + return -EFAULT; + } + + if (pos + count > reg->info->size) { + EMU_IAVF_LOG(ERR, "Access exceeds config space size\n"); + return -EINVAL; + } + + cfg = (struct iavf_emu_cfg_space *)reg->base; + reg_pos = (char *)reg->base + pos; + + if (!iswrite) { + rte_memcpy(buf, reg_pos, count); + ret = count; + } else { + ret = handle_cfg_write(&cfg->hdr, buf, count, pos); + if (ret < 0) { + EMU_IAVF_LOG(ERR, "Failed to write cfg space\n"); + return -EINVAL; + } + } + + return ret; +} + +static int iavf_emu_init_cfg_space(struct rte_vfio_user_reg_info *vinfo, + unsigned int numa_node) +{ + char *v_cfg; + + vinfo->base = rte_zmalloc_socket("cfg space", + IAVF_EMU_CFG_SPACE_SIZE, + 0, numa_node); + if (!vinfo->base) { + EMU_IAVF_LOG(ERR, "Failed to alloc cfg space\n"); + return -1; + } + vinfo->rw = iavf_emu_cfg_rw; + vinfo->fd = -1; + vinfo->priv = NULL; + + v_cfg = (char *)vinfo->base; + + STORE_LE16((uint16_t *)&v_cfg[PCI_VENDOR_ID], + PCI_VENDOR_ID_INTEL); + STORE_LE16((uint16_t *)&v_cfg[PCI_DEVICE_ID], + IAVF_DEV_ID_ADAPTIVE_VF); + STORE_LE16((uint16_t *)&v_cfg[PCI_SUBSYSTEM_VENDOR_ID], + PCI_VENDOR_ID_INTEL); + STORE_LE16((uint16_t *)&v_cfg[PCI_SUBSYSTEM_ID], + PCI_SUBDEVICE_ID); + + STORE_LE16((uint16_t *)&v_cfg[PCI_COMMAND], + PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + STORE_LE16((uint16_t *)&v_cfg[PCI_CLASS_DEVICE], + PCI_CLASS_ETHERNET); + v_cfg[PCI_CLASS_REVISION] = 0x01; + + STORE_LE16((uint16_t *)&v_cfg[PCI_STATUS], + PCI_STATUS_CAP_LIST); + + STORE_LE32((uint32_t *)&v_cfg[PCI_BASE_ADDRESS_0], + PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_TYPE_32 | + PCI_BASE_ADDRESS_MEM_PREFETCH); + + STORE_LE32((uint32_t *)&v_cfg[PCI_BASE_ADDRESS_3], + PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_TYPE_32); + + STORE_LE16((uint16_t *)&v_cfg[PCI_CAPABILITY_LIST], + 0x70); + STORE_LE16((uint16_t *)&v_cfg[0x70], + PCI_CAP_ID_MSIX); + + STORE_LE16((uint16_t *)&v_cfg[0x70 + PCI_MSIX_FLAGS], + (IAVF_EMU_MSIX_TABLE_SIZE & PCI_MSIX_FLAGS_QSIZE) | + PCI_MSIX_FLAGS_ENABLE); + + STORE_LE32((uint32_t *)&v_cfg[0x70 + PCI_MSIX_TABLE], + (0x3 & PCI_MSIX_TABLE_BIR)); + + STORE_LE32((uint32_t *)&v_cfg[0x70 + PCI_MSIX_PBA], + (0x3 & PCI_MSIX_PBA_BIR) | + (0x100 & PCI_MSIX_PBA_OFFSET)); + + return 0; +} + +static inline void iavf_emu_uninit_cfg_space( + struct rte_vfio_user_reg_info *vinfo) +{ + rte_free(vinfo->base); + vinfo->rw = NULL; + vinfo->info->size = 0; + vinfo->fd = -1; +} +static ssize_t iavf_emu_bar0_rw(struct rte_vfio_user_reg_info *reg, char *buf, + size_t count, loff_t pos, bool iswrite) +{ + struct iavf_emudev *dev = (struct iavf_emudev *)reg->priv; + char *reg_pos; + + if (!reg->base) { + EMU_IAVF_LOG(ERR, "BAR 0 does not exist\n"); + return -EFAULT; + } + + if (pos + count > reg->info->size) { + EMU_IAVF_LOG(ERR, "Access exceeds BAR 0 size\n"); + return -EINVAL; + } + + reg_pos = (char *)reg->base + pos; + + if (!iswrite) { + rte_memcpy(buf, reg_pos, count); + } else { + int tmp; + uint32_t val; + int idx = -1; + + if (count != 4) + return -EINVAL; + + val = *(uint32_t *)buf; + /* Only handle interrupt enable/disable for now */ + if (pos == IAVF_VFINT_DYN_CTL01) { + tmp = val & IAVF_VFINT_DYN_CTL01_INTENA_MASK; + idx = 0; + } else if ((pos >= IAVF_VFINT_DYN_CTLN1(0)) && pos <= + IAVF_VFINT_DYN_CTLN1(RTE_IAVF_EMU_MAX_INTR - 1)) { + tmp = val & IAVF_VFINT_DYN_CTLN1_INTENA_MASK; + idx = pos - IAVF_VFINT_DYN_CTLN1(0); + if (idx % 4) + return -EINVAL; + idx = idx / 4; + } + + if (idx != -1 && + tmp != dev->intr->info[idx].enable && dev->ready) { + dev->ops->update_status(dev->edev); + dev->intr->info[idx].enable = tmp; + } + + rte_memcpy(reg_pos, buf, count); + } + + return count; +} + +static int iavf_emu_alloc_reg(struct iavf_emudev *dev) +{ + struct rte_vfio_user_regions *reg = dev->vfio->reg; + struct rte_vfio_user_reg_info *vinfo; + char shm_str[64]; + uint32_t i; + int ret; + + for (i = 0; i < reg->reg_num; i++) { + vinfo = ®->reg_info[i]; + + switch (i) { + case VFIO_PCI_CONFIG_REGION_INDEX: + ret = iavf_emu_init_cfg_space(vinfo, dev->numa_node); + if (ret) + return ret; + break; + case VFIO_PCI_BAR0_REGION_INDEX: + case VFIO_PCI_BAR3_REGION_INDEX: + sprintf(shm_str, "AVF%d_BAR%d", + dev->edev->dev_id, i); + vinfo->fd = shm_open(shm_str, + O_RDWR|O_CREAT, 0700); + if (vinfo->fd == -1) { + EMU_IAVF_LOG(ERR, + "Failed to open shm for BAR %d\n", i); + goto exit; + } + + if (ftruncate(vinfo->fd, vinfo->info->size) == -1) { + EMU_IAVF_LOG(ERR, + "Failed to ftruncate BAR %d\n", i); + ret = -1; + goto exit; + } + + vinfo->base = mmap(NULL, vinfo->info->size, + PROT_READ | PROT_WRITE, + MAP_SHARED, vinfo->fd, 0); + memset(vinfo->base, 0, vinfo->info->size); + if (vinfo->base == MAP_FAILED) { + EMU_IAVF_LOG(ERR, + "Failed to mmap BAR %d\n", i); + ret = -1; + goto exit; + } + vinfo->priv = (void *)dev; + if (i == VFIO_PCI_BAR0_REGION_INDEX) + vinfo->rw = iavf_emu_bar0_rw; + else + vinfo->rw = NULL; + break; + default: + vinfo->base = NULL; + vinfo->rw = NULL; + vinfo->fd = -1; + vinfo->priv = NULL; + break; + } + } + + return 0; + +exit: + for (;; i--) { + vinfo = ®->reg_info[i]; + + if (i == VFIO_PCI_CONFIG_REGION_INDEX) + iavf_emu_uninit_cfg_space(vinfo); + + if (!vinfo->info->size) { + if (!vinfo->base) + munmap(vinfo->base, vinfo->info->size); + if (vinfo->fd > 0) { + close(vinfo->fd); + sprintf(shm_str, "AVF%d_BAR%d", + dev->edev->dev_id, i); + shm_unlink(shm_str); + vinfo->fd = -1; + } + } + + if (i == 0) + break; + } + return ret; +} + +static void iavf_emu_free_reg(struct iavf_emudev *dev) +{ + struct rte_vfio_user_regions *reg = dev->vfio->reg; + struct rte_vfio_user_reg_info *vinfo; + char shm_str[64]; + uint32_t i; + + for (i = 0; i < reg->reg_num; i++) { + vinfo = ®->reg_info[i]; + + switch (i) { + case VFIO_PCI_CONFIG_REGION_INDEX: + iavf_emu_uninit_cfg_space(vinfo); + break; + case VFIO_PCI_BAR0_REGION_INDEX: + /* FALLTHROUGH */ + case VFIO_PCI_BAR3_REGION_INDEX: + munmap(vinfo->base, vinfo->info->size); + close(vinfo->fd); + vinfo->fd = -1; + sprintf(shm_str, "AVF%d_BAR%d", + dev->edev->dev_id, i); + shm_unlink(shm_str); + vinfo->info->size = 0; + break; + default: + break; + } + } +} + static inline struct iavf_emu_sock_list * iavf_emu_find_sock_list(char *sock_addr) { @@ -382,3 +983,71 @@ int iavf_emu_unregister_vfio_user(struct iavf_emudev *dev) return 0; } + +int iavf_emu_init_vfio_user(struct iavf_emudev *dev) +{ + int ret; + struct iavf_emu_sock_list *list; + + if (iavf_emu_init_dev(dev)) { + EMU_IAVF_LOG(ERR, "Emulated iavf dev init failed.\n"); + ret = -1; + goto exit; + } + + if (iavf_emu_alloc_reg(dev)) { + EMU_IAVF_LOG(ERR, "Emulated iavf alloc region failed.\n"); + ret = -1; + goto err_alloc_reg; + } + + ret = rte_vfio_user_set_dev_info(dev->sock_addr, dev->vfio->dev_info); + if (ret) { + EMU_IAVF_LOG(ERR, "Failed to set vfio dev info\n"); + goto err_set; + } + + ret = rte_vfio_user_set_reg_info(dev->sock_addr, dev->vfio->reg); + if (ret) { + EMU_IAVF_LOG(ERR, "Failed to set vfio region info\n"); + goto err_set; + } + + ret = rte_vfio_user_set_irq_info(dev->sock_addr, dev->vfio->irq); + if (ret) { + EMU_IAVF_LOG(ERR, "Failed to set vfio irq info\n"); + goto err_set; + } + + list = rte_zmalloc_socket("list", sizeof(*list), 0, dev->numa_node); + list->emu_dev = dev->edev; + pthread_mutex_lock(&sock_list_lock); + TAILQ_INSERT_TAIL(&sock_list, list, next); + pthread_mutex_unlock(&sock_list_lock); + + return 0; + +err_set: + iavf_emu_free_reg(dev); +err_alloc_reg: + iavf_emu_uninit_dev(dev); +exit: + return ret; +} + +void iavf_emu_uninit_vfio_user(struct iavf_emudev *dev) +{ + iavf_emu_free_reg(dev); + iavf_emu_uninit_dev(dev); +} + +int iavf_emu_start_vfio_user(struct iavf_emudev *dev) +{ + int ret; + + ret = rte_vfio_user_start(dev->sock_addr); + if (ret) + EMU_IAVF_LOG(ERR, "Start vfio user failed.\n"); + + return ret; +} diff --git a/drivers/emu/iavf/iavf_vfio_user.h b/drivers/emu/iavf/iavf_vfio_user.h index aa2f3edc87..2ccb04eb48 100644 --- a/drivers/emu/iavf/iavf_vfio_user.h +++ b/drivers/emu/iavf/iavf_vfio_user.h @@ -5,12 +5,53 @@ #ifndef _IAVF_VFIO_USER_H #define _IAVF_VFIO_USER_H +#include + #include #include "iavf_emu_internal.h" +#define IAVF_EMU_CFG_SPACE_SIZE 0x100 + +struct iavf_emu_pci_hdr { + uint16_t vid; /* Vendor ID */ + uint16_t did; /* Device ID */ + uint16_t cmd; /* Command */ + uint16_t status; /* Status */ + uint8_t rid; /* Revision ID */ + uint8_t cc_pi; /* Program I/F in Class Code*/ + uint8_t cc_sub; /* Sub-Class Code */ + uint8_t cc_base; /* Base Class Code */ + uint8_t cl_size; /* Cache Line Size*/ + uint8_t lt_timer; /* Latency Timer */ + uint8_t hdr_type; /* Header Type */ + uint8_t bist; /* BIST */ + uint32_t bar[6]; /* Base Address Registers */ + uint32_t ccp; /* Cardbus CIC Pointer */ + uint16_t sub_vid; /* Subsystem Vendor ID */ + uint16_t sub_sid; /* Subsystem ID */ + uint32_t rom; /* Expansion ROM Base Address */ + uint8_t cap; /* Capabilities Pointer */ + uint8_t rsvd[7]; /* Reserved */ + uint8_t intrl; /* Interrupt Line */ + uint8_t intrp; /* Interrupt Pin */ + uint8_t min_gnt; /* Min_Gnt Register */ + uint8_t max_lat; /* Max_Lat Register */ +} __attribute((packed)); + +struct iavf_emu_cfg_space { + struct iavf_emu_pci_hdr hdr; + uint8_t cfg_non_std[IAVF_EMU_CFG_SPACE_SIZE - PCI_STD_HEADER_SIZEOF]; +} __attribute((packed)); + int iavf_emu_register_vfio_user(struct iavf_emudev *dev); int iavf_emu_unregister_vfio_user(struct iavf_emudev *dev); +int iavf_emu_init_vfio_user(struct iavf_emudev *dev); + +void iavf_emu_uninit_vfio_user(struct iavf_emudev *dev); + +int iavf_emu_start_vfio_user(struct iavf_emudev *dev); + #endif diff --git a/drivers/emu/iavf/meson.build b/drivers/emu/iavf/meson.build index 4f651258c2..3cab2226b7 100644 --- a/drivers/emu/iavf/meson.build +++ b/drivers/emu/iavf/meson.build @@ -1,6 +1,14 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2020 Intel Corporation +librt = cc.find_library('rt', required: false) +if not librt.found() + build = false + subdir_done() +endif + +ext_deps += librt + sources = files('iavf_emu.c', 'iavf_vfio_user.c', 'iavf_emudev.c') From patchwork Sat Dec 19 06:28:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chenbo Xia X-Patchwork-Id: 85494 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 84AD5A04B5; Sat, 19 Dec 2020 07:45:19 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id F0942CBA2; Sat, 19 Dec 2020 07:43:32 +0100 (CET) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id 9CC4DCB97 for ; Sat, 19 Dec 2020 07:43:30 +0100 (CET) IronPort-SDR: VCP7s5yYP3jDfkZDoIJgEdn5ZCMp4BzOzlextoIMX6pIhMScr76/8FMVuXC0Cl8TWuEEiR04Zz +WdFtfdDED3A== X-IronPort-AV: E=McAfee;i="6000,8403,9839"; a="163285196" X-IronPort-AV: E=Sophos;i="5.78,432,1599548400"; d="scan'208";a="163285196" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Dec 2020 22:43:30 -0800 IronPort-SDR: kBrNPOmv7JN6of+rHul9VKw0StdnARDexmkU4wJhougIJgWsbdOxIM3ZBJlcah+6/GyWUbmPN+ To5db5H2VJ9g== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,432,1599548400"; d="scan'208";a="454449632" Received: from npg-dpdk-virtio-xiachenbo-nw.sh.intel.com ([10.67.119.123]) by fmsmga001.fm.intel.com with ESMTP; 18 Dec 2020 22:43:28 -0800 From: Chenbo Xia To: dev@dpdk.org, thomas@monjalon.net, david.marchand@redhat.com Cc: stephen@networkplumber.org, cunming.liang@intel.com, xiuchun.lu@intel.com, miao.li@intel.com, jingjing.wu@intel.com Date: Sat, 19 Dec 2020 14:28:04 +0800 Message-Id: <20201219062806.56477-7-chenbo.xia@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201219062806.56477-1-chenbo.xia@intel.com> References: <20201218074736.93999-1-chenbo.xia@intel.com> <20201219062806.56477-1-chenbo.xia@intel.com> Subject: [dpdk-dev] [PATCH v2 6/8] emu/iavf: add emudev operations to fit in emudev framework X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" This patch implements emudev opertions to make emulated iavf fit into rte_emudev framework. Lifecycle related and device resource related operations are both implemented. Signed-off-by: Chenbo Xia Signed-off-by: Xiuchun Lu --- drivers/emu/iavf/iavf_emu.c | 218 ++++++++++++++++++++++++++++++++ drivers/emu/iavf/rte_iavf_emu.h | 59 +++++++++ 2 files changed, 277 insertions(+) diff --git a/drivers/emu/iavf/iavf_emu.c b/drivers/emu/iavf/iavf_emu.c index c1a702d744..9ad371ca98 100644 --- a/drivers/emu/iavf/iavf_emu.c +++ b/drivers/emu/iavf/iavf_emu.c @@ -2,7 +2,72 @@ * Copyright(c) 2020 Intel Corporation */ +#include +#include +#include + +#include +#include + #include "iavf_vfio_user.h" +#include + +static int iavf_emu_dev_start(struct rte_emudev *dev) +{ + struct iavf_emudev *iavf = (struct iavf_emudev *)dev->priv_data; + + if (iavf->ops != NULL && iavf->ops->device_start != NULL) + iavf->ops->device_start(dev); + + return 0; +} + +static void iavf_emu_dev_stop(struct rte_emudev *dev) +{ + struct iavf_emudev *iavf = (struct iavf_emudev *)dev->priv_data; + + if (iavf->ops != NULL && iavf->ops->device_stop != NULL) + iavf->ops->device_stop(dev); +} + +static int iavf_emu_dev_configure(struct rte_emudev *dev, + struct rte_emudev_info *dev_conf) +{ + struct iavf_emudev *iavf = (struct iavf_emudev *)dev->priv_data; + struct rte_iavf_emu_config *conf = + (struct rte_iavf_emu_config *)dev_conf->dev_priv; + + if (!dev_conf->dev_priv) + return -EINVAL; + + /* Currently emulated iavf does not support max_qp_num + * and region num configuration + */ + if (dev->dev_info.max_qp_num != dev_conf->max_qp_num || + dev->dev_info.region_num != dev_conf->region_num) { + EMU_IAVF_LOG(ERR, + "Configure max_qp_num/region num not supported\n"); + return -ENOTSUP; + } + + if (conf->qp_num > RTE_MAX_QUEUES_PER_PORT || + conf->qp_num > RTE_IAVF_EMU_MAX_QP_NUM) { + EMU_IAVF_LOG(ERR, "Queue pair num exceeds max\n"); + return -EINVAL; + } + + /* For now, we don't support device configure when data + * path driver is attached + */ + if (dev->backend_priv) { + EMU_IAVF_LOG(ERR, "Configure failed because of " + "data path attached\n"); + return -EPERM; + } + + iavf->max_be_lanqp = conf->qp_num; + return 0; +} static int iavf_emu_dev_close(struct rte_emudev *dev) { @@ -26,6 +91,159 @@ static int iavf_emu_dev_close(struct rte_emudev *dev) return 0; } +static int iavf_emu_get_dev_info(struct rte_emudev *dev, + rte_emudev_obj_t info) +{ + struct iavf_emudev *iavf = (struct iavf_emudev *)dev->priv_data; + struct rte_iavf_emu_config *conf = (struct rte_iavf_emu_config *)info; + + if (!info) + return -EINVAL; + + conf->qp_num = iavf->max_be_lanqp; + return 0; +} + +static int iavf_emu_get_mem_table(struct rte_emudev *dev, + rte_emudev_mem_table_t *tb) +{ + struct iavf_emudev *iavf = (struct iavf_emudev *)dev->priv_data; + + *tb = iavf->mem; + + return 0; +} + +static int iavf_emu_get_queue_info(struct rte_emudev *dev, uint32_t queue, + struct rte_emudev_q_info *info) +{ + struct iavf_emudev *iavf = (struct iavf_emudev *)dev->priv_data; + + if (queue < RTE_IAVF_EMU_ADMINQ_NUM) { + struct iavf_emu_adminQ *adq = &iavf->adq[queue]; + uint64_t base, size; + + if (adq->ring_addr_lo == NULL || + adq->ring_addr_hi == NULL || + adq->ring_sz == NULL) + return -1; + base = RTE_IAVF_EMU_32_TO_64(*adq->ring_addr_hi, + *adq->ring_addr_lo); + size = *adq->ring_sz; + info->base = base; + info->size = size; + info->doorbell_id = queue; + /* RX AdminQ should have IRQ vector 0 */ + info->irq_vector = queue - 1; + } else { + info->base = 0; + info->size = 0; + info->doorbell_id = queue; + info->irq_vector = -1; + } + + return 0; +} + +static int iavf_emu_get_irq_info(struct rte_emudev *dev, uint32_t vector, + struct rte_emudev_irq_info *info) +{ + struct iavf_emudev *iavf = (struct iavf_emudev *)dev->priv_data; + struct iavf_emu_intr *intr = iavf->intr; + struct iavf_emu_intr_info *intr_info = &intr->info[vector]; + + if (vector >= intr->intr_num) + return -EINVAL; + + info->eventfd = intr_info->fd; + info->enable = intr_info->enable; + info->vector = vector; + + return 0; +} + +static int iavf_emu_get_db_info(struct rte_emudev *dev, uint32_t doorbell, + struct rte_emudev_db_info *info) +{ + struct iavf_emudev *iavf = (struct iavf_emudev *)dev->priv_data; + + if (doorbell < RTE_IAVF_EMU_ADMINQ_NUM) { + struct iavf_emu_adminQ *adq = &iavf->adq[doorbell]; + + info->data.mem.base = (uint64_t)adq->doorbell; + info->data.mem.size = adq->db_size; + } else { + struct iavf_emu_lanQ *lanq = + &iavf->lanq[doorbell - RTE_IAVF_EMU_ADMINQ_NUM]; + + info->data.mem.base = (uint64_t)lanq->doorbell; + info->data.mem.size = lanq->db_size; + } + + info->flag |= RTE_EMUDEV_DB_MEM; + info->id = doorbell; + + return 0; +} + +static int iavf_emu_subs_ev(struct rte_emudev *dev, + rte_emudev_event_chnl_t ev_chnl) +{ + struct iavf_emudev *iavf = (struct iavf_emudev *)dev->priv_data; + + iavf->ops = (struct rte_iavf_emu_notify_ops *)ev_chnl; + + return 0; +} + +static int iavf_emu_unsubs_ev(struct rte_emudev *dev, + rte_emudev_event_chnl_t ev_chnl) +{ + struct iavf_emudev *iavf = (struct iavf_emudev *)dev->priv_data; + + if ((struct rte_iavf_emu_notify_ops *)ev_chnl == iavf->ops) { + iavf->ops = NULL; + return 0; + } + + return -EINVAL; +} + +static int iavf_emu_get_attr(struct rte_emudev *dev, const char *attr_name, + rte_emudev_attr_t attr) +{ + struct iavf_emudev *iavf = (struct iavf_emudev *)dev->priv_data; + struct rte_vfio_user_reg_info *info; + int ret = 0; + + info = &iavf->vfio->reg->reg_info[0]; + + if (!strcmp(attr_name, RTE_IAVF_EMU_ATTR_ASQ_HEAD)) + *(uint64_t *)attr = (uint64_t)(uintptr_t)info->base + + IAVF_VF_ATQH1; + else if (!strcmp(attr_name, RTE_IAVF_EMU_ATTR_ARQ_HEAD)) + *(uint64_t *)attr = (uint64_t)(uintptr_t)info->base + + IAVF_VF_ARQH1; + else if (!strcmp(attr_name, RTE_IAVF_EMU_ATTR_RESET)) + *(uint64_t *)attr = (uint64_t)(uintptr_t)info->base + + IAVF_VFGEN_RSTAT; + else + ret = -EINVAL; + + return ret; +} + struct rte_emudev_ops emu_iavf_ops = { + .dev_start = iavf_emu_dev_start, + .dev_stop = iavf_emu_dev_stop, + .dev_configure = iavf_emu_dev_configure, .dev_close = iavf_emu_dev_close, + .dev_info_get = iavf_emu_get_dev_info, + .get_mem_table = iavf_emu_get_mem_table, + .get_queue_info = iavf_emu_get_queue_info, + .get_irq_info = iavf_emu_get_irq_info, + .get_db_info = iavf_emu_get_db_info, + .subscribe_event = iavf_emu_subs_ev, + .unsubscribe_event = iavf_emu_unsubs_ev, + .get_attr = iavf_emu_get_attr, }; diff --git a/drivers/emu/iavf/rte_iavf_emu.h b/drivers/emu/iavf/rte_iavf_emu.h index 6de0989f0b..2abcec97d4 100644 --- a/drivers/emu/iavf/rte_iavf_emu.h +++ b/drivers/emu/iavf/rte_iavf_emu.h @@ -6,13 +6,24 @@ #define _IAVF_EMU_H #include +#include +#include +#include +#include +#include #include #define RTE_IAVF_EMUDEV_TYPE "iavf" +#define RTE_IAVF_EMU_ATTR_ASQ_HEAD "ASQ_H" +#define RTE_IAVF_EMU_ATTR_ARQ_HEAD "ARQ_H" +#define RTE_IAVF_EMU_ATTR_RESET "RESET" +#define RTE_IAVF_EMU_RESET_IN_PROGRESS 0x00 +#define RTE_IAVF_EMU_RESET_COMPLETED 0x01 #define RTE_IAVF_EMU_MAX_MEM_REGIONS 256 #define RTE_IAVF_EMU_MAX_QP_NUM 256 #define RTE_IAVF_EMU_MAX_INTR 32 +#define RTE_IAVF_EMU_32_TO_64(hi, lo) ((((uint64_t)(hi)) << 32) + (lo)) enum { RTE_IAVF_EMU_ADMINQ_TXQ = 0, @@ -26,6 +37,11 @@ enum { RTE_IAVF_EMU_MAPPABLE_REG_NUM = 2, }; +struct rte_iavf_emu_config { + /* Maximum queue pair number that data path driver can use */ + uint32_t qp_num; +}; + struct rte_iavf_emu_mem_reg { uint64_t guest_phys_addr; uint64_t host_user_addr; @@ -40,6 +56,49 @@ struct rte_iavf_emu_mem { struct rte_iavf_emu_mem_reg regions[RTE_IAVF_EMU_MAX_MEM_REGIONS]; }; +/** + * Helper function for data path driver to translate address + * of one region + * + * @param mem + * A pointer to DMA memory table + * @param g_addr + * Guest I/O virtual base address of the region + * @param[in/out] len + * The length of region + * @return + * - >0: Success, process virtual address returned + * - 0: Failure on translation + */ +__rte_experimental +__rte_always_inline uint64_t +rte_iavf_emu_get_dma_vaddr(struct rte_iavf_emu_mem *mem, + uint64_t g_addr, uint64_t *len) +{ + struct rte_iavf_emu_mem_reg *reg; + uint32_t i; + + for (i = 0; i < mem->region_num; i++) { + reg = &mem->regions[i]; + + if (g_addr >= reg->guest_phys_addr && + g_addr < reg->guest_phys_addr + reg->size) { + + if (unlikely(*len > reg->guest_phys_addr + + reg->size - g_addr)) + *len = reg->guest_phys_addr + + reg->size - g_addr; + + return g_addr - reg->guest_phys_addr + + reg->host_user_addr; + } + } + + *len = 0; + + return 0; +} + struct rte_iavf_emu_notify_ops { /* Device is ready */ int (*device_ready)(struct rte_emudev *dev); From patchwork Sat Dec 19 06:28:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chenbo Xia X-Patchwork-Id: 85495 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 35889A04B5; Sat, 19 Dec 2020 07:45:41 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 09846CBDC; Sat, 19 Dec 2020 07:43:35 +0100 (CET) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id 55B8ACBA9 for ; Sat, 19 Dec 2020 07:43:33 +0100 (CET) IronPort-SDR: 18fBoKVNLtJ1F5VogLh54X232Y6nEMyAeTRLPI5qwO7+OixaXB31PglGQu2S3ODGlivfWE2iR5 6jbHdZypJmeg== X-IronPort-AV: E=McAfee;i="6000,8403,9839"; a="163285200" X-IronPort-AV: E=Sophos;i="5.78,432,1599548400"; d="scan'208";a="163285200" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Dec 2020 22:43:32 -0800 IronPort-SDR: jgG0HKoa+xYrWlG3ug/0XhFjjo1EkZvqGWjav+79Bso1puTGTWqxDtkp4Ex/X4MSDw51tK+Rg/ 3hHkAcXu8oxg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,432,1599548400"; d="scan'208";a="454449638" Received: from npg-dpdk-virtio-xiachenbo-nw.sh.intel.com ([10.67.119.123]) by fmsmga001.fm.intel.com with ESMTP; 18 Dec 2020 22:43:30 -0800 From: Chenbo Xia To: dev@dpdk.org, thomas@monjalon.net, david.marchand@redhat.com Cc: stephen@networkplumber.org, cunming.liang@intel.com, xiuchun.lu@intel.com, miao.li@intel.com, jingjing.wu@intel.com Date: Sat, 19 Dec 2020 14:28:05 +0800 Message-Id: <20201219062806.56477-8-chenbo.xia@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201219062806.56477-1-chenbo.xia@intel.com> References: <20201218074736.93999-1-chenbo.xia@intel.com> <20201219062806.56477-1-chenbo.xia@intel.com> Subject: [dpdk-dev] [PATCH v2 7/8] test/emudev: introduce functional test X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" This patch introduces functional test for emudev. The implementation of iavf emudev selftest is also added. Signed-off-by: Miao Li Signed-off-by: Chenbo Xia --- app/test/meson.build | 5 +- app/test/test_emudev.c | 29 +++++ drivers/emu/iavf/iavf_emu.c | 1 + drivers/emu/iavf/iavf_emu_internal.h | 1 + drivers/emu/iavf/iavf_emu_test.c | 174 +++++++++++++++++++++++++++ drivers/emu/iavf/meson.build | 2 +- 6 files changed, 210 insertions(+), 2 deletions(-) create mode 100644 app/test/test_emudev.c create mode 100644 drivers/emu/iavf/iavf_emu_test.c diff --git a/app/test/meson.build b/app/test/meson.build index f5b15ac44c..b8b79bbc8b 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -139,6 +139,7 @@ test_sources = files('commands.c', 'test_trace_register.c', 'test_trace_perf.c', 'test_vfio_user.c', + 'test_emudev.c', 'test_version.c', 'virtual_pmd.c' ) @@ -176,7 +177,8 @@ test_deps = ['acl', 'stack', 'vfio_user', 'telemetry', - 'timer' + 'timer', + 'emudev' ] # Each test is marked with flag true/false @@ -327,6 +329,7 @@ driver_test_names = [ 'eventdev_selftest_octeontx', 'eventdev_selftest_sw', 'rawdev_autotest', + 'emudev_autotest', ] dump_test_names = [ diff --git a/app/test/test_emudev.c b/app/test/test_emudev.c new file mode 100644 index 0000000000..0dfce162ed --- /dev/null +++ b/app/test/test_emudev.c @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Intel Corporation + */ + +#include +#include + +#include "test.h" + +static int +test_emudev_selftest_impl(const char *pmd, const char *opts) +{ + int ret = 0; + + if (rte_emudev_get_dev_id(pmd) == -ENODEV) + ret = rte_vdev_init(pmd, opts); + if (ret) + return TEST_SKIPPED; + + return rte_emudev_selftest(rte_emudev_get_dev_id(pmd)); +} + +static int +test_emudev_selftest(void) +{ + return test_emudev_selftest_impl("emu_iavf", "sock=/tmp/sock1"); +} + +REGISTER_TEST_COMMAND(emudev_autotest, test_emudev_selftest); diff --git a/drivers/emu/iavf/iavf_emu.c b/drivers/emu/iavf/iavf_emu.c index 9ad371ca98..88bf2bdf94 100644 --- a/drivers/emu/iavf/iavf_emu.c +++ b/drivers/emu/iavf/iavf_emu.c @@ -246,4 +246,5 @@ struct rte_emudev_ops emu_iavf_ops = { .subscribe_event = iavf_emu_subs_ev, .unsubscribe_event = iavf_emu_unsubs_ev, .get_attr = iavf_emu_get_attr, + .dev_selftest = iavf_emu_selftest, }; diff --git a/drivers/emu/iavf/iavf_emu_internal.h b/drivers/emu/iavf/iavf_emu_internal.h index 10197c00ba..1ac7f96566 100644 --- a/drivers/emu/iavf/iavf_emu_internal.h +++ b/drivers/emu/iavf/iavf_emu_internal.h @@ -65,4 +65,5 @@ struct iavf_emudev { }; void iavf_emu_uninit_device(struct iavf_emudev *dev); +int iavf_emu_selftest(uint16_t dev_id); #endif diff --git a/drivers/emu/iavf/iavf_emu_test.c b/drivers/emu/iavf/iavf_emu_test.c new file mode 100644 index 0000000000..ad19134724 --- /dev/null +++ b/drivers/emu/iavf/iavf_emu_test.c @@ -0,0 +1,174 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Intel Corporation + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "iavf_emu_internal.h" + +#define TEST_DEV_NAME "emu_iavf" +#define TEST_SUCCESS 0 +#define TEST_FAILED -1 + +#define EMUDEV_TEST_RUN(setup, teardown, test) \ + emudev_test_run(setup, teardown, test, #test) +static uint16_t test_dev_id; +static int total; +static int passed; +static int failed; +static int unsupported; + +static int +testsuite_setup(void) +{ + uint8_t count; + count = rte_emudev_count(); + if (!count) { + EMU_IAVF_LOG(INFO, "No existing emu dev; " + "Creating emu_iavf\n"); + return rte_vdev_init(TEST_DEV_NAME, NULL); + } + + return TEST_SUCCESS; +} + +static void +testsuite_teardown(void) +{ + rte_vdev_uninit(TEST_DEV_NAME); +} + +static void emudev_test_run(int (*setup)(void), + void (*teardown)(void), + int (*test)(void), + const char *name) +{ + int ret = 0; + + if (setup) { + ret = setup(); + if (ret < 0) { + EMU_IAVF_LOG(INFO, "Error setting up test %s\n", name); + unsupported++; + } + } + + if (test) { + ret = test(); + if (ret < 0) { + failed++; + EMU_IAVF_LOG(INFO, "%s Failed\n", name); + } else { + passed++; + EMU_IAVF_LOG(INFO, "%s Passed\n", name); + } + } + + if (teardown) + teardown(); + + total++; +} + +static int +test_emu_dev_count(void) +{ + uint8_t count; + count = rte_emudev_count(); + RTE_TEST_ASSERT(count > 0, "Invalid emudev count %" PRIu8, count); + return TEST_SUCCESS; +} + +static int +test_emu_dev_get_dev_id(void) +{ + int ret; + ret = rte_emudev_get_dev_id("Invalid_emu_dev_device\n"); + RTE_TEST_ASSERT_FAIL(ret, "Expected <0 for invalid dev name, ret=%d", + ret); + return TEST_SUCCESS; +} + +static int +test_emu_dev_configure(void) +{ + int ret; + struct rte_emudev_info dev_conf; + struct rte_iavf_emu_config iavf_conf_set = {.qp_num = 1}; + struct rte_iavf_emu_config iavf_conf_get = {0}; + + rte_emudev_stop(test_dev_id); + + /* Check invalid configuration */ + ret = rte_emudev_configure(test_dev_id, NULL); + RTE_TEST_ASSERT(ret == -EINVAL, + "Null configure; Expected -EINVAL, got %d", ret); + + /* Valid configuration test */ + dev_conf.dev_priv = (rte_emudev_obj_t)&iavf_conf_get; + ret = rte_emudev_get_dev_info(test_dev_id, &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, + "Failed to obtain emudev configuration (%d)", + ret); + dev_conf.dev_priv = (rte_emudev_obj_t)&iavf_conf_set; + ret = rte_emudev_configure(test_dev_id, &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure emudev (%d)", ret); + + memset(&iavf_conf_get, 0, sizeof(iavf_conf_get)); + dev_conf.dev_priv = (rte_emudev_obj_t)&iavf_conf_get; + ret = rte_emudev_get_dev_info(test_dev_id, &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, + "Failed to obtain emudev configuration (%d)", + ret); + + RTE_TEST_ASSERT_EQUAL(iavf_conf_set.qp_num, + iavf_conf_get.qp_num, + "Configuration test failed; num_queues (%d)(%d)", + iavf_conf_set.qp_num, + iavf_conf_get.qp_num); + + return TEST_SUCCESS; +} + +static int +test_emu_dev_start_stop(void) +{ + int ret; + ret = rte_emudev_start(test_dev_id); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start emudev (%d)", ret); + + rte_emudev_stop(test_dev_id); + + return TEST_SUCCESS; +} + +int iavf_emu_selftest(uint16_t dev_id) +{ + test_dev_id = dev_id; + testsuite_setup(); + + EMUDEV_TEST_RUN(NULL, NULL, test_emu_dev_count); + EMUDEV_TEST_RUN(NULL, NULL, test_emu_dev_get_dev_id); + EMUDEV_TEST_RUN(NULL, NULL, test_emu_dev_configure); + EMUDEV_TEST_RUN(NULL, NULL, test_emu_dev_start_stop); + + testsuite_teardown(); + + EMU_IAVF_LOG(INFO, "Total tests : %d\n", total); + EMU_IAVF_LOG(INFO, "Passed : %d\n", passed); + EMU_IAVF_LOG(INFO, "Failed : %d\n", failed); + EMU_IAVF_LOG(INFO, "Not supported : %d\n", unsupported); + + if (failed) + return -1; + + return 0; +} diff --git a/drivers/emu/iavf/meson.build b/drivers/emu/iavf/meson.build index 3cab2226b7..613783e407 100644 --- a/drivers/emu/iavf/meson.build +++ b/drivers/emu/iavf/meson.build @@ -10,7 +10,7 @@ endif ext_deps += librt sources = files('iavf_emu.c', 'iavf_vfio_user.c', - 'iavf_emudev.c') + 'iavf_emu_test.c', 'iavf_emudev.c') deps += ['bus_vdev', 'emudev', 'vfio_user', 'common_iavf'] From patchwork Sat Dec 19 06:28:06 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chenbo Xia X-Patchwork-Id: 85496 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id CF5F5A04B5; Sat, 19 Dec 2020 07:46:01 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 8C56CCBEC; Sat, 19 Dec 2020 07:43:38 +0100 (CET) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id 3FA68CB2F for ; Sat, 19 Dec 2020 07:43:36 +0100 (CET) IronPort-SDR: aj2S2Lsjx+XNRw6PFCpljiCJZxNPsNHgovooG0x5wwJhZv5bi+MOnIgYCvCADVuqJzlB8uHdg7 7uvndOensXwQ== X-IronPort-AV: E=McAfee;i="6000,8403,9839"; a="163285202" X-IronPort-AV: E=Sophos;i="5.78,432,1599548400"; d="scan'208";a="163285202" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Dec 2020 22:43:35 -0800 IronPort-SDR: zkFPXrrTlPw7PG1wxuAVrpG5KLj1872nG7szk78QMXnKNFhfxQcIJYKr+hssYoO3qrprxiNHpy 1pjQv2+pMPhQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,432,1599548400"; d="scan'208";a="454449653" Received: from npg-dpdk-virtio-xiachenbo-nw.sh.intel.com ([10.67.119.123]) by fmsmga001.fm.intel.com with ESMTP; 18 Dec 2020 22:43:33 -0800 From: Chenbo Xia To: dev@dpdk.org, thomas@monjalon.net, david.marchand@redhat.com Cc: stephen@networkplumber.org, cunming.liang@intel.com, xiuchun.lu@intel.com, miao.li@intel.com, jingjing.wu@intel.com Date: Sat, 19 Dec 2020 14:28:06 +0800 Message-Id: <20201219062806.56477-9-chenbo.xia@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201219062806.56477-1-chenbo.xia@intel.com> References: <20201218074736.93999-1-chenbo.xia@intel.com> <20201219062806.56477-1-chenbo.xia@intel.com> Subject: [dpdk-dev] [PATCH v2 8/8] doc: update release notes for iavf emudev driver X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Update release notes for emulated iavf driver. Signed-off-by: Chenbo Xia --- doc/guides/rel_notes/release_21_02.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/guides/rel_notes/release_21_02.rst b/doc/guides/rel_notes/release_21_02.rst index 3d26b6b580..b310b67b7d 100644 --- a/doc/guides/rel_notes/release_21_02.rst +++ b/doc/guides/rel_notes/release_21_02.rst @@ -67,7 +67,7 @@ New Features See :doc:`../prog_guide/vfio_user_lib` for more information. -* **Added emudev Library.** +* **Added emudev Library and first emudev driver.** Added an experimental library ``librte_emudev`` to provide device abstraction for an emulated device. @@ -77,6 +77,10 @@ New Features crypto and etc.). It can be attached to another data path driver (e.g, ethdev driver) to leverage the high performance of DPDK data path driver. + The first emudev driver is also introduced, which emulates software iavf + devices. This driver emulates all iavf device behavior except data path + handling. + See :doc:`../prog_guide/emudev` for more information. Removed Items