DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH v1 0/2] introduce new iavf driver on vfio-user client
@ 2020-12-19 14:38 Jingjing Wu
  2020-12-19 14:38 ` [dpdk-dev] [PATCH v1 1/2] common/iavf: emulated pci interfaces " Jingjing Wu
                   ` (2 more replies)
  0 siblings, 3 replies; 18+ messages in thread
From: Jingjing Wu @ 2020-12-19 14:38 UTC (permalink / raw)
  To: dev; +Cc: jingjing.wu, beilei.xing, chenbo.xia, xiuchun.lu

This series introduces a new net virtual device called iavf_client which
is based on vfio-user client interface. Through vfio-user client interface,
PCI liked device could be used similar as Intel® Ethernet Adaptive Virtual
Function specification.
The code to enable iavf_client mainly contains two parts:
 - Emulated pci interfaces for vfio-user client which is located
   in common/iavf/vfio_user/.
 - A new net driver base on vdev abstraction, i.e. iavf_client_ethdev.c

      ----------------------
      | ------------------ |
      | |  iavf driver   | |----> (iavf_client_ethdev.c)
      | ------------------ |
      | ------------------ |
      | | device emulate | |------>(common/iavf/vfio_user/)
      | ------------------ |
      ----------------------
                |
                |  
      ----------------------
      |      vfio-user     |
      |       client       |
      ----------------------



This driver can be used to test the device emulation framework
mentioned in:
  [RFC 0/2] Add device emulation support in DPDK
  http://patchwork.dpdk.org/cover/75549/

                    +------------------------------------------------------+
                    |   +---------------+      +---------------+           |
                    |   | iavf_emudev   |      | iavfbe_ethdev |           |
                    |   |    driver     |      |     driver    |           |
                    |   +---------------+      +---------------+           |
                    |           |                       |                  |
                    | ------------------------------------------- VDEV BUS |
                    |           |                       |                  |
                    |   +---------------+       +--------------+           |
+--------------+    |   | vdev:         |       | vdev:        |           |
| +----------+ |    |   | /path/to/vfio |       |iavf_emudev_# |           |
| |   iavf   | |    |   +---------------+       +--------------+           |
| |  client  |      |           |                                          |
| +----------+ |    |           |                                          |
| +----------+ |    |      +----------+                                    |
| | vfio-user| |    |      | vfio-user|                                    |
| | client   | |<---|----->| server   |                                    |
| +----------+ |    |      +----------+                                    |
| QEMU/DPDK    |    | DPDK                                                 |
+--------------+    +------------------------------------------------------+

It can be launched together with patch series for the testing:
  [0/9] Introduce vfio-user library:
  http://patchwork.dpdk.org/cover/85389/
  [0/8]Introduce emudev library and iavf emudev driver
  http://patchwork.dpdk.org/cover/85488/


This series depends on patch serieses:
  [0/9] Introduce vfio-user library:
  http://patchwork.dpdk.org/cover/85389/

Jingjing Wu (2):
  common/iavf: emulated pci interfaces on vfio-user client
  net/iavf: introduce iavf driver on vfio-user client

 config/rte_config.h                           |   3 +
 drivers/common/iavf/iavf_common.c             |   7 +
 drivers/common/iavf/iavf_impl.c               |  45 +-
 drivers/common/iavf/iavf_osdep.h              |  14 +
 drivers/common/iavf/iavf_prototype.h          |   1 +
 drivers/common/iavf/iavf_type.h               |   3 +
 drivers/common/iavf/meson.build               |  11 +-
 drivers/common/iavf/version.map               |   5 +
 drivers/common/iavf/vfio_user/vfio_user_pci.c | 517 ++++++++++++++++++
 drivers/common/iavf/vfio_user/vfio_user_pci.h |  66 +++
 drivers/net/iavf/iavf.h                       |  18 +-
 drivers/net/iavf/iavf_client_ethdev.c         | 298 ++++++++++
 drivers/net/iavf/iavf_ethdev.c                |  26 +-
 drivers/net/iavf/iavf_rxtx.c                  |  23 +-
 drivers/net/iavf/meson.build                  |   1 +
 15 files changed, 1015 insertions(+), 23 deletions(-)
 create mode 100644 drivers/common/iavf/vfio_user/vfio_user_pci.c
 create mode 100644 drivers/common/iavf/vfio_user/vfio_user_pci.h
 create mode 100644 drivers/net/iavf/iavf_client_ethdev.c

-- 
2.21.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [dpdk-dev] [PATCH v1 1/2] common/iavf: emulated pci interfaces on vfio-user client
  2020-12-19 14:38 [dpdk-dev] [PATCH v1 0/2] introduce new iavf driver on vfio-user client Jingjing Wu
@ 2020-12-19 14:38 ` Jingjing Wu
  2020-12-19 14:38 ` [dpdk-dev] [PATCH v1 2/2] net/iavf: introduce iavf driver " Jingjing Wu
  2021-01-07  7:45 ` [dpdk-dev] [PATCH v2 0/4] introduce new " Jingjing Wu
  2 siblings, 0 replies; 18+ messages in thread
From: Jingjing Wu @ 2020-12-19 14:38 UTC (permalink / raw)
  To: dev; +Cc: jingjing.wu, beilei.xing, chenbo.xia, xiuchun.lu

This patch implements Emulated pci interfaces on vfio-user client
which is located in common/iavf/vfio_user/.
Four main functions provided to upper layer (driver) to set
up or talk to device:
 - client_vfio_user_setup
 - client_vfio_user_release
 - client_vfio_user_get_bar_addr
 - client_vfio_user_pci_bar_access

      ----------------------
      | ------------------ |
      | |  iavf driver   | |
      | ------------------ |
      | ------------------ |
      | | device emulate | |------>(common/iavf/vfio_user/)
      | ------------------ |
      ----------------------
                |
                |
      ----------------------
      |      vfio-user     |
      |       client       |
      ----------------------

Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
Signed-off-by: Chenbo Xia <chenbo.xia@intel.com>
---
 config/rte_config.h                           |   3 +
 drivers/common/iavf/iavf_common.c             |   7 +
 drivers/common/iavf/iavf_impl.c               |  45 +-
 drivers/common/iavf/iavf_osdep.h              |  14 +
 drivers/common/iavf/iavf_type.h               |   3 +
 drivers/common/iavf/meson.build               |  11 +-
 drivers/common/iavf/version.map               |   4 +
 drivers/common/iavf/vfio_user/vfio_user_pci.c | 517 ++++++++++++++++++
 drivers/common/iavf/vfio_user/vfio_user_pci.h |  66 +++
 9 files changed, 668 insertions(+), 2 deletions(-)
 create mode 100644 drivers/common/iavf/vfio_user/vfio_user_pci.c
 create mode 100644 drivers/common/iavf/vfio_user/vfio_user_pci.h

diff --git a/config/rte_config.h b/config/rte_config.h
index a0b5160ff2..76ed1ae83f 100644
--- a/config/rte_config.h
+++ b/config/rte_config.h
@@ -151,4 +151,7 @@
 #define RTE_LIBRTE_PMD_DLB2_SW_CREDIT_QUANTA 32
 #define RTE_PMD_DLB2_DEFAULT_DEPTH_THRESH 256
 
+/* IAVF bsed on vfio_user client */
+#define RTE_LIBRTE_IAVF_CLIENT 1
+
 #endif /* _RTE_CONFIG_H_ */
diff --git a/drivers/common/iavf/iavf_common.c b/drivers/common/iavf/iavf_common.c
index c951b7d787..2e68f5d08b 100644
--- a/drivers/common/iavf/iavf_common.c
+++ b/drivers/common/iavf/iavf_common.c
@@ -20,6 +20,13 @@ enum iavf_status iavf_set_mac_type(struct iavf_hw *hw)
 
 	DEBUGFUNC("iavf_set_mac_type\n");
 
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+	if (hw->bus.type == iavf_bus_type_vfio_user) {
+		hw->mac.type = IAVF_MAC_VF;
+		return status;
+	}
+#endif
+
 	if (hw->vendor_id == IAVF_INTEL_VENDOR_ID) {
 		switch (hw->device_id) {
 		case IAVF_DEV_ID_X722_VF:
diff --git a/drivers/common/iavf/iavf_impl.c b/drivers/common/iavf/iavf_impl.c
index fc0da31753..79262bf50d 100644
--- a/drivers/common/iavf/iavf_impl.c
+++ b/drivers/common/iavf/iavf_impl.c
@@ -10,9 +10,14 @@
 #include <rte_malloc.h>
 #include <rte_memzone.h>
 
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+#include "vfio_user/vfio_user_pci.h"
+#endif
 #include "iavf_type.h"
 #include "iavf_prototype.h"
 
+int iavf_common_logger;
+
 enum iavf_status
 iavf_allocate_dma_mem_d(__rte_unused struct iavf_hw *hw,
 			struct iavf_dma_mem *mem,
@@ -85,4 +90,42 @@ iavf_free_virt_mem_d(__rte_unused struct iavf_hw *hw,
 	return IAVF_SUCCESS;
 }
 
-RTE_LOG_REGISTER(iavf_common_logger, pmd.common.iavf, NOTICE);
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+uint32_t
+iavf_read_addr(struct iavf_hw *hw, uint32_t offset)
+{
+	uint32_t value = 0;
+
+	if (!hw || !hw->hw_addr)
+		return 0;
+
+	if (hw->bus.type == iavf_bus_type_vfio_user)
+		client_vfio_user_pci_bar_access(
+				(struct vfio_device *)hw->hw_addr,
+				0, offset, 4, &value, false);
+	else
+		value = readl(hw->hw_addr + offset);
+
+	return value;
+}
+
+void
+iavf_write_addr(struct iavf_hw *hw, uint32_t offset, uint32_t value)
+{
+	if (!hw || !hw->hw_addr)
+		return;
+	if (hw->bus.type == iavf_bus_type_vfio_user)
+		client_vfio_user_pci_bar_access(
+				(struct vfio_device *)hw->hw_addr,
+				0, offset, 4, &value, true);
+	else
+		writel(value, hw->hw_addr + offset);
+}
+#endif
+
+RTE_INIT(iavf_common_init_log)
+{
+	iavf_common_logger = rte_log_register("pmd.common.iavf");
+	if (iavf_common_logger >= 0)
+		rte_log_set_level(iavf_common_logger, RTE_LOG_NOTICE);
+}
diff --git a/drivers/common/iavf/iavf_osdep.h b/drivers/common/iavf/iavf_osdep.h
index 7cba13ff74..025d48a702 100644
--- a/drivers/common/iavf/iavf_osdep.h
+++ b/drivers/common/iavf/iavf_osdep.h
@@ -107,8 +107,22 @@ writeq(uint64_t value, volatile void *addr)
 	rte_write64(rte_cpu_to_le_64(value), addr);
 }
 
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+struct iavf_hw;
+
+__rte_internal
+uint32_t iavf_read_addr(struct iavf_hw *hw, uint32_t offset);
+__rte_internal
+void iavf_write_addr(struct iavf_hw *hw, uint32_t offset, uint32_t value);
+
+#define wr32(a, reg, value)  iavf_write_addr((a), (reg), (value))
+#define rd32(a, reg)         iavf_read_addr((a), (reg))
+
+#else
 #define wr32(a, reg, value) writel((value), (a)->hw_addr + (reg))
 #define rd32(a, reg)        readl((a)->hw_addr + (reg))
+#endif /* RTE_LIBRTE_IAVF_CLIENT */
+
 #define wr64(a, reg, value) writeq((value), (a)->hw_addr + (reg))
 #define rd64(a, reg)        readq((a)->hw_addr + (reg))
 
diff --git a/drivers/common/iavf/iavf_type.h b/drivers/common/iavf/iavf_type.h
index 0990c9aa33..faa4a21eac 100644
--- a/drivers/common/iavf/iavf_type.h
+++ b/drivers/common/iavf/iavf_type.h
@@ -264,6 +264,9 @@ enum iavf_bus_type {
 	iavf_bus_type_pci,
 	iavf_bus_type_pcix,
 	iavf_bus_type_pci_express,
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+	iavf_bus_type_vfio_user,
+#endif
 	iavf_bus_type_reserved
 };
 
diff --git a/drivers/common/iavf/meson.build b/drivers/common/iavf/meson.build
index 1f4d8b898d..e0160ea135 100644
--- a/drivers/common/iavf/meson.build
+++ b/drivers/common/iavf/meson.build
@@ -1,7 +1,16 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2019-2020 Intel Corporation
 
-sources = files('iavf_adminq.c', 'iavf_common.c', 'iavf_impl.c')
+includes += include_directories('vfio_user')
+
+sources = files(
+	'iavf_adminq.c',
+	'iavf_common.c',
+	'iavf_impl.c',
+	'vfio_user/vfio_user_pci.c'
+)
+
+deps += ['vfio_user']
 
 if cc.has_argument('-Wno-pointer-to-int-cast')
         cflags += '-Wno-pointer-to-int-cast'
diff --git a/drivers/common/iavf/version.map b/drivers/common/iavf/version.map
index e0f117197c..8808779ab7 100644
--- a/drivers/common/iavf/version.map
+++ b/drivers/common/iavf/version.map
@@ -7,6 +7,10 @@ INTERNAL {
 	iavf_set_mac_type;
 	iavf_shutdown_adminq;
 	iavf_vf_parse_hw_config;
+	client_vfio_user_setup;
+	client_vfio_user_get_bar_addr;
+	iavf_write_addr;
+	iavf_read_addr;
 
 	local: *;
 };
diff --git a/drivers/common/iavf/vfio_user/vfio_user_pci.c b/drivers/common/iavf/vfio_user/vfio_user_pci.c
new file mode 100644
index 0000000000..0ff2adeb40
--- /dev/null
+++ b/drivers/common/iavf/vfio_user/vfio_user_pci.c
@@ -0,0 +1,517 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <sys/queue.h>
+#include <sys/mman.h>
+#include <sys/eventfd.h>
+
+#include <rte_common.h>
+#include <rte_memory.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_tailq.h>
+#include <rte_errno.h>
+#include <rte_vfio_user.h>
+
+#include "vfio_user_pci.h"
+
+#define IAVF_MEM_EVENT_CLB_NAME "iavf_mem_event_clb"
+
+/* buffer length for irq set */
+#define MSIX_IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + \
+				sizeof(int) * IAVF_CLIENT_MAX_VECTORS)
+/* buffer length for region infor get */
+#define REG_INFO_GET_BUF_LEN (sizeof(struct vfio_region_info) + \
+			sizeof(struct vfio_region_info_cap_sparse_mmap) \
+			+ 2 * sizeof(struct vfio_region_sparse_mmap_area))
+
+static inline int
+vfio_add_mr(struct vfio_device *dev, struct vfio_memory_region *mr)
+{
+	if (dev->nb_mrs == RTE_VUSER_MAX_DMA) {
+		CLIENT_LOG(ERR, "Exceed Maximum supported memory regions %d",
+			RTE_VUSER_MAX_DMA);
+		return -EINVAL;
+	}
+
+	TAILQ_INSERT_HEAD(&dev->mrs_list, mr, link);
+	dev->nb_mrs++;
+
+	CLIENT_LOG(DEBUG, "Add memory region: FD %d, VADDR 0x%lx,"
+			  " IOVA 0x%lx, Size 0x%lx",
+			  mr->fd, mr->vaddr, mr->iova, mr->size);
+	return 0;
+}
+
+static inline void
+vfio_remove_mr(struct vfio_device *dev, struct vfio_memory_region *mr)
+{
+	if (dev->nb_mrs == 0)
+		return;
+
+	CLIENT_LOG(DEBUG, "Remove memory region: FD %d, VADDR 0x%lx,"
+			  " IOVA 0x%lx, Size 0x%lx",
+			  mr->fd, mr->vaddr, mr->iova, mr->size);
+	TAILQ_REMOVE(&dev->mrs_list, mr, link);
+	dev->nb_mrs--;
+	rte_free(mr);
+}
+
+static int
+update_vfio_memory_region(const struct rte_memseg_list *msl __rte_unused,
+		const struct rte_memseg *ms, void *arg)
+{
+	int ret = 0;
+	struct vfio_device *dev = arg;
+	struct vfio_memory_region *mr;
+	struct rte_vfio_user_mem_reg mem;
+	uint64_t offset;
+
+	mr = rte_zmalloc_socket("iavf_client_vfio_user", sizeof(*mr),
+				0, SOCKET_ID_ANY);
+	if (mr == NULL)
+		return -ENOMEM;
+
+	mr->vaddr = (uint64_t)(uintptr_t)ms->addr;
+	mr->iova = ms->iova;
+	mr->size = ms->len;
+	mr->fd = rte_memseg_get_fd_thread_unsafe(ms);
+	if (mr->fd == -1) {
+		CLIENT_LOG(ERR, "Error to get the memory fd");
+		rte_free(mr);
+		return -EFAULT;
+	}
+	if (rte_memseg_get_fd_offset_thread_unsafe(ms, &offset) < 0) {
+		CLIENT_LOG(ERR, "Error to get the memory map offset");
+		rte_free(mr);
+		return -EFAULT;
+	}
+	mr->offset = offset;
+
+	ret = vfio_add_mr(dev, mr);
+	if (ret) {
+		CLIENT_LOG(ERR, "Error to add memory region");
+		rte_free(mr);
+		return ret;
+	}
+
+	mem.gpa = mr->iova;
+	mem.size = mr->size;
+	mem.fd_offset = mr->offset;
+	mem.protection = PROT_WRITE | PROT_READ;
+	mem.flags = RTE_VUSER_MEM_MAPPABLE;
+
+	ret = rte_vfio_user_dma_map(dev->dev_id, &mem, &mr->fd, 1);
+	if (ret) {
+		CLIENT_LOG(ERR, "Error to send dma map request");
+		vfio_remove_mr(dev, mr);
+		rte_free(mr);
+		return ret;
+	}
+	return ret;
+
+}
+
+static int
+vfio_device_dma_map(struct vfio_device *dev)
+{
+	if (rte_memseg_walk_thread_unsafe(update_vfio_memory_region, dev) < 0)
+		return -1;
+
+	return 0;
+}
+
+
+static void
+vfio_device_dma_unmap(struct vfio_device *dev)
+{
+	int ret;
+	struct vfio_memory_region *mr;
+
+	if (dev->nb_mrs == 0)
+		return;
+
+	while ((mr = TAILQ_FIRST(&dev->mrs_list))) {
+		struct rte_vfio_user_mem_reg mem;
+
+		mem.gpa = mr->iova;
+		mem.size = mr->size;
+		mem.fd_offset = mr->offset;
+		mem.protection = PROT_WRITE | PROT_READ;
+		ret = rte_vfio_user_dma_unmap(dev->dev_id, &mem, 1);
+		if (ret)
+			CLIENT_LOG(ERR, "Error to send dma unmap request for"
+				" mr FD %d, VADDR 0x%lx, IOVA 0x%lx, Size 0x%lx",
+				 mr->fd, mr->vaddr, mr->iova, mr->size);
+		TAILQ_REMOVE(&dev->mrs_list, mr, link);
+		dev->nb_mrs--;
+		rte_free(mr);
+	}
+	return;
+}
+
+static void
+iavf_mem_event_cb(enum rte_mem_event type __rte_unused,
+			 const void *addr,
+			 size_t len __rte_unused,
+			 void *arg)
+{
+	struct vfio_device *dev = arg;
+	struct rte_memseg_list *msl;
+	uint16_t ret;
+
+	/* ignore externally allocated memory */
+	msl = rte_mem_virt2memseg_list(addr);
+	if (msl->external)
+		return;
+	ret = vfio_device_dma_map(dev);
+	if (ret)
+		CLIENT_LOG(ERR, "DMA map failed");
+}
+
+static inline struct vfio_info_cap_header *
+vfio_device_get_info_cap(struct vfio_region_info *info, int cap)
+{
+	struct vfio_info_cap_header *h;
+	size_t offset;
+
+	offset = info->cap_offset;
+	while (offset != 0 && offset < info->argsz) {
+		h = (struct vfio_info_cap_header *)((uintptr_t)info + offset);
+		if (h->id == cap) {
+			return h;
+		}
+		offset = h->next;
+	}
+
+	return NULL;
+}
+
+static int
+vfio_device_setup_sparse_mmaps(struct vfio_device *device, int index,
+			       struct vfio_region_info *info, int *fds)
+{
+	struct vfio_info_cap_header *hdr;
+	struct vfio_region_info_cap_sparse_mmap *sparse;
+	struct vfio_pci_region *region = &device->regions[index];
+	uint32_t i, j = 0;
+	int prot = 0;
+
+	hdr = vfio_device_get_info_cap(info, VFIO_REGION_INFO_CAP_SPARSE_MMAP);
+	if (!hdr) {
+		CLIENT_LOG(ERR, "Device doesn't have sparse mmap");
+		return -EEXIST;
+	}
+
+	sparse = container_of(hdr, struct vfio_region_info_cap_sparse_mmap, header);
+	for (i = 0; i < sparse->nr_areas; i++) {
+		if (sparse->areas[i].size == 0)
+			continue;
+		region->mmaps[j].offset = sparse->areas[i].offset;
+		region->mmaps[j].size = sparse->areas[i].size;
+		prot |= info->flags & VFIO_REGION_INFO_FLAG_READ ? PROT_READ : 0;
+		prot |= info->flags & VFIO_REGION_INFO_FLAG_WRITE ? PROT_WRITE : 0;
+		if (*fds) {
+			/* Use single fd for now*/
+			region->mmaps[j].mem = mmap(NULL, region->mmaps[j].size,
+						prot, MAP_SHARED, fds[0],
+						region->offset + region->mmaps[j].offset);
+			if (region->mmaps[j].mem == MAP_FAILED) {
+				CLIENT_LOG(ERR, "Device SPARSE MMAP failed");
+				return -EIO;
+			}
+		} else {
+			CLIENT_LOG(ERR, "No valid fd, skip mmap for"
+					" bar %d region %u", index, i);
+		}
+		CLIENT_LOG(DEBUG, "Sparse region %u, Size 0x%llx,"
+				  " Offset 0x%llx, Map addr %p",
+				  i, sparse->areas[i].size,
+				  sparse->areas[i].offset, region->mmaps[j].mem);
+		j++;
+	}
+	device->regions[index].nr_mmaps = j;
+
+	return 0;
+}
+
+static int
+vfio_device_map_region(struct vfio_device *device __rte_unused,
+			struct vfio_pci_region *region, int fd)
+{
+	int prot = 0;
+
+	prot |= region->flags & VFIO_REGION_INFO_FLAG_READ ? PROT_READ : 0;
+	prot |= region->flags & VFIO_REGION_INFO_FLAG_WRITE ? PROT_WRITE : 0;
+
+	region->mmaps[0].offset = 0;
+	region->mmaps[0].size = region->size;
+
+	region->mmaps[0].mem = mmap(NULL, region->size, prot, MAP_SHARED,
+				    fd, region->offset);
+	if (region->mmaps[0].mem == MAP_FAILED) {
+		CLIENT_LOG(ERR, "Device Region MMAP failed");
+		return -EFAULT;
+	}
+	CLIENT_LOG(DEBUG, "Memory mapped to %p", region->mmaps[0].mem);
+	region->nr_mmaps = 1;
+
+	return 0;
+}
+
+static void
+vfio_device_unmap_bars(struct vfio_device *dev)
+{
+	uint32_t i, j;
+	struct vfio_pci_region *region;
+
+	for (i = 0; i < dev->pci_regions; i++) {
+		region = &dev->regions[i];
+		for (j = 0; j < region->nr_mmaps; j++) {
+			if (region->mmaps[j].mem)
+				munmap(region->mmaps[j].mem, region->mmaps[j].size);
+		}
+	}
+	memset(dev->regions, 0, sizeof(dev->regions));
+}
+
+static int
+vfio_user_create_irqfd(struct vfio_device *device, uint32_t count)
+{
+	uint32_t i;
+
+	for (i = 0; i < count; i++) {
+		device->irqfds[i] = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
+		if (device->irqfds[i] < 0) {
+			CLIENT_LOG(ERR, "Failed to create irqfd");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+struct vfio_device *
+client_vfio_user_setup(const char *path, int socket)
+{
+	struct vfio_device *device = NULL;
+	char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
+	char reg_get_buf[REG_INFO_GET_BUF_LEN];
+	int fds[VFIO_MAXIMUM_SPARSE_MMAP_REGISONS];
+	struct vfio_device_info dev_info = {};
+	struct vfio_irq_info irq_info = {};
+	struct vfio_irq_set *irq_set;
+	struct vfio_region_info *reg_info;
+	uint32_t i;
+	int dev_id;
+	int ret;
+
+	device = rte_zmalloc_socket("iavf_client_vfio_user",
+				    sizeof(struct vfio_device),
+				    0, socket);
+	if (!device)
+		return NULL;
+
+	TAILQ_INIT(&device->mrs_list);
+
+	dev_id = rte_vfio_user_attach_dev(path);
+	if (dev_id < 0) {
+		rte_free(device);
+		CLIENT_LOG(ERR, "Error to setup vfio-user via path %s", path);
+		return NULL;
+	}
+
+	device->dev_id = dev_id;
+	snprintf(device->name, sizeof(device->name), "vfio-user%u", dev_id);
+	snprintf(device->path, PATH_MAX, "%s", path);
+
+	ret = rte_vfio_user_get_dev_info(dev_id, &dev_info);
+	if (ret) {
+		CLIENT_LOG(ERR, "Device get info failed");
+		goto cleanup;
+	}
+	device->pci_regions = dev_info.num_regions;
+	device->flags = dev_info.flags;
+
+	irq_info.argsz = sizeof(struct vfio_irq_info);
+	irq_info.index = VFIO_PCI_MSIX_IRQ_INDEX;
+	ret = rte_vfio_user_get_irq_info(dev_id, &irq_info);
+	if (ret) {
+		CLIENT_LOG(ERR, "IRQ get info failed");
+		goto cleanup;
+	}
+
+	if (irq_info.count) {
+		if (vfio_user_create_irqfd(device, irq_info.count))
+			goto cleanup;
+
+		irq_set = (struct vfio_irq_set *)irq_set_buf;
+		irq_set->argsz = sizeof(irq_set_buf);
+		irq_set->count = RTE_MIN(irq_info.count,
+					 (uint32_t)IAVF_CLIENT_MAX_VECTORS);
+		irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
+				 VFIO_IRQ_SET_ACTION_TRIGGER;
+		irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
+		irq_set->start = 0;
+		rte_memcpy(irq_set->data, device->irqfds,
+			   sizeof(int) * IAVF_CLIENT_MAX_VECTORS);
+		ret = rte_vfio_user_set_irqs(dev_id, irq_set);
+		if (ret) {
+			CLIENT_LOG(ERR, "IRQ set failed");
+			goto cleanup;
+		}
+	}
+
+	reg_info = (struct vfio_region_info *)reg_get_buf;
+
+	for (i = 0; i < device->pci_regions; i++) {
+		memset(reg_info, 0, REG_INFO_GET_BUF_LEN);
+		memset(fds, 0, sizeof(fds));
+
+		reg_info->index = i;
+		reg_info->argsz = sizeof(struct vfio_region_info);
+		ret = rte_vfio_user_get_reg_info(dev_id, reg_info, fds);
+		if (reg_info->argsz > sizeof(struct vfio_region_info))
+			ret = rte_vfio_user_get_reg_info(dev_id, reg_info, fds);
+		if (ret) {
+			CLIENT_LOG(ERR, "Device setup bar %d failed", i);
+			goto cleanup;
+		}
+
+		device->regions[i].size = reg_info->size;
+		device->regions[i].offset = reg_info->offset;
+		device->regions[i].flags = reg_info->flags;
+
+		CLIENT_LOG(DEBUG, "Bar %d, Size 0x%llx, Offset 0x%llx,"
+			" Flags 0x%x, Cap offset %u",
+			i, reg_info->size, reg_info->offset,
+			reg_info->flags, reg_info->cap_offset);
+
+		/* Setup MMAP if any */
+		if (reg_info->size &&
+		    (reg_info->flags & VFIO_REGION_INFO_FLAG_MMAP)) {
+			/* Try to map sparse region first */
+			if (reg_info->flags & VFIO_REGION_INFO_FLAG_CAPS)
+				ret = vfio_device_setup_sparse_mmaps(device, i,
+							     reg_info, fds);
+			else
+				ret = vfio_device_map_region(device,
+						&device->regions[i], fds[0]);
+
+			if (ret != 0) {
+				CLIENT_LOG(ERR, "Setup Device %s region %d failed",
+					   device->name, i);
+				goto cleanup;
+			}
+		}
+	}
+
+	/* Register DMA Region */
+	ret = vfio_device_dma_map(device);
+	if (ret) {
+		CLIENT_LOG(ERR, "Container DMA map failed");
+		goto cleanup;
+	}
+
+	CLIENT_LOG(DEBUG, "Device %s, Path %s Setup Successfully",
+		   device->name, device->path);
+
+	if (rte_mem_event_callback_register(IAVF_MEM_EVENT_CLB_NAME,
+				iavf_mem_event_cb, device)) {
+		if (rte_errno != ENOTSUP) {
+			CLIENT_LOG(ERR, "Failed to register mem event"
+					" callback");
+			goto cleanup;
+		}
+	}
+
+	return device;
+
+cleanup:
+	rte_vfio_user_detach_dev(dev_id);
+	rte_free(device);
+	return NULL;
+}
+
+void
+client_vfio_user_release(struct vfio_device *dev)
+{
+	vfio_device_unmap_bars(dev);
+	vfio_device_dma_unmap(dev);
+	rte_vfio_user_detach_dev(dev->dev_id);
+
+	rte_free(dev);
+}
+
+void *
+client_vfio_user_get_bar_addr(struct vfio_device *dev, uint32_t index,
+			      uint64_t offset, uint32_t len)
+{
+	struct vfio_pci_region *region = &dev->regions[index];
+	uint32_t i;
+
+	if (!region->size || !(region->flags & VFIO_REGION_INFO_FLAG_MMAP))
+		return NULL;
+
+	for (i = 0; i < region->nr_mmaps; i++) {
+		if (region->mmaps[i].mem &&
+		    (region->mmaps[i].offset <= offset) &&
+		    ((offset + len) <= (region->mmaps[i].offset + region->mmaps[i].size))) {
+			return (void *)((uintptr_t)region->mmaps[i].mem + \
+					offset - region->mmaps[i].offset);
+		}
+	}
+
+	return NULL;
+}
+
+int
+client_vfio_user_pci_bar_access(struct vfio_device *dev, uint32_t index,
+				uint64_t offset, size_t len,
+				void *buf, bool is_write)
+{
+	struct vfio_pci_region *region = &dev->regions[index];
+	uint64_t sparse_size, sparse_offset, bar_addr;
+	uint32_t i;
+	int ret;
+
+	if ((offset + len > region->size) ||
+	    (is_write && !(region->flags & VFIO_REGION_INFO_FLAG_WRITE)) ||
+	    (!is_write && !(region->flags & VFIO_REGION_INFO_FLAG_READ)))
+		return -EINVAL;
+
+	/* Read/write through MMAP */
+	for (i = 0; i < region->nr_mmaps; i++) {
+		sparse_offset = region->mmaps[i].offset;
+		sparse_size = region->mmaps[i].offset + region->mmaps[i].size;
+
+		if ((offset >= sparse_offset) &&
+		    (offset + len <= sparse_size)) {
+			bar_addr = (uint64_t)(uintptr_t)region->mmaps[i].mem +
+				offset - sparse_offset;
+			if (is_write)
+				rte_memcpy((void *)bar_addr, buf, len);
+			else
+				rte_memcpy(buf, (void *)bar_addr, len);
+
+			return 0;
+		}
+	}
+
+	/* Read/write through message */
+	if (is_write)
+		ret = rte_vfio_user_region_write(dev->dev_id, index,
+						 offset, len, buf);
+	else
+		ret = rte_vfio_user_region_read(dev->dev_id, index,
+						 offset, len, buf);
+	return ret;
+}
diff --git a/drivers/common/iavf/vfio_user/vfio_user_pci.h b/drivers/common/iavf/vfio_user/vfio_user_pci.h
new file mode 100644
index 0000000000..da2a67343a
--- /dev/null
+++ b/drivers/common/iavf/vfio_user/vfio_user_pci.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _VFIO_USER_PCI_H
+#define _VFIO_USER_PCI_H
+
+#include <linux/vfio.h>
+#include <linux/limits.h>
+
+#define IAVF_CLIENT_MAX_VECTORS			16
+#define VFIO_MAXIMUM_SPARSE_MMAP_REGISONS	8
+
+struct vfio_memory_region {
+	TAILQ_ENTRY(vfio_memory_region) link;
+	uint64_t iova;
+	uint64_t size; /* bytes */
+	uint64_t vaddr;
+	uint64_t offset;
+	int fd;
+};
+
+struct vfio_sparse_mmaps {
+	void *mem;
+	uint64_t offset;
+	size_t size;
+};
+
+struct vfio_pci_region {
+	uint64_t offset;
+	size_t size;
+	uint64_t flags;
+	uint32_t nr_mmaps;
+	struct vfio_sparse_mmaps mmaps[VFIO_MAXIMUM_SPARSE_MMAP_REGISONS];
+};
+
+TAILQ_HEAD(vfio_memory_region_list, vfio_memory_region);
+
+struct vfio_device {
+	int dev_id;
+	char name[64];
+	char path[PATH_MAX];
+	uint64_t flags;
+	uint32_t pci_regions;
+	uint32_t nb_mrs;
+	struct vfio_pci_region regions[VFIO_PCI_NUM_REGIONS];
+	int irqfds[IAVF_CLIENT_MAX_VECTORS];
+	struct vfio_memory_region_list mrs_list;
+};
+
+extern int iavf_common_logger;
+#define CLIENT_LOG(level, fmt, args...) \
+	rte_log(RTE_LOG_ ## level, iavf_common_logger, "%s(): " fmt "\n", \
+		__func__, ## args)
+
+__rte_internal
+struct vfio_device *client_vfio_user_setup(const char *path, int socket);
+void client_vfio_user_release(struct vfio_device *dev);
+__rte_internal
+void *client_vfio_user_get_bar_addr(struct vfio_device *dev, uint32_t index,
+				    uint64_t offset, uint32_t len);
+int client_vfio_user_pci_bar_access(struct vfio_device *dev, uint32_t index,
+				    uint64_t offset, size_t len, void *buf,
+				    bool is_write);
+
+#endif
-- 
2.21.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [dpdk-dev] [PATCH v1 2/2] net/iavf: introduce iavf driver on vfio-user client
  2020-12-19 14:38 [dpdk-dev] [PATCH v1 0/2] introduce new iavf driver on vfio-user client Jingjing Wu
  2020-12-19 14:38 ` [dpdk-dev] [PATCH v1 1/2] common/iavf: emulated pci interfaces " Jingjing Wu
@ 2020-12-19 14:38 ` Jingjing Wu
  2020-12-22  8:14   ` Xia, Chenbo
  2021-01-07  7:45 ` [dpdk-dev] [PATCH v2 0/4] introduce new " Jingjing Wu
  2 siblings, 1 reply; 18+ messages in thread
From: Jingjing Wu @ 2020-12-19 14:38 UTC (permalink / raw)
  To: dev; +Cc: jingjing.wu, beilei.xing, chenbo.xia, xiuchun.lu

This patch add a new net driver based on vdev abstraction,
i.e. iavf_client_ethdev.c. It is using common iavf functions
to talk with Emulated pci interfaces based on vfio-user.

      ----------------------
      | ------------------ |
      | |  iavf driver   | |----> (iavf_client_ethdev.c)
      | ------------------ |
      | ------------------ |
      | | device emulate | |
      | | vfio-user adapt| |
      | ------------------ |
      ----------------------
                |
                |
      ----------------------
      |      vfio-user     |
      |       client       |
      ----------------------

Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
---
 drivers/common/iavf/iavf_prototype.h  |   1 +
 drivers/common/iavf/version.map       |   1 +
 drivers/net/iavf/iavf.h               |  18 +-
 drivers/net/iavf/iavf_client_ethdev.c | 298 ++++++++++++++++++++++++++
 drivers/net/iavf/iavf_ethdev.c        |  26 +--
 drivers/net/iavf/iavf_rxtx.c          |  23 +-
 drivers/net/iavf/meson.build          |   1 +
 7 files changed, 347 insertions(+), 21 deletions(-)
 create mode 100644 drivers/net/iavf/iavf_client_ethdev.c

diff --git a/drivers/common/iavf/iavf_prototype.h b/drivers/common/iavf/iavf_prototype.h
index f34e77db0f..3998d26dc0 100644
--- a/drivers/common/iavf/iavf_prototype.h
+++ b/drivers/common/iavf/iavf_prototype.h
@@ -83,6 +83,7 @@ void iavf_destroy_spinlock(struct iavf_spinlock *sp);
 __rte_internal
 void iavf_vf_parse_hw_config(struct iavf_hw *hw,
 			     struct virtchnl_vf_resource *msg);
+__rte_internal
 enum iavf_status iavf_vf_reset(struct iavf_hw *hw);
 __rte_internal
 enum iavf_status iavf_aq_send_msg_to_pf(struct iavf_hw *hw,
diff --git a/drivers/common/iavf/version.map b/drivers/common/iavf/version.map
index 8808779ab7..4dc2d42196 100644
--- a/drivers/common/iavf/version.map
+++ b/drivers/common/iavf/version.map
@@ -7,6 +7,7 @@ INTERNAL {
 	iavf_set_mac_type;
 	iavf_shutdown_adminq;
 	iavf_vf_parse_hw_config;
+	iavf_vf_reset;
 	client_vfio_user_setup;
 	client_vfio_user_get_bar_addr;
 	iavf_write_addr;
diff --git a/drivers/net/iavf/iavf.h b/drivers/net/iavf/iavf.h
index 6d5912d8c1..c34f971721 100644
--- a/drivers/net/iavf/iavf.h
+++ b/drivers/net/iavf/iavf.h
@@ -195,7 +195,10 @@ struct iavf_adapter {
 	struct iavf_hw hw;
 	struct rte_eth_dev *eth_dev;
 	struct iavf_info vf;
-
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+	/* used for avf_client driver */
+	struct vfio_device *user_dev;
+#endif
 	bool rx_bulk_alloc_allowed;
 	/* For vector PMD */
 	bool rx_vec_allowed;
@@ -231,6 +234,16 @@ iavf_init_adminq_parameter(struct iavf_hw *hw)
 	hw->aq.asq_buf_size = IAVF_AQ_BUF_SZ;
 }
 
+static inline void
+iavf_disable_irq0(struct iavf_hw *hw)
+{
+	/* Disable all interrupt types */
+	IAVF_WRITE_REG(hw, IAVF_VFINT_ICR0_ENA1, 0);
+	IAVF_WRITE_REG(hw, IAVF_VFINT_DYN_CTL01,
+		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+	IAVF_WRITE_FLUSH(hw);
+}
+
 static inline uint16_t
 iavf_calc_itr_interval(int16_t interval)
 {
@@ -284,6 +297,9 @@ _atomic_set_cmd(struct iavf_info *vf, enum virtchnl_ops ops)
 	return !ret;
 }
 
+extern const struct eth_dev_ops iavf_eth_dev_ops;
+
+int iavf_init_vf(struct rte_eth_dev *dev);
 int iavf_check_api_version(struct iavf_adapter *adapter);
 int iavf_get_vf_resource(struct iavf_adapter *adapter);
 void iavf_handle_virtchnl_msg(struct rte_eth_dev *dev);
diff --git a/drivers/net/iavf/iavf_client_ethdev.c b/drivers/net/iavf/iavf_client_ethdev.c
new file mode 100644
index 0000000000..03f759c761
--- /dev/null
+++ b/drivers/net/iavf/iavf_client_ethdev.c
@@ -0,0 +1,298 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Intel Corporation
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_vdev.h>
+#include <rte_alarm.h>
+#include <rte_bus_vdev.h>
+#include <rte_malloc.h>
+#include <vfio_user/vfio_user_pci.h>
+
+#include "iavf.h"
+#include "iavf_rxtx.h"
+
+static int iavf_client_dev_close(struct rte_eth_dev *dev);
+static int iavf_client_dev_reset(struct rte_eth_dev *dev);
+
+/* set iavf_client_dev_ops to iavf's by default */
+static struct eth_dev_ops iavf_client_eth_dev_ops;
+
+static const char *valid_args[] = {
+#define AVF_CLIENT_ARG_PATH           "path"
+	AVF_CLIENT_ARG_PATH,
+	NULL
+};
+
+/* set up vfio_device for iavf_client*/
+static int
+iavf_client_vfio_user_setup(struct rte_eth_dev *dev, const char *path)
+{
+	struct iavf_adapter *adapter =
+		IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(adapter);
+	struct vfio_device *vfio_dev;
+	int max_fds, i;
+
+	vfio_dev = client_vfio_user_setup(path, dev->device->numa_node);
+	if (vfio_dev == NULL) {
+		printf("Error to create vfio_device for iavf_client\n");
+		return -1;
+	}
+	hw->bus.type = iavf_bus_type_vfio_user;
+
+	/* Use hw_addr to record dev ptr */
+	hw->hw_addr = (uint8_t *)vfio_dev;
+
+	hw->back = IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+
+	if (!dev->intr_handle) {
+		dev->intr_handle = malloc(sizeof(*dev->intr_handle));
+		if (!dev->intr_handle) {
+			PMD_INIT_LOG(ERR, "fail to allocate intr_handle");
+			return -1;
+		}
+		memset(dev->intr_handle, 0, sizeof(*dev->intr_handle));
+	}
+
+	max_fds = RTE_MIN(RTE_MAX_RXTX_INTR_VEC_ID, adapter->vf.num_queue_pairs);
+
+	/* FD for control has been enabled */
+	dev->intr_handle->fd = -1;
+	dev->intr_handle->type = RTE_INTR_HANDLE_VDEV;
+	dev->intr_handle->max_intr = max_fds + 1;
+	dev->intr_handle->nb_efd = max_fds;
+	for (i = 0; i < max_fds; ++i)
+		dev->intr_handle->efds[i] = vfio_dev->irqfds[i];
+	dev->intr_handle->efd_counter_size = 0;
+
+	return 0;
+}
+
+
+static inline void
+avf_client_init_eth_ops(void)
+{
+	iavf_client_eth_dev_ops = iavf_eth_dev_ops;
+	/* keep other unchanged */
+	iavf_client_eth_dev_ops.dev_close  = iavf_client_dev_close,
+	iavf_client_eth_dev_ops.dev_reset  = iavf_client_dev_reset,
+	iavf_client_eth_dev_ops.dev_supported_ptypes_get   = NULL;
+	iavf_client_eth_dev_ops.reta_update                = NULL;
+	iavf_client_eth_dev_ops.reta_query                 = NULL;
+	iavf_client_eth_dev_ops.rss_hash_update            = NULL;
+	iavf_client_eth_dev_ops.rss_hash_conf_get          = NULL;
+	iavf_client_eth_dev_ops.rx_queue_intr_enable       = NULL;
+	iavf_client_eth_dev_ops.rx_queue_intr_disable      = NULL;
+}
+
+#define IAVF_CLIENT_ALARM_INTERVAL 50000 /* us */
+static void
+iavf_client_dev_alarm_handler(void *param)
+{
+	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
+
+	iavf_handle_virtchnl_msg(dev);
+
+	rte_eal_alarm_set(IAVF_CLIENT_ALARM_INTERVAL,
+			  iavf_client_dev_alarm_handler, dev);
+}
+
+/* init ethdev for the avf client device*/
+static int
+iavf_client_eth_init(struct rte_eth_dev *eth_dev)
+{
+	struct iavf_adapter *adapter =
+		IAVF_DEV_PRIVATE_TO_ADAPTER(eth_dev->data->dev_private);
+	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(adapter);
+
+	/* update eth_dev_op by assigning ops func pointer */
+	avf_client_init_eth_ops();
+	eth_dev->dev_ops = (const struct eth_dev_ops *)(&iavf_client_eth_dev_ops);
+
+	eth_dev->rx_pkt_burst = &iavf_recv_pkts;
+	eth_dev->tx_pkt_burst = &iavf_xmit_pkts;
+	eth_dev->tx_pkt_prepare = &iavf_prep_pkts;
+
+	hw->back = IAVF_DEV_PRIVATE_TO_ADAPTER(eth_dev->data->dev_private);
+	adapter->eth_dev = eth_dev;
+	adapter->stopped = 1;
+
+	if (iavf_init_vf(eth_dev) != 0) {
+		PMD_INIT_LOG(ERR, "Init vf failed");
+		return -1;
+	}
+
+	/* copy mac addr */
+	eth_dev->data->mac_addrs = rte_zmalloc(
+			"iavf_client_mac",
+			RTE_ETHER_ADDR_LEN * IAVF_NUM_MACADDR_MAX, 0);
+	if (!eth_dev->data->mac_addrs) {
+		PMD_INIT_LOG(ERR, "Failed to allocate %d bytes needed to"
+			     " store MAC addresses",
+			     RTE_ETHER_ADDR_LEN * IAVF_NUM_MACADDR_MAX);
+		return -ENOMEM;
+	}
+	/* If the MAC address is not configured by host,
+	 * generate a random one.
+	 */
+	if (!rte_is_valid_assigned_ether_addr(
+			(struct rte_ether_addr *)hw->mac.addr))
+		rte_eth_random_addr(hw->mac.addr);
+	rte_ether_addr_copy((struct rte_ether_addr *)hw->mac.addr,
+			&eth_dev->data->mac_addrs[0]);
+
+	rte_eal_alarm_set(IAVF_CLIENT_ALARM_INTERVAL,
+			  iavf_client_dev_alarm_handler, eth_dev);
+	return 0;
+}
+
+static int
+iavf_client_dev_reset(struct rte_eth_dev *dev)
+{
+	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int ret;
+
+	rte_eal_alarm_cancel(iavf_client_dev_alarm_handler, dev);
+
+	iavf_shutdown_adminq(hw);
+	ret = iavf_init_vf(dev);
+
+	/* send reset msg to PF */
+	iavf_vf_reset(hw);
+	rte_eal_alarm_set(IAVF_CLIENT_ALARM_INTERVAL,
+			  iavf_client_dev_alarm_handler, dev);
+
+	return ret;
+}
+
+static int
+iavf_client_dev_close(struct rte_eth_dev *dev)
+{
+	struct iavf_adapter *adapter =
+		IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct rte_intr_handle *intr_handle = dev->intr_handle;
+
+	if (!adapter->stopped) {
+		iavf_stop_queues(dev);
+
+		if (intr_handle) {
+			/* Disable the interrupt for Rx */
+			rte_intr_efd_disable(intr_handle);
+			/* Rx interrupt vector mapping free */
+			if (intr_handle->intr_vec) {
+				rte_free(intr_handle->intr_vec);
+				intr_handle->intr_vec = NULL;
+			}
+		}
+		/* Remove all mac addrs */
+		iavf_add_del_all_mac_addr(adapter, false);
+		adapter->stopped = 1;
+	}
+	iavf_shutdown_adminq(hw);
+	iavf_disable_irq0(hw);
+	rte_eal_alarm_cancel(iavf_client_dev_alarm_handler, dev);
+
+	return 0;
+}
+
+static int
+iavf_client_get_string_arg(const char *key __rte_unused,
+	       const char *value, void *extra_args)
+{
+	if (!value || !extra_args)
+		return -EINVAL;
+
+	*(char **)extra_args = strdup(value);
+
+	if (!*(char **)extra_args)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int
+avf_client_pmd_probe(struct rte_vdev_device *vdev)
+{
+	struct rte_kvargs *kvlist = NULL;
+	struct rte_eth_dev *eth_dev;
+	struct iavf_adapter *adapter;
+	char *path = NULL;
+	int ret;
+
+	kvlist = rte_kvargs_parse(rte_vdev_device_args(vdev), valid_args);
+	if (!kvlist) {
+		PMD_INIT_LOG(ERR, "error when parsing param");
+		return -EINVAL;
+	}
+
+	if (rte_kvargs_count(kvlist, AVF_CLIENT_ARG_PATH) == 1) {
+		if (rte_kvargs_process(kvlist, AVF_CLIENT_ARG_PATH,
+				       &iavf_client_get_string_arg, &path) < 0) {
+			PMD_INIT_LOG(ERR, "error to parse %s",
+				     AVF_CLIENT_ARG_PATH);
+			return -EINVAL;
+		}
+	} else {
+		PMD_INIT_LOG(ERR, "arg %s is mandatory for virtio_user",
+			     AVF_CLIENT_ARG_PATH);
+		return -EINVAL;
+	}
+
+	eth_dev = rte_eth_vdev_allocate(vdev, sizeof(*adapter));
+
+	ret = iavf_client_vfio_user_setup(eth_dev, path);
+	if (ret) {
+		goto err;
+	}
+
+	ret = iavf_client_eth_init(eth_dev);
+	if (ret) {
+		goto err;
+	}
+
+	rte_eth_dev_probing_finish(eth_dev);
+	rte_kvargs_free(kvlist);
+
+	return 0;
+err:
+	rte_eth_dev_release_port(eth_dev);
+	rte_kvargs_free(kvlist);
+	return ret;
+}
+
+
+static int
+avf_client_pmd_remove(struct rte_vdev_device *vdev)
+{
+	struct rte_eth_dev *eth_dev = NULL;
+
+	if (vdev == NULL)
+		return -1;
+
+	/* find the ethdev entry */
+	eth_dev = rte_eth_dev_allocated(rte_vdev_device_name(vdev));
+	if (eth_dev == NULL)
+		return 0;
+
+	iavf_client_dev_close(eth_dev);
+	rte_eth_dev_release_port(eth_dev);
+	return 0;
+}
+
+static struct rte_vdev_driver iavf_client_driver = {
+	.probe = avf_client_pmd_probe,
+	.remove = avf_client_pmd_remove,
+};
+
+RTE_PMD_REGISTER_VDEV(net_iavf_client, iavf_client_driver);
+RTE_PMD_REGISTER_ALIAS(net_iavf_client, iavf_client);
+RTE_PMD_REGISTER_PARAM_STRING(net_iavf_client,
+	"path=<path>");
diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
index 7e3c26a94e..6b5e47adf2 100644
--- a/drivers/net/iavf/iavf_ethdev.c
+++ b/drivers/net/iavf/iavf_ethdev.c
@@ -154,7 +154,7 @@ static const struct rte_iavf_xstats_name_off rte_iavf_stats_strings[] = {
 #define IAVF_NB_XSTATS (sizeof(rte_iavf_stats_strings) / \
 		sizeof(rte_iavf_stats_strings[0]))
 
-static const struct eth_dev_ops iavf_eth_dev_ops = {
+const struct eth_dev_ops iavf_eth_dev_ops = {
 	.dev_configure              = iavf_dev_configure,
 	.dev_start                  = iavf_dev_start,
 	.dev_stop                   = iavf_dev_stop,
@@ -1780,7 +1780,7 @@ iavf_init_proto_xtr(struct rte_eth_dev *dev)
 	}
 }
 
-static int
+int
 iavf_init_vf(struct rte_eth_dev *dev)
 {
 	int err, bufsz;
@@ -1789,12 +1789,6 @@ iavf_init_vf(struct rte_eth_dev *dev)
 	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
 
-	err = iavf_parse_devargs(dev);
-	if (err) {
-		PMD_INIT_LOG(ERR, "Failed to parse devargs");
-		goto err;
-	}
-
 	err = iavf_set_mac_type(hw);
 	if (err) {
 		PMD_INIT_LOG(ERR, "set_mac_type failed: %d", err);
@@ -1891,16 +1885,6 @@ iavf_enable_irq0(struct iavf_hw *hw)
 	IAVF_WRITE_FLUSH(hw);
 }
 
-static inline void
-iavf_disable_irq0(struct iavf_hw *hw)
-{
-	/* Disable all interrupt types */
-	IAVF_WRITE_REG(hw, IAVF_VFINT_ICR0_ENA1, 0);
-	IAVF_WRITE_REG(hw, IAVF_VFINT_DYN_CTL01,
-		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
-	IAVF_WRITE_FLUSH(hw);
-}
-
 static void
 iavf_dev_interrupt_handler(void *param)
 {
@@ -1986,6 +1970,12 @@ iavf_dev_init(struct rte_eth_dev *eth_dev)
 	adapter->eth_dev = eth_dev;
 	adapter->stopped = 1;
 
+	ret  = iavf_parse_devargs(eth_dev);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "Failed to parse devargs");
+		return ret;
+	}
+
 	if (iavf_init_vf(eth_dev) != 0) {
 		PMD_INIT_LOG(ERR, "Init vf failed");
 		return -1;
diff --git a/drivers/net/iavf/iavf_rxtx.c b/drivers/net/iavf/iavf_rxtx.c
index 21d508b3f4..d8192f3675 100644
--- a/drivers/net/iavf/iavf_rxtx.c
+++ b/drivers/net/iavf/iavf_rxtx.c
@@ -24,6 +24,9 @@
 #include <rte_ip.h>
 #include <rte_net.h>
 #include <rte_vect.h>
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+#include <vfio_user/vfio_user_pci.h>
+#endif
 
 #include "iavf.h"
 #include "iavf_rxtx.h"
@@ -595,7 +598,15 @@ iavf_dev_rx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_idx,
 	reset_rx_queue(rxq);
 	rxq->q_set = true;
 	dev->data->rx_queues[queue_idx] = rxq;
-	rxq->qrx_tail = hw->hw_addr + IAVF_QRX_TAIL1(rxq->queue_id);
+
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+	if (hw->bus.type == iavf_bus_type_vfio_user)
+		rxq->qrx_tail = client_vfio_user_get_bar_addr(
+				(struct vfio_device *)hw->hw_addr, 0,
+				IAVF_QRX_TAIL1(rxq->queue_id), 4);
+	else
+#endif
+		rxq->qrx_tail = hw->hw_addr + IAVF_QRX_TAIL1(rxq->queue_id);
 	rxq->ops = &def_rxq_ops;
 
 	if (check_rx_bulk_allow(rxq) == true) {
@@ -705,7 +716,15 @@ iavf_dev_tx_queue_setup(struct rte_eth_dev *dev,
 	reset_tx_queue(txq);
 	txq->q_set = true;
 	dev->data->tx_queues[queue_idx] = txq;
-	txq->qtx_tail = hw->hw_addr + IAVF_QTX_TAIL1(queue_idx);
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+	if (hw->bus.type == iavf_bus_type_vfio_user)
+		txq->qtx_tail = client_vfio_user_get_bar_addr(
+			(struct vfio_device *)hw->hw_addr, 0,
+			IAVF_QTX_TAIL1(queue_idx), 4);
+	else
+#endif
+		txq->qtx_tail = hw->hw_addr + IAVF_QTX_TAIL1(queue_idx);
+
 	txq->ops = &def_txq_ops;
 
 	if (check_tx_vec_allow(txq) == false) {
diff --git a/drivers/net/iavf/meson.build b/drivers/net/iavf/meson.build
index 26c02c4401..580307c462 100644
--- a/drivers/net/iavf/meson.build
+++ b/drivers/net/iavf/meson.build
@@ -13,6 +13,7 @@ sources = files(
 	'iavf_generic_flow.c',
 	'iavf_fdir.c',
 	'iavf_hash.c',
+	'iavf_client_ethdev.c',
 )
 
 if arch_subdir == 'x86'
-- 
2.21.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [dpdk-dev] [PATCH v1 2/2] net/iavf: introduce iavf driver on vfio-user client
  2020-12-19 14:38 ` [dpdk-dev] [PATCH v1 2/2] net/iavf: introduce iavf driver " Jingjing Wu
@ 2020-12-22  8:14   ` Xia, Chenbo
  0 siblings, 0 replies; 18+ messages in thread
From: Xia, Chenbo @ 2020-12-22  8:14 UTC (permalink / raw)
  To: Wu, Jingjing, dev; +Cc: Xing, Beilei, Lu, Xiuchun

Hi Jingjing,

> -----Original Message-----
> From: Wu, Jingjing <jingjing.wu@intel.com>
> Sent: Saturday, December 19, 2020 10:38 PM
> To: dev@dpdk.org
> Cc: Wu, Jingjing <jingjing.wu@intel.com>; Xing, Beilei <beilei.xing@intel.com>;
> Xia, Chenbo <chenbo.xia@intel.com>; Lu, Xiuchun <xiuchun.lu@intel.com>
> Subject: [PATCH v1 2/2] net/iavf: introduce iavf driver on vfio-user client
> 
> This patch add a new net driver based on vdev abstraction,
> i.e. iavf_client_ethdev.c. It is using common iavf functions
> to talk with Emulated pci interfaces based on vfio-user.
> 
>       ----------------------
>       | ------------------ |
>       | |  iavf driver   | |----> (iavf_client_ethdev.c)
>       | ------------------ |
>       | ------------------ |
>       | | device emulate | |
>       | | vfio-user adapt| |
>       | ------------------ |
>       ----------------------
>                 |
>                 |
>       ----------------------
>       |      vfio-user     |
>       |       client       |
>       ----------------------
> 
> Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
> ---
>  drivers/common/iavf/iavf_prototype.h  |   1 +
>  drivers/common/iavf/version.map       |   1 +
>  drivers/net/iavf/iavf.h               |  18 +-
>  drivers/net/iavf/iavf_client_ethdev.c | 298 ++++++++++++++++++++++++++
>  drivers/net/iavf/iavf_ethdev.c        |  26 +--
>  drivers/net/iavf/iavf_rxtx.c          |  23 +-
>  drivers/net/iavf/meson.build          |   1 +
>  7 files changed, 347 insertions(+), 21 deletions(-)
>  create mode 100644 drivers/net/iavf/iavf_client_ethdev.c
> 
> diff --git a/drivers/common/iavf/iavf_prototype.h
> b/drivers/common/iavf/iavf_prototype.h
> index f34e77db0f..3998d26dc0 100644
> --- a/drivers/common/iavf/iavf_prototype.h
> +++ b/drivers/common/iavf/iavf_prototype.h
> @@ -83,6 +83,7 @@ void iavf_destroy_spinlock(struct iavf_spinlock *sp);
>  __rte_internal
>  void iavf_vf_parse_hw_config(struct iavf_hw *hw,
>  			     struct virtchnl_vf_resource *msg);
> +__rte_internal
>  enum iavf_status iavf_vf_reset(struct iavf_hw *hw);
>  __rte_internal
>  enum iavf_status iavf_aq_send_msg_to_pf(struct iavf_hw *hw,
> diff --git a/drivers/common/iavf/version.map b/drivers/common/iavf/version.map
> index 8808779ab7..4dc2d42196 100644
> --- a/drivers/common/iavf/version.map
> +++ b/drivers/common/iavf/version.map
> @@ -7,6 +7,7 @@ INTERNAL {
>  	iavf_set_mac_type;
>  	iavf_shutdown_adminq;
>  	iavf_vf_parse_hw_config;
> +	iavf_vf_reset;
>  	client_vfio_user_setup;
>  	client_vfio_user_get_bar_addr;
>  	iavf_write_addr;
> diff --git a/drivers/net/iavf/iavf.h b/drivers/net/iavf/iavf.h
> index 6d5912d8c1..c34f971721 100644
> --- a/drivers/net/iavf/iavf.h
> +++ b/drivers/net/iavf/iavf.h
> @@ -195,7 +195,10 @@ struct iavf_adapter {
>  	struct iavf_hw hw;
>  	struct rte_eth_dev *eth_dev;
>  	struct iavf_info vf;
> -
> +#ifdef RTE_LIBRTE_IAVF_CLIENT
> +	/* used for avf_client driver */
> +	struct vfio_device *user_dev;
> +#endif
>  	bool rx_bulk_alloc_allowed;
>  	/* For vector PMD */
>  	bool rx_vec_allowed;
> @@ -231,6 +234,16 @@ iavf_init_adminq_parameter(struct iavf_hw *hw)
>  	hw->aq.asq_buf_size = IAVF_AQ_BUF_SZ;
>  }
> 
> +static inline void
> +iavf_disable_irq0(struct iavf_hw *hw)
> +{
> +	/* Disable all interrupt types */
> +	IAVF_WRITE_REG(hw, IAVF_VFINT_ICR0_ENA1, 0);
> +	IAVF_WRITE_REG(hw, IAVF_VFINT_DYN_CTL01,
> +		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
> +	IAVF_WRITE_FLUSH(hw);
> +}
> +
>  static inline uint16_t
>  iavf_calc_itr_interval(int16_t interval)
>  {
> @@ -284,6 +297,9 @@ _atomic_set_cmd(struct iavf_info *vf, enum virtchnl_ops
> ops)
>  	return !ret;
>  }
> 
> +extern const struct eth_dev_ops iavf_eth_dev_ops;
> +
> +int iavf_init_vf(struct rte_eth_dev *dev);
>  int iavf_check_api_version(struct iavf_adapter *adapter);
>  int iavf_get_vf_resource(struct iavf_adapter *adapter);
>  void iavf_handle_virtchnl_msg(struct rte_eth_dev *dev);
> diff --git a/drivers/net/iavf/iavf_client_ethdev.c
> b/drivers/net/iavf/iavf_client_ethdev.c
> new file mode 100644
> index 0000000000..03f759c761
> --- /dev/null
> +++ b/drivers/net/iavf/iavf_client_ethdev.c
> @@ -0,0 +1,298 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2017 Intel Corporation
> + */
> +
> +#include <errno.h>
> +#include <stdint.h>
> +#include <string.h>
> +
> +#include <rte_common.h>
> +#include <rte_ether.h>
> +#include <rte_ethdev_driver.h>
> +#include <rte_ethdev_vdev.h>
> +#include <rte_alarm.h>
> +#include <rte_bus_vdev.h>
> +#include <rte_malloc.h>
> +#include <vfio_user/vfio_user_pci.h>
> +
> +#include "iavf.h"
> +#include "iavf_rxtx.h"
> +
> +static int iavf_client_dev_close(struct rte_eth_dev *dev);
> +static int iavf_client_dev_reset(struct rte_eth_dev *dev);
> +
> +/* set iavf_client_dev_ops to iavf's by default */
> +static struct eth_dev_ops iavf_client_eth_dev_ops;
> +
> +static const char *valid_args[] = {
> +#define AVF_CLIENT_ARG_PATH           "path"
> +	AVF_CLIENT_ARG_PATH,
> +	NULL
> +};
> +
> +/* set up vfio_device for iavf_client*/
> +static int
> +iavf_client_vfio_user_setup(struct rte_eth_dev *dev, const char *path)
> +{
> +	struct iavf_adapter *adapter =
> +		IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
> +	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(adapter);
> +	struct vfio_device *vfio_dev;
> +	int max_fds, i;
> +
> +	vfio_dev = client_vfio_user_setup(path, dev->device->numa_node);
> +	if (vfio_dev == NULL) {
> +		printf("Error to create vfio_device for iavf_client\n");
> +		return -1;
> +	}
> +	hw->bus.type = iavf_bus_type_vfio_user;
> +
> +	/* Use hw_addr to record dev ptr */
> +	hw->hw_addr = (uint8_t *)vfio_dev;
> +
> +	hw->back = IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
> +
> +	if (!dev->intr_handle) {
> +		dev->intr_handle = malloc(sizeof(*dev->intr_handle));
> +		if (!dev->intr_handle) {
> +			PMD_INIT_LOG(ERR, "fail to allocate intr_handle");
> +			return -1;
> +		}
> +		memset(dev->intr_handle, 0, sizeof(*dev->intr_handle));
> +	}
> +
> +	max_fds = RTE_MIN(RTE_MAX_RXTX_INTR_VEC_ID, adapter->vf.num_queue_pairs);
> +
> +	/* FD for control has been enabled */
> +	dev->intr_handle->fd = -1;
> +	dev->intr_handle->type = RTE_INTR_HANDLE_VDEV;
> +	dev->intr_handle->max_intr = max_fds + 1;
> +	dev->intr_handle->nb_efd = max_fds;
> +	for (i = 0; i < max_fds; ++i)
> +		dev->intr_handle->efds[i] = vfio_dev->irqfds[i];
> +	dev->intr_handle->efd_counter_size = 0;
> +
> +	return 0;
> +}
> +
> +
> +static inline void
> +avf_client_init_eth_ops(void)
> +{
> +	iavf_client_eth_dev_ops = iavf_eth_dev_ops;
> +	/* keep other unchanged */
> +	iavf_client_eth_dev_ops.dev_close  = iavf_client_dev_close,
> +	iavf_client_eth_dev_ops.dev_reset  = iavf_client_dev_reset,
> +	iavf_client_eth_dev_ops.dev_supported_ptypes_get   = NULL;
> +	iavf_client_eth_dev_ops.reta_update                = NULL;
> +	iavf_client_eth_dev_ops.reta_query                 = NULL;
> +	iavf_client_eth_dev_ops.rss_hash_update            = NULL;
> +	iavf_client_eth_dev_ops.rss_hash_conf_get          = NULL;
> +	iavf_client_eth_dev_ops.rx_queue_intr_enable       = NULL;
> +	iavf_client_eth_dev_ops.rx_queue_intr_disable      = NULL;
> +}
> +
> +#define IAVF_CLIENT_ALARM_INTERVAL 50000 /* us */
> +static void
> +iavf_client_dev_alarm_handler(void *param)
> +{
> +	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
> +
> +	iavf_handle_virtchnl_msg(dev);
> +
> +	rte_eal_alarm_set(IAVF_CLIENT_ALARM_INTERVAL,
> +			  iavf_client_dev_alarm_handler, dev);
> +}
> +
> +/* init ethdev for the avf client device*/
> +static int
> +iavf_client_eth_init(struct rte_eth_dev *eth_dev)
> +{
> +	struct iavf_adapter *adapter =
> +		IAVF_DEV_PRIVATE_TO_ADAPTER(eth_dev->data->dev_private);
> +	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(adapter);
> +
> +	/* update eth_dev_op by assigning ops func pointer */
> +	avf_client_init_eth_ops();
> +	eth_dev->dev_ops = (const struct eth_dev_ops
> *)(&iavf_client_eth_dev_ops);
> +
> +	eth_dev->rx_pkt_burst = &iavf_recv_pkts;
> +	eth_dev->tx_pkt_burst = &iavf_xmit_pkts;
> +	eth_dev->tx_pkt_prepare = &iavf_prep_pkts;
> +
> +	hw->back = IAVF_DEV_PRIVATE_TO_ADAPTER(eth_dev->data->dev_private);
> +	adapter->eth_dev = eth_dev;
> +	adapter->stopped = 1;
> +

I think the ptype table (adapter->ptype_tbl) should be set during init.

Maybe using iavf_get_default_ptype_table().

Thanks!
Chenbo

> +	if (iavf_init_vf(eth_dev) != 0) {
> +		PMD_INIT_LOG(ERR, "Init vf failed");
> +		return -1;
> +	}
> +
> +	/* copy mac addr */
> +	eth_dev->data->mac_addrs = rte_zmalloc(
> +			"iavf_client_mac",
> +			RTE_ETHER_ADDR_LEN * IAVF_NUM_MACADDR_MAX, 0);
> +	if (!eth_dev->data->mac_addrs) {
> +		PMD_INIT_LOG(ERR, "Failed to allocate %d bytes needed to"
> +			     " store MAC addresses",
> +			     RTE_ETHER_ADDR_LEN * IAVF_NUM_MACADDR_MAX);
> +		return -ENOMEM;
> +	}
> +	/* If the MAC address is not configured by host,
> +	 * generate a random one.
> +	 */
> +	if (!rte_is_valid_assigned_ether_addr(
> +			(struct rte_ether_addr *)hw->mac.addr))
> +		rte_eth_random_addr(hw->mac.addr);
> +	rte_ether_addr_copy((struct rte_ether_addr *)hw->mac.addr,
> +			&eth_dev->data->mac_addrs[0]);
> +
> +	rte_eal_alarm_set(IAVF_CLIENT_ALARM_INTERVAL,
> +			  iavf_client_dev_alarm_handler, eth_dev);
> +	return 0;
> +}
> +
> +static int
> +iavf_client_dev_reset(struct rte_eth_dev *dev)
> +{
> +	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
> +	int ret;
> +
> +	rte_eal_alarm_cancel(iavf_client_dev_alarm_handler, dev);
> +
> +	iavf_shutdown_adminq(hw);
> +	ret = iavf_init_vf(dev);
> +
> +	/* send reset msg to PF */
> +	iavf_vf_reset(hw);
> +	rte_eal_alarm_set(IAVF_CLIENT_ALARM_INTERVAL,
> +			  iavf_client_dev_alarm_handler, dev);
> +
> +	return ret;
> +}
> +
> +static int
> +iavf_client_dev_close(struct rte_eth_dev *dev)
> +{
> +	struct iavf_adapter *adapter =
> +		IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
> +	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
> +	struct rte_intr_handle *intr_handle = dev->intr_handle;
> +
> +	if (!adapter->stopped) {
> +		iavf_stop_queues(dev);
> +
> +		if (intr_handle) {
> +			/* Disable the interrupt for Rx */
> +			rte_intr_efd_disable(intr_handle);
> +			/* Rx interrupt vector mapping free */
> +			if (intr_handle->intr_vec) {
> +				rte_free(intr_handle->intr_vec);
> +				intr_handle->intr_vec = NULL;
> +			}
> +		}
> +		/* Remove all mac addrs */
> +		iavf_add_del_all_mac_addr(adapter, false);
> +		adapter->stopped = 1;
> +	}
> +	iavf_shutdown_adminq(hw);
> +	iavf_disable_irq0(hw);
> +	rte_eal_alarm_cancel(iavf_client_dev_alarm_handler, dev);
> +
> +	return 0;
> +}
> +
> +static int
> +iavf_client_get_string_arg(const char *key __rte_unused,
> +	       const char *value, void *extra_args)
> +{
> +	if (!value || !extra_args)
> +		return -EINVAL;
> +
> +	*(char **)extra_args = strdup(value);
> +
> +	if (!*(char **)extra_args)
> +		return -ENOMEM;
> +
> +	return 0;
> +}
> +
> +static int
> +avf_client_pmd_probe(struct rte_vdev_device *vdev)
> +{
> +	struct rte_kvargs *kvlist = NULL;
> +	struct rte_eth_dev *eth_dev;
> +	struct iavf_adapter *adapter;
> +	char *path = NULL;
> +	int ret;
> +
> +	kvlist = rte_kvargs_parse(rte_vdev_device_args(vdev), valid_args);
> +	if (!kvlist) {
> +		PMD_INIT_LOG(ERR, "error when parsing param");
> +		return -EINVAL;
> +	}
> +
> +	if (rte_kvargs_count(kvlist, AVF_CLIENT_ARG_PATH) == 1) {
> +		if (rte_kvargs_process(kvlist, AVF_CLIENT_ARG_PATH,
> +				       &iavf_client_get_string_arg, &path) < 0) {
> +			PMD_INIT_LOG(ERR, "error to parse %s",
> +				     AVF_CLIENT_ARG_PATH);
> +			return -EINVAL;
> +		}
> +	} else {
> +		PMD_INIT_LOG(ERR, "arg %s is mandatory for virtio_user",
> +			     AVF_CLIENT_ARG_PATH);
> +		return -EINVAL;
> +	}
> +
> +	eth_dev = rte_eth_vdev_allocate(vdev, sizeof(*adapter));
> +
> +	ret = iavf_client_vfio_user_setup(eth_dev, path);
> +	if (ret) {
> +		goto err;
> +	}
> +
> +	ret = iavf_client_eth_init(eth_dev);
> +	if (ret) {
> +		goto err;
> +	}
> +
> +	rte_eth_dev_probing_finish(eth_dev);
> +	rte_kvargs_free(kvlist);
> +
> +	return 0;
> +err:
> +	rte_eth_dev_release_port(eth_dev);
> +	rte_kvargs_free(kvlist);
> +	return ret;
> +}
> +
> +
> +static int
> +avf_client_pmd_remove(struct rte_vdev_device *vdev)
> +{
> +	struct rte_eth_dev *eth_dev = NULL;
> +
> +	if (vdev == NULL)
> +		return -1;
> +
> +	/* find the ethdev entry */
> +	eth_dev = rte_eth_dev_allocated(rte_vdev_device_name(vdev));
> +	if (eth_dev == NULL)
> +		return 0;
> +
> +	iavf_client_dev_close(eth_dev);
> +	rte_eth_dev_release_port(eth_dev);
> +	return 0;
> +}
> +
> +static struct rte_vdev_driver iavf_client_driver = {
> +	.probe = avf_client_pmd_probe,
> +	.remove = avf_client_pmd_remove,
> +};
> +
> +RTE_PMD_REGISTER_VDEV(net_iavf_client, iavf_client_driver);
> +RTE_PMD_REGISTER_ALIAS(net_iavf_client, iavf_client);
> +RTE_PMD_REGISTER_PARAM_STRING(net_iavf_client,
> +	"path=<path>");
> diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
> index 7e3c26a94e..6b5e47adf2 100644
> --- a/drivers/net/iavf/iavf_ethdev.c
> +++ b/drivers/net/iavf/iavf_ethdev.c
> @@ -154,7 +154,7 @@ static const struct rte_iavf_xstats_name_off
> rte_iavf_stats_strings[] = {
>  #define IAVF_NB_XSTATS (sizeof(rte_iavf_stats_strings) / \
>  		sizeof(rte_iavf_stats_strings[0]))
> 
> -static const struct eth_dev_ops iavf_eth_dev_ops = {
> +const struct eth_dev_ops iavf_eth_dev_ops = {
>  	.dev_configure              = iavf_dev_configure,
>  	.dev_start                  = iavf_dev_start,
>  	.dev_stop                   = iavf_dev_stop,
> @@ -1780,7 +1780,7 @@ iavf_init_proto_xtr(struct rte_eth_dev *dev)
>  	}
>  }
> 
> -static int
> +int
>  iavf_init_vf(struct rte_eth_dev *dev)
>  {
>  	int err, bufsz;
> @@ -1789,12 +1789,6 @@ iavf_init_vf(struct rte_eth_dev *dev)
>  	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
>  	struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
> 
> -	err = iavf_parse_devargs(dev);
> -	if (err) {
> -		PMD_INIT_LOG(ERR, "Failed to parse devargs");
> -		goto err;
> -	}
> -
>  	err = iavf_set_mac_type(hw);
>  	if (err) {
>  		PMD_INIT_LOG(ERR, "set_mac_type failed: %d", err);
> @@ -1891,16 +1885,6 @@ iavf_enable_irq0(struct iavf_hw *hw)
>  	IAVF_WRITE_FLUSH(hw);
>  }
> 
> -static inline void
> -iavf_disable_irq0(struct iavf_hw *hw)
> -{
> -	/* Disable all interrupt types */
> -	IAVF_WRITE_REG(hw, IAVF_VFINT_ICR0_ENA1, 0);
> -	IAVF_WRITE_REG(hw, IAVF_VFINT_DYN_CTL01,
> -		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
> -	IAVF_WRITE_FLUSH(hw);
> -}
> -
>  static void
>  iavf_dev_interrupt_handler(void *param)
>  {
> @@ -1986,6 +1970,12 @@ iavf_dev_init(struct rte_eth_dev *eth_dev)
>  	adapter->eth_dev = eth_dev;
>  	adapter->stopped = 1;
> 
> +	ret  = iavf_parse_devargs(eth_dev);
> +	if (ret) {
> +		PMD_INIT_LOG(ERR, "Failed to parse devargs");
> +		return ret;
> +	}
> +
>  	if (iavf_init_vf(eth_dev) != 0) {
>  		PMD_INIT_LOG(ERR, "Init vf failed");
>  		return -1;
> diff --git a/drivers/net/iavf/iavf_rxtx.c b/drivers/net/iavf/iavf_rxtx.c
> index 21d508b3f4..d8192f3675 100644
> --- a/drivers/net/iavf/iavf_rxtx.c
> +++ b/drivers/net/iavf/iavf_rxtx.c
> @@ -24,6 +24,9 @@
>  #include <rte_ip.h>
>  #include <rte_net.h>
>  #include <rte_vect.h>
> +#ifdef RTE_LIBRTE_IAVF_CLIENT
> +#include <vfio_user/vfio_user_pci.h>
> +#endif
> 
>  #include "iavf.h"
>  #include "iavf_rxtx.h"
> @@ -595,7 +598,15 @@ iavf_dev_rx_queue_setup(struct rte_eth_dev *dev, uint16_t
> queue_idx,
>  	reset_rx_queue(rxq);
>  	rxq->q_set = true;
>  	dev->data->rx_queues[queue_idx] = rxq;
> -	rxq->qrx_tail = hw->hw_addr + IAVF_QRX_TAIL1(rxq->queue_id);
> +
> +#ifdef RTE_LIBRTE_IAVF_CLIENT
> +	if (hw->bus.type == iavf_bus_type_vfio_user)
> +		rxq->qrx_tail = client_vfio_user_get_bar_addr(
> +				(struct vfio_device *)hw->hw_addr, 0,
> +				IAVF_QRX_TAIL1(rxq->queue_id), 4);
> +	else
> +#endif
> +		rxq->qrx_tail = hw->hw_addr + IAVF_QRX_TAIL1(rxq->queue_id);
>  	rxq->ops = &def_rxq_ops;
> 
>  	if (check_rx_bulk_allow(rxq) == true) {
> @@ -705,7 +716,15 @@ iavf_dev_tx_queue_setup(struct rte_eth_dev *dev,
>  	reset_tx_queue(txq);
>  	txq->q_set = true;
>  	dev->data->tx_queues[queue_idx] = txq;
> -	txq->qtx_tail = hw->hw_addr + IAVF_QTX_TAIL1(queue_idx);
> +#ifdef RTE_LIBRTE_IAVF_CLIENT
> +	if (hw->bus.type == iavf_bus_type_vfio_user)
> +		txq->qtx_tail = client_vfio_user_get_bar_addr(
> +			(struct vfio_device *)hw->hw_addr, 0,
> +			IAVF_QTX_TAIL1(queue_idx), 4);
> +	else
> +#endif
> +		txq->qtx_tail = hw->hw_addr + IAVF_QTX_TAIL1(queue_idx);
> +
>  	txq->ops = &def_txq_ops;
> 
>  	if (check_tx_vec_allow(txq) == false) {
> diff --git a/drivers/net/iavf/meson.build b/drivers/net/iavf/meson.build
> index 26c02c4401..580307c462 100644
> --- a/drivers/net/iavf/meson.build
> +++ b/drivers/net/iavf/meson.build
> @@ -13,6 +13,7 @@ sources = files(
>  	'iavf_generic_flow.c',
>  	'iavf_fdir.c',
>  	'iavf_hash.c',
> +	'iavf_client_ethdev.c',
>  )
> 
>  if arch_subdir == 'x86'
> --
> 2.21.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [dpdk-dev] [PATCH v2 0/4] introduce new iavf driver on vfio-user client
  2020-12-19 14:38 [dpdk-dev] [PATCH v1 0/2] introduce new iavf driver on vfio-user client Jingjing Wu
  2020-12-19 14:38 ` [dpdk-dev] [PATCH v1 1/2] common/iavf: emulated pci interfaces " Jingjing Wu
  2020-12-19 14:38 ` [dpdk-dev] [PATCH v1 2/2] net/iavf: introduce iavf driver " Jingjing Wu
@ 2021-01-07  7:45 ` Jingjing Wu
  2021-01-07  7:45   ` [dpdk-dev] [PATCH v2 1/4] net/iavf_client: introduce " Jingjing Wu
                     ` (4 more replies)
  2 siblings, 5 replies; 18+ messages in thread
From: Jingjing Wu @ 2021-01-07  7:45 UTC (permalink / raw)
  To: dev; +Cc: jingjing.wu, beilei.xing, chenbo.xia, xiuchun.lu

This series introduces a new net virtual device called iavf_client which
is based on vfio-user client interface. Through vfio-user client interface,
PCI liked device could be used similar as Intel® Ethernet Adaptive Virtual
Function specification.
The code to enable iavf_client mainly contains two parts:
 - Emulated pci interfaces for vfio-user client which is located
   in common/iavf/vfio_user/.
 - A new net driver base on vdev abstraction, i.e. iavf_client_ethdev.c

      ----------------------
      | ------------------ |
      | |  iavf driver   | |----> (iavf_client_ethdev.c)
      | ------------------ |
      | ------------------ |
      | | device emulate | |------>(common/iavf/vfio_user/)
      | ------------------ |
      ----------------------
                |
                |  
      ----------------------
      |      vfio-user     |
      |       client       |
      ----------------------



This driver can be used to test the device emulation framework
mentioned in:
  [RFC 0/2] Add device emulation support in DPDK
  http://patchwork.dpdk.org/cover/75549/

                    +------------------------------------------------------+
                    |   +---------------+      +---------------+           |
                    |   | iavf_emudev   |      | iavfbe_ethdev |           |
                    |   |    driver     |      |     driver    |           |
                    |   +---------------+      +---------------+           |
                    |           |                       |                  |
                    | ------------------------------------------- VDEV BUS |
                    |           |                       |                  |
                    |   +---------------+       +--------------+           |
+--------------+    |   | vdev:         |       | vdev:        |           |
| +----------+ |    |   | /path/to/vfio |       |iavf_emudev_# |           |
| |   iavf   | |    |   +---------------+       +--------------+           |
| |  client  |      |           |                                          |
| +----------+ |    |           |                                          |
| +----------+ |    |      +----------+                                    |
| | vfio-user| |    |      | vfio-user|                                    |
| | client   | |<---|----->| server   |                                    |
| +----------+ |    |      +----------+                                    |
| QEMU/DPDK    |    | DPDK                                                 |
+--------------+    +------------------------------------------------------+

It can be launched together with patch series for the testing:
  [0/9] Introduce vfio-user library:
  http://patchwork.dpdk.org/cover/85389/
  [0/8] Introduce emudev library and iavf emudev driver
  http://patchwork.dpdk.org/cover/85488/
  [0/6] Introduce iavf backend driver
  http://patchwork.dpdk.org/cover/86084/

This series depends on patch serieses:
  [0/9] Introduce vfio-user library:
  http://patchwork.dpdk.org/cover/85389/

v2:
 - Enable interrupt for control queue
 - Enable interrupt for rx queue
 - Rename some Macros
 - Fix resource release when close
 - Fix ptype_tbl assignment
 - Fix typo

Jingjing Wu (4):
  net/iavf_client: introduce iavf driver on vfio-user client
  net/iavf_client: enable interrupt on control queue
  net/iavf_client: client to enable intr_handle for rx_irq
  net/iavf: fix vector mapping with queue

 drivers/common/iavf/iavf_prototype.h  |   1 +
 drivers/common/iavf/version.map       |   1 +
 drivers/net/iavf/iavf.h               |  37 ++-
 drivers/net/iavf/iavf_client_ethdev.c | 404 ++++++++++++++++++++++++++
 drivers/net/iavf/iavf_ethdev.c        |  55 +---
 drivers/net/iavf/iavf_rxtx.c          |  23 +-
 drivers/net/iavf/meson.build          |   1 +
 7 files changed, 477 insertions(+), 45 deletions(-)
 create mode 100644 drivers/net/iavf/iavf_client_ethdev.c

-- 
2.21.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [dpdk-dev] [PATCH v2 1/4] net/iavf_client: introduce iavf driver on vfio-user client
  2021-01-07  7:45 ` [dpdk-dev] [PATCH v2 0/4] introduce new " Jingjing Wu
@ 2021-01-07  7:45   ` Jingjing Wu
  2021-01-07  7:45   ` [dpdk-dev] [PATCH v2 2/4] net/iavf_client: enable interrupt on control queue Jingjing Wu
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 18+ messages in thread
From: Jingjing Wu @ 2021-01-07  7:45 UTC (permalink / raw)
  To: dev; +Cc: jingjing.wu, beilei.xing, chenbo.xia, xiuchun.lu

This patch add a new net driver based on vdev abstraction,
i.e. iavf_client_ethdev.c. It is using common iavf functions
to talk with Emulated pci interfaces based on vfio-user.

      ----------------------
      | ------------------ |
      | |  iavf driver   | |----> (iavf_client_ethdev.c)
      | ------------------ |
      | ------------------ |
      | | device emulate | |
      | | vfio-user adapt| |
      | ------------------ |
      ----------------------
                |
                |
      ----------------------
      |      vfio-user     |
      |       client       |
      ----------------------

Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
---
 drivers/common/iavf/iavf_prototype.h  |   1 +
 drivers/common/iavf/version.map       |   1 +
 drivers/net/iavf/iavf.h               |  18 +-
 drivers/net/iavf/iavf_client_ethdev.c | 290 ++++++++++++++++++++++++++
 drivers/net/iavf/iavf_ethdev.c        |  26 +--
 drivers/net/iavf/iavf_rxtx.c          |  23 +-
 drivers/net/iavf/meson.build          |   1 +
 7 files changed, 339 insertions(+), 21 deletions(-)
 create mode 100644 drivers/net/iavf/iavf_client_ethdev.c

diff --git a/drivers/common/iavf/iavf_prototype.h b/drivers/common/iavf/iavf_prototype.h
index f34e77db0f..3998d26dc0 100644
--- a/drivers/common/iavf/iavf_prototype.h
+++ b/drivers/common/iavf/iavf_prototype.h
@@ -83,6 +83,7 @@ void iavf_destroy_spinlock(struct iavf_spinlock *sp);
 __rte_internal
 void iavf_vf_parse_hw_config(struct iavf_hw *hw,
 			     struct virtchnl_vf_resource *msg);
+__rte_internal
 enum iavf_status iavf_vf_reset(struct iavf_hw *hw);
 __rte_internal
 enum iavf_status iavf_aq_send_msg_to_pf(struct iavf_hw *hw,
diff --git a/drivers/common/iavf/version.map b/drivers/common/iavf/version.map
index 883d919487..23c3577b3e 100644
--- a/drivers/common/iavf/version.map
+++ b/drivers/common/iavf/version.map
@@ -7,6 +7,7 @@ INTERNAL {
 	iavf_set_mac_type;
 	iavf_shutdown_adminq;
 	iavf_vf_parse_hw_config;
+	iavf_vf_reset;
 	client_vfio_user_setup;
 	client_vfio_user_release;
 	client_vfio_user_get_bar_addr;
diff --git a/drivers/net/iavf/iavf.h b/drivers/net/iavf/iavf.h
index 6d5912d8c1..c34f971721 100644
--- a/drivers/net/iavf/iavf.h
+++ b/drivers/net/iavf/iavf.h
@@ -195,7 +195,10 @@ struct iavf_adapter {
 	struct iavf_hw hw;
 	struct rte_eth_dev *eth_dev;
 	struct iavf_info vf;
-
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+	/* used for avf_client driver */
+	struct vfio_device *user_dev;
+#endif
 	bool rx_bulk_alloc_allowed;
 	/* For vector PMD */
 	bool rx_vec_allowed;
@@ -231,6 +234,16 @@ iavf_init_adminq_parameter(struct iavf_hw *hw)
 	hw->aq.asq_buf_size = IAVF_AQ_BUF_SZ;
 }
 
+static inline void
+iavf_disable_irq0(struct iavf_hw *hw)
+{
+	/* Disable all interrupt types */
+	IAVF_WRITE_REG(hw, IAVF_VFINT_ICR0_ENA1, 0);
+	IAVF_WRITE_REG(hw, IAVF_VFINT_DYN_CTL01,
+		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+	IAVF_WRITE_FLUSH(hw);
+}
+
 static inline uint16_t
 iavf_calc_itr_interval(int16_t interval)
 {
@@ -284,6 +297,9 @@ _atomic_set_cmd(struct iavf_info *vf, enum virtchnl_ops ops)
 	return !ret;
 }
 
+extern const struct eth_dev_ops iavf_eth_dev_ops;
+
+int iavf_init_vf(struct rte_eth_dev *dev);
 int iavf_check_api_version(struct iavf_adapter *adapter);
 int iavf_get_vf_resource(struct iavf_adapter *adapter);
 void iavf_handle_virtchnl_msg(struct rte_eth_dev *dev);
diff --git a/drivers/net/iavf/iavf_client_ethdev.c b/drivers/net/iavf/iavf_client_ethdev.c
new file mode 100644
index 0000000000..989f9d6062
--- /dev/null
+++ b/drivers/net/iavf/iavf_client_ethdev.c
@@ -0,0 +1,290 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_vdev.h>
+#include <rte_alarm.h>
+#include <rte_bus_vdev.h>
+#include <rte_malloc.h>
+#include <vfio_user/vfio_user_pci.h>
+
+#include "iavf.h"
+#include "iavf_rxtx.h"
+
+static int iavf_client_dev_close(struct rte_eth_dev *dev);
+static int iavf_client_dev_reset(struct rte_eth_dev *dev);
+
+/* set iavf_client_dev_ops to iavf's by default */
+static struct eth_dev_ops iavf_client_eth_dev_ops;
+
+static const char *valid_args[] = {
+#define AVF_CLIENT_ARG_PATH           "path"
+	AVF_CLIENT_ARG_PATH,
+	NULL
+};
+
+/* set up vfio_device for iavf_client*/
+static int
+iavf_client_vfio_user_setup(struct rte_eth_dev *dev, const char *path)
+{
+	struct iavf_adapter *adapter =
+		IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(adapter);
+	struct vfio_device *vfio_dev;
+
+	vfio_dev = client_vfio_user_setup(path, dev->device->numa_node);
+	if (vfio_dev == NULL) {
+		PMD_INIT_LOG(ERR, "Error to create vfio_device for iavf_client\n");
+		return -1;
+	}
+	hw->bus.type = iavf_bus_type_vfio_user;
+
+	/* Use hw_addr to record dev ptr */
+	hw->hw_addr = (uint8_t *)vfio_dev;
+
+	hw->back = IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+
+	if (!dev->intr_handle) {
+		dev->intr_handle = rte_zmalloc_socket("iavf_client_intr",
+				sizeof(*dev->intr_handle),
+				0, dev->device->numa_node);
+		if (!dev->intr_handle) {
+			PMD_INIT_LOG(ERR, "fail to allocate intr_handle");
+			return -1;
+		}
+
+	}
+
+	dev->intr_handle->fd = -1;
+	dev->intr_handle->type = RTE_INTR_HANDLE_VDEV;
+	dev->intr_handle->max_intr = 1;
+
+	return 0;
+}
+
+
+static inline void
+avf_client_init_eth_ops(void)
+{
+	iavf_client_eth_dev_ops = iavf_eth_dev_ops;
+	/* keep other unchanged */
+	iavf_client_eth_dev_ops.dev_close  = iavf_client_dev_close,
+	iavf_client_eth_dev_ops.dev_reset  = iavf_client_dev_reset,
+	iavf_client_eth_dev_ops.dev_supported_ptypes_get   = NULL;
+	iavf_client_eth_dev_ops.reta_update                = NULL;
+	iavf_client_eth_dev_ops.reta_query                 = NULL;
+	iavf_client_eth_dev_ops.rss_hash_update            = NULL;
+	iavf_client_eth_dev_ops.rss_hash_conf_get          = NULL;
+	iavf_client_eth_dev_ops.rx_queue_intr_enable       = NULL;
+	iavf_client_eth_dev_ops.rx_queue_intr_disable      = NULL;
+}
+
+#define IAVF_CLIENT_ALARM_INTERVAL 50000 /* us */
+static void
+iavf_client_dev_alarm_handler(void *param)
+{
+	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
+
+	iavf_handle_virtchnl_msg(dev);
+
+	rte_eal_alarm_set(IAVF_CLIENT_ALARM_INTERVAL,
+			  iavf_client_dev_alarm_handler, dev);
+}
+
+/* init ethdev for the avf client device*/
+static int
+iavf_client_eth_init(struct rte_eth_dev *eth_dev)
+{
+	struct iavf_adapter *adapter =
+		IAVF_DEV_PRIVATE_TO_ADAPTER(eth_dev->data->dev_private);
+	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(adapter);
+
+	/* update eth_dev_op by assigning ops func pointer */
+	avf_client_init_eth_ops();
+	eth_dev->dev_ops = (const struct eth_dev_ops *)(&iavf_client_eth_dev_ops);
+
+	eth_dev->rx_pkt_burst = &iavf_recv_pkts;
+	eth_dev->tx_pkt_burst = &iavf_xmit_pkts;
+	eth_dev->tx_pkt_prepare = &iavf_prep_pkts;
+
+	hw->back = IAVF_DEV_PRIVATE_TO_ADAPTER(eth_dev->data->dev_private);
+	adapter->eth_dev = eth_dev;
+	adapter->stopped = 1;
+
+	if (iavf_init_vf(eth_dev) != 0) {
+		PMD_INIT_LOG(ERR, "Init vf failed");
+		return -1;
+	}
+
+	/* set default ptype table */
+	adapter->ptype_tbl = iavf_get_default_ptype_table();
+
+	/* copy mac addr */
+	eth_dev->data->mac_addrs = rte_zmalloc(
+			"iavf_client_mac",
+			RTE_ETHER_ADDR_LEN * IAVF_NUM_MACADDR_MAX, 0);
+	if (!eth_dev->data->mac_addrs) {
+		PMD_INIT_LOG(ERR, "Failed to allocate %d bytes needed to"
+			     " store MAC addresses",
+			     RTE_ETHER_ADDR_LEN * IAVF_NUM_MACADDR_MAX);
+		return -ENOMEM;
+	}
+	/* If the MAC address is not configured by host,
+	 * generate a random one.
+	 */
+	if (!rte_is_valid_assigned_ether_addr(
+			(struct rte_ether_addr *)hw->mac.addr))
+		rte_eth_random_addr(hw->mac.addr);
+	rte_ether_addr_copy((struct rte_ether_addr *)hw->mac.addr,
+			&eth_dev->data->mac_addrs[0]);
+
+	rte_eal_alarm_set(IAVF_CLIENT_ALARM_INTERVAL,
+			  iavf_client_dev_alarm_handler, eth_dev);
+	return 0;
+}
+
+static int
+iavf_client_dev_reset(struct rte_eth_dev *dev)
+{
+	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int ret;
+
+	rte_eal_alarm_cancel(iavf_client_dev_alarm_handler, dev);
+
+	iavf_shutdown_adminq(hw);
+	ret = iavf_init_vf(dev);
+
+	/* send reset msg to PF */
+	iavf_vf_reset(hw);
+	rte_eal_alarm_set(IAVF_CLIENT_ALARM_INTERVAL,
+			  iavf_client_dev_alarm_handler, dev);
+
+	return ret;
+}
+
+static int
+iavf_client_dev_close(struct rte_eth_dev *dev)
+{
+	struct iavf_adapter *adapter =
+		IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	if (!adapter->stopped) {
+		iavf_stop_queues(dev);
+
+		if (dev->intr_handle) {
+			rte_free(dev->intr_handle);
+			dev->intr_handle = NULL;
+		}
+
+		/* Remove all mac addrs */
+		iavf_add_del_all_mac_addr(adapter, false);
+		adapter->stopped = 1;
+	}
+	iavf_shutdown_adminq(hw);
+	iavf_disable_irq0(hw);
+	rte_eal_alarm_cancel(iavf_client_dev_alarm_handler, dev);
+	client_vfio_user_release((struct vfio_device *)hw->hw_addr);
+	return 0;
+}
+
+static int
+iavf_client_get_string_arg(const char *key __rte_unused,
+	       const char *value, void *extra_args)
+{
+	if (!value || !extra_args)
+		return -EINVAL;
+
+	*(char **)extra_args = strdup(value);
+
+	if (!*(char **)extra_args)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int
+iavf_client_pmd_probe(struct rte_vdev_device *vdev)
+{
+	struct rte_kvargs *kvlist = NULL;
+	struct rte_eth_dev *eth_dev;
+	struct iavf_adapter *adapter;
+	char *path = NULL;
+	int ret;
+
+	kvlist = rte_kvargs_parse(rte_vdev_device_args(vdev), valid_args);
+	if (!kvlist) {
+		PMD_INIT_LOG(ERR, "error when parsing param");
+		return -EINVAL;
+	}
+
+	if (rte_kvargs_count(kvlist, AVF_CLIENT_ARG_PATH) == 1) {
+		if (rte_kvargs_process(kvlist, AVF_CLIENT_ARG_PATH,
+				       &iavf_client_get_string_arg, &path) < 0) {
+			PMD_INIT_LOG(ERR, "error to parse %s",
+				     AVF_CLIENT_ARG_PATH);
+			return -EINVAL;
+		}
+	} else {
+		PMD_INIT_LOG(ERR, "arg %s is mandatory for iavf_client",
+			     AVF_CLIENT_ARG_PATH);
+		return -EINVAL;
+	}
+
+	eth_dev = rte_eth_vdev_allocate(vdev, sizeof(*adapter));
+
+	ret = iavf_client_vfio_user_setup(eth_dev, path);
+	if (ret) {
+		goto err;
+	}
+
+	ret = iavf_client_eth_init(eth_dev);
+	if (ret) {
+		goto err;
+	}
+
+	rte_eth_dev_probing_finish(eth_dev);
+	rte_kvargs_free(kvlist);
+
+	return 0;
+err:
+	rte_eth_dev_release_port(eth_dev);
+	rte_kvargs_free(kvlist);
+	return ret;
+}
+
+
+static int
+iavf_client_pmd_remove(struct rte_vdev_device *vdev)
+{
+	struct rte_eth_dev *eth_dev = NULL;
+
+	if (vdev == NULL)
+		return -1;
+
+	/* find the ethdev entry */
+	eth_dev = rte_eth_dev_allocated(rte_vdev_device_name(vdev));
+	if (eth_dev == NULL)
+		return 0;
+
+	iavf_client_dev_close(eth_dev);
+	rte_eth_dev_release_port(eth_dev);
+	return 0;
+}
+
+static struct rte_vdev_driver iavf_client_driver = {
+	.probe = iavf_client_pmd_probe,
+	.remove = iavf_client_pmd_remove,
+};
+
+RTE_PMD_REGISTER_VDEV(net_iavf_client, iavf_client_driver);
+RTE_PMD_REGISTER_ALIAS(net_iavf_client, iavf_client);
+RTE_PMD_REGISTER_PARAM_STRING(net_iavf_client,
+	"path=<path>");
diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
index 7e3c26a94e..6b5e47adf2 100644
--- a/drivers/net/iavf/iavf_ethdev.c
+++ b/drivers/net/iavf/iavf_ethdev.c
@@ -154,7 +154,7 @@ static const struct rte_iavf_xstats_name_off rte_iavf_stats_strings[] = {
 #define IAVF_NB_XSTATS (sizeof(rte_iavf_stats_strings) / \
 		sizeof(rte_iavf_stats_strings[0]))
 
-static const struct eth_dev_ops iavf_eth_dev_ops = {
+const struct eth_dev_ops iavf_eth_dev_ops = {
 	.dev_configure              = iavf_dev_configure,
 	.dev_start                  = iavf_dev_start,
 	.dev_stop                   = iavf_dev_stop,
@@ -1780,7 +1780,7 @@ iavf_init_proto_xtr(struct rte_eth_dev *dev)
 	}
 }
 
-static int
+int
 iavf_init_vf(struct rte_eth_dev *dev)
 {
 	int err, bufsz;
@@ -1789,12 +1789,6 @@ iavf_init_vf(struct rte_eth_dev *dev)
 	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
 
-	err = iavf_parse_devargs(dev);
-	if (err) {
-		PMD_INIT_LOG(ERR, "Failed to parse devargs");
-		goto err;
-	}
-
 	err = iavf_set_mac_type(hw);
 	if (err) {
 		PMD_INIT_LOG(ERR, "set_mac_type failed: %d", err);
@@ -1891,16 +1885,6 @@ iavf_enable_irq0(struct iavf_hw *hw)
 	IAVF_WRITE_FLUSH(hw);
 }
 
-static inline void
-iavf_disable_irq0(struct iavf_hw *hw)
-{
-	/* Disable all interrupt types */
-	IAVF_WRITE_REG(hw, IAVF_VFINT_ICR0_ENA1, 0);
-	IAVF_WRITE_REG(hw, IAVF_VFINT_DYN_CTL01,
-		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
-	IAVF_WRITE_FLUSH(hw);
-}
-
 static void
 iavf_dev_interrupt_handler(void *param)
 {
@@ -1986,6 +1970,12 @@ iavf_dev_init(struct rte_eth_dev *eth_dev)
 	adapter->eth_dev = eth_dev;
 	adapter->stopped = 1;
 
+	ret  = iavf_parse_devargs(eth_dev);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "Failed to parse devargs");
+		return ret;
+	}
+
 	if (iavf_init_vf(eth_dev) != 0) {
 		PMD_INIT_LOG(ERR, "Init vf failed");
 		return -1;
diff --git a/drivers/net/iavf/iavf_rxtx.c b/drivers/net/iavf/iavf_rxtx.c
index 21d508b3f4..d8192f3675 100644
--- a/drivers/net/iavf/iavf_rxtx.c
+++ b/drivers/net/iavf/iavf_rxtx.c
@@ -24,6 +24,9 @@
 #include <rte_ip.h>
 #include <rte_net.h>
 #include <rte_vect.h>
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+#include <vfio_user/vfio_user_pci.h>
+#endif
 
 #include "iavf.h"
 #include "iavf_rxtx.h"
@@ -595,7 +598,15 @@ iavf_dev_rx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_idx,
 	reset_rx_queue(rxq);
 	rxq->q_set = true;
 	dev->data->rx_queues[queue_idx] = rxq;
-	rxq->qrx_tail = hw->hw_addr + IAVF_QRX_TAIL1(rxq->queue_id);
+
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+	if (hw->bus.type == iavf_bus_type_vfio_user)
+		rxq->qrx_tail = client_vfio_user_get_bar_addr(
+				(struct vfio_device *)hw->hw_addr, 0,
+				IAVF_QRX_TAIL1(rxq->queue_id), 4);
+	else
+#endif
+		rxq->qrx_tail = hw->hw_addr + IAVF_QRX_TAIL1(rxq->queue_id);
 	rxq->ops = &def_rxq_ops;
 
 	if (check_rx_bulk_allow(rxq) == true) {
@@ -705,7 +716,15 @@ iavf_dev_tx_queue_setup(struct rte_eth_dev *dev,
 	reset_tx_queue(txq);
 	txq->q_set = true;
 	dev->data->tx_queues[queue_idx] = txq;
-	txq->qtx_tail = hw->hw_addr + IAVF_QTX_TAIL1(queue_idx);
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+	if (hw->bus.type == iavf_bus_type_vfio_user)
+		txq->qtx_tail = client_vfio_user_get_bar_addr(
+			(struct vfio_device *)hw->hw_addr, 0,
+			IAVF_QTX_TAIL1(queue_idx), 4);
+	else
+#endif
+		txq->qtx_tail = hw->hw_addr + IAVF_QTX_TAIL1(queue_idx);
+
 	txq->ops = &def_txq_ops;
 
 	if (check_tx_vec_allow(txq) == false) {
diff --git a/drivers/net/iavf/meson.build b/drivers/net/iavf/meson.build
index 26c02c4401..580307c462 100644
--- a/drivers/net/iavf/meson.build
+++ b/drivers/net/iavf/meson.build
@@ -13,6 +13,7 @@ sources = files(
 	'iavf_generic_flow.c',
 	'iavf_fdir.c',
 	'iavf_hash.c',
+	'iavf_client_ethdev.c',
 )
 
 if arch_subdir == 'x86'
-- 
2.21.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [dpdk-dev] [PATCH v2 2/4] net/iavf_client: enable interrupt on control queue
  2021-01-07  7:45 ` [dpdk-dev] [PATCH v2 0/4] introduce new " Jingjing Wu
  2021-01-07  7:45   ` [dpdk-dev] [PATCH v2 1/4] net/iavf_client: introduce " Jingjing Wu
@ 2021-01-07  7:45   ` Jingjing Wu
  2021-01-07  7:45   ` [dpdk-dev] [PATCH v2 3/4] net/iavf_client: enable interrupt of " Jingjing Wu
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 18+ messages in thread
From: Jingjing Wu @ 2021-01-07  7:45 UTC (permalink / raw)
  To: dev; +Cc: jingjing.wu, beilei.xing, chenbo.xia, xiuchun.lu

New devarg "intr": if intr=1, use interrupt mode on control queue

Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
---
 drivers/net/iavf/iavf.h               |  19 ++++
 drivers/net/iavf/iavf_client_ethdev.c | 131 ++++++++++++++++++++++----
 drivers/net/iavf/iavf_ethdev.c        |  18 +---
 3 files changed, 134 insertions(+), 34 deletions(-)

diff --git a/drivers/net/iavf/iavf.h b/drivers/net/iavf/iavf.h
index c34f971721..5516ecf021 100644
--- a/drivers/net/iavf/iavf.h
+++ b/drivers/net/iavf/iavf.h
@@ -198,6 +198,7 @@ struct iavf_adapter {
 #ifdef RTE_LIBRTE_IAVF_CLIENT
 	/* used for avf_client driver */
 	struct vfio_device *user_dev;
+	int intr_mode; /* interrupt mode if true */
 #endif
 	bool rx_bulk_alloc_allowed;
 	/* For vector PMD */
@@ -234,6 +235,22 @@ iavf_init_adminq_parameter(struct iavf_hw *hw)
 	hw->aq.asq_buf_size = IAVF_AQ_BUF_SZ;
 }
 
+/* Enable default admin queue interrupt setting */
+static inline void
+iavf_enable_irq0(struct iavf_hw *hw)
+{
+	/* Enable admin queue interrupt trigger */
+	IAVF_WRITE_REG(hw, IAVF_VFINT_ICR0_ENA1,
+		       IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK);
+
+	IAVF_WRITE_REG(hw, IAVF_VFINT_DYN_CTL01,
+		       IAVF_VFINT_DYN_CTL01_INTENA_MASK |
+		       IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK |
+		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+	IAVF_WRITE_FLUSH(hw);
+}
+
 static inline void
 iavf_disable_irq0(struct iavf_hw *hw)
 {
@@ -342,4 +359,6 @@ int iavf_add_del_mc_addr_list(struct iavf_adapter *adapter,
 			uint32_t mc_addrs_num, bool add);
 int iavf_request_queues(struct iavf_adapter *adapter, uint16_t num);
 int iavf_get_max_rss_queue_region(struct iavf_adapter *adapter);
+void iavf_dev_interrupt_handler(void *param);
+
 #endif /* _IAVF_ETHDEV_H_ */
diff --git a/drivers/net/iavf/iavf_client_ethdev.c b/drivers/net/iavf/iavf_client_ethdev.c
index 989f9d6062..770a7a8200 100644
--- a/drivers/net/iavf/iavf_client_ethdev.c
+++ b/drivers/net/iavf/iavf_client_ethdev.c
@@ -6,6 +6,8 @@
 #include <stdint.h>
 #include <string.h>
 
+#include <sys/eventfd.h>
+
 #include <rte_common.h>
 #include <rte_ether.h>
 #include <rte_ethdev_driver.h>
@@ -18,6 +20,9 @@
 #include "iavf.h"
 #include "iavf_rxtx.h"
 
+#define AVF_CLIENT_ARG_PATH           "path"
+#define AVF_CLIENT_ARG_INTR           "intr"
+
 static int iavf_client_dev_close(struct rte_eth_dev *dev);
 static int iavf_client_dev_reset(struct rte_eth_dev *dev);
 
@@ -25,11 +30,27 @@ static int iavf_client_dev_reset(struct rte_eth_dev *dev);
 static struct eth_dev_ops iavf_client_eth_dev_ops;
 
 static const char *valid_args[] = {
-#define AVF_CLIENT_ARG_PATH           "path"
 	AVF_CLIENT_ARG_PATH,
+	AVF_CLIENT_ARG_INTR,
 	NULL
 };
 
+static void
+iavf_client_event_handler(void *param)
+{
+	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
+	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	eventfd_t buf;
+
+	eventfd_read(dev->intr_handle->fd, &buf);
+
+	iavf_disable_irq0(hw);
+
+	iavf_handle_virtchnl_msg(dev);
+
+	iavf_enable_irq0(hw);
+}
+
 /* set up vfio_device for iavf_client*/
 static int
 iavf_client_vfio_user_setup(struct rte_eth_dev *dev, const char *path)
@@ -51,6 +72,11 @@ iavf_client_vfio_user_setup(struct rte_eth_dev *dev, const char *path)
 
 	hw->back = IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
 
+	if (!vfio_dev->nb_irqs && adapter->intr_mode) {
+		PMD_INIT_LOG(ERR, "No irq support on device");
+		return -1;
+	}
+
 	if (!dev->intr_handle) {
 		dev->intr_handle = rte_zmalloc_socket("iavf_client_intr",
 				sizeof(*dev->intr_handle),
@@ -62,7 +88,7 @@ iavf_client_vfio_user_setup(struct rte_eth_dev *dev, const char *path)
 
 	}
 
-	dev->intr_handle->fd = -1;
+	dev->intr_handle->fd = vfio_dev->irqfds[0];
 	dev->intr_handle->type = RTE_INTR_HANDLE_VDEV;
 	dev->intr_handle->max_intr = 1;
 
@@ -145,26 +171,52 @@ iavf_client_eth_init(struct rte_eth_dev *eth_dev)
 	rte_ether_addr_copy((struct rte_ether_addr *)hw->mac.addr,
 			&eth_dev->data->mac_addrs[0]);
 
-	rte_eal_alarm_set(IAVF_CLIENT_ALARM_INTERVAL,
-			  iavf_client_dev_alarm_handler, eth_dev);
+	if (adapter->intr_mode) {
+		/* register callback func to eal lib */
+		rte_intr_callback_register(eth_dev->intr_handle,
+					   iavf_client_event_handler,
+					   (void *)eth_dev);
+		iavf_enable_irq0(hw);
+	} else {
+		rte_eal_alarm_set(IAVF_CLIENT_ALARM_INTERVAL,
+				  iavf_client_dev_alarm_handler, eth_dev);
+	}
 	return 0;
 }
 
 static int
 iavf_client_dev_reset(struct rte_eth_dev *dev)
 {
+	struct iavf_adapter *adapter =
+		IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
 	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct rte_intr_handle *intr_handle = dev->intr_handle;
 	int ret;
 
-	rte_eal_alarm_cancel(iavf_client_dev_alarm_handler, dev);
+	if (adapter->intr_mode) {
+		iavf_disable_irq0(hw);
+		/* unregister callback func from eal lib */
+		rte_intr_callback_unregister(intr_handle,
+					     iavf_client_event_handler, dev);
+	} else {
+		rte_eal_alarm_cancel(iavf_client_dev_alarm_handler, dev);
+	}
 
 	iavf_shutdown_adminq(hw);
 	ret = iavf_init_vf(dev);
 
 	/* send reset msg to PF */
 	iavf_vf_reset(hw);
-	rte_eal_alarm_set(IAVF_CLIENT_ALARM_INTERVAL,
-			  iavf_client_dev_alarm_handler, dev);
+	if (adapter->intr_mode) {
+		/* register callback func to eal lib */
+		rte_intr_callback_register(dev->intr_handle,
+					   iavf_client_event_handler,
+					   (void *)dev);
+		iavf_enable_irq0(hw);
+	} else {
+		rte_eal_alarm_set(IAVF_CLIENT_ALARM_INTERVAL,
+				  iavf_client_dev_alarm_handler, dev);
+	}
 
 	return ret;
 }
@@ -176,6 +228,15 @@ iavf_client_dev_close(struct rte_eth_dev *dev)
 		IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
 	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
+	if (adapter->intr_mode) {
+		iavf_disable_irq0(hw);
+		/* unregister callback func from eal lib */
+		rte_intr_callback_unregister(dev->intr_handle,
+					     iavf_client_event_handler, dev);
+	} else {
+		rte_eal_alarm_cancel(iavf_client_dev_alarm_handler, dev);
+	}
+
 	if (!adapter->stopped) {
 		iavf_stop_queues(dev);
 
@@ -188,10 +249,10 @@ iavf_client_dev_close(struct rte_eth_dev *dev)
 		iavf_add_del_all_mac_addr(adapter, false);
 		adapter->stopped = 1;
 	}
+
 	iavf_shutdown_adminq(hw);
-	iavf_disable_irq0(hw);
-	rte_eal_alarm_cancel(iavf_client_dev_alarm_handler, dev);
 	client_vfio_user_release((struct vfio_device *)hw->hw_addr);
+
 	return 0;
 }
 
@@ -210,6 +271,23 @@ iavf_client_get_string_arg(const char *key __rte_unused,
 	return 0;
 }
 
+static int
+iavf_client_intr_check(__rte_unused const char *key,
+			const char *value, void *opaque)
+{
+	int *intr = (int *)opaque;
+	int ret = 0;
+
+	if (!strcmp(value, "1"))
+		*intr  = 1;
+	else if (!strcmp(value, "0"))
+		*intr = 0;
+	else
+		ret = -1;
+
+	return ret;
+}
+
 static int
 iavf_client_pmd_probe(struct rte_vdev_device *vdev)
 {
@@ -217,6 +295,7 @@ iavf_client_pmd_probe(struct rte_vdev_device *vdev)
 	struct rte_eth_dev *eth_dev;
 	struct iavf_adapter *adapter;
 	char *path = NULL;
+	int intr_mode = 0;
 	int ret;
 
 	kvlist = rte_kvargs_parse(rte_vdev_device_args(vdev), valid_args);
@@ -227,35 +306,52 @@ iavf_client_pmd_probe(struct rte_vdev_device *vdev)
 
 	if (rte_kvargs_count(kvlist, AVF_CLIENT_ARG_PATH) == 1) {
 		if (rte_kvargs_process(kvlist, AVF_CLIENT_ARG_PATH,
-				       &iavf_client_get_string_arg, &path) < 0) {
+					&iavf_client_get_string_arg,
+					&path) < 0) {
 			PMD_INIT_LOG(ERR, "error to parse %s",
 				     AVF_CLIENT_ARG_PATH);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto free_kvlist;
 		}
 	} else {
 		PMD_INIT_LOG(ERR, "arg %s is mandatory for iavf_client",
 			     AVF_CLIENT_ARG_PATH);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto free_kvlist;
+	}
+
+	if (rte_kvargs_count(kvlist, AVF_CLIENT_ARG_INTR) == 1) {
+		if (rte_kvargs_process(kvlist, AVF_CLIENT_ARG_INTR,
+					iavf_client_intr_check,
+					&intr_mode) < 0) {
+			PMD_INIT_LOG(ERR, "arg %s must be 1 or 0",
+				     AVF_CLIENT_ARG_INTR);
+			ret = -EINVAL;
+			goto free_kvlist;
+		}
 	}
 
 	eth_dev = rte_eth_vdev_allocate(vdev, sizeof(*adapter));
 
 	ret = iavf_client_vfio_user_setup(eth_dev, path);
-	if (ret) {
+	if (ret)
 		goto err;
-	}
+
+	adapter = IAVF_DEV_PRIVATE_TO_ADAPTER(eth_dev->data->dev_private);
+	adapter->intr_mode = intr_mode;
 
 	ret = iavf_client_eth_init(eth_dev);
-	if (ret) {
+	if (ret)
 		goto err;
-	}
 
 	rte_eth_dev_probing_finish(eth_dev);
+
 	rte_kvargs_free(kvlist);
 
 	return 0;
 err:
 	rte_eth_dev_release_port(eth_dev);
+free_kvlist:
 	rte_kvargs_free(kvlist);
 	return ret;
 }
@@ -287,4 +383,5 @@ static struct rte_vdev_driver iavf_client_driver = {
 RTE_PMD_REGISTER_VDEV(net_iavf_client, iavf_client_driver);
 RTE_PMD_REGISTER_ALIAS(net_iavf_client, iavf_client);
 RTE_PMD_REGISTER_PARAM_STRING(net_iavf_client,
-	"path=<path>");
+	"path=<path>"
+	"intr=[0|1]");
diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
index 6b5e47adf2..bc07ecbed7 100644
--- a/drivers/net/iavf/iavf_ethdev.c
+++ b/drivers/net/iavf/iavf_ethdev.c
@@ -1869,23 +1869,7 @@ iavf_init_vf(struct rte_eth_dev *dev)
 	return -1;
 }
 
-/* Enable default admin queue interrupt setting */
-static inline void
-iavf_enable_irq0(struct iavf_hw *hw)
-{
-	/* Enable admin queue interrupt trigger */
-	IAVF_WRITE_REG(hw, IAVF_VFINT_ICR0_ENA1,
-		       IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK);
-
-	IAVF_WRITE_REG(hw, IAVF_VFINT_DYN_CTL01,
-		       IAVF_VFINT_DYN_CTL01_INTENA_MASK |
-		       IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK |
-		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
-
-	IAVF_WRITE_FLUSH(hw);
-}
-
-static void
+void
 iavf_dev_interrupt_handler(void *param)
 {
 	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
-- 
2.21.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [dpdk-dev] [PATCH v2 3/4] net/iavf_client: enable interrupt of control queue
  2021-01-07  7:45 ` [dpdk-dev] [PATCH v2 0/4] introduce new " Jingjing Wu
  2021-01-07  7:45   ` [dpdk-dev] [PATCH v2 1/4] net/iavf_client: introduce " Jingjing Wu
  2021-01-07  7:45   ` [dpdk-dev] [PATCH v2 2/4] net/iavf_client: enable interrupt on control queue Jingjing Wu
@ 2021-01-07  7:45   ` Jingjing Wu
  2021-01-07  7:45   ` [dpdk-dev] [PATCH v2 4/4] net/iavf: fix vector mapping with queue Jingjing Wu
  2021-01-07  8:27   ` [dpdk-dev] [PATCH v3 0/5] introduce new iavf driver on vfio-user client Jingjing Wu
  4 siblings, 0 replies; 18+ messages in thread
From: Jingjing Wu @ 2021-01-07  7:45 UTC (permalink / raw)
  To: dev; +Cc: jingjing.wu, beilei.xing, chenbo.xia, xiuchun.lu

Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
---
 drivers/net/iavf/iavf_client_ethdev.c | 29 +++++++++++++++++++++------
 drivers/net/iavf/iavf_ethdev.c        |  9 +++------
 2 files changed, 26 insertions(+), 12 deletions(-)

diff --git a/drivers/net/iavf/iavf_client_ethdev.c b/drivers/net/iavf/iavf_client_ethdev.c
index 770a7a8200..27daaed0e8 100644
--- a/drivers/net/iavf/iavf_client_ethdev.c
+++ b/drivers/net/iavf/iavf_client_ethdev.c
@@ -59,6 +59,7 @@ iavf_client_vfio_user_setup(struct rte_eth_dev *dev, const char *path)
 		IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
 	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(adapter);
 	struct vfio_device *vfio_dev;
+	uint32_t max_fds, i;
 
 	vfio_dev = client_vfio_user_setup(path, dev->device->numa_node);
 	if (vfio_dev == NULL) {
@@ -87,11 +88,21 @@ iavf_client_vfio_user_setup(struct rte_eth_dev *dev, const char *path)
 		}
 
 	}
-
 	dev->intr_handle->fd = vfio_dev->irqfds[0];
 	dev->intr_handle->type = RTE_INTR_HANDLE_VDEV;
 	dev->intr_handle->max_intr = 1;
 
+	/* Assign rxq fds */
+	if (vfio_dev->nb_irqs > 1) {
+		max_fds = RTE_MIN((uint32_t)RTE_MAX_RXTX_INTR_VEC_ID,
+				  vfio_dev->nb_irqs - 1);
+		dev->intr_handle->nb_efd = max_fds;
+		for (i = 0; i < max_fds; ++i)
+			dev->intr_handle->efds[i] =
+				vfio_dev->irqfds[i + RTE_INTR_VEC_RXTX_OFFSET];
+		dev->intr_handle->efd_counter_size = 0;
+		dev->intr_handle->max_intr += max_fds;
+	}
 	return 0;
 }
 
@@ -108,8 +119,6 @@ avf_client_init_eth_ops(void)
 	iavf_client_eth_dev_ops.reta_query                 = NULL;
 	iavf_client_eth_dev_ops.rss_hash_update            = NULL;
 	iavf_client_eth_dev_ops.rss_hash_conf_get          = NULL;
-	iavf_client_eth_dev_ops.rx_queue_intr_enable       = NULL;
-	iavf_client_eth_dev_ops.rx_queue_intr_disable      = NULL;
 }
 
 #define IAVF_CLIENT_ALARM_INTERVAL 50000 /* us */
@@ -227,11 +236,12 @@ iavf_client_dev_close(struct rte_eth_dev *dev)
 	struct iavf_adapter *adapter =
 		IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
 	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct rte_intr_handle *intr_handle = dev->intr_handle;
 
 	if (adapter->intr_mode) {
 		iavf_disable_irq0(hw);
 		/* unregister callback func from eal lib */
-		rte_intr_callback_unregister(dev->intr_handle,
+		rte_intr_callback_unregister(intr_handle,
 					     iavf_client_event_handler, dev);
 	} else {
 		rte_eal_alarm_cancel(iavf_client_dev_alarm_handler, dev);
@@ -240,8 +250,15 @@ iavf_client_dev_close(struct rte_eth_dev *dev)
 	if (!adapter->stopped) {
 		iavf_stop_queues(dev);
 
-		if (dev->intr_handle) {
-			rte_free(dev->intr_handle);
+		if (intr_handle) {
+			/* Disable the interrupt for Rx */
+			rte_intr_efd_disable(intr_handle);
+			/* Rx interrupt vector mapping free */
+			if (intr_handle->intr_vec) {
+				rte_free(intr_handle->intr_vec);
+				intr_handle->intr_vec = NULL;
+			}
+			rte_free(intr_handle);
 			dev->intr_handle = NULL;
 		}
 
diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
index bc07ecbed7..06395f852b 100644
--- a/drivers/net/iavf/iavf_ethdev.c
+++ b/drivers/net/iavf/iavf_ethdev.c
@@ -1368,11 +1368,10 @@ iavf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 {
 	struct iavf_adapter *adapter =
 		IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
-	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
 	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(adapter);
 	uint16_t msix_intr;
 
-	msix_intr = pci_dev->intr_handle.intr_vec[queue_id];
+	msix_intr = dev->intr_handle->intr_vec[queue_id];
 	if (msix_intr == IAVF_MISC_VEC_ID) {
 		PMD_DRV_LOG(INFO, "MISC is also enabled for control");
 		IAVF_WRITE_REG(hw, IAVF_VFINT_DYN_CTL01,
@@ -1387,10 +1386,9 @@ iavf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 			       IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK |
 			       IAVF_VFINT_DYN_CTLN1_ITR_INDX_MASK);
 	}
-
 	IAVF_WRITE_FLUSH(hw);
 
-	rte_intr_ack(&pci_dev->intr_handle);
+	rte_intr_ack(dev->intr_handle);
 
 	return 0;
 }
@@ -1398,11 +1396,10 @@ iavf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 static int
 iavf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
 {
-	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
 	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	uint16_t msix_intr;
 
-	msix_intr = pci_dev->intr_handle.intr_vec[queue_id];
+	msix_intr = dev->intr_handle->intr_vec[queue_id];
 	if (msix_intr == IAVF_MISC_VEC_ID) {
 		PMD_DRV_LOG(ERR, "MISC is used for control, cannot disable it");
 		return -EIO;
-- 
2.21.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [dpdk-dev] [PATCH v2 4/4] net/iavf: fix vector mapping with queue
  2021-01-07  7:45 ` [dpdk-dev] [PATCH v2 0/4] introduce new " Jingjing Wu
                     ` (2 preceding siblings ...)
  2021-01-07  7:45   ` [dpdk-dev] [PATCH v2 3/4] net/iavf_client: enable interrupt of " Jingjing Wu
@ 2021-01-07  7:45   ` Jingjing Wu
  2021-01-07  8:27   ` [dpdk-dev] [PATCH v3 0/5] introduce new iavf driver on vfio-user client Jingjing Wu
  4 siblings, 0 replies; 18+ messages in thread
From: Jingjing Wu @ 2021-01-07  7:45 UTC (permalink / raw)
  To: dev; +Cc: jingjing.wu, beilei.xing, chenbo.xia, xiuchun.lu

Fix the vector mapping with queue by changing the recircle when
exceeds RX_VEC_START + nb_msix;

Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
---
 drivers/net/iavf/iavf_ethdev.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
index 06395f852b..6182fc6f4f 100644
--- a/drivers/net/iavf/iavf_ethdev.c
+++ b/drivers/net/iavf/iavf_ethdev.c
@@ -578,7 +578,7 @@ static int iavf_config_rx_queues_irqs(struct rte_eth_dev *dev,
 				qv_map[i].queue_id = i;
 				qv_map[i].vector_id = vec;
 				intr_handle->intr_vec[i] = vec++;
-				if (vec >= vf->nb_msix)
+				if (vec >= vf->nb_msix + IAVF_RX_VEC_START)
 					vec = IAVF_RX_VEC_START;
 			}
 			vf->qv_map = qv_map;
-- 
2.21.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [dpdk-dev] [PATCH v3 0/5] introduce new iavf driver on vfio-user client
  2021-01-07  7:45 ` [dpdk-dev] [PATCH v2 0/4] introduce new " Jingjing Wu
                     ` (3 preceding siblings ...)
  2021-01-07  7:45   ` [dpdk-dev] [PATCH v2 4/4] net/iavf: fix vector mapping with queue Jingjing Wu
@ 2021-01-07  8:27   ` Jingjing Wu
  2021-01-07  8:27     ` [dpdk-dev] [PATCH v3 1/5] common/iavf: emulated pci interfaces " Jingjing Wu
                       ` (4 more replies)
  4 siblings, 5 replies; 18+ messages in thread
From: Jingjing Wu @ 2021-01-07  8:27 UTC (permalink / raw)
  To: dev; +Cc: jingjing.wu, beilei.xing, chenbo.xia, xiuchun.lu

This series introduces a new net virtual device called iavf_client which
is based on vfio-user client interface. Through vfio-user client interface,
PCI liked device could be used similar as Intel® Ethernet Adaptive Virtual
Function specification.
The code to enable iavf_client mainly contains two parts:
 - Emulated pci interfaces for vfio-user client which is located
   in common/iavf/vfio_user/.
 - A new net driver base on vdev abstraction, i.e. iavf_client_ethdev.c

      ----------------------
      | ------------------ |
      | |  iavf driver   | |----> (iavf_client_ethdev.c)
      | ------------------ |
      | ------------------ |
      | | device emulate | |------>(common/iavf/vfio_user/)
      | ------------------ |
      ----------------------
                |
                |  
      ----------------------
      |      vfio-user     |
      |       client       |
      ----------------------



This driver can be used to test the device emulation framework
mentioned in:
  [RFC 0/2] Add device emulation support in DPDK
  http://patchwork.dpdk.org/cover/75549/

                    +------------------------------------------------------+
                    |   +---------------+      +---------------+           |
                    |   | iavf_emudev   |      | iavfbe_ethdev |           |
                    |   |    driver     |      |     driver    |           |
                    |   +---------------+      +---------------+           |
                    |           |                       |                  |
                    | ------------------------------------------- VDEV BUS |
                    |           |                       |                  |
                    |   +---------------+       +--------------+           |
+--------------+    |   | vdev:         |       | vdev:        |           |
| +----------+ |    |   | /path/to/vfio |       |iavf_emudev_# |           |
| |   iavf   | |    |   +---------------+       +--------------+           |
| |  client  |      |           |                                          |
| +----------+ |    |           |                                          |
| +----------+ |    |      +----------+                                    |
| | vfio-user| |    |      | vfio-user|                                    |
| | client   | |<---|----->| server   |                                    |
| +----------+ |    |      +----------+                                    |
| QEMU/DPDK    |    | DPDK                                                 |
+--------------+    +------------------------------------------------------+

It can be launched together with patch series for the testing:
  [0/9] Introduce vfio-user library:
  http://patchwork.dpdk.org/cover/85389/
  [0/8] Introduce emudev library and iavf emudev driver
  http://patchwork.dpdk.org/cover/85488/
  [0/6] Introduce iavf backend driver
  http://patchwork.dpdk.org/cover/86084/

This series depends on patch serieses:
  [0/9] Introduce vfio-user library:
  http://patchwork.dpdk.org/cover/85389/


v3:
 - Reword commit log
 - Add missed patch in v2

v2:
 - Enable interrupt for control queue
 - Enable interrupt for rx queue
 - Rename some Macros
 - Fix resource release when close
 - Fix ptype_tbl assignment
 - Fix typo


Jingjing Wu (5):
  common/iavf: emulated pci interfaces on vfio-user client
  net/iavf_client: introduce iavf driver on vfio-user client
  net/iavf_client: enable interrupt on control queue
  net/iavf_client: enable interrupt of Rx queue
  net/iavf: fix vector mapping with queue

 config/rte_config.h                           |   3 +
 drivers/common/iavf/iavf_common.c             |   7 +
 drivers/common/iavf/iavf_impl.c               |  45 +-
 drivers/common/iavf/iavf_osdep.h              |  14 +
 drivers/common/iavf/iavf_prototype.h          |   1 +
 drivers/common/iavf/iavf_type.h               |   3 +
 drivers/common/iavf/meson.build               |  11 +-
 drivers/common/iavf/version.map               |   6 +
 drivers/common/iavf/vfio_user/vfio_user_pci.c | 525 ++++++++++++++++++
 drivers/common/iavf/vfio_user/vfio_user_pci.h |  68 +++
 drivers/net/iavf/iavf.h                       |  37 +-
 drivers/net/iavf/iavf_client_ethdev.c         | 404 ++++++++++++++
 drivers/net/iavf/iavf_ethdev.c                |  57 +-
 drivers/net/iavf/iavf_rxtx.c                  |  23 +-
 drivers/net/iavf/meson.build                  |   1 +
 15 files changed, 1157 insertions(+), 48 deletions(-)
 create mode 100644 drivers/common/iavf/vfio_user/vfio_user_pci.c
 create mode 100644 drivers/common/iavf/vfio_user/vfio_user_pci.h
 create mode 100644 drivers/net/iavf/iavf_client_ethdev.c

-- 
2.21.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [dpdk-dev] [PATCH v3 1/5] common/iavf: emulated pci interfaces on vfio-user client
  2021-01-07  8:27   ` [dpdk-dev] [PATCH v3 0/5] introduce new iavf driver on vfio-user client Jingjing Wu
@ 2021-01-07  8:27     ` Jingjing Wu
  2021-01-07  8:27     ` [dpdk-dev] [PATCH v3 2/5] net/iavf_client: introduce iavf driver " Jingjing Wu
                       ` (3 subsequent siblings)
  4 siblings, 0 replies; 18+ messages in thread
From: Jingjing Wu @ 2021-01-07  8:27 UTC (permalink / raw)
  To: dev; +Cc: jingjing.wu, beilei.xing, chenbo.xia, xiuchun.lu

This patch implements Emulated pci interfaces on vfio-user client
which is located in common/iavf/vfio_user/.
Four main functions provided to upper layer (driver) to set
up or talk to device:
 - client_vfio_user_setup
 - client_vfio_user_release
 - client_vfio_user_get_bar_addr
 - client_vfio_user_pci_bar_access

      ----------------------
      | ------------------ |
      | |  iavf driver   | |
      | ------------------ |
      | ------------------ |
      | | device emulate | |------>(common/iavf/vfio_user/)
      | ------------------ |
      ----------------------
                |
                |
      ----------------------
      |      vfio-user     |
      |       client       |
      ----------------------

Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
Signed-off-by: Chenbo Xia <chenbo.xia@intel.com>
---
 config/rte_config.h                           |   3 +
 drivers/common/iavf/iavf_common.c             |   7 +
 drivers/common/iavf/iavf_impl.c               |  45 +-
 drivers/common/iavf/iavf_osdep.h              |  14 +
 drivers/common/iavf/iavf_type.h               |   3 +
 drivers/common/iavf/meson.build               |  11 +-
 drivers/common/iavf/version.map               |   5 +
 drivers/common/iavf/vfio_user/vfio_user_pci.c | 525 ++++++++++++++++++
 drivers/common/iavf/vfio_user/vfio_user_pci.h |  68 +++
 9 files changed, 679 insertions(+), 2 deletions(-)
 create mode 100644 drivers/common/iavf/vfio_user/vfio_user_pci.c
 create mode 100644 drivers/common/iavf/vfio_user/vfio_user_pci.h

diff --git a/config/rte_config.h b/config/rte_config.h
index a0b5160ff2..76ed1ae83f 100644
--- a/config/rte_config.h
+++ b/config/rte_config.h
@@ -151,4 +151,7 @@
 #define RTE_LIBRTE_PMD_DLB2_SW_CREDIT_QUANTA 32
 #define RTE_PMD_DLB2_DEFAULT_DEPTH_THRESH 256
 
+/* IAVF bsed on vfio_user client */
+#define RTE_LIBRTE_IAVF_CLIENT 1
+
 #endif /* _RTE_CONFIG_H_ */
diff --git a/drivers/common/iavf/iavf_common.c b/drivers/common/iavf/iavf_common.c
index c951b7d787..2e68f5d08b 100644
--- a/drivers/common/iavf/iavf_common.c
+++ b/drivers/common/iavf/iavf_common.c
@@ -20,6 +20,13 @@ enum iavf_status iavf_set_mac_type(struct iavf_hw *hw)
 
 	DEBUGFUNC("iavf_set_mac_type\n");
 
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+	if (hw->bus.type == iavf_bus_type_vfio_user) {
+		hw->mac.type = IAVF_MAC_VF;
+		return status;
+	}
+#endif
+
 	if (hw->vendor_id == IAVF_INTEL_VENDOR_ID) {
 		switch (hw->device_id) {
 		case IAVF_DEV_ID_X722_VF:
diff --git a/drivers/common/iavf/iavf_impl.c b/drivers/common/iavf/iavf_impl.c
index fc0da31753..79262bf50d 100644
--- a/drivers/common/iavf/iavf_impl.c
+++ b/drivers/common/iavf/iavf_impl.c
@@ -10,9 +10,14 @@
 #include <rte_malloc.h>
 #include <rte_memzone.h>
 
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+#include "vfio_user/vfio_user_pci.h"
+#endif
 #include "iavf_type.h"
 #include "iavf_prototype.h"
 
+int iavf_common_logger;
+
 enum iavf_status
 iavf_allocate_dma_mem_d(__rte_unused struct iavf_hw *hw,
 			struct iavf_dma_mem *mem,
@@ -85,4 +90,42 @@ iavf_free_virt_mem_d(__rte_unused struct iavf_hw *hw,
 	return IAVF_SUCCESS;
 }
 
-RTE_LOG_REGISTER(iavf_common_logger, pmd.common.iavf, NOTICE);
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+uint32_t
+iavf_read_addr(struct iavf_hw *hw, uint32_t offset)
+{
+	uint32_t value = 0;
+
+	if (!hw || !hw->hw_addr)
+		return 0;
+
+	if (hw->bus.type == iavf_bus_type_vfio_user)
+		client_vfio_user_pci_bar_access(
+				(struct vfio_device *)hw->hw_addr,
+				0, offset, 4, &value, false);
+	else
+		value = readl(hw->hw_addr + offset);
+
+	return value;
+}
+
+void
+iavf_write_addr(struct iavf_hw *hw, uint32_t offset, uint32_t value)
+{
+	if (!hw || !hw->hw_addr)
+		return;
+	if (hw->bus.type == iavf_bus_type_vfio_user)
+		client_vfio_user_pci_bar_access(
+				(struct vfio_device *)hw->hw_addr,
+				0, offset, 4, &value, true);
+	else
+		writel(value, hw->hw_addr + offset);
+}
+#endif
+
+RTE_INIT(iavf_common_init_log)
+{
+	iavf_common_logger = rte_log_register("pmd.common.iavf");
+	if (iavf_common_logger >= 0)
+		rte_log_set_level(iavf_common_logger, RTE_LOG_NOTICE);
+}
diff --git a/drivers/common/iavf/iavf_osdep.h b/drivers/common/iavf/iavf_osdep.h
index 7cba13ff74..025d48a702 100644
--- a/drivers/common/iavf/iavf_osdep.h
+++ b/drivers/common/iavf/iavf_osdep.h
@@ -107,8 +107,22 @@ writeq(uint64_t value, volatile void *addr)
 	rte_write64(rte_cpu_to_le_64(value), addr);
 }
 
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+struct iavf_hw;
+
+__rte_internal
+uint32_t iavf_read_addr(struct iavf_hw *hw, uint32_t offset);
+__rte_internal
+void iavf_write_addr(struct iavf_hw *hw, uint32_t offset, uint32_t value);
+
+#define wr32(a, reg, value)  iavf_write_addr((a), (reg), (value))
+#define rd32(a, reg)         iavf_read_addr((a), (reg))
+
+#else
 #define wr32(a, reg, value) writel((value), (a)->hw_addr + (reg))
 #define rd32(a, reg)        readl((a)->hw_addr + (reg))
+#endif /* RTE_LIBRTE_IAVF_CLIENT */
+
 #define wr64(a, reg, value) writeq((value), (a)->hw_addr + (reg))
 #define rd64(a, reg)        readq((a)->hw_addr + (reg))
 
diff --git a/drivers/common/iavf/iavf_type.h b/drivers/common/iavf/iavf_type.h
index 0990c9aa33..faa4a21eac 100644
--- a/drivers/common/iavf/iavf_type.h
+++ b/drivers/common/iavf/iavf_type.h
@@ -264,6 +264,9 @@ enum iavf_bus_type {
 	iavf_bus_type_pci,
 	iavf_bus_type_pcix,
 	iavf_bus_type_pci_express,
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+	iavf_bus_type_vfio_user,
+#endif
 	iavf_bus_type_reserved
 };
 
diff --git a/drivers/common/iavf/meson.build b/drivers/common/iavf/meson.build
index 1f4d8b898d..e0160ea135 100644
--- a/drivers/common/iavf/meson.build
+++ b/drivers/common/iavf/meson.build
@@ -1,7 +1,16 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2019-2020 Intel Corporation
 
-sources = files('iavf_adminq.c', 'iavf_common.c', 'iavf_impl.c')
+includes += include_directories('vfio_user')
+
+sources = files(
+	'iavf_adminq.c',
+	'iavf_common.c',
+	'iavf_impl.c',
+	'vfio_user/vfio_user_pci.c'
+)
+
+deps += ['vfio_user']
 
 if cc.has_argument('-Wno-pointer-to-int-cast')
         cflags += '-Wno-pointer-to-int-cast'
diff --git a/drivers/common/iavf/version.map b/drivers/common/iavf/version.map
index e0f117197c..883d919487 100644
--- a/drivers/common/iavf/version.map
+++ b/drivers/common/iavf/version.map
@@ -7,6 +7,11 @@ INTERNAL {
 	iavf_set_mac_type;
 	iavf_shutdown_adminq;
 	iavf_vf_parse_hw_config;
+	client_vfio_user_setup;
+	client_vfio_user_release;
+	client_vfio_user_get_bar_addr;
+	iavf_write_addr;
+	iavf_read_addr;
 
 	local: *;
 };
diff --git a/drivers/common/iavf/vfio_user/vfio_user_pci.c b/drivers/common/iavf/vfio_user/vfio_user_pci.c
new file mode 100644
index 0000000000..6e95ce4600
--- /dev/null
+++ b/drivers/common/iavf/vfio_user/vfio_user_pci.c
@@ -0,0 +1,525 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <sys/queue.h>
+#include <sys/mman.h>
+#include <sys/eventfd.h>
+
+#include <rte_common.h>
+#include <rte_memory.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_tailq.h>
+#include <rte_errno.h>
+#include <rte_vfio_user.h>
+
+#include "vfio_user_pci.h"
+
+#define IAVF_MEM_EVENT_CLB_NAME "iavf_mem_event_clb"
+
+/* buffer length for irq set */
+#define MSIX_IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + \
+				sizeof(int) * IAVF_CLIENT_MAX_VECTORS)
+/* buffer length for region infor get */
+#define REG_INFO_GET_BUF_LEN (sizeof(struct vfio_region_info) + \
+			sizeof(struct vfio_region_info_cap_sparse_mmap) \
+			+ 2 * sizeof(struct vfio_region_sparse_mmap_area))
+
+static inline int
+vfio_add_mr(struct vfio_device *dev, struct vfio_memory_region *mr)
+{
+	if (dev->nb_mrs == RTE_VUSER_MAX_DMA) {
+		CLIENT_LOG(ERR, "Exceed Maximum supported memory regions %d",
+			RTE_VUSER_MAX_DMA);
+		return -EINVAL;
+	}
+
+	TAILQ_INSERT_HEAD(&dev->mrs_list, mr, link);
+	dev->nb_mrs++;
+
+	CLIENT_LOG(DEBUG, "Add memory region: FD %d, VADDR 0x%lx,"
+			  " IOVA 0x%lx, Size 0x%lx",
+			  mr->fd, mr->vaddr, mr->iova, mr->size);
+	return 0;
+}
+
+static inline void
+vfio_remove_mr(struct vfio_device *dev, struct vfio_memory_region *mr)
+{
+	if (dev->nb_mrs == 0)
+		return;
+
+	CLIENT_LOG(DEBUG, "Remove memory region: FD %d, VADDR 0x%lx,"
+			  " IOVA 0x%lx, Size 0x%lx",
+			  mr->fd, mr->vaddr, mr->iova, mr->size);
+	TAILQ_REMOVE(&dev->mrs_list, mr, link);
+	dev->nb_mrs--;
+	rte_free(mr);
+}
+
+static int
+update_vfio_memory_region(const struct rte_memseg_list *msl __rte_unused,
+		const struct rte_memseg *ms, void *arg)
+{
+	int ret = 0;
+	struct vfio_device *dev = arg;
+	struct vfio_memory_region *mr, *mrs;
+	struct rte_vfio_user_mem_reg mem;
+	uint64_t offset;
+
+	mr = rte_zmalloc_socket("iavf_client_vfio_user", sizeof(*mr),
+				0, SOCKET_ID_ANY);
+	if (mr == NULL)
+		return -ENOMEM;
+
+	mr->vaddr = (uint64_t)(uintptr_t)ms->addr;
+	mr->iova = ms->iova;
+	mr->size = ms->len;
+	mr->fd = rte_memseg_get_fd_thread_unsafe(ms);
+	if (mr->fd == -1) {
+		CLIENT_LOG(ERR, "Error to get the memory fd");
+		rte_free(mr);
+		return -EFAULT;
+	}
+	if (rte_memseg_get_fd_offset_thread_unsafe(ms, &offset) < 0) {
+		CLIENT_LOG(ERR, "Error to get the memory map offset");
+		rte_free(mr);
+		return -EFAULT;
+	}
+	mr->offset = offset;
+
+	TAILQ_FOREACH(mrs, &dev->mrs_list, link) {
+		if (mrs->vaddr == mr->vaddr)
+			return 0;
+	}
+
+	ret = vfio_add_mr(dev, mr);
+	if (ret) {
+		CLIENT_LOG(ERR, "Error to add memory region");
+		rte_free(mr);
+		return ret;
+	}
+
+	mem.gpa = mr->iova;
+	mem.size = mr->size;
+	mem.fd_offset = mr->offset;
+	mem.protection = PROT_WRITE | PROT_READ;
+	mem.flags = RTE_VUSER_MEM_MAPPABLE;
+
+	ret = rte_vfio_user_dma_map(dev->dev_id, &mem, &mr->fd, 1);
+	if (ret) {
+		CLIENT_LOG(ERR, "Error to send dma map request");
+		vfio_remove_mr(dev, mr);
+		rte_free(mr);
+		return ret;
+	}
+	return ret;
+
+}
+
+static int
+vfio_device_dma_map(struct vfio_device *dev)
+{
+	if (rte_memseg_walk_thread_unsafe(update_vfio_memory_region, dev) < 0)
+		return -1;
+
+	return 0;
+}
+
+
+static void
+vfio_device_dma_unmap(struct vfio_device *dev)
+{
+	int ret;
+	struct vfio_memory_region *mr;
+
+	if (dev->nb_mrs == 0)
+		return;
+
+	while ((mr = TAILQ_FIRST(&dev->mrs_list))) {
+		struct rte_vfio_user_mem_reg mem;
+
+		mem.gpa = mr->iova;
+		mem.size = mr->size;
+		mem.fd_offset = mr->offset;
+		mem.protection = PROT_WRITE | PROT_READ;
+		ret = rte_vfio_user_dma_unmap(dev->dev_id, &mem, 1);
+		if (ret)
+			CLIENT_LOG(ERR, "Error to send dma unmap request for"
+				" mr FD %d, VADDR 0x%lx, IOVA 0x%lx, Size 0x%lx",
+				 mr->fd, mr->vaddr, mr->iova, mr->size);
+		TAILQ_REMOVE(&dev->mrs_list, mr, link);
+		dev->nb_mrs--;
+		rte_free(mr);
+	}
+	return;
+}
+
+static void
+iavf_mem_event_cb(enum rte_mem_event type __rte_unused,
+			 const void *addr,
+			 size_t len __rte_unused,
+			 void *arg)
+{
+	struct vfio_device *dev = arg;
+	struct rte_memseg_list *msl;
+	uint16_t ret;
+
+	/* ignore externally allocated memory */
+	msl = rte_mem_virt2memseg_list(addr);
+	if (msl->external)
+		return;
+	ret = vfio_device_dma_map(dev);
+	if (ret)
+		CLIENT_LOG(ERR, "DMA map failed");
+}
+
+static inline struct vfio_info_cap_header *
+vfio_device_get_info_cap(struct vfio_region_info *info, int cap)
+{
+	struct vfio_info_cap_header *h;
+	size_t offset;
+
+	offset = info->cap_offset;
+	while (offset != 0 && offset < info->argsz) {
+		h = (struct vfio_info_cap_header *)((uintptr_t)info + offset);
+		if (h->id == cap) {
+			return h;
+		}
+		offset = h->next;
+	}
+
+	return NULL;
+}
+
+static int
+vfio_device_setup_sparse_mmaps(struct vfio_device *device, int index,
+			       struct vfio_region_info *info, int *fds)
+{
+	struct vfio_info_cap_header *hdr;
+	struct vfio_region_info_cap_sparse_mmap *sparse;
+	struct vfio_pci_region *region = &device->regions[index];
+	uint32_t i, j = 0;
+	int prot = 0;
+
+	hdr = vfio_device_get_info_cap(info, VFIO_REGION_INFO_CAP_SPARSE_MMAP);
+	if (!hdr) {
+		CLIENT_LOG(ERR, "Device doesn't have sparse mmap");
+		return -EEXIST;
+	}
+
+	sparse = container_of(hdr, struct vfio_region_info_cap_sparse_mmap, header);
+	for (i = 0; i < sparse->nr_areas; i++) {
+		if (sparse->areas[i].size == 0)
+			continue;
+		region->mmaps[j].offset = sparse->areas[i].offset;
+		region->mmaps[j].size = sparse->areas[i].size;
+		prot |= info->flags & VFIO_REGION_INFO_FLAG_READ ? PROT_READ : 0;
+		prot |= info->flags & VFIO_REGION_INFO_FLAG_WRITE ? PROT_WRITE : 0;
+		if (*fds) {
+			/* Use single fd for now*/
+			region->mmaps[j].mem = mmap(NULL, region->mmaps[j].size,
+						prot, MAP_SHARED, fds[0],
+						region->offset + region->mmaps[j].offset);
+			if (region->mmaps[j].mem == MAP_FAILED) {
+				CLIENT_LOG(ERR, "Device SPARSE MMAP failed");
+				return -EIO;
+			}
+		} else {
+			CLIENT_LOG(ERR, "No valid fd, skip mmap for"
+					" bar %d region %u", index, i);
+		}
+		CLIENT_LOG(DEBUG, "Sparse region %u, Size 0x%llx,"
+				  " Offset 0x%llx, Map addr %p",
+				  i, sparse->areas[i].size,
+				  sparse->areas[i].offset, region->mmaps[j].mem);
+		j++;
+	}
+	device->regions[index].nr_mmaps = j;
+
+	return 0;
+}
+
+static int
+vfio_device_map_region(struct vfio_device *device __rte_unused,
+			struct vfio_pci_region *region, int fd)
+{
+	int prot = 0;
+
+	prot |= region->flags & VFIO_REGION_INFO_FLAG_READ ? PROT_READ : 0;
+	prot |= region->flags & VFIO_REGION_INFO_FLAG_WRITE ? PROT_WRITE : 0;
+
+	region->mmaps[0].offset = 0;
+	region->mmaps[0].size = region->size;
+
+	region->mmaps[0].mem = mmap(NULL, region->size, prot, MAP_SHARED,
+				    fd, region->offset);
+	if (region->mmaps[0].mem == MAP_FAILED) {
+		CLIENT_LOG(ERR, "Device Region MMAP failed");
+		return -EFAULT;
+	}
+	CLIENT_LOG(DEBUG, "Memory mapped to %p", region->mmaps[0].mem);
+	region->nr_mmaps = 1;
+
+	return 0;
+}
+
+static void
+vfio_device_unmap_bars(struct vfio_device *dev)
+{
+	uint32_t i, j;
+	struct vfio_pci_region *region;
+
+	for (i = 0; i < dev->pci_regions; i++) {
+		region = &dev->regions[i];
+		for (j = 0; j < region->nr_mmaps; j++) {
+			if (region->mmaps[j].mem)
+				munmap(region->mmaps[j].mem, region->mmaps[j].size);
+		}
+	}
+	memset(dev->regions, 0, sizeof(dev->regions));
+}
+
+static int
+vfio_user_create_irqfd(struct vfio_device *device, uint32_t count)
+{
+	uint32_t i;
+
+	for (i = 0; i < count; i++) {
+		device->irqfds[i] = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
+		if (device->irqfds[i] < 0) {
+			CLIENT_LOG(ERR, "Failed to create irqfd");
+			return -1;
+		}
+	}
+	device->nb_irqs = count;
+	return 0;
+}
+
+struct vfio_device *
+client_vfio_user_setup(const char *path, int socket)
+{
+	struct vfio_device *device = NULL;
+	char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
+	char reg_get_buf[REG_INFO_GET_BUF_LEN];
+	int fds[VFIO_MAXIMUM_SPARSE_MMAP_REGISONS];
+	struct vfio_device_info dev_info = {};
+	struct vfio_irq_info irq_info = {};
+	struct vfio_irq_set *irq_set;
+	struct vfio_region_info *reg_info;
+	uint32_t i, irq_count;
+	int dev_id;
+	int ret;
+
+	device = rte_zmalloc_socket("iavf_client_vfio_user",
+				    sizeof(struct vfio_device),
+				    0, socket);
+	if (!device)
+		return NULL;
+
+	TAILQ_INIT(&device->mrs_list);
+
+	dev_id = rte_vfio_user_attach_dev(path);
+	if (dev_id < 0) {
+		rte_free(device);
+		CLIENT_LOG(ERR, "Error to setup vfio-user via path %s", path);
+		return NULL;
+	}
+
+	device->dev_id = dev_id;
+	snprintf(device->name, sizeof(device->name), "vfio-user%u", dev_id);
+	snprintf(device->path, PATH_MAX, "%s", path);
+
+	ret = rte_vfio_user_get_dev_info(dev_id, &dev_info);
+	if (ret) {
+		CLIENT_LOG(ERR, "Device get info failed");
+		goto cleanup;
+	}
+	device->pci_regions = dev_info.num_regions;
+	device->flags = dev_info.flags;
+
+	irq_info.argsz = sizeof(struct vfio_irq_info);
+	irq_info.index = VFIO_PCI_MSIX_IRQ_INDEX;
+	ret = rte_vfio_user_get_irq_info(dev_id, &irq_info);
+	if (ret) {
+		CLIENT_LOG(ERR, "IRQ get info failed");
+		goto cleanup;
+	}
+
+	if (irq_info.count) {
+		irq_count = RTE_MIN(irq_info.count,
+				    (uint32_t)IAVF_CLIENT_MAX_VECTORS);
+		if (vfio_user_create_irqfd(device, irq_count))
+			goto cleanup;
+
+		irq_set = (struct vfio_irq_set *)irq_set_buf;
+		irq_set->argsz = sizeof(irq_set_buf);
+		irq_set->count = irq_count;
+		irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
+				 VFIO_IRQ_SET_ACTION_TRIGGER;
+		irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
+		irq_set->start = 0;
+		rte_memcpy(irq_set->data, device->irqfds,
+			   sizeof(int) * IAVF_CLIENT_MAX_VECTORS);
+		ret = rte_vfio_user_set_irqs(dev_id, irq_set);
+		if (ret) {
+			CLIENT_LOG(ERR, "IRQ set failed");
+			goto cleanup;
+		}
+	}
+
+	reg_info = (struct vfio_region_info *)reg_get_buf;
+
+	for (i = 0; i < device->pci_regions; i++) {
+		memset(reg_info, 0, REG_INFO_GET_BUF_LEN);
+		memset(fds, 0, sizeof(fds));
+
+		reg_info->index = i;
+		reg_info->argsz = sizeof(struct vfio_region_info);
+		ret = rte_vfio_user_get_reg_info(dev_id, reg_info, fds);
+		if (reg_info->argsz > sizeof(struct vfio_region_info))
+			ret = rte_vfio_user_get_reg_info(dev_id, reg_info, fds);
+		if (ret) {
+			CLIENT_LOG(ERR, "Device setup bar %d failed", i);
+			goto cleanup;
+		}
+
+		device->regions[i].size = reg_info->size;
+		device->regions[i].offset = reg_info->offset;
+		device->regions[i].flags = reg_info->flags;
+
+		CLIENT_LOG(DEBUG, "Bar %d, Size 0x%llx, Offset 0x%llx,"
+			" Flags 0x%x, Cap offset %u",
+			i, reg_info->size, reg_info->offset,
+			reg_info->flags, reg_info->cap_offset);
+
+		/* Setup MMAP if any */
+		if (reg_info->size &&
+		    (reg_info->flags & VFIO_REGION_INFO_FLAG_MMAP)) {
+			/* Try to map sparse region first */
+			if (reg_info->flags & VFIO_REGION_INFO_FLAG_CAPS)
+				ret = vfio_device_setup_sparse_mmaps(device, i,
+							     reg_info, fds);
+			else
+				ret = vfio_device_map_region(device,
+						&device->regions[i], fds[0]);
+
+			if (ret != 0) {
+				CLIENT_LOG(ERR, "Setup Device %s region %d failed",
+					   device->name, i);
+				goto cleanup;
+			}
+		}
+	}
+
+	/* Register DMA Region */
+	ret = vfio_device_dma_map(device);
+	if (ret) {
+		CLIENT_LOG(ERR, "Container DMA map failed");
+		goto cleanup;
+	}
+
+	CLIENT_LOG(DEBUG, "Device %s, Path %s Setup Successfully",
+		   device->name, device->path);
+
+	if (rte_mem_event_callback_register(IAVF_MEM_EVENT_CLB_NAME,
+				iavf_mem_event_cb, device)) {
+		if (rte_errno != ENOTSUP) {
+			CLIENT_LOG(ERR, "Failed to register mem event"
+					" callback");
+			goto cleanup;
+		}
+	}
+	return device;
+
+cleanup:
+	rte_vfio_user_detach_dev(dev_id);
+	rte_free(device);
+	return NULL;
+}
+
+void
+client_vfio_user_release(struct vfio_device *dev)
+{
+	rte_mem_event_callback_unregister(IAVF_MEM_EVENT_CLB_NAME, dev);
+
+	vfio_device_unmap_bars(dev);
+	vfio_device_dma_unmap(dev);
+	rte_vfio_user_detach_dev(dev->dev_id);
+
+	rte_free(dev);
+}
+
+void *
+client_vfio_user_get_bar_addr(struct vfio_device *dev, uint32_t index,
+			      uint64_t offset, uint32_t len)
+{
+	struct vfio_pci_region *region = &dev->regions[index];
+	uint32_t i;
+
+	if (!region->size || !(region->flags & VFIO_REGION_INFO_FLAG_MMAP))
+		return NULL;
+
+	for (i = 0; i < region->nr_mmaps; i++) {
+		if (region->mmaps[i].mem &&
+		    (region->mmaps[i].offset <= offset) &&
+		    ((offset + len) <= (region->mmaps[i].offset + region->mmaps[i].size))) {
+			return (void *)((uintptr_t)region->mmaps[i].mem + \
+					offset - region->mmaps[i].offset);
+		}
+	}
+
+	return NULL;
+}
+
+int
+client_vfio_user_pci_bar_access(struct vfio_device *dev, uint32_t index,
+				uint64_t offset, size_t len,
+				void *buf, bool is_write)
+{
+	struct vfio_pci_region *region = &dev->regions[index];
+	uint64_t sparse_size, sparse_offset, bar_addr;
+	uint32_t i;
+	int ret;
+
+	if ((offset + len > region->size) ||
+	    (is_write && !(region->flags & VFIO_REGION_INFO_FLAG_WRITE)) ||
+	    (!is_write && !(region->flags & VFIO_REGION_INFO_FLAG_READ)))
+		return -EINVAL;
+
+	/* Read/write through MMAP */
+	for (i = 0; i < region->nr_mmaps; i++) {
+		sparse_offset = region->mmaps[i].offset;
+		sparse_size = region->mmaps[i].offset + region->mmaps[i].size;
+
+		if ((offset >= sparse_offset) &&
+		    (offset + len <= sparse_size)) {
+			bar_addr = (uint64_t)(uintptr_t)region->mmaps[i].mem +
+				offset - sparse_offset;
+			if (is_write)
+				rte_memcpy((void *)bar_addr, buf, len);
+			else
+				rte_memcpy(buf, (void *)bar_addr, len);
+
+			return 0;
+		}
+	}
+
+	/* Read/write through message */
+	if (is_write)
+		ret = rte_vfio_user_region_write(dev->dev_id, index,
+						 offset, len, buf);
+	else
+		ret = rte_vfio_user_region_read(dev->dev_id, index,
+						 offset, len, buf);
+	return ret;
+}
diff --git a/drivers/common/iavf/vfio_user/vfio_user_pci.h b/drivers/common/iavf/vfio_user/vfio_user_pci.h
new file mode 100644
index 0000000000..8a312a472c
--- /dev/null
+++ b/drivers/common/iavf/vfio_user/vfio_user_pci.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _VFIO_USER_PCI_H_
+#define _VFIO_USER_PCI_H_
+
+#include <linux/vfio.h>
+#include <linux/limits.h>
+
+#define IAVF_CLIENT_MAX_VECTORS			17
+#define VFIO_MAXIMUM_SPARSE_MMAP_REGISONS	8
+
+struct vfio_memory_region {
+	TAILQ_ENTRY(vfio_memory_region) link;
+	uint64_t iova;
+	uint64_t size; /* bytes */
+	uint64_t vaddr;
+	uint64_t offset;
+	int fd;
+};
+
+struct vfio_sparse_mmaps {
+	void *mem;
+	uint64_t offset;
+	size_t size;
+};
+
+struct vfio_pci_region {
+	uint64_t offset;
+	size_t size;
+	uint64_t flags;
+	uint32_t nr_mmaps;
+	struct vfio_sparse_mmaps mmaps[VFIO_MAXIMUM_SPARSE_MMAP_REGISONS];
+};
+
+TAILQ_HEAD(vfio_memory_region_list, vfio_memory_region);
+
+struct vfio_device {
+	int dev_id;
+	char name[64];
+	char path[PATH_MAX];
+	uint64_t flags;
+	uint32_t pci_regions;
+	uint32_t nb_mrs;
+	uint32_t nb_irqs;
+	struct vfio_pci_region regions[VFIO_PCI_NUM_REGIONS];
+	int irqfds[IAVF_CLIENT_MAX_VECTORS];
+	struct vfio_memory_region_list mrs_list;
+};
+
+extern int iavf_common_logger;
+#define CLIENT_LOG(level, fmt, args...) \
+	rte_log(RTE_LOG_ ## level, iavf_common_logger, "%s(): " fmt "\n", \
+		__func__, ## args)
+
+__rte_internal
+struct vfio_device *client_vfio_user_setup(const char *path, int socket);
+__rte_internal
+void client_vfio_user_release(struct vfio_device *dev);
+__rte_internal
+void *client_vfio_user_get_bar_addr(struct vfio_device *dev, uint32_t index,
+				    uint64_t offset, uint32_t len);
+int client_vfio_user_pci_bar_access(struct vfio_device *dev, uint32_t index,
+				    uint64_t offset, size_t len, void *buf,
+				    bool is_write);
+
+#endif /* _VFIO_USER_PCI_H_ */
-- 
2.21.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [dpdk-dev] [PATCH v3 2/5] net/iavf_client: introduce iavf driver on vfio-user client
  2021-01-07  8:27   ` [dpdk-dev] [PATCH v3 0/5] introduce new iavf driver on vfio-user client Jingjing Wu
  2021-01-07  8:27     ` [dpdk-dev] [PATCH v3 1/5] common/iavf: emulated pci interfaces " Jingjing Wu
@ 2021-01-07  8:27     ` Jingjing Wu
  2021-01-07  8:27     ` [dpdk-dev] [PATCH v3 3/5] net/iavf_client: enable interrupt on control queue Jingjing Wu
                       ` (2 subsequent siblings)
  4 siblings, 0 replies; 18+ messages in thread
From: Jingjing Wu @ 2021-01-07  8:27 UTC (permalink / raw)
  To: dev; +Cc: jingjing.wu, beilei.xing, chenbo.xia, xiuchun.lu

This patch add a new net driver based on vdev abstraction,
i.e. iavf_client_ethdev.c. It is using common iavf functions
to talk with Emulated pci interfaces based on vfio-user.

      ----------------------
      | ------------------ |
      | |  iavf driver   | |----> (iavf_client_ethdev.c)
      | ------------------ |
      | ------------------ |
      | | device emulate | |
      | | vfio-user adapt| |
      | ------------------ |
      ----------------------
                |
                |
      ----------------------
      |      vfio-user     |
      |       client       |
      ----------------------

Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
---
 drivers/common/iavf/iavf_prototype.h  |   1 +
 drivers/common/iavf/version.map       |   1 +
 drivers/net/iavf/iavf.h               |  18 +-
 drivers/net/iavf/iavf_client_ethdev.c | 290 ++++++++++++++++++++++++++
 drivers/net/iavf/iavf_ethdev.c        |  26 +--
 drivers/net/iavf/iavf_rxtx.c          |  23 +-
 drivers/net/iavf/meson.build          |   1 +
 7 files changed, 339 insertions(+), 21 deletions(-)
 create mode 100644 drivers/net/iavf/iavf_client_ethdev.c

diff --git a/drivers/common/iavf/iavf_prototype.h b/drivers/common/iavf/iavf_prototype.h
index f34e77db0f..3998d26dc0 100644
--- a/drivers/common/iavf/iavf_prototype.h
+++ b/drivers/common/iavf/iavf_prototype.h
@@ -83,6 +83,7 @@ void iavf_destroy_spinlock(struct iavf_spinlock *sp);
 __rte_internal
 void iavf_vf_parse_hw_config(struct iavf_hw *hw,
 			     struct virtchnl_vf_resource *msg);
+__rte_internal
 enum iavf_status iavf_vf_reset(struct iavf_hw *hw);
 __rte_internal
 enum iavf_status iavf_aq_send_msg_to_pf(struct iavf_hw *hw,
diff --git a/drivers/common/iavf/version.map b/drivers/common/iavf/version.map
index 883d919487..23c3577b3e 100644
--- a/drivers/common/iavf/version.map
+++ b/drivers/common/iavf/version.map
@@ -7,6 +7,7 @@ INTERNAL {
 	iavf_set_mac_type;
 	iavf_shutdown_adminq;
 	iavf_vf_parse_hw_config;
+	iavf_vf_reset;
 	client_vfio_user_setup;
 	client_vfio_user_release;
 	client_vfio_user_get_bar_addr;
diff --git a/drivers/net/iavf/iavf.h b/drivers/net/iavf/iavf.h
index 6d5912d8c1..c34f971721 100644
--- a/drivers/net/iavf/iavf.h
+++ b/drivers/net/iavf/iavf.h
@@ -195,7 +195,10 @@ struct iavf_adapter {
 	struct iavf_hw hw;
 	struct rte_eth_dev *eth_dev;
 	struct iavf_info vf;
-
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+	/* used for avf_client driver */
+	struct vfio_device *user_dev;
+#endif
 	bool rx_bulk_alloc_allowed;
 	/* For vector PMD */
 	bool rx_vec_allowed;
@@ -231,6 +234,16 @@ iavf_init_adminq_parameter(struct iavf_hw *hw)
 	hw->aq.asq_buf_size = IAVF_AQ_BUF_SZ;
 }
 
+static inline void
+iavf_disable_irq0(struct iavf_hw *hw)
+{
+	/* Disable all interrupt types */
+	IAVF_WRITE_REG(hw, IAVF_VFINT_ICR0_ENA1, 0);
+	IAVF_WRITE_REG(hw, IAVF_VFINT_DYN_CTL01,
+		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+	IAVF_WRITE_FLUSH(hw);
+}
+
 static inline uint16_t
 iavf_calc_itr_interval(int16_t interval)
 {
@@ -284,6 +297,9 @@ _atomic_set_cmd(struct iavf_info *vf, enum virtchnl_ops ops)
 	return !ret;
 }
 
+extern const struct eth_dev_ops iavf_eth_dev_ops;
+
+int iavf_init_vf(struct rte_eth_dev *dev);
 int iavf_check_api_version(struct iavf_adapter *adapter);
 int iavf_get_vf_resource(struct iavf_adapter *adapter);
 void iavf_handle_virtchnl_msg(struct rte_eth_dev *dev);
diff --git a/drivers/net/iavf/iavf_client_ethdev.c b/drivers/net/iavf/iavf_client_ethdev.c
new file mode 100644
index 0000000000..989f9d6062
--- /dev/null
+++ b/drivers/net/iavf/iavf_client_ethdev.c
@@ -0,0 +1,290 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_vdev.h>
+#include <rte_alarm.h>
+#include <rte_bus_vdev.h>
+#include <rte_malloc.h>
+#include <vfio_user/vfio_user_pci.h>
+
+#include "iavf.h"
+#include "iavf_rxtx.h"
+
+static int iavf_client_dev_close(struct rte_eth_dev *dev);
+static int iavf_client_dev_reset(struct rte_eth_dev *dev);
+
+/* set iavf_client_dev_ops to iavf's by default */
+static struct eth_dev_ops iavf_client_eth_dev_ops;
+
+static const char *valid_args[] = {
+#define AVF_CLIENT_ARG_PATH           "path"
+	AVF_CLIENT_ARG_PATH,
+	NULL
+};
+
+/* set up vfio_device for iavf_client*/
+static int
+iavf_client_vfio_user_setup(struct rte_eth_dev *dev, const char *path)
+{
+	struct iavf_adapter *adapter =
+		IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(adapter);
+	struct vfio_device *vfio_dev;
+
+	vfio_dev = client_vfio_user_setup(path, dev->device->numa_node);
+	if (vfio_dev == NULL) {
+		PMD_INIT_LOG(ERR, "Error to create vfio_device for iavf_client\n");
+		return -1;
+	}
+	hw->bus.type = iavf_bus_type_vfio_user;
+
+	/* Use hw_addr to record dev ptr */
+	hw->hw_addr = (uint8_t *)vfio_dev;
+
+	hw->back = IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+
+	if (!dev->intr_handle) {
+		dev->intr_handle = rte_zmalloc_socket("iavf_client_intr",
+				sizeof(*dev->intr_handle),
+				0, dev->device->numa_node);
+		if (!dev->intr_handle) {
+			PMD_INIT_LOG(ERR, "fail to allocate intr_handle");
+			return -1;
+		}
+
+	}
+
+	dev->intr_handle->fd = -1;
+	dev->intr_handle->type = RTE_INTR_HANDLE_VDEV;
+	dev->intr_handle->max_intr = 1;
+
+	return 0;
+}
+
+
+static inline void
+avf_client_init_eth_ops(void)
+{
+	iavf_client_eth_dev_ops = iavf_eth_dev_ops;
+	/* keep other unchanged */
+	iavf_client_eth_dev_ops.dev_close  = iavf_client_dev_close,
+	iavf_client_eth_dev_ops.dev_reset  = iavf_client_dev_reset,
+	iavf_client_eth_dev_ops.dev_supported_ptypes_get   = NULL;
+	iavf_client_eth_dev_ops.reta_update                = NULL;
+	iavf_client_eth_dev_ops.reta_query                 = NULL;
+	iavf_client_eth_dev_ops.rss_hash_update            = NULL;
+	iavf_client_eth_dev_ops.rss_hash_conf_get          = NULL;
+	iavf_client_eth_dev_ops.rx_queue_intr_enable       = NULL;
+	iavf_client_eth_dev_ops.rx_queue_intr_disable      = NULL;
+}
+
+#define IAVF_CLIENT_ALARM_INTERVAL 50000 /* us */
+static void
+iavf_client_dev_alarm_handler(void *param)
+{
+	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
+
+	iavf_handle_virtchnl_msg(dev);
+
+	rte_eal_alarm_set(IAVF_CLIENT_ALARM_INTERVAL,
+			  iavf_client_dev_alarm_handler, dev);
+}
+
+/* init ethdev for the avf client device*/
+static int
+iavf_client_eth_init(struct rte_eth_dev *eth_dev)
+{
+	struct iavf_adapter *adapter =
+		IAVF_DEV_PRIVATE_TO_ADAPTER(eth_dev->data->dev_private);
+	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(adapter);
+
+	/* update eth_dev_op by assigning ops func pointer */
+	avf_client_init_eth_ops();
+	eth_dev->dev_ops = (const struct eth_dev_ops *)(&iavf_client_eth_dev_ops);
+
+	eth_dev->rx_pkt_burst = &iavf_recv_pkts;
+	eth_dev->tx_pkt_burst = &iavf_xmit_pkts;
+	eth_dev->tx_pkt_prepare = &iavf_prep_pkts;
+
+	hw->back = IAVF_DEV_PRIVATE_TO_ADAPTER(eth_dev->data->dev_private);
+	adapter->eth_dev = eth_dev;
+	adapter->stopped = 1;
+
+	if (iavf_init_vf(eth_dev) != 0) {
+		PMD_INIT_LOG(ERR, "Init vf failed");
+		return -1;
+	}
+
+	/* set default ptype table */
+	adapter->ptype_tbl = iavf_get_default_ptype_table();
+
+	/* copy mac addr */
+	eth_dev->data->mac_addrs = rte_zmalloc(
+			"iavf_client_mac",
+			RTE_ETHER_ADDR_LEN * IAVF_NUM_MACADDR_MAX, 0);
+	if (!eth_dev->data->mac_addrs) {
+		PMD_INIT_LOG(ERR, "Failed to allocate %d bytes needed to"
+			     " store MAC addresses",
+			     RTE_ETHER_ADDR_LEN * IAVF_NUM_MACADDR_MAX);
+		return -ENOMEM;
+	}
+	/* If the MAC address is not configured by host,
+	 * generate a random one.
+	 */
+	if (!rte_is_valid_assigned_ether_addr(
+			(struct rte_ether_addr *)hw->mac.addr))
+		rte_eth_random_addr(hw->mac.addr);
+	rte_ether_addr_copy((struct rte_ether_addr *)hw->mac.addr,
+			&eth_dev->data->mac_addrs[0]);
+
+	rte_eal_alarm_set(IAVF_CLIENT_ALARM_INTERVAL,
+			  iavf_client_dev_alarm_handler, eth_dev);
+	return 0;
+}
+
+static int
+iavf_client_dev_reset(struct rte_eth_dev *dev)
+{
+	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int ret;
+
+	rte_eal_alarm_cancel(iavf_client_dev_alarm_handler, dev);
+
+	iavf_shutdown_adminq(hw);
+	ret = iavf_init_vf(dev);
+
+	/* send reset msg to PF */
+	iavf_vf_reset(hw);
+	rte_eal_alarm_set(IAVF_CLIENT_ALARM_INTERVAL,
+			  iavf_client_dev_alarm_handler, dev);
+
+	return ret;
+}
+
+static int
+iavf_client_dev_close(struct rte_eth_dev *dev)
+{
+	struct iavf_adapter *adapter =
+		IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	if (!adapter->stopped) {
+		iavf_stop_queues(dev);
+
+		if (dev->intr_handle) {
+			rte_free(dev->intr_handle);
+			dev->intr_handle = NULL;
+		}
+
+		/* Remove all mac addrs */
+		iavf_add_del_all_mac_addr(adapter, false);
+		adapter->stopped = 1;
+	}
+	iavf_shutdown_adminq(hw);
+	iavf_disable_irq0(hw);
+	rte_eal_alarm_cancel(iavf_client_dev_alarm_handler, dev);
+	client_vfio_user_release((struct vfio_device *)hw->hw_addr);
+	return 0;
+}
+
+static int
+iavf_client_get_string_arg(const char *key __rte_unused,
+	       const char *value, void *extra_args)
+{
+	if (!value || !extra_args)
+		return -EINVAL;
+
+	*(char **)extra_args = strdup(value);
+
+	if (!*(char **)extra_args)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int
+iavf_client_pmd_probe(struct rte_vdev_device *vdev)
+{
+	struct rte_kvargs *kvlist = NULL;
+	struct rte_eth_dev *eth_dev;
+	struct iavf_adapter *adapter;
+	char *path = NULL;
+	int ret;
+
+	kvlist = rte_kvargs_parse(rte_vdev_device_args(vdev), valid_args);
+	if (!kvlist) {
+		PMD_INIT_LOG(ERR, "error when parsing param");
+		return -EINVAL;
+	}
+
+	if (rte_kvargs_count(kvlist, AVF_CLIENT_ARG_PATH) == 1) {
+		if (rte_kvargs_process(kvlist, AVF_CLIENT_ARG_PATH,
+				       &iavf_client_get_string_arg, &path) < 0) {
+			PMD_INIT_LOG(ERR, "error to parse %s",
+				     AVF_CLIENT_ARG_PATH);
+			return -EINVAL;
+		}
+	} else {
+		PMD_INIT_LOG(ERR, "arg %s is mandatory for iavf_client",
+			     AVF_CLIENT_ARG_PATH);
+		return -EINVAL;
+	}
+
+	eth_dev = rte_eth_vdev_allocate(vdev, sizeof(*adapter));
+
+	ret = iavf_client_vfio_user_setup(eth_dev, path);
+	if (ret) {
+		goto err;
+	}
+
+	ret = iavf_client_eth_init(eth_dev);
+	if (ret) {
+		goto err;
+	}
+
+	rte_eth_dev_probing_finish(eth_dev);
+	rte_kvargs_free(kvlist);
+
+	return 0;
+err:
+	rte_eth_dev_release_port(eth_dev);
+	rte_kvargs_free(kvlist);
+	return ret;
+}
+
+
+static int
+iavf_client_pmd_remove(struct rte_vdev_device *vdev)
+{
+	struct rte_eth_dev *eth_dev = NULL;
+
+	if (vdev == NULL)
+		return -1;
+
+	/* find the ethdev entry */
+	eth_dev = rte_eth_dev_allocated(rte_vdev_device_name(vdev));
+	if (eth_dev == NULL)
+		return 0;
+
+	iavf_client_dev_close(eth_dev);
+	rte_eth_dev_release_port(eth_dev);
+	return 0;
+}
+
+static struct rte_vdev_driver iavf_client_driver = {
+	.probe = iavf_client_pmd_probe,
+	.remove = iavf_client_pmd_remove,
+};
+
+RTE_PMD_REGISTER_VDEV(net_iavf_client, iavf_client_driver);
+RTE_PMD_REGISTER_ALIAS(net_iavf_client, iavf_client);
+RTE_PMD_REGISTER_PARAM_STRING(net_iavf_client,
+	"path=<path>");
diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
index 7e3c26a94e..6b5e47adf2 100644
--- a/drivers/net/iavf/iavf_ethdev.c
+++ b/drivers/net/iavf/iavf_ethdev.c
@@ -154,7 +154,7 @@ static const struct rte_iavf_xstats_name_off rte_iavf_stats_strings[] = {
 #define IAVF_NB_XSTATS (sizeof(rte_iavf_stats_strings) / \
 		sizeof(rte_iavf_stats_strings[0]))
 
-static const struct eth_dev_ops iavf_eth_dev_ops = {
+const struct eth_dev_ops iavf_eth_dev_ops = {
 	.dev_configure              = iavf_dev_configure,
 	.dev_start                  = iavf_dev_start,
 	.dev_stop                   = iavf_dev_stop,
@@ -1780,7 +1780,7 @@ iavf_init_proto_xtr(struct rte_eth_dev *dev)
 	}
 }
 
-static int
+int
 iavf_init_vf(struct rte_eth_dev *dev)
 {
 	int err, bufsz;
@@ -1789,12 +1789,6 @@ iavf_init_vf(struct rte_eth_dev *dev)
 	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
 
-	err = iavf_parse_devargs(dev);
-	if (err) {
-		PMD_INIT_LOG(ERR, "Failed to parse devargs");
-		goto err;
-	}
-
 	err = iavf_set_mac_type(hw);
 	if (err) {
 		PMD_INIT_LOG(ERR, "set_mac_type failed: %d", err);
@@ -1891,16 +1885,6 @@ iavf_enable_irq0(struct iavf_hw *hw)
 	IAVF_WRITE_FLUSH(hw);
 }
 
-static inline void
-iavf_disable_irq0(struct iavf_hw *hw)
-{
-	/* Disable all interrupt types */
-	IAVF_WRITE_REG(hw, IAVF_VFINT_ICR0_ENA1, 0);
-	IAVF_WRITE_REG(hw, IAVF_VFINT_DYN_CTL01,
-		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
-	IAVF_WRITE_FLUSH(hw);
-}
-
 static void
 iavf_dev_interrupt_handler(void *param)
 {
@@ -1986,6 +1970,12 @@ iavf_dev_init(struct rte_eth_dev *eth_dev)
 	adapter->eth_dev = eth_dev;
 	adapter->stopped = 1;
 
+	ret  = iavf_parse_devargs(eth_dev);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "Failed to parse devargs");
+		return ret;
+	}
+
 	if (iavf_init_vf(eth_dev) != 0) {
 		PMD_INIT_LOG(ERR, "Init vf failed");
 		return -1;
diff --git a/drivers/net/iavf/iavf_rxtx.c b/drivers/net/iavf/iavf_rxtx.c
index 21d508b3f4..d8192f3675 100644
--- a/drivers/net/iavf/iavf_rxtx.c
+++ b/drivers/net/iavf/iavf_rxtx.c
@@ -24,6 +24,9 @@
 #include <rte_ip.h>
 #include <rte_net.h>
 #include <rte_vect.h>
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+#include <vfio_user/vfio_user_pci.h>
+#endif
 
 #include "iavf.h"
 #include "iavf_rxtx.h"
@@ -595,7 +598,15 @@ iavf_dev_rx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_idx,
 	reset_rx_queue(rxq);
 	rxq->q_set = true;
 	dev->data->rx_queues[queue_idx] = rxq;
-	rxq->qrx_tail = hw->hw_addr + IAVF_QRX_TAIL1(rxq->queue_id);
+
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+	if (hw->bus.type == iavf_bus_type_vfio_user)
+		rxq->qrx_tail = client_vfio_user_get_bar_addr(
+				(struct vfio_device *)hw->hw_addr, 0,
+				IAVF_QRX_TAIL1(rxq->queue_id), 4);
+	else
+#endif
+		rxq->qrx_tail = hw->hw_addr + IAVF_QRX_TAIL1(rxq->queue_id);
 	rxq->ops = &def_rxq_ops;
 
 	if (check_rx_bulk_allow(rxq) == true) {
@@ -705,7 +716,15 @@ iavf_dev_tx_queue_setup(struct rte_eth_dev *dev,
 	reset_tx_queue(txq);
 	txq->q_set = true;
 	dev->data->tx_queues[queue_idx] = txq;
-	txq->qtx_tail = hw->hw_addr + IAVF_QTX_TAIL1(queue_idx);
+#ifdef RTE_LIBRTE_IAVF_CLIENT
+	if (hw->bus.type == iavf_bus_type_vfio_user)
+		txq->qtx_tail = client_vfio_user_get_bar_addr(
+			(struct vfio_device *)hw->hw_addr, 0,
+			IAVF_QTX_TAIL1(queue_idx), 4);
+	else
+#endif
+		txq->qtx_tail = hw->hw_addr + IAVF_QTX_TAIL1(queue_idx);
+
 	txq->ops = &def_txq_ops;
 
 	if (check_tx_vec_allow(txq) == false) {
diff --git a/drivers/net/iavf/meson.build b/drivers/net/iavf/meson.build
index 26c02c4401..580307c462 100644
--- a/drivers/net/iavf/meson.build
+++ b/drivers/net/iavf/meson.build
@@ -13,6 +13,7 @@ sources = files(
 	'iavf_generic_flow.c',
 	'iavf_fdir.c',
 	'iavf_hash.c',
+	'iavf_client_ethdev.c',
 )
 
 if arch_subdir == 'x86'
-- 
2.21.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [dpdk-dev] [PATCH v3 3/5] net/iavf_client: enable interrupt on control queue
  2021-01-07  8:27   ` [dpdk-dev] [PATCH v3 0/5] introduce new iavf driver on vfio-user client Jingjing Wu
  2021-01-07  8:27     ` [dpdk-dev] [PATCH v3 1/5] common/iavf: emulated pci interfaces " Jingjing Wu
  2021-01-07  8:27     ` [dpdk-dev] [PATCH v3 2/5] net/iavf_client: introduce iavf driver " Jingjing Wu
@ 2021-01-07  8:27     ` Jingjing Wu
  2021-01-07  8:27     ` [dpdk-dev] [PATCH v3 4/5] net/iavf_client: enable interrupt of Rx queue Jingjing Wu
  2021-01-07  8:27     ` [dpdk-dev] [PATCH v3 5/5] net/iavf: fix vector mapping with queue Jingjing Wu
  4 siblings, 0 replies; 18+ messages in thread
From: Jingjing Wu @ 2021-01-07  8:27 UTC (permalink / raw)
  To: dev; +Cc: jingjing.wu, beilei.xing, chenbo.xia, xiuchun.lu

New devarg "intr": if intr=1, use interrupt mode on control queue

Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
---
 drivers/net/iavf/iavf.h               |  19 ++++
 drivers/net/iavf/iavf_client_ethdev.c | 131 ++++++++++++++++++++++----
 drivers/net/iavf/iavf_ethdev.c        |  18 +---
 3 files changed, 134 insertions(+), 34 deletions(-)

diff --git a/drivers/net/iavf/iavf.h b/drivers/net/iavf/iavf.h
index c34f971721..5516ecf021 100644
--- a/drivers/net/iavf/iavf.h
+++ b/drivers/net/iavf/iavf.h
@@ -198,6 +198,7 @@ struct iavf_adapter {
 #ifdef RTE_LIBRTE_IAVF_CLIENT
 	/* used for avf_client driver */
 	struct vfio_device *user_dev;
+	int intr_mode; /* interrupt mode if true */
 #endif
 	bool rx_bulk_alloc_allowed;
 	/* For vector PMD */
@@ -234,6 +235,22 @@ iavf_init_adminq_parameter(struct iavf_hw *hw)
 	hw->aq.asq_buf_size = IAVF_AQ_BUF_SZ;
 }
 
+/* Enable default admin queue interrupt setting */
+static inline void
+iavf_enable_irq0(struct iavf_hw *hw)
+{
+	/* Enable admin queue interrupt trigger */
+	IAVF_WRITE_REG(hw, IAVF_VFINT_ICR0_ENA1,
+		       IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK);
+
+	IAVF_WRITE_REG(hw, IAVF_VFINT_DYN_CTL01,
+		       IAVF_VFINT_DYN_CTL01_INTENA_MASK |
+		       IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK |
+		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+	IAVF_WRITE_FLUSH(hw);
+}
+
 static inline void
 iavf_disable_irq0(struct iavf_hw *hw)
 {
@@ -342,4 +359,6 @@ int iavf_add_del_mc_addr_list(struct iavf_adapter *adapter,
 			uint32_t mc_addrs_num, bool add);
 int iavf_request_queues(struct iavf_adapter *adapter, uint16_t num);
 int iavf_get_max_rss_queue_region(struct iavf_adapter *adapter);
+void iavf_dev_interrupt_handler(void *param);
+
 #endif /* _IAVF_ETHDEV_H_ */
diff --git a/drivers/net/iavf/iavf_client_ethdev.c b/drivers/net/iavf/iavf_client_ethdev.c
index 989f9d6062..770a7a8200 100644
--- a/drivers/net/iavf/iavf_client_ethdev.c
+++ b/drivers/net/iavf/iavf_client_ethdev.c
@@ -6,6 +6,8 @@
 #include <stdint.h>
 #include <string.h>
 
+#include <sys/eventfd.h>
+
 #include <rte_common.h>
 #include <rte_ether.h>
 #include <rte_ethdev_driver.h>
@@ -18,6 +20,9 @@
 #include "iavf.h"
 #include "iavf_rxtx.h"
 
+#define AVF_CLIENT_ARG_PATH           "path"
+#define AVF_CLIENT_ARG_INTR           "intr"
+
 static int iavf_client_dev_close(struct rte_eth_dev *dev);
 static int iavf_client_dev_reset(struct rte_eth_dev *dev);
 
@@ -25,11 +30,27 @@ static int iavf_client_dev_reset(struct rte_eth_dev *dev);
 static struct eth_dev_ops iavf_client_eth_dev_ops;
 
 static const char *valid_args[] = {
-#define AVF_CLIENT_ARG_PATH           "path"
 	AVF_CLIENT_ARG_PATH,
+	AVF_CLIENT_ARG_INTR,
 	NULL
 };
 
+static void
+iavf_client_event_handler(void *param)
+{
+	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
+	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	eventfd_t buf;
+
+	eventfd_read(dev->intr_handle->fd, &buf);
+
+	iavf_disable_irq0(hw);
+
+	iavf_handle_virtchnl_msg(dev);
+
+	iavf_enable_irq0(hw);
+}
+
 /* set up vfio_device for iavf_client*/
 static int
 iavf_client_vfio_user_setup(struct rte_eth_dev *dev, const char *path)
@@ -51,6 +72,11 @@ iavf_client_vfio_user_setup(struct rte_eth_dev *dev, const char *path)
 
 	hw->back = IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
 
+	if (!vfio_dev->nb_irqs && adapter->intr_mode) {
+		PMD_INIT_LOG(ERR, "No irq support on device");
+		return -1;
+	}
+
 	if (!dev->intr_handle) {
 		dev->intr_handle = rte_zmalloc_socket("iavf_client_intr",
 				sizeof(*dev->intr_handle),
@@ -62,7 +88,7 @@ iavf_client_vfio_user_setup(struct rte_eth_dev *dev, const char *path)
 
 	}
 
-	dev->intr_handle->fd = -1;
+	dev->intr_handle->fd = vfio_dev->irqfds[0];
 	dev->intr_handle->type = RTE_INTR_HANDLE_VDEV;
 	dev->intr_handle->max_intr = 1;
 
@@ -145,26 +171,52 @@ iavf_client_eth_init(struct rte_eth_dev *eth_dev)
 	rte_ether_addr_copy((struct rte_ether_addr *)hw->mac.addr,
 			&eth_dev->data->mac_addrs[0]);
 
-	rte_eal_alarm_set(IAVF_CLIENT_ALARM_INTERVAL,
-			  iavf_client_dev_alarm_handler, eth_dev);
+	if (adapter->intr_mode) {
+		/* register callback func to eal lib */
+		rte_intr_callback_register(eth_dev->intr_handle,
+					   iavf_client_event_handler,
+					   (void *)eth_dev);
+		iavf_enable_irq0(hw);
+	} else {
+		rte_eal_alarm_set(IAVF_CLIENT_ALARM_INTERVAL,
+				  iavf_client_dev_alarm_handler, eth_dev);
+	}
 	return 0;
 }
 
 static int
 iavf_client_dev_reset(struct rte_eth_dev *dev)
 {
+	struct iavf_adapter *adapter =
+		IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
 	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct rte_intr_handle *intr_handle = dev->intr_handle;
 	int ret;
 
-	rte_eal_alarm_cancel(iavf_client_dev_alarm_handler, dev);
+	if (adapter->intr_mode) {
+		iavf_disable_irq0(hw);
+		/* unregister callback func from eal lib */
+		rte_intr_callback_unregister(intr_handle,
+					     iavf_client_event_handler, dev);
+	} else {
+		rte_eal_alarm_cancel(iavf_client_dev_alarm_handler, dev);
+	}
 
 	iavf_shutdown_adminq(hw);
 	ret = iavf_init_vf(dev);
 
 	/* send reset msg to PF */
 	iavf_vf_reset(hw);
-	rte_eal_alarm_set(IAVF_CLIENT_ALARM_INTERVAL,
-			  iavf_client_dev_alarm_handler, dev);
+	if (adapter->intr_mode) {
+		/* register callback func to eal lib */
+		rte_intr_callback_register(dev->intr_handle,
+					   iavf_client_event_handler,
+					   (void *)dev);
+		iavf_enable_irq0(hw);
+	} else {
+		rte_eal_alarm_set(IAVF_CLIENT_ALARM_INTERVAL,
+				  iavf_client_dev_alarm_handler, dev);
+	}
 
 	return ret;
 }
@@ -176,6 +228,15 @@ iavf_client_dev_close(struct rte_eth_dev *dev)
 		IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
 	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
+	if (adapter->intr_mode) {
+		iavf_disable_irq0(hw);
+		/* unregister callback func from eal lib */
+		rte_intr_callback_unregister(dev->intr_handle,
+					     iavf_client_event_handler, dev);
+	} else {
+		rte_eal_alarm_cancel(iavf_client_dev_alarm_handler, dev);
+	}
+
 	if (!adapter->stopped) {
 		iavf_stop_queues(dev);
 
@@ -188,10 +249,10 @@ iavf_client_dev_close(struct rte_eth_dev *dev)
 		iavf_add_del_all_mac_addr(adapter, false);
 		adapter->stopped = 1;
 	}
+
 	iavf_shutdown_adminq(hw);
-	iavf_disable_irq0(hw);
-	rte_eal_alarm_cancel(iavf_client_dev_alarm_handler, dev);
 	client_vfio_user_release((struct vfio_device *)hw->hw_addr);
+
 	return 0;
 }
 
@@ -210,6 +271,23 @@ iavf_client_get_string_arg(const char *key __rte_unused,
 	return 0;
 }
 
+static int
+iavf_client_intr_check(__rte_unused const char *key,
+			const char *value, void *opaque)
+{
+	int *intr = (int *)opaque;
+	int ret = 0;
+
+	if (!strcmp(value, "1"))
+		*intr  = 1;
+	else if (!strcmp(value, "0"))
+		*intr = 0;
+	else
+		ret = -1;
+
+	return ret;
+}
+
 static int
 iavf_client_pmd_probe(struct rte_vdev_device *vdev)
 {
@@ -217,6 +295,7 @@ iavf_client_pmd_probe(struct rte_vdev_device *vdev)
 	struct rte_eth_dev *eth_dev;
 	struct iavf_adapter *adapter;
 	char *path = NULL;
+	int intr_mode = 0;
 	int ret;
 
 	kvlist = rte_kvargs_parse(rte_vdev_device_args(vdev), valid_args);
@@ -227,35 +306,52 @@ iavf_client_pmd_probe(struct rte_vdev_device *vdev)
 
 	if (rte_kvargs_count(kvlist, AVF_CLIENT_ARG_PATH) == 1) {
 		if (rte_kvargs_process(kvlist, AVF_CLIENT_ARG_PATH,
-				       &iavf_client_get_string_arg, &path) < 0) {
+					&iavf_client_get_string_arg,
+					&path) < 0) {
 			PMD_INIT_LOG(ERR, "error to parse %s",
 				     AVF_CLIENT_ARG_PATH);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto free_kvlist;
 		}
 	} else {
 		PMD_INIT_LOG(ERR, "arg %s is mandatory for iavf_client",
 			     AVF_CLIENT_ARG_PATH);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto free_kvlist;
+	}
+
+	if (rte_kvargs_count(kvlist, AVF_CLIENT_ARG_INTR) == 1) {
+		if (rte_kvargs_process(kvlist, AVF_CLIENT_ARG_INTR,
+					iavf_client_intr_check,
+					&intr_mode) < 0) {
+			PMD_INIT_LOG(ERR, "arg %s must be 1 or 0",
+				     AVF_CLIENT_ARG_INTR);
+			ret = -EINVAL;
+			goto free_kvlist;
+		}
 	}
 
 	eth_dev = rte_eth_vdev_allocate(vdev, sizeof(*adapter));
 
 	ret = iavf_client_vfio_user_setup(eth_dev, path);
-	if (ret) {
+	if (ret)
 		goto err;
-	}
+
+	adapter = IAVF_DEV_PRIVATE_TO_ADAPTER(eth_dev->data->dev_private);
+	adapter->intr_mode = intr_mode;
 
 	ret = iavf_client_eth_init(eth_dev);
-	if (ret) {
+	if (ret)
 		goto err;
-	}
 
 	rte_eth_dev_probing_finish(eth_dev);
+
 	rte_kvargs_free(kvlist);
 
 	return 0;
 err:
 	rte_eth_dev_release_port(eth_dev);
+free_kvlist:
 	rte_kvargs_free(kvlist);
 	return ret;
 }
@@ -287,4 +383,5 @@ static struct rte_vdev_driver iavf_client_driver = {
 RTE_PMD_REGISTER_VDEV(net_iavf_client, iavf_client_driver);
 RTE_PMD_REGISTER_ALIAS(net_iavf_client, iavf_client);
 RTE_PMD_REGISTER_PARAM_STRING(net_iavf_client,
-	"path=<path>");
+	"path=<path>"
+	"intr=[0|1]");
diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
index 6b5e47adf2..bc07ecbed7 100644
--- a/drivers/net/iavf/iavf_ethdev.c
+++ b/drivers/net/iavf/iavf_ethdev.c
@@ -1869,23 +1869,7 @@ iavf_init_vf(struct rte_eth_dev *dev)
 	return -1;
 }
 
-/* Enable default admin queue interrupt setting */
-static inline void
-iavf_enable_irq0(struct iavf_hw *hw)
-{
-	/* Enable admin queue interrupt trigger */
-	IAVF_WRITE_REG(hw, IAVF_VFINT_ICR0_ENA1,
-		       IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK);
-
-	IAVF_WRITE_REG(hw, IAVF_VFINT_DYN_CTL01,
-		       IAVF_VFINT_DYN_CTL01_INTENA_MASK |
-		       IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK |
-		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
-
-	IAVF_WRITE_FLUSH(hw);
-}
-
-static void
+void
 iavf_dev_interrupt_handler(void *param)
 {
 	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
-- 
2.21.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [dpdk-dev] [PATCH v3 4/5] net/iavf_client: enable interrupt of Rx queue
  2021-01-07  8:27   ` [dpdk-dev] [PATCH v3 0/5] introduce new iavf driver on vfio-user client Jingjing Wu
                       ` (2 preceding siblings ...)
  2021-01-07  8:27     ` [dpdk-dev] [PATCH v3 3/5] net/iavf_client: enable interrupt on control queue Jingjing Wu
@ 2021-01-07  8:27     ` Jingjing Wu
  2021-01-07  8:27     ` [dpdk-dev] [PATCH v3 5/5] net/iavf: fix vector mapping with queue Jingjing Wu
  4 siblings, 0 replies; 18+ messages in thread
From: Jingjing Wu @ 2021-01-07  8:27 UTC (permalink / raw)
  To: dev; +Cc: jingjing.wu, beilei.xing, chenbo.xia, xiuchun.lu

Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
---
 drivers/net/iavf/iavf_client_ethdev.c | 29 +++++++++++++++++++++------
 drivers/net/iavf/iavf_ethdev.c        |  9 +++------
 2 files changed, 26 insertions(+), 12 deletions(-)

diff --git a/drivers/net/iavf/iavf_client_ethdev.c b/drivers/net/iavf/iavf_client_ethdev.c
index 770a7a8200..27daaed0e8 100644
--- a/drivers/net/iavf/iavf_client_ethdev.c
+++ b/drivers/net/iavf/iavf_client_ethdev.c
@@ -59,6 +59,7 @@ iavf_client_vfio_user_setup(struct rte_eth_dev *dev, const char *path)
 		IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
 	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(adapter);
 	struct vfio_device *vfio_dev;
+	uint32_t max_fds, i;
 
 	vfio_dev = client_vfio_user_setup(path, dev->device->numa_node);
 	if (vfio_dev == NULL) {
@@ -87,11 +88,21 @@ iavf_client_vfio_user_setup(struct rte_eth_dev *dev, const char *path)
 		}
 
 	}
-
 	dev->intr_handle->fd = vfio_dev->irqfds[0];
 	dev->intr_handle->type = RTE_INTR_HANDLE_VDEV;
 	dev->intr_handle->max_intr = 1;
 
+	/* Assign rxq fds */
+	if (vfio_dev->nb_irqs > 1) {
+		max_fds = RTE_MIN((uint32_t)RTE_MAX_RXTX_INTR_VEC_ID,
+				  vfio_dev->nb_irqs - 1);
+		dev->intr_handle->nb_efd = max_fds;
+		for (i = 0; i < max_fds; ++i)
+			dev->intr_handle->efds[i] =
+				vfio_dev->irqfds[i + RTE_INTR_VEC_RXTX_OFFSET];
+		dev->intr_handle->efd_counter_size = 0;
+		dev->intr_handle->max_intr += max_fds;
+	}
 	return 0;
 }
 
@@ -108,8 +119,6 @@ avf_client_init_eth_ops(void)
 	iavf_client_eth_dev_ops.reta_query                 = NULL;
 	iavf_client_eth_dev_ops.rss_hash_update            = NULL;
 	iavf_client_eth_dev_ops.rss_hash_conf_get          = NULL;
-	iavf_client_eth_dev_ops.rx_queue_intr_enable       = NULL;
-	iavf_client_eth_dev_ops.rx_queue_intr_disable      = NULL;
 }
 
 #define IAVF_CLIENT_ALARM_INTERVAL 50000 /* us */
@@ -227,11 +236,12 @@ iavf_client_dev_close(struct rte_eth_dev *dev)
 	struct iavf_adapter *adapter =
 		IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
 	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct rte_intr_handle *intr_handle = dev->intr_handle;
 
 	if (adapter->intr_mode) {
 		iavf_disable_irq0(hw);
 		/* unregister callback func from eal lib */
-		rte_intr_callback_unregister(dev->intr_handle,
+		rte_intr_callback_unregister(intr_handle,
 					     iavf_client_event_handler, dev);
 	} else {
 		rte_eal_alarm_cancel(iavf_client_dev_alarm_handler, dev);
@@ -240,8 +250,15 @@ iavf_client_dev_close(struct rte_eth_dev *dev)
 	if (!adapter->stopped) {
 		iavf_stop_queues(dev);
 
-		if (dev->intr_handle) {
-			rte_free(dev->intr_handle);
+		if (intr_handle) {
+			/* Disable the interrupt for Rx */
+			rte_intr_efd_disable(intr_handle);
+			/* Rx interrupt vector mapping free */
+			if (intr_handle->intr_vec) {
+				rte_free(intr_handle->intr_vec);
+				intr_handle->intr_vec = NULL;
+			}
+			rte_free(intr_handle);
 			dev->intr_handle = NULL;
 		}
 
diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
index bc07ecbed7..06395f852b 100644
--- a/drivers/net/iavf/iavf_ethdev.c
+++ b/drivers/net/iavf/iavf_ethdev.c
@@ -1368,11 +1368,10 @@ iavf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 {
 	struct iavf_adapter *adapter =
 		IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
-	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
 	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(adapter);
 	uint16_t msix_intr;
 
-	msix_intr = pci_dev->intr_handle.intr_vec[queue_id];
+	msix_intr = dev->intr_handle->intr_vec[queue_id];
 	if (msix_intr == IAVF_MISC_VEC_ID) {
 		PMD_DRV_LOG(INFO, "MISC is also enabled for control");
 		IAVF_WRITE_REG(hw, IAVF_VFINT_DYN_CTL01,
@@ -1387,10 +1386,9 @@ iavf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 			       IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK |
 			       IAVF_VFINT_DYN_CTLN1_ITR_INDX_MASK);
 	}
-
 	IAVF_WRITE_FLUSH(hw);
 
-	rte_intr_ack(&pci_dev->intr_handle);
+	rte_intr_ack(dev->intr_handle);
 
 	return 0;
 }
@@ -1398,11 +1396,10 @@ iavf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 static int
 iavf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
 {
-	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
 	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	uint16_t msix_intr;
 
-	msix_intr = pci_dev->intr_handle.intr_vec[queue_id];
+	msix_intr = dev->intr_handle->intr_vec[queue_id];
 	if (msix_intr == IAVF_MISC_VEC_ID) {
 		PMD_DRV_LOG(ERR, "MISC is used for control, cannot disable it");
 		return -EIO;
-- 
2.21.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [dpdk-dev] [PATCH v3 5/5] net/iavf: fix vector mapping with queue
  2021-01-07  8:27   ` [dpdk-dev] [PATCH v3 0/5] introduce new iavf driver on vfio-user client Jingjing Wu
                       ` (3 preceding siblings ...)
  2021-01-07  8:27     ` [dpdk-dev] [PATCH v3 4/5] net/iavf_client: enable interrupt of Rx queue Jingjing Wu
@ 2021-01-07  8:27     ` Jingjing Wu
  2021-01-12  6:10       ` Xing, Beilei
  2021-01-14 10:24       ` Xie, WeiX
  4 siblings, 2 replies; 18+ messages in thread
From: Jingjing Wu @ 2021-01-07  8:27 UTC (permalink / raw)
  To: dev; +Cc: jingjing.wu, beilei.xing, chenbo.xia, xiuchun.lu

Fix the vector mapping with queue by changing the recircle when
exceeds RX_VEC_START + nb_msix;

Fixes: d6bde6b5eae9 ("net/avf: enable Rx interrupt")

Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
---
 drivers/net/iavf/iavf_ethdev.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
index 06395f852b..b169b19975 100644
--- a/drivers/net/iavf/iavf_ethdev.c
+++ b/drivers/net/iavf/iavf_ethdev.c
@@ -570,7 +570,7 @@ static int iavf_config_rx_queues_irqs(struct rte_eth_dev *dev,
 			/* If Rx interrupt is reuquired, and we can use
 			 * multi interrupts, then the vec is from 1
 			 */
-			vf->nb_msix = RTE_MIN(vf->vf_res->max_vectors,
+			vf->nb_msix = RTE_MIN(vf->vf_res->max_vectors - 1,
 					      intr_handle->nb_efd);
 			vf->msix_base = IAVF_RX_VEC_START;
 			vec = IAVF_RX_VEC_START;
@@ -578,7 +578,7 @@ static int iavf_config_rx_queues_irqs(struct rte_eth_dev *dev,
 				qv_map[i].queue_id = i;
 				qv_map[i].vector_id = vec;
 				intr_handle->intr_vec[i] = vec++;
-				if (vec >= vf->nb_msix)
+				if (vec >= vf->nb_msix + IAVF_RX_VEC_START)
 					vec = IAVF_RX_VEC_START;
 			}
 			vf->qv_map = qv_map;
-- 
2.21.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [dpdk-dev] [PATCH v3 5/5] net/iavf: fix vector mapping with queue
  2021-01-07  8:27     ` [dpdk-dev] [PATCH v3 5/5] net/iavf: fix vector mapping with queue Jingjing Wu
@ 2021-01-12  6:10       ` Xing, Beilei
  2021-01-12  6:45         ` Wu, Jingjing
  2021-01-14 10:24       ` Xie, WeiX
  1 sibling, 1 reply; 18+ messages in thread
From: Xing, Beilei @ 2021-01-12  6:10 UTC (permalink / raw)
  To: Wu, Jingjing, dev; +Cc: Xia, Chenbo, Lu, Xiuchun

Seems the patch is conflict with patch https://patches.dpdk.org/patch/86202/, please help to review.

> -----Original Message-----
> From: Wu, Jingjing <jingjing.wu@intel.com>
> Sent: Thursday, January 7, 2021 4:27 PM
> To: dev@dpdk.org
> Cc: Wu, Jingjing <jingjing.wu@intel.com>; Xing, Beilei <beilei.xing@intel.com>;
> Xia, Chenbo <chenbo.xia@intel.com>; Lu, Xiuchun <xiuchun.lu@intel.com>
> Subject: [PATCH v3 5/5] net/iavf: fix vector mapping with queue
> 
> Fix the vector mapping with queue by changing the recircle when exceeds
> RX_VEC_START + nb_msix;
> 
> Fixes: d6bde6b5eae9 ("net/avf: enable Rx interrupt")
> 
> Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
> ---
>  drivers/net/iavf/iavf_ethdev.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
> index 06395f852b..b169b19975 100644
> --- a/drivers/net/iavf/iavf_ethdev.c
> +++ b/drivers/net/iavf/iavf_ethdev.c
> @@ -570,7 +570,7 @@ static int iavf_config_rx_queues_irqs(struct
> rte_eth_dev *dev,
>  			/* If Rx interrupt is reuquired, and we can use
>  			 * multi interrupts, then the vec is from 1
>  			 */
> -			vf->nb_msix = RTE_MIN(vf->vf_res->max_vectors,
> +			vf->nb_msix = RTE_MIN(vf->vf_res->max_vectors - 1,
>  					      intr_handle->nb_efd);
>  			vf->msix_base = IAVF_RX_VEC_START;
>  			vec = IAVF_RX_VEC_START;
> @@ -578,7 +578,7 @@ static int iavf_config_rx_queues_irqs(struct
> rte_eth_dev *dev,
>  				qv_map[i].queue_id = i;
>  				qv_map[i].vector_id = vec;
>  				intr_handle->intr_vec[i] = vec++;
> -				if (vec >= vf->nb_msix)
> +				if (vec >= vf->nb_msix + IAVF_RX_VEC_START)
>  					vec = IAVF_RX_VEC_START;
>  			}
>  			vf->qv_map = qv_map;
> --
> 2.21.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [dpdk-dev] [PATCH v3 5/5] net/iavf: fix vector mapping with queue
  2021-01-12  6:10       ` Xing, Beilei
@ 2021-01-12  6:45         ` Wu, Jingjing
  0 siblings, 0 replies; 18+ messages in thread
From: Wu, Jingjing @ 2021-01-12  6:45 UTC (permalink / raw)
  To: Xing, Beilei, dev; +Cc: Xia, Chenbo, Lu, Xiuchun

> -----Original Message-----
> From: Xing, Beilei <beilei.xing@intel.com>
> Sent: Tuesday, January 12, 2021 2:11 PM
> To: Wu, Jingjing <jingjing.wu@intel.com>; dev@dpdk.org
> Cc: Xia, Chenbo <chenbo.xia@intel.com>; Lu, Xiuchun
> <xiuchun.lu@intel.com>
> Subject: RE: [PATCH v3 5/5] net/iavf: fix vector mapping with queue
> 
> Seems the patch is conflict with patch
> https://patches.dpdk.org/patch/86202/, please help to review.

Thanks. Looks like the similar fix. Will comment that patch and drop this one if that is merged.
> 
> > -----Original Message-----
> > From: Wu, Jingjing <jingjing.wu@intel.com>
> > Sent: Thursday, January 7, 2021 4:27 PM
> > To: dev@dpdk.org
> > Cc: Wu, Jingjing <jingjing.wu@intel.com>; Xing, Beilei
> > <beilei.xing@intel.com>; Xia, Chenbo <chenbo.xia@intel.com>; Lu,
> > Xiuchun <xiuchun.lu@intel.com>
> > Subject: [PATCH v3 5/5] net/iavf: fix vector mapping with queue
> >
> > Fix the vector mapping with queue by changing the recircle when
> > exceeds RX_VEC_START + nb_msix;
> >
> > Fixes: d6bde6b5eae9 ("net/avf: enable Rx interrupt")
> >
> > Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
> > ---
> >  drivers/net/iavf/iavf_ethdev.c | 4 ++--
> >  1 file changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/net/iavf/iavf_ethdev.c
> > b/drivers/net/iavf/iavf_ethdev.c index 06395f852b..b169b19975 100644
> > --- a/drivers/net/iavf/iavf_ethdev.c
> > +++ b/drivers/net/iavf/iavf_ethdev.c
> > @@ -570,7 +570,7 @@ static int iavf_config_rx_queues_irqs(struct
> > rte_eth_dev *dev,
> >  			/* If Rx interrupt is reuquired, and we can use
> >  			 * multi interrupts, then the vec is from 1
> >  			 */
> > -			vf->nb_msix = RTE_MIN(vf->vf_res->max_vectors,
> > +			vf->nb_msix = RTE_MIN(vf->vf_res->max_vectors -
> 1,
> >  					      intr_handle->nb_efd);
> >  			vf->msix_base = IAVF_RX_VEC_START;
> >  			vec = IAVF_RX_VEC_START;
> > @@ -578,7 +578,7 @@ static int iavf_config_rx_queues_irqs(struct
> > rte_eth_dev *dev,
> >  				qv_map[i].queue_id = i;
> >  				qv_map[i].vector_id = vec;
> >  				intr_handle->intr_vec[i] = vec++;
> > -				if (vec >= vf->nb_msix)
> > +				if (vec >= vf->nb_msix +
> IAVF_RX_VEC_START)
> >  					vec = IAVF_RX_VEC_START;
> >  			}
> >  			vf->qv_map = qv_map;
> > --
> > 2.21.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [dpdk-dev] [PATCH v3 5/5] net/iavf: fix vector mapping with queue
  2021-01-07  8:27     ` [dpdk-dev] [PATCH v3 5/5] net/iavf: fix vector mapping with queue Jingjing Wu
  2021-01-12  6:10       ` Xing, Beilei
@ 2021-01-14 10:24       ` Xie, WeiX
  1 sibling, 0 replies; 18+ messages in thread
From: Xie, WeiX @ 2021-01-14 10:24 UTC (permalink / raw)
  To: Wu, Jingjing, dev; +Cc: Wu, Jingjing, Xing, Beilei, Xia, Chenbo, Lu, Xiuchun

Tested-by:  Xie,WeiX < weix.xie@intel.com>

Regards,
Xie Wei


> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jingjing Wu
> Sent: Thursday, January 7, 2021 4:27 PM
> To: dev@dpdk.org
> Cc: Wu, Jingjing <jingjing.wu@intel.com>; Xing, Beilei
> <beilei.xing@intel.com>; Xia, Chenbo <chenbo.xia@intel.com>; Lu, Xiuchun
> <xiuchun.lu@intel.com>
> Subject: [dpdk-dev] [PATCH v3 5/5] net/iavf: fix vector mapping with queue
> 
> Fix the vector mapping with queue by changing the recircle when exceeds
> RX_VEC_START + nb_msix;
> 
> Fixes: d6bde6b5eae9 ("net/avf: enable Rx interrupt")
> 
> Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
> ---
>  drivers/net/iavf/iavf_ethdev.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
> index 06395f852b..b169b19975 100644
> --- a/drivers/net/iavf/iavf_ethdev.c
> +++ b/drivers/net/iavf/iavf_ethdev.c
> @@ -570,7 +570,7 @@ static int iavf_config_rx_queues_irqs(struct
> rte_eth_dev *dev,
>  			/* If Rx interrupt is reuquired, and we can use
>  			 * multi interrupts, then the vec is from 1
>  			 */
> -			vf->nb_msix = RTE_MIN(vf->vf_res->max_vectors,
> +			vf->nb_msix = RTE_MIN(vf->vf_res->max_vectors -
> 1,
>  					      intr_handle->nb_efd);
>  			vf->msix_base = IAVF_RX_VEC_START;
>  			vec = IAVF_RX_VEC_START;
> @@ -578,7 +578,7 @@ static int iavf_config_rx_queues_irqs(struct
> rte_eth_dev *dev,
>  				qv_map[i].queue_id = i;
>  				qv_map[i].vector_id = vec;
>  				intr_handle->intr_vec[i] = vec++;
> -				if (vec >= vf->nb_msix)
> +				if (vec >= vf->nb_msix +
> IAVF_RX_VEC_START)
>  					vec = IAVF_RX_VEC_START;
>  			}
>  			vf->qv_map = qv_map;
> --
> 2.21.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2021-01-14 10:24 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-19 14:38 [dpdk-dev] [PATCH v1 0/2] introduce new iavf driver on vfio-user client Jingjing Wu
2020-12-19 14:38 ` [dpdk-dev] [PATCH v1 1/2] common/iavf: emulated pci interfaces " Jingjing Wu
2020-12-19 14:38 ` [dpdk-dev] [PATCH v1 2/2] net/iavf: introduce iavf driver " Jingjing Wu
2020-12-22  8:14   ` Xia, Chenbo
2021-01-07  7:45 ` [dpdk-dev] [PATCH v2 0/4] introduce new " Jingjing Wu
2021-01-07  7:45   ` [dpdk-dev] [PATCH v2 1/4] net/iavf_client: introduce " Jingjing Wu
2021-01-07  7:45   ` [dpdk-dev] [PATCH v2 2/4] net/iavf_client: enable interrupt on control queue Jingjing Wu
2021-01-07  7:45   ` [dpdk-dev] [PATCH v2 3/4] net/iavf_client: enable interrupt of " Jingjing Wu
2021-01-07  7:45   ` [dpdk-dev] [PATCH v2 4/4] net/iavf: fix vector mapping with queue Jingjing Wu
2021-01-07  8:27   ` [dpdk-dev] [PATCH v3 0/5] introduce new iavf driver on vfio-user client Jingjing Wu
2021-01-07  8:27     ` [dpdk-dev] [PATCH v3 1/5] common/iavf: emulated pci interfaces " Jingjing Wu
2021-01-07  8:27     ` [dpdk-dev] [PATCH v3 2/5] net/iavf_client: introduce iavf driver " Jingjing Wu
2021-01-07  8:27     ` [dpdk-dev] [PATCH v3 3/5] net/iavf_client: enable interrupt on control queue Jingjing Wu
2021-01-07  8:27     ` [dpdk-dev] [PATCH v3 4/5] net/iavf_client: enable interrupt of Rx queue Jingjing Wu
2021-01-07  8:27     ` [dpdk-dev] [PATCH v3 5/5] net/iavf: fix vector mapping with queue Jingjing Wu
2021-01-12  6:10       ` Xing, Beilei
2021-01-12  6:45         ` Wu, Jingjing
2021-01-14 10:24       ` Xie, WeiX

DPDK patches and discussions

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://inbox.dpdk.org/dev/0 dev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 dev dev/ https://inbox.dpdk.org/dev \
		dev@dpdk.org
	public-inbox-index dev

Example config snippet for mirrors.
Newsgroup available over NNTP:
	nntp://inbox.dpdk.org/inbox.dpdk.dev


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git