summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/radeon_semaphore.c
diff options
context:
space:
mode:
authorChristian König <deathsimple@vodafone.de>2012-05-02 15:11:18 +0200
committerDave Airlie <airlied@redhat.com>2012-05-03 09:16:27 +0100
commit8f676c4c6f0f500616560f13c0276ab6b4e39a6a (patch)
tree722ab761de1b53460f4b0308c08f0e41a18b4b5c /drivers/gpu/drm/radeon/radeon_semaphore.c
parentbfb9a07785fea0c41dff1a38890bc9b4679a9430 (diff)
downloadlinux-8f676c4c6f0f500616560f13c0276ab6b4e39a6a.tar.bz2
drm/radeon: fix a bug with the ring syncing code
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 <deathsimple@vodafone.de> Reviewed-by: Jerome Glisse <jglisse@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_semaphore.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_semaphore.c56
1 files changed, 56 insertions, 0 deletions
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)
{