[PATCH] drm/amdkfd: zero SDMA mid-command save state before restoring user queues

Andrew Martin <[email protected]> Tue, 28 Jul 2026 14:16:08 -0400
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
From: Andrew Martin <[email protected]>

Applies to gfx10 (RDNA2) and gfx11 (RDNA3).

The SDMA firmware's saved mid-command state for a preempted COPY_LINEAR
(sdmax_rlcx_midcmd_data0 = source byte offset) has been observed to
overshoot the packet's byte count on gfx10.3 (Navi21, XNACK off) after
rapid quiesce/resume cycles driven by userptr/SVM eviction. On
MAP_QUEUES the engine resumes the copy at src+offset past the buffer:
an unmapped VA turns into a UTCL2 'Page not present' fault, a mapped
one into silent data corruption.

The silent corruption variant produces no dmesg output and is only
detectable through application-level data integrity checks (checksums,
validation). This makes diagnosis extremely difficult as there is no
kernel-level indication of the failure.

Zero the mid-command save area before remapping so the pending packet
re-executes from its packet boundary (idempotent for COPY/GCR/FENCE).
Workaround for field crashes of ROCm workloads on RDNA2/RDNA3.

Signed-off-by: Andrew Martin <[email protected]>
Assisted-by: Claude:Sonnet 4-5
---
 .../drm/amd/amdkfd/kfd_device_queue_manager.c | 37 ++++++++++++++++++-
 1 file changed, 36 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
index 51ee9c39104b..1507d371f741 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
@@ -40,6 +40,8 @@
 #include "amdgpu_ring.h"
 #include "amdgpu_mes.h"
 #include "kfd_debug.h"
+#include "v10_structs.h"
+#include "v11_structs.h"
 
 /* Size of the per-pipe EOP queue */
 #define CIK_HPD_EOP_BYTES_LOG2 11
@@ -1447,6 +1449,37 @@ static int restore_process_queues_nocpsch(struct device_queue_manager *dqm,
 	return ret;
 }
 
+/*
+ * Zero SDMA mid-command state before MAP_QUEUES. Firmware bug: preempted
+ * COPY_LINEAR can resume at corrupted offset past buffer (silent corruption
+ * or VM fault). Re-executing from packet start is idempotent and safe.
+ */
+static void clamp_sdma_midcmd_state(struct device_queue_manager *dqm,
+				    struct qcm_process_device *qpd)
+{
+	struct queue *q;
+	uint32_t gc_ver = KFD_GC_VERSION(dqm->dev);
+
+	if (gc_ver < IP_VERSION(10, 1, 1) || gc_ver >= IP_VERSION(12, 0, 0))
+		return;
+
+	list_for_each_entry(q, &qpd->queues_list, list) {
+		if ((q->properties.type != KFD_QUEUE_TYPE_SDMA &&
+		     q->properties.type != KFD_QUEUE_TYPE_SDMA_XGMI) || !q->mqd)
+			continue;
+
+		if (gc_ver < IP_VERSION(11, 0, 0)) {
+			struct v10_sdma_mqd *m = q->mqd;
+
+			memset(&m->sdmax_rlcx_midcmd_data0, 0, 10 * sizeof(uint32_t));
+		} else {
+			struct v11_sdma_mqd *m = q->mqd;
+
+			memset(&m->sdmax_rlcx_midcmd_data0, 0, 12 * sizeof(uint32_t));
+		}
+	}
+}
+
 static int restore_process_queues_cpsch(struct device_queue_manager *dqm,
 					struct qcm_process_device *qpd)
 {
@@ -1498,9 +1531,11 @@ static int restore_process_queues_cpsch(struct device_queue_manager *dqm,
 			}
 		}
 	}
-	if (!dqm->dev->kfd->shared_resources.enable_mes)
+	if (!dqm->dev->kfd->shared_resources.enable_mes) {
+		clamp_sdma_midcmd_state(dqm, qpd);
 		retval = execute_queues_cpsch(dqm,
 					      KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0, USE_DEFAULT_GRACE_PERIOD);
+	}
 	eviction_duration = get_jiffies_64() - pdd->last_evict_timestamp;
 	atomic64_add(eviction_duration, &pdd->evict_duration_counter);
 vm_not_acquired:
-- 
2.43.0