@@ -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;
@@ -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;
};
@@ -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"
@@ -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:
new file mode 100644
@@ -0,0 +1,399 @@
+/* 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_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;
+}
new file mode 100644
@@ -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
@@ -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')
@@ -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