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