mirror of
https://github.com/torvalds/linux.git
synced 2026-06-04 12:35:52 +02:00
iommu/io-pgtable-arm: Make pgtable walker more generic
We can re-use this basic pgtable walk logic in a few places. Signed-off-by: Rob Clark <robdclark@chromium.org> Reviewed-by: Mostafa Saleh <smostafa@google.com> Link: https://lore.kernel.org/r/20241210165127.600817-2-robdclark@gmail.com Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
parent
3e35c3e725
commit
821500d5c5
|
|
@ -741,33 +741,33 @@ static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops,
|
|||
}
|
||||
|
||||
struct io_pgtable_walk_data {
|
||||
struct iommu_dirty_bitmap *dirty;
|
||||
struct io_pgtable *iop;
|
||||
void *data;
|
||||
int (*visit)(struct io_pgtable_walk_data *walk_data, int lvl,
|
||||
arm_lpae_iopte *ptep, size_t size);
|
||||
unsigned long flags;
|
||||
u64 addr;
|
||||
const u64 end;
|
||||
};
|
||||
|
||||
static int __arm_lpae_iopte_walk_dirty(struct arm_lpae_io_pgtable *data,
|
||||
struct io_pgtable_walk_data *walk_data,
|
||||
arm_lpae_iopte *ptep,
|
||||
int lvl);
|
||||
static int __arm_lpae_iopte_walk(struct arm_lpae_io_pgtable *data,
|
||||
struct io_pgtable_walk_data *walk_data,
|
||||
arm_lpae_iopte *ptep,
|
||||
int lvl);
|
||||
|
||||
static int io_pgtable_visit_dirty(struct arm_lpae_io_pgtable *data,
|
||||
struct io_pgtable_walk_data *walk_data,
|
||||
arm_lpae_iopte *ptep, int lvl)
|
||||
static int io_pgtable_visit(struct arm_lpae_io_pgtable *data,
|
||||
struct io_pgtable_walk_data *walk_data,
|
||||
arm_lpae_iopte *ptep, int lvl)
|
||||
{
|
||||
struct io_pgtable *iop = &data->iop;
|
||||
arm_lpae_iopte pte = READ_ONCE(*ptep);
|
||||
|
||||
if (iopte_leaf(pte, lvl, iop->fmt)) {
|
||||
size_t size = ARM_LPAE_BLOCK_SIZE(lvl, data);
|
||||
size_t size = ARM_LPAE_BLOCK_SIZE(lvl, data);
|
||||
int ret = walk_data->visit(walk_data, lvl, ptep, size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (iopte_writeable_dirty(pte)) {
|
||||
iommu_dirty_bitmap_record(walk_data->dirty,
|
||||
walk_data->addr, size);
|
||||
if (!(walk_data->flags & IOMMU_DIRTY_NO_CLEAR))
|
||||
iopte_set_writeable_clean(ptep);
|
||||
}
|
||||
if (iopte_leaf(pte, lvl, iop->fmt)) {
|
||||
walk_data->addr += size;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -776,13 +776,13 @@ static int io_pgtable_visit_dirty(struct arm_lpae_io_pgtable *data,
|
|||
return -EINVAL;
|
||||
|
||||
ptep = iopte_deref(pte, data);
|
||||
return __arm_lpae_iopte_walk_dirty(data, walk_data, ptep, lvl + 1);
|
||||
return __arm_lpae_iopte_walk(data, walk_data, ptep, lvl + 1);
|
||||
}
|
||||
|
||||
static int __arm_lpae_iopte_walk_dirty(struct arm_lpae_io_pgtable *data,
|
||||
struct io_pgtable_walk_data *walk_data,
|
||||
arm_lpae_iopte *ptep,
|
||||
int lvl)
|
||||
static int __arm_lpae_iopte_walk(struct arm_lpae_io_pgtable *data,
|
||||
struct io_pgtable_walk_data *walk_data,
|
||||
arm_lpae_iopte *ptep,
|
||||
int lvl)
|
||||
{
|
||||
u32 idx;
|
||||
int max_entries, ret;
|
||||
|
|
@ -797,7 +797,7 @@ static int __arm_lpae_iopte_walk_dirty(struct arm_lpae_io_pgtable *data,
|
|||
|
||||
for (idx = ARM_LPAE_LVL_IDX(walk_data->addr, lvl, data);
|
||||
(idx < max_entries) && (walk_data->addr < walk_data->end); ++idx) {
|
||||
ret = io_pgtable_visit_dirty(data, walk_data, ptep + idx, lvl);
|
||||
ret = io_pgtable_visit(data, walk_data, ptep + idx, lvl);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -805,6 +805,23 @@ static int __arm_lpae_iopte_walk_dirty(struct arm_lpae_io_pgtable *data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int visit_dirty(struct io_pgtable_walk_data *walk_data, int lvl,
|
||||
arm_lpae_iopte *ptep, size_t size)
|
||||
{
|
||||
struct iommu_dirty_bitmap *dirty = walk_data->data;
|
||||
|
||||
if (!iopte_leaf(*ptep, lvl, walk_data->iop->fmt))
|
||||
return 0;
|
||||
|
||||
if (iopte_writeable_dirty(*ptep)) {
|
||||
iommu_dirty_bitmap_record(dirty, walk_data->addr, size);
|
||||
if (!(walk_data->flags & IOMMU_DIRTY_NO_CLEAR))
|
||||
iopte_set_writeable_clean(ptep);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int arm_lpae_read_and_clear_dirty(struct io_pgtable_ops *ops,
|
||||
unsigned long iova, size_t size,
|
||||
unsigned long flags,
|
||||
|
|
@ -813,7 +830,9 @@ static int arm_lpae_read_and_clear_dirty(struct io_pgtable_ops *ops,
|
|||
struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
|
||||
struct io_pgtable_cfg *cfg = &data->iop.cfg;
|
||||
struct io_pgtable_walk_data walk_data = {
|
||||
.dirty = dirty,
|
||||
.iop = &data->iop,
|
||||
.data = dirty,
|
||||
.visit = visit_dirty,
|
||||
.flags = flags,
|
||||
.addr = iova,
|
||||
.end = iova + size,
|
||||
|
|
@ -828,7 +847,7 @@ static int arm_lpae_read_and_clear_dirty(struct io_pgtable_ops *ops,
|
|||
if (data->iop.fmt != ARM_64_LPAE_S1)
|
||||
return -EINVAL;
|
||||
|
||||
return __arm_lpae_iopte_walk_dirty(data, &walk_data, ptep, lvl);
|
||||
return __arm_lpae_iopte_walk(data, &walk_data, ptep, lvl);
|
||||
}
|
||||
|
||||
static void arm_lpae_restrict_pgsizes(struct io_pgtable_cfg *cfg)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user