drm/radeon: avoid deadlock if GPU lockup is detected in ib_pool_get
authorJerome Glisse <jglisse@redhat.com>
Mon, 23 Jan 2012 16:52:15 +0000 (11:52 -0500)
committerDave Airlie <airlied@redhat.com>
Wed, 25 Jan 2012 09:42:06 +0000 (09:42 +0000)
If GPU lockup is detected in ib_pool get we are holding the ib_pool
mutex that will be needed by the GPU reset code. As ib_pool code is
safe to be reentrant from GPU reset code we should not block if we
are trying to get the ib pool lock on the behalf of the same userspace
caller, thus use the radeon_mutex_lock helper.

Signed-off-by: Jerome Glisse <jglisse@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_ring.c

index 73e05cb85eca03cd2c65461ce1af7ca3f82e0bfc..1668ec1ee77047d945bb8cb952a523d51f8bd452 100644 (file)
@@ -156,6 +156,47 @@ static inline int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len)
 bool radeon_get_bios(struct radeon_device *rdev);
 
 
+/*
+ * Mutex which allows recursive locking from the same process.
+ */
+struct radeon_mutex {
+       struct mutex            mutex;
+       struct task_struct      *owner;
+       int                     level;
+};
+
+static inline void radeon_mutex_init(struct radeon_mutex *mutex)
+{
+       mutex_init(&mutex->mutex);
+       mutex->owner = NULL;
+       mutex->level = 0;
+}
+
+static inline void radeon_mutex_lock(struct radeon_mutex *mutex)
+{
+       if (mutex_trylock(&mutex->mutex)) {
+               /* The mutex was unlocked before, so it's ours now */
+               mutex->owner = current;
+       } else if (mutex->owner != current) {
+               /* Another process locked the mutex, take it */
+               mutex_lock(&mutex->mutex);
+               mutex->owner = current;
+       }
+       /* Otherwise the mutex was already locked by this process */
+
+       mutex->level++;
+}
+
+static inline void radeon_mutex_unlock(struct radeon_mutex *mutex)
+{
+       if (--mutex->level > 0)
+               return;
+
+       mutex->owner = NULL;
+       mutex_unlock(&mutex->mutex);
+}
+
+
 /*
  * Dummy page
  */
@@ -598,7 +639,7 @@ struct radeon_ib {
  * mutex protects scheduled_ibs, ready, alloc_bm
  */
 struct radeon_ib_pool {
-       struct mutex                    mutex;
+       struct radeon_mutex             mutex;
        struct radeon_sa_manager        sa_manager;
        struct radeon_ib                ibs[RADEON_IB_POOL_SIZE];
        bool                            ready;
@@ -1354,47 +1395,6 @@ struct r600_vram_scratch {
 };
 
 
-/*
- * Mutex which allows recursive locking from the same process.
- */
-struct radeon_mutex {
-       struct mutex            mutex;
-       struct task_struct      *owner;
-       int                     level;
-};
-
-static inline void radeon_mutex_init(struct radeon_mutex *mutex)
-{
-       mutex_init(&mutex->mutex);
-       mutex->owner = NULL;
-       mutex->level = 0;
-}
-
-static inline void radeon_mutex_lock(struct radeon_mutex *mutex)
-{
-       if (mutex_trylock(&mutex->mutex)) {
-               /* The mutex was unlocked before, so it's ours now */
-               mutex->owner = current;
-       } else if (mutex->owner != current) {
-               /* Another process locked the mutex, take it */
-               mutex_lock(&mutex->mutex);
-               mutex->owner = current;
-       }
-       /* Otherwise the mutex was already locked by this process */
-
-       mutex->level++;
-}
-
-static inline void radeon_mutex_unlock(struct radeon_mutex *mutex)
-{
-       if (--mutex->level > 0)
-               return;
-
-       mutex->owner = NULL;
-       mutex_unlock(&mutex->mutex);
-}
-
-
 /*
  * Core structure, functions and helpers.
  */
index a811bc64ad5c98d22bcfafb5f1f6b007dac1bbb3..cec51a5b69ddd7fae455e1e6f2814f9e36911bcd 100644 (file)
@@ -720,7 +720,7 @@ int radeon_device_init(struct radeon_device *rdev,
        /* mutex initialization are all done here so we
         * can recall function without having locking issues */
        radeon_mutex_init(&rdev->cs_mutex);
-       mutex_init(&rdev->ib_pool.mutex);
+       radeon_mutex_init(&rdev->ib_pool.mutex);
        for (i = 0; i < RADEON_NUM_RINGS; ++i)
                mutex_init(&rdev->ring[i].mutex);
        mutex_init(&rdev->dc_hw_i2c_mutex);
index 1cb4b941be4756447cbfdc9ecf1b6d52e06e4cd0..30a4c5014c8b3f6a19f2e5e6d3102c488ac013e2 100644 (file)
@@ -109,12 +109,12 @@ int radeon_ib_get(struct radeon_device *rdev, int ring,
                return r;
        }
 
-       mutex_lock(&rdev->ib_pool.mutex);
+       radeon_mutex_lock(&rdev->ib_pool.mutex);
        idx = rdev->ib_pool.head_id;
 retry:
        if (cretry > 5) {
                dev_err(rdev->dev, "failed to get an ib after 5 retry\n");
-               mutex_unlock(&rdev->ib_pool.mutex);
+               radeon_mutex_unlock(&rdev->ib_pool.mutex);
                radeon_fence_unref(&fence);
                return -ENOMEM;
        }
@@ -139,7 +139,7 @@ retry:
                                 */
                                rdev->ib_pool.head_id = (1 + idx);
                                rdev->ib_pool.head_id &= (RADEON_IB_POOL_SIZE - 1);
-                               mutex_unlock(&rdev->ib_pool.mutex);
+                               radeon_mutex_unlock(&rdev->ib_pool.mutex);
                                return 0;
                        }
                }
@@ -158,7 +158,7 @@ retry:
                }
                idx = (idx + 1) & (RADEON_IB_POOL_SIZE - 1);
        }
-       mutex_unlock(&rdev->ib_pool.mutex);
+       radeon_mutex_unlock(&rdev->ib_pool.mutex);
        radeon_fence_unref(&fence);
        return r;
 }
@@ -171,12 +171,12 @@ void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib)
        if (tmp == NULL) {
                return;
        }
-       mutex_lock(&rdev->ib_pool.mutex);
+       radeon_mutex_lock(&rdev->ib_pool.mutex);
        if (tmp->fence && !tmp->fence->emitted) {
                radeon_sa_bo_free(rdev, &tmp->sa_bo);
                radeon_fence_unref(&tmp->fence);
        }
-       mutex_unlock(&rdev->ib_pool.mutex);
+       radeon_mutex_unlock(&rdev->ib_pool.mutex);
 }
 
 int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib)
@@ -214,9 +214,9 @@ int radeon_ib_pool_init(struct radeon_device *rdev)
                return r;
        }
 
-       mutex_lock(&rdev->ib_pool.mutex);
+       radeon_mutex_lock(&rdev->ib_pool.mutex);
        if (rdev->ib_pool.ready) {
-               mutex_unlock(&rdev->ib_pool.mutex);
+               radeon_mutex_unlock(&rdev->ib_pool.mutex);
                radeon_sa_bo_manager_fini(rdev, &tmp);
                return 0;
        }
@@ -239,7 +239,7 @@ int radeon_ib_pool_init(struct radeon_device *rdev)
        if (radeon_debugfs_ring_init(rdev)) {
                DRM_ERROR("Failed to register debugfs file for rings !\n");
        }
-       mutex_unlock(&rdev->ib_pool.mutex);
+       radeon_mutex_unlock(&rdev->ib_pool.mutex);
        return 0;
 }
 
@@ -247,7 +247,7 @@ void radeon_ib_pool_fini(struct radeon_device *rdev)
 {
        unsigned i;
 
-       mutex_lock(&rdev->ib_pool.mutex);
+       radeon_mutex_lock(&rdev->ib_pool.mutex);
        if (rdev->ib_pool.ready) {
                for (i = 0; i < RADEON_IB_POOL_SIZE; i++) {
                        radeon_sa_bo_free(rdev, &rdev->ib_pool.ibs[i].sa_bo);
@@ -256,7 +256,7 @@ void radeon_ib_pool_fini(struct radeon_device *rdev)
                radeon_sa_bo_manager_fini(rdev, &rdev->ib_pool.sa_manager);
                rdev->ib_pool.ready = false;
        }
-       mutex_unlock(&rdev->ib_pool.mutex);
+       radeon_mutex_unlock(&rdev->ib_pool.mutex);
 }
 
 int radeon_ib_pool_start(struct radeon_device *rdev)