From 8f676c4c6f0f500616560f13c0276ab6b4e39a6a Mon Sep 17 00:00:00 2001 From: Christian König Date: Wed, 2 May 2012 15:11:18 +0200 Subject: drm/radeon: fix a bug with the ring syncing code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rings need to lock in order, otherwise the ring subsystem can deadlock. v2: fix error handling and number of locked doublewords. v3: stop creating unneeded semaphores. Signed-off-by: Christian König Reviewed-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_semaphore.c | 56 +++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'drivers/gpu/drm/radeon/radeon_semaphore.c') diff --git a/drivers/gpu/drm/radeon/radeon_semaphore.c b/drivers/gpu/drm/radeon/radeon_semaphore.c index 61dd4e3c9209..930a08af900f 100644 --- a/drivers/gpu/drm/radeon/radeon_semaphore.c +++ b/drivers/gpu/drm/radeon/radeon_semaphore.c @@ -149,6 +149,62 @@ void radeon_semaphore_emit_wait(struct radeon_device *rdev, int ring, radeon_semaphore_ring_emit(rdev, ring, &rdev->ring[ring], semaphore, true); } +int radeon_semaphore_sync_rings(struct radeon_device *rdev, + struct radeon_semaphore *semaphore, + bool sync_to[RADEON_NUM_RINGS], + int dst_ring) +{ + int i, r; + + for (i = 0; i < RADEON_NUM_RINGS; ++i) { + unsigned num_ops = i == dst_ring ? RADEON_NUM_RINGS : 1; + + /* don't lock unused rings */ + if (!sync_to[i] && i != dst_ring) + continue; + + /* prevent GPU deadlocks */ + if (!rdev->ring[i].ready) { + dev_err(rdev->dev, "Trying to sync to a disabled ring!"); + r = -EINVAL; + goto error; + } + + r = radeon_ring_lock(rdev, &rdev->ring[i], num_ops * 8); + if (r) + goto error; + } + + for (i = 0; i < RADEON_NUM_RINGS; ++i) { + /* no need to sync to our own or unused rings */ + if (!sync_to[i] || i == dst_ring) + continue; + + radeon_semaphore_emit_signal(rdev, i, semaphore); + radeon_semaphore_emit_wait(rdev, dst_ring, semaphore); + } + + for (i = 0; i < RADEON_NUM_RINGS; ++i) { + + /* don't unlock unused rings */ + if (!sync_to[i] && i != dst_ring) + continue; + + radeon_ring_unlock_commit(rdev, &rdev->ring[i]); + } + + return 0; + +error: + /* unlock all locks taken so far */ + for (--i; i >= 0; --i) { + if (sync_to[i] || i == dst_ring) { + radeon_ring_unlock_undo(rdev, &rdev->ring[i]); + } + } + return r; +} + void radeon_semaphore_free(struct radeon_device *rdev, struct radeon_semaphore *semaphore) { -- cgit v1.2.3