iommu/exynos: support 1:1 mapping between DVA and PA
authorJanghyuck Kim <janghyuck.kim@samsung.com>
Tue, 8 Aug 2017 06:15:08 +0000 (15:15 +0900)
committerCosmin Tanislav <demonsingur@gmail.com>
Mon, 22 Apr 2024 17:22:32 +0000 (20:22 +0300)
This patch supports interface of 1:1 mapping between DVA and PA, which
is required for frame buffer handover

Change-Id: Ib7b3a2382621900e05016e289fbadccb51c5f663
Signed-off-by: Janghyuck Kim <janghyuck.kim@samsung.com>
Signed-off-by: ChiHun Won <chihun.won@samsung.com>
drivers/iommu/exynos-iovmm.c
include/linux/exynos_iovmm.h

index df48570490945bc61e60d513f3a781eff654e7ea..07c449f4fe633c6823cd479151d5c8daa389496c 100644 (file)
@@ -613,6 +613,69 @@ void exynos_iovmm_unmap_userptr(struct device *dev, dma_addr_t iova)
        }
 }
 
+int iovmm_map_oto(struct device *dev, phys_addr_t phys, size_t size)
+{
+       struct exynos_iovmm *vmm = exynos_get_iovmm(dev);
+       int ret;
+
+       BUG_ON(!IS_ALIGNED(phys, PAGE_SIZE));
+       BUG_ON(!IS_ALIGNED(size, PAGE_SIZE));
+
+       if (vmm == NULL) {
+               dev_err(dev, "%s: IOVMM not found\n", __func__);
+               return -EINVAL;
+       }
+
+       if (WARN_ON((phys < vmm->iova_start) ||
+                       (phys + size) >= (vmm->iova_start + vmm->iovm_size))) {
+               dev_err(dev,
+                       "Unable to create one to one mapping for %#zx @ %pa\n",
+                       size, &phys);
+               return -EINVAL;
+       }
+
+       if (!add_iovm_region(vmm, (dma_addr_t)phys, size))
+               return -EADDRINUSE;
+
+       ret = iommu_map(vmm->domain, (dma_addr_t)phys, phys, size, 0);
+       if (ret < 0)
+               free_iovm_region(vmm,
+                               remove_iovm_region(vmm, (dma_addr_t)phys));
+
+       return ret;
+}
+
+void iovmm_unmap_oto(struct device *dev, phys_addr_t phys)
+{
+       struct exynos_iovmm *vmm = exynos_get_iovmm(dev);
+       struct exynos_vm_region *region;
+       size_t unmap_size;
+
+       /* This function must not be called in IRQ handlers */
+       BUG_ON(in_irq());
+       BUG_ON(!IS_ALIGNED(phys, PAGE_SIZE));
+
+       if (vmm == NULL) {
+               dev_err(dev, "%s: IOVMM not found\n", __func__);
+               return;
+       }
+
+       region = remove_iovm_region(vmm, (dma_addr_t)phys);
+       if (region) {
+               unmap_size = iommu_unmap(vmm->domain, (dma_addr_t)phys,
+                                                       region->size);
+               WARN_ON(unmap_size != region->size);
+
+               exynos_sysmmu_tlb_invalidate(vmm->domain, (dma_addr_t)phys,
+                                            region->size);
+
+               free_iovm_region(vmm, region);
+
+               dev_dbg(dev, "IOVMM: Unmapped %#zx bytes from %pa.\n",
+                                               unmap_size, &phys);
+       }
+}
+
 static struct dentry *exynos_iovmm_debugfs_root;
 static struct dentry *exynos_iommu_debugfs_root;
 
index d219a9c37bc3c48b11933defbbcfafa78649da93..6c69c939c8d7d75cfbfedf60ab828427b87d884e 100644 (file)
@@ -240,6 +240,8 @@ dma_addr_t exynos_iovmm_map_userptr(struct device *dev, unsigned long vaddr,
  */
 void exynos_iovmm_unmap_userptr(struct device *dev, dma_addr_t iova);
 
+int iovmm_map_oto(struct device *dev, phys_addr_t phys, size_t size);
+void iovmm_unmap_oto(struct device *dev, phys_addr_t phys);
 /*
  * The handle_pte_fault() is called by exynos_sysmmu_map_user_pages().
  * Driver cannot include include/linux/huge_mm.h because