iommu/io-pgtable-arm: Re-use the pgtable walk for iova_to_phys

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>
This commit is contained in:
Rob Clark 2024-12-10 08:51:20 -08:00 committed by Will Deacon
parent 821500d5c5
commit d9e589e6ad

View 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);