[PATCH v9 2/3] drm/xe/lrc: Fix torn read of CTX_TIMESTAMP from LRC

Gajendra Uttamchand <[email protected]> Fri, 31 Jul 2026 04:00:07 +0000
Newsgroups org.freedesktop.lists.intel-xe
Message-ID <[email protected]>
xe_lrc_ctx_timestamp() reads the 64-bit CTX_TIMESTAMP value stored in
the LRC as two independent 32-bit reads (ldw, then udw). The GPU can
concurrently overwrite this location as part of a context-save, so a
plain back-to-back read of the two dwords can observe a torn
combination that matches neither the previous value (e.g. the
CONTEXT_ACTIVE sentinel written on context-restore) nor the final
saved timestamp written by hardware. Callers such as context_active()
and xe_lrc_context_timestamp() rely on this value being coherent to
decide whether the context is still active, so a torn read can lead to
an incorrect/garbage timestamp being sampled or reported.

Make xe_lrc_ctx_timestamp() robust against torn reads by reading the
upper 32-bit half first and re-reading the lower/upper pair until the
upper half stabilizes across two consecutive reads (bounded to a small
retry limit), then combine them into the final 64-bit value.

This fixes the problem at the source so all callers get a coherent
timestamp, instead of patching individual callers.

Assisted-by: GitHub-Copilot:claude-sonnet-5
Signed-off-by: Gajendra Uttamchand <[email protected]>
---
 drivers/gpu/drm/xe/xe_lrc.c | 27 +++++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c
index 78d0456cf3c9..6f0247bdf8e4 100644
--- a/drivers/gpu/drm/xe/xe_lrc.c
+++ b/drivers/gpu/drm/xe/xe_lrc.c
@@ -874,14 +874,33 @@ static u64 xe_lrc_ctx_timestamp(struct xe_lrc *lrc)
 {
 	struct xe_device *xe = lrc_to_xe(lrc);
 	struct iosys_map map;
-	u32 ldw, udw = 0;
+	u32 ldw, udw = 0, old_ldw, old_udw;
+	int retries;

-	map = __xe_lrc_ctx_timestamp_map(lrc);
-	ldw = xe_map_read32(xe, &map);
+	if (!xe->info.has_64bit_timestamp) {
+		map = __xe_lrc_ctx_timestamp_map(lrc);
+		return xe_map_read32(xe, &map);
+	}
+
+	for (retries = 5; retries; --retries) {
+		map = __xe_lrc_ctx_timestamp_udw_map(lrc);
+		old_udw = xe_map_read32(xe, &map);
+
+		map = __xe_lrc_ctx_timestamp_map(lrc);
+		old_ldw = xe_map_read32(xe, &map);
+
+		smp_rmb();

-	if (xe->info.has_64bit_timestamp) {
 		map = __xe_lrc_ctx_timestamp_udw_map(lrc);
 		udw = xe_map_read32(xe, &map);
+
+		map = __xe_lrc_ctx_timestamp_map(lrc);
+		ldw = xe_map_read32(xe, &map);
+
+		if (udw == old_udw && ldw == old_ldw)
+			return (u64)udw << 32 | ldw;
+
+		cpu_relax();
 	}

 	return (u64)udw << 32 | ldw;
--
2.43.0