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:41:10 -0700
| Newsgroups | org.freedesktop.lists.intel-xe |
|---|---|
| Message-ID | <[email protected]> |
On Mon, Aug 03, 2026 at 02:25:47PM -0700, Umesh Nerlige Ramappa wrote: >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; > } &map when passing to iosys_map_rd > > 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 >>