From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id D2A37A04B5; Sat, 19 Dec 2020 07:44:39 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 514D2CB69; Sat, 19 Dec 2020 07:43:27 +0100 (CET) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id F0A34CB69 for ; Sat, 19 Dec 2020 07:43:24 +0100 (CET) IronPort-SDR: VDnEzV2ElxaSjLEBmMgLWgEIek74cZ5PkMD3OLoWVSUD0P0Hb93RkLOkJZkXQ7anh1m0hM4/QG rwgvoHu7pBtQ== X-IronPort-AV: E=McAfee;i="6000,8403,9839"; a="163285190" X-IronPort-AV: E=Sophos;i="5.78,432,1599548400"; d="scan'208";a="163285190" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Dec 2020 22:43:24 -0800 IronPort-SDR: drW/qdCNskiFGR9DEHnOuzXzkOOR1NaSKGvHqKR1R7Z9tpfBAS0S43+2lDc4FQ1OUnOkTlWV1m wuwAz1KDI+Ng== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,432,1599548400"; d="scan'208";a="454449614" Received: from npg-dpdk-virtio-xiachenbo-nw.sh.intel.com ([10.67.119.123]) by fmsmga001.fm.intel.com with ESMTP; 18 Dec 2020 22:43:21 -0800 From: Chenbo Xia To: dev@dpdk.org, thomas@monjalon.net, david.marchand@redhat.com Cc: stephen@networkplumber.org, cunming.liang@intel.com, xiuchun.lu@intel.com, miao.li@intel.com, jingjing.wu@intel.com Date: Sat, 19 Dec 2020 14:28:02 +0800 Message-Id: <20201219062806.56477-5-chenbo.xia@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201219062806.56477-1-chenbo.xia@intel.com> References: <20201218074736.93999-1-chenbo.xia@intel.com> <20201219062806.56477-1-chenbo.xia@intel.com> Subject: [dpdk-dev] [PATCH v2 4/8] emu/iavf: add vfio-user device register and unregister X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" This patch adds vfio-user APIs call in driver probe and remove. rte_vfio_user_register() and rte_vfio_user_unregister() are called to create/destroy a vfio-user device. Notify callbacks that libvfio_user defines are also implemented. Signed-off-by: Chenbo Xia Signed-off-by: Miao Li --- drivers/emu/iavf/iavf_emu.c | 3 +- drivers/emu/iavf/iavf_emu_internal.h | 19 ++ drivers/emu/iavf/iavf_emudev.c | 12 +- drivers/emu/iavf/iavf_vfio_user.c | 384 +++++++++++++++++++++++++++ drivers/emu/iavf/iavf_vfio_user.h | 16 ++ drivers/emu/iavf/meson.build | 5 +- drivers/emu/iavf/rte_iavf_emu.h | 17 ++ 7 files changed, 452 insertions(+), 4 deletions(-) create mode 100644 drivers/emu/iavf/iavf_vfio_user.c create mode 100644 drivers/emu/iavf/iavf_vfio_user.h diff --git a/drivers/emu/iavf/iavf_emu.c b/drivers/emu/iavf/iavf_emu.c index 68d2c440e3..dfd9796920 100644 --- a/drivers/emu/iavf/iavf_emu.c +++ b/drivers/emu/iavf/iavf_emu.c @@ -2,7 +2,7 @@ * Copyright(c) 2020 Intel Corporation */ -#include "iavf_emu_internal.h" +#include "iavf_vfio_user.h" static int iavf_emu_dev_close(struct rte_emudev *dev) { @@ -18,6 +18,7 @@ static int iavf_emu_dev_close(struct rte_emudev *dev) } iavf = (struct iavf_emudev *)dev->priv_data; + iavf_emu_unregister_vfio_user(iavf); iavf_emu_uninit_device(iavf); dev->priv_data = NULL; diff --git a/drivers/emu/iavf/iavf_emu_internal.h b/drivers/emu/iavf/iavf_emu_internal.h index a726bfe577..10197c00ba 100644 --- a/drivers/emu/iavf/iavf_emu_internal.h +++ b/drivers/emu/iavf/iavf_emu_internal.h @@ -17,6 +17,13 @@ extern int emu_iavf_logtype; #define EMU_IAVF_LOG(level, ...) \ rte_log(RTE_LOG_ ## level, emu_iavf_logtype, "EMU_IAVF: " __VA_ARGS__) +struct iavf_emu_vfio_user { + int dev_id; + struct vfio_device_info *dev_info; + struct rte_vfio_user_regions *reg; + struct rte_vfio_user_irq_info *irq; +}; + struct iavf_emu_intr_info { int enable; int fd; @@ -27,6 +34,14 @@ struct iavf_emu_intr { struct iavf_emu_intr_info info[RTE_IAVF_EMU_MAX_INTR]; }; +struct iavf_emu_adminQ { + uint32_t *ring_addr_lo; + uint32_t *ring_addr_hi; + uint32_t *ring_sz; + uint16_t db_size; + void *doorbell; +}; + struct iavf_emu_lanQ { uint16_t db_size; void *doorbell; @@ -34,14 +49,18 @@ struct iavf_emu_lanQ { struct iavf_emudev { struct rte_emudev *edev; + struct iavf_emu_vfio_user *vfio; /* Maximum LANQ queue pair that this emulated iavf has */ uint16_t max_lanqp; /* Maximum LANQ queue pair number that back-end driver can use */ uint16_t max_be_lanqp; unsigned int numa_node; + int ready; char *sock_addr; + struct rte_iavf_emu_notify_ops *ops; struct rte_iavf_emu_mem *mem; struct iavf_emu_intr *intr; + struct iavf_emu_adminQ adq[RTE_IAVF_EMU_ADMINQ_NUM]; struct iavf_emu_lanQ *lanq; }; diff --git a/drivers/emu/iavf/iavf_emudev.c b/drivers/emu/iavf/iavf_emudev.c index a4cd2deb06..fbbe3d95a7 100644 --- a/drivers/emu/iavf/iavf_emudev.c +++ b/drivers/emu/iavf/iavf_emudev.c @@ -6,7 +6,7 @@ #include #include -#include "iavf_emu_internal.h" +#include "iavf_vfio_user.h" #define EMU_IAVF_SOCK_ARG "sock" #define EMU_IAVF_QUEUES_ARG "queues" @@ -170,10 +170,20 @@ rte_emu_iavf_probe(struct rte_vdev_device *dev) iavf->max_lanqp = queues; edev->priv_data = (void *)iavf; + ret = iavf_emu_register_vfio_user(iavf); + if (ret) { + EMU_IAVF_LOG(ERR, + "Emulated iavf failed to register vfio user.\n"); + ret = -1; + goto err_reg; + } + edev->started = 1; rte_kvargs_free(kvlist); return 0; +err_reg: + iavf_emu_uninit_device(iavf); err_ndev: rte_emudev_release(edev); err: diff --git a/drivers/emu/iavf/iavf_vfio_user.c b/drivers/emu/iavf/iavf_vfio_user.c new file mode 100644 index 0000000000..aae47de9f3 --- /dev/null +++ b/drivers/emu/iavf/iavf_vfio_user.c @@ -0,0 +1,384 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Intel Corporation + */ + +#include + +#include + +#include "iavf_vfio_user.h" +#include + +struct iavf_emu_sock_list { + TAILQ_ENTRY(iavf_emu_sock_list) next; + struct rte_emudev *emu_dev; +}; + +TAILQ_HEAD(iavf_emu_sock_list_head, iavf_emu_sock_list); + +static struct iavf_emu_sock_list_head sock_list = + TAILQ_HEAD_INITIALIZER(sock_list); + +static pthread_mutex_t sock_list_lock = PTHREAD_MUTEX_INITIALIZER; + +static int iavf_emu_setup_irq(struct iavf_emudev *dev) +{ + struct iavf_emu_intr *intr; + struct rte_vfio_user_irq_info *irq; + int *fds = NULL; + uint32_t i, count; + + irq = dev->vfio->irq; + if (!irq) + return -1; + + count = irq->irq_info[VFIO_PCI_MSIX_IRQ_INDEX].count; + if (count) { + fds = rte_zmalloc("irq_fds", sizeof(int) * count, 0); + if (!fds) { + EMU_IAVF_LOG(ERR, + "Failed to alloc irq fds.\n"); + return -1; + } + } + + if (rte_vfio_user_get_irq(dev->vfio->dev_id, + VFIO_PCI_MSIX_IRQ_INDEX, count, fds)) { + EMU_IAVF_LOG(ERR, "Failed to get irqfds from vfio-user.\n"); + return -1; + } + + intr = dev->intr; + intr->intr_num = irq->irq_info[VFIO_PCI_MSIX_IRQ_INDEX].count; + + for (i = 0; i < count; i++) { + intr->info[i].fd = fds[i]; + intr->info[i].enable = 0; + } + + rte_free(fds); + + return 0; +} + +static inline void iavf_emu_reset_irq(struct iavf_emudev *dev) +{ + struct iavf_emu_intr *intr = dev->intr; + uint32_t i; + + for (i = 0; i < intr->intr_num; i++) { + intr->info[i].enable = 0; + intr->info[i].fd = -1; + } +} + +static inline void iavf_emu_reset_regions(struct iavf_emudev *dev) +{ + struct rte_vfio_user_regions *reg = dev->vfio->reg; + struct rte_vfio_user_reg_info *vinfo; + uint32_t i; + + for (i = 0; i < reg->reg_num; i++) { + vinfo = ®->reg_info[i]; + if (vinfo->info->size && vinfo->base) + memset(vinfo->base, 0, vinfo->info->size); + } +} + +static int iavf_emu_setup_mem_table(struct iavf_emudev *dev) +{ + const struct rte_vfio_user_mem *vfio_mem; + const struct rte_vfio_user_mtb_entry *entry; + struct rte_iavf_emu_mem *mem; + uint32_t i; + + vfio_mem = rte_vfio_user_get_mem_table(dev->vfio->dev_id); + if (!vfio_mem) { + EMU_IAVF_LOG(ERR, "Unable to get vfio mem table.\n"); + return -1; + } + + mem = dev->mem; + + mem->region_num = vfio_mem->entry_num; + if (mem->region_num > RTE_IAVF_EMU_MAX_MEM_REGIONS) { + EMU_IAVF_LOG(ERR, "Failed to set up mem table," + "exceed max region num.\n"); + return -1; + } + + for (i = 0; i < vfio_mem->entry_num; i++) { + entry = &vfio_mem->entry[i]; + + mem->regions[i].guest_phys_addr = entry->gpa; + mem->regions[i].host_user_addr = entry->host_user_addr; + mem->regions[i].mmap_addr = entry->mmap_addr; + mem->regions[i].mmap_size = entry->mmap_size; + mem->regions[i].size = entry->size; + mem->regions[i].fd = entry->fd; + } + + return 0; +} + +static inline void iavf_emu_reset_mem_table(struct iavf_emudev *dev) +{ + struct rte_iavf_emu_mem *mem = dev->mem; + uint32_t i; + + for (i = 0; i < mem->region_num; i++) { + mem->regions[i].guest_phys_addr = 0; + mem->regions[i].host_user_addr = 0; + mem->regions[i].mmap_addr = 0; + mem->regions[i].mmap_size = 0; + mem->regions[i].size = 0; + mem->regions[i].fd = -1; + } +} + +static int iavf_emu_setup_queues(struct iavf_emudev *dev) +{ + struct iavf_emu_adminQ *asq, *arq; + struct rte_vfio_user_reg_info *info; + uint16_t i; + + info = &dev->vfio->reg->reg_info[0]; + asq = &dev->adq[RTE_IAVF_EMU_ADMINQ_TXQ]; + arq = &dev->adq[RTE_IAVF_EMU_ADMINQ_RXQ]; + + asq->doorbell = (uint8_t *)info->base + IAVF_VF_ATQT1; + asq->db_size = 4; + asq->ring_addr_lo = (uint32_t *)((uint8_t *)info->base + + IAVF_VF_ATQBAL1); + asq->ring_addr_hi = (uint32_t *)((uint8_t *)info->base + + IAVF_VF_ATQBAH1); + asq->ring_sz = (uint32_t *)((uint8_t *)info->base + IAVF_VF_ATQLEN1); + + arq->doorbell = (uint8_t *)info->base + IAVF_VF_ARQT1; + arq->db_size = 4; + arq->ring_addr_lo = (uint32_t *)((uint8_t *)info->base + + IAVF_VF_ARQBAL1); + arq->ring_addr_hi = (uint32_t *)((uint8_t *)info->base + + IAVF_VF_ARQBAH1); + arq->ring_sz = (uint32_t *)((uint8_t *)info->base + IAVF_VF_ARQLEN1); + + for (i = 0; i < dev->max_lanqp; i++) { + dev->lanq[i * 2].doorbell = (uint8_t *)info->base + + IAVF_QTX_TAIL1(i); + dev->lanq[i * 2].db_size = 4; + dev->lanq[i * 2 + 1].doorbell = (uint8_t *)info->base + + IAVF_QRX_TAIL1(i); + dev->lanq[i * 2 + 1].db_size = 4; + } + + return 0; +} + +static inline void iavf_emu_reset_queues(struct iavf_emudev *dev) +{ + memset(&dev->adq, 0, RTE_IAVF_EMU_ADMINQ_NUM * + sizeof(struct iavf_emu_adminQ)); + + memset(dev->lanq, 0, dev->max_lanqp * 2 * + sizeof(struct iavf_emu_lanQ)); +} + +static void iavf_emu_reset_all_resources(struct iavf_emudev *dev) +{ + iavf_emu_reset_mem_table(dev); + iavf_emu_reset_irq(dev); + iavf_emu_reset_queues(dev); + iavf_emu_reset_regions(dev); +} + +static inline struct iavf_emu_sock_list * +iavf_emu_find_sock_list(char *sock_addr) +{ + struct iavf_emu_sock_list *list; + struct iavf_emudev *dev; + int list_exist; + + if (!sock_addr) + return NULL; + + pthread_mutex_lock(&sock_list_lock); + + TAILQ_FOREACH(list, &sock_list, next) { + dev = (struct iavf_emudev *)list->emu_dev->priv_data; + + if (!strcmp(dev->sock_addr, sock_addr)) { + list_exist = 1; + break; + } + break; + } + + pthread_mutex_unlock(&sock_list_lock); + + if (!list_exist) + return NULL; + + return list; +} + +static struct iavf_emudev *find_iavf_with_dev_id(int vfio_dev_id) +{ + struct iavf_emu_sock_list *list; + char sock_addr[PATH_MAX]; + int ret; + + ret = rte_vfio_get_sock_addr(vfio_dev_id, sock_addr, + sizeof(sock_addr)); + if (ret) { + EMU_IAVF_LOG(ERR, "Can not find vfio device %d " + "sock_addr.\n", vfio_dev_id); + return NULL; + } + + list = iavf_emu_find_sock_list(sock_addr); + if (!list) { + EMU_IAVF_LOG(ERR, "Can not find sock list.\n"); + return NULL; + } + + return (struct iavf_emudev *)list->emu_dev->priv_data; +} + +static int iavf_emu_new_device(int vfio_dev_id) +{ + struct iavf_emudev *dev; + int ret; + + dev = find_iavf_with_dev_id(vfio_dev_id); + if (!dev) + return -1; + + dev->vfio->dev_id = vfio_dev_id; + + ret = iavf_emu_setup_mem_table(dev); + if (ret) { + EMU_IAVF_LOG(ERR, "Failed to set up memtable for " + "device %d", dev->vfio->dev_id); + return ret; + } + + ret = iavf_emu_setup_irq(dev); + if (ret) { + EMU_IAVF_LOG(ERR, "Failed to set up irq for " + "device %d", dev->vfio->dev_id); + return ret; + } + + ret = iavf_emu_setup_queues(dev); + if (ret) { + EMU_IAVF_LOG(ERR, "Failed to set up queues for " + "device %d", dev->vfio->dev_id); + return ret; + } + + ret = dev->ops->device_ready(dev->edev); + if (ret) + return ret; + + dev->ready = 1; + return 0; +} + +static void iavf_emu_destroy_device(int vfio_dev_id) +{ + struct iavf_emudev *dev; + + dev = find_iavf_with_dev_id(vfio_dev_id); + if (!dev) + return; + + iavf_emu_reset_all_resources(dev); + + dev->ops->device_destroy(dev->edev); +} + +static int iavf_emu_update_status(int vfio_dev_id) +{ + struct iavf_emudev *dev; + int ret; + + dev = find_iavf_with_dev_id(vfio_dev_id); + if (!dev) + return -1; + + ret = iavf_emu_setup_mem_table(dev); + if (ret) { + EMU_IAVF_LOG(ERR, "Failed to set up memtable for " + "device %d", dev->vfio->dev_id); + return ret; + } + + ret = iavf_emu_setup_irq(dev); + if (ret) { + EMU_IAVF_LOG(ERR, "Failed to set up irq for " + "device %d", dev->vfio->dev_id); + return ret; + } + + dev->ops->update_status(dev->edev); + + return 0; +} + +static int iavf_emu_lock_datapath(int vfio_dev_id, int lock) +{ + struct iavf_emudev *dev; + + dev = find_iavf_with_dev_id(vfio_dev_id); + if (!dev) + return -1; + + return dev->ops->lock_dp(dev->edev, lock); +} + +static int iavf_emu_reset_device(int vfio_dev_id) +{ + struct iavf_emudev *dev; + + dev = find_iavf_with_dev_id(vfio_dev_id); + if (!dev) + return -1; + + iavf_emu_reset_all_resources(dev); + + return dev->ops->reset_device(dev->edev); +} + +struct rte_vfio_user_notify_ops vfio_ops = { + .new_device = iavf_emu_new_device, + .destroy_device = iavf_emu_destroy_device, + .update_status = iavf_emu_update_status, + .lock_dp = iavf_emu_lock_datapath, + .reset_device = iavf_emu_reset_device, +}; + +int iavf_emu_register_vfio_user(struct iavf_emudev *dev) +{ + int ret; + + ret = rte_vfio_user_register(dev->sock_addr, &vfio_ops); + if (ret) { + EMU_IAVF_LOG(ERR, "Register vfio_user failed\n"); + return -1; + } + + return 0; +} + +int iavf_emu_unregister_vfio_user(struct iavf_emudev *dev) +{ + int ret; + + ret = rte_vfio_user_unregister(dev->sock_addr); + if (ret) { + EMU_IAVF_LOG(ERR, "Unregister vfio_user failed\n"); + return -1; + } + + return 0; +} diff --git a/drivers/emu/iavf/iavf_vfio_user.h b/drivers/emu/iavf/iavf_vfio_user.h new file mode 100644 index 0000000000..aa2f3edc87 --- /dev/null +++ b/drivers/emu/iavf/iavf_vfio_user.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Intel Corporation + */ + +#ifndef _IAVF_VFIO_USER_H +#define _IAVF_VFIO_USER_H + +#include + +#include "iavf_emu_internal.h" + +int iavf_emu_register_vfio_user(struct iavf_emudev *dev); + +int iavf_emu_unregister_vfio_user(struct iavf_emudev *dev); + +#endif diff --git a/drivers/emu/iavf/meson.build b/drivers/emu/iavf/meson.build index 58c2a90383..4f651258c2 100644 --- a/drivers/emu/iavf/meson.build +++ b/drivers/emu/iavf/meson.build @@ -1,8 +1,9 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2020 Intel Corporation -sources = files('iavf_emu.c', 'iavf_emudev.c') +sources = files('iavf_emu.c', 'iavf_vfio_user.c', + 'iavf_emudev.c') -deps += ['bus_vdev', 'emudev'] +deps += ['bus_vdev', 'emudev', 'vfio_user', 'common_iavf'] headers = files('rte_iavf_emu.h') diff --git a/drivers/emu/iavf/rte_iavf_emu.h b/drivers/emu/iavf/rte_iavf_emu.h index 623c3c5d99..6de0989f0b 100644 --- a/drivers/emu/iavf/rte_iavf_emu.h +++ b/drivers/emu/iavf/rte_iavf_emu.h @@ -40,4 +40,21 @@ struct rte_iavf_emu_mem { struct rte_iavf_emu_mem_reg regions[RTE_IAVF_EMU_MAX_MEM_REGIONS]; }; +struct rte_iavf_emu_notify_ops { + /* Device is ready */ + int (*device_ready)(struct rte_emudev *dev); + /* Device is destroyed */ + void (*device_destroy)(struct rte_emudev *dev); + /* Update device status */ + int (*update_status)(struct rte_emudev *dev); + /* Start device */ + int (*device_start)(struct rte_emudev *dev); + /* Stop device */ + int (*device_stop)(struct rte_emudev *dev); + /* Lock or unlock data path */ + int (*lock_dp)(struct rte_emudev *dev, int lock); + /* Reset device */ + int (*reset_device)(struct rte_emudev *dev); +}; + #endif -- 2.17.1