From: Gowrishankar Muthukrishnan <gowrishanka...@linux.vnet.ibm.com>

Below patch adds powerpc arch specific changes.

Signed-off-by: Gowrishankar Muthukrishnan <gowrishanka...@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

Reply via email to