From patchwork Thu Jan 14 06:14: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: 86505 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 534A0A0A02; Thu, 14 Jan 2021 07:20:40 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id B1485140DDA; Thu, 14 Jan 2021 07:19:54 +0100 (CET) Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by mails.dpdk.org (Postfix) with ESMTP id C9976140DDB for ; Thu, 14 Jan 2021 07:19:53 +0100 (CET) IronPort-SDR: Auc/1sTt39a6GWxnmZDwtjU2EAsaSbyFocpuyedy3C5jkFrIEqNvZt3Yb69lDOWzbFgjk564gV Gi0t5iaULQfw== X-IronPort-AV: E=McAfee;i="6000,8403,9863"; a="175735659" X-IronPort-AV: E=Sophos;i="5.79,346,1602572400"; d="scan'208";a="175735659" Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Jan 2021 22:19:53 -0800 IronPort-SDR: hIgetsdrr0OjdkziWgDBNYixN6FbZZhqTVBx1Ikgo+5aaSDvXU8In2k4MYTc0fSuL5R8NOXaUG oFxy3pimwu0A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.79,346,1602572400"; d="scan'208";a="349069023" Received: from npg-dpdk-virtio-xiachenbo-nw.sh.intel.com ([10.67.119.123]) by orsmga003.jf.intel.com with ESMTP; 13 Jan 2021 22:19:50 -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:14:09 +0800 Message-Id: <20210114061411.39166-8-chenbo.xia@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210114061411.39166-1-chenbo.xia@intel.com> References: <20201218073851.93609-1-chenbo.xia@intel.com> <20210114061411.39166-1-chenbo.xia@intel.com> Subject: [dpdk-dev] [PATCH v2 7/9] vfio_user: add client APIs of DMA/IRQ/region 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 nine APIs - Device related: rte_vfio_user_get_dev_info and rte_vfio_user_reset - DMA related: rte_vfio_user_dma_map/unmap - Region related: rte_vfio_user_get_reg_info and rte_vfio_user_region_read/write - IRQ related: rte_vfio_user_get_irq_info and rte_vfio_user_set_irqs Signed-off-by: Chenbo Xia Signed-off-by: Xiuchun Lu --- lib/librte_vfio_user/rte_vfio_user.h | 177 ++++++++++ lib/librte_vfio_user/version.map | 9 + lib/librte_vfio_user/vfio_user_client.c | 419 ++++++++++++++++++++++++ 3 files changed, 605 insertions(+) diff --git a/lib/librte_vfio_user/rte_vfio_user.h b/lib/librte_vfio_user/rte_vfio_user.h index adafa552e2..e5fedcff90 100644 --- a/lib/librte_vfio_user/rte_vfio_user.h +++ b/lib/librte_vfio_user/rte_vfio_user.h @@ -238,6 +238,15 @@ rte_vfio_user_set_irq_info(const char *sock_addr, * Below APIs are for vfio-user client (device consumer) to use: * *rte_vfio_user_attach_dev * *rte_vfio_user_detach_dev + * *rte_vfio_user_get_dev_info + * *rte_vfio_user_get_reg_info + * *rte_vfio_user_get_irq_info + * *rte_vfio_user_dma_map + * *rte_vfio_user_dma_unmap + * *rte_vfio_user_set_irqs + * *rte_vfio_user_region_read + * *rte_vfio_user_region_write + * *rte_vfio_user_reset */ /** @@ -266,4 +275,172 @@ __rte_experimental int rte_vfio_user_detach_dev(int dev_id); +/** + * Get device information of a vfio-user device. + * + * @param dev_id + * Device ID of the vfio-user device + * @param[out] info + * A pointer to a structure of type *vfio_device_info* to be filled with the + * information of the device. + * @return + * - 0: Success, device information updated + * - <0: Failure on get device information + */ +__rte_experimental +int +rte_vfio_user_get_dev_info(int dev_id, struct vfio_device_info *info); + +/** + * Get region information of a vfio-user device. + * + * @param dev_id + * Device ID of the vfio-user device + * @param[out] info + * A pointer to a structure of type *vfio_region_info* to be filled with the + * information of the device region. + * @param[out] fd + * A pointer to the file descriptor of the region + * @return + * - 0: Success, region information and file descriptor updated. If the region + * can not be mmaped, the file descriptor should be -1. + * - <0: Failure on get region information + */ +__rte_experimental +int +rte_vfio_user_get_reg_info(int dev_id, struct vfio_region_info *info, + int *fd); + +/** + * Get IRQ information of a vfio-user device. + * + * @param dev_id + * Device ID of the vfio-user device + * @param[out] info + * A pointer to a structure of type *vfio_irq_info* to be filled with the + * information of the IRQ. + * @return + * - 0: Success, IRQ information updated + * - <0: Failure on get IRQ information + */ +__rte_experimental +int +rte_vfio_user_get_irq_info(int dev_id, struct vfio_irq_info *info); + +/** + * Map DMA regions for the vfio-user device. + * + * @param dev_id + * Device ID of the vfio-user device + * @param mem + * A pointer to a structure of type *vfio_user_mem_reg* that identifies + * one or several DMA regions. + * @param fds + * A pointer to a list of file descriptors. One file descriptor maps to + * one DMA region. + * @param num + * Number of DMA regions (or file descriptors) + * @return + * - 0: Success, all DMA regions are mapped. + * - <0: Failure on DMA map. It should be assumed that all DMA regions + * are not mapped. + */ +__rte_experimental +int +rte_vfio_user_dma_map(int dev_id, struct rte_vfio_user_mem_reg *mem, + int *fds, uint32_t num); + +/** + * Unmap DMA regions for the vfio-user device. + * + * @param dev_id + * Device ID of the vfio-user device + * @param mem + * A pointer to a structure of type *vfio_user_mem_reg* that identifies + * one or several DMA regions. + * @param num + * Number of DMA regions + * @return + * - 0: Success, all DMA regions are unmapped. + * - <0: Failure on DMA unmap. It should be assumed that all DMA regions + * are not unmapped. + */ +__rte_experimental +int +rte_vfio_user_dma_unmap(int dev_id, struct rte_vfio_user_mem_reg *mem, + uint32_t num); + +/** + * Set interrupt signaling, masking, and unmasking for the vfio-user device. + * + * @param dev_id + * Device ID of the vfio-user device + * @param set + * A pointer to a structure of type *vfio_irq_set* that specifies the set + * data and action + * @return + * - 0: Success, IRQs are set successfully. + * - <0: Failure on IRQ set. + */ +__rte_experimental +int +rte_vfio_user_set_irqs(int dev_id, struct vfio_irq_set *set); + +/** + * Read region of the vfio-user device. + * + * @param dev_id + * Device ID of the vfio-user device + * @param idx + * The region index + * @param offset + * The region offset + * @param size + * Size of the read data + * @param[out] data + * The pointer to data to be filled with correct region data + * @return + * - 0: Success on region read + * - <0: Failure on region read + */ +__rte_experimental +int +rte_vfio_user_region_read(int dev_id, uint32_t idx, uint64_t offset, + uint32_t size, void *data); + +/** + * Write region of the vfio-user device. + * + * @param dev_id + * Device ID of the vfio-user device + * @param idx + * The region index + * @param offset + * The region offset + * @param size + * Size of the read data + * @param data + * The pointer to data that will be written to the region + * @return + * - 0: Success on region write + * - <0: Failure on region write + */ +__rte_experimental +int +rte_vfio_user_region_write(int dev_id, uint32_t idx, uint64_t offset, + uint32_t size, const void *data); + +/** + * Reset the vfio-user device + * + * @param dev_id + * Device ID of the vfio-user device + * @return + * - 0: Success on device reset + * - <0: Failure on device reset + */ +__rte_experimental +int +rte_vfio_user_reset(int dev_id); + #endif diff --git a/lib/librte_vfio_user/version.map b/lib/librte_vfio_user/version.map index a0cda2b49c..2e362d00bc 100644 --- a/lib/librte_vfio_user/version.map +++ b/lib/librte_vfio_user/version.map @@ -12,6 +12,15 @@ EXPERIMENTAL { rte_vfio_user_set_irq_info; rte_vfio_user_attach_dev; rte_vfio_user_detach_dev; + rte_vfio_user_get_dev_info; + rte_vfio_user_get_reg_info; + rte_vfio_user_get_irq_info; + rte_vfio_user_dma_map; + rte_vfio_user_dma_unmap; + rte_vfio_user_set_irqs; + rte_vfio_user_region_read; + rte_vfio_user_region_write; + rte_vfio_user_reset; local: *; }; diff --git a/lib/librte_vfio_user/vfio_user_client.c b/lib/librte_vfio_user/vfio_user_client.c index f288cf70f5..852e7f253a 100644 --- a/lib/librte_vfio_user/vfio_user_client.c +++ b/lib/librte_vfio_user/vfio_user_client.c @@ -279,3 +279,422 @@ rte_vfio_user_detach_dev(int dev_id) return ret; } + +int +rte_vfio_user_get_dev_info(int dev_id, struct vfio_device_info *info) +{ + struct vfio_user_msg msg = { 0 }; + struct vfio_user_client *dev; + int ret; + uint32_t sz = VFIO_USER_MSG_HDR_SIZE + sizeof(struct vfio_device_info); + + if (!info) + return -EINVAL; + + dev = vfio_client_devs.cl[dev_id]; + if (!dev) { + VFIO_USER_LOG(ERR, "Failed to get device info: " + "wrong device ID\n"); + return -EINVAL; + } + + vfio_user_client_fill_hdr(&msg, VFIO_USER_DEVICE_GET_INFO, + sz, dev->msg_id++); + + ret = vfio_user_client_send_recv(dev->sock.sock_fd, &msg); + if (ret) + return ret; + + if (msg.flags & VFIO_USER_ERROR) { + VFIO_USER_LOG(ERR, "Failed to get device info: %s\n", + msg.err ? strerror(msg.err) : "Unknown error"); + return msg.err ? -(int)msg.err : -1; + } + + if (vfio_user_check_msg_fdnum(&msg, 0) != 0) + return -1; + + memcpy(info, &msg.payload.dev_info, sizeof(*info)); + return ret; +} + +int +rte_vfio_user_get_reg_info(int dev_id, struct vfio_region_info *info, + int *fd) +{ + struct vfio_user_msg msg = { 0 }; + int ret, fd_num = 0; + struct vfio_user_client *dev; + uint32_t sz = VFIO_USER_MSG_HDR_SIZE + info->argsz; + struct vfio_user_reg *reg = &msg.payload.reg_info; + + if (!info || !fd) + return -EINVAL; + + dev = vfio_client_devs.cl[dev_id]; + if (!dev) { + VFIO_USER_LOG(ERR, "Failed to get region info: " + "wrong device ID\n"); + return -EINVAL; + } + + vfio_user_client_fill_hdr(&msg, VFIO_USER_DEVICE_GET_REGION_INFO, + sz, dev->msg_id++); + reg->reg_info.index = info->index; + + ret = vfio_user_client_send_recv(dev->sock.sock_fd, &msg); + if (ret) + return ret; + + if (msg.flags & VFIO_USER_ERROR) { + VFIO_USER_LOG(ERR, "Failed to get region(%u) info: %s\n", + info->index, msg.err ? strerror(msg.err) : + "Unknown error"); + return msg.err ? -(int)msg.err : -1; + } + + if (reg->reg_info.flags & VFIO_REGION_INFO_FLAG_MMAP) + fd_num = 1; + + if (vfio_user_check_msg_fdnum(&msg, fd_num) != 0) + return -1; + + if (reg->reg_info.index != info->index || + msg.size - VFIO_USER_MSG_HDR_SIZE > sizeof(*reg)) { + VFIO_USER_LOG(ERR, + "Incorrect reply message for region info\n"); + return -1; + } + + memcpy(info, &msg.payload.reg_info, info->argsz); + *fd = fd_num == 1 ? msg.fds[0] : -1; + + return 0; +} + +int +rte_vfio_user_get_irq_info(int dev_id, struct vfio_irq_info *info) +{ + struct vfio_user_msg msg = { 0 }; + int ret; + struct vfio_user_client *dev; + uint32_t sz = VFIO_USER_MSG_HDR_SIZE + sizeof(struct vfio_irq_info); + struct vfio_irq_info *irq_info = &msg.payload.irq_info; + + if (!info) + return -EINVAL; + + dev = vfio_client_devs.cl[dev_id]; + if (!dev) { + VFIO_USER_LOG(ERR, "Failed to get region info: " + "wrong device ID\n"); + return -EINVAL; + } + + vfio_user_client_fill_hdr(&msg, VFIO_USER_DEVICE_GET_IRQ_INFO, + sz, dev->msg_id++); + irq_info->index = info->index; + + ret = vfio_user_client_send_recv(dev->sock.sock_fd, &msg); + if (ret) + return ret; + + if (msg.flags & VFIO_USER_ERROR) { + VFIO_USER_LOG(ERR, "Failed to get irq(%u) info: %s\n", + info->index, msg.err ? strerror(msg.err) : + "Unknown error"); + return msg.err ? -(int)msg.err : -1; + } + + if (vfio_user_check_msg_fdnum(&msg, 0) != 0) + return -1; + + if (irq_info->index != info->index || + msg.size - VFIO_USER_MSG_HDR_SIZE != sizeof(*irq_info)) { + VFIO_USER_LOG(ERR, + "Incorrect reply message for IRQ info\n"); + return -1; + } + + memcpy(info, irq_info, sizeof(*info)); + return 0; +} + +static int +vfio_user_client_dma_map_unmap(struct vfio_user_client *dev, + struct rte_vfio_user_mem_reg *mem, int *fds, uint32_t num, bool ismap) +{ + struct vfio_user_msg msg = { 0 }; + int ret; + uint32_t i, mem_sz, map; + uint16_t cmd = VFIO_USER_DMA_UNMAP; + + if (num > VFIO_USER_MSG_MAX_NREG) { + VFIO_USER_LOG(ERR, + "Too many memory regions to %s (MAX: %u)\n", + ismap ? "map" : "unmap", VFIO_USER_MSG_MAX_NREG); + return -EINVAL; + } + + if (ismap) { + cmd = VFIO_USER_DMA_MAP; + + for (i = 0; i < num; i++) { + map = mem->flags & RTE_VUSER_MEM_MAPPABLE; + if ((map && (fds[i] == -1)) || + (!map && (fds[i] != -1))) { + VFIO_USER_LOG(ERR, "%spable memory region " + "should%s have valid fd\n", + ismap ? "Map" : "Unmap", + ismap ? "" : " not"); + return -EINVAL; + } + + if (fds[i] != -1) + msg.fds[msg.fd_num++] = fds[i]; + } + } + + mem_sz = sizeof(struct rte_vfio_user_mem_reg) * num; + memcpy(&msg.payload, mem, mem_sz); + + vfio_user_client_fill_hdr(&msg, cmd, mem_sz + VFIO_USER_MSG_HDR_SIZE, + dev->msg_id++); + + ret = vfio_user_client_send_recv(dev->sock.sock_fd, &msg); + if (ret) + return ret; + + if (msg.flags & VFIO_USER_ERROR) { + VFIO_USER_LOG(ERR, "Failed to %smap memory regions: " + "%s\n", ismap ? "" : "un", + msg.err ? strerror(msg.err) : "Unknown error"); + return msg.err ? -(int)msg.err : -1; + } + + if (vfio_user_check_msg_fdnum(&msg, 0) != 0) + return -1; + + return 0; +} + +int +rte_vfio_user_dma_map(int dev_id, struct rte_vfio_user_mem_reg *mem, + int *fds, uint32_t num) +{ + struct vfio_user_client *dev; + + if (!mem || !fds) + return -EINVAL; + + dev = vfio_client_devs.cl[dev_id]; + if (!dev) { + VFIO_USER_LOG(ERR, "Failed to dma map: " + "wrong device ID\n"); + return -EINVAL; + } + + return vfio_user_client_dma_map_unmap(dev, mem, fds, num, true); +} + +int +rte_vfio_user_dma_unmap(int dev_id, struct rte_vfio_user_mem_reg *mem, + uint32_t num) +{ + struct vfio_user_client *dev; + + if (!mem) + return -EINVAL; + + dev = vfio_client_devs.cl[dev_id]; + if (!dev) { + VFIO_USER_LOG(ERR, "Failed to dma unmap: " + "wrong device ID\n"); + return -EINVAL; + } + + return vfio_user_client_dma_map_unmap(dev, mem, NULL, num, false); +} + +int +rte_vfio_user_set_irqs(int dev_id, struct vfio_irq_set *set) +{ + struct vfio_user_msg msg = { 0 }; + int ret; + struct vfio_user_client *dev; + uint32_t set_sz = set->argsz; + struct vfio_user_irq_set *irq_set = &msg.payload.irq_set; + + if (!set) + return -EINVAL; + + dev = vfio_client_devs.cl[dev_id]; + if (!dev) { + VFIO_USER_LOG(ERR, "Failed to set irqs: " + "wrong device ID\n"); + return -EINVAL; + } + + if (set->flags & VFIO_IRQ_SET_DATA_EVENTFD) { + msg.fd_num = set->count; + memcpy(msg.fds, set->data, sizeof(int) * set->count); + set_sz -= sizeof(int) * set->count; + } + memcpy(irq_set, set, set_sz); + irq_set->set.argsz = set_sz; + vfio_user_client_fill_hdr(&msg, VFIO_USER_DEVICE_SET_IRQS, + VFIO_USER_MSG_HDR_SIZE + set_sz, dev->msg_id++); + + ret = vfio_user_client_send_recv(dev->sock.sock_fd, &msg); + if (ret) + return ret; + + if (msg.flags & VFIO_USER_ERROR) { + VFIO_USER_LOG(ERR, "Failed to set irq(%u): %s\n", + set->index, msg.err ? strerror(msg.err) : + "Unknown error"); + return msg.err ? -(int)msg.err : -1; + } + + if (vfio_user_check_msg_fdnum(&msg, 0) != 0) + return -1; + + return 0; +} + +int +rte_vfio_user_region_read(int dev_id, uint32_t idx, uint64_t offset, + uint32_t size, void *data) +{ + struct vfio_user_msg msg = { 0 }; + int ret; + struct vfio_user_client *dev; + uint32_t sz = VFIO_USER_MSG_HDR_SIZE + sizeof(struct vfio_user_reg_rw) + - VFIO_USER_MAX_RW_DATA; + struct vfio_user_reg_rw *rw = &msg.payload.reg_rw; + + if (!data) + return -EINVAL; + + dev = vfio_client_devs.cl[dev_id]; + if (!dev) { + VFIO_USER_LOG(ERR, "Failed to read region: " + "wrong device ID\n"); + return -EINVAL; + } + + if (sz > VFIO_USER_MAX_RW_DATA) { + VFIO_USER_LOG(ERR, "Region read size exceeds max\n"); + return -1; + } + + vfio_user_client_fill_hdr(&msg, VFIO_USER_REGION_READ, + sz, dev->msg_id++); + + rw->reg_idx = idx; + rw->reg_offset = offset; + rw->size = size; + + ret = vfio_user_client_send_recv(dev->sock.sock_fd, &msg); + if (ret) + return ret; + + if (msg.flags & VFIO_USER_ERROR) { + VFIO_USER_LOG(ERR, "Failed to read region(%u): %s\n", + idx, msg.err ? strerror(msg.err) : + "Unknown error"); + return msg.err ? -(int)msg.err : -1; + } + + if (vfio_user_check_msg_fdnum(&msg, 0) != 0) + return -1; + + memcpy(data, rw->data, size); + return 0; +} + +int +rte_vfio_user_region_write(int dev_id, uint32_t idx, uint64_t offset, + uint32_t size, const void *data) +{ + struct vfio_user_msg msg = { 0 }; + int ret; + struct vfio_user_client *dev; + uint32_t sz = VFIO_USER_MSG_HDR_SIZE + sizeof(struct vfio_user_reg_rw) + - VFIO_USER_MAX_RW_DATA + size; + struct vfio_user_reg_rw *rw = &msg.payload.reg_rw; + + if (!data) + return -EINVAL; + + dev = vfio_client_devs.cl[dev_id]; + if (!dev) { + VFIO_USER_LOG(ERR, "Failed to write region: " + "wrong device ID\n"); + return -EINVAL; + } + + if (sz > VFIO_USER_MAX_RW_DATA) { + VFIO_USER_LOG(ERR, "Region write size exceeds max\n"); + return -EINVAL; + } + + vfio_user_client_fill_hdr(&msg, VFIO_USER_REGION_WRITE, + sz, dev->msg_id++); + + rw->reg_idx = idx; + rw->reg_offset = offset; + rw->size = size; + memcpy(rw->data, data, size); + + ret = vfio_user_client_send_recv(dev->sock.sock_fd, &msg); + if (ret) + return ret; + + if (msg.flags & VFIO_USER_ERROR) { + VFIO_USER_LOG(ERR, "Failed to write region(%u): %s\n", + idx, msg.err ? strerror(msg.err) : + "Unknown error"); + return msg.err ? -(int)msg.err : -1; + } + + if (vfio_user_check_msg_fdnum(&msg, 0) != 0) + return -1; + + return 0; +} + +int +rte_vfio_user_reset(int dev_id) +{ + struct vfio_user_msg msg = { 0 }; + int ret; + struct vfio_user_client *dev; + uint32_t sz = VFIO_USER_MSG_HDR_SIZE; + + dev = vfio_client_devs.cl[dev_id]; + if (!dev) { + VFIO_USER_LOG(ERR, "Failed to write region: " + "wrong device ID\n"); + return -EINVAL; + } + + vfio_user_client_fill_hdr(&msg, VFIO_USER_DEVICE_RESET, + sz, dev->msg_id++); + + ret = vfio_user_client_send_recv(dev->sock.sock_fd, &msg); + if (ret) + return ret; + + if (msg.flags & VFIO_USER_ERROR) { + VFIO_USER_LOG(ERR, "Failed to reset device: %s\n", + msg.err ? strerror(msg.err) : + "Unknown error"); + return msg.err ? -(int)msg.err : -1; + } + + if (vfio_user_check_msg_fdnum(&msg, 0) != 0) + return -1; + + return ret; +}