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 <chenbo....@intel.com>
Signed-off-by: Miao Li <miao...@intel.com>
---
 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 <rte_emudev.h>
 #include <rte_emudev_vdev.h>
 
-#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 <pthread.h>
+
+#include <rte_malloc.h>
+
+#include "iavf_vfio_user.h"
+#include <iavf_type.h>
+
+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->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 <rte_vfio_user.h>
+
+#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

Reply via email to