ANDROID: iommu/io-pgtable: Add new tlb operation free_leaf

free_leaf would be called when a page table is freed with valid
entries inside, for each entry.

That means, for pKVM SMMUv3 driver, we don't have to walk the
table on walk flush.

Bug: 357781595
Bug: 348382247
Bug: 236685427
Change-Id: I1a0f9ab3650fea0c670449f9cd3a452867e41db0
Signed-off-by: Mostafa Saleh <smostafa@google.com>
This commit is contained in:
Mostafa Saleh
2025-03-07 17:14:43 +00:00
committed by Carlos Llamas
parent 76e0641e68
commit 267fb29e09
3 changed files with 23 additions and 25 deletions
@@ -908,25 +908,8 @@ static void smmu_tlb_flush_walk(unsigned long iova, size_t size,
size_t granule, void *cookie)
{
struct kvm_hyp_iommu_domain *domain = cookie;
struct hyp_arm_smmu_v3_domain *smmu_domain = domain->priv;
struct io_pgtable *pgtable = smmu_domain->pgtable;
struct arm_lpae_io_pgtable *data = io_pgtable_to_data(pgtable);
struct arm_lpae_io_pgtable_walk_data wd = {
.cookie = data,
};
struct io_pgtable_walk_common walk_data = {
.visit_leaf = smmu_unmap_visit_leaf,
.data = &wd,
};
smmu_tlb_inv_range(domain, iova, size, granule, false);
/* idmapped domains doesn't elevate refcounts. */
if (data->idmapped)
return;
/* We need to walk the table to make sure all leafs un-tracked. */
pgtable->ops.pgtable_walk(&pgtable->ops, iova, size, &walk_data);
}
static void smmu_tlb_add_page(struct iommu_iotlb_gather *gather,
@@ -939,10 +922,16 @@ static void smmu_tlb_add_page(struct iommu_iotlb_gather *gather,
smmu_tlb_inv_range(cookie, iova, granule, granule, true);
}
static void smmu_free_leaf(unsigned long phys, size_t granule, void *cookie)
{
WARN_ON(iommu_pkvm_unuse_dma(phys, granule));
}
static const struct iommu_flush_ops smmu_tlb_ops = {
.tlb_flush_all = smmu_tlb_flush_all,
.tlb_flush_walk = smmu_tlb_flush_walk,
.tlb_add_page = smmu_tlb_add_page,
.free_leaf = smmu_free_leaf,
};
static void smmu_iotlb_sync(struct kvm_hyp_iommu_domain *domain,
+8 -8
View File
@@ -351,20 +351,20 @@ void __arm_lpae_free_pgtable(struct arm_lpae_io_pgtable *data, int lvl,
table_size = ARM_LPAE_GRANULE(data);
start = ptep;
/* Only leaf entries at the last level */
if (lvl == ARM_LPAE_MAX_LEVELS - 1)
end = ptep;
else
end = (void *)ptep + table_size;
end = (void *)ptep + table_size;
while (ptep != end) {
arm_lpae_iopte pte = *ptep++;
if (!iopte_valid(pte) || iopte_leaf(pte, lvl, data->iop.fmt))
if (iopte_leaf(pte, lvl, data->iop.fmt)) {
io_pgtable_free_leaf(&data->iop, iopte_to_paddr(pte, data),
ARM_LPAE_BLOCK_SIZE(lvl, data));
continue;
}
__arm_lpae_free_pgtable(data, lvl + 1, iopte_deref(pte, data));
/* Only leaf entries at the last level */
if ((lvl != ARM_LPAE_MAX_LEVELS - 1) && iopte_valid(pte))
__arm_lpae_free_pgtable(data, lvl + 1, iopte_deref(pte, data));
}
__arm_lpae_free_pages(start, table_size, &data->iop.cfg, data->iop.cookie);
+9
View File
@@ -35,6 +35,7 @@ enum io_pgtable_fmt {
* operations efficiently will typically issue them here, but
* others may decide to update the iommu_iotlb_gather structure
* and defer the invalidation until iommu_iotlb_sync() instead.
* @free_leaf: Called when a valid leaf is removed when page table is freed.
*
* Note that these can all be called in atomic context and must therefore
* not block.
@@ -45,6 +46,7 @@ struct iommu_flush_ops {
void *cookie);
void (*tlb_add_page)(struct iommu_iotlb_gather *gather,
unsigned long iova, size_t granule, void *cookie);
void (*free_leaf)(unsigned long phys, size_t granule, void *cookie);
};
/**
@@ -322,6 +324,13 @@ io_pgtable_tlb_add_page(struct io_pgtable *iop,
iop->cfg.tlb->tlb_add_page(gather, iova, granule, iop->cookie);
}
static inline void
io_pgtable_free_leaf(struct io_pgtable *iop, unsigned long phys, size_t granule)
{
if (iop->cfg.tlb && iop->cfg.tlb->free_leaf)
iop->cfg.tlb->free_leaf(phys, granule, iop->cookie);
}
/**
* enum io_pgtable_caps - IO page table backend capabilities.
*/