Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/msm/a6xx: Avoid freeing gmu resources multiple times

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@codeaurora.org>
Reviewed-by: Jordan Crouse <jcrouse@codeaurora.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20190523171653.138678-1-sean@poorly.run

+10 -5
+9 -5
drivers/gpu/drm/msm/adreno/a6xx_gmu.c
··· 74 74 u32 val; 75 75 76 76 /* This can be called from gpu state code so make sure GMU is valid */ 77 - if (IS_ERR_OR_NULL(gmu->mmio)) 77 + if (!gmu->initialized) 78 78 return false; 79 79 80 80 val = gmu_read(gmu, REG_A6XX_GMU_SPTPRAC_PWR_CLK_STATUS); ··· 90 90 u32 val; 91 91 92 92 /* This can be called from gpu state code so make sure GMU is valid */ 93 - if (IS_ERR_OR_NULL(gmu->mmio)) 93 + if (!gmu->initialized) 94 94 return false; 95 95 96 96 val = gmu_read(gmu, REG_A6XX_GMU_SPTPRAC_PWR_CLK_STATUS); ··· 695 695 struct a6xx_gmu *gmu = &a6xx_gpu->gmu; 696 696 int status, ret; 697 697 698 - if (WARN(!gmu->mmio, "The GMU is not set up yet\n")) 698 + if (WARN(!gmu->initialized, "The GMU is not set up yet\n")) 699 699 return 0; 700 700 701 701 gmu->hung = false; ··· 765 765 { 766 766 u32 reg; 767 767 768 - if (!gmu->mmio) 768 + if (!gmu->initialized) 769 769 return true; 770 770 771 771 reg = gmu_read(gmu, REG_A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS); ··· 1227 1227 { 1228 1228 struct a6xx_gmu *gmu = &a6xx_gpu->gmu; 1229 1229 1230 - if (IS_ERR_OR_NULL(gmu->mmio)) 1230 + if (!gmu->initialized) 1231 1231 return; 1232 1232 1233 1233 a6xx_gmu_stop(a6xx_gpu); ··· 1245 1245 iommu_detach_device(gmu->domain, gmu->dev); 1246 1246 1247 1247 iommu_domain_free(gmu->domain); 1248 + 1249 + gmu->initialized = false; 1248 1250 } 1249 1251 1250 1252 int a6xx_gmu_probe(struct a6xx_gpu *a6xx_gpu, struct device_node *node) ··· 1310 1308 1311 1309 /* Set up the HFI queues */ 1312 1310 a6xx_hfi_init(gmu); 1311 + 1312 + gmu->initialized = true; 1313 1313 1314 1314 return 0; 1315 1315 err:
+1
drivers/gpu/drm/msm/adreno/a6xx_gmu.h
··· 75 75 76 76 struct a6xx_hfi_queue queues[2]; 77 77 78 + bool initialized; 78 79 bool hung; 79 80 }; 80 81