Hi Rob, On Wed, Jun 26, 2024 at 01:40:26PM -0700, Rob Clark wrote: > From: Rob Clark <robdclark@xxxxxxxxxxxx> > > Add an io-pgtable method to walk the pgtable returning the raw PTEs that > would be traversed for a given iova access. > > Signed-off-by: Rob Clark <robdclark@xxxxxxxxxxxx> > --- > drivers/iommu/io-pgtable-arm.c | 34 +++++++++++++++++++++++++--------- > include/linux/io-pgtable.h | 16 ++++++++++++++++ > 2 files changed, 41 insertions(+), 9 deletions(-) Non-technical question, but with patch 2/2 being drm-specific, how do you plan to get this merged this once it's finalised? I can take this part via the IOMMU tree? > +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 io_pgtable_walk_data wd = {}; > + int ret, lvl; > + > + ret = arm_lpae_pgtable_walk(ops, iova, &wd); > + if (ret) > + return 0; > + > + lvl = wd.level + data->start_level; nit, but the level is architectural so I think we should initialise wd.level to data->start_level instead. > > -found_translation: > iova &= (ARM_LPAE_BLOCK_SIZE(lvl, data) - 1); > - return iopte_to_paddr(pte, data) | iova; > + return iopte_to_paddr(wd.ptes[wd.level - 1], data) | iova; > } > > static void arm_lpae_restrict_pgsizes(struct io_pgtable_cfg *cfg) > @@ -804,6 +819,7 @@ arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg) > .map_pages = arm_lpae_map_pages, > .unmap_pages = arm_lpae_unmap_pages, > .iova_to_phys = arm_lpae_iova_to_phys, > + .pgtable_walk = arm_lpae_pgtable_walk, > }; > > return data; > diff --git a/include/linux/io-pgtable.h b/include/linux/io-pgtable.h > index 86cf1f7ae389..4d696724c7da 100644 > --- a/include/linux/io-pgtable.h > +++ b/include/linux/io-pgtable.h > @@ -171,12 +171,26 @@ struct io_pgtable_cfg { > }; > }; > > +/** > + * struct io_pgtable_walk_data - information from a pgtable walk > + * > + * @ptes: The recorded PTE values from the walk > + * @level: The level of the last PTE > + * > + * @level also specifies the last valid index in @ptes > + */ > +struct io_pgtable_walk_data { > + u64 ptes[4]; > + int level; > +}; I wonder if we can do better than hardcoding the '4' here? I wouldn't be surprised if this doesn't work, but could we do something along the lines of: struct io_pgtable_walk_data { int level; int num_levels; u64 ptes[] __counted_by(num_levels); }; and then have the Arm (LPAE)-specific code wrap that in a private structure: struct arm_lpae_io_pgtable_walk_data { struct io_pgtable_walk_data data; u64 ptes[ARM_LPAE_MAX_LEVELS]; }; which is used by the walker? Will