aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/2028-drm-amdgpu-busywait-KIQ-register-accessing-v4.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/2028-drm-amdgpu-busywait-KIQ-register-accessing-v4.patch')
-rw-r--r--meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/2028-drm-amdgpu-busywait-KIQ-register-accessing-v4.patch254
1 files changed, 254 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/2028-drm-amdgpu-busywait-KIQ-register-accessing-v4.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/2028-drm-amdgpu-busywait-KIQ-register-accessing-v4.patch
new file mode 100644
index 00000000..a6ac1e03
--- /dev/null
+++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/2028-drm-amdgpu-busywait-KIQ-register-accessing-v4.patch
@@ -0,0 +1,254 @@
+From 437b7a31501b7a096e3cd9ea19d830895b2766a4 Mon Sep 17 00:00:00 2001
+From: pding <Pixel.Ding@amd.com>
+Date: Fri, 13 Oct 2017 15:38:35 +0800
+Subject: [PATCH 2028/4131] drm/amdgpu: busywait KIQ register accessing (v4)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Register accessing is performed when IRQ is disabled. Never sleep in
+this function.
+
+Known issue: dead sleep in many use cases of index/data registers.
+
+v2:
+ - wrap polling fence functions.
+ - don't trigger IRQ for polling in case of wrongly fence signal.
+
+v3:
+ - handle wrap round gracefully.
+ - add comments for polling function
+
+v4:
+ - don't return negative timeout confused with error code
+
+Signed-off-by: pding <Pixel.Ding@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_device.c | 8 ++---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 50 ++++++++++++++++++++++++++++++
+ drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c | 2 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h | 4 +++
+ drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 30 ++++++++----------
+ 6 files changed, 71 insertions(+), 25 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+index b13c94f..65860f7 100755
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+@@ -905,7 +905,7 @@ struct amdgpu_mec {
+ struct amdgpu_kiq {
+ u64 eop_gpu_addr;
+ struct amdgpu_bo *eop_obj;
+- struct mutex ring_mutex;
++ spinlock_t ring_lock;
+ struct amdgpu_ring ring;
+ struct amdgpu_irq_src irq;
+ };
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+index 74a63c2..05f4be0 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+@@ -110,10 +110,8 @@ uint32_t amdgpu_mm_rreg(struct amdgpu_device *adev, uint32_t reg,
+ {
+ uint32_t ret;
+
+- if (!(acc_flags & AMDGPU_REGS_NO_KIQ) && amdgpu_sriov_runtime(adev)) {
+- BUG_ON(in_interrupt());
++ if (!(acc_flags & AMDGPU_REGS_NO_KIQ) && amdgpu_sriov_runtime(adev))
+ return amdgpu_virt_kiq_rreg(adev, reg);
+- }
+
+ if ((reg * 4) < adev->rmmio_size && !(acc_flags & AMDGPU_REGS_IDX))
+ ret = readl(((void __iomem *)adev->rmmio) + (reg * 4));
+@@ -138,10 +136,8 @@ void amdgpu_mm_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v,
+ adev->last_mm_index = v;
+ }
+
+- if (!(acc_flags & AMDGPU_REGS_NO_KIQ) && amdgpu_sriov_runtime(adev)) {
+- BUG_ON(in_interrupt());
++ if (!(acc_flags & AMDGPU_REGS_NO_KIQ) && amdgpu_sriov_runtime(adev))
+ return amdgpu_virt_kiq_wreg(adev, reg, v);
+- }
+
+ if ((reg * 4) < adev->rmmio_size && !(acc_flags & AMDGPU_REGS_IDX))
+ writel(v, ((void __iomem *)adev->rmmio) + (reg * 4));
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
+index 7bdedd7..fb9f88ef 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
+@@ -169,6 +169,32 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f)
+ }
+
+ /**
++ * amdgpu_fence_emit_polling - emit a fence on the requeste ring
++ *
++ * @ring: ring the fence is associated with
++ * @s: resulting sequence number
++ *
++ * Emits a fence command on the requested ring (all asics).
++ * Used For polling fence.
++ * Returns 0 on success, -ENOMEM on failure.
++ */
++int amdgpu_fence_emit_polling(struct amdgpu_ring *ring, uint32_t *s)
++{
++ uint32_t seq;
++
++ if (!s)
++ return -EINVAL;
++
++ seq = ++ring->fence_drv.sync_seq;
++ amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr,
++ seq, AMDGPU_FENCE_FLAG_INT);
++
++ *s = seq;
++
++ return 0;
++}
++
++/**
+ * amdgpu_fence_schedule_fallback - schedule fallback check
+ *
+ * @ring: pointer to struct amdgpu_ring
+@@ -282,6 +308,30 @@ int amdgpu_fence_wait_empty(struct amdgpu_ring *ring)
+ }
+
+ /**
++ * amdgpu_fence_wait_polling - busy wait for givn sequence number
++ *
++ * @ring: ring index the fence is associated with
++ * @wait_seq: sequence number to wait
++ * @timeout: the timeout for waiting in usecs
++ *
++ * Wait for all fences on the requested ring to signal (all asics).
++ * Returns left time if no timeout, 0 or minus if timeout.
++ */
++signed long amdgpu_fence_wait_polling(struct amdgpu_ring *ring,
++ uint32_t wait_seq,
++ signed long timeout)
++{
++ uint32_t seq;
++
++ do {
++ seq = amdgpu_fence_read(ring);
++ udelay(5);
++ timeout -= 5;
++ } while ((int32_t)(wait_seq - seq) > 0 && timeout > 0);
++
++ return timeout > 0 ? timeout : 0;
++}
++/**
+ * amdgpu_fence_count_emitted - get the count of emitted fences
+ *
+ * @ring: ring the fence is associated with
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
+index 9391db0..95f46b8 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
+@@ -201,7 +201,7 @@ int amdgpu_gfx_kiq_init_ring(struct amdgpu_device *adev,
+ struct amdgpu_kiq *kiq = &adev->gfx.kiq;
+ int r = 0;
+
+- mutex_init(&kiq->ring_mutex);
++ spin_lock_init(&kiq->ring_lock);
+
+ r = amdgpu_wb_get(adev, &adev->virt.reg_val_offs);
+ if (r)
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
+index 494ff48..9fef7c7 100755
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
+@@ -91,8 +91,12 @@ int amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring,
+ void amdgpu_fence_driver_suspend(struct amdgpu_device *adev);
+ void amdgpu_fence_driver_resume(struct amdgpu_device *adev);
+ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **fence);
++int amdgpu_fence_emit_polling(struct amdgpu_ring *ring, uint32_t *s);
+ void amdgpu_fence_process(struct amdgpu_ring *ring);
+ int amdgpu_fence_wait_empty(struct amdgpu_ring *ring);
++signed long amdgpu_fence_wait_polling(struct amdgpu_ring *ring,
++ uint32_t wait_seq,
++ signed long timeout);
+ unsigned amdgpu_fence_count_emitted(struct amdgpu_ring *ring);
+
+ /*
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
+index ed7be2e..e97f80f 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
+@@ -22,7 +22,7 @@
+ */
+
+ #include "amdgpu.h"
+-#define MAX_KIQ_REG_WAIT 100000
++#define MAX_KIQ_REG_WAIT 100000000 /* in usecs */
+
+ int amdgpu_allocate_static_csa(struct amdgpu_device *adev)
+ {
+@@ -114,27 +114,24 @@ void amdgpu_virt_init_setting(struct amdgpu_device *adev)
+ uint32_t amdgpu_virt_kiq_rreg(struct amdgpu_device *adev, uint32_t reg)
+ {
+ signed long r;
+- uint32_t val;
+- struct dma_fence *f;
++ uint32_t val, seq;
+ struct amdgpu_kiq *kiq = &adev->gfx.kiq;
+ struct amdgpu_ring *ring = &kiq->ring;
+
+ BUG_ON(!ring->funcs->emit_rreg);
+
+- mutex_lock(&kiq->ring_mutex);
++ spin_lock(&kiq->ring_lock);
+ amdgpu_ring_alloc(ring, 32);
+ amdgpu_ring_emit_rreg(ring, reg);
+- amdgpu_fence_emit(ring, &f);
++ amdgpu_fence_emit_polling(ring, &seq);
+ amdgpu_ring_commit(ring);
+- mutex_unlock(&kiq->ring_mutex);
++ spin_unlock(&kiq->ring_lock);
+
+- r = dma_fence_wait_timeout(f, false, msecs_to_jiffies(MAX_KIQ_REG_WAIT));
+- dma_fence_put(f);
++ r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT);
+ if (r < 1) {
+- DRM_ERROR("wait for kiq fence error: %ld.\n", r);
++ DRM_ERROR("wait for kiq fence error: %ld\n", r);
+ return ~0;
+ }
+-
+ val = adev->wb.wb[adev->virt.reg_val_offs];
+
+ return val;
+@@ -143,23 +140,22 @@ uint32_t amdgpu_virt_kiq_rreg(struct amdgpu_device *adev, uint32_t reg)
+ void amdgpu_virt_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v)
+ {
+ signed long r;
+- struct dma_fence *f;
++ uint32_t seq;
+ struct amdgpu_kiq *kiq = &adev->gfx.kiq;
+ struct amdgpu_ring *ring = &kiq->ring;
+
+ BUG_ON(!ring->funcs->emit_wreg);
+
+- mutex_lock(&kiq->ring_mutex);
++ spin_lock(&kiq->ring_lock);
+ amdgpu_ring_alloc(ring, 32);
+ amdgpu_ring_emit_wreg(ring, reg, v);
+- amdgpu_fence_emit(ring, &f);
++ amdgpu_fence_emit_polling(ring, &seq);
+ amdgpu_ring_commit(ring);
+- mutex_unlock(&kiq->ring_mutex);
++ spin_unlock(&kiq->ring_lock);
+
+- r = dma_fence_wait_timeout(f, false, msecs_to_jiffies(MAX_KIQ_REG_WAIT));
++ r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT);
+ if (r < 1)
+- DRM_ERROR("wait for kiq fence error: %ld.\n", r);
+- dma_fence_put(f);
++ DRM_ERROR("wait for kiq fence error: %ld\n", r);
+ }
+
+ /**
+--
+2.7.4
+