From: Tangudu Tilak Tirumalesh <[email protected]>
xe_ggtt_clear() wrote a scratch PTE across the range for both
initial_clear() and the node_remove() unmap path.
On unmap the scratch PTE hides stale-TLB gaps: after the range is
invalidated a re-walk lands on the still-valid scratch PTE, so a stale
engine TLB translation for the freed range never faults and the
invalidation gap stays invisible.
Add an explicit use_scratch bool. initial_clear() keeps writing scratch.
On multi-queue platforms, where engines cache GGTT independently,
node_remove() writes PTE=0 so a stale translation to a freed range
faults and the gap becomes observable; other platforms keep scratch.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Tangudu Tilak Tirumalesh <[email protected]>
---
drivers/gpu/drm/xe/xe_ggtt.c | 38 ++++++++++++++++++++++++------------
1 file changed, 25 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_ggtt.c b/drivers/gpu/drm/xe/xe_ggtt.c
index 8ec23862477f..3564345fd740 100644
--- a/drivers/gpu/drm/xe/xe_ggtt.c
+++ b/drivers/gpu/drm/xe/xe_ggtt.c
@@ -257,23 +257,31 @@ static u64 xe_ggtt_get_pte(struct xe_ggtt *ggtt, u64 addr)
return readq(&ggtt->gsm[addr >> XE_PTE_SHIFT]);
}
-static void xe_ggtt_clear(struct xe_ggtt *ggtt, u64 start, u64 size)
+/*
+ * @use_scratch: true fills the range with the scratch PTE (init-time clear so
+ * engines walking free holes read zeros safely); false writes PTE=0 so a
+ * stale HW TLB entry faults instead of silently landing on scratch.
+ */
+static void xe_ggtt_clear(struct xe_ggtt *ggtt, u64 start, u64 size,
+ bool use_scratch)
{
- u16 pat_index = xe_cache_pat_idx(tile_to_xe(ggtt->tile), XE_CACHE_WB);
u64 end = start + size - 1;
- u64 scratch_pte;
+ u64 pte;
xe_tile_assert(ggtt->tile, start < end);
- if (ggtt->scratch)
- scratch_pte = xe_bo_addr(ggtt->scratch, 0, XE_PAGE_SIZE) |
- ggtt->pt_ops->pte_encode_flags(ggtt->scratch,
- pat_index);
- else
- scratch_pte = 0;
+ if (use_scratch && ggtt->scratch) {
+ u16 pat_index = xe_cache_pat_idx(tile_to_xe(ggtt->tile),
+ XE_CACHE_WB);
+
+ pte = xe_bo_addr(ggtt->scratch, 0, XE_PAGE_SIZE) |
+ ggtt->pt_ops->pte_encode_flags(ggtt->scratch, pat_index);
+ } else {
+ pte = 0;
+ }
while (start < end) {
- ggtt->pt_ops->ggtt_set_pte(ggtt, start, scratch_pte);
+ ggtt->pt_ops->ggtt_set_pte(ggtt, start, pte);
start += XE_PAGE_SIZE;
}
}
@@ -459,7 +467,7 @@ static void xe_ggtt_initial_clear(struct xe_ggtt *ggtt)
/* Display may have allocated inside ggtt, so be careful with clearing here */
mutex_lock(&ggtt->lock);
drm_mm_for_each_hole(hole, &ggtt->mm, start, end)
- xe_ggtt_clear(ggtt, ggtt->start + start, end - start);
+ xe_ggtt_clear(ggtt, ggtt->start + start, end - start, true);
xe_ggtt_invalidate(ggtt);
mutex_unlock(&ggtt->lock);
@@ -473,12 +481,16 @@ static void ggtt_node_fini(struct xe_ggtt_node *node)
static void ggtt_node_remove(struct xe_ggtt_node *node)
{
struct xe_ggtt *ggtt = node->ggtt;
- bool bound;
+ struct xe_gt *primary_gt = ggtt->tile->primary_gt;
+ bool use_scratch, bound;
+
+ use_scratch = !(primary_gt && primary_gt->info.multi_queue_engine_class_mask);
mutex_lock(&ggtt->lock);
bound = ggtt->flags & XE_GGTT_FLAGS_ONLINE;
if (bound)
- xe_ggtt_clear(ggtt, xe_ggtt_node_addr(node), xe_ggtt_node_size(node));
+ xe_ggtt_clear(ggtt, xe_ggtt_node_addr(node),
+ xe_ggtt_node_size(node), use_scratch);
drm_mm_remove_node(&node->base);
node->base.size = 0;
if (bound && node->invalidate_on_remove)
--
2.46.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.