| From 8f53492f86f9ca66bc762be98f0a9fce9bcb319a Mon Sep 17 00:00:00 2001 |
| From: Christian König <christian.koenig@amd.com> |
| Date: Tue, 18 Feb 2014 11:37:20 +0100 |
| Subject: drm/radeon: fix CP semaphores on CIK |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Christian König <christian.koenig@amd.com> |
| |
| commit 8f53492f86f9ca66bc762be98f0a9fce9bcb319a upstream. |
| |
| 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> |
| Signed-off-by: Alex Deucher <alexander.deucher@amd.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/gpu/drm/radeon/radeon.h | 4 +++- |
| drivers/gpu/drm/radeon/radeon_ring.c | 2 +- |
| drivers/gpu/drm/radeon/radeon_semaphore.c | 19 ++++++++++++++++--- |
| 3 files changed, 20 insertions(+), 5 deletions(-) |
| |
| --- a/drivers/gpu/drm/radeon/radeon.h |
| +++ b/drivers/gpu/drm/radeon/radeon.h |
| @@ -134,6 +134,9 @@ extern int radeon_runtime_pm; |
| /* 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) |
| @@ -544,7 +547,6 @@ int radeon_mode_dumb_mmap(struct drm_fil |
| /* |
| * Semaphores. |
| */ |
| -/* everything here is constant */ |
| struct radeon_semaphore { |
| struct radeon_sa_bo *sa_bo; |
| signed waiters; |
| --- a/drivers/gpu/drm/radeon/radeon_ring.c |
| +++ b/drivers/gpu/drm/radeon/radeon_ring.c |
| @@ -139,7 +139,7 @@ int radeon_ib_schedule(struct radeon_dev |
| } |
| |
| /* 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; |
| --- a/drivers/gpu/drm/radeon/radeon_semaphore.c |
| +++ b/drivers/gpu/drm/radeon/radeon_semaphore.c |
| @@ -34,14 +34,15 @@ |
| 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 radeo |
| } |
| (*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 r |
| 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 r |
| 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 r |
| |
| radeon_ring_commit(rdev, &rdev->ring[i]); |
| radeon_fence_note_sync(fence, ring); |
| + |
| + semaphore->gpu_addr += 8; |
| } |
| |
| return 0; |