[dpdk-dev] [PATCH v2 24/41] vfio: allow to map other memory regions

Gowrishankar gowrishankar.m at linux.vnet.ibm.com
Mon Apr 2 13:36:50 CEST 2018


From: Gowrishankar Muthukrishnan <gowrishankar.m at linux.vnet.ibm.com>

Below patch adds powerpc arch specific changes.

Signed-off-by: Gowrishankar Muthukrishnan <gowrishankar.m at linux.vnet.ibm.com>
---
 lib/librte_eal/linuxapp/eal/eal_vfio.c | 110 +++++++++++++++++++++++++++++++--
 1 file changed, 105 insertions(+), 5 deletions(-)

diff --git a/lib/librte_eal/linuxapp/eal/eal_vfio.c b/lib/librte_eal/linuxapp/eal/eal_vfio.c
index 4e9e296..985acf4 100644
--- a/lib/librte_eal/linuxapp/eal/eal_vfio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_vfio.c
@@ -24,6 +24,7 @@
 static int vfio_type1_dma_map(int);
 static int vfio_type1_dma_mem_map(int, uint64_t, uint64_t, uint64_t, int);
 static int vfio_spapr_dma_map(int);
+static int vfio_spapr_dma_mem_map(int, uint64_t, uint64_t, uint64_t, int);
 static int vfio_noiommu_dma_map(int);
 static int vfio_noiommu_dma_mem_map(int, uint64_t, uint64_t, uint64_t, int);
 
@@ -41,8 +42,7 @@
 		.type_id = RTE_VFIO_SPAPR,
 		.name = "sPAPR",
 		.dma_map_func = &vfio_spapr_dma_map,
-		.dma_user_map_func = NULL
-		// TODO: work with PPC64 people on enabling this, window size!
+		.dma_user_map_func = &vfio_spapr_dma_mem_map
 	},
 	/* IOMMU-less mode */
 	{
@@ -838,7 +838,6 @@ struct spapr_create_window_walk_param {
 
 	ret = ioctl(*vfio_container_fd, VFIO_IOMMU_MAP_DMA,
 			&dma_map);
-
 	if (ret) {
 		RTE_LOG(ERR, EAL, "  cannot set up DMA remapping, error %i (%s)\n",
 				errno, strerror(errno));
@@ -852,7 +851,6 @@ struct spapr_create_window_walk_param {
 vfio_spapr_dma_map(int vfio_container_fd)
 {
 	int ret;
-	uint64_t hugepage_sz = 0;
 	struct spapr_create_window_walk_param wa;
 
 	struct vfio_iommu_spapr_tce_info info = {
@@ -890,7 +888,7 @@ struct spapr_create_window_walk_param {
 
 	/* sPAPR requires window size to be a power of 2 */
 	create.window_size = rte_align64pow2(create.window_size);
-	create.page_shift = __builtin_ctzll(hugepage_sz);
+	create.page_shift = __builtin_ctzll(wa.hugepage_sz);
 	create.levels = 1;
 
 	ret = ioctl(vfio_container_fd, VFIO_IOMMU_SPAPR_TCE_CREATE, &create);
@@ -912,6 +910,108 @@ struct spapr_create_window_walk_param {
 }
 
 static int
+vfio_spapr_dma_mem_map(int vfio_container_fd, uint64_t vaddr, uint64_t iova,
+		uint64_t len, int do_map)
+{
+	int ret;
+	struct spapr_create_window_walk_param wa = {
+		.hugepage_sz = 0,
+	};
+	struct vfio_iommu_spapr_tce_create create = {
+		.argsz = sizeof(create),
+	};
+
+	/* check if DMA window is from 0 to max(phys_addr + len) */
+	wa.create = &create;
+	rte_memseg_walk(vfio_spapr_create_window_walk, &wa);
+	create.window_size = rte_align64pow2(create.window_size);
+	if (iova > create.window_size) {
+		struct vfio_iommu_spapr_tce_info info = {
+			.argsz = sizeof(info),
+		};
+		struct vfio_iommu_spapr_tce_remove remove = {
+			.argsz = sizeof(remove),
+		};
+
+		/* query spapr iommu info */
+		ret = ioctl(vfio_container_fd,
+				VFIO_IOMMU_SPAPR_TCE_GET_INFO, &info);
+		if (ret) {
+			RTE_LOG(ERR, EAL, "  cannot get iommu info, "
+					"error %i (%s)\n", errno, strerror(errno));
+			return -1;
+		}
+
+		/* remove old DMA window */
+		remove.start_addr = info.dma32_window_start;
+		ret = ioctl(vfio_container_fd,
+				VFIO_IOMMU_SPAPR_TCE_REMOVE, &remove);
+		if (ret) {
+			RTE_LOG(ERR, EAL, "  cannot remove default DMA window, "
+					"error %i (%s)\n", errno, strerror(errno));
+			return -1;
+		}
+		create.page_shift = __builtin_ctzll(wa.hugepage_sz);
+		create.levels = 1;
+
+		ret = ioctl(vfio_container_fd,
+				VFIO_IOMMU_SPAPR_TCE_CREATE, &create);
+		if (ret) {
+			RTE_LOG(ERR, EAL, "  cannot create new DMA window, "
+					"error %i (%s)\n", errno, strerror(errno));
+			return -1;
+		}
+
+		if (create.start_addr != 0) {
+			RTE_LOG(ERR, EAL, "  DMA window start address != 0\n");
+			return -1;
+		}
+
+	}
+
+	if (do_map != 0) {
+		if (rte_memseg_walk(vfio_spapr_dma_map_walk, &vfio_container_fd))
+			return -1;
+	} else {
+		struct vfio_iommu_type1_dma_unmap dma_unmap;
+		struct vfio_iommu_spapr_register_memory reg = {
+			.argsz = sizeof(reg),
+			.flags = 0
+		};
+
+		/* for unmap, check if iova within DMA window */
+		if (iova > create.window_size) {
+			RTE_LOG(ERR, EAL, "iova not beyond DMA window for unmap");
+			return -1;
+		}
+
+		reg.vaddr = (uintptr_t) vaddr;
+		reg.size = len;
+		ret = ioctl(vfio_container_fd,
+			VFIO_IOMMU_SPAPR_UNREGISTER_MEMORY, &reg);
+		if (ret) {
+			RTE_LOG(ERR, EAL, "  cannot unregister vaddr for IOMMU, error %i (%s)\n",
+					errno, strerror(errno));
+			return -1;
+		}
+
+		memset(&dma_unmap, 0, sizeof(dma_unmap));
+		dma_unmap.argsz = sizeof(struct vfio_iommu_type1_dma_unmap);
+		dma_unmap.size = len;
+		dma_unmap.iova = iova;
+
+		ret = ioctl(vfio_container_fd, VFIO_IOMMU_UNMAP_DMA,
+				&dma_unmap);
+		if (ret) {
+			RTE_LOG(ERR, EAL, "  cannot clear DMA remapping, error %i (%s)\n",
+					errno, strerror(errno));
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int
 vfio_noiommu_dma_map(int __rte_unused vfio_container_fd)
 {
 	/* No-IOMMU mode does not need DMA mapping */
-- 
1.9.1



More information about the dev mailing list