mirror of
https://github.com/torvalds/linux.git
synced 2026-06-04 20:46:48 +02:00
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:
parent
821500d5c5
commit
d9e589e6ad
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user