diff options
author | Harshitha Sai Neelati <quic_hsaineel@quicinc.com> | 2023-02-15 23:07:29 +0530 |
---|---|---|
committer | Harshitha Sai Neelati <quic_hsaineel@quicinc.com> | 2023-02-28 14:01:07 +0530 |
commit | 4d87657af0d3159c77ab4c05b4c04e7869249c24 (patch) | |
tree | 4f04d9ef0140cdf74c387ad338d9debad7f33e5d | |
parent | 23fb0f089b60ff8564f7aff5cf5285e4c265769d (diff) | |
download | graphics-4d87657af0d3159c77ab4c05b4c04e7869249c24.tar.gz |
msm: kgsl: Fix null pointer dereference in deferred_destroy
iommu->user_context can get detached in kgsl_iommu_close and later
get accessed in the deferred_destroy path. Flush the workqueue to
ensure pagetables are destroyed before proceeding for context detach.
Also handle set_ttbr0_cfg properly in the close path.
Change-Id: Idd936957e9c7617d978056604241e2e24dac8af4
Signed-off-by: Harshitha Sai Neelati <quic_hsaineel@quicinc.com>
-rw-r--r-- | kgsl_iommu.c | 63 |
1 files changed, 34 insertions, 29 deletions
diff --git a/kgsl_iommu.c b/kgsl_iommu.c index 1dc1daf..d62626a 100644 --- a/kgsl_iommu.c +++ b/kgsl_iommu.c @@ -1125,6 +1125,24 @@ static u64 kgsl_iommu_get_ttbr0(struct kgsl_pagetable *pagetable) return pt->ttbr0; } +/* Set TTBR0 for the given context with the specific configuration */ +static void kgsl_iommu_set_ttbr0(struct kgsl_iommu_context *context, + struct kgsl_mmu *mmu, const struct io_pgtable_cfg *pgtbl_cfg) +{ + struct adreno_smmu_priv *adreno_smmu; + + /* Quietly return if the context doesn't have a domain */ + if (!context->domain) + return; + + adreno_smmu = dev_get_drvdata(&context->pdev->dev); + + /* Enable CX and clocks before we call into SMMU to setup registers */ + kgsl_iommu_enable_clk(mmu); + adreno_smmu->set_ttbr0_cfg(adreno_smmu->cookie, pgtbl_cfg); + kgsl_iommu_disable_clk(mmu); +} + static int kgsl_iommu_get_context_bank(struct kgsl_pagetable *pt, struct kgsl_context *context) { struct kgsl_iommu *iommu = to_kgsl_iommu(pt); @@ -1154,9 +1172,6 @@ static int kgsl_iommu_get_asid(struct kgsl_pagetable *pt, struct kgsl_context *c static void kgsl_iommu_destroy_default_pagetable(struct kgsl_pagetable *pagetable) { struct kgsl_device *device = KGSL_MMU_DEVICE(pagetable->mmu); - struct kgsl_iommu *iommu = to_kgsl_iommu(pagetable); - struct kgsl_iommu_context *context = &iommu->user_context; - struct adreno_smmu_priv *adreno_smmu = dev_get_drvdata(&context->pdev->dev); struct kgsl_iommu_pt *pt = to_iommu_pt(pagetable); struct kgsl_global_memdesc *md; @@ -1167,8 +1182,6 @@ static void kgsl_iommu_destroy_default_pagetable(struct kgsl_pagetable *pagetabl kgsl_iommu_default_unmap(pagetable, &md->memdesc); } - adreno_smmu->set_ttbr0_cfg(adreno_smmu->cookie, NULL); - kfree(pt); } @@ -1256,25 +1269,6 @@ static int kgsl_iopgtbl_alloc(struct kgsl_iommu_context *ctx, struct kgsl_iommu_ return 0; } -/* Enable TTBR0 for the given context with the specific configuration */ -static void kgsl_iommu_enable_ttbr0(struct kgsl_iommu_context *context, - struct kgsl_iommu_pt *pt) -{ - struct adreno_smmu_priv *adreno_smmu; - struct kgsl_mmu *mmu = pt->base.mmu; - - /* Quietly return if the context doesn't have a domain */ - if (!context->domain) - return; - - adreno_smmu = dev_get_drvdata(&context->pdev->dev); - - /* Enable CX and clocks before we call into SMMU to setup registers */ - kgsl_iommu_enable_clk(mmu); - adreno_smmu->set_ttbr0_cfg(adreno_smmu->cookie, &pt->cfg); - kgsl_iommu_disable_clk(mmu); -} - static struct kgsl_pagetable *kgsl_iommu_default_pagetable(struct kgsl_mmu *mmu) { struct kgsl_iommu *iommu = &mmu->iommu; @@ -1457,11 +1451,21 @@ static void kgsl_iommu_close(struct kgsl_mmu *mmu) /* First put away the default pagetables */ kgsl_mmu_putpagetable(mmu->defaultpagetable); - mmu->defaultpagetable = NULL; kgsl_mmu_putpagetable(mmu->securepagetable); + + /* + * Flush the workqueue to ensure pagetables are + * destroyed before proceeding further + */ + flush_workqueue(kgsl_driver.workqueue); + + mmu->defaultpagetable = NULL; mmu->securepagetable = NULL; + kgsl_iommu_set_ttbr0(&iommu->lpac_context, mmu, NULL); + kgsl_iommu_set_ttbr0(&iommu->user_context, mmu, NULL); + /* Next, detach the context banks */ kgsl_iommu_detach_context(&iommu->user_context); kgsl_iommu_detach_context(&iommu->lpac_context); @@ -2195,6 +2199,7 @@ static int iommu_probe_user_context(struct kgsl_device *device, struct kgsl_iommu *iommu = KGSL_IOMMU(device); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct kgsl_mmu *mmu = &device->mmu; + struct kgsl_iommu_pt *pt; int ret; ret = kgsl_iommu_setup_context(mmu, node, &iommu->user_context, @@ -2236,14 +2241,14 @@ static int iommu_probe_user_context(struct kgsl_device *device, if (!test_bit(KGSL_MMU_IOPGTABLE, &mmu->features)) return 0; + pt = to_iommu_pt(mmu->defaultpagetable); + /* Enable TTBR0 on the default and LPAC contexts */ - kgsl_iommu_enable_ttbr0(&iommu->user_context, - to_iommu_pt(mmu->defaultpagetable)); + kgsl_iommu_set_ttbr0(&iommu->user_context, mmu, &pt->cfg); kgsl_set_smmu_aperture(device, &iommu->user_context); - kgsl_iommu_enable_ttbr0(&iommu->lpac_context, - to_iommu_pt(mmu->defaultpagetable)); + kgsl_iommu_set_ttbr0(&iommu->lpac_context, mmu, &pt->cfg); ret = set_smmu_lpac_aperture(device, &iommu->lpac_context); /* LPAC is optional, ignore setup failures in absence of LPAC feature */ |