Skip to content

Commit

Permalink
drm/radeon: avoid deadlock if GPU lockup is detected in ib_pool_get
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jerome Glisse authored and Dave Airlie committed Jan 25, 2012
1 parent d54fbd4 commit 9fc04b5
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 54 deletions.
84 changes: 42 additions & 42 deletions drivers/gpu/drm/radeon/radeon.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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.
*/
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/radeon/radeon_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
22 changes: 11 additions & 11 deletions drivers/gpu/drm/radeon/radeon_ring.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -139,7 +139,7 @@ int radeon_ib_get(struct radeon_device *rdev, int ring,
*/
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;
}
}
Expand All @@ -158,7 +158,7 @@ int radeon_ib_get(struct radeon_device *rdev, int ring,
}
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;
}
Expand All @@ -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)
Expand Down Expand Up @@ -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;
}
Expand All @@ -239,15 +239,15 @@ 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;
}

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);
Expand All @@ -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)
Expand Down

0 comments on commit 9fc04b5

Please sign in to comment.