From patchwork Thu Jan 14 06:25:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Chenbo Xia X-Patchwork-Id: 86509 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 24254A0A02; Thu, 14 Jan 2021 07:30:13 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id DEB66140E10; Thu, 14 Jan 2021 07:30:10 +0100 (CET) Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by mails.dpdk.org (Postfix) with ESMTP id 930EF140E0A for ; Thu, 14 Jan 2021 07:30:09 +0100 (CET) IronPort-SDR: CAWnUs5k7Z5Nl0s/PrZ3KMa34KapfJzsI09/WgssuvC1GVCPKyW+rR5gQG8llfWMHBvbvIYM7f McZTCgQrkHeA== X-IronPort-AV: E=McAfee;i="6000,8403,9863"; a="178407158" X-IronPort-AV: E=Sophos;i="5.79,346,1602572400"; d="scan'208";a="178407158" Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Jan 2021 22:30:09 -0800 IronPort-SDR: vvCrjd/6GnnRhE37vAgiJ3vhwo9jwkwbOGQk5ayv+YaIT6ARZUy43rDdN1DDwgjEJbGpEEqCXu UsINOKiXCAig== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.79,346,1602572400"; d="scan'208";a="400799393" Received: from npg-dpdk-virtio-xiachenbo-nw.sh.intel.com ([10.67.119.123]) by fmsmga002.fm.intel.com with ESMTP; 13 Jan 2021 22:30:06 -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, beilei.xing@intel.com Date: Thu, 14 Jan 2021 14:25:05 +0800 Message-Id: <20210114062512.45462-2-chenbo.xia@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210114062512.45462-1-chenbo.xia@intel.com> References: <20201219062806.56477-1-chenbo.xia@intel.com> <20210114062512.45462-1-chenbo.xia@intel.com> MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH v3 1/8] lib: introduce emudev library X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 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 | 502 ++++++++++++++++++++++++++++ lib/librte_emudev/rte_emudev.h | 431 ++++++++++++++++++++++++ lib/librte_emudev/rte_emudev_vdev.h | 53 +++ lib/librte_emudev/version.map | 27 ++ lib/meson.build | 2 +- 7 files changed, 1024 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 91b8b2ccc1..f5f2c4fe15 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1546,6 +1546,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..9a0e42bead --- /dev/null +++ b/lib/librte_emudev/rte_emudev.c @@ -0,0 +1,502 @@ +/* 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..d7328d4d12 --- /dev/null +++ b/lib/librte_emudev/rte_emudev.h @@ -0,0 +1,431 @@ +/* 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 Thu Jan 14 06:25:06 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chenbo Xia X-Patchwork-Id: 86510 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id E2CD2A0A02; Thu, 14 Jan 2021 07:30:24 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 9D193140E25; Thu, 14 Jan 2021 07:30:15 +0100 (CET) Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by mails.dpdk.org (Postfix) with ESMTP id E8E3F140E25 for ; Thu, 14 Jan 2021 07:30:12 +0100 (CET) IronPort-SDR: x9LeGM7ZwCmVMLGkLALcC4EgXem4cwgP/HrSjMe139wol3ZX1vMIjILKFh7DeKmbEEHSMXtSC5 w/nZAR8i/J/Q== X-IronPort-AV: E=McAfee;i="6000,8403,9863"; a="178407161" X-IronPort-AV: E=Sophos;i="5.79,346,1602572400"; d="scan'208";a="178407161" Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Jan 2021 22:30:12 -0800 IronPort-SDR: sPgyrVPLoVC1eDNE3ANpcevANilMdCcLzkFn78gSb/8A4a8ibXQJtdS8hYwHN3V1uUoC4DKkL5 HyVTOqTEfyRw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.79,346,1602572400"; d="scan'208";a="400799411" Received: from npg-dpdk-virtio-xiachenbo-nw.sh.intel.com ([10.67.119.123]) by fmsmga002.fm.intel.com with ESMTP; 13 Jan 2021 22:30:10 -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, beilei.xing@intel.com Date: Thu, 14 Jan 2021 14:25:06 +0800 Message-Id: <20210114062512.45462-3-chenbo.xia@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210114062512.45462-1-chenbo.xia@intel.com> References: <20201219062806.56477-1-chenbo.xia@intel.com> <20210114062512.45462-1-chenbo.xia@intel.com> Subject: [dpdk-dev] [PATCH v3 2/8] doc: add emudev library guide X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 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..e40213bb5e --- /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 transport 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 eabbbfebef..9686930de3 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 Thu Jan 14 06:25:07 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chenbo Xia X-Patchwork-Id: 86511 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 05970A0A02; Thu, 14 Jan 2021 07:30:35 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id CBF92140E2A; Thu, 14 Jan 2021 07:30:17 +0100 (CET) Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by mails.dpdk.org (Postfix) with ESMTP id 13250140E2A for ; Thu, 14 Jan 2021 07:30:15 +0100 (CET) IronPort-SDR: 8W5evIHYEZssBdWsPmw3mPC+NXKJHwQFyakKqO19aodTwBiBgdiDD4aLZ8u2szl7dWpRxA5SBk A5uUq7yvQdKQ== X-IronPort-AV: E=McAfee;i="6000,8403,9863"; a="178407163" X-IronPort-AV: E=Sophos;i="5.79,346,1602572400"; d="scan'208";a="178407163" Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Jan 2021 22:30:15 -0800 IronPort-SDR: rOKE2NHOnsqkqQbD14Rfv3TW2pRL4VDDUsfofL1FOPUyDlUeoYYqaNcgcUQ770/akiI8dxDL8l RABrH2Q79zDw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.79,346,1602572400"; d="scan'208";a="400799423" Received: from npg-dpdk-virtio-xiachenbo-nw.sh.intel.com ([10.67.119.123]) by fmsmga002.fm.intel.com with ESMTP; 13 Jan 2021 22:30:13 -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, beilei.xing@intel.com Date: Thu, 14 Jan 2021 14:25:07 +0800 Message-Id: <20210114062512.45462-4-chenbo.xia@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210114062512.45462-1-chenbo.xia@intel.com> References: <20201219062806.56477-1-chenbo.xia@intel.com> <20210114062512.45462-1-chenbo.xia@intel.com> Subject: [dpdk-dev] [PATCH v3 3/8] emu: introduce emulated iavf driver X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 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 | 30 ++++ drivers/emu/iavf/iavf_emu_internal.h | 49 +++++++ drivers/emu/iavf/iavf_emudev.c | 209 +++++++++++++++++++++++++++ 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, 356 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 f5f2c4fe15..3ef8bd1999 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1276,6 +1276,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..98abfcdca2 --- /dev/null +++ b/drivers/emu/iavf/iavf_emu.c @@ -0,0 +1,30 @@ +/* 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..35c3557188 --- /dev/null +++ b/drivers/emu/iavf/iavf_emudev.c @@ -0,0 +1,209 @@ +/* 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 Thu Jan 14 06:25:08 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chenbo Xia X-Patchwork-Id: 86512 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 85913A0A02; Thu, 14 Jan 2021 07:30:44 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 1333B140E38; Thu, 14 Jan 2021 07:30:21 +0100 (CET) Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by mails.dpdk.org (Postfix) with ESMTP id 82979140E36 for ; Thu, 14 Jan 2021 07:30:19 +0100 (CET) IronPort-SDR: gYA6ny9Y0KINLOP0jAonv/o7VX5I0LSWYX8t+8fFPEaDw5/5mNekR5oSKRteo6iw59V7bj8vaS ZXN4Pwvqxbxw== X-IronPort-AV: E=McAfee;i="6000,8403,9863"; a="178407165" X-IronPort-AV: E=Sophos;i="5.79,346,1602572400"; d="scan'208";a="178407165" Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Jan 2021 22:30:19 -0800 IronPort-SDR: w0mqP6S/EtDVl0AA/swI6bL00YKjcey3+Yy6kQhhW3ZLW9YGrx/47yPIeLLfNb0Yezd0gz7jlf v6b5XMpJrSjQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.79,346,1602572400"; d="scan'208";a="400799437" Received: from npg-dpdk-virtio-xiachenbo-nw.sh.intel.com ([10.67.119.123]) by fmsmga002.fm.intel.com with ESMTP; 13 Jan 2021 22:30:16 -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, beilei.xing@intel.com Date: Thu, 14 Jan 2021 14:25:08 +0800 Message-Id: <20210114062512.45462-5-chenbo.xia@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210114062512.45462-1-chenbo.xia@intel.com> References: <20201219062806.56477-1-chenbo.xia@intel.com> <20210114062512.45462-1-chenbo.xia@intel.com> Subject: [dpdk-dev] [PATCH v3 4/8] emu/iavf: add vfio-user device register and unregister X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 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 | 399 +++++++++++++++++++++++++++ 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, 467 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 98abfcdca2..2f1513137c 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) @@ -19,6 +19,7 @@ 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 35c3557188..6ba1cc2a89 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" @@ -172,10 +172,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..0cc4c433c2 --- /dev/null +++ b/drivers/emu/iavf/iavf_vfio_user.c @@ -0,0 +1,399 @@ +/* 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 = 0; + + 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; + } + } + + 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 Thu Jan 14 06:25:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chenbo Xia X-Patchwork-Id: 86513 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 0A626A0A02; Thu, 14 Jan 2021 07:30:57 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id A7223140E45; Thu, 14 Jan 2021 07:30:24 +0100 (CET) Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by mails.dpdk.org (Postfix) with ESMTP id 6C464140E42 for ; Thu, 14 Jan 2021 07:30:22 +0100 (CET) IronPort-SDR: rSfMlH/TLB146nitaXgDFgPbvvv4JH4hDT5gUEsnTpCnlA/vipJ9nFNFupoWAk2evxhVauoKNd 5V+RyBrHak7g== X-IronPort-AV: E=McAfee;i="6000,8403,9863"; a="178407168" X-IronPort-AV: E=Sophos;i="5.79,346,1602572400"; d="scan'208";a="178407168" Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Jan 2021 22:30:22 -0800 IronPort-SDR: jH8m569lhUulQyoytHw7eEikjjkLQ/8EvBZgMnk4a3t8NnbZ+FOHDyL5LrWI0MpgKOPlE/sT8U wh1JBn4FVkiw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.79,346,1602572400"; d="scan'208";a="400799452" Received: from npg-dpdk-virtio-xiachenbo-nw.sh.intel.com ([10.67.119.123]) by fmsmga002.fm.intel.com with ESMTP; 13 Jan 2021 22:30:19 -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, beilei.xing@intel.com Date: Thu, 14 Jan 2021 14:25:09 +0800 Message-Id: <20210114062512.45462-6-chenbo.xia@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210114062512.45462-1-chenbo.xia@intel.com> References: <20201219062806.56477-1-chenbo.xia@intel.com> <20210114062512.45462-1-chenbo.xia@intel.com> Subject: [dpdk-dev] [PATCH v3 5/8] emu/iavf: add resource management and internal logic of iavf X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 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 | 683 +++++++++++++++++++++++++++++- drivers/emu/iavf/iavf_vfio_user.h | 41 ++ drivers/emu/iavf/meson.build | 8 + 5 files changed, 750 insertions(+), 3 deletions(-) diff --git a/drivers/emu/iavf/iavf_emu.c b/drivers/emu/iavf/iavf_emu.c index 2f1513137c..7506849e42 100644 --- a/drivers/emu/iavf/iavf_emu.c +++ b/drivers/emu/iavf/iavf_emu.c @@ -19,6 +19,7 @@ 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 6ba1cc2a89..74f4829e7f 100644 --- a/drivers/emu/iavf/iavf_emudev.c +++ b/drivers/emu/iavf/iavf_emudev.c @@ -180,10 +180,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 0cc4c433c2..5c690978bd 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 0x20 + +#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; @@ -52,10 +75,8 @@ iavf_emu_setup_irq(struct iavf_emudev *dev) intr = dev->intr; intr->intr_num = irq->irq_info[VFIO_PCI_MSIX_IRQ_INDEX].count; - for (i = 0; i < count; i++) { + for (i = 0; i < count; i++) intr->info[i].fd = fds[i]; - intr->info[i].enable = 0; - } rte_free(fds); @@ -199,6 +220,591 @@ 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 + 1; + } + + if (idx != -1 && + tmp != dev->intr->info[idx].enable && dev->ready) { + dev->intr->info[idx].enable = tmp; + rte_wmb(); + dev->ops->lock_dp(dev->edev, 1); + dev->ops->update_status(dev->edev); + dev->ops->lock_dp(dev->edev, 0); + } + + 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) { @@ -397,3 +1003,74 @@ 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 Thu Jan 14 06:25:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chenbo Xia X-Patchwork-Id: 86514 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 16D6DA0A02; Thu, 14 Jan 2021 07:31:07 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id E5A3A140E4D; Thu, 14 Jan 2021 07:30:27 +0100 (CET) Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by mails.dpdk.org (Postfix) with ESMTP id 2B9FE140E4B for ; Thu, 14 Jan 2021 07:30:25 +0100 (CET) IronPort-SDR: 82L58yDrMd+0EAY8ceuLlG9jTZxsUZoiN2kXIsgK+qRK6Ngw/d9sCb0DOXC8W/OliiFvGrdnGb c9BLQHmni36A== X-IronPort-AV: E=McAfee;i="6000,8403,9863"; a="178407172" X-IronPort-AV: E=Sophos;i="5.79,346,1602572400"; d="scan'208";a="178407172" Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Jan 2021 22:30:24 -0800 IronPort-SDR: rToLVGwONUQ299Uwy7+8NZXcPCHqaNgFgY5deYlKJ0IUNr39NLYSBujMOuTztCF0YRrdk4pRM3 P4Hqd5De9/WA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.79,346,1602572400"; d="scan'208";a="400799465" Received: from npg-dpdk-virtio-xiachenbo-nw.sh.intel.com ([10.67.119.123]) by fmsmga002.fm.intel.com with ESMTP; 13 Jan 2021 22:30:22 -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, beilei.xing@intel.com Date: Thu, 14 Jan 2021 14:25:10 +0800 Message-Id: <20210114062512.45462-7-chenbo.xia@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210114062512.45462-1-chenbo.xia@intel.com> References: <20201219062806.56477-1-chenbo.xia@intel.com> <20210114062512.45462-1-chenbo.xia@intel.com> Subject: [dpdk-dev] [PATCH v3 6/8] emu/iavf: add emudev operations to fit in emudev framework X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 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 operations 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 | 229 ++++++++++++++++++++++++++++++++ drivers/emu/iavf/rte_iavf_emu.h | 59 ++++++++ 2 files changed, 288 insertions(+) diff --git a/drivers/emu/iavf/iavf_emu.c b/drivers/emu/iavf/iavf_emu.c index 7506849e42..cc56ec1c4b 100644 --- a/drivers/emu/iavf/iavf_emu.c +++ b/drivers/emu/iavf/iavf_emu.c @@ -2,7 +2,75 @@ * 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) @@ -27,6 +95,167 @@ 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 Thu Jan 14 06:25:11 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chenbo Xia X-Patchwork-Id: 86515 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 21527A0A02; Thu, 14 Jan 2021 07:31:20 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 7FFE5140E5B; Thu, 14 Jan 2021 07:30:29 +0100 (CET) Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by mails.dpdk.org (Postfix) with ESMTP id E4109140E4B for ; Thu, 14 Jan 2021 07:30:27 +0100 (CET) IronPort-SDR: aQMao5l8foWFmzz8jpAkuoe+zCaONKjiekWetaD1+442PkSUmim1+dSF17B29TGTEFXEhlAiBS EGA42+dwjvpg== X-IronPort-AV: E=McAfee;i="6000,8403,9863"; a="178407175" X-IronPort-AV: E=Sophos;i="5.79,346,1602572400"; d="scan'208";a="178407175" Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Jan 2021 22:30:27 -0800 IronPort-SDR: cMQFuKq9FY31H5aLSCqaK4ReWLYrYqvFTw0K3qCkR98VmXUqlWcashJVIc7hj9SHmj8ZCdJ+G5 H9fR2Hj5tHVw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.79,346,1602572400"; d="scan'208";a="400799484" Received: from npg-dpdk-virtio-xiachenbo-nw.sh.intel.com ([10.67.119.123]) by fmsmga002.fm.intel.com with ESMTP; 13 Jan 2021 22:30: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, beilei.xing@intel.com Date: Thu, 14 Jan 2021 14:25:11 +0800 Message-Id: <20210114062512.45462-8-chenbo.xia@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210114062512.45462-1-chenbo.xia@intel.com> References: <20201219062806.56477-1-chenbo.xia@intel.com> <20210114062512.45462-1-chenbo.xia@intel.com> Subject: [dpdk-dev] [PATCH v3 7/8] test/emudev: introduce functional test X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 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 cc56ec1c4b..8439677b65 100644 --- a/drivers/emu/iavf/iavf_emu.c +++ b/drivers/emu/iavf/iavf_emu.c @@ -258,4 +258,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..22450c1970 --- /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 Thu Jan 14 06:25:12 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chenbo Xia X-Patchwork-Id: 86516 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id C43CEA0A02; Thu, 14 Jan 2021 07:31:30 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id AEEDD140E4B; Thu, 14 Jan 2021 07:30:33 +0100 (CET) Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by mails.dpdk.org (Postfix) with ESMTP id 89E75140E69 for ; Thu, 14 Jan 2021 07:30:30 +0100 (CET) IronPort-SDR: Y+lldtUQJClIpWi475vHwpD+quQCu+k84Rlc1VS7AirDDr4c270VjRyWPC9ebYH+kmLAp31qdC P/af2jxkoB0A== X-IronPort-AV: E=McAfee;i="6000,8403,9863"; a="178407184" X-IronPort-AV: E=Sophos;i="5.79,346,1602572400"; d="scan'208";a="178407184" Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Jan 2021 22:30:30 -0800 IronPort-SDR: Ze7jc8bx2MhzIBypIleEgmv7Qk70pkGZrGrD/P1Dcqx9z2wIUjLWqMqgDunha8zVC2A0kcbpjh AibCvniAG5mA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.79,346,1602572400"; d="scan'208";a="400799498" Received: from npg-dpdk-virtio-xiachenbo-nw.sh.intel.com ([10.67.119.123]) by fmsmga002.fm.intel.com with ESMTP; 13 Jan 2021 22:30: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, beilei.xing@intel.com Date: Thu, 14 Jan 2021 14:25:12 +0800 Message-Id: <20210114062512.45462-9-chenbo.xia@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210114062512.45462-1-chenbo.xia@intel.com> References: <20201219062806.56477-1-chenbo.xia@intel.com> <20210114062512.45462-1-chenbo.xia@intel.com> Subject: [dpdk-dev] [PATCH v3 8/8] doc: update release notes for iavf emudev driver X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 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 9686930de3..90030079a5 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