drm/radeon: fix CP semaphores on CIK
authorChristian König <christian.koenig@amd.com>
Tue, 18 Feb 2014 10:37:20 +0000 (11:37 +0100)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 18 Feb 2014 18:41:05 +0000 (13:41 -0500)
The CP semaphore queue on CIK has a bug that triggers if uncompleted
waits use the same address while a signal is still pending. Work around
this by using different addresses for each sync.

Signed-off-by: Christian König <christian.koenig@amd.com>
Cc: stable@vger.kernel.org
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_ring.c
drivers/gpu/drm/radeon/radeon_semaphore.c

index 4a8ac1cd6b4c65582690e035e026aa6f1b125e00..024db37b1832fdead3f64fbcecccff851493a633 100644 (file)
@@ -135,6 +135,9 @@ extern int radeon_hard_reset;
 /* R600+ */
 #define R600_RING_TYPE_UVD_INDEX       5
 
+/* number of hw syncs before falling back on blocking */
+#define RADEON_NUM_SYNCS                       4
+
 /* hardcode those limit for now */
 #define RADEON_VA_IB_OFFSET                    (1 << 20)
 #define RADEON_VA_RESERVED_SIZE                        (8 << 20)
@@ -554,7 +557,6 @@ int radeon_mode_dumb_mmap(struct drm_file *filp,
 /*
  * Semaphores.
  */
-/* everything here is constant */
 struct radeon_semaphore {
        struct radeon_sa_bo             *sa_bo;
        signed                          waiters;
index 1b783f0e6d3ad084b0a62629a4b5d67c9e92453f..15e44a7281ab96f6b14592ed2e4e840ddae0b74f 100644 (file)
@@ -139,7 +139,7 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib,
        }
 
        /* 64 dwords should be enough for fence too */
-       r = radeon_ring_lock(rdev, ring, 64 + RADEON_NUM_RINGS * 8);
+       r = radeon_ring_lock(rdev, ring, 64 + RADEON_NUM_SYNCS * 8);
        if (r) {
                dev_err(rdev->dev, "scheduling IB failed (%d).\n", r);
                return r;
index 2b42aa1914f2006dabddee990cd14fc919668d59..9006b32d5eed0433d336ef56e1bfb17c6fffa0de 100644 (file)
 int radeon_semaphore_create(struct radeon_device *rdev,
                            struct radeon_semaphore **semaphore)
 {
+       uint32_t *cpu_addr;
        int i, r;
 
        *semaphore = kmalloc(sizeof(struct radeon_semaphore), GFP_KERNEL);
        if (*semaphore == NULL) {
                return -ENOMEM;
        }
-       r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo,
-                            &(*semaphore)->sa_bo, 8, 8, true);
+       r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, &(*semaphore)->sa_bo,
+                            8 * RADEON_NUM_SYNCS, 8, true);
        if (r) {
                kfree(*semaphore);
                *semaphore = NULL;
@@ -49,7 +50,10 @@ int radeon_semaphore_create(struct radeon_device *rdev,
        }
        (*semaphore)->waiters = 0;
        (*semaphore)->gpu_addr = radeon_sa_bo_gpu_addr((*semaphore)->sa_bo);
-       *((uint64_t*)radeon_sa_bo_cpu_addr((*semaphore)->sa_bo)) = 0;
+
+       cpu_addr = radeon_sa_bo_cpu_addr((*semaphore)->sa_bo);
+       for (i = 0; i < RADEON_NUM_SYNCS; ++i)
+               cpu_addr[i] = 0;
 
        for (i = 0; i < RADEON_NUM_RINGS; ++i)
                (*semaphore)->sync_to[i] = NULL;
@@ -125,6 +129,7 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev,
                                struct radeon_semaphore *semaphore,
                                int ring)
 {
+       unsigned count = 0;
        int i, r;
 
         for (i = 0; i < RADEON_NUM_RINGS; ++i) {
@@ -140,6 +145,12 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev,
                        return -EINVAL;
                }
 
+               if (++count > RADEON_NUM_SYNCS) {
+                       /* not enough room, wait manually */
+                       radeon_fence_wait_locked(fence);
+                       continue;
+               }
+
                /* allocate enough space for sync command */
                r = radeon_ring_alloc(rdev, &rdev->ring[i], 16);
                if (r) {
@@ -164,6 +175,8 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev,
 
                radeon_ring_commit(rdev, &rdev->ring[i]);
                radeon_fence_note_sync(fence, ring);
+
+               semaphore->gpu_addr += 8;
        }
 
        return 0;