iommu/arm-smmu: fix a DOMAIN_ATTR_DYNAMIC memory leak
The pagetable memory for a domain is freed by free_io_pgtable_ops(), which is only called from arm_smmu_destroy_domain_context(). This function also cleans up the hardware's context bank state and it is called during iommu_device_detach(). Because dynamic domains don't have context bank state, they don't call arm_smmu_destroy_domain_context() and thus their pagetable memory was leaked. Fix this by instead calling free_io_pgtable_ops() during iommu_domain_destroy(). This ensures that the pagetable is freed for all domains. Change-Id: Id349fdc7df673cd4513468f23dcc95a9281d2657 Signed-off-by: Jeremy Gebben <jgebben@codeaurora.org>
This commit is contained in:
parent
599de5c63b
commit
fe676929a9
1 changed files with 13 additions and 6 deletions
|
@ -853,6 +853,10 @@ static void arm_smmu_tlb_sync_cb(struct arm_smmu_device *smmu,
|
||||||
static void arm_smmu_tlb_sync(void *cookie)
|
static void arm_smmu_tlb_sync(void *cookie)
|
||||||
{
|
{
|
||||||
struct arm_smmu_domain *smmu_domain = cookie;
|
struct arm_smmu_domain *smmu_domain = cookie;
|
||||||
|
|
||||||
|
if (smmu_domain->smmu == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
arm_smmu_tlb_sync_cb(smmu_domain->smmu, smmu_domain->cfg.cbndx);
|
arm_smmu_tlb_sync_cb(smmu_domain->smmu, smmu_domain->cfg.cbndx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1479,17 +1483,13 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain)
|
||||||
cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
|
cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
|
||||||
writel_relaxed(0, cb_base + ARM_SMMU_CB_SCTLR);
|
writel_relaxed(0, cb_base + ARM_SMMU_CB_SCTLR);
|
||||||
|
|
||||||
|
arm_smmu_tlb_inv_context(smmu_domain);
|
||||||
|
|
||||||
if (cfg->irptndx != INVALID_IRPTNDX) {
|
if (cfg->irptndx != INVALID_IRPTNDX) {
|
||||||
irq = smmu->irqs[smmu->num_global_irqs + cfg->irptndx];
|
irq = smmu->irqs[smmu->num_global_irqs + cfg->irptndx];
|
||||||
free_irq(irq, domain);
|
free_irq(irq, domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (smmu_domain->pgtbl_ops) {
|
|
||||||
free_io_pgtable_ops(smmu_domain->pgtbl_ops);
|
|
||||||
/* unassign any freed page table memory */
|
|
||||||
arm_smmu_unassign_table(smmu_domain);
|
|
||||||
}
|
|
||||||
|
|
||||||
arm_smmu_disable_clocks(smmu_domain->smmu);
|
arm_smmu_disable_clocks(smmu_domain->smmu);
|
||||||
|
|
||||||
__arm_smmu_free_bitmap(smmu->context_map, cfg->cbndx);
|
__arm_smmu_free_bitmap(smmu->context_map, cfg->cbndx);
|
||||||
|
@ -1533,6 +1533,13 @@ static void arm_smmu_domain_destroy(struct iommu_domain *domain)
|
||||||
* Free the domain resources. We assume that all devices have
|
* Free the domain resources. We assume that all devices have
|
||||||
* already been detached.
|
* already been detached.
|
||||||
*/
|
*/
|
||||||
|
if (smmu_domain->pgtbl_ops) {
|
||||||
|
free_io_pgtable_ops(smmu_domain->pgtbl_ops);
|
||||||
|
/* unassign any freed page table memory */
|
||||||
|
arm_smmu_unassign_table(smmu_domain);
|
||||||
|
smmu_domain->pgtbl_ops = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
kfree(smmu_domain);
|
kfree(smmu_domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue