Implement the map_sg io-pgtable op for the ARMv7s io-pgtable
code, so that IOMMU drivers can call it when they need to map
a scatter-gather list.

Signed-off-by: Isaac J. Manjarres <isa...@codeaurora.org>
---
 drivers/iommu/io-pgtable-arm-v7s.c | 90 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)

diff --git a/drivers/iommu/io-pgtable-arm-v7s.c 
b/drivers/iommu/io-pgtable-arm-v7s.c
index 1d92ac9..40d96d2 100644
--- a/drivers/iommu/io-pgtable-arm-v7s.c
+++ b/drivers/iommu/io-pgtable-arm-v7s.c
@@ -545,6 +545,95 @@ static int arm_v7s_map(struct io_pgtable_ops *ops, 
unsigned long iova,
        return ret;
 }
 
+static int arm_v7s_map_by_pgsize(struct io_pgtable_ops *ops,
+                                unsigned long iova, phys_addr_t paddr,
+                                size_t size, int prot, gfp_t gfp,
+                                size_t *mapped)
+{
+       struct arm_v7s_io_pgtable *data = io_pgtable_ops_to_data(ops);
+       struct io_pgtable *iop = &data->iop;
+       struct io_pgtable_cfg *cfg = &iop->cfg;
+       unsigned int min_pagesz = 1 << __ffs(cfg->pgsize_bitmap);
+       int ret;
+       size_t pgsize;
+
+       if (!IS_ALIGNED(iova | paddr | size, min_pagesz)) {
+               pr_err("unaligned: iova 0x%lx pa %pa size 0x%zx min_pagesz 
0x%x\n",
+                      iova, &paddr, size, min_pagesz);
+               return -EINVAL;
+       }
+
+       if (WARN_ON((iova + size) >= (1ULL << cfg->ias) ||
+                   (paddr + size) >= (1ULL << cfg->oas)))
+               return -ERANGE;
+
+       while (size) {
+               pgsize = iommu_pgsize(cfg->pgsize_bitmap, iova | paddr, size);
+               ret = __arm_v7s_map(data, iova, paddr, pgsize, prot, 1,
+                                   data->pgd, gfp);
+
+               if (iop->cfg.quirks & IO_PGTABLE_QUIRK_TLBI_ON_MAP) {
+                       io_pgtable_tlb_flush_walk(&data->iop, iova, size,
+                                                 ARM_V7S_BLOCK_SIZE(2));
+               } else {
+                       wmb();
+               }
+
+               if (ret)
+                       return ret;
+
+               iova += pgsize;
+               paddr += pgsize;
+               *mapped += pgsize;
+               size -= pgsize;
+       }
+
+       return 0;
+}
+
+static int arm_v7s_map_sg(struct io_pgtable_ops *ops, unsigned long iova,
+                         struct scatterlist *sg, unsigned int nents,
+                         int iommu_prot, gfp_t gfp, size_t *mapped)
+{
+       size_t len = 0;
+       unsigned int i = 0;
+       int ret;
+       phys_addr_t start;
+
+       *mapped = 0;
+
+       /* If no access, then nothing to do */
+       if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE)))
+               return 0;
+
+       while (i <= nents) {
+               phys_addr_t s_phys = sg_phys(sg);
+
+               if (len && s_phys != start + len) {
+                       ret = arm_v7s_map_by_pgsize(ops, iova + *mapped, start,
+                                                   len, iommu_prot, gfp,
+                                                   mapped);
+
+                       if (ret)
+                               return ret;
+
+                       len = 0;
+               }
+
+               if (len) {
+                       len += sg->length;
+               } else {
+                       len = sg->length;
+                       start = s_phys;
+               }
+
+               if (++i < nents)
+                       sg = sg_next(sg);
+       }
+
+       return 0;
+}
+
 static void arm_v7s_free_pgtable(struct io_pgtable *iop)
 {
        struct arm_v7s_io_pgtable *data = io_pgtable_to_data(iop);
@@ -783,6 +872,7 @@ static struct io_pgtable *arm_v7s_alloc_pgtable(struct 
io_pgtable_cfg *cfg,
 
        data->iop.ops = (struct io_pgtable_ops) {
                .map            = arm_v7s_map,
+               .map_sg         = arm_v7s_map_sg,
                .unmap          = arm_v7s_unmap,
                .iova_to_phys   = arm_v7s_iova_to_phys,
        };
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

Reply via email to