reserve space to avoid page fault and data loss.`

Signed-off-by: James Zhu <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_spm.c | 41 +++++++++++++++++++++++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_spm.h |  2 ++
 2 files changed, 43 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_spm.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_spm.c
index 7acbd966cd3e..f09c237cc8f7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_spm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_spm.c
@@ -60,9 +60,24 @@ struct amdgpu_spm_cntr {
        bool  are_users_buf_filled;
 };
 
+/* used to detect SPM overflow */
+#define SPM_OVERFLOW_MAGIC        0xBEEFABCDDEADABCD
+
 static int amdgpu_spm_release(struct amdgpu_spm_mgr *spm_mgr, struct drm_file 
*filp);
 static void _amdgpu_spm_release(struct amdgpu_spm_mgr *spm_mgr, int inst, 
struct drm_file *filp);
 
+static void amdgpu_spm_preset(struct amdgpu_spm_base *spm, u32 size)
+{
+       uint64_t *overflow_ptr, *overflow_end_ptr;
+
+       overflow_ptr = (uint64_t *)((uint64_t)spm->cpu_addr
+                               + spm->ring_size + 0x20);
+       overflow_end_ptr = overflow_ptr + (size >> 3);
+       /* SPM data filling is 0x20 alignment */
+       for ( ;  overflow_ptr < overflow_end_ptr; overflow_ptr += 4)
+               *overflow_ptr = SPM_OVERFLOW_MAGIC;
+}
+
 static int amdgpu_spm_data_copy(struct amdgpu_spm_mgr *spm_mgr, u32 
size_to_copy, int inst)
 {
        struct amdgpu_spm_base *spm = &(spm_mgr->spm_cntr->spm[inst]);
@@ -141,6 +156,22 @@ static int amdgpu_spm_read_ring_buffer(struct 
amdgpu_spm_mgr *spm_mgr, int inst)
                size_to_copy = ring_wptr - spm->ring_rptr;
                ret = amdgpu_spm_data_copy(spm_mgr, size_to_copy, inst);
        } else {
+               uint64_t *ring_start, *ring_end;
+
+               ring_start = (uint64_t *)((uint64_t)spm->cpu_addr + 0x20);
+               ring_end = ring_start + (spm->ring_size >> 3);
+               for ( ; overflow_size < spm_mgr->spm_overflow_reserved; 
overflow_size += 0x20) {
+                       uint64_t *overflow_ptr = ring_end + (overflow_size >> 
3);
+
+                       if (*overflow_ptr == SPM_OVERFLOW_MAGIC)
+                               break;
+               }
+               if (overflow_size)
+                       dev_dbg(adev->dev,
+                               "SPM ring buffer overflow size 0x%x", 
overflow_size);
+               /* move overflow counters into ring buffer to avoid data loss */
+               memcpy(ring_start, ring_end, overflow_size);
+
                size_to_copy = spm->ring_size - spm->ring_rptr;
                ret = amdgpu_spm_data_copy(spm_mgr, size_to_copy, inst);
 
@@ -159,6 +190,7 @@ static int amdgpu_spm_read_ring_buffer(struct 
amdgpu_spm_mgr *spm_mgr, int inst)
        }
 
 exit:
+       amdgpu_spm_preset(spm, overflow_size);
        amdgpu_rlc_spm_set_rdptr(adev, inst, spm->ring_rptr);
        return ret;
 }
@@ -198,6 +230,12 @@ static void amdgpu_spm_work(struct work_struct *work)
 
 static void amdgpu_spm_init_device(struct amdgpu_spm_mgr *spm_mgr)
 {
+       struct amdgpu_device *adev = mgr_to_adev(spm_mgr, spm_mgr);
+
+       /* pre-gfx11 spm has a hardware bug to cause overflow */
+       if (adev->ip_versions[GC_HWIP][0] < IP_VERSION(11, 0, 1))
+               spm_mgr->spm_overflow_reserved = 0x400;
+
        spm_mgr->spm_cntr = NULL;
 }
 
@@ -224,6 +262,8 @@ static int _amdgpu_spm_acquire(struct amdgpu_spm_mgr 
*spm_mgr, int inst, struct
        if (ret)
                goto out;
 
+       /* reserve space to fix spm overflow */
+       spm->ring_size -= spm_mgr->spm_overflow_reserved;
        ret = amdgpu_rlc_spm_acquire(adev, inst, drm_priv_to_vm(filp),
                        spm->gpu_addr, spm->ring_size);
 
@@ -236,6 +276,7 @@ static int _amdgpu_spm_acquire(struct amdgpu_spm_mgr 
*spm_mgr, int inst, struct
        if (ret)
                goto rlc_spm_acquire_failure;
 
+       amdgpu_spm_preset(spm, spm_mgr->spm_overflow_reserved);
        goto out;
 
 rlc_spm_acquire_failure:
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_spm.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_spm.h
index 075ad7eaad01..f3d812fa4e2b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_spm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_spm.h
@@ -32,6 +32,8 @@ struct amdgpu_spm_mgr {
        struct amdgpu_spm_cntr *spm_cntr;
        struct work_struct spm_work;
        spinlock_t spm_irq_lock;
+       /* reserve space to fix spm overflow */
+       u32    spm_overflow_reserved;
 };
 
 int amdgpu_spm_ioctl(struct drm_device *dev, void __user *data,
-- 
2.34.1

Reply via email to