aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/files/0411-drm-amdgpu-move-wait_queue_head-from-adev-to-ring-v2.patch
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-kernel/linux/files/0411-drm-amdgpu-move-wait_queue_head-from-adev-to-ring-v2.patch')
-rw-r--r--common/recipes-kernel/linux/files/0411-drm-amdgpu-move-wait_queue_head-from-adev-to-ring-v2.patch402
1 files changed, 402 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/files/0411-drm-amdgpu-move-wait_queue_head-from-adev-to-ring-v2.patch b/common/recipes-kernel/linux/files/0411-drm-amdgpu-move-wait_queue_head-from-adev-to-ring-v2.patch
new file mode 100644
index 00000000..0f7202a6
--- /dev/null
+++ b/common/recipes-kernel/linux/files/0411-drm-amdgpu-move-wait_queue_head-from-adev-to-ring-v2.patch
@@ -0,0 +1,402 @@
+From 7f06c236b964db3d8d086c5a0087b2eb4de3bf7a Mon Sep 17 00:00:00 2001
+From: "monk.liu" <monk.liu@amd.com>
+Date: Thu, 30 Jul 2015 18:28:12 +0800
+Subject: [PATCH 0411/1050] drm/amdgpu: move wait_queue_head from adev to ring
+ (v2)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+thus unnecessary wake up could be avoid between rings
+v2:
+move wait_queue_head to fence_drv from ring
+
+Signed-off-by: monk.liu <monk.liu@amd.com>
+Reviewed-by: Christian König <christian.koenig@amd.com>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 225 ++++++++++--------------------
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 2 +
+ 3 files changed, 77 insertions(+), 152 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+index 5f32f85..98b4760 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+@@ -391,6 +391,7 @@ struct amdgpu_fence_driver {
+ struct amdgpu_irq_src *irq_src;
+ unsigned irq_type;
+ struct delayed_work lockup_work;
++ wait_queue_head_t fence_queue;
+ };
+
+ /* some special values for the owner field */
+@@ -2036,7 +2037,6 @@ struct amdgpu_device {
+ struct amdgpu_irq_src hpd_irq;
+
+ /* rings */
+- wait_queue_head_t fence_queue;
+ unsigned fence_context;
+ struct mutex ring_lock;
+ unsigned num_rings;
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
+index 0f9800b..60e6d66 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
+@@ -126,7 +126,8 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, void *owner,
+ (*fence)->ring = ring;
+ (*fence)->owner = owner;
+ fence_init(&(*fence)->base, &amdgpu_fence_ops,
+- &adev->fence_queue.lock, adev->fence_context + ring->idx,
++ &ring->fence_drv.fence_queue.lock,
++ adev->fence_context + ring->idx,
+ (*fence)->seq);
+ amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr,
+ (*fence)->seq,
+@@ -164,7 +165,7 @@ static int amdgpu_fence_check_signaled(wait_queue_t *wait, unsigned mode, int fl
+ else
+ FENCE_TRACE(&fence->base, "was already signaled\n");
+
+- __remove_wait_queue(&adev->fence_queue, &fence->fence_wake);
++ __remove_wait_queue(&fence->ring->fence_drv.fence_queue, &fence->fence_wake);
+ fence_put(&fence->base);
+ } else
+ FENCE_TRACE(&fence->base, "pending\n");
+@@ -265,8 +266,9 @@ static void amdgpu_fence_check_lockup(struct work_struct *work)
+ return;
+ }
+
+- if (amdgpu_fence_activity(ring))
+- wake_up_all(&ring->adev->fence_queue);
++ if (amdgpu_fence_activity(ring)) {
++ wake_up_all(&ring->fence_drv.fence_queue);
++ }
+ else if (amdgpu_ring_is_lockup(ring)) {
+ /* good news we believe it's a lockup */
+ dev_warn(ring->adev->dev, "GPU lockup (current fence id "
+@@ -276,7 +278,7 @@ static void amdgpu_fence_check_lockup(struct work_struct *work)
+
+ /* remember that we need an reset */
+ ring->adev->needs_reset = true;
+- wake_up_all(&ring->adev->fence_queue);
++ wake_up_all(&ring->fence_drv.fence_queue);
+ }
+ up_read(&ring->adev->exclusive_lock);
+ }
+@@ -364,7 +366,7 @@ void amdgpu_fence_process(struct amdgpu_ring *ring)
+ } while (amd_sched_get_handled_seq(ring->scheduler) < latest_seq);
+ }
+
+- wake_up_all(&ring->adev->fence_queue);
++ wake_up_all(&ring->fence_drv.fence_queue);
+ }
+ exit:
+ spin_unlock_irqrestore(&ring->fence_lock, irqflags);
+@@ -427,7 +429,6 @@ static bool amdgpu_fence_enable_signaling(struct fence *f)
+ {
+ struct amdgpu_fence *fence = to_amdgpu_fence(f);
+ struct amdgpu_ring *ring = fence->ring;
+- struct amdgpu_device *adev = ring->adev;
+
+ if (atomic64_read(&ring->fence_drv.last_seq) >= fence->seq)
+ return false;
+@@ -435,7 +436,7 @@ static bool amdgpu_fence_enable_signaling(struct fence *f)
+ fence->fence_wake.flags = 0;
+ fence->fence_wake.private = NULL;
+ fence->fence_wake.func = amdgpu_fence_check_signaled;
+- __add_wait_queue(&adev->fence_queue, &fence->fence_wake);
++ __add_wait_queue(&ring->fence_drv.fence_queue, &fence->fence_wake);
+ fence_get(f);
+ FENCE_TRACE(&fence->base, "armed on ring %i!\n", ring->idx);
+ return true;
+@@ -463,152 +464,79 @@ bool amdgpu_fence_signaled(struct amdgpu_fence *fence)
+ return false;
+ }
+
+-/**
+- * amdgpu_fence_any_seq_signaled - check if any sequence number is signaled
+- *
+- * @adev: amdgpu device pointer
+- * @seq: sequence numbers
+- *
+- * Check if the last signaled fence sequnce number is >= the requested
+- * sequence number (all asics).
+- * Returns true if any has signaled (current value is >= requested value)
+- * or false if it has not. Helper function for amdgpu_fence_wait_seq.
+- */
+-static bool amdgpu_fence_any_seq_signaled(struct amdgpu_device *adev, u64 *seq)
+-{
+- unsigned i;
+-
+- for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+- if (!adev->rings[i] || !seq[i])
+- continue;
+-
+- if (amdgpu_fence_seq_signaled(adev->rings[i], seq[i]))
+- return true;
+- }
+-
+- return false;
+-}
+-
+-/**
+- * amdgpu_fence_wait_seq_timeout - wait for a specific sequence numbers
+- *
+- * @adev: amdgpu device pointer
+- * @target_seq: sequence number(s) we want to wait for
+- * @intr: use interruptable sleep
+- * @timeout: maximum time to wait, or MAX_SCHEDULE_TIMEOUT for infinite wait
++/*
++ * amdgpu_ring_wait_seq_timeout - wait for seq of the specific ring to signal
++ * @ring: ring to wait on for the seq number
++ * @seq: seq number wait for
++ * @intr: if interruptible
++ * @timeout: jiffies before time out
+ *
+- * Wait for the requested sequence number(s) to be written by any ring
+- * (all asics). Sequnce number array is indexed by ring id.
+- * @intr selects whether to use interruptable (true) or non-interruptable
+- * (false) sleep when waiting for the sequence number. Helper function
+- * for amdgpu_fence_wait_*().
+- * Returns remaining time if the sequence number has passed, 0 when
+- * the wait timeout, or an error for all other cases.
+- * -EDEADLK is returned when a GPU lockup has been detected.
++ * return value:
++ * 0: time out but seq not signaled, and gpu not hang
++ * X (X > 0): seq signaled and X means how many jiffies remains before time out
++ * -EDEADL: GPU hang before time out
++ * -ESYSRESTART: interrupted before seq signaled
++ * -EINVAL: some paramter is not valid
+ */
+-static long amdgpu_fence_wait_seq_timeout(struct amdgpu_device *adev,
+- u64 *target_seq, bool intr,
+- long timeout)
++static long amdgpu_fence_ring_wait_seq_timeout(struct amdgpu_ring *ring, uint64_t seq,
++ bool intr, long timeout)
+ {
+- uint64_t last_seq[AMDGPU_MAX_RINGS];
+- bool signaled;
+- int i;
+- long r;
+-
+- if (timeout == 0) {
+- return amdgpu_fence_any_seq_signaled(adev, target_seq);
+- }
+-
+- while (!amdgpu_fence_any_seq_signaled(adev, target_seq)) {
+-
+- /* Save current sequence values, used to check for GPU lockups */
+- for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+- struct amdgpu_ring *ring = adev->rings[i];
++ struct amdgpu_device *adev = ring->adev;
++ long r = 0;
++ bool signaled = false;
+
+- if (!ring || !target_seq[i])
+- continue;
++ BUG_ON(!ring);
++ if (seq > ring->fence_drv.sync_seq[ring->idx])
++ return -EINVAL;
+
+- last_seq[i] = atomic64_read(&ring->fence_drv.last_seq);
+- trace_amdgpu_fence_wait_begin(adev->ddev, i, target_seq[i]);
+- }
++ if (atomic64_read(&ring->fence_drv.last_seq) >= seq)
++ return timeout;
+
++ while (1) {
+ if (intr) {
+- r = wait_event_interruptible_timeout(adev->fence_queue, (
+- (signaled = amdgpu_fence_any_seq_signaled(adev, target_seq))
+- || adev->needs_reset), AMDGPU_FENCE_JIFFIES_TIMEOUT);
++ r = wait_event_interruptible_timeout(ring->fence_drv.fence_queue, (
++ (signaled = amdgpu_fence_seq_signaled(ring, seq))
++ || adev->needs_reset), AMDGPU_FENCE_JIFFIES_TIMEOUT);
++
++ if (r == -ERESTARTSYS) /* interrupted */
++ return r;
+ } else {
+- r = wait_event_timeout(adev->fence_queue, (
+- (signaled = amdgpu_fence_any_seq_signaled(adev, target_seq))
+- || adev->needs_reset), AMDGPU_FENCE_JIFFIES_TIMEOUT);
++ r = wait_event_timeout(ring->fence_drv.fence_queue, (
++ (signaled = amdgpu_fence_seq_signaled(ring, seq))
++ || adev->needs_reset), AMDGPU_FENCE_JIFFIES_TIMEOUT);
+ }
+
+- for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+- struct amdgpu_ring *ring = adev->rings[i];
+-
+- if (!ring || !target_seq[i])
+- continue;
+-
+- trace_amdgpu_fence_wait_end(adev->ddev, i, target_seq[i]);
++ if (signaled) {
++ /* seq signaled */
++ if (timeout == MAX_SCHEDULE_TIMEOUT)
++ return timeout;
++ return (timeout - AMDGPU_FENCE_JIFFIES_TIMEOUT - r);
++ }
++ else if (adev->needs_reset) {
++ return -EDEADLK;
+ }
+
+- if (unlikely(r < 0))
+- return r;
+-
+- if (unlikely(!signaled)) {
+-
+- if (adev->needs_reset)
+- return -EDEADLK;
+-
+- /* we were interrupted for some reason and fence
+- * isn't signaled yet, resume waiting */
+- if (r)
+- continue;
+-
+- for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+- struct amdgpu_ring *ring = adev->rings[i];
+-
+- if (!ring || !target_seq[i])
+- continue;
+-
+- if (last_seq[i] != atomic64_read(&ring->fence_drv.last_seq))
+- break;
+- }
+-
+- if (i != AMDGPU_MAX_RINGS)
+- continue;
+-
+- for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+- if (!adev->rings[i] || !target_seq[i])
+- continue;
+-
+- if (amdgpu_ring_is_lockup(adev->rings[i]))
+- break;
+- }
+-
+- if (i < AMDGPU_MAX_RINGS) {
+- /* good news we believe it's a lockup */
+- dev_warn(adev->dev, "GPU lockup (waiting for "
++ /* check if it's a lockup */
++ if (amdgpu_ring_is_lockup(ring)) {
++ uint64_t last_seq = atomic64_read(&ring->fence_drv.last_seq);
++ /* ring lookup */
++ dev_warn(adev->dev, "GPU lockup (waiting for "
+ "0x%016llx last fence id 0x%016llx on"
+ " ring %d)\n",
+- target_seq[i], last_seq[i], i);
+-
+- /* remember that we need an reset */
+- adev->needs_reset = true;
+- wake_up_all(&adev->fence_queue);
+- return -EDEADLK;
+- }
++ seq, last_seq, ring->idx);
++ wake_up_all(&ring->fence_drv.fence_queue);
++ return -EDEADLK;
++ }
+
+- if (timeout < MAX_SCHEDULE_TIMEOUT) {
+- timeout -= AMDGPU_FENCE_JIFFIES_TIMEOUT;
+- if (timeout <= 0) {
+- return 0;
+- }
+- }
++ if (timeout < MAX_SCHEDULE_TIMEOUT) {
++ timeout -= AMDGPU_FENCE_JIFFIES_TIMEOUT;
++ if (timeout < 1)
++ return 0;
+ }
+ }
+- return timeout;
+ }
+
++
+ /**
+ * amdgpu_fence_wait - wait for a fence to signal
+ *
+@@ -642,18 +570,15 @@ int amdgpu_fence_wait(struct amdgpu_fence *fence, bool intr)
+ */
+ int amdgpu_fence_wait_next(struct amdgpu_ring *ring)
+ {
+- uint64_t seq[AMDGPU_MAX_RINGS] = {};
+ long r;
+
+- seq[ring->idx] = atomic64_read(&ring->fence_drv.last_seq) + 1ULL;
+- if (seq[ring->idx] >= ring->fence_drv.sync_seq[ring->idx]) {
+- /* nothing to wait for, last_seq is
+- already the last emited fence */
++ uint64_t seq = atomic64_read(&ring->fence_drv.last_seq) + 1ULL;
++ if (seq >= ring->fence_drv.sync_seq[ring->idx])
+ return -ENOENT;
+- }
+- r = amdgpu_fence_wait_seq_timeout(ring->adev, seq, false, MAX_SCHEDULE_TIMEOUT);
++ r = amdgpu_fence_ring_wait_seq_timeout(ring, seq, false, MAX_SCHEDULE_TIMEOUT);
+ if (r < 0)
+ return r;
++
+ return 0;
+ }
+
+@@ -669,21 +594,20 @@ int amdgpu_fence_wait_next(struct amdgpu_ring *ring)
+ */
+ int amdgpu_fence_wait_empty(struct amdgpu_ring *ring)
+ {
+- struct amdgpu_device *adev = ring->adev;
+- uint64_t seq[AMDGPU_MAX_RINGS] = {};
+ long r;
+
+- seq[ring->idx] = ring->fence_drv.sync_seq[ring->idx];
+- if (!seq[ring->idx])
++ uint64_t seq = ring->fence_drv.sync_seq[ring->idx];
++ if (!seq)
+ return 0;
+
+- r = amdgpu_fence_wait_seq_timeout(adev, seq, false, MAX_SCHEDULE_TIMEOUT);
++ r = amdgpu_fence_ring_wait_seq_timeout(ring, seq, false, MAX_SCHEDULE_TIMEOUT);
++
+ if (r < 0) {
+ if (r == -EDEADLK)
+ return -EDEADLK;
+
+- dev_err(adev->dev, "error waiting for ring[%d] to become idle (%ld)\n",
+- ring->idx, r);
++ dev_err(ring->adev->dev, "error waiting for ring[%d] to become idle (%ld)\n",
++ ring->idx, r);
+ }
+ return 0;
+ }
+@@ -898,7 +822,6 @@ void amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring)
+ */
+ int amdgpu_fence_driver_init(struct amdgpu_device *adev)
+ {
+- init_waitqueue_head(&adev->fence_queue);
+ if (amdgpu_debugfs_fence_init(adev))
+ dev_err(adev->dev, "fence debugfs file creation failed\n");
+
+@@ -927,7 +850,7 @@ void amdgpu_fence_driver_fini(struct amdgpu_device *adev)
+ /* no need to trigger GPU reset as we are unloading */
+ amdgpu_fence_driver_force_completion(adev);
+ }
+- wake_up_all(&adev->fence_queue);
++ wake_up_all(&ring->fence_drv.fence_queue);
+ amdgpu_irq_put(adev, ring->fence_drv.irq_src,
+ ring->fence_drv.irq_type);
+ if (ring->scheduler)
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
+index 1e68a56..7d442c5 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
+@@ -342,6 +342,8 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
+ amdgpu_fence_driver_init_ring(ring);
+ }
+
++ init_waitqueue_head(&ring->fence_drv.fence_queue);
++
+ r = amdgpu_wb_get(adev, &ring->rptr_offs);
+ if (r) {
+ dev_err(adev->dev, "(%d) ring rptr_offs wb alloc failed\n", r);
+--
+1.9.1
+