[PATCH AUTOSEL 5.2 020/171] drm/msm/a6xx: Avoid freeing gmu resources multiple times

From: Sasha Levin
Date: Thu Jul 18 2019 - 23:57:42 EST


From: Sean Paul <seanpaul@xxxxxxxxxxxx>

[ Upstream commit 606ec90fc2266284f584a96ebf7f874589f56251 ]

The driver checks for gmu->mmio as a sign that the device has been
initialized, however there are failures in probe below the mmio init.
If one of those is hit, mmio will be non-null but freed.

In that case, a6xx_gmu_probe will return an error to a6xx_gpu_init which
will in turn call a6xx_gmu_remove which checks gmu->mmio and tries to free
resources for a second time. This causes a great boom.

Fix this by adding an initialized member to gmu which is set on
successful probe and cleared on removal.

Changes in v2:
- None

Cc: Jordan Crouse <jcrouse@xxxxxxxxxxxxxx>
Reviewed-by: Jordan Crouse <jcrouse@xxxxxxxxxxxxxx>
Signed-off-by: Sean Paul <seanpaul@xxxxxxxxxxxx>
Link: https://patchwork.freedesktop.org/patch/msgid/20190523171653.138678-1-sean@xxxxxxxxxx
Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>
---
drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 14 +++++++++-----
drivers/gpu/drm/msm/adreno/a6xx_gmu.h | 1 +
2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
index 418bb08bbed7..6910d0468e3c 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
@@ -74,7 +74,7 @@ bool a6xx_gmu_sptprac_is_on(struct a6xx_gmu *gmu)
u32 val;

/* This can be called from gpu state code so make sure GMU is valid */
- if (IS_ERR_OR_NULL(gmu->mmio))
+ if (!gmu->initialized)
return false;

val = gmu_read(gmu, REG_A6XX_GMU_SPTPRAC_PWR_CLK_STATUS);
@@ -90,7 +90,7 @@ bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu)
u32 val;

/* This can be called from gpu state code so make sure GMU is valid */
- if (IS_ERR_OR_NULL(gmu->mmio))
+ if (!gmu->initialized)
return false;

val = gmu_read(gmu, REG_A6XX_GMU_SPTPRAC_PWR_CLK_STATUS);
@@ -697,7 +697,7 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
int status, ret;

- if (WARN(!gmu->mmio, "The GMU is not set up yet\n"))
+ if (WARN(!gmu->initialized, "The GMU is not set up yet\n"))
return 0;

gmu->hung = false;
@@ -767,7 +767,7 @@ bool a6xx_gmu_isidle(struct a6xx_gmu *gmu)
{
u32 reg;

- if (!gmu->mmio)
+ if (!gmu->initialized)
return true;

reg = gmu_read(gmu, REG_A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS);
@@ -1229,7 +1229,7 @@ void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu)
{
struct a6xx_gmu *gmu = &a6xx_gpu->gmu;

- if (IS_ERR_OR_NULL(gmu->mmio))
+ if (!gmu->initialized)
return;

a6xx_gmu_stop(a6xx_gpu);
@@ -1247,6 +1247,8 @@ void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu)
iommu_detach_device(gmu->domain, gmu->dev);

iommu_domain_free(gmu->domain);
+
+ gmu->initialized = false;
}

int a6xx_gmu_probe(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
@@ -1311,6 +1313,8 @@ int a6xx_gmu_probe(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
/* Set up the HFI queues */
a6xx_hfi_init(gmu);

+ gmu->initialized = true;
+
return 0;
err:
a6xx_gmu_memory_free(gmu, gmu->hfi);
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
index bedd8e6a63aa..39a26dd63674 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
@@ -75,6 +75,7 @@ struct a6xx_gmu {

struct a6xx_hfi_queue queues[2];

+ bool initialized;
bool hung;
};

--
2.20.1