Re: [PATCH v9 2/3] drm/xe/lrc: Fix torn read of CTX_TIMESTAMP from LRC
Umesh Nerlige Ramappa <[email protected]> Mon, 3 Aug 2026 14:25:47 -0700
| Newsgroups | org.freedesktop.lists.intel-xe |
|---|---|
| Message-ID | <[email protected]> |
On Fri, Jul 31, 2026 at 04:00:07AM +0000, Gajendra Uttamchand wrote: >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); The map can move out of the loop. You could define a new map_udw for the udw value. >+ 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(); cpu_relax() is not needed here and can be dropped. After looking into this a bit more, I think it is best to use the iosys_map helpers instead of the xe_map_read32. Also note that xe_map_* helpers may be removed in future. The only value add that xe_map helpers provide is the pm_runtime check. I have added it below. So this should look something like: static u64 xe_lrc_ctx_timestamp(struct xe_lrc *lrc) { struct xe_device *xe = lrc_to_xe(lrc); struct iosys_map map; int retries; u64 val; xe_assert(xe, !xe_pm_runtime_suspended(xe)); map = __xe_lrc_ctx_timestamp_map(lrc); if (!xe->info.has_64bit_timestamp) return iosys_map_rd(map, 0, u32); for (retries = 5; retries; --retries) { val = iosys_map_rd(map, 0, u64); if (iosys_map_rd(map, 0, u64) == val) break; } return val; } The barrier is also not required (or is handled by the iosys_map helpers internally when needed). Thanks, Umesh > } > > return (u64)udw << 32 | ldw; >-- >2.43.0 >