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:
committed by
Carlos Llamas
parent
76e0641e68
commit
267fb29e09
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user