This patch implements emudev opertions to make emulated iavf fit into rte_emudev framework. Lifecycle related and device resource related operations are both implemented.
Signed-off-by: Chenbo Xia <chenbo....@intel.com> Signed-off-by: Xiuchun Lu <xiuchun...@intel.com> --- drivers/emu/iavf/iavf_emu.c | 218 ++++++++++++++++++++++++++++++++ drivers/emu/iavf/rte_iavf_emu.h | 59 +++++++++ 2 files changed, 277 insertions(+) diff --git a/drivers/emu/iavf/iavf_emu.c b/drivers/emu/iavf/iavf_emu.c index c1a702d744..9ad371ca98 100644 --- a/drivers/emu/iavf/iavf_emu.c +++ b/drivers/emu/iavf/iavf_emu.c @@ -2,7 +2,72 @@ * Copyright(c) 2020 Intel Corporation */ +#include <stdint.h> +#include <string.h> +#include <unistd.h> + +#include <rte_malloc.h> +#include <rte_emudev.h> + #include "iavf_vfio_user.h" +#include <iavf_type.h> + +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) { @@ -26,6 +91,159 @@ static int 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 <stdint.h> +#include <stddef.h> +#include <limits.h> +#include <net/if.h> +#include <sys/queue.h> +#include <rte_vfio_user.h> #include <rte_emudev.h> #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); -- 2.17.1