From: Philip Yang <[email protected]>

Add mutex to serialize LSDMA PIO copy and fill operations for
concurrent access from multiple threads.

A mutex is used rather than a spinlock because the underlying
lsdma_v7_1_wait_pio_status() polls with udelay(), which can
busy-wait for up to usec_timeout microseconds.

It is optional to call mutex_destroy for clarity and debug
correctness, it is no-op for release build, leave it as lsdma
block no ip callback funcs to call mutex_destroy.

Signed-off-by: Philip Yang <[email protected]>
Reviewed-by: Felix Kuehling <[email protected]>
Signed-off-by: Alex Deucher <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c |  1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_lsdma.c  | 20 ++++++++++++++------
 drivers/gpu/drm/amd/amdgpu/amdgpu_lsdma.h  |  1 +
 3 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index b61c641b5be4f..1503bbf473c49 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -3849,6 +3849,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
        spin_lock_init(&adev->mm_stats.lock);
        spin_lock_init(&adev->virt.rlcg_reg_lock);
        spin_lock_init(&adev->wb.lock);
+       mutex_init(&adev->lsdma.lock);
 
        INIT_LIST_HEAD(&adev->reset_list);
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_lsdma.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_lsdma.c
index 4d1d4994ea3fe..05bc281216bfc 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_lsdma.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_lsdma.c
@@ -48,23 +48,27 @@ int amdgpu_lsdma_copy_mem(struct amdgpu_device *adev,
                          uint64_t dst_addr,
                          uint64_t mem_size)
 {
-       int ret;
+       int ret = 0;
 
        if (mem_size == 0)
                return -EINVAL;
 
+       mutex_lock(&adev->lsdma.lock);
+
        while (mem_size > 0) {
                uint64_t current_copy_size = min(mem_size, 
AMDGPU_LSDMA_MAX_SIZE);
 
                ret = adev->lsdma.funcs->copy_mem(adev, src_addr, dst_addr, 
current_copy_size);
                if (ret)
-                       return ret;
+                       goto out_unlock;
                src_addr += current_copy_size;
                dst_addr += current_copy_size;
                mem_size -= current_copy_size;
        }
 
-       return 0;
+out_unlock:
+       mutex_unlock(&adev->lsdma.lock);
+       return ret;
 }
 
 int amdgpu_lsdma_fill_mem(struct amdgpu_device *adev,
@@ -72,20 +76,24 @@ int amdgpu_lsdma_fill_mem(struct amdgpu_device *adev,
                          uint32_t data,
                          uint64_t mem_size)
 {
-       int ret;
+       int ret = 0;
 
        if (mem_size == 0)
                return -EINVAL;
 
+       mutex_lock(&adev->lsdma.lock);
+
        while (mem_size > 0) {
                uint64_t current_fill_size = min(mem_size, 
AMDGPU_LSDMA_MAX_SIZE);
 
                ret = adev->lsdma.funcs->fill_mem(adev, dst_addr, data, 
current_fill_size);
                if (ret)
-                       return ret;
+                       goto out_unlock;
                dst_addr += current_fill_size;
                mem_size -= current_fill_size;
        }
 
-       return 0;
+out_unlock:
+       mutex_unlock(&adev->lsdma.lock);
+       return ret;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_lsdma.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_lsdma.h
index c61ba58c5ee0d..e9a0237efd80b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_lsdma.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_lsdma.h
@@ -25,6 +25,7 @@
 #define __AMDGPU_LSDMA_H__
 
 struct amdgpu_lsdma {
+       struct mutex lock;
        const struct amdgpu_lsdma_funcs      *funcs;
 };
 
-- 
2.55.0

Reply via email to