drm/msm: fix potential deadlock in gpu init
authorRob Clark <robdclark@gmail.com>
Fri, 11 Jul 2014 15:59:22 +0000 (11:59 -0400)
committerRob Clark <robdclark@gmail.com>
Mon, 4 Aug 2014 15:55:29 +0000 (11:55 -0400)
Somewhere along the way, the firmware loader sprouted another lock
dependency, resulting in possible deadlock scenario:

 &dev->struct_mutex --> &sb->s_type->i_mutex_key#2 --> &mm->mmap_sem

which is problematic vs things like gem mmap.

So introduce a separate mutex to synchronize gpu init.

Signed-off-by: Rob Clark <robdclark@gmail.com>
drivers/gpu/drm/msm/adreno/adreno_gpu.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_gpu.c

index 76c1df73e7475fff826b93536d4b5d713125bef5..655ce5b14ad04564a5fb73e72e26b338bb3fb4e3 100644 (file)
@@ -95,7 +95,7 @@ int adreno_hw_init(struct msm_gpu *gpu)
 
        DBG("%s", gpu->name);
 
-       ret = msm_gem_get_iova_locked(gpu->rb->bo, gpu->id, &gpu->rb_iova);
+       ret = msm_gem_get_iova(gpu->rb->bo, gpu->id, &gpu->rb_iova);
        if (ret) {
                gpu->rb_iova = 0;
                dev_err(gpu->dev->dev, "could not map ringbuffer: %d\n", ret);
@@ -370,8 +370,10 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
                        return ret;
        }
 
+       mutex_lock(&drm->struct_mutex);
        gpu->memptrs_bo = msm_gem_new(drm, sizeof(*gpu->memptrs),
                        MSM_BO_UNCACHED);
+       mutex_unlock(&drm->struct_mutex);
        if (IS_ERR(gpu->memptrs_bo)) {
                ret = PTR_ERR(gpu->memptrs_bo);
                gpu->memptrs_bo = NULL;
@@ -379,13 +381,13 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
                return ret;
        }
 
-       gpu->memptrs = msm_gem_vaddr_locked(gpu->memptrs_bo);
+       gpu->memptrs = msm_gem_vaddr(gpu->memptrs_bo);
        if (!gpu->memptrs) {
                dev_err(drm->dev, "could not vmap memptrs\n");
                return -ENOMEM;
        }
 
-       ret = msm_gem_get_iova_locked(gpu->memptrs_bo, gpu->base.id,
+       ret = msm_gem_get_iova(gpu->memptrs_bo, gpu->base.id,
                        &gpu->memptrs_iova);
        if (ret) {
                dev_err(drm->dev, "could not map memptrs: %d\n", ret);
index a2f5bf6da6f3d10c07efc06afb825a040d4ea674..b447c01ad89c86c909b92679444843989df22c9e 100644 (file)
@@ -181,7 +181,6 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
        struct msm_kms *kms;
        int ret;
 
-
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv) {
                dev_err(dev->dev, "failed to allocate private data\n");
@@ -314,13 +313,15 @@ fail:
 
 static void load_gpu(struct drm_device *dev)
 {
+       static DEFINE_MUTEX(init_lock);
        struct msm_drm_private *priv = dev->dev_private;
        struct msm_gpu *gpu;
 
+       mutex_lock(&init_lock);
+
        if (priv->gpu)
-               return;
+               goto out;
 
-       mutex_lock(&dev->struct_mutex);
        gpu = a3xx_gpu_init(dev);
        if (IS_ERR(gpu)) {
                dev_warn(dev->dev, "failed to load a3xx gpu\n");
@@ -330,7 +331,9 @@ static void load_gpu(struct drm_device *dev)
 
        if (gpu) {
                int ret;
+               mutex_lock(&dev->struct_mutex);
                gpu->funcs->pm_resume(gpu);
+               mutex_unlock(&dev->struct_mutex);
                ret = gpu->funcs->hw_init(gpu);
                if (ret) {
                        dev_err(dev->dev, "gpu hw init failed: %d\n", ret);
@@ -340,12 +343,12 @@ static void load_gpu(struct drm_device *dev)
                        /* give inactive pm a chance to kick in: */
                        msm_gpu_retire(gpu);
                }
-
        }
 
        priv->gpu = gpu;
 
-       mutex_unlock(&dev->struct_mutex);
+out:
+       mutex_unlock(&init_lock);
 }
 
 static int msm_open(struct drm_device *dev, struct drm_file *file)
index 915240b4b80a082277d4f5c20f1c1f9ba68ad507..4a0dce58774571bc2fb885f0e867bee58ad434d8 100644 (file)
@@ -612,8 +612,11 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
        }
        gpu->id = msm_register_mmu(drm, gpu->mmu);
 
+
        /* Create ringbuffer: */
+       mutex_lock(&drm->struct_mutex);
        gpu->rb = msm_ringbuffer_new(gpu, ringsz);
+       mutex_unlock(&drm->struct_mutex);
        if (IS_ERR(gpu->rb)) {
                ret = PTR_ERR(gpu->rb);
                gpu->rb = NULL;