]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
iommu/io-pgtable-arm: Re-use the pgtable walk for iova_to_phys
authorRob Clark <robdclark@chromium.org>
Tue, 10 Dec 2024 16:51:20 +0000 (08:51 -0800)
committerWill Deacon <will@kernel.org>
Tue, 7 Jan 2025 15:42:23 +0000 (15:42 +0000)
Re-use the generic pgtable walk path.

Signed-off-by: Rob Clark <robdclark@chromium.org>
Reviewed-by: Mostafa Saleh <smostafa@google.com>
Link: https://lore.kernel.org/r/20241210165127.600817-3-robdclark@gmail.com
Signed-off-by: Will Deacon <will@kernel.org>
drivers/iommu/io-pgtable-arm.c

index e8e9f77a617000cc92df744d3def788558dc131c..dd2111731e19aaf3c36e4fc4fe3e9fd4883f1c59 100644 (file)
@@ -704,42 +704,6 @@ static size_t arm_lpae_unmap_pages(struct io_pgtable_ops *ops, unsigned long iov
                                data->start_level, ptep);
 }
 
-static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops,
-                                        unsigned long iova)
-{
-       struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
-       arm_lpae_iopte pte, *ptep = data->pgd;
-       int lvl = data->start_level;
-
-       do {
-               /* Valid IOPTE pointer? */
-               if (!ptep)
-                       return 0;
-
-               /* Grab the IOPTE we're interested in */
-               ptep += ARM_LPAE_LVL_IDX(iova, lvl, data);
-               pte = READ_ONCE(*ptep);
-
-               /* Valid entry? */
-               if (!pte)
-                       return 0;
-
-               /* Leaf entry? */
-               if (iopte_leaf(pte, lvl, data->iop.fmt))
-                       goto found_translation;
-
-               /* Take it to the next level */
-               ptep = iopte_deref(pte, data);
-       } while (++lvl < ARM_LPAE_MAX_LEVELS);
-
-       /* Ran out of page tables to walk */
-       return 0;
-
-found_translation:
-       iova &= (ARM_LPAE_BLOCK_SIZE(lvl, data) - 1);
-       return iopte_to_paddr(pte, data) | iova;
-}
-
 struct io_pgtable_walk_data {
        struct io_pgtable               *iop;
        void                            *data;
@@ -755,6 +719,41 @@ static int __arm_lpae_iopte_walk(struct arm_lpae_io_pgtable *data,
                                 arm_lpae_iopte *ptep,
                                 int lvl);
 
+struct iova_to_phys_data {
+       arm_lpae_iopte pte;
+       int lvl;
+};
+
+static int visit_iova_to_phys(struct io_pgtable_walk_data *walk_data, int lvl,
+                             arm_lpae_iopte *ptep, size_t size)
+{
+       struct iova_to_phys_data *data = walk_data->data;
+       data->pte = *ptep;
+       data->lvl = lvl;
+       return 0;
+}
+
+static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops,
+                                        unsigned long iova)
+{
+       struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
+       struct iova_to_phys_data d;
+       struct io_pgtable_walk_data walk_data = {
+               .data = &d,
+               .visit = visit_iova_to_phys,
+               .addr = iova,
+               .end = iova + 1,
+       };
+       int ret;
+
+       ret = __arm_lpae_iopte_walk(data, &walk_data, data->pgd, data->start_level);
+       if (ret)
+               return 0;
+
+       iova &= (ARM_LPAE_BLOCK_SIZE(d.lvl, data) - 1);
+       return iopte_to_paddr(d.pte, data) | iova;
+}
+
 static int io_pgtable_visit(struct arm_lpae_io_pgtable *data,
                            struct io_pgtable_walk_data *walk_data,
                            arm_lpae_iopte *ptep, int lvl)
@@ -772,8 +771,9 @@ static int io_pgtable_visit(struct arm_lpae_io_pgtable *data,
                return 0;
        }
 
-       if (WARN_ON(!iopte_table(pte, lvl)))
+       if (!iopte_table(pte, lvl)) {
                return -EINVAL;
+       }
 
        ptep = iopte_deref(pte, data);
        return __arm_lpae_iopte_walk(data, walk_data, ptep, lvl + 1);