From fe676929a9601610dec537cc62dc84a66ca7f43f Mon Sep 17 00:00:00 2001 From: Jeremy Gebben Date: Mon, 24 Aug 2015 16:16:31 -0600 Subject: [PATCH] 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 --- drivers/iommu/arm-smmu.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 67c3d70ed946..89c53d93f48c 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -853,6 +853,10 @@ static void arm_smmu_tlb_sync_cb(struct arm_smmu_device *smmu, static void arm_smmu_tlb_sync(void *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); } @@ -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); writel_relaxed(0, cb_base + ARM_SMMU_CB_SCTLR); + arm_smmu_tlb_inv_context(smmu_domain); + if (cfg->irptndx != INVALID_IRPTNDX) { irq = smmu->irqs[smmu->num_global_irqs + cfg->irptndx]; 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_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 * 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); } -- 2.11.0