diff mbox

drm/radeon: fix CP semaphores on CIK

Message ID 1392719881-1619-1-git-send-email-deathsimple@vodafone.de (mailing list archive)
State New, archived
Headers show

Commit Message

Christian König Feb. 18, 2014, 10:38 a.m. UTC
From: Christian König <christian.koenig@amd.com>

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
---
 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(-)

Comments

Alex Deucher Feb. 18, 2014, 5:55 p.m. UTC | #1
On Tue, Feb 18, 2014 at 5:38 AM, Christian König
<deathsimple@vodafone.de> wrote:
> From: Christian König <christian.koenig@amd.com>
>
> 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

Applied to -fixes.  thanks!

Alex

> ---
>  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(-)
>
> diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
> index 4a8ac1c..024db37 100644
> --- a/drivers/gpu/drm/radeon/radeon.h
> +++ b/drivers/gpu/drm/radeon/radeon.h
> @@ -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;
> diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
> index 1b783f0..15e44a7 100644
> --- 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_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;
> diff --git a/drivers/gpu/drm/radeon/radeon_semaphore.c b/drivers/gpu/drm/radeon/radeon_semaphore.c
> index 2b42aa1..9006b32 100644
> --- 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 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;
> --
> 1.8.3.2
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
diff mbox

Patch

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 4a8ac1c..024db37 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -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;
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
index 1b783f0..15e44a7 100644
--- 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_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;
diff --git a/drivers/gpu/drm/radeon/radeon_semaphore.c b/drivers/gpu/drm/radeon/radeon_semaphore.c
index 2b42aa1..9006b32 100644
--- 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 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;