* [PATCH v5 01/12] drm/xe: Fine grained page fault locking
2026-07-23 21:47 [PATCH v5 00/12] Fine grained fault locking, threaded prefetch, storm cache Matthew Brost
@ 2026-07-23 21:47 ` Matthew Brost
2026-07-23 21:47 ` [PATCH v5 02/12] drm/xe: Allow prefetch-only VM bind IOCTLs to use VM read lock Matthew Brost
` (13 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Matthew Brost @ 2026-07-23 21:47 UTC (permalink / raw)
To: intel-xe; +Cc: Gwan-gyeong Mun
Enable page faults to be serviced while holding vm->lock in read mode.
Introduce additional locks to:
- Ensure only one page fault thread services a given range or VMA
- Serialize SVM garbage collection
- Protect SVM range insertion and removal
While these locks may contend during page faults, expensive operations
like migration can now run in parallel within a single VM.
In addition to new locking, ranges must be reference-counted after
lookup, as another thread could immediately remove them from the GPU SVM
tree, potentially dropping the last reference.
Lastly, decouple the VM’s ASID from the page fault queue selection to
allow parallel page fault handling within the same VM.
Lays the groundwork for prefetch IOCTLs to use threaded migration too.
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
---
drivers/gpu/drm/xe/xe_device_types.h | 2 +
drivers/gpu/drm/xe/xe_pagefault.c | 102 +++++++++++++++------------
drivers/gpu/drm/xe/xe_svm.c | 98 +++++++++++++++++--------
drivers/gpu/drm/xe/xe_svm.h | 44 ++++++++++++
drivers/gpu/drm/xe/xe_userptr.c | 20 +++++-
drivers/gpu/drm/xe/xe_vm.c | 67 ++++++++++--------
drivers/gpu/drm/xe/xe_vm_types.h | 29 ++++++--
7 files changed, 251 insertions(+), 111 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
index 860ad322237f..b8d1726c0513 100644
--- a/drivers/gpu/drm/xe/xe_device_types.h
+++ b/drivers/gpu/drm/xe/xe_device_types.h
@@ -303,6 +303,8 @@ struct xe_device {
struct xarray asid_to_vm;
/** @usm.next_asid: next ASID, used to cyclical alloc asids */
u32 next_asid;
+ /** @usm.current_pf_queue: current page fault queue */
+ u32 current_pf_queue;
/** @usm.lock: protects UM state */
struct rw_semaphore lock;
/** @usm.pf_wq: page fault work queue, unbound, high priority */
diff --git a/drivers/gpu/drm/xe/xe_pagefault.c b/drivers/gpu/drm/xe/xe_pagefault.c
index dd3c068e1a39..80196e874e06 100644
--- a/drivers/gpu/drm/xe/xe_pagefault.c
+++ b/drivers/gpu/drm/xe/xe_pagefault.c
@@ -84,9 +84,9 @@ static int xe_pagefault_handle_vma(struct xe_gt *gt, struct xe_vma *vma,
struct xe_validation_ctx ctx;
struct drm_exec exec;
struct dma_fence *fence;
- int err, needs_vram;
+ int err = 0, needs_vram;
- lockdep_assert_held_write(&vm->lock);
+ lockdep_assert_held(&vm->lock);
needs_vram = xe_vma_need_vram_for_atomic(vm->xe, vma, atomic);
if (needs_vram < 0 || (needs_vram && xe_vma_is_userptr(vma)))
@@ -98,50 +98,52 @@ static int xe_pagefault_handle_vma(struct xe_gt *gt, struct xe_vma *vma,
trace_xe_vma_pagefault(vma);
+ guard(mutex)(&vma->fault_lock);
+
/* Check if VMA is valid, opportunistic check only */
if (xe_vm_has_valid_gpu_mapping(tile, vma->tile_present,
vma->tile_invalidated) && !atomic)
return 0;
-retry_userptr:
- if (xe_vma_is_userptr(vma) &&
- xe_vma_userptr_check_repin(to_userptr_vma(vma))) {
- struct xe_userptr_vma *uvma = to_userptr_vma(vma);
+ do {
+ if (xe_vma_is_userptr(vma) &&
+ xe_vma_userptr_check_repin(to_userptr_vma(vma))) {
+ struct xe_userptr_vma *uvma = to_userptr_vma(vma);
- err = xe_vma_userptr_pin_pages(uvma);
- if (err)
- return err;
- }
+ err = xe_vma_userptr_pin_pages(uvma);
+ if (err)
+ return err;
+ }
- /* Lock VM and BOs dma-resv */
- xe_validation_ctx_init(&ctx, &vm->xe->val, &exec, (struct xe_val_flags) {});
- drm_exec_until_all_locked(&exec) {
- err = xe_pagefault_begin(&exec, vma, tile->mem.vram,
- needs_vram == 1);
- drm_exec_retry_on_contention(&exec);
- xe_validation_retry_on_oom(&ctx, &err);
- if (err)
- goto unlock_dma_resv;
-
- /* Bind VMA only to the GT that has faulted */
- trace_xe_vma_pf_bind(vma);
- xe_vm_set_validation_exec(vm, &exec);
- fence = xe_vma_rebind(vm, vma, BIT(tile->id));
- xe_vm_set_validation_exec(vm, NULL);
- if (IS_ERR(fence)) {
- err = PTR_ERR(fence);
+ /* Lock VM and BOs dma-resv */
+ xe_validation_ctx_init(&ctx, &vm->xe->val, &exec,
+ (struct xe_val_flags) {});
+ drm_exec_until_all_locked(&exec) {
+ err = xe_pagefault_begin(&exec, vma, tile->mem.vram,
+ needs_vram == 1);
+ drm_exec_retry_on_contention(&exec);
xe_validation_retry_on_oom(&ctx, &err);
- goto unlock_dma_resv;
+ if (err)
+ break;
+
+ /* Bind VMA only to the GT that has faulted */
+ trace_xe_vma_pf_bind(vma);
+ xe_vm_set_validation_exec(vm, &exec);
+ fence = xe_vma_rebind(vm, vma, BIT(tile->id));
+ xe_vm_set_validation_exec(vm, NULL);
+ if (IS_ERR(fence)) {
+ err = PTR_ERR(fence);
+ xe_validation_retry_on_oom(&ctx, &err);
+ break;
+ }
}
- }
+ xe_validation_ctx_fini(&ctx);
+ } while (err == -EAGAIN);
- dma_fence_wait(fence, false);
- dma_fence_put(fence);
-
-unlock_dma_resv:
- xe_validation_ctx_fini(&ctx);
- if (err == -EAGAIN)
- goto retry_userptr;
+ if (!err) {
+ dma_fence_wait(fence, false);
+ dma_fence_put(fence);
+ }
return err;
}
@@ -184,10 +186,7 @@ static int xe_pagefault_service(struct xe_pagefault *pf)
if (IS_ERR(vm))
return PTR_ERR(vm);
- /*
- * TODO: Change to read lock? Using write lock for simplicity.
- */
- down_write(&vm->lock);
+ down_read(&vm->lock);
if (xe_vm_is_closed(vm)) {
err = -ENOENT;
@@ -215,9 +214,7 @@ static int xe_pagefault_service(struct xe_pagefault *pf)
err = xe_pagefault_handle_vma(gt, vma, atomic);
unlock_vm:
- if (!err)
- vm->usm.last_fault_vma = vma;
- up_write(&vm->lock);
+ up_read(&vm->lock);
xe_vm_put(vm);
return err;
@@ -462,6 +459,19 @@ static bool xe_pagefault_queue_full(struct xe_pagefault_queue *pf_queue)
xe_pagefault_entry_size();
}
+/*
+ * This function can race with multiple page fault producers, but worst case we
+ * stick a page fault on the same queue for consumption.
+ */
+static int xe_pagefault_queue_index(struct xe_device *xe)
+{
+ u32 old_pf_queue = READ_ONCE(xe->usm.current_pf_queue);
+
+ WRITE_ONCE(xe->usm.current_pf_queue, (old_pf_queue + 1));
+
+ return old_pf_queue % XE_PAGEFAULT_QUEUE_COUNT;
+}
+
/**
* xe_pagefault_handler() - Page fault handler
* @xe: xe device instance
@@ -474,8 +484,8 @@ static bool xe_pagefault_queue_full(struct xe_pagefault_queue *pf_queue)
*/
int xe_pagefault_handler(struct xe_device *xe, struct xe_pagefault *pf)
{
- struct xe_pagefault_queue *pf_queue = xe->usm.pf_queue +
- (pf->consumer.asid % XE_PAGEFAULT_QUEUE_COUNT);
+ int queue_index = xe_pagefault_queue_index(xe);
+ struct xe_pagefault_queue *pf_queue = xe->usm.pf_queue + queue_index;
unsigned long flags;
bool full;
@@ -489,7 +499,7 @@ int xe_pagefault_handler(struct xe_device *xe, struct xe_pagefault *pf)
} else {
drm_warn(&xe->drm,
"PageFault Queue (%d) full, shouldn't be possible\n",
- pf->consumer.asid % XE_PAGEFAULT_QUEUE_COUNT);
+ queue_index);
}
spin_unlock_irqrestore(&pf_queue->lock, flags);
diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c
index b228a737cfd6..8d604aa095f0 100644
--- a/drivers/gpu/drm/xe/xe_svm.c
+++ b/drivers/gpu/drm/xe/xe_svm.c
@@ -115,6 +115,7 @@ xe_svm_range_alloc(struct drm_gpusvm *gpusvm)
return NULL;
INIT_LIST_HEAD(&range->garbage_collector_link);
+ mutex_init(&range->lock);
drm_gpusvm_init_pages(&range->pages, &gpusvm_to_vm(gpusvm)->xe->drm);
xe_vm_get(gpusvm_to_vm(gpusvm));
@@ -125,6 +126,7 @@ static void xe_svm_range_free(struct drm_gpusvm_range *range)
{
drm_gpusvm_free_pages(range->gpusvm, &(to_xe_range(range)->pages),
drm_gpusvm_range_size(range) >> PAGE_SHIFT);
+ mutex_destroy(&to_xe_range(range)->lock);
xe_vm_put(range_to_vm(range));
kfree(to_xe_range(range));
}
@@ -140,11 +142,11 @@ xe_svm_garbage_collector_add_range(struct xe_vm *vm, struct xe_svm_range *range,
drm_gpusvm_range_set_unmapped(&range->base, &range->pages, 1,
mmu_range);
- spin_lock(&vm->svm.garbage_collector.lock);
+ spin_lock(&vm->svm.garbage_collector.list_lock);
if (list_empty(&range->garbage_collector_link))
list_add_tail(&range->garbage_collector_link,
&vm->svm.garbage_collector.range_list);
- spin_unlock(&vm->svm.garbage_collector.lock);
+ spin_unlock(&vm->svm.garbage_collector.list_lock);
queue_work(xe->usm.pf_wq, &vm->svm.garbage_collector.work);
}
@@ -309,18 +311,28 @@ static int __xe_svm_garbage_collector(struct xe_vm *vm,
range_debug(range, "GARBAGE COLLECTOR");
- xe_vm_lock(vm, false);
- fence = xe_vm_range_unbind(vm, range);
- xe_vm_unlock(vm);
- if (IS_ERR(fence))
- return PTR_ERR(fence);
- dma_fence_put(fence);
+ scoped_guard(mutex, &range->lock) {
+ drm_gpusvm_range_get(&range->base);
+ range->removed = true;
+
+ range_debug(range, "GARBAGE COLLECTOR");
+
+ xe_vm_lock(vm, false);
+ fence = xe_vm_range_unbind(vm, range);
+ xe_vm_unlock(vm);
+ if (IS_ERR(fence))
+ return PTR_ERR(fence);
+ dma_fence_put(fence);
+
+ drm_gpusvm_unmap_pages(&vm->svm.gpusvm, &range->pages,
+ drm_gpusvm_range_size(&range->base) >> PAGE_SHIFT,
+ &ctx);
- drm_gpusvm_unmap_pages(&vm->svm.gpusvm, &range->pages,
- drm_gpusvm_range_size(&range->base) >> PAGE_SHIFT,
- &ctx);
+ scoped_guard(mutex, &vm->svm.range_lock)
+ drm_gpusvm_range_remove(&vm->svm.gpusvm, &range->base);
+ }
- drm_gpusvm_range_remove(&vm->svm.gpusvm, &range->base);
+ drm_gpusvm_range_put(&range->base);
return 0;
}
@@ -393,13 +405,15 @@ static int xe_svm_garbage_collector(struct xe_vm *vm)
u64 range_end;
int err, ret = 0;
- lockdep_assert_held_write(&vm->lock);
+ lockdep_assert_held(&vm->lock);
if (xe_vm_is_closed_or_banned(vm))
return -ENOENT;
+ guard(mutex)(&vm->svm.garbage_collector.lock);
+
for (;;) {
- spin_lock(&vm->svm.garbage_collector.lock);
+ spin_lock(&vm->svm.garbage_collector.list_lock);
range = list_first_entry_or_null(&vm->svm.garbage_collector.range_list,
typeof(*range),
garbage_collector_link);
@@ -410,7 +424,7 @@ static int xe_svm_garbage_collector(struct xe_vm *vm)
range_end = xe_svm_range_end(range);
list_del(&range->garbage_collector_link);
- spin_unlock(&vm->svm.garbage_collector.lock);
+ spin_unlock(&vm->svm.garbage_collector.list_lock);
err = __xe_svm_garbage_collector(vm, range);
if (err) {
@@ -429,7 +443,7 @@ static int xe_svm_garbage_collector(struct xe_vm *vm)
return err;
}
}
- spin_unlock(&vm->svm.garbage_collector.lock);
+ spin_unlock(&vm->svm.garbage_collector.list_lock);
return ret;
}
@@ -439,9 +453,8 @@ static void xe_svm_garbage_collector_work_func(struct work_struct *w)
struct xe_vm *vm = container_of(w, struct xe_vm,
svm.garbage_collector.work);
- down_write(&vm->lock);
+ guard(rwsem_read)(&vm->lock);
xe_svm_garbage_collector(vm);
- up_write(&vm->lock);
}
#if IS_ENABLED(CONFIG_DRM_XE_PAGEMAP)
@@ -893,8 +906,11 @@ int xe_svm_init(struct xe_vm *vm)
{
int err;
+ mutex_init(&vm->svm.range_lock);
+ mutex_init(&vm->svm.garbage_collector.lock);
+
if (vm->flags & XE_VM_FLAG_FAULT_MODE) {
- spin_lock_init(&vm->svm.garbage_collector.lock);
+ spin_lock_init(&vm->svm.garbage_collector.list_lock);
INIT_LIST_HEAD(&vm->svm.garbage_collector.range_list);
INIT_WORK(&vm->svm.garbage_collector.work,
xe_svm_garbage_collector_work_func);
@@ -916,7 +932,7 @@ int xe_svm_init(struct xe_vm *vm)
xe_modparam.svm_notifier_size * SZ_1M,
&gpusvm_ops, fault_chunk_sizes,
ARRAY_SIZE(fault_chunk_sizes));
- drm_gpusvm_driver_set_lock(&vm->svm.gpusvm, &vm->lock);
+ drm_gpusvm_driver_set_lock(&vm->svm.gpusvm, &vm->svm.range_lock);
if (err) {
xe_svm_put_pagemaps(vm);
@@ -969,7 +985,10 @@ void xe_svm_fini(struct xe_vm *vm)
&ctx);
}
- drm_gpusvm_fini(&vm->svm.gpusvm);
+ scoped_guard(mutex, &vm->svm.range_lock)
+ drm_gpusvm_fini(&vm->svm.gpusvm);
+ mutex_destroy(&vm->svm.range_lock);
+ mutex_destroy(&vm->svm.garbage_collector.lock);
}
static bool xe_svm_range_has_pagemap_locked(const struct xe_svm_range *range,
@@ -1246,21 +1265,27 @@ static int __xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
};
struct xe_validation_ctx vctx;
struct drm_exec exec;
- struct xe_svm_range *range;
+ struct xe_svm_range *range = NULL;
struct drm_gpusvm_range_flags range_flags;
struct dma_fence *fence;
struct drm_pagemap *dpagemap;
struct xe_tile *tile = gt_to_tile(gt);
int migrate_try_count = ctx.devmem_only ? 3 : 1;
ktime_t start = xe_gt_stats_ktime_get(), bind_start, get_pages_start;
- int err;
+ int err = 0;
- lockdep_assert_held_write(&vm->lock);
+ lockdep_assert_held(&vm->lock);
xe_assert(vm->xe, xe_vma_is_cpu_addr_mirror(vma));
xe_gt_stats_incr(gt, XE_GT_STATS_ID_SVM_PAGEFAULT_COUNT, 1);
retry:
+ /* Release old range */
+ if (range) {
+ mutex_unlock(&range->lock);
+ drm_gpusvm_range_put(&range->base);
+ }
+
/* Always process UNMAPs first so view SVM ranges is current */
err = xe_svm_garbage_collector(vm);
if (err)
@@ -1276,6 +1301,11 @@ static int __xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
xe_svm_range_fault_count_stats_incr(gt, range);
+ mutex_lock(&range->lock);
+
+ if (xe_svm_range_is_removed(range))
+ goto retry;
+
/* READ_ONCE pairs with WRITE_ONCE in drm_gpusvm_range_set_unmapped() */
range_flags.__flags = READ_ONCE(range->base.flags.__flags);
if (ctx.devmem_only && !range_flags.migrate_devmem)
@@ -1317,7 +1347,7 @@ static int __xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
drm_err(&vm->xe->drm,
"VRAM allocation failed, retry count exceeded, asid=%u, errno=%pe\n",
vm->usm.asid, ERR_PTR(err));
- return err;
+ goto err_out;
}
}
}
@@ -1379,6 +1409,8 @@ static int __xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
out:
xe_svm_range_fault_us_stats_incr(gt, range, start);
+ mutex_unlock(&range->lock);
+ drm_gpusvm_range_put(&range->base);
return 0;
err_out:
@@ -1388,6 +1420,9 @@ static int __xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
goto retry;
}
+ mutex_unlock(&range->lock);
+ drm_gpusvm_range_put(&range->base);
+
return err;
}
@@ -1470,9 +1505,9 @@ void xe_svm_unmap_address_range(struct xe_vm *vm, u64 start, u64 end)
drm_gpusvm_range_get(range);
__xe_svm_garbage_collector(vm, to_xe_range(range));
if (!list_empty(&to_xe_range(range)->garbage_collector_link)) {
- spin_lock(&vm->svm.garbage_collector.lock);
+ spin_lock(&vm->svm.garbage_collector.list_lock);
list_del(&to_xe_range(range)->garbage_collector_link);
- spin_unlock(&vm->svm.garbage_collector.lock);
+ spin_unlock(&vm->svm.garbage_collector.list_lock);
}
drm_gpusvm_range_put(range);
}
@@ -1502,7 +1537,7 @@ int xe_svm_bo_evict(struct xe_bo *bo)
* @ctx: GPU SVM context
*
* This function finds or inserts a newly allocated a SVM range based on the
- * address.
+ * address. Take a reference to SVM range on success.
*
* Return: Pointer to the SVM range on success, ERR_PTR() on failure.
*/
@@ -1511,11 +1546,15 @@ struct xe_svm_range *xe_svm_range_find_or_insert(struct xe_vm *vm, u64 addr,
{
struct drm_gpusvm_range *r;
+ guard(mutex)(&vm->svm.range_lock);
+
r = drm_gpusvm_range_find_or_insert(&vm->svm.gpusvm, max(addr, xe_vma_start(vma)),
xe_vma_start(vma), xe_vma_end(vma), ctx);
if (IS_ERR(r))
return ERR_CAST(r);
+ drm_gpusvm_range_get(r);
+
return to_xe_range(r);
}
@@ -1535,6 +1574,8 @@ int xe_svm_range_get_pages(struct xe_vm *vm, struct xe_svm_range *range,
{
int err = 0;
+ lockdep_assert_held(&range->lock);
+
err = drm_gpusvm_get_pages(&vm->svm.gpusvm, &range->pages,
vm->svm.gpusvm.mm,
&range->base.notifier->notifier,
@@ -1659,6 +1700,7 @@ int xe_svm_alloc_vram(struct xe_svm_range *range, const struct drm_gpusvm_ctx *c
.__flags = READ_ONCE(range->base.flags.__flags),
};
+ lockdep_assert_held(&range->lock);
xe_assert(range_to_vm(&range->base)->xe, flags.migrate_devmem);
range_debug(range, "ALLOCATE VRAM");
diff --git a/drivers/gpu/drm/xe/xe_svm.h b/drivers/gpu/drm/xe/xe_svm.h
index a921556d3466..0d1f1107af5f 100644
--- a/drivers/gpu/drm/xe/xe_svm.h
+++ b/drivers/gpu/drm/xe/xe_svm.h
@@ -38,6 +38,13 @@ struct xe_svm_range {
* list. Protected by VM's garbage collect lock.
*/
struct list_head garbage_collector_link;
+ /**
+ * @lock: Protects fault handler, garbage collector, and prefetch
+ * critical sections, ensuring only one thread operates on a range at a
+ * time. Locking order: inside vm->lock and garbage collector, outside
+ * dma-resv locks, vm->svm.range_lock.
+ */
+ struct mutex lock;
/**
* @tile_present: Tile mask of binding is present for this range.
* Protected by GPU SVM notifier lock.
@@ -48,8 +55,22 @@ struct xe_svm_range {
* range. Protected by GPU SVM notifier lock.
*/
u8 tile_invalidated;
+ /**
+ * @removed: Range has been removed from GPU SVM tree, protected by
+ * @lock.
+ */
+ bool removed;
};
+/**
+ * xe_svm_range_put() - SVM range put
+ * @range: SVM range
+ */
+static inline void xe_svm_range_put(struct xe_svm_range *range)
+{
+ drm_gpusvm_range_put(&range->base);
+}
+
/**
* struct xe_pagemap - Manages xe device_private memory for SVM.
* @pagemap: The struct dev_pagemap providing the struct pages.
@@ -137,6 +158,19 @@ static inline bool xe_svm_range_has_dma_mapping(struct xe_svm_range *range)
return range->pages.flags.has_dma_mapping;
}
+/**
+ * xe_svm_range_is_removed() - SVM range is removed from GPU SVM tree
+ * @range: SVM range
+ *
+ * Return: True if SVM range is removed from GPU SVM tree, False otherwise
+ */
+static inline bool xe_svm_range_is_removed(struct xe_svm_range *range)
+{
+ lockdep_assert_held(&range->lock);
+
+ return range->removed;
+}
+
/**
* to_xe_range - Convert a drm_gpusvm_range pointer to a xe_svm_range
* @r: Pointer to the drm_gpusvm_range structure
@@ -216,10 +250,15 @@ struct xe_svm_range {
struct {
const struct drm_pagemap_addr *dma_addr;
} pages;
+ struct mutex lock;
u32 tile_present;
u32 tile_invalidated;
};
+static inline void xe_svm_range_put(struct xe_svm_range *range)
+{
+}
+
static inline bool xe_svm_range_pages_valid(struct xe_svm_range *range)
{
return false;
@@ -389,6 +428,11 @@ static inline struct drm_pagemap *xe_drm_pagemap_from_fd(int fd, u32 region_inst
return ERR_PTR(-ENOENT);
}
+static inline bool xe_svm_range_is_removed(struct xe_svm_range *range)
+{
+ return false;
+}
+
#define xe_svm_range_has_dma_mapping(...) false
#endif /* CONFIG_DRM_XE_GPUSVM */
diff --git a/drivers/gpu/drm/xe/xe_userptr.c b/drivers/gpu/drm/xe/xe_userptr.c
index 8b2d461ea0b2..252155ee723f 100644
--- a/drivers/gpu/drm/xe/xe_userptr.c
+++ b/drivers/gpu/drm/xe/xe_userptr.c
@@ -57,6 +57,22 @@ int __xe_vm_userptr_needs_repin(struct xe_vm *vm)
list_empty(&vm->userptr.invalidated)) ? 0 : -EAGAIN;
}
+#if IS_ENABLED(CONFIG_PROVE_LOCKING)
+static bool __xe_vma_userptr_lockdep(struct xe_userptr_vma *uvma)
+{
+ struct xe_vma *vma = &uvma->vma;
+ struct xe_vm *vm = xe_vma_vm(vma);
+
+ return lockdep_is_held_type(&vm->lock, 0) ||
+ (lockdep_is_held_type(&vm->lock, 1) &&
+ lockdep_is_held_type(&vma->fault_lock, 0));
+}
+#define xe_vma_userptr_lockdep(uvma) \
+ lockdep_assert(__xe_vma_userptr_lockdep(uvma))
+#else
+#define xe_vma_userptr_lockdep(uvma)
+#endif
+
int xe_vma_userptr_pin_pages(struct xe_userptr_vma *uvma)
{
struct xe_vma *vma = &uvma->vma;
@@ -68,7 +84,7 @@ int xe_vma_userptr_pin_pages(struct xe_userptr_vma *uvma)
.allow_mixed = true,
};
- lockdep_assert_held(&vm->lock);
+ xe_vma_userptr_lockdep(uvma);
xe_assert(xe, xe_vma_is_userptr(vma));
if (vma->gpuva.flags & XE_VMA_DESTROYED)
@@ -273,7 +289,7 @@ void xe_vma_userptr_force_invalidate(struct xe_userptr_vma *uvma)
struct xe_vm *vm = xe_vma_vm(&uvma->vma);
/* Protect against concurrent userptr pinning */
- lockdep_assert_held(&vm->lock);
+ xe_vma_userptr_lockdep(uvma);
/* Protect against concurrent notifiers */
lockdep_assert_held(&vm->svm.gpusvm.notifier_lock);
/*
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index 9e0176861cb6..aaaee825291f 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -689,6 +689,17 @@ static int xe_vma_ops_alloc(struct xe_vma_ops *vops, bool array_of_binds)
}
ALLOW_ERROR_INJECTION(xe_vma_ops_alloc, ERRNO);
+static void xe_vma_svm_prefetch_ranges_fini(struct xe_vma_op *op)
+{
+ struct xe_svm_range *svm_range;
+ unsigned long i;
+
+ xa_for_each(&op->prefetch_range.range, i, svm_range)
+ xe_svm_range_put(svm_range);
+
+ xa_destroy(&op->prefetch_range.range);
+}
+
static void xe_vma_svm_prefetch_op_fini(struct xe_vma_op *op)
{
struct xe_vma *vma;
@@ -696,7 +707,7 @@ static void xe_vma_svm_prefetch_op_fini(struct xe_vma_op *op)
vma = gpuva_to_vma(op->base.prefetch.va);
if (op->base.op == DRM_GPUVA_OP_PREFETCH && xe_vma_is_cpu_addr_mirror(vma))
- xa_destroy(&op->prefetch_range.range);
+ xe_vma_svm_prefetch_ranges_fini(op);
}
static void xe_vma_svm_prefetch_ops_fini(struct xe_vma_ops *vops)
@@ -930,6 +941,7 @@ struct dma_fence *xe_vm_range_rebind(struct xe_vm *vm,
u8 id;
int err;
+ lockdep_assert_held(&range->lock);
lockdep_assert_held(&vm->lock);
xe_vm_assert_held(vm);
xe_assert(vm->xe, xe_vm_in_fault_mode(vm));
@@ -1012,6 +1024,7 @@ struct dma_fence *xe_vm_range_unbind(struct xe_vm *vm,
u8 id;
int err;
+ lockdep_assert_held(&range->lock);
lockdep_assert_held(&vm->lock);
xe_vm_assert_held(vm);
xe_assert(vm->xe, xe_vm_in_fault_mode(vm));
@@ -1115,6 +1128,8 @@ static struct xe_vma *xe_vma_create(struct xe_vm *vm,
vma->gpuva.gem.obj = &bo->ttm.base;
}
+ mutex_init(&vma->fault_lock);
+
INIT_LIST_HEAD(&vma->combined_links.rebind);
INIT_LIST_HEAD(&vma->gpuva.gem.entry);
@@ -1211,6 +1226,7 @@ static void xe_vma_destroy_late(struct xe_vma *vma)
xe_bo_put(bo);
}
+ mutex_destroy(&vma->fault_lock);
xe_vma_free(vma);
}
@@ -1231,12 +1247,19 @@ static void vma_destroy_cb(struct dma_fence *fence,
queue_work(system_dfl_wq, &vma->destroy_work);
}
+static void xe_vm_assert_write_mode_or_garbage_collector(struct xe_vm *vm)
+{
+ lockdep_assert(lockdep_is_held_type(&vm->lock, 0) ||
+ (lockdep_is_held_type(&vm->lock, 1) &&
+ lockdep_is_held_type(&vm->svm.garbage_collector.lock, 0)));
+}
+
static void xe_vma_destroy(struct xe_vma *vma, struct dma_fence *fence)
{
struct xe_vm *vm = xe_vma_vm(vma);
struct xe_bo *bo = xe_vma_bo(vma);
- lockdep_assert_held_write(&vm->lock);
+ xe_vm_assert_write_mode_or_garbage_collector(vm);
xe_assert(vm->xe, list_empty(&vma->combined_links.destroy));
if (xe_vma_is_userptr(vma)) {
@@ -1348,8 +1371,6 @@ static void xe_vm_remove_vma(struct xe_vm *vm, struct xe_vma *vma)
mutex_lock(&vm->snap_mutex);
drm_gpuva_remove(&vma->gpuva);
mutex_unlock(&vm->snap_mutex);
- if (vm->usm.last_fault_vma == vma)
- vm->usm.last_fault_vma = NULL;
}
static struct drm_gpuva_op *xe_vm_op_alloc(void)
@@ -2284,15 +2305,6 @@ int xe_vm_query_vmas_attrs_ioctl(struct drm_device *dev, void *data, struct drm_
return err;
}
-static bool vma_matches(struct xe_vma *vma, u64 page_addr)
-{
- if (page_addr > xe_vma_end(vma) - 1 ||
- page_addr + SZ_4K - 1 < xe_vma_start(vma))
- return false;
-
- return true;
-}
-
/**
* xe_vm_find_vma_by_addr() - Find a VMA by its address
*
@@ -2301,16 +2313,7 @@ static bool vma_matches(struct xe_vma *vma, u64 page_addr)
*/
struct xe_vma *xe_vm_find_vma_by_addr(struct xe_vm *vm, u64 page_addr)
{
- struct xe_vma *vma = NULL;
-
- if (vm->usm.last_fault_vma) { /* Fast lookup */
- if (vma_matches(vm->usm.last_fault_vma, page_addr))
- vma = vm->usm.last_fault_vma;
- }
- if (!vma)
- vma = xe_vm_find_overlapping_vma(vm, page_addr, SZ_4K);
-
- return vma;
+ return xe_vm_find_overlapping_vma(vm, page_addr, SZ_4K);
}
static const u32 region_to_mem_type[] = {
@@ -2552,6 +2555,7 @@ vm_bind_ioctl_ops_create(struct xe_vm *vm, struct xe_vma_ops *vops,
}
if (xe_svm_range_validate(vm, svm_range, tile_mask, dpagemap)) {
+ xe_svm_range_put(svm_range);
xe_svm_range_debug(svm_range, "PREFETCH - RANGE IS VALID");
goto check_next_range;
}
@@ -2560,8 +2564,10 @@ vm_bind_ioctl_ops_create(struct xe_vm *vm, struct xe_vma_ops *vops,
&i, svm_range, xa_limit_32b,
GFP_KERNEL);
- if (err)
+ if (err) {
+ xe_svm_range_put(svm_range);
goto unwind_prefetch_ops;
+ }
op->prefetch_range.ranges_count++;
vops->flags |= XE_VMA_OPS_FLAG_HAS_SVM_PREFETCH;
@@ -2596,7 +2602,7 @@ static struct xe_vma *new_vma(struct xe_vm *vm, struct drm_gpuva_op_map *op,
struct xe_vma *vma;
int err = 0;
- lockdep_assert_held_write(&vm->lock);
+ xe_vm_assert_write_mode_or_garbage_collector(vm);
if (bo) {
err = 0;
@@ -2693,7 +2699,7 @@ static int xe_vma_op_commit(struct xe_vm *vm, struct xe_vma_op *op)
{
int err = 0;
- lockdep_assert_held_write(&vm->lock);
+ xe_vm_assert_write_mode_or_garbage_collector(vm);
switch (op->base.op) {
case DRM_GPUVA_OP_MAP:
@@ -2785,7 +2791,7 @@ static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct drm_gpuva_ops *ops,
u8 id, tile_mask = 0;
int err = 0;
- lockdep_assert_held_write(&vm->lock);
+ xe_vm_assert_write_mode_or_garbage_collector(vm);
for_each_tile(tile, vm->xe, id)
tile_mask |= 0x1 << id;
@@ -2964,7 +2970,7 @@ static void xe_vma_op_unwind(struct xe_vm *vm, struct xe_vma_op *op,
bool post_commit, bool prev_post_commit,
bool next_post_commit)
{
- lockdep_assert_held_write(&vm->lock);
+ xe_vm_assert_write_mode_or_garbage_collector(vm);
switch (op->base.op) {
case DRM_GPUVA_OP_MAP:
@@ -3139,6 +3145,11 @@ static int prefetch_ranges(struct xe_vm *vm, struct xe_vma_op *op)
/* TODO: Threading the migration */
xa_for_each(&op->prefetch_range.range, i, svm_range) {
+ guard(mutex)(&svm_range->lock);
+
+ if (xe_svm_range_is_removed(svm_range))
+ return -ENODATA;
+
if (!dpagemap)
xe_svm_range_migrate_to_smem(vm, svm_range);
diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h
index 635ed29b9a69..b94eb018d532 100644
--- a/drivers/gpu/drm/xe/xe_vm_types.h
+++ b/drivers/gpu/drm/xe/xe_vm_types.h
@@ -132,6 +132,12 @@ struct xe_vma {
struct work_struct destroy_work;
};
+ /**
+ * @fault_lock: Synchronizes fault processing. Locking order: inside
+ * vm->lock, outside dma-resv.
+ */
+ struct mutex fault_lock;
+
/**
* @tile_invalidated: Tile mask of binding are invalidated for this VMA.
* protected by BO's resv and for userptrs, vm->svm.gpusvm.notifier_lock in
@@ -214,13 +220,27 @@ struct xe_vm {
struct {
/** @svm.gpusvm: base GPUSVM used to track fault allocations */
struct drm_gpusvm gpusvm;
+ /**
+ * @svm.range_lock: Protects insertion and removal of ranges
+ * from GPU SVM tree.
+ */
+ struct mutex range_lock;
/**
* @svm.garbage_collector: Garbage collector which is used unmap
* SVM range's GPU bindings and destroy the ranges.
*/
struct {
- /** @svm.garbage_collector.lock: Protect's range list */
- spinlock_t lock;
+ /**
+ * @svm.garbage_collector.lock: Ensures only one thread
+ * runs the garbage collector at a time. Locking order:
+ * inside vm->lock, outside range->lock and dma-resv.
+ */
+ struct mutex lock;
+ /**
+ * @svm.garbage_collector.list_lock: Protect's range
+ * list
+ */
+ spinlock_t list_lock;
/**
* @svm.garbage_collector.range_list: List of SVM ranges
* in the garbage collector.
@@ -350,11 +370,6 @@ struct xe_vm {
struct {
/** @asid: address space ID, unique to each VM */
u32 asid;
- /**
- * @last_fault_vma: Last fault VMA, used for fast lookup when we
- * get a flood of faults to the same VMA
- */
- struct xe_vma *last_fault_vma;
} usm;
/** @error_capture: allow to track errors */
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v5 02/12] drm/xe: Allow prefetch-only VM bind IOCTLs to use VM read lock
2026-07-23 21:47 [PATCH v5 00/12] Fine grained fault locking, threaded prefetch, storm cache Matthew Brost
2026-07-23 21:47 ` [PATCH v5 01/12] drm/xe: Fine grained page fault locking Matthew Brost
@ 2026-07-23 21:47 ` Matthew Brost
2026-07-23 21:47 ` [PATCH v5 03/12] drm/xe: Thread prefetch of SVM ranges Matthew Brost
` (12 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Matthew Brost @ 2026-07-23 21:47 UTC (permalink / raw)
To: intel-xe
Prefetch-only VM bind IOCTLs do not modify VMAs after pinning userptr
pages. Downgrade vm->lock to read mode once pinning is complete.
Lays the groundwork for prefetch IOCTLs to use threaded migration.
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
---
drivers/gpu/drm/xe/xe_vm.c | 36 +++++++++++++++++++++++++++-----
drivers/gpu/drm/xe/xe_vm_types.h | 2 ++
2 files changed, 33 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index aaaee825291f..9e3e354adc4c 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -2449,10 +2449,12 @@ vm_bind_ioctl_ops_create(struct xe_vm *vm, struct xe_vma_ops *vops,
.map.gem.offset = bo_offset_or_userptr,
};
+ vops->flags |= XE_VMA_OPS_FLAG_MODIFIES_GPUVA;
ops = drm_gpuvm_sm_map_ops_create(&vm->gpuvm, &map_req);
break;
}
case DRM_XE_VM_BIND_OP_UNMAP:
+ vops->flags |= XE_VMA_OPS_FLAG_MODIFIES_GPUVA;
ops = drm_gpuvm_sm_unmap_ops_create(&vm->gpuvm, addr, range);
break;
case DRM_XE_VM_BIND_OP_PREFETCH:
@@ -2461,6 +2463,7 @@ vm_bind_ioctl_ops_create(struct xe_vm *vm, struct xe_vma_ops *vops,
case DRM_XE_VM_BIND_OP_UNMAP_ALL:
xe_assert(vm->xe, bo);
+ vops->flags |= XE_VMA_OPS_FLAG_MODIFIES_GPUVA;
err = xe_bo_lock(bo, true);
if (err)
return ERR_PTR(err);
@@ -2511,6 +2514,9 @@ vm_bind_ioctl_ops_create(struct xe_vm *vm, struct xe_vma_ops *vops,
u8 id, tile_mask = 0;
u32 i;
+ if (xe_vma_is_userptr(vma))
+ vops->flags |= XE_VMA_OPS_FLAG_MODIFIES_GPUVA;
+
if (!xe_vma_is_cpu_addr_mirror(vma)) {
op->prefetch.region = prefetch_region;
break;
@@ -2699,10 +2705,12 @@ static int xe_vma_op_commit(struct xe_vm *vm, struct xe_vma_op *op)
{
int err = 0;
- xe_vm_assert_write_mode_or_garbage_collector(vm);
+ lockdep_assert_held(&vm->lock);
switch (op->base.op) {
case DRM_GPUVA_OP_MAP:
+ xe_vm_assert_write_mode_or_garbage_collector(vm);
+
err |= xe_vm_insert_vma(vm, op->map.vma);
if (!err)
op->flags |= XE_VMA_OP_COMMITTED;
@@ -2712,6 +2720,8 @@ static int xe_vma_op_commit(struct xe_vm *vm, struct xe_vma_op *op)
u8 tile_present =
gpuva_to_vma(op->base.remap.unmap->va)->tile_present;
+ xe_vm_assert_write_mode_or_garbage_collector(vm);
+
prep_vma_destroy(vm, gpuva_to_vma(op->base.remap.unmap->va),
true);
op->flags |= XE_VMA_OP_COMMITTED;
@@ -2746,6 +2756,8 @@ static int xe_vma_op_commit(struct xe_vm *vm, struct xe_vma_op *op)
break;
}
case DRM_GPUVA_OP_UNMAP:
+ xe_vm_assert_write_mode_or_garbage_collector(vm);
+
prep_vma_destroy(vm, gpuva_to_vma(op->base.unmap.va), true);
op->flags |= XE_VMA_OP_COMMITTED;
break;
@@ -2970,10 +2982,12 @@ static void xe_vma_op_unwind(struct xe_vm *vm, struct xe_vma_op *op,
bool post_commit, bool prev_post_commit,
bool next_post_commit)
{
- xe_vm_assert_write_mode_or_garbage_collector(vm);
+ lockdep_assert_held(&vm->lock);
switch (op->base.op) {
case DRM_GPUVA_OP_MAP:
+ xe_vm_assert_write_mode_or_garbage_collector(vm);
+
if (op->map.vma) {
prep_vma_destroy(vm, op->map.vma, post_commit);
xe_vma_destroy_unlocked(op->map.vma);
@@ -2983,6 +2997,8 @@ static void xe_vma_op_unwind(struct xe_vm *vm, struct xe_vma_op *op,
{
struct xe_vma *vma = gpuva_to_vma(op->base.unmap.va);
+ xe_vm_assert_write_mode_or_garbage_collector(vm);
+
if (vma) {
xe_svm_notifier_lock(vm);
vma->gpuva.flags &= ~XE_VMA_DESTROYED;
@@ -2996,6 +3012,8 @@ static void xe_vma_op_unwind(struct xe_vm *vm, struct xe_vma_op *op,
{
struct xe_vma *vma = gpuva_to_vma(op->base.remap.unmap->va);
+ xe_vm_assert_write_mode_or_garbage_collector(vm);
+
if (op->remap.prev) {
prep_vma_destroy(vm, op->remap.prev, prev_post_commit);
xe_vma_destroy_unlocked(op->remap.prev);
@@ -3580,7 +3598,7 @@ static struct dma_fence *vm_bind_ioctl_ops_execute(struct xe_vm *vm,
struct dma_fence *fence;
int err = 0;
- lockdep_assert_held_write(&vm->lock);
+ lockdep_assert_held(&vm->lock);
xe_validation_guard(&ctx, &vm->xe->val, &exec,
((struct xe_val_flags) {
@@ -3903,7 +3921,7 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
u32 num_syncs, num_ufence = 0;
struct xe_sync_entry *syncs = NULL;
struct drm_xe_vm_bind_op *bind_ops = NULL;
- struct xe_vma_ops vops;
+ struct xe_vma_ops vops = { .flags = 0, };
struct dma_fence *fence;
int err;
int i;
@@ -4078,6 +4096,11 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
goto unwind_ops;
}
+ if (!(vops.flags & XE_VMA_OPS_FLAG_MODIFIES_GPUVA)) {
+ vops.flags |= XE_VMA_OPS_FLAG_DOWNGRADE_LOCK;
+ downgrade_write(&vm->lock);
+ }
+
err = xe_vma_ops_alloc(&vops, args->num_binds > 1);
if (err)
goto unwind_ops;
@@ -4114,7 +4137,10 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
free_bos:
kvfree(bos);
release_vm_lock:
- up_write(&vm->lock);
+ if (vops.flags & XE_VMA_OPS_FLAG_DOWNGRADE_LOCK)
+ up_read(&vm->lock);
+ else
+ up_write(&vm->lock);
put_exec_queue:
if (q)
xe_exec_queue_put(q);
diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h
index b94eb018d532..2f5f74fed9d2 100644
--- a/drivers/gpu/drm/xe/xe_vm_types.h
+++ b/drivers/gpu/drm/xe/xe_vm_types.h
@@ -561,6 +561,8 @@ struct xe_vma_ops {
#define XE_VMA_OPS_ARRAY_OF_BINDS BIT(2)
#define XE_VMA_OPS_FLAG_SKIP_TLB_WAIT BIT(3)
#define XE_VMA_OPS_FLAG_ALLOW_SVM_UNMAP BIT(4)
+#define XE_VMA_OPS_FLAG_MODIFIES_GPUVA BIT(5)
+#define XE_VMA_OPS_FLAG_DOWNGRADE_LOCK BIT(6)
u32 flags;
#ifdef TEST_VM_OPS_ERROR
/** @inject_error: inject error to test error handling */
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v5 03/12] drm/xe: Thread prefetch of SVM ranges
2026-07-23 21:47 [PATCH v5 00/12] Fine grained fault locking, threaded prefetch, storm cache Matthew Brost
2026-07-23 21:47 ` [PATCH v5 01/12] drm/xe: Fine grained page fault locking Matthew Brost
2026-07-23 21:47 ` [PATCH v5 02/12] drm/xe: Allow prefetch-only VM bind IOCTLs to use VM read lock Matthew Brost
@ 2026-07-23 21:47 ` Matthew Brost
2026-07-23 21:47 ` [PATCH v5 04/12] drm/xe: Use a single page-fault queue with multiple workers Matthew Brost
` (11 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Matthew Brost @ 2026-07-23 21:47 UTC (permalink / raw)
To: intel-xe; +Cc: Thomas Hellström, Himal Prasad Ghimiray
The migrate_vma_* functions are very CPU-intensive; as a result,
prefetching SVM ranges is limited by CPU performance rather than paging
copy engine bandwidth. To accelerate SVM range prefetching, the step
that calls migrate_vma_* is now threaded. Reuses the page fault work
queue for threading.
Running xe_exec_system_allocator --r prefetch-benchmark, which tests
64MB prefetches, shows an increase from ~4.35 GB/s to 12.25 GB/s with
this patch on drm-tip. Enabling high SLPC further increases throughput
to ~15.25 GB/s, and combining SLPC with ULLS raises it to ~16 GB/s. Both
of these optimizations are upcoming.
v2:
- Use dedicated prefetch workqueue
- Pick dedicated prefetch thread count based on profiling
- Skip threaded prefetch for only 1 range or if prefetching to SRAM
- Fully tested
v3:
- Use page fault work queue
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Cc: Himal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
---
drivers/gpu/drm/xe/xe_pagefault.c | 32 ++++++-
drivers/gpu/drm/xe/xe_svm.c | 23 ++++-
drivers/gpu/drm/xe/xe_svm.h | 6 +-
drivers/gpu/drm/xe/xe_vm.c | 150 +++++++++++++++++++++++-------
drivers/gpu/drm/xe/xe_vm_types.h | 15 +--
5 files changed, 175 insertions(+), 51 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_pagefault.c b/drivers/gpu/drm/xe/xe_pagefault.c
index 80196e874e06..c4df3b746dae 100644
--- a/drivers/gpu/drm/xe/xe_pagefault.c
+++ b/drivers/gpu/drm/xe/xe_pagefault.c
@@ -186,7 +186,17 @@ static int xe_pagefault_service(struct xe_pagefault *pf)
if (IS_ERR(vm))
return PTR_ERR(vm);
- down_read(&vm->lock);
+ /*
+ * We can't block threaded prefetches from completing. down_read() can
+ * block on a pending down_write(), so without a trylock here, we could
+ * deadlock, since the page fault workqueue is shared with prefetches,
+ * prefetches flush work items onto the same workqueue, and a
+ * down_write() could be pending.
+ */
+ if (!down_read_trylock(&vm->lock)) {
+ err = -EAGAIN;
+ goto put_vm;
+ }
if (xe_vm_is_closed(vm)) {
err = -ENOENT;
@@ -215,11 +225,23 @@ static int xe_pagefault_service(struct xe_pagefault *pf)
unlock_vm:
up_read(&vm->lock);
+put_vm:
xe_vm_put(vm);
return err;
}
+static void xe_pagefault_queue_retry(struct xe_pagefault_queue *pf_queue,
+ struct xe_pagefault *pf)
+{
+ spin_lock_irq(&pf_queue->lock);
+ if (!pf_queue->tail)
+ pf_queue->tail = pf_queue->size - xe_pagefault_entry_size();
+ else
+ pf_queue->tail -= xe_pagefault_entry_size();
+ spin_unlock_irq(&pf_queue->lock);
+}
+
static bool xe_pagefault_queue_pop(struct xe_pagefault_queue *pf_queue,
struct xe_pagefault *pf)
{
@@ -303,8 +325,12 @@ static void xe_pagefault_queue_work(struct work_struct *w)
err = xe_pagefault_service(&pf);
if (err) {
- xe_pagefault_save_to_vm(gt_to_xe(pf.gt), &pf);
- if (!(pf.consumer.access_type & XE_PAGEFAULT_ACCESS_PREFETCH)) {
+ if (err == -EAGAIN) {
+ xe_pagefault_queue_retry(pf_queue, &pf);
+ queue_work(gt_to_xe(pf.gt)->usm.pf_wq, w);
+ break;
+ } else if (!(pf.consumer.access_type & XE_PAGEFAULT_ACCESS_PREFETCH)) {
+ xe_pagefault_save_to_vm(gt_to_xe(pf.gt), &pf);
xe_pagefault_print(&pf);
xe_gt_info(pf.gt, "Fault response: Unsuccessful %pe\n",
ERR_PTR(err));
diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c
index 8d604aa095f0..705363bf3339 100644
--- a/drivers/gpu/drm/xe/xe_svm.c
+++ b/drivers/gpu/drm/xe/xe_svm.c
@@ -453,8 +453,19 @@ static void xe_svm_garbage_collector_work_func(struct work_struct *w)
struct xe_vm *vm = container_of(w, struct xe_vm,
svm.garbage_collector.work);
- guard(rwsem_read)(&vm->lock);
- xe_svm_garbage_collector(vm);
+ /*
+ * We can't block threaded prefetches from completing. down_read() can
+ * block on a pending down_write(), so without a trylock here, we could
+ * deadlock, since the page fault workqueue is shared with prefetches,
+ * prefetches flush work items onto the same workqueue, and a
+ * down_write() could be pending.
+ */
+ if (down_read_trylock(&vm->lock)) {
+ xe_svm_garbage_collector(vm);
+ up_read(&vm->lock);
+ } else {
+ queue_work(vm->xe->usm.pf_wq, &vm->svm.garbage_collector.work);
+ }
}
#if IS_ENABLED(CONFIG_DRM_XE_PAGEMAP)
@@ -1041,6 +1052,7 @@ void xe_svm_range_migrate_to_smem(struct xe_vm *vm, struct xe_svm_range *range)
* @tile_mask: Mask representing the tiles to be checked
* @dpagemap: if !%NULL, the range is expected to be present
* in device memory identified by this parameter.
+ * @valid_pages: Pages are valid, result written back to caller
*
* The xe_svm_range_validate() function checks if a range is
* valid and located in the desired memory region.
@@ -1049,7 +1061,8 @@ void xe_svm_range_migrate_to_smem(struct xe_vm *vm, struct xe_svm_range *range)
*/
bool xe_svm_range_validate(struct xe_vm *vm,
struct xe_svm_range *range,
- u8 tile_mask, const struct drm_pagemap *dpagemap)
+ u8 tile_mask, const struct drm_pagemap *dpagemap,
+ bool *valid_pages)
{
bool ret;
@@ -1061,6 +1074,8 @@ bool xe_svm_range_validate(struct xe_vm *vm,
else
ret = ret && !range->pages.dpagemap;
+ *valid_pages = xe_svm_range_pages_valid(range);
+
xe_svm_notifier_unlock(vm);
return ret;
@@ -2123,5 +2138,5 @@ struct drm_pagemap *xe_drm_pagemap_from_fd(int fd, u32 region_instance)
void xe_svm_flush(struct xe_vm *vm)
{
if (xe_vm_in_fault_mode(vm))
- flush_work(&vm->svm.garbage_collector.work);
+ __flush_workqueue(vm->xe->usm.pf_wq);
}
diff --git a/drivers/gpu/drm/xe/xe_svm.h b/drivers/gpu/drm/xe/xe_svm.h
index 0d1f1107af5f..46be2e5c6f7f 100644
--- a/drivers/gpu/drm/xe/xe_svm.h
+++ b/drivers/gpu/drm/xe/xe_svm.h
@@ -134,7 +134,8 @@ void xe_svm_range_migrate_to_smem(struct xe_vm *vm, struct xe_svm_range *range);
bool xe_svm_range_validate(struct xe_vm *vm,
struct xe_svm_range *range,
- u8 tile_mask, const struct drm_pagemap *dpagemap);
+ u8 tile_mask, const struct drm_pagemap *dpagemap,
+ bool *valid_pages);
u64 xe_svm_find_vma_start(struct xe_vm *vm, u64 addr, u64 end, struct xe_vma *vma);
@@ -376,7 +377,8 @@ void xe_svm_range_migrate_to_smem(struct xe_vm *vm, struct xe_svm_range *range)
static inline
bool xe_svm_range_validate(struct xe_vm *vm,
struct xe_svm_range *range,
- u8 tile_mask, bool devmem_preferred)
+ u8 tile_mask, const struct drm_pagemap *dpagemap,
+ bool *valid_pages)
{
return false;
}
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index 9e3e354adc4c..64caf8290517 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -2513,6 +2513,7 @@ vm_bind_ioctl_ops_create(struct xe_vm *vm, struct xe_vma_ops *vops,
struct drm_pagemap *dpagemap = NULL;
u8 id, tile_mask = 0;
u32 i;
+ bool valid_pages;
if (xe_vma_is_userptr(vma))
vops->flags |= XE_VMA_OPS_FLAG_MODIFIES_GPUVA;
@@ -2560,9 +2561,11 @@ vm_bind_ioctl_ops_create(struct xe_vm *vm, struct xe_vma_ops *vops,
goto unwind_prefetch_ops;
}
- if (xe_svm_range_validate(vm, svm_range, tile_mask, dpagemap)) {
+ if (xe_svm_range_validate(vm, svm_range, tile_mask,
+ dpagemap, &valid_pages)) {
xe_svm_range_put(svm_range);
xe_svm_range_debug(svm_range, "PREFETCH - RANGE IS VALID");
+ xe_assert(vm->xe, valid_pages);
goto check_next_range;
}
@@ -2577,6 +2580,8 @@ vm_bind_ioctl_ops_create(struct xe_vm *vm, struct xe_vma_ops *vops,
op->prefetch_range.ranges_count++;
vops->flags |= XE_VMA_OPS_FLAG_HAS_SVM_PREFETCH;
+ if (valid_pages)
+ vops->flags |= XE_VMA_OPS_FLAG_HAS_SVM_VALID_RANGE;
xe_svm_range_debug(svm_range, "PREFETCH - RANGE CREATED");
check_next_range:
if (range_end > xe_svm_range_end(svm_range) &&
@@ -3142,16 +3147,83 @@ static int check_ufence(struct xe_vma *vma)
return 0;
}
-static int prefetch_ranges(struct xe_vm *vm, struct xe_vma_op *op)
+struct prefetch_thread {
+ struct work_struct work;
+ struct drm_gpusvm_ctx *ctx;
+ struct xe_vma *vma;
+ struct xe_svm_range *svm_range;
+ struct drm_pagemap *dpagemap;
+ int err;
+};
+
+static void prefetch_thread_func(struct prefetch_thread *thread)
+{
+ struct xe_vma *vma = thread->vma;
+ struct xe_vm *vm = xe_vma_vm(vma);
+ struct xe_svm_range *svm_range = thread->svm_range;
+ struct drm_pagemap *dpagemap = thread->dpagemap;
+ int err = 0;
+
+ guard(mutex)(&svm_range->lock);
+
+ if (xe_svm_range_is_removed(svm_range)) {
+ thread->err = -ENODATA;
+ return;
+ }
+
+ if (!dpagemap)
+ xe_svm_range_migrate_to_smem(vm, svm_range);
+
+ if (IS_ENABLED(CONFIG_DRM_XE_DEBUG_VM)) {
+ drm_dbg(&vm->xe->drm,
+ "Prefetch pagemap is %s start 0x%016lx end 0x%016lx\n",
+ dpagemap ? dpagemap->drm->unique : "system",
+ xe_svm_range_start(svm_range), xe_svm_range_end(svm_range));
+ }
+
+ if (xe_svm_range_needs_migrate_to_vram(svm_range, vma, dpagemap)) {
+ err = xe_svm_alloc_vram(svm_range, thread->ctx, dpagemap);
+ if (err) {
+ drm_dbg(&vm->xe->drm, "VRAM allocation failed, retry from userspace, asid=%u, gpusvm=%p, errno=%pe\n",
+ vm->usm.asid, &vm->svm.gpusvm, ERR_PTR(err));
+ thread->err = -ENODATA;
+ return;
+ }
+ xe_svm_range_debug(svm_range, "PREFETCH - RANGE MIGRATED TO VRAM");
+ }
+
+ err = xe_svm_range_get_pages(vm, svm_range, thread->ctx);
+ if (err) {
+ drm_dbg(&vm->xe->drm, "Get pages failed, asid=%u, gpusvm=%p, errno=%pe\n",
+ vm->usm.asid, &vm->svm.gpusvm, ERR_PTR(err));
+ if (err == -EOPNOTSUPP || err == -EFAULT || err == -EPERM)
+ err = -ENODATA;
+ thread->err = err;
+ return;
+ }
+ xe_svm_range_debug(svm_range, "PREFETCH - RANGE GET PAGES DONE");
+}
+
+static void prefetch_work_func(struct work_struct *w)
+{
+ struct prefetch_thread *thread =
+ container_of(w, struct prefetch_thread, work);
+
+ prefetch_thread_func(thread);
+}
+
+static int prefetch_ranges(struct xe_vm *vm, struct xe_vma_ops *vops,
+ struct xe_vma_op *op)
{
bool devmem_possible = IS_DGFX(vm->xe) && IS_ENABLED(CONFIG_DRM_XE_PAGEMAP);
struct xe_vma *vma = gpuva_to_vma(op->base.prefetch.va);
struct drm_pagemap *dpagemap = op->prefetch_range.dpagemap;
- int err = 0;
-
struct xe_svm_range *svm_range;
struct drm_gpusvm_ctx ctx = {};
+ struct prefetch_thread stack_thread, *thread, *prefetches;
unsigned long i;
+ int err = 0, idx = 0;
+ bool skip_threads;
if (!xe_vma_is_cpu_addr_mirror(vma))
return 0;
@@ -3161,42 +3233,49 @@ static int prefetch_ranges(struct xe_vm *vm, struct xe_vma_op *op)
ctx.check_pages_threshold = devmem_possible ? SZ_64K : 0;
ctx.device_private_page_owner = xe_svm_private_page_owner(vm, !dpagemap);
- /* TODO: Threading the migration */
- xa_for_each(&op->prefetch_range.range, i, svm_range) {
- guard(mutex)(&svm_range->lock);
-
- if (xe_svm_range_is_removed(svm_range))
- return -ENODATA;
+ skip_threads = op->prefetch_range.ranges_count == 1 ||
+ (!dpagemap && !(vops->flags &
+ XE_VMA_OPS_FLAG_HAS_SVM_VALID_RANGE)) ||
+ !(vops->flags & XE_VMA_OPS_FLAG_DOWNGRADE_LOCK);
+ thread = skip_threads ? &stack_thread : NULL;
- if (!dpagemap)
- xe_svm_range_migrate_to_smem(vm, svm_range);
+ if (!skip_threads) {
+ prefetches = kvmalloc_array(op->prefetch_range.ranges_count,
+ sizeof(*prefetches), GFP_KERNEL);
+ if (!prefetches)
+ return -ENOMEM;
+ }
- if (IS_ENABLED(CONFIG_DRM_XE_DEBUG_VM)) {
- drm_dbg(&vm->xe->drm,
- "Prefetch pagemap is %s start 0x%016lx end 0x%016lx\n",
- dpagemap ? dpagemap->drm->unique : "system",
- xe_svm_range_start(svm_range), xe_svm_range_end(svm_range));
+ xa_for_each(&op->prefetch_range.range, i, svm_range) {
+ if (!skip_threads) {
+ thread = prefetches + idx++;
+ INIT_WORK(&thread->work, prefetch_work_func);
}
- if (xe_svm_range_needs_migrate_to_vram(svm_range, vma, dpagemap)) {
- err = xe_svm_alloc_vram(svm_range, &ctx, dpagemap);
- if (err) {
- drm_dbg(&vm->xe->drm, "VRAM allocation failed, retry from userspace, asid=%u, gpusvm=%p, errno=%pe\n",
- vm->usm.asid, &vm->svm.gpusvm, ERR_PTR(err));
- return -ENODATA;
- }
- xe_svm_range_debug(svm_range, "PREFETCH - RANGE MIGRATED TO VRAM");
+ thread->ctx = &ctx;
+ thread->vma = vma;
+ thread->svm_range = svm_range;
+ thread->dpagemap = dpagemap;
+ thread->err = 0;
+
+ if (skip_threads) {
+ prefetch_thread_func(thread);
+ if (thread->err)
+ return thread->err;
+ } else {
+ queue_work(vm->xe->usm.pf_wq, &thread->work);
}
+ }
- err = xe_svm_range_get_pages(vm, svm_range, &ctx);
- if (err) {
- drm_dbg(&vm->xe->drm, "Get pages failed, asid=%u, gpusvm=%p, errno=%pe\n",
- vm->usm.asid, &vm->svm.gpusvm, ERR_PTR(err));
- if (err == -EOPNOTSUPP || err == -EFAULT || err == -EPERM)
- err = -ENODATA;
- return err;
+ if (!skip_threads) {
+ for (i = 0; i < idx; ++i) {
+ thread = prefetches + i;
+
+ flush_work(&thread->work);
+ if (thread->err && (!err || err == -ENODATA))
+ err = thread->err;
}
- xe_svm_range_debug(svm_range, "PREFETCH - RANGE GET PAGES DONE");
+ kvfree(prefetches);
}
return err;
@@ -3327,7 +3406,8 @@ static int op_lock_and_prep(struct drm_exec *exec, struct xe_vm *vm,
return err;
}
-static int vm_bind_ioctl_ops_prefetch_ranges(struct xe_vm *vm, struct xe_vma_ops *vops)
+static int vm_bind_ioctl_ops_prefetch_ranges(struct xe_vm *vm,
+ struct xe_vma_ops *vops)
{
struct xe_vma_op *op;
int err;
@@ -3337,7 +3417,7 @@ static int vm_bind_ioctl_ops_prefetch_ranges(struct xe_vm *vm, struct xe_vma_ops
list_for_each_entry(op, &vops->list, link) {
if (op->base.op == DRM_GPUVA_OP_PREFETCH) {
- err = prefetch_ranges(vm, op);
+ err = prefetch_ranges(vm, vops, op);
if (err)
return err;
}
diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h
index 2f5f74fed9d2..68588b624212 100644
--- a/drivers/gpu/drm/xe/xe_vm_types.h
+++ b/drivers/gpu/drm/xe/xe_vm_types.h
@@ -556,13 +556,14 @@ struct xe_vma_ops {
/** @pt_update_ops: page table update operations */
struct xe_vm_pgtable_update_ops pt_update_ops[XE_MAX_TILES_PER_DEVICE];
/** @flag: signify the properties within xe_vma_ops*/
-#define XE_VMA_OPS_FLAG_HAS_SVM_PREFETCH BIT(0)
-#define XE_VMA_OPS_FLAG_MADVISE BIT(1)
-#define XE_VMA_OPS_ARRAY_OF_BINDS BIT(2)
-#define XE_VMA_OPS_FLAG_SKIP_TLB_WAIT BIT(3)
-#define XE_VMA_OPS_FLAG_ALLOW_SVM_UNMAP BIT(4)
-#define XE_VMA_OPS_FLAG_MODIFIES_GPUVA BIT(5)
-#define XE_VMA_OPS_FLAG_DOWNGRADE_LOCK BIT(6)
+#define XE_VMA_OPS_FLAG_HAS_SVM_PREFETCH BIT(0)
+#define XE_VMA_OPS_FLAG_MADVISE BIT(1)
+#define XE_VMA_OPS_ARRAY_OF_BINDS BIT(2)
+#define XE_VMA_OPS_FLAG_SKIP_TLB_WAIT BIT(3)
+#define XE_VMA_OPS_FLAG_ALLOW_SVM_UNMAP BIT(4)
+#define XE_VMA_OPS_FLAG_MODIFIES_GPUVA BIT(5)
+#define XE_VMA_OPS_FLAG_DOWNGRADE_LOCK BIT(6)
+#define XE_VMA_OPS_FLAG_HAS_SVM_VALID_RANGE BIT(7)
u32 flags;
#ifdef TEST_VM_OPS_ERROR
/** @inject_error: inject error to test error handling */
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v5 04/12] drm/xe: Use a single page-fault queue with multiple workers
2026-07-23 21:47 [PATCH v5 00/12] Fine grained fault locking, threaded prefetch, storm cache Matthew Brost
` (2 preceding siblings ...)
2026-07-23 21:47 ` [PATCH v5 03/12] drm/xe: Thread prefetch of SVM ranges Matthew Brost
@ 2026-07-23 21:47 ` Matthew Brost
2026-07-23 21:47 ` [PATCH v5 05/12] drm/xe: Add num_pf_work modparam Matthew Brost
` (10 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Matthew Brost @ 2026-07-23 21:47 UTC (permalink / raw)
To: intel-xe; +Cc: Maciej Patelczyk
With fine-grained page-fault locking, it no longer makes sense to
maintain multiple page-fault queues, as we no longer hash queues based
on the VM’s ASID. Multiple workers can pull page faults from a single
queue, eliminating any head-of-queue blocking. Refactor the structures
and code to use a single shared queue.
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
---
drivers/gpu/drm/xe/xe_device_types.h | 12 +++---
drivers/gpu/drm/xe/xe_pagefault.c | 52 +++++++++++++------------
drivers/gpu/drm/xe/xe_pagefault_types.h | 17 +++++++-
3 files changed, 50 insertions(+), 31 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
index b8d1726c0513..8d41b7e77176 100644
--- a/drivers/gpu/drm/xe/xe_device_types.h
+++ b/drivers/gpu/drm/xe/xe_device_types.h
@@ -303,8 +303,8 @@ struct xe_device {
struct xarray asid_to_vm;
/** @usm.next_asid: next ASID, used to cyclical alloc asids */
u32 next_asid;
- /** @usm.current_pf_queue: current page fault queue */
- u32 current_pf_queue;
+ /** @usm.current_pf_work: current page fault work item */
+ u32 current_pf_work;
/** @usm.lock: protects UM state */
struct rw_semaphore lock;
/** @usm.pf_wq: page fault work queue, unbound, high priority */
@@ -314,9 +314,11 @@ struct xe_device {
* yields the best bandwidth utilization of the kernel paging
* engine.
*/
-#define XE_PAGEFAULT_QUEUE_COUNT 4
- /** @usm.pf_queue: Page fault queues */
- struct xe_pagefault_queue pf_queue[XE_PAGEFAULT_QUEUE_COUNT];
+#define XE_PAGEFAULT_WORK_COUNT 4
+ /** @usm.pf_workers: Page fault workers */
+ struct xe_pagefault_work pf_workers[XE_PAGEFAULT_WORK_COUNT];
+ /** @usm.pf_queue: Page fault queue */
+ struct xe_pagefault_queue pf_queue;
#if IS_ENABLED(CONFIG_DRM_XE_PAGEMAP)
/** @usm.dpagemap_shrinker: Shrinker for unused pagemaps */
struct drm_pagemap_shrinker *dpagemap_shrinker;
diff --git a/drivers/gpu/drm/xe/xe_pagefault.c b/drivers/gpu/drm/xe/xe_pagefault.c
index c4df3b746dae..410dc53b7df6 100644
--- a/drivers/gpu/drm/xe/xe_pagefault.c
+++ b/drivers/gpu/drm/xe/xe_pagefault.c
@@ -239,6 +239,7 @@ static void xe_pagefault_queue_retry(struct xe_pagefault_queue *pf_queue,
pf_queue->tail = pf_queue->size - xe_pagefault_entry_size();
else
pf_queue->tail -= xe_pagefault_entry_size();
+ memcpy(pf_queue->data + pf_queue->tail, pf, sizeof(*pf));
spin_unlock_irq(&pf_queue->lock);
}
@@ -309,8 +310,10 @@ static void xe_pagefault_save_to_vm(struct xe_device *xe, struct xe_pagefault *p
static void xe_pagefault_queue_work(struct work_struct *w)
{
- struct xe_pagefault_queue *pf_queue =
- container_of(w, typeof(*pf_queue), worker);
+ struct xe_pagefault_work *pf_work =
+ container_of(w, typeof(*pf_work), work);
+ struct xe_device *xe = pf_work->xe;
+ struct xe_pagefault_queue *pf_queue = &xe->usm.pf_queue;
struct xe_pagefault pf;
unsigned long threshold;
@@ -327,7 +330,7 @@ static void xe_pagefault_queue_work(struct work_struct *w)
if (err) {
if (err == -EAGAIN) {
xe_pagefault_queue_retry(pf_queue, &pf);
- queue_work(gt_to_xe(pf.gt)->usm.pf_wq, w);
+ queue_work(xe->usm.pf_wq, w);
break;
} else if (!(pf.consumer.access_type & XE_PAGEFAULT_ACCESS_PREFETCH)) {
xe_pagefault_save_to_vm(gt_to_xe(pf.gt), &pf);
@@ -344,7 +347,7 @@ static void xe_pagefault_queue_work(struct work_struct *w)
pf.producer.ops->ack_fault(&pf, err);
if (time_after(jiffies, threshold)) {
- queue_work(gt_to_xe(pf.gt)->usm.pf_wq, w);
+ queue_work(xe->usm.pf_wq, w);
break;
}
}
@@ -389,7 +392,6 @@ static int xe_pagefault_queue_init(struct xe_device *xe,
xe_pagefault_entry_size(), total_num_eus, pf_queue->size);
spin_lock_init(&pf_queue->lock);
- INIT_WORK(&pf_queue->worker, xe_pagefault_queue_work);
pf_queue->data = drmm_kzalloc(&xe->drm, pf_queue->size, GFP_KERNEL);
if (!pf_queue->data)
@@ -422,14 +424,20 @@ int xe_pagefault_init(struct xe_device *xe)
xe->usm.pf_wq = alloc_workqueue("xe_page_fault_work_queue",
WQ_UNBOUND | WQ_HIGHPRI,
- XE_PAGEFAULT_QUEUE_COUNT);
+ XE_PAGEFAULT_WORK_COUNT);
if (!xe->usm.pf_wq)
return -ENOMEM;
- for (i = 0; i < XE_PAGEFAULT_QUEUE_COUNT; ++i) {
- err = xe_pagefault_queue_init(xe, xe->usm.pf_queue + i);
- if (err)
- goto err_out;
+ err = xe_pagefault_queue_init(xe, &xe->usm.pf_queue);
+ if (err)
+ goto err_out;
+
+ for (i = 0; i < XE_PAGEFAULT_WORK_COUNT; ++i) {
+ struct xe_pagefault_work *pf_work = xe->usm.pf_workers + i;
+
+ pf_work->xe = xe;
+ pf_work->id = i;
+ INIT_WORK(&pf_work->work, xe_pagefault_queue_work);
}
return devm_add_action_or_reset(xe->drm.dev, xe_pagefault_fini, xe);
@@ -471,10 +479,7 @@ static void xe_pagefault_queue_reset(struct xe_device *xe, struct xe_gt *gt,
*/
void xe_pagefault_reset(struct xe_device *xe, struct xe_gt *gt)
{
- int i;
-
- for (i = 0; i < XE_PAGEFAULT_QUEUE_COUNT; ++i)
- xe_pagefault_queue_reset(xe, gt, xe->usm.pf_queue + i);
+ xe_pagefault_queue_reset(xe, gt, &xe->usm.pf_queue);
}
static bool xe_pagefault_queue_full(struct xe_pagefault_queue *pf_queue)
@@ -489,13 +494,11 @@ static bool xe_pagefault_queue_full(struct xe_pagefault_queue *pf_queue)
* This function can race with multiple page fault producers, but worst case we
* stick a page fault on the same queue for consumption.
*/
-static int xe_pagefault_queue_index(struct xe_device *xe)
+static int xe_pagefault_work_index(struct xe_device *xe)
{
- u32 old_pf_queue = READ_ONCE(xe->usm.current_pf_queue);
-
- WRITE_ONCE(xe->usm.current_pf_queue, (old_pf_queue + 1));
+ lockdep_assert_held(&xe->usm.pf_queue.lock);
- return old_pf_queue % XE_PAGEFAULT_QUEUE_COUNT;
+ return xe->usm.current_pf_work++ % XE_PAGEFAULT_WORK_COUNT;
}
/**
@@ -510,22 +513,23 @@ static int xe_pagefault_queue_index(struct xe_device *xe)
*/
int xe_pagefault_handler(struct xe_device *xe, struct xe_pagefault *pf)
{
- int queue_index = xe_pagefault_queue_index(xe);
- struct xe_pagefault_queue *pf_queue = xe->usm.pf_queue + queue_index;
+ struct xe_pagefault_queue *pf_queue = &xe->usm.pf_queue;
unsigned long flags;
+ int work_index;
bool full;
spin_lock_irqsave(&pf_queue->lock, flags);
+ work_index = xe_pagefault_work_index(xe);
full = xe_pagefault_queue_full(pf_queue);
if (!full) {
memcpy(pf_queue->data + pf_queue->head, pf, sizeof(*pf));
pf_queue->head = (pf_queue->head + xe_pagefault_entry_size()) %
pf_queue->size;
- queue_work(xe->usm.pf_wq, &pf_queue->worker);
+ queue_work(xe->usm.pf_wq,
+ &xe->usm.pf_workers[work_index].work);
} else {
drm_warn(&xe->drm,
- "PageFault Queue (%d) full, shouldn't be possible\n",
- queue_index);
+ "PageFault Queue full, shouldn't be possible\n");
}
spin_unlock_irqrestore(&pf_queue->lock, flags);
diff --git a/drivers/gpu/drm/xe/xe_pagefault_types.h b/drivers/gpu/drm/xe/xe_pagefault_types.h
index c4ee625b93dd..64ab4ea8807b 100644
--- a/drivers/gpu/drm/xe/xe_pagefault_types.h
+++ b/drivers/gpu/drm/xe/xe_pagefault_types.h
@@ -131,8 +131,21 @@ struct xe_pagefault_queue {
u32 tail;
/** @lock: protects page fault queue */
spinlock_t lock;
- /** @worker: to process page faults */
- struct work_struct worker;
+};
+
+/**
+ * struct xe_pagefault_work - Xe page fault work item (consumer)
+ *
+ * Represents a worker that pops a &struct xe_pagefault from the page fault
+ * queue and processes it.
+ */
+struct xe_pagefault_work {
+ /** @xe: Back-pointer to the Xe device */
+ struct xe_device *xe;
+ /** @id: Identifier for this work item */
+ int id;
+ /** @work: Work item used to process the page fault */
+ struct work_struct work;
};
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v5 05/12] drm/xe: Add num_pf_work modparam
2026-07-23 21:47 [PATCH v5 00/12] Fine grained fault locking, threaded prefetch, storm cache Matthew Brost
` (3 preceding siblings ...)
2026-07-23 21:47 ` [PATCH v5 04/12] drm/xe: Use a single page-fault queue with multiple workers Matthew Brost
@ 2026-07-23 21:47 ` Matthew Brost
2026-07-23 21:47 ` [PATCH v5 06/12] drm/xe: Engine class and instance into a u8 Matthew Brost
` (9 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Matthew Brost @ 2026-07-23 21:47 UTC (permalink / raw)
To: intel-xe; +Cc: Maciej Patelczyk
Add a module parameter to control the number of page-fault work threads,
making it easy to experiment with how different numbers of work threads
impact performance.
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
---
drivers/gpu/drm/xe/xe_defaults.h | 1 +
drivers/gpu/drm/xe/xe_device.c | 14 ++++++++++++--
drivers/gpu/drm/xe/xe_device_types.h | 11 ++++-------
drivers/gpu/drm/xe/xe_module.c | 4 ++++
drivers/gpu/drm/xe/xe_module.h | 1 +
drivers/gpu/drm/xe/xe_pagefault.c | 6 +++---
drivers/gpu/drm/xe/xe_vm.c | 3 ++-
7 files changed, 27 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_defaults.h b/drivers/gpu/drm/xe/xe_defaults.h
index c8ae1d5f3d60..0884224ef7c7 100644
--- a/drivers/gpu/drm/xe/xe_defaults.h
+++ b/drivers/gpu/drm/xe/xe_defaults.h
@@ -22,5 +22,6 @@
#define XE_DEFAULT_WEDGED_MODE XE_WEDGED_MODE_UPON_CRITICAL_ERROR
#define XE_DEFAULT_WEDGED_MODE_STR "upon-critical-error"
#define XE_DEFAULT_SVM_NOTIFIER_SIZE 512
+#define XE_DEFAULT_NUM_PF_WORK 2
#endif
diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
index 4eed9a251e65..ff24d4a00c24 100644
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@ -513,6 +513,17 @@ struct xe_device *xe_device_create(struct pci_dev *pdev)
}
ALLOW_ERROR_INJECTION(xe_device_create, ERRNO); /* See xe_pci_probe() */
+static void xe_device_parse_modparam(struct xe_device *xe)
+{
+ xe->atomic_svm_timeslice_ms = 5;
+ xe->min_run_period_lr_ms = 5;
+ xe->info.num_pf_work = xe_modparam.num_pf_work;
+ if (xe->info.num_pf_work < 1)
+ xe->info.num_pf_work = 1;
+ else if (xe->info.num_pf_work > XE_PAGEFAULT_WORK_MAX)
+ xe->info.num_pf_work = XE_PAGEFAULT_WORK_MAX;
+}
+
/**
* xe_device_init_early() - Initialize a new &xe_device instance
* @xe: the &xe_device to initialize
@@ -539,8 +550,7 @@ int xe_device_init_early(struct xe_device *xe)
if (err)
return err;
- xe->atomic_svm_timeslice_ms = 5;
- xe->min_run_period_lr_ms = 5;
+ xe_device_parse_modparam(xe);
err = xe_irq_init(xe);
if (err)
diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
index 8d41b7e77176..6c037b205942 100644
--- a/drivers/gpu/drm/xe/xe_device_types.h
+++ b/drivers/gpu/drm/xe/xe_device_types.h
@@ -123,6 +123,8 @@ struct xe_device {
u8 revid;
/** @info.step: stepping information for each IP */
struct xe_step_info step;
+ /** @info.num_pf_work: Number of page fault work thread */
+ int num_pf_work;
/** @info.dma_mask_size: DMA address bits */
u8 dma_mask_size;
/** @info.vram_flags: Vram flags */
@@ -309,14 +311,9 @@ struct xe_device {
struct rw_semaphore lock;
/** @usm.pf_wq: page fault work queue, unbound, high priority */
struct workqueue_struct *pf_wq;
- /*
- * We pick 4 here because, in the current implementation, it
- * yields the best bandwidth utilization of the kernel paging
- * engine.
- */
-#define XE_PAGEFAULT_WORK_COUNT 4
+#define XE_PAGEFAULT_WORK_MAX 8
/** @usm.pf_workers: Page fault workers */
- struct xe_pagefault_work pf_workers[XE_PAGEFAULT_WORK_COUNT];
+ struct xe_pagefault_work pf_workers[XE_PAGEFAULT_WORK_MAX];
/** @usm.pf_queue: Page fault queue */
struct xe_pagefault_queue pf_queue;
#if IS_ENABLED(CONFIG_DRM_XE_PAGEMAP)
diff --git a/drivers/gpu/drm/xe/xe_module.c b/drivers/gpu/drm/xe/xe_module.c
index 848d65265443..3187c2b7df81 100644
--- a/drivers/gpu/drm/xe/xe_module.c
+++ b/drivers/gpu/drm/xe/xe_module.c
@@ -29,6 +29,7 @@ struct xe_modparam xe_modparam = {
.max_vfs = XE_DEFAULT_MAX_VFS,
#endif
.wedged_mode = XE_DEFAULT_WEDGED_MODE,
+ .num_pf_work = XE_DEFAULT_NUM_PF_WORK,
.svm_notifier_size = XE_DEFAULT_SVM_NOTIFIER_SIZE,
/* the rest are 0 by default */
};
@@ -81,6 +82,9 @@ MODULE_PARM_DESC(wedged_mode,
"Module's default policy for the wedged mode (0=never, 1=upon-critical-error, 2=upon-any-hang-no-reset "
"[default=" XE_DEFAULT_WEDGED_MODE_STR "])");
+module_param_named(num_pf_work, xe_modparam.num_pf_work, int, 0600);
+MODULE_PARM_DESC(num_pf_work, "Number of page fault work threads, default=2, min=1, max=8");
+
static int xe_check_nomodeset(void)
{
if (drm_firmware_drivers_only())
diff --git a/drivers/gpu/drm/xe/xe_module.h b/drivers/gpu/drm/xe/xe_module.h
index a0eb7db07770..6272d9e41207 100644
--- a/drivers/gpu/drm/xe/xe_module.h
+++ b/drivers/gpu/drm/xe/xe_module.h
@@ -23,6 +23,7 @@ struct xe_modparam {
unsigned int max_vfs;
#endif
unsigned int wedged_mode;
+ unsigned int num_pf_work;
u32 svm_notifier_size;
};
diff --git a/drivers/gpu/drm/xe/xe_pagefault.c b/drivers/gpu/drm/xe/xe_pagefault.c
index 410dc53b7df6..2322eb7369f1 100644
--- a/drivers/gpu/drm/xe/xe_pagefault.c
+++ b/drivers/gpu/drm/xe/xe_pagefault.c
@@ -424,7 +424,7 @@ int xe_pagefault_init(struct xe_device *xe)
xe->usm.pf_wq = alloc_workqueue("xe_page_fault_work_queue",
WQ_UNBOUND | WQ_HIGHPRI,
- XE_PAGEFAULT_WORK_COUNT);
+ xe->info.num_pf_work);
if (!xe->usm.pf_wq)
return -ENOMEM;
@@ -432,7 +432,7 @@ int xe_pagefault_init(struct xe_device *xe)
if (err)
goto err_out;
- for (i = 0; i < XE_PAGEFAULT_WORK_COUNT; ++i) {
+ for (i = 0; i < xe->info.num_pf_work; ++i) {
struct xe_pagefault_work *pf_work = xe->usm.pf_workers + i;
pf_work->xe = xe;
@@ -498,7 +498,7 @@ static int xe_pagefault_work_index(struct xe_device *xe)
{
lockdep_assert_held(&xe->usm.pf_queue.lock);
- return xe->usm.current_pf_work++ % XE_PAGEFAULT_WORK_COUNT;
+ return xe->usm.current_pf_work++ % xe->info.num_pf_work;
}
/**
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index 64caf8290517..286aebfcc461 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -3236,7 +3236,8 @@ static int prefetch_ranges(struct xe_vm *vm, struct xe_vma_ops *vops,
skip_threads = op->prefetch_range.ranges_count == 1 ||
(!dpagemap && !(vops->flags &
XE_VMA_OPS_FLAG_HAS_SVM_VALID_RANGE)) ||
- !(vops->flags & XE_VMA_OPS_FLAG_DOWNGRADE_LOCK);
+ !(vops->flags & XE_VMA_OPS_FLAG_DOWNGRADE_LOCK) ||
+ vm->xe->info.num_pf_work == 1;
thread = skip_threads ? &stack_thread : NULL;
if (!skip_threads) {
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v5 06/12] drm/xe: Engine class and instance into a u8
2026-07-23 21:47 [PATCH v5 00/12] Fine grained fault locking, threaded prefetch, storm cache Matthew Brost
` (4 preceding siblings ...)
2026-07-23 21:47 ` [PATCH v5 05/12] drm/xe: Add num_pf_work modparam Matthew Brost
@ 2026-07-23 21:47 ` Matthew Brost
2026-07-23 21:47 ` [PATCH v5 07/12] drm/xe: Track pagefault worker runtime Matthew Brost
` (8 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Matthew Brost @ 2026-07-23 21:47 UTC (permalink / raw)
To: intel-xe; +Cc: Maciej Patelczyk
Pack the engine class and instance fields into a single u8 to save space
in struct xe_pagefault. This also makes future extensions easier.
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
---
drivers/gpu/drm/xe/xe_guc_pagefault.c | 7 +++++--
drivers/gpu/drm/xe/xe_pagefault.c | 12 ++++++++----
drivers/gpu/drm/xe/xe_pagefault_types.h | 10 ++++++----
drivers/gpu/drm/xe/xe_vm.c | 7 +++++--
4 files changed, 24 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_guc_pagefault.c b/drivers/gpu/drm/xe/xe_guc_pagefault.c
index 607e32392f46..2470faf3d5d8 100644
--- a/drivers/gpu/drm/xe/xe_guc_pagefault.c
+++ b/drivers/gpu/drm/xe/xe_guc_pagefault.c
@@ -89,8 +89,11 @@ int xe_guc_pagefault_handler(struct xe_guc *guc, u32 *msg, u32 len)
FIELD_GET(PFD_FAULT_LEVEL, msg[0])) |
FIELD_PREP(XE_PAGEFAULT_TYPE_MASK,
FIELD_GET(PFD_FAULT_TYPE, msg[2]));
- pf.consumer.engine_class = FIELD_GET(PFD_ENG_CLASS, msg[0]);
- pf.consumer.engine_instance = FIELD_GET(PFD_ENG_INSTANCE, msg[0]);
+ pf.consumer.engine_class_instance =
+ FIELD_PREP(XE_PAGEFAULT_ENGINE_CLASS_MASK,
+ FIELD_GET(PFD_ENG_CLASS, msg[0])) |
+ FIELD_PREP(XE_PAGEFAULT_ENGINE_INSTANCE_MASK,
+ FIELD_GET(PFD_ENG_INSTANCE, msg[0]));
pf.producer.private = guc;
pf.producer.ops = &guc_pagefault_ops;
diff --git a/drivers/gpu/drm/xe/xe_pagefault.c b/drivers/gpu/drm/xe/xe_pagefault.c
index 2322eb7369f1..0ee9b7acef41 100644
--- a/drivers/gpu/drm/xe/xe_pagefault.c
+++ b/drivers/gpu/drm/xe/xe_pagefault.c
@@ -262,13 +262,16 @@ static bool xe_pagefault_queue_pop(struct xe_pagefault_queue *pf_queue,
static void xe_pagefault_print(struct xe_pagefault *pf)
{
+ u8 engine_class = FIELD_GET(XE_PAGEFAULT_ENGINE_CLASS_MASK,
+ pf->consumer.engine_class_instance);
+
xe_gt_info(pf->gt, "\n\tASID: %d\n"
"\tFaulted Address: 0x%08x%08x\n"
"\tFaultType: %lu\n"
"\tAccessType: %lu\n"
"\tFaultLevel: %lu\n"
"\tEngineClass: %d %s\n"
- "\tEngineInstance: %d\n",
+ "\tEngineInstance: %lu\n",
pf->consumer.asid,
upper_32_bits(pf->consumer.page_addr),
lower_32_bits(pf->consumer.page_addr),
@@ -278,9 +281,10 @@ static void xe_pagefault_print(struct xe_pagefault *pf)
pf->consumer.access_type),
FIELD_GET(XE_PAGEFAULT_LEVEL_MASK,
pf->consumer.fault_type_level),
- pf->consumer.engine_class,
- xe_hw_engine_class_to_str(pf->consumer.engine_class),
- pf->consumer.engine_instance);
+ engine_class,
+ xe_hw_engine_class_to_str(engine_class),
+ FIELD_GET(XE_PAGEFAULT_ENGINE_INSTANCE_MASK,
+ pf->consumer.engine_class_instance));
}
static void xe_pagefault_save_to_vm(struct xe_device *xe, struct xe_pagefault *pf)
diff --git a/drivers/gpu/drm/xe/xe_pagefault_types.h b/drivers/gpu/drm/xe/xe_pagefault_types.h
index 64ab4ea8807b..d349d79bc95e 100644
--- a/drivers/gpu/drm/xe/xe_pagefault_types.h
+++ b/drivers/gpu/drm/xe/xe_pagefault_types.h
@@ -82,10 +82,12 @@ struct xe_pagefault {
#define XE_PAGEFAULT_TYPE_LEVEL_NACK 0xff /* Producer indicates nack fault */
#define XE_PAGEFAULT_LEVEL_MASK GENMASK(3, 0)
#define XE_PAGEFAULT_TYPE_MASK GENMASK(7, 4)
- /** @consumer.engine_class: engine class */
- u8 engine_class;
- /** @consumer.engine_instance: engine instance */
- u8 engine_instance;
+ /** @consumer.engine_class_instance: engine class and instance */
+ u8 engine_class_instance;
+#define XE_PAGEFAULT_ENGINE_CLASS_MASK GENMASK(3, 0)
+#define XE_PAGEFAULT_ENGINE_INSTANCE_MASK GENMASK(7, 4)
+ /** @pad: alignment padding */
+ u8 pad;
/** @consumer.reserved: reserved bits for future expansion */
u64 reserved;
} consumer;
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index 286aebfcc461..410fb03f1ca9 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -615,10 +615,13 @@ void xe_vm_add_fault_entry_pf(struct xe_vm *vm, struct xe_pagefault *pf)
{
struct xe_vm_fault_entry *e;
struct xe_hw_engine *hwe;
+ u8 engine_class = FIELD_GET(XE_PAGEFAULT_ENGINE_CLASS_MASK,
+ pf->consumer.engine_class_instance);
+ u8 engine_instance = FIELD_GET(XE_PAGEFAULT_ENGINE_INSTANCE_MASK,
+ pf->consumer.engine_class_instance);
/* Do not report faults on reserved engines */
- hwe = xe_gt_hw_engine(pf->gt, pf->consumer.engine_class,
- pf->consumer.engine_instance, false);
+ hwe = xe_gt_hw_engine(pf->gt, engine_class, engine_instance, false);
if (!hwe || xe_hw_engine_is_reserved(hwe))
return;
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v5 07/12] drm/xe: Track pagefault worker runtime
2026-07-23 21:47 [PATCH v5 00/12] Fine grained fault locking, threaded prefetch, storm cache Matthew Brost
` (5 preceding siblings ...)
2026-07-23 21:47 ` [PATCH v5 06/12] drm/xe: Engine class and instance into a u8 Matthew Brost
@ 2026-07-23 21:47 ` Matthew Brost
2026-07-23 21:47 ` [PATCH v5 08/12] drm/xe: Chain page faults via queue-resident cache to avoid fault storms Matthew Brost
` (7 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Matthew Brost @ 2026-07-23 21:47 UTC (permalink / raw)
To: intel-xe; +Cc: Maciej Patelczyk
Add a GT stat measuring total time spent servicing pagefault workqueue
iterations. The counter accumulates the runtime of the pagefault worker
in microseconds, allowing correlation of fault storms and chaining
behavior with CPU time spent in the fault handler.
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
---
drivers/gpu/drm/xe/xe_gt_stats.c | 1 +
drivers/gpu/drm/xe/xe_gt_stats_types.h | 3 +++
drivers/gpu/drm/xe/xe_pagefault.c | 8 ++++++++
3 files changed, 12 insertions(+)
diff --git a/drivers/gpu/drm/xe/xe_gt_stats.c b/drivers/gpu/drm/xe/xe_gt_stats.c
index 789397514f3e..513fe28c0e76 100644
--- a/drivers/gpu/drm/xe/xe_gt_stats.c
+++ b/drivers/gpu/drm/xe/xe_gt_stats.c
@@ -101,6 +101,7 @@ static const char *const stat_description[__XE_GT_STATS_NUM_IDS] = {
DEF_STAT_STR(SVM_TLB_INVAL_US, "svm_tlb_inval_us"),
DEF_STAT_STR(VMA_PAGEFAULT_COUNT, "vma_pagefault_count"),
DEF_STAT_STR(VMA_PAGEFAULT_KB, "vma_pagefault_kb"),
+ DEF_STAT_STR(PAGEFAULT_US, "pagefault_us"),
DEF_STAT_STR(INVALID_PREFETCH_PAGEFAULT_COUNT, "invalid_prefetch_pagefault_count"),
DEF_STAT_STR(SVM_4K_PAGEFAULT_COUNT, "svm_4K_pagefault_count"),
DEF_STAT_STR(SVM_64K_PAGEFAULT_COUNT, "svm_64K_pagefault_count"),
diff --git a/drivers/gpu/drm/xe/xe_gt_stats_types.h b/drivers/gpu/drm/xe/xe_gt_stats_types.h
index 425491bed6c4..a7021a298e3e 100644
--- a/drivers/gpu/drm/xe/xe_gt_stats_types.h
+++ b/drivers/gpu/drm/xe/xe_gt_stats_types.h
@@ -22,6 +22,8 @@
* handled.
* @XE_GT_STATS_ID_VMA_PAGEFAULT_KB: Size (KiB) of VMAs involved in
* buffer-object page fault handling.
+ * @XE_GT_STATS_ID_PAGEFAULT_US: Cumulative time (µs) handling of all page
+ * faults.
* @XE_GT_STATS_ID_INVALID_PREFETCH_PAGEFAULT_COUNT: GPU prefetch faults for
* addresses with no valid backing.
*
@@ -133,6 +135,7 @@ enum xe_gt_stats_id {
XE_GT_STATS_ID_SVM_TLB_INVAL_US,
XE_GT_STATS_ID_VMA_PAGEFAULT_COUNT,
XE_GT_STATS_ID_VMA_PAGEFAULT_KB,
+ XE_GT_STATS_ID_PAGEFAULT_US,
XE_GT_STATS_ID_INVALID_PREFETCH_PAGEFAULT_COUNT,
XE_GT_STATS_ID_SVM_4K_PAGEFAULT_COUNT,
XE_GT_STATS_ID_SVM_64K_PAGEFAULT_COUNT,
diff --git a/drivers/gpu/drm/xe/xe_pagefault.c b/drivers/gpu/drm/xe/xe_pagefault.c
index 0ee9b7acef41..7684d986c8f7 100644
--- a/drivers/gpu/drm/xe/xe_pagefault.c
+++ b/drivers/gpu/drm/xe/xe_pagefault.c
@@ -319,6 +319,8 @@ static void xe_pagefault_queue_work(struct work_struct *w)
struct xe_device *xe = pf_work->xe;
struct xe_pagefault_queue *pf_queue = &xe->usm.pf_queue;
struct xe_pagefault pf;
+ ktime_t start = xe_gt_stats_ktime_get();
+ struct xe_gt *gt = NULL;
unsigned long threshold;
#define USM_QUEUE_MAX_RUNTIME_MS 20
@@ -330,6 +332,7 @@ static void xe_pagefault_queue_work(struct work_struct *w)
if (!pf.gt) /* Fault squashed during reset */
continue;
+ gt = pf.gt;
err = xe_pagefault_service(&pf);
if (err) {
if (err == -EAGAIN) {
@@ -356,6 +359,11 @@ static void xe_pagefault_queue_work(struct work_struct *w)
}
}
#undef USM_QUEUE_MAX_RUNTIME_MS
+
+ if (gt)
+ xe_gt_stats_incr(xe_root_mmio_gt(gt_to_xe(gt)),
+ XE_GT_STATS_ID_PAGEFAULT_US,
+ xe_gt_stats_ktime_us_delta(start));
}
static int xe_pagefault_queue_init(struct xe_device *xe,
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v5 08/12] drm/xe: Chain page faults via queue-resident cache to avoid fault storms
2026-07-23 21:47 [PATCH v5 00/12] Fine grained fault locking, threaded prefetch, storm cache Matthew Brost
` (6 preceding siblings ...)
2026-07-23 21:47 ` [PATCH v5 07/12] drm/xe: Track pagefault worker runtime Matthew Brost
@ 2026-07-23 21:47 ` Matthew Brost
2026-07-23 21:47 ` [PATCH v5 09/12] drm/xe: Add pagefault chaining stats Matthew Brost
` (6 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Matthew Brost @ 2026-07-23 21:47 UTC (permalink / raw)
To: intel-xe
Some Xe platforms can generate pagefault storms where many faults target
the same address range in a short time window (e.g. many EU threads
faulting the same page). The current worker/locking model effectively
serializes faults for a given range and repeatedly performs VMA/range
lookups for each fault, which creates head-of-queue blocking and wastes
CPU in the hot path.
Introduce a page fault chaining cache that coalesces faults targeting
the samr ASID and address range.
Each worker tracks the active fault range it is servicing. Fault entries
reside in stable queue storage, allowing the IRQ handler to match new
faults against the worker cache and directly chain cache hits onto the
active entry without allocation or waiting for dequeue. Once the leading
fault completes, the worker acknowledges the entire chain.
A small allocation state is added to each entry so queue, worker, and
IRQ pathd can safely reference the same fault object. This prevents
reuse while the fault is active and guarantees that chained faults
remain valid until acknowledged.
Fault handlers also record the serviced range so subsequent faults can
be acknowledged without re-running the full resolution path.
This removes repeated fault resolution during fault storms and
significantly improves forward progress in SVM workloads.
Assisted-by: ChatGPT:gpt-5 # Documentation
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
---
drivers/gpu/drm/xe/xe_pagefault.c | 455 ++++++++++++++++++++----
drivers/gpu/drm/xe/xe_pagefault.h | 71 ++++
drivers/gpu/drm/xe/xe_pagefault_types.h | 81 +++--
drivers/gpu/drm/xe/xe_svm.c | 16 +-
drivers/gpu/drm/xe/xe_svm.h | 9 +-
5 files changed, 534 insertions(+), 98 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_pagefault.c b/drivers/gpu/drm/xe/xe_pagefault.c
index 7684d986c8f7..34cca2e4411f 100644
--- a/drivers/gpu/drm/xe/xe_pagefault.c
+++ b/drivers/gpu/drm/xe/xe_pagefault.c
@@ -35,6 +35,70 @@
* xe_pagefault.c implements the consumer layer.
*/
+/**
+ * DOC: Xe page fault cache
+ *
+ * Some Xe hardware can trigger “fault storms,” which are many page faults to
+ * the same address within a short period of time. An example is many EU threads
+ * faulting on the same page simultaneously. With the current page fault locking
+ * structure, only one page fault for a given address range can be processed at
+ * a time. This causes head-of-queue blocking across workers, killing
+ * parallelism. If the page fault handler must repeatedly look up resources
+ * (VMAs, ranges) to determine that the pages are valid for each fault in the
+ * storm, the time complexity grows rapidly.
+ *
+ * To address this, each page fault worker maintains a cache of the active fault
+ * being processed. Subsequent faults that hit in the cache are chained to the
+ * pending fault, and all chained faults are acknowledged once the initial fault
+ * completes. This alleviates head-of-queue blocking and quickly chains faults
+ * in the upper layers, avoiding expensive lookups in the main fault-handling
+ * path.
+ *
+ * Faults are buffered in the page fault queue in a way that provides stable
+ * storage for outstanding faults. In particular, faults may be chained directly
+ * while still resident in the queue storage (i.e., outside the worker’s current
+ * head/tail dequeue position). This allows the IRQ handler to match newly
+ * arrived faults against the per-worker cache and immediately chain cache hits
+ * onto the active fault under the queue lock, without allocating memory or
+ * waiting for the worker to pop the fault first.
+ *
+ * A per-fault state field is used to assert correctness of these invariants.
+ * The state tracks whether an entry is free, queued, chained, or currently
+ * active. Transitions are performed under the page fault queue lock, and the
+ * worker acknowledges faults by walking the chain and returning entries to the
+ * free state once they are complete.
+ */
+
+/**
+ * enum xe_pagefault_alloc_state - lifetime state for a page fault queue entry
+ * @XE_PAGEFAULT_ALLOC_STATE_FREE:
+ * Entry is unused and may be overwritten by the producer, consumer retry
+ * or requeue..
+ * @XE_PAGEFAULT_ALLOC_STATE_QUEUED:
+ * Entry has been enqueued and may be dequeued by a worker.
+ * @XE_PAGEFAULT_ALLOC_STATE_ACTIVE:
+ * Entry has been dequeued and is the worker's currently serviced fault.
+ * The worker may attach additional faults to it via consumer.next.
+ * @XE_PAGEFAULT_ALLOC_STATE_CHAINED:
+ * Entry is not independently serviced; it has been chained onto an
+ * ACTIVE entry via consumer.next and will be acknowledged when the
+ * leading fault completes.
+ *
+ * The page fault queue provides stable storage for outstanding faults so the
+ * IRQ handler can chain new cache hits directly onto a worker's active fault.
+ * Because entries may remain referenced outside the consumer dequeue window,
+ * the producer must only write into entries in the FREE state.
+ *
+ * State transitions are protected by the page fault queue lock. Workers return
+ * entries to FREE after acknowledging the fault (either as ACTIVE or CHAINED).
+ */
+enum xe_pagefault_alloc_state {
+ XE_PAGEFAULT_ALLOC_STATE_FREE = 0,
+ XE_PAGEFAULT_ALLOC_STATE_QUEUED = 1,
+ XE_PAGEFAULT_ALLOC_STATE_CHAINED = 2,
+ XE_PAGEFAULT_ALLOC_STATE_ACTIVE = 3,
+};
+
static int xe_pagefault_entry_size(void)
{
/*
@@ -77,7 +141,7 @@ static int xe_pagefault_begin(struct drm_exec *exec, struct xe_vma *vma,
}
static int xe_pagefault_handle_vma(struct xe_gt *gt, struct xe_vma *vma,
- bool atomic)
+ struct xe_pagefault *pf, bool atomic)
{
struct xe_vm *vm = xe_vma_vm(vma);
struct xe_tile *tile = gt_to_tile(gt);
@@ -102,8 +166,11 @@ static int xe_pagefault_handle_vma(struct xe_gt *gt, struct xe_vma *vma,
/* Check if VMA is valid, opportunistic check only */
if (xe_vm_has_valid_gpu_mapping(tile, vma->tile_present,
- vma->tile_invalidated) && !atomic)
+ vma->tile_invalidated) && !atomic) {
+ xe_pagefault_set_start_addr(pf, xe_vma_start(vma));
+ xe_pagefault_set_end_addr(pf, xe_vma_end(vma));
return 0;
+ }
do {
if (xe_vma_is_userptr(vma) &&
@@ -141,6 +208,10 @@ static int xe_pagefault_handle_vma(struct xe_gt *gt, struct xe_vma *vma,
} while (err == -EAGAIN);
if (!err) {
+ /* Give hint to immediately ack faults */
+ xe_pagefault_set_start_addr(pf, xe_vma_start(vma));
+ xe_pagefault_set_end_addr(pf, xe_vma_end(vma));
+
dma_fence_wait(fence, false);
dma_fence_put(fence);
}
@@ -218,10 +289,10 @@ static int xe_pagefault_service(struct xe_pagefault *pf)
atomic = xe_pagefault_access_is_atomic(pf->consumer.access_type);
if (xe_vma_is_cpu_addr_mirror(vma))
- err = xe_svm_handle_pagefault(vm, vma, gt,
+ err = xe_svm_handle_pagefault(vm, vma, pf, gt,
pf->consumer.page_addr, atomic);
else
- err = xe_pagefault_handle_vma(gt, vma, atomic);
+ err = xe_pagefault_handle_vma(gt, vma, pf, atomic);
unlock_vm:
up_read(&vm->lock);
@@ -231,33 +302,236 @@ static int xe_pagefault_service(struct xe_pagefault *pf)
return err;
}
+#define XE_PAGEFAULT_CACHE_START_INVALID U64_MAX
+#define xe_pagefault_cache_start_invalidate(val) \
+ (val = XE_PAGEFAULT_CACHE_START_INVALID)
+
+static void
+xe_pagefault_cache_invalidate(struct xe_pagefault_queue *pf_queue,
+ struct xe_pagefault_work *pf_work)
+{
+ lockdep_assert_held(&pf_queue->lock);
+
+ xe_pagefault_cache_start_invalidate(pf_work->cache.start);
+}
+
+static bool xe_pagefault_queue_full(struct xe_pagefault_queue *pf_queue)
+{
+ lockdep_assert_held(&pf_queue->lock);
+
+ return CIRC_SPACE(pf_queue->head, pf_queue->tail,
+ pf_queue->size) <= xe_pagefault_entry_size();
+}
+
+static struct xe_pagefault *
+xe_pagefault_queue_add(struct xe_pagefault_queue *pf_queue,
+ struct xe_pagefault *pf)
+{
+ struct xe_device *xe = container_of(pf_queue, typeof(*xe),
+ usm.pf_queue);
+ struct xe_pagefault *lpf;
+
+ lockdep_assert_held(&pf_queue->lock);
+
+ do {
+ /* Not possible, warn on and drop page fault */
+ if (WARN_ON(xe_pagefault_queue_full(pf_queue)))
+ return NULL;
+
+ lpf = (pf_queue->data + pf_queue->head);
+ pf_queue->head = (pf_queue->head + xe_pagefault_entry_size()) %
+ pf_queue->size;
+ } while (lpf->consumer.alloc_state != XE_PAGEFAULT_ALLOC_STATE_FREE);
+
+ memcpy(lpf, pf, sizeof(*pf));
+ lpf->consumer.alloc_state = XE_PAGEFAULT_ALLOC_STATE_QUEUED;
+
+ return lpf;
+}
+
static void xe_pagefault_queue_retry(struct xe_pagefault_queue *pf_queue,
- struct xe_pagefault *pf)
+ struct xe_pagefault *pf,
+ struct xe_pagefault_work *pf_work)
{
- spin_lock_irq(&pf_queue->lock);
- if (!pf_queue->tail)
- pf_queue->tail = pf_queue->size - xe_pagefault_entry_size();
- else
- pf_queue->tail -= xe_pagefault_entry_size();
- memcpy(pf_queue->data + pf_queue->tail, pf, sizeof(*pf));
- spin_unlock_irq(&pf_queue->lock);
+ struct xe_device *xe = container_of(pf_queue, typeof(*xe),
+ usm.pf_queue);
+
+ xe_assert(xe, pf->consumer.alloc_state ==
+ XE_PAGEFAULT_ALLOC_STATE_ACTIVE);
+
+ guard(spinlock_irq)(&pf_queue->lock);
+ pf->consumer.alloc_state = XE_PAGEFAULT_ALLOC_STATE_FREE;
+ xe_pagefault_queue_add(pf_queue, pf);
+ xe_pagefault_cache_invalidate(pf_queue, pf_work);
}
-static bool xe_pagefault_queue_pop(struct xe_pagefault_queue *pf_queue,
+static struct xe_pagefault *
+xe_pagefault_queue_unchain_requeue(struct xe_pagefault_queue *pf_queue,
+ struct xe_pagefault *pf, struct xe_gt *gt)
+{
+ struct xe_device *xe = container_of(pf_queue, typeof(*xe),
+ usm.pf_queue);
+ struct xe_pagefault *next = pf->consumer.next, *lpf;
+
+ lockdep_assert_held(&pf_queue->lock);
+ xe_assert(xe, pf->consumer.alloc_state ==
+ XE_PAGEFAULT_ALLOC_STATE_CHAINED);
+
+ pf->consumer.alloc_state = XE_PAGEFAULT_ALLOC_STATE_FREE;
+ lpf = xe_pagefault_queue_add(pf_queue, pf);
+ if (lpf) {
+ lpf->consumer.next = NULL;
+ lpf->consumer.fault_type_level |= XE_PAGEFAULT_REQUEUE_MASK;
+ }
+
+ return next;
+}
+
+static bool xe_pagefault_match(struct xe_pagefault *pf, u64 start,
+ u64 end, u64 cache_asid)
+{
+ struct xe_device *xe = gt_to_xe(pf->gt);
+ u64 page_addr = pf->consumer.page_addr;
+ u32 pf_asid = pf->consumer.asid;
+
+ xe_assert(xe, pf->consumer.alloc_state !=
+ XE_PAGEFAULT_ALLOC_STATE_FREE);
+
+ return page_addr >= start && page_addr < end &&
+ pf_asid == cache_asid;
+}
+
+static bool xe_pagefault_try_chain(struct xe_pagefault_queue *pf_queue,
struct xe_pagefault *pf)
{
- bool found_fault = false;
+ struct xe_device *xe = container_of(pf_queue, typeof(*xe),
+ usm.pf_queue);
+ struct xe_pagefault_work *pf_work;
+ bool requeue = FIELD_GET(XE_PAGEFAULT_REQUEUE_MASK,
+ pf->consumer.fault_type_level);
+ int i;
- spin_lock_irq(&pf_queue->lock);
- if (pf_queue->tail != pf_queue->head) {
- memcpy(pf, pf_queue->data + pf_queue->tail, sizeof(*pf));
- pf_queue->tail = (pf_queue->tail + xe_pagefault_entry_size()) %
- pf_queue->size;
- found_fault = true;
+ lockdep_assert_held(&pf_queue->lock);
+ xe_assert(xe, pf->consumer.alloc_state ==
+ XE_PAGEFAULT_ALLOC_STATE_QUEUED);
+
+ /*
+ * If this is a retry, we may already have a chain attached. In that
+ * case, we cannot hit in the cache because chains cannot easily be
+ * combined.
+ */
+ if (pf->consumer.next)
+ return false;
+
+ for (i = 0, pf_work = xe->usm.pf_workers;
+ i < xe->info.num_pf_work; ++i, ++pf_work) {
+ u64 start = pf_work->cache.start;
+ u64 end = requeue ? start + SZ_4K : pf_work->cache.end;
+ u32 asid = pf_work->cache.asid;
+
+ if (xe_pagefault_match(pf, start, end, asid)) {
+ xe_assert(xe, pf_work->cache.pf->consumer.alloc_state ==
+ XE_PAGEFAULT_ALLOC_STATE_ACTIVE);
+
+ pf->consumer.alloc_state =
+ XE_PAGEFAULT_ALLOC_STATE_CHAINED;
+ pf->consumer.next = pf_work->cache.pf->consumer.next;
+ pf_work->cache.pf->consumer.next = pf;
+
+ return true;
+ }
}
- spin_unlock_irq(&pf_queue->lock);
- return found_fault;
+ return false;
+}
+
+static void xe_pagefault_queue_advance(struct xe_pagefault_queue *pf_queue)
+{
+ lockdep_assert_held(&pf_queue->lock);
+
+ pf_queue->tail = (pf_queue->tail + xe_pagefault_entry_size()) %
+ pf_queue->size;
+}
+
+static struct xe_pagefault *
+xe_pagefault_queue_tail_fault(struct xe_pagefault_queue *pf_queue)
+{
+ lockdep_assert_held(&pf_queue->lock);
+
+ return pf_queue->data + pf_queue->tail;
+}
+
+static bool xe_pagefault_queue_empty(struct xe_pagefault_queue *pf_queue)
+{
+ lockdep_assert_held(&pf_queue->lock);
+
+ return pf_queue->head == pf_queue->tail;
+}
+
+static bool xe_pagefault_queue_pop(struct xe_pagefault_queue *pf_queue,
+ struct xe_pagefault **pf, int id)
+{
+ struct xe_device *xe = container_of(pf_queue, typeof(*xe),
+ usm.pf_queue);
+ struct xe_pagefault_work *pf_work;
+ struct xe_pagefault *lpf;
+ size_t align = SZ_2M;
+
+ guard(spinlock_irq)(&pf_queue->lock);
+
+ for (*pf = NULL; !*pf;) {
+ if (xe_pagefault_queue_empty(pf_queue))
+ return false;
+
+ lpf = xe_pagefault_queue_tail_fault(pf_queue);
+ xe_pagefault_queue_advance(pf_queue);
+
+ if (lpf->consumer.alloc_state !=
+ XE_PAGEFAULT_ALLOC_STATE_QUEUED)
+ continue;
+
+ if (xe_pagefault_try_chain(pf_queue, lpf))
+ continue;
+
+ *pf = lpf; /* Hand back page fault for processing */
+ }
+
+ /*
+ * No cache hit; allocate a new cache entry. We assume most faults
+ * within a 2M range will hit the same pages. If this assumption proves
+ * false, the mismatched fault is requeued after the initial fault is
+ * acknowledged.
+ */
+ pf_work = xe->usm.pf_workers + id;
+ if (FIELD_GET(XE_PAGEFAULT_REQUEUE_MASK,
+ lpf->consumer.fault_type_level))
+ align = SZ_4K;
+ pf_work->cache.start = ALIGN_DOWN(lpf->consumer.page_addr, align);
+ pf_work->cache.end = pf_work->cache.start + align;
+ pf_work->cache.asid = lpf->consumer.asid;
+ pf_work->cache.pf = lpf;
+ lpf->consumer.alloc_state = XE_PAGEFAULT_ALLOC_STATE_ACTIVE;
+
+ /* Drain queue until empty or new fault found */
+ while (1) {
+ if (xe_pagefault_queue_empty(pf_queue))
+ break;
+
+ lpf = xe_pagefault_queue_tail_fault(pf_queue);
+
+ if (lpf->consumer.alloc_state !=
+ XE_PAGEFAULT_ALLOC_STATE_QUEUED) {
+ xe_pagefault_queue_advance(pf_queue);
+ continue;
+ }
+
+ if (!xe_pagefault_try_chain(pf_queue, lpf))
+ break;
+
+ xe_pagefault_queue_advance(pf_queue);
+ }
+
+ return true;
}
static void xe_pagefault_print(struct xe_pagefault *pf)
@@ -318,40 +592,82 @@ static void xe_pagefault_queue_work(struct work_struct *w)
container_of(w, typeof(*pf_work), work);
struct xe_device *xe = pf_work->xe;
struct xe_pagefault_queue *pf_queue = &xe->usm.pf_queue;
- struct xe_pagefault pf;
+ struct xe_pagefault *pf;
ktime_t start = xe_gt_stats_ktime_get();
- struct xe_gt *gt = NULL;
unsigned long threshold;
+ u64 cache_start = XE_PAGEFAULT_CACHE_START_INVALID, cache_end = 0;
+ u32 cache_asid = 0;
#define USM_QUEUE_MAX_RUNTIME_MS 20
threshold = jiffies + msecs_to_jiffies(USM_QUEUE_MAX_RUNTIME_MS);
- while (xe_pagefault_queue_pop(pf_queue, &pf)) {
- int err;
+ while (xe_pagefault_queue_pop(pf_queue, &pf, pf_work->id)) {
+ struct xe_gt *gt = pf->gt;
+ u32 asid = pf->consumer.asid;
+ int err = 0;
- if (!pf.gt) /* Fault squashed during reset */
- continue;
+ /* Last fault same address, ack immediately */
+ if (xe_pagefault_match(pf, cache_start, cache_end, cache_asid))
+ goto ack_fault;
- gt = pf.gt;
- err = xe_pagefault_service(&pf);
- if (err) {
- if (err == -EAGAIN) {
- xe_pagefault_queue_retry(pf_queue, &pf);
- queue_work(xe->usm.pf_wq, w);
- break;
- } else if (!(pf.consumer.access_type & XE_PAGEFAULT_ACCESS_PREFETCH)) {
- xe_pagefault_save_to_vm(gt_to_xe(pf.gt), &pf);
- xe_pagefault_print(&pf);
- xe_gt_info(pf.gt, "Fault response: Unsuccessful %pe\n",
+ err = xe_pagefault_service(pf);
+
+ if (err == -EAGAIN) {
+ xe_pagefault_queue_retry(pf_queue, pf, pf_work);
+ queue_work(xe->usm.pf_wq, w);
+ break;
+ } else if (err) {
+ if (!(pf->consumer.access_type & XE_PAGEFAULT_ACCESS_PREFETCH)) {
+ xe_pagefault_save_to_vm(gt_to_xe(gt), pf);
+ xe_pagefault_cache_start_invalidate(cache_start);
+ xe_pagefault_print(pf);
+ xe_gt_info(pf->gt, "Fault response: Unsuccessful %pe\n",
ERR_PTR(err));
} else {
- xe_gt_stats_incr(pf.gt, XE_GT_STATS_ID_INVALID_PREFETCH_PAGEFAULT_COUNT, 1);
- xe_gt_dbg(pf.gt, "Prefetch Fault response: Unsuccessful %pe\n",
+ xe_gt_stats_incr(pf->gt, XE_GT_STATS_ID_INVALID_PREFETCH_PAGEFAULT_COUNT, 1);
+ xe_gt_dbg(pf->gt, "Prefetch Fault response: Unsuccessful %pe\n",
ERR_PTR(err));
}
+ } else {
+ /* Cache valid fault locally */
+ cache_start = xe_pagefault_start_addr(pf);
+ cache_end = xe_pagefault_end_addr(pf);
+ cache_asid = asid;
}
- pf.producer.ops->ack_fault(&pf, err);
+ack_fault:
+ xe_assert(xe, pf->consumer.alloc_state ==
+ XE_PAGEFAULT_ALLOC_STATE_ACTIVE);
+ xe_assert(xe, pf == pf_work->cache.pf);
+
+ while (pf) {
+ xe_assert(xe, pf->consumer.alloc_state ==
+ XE_PAGEFAULT_ALLOC_STATE_CHAINED ||
+ pf->consumer.alloc_state ==
+ XE_PAGEFAULT_ALLOC_STATE_ACTIVE);
+
+ pf->producer.ops->ack_fault(pf, err);
+
+ spin_lock_irq(&pf_queue->lock);
+
+ if (pf->consumer.alloc_state ==
+ XE_PAGEFAULT_ALLOC_STATE_ACTIVE)
+ xe_pagefault_cache_invalidate(pf_queue,
+ pf_work);
+
+ pf->consumer.alloc_state = XE_PAGEFAULT_ALLOC_STATE_FREE;
+ pf = pf->consumer.next;
+
+ /*
+ * Requeue chained faults which do not match the last
+ * fault processed
+ */
+ while (pf && !xe_pagefault_match(pf, cache_start,
+ cache_end, cache_asid))
+ pf = xe_pagefault_queue_unchain_requeue(pf_queue, pf, gt);
+
+ spin_unlock_irq(&pf_queue->lock);
+ }
if (time_after(jiffies, threshold)) {
queue_work(xe->usm.pf_wq, w);
@@ -360,10 +676,8 @@ static void xe_pagefault_queue_work(struct work_struct *w)
}
#undef USM_QUEUE_MAX_RUNTIME_MS
- if (gt)
- xe_gt_stats_incr(xe_root_mmio_gt(gt_to_xe(gt)),
- XE_GT_STATS_ID_PAGEFAULT_US,
- xe_gt_stats_ktime_us_delta(start));
+ xe_gt_stats_incr(xe_root_mmio_gt(xe), XE_GT_STATS_ID_PAGEFAULT_US,
+ xe_gt_stats_ktime_us_delta(start));
}
static int xe_pagefault_queue_init(struct xe_device *xe,
@@ -449,6 +763,7 @@ int xe_pagefault_init(struct xe_device *xe)
pf_work->xe = xe;
pf_work->id = i;
+ xe_pagefault_cache_start_invalidate(pf_work->cache.start);
INIT_WORK(&pf_work->work, xe_pagefault_queue_work);
}
@@ -470,15 +785,19 @@ static void xe_pagefault_queue_reset(struct xe_device *xe, struct xe_gt *gt,
/* Squash all pending faults on the GT */
- spin_lock_irq(&pf_queue->lock);
- for (i = pf_queue->tail; i != pf_queue->head;
- i = (i + xe_pagefault_entry_size()) % pf_queue->size) {
+ guard(spinlock_irq)(&pf_queue->lock);
+
+ for (i = 0; i < pf_queue->size; i += xe_pagefault_entry_size()) {
struct xe_pagefault *pf = pf_queue->data + i;
- if (pf->gt == gt)
- pf->gt = NULL;
+ if (pf->gt != gt || pf->consumer.alloc_state !=
+ XE_PAGEFAULT_ALLOC_STATE_QUEUED)
+ continue;
+
+ pf->consumer.alloc_state =
+ XE_PAGEFAULT_ALLOC_STATE_FREE;
+ pf->consumer.next = NULL;
}
- spin_unlock_irq(&pf_queue->lock);
}
/**
@@ -494,14 +813,6 @@ void xe_pagefault_reset(struct xe_device *xe, struct xe_gt *gt)
xe_pagefault_queue_reset(xe, gt, &xe->usm.pf_queue);
}
-static bool xe_pagefault_queue_full(struct xe_pagefault_queue *pf_queue)
-{
- lockdep_assert_held(&pf_queue->lock);
-
- return CIRC_SPACE(pf_queue->head, pf_queue->tail, pf_queue->size) <=
- xe_pagefault_entry_size();
-}
-
/*
* This function can race with multiple page fault producers, but worst case we
* stick a page fault on the same queue for consumption.
@@ -527,18 +838,28 @@ int xe_pagefault_handler(struct xe_device *xe, struct xe_pagefault *pf)
{
struct xe_pagefault_queue *pf_queue = &xe->usm.pf_queue;
unsigned long flags;
- int work_index;
bool full;
spin_lock_irqsave(&pf_queue->lock, flags);
- work_index = xe_pagefault_work_index(xe);
full = xe_pagefault_queue_full(pf_queue);
if (!full) {
- memcpy(pf_queue->data + pf_queue->head, pf, sizeof(*pf));
- pf_queue->head = (pf_queue->head + xe_pagefault_entry_size()) %
- pf_queue->size;
- queue_work(xe->usm.pf_wq,
- &xe->usm.pf_workers[work_index].work);
+ struct xe_pagefault *lpf;
+ bool empty = xe_pagefault_queue_empty(pf_queue);
+
+ lpf = xe_pagefault_queue_add(pf_queue, pf);
+ if (lpf) {
+ lpf->consumer.next = NULL;
+
+ if (xe_pagefault_try_chain(pf_queue, lpf)) {
+ if (empty)
+ xe_pagefault_queue_advance(pf_queue);
+ } else {
+ int work_index = xe_pagefault_work_index(xe);
+
+ queue_work(xe->usm.pf_wq,
+ &xe->usm.pf_workers[work_index].work);
+ }
+ }
} else {
drm_warn(&xe->drm,
"PageFault Queue full, shouldn't be possible\n");
diff --git a/drivers/gpu/drm/xe/xe_pagefault.h b/drivers/gpu/drm/xe/xe_pagefault.h
index bd0cdf9ed37f..feaf2a69674a 100644
--- a/drivers/gpu/drm/xe/xe_pagefault.h
+++ b/drivers/gpu/drm/xe/xe_pagefault.h
@@ -6,6 +6,8 @@
#ifndef _XE_PAGEFAULT_H_
#define _XE_PAGEFAULT_H_
+#include "xe_pagefault_types.h"
+
struct xe_device;
struct xe_gt;
struct xe_pagefault;
@@ -16,4 +18,73 @@ void xe_pagefault_reset(struct xe_device *xe, struct xe_gt *gt);
int xe_pagefault_handler(struct xe_device *xe, struct xe_pagefault *pf);
+#define XE_PAGEFAULT_END_ADDR_MASK (~0xfffull)
+
+/**
+ * xe_pagefault_set_end_addr() - store serviced range end for a pagefault
+ * @pf: Pagefault entry
+ * @end_addr: Inclusive end address of the serviced fault range
+ *
+ * The pagefault consumer stores the resolved fault range so subsequent faults
+ * hitting the same range can be immediately acknowledged without re-running
+ * the full fault handling path.
+ *
+ * The end address shares storage with other consumer metadata and therefore
+ * must be masked with %XE_PAGEFAULT_END_ADDR_MASK before storing. Bits outside
+ * the mask are reserved for internal state tracking and must be preserved.
+ */
+static inline void
+xe_pagefault_set_end_addr(struct xe_pagefault *pf, u64 end_addr)
+{
+ pf->consumer.end_addr &= ~XE_PAGEFAULT_END_ADDR_MASK;
+ pf->consumer.end_addr |= end_addr;
+}
+
+/**
+ * xe_pagefault_end_addr() - read serviced range end for a pagefault
+ * @pf: Pagefault entry
+ *
+ * Returns the inclusive end address of the range previously recorded by
+ * xe_pagefault_set_end_addr(). Only the bits covered by
+ * %XE_PAGEFAULT_END_ADDR_MASK are returned; other bits in the storage are
+ * reserved for internal state.
+ *
+ * Return: End address of the serviced fault range.
+ */
+static inline u64 xe_pagefault_end_addr(struct xe_pagefault *pf)
+{
+ return pf->consumer.end_addr & XE_PAGEFAULT_END_ADDR_MASK;
+}
+
+#undef XE_PAGEFAULT_END_ADDR_MASK
+
+/**
+ * xe_pagefault_set_start_addr() - store serviced range start for a pagefault
+ * @pf: Pagefault entry
+ * @start_addr: Start address of the serviced fault range
+ *
+ * The pagefault consumer stores the resolved fault range so subsequent faults
+ * hitting the same range can be immediately acknowledged without re-running
+ * the full fault handling path.
+ */
+static inline void
+xe_pagefault_set_start_addr(struct xe_pagefault *pf, u64 start_addr)
+{
+ pf->consumer.page_addr = start_addr;
+}
+
+/**
+ * xe_pagefault_start_addr() - read serviced range start for a pagefault
+ * @pf: Pagefault entry
+ *
+ * Returns the inclusive start address of the range previously recorded by
+ * xe_pagefault_set_start_addr().
+ *
+ * Return: Start address of the serviced fault range.
+ */
+static inline u64 xe_pagefault_start_addr(struct xe_pagefault *pf)
+{
+ return pf->consumer.page_addr;
+}
+
#endif
diff --git a/drivers/gpu/drm/xe/xe_pagefault_types.h b/drivers/gpu/drm/xe/xe_pagefault_types.h
index d349d79bc95e..a1fff0e47fa5 100644
--- a/drivers/gpu/drm/xe/xe_pagefault_types.h
+++ b/drivers/gpu/drm/xe/xe_pagefault_types.h
@@ -60,36 +60,58 @@ struct xe_pagefault {
/**
* @consumer: State for the software handling the fault. Populated by
* the producer and may be modified by the consumer to communicate
- * information back to the producer upon fault acknowledgment.
+ * information back to the producer upon fault acknowledgment. After
+ * fault acknowledgment, the producer should only access consumer fields
+ * via well defined helpers.
*/
struct {
- /** @consumer.page_addr: address of page fault */
- u64 page_addr;
- /** @consumer.asid: address space ID */
- u32 asid;
/**
- * @consumer.access_type: access type and prefetch flag packed
- * into a u8.
+ * @consumer.page_addr: address of page fault, populated by
+ * consumer after fault completion
*/
- u8 access_type;
+ u64 page_addr;
+ union {
+ struct {
+ /**
+ * @consumer.alloc_state: page fault allocation
+ * state
+ */
+ u8 alloc_state;
+ /**
+ * @consumer.access_type: access type, u8 rather
+ * than enum to keep size compact
+ */
+ u8 access_type;
#define XE_PAGEFAULT_ACCESS_TYPE_MASK GENMASK(1, 0)
#define XE_PAGEFAULT_ACCESS_PREFETCH BIT(7)
- /**
- * @consumer.fault_type_level: fault type and level, u8 rather
- * than enum to keep size compact
- */
- u8 fault_type_level;
+ /**
+ * @consumer.fault_type_level: fault type and
+ * level, u8 rather than enum to keep size
+ * compact
+ */
+ u8 fault_type_level;
#define XE_PAGEFAULT_TYPE_LEVEL_NACK 0xff /* Producer indicates nack fault */
-#define XE_PAGEFAULT_LEVEL_MASK GENMASK(3, 0)
-#define XE_PAGEFAULT_TYPE_MASK GENMASK(7, 4)
- /** @consumer.engine_class_instance: engine class and instance */
- u8 engine_class_instance;
+#define XE_PAGEFAULT_LEVEL_MASK GENMASK(2, 0)
+#define XE_PAGEFAULT_TYPE_MASK GENMASK(6, 3)
+#define XE_PAGEFAULT_REQUEUE_MASK BIT(7)
+ /** @consumer.engine_class_instance: engine class and instance */
+ u8 engine_class_instance;
#define XE_PAGEFAULT_ENGINE_CLASS_MASK GENMASK(3, 0)
#define XE_PAGEFAULT_ENGINE_INSTANCE_MASK GENMASK(7, 4)
- /** @pad: alignment padding */
- u8 pad;
- /** @consumer.reserved: reserved bits for future expansion */
- u64 reserved;
+ /** @consumer.asid: address space ID */
+ u32 asid;
+ };
+ /**
+ * @consumer.end_addr: end address of page fault,
+ * populated by consumer after fault completion
+ */
+ u64 end_addr;
+ };
+ /**
+ * @consumer.next: next pagefault chained to this fault,
+ * protected by pf_queue lock
+ */
+ struct xe_pagefault *next;
} consumer;
/**
* @producer: State for the producer (i.e., HW/FW interface). Populated
@@ -131,7 +153,7 @@ struct xe_pagefault_queue {
u32 head;
/** @tail: Tail pointer in bytes, moved by consumer, protected by @lock */
u32 tail;
- /** @lock: protects page fault queue */
+ /** @lock: protects page fault queue, workers caches */
spinlock_t lock;
};
@@ -146,6 +168,21 @@ struct xe_pagefault_work {
struct xe_device *xe;
/** @id: Identifier for this work item */
int id;
+ /**
+ * @cache: Page fault cache for the currently processed fault
+ *
+ * Protected by the page fault queue lock.
+ */
+ struct {
+ /** @cache.start: Start address of the current page fault */
+ u64 start;
+ /** @cache.end: End address of the current page fault */
+ u64 end;
+ /** @cache.asid: Address space ID of the current page fault */
+ u32 asid;
+ /** @cache.pf: Pointer to the current page fault */
+ struct xe_pagefault *pf;
+ } cache;
/** @work: Work item used to process the page fault */
struct work_struct work;
};
diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c
index 705363bf3339..66576139fe05 100644
--- a/drivers/gpu/drm/xe/xe_svm.c
+++ b/drivers/gpu/drm/xe/xe_svm.c
@@ -15,6 +15,7 @@
#include "xe_gt_stats.h"
#include "xe_migrate.h"
#include "xe_module.h"
+#include "xe_pagefault.h"
#include "xe_pm.h"
#include "xe_pt.h"
#include "xe_svm.h"
@@ -1265,8 +1266,8 @@ DECL_SVM_RANGE_US_STATS(bind, BIND)
DECL_SVM_RANGE_US_STATS(fault, PAGEFAULT)
static int __xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
- struct xe_gt *gt, u64 fault_addr,
- bool need_vram)
+ struct xe_pagefault *pf, struct xe_gt *gt,
+ u64 fault_addr, bool need_vram)
{
int devmem_possible = IS_DGFX(vm->xe) &&
IS_ENABLED(CONFIG_DRM_XE_PAGEMAP);
@@ -1423,6 +1424,10 @@ static int __xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
xe_svm_range_bind_us_stats_incr(gt, range, bind_start);
out:
+ /* Give hint to immediately ack faults */
+ xe_pagefault_set_start_addr(pf, xe_svm_range_start(range));
+ xe_pagefault_set_end_addr(pf, xe_svm_range_end(range));
+
xe_svm_range_fault_us_stats_incr(gt, range, start);
mutex_unlock(&range->lock);
drm_gpusvm_range_put(&range->base);
@@ -1445,6 +1450,7 @@ static int __xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
* xe_svm_handle_pagefault() - SVM handle page fault
* @vm: The VM.
* @vma: The CPU address mirror VMA.
+ * @pf: Pagefault structure
* @gt: The gt upon the fault occurred.
* @fault_addr: The GPU fault address.
* @atomic: The fault atomic access bit.
@@ -1455,8 +1461,8 @@ static int __xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
* Return: 0 on success, negative error code on error.
*/
int xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
- struct xe_gt *gt, u64 fault_addr,
- bool atomic)
+ struct xe_pagefault *pf, struct xe_gt *gt,
+ u64 fault_addr, bool atomic)
{
int need_vram, ret;
retry:
@@ -1464,7 +1470,7 @@ int xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
if (need_vram < 0)
return need_vram;
- ret = __xe_svm_handle_pagefault(vm, vma, gt, fault_addr,
+ ret = __xe_svm_handle_pagefault(vm, vma, pf, gt, fault_addr,
need_vram ? true : false);
if (ret == -EAGAIN) {
/*
diff --git a/drivers/gpu/drm/xe/xe_svm.h b/drivers/gpu/drm/xe/xe_svm.h
index 46be2e5c6f7f..2a0dc0d125c9 100644
--- a/drivers/gpu/drm/xe/xe_svm.h
+++ b/drivers/gpu/drm/xe/xe_svm.h
@@ -21,6 +21,7 @@ struct drm_file;
struct xe_bo;
struct xe_gt;
struct xe_device;
+struct xe_pagefault;
struct xe_vram_region;
struct xe_tile;
struct xe_vm;
@@ -109,8 +110,8 @@ void xe_svm_fini(struct xe_vm *vm);
void xe_svm_close(struct xe_vm *vm);
int xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
- struct xe_gt *gt, u64 fault_addr,
- bool atomic);
+ struct xe_pagefault *pf, struct xe_gt *gt,
+ u64 fault_addr, bool atomic);
bool xe_svm_has_mapping(struct xe_vm *vm, u64 start, u64 end);
@@ -298,8 +299,8 @@ void xe_svm_close(struct xe_vm *vm)
static inline
int xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
- struct xe_gt *gt, u64 fault_addr,
- bool atomic)
+ struct xe_pagefault *pf, struct xe_gt *gt,
+ u64 fault_addr, bool atomic)
{
return 0;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v5 09/12] drm/xe: Add pagefault chaining stats
2026-07-23 21:47 [PATCH v5 00/12] Fine grained fault locking, threaded prefetch, storm cache Matthew Brost
` (7 preceding siblings ...)
2026-07-23 21:47 ` [PATCH v5 08/12] drm/xe: Chain page faults via queue-resident cache to avoid fault storms Matthew Brost
@ 2026-07-23 21:47 ` Matthew Brost
2026-07-23 21:47 ` [PATCH v5 10/12] drm/xe: Add debugfs pagefault_info Matthew Brost
` (5 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Matthew Brost @ 2026-07-23 21:47 UTC (permalink / raw)
To: intel-xe; +Cc: Maciej Patelczyk
Add GT stats to quantify pagefault chaining behavior during fault storms.
Track total chained faults, faults chained directly from the IRQ
handler, cases where IRQ chaining also drained the queue, chained faults
that had to be requeued due to range mismatch, and cases where the last
serviced range allowed immediate ack.
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
---
drivers/gpu/drm/xe/xe_gt_stats.c | 5 +++++
drivers/gpu/drm/xe/xe_gt_stats_types.h | 16 ++++++++++++++++
drivers/gpu/drm/xe/xe_pagefault.c | 19 +++++++++++++++++--
3 files changed, 38 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_gt_stats.c b/drivers/gpu/drm/xe/xe_gt_stats.c
index 513fe28c0e76..f2e77df0f224 100644
--- a/drivers/gpu/drm/xe/xe_gt_stats.c
+++ b/drivers/gpu/drm/xe/xe_gt_stats.c
@@ -95,6 +95,11 @@ void xe_gt_stats_incr(struct xe_gt *gt, const enum xe_gt_stats_id id, int incr)
#define DEF_STAT_STR(ID, name) [XE_GT_STATS_ID_##ID] = name
static const char *const stat_description[__XE_GT_STATS_NUM_IDS] = {
+ DEF_STAT_STR(CHAIN_PAGEFAULT_COUNT, "chain_pagefault_count"),
+ DEF_STAT_STR(CHAIN_IRQ_PAGEFAULT_COUNT, "chain_irq_pagefault_count"),
+ DEF_STAT_STR(CHAIN_DRAIN_IRQ_PAGEFAULT_COUNT, "chain_drain_irq_pagefault_count"),
+ DEF_STAT_STR(CHAIN_MISMATCH_PAGEFAULT_COUNT, "chain_mismatch_pagefault_count"),
+ DEF_STAT_STR(LAST_PAGEFAULT_COUNT, "last_pagefault_count"),
DEF_STAT_STR(SVM_PAGEFAULT_COUNT, "svm_pagefault_count"),
DEF_STAT_STR(TLB_INVAL, "tlb_inval_count"),
DEF_STAT_STR(SVM_TLB_INVAL_COUNT, "svm_tlb_inval_count"),
diff --git a/drivers/gpu/drm/xe/xe_gt_stats_types.h b/drivers/gpu/drm/xe/xe_gt_stats_types.h
index a7021a298e3e..ab5506f915cb 100644
--- a/drivers/gpu/drm/xe/xe_gt_stats_types.h
+++ b/drivers/gpu/drm/xe/xe_gt_stats_types.h
@@ -10,6 +10,17 @@
/**
* enum xe_gt_stats_id - GT statistics identifiers
+ * @XE_GT_STATS_ID_CHAIN_PAGEFAULT_COUNT: Total page faults chained onto an
+ * in-flight fault instead of being queued separately.
+ * @XE_GT_STATS_ID_CHAIN_IRQ_PAGEFAULT_COUNT: Page faults chained directly from
+ * the IRQ handler.
+ * @XE_GT_STATS_ID_CHAIN_DRAIN_IRQ_PAGEFAULT_COUNT: IRQ-handler chained faults
+ * that also drained the fault queue.
+ * @XE_GT_STATS_ID_CHAIN_MISMATCH_PAGEFAULT_COUNT: Chained faults requeued
+ * because their fault range did not match the fault they were chained onto.
+ * @XE_GT_STATS_ID_LAST_PAGEFAULT_COUNT: Faults whose range matched the last
+ * serviced range, allowing an immediate ack.
+ *
* @XE_GT_STATS_ID_SVM_PAGEFAULT_COUNT: Total SVM page faults handled.
* @XE_GT_STATS_ID_TLB_INVAL: Total GPU Translation Lookaside Buffer (TLB)
* invalidations issued.
@@ -129,6 +140,11 @@
* See Documentation/gpu/xe/xe_gt_stats.rst.
*/
enum xe_gt_stats_id {
+ XE_GT_STATS_ID_CHAIN_PAGEFAULT_COUNT,
+ XE_GT_STATS_ID_CHAIN_IRQ_PAGEFAULT_COUNT,
+ XE_GT_STATS_ID_CHAIN_DRAIN_IRQ_PAGEFAULT_COUNT,
+ XE_GT_STATS_ID_CHAIN_MISMATCH_PAGEFAULT_COUNT,
+ XE_GT_STATS_ID_LAST_PAGEFAULT_COUNT,
XE_GT_STATS_ID_SVM_PAGEFAULT_COUNT,
XE_GT_STATS_ID_TLB_INVAL,
XE_GT_STATS_ID_SVM_TLB_INVAL_COUNT,
diff --git a/drivers/gpu/drm/xe/xe_pagefault.c b/drivers/gpu/drm/xe/xe_pagefault.c
index 34cca2e4411f..6903c9fbb3d3 100644
--- a/drivers/gpu/drm/xe/xe_pagefault.c
+++ b/drivers/gpu/drm/xe/xe_pagefault.c
@@ -377,6 +377,8 @@ xe_pagefault_queue_unchain_requeue(struct xe_pagefault_queue *pf_queue,
xe_assert(xe, pf->consumer.alloc_state ==
XE_PAGEFAULT_ALLOC_STATE_CHAINED);
+ xe_gt_stats_incr(gt, XE_GT_STATS_ID_CHAIN_MISMATCH_PAGEFAULT_COUNT, 1);
+
pf->consumer.alloc_state = XE_PAGEFAULT_ALLOC_STATE_FREE;
lpf = xe_pagefault_queue_add(pf_queue, pf);
if (lpf) {
@@ -433,6 +435,10 @@ static bool xe_pagefault_try_chain(struct xe_pagefault_queue *pf_queue,
xe_assert(xe, pf_work->cache.pf->consumer.alloc_state ==
XE_PAGEFAULT_ALLOC_STATE_ACTIVE);
+ xe_gt_stats_incr(pf->gt,
+ XE_GT_STATS_ID_CHAIN_PAGEFAULT_COUNT,
+ 1);
+
pf->consumer.alloc_state =
XE_PAGEFAULT_ALLOC_STATE_CHAINED;
pf->consumer.next = pf_work->cache.pf->consumer.next;
@@ -607,8 +613,10 @@ static void xe_pagefault_queue_work(struct work_struct *w)
int err = 0;
/* Last fault same address, ack immediately */
- if (xe_pagefault_match(pf, cache_start, cache_end, cache_asid))
+ if (xe_pagefault_match(pf, cache_start, cache_end, cache_asid)) {
+ xe_gt_stats_incr(gt, XE_GT_STATS_ID_LAST_PAGEFAULT_COUNT, 1);
goto ack_fault;
+ }
err = xe_pagefault_service(pf);
@@ -851,8 +859,15 @@ int xe_pagefault_handler(struct xe_device *xe, struct xe_pagefault *pf)
lpf->consumer.next = NULL;
if (xe_pagefault_try_chain(pf_queue, lpf)) {
- if (empty)
+ xe_gt_stats_incr(pf->gt,
+ XE_GT_STATS_ID_CHAIN_IRQ_PAGEFAULT_COUNT,
+ 1);
+ if (empty) {
+ xe_gt_stats_incr(pf->gt,
+ XE_GT_STATS_ID_CHAIN_DRAIN_IRQ_PAGEFAULT_COUNT,
+ 1);
xe_pagefault_queue_advance(pf_queue);
+ }
} else {
int work_index = xe_pagefault_work_index(xe);
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v5 10/12] drm/xe: Add debugfs pagefault_info
2026-07-23 21:47 [PATCH v5 00/12] Fine grained fault locking, threaded prefetch, storm cache Matthew Brost
` (8 preceding siblings ...)
2026-07-23 21:47 ` [PATCH v5 09/12] drm/xe: Add pagefault chaining stats Matthew Brost
@ 2026-07-23 21:47 ` Matthew Brost
2026-07-23 21:47 ` [PATCH v5 11/12] drm/xe: batch CT pagefault acks with periodic flush Matthew Brost
` (4 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Matthew Brost @ 2026-07-23 21:47 UTC (permalink / raw)
To: intel-xe; +Cc: Maciej Patelczyk
Add a debugfs entry to dump Xe page fault queue state. The output
includes queue geometry (entry size, total size, head/tail), per-entry
allocation state counts, and whether each page fault worker cache is
currently valid.
This is intended to help debug page fault storms, chaining, and retry
behaviour without needing tracing.
Assisted-by: ChatGPT:gpt-5 # Documentation
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
---
drivers/gpu/drm/xe/xe_debugfs.c | 11 +++++
drivers/gpu/drm/xe/xe_pagefault.c | 68 +++++++++++++++++++++++++++++++
drivers/gpu/drm/xe/xe_pagefault.h | 3 ++
3 files changed, 82 insertions(+)
diff --git a/drivers/gpu/drm/xe/xe_debugfs.c b/drivers/gpu/drm/xe/xe_debugfs.c
index 5a3877fcb0f0..5a7286679958 100644
--- a/drivers/gpu/drm/xe/xe_debugfs.c
+++ b/drivers/gpu/drm/xe/xe_debugfs.c
@@ -22,6 +22,7 @@
#include "xe_guc_ads.h"
#include "xe_hw_engine.h"
#include "xe_mmio.h"
+#include "xe_pagefault.h"
#include "xe_pcode.h"
#include "xe_pm.h"
#include "xe_psmi.h"
@@ -194,6 +195,15 @@ static int sriov_info(struct seq_file *m, void *data)
return 0;
}
+static int pagefault_info(struct seq_file *m, void *data)
+{
+ struct xe_device *xe = node_to_xe(m->private);
+ struct drm_printer p = drm_seq_file_printer(m);
+
+ xe_pagefault_print_info(xe, &p);
+ return 0;
+}
+
static int workarounds(struct xe_device *xe, struct drm_printer *p)
{
guard(xe_pm_runtime)(xe);
@@ -285,6 +295,7 @@ static const struct drm_info_list debugfs_list[] = {
{"info", info, 0},
{ .name = "sriov_info", .show = sriov_info, },
{ .name = "workarounds", .show = workaround_info, },
+ { .name = "pagefault_info", .show = pagefault_info, },
};
static const struct drm_info_list pcode_info_debugfs[] = {
diff --git a/drivers/gpu/drm/xe/xe_pagefault.c b/drivers/gpu/drm/xe/xe_pagefault.c
index 6903c9fbb3d3..3a1cecf448ed 100644
--- a/drivers/gpu/drm/xe/xe_pagefault.c
+++ b/drivers/gpu/drm/xe/xe_pagefault.c
@@ -83,6 +83,8 @@
* Entry is not independently serviced; it has been chained onto an
* ACTIVE entry via consumer.next and will be acknowledged when the
* leading fault completes.
+ * @XE_PAGEFAULT_ALLOC_STATE_COUNT:
+ * Count of allocation states.
*
* The page fault queue provides stable storage for outstanding faults so the
* IRQ handler can chain new cache hits directly onto a worker's active fault.
@@ -97,6 +99,7 @@ enum xe_pagefault_alloc_state {
XE_PAGEFAULT_ALLOC_STATE_QUEUED = 1,
XE_PAGEFAULT_ALLOC_STATE_CHAINED = 2,
XE_PAGEFAULT_ALLOC_STATE_ACTIVE = 3,
+ XE_PAGEFAULT_ALLOC_STATE_COUNT = 4,
};
static int xe_pagefault_entry_size(void)
@@ -883,3 +886,68 @@ int xe_pagefault_handler(struct xe_device *xe, struct xe_pagefault *pf)
return full ? -ENOSPC : 0;
}
+
+/**
+ * xe_pagefault_print_info() - dump page fault queue/cache debug information
+ * @xe: Xe device
+ * @p: DRM printer to emit output to
+ *
+ * Print a snapshot of the page fault queue state for debugging. The output
+ * includes queue parameters (entry size, total size, head/tail), a histogram
+ * of per-entry allocation state values, and the validity of each per-worker
+ * page fault cache.
+ *
+ * This function is intended for debugfs and similar diagnostics. It acquires
+ * the page fault queue spinlock internally to serialize against IRQ-side
+ * producers and the worker consumer path, so callers must not hold the queue
+ * lock.
+ */
+void xe_pagefault_print_info(struct xe_device *xe, struct drm_printer *p)
+{
+ struct xe_pagefault_queue *pf_queue = &xe->usm.pf_queue;
+ struct xe_pagefault_work *pf_work;
+ static const char * const alloc_state_names[] = {
+ [XE_PAGEFAULT_ALLOC_STATE_FREE] = "free",
+ [XE_PAGEFAULT_ALLOC_STATE_QUEUED] = "queued",
+ [XE_PAGEFAULT_ALLOC_STATE_CHAINED] = "chained",
+ [XE_PAGEFAULT_ALLOC_STATE_ACTIVE] = "active",
+ };
+ u32 i, counts[XE_PAGEFAULT_ALLOC_STATE_COUNT] = {};
+
+ /* Driver load failure guard / USM not enabled guard */
+ if (!pf_queue->data)
+ return;
+
+ guard(spinlock_irq)(&pf_queue->lock);
+
+ drm_printf(p, "pagefault size: %u\n", xe_pagefault_entry_size());
+ drm_printf(p, "pagefault queue size: %u\n", pf_queue->size);
+ drm_printf(p, "pagefault queue head: %u\n", pf_queue->head);
+ drm_printf(p, "pagefault queue tail: %u\n", pf_queue->tail);
+
+ for (i = 0; i < pf_queue->size; i += xe_pagefault_entry_size()) {
+ struct xe_pagefault *pf = pf_queue->data + i;
+
+ if (pf->consumer.alloc_state >=
+ XE_PAGEFAULT_ALLOC_STATE_COUNT) {
+ drm_printf(p, "pagefault[%u] corrupted alloc_state=%u\n",
+ i, pf->consumer.alloc_state);
+ continue;
+ }
+
+ counts[pf->consumer.alloc_state]++;
+ }
+
+ for (i = 0; i < XE_PAGEFAULT_ALLOC_STATE_COUNT; ++i)
+ drm_printf(p, "pagefault queue %s count: %u\n",
+ alloc_state_names[i], counts[i]);
+
+ for (i = 0, pf_work = xe->usm.pf_workers;
+ i < xe->info.num_pf_work; ++i, ++pf_work) {
+ if (pf_work->cache.start == XE_PAGEFAULT_CACHE_START_INVALID)
+ drm_printf(p, "pagefault work[%u] cache invalid\n", i);
+ else
+ drm_printf(p, "pagefault work[%u] cache valid\n", i);
+
+ }
+}
diff --git a/drivers/gpu/drm/xe/xe_pagefault.h b/drivers/gpu/drm/xe/xe_pagefault.h
index feaf2a69674a..e9c5d1f03760 100644
--- a/drivers/gpu/drm/xe/xe_pagefault.h
+++ b/drivers/gpu/drm/xe/xe_pagefault.h
@@ -8,6 +8,7 @@
#include "xe_pagefault_types.h"
+struct drm_printer;
struct xe_device;
struct xe_gt;
struct xe_pagefault;
@@ -18,6 +19,8 @@ void xe_pagefault_reset(struct xe_device *xe, struct xe_gt *gt);
int xe_pagefault_handler(struct xe_device *xe, struct xe_pagefault *pf);
+void xe_pagefault_print_info(struct xe_device *xe, struct drm_printer *p);
+
#define XE_PAGEFAULT_END_ADDR_MASK (~0xfffull)
/**
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v5 11/12] drm/xe: batch CT pagefault acks with periodic flush
2026-07-23 21:47 [PATCH v5 00/12] Fine grained fault locking, threaded prefetch, storm cache Matthew Brost
` (9 preceding siblings ...)
2026-07-23 21:47 ` [PATCH v5 10/12] drm/xe: Add debugfs pagefault_info Matthew Brost
@ 2026-07-23 21:47 ` Matthew Brost
2026-07-23 21:47 ` [PATCH v5 12/12] drm/xe: Track parallel page fault activity in GT stats Matthew Brost
` (3 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Matthew Brost @ 2026-07-23 21:47 UTC (permalink / raw)
To: intel-xe
Pagefault storms can generate long chains of acknowledgments back to the
GuC. Sending each ack as a full CT submission forces a barrier,
descriptor update and doorbell per fault.
Extend xe_guc_ct_send_locked() with a “write-only” mode that copies the
message into the H2G ring but defers publishing the descriptor and
ringing the doorbell. Add xe_guc_ct_send_flush() to publish pending
writes and notify GuC once per batch. Wire this into the pagefault
producer via new ack_fault_begin/ack_fault_end callbacks and CT lock
wrappers.
To avoid excessive flush latency while still amortizing MMIO costs, use
a simple periodic flush heuristic for GuC pagefault acks: batch most
acks as write-only and force a publish at a fixed interval (e.g., every
16th ack), with a final flush at end-of-batch.
Also increase the H2G CTB size to 16K to better absorb bursts.
Assisted-by: ChatGPT:gpt-5 # Documentation
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
---
drivers/gpu/drm/xe/xe_guc_ct.c | 89 ++++++++++++++++++++-----
drivers/gpu/drm/xe/xe_guc_ct.h | 35 +++++++++-
drivers/gpu/drm/xe/xe_guc_pagefault.c | 32 ++++++++-
drivers/gpu/drm/xe/xe_guc_types.h | 6 ++
drivers/gpu/drm/xe/xe_pagefault.c | 12 +++-
drivers/gpu/drm/xe/xe_pagefault_types.h | 14 ++++
6 files changed, 169 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c
index fe70c0fd85c5..3361fa751676 100644
--- a/drivers/gpu/drm/xe/xe_guc_ct.c
+++ b/drivers/gpu/drm/xe/xe_guc_ct.c
@@ -265,7 +265,7 @@ static bool g2h_fence_needs_alloc(struct g2h_fence *g2h_fence)
#define CTB_DESC_SIZE ALIGN(sizeof(struct guc_ct_buffer_desc), SZ_2K)
#define CTB_H2G_BUFFER_OFFSET (CTB_DESC_SIZE * 2)
#define CTB_G2H_BUFFER_OFFSET (CTB_DESC_SIZE * 2)
-#define CTB_H2G_BUFFER_SIZE (SZ_4K)
+#define CTB_H2G_BUFFER_SIZE (SZ_16K)
#define CTB_H2G_BUFFER_DWORDS (CTB_H2G_BUFFER_SIZE / sizeof(u32))
#define CTB_G2H_BUFFER_SIZE (SZ_128K)
#define CTB_G2H_BUFFER_DWORDS (CTB_G2H_BUFFER_SIZE / sizeof(u32))
@@ -939,7 +939,7 @@ static bool vf_action_can_safely_fail(struct xe_device *xe, u32 action)
#define H2G_CT_HEADERS (GUC_CTB_HDR_LEN + 1) /* one DW CTB header and one DW HxG header */
static int h2g_write(struct xe_guc_ct *ct, const u32 *action, u32 len,
- u32 ct_fence_value, bool want_response)
+ u32 ct_fence_value, bool want_response, bool write_only)
{
struct xe_device *xe = ct_to_xe(ct);
struct xe_gt *gt = ct_to_gt(ct);
@@ -966,7 +966,7 @@ static int h2g_write(struct xe_guc_ct *ct, const u32 *action, u32 len,
goto corrupted;
}
- if (tail != desc_tail) {
+ if (!write_only && tail != desc_tail) {
desc_write(xe, h2g, status, desc_status | GUC_CTB_STATUS_MISMATCH);
xe_gt_err(gt, "CT write: tail was modified %u != %u\n", desc_tail, tail);
goto corrupted;
@@ -993,7 +993,8 @@ static int h2g_write(struct xe_guc_ct *ct, const u32 *action, u32 len,
(h2g->info.size - tail) * sizeof(u32));
h2g_reserve_space(ct, (h2g->info.size - tail));
h2g->info.tail = 0;
- desc_write(xe, h2g, tail, h2g->info.tail);
+ if (!write_only)
+ desc_write(xe, h2g, tail, h2g->info.tail);
return -EAGAIN;
}
@@ -1024,14 +1025,15 @@ static int h2g_write(struct xe_guc_ct *ct, const u32 *action, u32 len,
/* Write H2G ensuring visible before descriptor update */
xe_map_memcpy_to(xe, &map, 0, cmd, H2G_CT_HEADERS * sizeof(u32));
xe_map_memcpy_to(xe, &map, H2G_CT_HEADERS * sizeof(u32), action, len * sizeof(u32));
- xe_device_wmb(xe);
-
/* Update local copies */
h2g->info.tail = (tail + full_len) % h2g->info.size;
h2g_reserve_space(ct, full_len);
/* Update descriptor */
- desc_write(xe, h2g, tail, h2g->info.tail);
+ if (!write_only) {
+ xe_device_wmb(xe);
+ desc_write(xe, h2g, tail, h2g->info.tail);
+ }
/*
* desc_read() performs an VRAM read which serializes the CPU and drains
@@ -1052,7 +1054,7 @@ static int h2g_write(struct xe_guc_ct *ct, const u32 *action, u32 len,
static int __guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action,
u32 len, u32 g2h_len, u32 num_g2h,
- struct g2h_fence *g2h_fence)
+ struct g2h_fence *g2h_fence, bool write_only)
{
struct xe_gt *gt = ct_to_gt(ct);
u16 seqno;
@@ -1112,7 +1114,7 @@ static int __guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action,
if (unlikely(ret))
goto out_unlock;
- ret = h2g_write(ct, action, len, seqno, !!g2h_fence);
+ ret = h2g_write(ct, action, len, seqno, !!g2h_fence, write_only);
if (unlikely(ret)) {
if (ret == -EAGAIN)
goto retry;
@@ -1120,7 +1122,8 @@ static int __guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action,
}
__g2h_reserve_space(ct, g2h_len, num_g2h);
- xe_guc_notify(ct_to_guc(ct));
+ if (!write_only)
+ xe_guc_notify(ct_to_guc(ct));
out_unlock:
if (g2h_len)
spin_unlock_irq(&ct->fast_lock);
@@ -1196,7 +1199,7 @@ static bool guc_ct_send_wait_for_retry(struct xe_guc_ct *ct, u32 len,
static int guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action, u32 len,
u32 g2h_len, u32 num_g2h,
- struct g2h_fence *g2h_fence)
+ struct g2h_fence *g2h_fence, bool write_only)
{
struct xe_gt *gt = ct_to_gt(ct);
unsigned int sleep_period_ms = 1;
@@ -1209,9 +1212,11 @@ static int guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action, u32 len,
try_again:
ret = __guc_ct_send_locked(ct, action, len, g2h_len, num_g2h,
- g2h_fence);
+ g2h_fence, write_only);
if (unlikely(ret == -EBUSY)) {
+ if (write_only)
+ xe_guc_ct_send_flush(ct);
if (!guc_ct_send_wait_for_retry(ct, len, g2h_len, g2h_fence,
&sleep_period_ms, &sleep_total_ms))
goto broken;
@@ -1235,7 +1240,8 @@ static int guc_ct_send(struct xe_guc_ct *ct, const u32 *action, u32 len,
xe_gt_assert(ct_to_gt(ct), !g2h_len || !g2h_fence);
mutex_lock(&ct->lock);
- ret = guc_ct_send_locked(ct, action, len, g2h_len, num_g2h, g2h_fence);
+ ret = guc_ct_send_locked(ct, action, len, g2h_len, num_g2h, g2h_fence,
+ false);
mutex_unlock(&ct->lock);
return ret;
@@ -1283,25 +1289,76 @@ int xe_guc_ct_send(struct xe_guc_ct *ct, const u32 *action, u32 len,
return ret;
}
+/**
+ * xe_guc_ct_send_locked() - submit a GuC CT H2G message with CT lock held
+ * @ct: GuC CT object
+ * @action: payload dwords (HxG header dword is expected at @action[-1])
+ * @len: number of payload dwords in @action
+ * @write_only: defer publishing/doorbell for batching
+ *
+ * Sends a single H2G message to the GuC CT buffer while the caller already
+ * holds @ct->lock.
+ *
+ * If @write_only is false, the function completes the submission immediately:
+ * it makes the payload visible to the device, updates the H2G descriptor and
+ * rings the GuC doorbell.
+ *
+ * If @write_only is true, the message payload is copied into the H2G ring and
+ * the software tail is advanced, but the descriptor update and doorbell are
+ * deferred so multiple messages can be batched. In this mode, the caller must
+ * eventually call xe_guc_ct_send_flush() (still holding @ct->lock) to publish
+ * the descriptor and notify the GuC. On internal retry paths (-EBUSY), the
+ * implementation may force a flush to ensure forward progress.
+ *
+ * Return: 0 on success, negative errno on failure.
+ *
+ * Locking:
+ * Must be called with @ct->lock held.
+ */
int xe_guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action, u32 len,
- u32 g2h_len, u32 num_g2h)
+ bool write_only)
{
int ret;
- ret = guc_ct_send_locked(ct, action, len, g2h_len, num_g2h, NULL);
+ ret = guc_ct_send_locked(ct, action, len, 0, 0, NULL, write_only);
if (ret == -EDEADLK)
kick_reset(ct);
return ret;
}
+/**
+ * xe_guc_ct_send_flush() - flush pending GuC CT H2G writes
+ * @ct: GuC CT instance
+ *
+ * Some callers batch multiple H2G writes using xe_guc_ct_send_locked() in
+ * "write-only" mode (i.e., queue the message payloads but defer ringing the
+ * doorbell / updating the CT descriptor). This helper completes the submission
+ * by ensuring the payload writes are visible to the device, updating the H2G
+ * descriptor, and ringing the GuC CT doorbell.
+ *
+ * Locking:
+ * Must be called with @ct->lock held.
+ */
+void xe_guc_ct_send_flush(struct xe_guc_ct *ct)
+{
+ struct xe_device *xe = ct_to_xe(ct);
+ struct guc_ctb *h2g = &ct->ctbs.h2g;
+
+ lockdep_assert_held(&ct->lock);
+
+ xe_device_wmb(xe);
+ desc_write(xe, h2g, tail, h2g->info.tail);
+ xe_guc_notify(ct_to_guc(ct));
+}
+
int xe_guc_ct_send_g2h_handler(struct xe_guc_ct *ct, const u32 *action, u32 len)
{
int ret;
lockdep_assert_held(&ct->lock);
- ret = guc_ct_send_locked(ct, action, len, 0, 0, NULL);
+ ret = guc_ct_send_locked(ct, action, len, 0, 0, NULL, false);
if (ret == -EDEADLK)
kick_reset(ct);
diff --git a/drivers/gpu/drm/xe/xe_guc_ct.h b/drivers/gpu/drm/xe/xe_guc_ct.h
index 767365a33dee..2db4dded6b96 100644
--- a/drivers/gpu/drm/xe/xe_guc_ct.h
+++ b/drivers/gpu/drm/xe/xe_guc_ct.h
@@ -54,7 +54,7 @@ static inline void xe_guc_ct_irq_handler(struct xe_guc_ct *ct)
int xe_guc_ct_send(struct xe_guc_ct *ct, const u32 *action, u32 len,
u32 g2h_len, u32 num_g2h);
int xe_guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action, u32 len,
- u32 g2h_len, u32 num_g2h);
+ bool write_only);
int xe_guc_ct_send_recv(struct xe_guc_ct *ct, const u32 *action, u32 len,
u32 *response_buffer);
static inline int
@@ -62,6 +62,7 @@ xe_guc_ct_send_block(struct xe_guc_ct *ct, const u32 *action, u32 len)
{
return xe_guc_ct_send_recv(ct, action, len, NULL);
}
+void xe_guc_ct_send_flush(struct xe_guc_ct *ct);
/* This is only version of the send CT you can call from a G2H handler */
int xe_guc_ct_send_g2h_handler(struct xe_guc_ct *ct, const u32 *action,
@@ -87,4 +88,36 @@ static inline void xe_guc_ct_wake_waiters(struct xe_guc_ct *ct)
wake_up_all(&ct->wq);
}
+/**
+ * xe_guc_ct_lock() - take the GuC CT mutex
+ * @ct: GuC CT object
+ *
+ * Wrapper around mutex_lock(&ct->lock) for cases where CT operations need to be
+ * performed from contexts that want an explicit "CT locked" pair without
+ * exporting the lock itself.
+ *
+ * Return/Locking:
+ * Acquires @ct->lock.
+ */
+static inline void xe_guc_ct_lock(struct xe_guc_ct *ct)
+__acquires(&ct->lock)
+{
+ mutex_lock(&ct->lock);
+}
+
+/**
+ * xe_guc_ct_unlock() - release the GuC CT mutex
+ * @ct: GuC CT object
+ *
+ * Counterpart to xe_guc_ct_lock().
+ *
+ * Locking:
+ * Releases @ct->lock.
+ */
+static inline void xe_guc_ct_unlock(struct xe_guc_ct *ct)
+__releases(&ct->lock)
+{
+ mutex_unlock(&ct->lock);
+}
+
#endif
diff --git a/drivers/gpu/drm/xe/xe_guc_pagefault.c b/drivers/gpu/drm/xe/xe_guc_pagefault.c
index 2470faf3d5d8..442f90590db6 100644
--- a/drivers/gpu/drm/xe/xe_guc_pagefault.c
+++ b/drivers/gpu/drm/xe/xe_guc_pagefault.c
@@ -10,6 +10,22 @@
#include "xe_pagefault.h"
#include "xe_pagefault_types.h"
+#define XE_GUC_PAGEFAULT_FLUSH_PERIOD BIT(4) /* Sixteen */
+
+static void guc_ack_fault_begin(void *private)
+{
+ struct xe_guc *guc = private;
+
+ xe_guc_ct_lock(&guc->ct);
+
+ BUILD_BUG_ON(((XE_GUC_PAGEFAULT_FLUSH_PERIOD - 1) &
+ XE_GUC_PAGEFAULT_FLUSH_PERIOD) != 0);
+
+ /* Ack the 2th, then 18th, etc... */
+ guc->pagefault_ack_counter =
+ XE_GUC_PAGEFAULT_FLUSH_PERIOD - 1;
+}
+
static void guc_ack_fault(struct xe_pagefault *pf, int err)
{
u32 vfid = FIELD_GET(PFD_VFID, pf->producer.msg[2]);
@@ -36,12 +52,26 @@ static void guc_ack_fault(struct xe_pagefault *pf, int err)
FIELD_PREP(PFR_PDATA, pdata),
};
struct xe_guc *guc = pf->producer.private;
+ bool write_only = guc->pagefault_ack_counter++ &
+ (XE_GUC_PAGEFAULT_FLUSH_PERIOD - 1);
+
+ xe_guc_ct_send_locked(&guc->ct, action, ARRAY_SIZE(action),
+ write_only);
+}
+
+static void guc_ack_fault_end(void *private)
+{
+ struct xe_guc *guc = private;
- xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), 0, 0);
+ if ((guc->pagefault_ack_counter & (XE_GUC_PAGEFAULT_FLUSH_PERIOD - 1)) != 1)
+ xe_guc_ct_send_flush(&guc->ct);
+ xe_guc_ct_unlock(&guc->ct);
}
static const struct xe_pagefault_ops guc_pagefault_ops = {
+ .ack_fault_begin = guc_ack_fault_begin,
.ack_fault = guc_ack_fault,
+ .ack_fault_end = guc_ack_fault_end,
};
/**
diff --git a/drivers/gpu/drm/xe/xe_guc_types.h b/drivers/gpu/drm/xe/xe_guc_types.h
index 31a2acb63ac3..3dbcb1331690 100644
--- a/drivers/gpu/drm/xe/xe_guc_types.h
+++ b/drivers/gpu/drm/xe/xe_guc_types.h
@@ -122,6 +122,12 @@ struct xe_guc {
struct xe_reg notify_reg;
/** @params: Control params for fw initialization */
u32 params[GUC_CTL_MAX_DWORDS];
+
+ /**
+ * @pagefault_ack_counter: Counter to determine when periodically ack
+ * pagefaults in a batch.
+ */
+ u32 pagefault_ack_counter;
};
#endif
diff --git a/drivers/gpu/drm/xe/xe_pagefault.c b/drivers/gpu/drm/xe/xe_pagefault.c
index 3a1cecf448ed..b57767fffc18 100644
--- a/drivers/gpu/drm/xe/xe_pagefault.c
+++ b/drivers/gpu/drm/xe/xe_pagefault.c
@@ -438,6 +438,10 @@ static bool xe_pagefault_try_chain(struct xe_pagefault_queue *pf_queue,
xe_assert(xe, pf_work->cache.pf->consumer.alloc_state ==
XE_PAGEFAULT_ALLOC_STATE_ACTIVE);
+ if (pf->producer.private !=
+ pf_work->cache.pf->producer.private)
+ continue;
+
xe_gt_stats_incr(pf->gt,
XE_GT_STATS_ID_CHAIN_PAGEFAULT_COUNT,
1);
@@ -611,6 +615,8 @@ static void xe_pagefault_queue_work(struct work_struct *w)
threshold = jiffies + msecs_to_jiffies(USM_QUEUE_MAX_RUNTIME_MS);
while (xe_pagefault_queue_pop(pf_queue, &pf, pf_work->id)) {
+ const struct xe_pagefault_ops *ops = pf->producer.ops;
+ void *private = pf->producer.private;
struct xe_gt *gt = pf->gt;
u32 asid = pf->consumer.asid;
int err = 0;
@@ -651,13 +657,16 @@ static void xe_pagefault_queue_work(struct work_struct *w)
XE_PAGEFAULT_ALLOC_STATE_ACTIVE);
xe_assert(xe, pf == pf_work->cache.pf);
+ ops->ack_fault_begin(private);
while (pf) {
xe_assert(xe, pf->consumer.alloc_state ==
XE_PAGEFAULT_ALLOC_STATE_CHAINED ||
pf->consumer.alloc_state ==
XE_PAGEFAULT_ALLOC_STATE_ACTIVE);
+ xe_assert(xe, ops == pf->producer.ops);
+ xe_assert(xe, gt == pf->gt);
- pf->producer.ops->ack_fault(pf, err);
+ ops->ack_fault(pf, err);
spin_lock_irq(&pf_queue->lock);
@@ -679,6 +688,7 @@ static void xe_pagefault_queue_work(struct work_struct *w)
spin_unlock_irq(&pf_queue->lock);
}
+ ops->ack_fault_end(private);
if (time_after(jiffies, threshold)) {
queue_work(xe->usm.pf_wq, w);
diff --git a/drivers/gpu/drm/xe/xe_pagefault_types.h b/drivers/gpu/drm/xe/xe_pagefault_types.h
index a1fff0e47fa5..efeba5c3a58b 100644
--- a/drivers/gpu/drm/xe/xe_pagefault_types.h
+++ b/drivers/gpu/drm/xe/xe_pagefault_types.h
@@ -33,6 +33,13 @@ enum xe_pagefault_type {
/** struct xe_pagefault_ops - Xe pagefault ops (producer) */
struct xe_pagefault_ops {
+ /**
+ * @ack_fault_begin: Ack fault begin
+ * @private: producer private data
+ *
+ * Page fault producer begins acknowledgment from the consumer.
+ */
+ void (*ack_fault_begin)(void *private);
/**
* @ack_fault: Ack fault
* @pf: Page fault
@@ -42,6 +49,13 @@ struct xe_pagefault_ops {
* sends the result to the HW/FW interface.
*/
void (*ack_fault)(struct xe_pagefault *pf, int err);
+ /**
+ * @ack_fault_end: Ack fault end
+ * @private: producer private data
+ *
+ * Page fault producer ends acknowledgment from the consumer.
+ */
+ void (*ack_fault_end)(void *private);
};
/**
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v5 12/12] drm/xe: Track parallel page fault activity in GT stats
2026-07-23 21:47 [PATCH v5 00/12] Fine grained fault locking, threaded prefetch, storm cache Matthew Brost
` (10 preceding siblings ...)
2026-07-23 21:47 ` [PATCH v5 11/12] drm/xe: batch CT pagefault acks with periodic flush Matthew Brost
@ 2026-07-23 21:47 ` Matthew Brost
2026-07-23 21:54 ` ✗ CI.checkpatch: warning for Fine grained fault locking, threaded prefetch, storm cache (rev5) Patchwork
` (2 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Matthew Brost @ 2026-07-23 21:47 UTC (permalink / raw)
To: intel-xe; +Cc: Maciej Patelczyk
Add a new GT statistic, PARALLEL_PAGEFAULT_COUNT, to record when
multiple page fault workers are active concurrently.
When a worker dequeues a fault, scan peer workers for an active
cache entry and increment the counter if another fault is already
in flight. This provides basic visibility into parallel fault
handling behavior for performance analysis and tuning.
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
---
drivers/gpu/drm/xe/xe_gt_stats.c | 1 +
drivers/gpu/drm/xe/xe_gt_stats_types.h | 3 +++
drivers/gpu/drm/xe/xe_pagefault.c | 18 +++++++++++++++++-
3 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/xe/xe_gt_stats.c b/drivers/gpu/drm/xe/xe_gt_stats.c
index f2e77df0f224..2a40924660ee 100644
--- a/drivers/gpu/drm/xe/xe_gt_stats.c
+++ b/drivers/gpu/drm/xe/xe_gt_stats.c
@@ -99,6 +99,7 @@ static const char *const stat_description[__XE_GT_STATS_NUM_IDS] = {
DEF_STAT_STR(CHAIN_IRQ_PAGEFAULT_COUNT, "chain_irq_pagefault_count"),
DEF_STAT_STR(CHAIN_DRAIN_IRQ_PAGEFAULT_COUNT, "chain_drain_irq_pagefault_count"),
DEF_STAT_STR(CHAIN_MISMATCH_PAGEFAULT_COUNT, "chain_mismatch_pagefault_count"),
+ DEF_STAT_STR(PARALLEL_PAGEFAULT_COUNT, "parallel_pagefault_count"),
DEF_STAT_STR(LAST_PAGEFAULT_COUNT, "last_pagefault_count"),
DEF_STAT_STR(SVM_PAGEFAULT_COUNT, "svm_pagefault_count"),
DEF_STAT_STR(TLB_INVAL, "tlb_inval_count"),
diff --git a/drivers/gpu/drm/xe/xe_gt_stats_types.h b/drivers/gpu/drm/xe/xe_gt_stats_types.h
index ab5506f915cb..24abeb9f2137 100644
--- a/drivers/gpu/drm/xe/xe_gt_stats_types.h
+++ b/drivers/gpu/drm/xe/xe_gt_stats_types.h
@@ -18,6 +18,8 @@
* that also drained the fault queue.
* @XE_GT_STATS_ID_CHAIN_MISMATCH_PAGEFAULT_COUNT: Chained faults requeued
* because their fault range did not match the fault they were chained onto.
+ * @XE_GT_STATS_ID_PARALLEL_PAGEFAULT_COUNT: Faults dequeued while another page
+ * fault worker was already handling a fault concurrently.
* @XE_GT_STATS_ID_LAST_PAGEFAULT_COUNT: Faults whose range matched the last
* serviced range, allowing an immediate ack.
*
@@ -144,6 +146,7 @@ enum xe_gt_stats_id {
XE_GT_STATS_ID_CHAIN_IRQ_PAGEFAULT_COUNT,
XE_GT_STATS_ID_CHAIN_DRAIN_IRQ_PAGEFAULT_COUNT,
XE_GT_STATS_ID_CHAIN_MISMATCH_PAGEFAULT_COUNT,
+ XE_GT_STATS_ID_PARALLEL_PAGEFAULT_COUNT,
XE_GT_STATS_ID_LAST_PAGEFAULT_COUNT,
XE_GT_STATS_ID_SVM_PAGEFAULT_COUNT,
XE_GT_STATS_ID_TLB_INVAL,
diff --git a/drivers/gpu/drm/xe/xe_pagefault.c b/drivers/gpu/drm/xe/xe_pagefault.c
index b57767fffc18..d332ef8515f5 100644
--- a/drivers/gpu/drm/xe/xe_pagefault.c
+++ b/drivers/gpu/drm/xe/xe_pagefault.c
@@ -486,9 +486,10 @@ static bool xe_pagefault_queue_pop(struct xe_pagefault_queue *pf_queue,
{
struct xe_device *xe = container_of(pf_queue, typeof(*xe),
usm.pf_queue);
- struct xe_pagefault_work *pf_work;
+ struct xe_pagefault_work *pf_work, *__pf_work;
struct xe_pagefault *lpf;
size_t align = SZ_2M;
+ int i;
guard(spinlock_irq)(&pf_queue->lock);
@@ -525,6 +526,21 @@ static bool xe_pagefault_queue_pop(struct xe_pagefault_queue *pf_queue,
pf_work->cache.pf = lpf;
lpf->consumer.alloc_state = XE_PAGEFAULT_ALLOC_STATE_ACTIVE;
+ for (i = 0, __pf_work = xe->usm.pf_workers;
+ i < xe->info.num_pf_work; ++i, ++__pf_work) {
+ u64 cache_start = __pf_work->cache.start;
+
+ if (__pf_work == pf_work)
+ continue;
+
+ if (cache_start != XE_PAGEFAULT_CACHE_START_INVALID) {
+ xe_gt_stats_incr(xe_root_mmio_gt(xe),
+ XE_GT_STATS_ID_PARALLEL_PAGEFAULT_COUNT,
+ 1);
+ break;
+ }
+ }
+
/* Drain queue until empty or new fault found */
while (1) {
if (xe_pagefault_queue_empty(pf_queue))
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* ✗ CI.checkpatch: warning for Fine grained fault locking, threaded prefetch, storm cache (rev5)
2026-07-23 21:47 [PATCH v5 00/12] Fine grained fault locking, threaded prefetch, storm cache Matthew Brost
` (11 preceding siblings ...)
2026-07-23 21:47 ` [PATCH v5 12/12] drm/xe: Track parallel page fault activity in GT stats Matthew Brost
@ 2026-07-23 21:54 ` Patchwork
2026-07-23 21:55 ` ✓ CI.KUnit: success " Patchwork
2026-07-23 22:47 ` ✗ Xe.CI.BAT: failure " Patchwork
14 siblings, 0 replies; 16+ messages in thread
From: Patchwork @ 2026-07-23 21:54 UTC (permalink / raw)
To: Matthew Brost; +Cc: intel-xe
== Series Details ==
Series: Fine grained fault locking, threaded prefetch, storm cache (rev5)
URL : https://patchwork.freedesktop.org/series/162167/
State : warning
== Summary ==
+ KERNEL=/kernel
+ git clone https://gitlab.freedesktop.org/drm/maintainer-tools mt
Cloning into 'mt'...
warning: redirecting to https://gitlab.freedesktop.org/drm/maintainer-tools.git/
+ git -C mt rev-list -n1 origin/master
061140b9bc586ae7f40abc1249c97e1cc72d1b9d
+ cd /kernel
+ git config --global --add safe.directory /kernel
+ git log -n1
commit 0487e2f6a208063dec337ac19f59a2828799772b
Author: Matthew Brost <matthew.brost@intel.com>
Date: Thu Jul 23 14:47:43 2026 -0700
drm/xe: Track parallel page fault activity in GT stats
Add a new GT statistic, PARALLEL_PAGEFAULT_COUNT, to record when
multiple page fault workers are active concurrently.
When a worker dequeues a fault, scan peer workers for an active
cache entry and increment the counter if another fault is already
in flight. This provides basic visibility into parallel fault
handling behavior for performance analysis and tuning.
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
+ /mt/dim checkpatch 1b41172259f1c761714ee4d65a4386b42181c492 drm-intel
1300e7d89ac3 drm/xe: Fine grained page fault locking
-:554: CHECK:UNCOMMENTED_DEFINITION: struct mutex definition without comment
#554: FILE: drivers/gpu/drm/xe/xe_svm.h:253:
+ struct mutex lock;
-:596: CHECK:LINE_SPACING: Please use a blank line after function/struct/union/enum declarations
#596: FILE: drivers/gpu/drm/xe/xe_userptr.c:70:
+}
+#define xe_vma_userptr_lockdep(uvma) \
total: 0 errors, 0 warnings, 2 checks, 762 lines checked
506012e4d197 drm/xe: Allow prefetch-only VM bind IOCTLs to use VM read lock
be07693753a1 drm/xe: Thread prefetch of SVM ranges
aa9986721179 drm/xe: Use a single page-fault queue with multiple workers
76b0e43a11b4 drm/xe: Add num_pf_work modparam
0beca879505d drm/xe: Engine class and instance into a u8
2675a3add6e0 drm/xe: Track pagefault worker runtime
75c8fbc090aa drm/xe: Chain page faults via queue-resident cache to avoid fault storms
-:468: WARNING:LONG_LINE: line length of 109 exceeds 100 columns
#468: FILE: drivers/gpu/drm/xe/xe_pagefault.c:627:
+ xe_gt_stats_incr(pf->gt, XE_GT_STATS_ID_INVALID_PREFETCH_PAGEFAULT_COUNT, 1);
total: 0 errors, 1 warnings, 0 checks, 829 lines checked
10ce2d0b9613 drm/xe: Add pagefault chaining stats
-:112: WARNING:LONG_LINE: line length of 104 exceeds 100 columns
#112: FILE: drivers/gpu/drm/xe/xe_pagefault.c:867:
+ XE_GT_STATS_ID_CHAIN_DRAIN_IRQ_PAGEFAULT_COUNT,
total: 0 errors, 1 warnings, 0 checks, 84 lines checked
8b7f1643b6a5 drm/xe: Add debugfs pagefault_info
-:142: CHECK:BRACES: Blank lines aren't necessary before a close brace '}'
#142: FILE: drivers/gpu/drm/xe/xe_pagefault.c:952:
+
+ }
total: 0 errors, 0 warnings, 1 checks, 127 lines checked
4e4ba02aea85 drm/xe: batch CT pagefault acks with periodic flush
-:247: CHECK:LINE_SPACING: Please use a blank line after function/struct/union/enum declarations
#247: FILE: drivers/gpu/drm/xe/xe_guc_ct.h:65:
}
+void xe_guc_ct_send_flush(struct xe_guc_ct *ct);
total: 0 errors, 0 warnings, 1 checks, 364 lines checked
0487e2f6a208 drm/xe: Track parallel page fault activity in GT stats
^ permalink raw reply [flat|nested] 16+ messages in thread* ✓ CI.KUnit: success for Fine grained fault locking, threaded prefetch, storm cache (rev5)
2026-07-23 21:47 [PATCH v5 00/12] Fine grained fault locking, threaded prefetch, storm cache Matthew Brost
` (12 preceding siblings ...)
2026-07-23 21:54 ` ✗ CI.checkpatch: warning for Fine grained fault locking, threaded prefetch, storm cache (rev5) Patchwork
@ 2026-07-23 21:55 ` Patchwork
2026-07-23 22:47 ` ✗ Xe.CI.BAT: failure " Patchwork
14 siblings, 0 replies; 16+ messages in thread
From: Patchwork @ 2026-07-23 21:55 UTC (permalink / raw)
To: Matthew Brost; +Cc: intel-xe
== Series Details ==
Series: Fine grained fault locking, threaded prefetch, storm cache (rev5)
URL : https://patchwork.freedesktop.org/series/162167/
State : success
== Summary ==
+ trap cleanup EXIT
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/gpu/drm/xe/.kunitconfig
[21:54:16] Configuring KUnit Kernel ...
Generating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[21:54:20] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=48
[21:54:52] Starting KUnit Kernel (1/1)...
[21:54:52] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[21:54:53] ================== guc_buf (11 subtests) ===================
[21:54:53] [PASSED] test_smallest
[21:54:53] [PASSED] test_largest
[21:54:53] [PASSED] test_granular
[21:54:53] [PASSED] test_unique
[21:54:53] [PASSED] test_overlap
[21:54:53] [PASSED] test_reusable
[21:54:53] [PASSED] test_too_big
[21:54:53] [PASSED] test_flush
[21:54:53] [PASSED] test_lookup
[21:54:53] [PASSED] test_data
[21:54:53] [PASSED] test_class
[21:54:53] ===================== [PASSED] guc_buf =====================
[21:54:53] =================== guc_dbm (7 subtests) ===================
[21:54:53] [PASSED] test_empty
[21:54:53] [PASSED] test_default
[21:54:53] ======================== test_size ========================
[21:54:53] [PASSED] 4
[21:54:53] [PASSED] 8
[21:54:53] [PASSED] 32
[21:54:53] [PASSED] 256
[21:54:53] ==================== [PASSED] test_size ====================
[21:54:53] ======================= test_reuse ========================
[21:54:53] [PASSED] 4
[21:54:53] [PASSED] 8
[21:54:53] [PASSED] 32
[21:54:53] [PASSED] 256
[21:54:53] =================== [PASSED] test_reuse ====================
[21:54:53] =================== test_range_overlap ====================
[21:54:53] [PASSED] 4
[21:54:53] [PASSED] 8
[21:54:53] [PASSED] 32
[21:54:53] [PASSED] 256
[21:54:53] =============== [PASSED] test_range_overlap ================
[21:54:53] =================== test_range_compact ====================
[21:54:53] [PASSED] 4
[21:54:53] [PASSED] 8
[21:54:53] [PASSED] 32
[21:54:53] [PASSED] 256
[21:54:53] =============== [PASSED] test_range_compact ================
[21:54:53] ==================== test_range_spare =====================
[21:54:53] [PASSED] 4
[21:54:53] [PASSED] 8
[21:54:53] [PASSED] 32
[21:54:53] [PASSED] 256
[21:54:53] ================ [PASSED] test_range_spare =================
[21:54:53] ===================== [PASSED] guc_dbm =====================
[21:54:53] =================== guc_idm (6 subtests) ===================
[21:54:53] [PASSED] bad_init
[21:54:53] [PASSED] no_init
[21:54:53] [PASSED] init_fini
[21:54:53] [PASSED] check_used
[21:54:53] [PASSED] check_quota
[21:54:53] [PASSED] check_all
[21:54:53] ===================== [PASSED] guc_idm =====================
[21:54:53] =============== guc_klv_helpers (9 subtests) ===============
[21:54:53] [PASSED] test_count
[21:54:53] [PASSED] test_encode_u32
[21:54:53] [PASSED] test_encode_u64
[21:54:53] [PASSED] test_encode_string
[21:54:53] [PASSED] test_encode_object_raw
[21:54:53] [PASSED] test_encode_object_klv
[21:54:53] [PASSED] test_encode_object_nested
[21:54:53] [PASSED] test_encode_object_basic
[21:54:53] [PASSED] test_print
[21:54:53] ================= [PASSED] guc_klv_helpers =================
[21:54:53] ================== no_relay (3 subtests) ===================
[21:54:53] [PASSED] xe_drops_guc2pf_if_not_ready
[21:54:53] [PASSED] xe_drops_guc2vf_if_not_ready
[21:54:53] [PASSED] xe_rejects_send_if_not_ready
[21:54:53] ==================== [PASSED] no_relay =====================
[21:54:53] ================== pf_relay (14 subtests) ==================
[21:54:53] [PASSED] pf_rejects_guc2pf_too_short
[21:54:53] [PASSED] pf_rejects_guc2pf_too_long
[21:54:53] [PASSED] pf_rejects_guc2pf_no_payload
[21:54:53] [PASSED] pf_fails_no_payload
[21:54:53] [PASSED] pf_fails_bad_origin
[21:54:53] [PASSED] pf_fails_bad_type
[21:54:53] [PASSED] pf_txn_reports_error
[21:54:53] [PASSED] pf_txn_sends_pf2guc
[21:54:53] [PASSED] pf_sends_pf2guc
[21:54:53] [SKIPPED] pf_loopback_nop (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[21:54:53] [SKIPPED] pf_loopback_echo (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[21:54:53] [SKIPPED] pf_loopback_fail (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[21:54:53] [SKIPPED] pf_loopback_busy (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[21:54:53] [SKIPPED] pf_loopback_retry (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[21:54:53] ==================== [PASSED] pf_relay =====================
[21:54:53] ================== vf_relay (3 subtests) ===================
[21:54:53] [PASSED] vf_rejects_guc2vf_too_short
[21:54:53] [PASSED] vf_rejects_guc2vf_too_long
[21:54:53] [PASSED] vf_rejects_guc2vf_no_payload
[21:54:53] ==================== [PASSED] vf_relay =====================
[21:54:53] ================ pf_gt_config (9 subtests) =================
[21:54:53] [PASSED] fair_contexts_1vf
[21:54:53] [PASSED] fair_doorbells_1vf
[21:54:53] [PASSED] fair_ggtt_1vf
[21:54:53] ====================== fair_vram_1vf ======================
[21:54:53] [PASSED] 3.50 GiB
[21:54:53] [PASSED] 11.5 GiB
[21:54:53] [PASSED] 15.5 GiB
[21:54:53] [PASSED] 31.5 GiB
[21:54:53] [PASSED] 63.5 GiB
[21:54:53] [PASSED] 1.91 GiB
[21:54:53] ================== [PASSED] fair_vram_1vf ==================
[21:54:53] ================ fair_vram_1vf_admin_only =================
[21:54:53] [PASSED] 3.50 GiB
[21:54:53] [PASSED] 11.5 GiB
[21:54:53] [PASSED] 15.5 GiB
[21:54:53] [PASSED] 31.5 GiB
[21:54:53] [PASSED] 63.5 GiB
[21:54:53] [PASSED] 1.91 GiB
[21:54:53] ============ [PASSED] fair_vram_1vf_admin_only =============
[21:54:53] ====================== fair_contexts ======================
[21:54:53] [PASSED] 1 VF
[21:54:53] [PASSED] 2 VFs
[21:54:53] [PASSED] 3 VFs
[21:54:53] [PASSED] 4 VFs
[21:54:53] [PASSED] 5 VFs
[21:54:53] [PASSED] 6 VFs
[21:54:53] [PASSED] 7 VFs
[21:54:53] [PASSED] 8 VFs
[21:54:53] [PASSED] 9 VFs
[21:54:53] [PASSED] 10 VFs
[21:54:53] [PASSED] 11 VFs
[21:54:53] [PASSED] 12 VFs
[21:54:53] [PASSED] 13 VFs
[21:54:53] [PASSED] 14 VFs
[21:54:53] [PASSED] 15 VFs
[21:54:53] [PASSED] 16 VFs
[21:54:53] [PASSED] 17 VFs
[21:54:53] [PASSED] 18 VFs
[21:54:53] [PASSED] 19 VFs
[21:54:53] [PASSED] 20 VFs
[21:54:53] [PASSED] 21 VFs
[21:54:53] [PASSED] 22 VFs
[21:54:53] [PASSED] 23 VFs
[21:54:53] [PASSED] 24 VFs
[21:54:53] [PASSED] 25 VFs
[21:54:53] [PASSED] 26 VFs
[21:54:53] [PASSED] 27 VFs
[21:54:53] [PASSED] 28 VFs
[21:54:53] [PASSED] 29 VFs
[21:54:53] [PASSED] 30 VFs
[21:54:53] [PASSED] 31 VFs
[21:54:53] [PASSED] 32 VFs
[21:54:53] [PASSED] 33 VFs
[21:54:53] [PASSED] 34 VFs
[21:54:53] [PASSED] 35 VFs
[21:54:53] [PASSED] 36 VFs
[21:54:53] [PASSED] 37 VFs
[21:54:53] [PASSED] 38 VFs
[21:54:53] [PASSED] 39 VFs
[21:54:53] [PASSED] 40 VFs
[21:54:53] [PASSED] 41 VFs
[21:54:53] [PASSED] 42 VFs
[21:54:53] [PASSED] 43 VFs
[21:54:53] [PASSED] 44 VFs
[21:54:53] [PASSED] 45 VFs
[21:54:53] [PASSED] 46 VFs
[21:54:53] [PASSED] 47 VFs
[21:54:53] [PASSED] 48 VFs
[21:54:53] [PASSED] 49 VFs
[21:54:53] [PASSED] 50 VFs
[21:54:53] [PASSED] 51 VFs
[21:54:53] [PASSED] 52 VFs
[21:54:53] [PASSED] 53 VFs
[21:54:53] [PASSED] 54 VFs
[21:54:53] [PASSED] 55 VFs
[21:54:53] [PASSED] 56 VFs
[21:54:53] [PASSED] 57 VFs
[21:54:53] [PASSED] 58 VFs
[21:54:53] [PASSED] 59 VFs
[21:54:53] [PASSED] 60 VFs
[21:54:53] [PASSED] 61 VFs
[21:54:53] [PASSED] 62 VFs
[21:54:53] [PASSED] 63 VFs
[21:54:53] ================== [PASSED] fair_contexts ==================
[21:54:53] ===================== fair_doorbells ======================
[21:54:53] [PASSED] 1 VF
[21:54:53] [PASSED] 2 VFs
[21:54:53] [PASSED] 3 VFs
[21:54:53] [PASSED] 4 VFs
[21:54:53] [PASSED] 5 VFs
[21:54:53] [PASSED] 6 VFs
[21:54:53] [PASSED] 7 VFs
[21:54:53] [PASSED] 8 VFs
[21:54:53] [PASSED] 9 VFs
[21:54:53] [PASSED] 10 VFs
[21:54:53] [PASSED] 11 VFs
[21:54:53] [PASSED] 12 VFs
[21:54:53] [PASSED] 13 VFs
[21:54:53] [PASSED] 14 VFs
[21:54:53] [PASSED] 15 VFs
[21:54:53] [PASSED] 16 VFs
[21:54:53] [PASSED] 17 VFs
[21:54:53] [PASSED] 18 VFs
[21:54:53] [PASSED] 19 VFs
[21:54:53] [PASSED] 20 VFs
[21:54:53] [PASSED] 21 VFs
[21:54:53] [PASSED] 22 VFs
[21:54:53] [PASSED] 23 VFs
[21:54:53] [PASSED] 24 VFs
[21:54:53] [PASSED] 25 VFs
[21:54:53] [PASSED] 26 VFs
[21:54:53] [PASSED] 27 VFs
[21:54:53] [PASSED] 28 VFs
[21:54:53] [PASSED] 29 VFs
[21:54:53] [PASSED] 30 VFs
[21:54:53] [PASSED] 31 VFs
[21:54:53] [PASSED] 32 VFs
[21:54:53] [PASSED] 33 VFs
[21:54:53] [PASSED] 34 VFs
[21:54:53] [PASSED] 35 VFs
[21:54:53] [PASSED] 36 VFs
[21:54:53] [PASSED] 37 VFs
[21:54:53] [PASSED] 38 VFs
[21:54:53] [PASSED] 39 VFs
[21:54:53] [PASSED] 40 VFs
[21:54:53] [PASSED] 41 VFs
[21:54:53] [PASSED] 42 VFs
[21:54:53] [PASSED] 43 VFs
[21:54:53] [PASSED] 44 VFs
[21:54:53] [PASSED] 45 VFs
[21:54:53] [PASSED] 46 VFs
[21:54:53] [PASSED] 47 VFs
[21:54:53] [PASSED] 48 VFs
[21:54:53] [PASSED] 49 VFs
[21:54:53] [PASSED] 50 VFs
[21:54:53] [PASSED] 51 VFs
[21:54:53] [PASSED] 52 VFs
[21:54:53] [PASSED] 53 VFs
[21:54:53] [PASSED] 54 VFs
[21:54:53] [PASSED] 55 VFs
[21:54:53] [PASSED] 56 VFs
[21:54:53] [PASSED] 57 VFs
[21:54:53] [PASSED] 58 VFs
[21:54:53] [PASSED] 59 VFs
[21:54:53] [PASSED] 60 VFs
[21:54:53] [PASSED] 61 VFs
[21:54:53] [PASSED] 62 VFs
[21:54:53] [PASSED] 63 VFs
[21:54:53] ================= [PASSED] fair_doorbells ==================
[21:54:53] ======================== fair_ggtt ========================
[21:54:53] [PASSED] 1 VF
[21:54:53] [PASSED] 2 VFs
[21:54:53] [PASSED] 3 VFs
[21:54:53] [PASSED] 4 VFs
[21:54:53] [PASSED] 5 VFs
[21:54:53] [PASSED] 6 VFs
[21:54:53] [PASSED] 7 VFs
[21:54:53] [PASSED] 8 VFs
[21:54:53] [PASSED] 9 VFs
[21:54:53] [PASSED] 10 VFs
[21:54:53] [PASSED] 11 VFs
[21:54:53] [PASSED] 12 VFs
[21:54:53] [PASSED] 13 VFs
[21:54:53] [PASSED] 14 VFs
[21:54:53] [PASSED] 15 VFs
[21:54:53] [PASSED] 16 VFs
[21:54:53] [PASSED] 17 VFs
[21:54:53] [PASSED] 18 VFs
[21:54:53] [PASSED] 19 VFs
[21:54:53] [PASSED] 20 VFs
[21:54:53] [PASSED] 21 VFs
[21:54:53] [PASSED] 22 VFs
[21:54:53] [PASSED] 23 VFs
[21:54:53] [PASSED] 24 VFs
[21:54:53] [PASSED] 25 VFs
[21:54:53] [PASSED] 26 VFs
[21:54:53] [PASSED] 27 VFs
[21:54:53] [PASSED] 28 VFs
[21:54:53] [PASSED] 29 VFs
[21:54:53] [PASSED] 30 VFs
[21:54:53] [PASSED] 31 VFs
[21:54:53] [PASSED] 32 VFs
[21:54:53] [PASSED] 33 VFs
[21:54:53] [PASSED] 34 VFs
[21:54:53] [PASSED] 35 VFs
[21:54:53] [PASSED] 36 VFs
[21:54:53] [PASSED] 37 VFs
[21:54:53] [PASSED] 38 VFs
[21:54:53] [PASSED] 39 VFs
[21:54:53] [PASSED] 40 VFs
[21:54:53] [PASSED] 41 VFs
[21:54:53] [PASSED] 42 VFs
[21:54:53] [PASSED] 43 VFs
[21:54:53] [PASSED] 44 VFs
[21:54:53] [PASSED] 45 VFs
[21:54:53] [PASSED] 46 VFs
[21:54:53] [PASSED] 47 VFs
[21:54:53] [PASSED] 48 VFs
[21:54:53] [PASSED] 49 VFs
[21:54:53] [PASSED] 50 VFs
[21:54:53] [PASSED] 51 VFs
[21:54:53] [PASSED] 52 VFs
[21:54:53] [PASSED] 53 VFs
[21:54:53] [PASSED] 54 VFs
[21:54:53] [PASSED] 55 VFs
[21:54:53] [PASSED] 56 VFs
[21:54:53] [PASSED] 57 VFs
[21:54:53] [PASSED] 58 VFs
[21:54:53] [PASSED] 59 VFs
[21:54:53] [PASSED] 60 VFs
[21:54:53] [PASSED] 61 VFs
[21:54:53] [PASSED] 62 VFs
[21:54:53] [PASSED] 63 VFs
[21:54:53] ==================== [PASSED] fair_ggtt ====================
[21:54:53] ======================== fair_vram ========================
[21:54:53] [PASSED] 1 VF
[21:54:53] [PASSED] 2 VFs
[21:54:53] [PASSED] 3 VFs
[21:54:53] [PASSED] 4 VFs
[21:54:53] [PASSED] 5 VFs
[21:54:53] [PASSED] 6 VFs
[21:54:53] [PASSED] 7 VFs
[21:54:53] [PASSED] 8 VFs
[21:54:53] [PASSED] 9 VFs
[21:54:53] [PASSED] 10 VFs
[21:54:53] [PASSED] 11 VFs
[21:54:53] [PASSED] 12 VFs
[21:54:53] [PASSED] 13 VFs
[21:54:53] [PASSED] 14 VFs
[21:54:53] [PASSED] 15 VFs
[21:54:53] [PASSED] 16 VFs
[21:54:53] [PASSED] 17 VFs
[21:54:53] [PASSED] 18 VFs
[21:54:53] [PASSED] 19 VFs
[21:54:53] [PASSED] 20 VFs
[21:54:53] [PASSED] 21 VFs
[21:54:53] [PASSED] 22 VFs
[21:54:53] [PASSED] 23 VFs
[21:54:53] [PASSED] 24 VFs
[21:54:53] [PASSED] 25 VFs
[21:54:53] [PASSED] 26 VFs
[21:54:53] [PASSED] 27 VFs
[21:54:53] [PASSED] 28 VFs
[21:54:53] [PASSED] 29 VFs
[21:54:53] [PASSED] 30 VFs
[21:54:53] [PASSED] 31 VFs
[21:54:53] [PASSED] 32 VFs
[21:54:53] [PASSED] 33 VFs
[21:54:53] [PASSED] 34 VFs
[21:54:53] [PASSED] 35 VFs
[21:54:53] [PASSED] 36 VFs
[21:54:53] [PASSED] 37 VFs
[21:54:53] [PASSED] 38 VFs
[21:54:53] [PASSED] 39 VFs
[21:54:53] [PASSED] 40 VFs
[21:54:53] [PASSED] 41 VFs
[21:54:53] [PASSED] 42 VFs
[21:54:53] [PASSED] 43 VFs
[21:54:53] [PASSED] 44 VFs
[21:54:53] [PASSED] 45 VFs
[21:54:53] [PASSED] 46 VFs
[21:54:53] [PASSED] 47 VFs
[21:54:53] [PASSED] 48 VFs
[21:54:53] [PASSED] 49 VFs
[21:54:53] [PASSED] 50 VFs
[21:54:53] [PASSED] 51 VFs
[21:54:53] [PASSED] 52 VFs
[21:54:53] [PASSED] 53 VFs
[21:54:53] [PASSED] 54 VFs
[21:54:53] [PASSED] 55 VFs
[21:54:53] [PASSED] 56 VFs
[21:54:53] [PASSED] 57 VFs
[21:54:53] [PASSED] 58 VFs
[21:54:53] [PASSED] 59 VFs
[21:54:53] [PASSED] 60 VFs
[21:54:53] [PASSED] 61 VFs
[21:54:53] [PASSED] 62 VFs
[21:54:53] [PASSED] 63 VFs
[21:54:53] ==================== [PASSED] fair_vram ====================
[21:54:53] ================== [PASSED] pf_gt_config ===================
[21:54:53] ===================== lmtt (1 subtest) =====================
[21:54:53] ======================== test_ops =========================
[21:54:53] [PASSED] 2-level
[21:54:53] [PASSED] multi-level
[21:54:53] ==================== [PASSED] test_ops =====================
[21:54:53] ====================== [PASSED] lmtt =======================
[21:54:53] ================= sriov_packet (1 subtest) =================
[21:54:53] [PASSED] test_descriptor_init
[21:54:53] ================== [PASSED] sriov_packet ===================
[21:54:53] ================= pf_service (11 subtests) =================
[21:54:53] [PASSED] pf_negotiate_any
[21:54:53] [PASSED] pf_negotiate_base_match
[21:54:53] [PASSED] pf_negotiate_base_newer
[21:54:53] [PASSED] pf_negotiate_base_next
[21:54:53] [SKIPPED] pf_negotiate_base_older (no older minor)
[21:54:53] [PASSED] pf_negotiate_base_prev
[21:54:53] [PASSED] pf_negotiate_latest_match
[21:54:53] [PASSED] pf_negotiate_latest_newer
[21:54:53] [PASSED] pf_negotiate_latest_next
[21:54:53] [SKIPPED] pf_negotiate_latest_older (no older minor)
[21:54:53] [SKIPPED] pf_negotiate_latest_prev (no prev major)
[21:54:53] =================== [PASSED] pf_service ====================
[21:54:53] ================= xe_guc_g2g (2 subtests) ==================
[21:54:53] ============== xe_live_guc_g2g_kunit_default ==============
[21:54:53] ========= [SKIPPED] xe_live_guc_g2g_kunit_default ==========
[21:54:53] ============== xe_live_guc_g2g_kunit_allmem ===============
[21:54:53] ========== [SKIPPED] xe_live_guc_g2g_kunit_allmem ==========
[21:54:53] =================== [SKIPPED] xe_guc_g2g ===================
[21:54:53] =================== xe_mocs (2 subtests) ===================
[21:54:53] ================ xe_live_mocs_kernel_kunit ================
[21:54:53] =========== [SKIPPED] xe_live_mocs_kernel_kunit ============
[21:54:53] ================ xe_live_mocs_reset_kunit =================
[21:54:53] ============ [SKIPPED] xe_live_mocs_reset_kunit ============
[21:54:53] ==================== [SKIPPED] xe_mocs =====================
[21:54:53] ================= xe_migrate (2 subtests) ==================
[21:54:53] ================= xe_migrate_sanity_kunit =================
[21:54:53] ============ [SKIPPED] xe_migrate_sanity_kunit =============
[21:54:53] ================== xe_validate_ccs_kunit ==================
[21:54:53] ============= [SKIPPED] xe_validate_ccs_kunit ==============
[21:54:53] =================== [SKIPPED] xe_migrate ===================
[21:54:53] ================== xe_dma_buf (1 subtest) ==================
[21:54:53] ==================== xe_dma_buf_kunit =====================
[21:54:53] ================ [SKIPPED] xe_dma_buf_kunit ================
[21:54:53] =================== [SKIPPED] xe_dma_buf ===================
[21:54:53] ================= xe_bo_shrink (1 subtest) =================
[21:54:53] =================== xe_bo_shrink_kunit ====================
[21:54:53] =============== [SKIPPED] xe_bo_shrink_kunit ===============
[21:54:53] ================== [SKIPPED] xe_bo_shrink ==================
[21:54:53] ==================== xe_bo (2 subtests) ====================
[21:54:53] ================== xe_ccs_migrate_kunit ===================
[21:54:53] ============== [SKIPPED] xe_ccs_migrate_kunit ==============
[21:54:53] ==================== xe_bo_evict_kunit ====================
[21:54:53] =============== [SKIPPED] xe_bo_evict_kunit ================
[21:54:53] ===================== [SKIPPED] xe_bo ======================
[21:54:53] ==================== args (13 subtests) ====================
[21:54:53] [PASSED] count_args_test
[21:54:53] [PASSED] call_args_example
[21:54:53] [PASSED] call_args_test
[21:54:53] [PASSED] drop_first_arg_example
[21:54:53] [PASSED] drop_first_arg_test
[21:54:53] [PASSED] first_arg_example
[21:54:53] [PASSED] first_arg_test
[21:54:53] [PASSED] last_arg_example
[21:54:53] [PASSED] last_arg_test
[21:54:53] [PASSED] pick_arg_example
[21:54:53] [PASSED] if_args_example
[21:54:53] [PASSED] if_args_test
[21:54:53] [PASSED] sep_comma_example
[21:54:53] ====================== [PASSED] args =======================
[21:54:53] =================== xe_pci (3 subtests) ====================
[21:54:53] ==================== check_graphics_ip ====================
[21:54:53] [PASSED] 12.00 Xe_LP
[21:54:53] [PASSED] 12.10 Xe_LP+
[21:54:53] [PASSED] 12.55 Xe_HPG
[21:54:53] [PASSED] 12.60 Xe_HPC
[21:54:53] [PASSED] 12.70 Xe_LPG
[21:54:53] [PASSED] 12.71 Xe_LPG
[21:54:53] [PASSED] 12.74 Xe_LPG+
[21:54:53] [PASSED] 20.01 Xe2_HPG
[21:54:53] [PASSED] 20.02 Xe2_HPG
[21:54:53] [PASSED] 20.04 Xe2_LPG
[21:54:53] [PASSED] 30.00 Xe3_LPG
[21:54:53] [PASSED] 30.01 Xe3_LPG
[21:54:53] [PASSED] 30.03 Xe3_LPG
[21:54:53] [PASSED] 30.04 Xe3_LPG
[21:54:53] [PASSED] 30.05 Xe3_LPG
[21:54:53] [PASSED] 35.10 Xe3p_LPG
[21:54:53] [PASSED] 35.11 Xe3p_XPC
[21:54:53] ================ [PASSED] check_graphics_ip ================
[21:54:53] ===================== check_media_ip ======================
[21:54:53] [PASSED] 12.00 Xe_M
[21:54:53] [PASSED] 12.55 Xe_HPM
[21:54:53] [PASSED] 13.00 Xe_LPM+
[21:54:53] [PASSED] 13.01 Xe2_HPM
[21:54:53] [PASSED] 20.00 Xe2_LPM
[21:54:53] [PASSED] 30.00 Xe3_LPM
[21:54:53] [PASSED] 30.02 Xe3_LPM
[21:54:53] [PASSED] 35.00 Xe3p_LPM
[21:54:53] [PASSED] 35.03 Xe3p_HPM
[21:54:53] ================= [PASSED] check_media_ip ==================
[21:54:53] =================== check_platform_desc ===================
[21:54:53] [PASSED] 0x9A60 (TIGERLAKE)
[21:54:53] [PASSED] 0x9A68 (TIGERLAKE)
[21:54:53] [PASSED] 0x9A70 (TIGERLAKE)
[21:54:53] [PASSED] 0x9A40 (TIGERLAKE)
[21:54:53] [PASSED] 0x9A49 (TIGERLAKE)
[21:54:53] [PASSED] 0x9A59 (TIGERLAKE)
[21:54:53] [PASSED] 0x9A78 (TIGERLAKE)
[21:54:53] [PASSED] 0x9AC0 (TIGERLAKE)
[21:54:53] [PASSED] 0x9AC9 (TIGERLAKE)
[21:54:53] [PASSED] 0x9AD9 (TIGERLAKE)
[21:54:53] [PASSED] 0x9AF8 (TIGERLAKE)
[21:54:53] [PASSED] 0x4C80 (ROCKETLAKE)
[21:54:53] [PASSED] 0x4C8A (ROCKETLAKE)
[21:54:53] [PASSED] 0x4C8B (ROCKETLAKE)
[21:54:53] [PASSED] 0x4C8C (ROCKETLAKE)
[21:54:53] [PASSED] 0x4C90 (ROCKETLAKE)
[21:54:53] [PASSED] 0x4C9A (ROCKETLAKE)
[21:54:53] [PASSED] 0x4680 (ALDERLAKE_S)
[21:54:53] [PASSED] 0x4682 (ALDERLAKE_S)
[21:54:53] [PASSED] 0x4688 (ALDERLAKE_S)
[21:54:53] [PASSED] 0x468A (ALDERLAKE_S)
[21:54:53] [PASSED] 0x468B (ALDERLAKE_S)
[21:54:53] [PASSED] 0x4690 (ALDERLAKE_S)
[21:54:53] [PASSED] 0x4692 (ALDERLAKE_S)
[21:54:53] [PASSED] 0x4693 (ALDERLAKE_S)
[21:54:53] [PASSED] 0x46A0 (ALDERLAKE_P)
[21:54:53] [PASSED] 0x46A1 (ALDERLAKE_P)
[21:54:53] [PASSED] 0x46A2 (ALDERLAKE_P)
[21:54:53] [PASSED] 0x46A3 (ALDERLAKE_P)
[21:54:53] [PASSED] 0x46A6 (ALDERLAKE_P)
[21:54:53] [PASSED] 0x46A8 (ALDERLAKE_P)
[21:54:53] [PASSED] 0x46AA (ALDERLAKE_P)
[21:54:53] [PASSED] 0x462A (ALDERLAKE_P)
[21:54:53] [PASSED] 0x4626 (ALDERLAKE_P)
[21:54:53] [PASSED] 0x4628 (ALDERLAKE_P)
[21:54:53] [PASSED] 0x46B0 (ALDERLAKE_P)
[21:54:53] [PASSED] 0x46B1 (ALDERLAKE_P)
[21:54:53] [PASSED] 0x46B2 (ALDERLAKE_P)
[21:54:53] [PASSED] 0x46B3 (ALDERLAKE_P)
[21:54:53] [PASSED] 0x46C0 (ALDERLAKE_P)
[21:54:53] [PASSED] 0x46C1 (ALDERLAKE_P)
[21:54:53] [PASSED] 0x46C2 (ALDERLAKE_P)
[21:54:53] [PASSED] 0x46C3 (ALDERLAKE_P)
[21:54:53] [PASSED] 0x46D0 (ALDERLAKE_N)
[21:54:53] [PASSED] 0x46D1 (ALDERLAKE_N)
[21:54:53] [PASSED] 0x46D2 (ALDERLAKE_N)
[21:54:53] [PASSED] 0x46D3 (ALDERLAKE_N)
[21:54:53] [PASSED] 0x46D4 (ALDERLAKE_N)
[21:54:53] [PASSED] 0xA721 (ALDERLAKE_P)
[21:54:53] [PASSED] 0xA7A1 (ALDERLAKE_P)
[21:54:53] [PASSED] 0xA7A9 (ALDERLAKE_P)
[21:54:53] [PASSED] 0xA7AC (ALDERLAKE_P)
[21:54:53] [PASSED] 0xA7AD (ALDERLAKE_P)
[21:54:53] [PASSED] 0xA720 (ALDERLAKE_P)
[21:54:53] [PASSED] 0xA7A0 (ALDERLAKE_P)
[21:54:53] [PASSED] 0xA7A8 (ALDERLAKE_P)
[21:54:53] [PASSED] 0xA7AA (ALDERLAKE_P)
[21:54:53] [PASSED] 0xA7AB (ALDERLAKE_P)
[21:54:53] [PASSED] 0xA780 (ALDERLAKE_S)
[21:54:53] [PASSED] 0xA781 (ALDERLAKE_S)
[21:54:53] [PASSED] 0xA782 (ALDERLAKE_S)
[21:54:53] [PASSED] 0xA783 (ALDERLAKE_S)
[21:54:53] [PASSED] 0xA788 (ALDERLAKE_S)
[21:54:53] [PASSED] 0xA789 (ALDERLAKE_S)
[21:54:53] [PASSED] 0xA78A (ALDERLAKE_S)
[21:54:53] [PASSED] 0xA78B (ALDERLAKE_S)
[21:54:53] [PASSED] 0x4905 (DG1)
[21:54:53] [PASSED] 0x4906 (DG1)
[21:54:53] [PASSED] 0x4907 (DG1)
[21:54:53] [PASSED] 0x4908 (DG1)
[21:54:53] [PASSED] 0x4909 (DG1)
[21:54:53] [PASSED] 0x56C0 (DG2)
[21:54:53] [PASSED] 0x56C2 (DG2)
[21:54:53] [PASSED] 0x56C1 (DG2)
[21:54:53] [PASSED] 0x7D51 (METEORLAKE)
[21:54:53] [PASSED] 0x7DD1 (METEORLAKE)
[21:54:53] [PASSED] 0x7D41 (METEORLAKE)
[21:54:53] [PASSED] 0x7D67 (METEORLAKE)
[21:54:53] [PASSED] 0xB640 (METEORLAKE)
[21:54:53] [PASSED] 0x56A0 (DG2)
[21:54:53] [PASSED] 0x56A1 (DG2)
[21:54:53] [PASSED] 0x56A2 (DG2)
[21:54:53] [PASSED] 0x56BE (DG2)
[21:54:53] [PASSED] 0x56BF (DG2)
[21:54:53] [PASSED] 0x5690 (DG2)
[21:54:53] [PASSED] 0x5691 (DG2)
[21:54:53] [PASSED] 0x5692 (DG2)
[21:54:53] [PASSED] 0x56A5 (DG2)
[21:54:53] [PASSED] 0x56A6 (DG2)
[21:54:53] [PASSED] 0x56B0 (DG2)
[21:54:53] [PASSED] 0x56B1 (DG2)
[21:54:53] [PASSED] 0x56BA (DG2)
[21:54:53] [PASSED] 0x56BB (DG2)
[21:54:53] [PASSED] 0x56BC (DG2)
[21:54:53] [PASSED] 0x56BD (DG2)
[21:54:53] [PASSED] 0x5693 (DG2)
[21:54:53] [PASSED] 0x5694 (DG2)
[21:54:53] [PASSED] 0x5695 (DG2)
[21:54:53] [PASSED] 0x56A3 (DG2)
[21:54:53] [PASSED] 0x56A4 (DG2)
[21:54:53] [PASSED] 0x56B2 (DG2)
[21:54:53] [PASSED] 0x56B3 (DG2)
[21:54:53] [PASSED] 0x5696 (DG2)
[21:54:53] [PASSED] 0x5697 (DG2)
[21:54:53] [PASSED] 0xB69 (PVC)
[21:54:53] [PASSED] 0xB6E (PVC)
[21:54:53] [PASSED] 0xBD4 (PVC)
[21:54:53] [PASSED] 0xBD5 (PVC)
[21:54:53] [PASSED] 0xBD6 (PVC)
[21:54:53] [PASSED] 0xBD7 (PVC)
[21:54:53] [PASSED] 0xBD8 (PVC)
[21:54:53] [PASSED] 0xBD9 (PVC)
[21:54:53] [PASSED] 0xBDA (PVC)
[21:54:53] [PASSED] 0xBDB (PVC)
[21:54:53] [PASSED] 0xBE0 (PVC)
[21:54:53] [PASSED] 0xBE1 (PVC)
[21:54:53] [PASSED] 0xBE5 (PVC)
[21:54:53] [PASSED] 0x7D40 (METEORLAKE)
[21:54:53] [PASSED] 0x7D45 (METEORLAKE)
[21:54:53] [PASSED] 0x7D55 (METEORLAKE)
[21:54:53] [PASSED] 0x7D60 (METEORLAKE)
[21:54:53] [PASSED] 0x7DD5 (METEORLAKE)
[21:54:53] [PASSED] 0x6420 (LUNARLAKE)
[21:54:53] [PASSED] 0x64A0 (LUNARLAKE)
[21:54:53] [PASSED] 0x64B0 (LUNARLAKE)
[21:54:53] [PASSED] 0xE202 (BATTLEMAGE)
[21:54:53] [PASSED] 0xE209 (BATTLEMAGE)
[21:54:53] [PASSED] 0xE20B (BATTLEMAGE)
[21:54:53] [PASSED] 0xE20C (BATTLEMAGE)
[21:54:53] [PASSED] 0xE20D (BATTLEMAGE)
[21:54:53] [PASSED] 0xE210 (BATTLEMAGE)
[21:54:53] [PASSED] 0xE211 (BATTLEMAGE)
[21:54:53] [PASSED] 0xE212 (BATTLEMAGE)
[21:54:53] [PASSED] 0xE216 (BATTLEMAGE)
[21:54:53] [PASSED] 0xE220 (BATTLEMAGE)
[21:54:53] [PASSED] 0xE221 (BATTLEMAGE)
[21:54:53] [PASSED] 0xE222 (BATTLEMAGE)
[21:54:53] [PASSED] 0xE223 (BATTLEMAGE)
[21:54:53] [PASSED] 0xB080 (PANTHERLAKE)
[21:54:53] [PASSED] 0xB081 (PANTHERLAKE)
[21:54:53] [PASSED] 0xB082 (PANTHERLAKE)
[21:54:53] [PASSED] 0xB083 (PANTHERLAKE)
[21:54:53] [PASSED] 0xB084 (PANTHERLAKE)
[21:54:53] [PASSED] 0xB085 (PANTHERLAKE)
[21:54:53] [PASSED] 0xB086 (PANTHERLAKE)
[21:54:53] [PASSED] 0xB087 (PANTHERLAKE)
[21:54:53] [PASSED] 0xB08F (PANTHERLAKE)
[21:54:53] [PASSED] 0xB090 (PANTHERLAKE)
[21:54:53] [PASSED] 0xB0A0 (PANTHERLAKE)
[21:54:53] [PASSED] 0xB0B0 (PANTHERLAKE)
[21:54:53] [PASSED] 0xFD80 (PANTHERLAKE)
[21:54:53] [PASSED] 0xFD81 (PANTHERLAKE)
[21:54:53] [PASSED] 0xD740 (NOVALAKE_S)
[21:54:53] [PASSED] 0xD741 (NOVALAKE_S)
[21:54:53] [PASSED] 0xD742 (NOVALAKE_S)
[21:54:53] [PASSED] 0xD743 (NOVALAKE_S)
[21:54:53] [PASSED] 0xD745 (NOVALAKE_S)
[21:54:53] [PASSED] 0xD74A (NOVALAKE_S)
[21:54:53] [PASSED] 0xD74B (NOVALAKE_S)
[21:54:53] [PASSED] 0x674C (CRESCENTISLAND)
[21:54:53] [PASSED] 0x674D (CRESCENTISLAND)
[21:54:53] [PASSED] 0x674E (CRESCENTISLAND)
[21:54:53] [PASSED] 0x674F (CRESCENTISLAND)
[21:54:53] [PASSED] 0x6750 (CRESCENTISLAND)
[21:54:53] [PASSED] 0xD750 (NOVALAKE_P)
[21:54:53] [PASSED] 0xD751 (NOVALAKE_P)
[21:54:53] [PASSED] 0xD752 (NOVALAKE_P)
[21:54:53] [PASSED] 0xD753 (NOVALAKE_P)
[21:54:53] [PASSED] 0xD754 (NOVALAKE_P)
[21:54:53] [PASSED] 0xD755 (NOVALAKE_P)
[21:54:53] [PASSED] 0xD756 (NOVALAKE_P)
[21:54:53] [PASSED] 0xD757 (NOVALAKE_P)
[21:54:53] [PASSED] 0xD75F (NOVALAKE_P)
[21:54:53] =============== [PASSED] check_platform_desc ===============
[21:54:53] ===================== [PASSED] xe_pci ======================
[21:54:53] ============= xe_rtp_tables_test (5 subtests) ==============
[21:54:53] ================== xe_rtp_table_gt_test ===================
[21:54:53] [PASSED] gt_was/14011060649
[21:54:53] [PASSED] gt_was/14011059788
[21:54:53] [PASSED] gt_was/14015795083
[21:54:53] [PASSED] gt_was/16021867713
[21:54:53] [PASSED] gt_was/14019449301
[21:54:53] [PASSED] gt_was/16028005424
[21:54:53] [PASSED] gt_was/14026578760
[21:54:53] [PASSED] gt_was/1409420604
[21:54:53] [PASSED] gt_was/1408615072
[21:54:53] [PASSED] gt_was/22010523718
[21:54:53] [PASSED] gt_was/14011006942
[21:54:53] [PASSED] gt_was/14014830051
[21:54:53] [PASSED] gt_was/18018781329
[21:54:53] [PASSED] gt_was/1509235366
[21:54:53] [PASSED] gt_was/18018781329
[21:54:53] [PASSED] gt_was/16016694945
[21:54:53] [PASSED] gt_was/14018575942
[21:54:53] [PASSED] gt_was/22016670082
[21:54:53] [PASSED] gt_was/22016670082
[21:54:53] [PASSED] gt_was/14017421178
[21:54:53] [PASSED] gt_was/16025250150
[21:54:53] [PASSED] gt_was/14021871409
[21:54:53] [PASSED] gt_was/16021865536
[21:54:53] [PASSED] gt_was/14021486841
[21:54:53] [PASSED] gt_was/14025160223
[21:54:53] [PASSED] gt_was/14026144927, 16029437861, 14026127056
[21:54:53] [PASSED] gt_was/14025635424
[21:54:53] [PASSED] gt_was/16028005424
[21:54:53] ============== [PASSED] xe_rtp_table_gt_test ===============
[21:54:53] ================== xe_rtp_table_gt_test ===================
[21:54:53] [PASSED] gt_tunings/Tuning: Blend Fill Caching Optimization Disable
[21:54:53] [PASSED] gt_tunings/Tuning: 32B Access Enable
[21:54:53] [PASSED] gt_tunings/Tuning: L3 cache
[21:54:53] [PASSED] gt_tunings/Tuning: L3 cache - media
[21:54:53] [PASSED] gt_tunings/Tuning: Compression Overfetch
[21:54:53] [PASSED] gt_tunings/Tuning: Compression Overfetch - media
[21:54:53] [PASSED] gt_tunings/Tuning: Enable compressible partial write overfetch in L3
[21:54:53] [PASSED] gt_tunings/Tuning: Enable compressible partial write overfetch in L3 - media
[21:54:53] [PASSED] gt_tunings/Tuning: L2 Overfetch Compressible Only
[21:54:53] [PASSED] gt_tunings/Tuning: L2 Overfetch Compressible Only - media
[21:54:53] [PASSED] gt_tunings/Tuning: Stateless compression control
[21:54:53] [PASSED] gt_tunings/Tuning: Stateless compression control - media
[21:54:53] [PASSED] gt_tunings/Tuning: L3 RW flush all Cache
[21:54:53] [PASSED] gt_tunings/Tuning: L3 RW flush all cache - media
[21:54:53] [PASSED] gt_tunings/Tuning: Set STLB Bank Hash Mode to 4KB
[21:54:53] ============== [PASSED] xe_rtp_table_gt_test ===============
[21:54:53] ================== xe_rtp_table_oob_test ==================
[21:54:53] [PASSED] oob_was/1607983814
[21:54:53] [PASSED] oob_was/16010904313
[21:54:53] [PASSED] oob_was/18022495364
[21:54:53] [PASSED] oob_was/22012773006
[21:54:53] [PASSED] oob_was/14014475959
[21:54:53] [PASSED] oob_was/22011391025
[21:54:53] [PASSED] oob_was/22012727170
[21:54:53] [PASSED] oob_was/22012727685
[21:54:53] [PASSED] oob_was/22016596838
[21:54:53] [PASSED] oob_was/18020744125
[21:54:53] [PASSED] oob_was/1409600907
[21:54:53] [PASSED] oob_was/22014953428
[21:54:53] [PASSED] oob_was/16017236439
[21:54:53] [PASSED] oob_was/14019821291
[21:54:53] [PASSED] oob_was/14015076503
[21:54:53] [PASSED] oob_was/14018913170
[21:54:53] [PASSED] oob_was/14018094691
[21:54:53] [PASSED] oob_was/18024947630
[21:54:53] [PASSED] oob_was/16022287689
[21:54:53] [PASSED] oob_was/13011645652
[21:54:53] [PASSED] oob_was/14022293748
[21:54:53] [PASSED] oob_was/22019794406
[21:54:53] [PASSED] oob_was/22019338487
[21:54:53] [PASSED] oob_was/16023588340
[21:54:53] [PASSED] oob_was/14019789679
[21:54:53] [PASSED] oob_was/14022866841
[21:54:53] [PASSED] oob_was/16021333562
[21:54:53] [PASSED] oob_was/14016712196
[21:54:53] [PASSED] oob_was/14015568240
[21:54:53] [PASSED] oob_was/18013179988
[21:54:53] [PASSED] oob_was/1508761755
[21:54:53] [PASSED] oob_was/16023105232
[21:54:53] [PASSED] oob_was/16026508708
[21:54:53] [PASSED] oob_was/14020001231
[21:54:53] [PASSED] oob_was/16023683509
[21:54:53] [PASSED] oob_was/14025515070
[21:54:53] [PASSED] oob_was/15015404425_disable
[21:54:53] [PASSED] oob_was/16026007364
[21:54:53] [PASSED] oob_was/14020316580
[21:54:53] [PASSED] oob_was/14025883347
[21:54:53] [PASSED] oob_was/16029380221
[21:54:53] [PASSED] oob_was/22022079272
[21:54:53] [PASSED] oob_was/16029897822
[21:54:53] ============== [PASSED] xe_rtp_table_oob_test ==============
[21:54:53] ================ xe_rtp_table_dev_oob_test ================
[21:54:53] [PASSED] device_oob_was/22010954014
[21:54:53] [PASSED] device_oob_was/15015404425
[21:54:53] [PASSED] device_oob_was/22019338487_display
[21:54:53] [PASSED] device_oob_was/14022085890
[21:54:53] [PASSED] device_oob_was/14026539277
[21:54:53] [PASSED] device_oob_was/14026633728
[21:54:53] [PASSED] device_oob_was/14026746987
[21:54:53] [PASSED] device_oob_was/14026779378
[21:54:53] ============ [PASSED] xe_rtp_table_dev_oob_test ============
[21:54:53] ========== xe_rtp_table_missing_upper_bound_test ==========
[21:54:53] [PASSED] register_whitelist/WaAllowPMDepthAndInvocationCountAccessFromUMD, 1408556865
[21:54:53] [PASSED] register_whitelist/1508744258, 14012131227, 1808121037
[21:54:53] [PASSED] register_whitelist/1806527549
[21:54:53] [PASSED] register_whitelist/allow_read_ctx_timestamp
[21:54:53] [PASSED] register_whitelist/allow_read_queue_timestamp
[21:54:53] [PASSED] register_whitelist/16014440446
[21:54:53] [PASSED] register_whitelist/16017236439
[21:54:53] [PASSED] register_whitelist/16020183090
[21:54:53] [PASSED] register_whitelist/14024997852
[21:54:53] [PASSED] register_whitelist/14024997852
[21:54:53] ====== [PASSED] xe_rtp_table_missing_upper_bound_test ======
[21:54:53] =============== [PASSED] xe_rtp_tables_test ================
[21:54:53] =================== xe_rtp (3 subtests) ====================
[21:54:53] =================== xe_rtp_rules_tests ====================
[21:54:53] [PASSED] no
[21:54:53] [PASSED] yes
[21:54:53] [PASSED] no-and-no
[21:54:53] [PASSED] no-and-yes
[21:54:53] [PASSED] yes-and-no
[21:54:53] [PASSED] yes-and-yes
[21:54:53] [PASSED] no-or-no
[21:54:53] [PASSED] no-or-yes
[21:54:53] [PASSED] yes-or-no
[21:54:53] [PASSED] yes-or-yes
[21:54:53] [PASSED] no-yes-or-yes-no
[21:54:53] [PASSED] no-yes-or-yes-yes
[21:54:53] [PASSED] yes-yes-or-no-yes
[21:54:53] [PASSED] yes-yes-or-yes-yes
[21:54:53] [PASSED] no-no-or-yes-or-no
[21:54:53] [PASSED] or
[21:54:53] [PASSED] or-yes
[21:54:53] [PASSED] or-no
[21:54:53] [PASSED] yes-or
[21:54:53] [PASSED] no-or
[21:54:53] [PASSED] no-or-or-yes
[21:54:53] [PASSED] yes-or-or-no
[21:54:53] [PASSED] no-or-or-no
[21:54:53] [PASSED] missing-context-engine-class
[21:54:53] [PASSED] missing-context-engine-class-or-yes
[21:54:53] [PASSED] missing-context-engine-class-or-or-yes
[21:54:53] =============== [PASSED] xe_rtp_rules_tests ================
[21:54:53] =============== xe_rtp_process_to_sr_tests ================
[21:54:53] [PASSED] coalesce-same-reg
[21:54:53] [PASSED] coalesce-same-reg-literal-and-func
[21:54:53] [PASSED] no-match-no-add
[21:54:53] [PASSED] two-regs-two-entries
[21:54:53] [PASSED] clr-one-set-other
[21:54:53] [PASSED] set-field
[21:54:53] [PASSED] conflict-duplicate
[21:54:53] [PASSED] conflict-not-disjoint
[21:54:53] [PASSED] conflict-not-disjoint-literal-and-func
[21:54:53] [PASSED] conflict-reg-type
[21:54:53] [PASSED] bad-mcr-reg-forced-to-regular
[21:54:53] [PASSED] bad-regular-reg-forced-to-mcr
[21:54:53] =========== [PASSED] xe_rtp_process_to_sr_tests ============
[21:54:53] ================== xe_rtp_process_tests ===================
[21:54:53] [PASSED] active1
[21:54:53] [PASSED] active2
[21:54:53] [PASSED] active-inactive
[21:54:53] [PASSED] inactive-active
[21:54:53] [PASSED] inactive-active-inactive
[21:54:53] [PASSED] inactive-inactive-inactive
[21:54:53] ============== [PASSED] xe_rtp_process_tests ===============
[21:54:53] ===================== [PASSED] xe_rtp ======================
[21:54:53] ==================== xe_wa (1 subtest) =====================
[21:54:53] ======================== xe_wa_gt =========================
[21:54:53] [PASSED] TIGERLAKE B0
[21:54:53] [PASSED] DG1 A0
[21:54:53] [PASSED] DG1 B0
[21:54:53] [PASSED] ALDERLAKE_S A0
[21:54:53] [PASSED] ALDERLAKE_S B0
[21:54:53] [PASSED] ALDERLAKE_S C0
[21:54:53] [PASSED] ALDERLAKE_S D0
[21:54:53] [PASSED] ALDERLAKE_P A0
[21:54:53] [PASSED] ALDERLAKE_P B0
[21:54:53] [PASSED] ALDERLAKE_P C0
[21:54:53] [PASSED] ALDERLAKE_S RPLS D0
[21:54:53] [PASSED] ALDERLAKE_P RPLU E0
[21:54:53] [PASSED] DG2 G10 C0
[21:54:53] [PASSED] DG2 G11 B1
[21:54:53] [PASSED] DG2 G12 A1
[21:54:53] [PASSED] METEORLAKE 12.70(Xe_LPG) A0 13.00(Xe_LPM+) A0
[21:54:53] [PASSED] METEORLAKE 12.71(Xe_LPG) A0 13.00(Xe_LPM+) A0
[21:54:53] [PASSED] METEORLAKE 12.74(Xe_LPG+) A0 13.00(Xe_LPM+) A0
[21:54:53] [PASSED] LUNARLAKE 20.04(Xe2_LPG) A0 20.00(Xe2_LPM) A0
[21:54:53] [PASSED] LUNARLAKE 20.04(Xe2_LPG) B0 20.00(Xe2_LPM) A0
[21:54:53] [PASSED] BATTLEMAGE 20.01(Xe2_HPG) A0 13.01(Xe2_HPM) A1
[21:54:53] [PASSED] PANTHERLAKE 30.00(Xe3_LPG) A0 30.00(Xe3_LPM) A0
[21:54:53] ==================== [PASSED] xe_wa_gt =====================
[21:54:53] ====================== [PASSED] xe_wa ======================
[21:54:53] ============================================================
[21:54:53] Testing complete. Ran 741 tests: passed: 723, skipped: 18
[21:54:53] Elapsed time: 37.263s total, 4.428s configuring, 32.169s building, 0.637s running
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/gpu/drm/tests/.kunitconfig
[21:54:53] Configuring KUnit Kernel ...
Regenerating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[21:54:55] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=48
[21:55:20] Starting KUnit Kernel (1/1)...
[21:55:20] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[21:55:20] ============ drm_test_pick_cmdline (2 subtests) ============
[21:55:20] [PASSED] drm_test_pick_cmdline_res_1920_1080_60
[21:55:20] =============== drm_test_pick_cmdline_named ===============
[21:55:20] [PASSED] NTSC
[21:55:20] [PASSED] NTSC-J
[21:55:20] [PASSED] PAL
[21:55:20] [PASSED] PAL-M
[21:55:20] =========== [PASSED] drm_test_pick_cmdline_named ===========
[21:55:20] ============== [PASSED] drm_test_pick_cmdline ==============
[21:55:20] == drm_test_atomic_get_connector_for_encoder (1 subtest) ===
[21:55:20] [PASSED] drm_test_drm_atomic_get_connector_for_encoder
[21:55:20] ==== [PASSED] drm_test_atomic_get_connector_for_encoder ====
[21:55:20] =========== drm_validate_clone_mode (2 subtests) ===========
[21:55:20] ============== drm_test_check_in_clone_mode ===============
[21:55:20] [PASSED] in_clone_mode
[21:55:20] [PASSED] not_in_clone_mode
[21:55:20] ========== [PASSED] drm_test_check_in_clone_mode ===========
[21:55:20] =============== drm_test_check_valid_clones ===============
[21:55:20] [PASSED] not_in_clone_mode
[21:55:20] [PASSED] valid_clone
[21:55:20] [PASSED] invalid_clone
[21:55:20] =========== [PASSED] drm_test_check_valid_clones ===========
[21:55:20] ============= [PASSED] drm_validate_clone_mode =============
[21:55:20] ============= drm_validate_modeset (1 subtest) =============
[21:55:20] [PASSED] drm_test_check_connector_changed_modeset
[21:55:20] ============== [PASSED] drm_validate_modeset ===============
[21:55:20] ====== drm_test_bridge_get_current_state (1 subtest) =======
[21:55:20] [PASSED] drm_test_drm_bridge_get_current_state_atomic
[21:55:20] ======== [PASSED] drm_test_bridge_get_current_state ========
[21:55:20] ====== drm_test_bridge_helper_reset_crtc (3 subtests) ======
[21:55:20] [PASSED] drm_test_drm_bridge_helper_reset_crtc_atomic
[21:55:20] [PASSED] drm_test_drm_bridge_helper_reset_crtc_atomic_disabled
[21:55:20] [PASSED] drm_test_drm_bridge_helper_hdmi_output_bus_fmts
[21:55:20] ======== [PASSED] drm_test_bridge_helper_reset_crtc ========
[21:55:20] ============== drm_bridge_alloc (2 subtests) ===============
[21:55:20] [PASSED] drm_test_drm_bridge_alloc_basic
[21:55:20] [PASSED] drm_test_drm_bridge_alloc_get_put
[21:55:20] ================ [PASSED] drm_bridge_alloc =================
[21:55:20] ============= drm_bridge_bus_fmt (5 subtests) ==============
[21:55:20] [PASSED] drm_test_bridge_rgb_yuv_rgb
[21:55:20] [PASSED] drm_test_bridge_must_convert_to_yuv444
[21:55:20] [PASSED] drm_test_bridge_hdmi_auto_rgb
[21:55:20] [PASSED] drm_test_bridge_auto_first
[21:55:20] [PASSED] drm_test_bridge_rgb_yuv_no_path
[21:55:20] =============== [PASSED] drm_bridge_bus_fmt ================
[21:55:20] ============= drm_cmdline_parser (40 subtests) =============
[21:55:20] [PASSED] drm_test_cmdline_force_d_only
[21:55:20] [PASSED] drm_test_cmdline_force_D_only_dvi
[21:55:20] [PASSED] drm_test_cmdline_force_D_only_hdmi
[21:55:20] [PASSED] drm_test_cmdline_force_D_only_not_digital
[21:55:20] [PASSED] drm_test_cmdline_force_e_only
[21:55:20] [PASSED] drm_test_cmdline_res
[21:55:20] [PASSED] drm_test_cmdline_res_vesa
[21:55:20] [PASSED] drm_test_cmdline_res_vesa_rblank
[21:55:20] [PASSED] drm_test_cmdline_res_rblank
[21:55:20] [PASSED] drm_test_cmdline_res_bpp
[21:55:20] [PASSED] drm_test_cmdline_res_refresh
[21:55:20] [PASSED] drm_test_cmdline_res_bpp_refresh
[21:55:20] [PASSED] drm_test_cmdline_res_bpp_refresh_interlaced
[21:55:20] [PASSED] drm_test_cmdline_res_bpp_refresh_margins
[21:55:20] [PASSED] drm_test_cmdline_res_bpp_refresh_force_off
[21:55:20] [PASSED] drm_test_cmdline_res_bpp_refresh_force_on
[21:55:20] [PASSED] drm_test_cmdline_res_bpp_refresh_force_on_analog
[21:55:20] [PASSED] drm_test_cmdline_res_bpp_refresh_force_on_digital
[21:55:20] [PASSED] drm_test_cmdline_res_bpp_refresh_interlaced_margins_force_on
[21:55:20] [PASSED] drm_test_cmdline_res_margins_force_on
[21:55:20] [PASSED] drm_test_cmdline_res_vesa_margins
[21:55:20] [PASSED] drm_test_cmdline_name
[21:55:20] [PASSED] drm_test_cmdline_name_bpp
[21:55:20] [PASSED] drm_test_cmdline_name_option
[21:55:20] [PASSED] drm_test_cmdline_name_bpp_option
[21:55:20] [PASSED] drm_test_cmdline_rotate_0
[21:55:20] [PASSED] drm_test_cmdline_rotate_90
[21:55:20] [PASSED] drm_test_cmdline_rotate_180
[21:55:20] [PASSED] drm_test_cmdline_rotate_270
[21:55:20] [PASSED] drm_test_cmdline_hmirror
[21:55:20] [PASSED] drm_test_cmdline_vmirror
[21:55:20] [PASSED] drm_test_cmdline_margin_options
[21:55:20] [PASSED] drm_test_cmdline_multiple_options
[21:55:20] [PASSED] drm_test_cmdline_bpp_extra_and_option
[21:55:20] [PASSED] drm_test_cmdline_extra_and_option
[21:55:20] [PASSED] drm_test_cmdline_freestanding_options
[21:55:20] [PASSED] drm_test_cmdline_freestanding_force_e_and_options
[21:55:20] [PASSED] drm_test_cmdline_panel_orientation
[21:55:20] ================ drm_test_cmdline_invalid =================
[21:55:20] [PASSED] margin_only
[21:55:20] [PASSED] interlace_only
[21:55:20] [PASSED] res_missing_x
[21:55:20] [PASSED] res_missing_y
[21:55:20] [PASSED] res_bad_y
[21:55:20] [PASSED] res_missing_y_bpp
[21:55:20] [PASSED] res_bad_bpp
[21:55:20] [PASSED] res_bad_refresh
[21:55:20] [PASSED] res_bpp_refresh_force_on_off
[21:55:20] [PASSED] res_invalid_mode
[21:55:20] [PASSED] res_bpp_wrong_place_mode
[21:55:20] [PASSED] name_bpp_refresh
[21:55:20] [PASSED] name_refresh
[21:55:20] [PASSED] name_refresh_wrong_mode
[21:55:20] [PASSED] name_refresh_invalid_mode
[21:55:20] [PASSED] rotate_multiple
[21:55:20] [PASSED] rotate_invalid_val
[21:55:20] [PASSED] rotate_truncated
[21:55:20] [PASSED] invalid_option
[21:55:20] [PASSED] invalid_tv_option
[21:55:20] [PASSED] truncated_tv_option
[21:55:20] ============ [PASSED] drm_test_cmdline_invalid =============
[21:55:20] =============== drm_test_cmdline_tv_options ===============
[21:55:20] [PASSED] NTSC
[21:55:20] [PASSED] NTSC_443
[21:55:20] [PASSED] NTSC_J
[21:55:20] [PASSED] PAL
[21:55:20] [PASSED] PAL_M
[21:55:20] [PASSED] PAL_N
[21:55:20] [PASSED] SECAM
[21:55:20] [PASSED] MONO_525
[21:55:20] [PASSED] MONO_625
[21:55:20] =========== [PASSED] drm_test_cmdline_tv_options ===========
[21:55:20] =============== [PASSED] drm_cmdline_parser ================
[21:55:20] ========== drmm_connector_hdmi_init (20 subtests) ==========
[21:55:20] [PASSED] drm_test_connector_hdmi_init_valid
[21:55:20] [PASSED] drm_test_connector_hdmi_init_bpc_8
[21:55:20] [PASSED] drm_test_connector_hdmi_init_bpc_10
[21:55:20] [PASSED] drm_test_connector_hdmi_init_bpc_12
[21:55:20] [PASSED] drm_test_connector_hdmi_init_bpc_invalid
[21:55:20] [PASSED] drm_test_connector_hdmi_init_bpc_null
[21:55:20] [PASSED] drm_test_connector_hdmi_init_formats_empty
[21:55:20] [PASSED] drm_test_connector_hdmi_init_formats_no_rgb
[21:55:20] === drm_test_connector_hdmi_init_formats_yuv420_allowed ===
[21:55:20] [PASSED] supported_formats=0x9 yuv420_allowed=1
[21:55:20] [PASSED] supported_formats=0x9 yuv420_allowed=0
[21:55:20] [PASSED] supported_formats=0x5 yuv420_allowed=1
[21:55:20] [PASSED] supported_formats=0x5 yuv420_allowed=0
[21:55:20] === [PASSED] drm_test_connector_hdmi_init_formats_yuv420_allowed ===
[21:55:20] [PASSED] drm_test_connector_hdmi_init_null_ddc
[21:55:20] [PASSED] drm_test_connector_hdmi_init_null_product
[21:55:20] [PASSED] drm_test_connector_hdmi_init_null_vendor
[21:55:20] [PASSED] drm_test_connector_hdmi_init_product_length_exact
[21:55:20] [PASSED] drm_test_connector_hdmi_init_product_length_too_long
[21:55:20] [PASSED] drm_test_connector_hdmi_init_product_valid
[21:55:20] [PASSED] drm_test_connector_hdmi_init_vendor_length_exact
[21:55:20] [PASSED] drm_test_connector_hdmi_init_vendor_length_too_long
[21:55:20] [PASSED] drm_test_connector_hdmi_init_vendor_valid
[21:55:20] ========= drm_test_connector_hdmi_init_type_valid =========
[21:55:20] [PASSED] HDMI-A
[21:55:20] [PASSED] HDMI-B
[21:55:20] ===== [PASSED] drm_test_connector_hdmi_init_type_valid =====
[21:55:20] ======== drm_test_connector_hdmi_init_type_invalid ========
[21:55:20] [PASSED] Unknown
[21:55:20] [PASSED] VGA
[21:55:20] [PASSED] DVI-I
[21:55:20] [PASSED] DVI-D
[21:55:20] [PASSED] DVI-A
[21:55:20] [PASSED] Composite
[21:55:20] [PASSED] SVIDEO
[21:55:20] [PASSED] LVDS
[21:55:20] [PASSED] Component
[21:55:20] [PASSED] DIN
[21:55:20] [PASSED] DP
[21:55:20] [PASSED] TV
[21:55:20] [PASSED] eDP
[21:55:20] [PASSED] Virtual
[21:55:20] [PASSED] DSI
[21:55:20] [PASSED] DPI
[21:55:20] [PASSED] Writeback
[21:55:20] [PASSED] SPI
[21:55:20] [PASSED] USB
[21:55:20] ==== [PASSED] drm_test_connector_hdmi_init_type_invalid ====
[21:55:20] ============ [PASSED] drmm_connector_hdmi_init =============
[21:55:20] ============= drmm_connector_init (3 subtests) =============
[21:55:20] [PASSED] drm_test_drmm_connector_init
[21:55:20] [PASSED] drm_test_drmm_connector_init_null_ddc
[21:55:20] ========= drm_test_drmm_connector_init_type_valid =========
[21:55:20] [PASSED] Unknown
[21:55:20] [PASSED] VGA
[21:55:20] [PASSED] DVI-I
[21:55:20] [PASSED] DVI-D
[21:55:20] [PASSED] DVI-A
[21:55:20] [PASSED] Composite
[21:55:20] [PASSED] SVIDEO
[21:55:20] [PASSED] LVDS
[21:55:20] [PASSED] Component
[21:55:20] [PASSED] DIN
[21:55:20] [PASSED] DP
[21:55:20] [PASSED] HDMI-A
[21:55:20] [PASSED] HDMI-B
[21:55:20] [PASSED] TV
[21:55:20] [PASSED] eDP
[21:55:20] [PASSED] Virtual
[21:55:20] [PASSED] DSI
[21:55:20] [PASSED] DPI
[21:55:20] [PASSED] Writeback
[21:55:20] [PASSED] SPI
[21:55:20] [PASSED] USB
[21:55:20] ===== [PASSED] drm_test_drmm_connector_init_type_valid =====
[21:55:20] =============== [PASSED] drmm_connector_init ===============
[21:55:20] ========= drm_connector_dynamic_init (6 subtests) ==========
[21:55:20] [PASSED] drm_test_drm_connector_dynamic_init
[21:55:20] [PASSED] drm_test_drm_connector_dynamic_init_null_ddc
[21:55:20] [PASSED] drm_test_drm_connector_dynamic_init_not_added
[21:55:20] [PASSED] drm_test_drm_connector_dynamic_init_properties
[21:55:20] ===== drm_test_drm_connector_dynamic_init_type_valid ======
[21:55:20] [PASSED] Unknown
[21:55:20] [PASSED] VGA
[21:55:20] [PASSED] DVI-I
[21:55:20] [PASSED] DVI-D
[21:55:20] [PASSED] DVI-A
[21:55:20] [PASSED] Composite
[21:55:20] [PASSED] SVIDEO
[21:55:20] [PASSED] LVDS
[21:55:20] [PASSED] Component
[21:55:20] [PASSED] DIN
[21:55:20] [PASSED] DP
[21:55:20] [PASSED] HDMI-A
[21:55:20] [PASSED] HDMI-B
[21:55:20] [PASSED] TV
[21:55:20] [PASSED] eDP
[21:55:20] [PASSED] Virtual
[21:55:20] [PASSED] DSI
[21:55:20] [PASSED] DPI
[21:55:20] [PASSED] Writeback
[21:55:20] [PASSED] SPI
[21:55:20] [PASSED] USB
[21:55:20] = [PASSED] drm_test_drm_connector_dynamic_init_type_valid ==
[21:55:20] ======== drm_test_drm_connector_dynamic_init_name =========
[21:55:20] [PASSED] Unknown
[21:55:20] [PASSED] VGA
[21:55:20] [PASSED] DVI-I
[21:55:20] [PASSED] DVI-D
[21:55:20] [PASSED] DVI-A
[21:55:20] [PASSED] Composite
[21:55:20] [PASSED] SVIDEO
[21:55:20] [PASSED] LVDS
[21:55:20] [PASSED] Component
[21:55:20] [PASSED] DIN
[21:55:20] [PASSED] DP
[21:55:20] [PASSED] HDMI-A
[21:55:20] [PASSED] HDMI-B
[21:55:20] [PASSED] TV
[21:55:20] [PASSED] eDP
[21:55:20] [PASSED] Virtual
[21:55:20] [PASSED] DSI
[21:55:20] [PASSED] DPI
[21:55:20] [PASSED] Writeback
[21:55:20] [PASSED] SPI
[21:55:20] [PASSED] USB
[21:55:20] ==== [PASSED] drm_test_drm_connector_dynamic_init_name =====
[21:55:20] =========== [PASSED] drm_connector_dynamic_init ============
[21:55:20] ==== drm_connector_dynamic_register_early (4 subtests) =====
[21:55:20] [PASSED] drm_test_drm_connector_dynamic_register_early_on_list
[21:55:20] [PASSED] drm_test_drm_connector_dynamic_register_early_defer
[21:55:20] [PASSED] drm_test_drm_connector_dynamic_register_early_no_init
[21:55:20] [PASSED] drm_test_drm_connector_dynamic_register_early_no_mode_object
[21:55:20] ====== [PASSED] drm_connector_dynamic_register_early =======
[21:55:20] ======= drm_connector_dynamic_register (7 subtests) ========
[21:55:20] [PASSED] drm_test_drm_connector_dynamic_register_on_list
[21:55:20] [PASSED] drm_test_drm_connector_dynamic_register_no_defer
[21:55:20] [PASSED] drm_test_drm_connector_dynamic_register_no_init
[21:55:20] [PASSED] drm_test_drm_connector_dynamic_register_mode_object
[21:55:20] [PASSED] drm_test_drm_connector_dynamic_register_sysfs
[21:55:20] [PASSED] drm_test_drm_connector_dynamic_register_sysfs_name
[21:55:20] [PASSED] drm_test_drm_connector_dynamic_register_debugfs
[21:55:20] ========= [PASSED] drm_connector_dynamic_register ==========
[21:55:20] = drm_connector_attach_broadcast_rgb_property (2 subtests) =
[21:55:20] [PASSED] drm_test_drm_connector_attach_broadcast_rgb_property
[21:55:20] [PASSED] drm_test_drm_connector_attach_broadcast_rgb_property_hdmi_connector
[21:55:20] === [PASSED] drm_connector_attach_broadcast_rgb_property ===
[21:55:20] ========== drm_get_tv_mode_from_name (2 subtests) ==========
[21:55:20] ========== drm_test_get_tv_mode_from_name_valid ===========
[21:55:20] [PASSED] NTSC
[21:55:20] [PASSED] NTSC-443
[21:55:20] [PASSED] NTSC-J
[21:55:20] [PASSED] PAL
[21:55:20] [PASSED] PAL-M
[21:55:20] [PASSED] PAL-N
[21:55:20] [PASSED] SECAM
[21:55:20] [PASSED] Mono
[21:55:20] ====== [PASSED] drm_test_get_tv_mode_from_name_valid =======
[21:55:20] [PASSED] drm_test_get_tv_mode_from_name_truncated
[21:55:20] ============ [PASSED] drm_get_tv_mode_from_name ============
[21:55:20] = drm_test_connector_hdmi_compute_mode_clock (12 subtests) =
[21:55:20] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb
[21:55:20] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc
[21:55:20] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc_vic_1
[21:55:20] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc
[21:55:20] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc_vic_1
[21:55:20] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_double
[21:55:20] = drm_test_connector_hdmi_compute_mode_clock_yuv420_valid =
[21:55:20] [PASSED] VIC 96
[21:55:20] [PASSED] VIC 97
[21:55:20] [PASSED] VIC 101
[21:55:20] [PASSED] VIC 102
[21:55:20] [PASSED] VIC 106
[21:55:20] [PASSED] VIC 107
[21:55:20] === [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv420_valid ===
[21:55:20] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv420_10_bpc
[21:55:20] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv420_12_bpc
[21:55:20] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv422_8_bpc
[21:55:20] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv422_10_bpc
[21:55:20] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv422_12_bpc
[21:55:20] === [PASSED] drm_test_connector_hdmi_compute_mode_clock ====
[21:55:20] == drm_hdmi_connector_get_broadcast_rgb_name (2 subtests) ==
[21:55:20] === drm_test_drm_hdmi_connector_get_broadcast_rgb_name ====
[21:55:20] [PASSED] Automatic
[21:55:20] [PASSED] Full
[21:55:20] [PASSED] Limited 16:235
[21:55:20] === [PASSED] drm_test_drm_hdmi_connector_get_broadcast_rgb_name ===
[21:55:20] [PASSED] drm_test_drm_hdmi_connector_get_broadcast_rgb_name_invalid
[21:55:20] ==== [PASSED] drm_hdmi_connector_get_broadcast_rgb_name ====
[21:55:20] == drm_hdmi_connector_get_output_format_name (2 subtests) ==
[21:55:20] === drm_test_drm_hdmi_connector_get_output_format_name ====
[21:55:20] [PASSED] RGB
[21:55:20] [PASSED] YUV 4:2:0
[21:55:20] [PASSED] YUV 4:2:2
[21:55:20] [PASSED] YUV 4:4:4
[21:55:20] === [PASSED] drm_test_drm_hdmi_connector_get_output_format_name ===
[21:55:20] [PASSED] drm_test_drm_hdmi_connector_get_output_format_name_invalid
[21:55:20] ==== [PASSED] drm_hdmi_connector_get_output_format_name ====
[21:55:20] ============= drm_damage_helper (21 subtests) ==============
[21:55:20] [PASSED] drm_test_damage_iter_no_damage
[21:55:20] [PASSED] drm_test_damage_iter_no_damage_fractional_src
[21:55:20] [PASSED] drm_test_damage_iter_no_damage_src_moved
[21:55:20] [PASSED] drm_test_damage_iter_no_damage_fractional_src_moved
[21:55:20] [PASSED] drm_test_damage_iter_no_damage_not_visible
[21:55:20] [PASSED] drm_test_damage_iter_no_damage_no_crtc
[21:55:20] [PASSED] drm_test_damage_iter_no_damage_no_fb
[21:55:20] [PASSED] drm_test_damage_iter_simple_damage
[21:55:20] [PASSED] drm_test_damage_iter_single_damage
[21:55:20] [PASSED] drm_test_damage_iter_single_damage_intersect_src
[21:55:20] [PASSED] drm_test_damage_iter_single_damage_outside_src
[21:55:20] [PASSED] drm_test_damage_iter_single_damage_fractional_src
[21:55:20] [PASSED] drm_test_damage_iter_single_damage_intersect_fractional_src
[21:55:20] [PASSED] drm_test_damage_iter_single_damage_outside_fractional_src
[21:55:20] [PASSED] drm_test_damage_iter_single_damage_src_moved
[21:55:20] [PASSED] drm_test_damage_iter_single_damage_fractional_src_moved
[21:55:20] [PASSED] drm_test_damage_iter_damage
[21:55:20] [PASSED] drm_test_damage_iter_damage_one_intersect
[21:55:20] [PASSED] drm_test_damage_iter_damage_one_outside
[21:55:20] [PASSED] drm_test_damage_iter_damage_src_moved
[21:55:20] [PASSED] drm_test_damage_iter_damage_not_visible
[21:55:20] ================ [PASSED] drm_damage_helper ================
[21:55:20] ============== drm_dp_mst_helper (3 subtests) ==============
[21:55:20] ============== drm_test_dp_mst_calc_pbn_mode ==============
[21:55:20] [PASSED] Clock 154000 BPP 30 DSC disabled
[21:55:20] [PASSED] Clock 234000 BPP 30 DSC disabled
[21:55:20] [PASSED] Clock 297000 BPP 24 DSC disabled
[21:55:20] [PASSED] Clock 332880 BPP 24 DSC enabled
[21:55:20] [PASSED] Clock 324540 BPP 24 DSC enabled
[21:55:20] ========== [PASSED] drm_test_dp_mst_calc_pbn_mode ==========
[21:55:20] ============== drm_test_dp_mst_calc_pbn_div ===============
[21:55:20] [PASSED] Link rate 2000000 lane count 4
[21:55:20] [PASSED] Link rate 2000000 lane count 2
[21:55:20] [PASSED] Link rate 2000000 lane count 1
[21:55:20] [PASSED] Link rate 1350000 lane count 4
[21:55:20] [PASSED] Link rate 1350000 lane count 2
[21:55:20] [PASSED] Link rate 1350000 lane count 1
[21:55:20] [PASSED] Link rate 1000000 lane count 4
[21:55:20] [PASSED] Link rate 1000000 lane count 2
[21:55:20] [PASSED] Link rate 1000000 lane count 1
[21:55:20] [PASSED] Link rate 810000 lane count 4
[21:55:20] [PASSED] Link rate 810000 lane count 2
[21:55:20] [PASSED] Link rate 810000 lane count 1
[21:55:20] [PASSED] Link rate 540000 lane count 4
[21:55:20] [PASSED] Link rate 540000 lane count 2
[21:55:20] [PASSED] Link rate 540000 lane count 1
[21:55:20] [PASSED] Link rate 270000 lane count 4
[21:55:20] [PASSED] Link rate 270000 lane count 2
[21:55:20] [PASSED] Link rate 270000 lane count 1
[21:55:20] [PASSED] Link rate 162000 lane count 4
[21:55:20] [PASSED] Link rate 162000 lane count 2
[21:55:20] [PASSED] Link rate 162000 lane count 1
[21:55:20] ========== [PASSED] drm_test_dp_mst_calc_pbn_div ===========
[21:55:20] ========= drm_test_dp_mst_sideband_msg_req_decode =========
[21:55:20] [PASSED] DP_ENUM_PATH_RESOURCES with port number
[21:55:20] [PASSED] DP_POWER_UP_PHY with port number
[21:55:20] [PASSED] DP_POWER_DOWN_PHY with port number
[21:55:20] [PASSED] DP_ALLOCATE_PAYLOAD with SDP stream sinks
[21:55:20] [PASSED] DP_ALLOCATE_PAYLOAD with port number
[21:55:20] [PASSED] DP_ALLOCATE_PAYLOAD with VCPI
[21:55:20] [PASSED] DP_ALLOCATE_PAYLOAD with PBN
[21:55:20] [PASSED] DP_QUERY_PAYLOAD with port number
[21:55:20] [PASSED] DP_QUERY_PAYLOAD with VCPI
[21:55:20] [PASSED] DP_REMOTE_DPCD_READ with port number
[21:55:20] [PASSED] DP_REMOTE_DPCD_READ with DPCD address
[21:55:20] [PASSED] DP_REMOTE_DPCD_READ with max number of bytes
[21:55:20] [PASSED] DP_REMOTE_DPCD_WRITE with port number
[21:55:20] [PASSED] DP_REMOTE_DPCD_WRITE with DPCD address
[21:55:20] [PASSED] DP_REMOTE_DPCD_WRITE with data array
[21:55:20] [PASSED] DP_REMOTE_I2C_READ with port number
[21:55:20] [PASSED] DP_REMOTE_I2C_READ with I2C device ID
[21:55:20] [PASSED] DP_REMOTE_I2C_READ with transactions array
[21:55:20] [PASSED] DP_REMOTE_I2C_WRITE with port number
[21:55:20] [PASSED] DP_REMOTE_I2C_WRITE with I2C device ID
[21:55:20] [PASSED] DP_REMOTE_I2C_WRITE with data array
[21:55:20] [PASSED] DP_QUERY_STREAM_ENC_STATUS with stream ID
[21:55:20] [PASSED] DP_QUERY_STREAM_ENC_STATUS with client ID
[21:55:20] [PASSED] DP_QUERY_STREAM_ENC_STATUS with stream event
[21:55:20] [PASSED] DP_QUERY_STREAM_ENC_STATUS with valid stream event
[21:55:20] [PASSED] DP_QUERY_STREAM_ENC_STATUS with stream behavior
[21:55:20] [PASSED] DP_QUERY_STREAM_ENC_STATUS with a valid stream behavior
[21:55:20] ===== [PASSED] drm_test_dp_mst_sideband_msg_req_decode =====
[21:55:20] ================ [PASSED] drm_dp_mst_helper ================
[21:55:20] ================== drm_exec (7 subtests) ===================
[21:55:20] [PASSED] sanitycheck
[21:55:20] [PASSED] test_lock
[21:55:20] [PASSED] test_lock_unlock
[21:55:20] [PASSED] test_duplicates
[21:55:20] [PASSED] test_prepare
[21:55:20] [PASSED] test_prepare_array
[21:55:20] [PASSED] test_multiple_loops
[21:55:20] ==================== [PASSED] drm_exec =====================
[21:55:20] =========== drm_format_helper_test (17 subtests) ===========
[21:55:20] ============== drm_test_fb_xrgb8888_to_gray8 ==============
[21:55:20] [PASSED] single_pixel_source_buffer
[21:55:20] [PASSED] single_pixel_clip_rectangle
[21:55:20] [PASSED] well_known_colors
[21:55:20] [PASSED] destination_pitch
[21:55:20] ========== [PASSED] drm_test_fb_xrgb8888_to_gray8 ==========
[21:55:20] ============= drm_test_fb_xrgb8888_to_rgb332 ==============
[21:55:20] [PASSED] single_pixel_source_buffer
[21:55:20] [PASSED] single_pixel_clip_rectangle
[21:55:20] [PASSED] well_known_colors
[21:55:20] [PASSED] destination_pitch
[21:55:20] ========= [PASSED] drm_test_fb_xrgb8888_to_rgb332 ==========
[21:55:20] ============= drm_test_fb_xrgb8888_to_rgb565 ==============
[21:55:20] [PASSED] single_pixel_source_buffer
[21:55:20] [PASSED] single_pixel_clip_rectangle
[21:55:20] [PASSED] well_known_colors
[21:55:20] [PASSED] destination_pitch
[21:55:20] ========= [PASSED] drm_test_fb_xrgb8888_to_rgb565 ==========
[21:55:20] ============ drm_test_fb_xrgb8888_to_xrgb1555 =============
[21:55:20] [PASSED] single_pixel_source_buffer
[21:55:20] [PASSED] single_pixel_clip_rectangle
[21:55:20] [PASSED] well_known_colors
[21:55:20] [PASSED] destination_pitch
[21:55:20] ======== [PASSED] drm_test_fb_xrgb8888_to_xrgb1555 =========
[21:55:20] ============ drm_test_fb_xrgb8888_to_argb1555 =============
[21:55:20] [PASSED] single_pixel_source_buffer
[21:55:20] [PASSED] single_pixel_clip_rectangle
[21:55:20] [PASSED] well_known_colors
[21:55:20] [PASSED] destination_pitch
[21:55:20] ======== [PASSED] drm_test_fb_xrgb8888_to_argb1555 =========
[21:55:20] ============ drm_test_fb_xrgb8888_to_rgba5551 =============
[21:55:20] [PASSED] single_pixel_source_buffer
[21:55:20] [PASSED] single_pixel_clip_rectangle
[21:55:20] [PASSED] well_known_colors
[21:55:20] [PASSED] destination_pitch
[21:55:20] ======== [PASSED] drm_test_fb_xrgb8888_to_rgba5551 =========
[21:55:20] ============= drm_test_fb_xrgb8888_to_rgb888 ==============
[21:55:20] [PASSED] single_pixel_source_buffer
[21:55:20] [PASSED] single_pixel_clip_rectangle
[21:55:20] [PASSED] well_known_colors
[21:55:20] [PASSED] destination_pitch
[21:55:20] ========= [PASSED] drm_test_fb_xrgb8888_to_rgb888 ==========
[21:55:20] ============= drm_test_fb_xrgb8888_to_bgr888 ==============
[21:55:20] [PASSED] single_pixel_source_buffer
[21:55:20] [PASSED] single_pixel_clip_rectangle
[21:55:20] [PASSED] well_known_colors
[21:55:20] [PASSED] destination_pitch
[21:55:20] ========= [PASSED] drm_test_fb_xrgb8888_to_bgr888 ==========
[21:55:20] ============ drm_test_fb_xrgb8888_to_argb8888 =============
[21:55:20] [PASSED] single_pixel_source_buffer
[21:55:20] [PASSED] single_pixel_clip_rectangle
[21:55:20] [PASSED] well_known_colors
[21:55:20] [PASSED] destination_pitch
[21:55:20] ======== [PASSED] drm_test_fb_xrgb8888_to_argb8888 =========
[21:55:20] =========== drm_test_fb_xrgb8888_to_xrgb2101010 ===========
[21:55:20] [PASSED] single_pixel_source_buffer
[21:55:20] [PASSED] single_pixel_clip_rectangle
[21:55:20] [PASSED] well_known_colors
[21:55:20] [PASSED] destination_pitch
[21:55:20] ======= [PASSED] drm_test_fb_xrgb8888_to_xrgb2101010 =======
[21:55:20] =========== drm_test_fb_xrgb8888_to_argb2101010 ===========
[21:55:20] [PASSED] single_pixel_source_buffer
[21:55:20] [PASSED] single_pixel_clip_rectangle
[21:55:20] [PASSED] well_known_colors
[21:55:20] [PASSED] destination_pitch
[21:55:20] ======= [PASSED] drm_test_fb_xrgb8888_to_argb2101010 =======
[21:55:20] ============== drm_test_fb_xrgb8888_to_mono ===============
[21:55:20] [PASSED] single_pixel_source_buffer
[21:55:20] [PASSED] single_pixel_clip_rectangle
[21:55:20] [PASSED] well_known_colors
[21:55:20] [PASSED] destination_pitch
[21:55:20] ========== [PASSED] drm_test_fb_xrgb8888_to_mono ===========
[21:55:20] ==================== drm_test_fb_swab =====================
[21:55:20] [PASSED] single_pixel_source_buffer
[21:55:20] [PASSED] single_pixel_clip_rectangle
[21:55:20] [PASSED] well_known_colors
[21:55:20] [PASSED] destination_pitch
[21:55:20] ================ [PASSED] drm_test_fb_swab =================
[21:55:20] ============ drm_test_fb_xrgb8888_to_xbgr8888 =============
[21:55:20] [PASSED] single_pixel_source_buffer
[21:55:20] [PASSED] single_pixel_clip_rectangle
[21:55:20] [PASSED] well_known_colors
[21:55:20] [PASSED] destination_pitch
[21:55:20] ======== [PASSED] drm_test_fb_xrgb8888_to_xbgr8888 =========
[21:55:20] ============ drm_test_fb_xrgb8888_to_abgr8888 =============
[21:55:20] [PASSED] single_pixel_source_buffer
[21:55:20] [PASSED] single_pixel_clip_rectangle
[21:55:20] [PASSED] well_known_colors
[21:55:20] [PASSED] destination_pitch
[21:55:20] ======== [PASSED] drm_test_fb_xrgb8888_to_abgr8888 =========
[21:55:20] ================= drm_test_fb_clip_offset =================
[21:55:20] [PASSED] pass through
[21:55:20] [PASSED] horizontal offset
[21:55:20] [PASSED] vertical offset
[21:55:20] [PASSED] horizontal and vertical offset
[21:55:20] [PASSED] horizontal offset (custom pitch)
[21:55:20] [PASSED] vertical offset (custom pitch)
[21:55:20] [PASSED] horizontal and vertical offset (custom pitch)
[21:55:20] ============= [PASSED] drm_test_fb_clip_offset =============
[21:55:20] =================== drm_test_fb_memcpy ====================
[21:55:20] [PASSED] single_pixel_source_buffer: XR24 little-endian (0x34325258)
[21:55:20] [PASSED] single_pixel_source_buffer: XRA8 little-endian (0x38415258)
[21:55:20] [PASSED] single_pixel_source_buffer: YU24 little-endian (0x34325559)
[21:55:20] [PASSED] single_pixel_clip_rectangle: XB24 little-endian (0x34324258)
[21:55:20] [PASSED] single_pixel_clip_rectangle: XRA8 little-endian (0x38415258)
[21:55:20] [PASSED] single_pixel_clip_rectangle: YU24 little-endian (0x34325559)
[21:55:20] [PASSED] well_known_colors: XB24 little-endian (0x34324258)
[21:55:20] [PASSED] well_known_colors: XRA8 little-endian (0x38415258)
[21:55:20] [PASSED] well_known_colors: YU24 little-endian (0x34325559)
[21:55:20] [PASSED] destination_pitch: XB24 little-endian (0x34324258)
[21:55:20] [PASSED] destination_pitch: XRA8 little-endian (0x38415258)
[21:55:20] [PASSED] destination_pitch: YU24 little-endian (0x34325559)
[21:55:20] =============== [PASSED] drm_test_fb_memcpy ================
[21:55:20] ============= [PASSED] drm_format_helper_test ==============
[21:55:20] ================= drm_format (18 subtests) =================
[21:55:20] [PASSED] drm_test_format_block_width_invalid
[21:55:20] [PASSED] drm_test_format_block_width_one_plane
[21:55:20] [PASSED] drm_test_format_block_width_two_plane
[21:55:20] [PASSED] drm_test_format_block_width_three_plane
[21:55:20] [PASSED] drm_test_format_block_width_tiled
[21:55:20] [PASSED] drm_test_format_block_height_invalid
[21:55:20] [PASSED] drm_test_format_block_height_one_plane
[21:55:20] [PASSED] drm_test_format_block_height_two_plane
[21:55:20] [PASSED] drm_test_format_block_height_three_plane
[21:55:20] [PASSED] drm_test_format_block_height_tiled
[21:55:20] [PASSED] drm_test_format_min_pitch_invalid
[21:55:20] [PASSED] drm_test_format_min_pitch_one_plane_8bpp
[21:55:20] [PASSED] drm_test_format_min_pitch_one_plane_16bpp
[21:55:20] [PASSED] drm_test_format_min_pitch_one_plane_24bpp
[21:55:20] [PASSED] drm_test_format_min_pitch_one_plane_32bpp
[21:55:20] [PASSED] drm_test_format_min_pitch_two_plane
[21:55:20] [PASSED] drm_test_format_min_pitch_three_plane_8bpp
[21:55:20] [PASSED] drm_test_format_min_pitch_tiled
[21:55:20] =================== [PASSED] drm_format ====================
[21:55:20] ============== drm_framebuffer (10 subtests) ===============
[21:55:20] ========== drm_test_framebuffer_check_src_coords ==========
[21:55:20] [PASSED] Success: source fits into fb
[21:55:20] [PASSED] Fail: overflowing fb with x-axis coordinate
[21:55:20] [PASSED] Fail: overflowing fb with y-axis coordinate
[21:55:20] [PASSED] Fail: overflowing fb with source width
[21:55:20] [PASSED] Fail: overflowing fb with source height
[21:55:20] ====== [PASSED] drm_test_framebuffer_check_src_coords ======
[21:55:20] [PASSED] drm_test_framebuffer_cleanup
[21:55:20] =============== drm_test_framebuffer_create ===============
[21:55:20] [PASSED] ABGR8888 normal sizes
[21:55:20] [PASSED] ABGR8888 max sizes
[21:55:20] [PASSED] ABGR8888 pitch greater than min required
[21:55:20] [PASSED] ABGR8888 pitch less than min required
[21:55:20] [PASSED] ABGR8888 Invalid width
[21:55:20] [PASSED] ABGR8888 Invalid buffer handle
[21:55:20] [PASSED] No pixel format
[21:55:20] [PASSED] ABGR8888 Width 0
[21:55:20] [PASSED] ABGR8888 Height 0
[21:55:20] [PASSED] ABGR8888 Out of bound height * pitch combination
[21:55:20] [PASSED] ABGR8888 Large buffer offset
[21:55:20] [PASSED] ABGR8888 Buffer offset for inexistent plane
[21:55:20] [PASSED] ABGR8888 Invalid flag
[21:55:20] [PASSED] ABGR8888 Set DRM_MODE_FB_MODIFIERS without modifiers
[21:55:20] [PASSED] ABGR8888 Valid buffer modifier
[21:55:20] [PASSED] ABGR8888 Invalid buffer modifier(DRM_FORMAT_MOD_SAMSUNG_64_32_TILE)
[21:55:20] [PASSED] ABGR8888 Extra pitches without DRM_MODE_FB_MODIFIERS
[21:55:20] [PASSED] ABGR8888 Extra pitches with DRM_MODE_FB_MODIFIERS
[21:55:20] [PASSED] NV12 Normal sizes
[21:55:20] [PASSED] NV12 Max sizes
[21:55:20] [PASSED] NV12 Invalid pitch
[21:55:20] [PASSED] NV12 Invalid modifier/missing DRM_MODE_FB_MODIFIERS flag
[21:55:20] [PASSED] NV12 different modifier per-plane
[21:55:20] [PASSED] NV12 with DRM_FORMAT_MOD_SAMSUNG_64_32_TILE
[21:55:20] [PASSED] NV12 Valid modifiers without DRM_MODE_FB_MODIFIERS
[21:55:20] [PASSED] NV12 Modifier for inexistent plane
[21:55:20] [PASSED] NV12 Handle for inexistent plane
[21:55:20] [PASSED] NV12 Handle for inexistent plane without DRM_MODE_FB_MODIFIERS
[21:55:20] [PASSED] YVU420 DRM_MODE_FB_MODIFIERS set without modifier
[21:55:20] [PASSED] YVU420 Normal sizes
[21:55:20] [PASSED] YVU420 Max sizes
[21:55:20] [PASSED] YVU420 Invalid pitch
[21:55:20] [PASSED] YVU420 Different pitches
[21:55:20] [PASSED] YVU420 Different buffer offsets/pitches
[21:55:20] [PASSED] YVU420 Modifier set just for plane 0, without DRM_MODE_FB_MODIFIERS
[21:55:20] [PASSED] YVU420 Modifier set just for planes 0, 1, without DRM_MODE_FB_MODIFIERS
[21:55:20] [PASSED] YVU420 Modifier set just for plane 0, 1, with DRM_MODE_FB_MODIFIERS
[21:55:20] [PASSED] YVU420 Valid modifier
[21:55:20] [PASSED] YVU420 Different modifiers per plane
[21:55:20] [PASSED] YVU420 Modifier for inexistent plane
[21:55:20] [PASSED] YUV420_10BIT Invalid modifier(DRM_FORMAT_MOD_LINEAR)
[21:55:20] [PASSED] X0L2 Normal sizes
[21:55:20] [PASSED] X0L2 Max sizes
[21:55:20] [PASSED] X0L2 Invalid pitch
[21:55:20] [PASSED] X0L2 Pitch greater than minimum required
[21:55:20] [PASSED] X0L2 Handle for inexistent plane
[21:55:20] [PASSED] X0L2 Offset for inexistent plane, without DRM_MODE_FB_MODIFIERS set
[21:55:20] [PASSED] X0L2 Modifier without DRM_MODE_FB_MODIFIERS set
[21:55:20] [PASSED] X0L2 Valid modifier
[21:55:20] [PASSED] X0L2 Modifier for inexistent plane
[21:55:20] =========== [PASSED] drm_test_framebuffer_create ===========
[21:55:20] [PASSED] drm_test_framebuffer_free
[21:55:20] [PASSED] drm_test_framebuffer_init
[21:55:20] [PASSED] drm_test_framebuffer_init_bad_format
[21:55:20] [PASSED] drm_test_framebuffer_init_dev_mismatch
[21:55:20] [PASSED] drm_test_framebuffer_lookup
[21:55:20] [PASSED] drm_test_framebuffer_lookup_inexistent
[21:55:20] [PASSED] drm_test_framebuffer_modifiers_not_supported
[21:55:20] ================= [PASSED] drm_framebuffer =================
[21:55:20] ================ drm_gem_shmem (8 subtests) ================
[21:55:20] [PASSED] drm_gem_shmem_test_obj_create
[21:55:20] [PASSED] drm_gem_shmem_test_obj_create_private
[21:55:20] [PASSED] drm_gem_shmem_test_pin_pages
[21:55:20] [PASSED] drm_gem_shmem_test_vmap
[21:55:20] [PASSED] drm_gem_shmem_test_get_sg_table
[21:55:20] [PASSED] drm_gem_shmem_test_get_pages_sgt
[21:55:20] [PASSED] drm_gem_shmem_test_madvise
[21:55:20] [PASSED] drm_gem_shmem_test_purge
[21:55:20] ================== [PASSED] drm_gem_shmem ==================
[21:55:20] === drm_atomic_helper_connector_hdmi_check (29 subtests) ===
[21:55:20] [PASSED] drm_test_check_broadcast_rgb_auto_cea_mode
[21:55:20] [PASSED] drm_test_check_broadcast_rgb_auto_cea_mode_vic_1
[21:55:20] [PASSED] drm_test_check_broadcast_rgb_full_cea_mode
[21:55:20] [PASSED] drm_test_check_broadcast_rgb_full_cea_mode_vic_1
[21:55:20] [PASSED] drm_test_check_broadcast_rgb_limited_cea_mode
[21:55:20] [PASSED] drm_test_check_broadcast_rgb_limited_cea_mode_vic_1
[21:55:20] ====== drm_test_check_broadcast_rgb_cea_mode_yuv420 =======
[21:55:20] [PASSED] Automatic
[21:55:20] [PASSED] Full
[21:55:20] [PASSED] Limited 16:235
[21:55:20] == [PASSED] drm_test_check_broadcast_rgb_cea_mode_yuv420 ===
[21:55:20] [PASSED] drm_test_check_broadcast_rgb_crtc_mode_changed
[21:55:20] [PASSED] drm_test_check_broadcast_rgb_crtc_mode_not_changed
[21:55:20] [PASSED] drm_test_check_disable_connector
[21:55:20] [PASSED] drm_test_check_hdmi_funcs_reject_rate
[21:55:20] [PASSED] drm_test_check_max_tmds_rate_bpc_fallback_rgb
[21:55:20] [PASSED] drm_test_check_max_tmds_rate_bpc_fallback_yuv420
[21:55:20] [PASSED] drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422
[21:55:20] [PASSED] drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420
[21:55:20] [PASSED] drm_test_check_driver_unsupported_fallback_yuv420
[21:55:20] [PASSED] drm_test_check_output_bpc_crtc_mode_changed
[21:55:20] [PASSED] drm_test_check_output_bpc_crtc_mode_not_changed
[21:55:20] [PASSED] drm_test_check_output_bpc_dvi
[21:55:20] [PASSED] drm_test_check_output_bpc_format_vic_1
[21:55:20] [PASSED] drm_test_check_output_bpc_format_display_8bpc_only
[21:55:20] [PASSED] drm_test_check_output_bpc_format_display_rgb_only
[21:55:20] [PASSED] drm_test_check_output_bpc_format_driver_8bpc_only
[21:55:20] [PASSED] drm_test_check_output_bpc_format_driver_rgb_only
[21:55:20] [PASSED] drm_test_check_tmds_char_rate_rgb_8bpc
[21:55:20] [PASSED] drm_test_check_tmds_char_rate_rgb_10bpc
[21:55:20] [PASSED] drm_test_check_tmds_char_rate_rgb_12bpc
[21:55:20] ============ drm_test_check_hdmi_color_format =============
[21:55:20] [PASSED] AUTO -> RGB
[21:55:20] [PASSED] YCBCR422 -> YUV422
[21:55:20] [PASSED] YCBCR420 -> YUV420
[21:55:20] [PASSED] YCBCR444 -> YUV444
[21:55:20] [PASSED] RGB -> RGB
[21:55:20] ======== [PASSED] drm_test_check_hdmi_color_format =========
[21:55:20] ======== drm_test_check_hdmi_color_format_420_only ========
[21:55:20] [PASSED] RGB should fail
[21:55:20] [PASSED] YUV444 should fail
[21:55:20] [PASSED] YUV422 should fail
[21:55:20] [PASSED] YUV420 should work
[21:55:20] ==== [PASSED] drm_test_check_hdmi_color_format_420_only ====
[21:55:20] ===== [PASSED] drm_atomic_helper_connector_hdmi_check ======
[21:55:20] === drm_atomic_helper_connector_hdmi_reset (6 subtests) ====
[21:55:20] [PASSED] drm_test_check_broadcast_rgb_value
[21:55:20] [PASSED] drm_test_check_bpc_8_value
[21:55:20] [PASSED] drm_test_check_bpc_10_value
[21:55:20] [PASSED] drm_test_check_bpc_12_value
[21:55:20] [PASSED] drm_test_check_format_value
[21:55:20] [PASSED] drm_test_check_tmds_char_value
[21:55:20] ===== [PASSED] drm_atomic_helper_connector_hdmi_reset ======
[21:55:20] = drm_atomic_helper_connector_hdmi_mode_valid (7 subtests) =
[21:55:20] [PASSED] drm_test_check_mode_valid
[21:55:20] [PASSED] drm_test_check_mode_valid_reject
[21:55:20] [PASSED] drm_test_check_mode_valid_reject_rate
[21:55:20] [PASSED] drm_test_check_mode_valid_reject_max_clock
[21:55:20] [PASSED] drm_test_check_mode_valid_yuv420_only_max_clock
[21:55:20] [PASSED] drm_test_check_mode_valid_reject_yuv420_only_connector
[21:55:20] [PASSED] drm_test_check_mode_valid_accept_yuv420_also_connector_rgb
[21:55:20] === [PASSED] drm_atomic_helper_connector_hdmi_mode_valid ===
[21:55:20] = drm_atomic_helper_connector_hdmi_infoframes (5 subtests) =
[21:55:20] [PASSED] drm_test_check_infoframes
[21:55:20] [PASSED] drm_test_check_reject_avi_infoframe
[21:55:20] [PASSED] drm_test_check_reject_hdr_infoframe_bpc_8
[21:55:20] [PASSED] drm_test_check_reject_hdr_infoframe_bpc_10
[21:55:20] [PASSED] drm_test_check_reject_audio_infoframe
[21:55:20] === [PASSED] drm_atomic_helper_connector_hdmi_infoframes ===
[21:55:20] ================= drm_managed (2 subtests) =================
[21:55:20] [PASSED] drm_test_managed_release_action
[21:55:20] [PASSED] drm_test_managed_run_action
[21:55:20] =================== [PASSED] drm_managed ===================
[21:55:20] =================== drm_mm (6 subtests) ====================
[21:55:20] [PASSED] drm_test_mm_init
[21:55:20] [PASSED] drm_test_mm_debug
[21:55:20] [PASSED] drm_test_mm_align32
[21:55:20] [PASSED] drm_test_mm_align64
[21:55:20] [PASSED] drm_test_mm_lowest
[21:55:20] [PASSED] drm_test_mm_highest
[21:55:20] ===================== [PASSED] drm_mm ======================
[21:55:20] ============= drm_modes_analog_tv (5 subtests) =============
[21:55:20] [PASSED] drm_test_modes_analog_tv_mono_576i
[21:55:20] [PASSED] drm_test_modes_analog_tv_ntsc_480i
[21:55:20] [PASSED] drm_test_modes_analog_tv_ntsc_480i_inlined
[21:55:20] [PASSED] drm_test_modes_analog_tv_pal_576i
[21:55:20] [PASSED] drm_test_modes_analog_tv_pal_576i_inlined
[21:55:20] =============== [PASSED] drm_modes_analog_tv ===============
[21:55:20] ============== drm_plane_helper (2 subtests) ===============
[21:55:20] =============== drm_test_check_plane_state ================
[21:55:20] [PASSED] clipping_simple
[21:55:20] [PASSED] clipping_rotate_reflect
[21:55:20] [PASSED] positioning_simple
[21:55:20] [PASSED] upscaling
[21:55:20] [PASSED] downscaling
[21:55:20] [PASSED] rounding1
[21:55:20] [PASSED] rounding2
[21:55:20] [PASSED] rounding3
[21:55:20] [PASSED] rounding4
[21:55:20] =========== [PASSED] drm_test_check_plane_state ============
[21:55:20] =========== drm_test_check_invalid_plane_state ============
[21:55:20] [PASSED] positioning_invalid
[21:55:20] [PASSED] upscaling_invalid
[21:55:20] [PASSED] downscaling_invalid
[21:55:20] ======= [PASSED] drm_test_check_invalid_plane_state ========
[21:55:20] ================ [PASSED] drm_plane_helper =================
[21:55:20] ====== drm_connector_helper_tv_get_modes (1 subtest) =======
[21:55:20] ====== drm_test_connector_helper_tv_get_modes_check =======
[21:55:20] [PASSED] None
[21:55:20] [PASSED] PAL
[21:55:20] [PASSED] NTSC
[21:55:20] [PASSED] Both, NTSC Default
[21:55:20] [PASSED] Both, PAL Default
[21:55:20] [PASSED] Both, NTSC Default, with PAL on command-line
[21:55:20] [PASSED] Both, PAL Default, with NTSC on command-line
[21:55:20] == [PASSED] drm_test_connector_helper_tv_get_modes_check ===
[21:55:20] ======== [PASSED] drm_connector_helper_tv_get_modes ========
[21:55:20] ================== drm_rect (9 subtests) ===================
[21:55:20] [PASSED] drm_test_rect_clip_scaled_div_by_zero
[21:55:20] [PASSED] drm_test_rect_clip_scaled_not_clipped
[21:55:20] [PASSED] drm_test_rect_clip_scaled_clipped
[21:55:20] [PASSED] drm_test_rect_clip_scaled_signed_vs_unsigned
[21:55:20] ================= drm_test_rect_intersect =================
[21:55:20] [PASSED] top-left x bottom-right: 2x2+1+1 x 2x2+0+0
[21:55:20] [PASSED] top-right x bottom-left: 2x2+0+0 x 2x2+1-1
[21:55:20] [PASSED] bottom-left x top-right: 2x2+1-1 x 2x2+0+0
[21:55:20] [PASSED] bottom-right x top-left: 2x2+0+0 x 2x2+1+1
[21:55:20] [PASSED] right x left: 2x1+0+0 x 3x1+1+0
[21:55:20] [PASSED] left x right: 3x1+1+0 x 2x1+0+0
[21:55:20] [PASSED] up x bottom: 1x2+0+0 x 1x3+0-1
[21:55:20] [PASSED] bottom x up: 1x3+0-1 x 1x2+0+0
[21:55:20] [PASSED] touching corner: 1x1+0+0 x 2x2+1+1
[21:55:20] [PASSED] touching side: 1x1+0+0 x 1x1+1+0
[21:55:20] [PASSED] equal rects: 2x2+0+0 x 2x2+0+0
[21:55:20] [PASSED] inside another: 2x2+0+0 x 1x1+1+1
[21:55:20] [PASSED] far away: 1x1+0+0 x 1x1+3+6
[21:55:20] [PASSED] points intersecting: 0x0+5+10 x 0x0+5+10
[21:55:20] [PASSED] points not intersecting: 0x0+0+0 x 0x0+5+10
[21:55:20] ============= [PASSED] drm_test_rect_intersect =============
[21:55:20] ================ drm_test_rect_calc_hscale ================
[21:55:20] [PASSED] normal use
[21:55:20] [PASSED] out of max range
[21:55:20] [PASSED] out of min range
[21:55:20] [PASSED] zero dst
[21:55:20] [PASSED] negative src
[21:55:20] [PASSED] negative dst
[21:55:20] ============ [PASSED] drm_test_rect_calc_hscale ============
[21:55:20] ================ drm_test_rect_calc_vscale ================
[21:55:20] [PASSED] normal use
[21:55:20] [PASSED] out of max range
[21:55:20] [PASSED] out of min range
[21:55:20] [PASSED] zero dst
[21:55:20] [PASSED] negative src
[21:55:20] [PASSED] negative dst
[21:55:20] ============ [PASSED] drm_test_rect_calc_vscale ============
[21:55:20] ================== drm_test_rect_rotate ===================
[21:55:20] [PASSED] reflect-x
[21:55:20] [PASSED] reflect-y
[21:55:20] [PASSED] rotate-0
[21:55:20] [PASSED] rotate-90
[21:55:20] [PASSED] rotate-180
[21:55:20] [PASSED] rotate-270
[21:55:20] ============== [PASSED] drm_test_rect_rotate ===============
[21:55:20] ================ drm_test_rect_rotate_inv =================
[21:55:20] [PASSED] reflect-x
[21:55:20] [PASSED] reflect-y
[21:55:20] [PASSED] rotate-0
[21:55:20] [PASSED] rotate-90
[21:55:20] [PASSED] rotate-180
[21:55:20] [PASSED] rotate-270
[21:55:20] ============ [PASSED] drm_test_rect_rotate_inv =============
[21:55:20] ==================== [PASSED] drm_rect =====================
[21:55:20] ============ drm_sysfb_modeset_test (1 subtest) ============
[21:55:20] ============ drm_test_sysfb_build_fourcc_list =============
[21:55:20] [PASSED] no native formats
[21:55:20] [PASSED] XRGB8888 as native format
[21:55:20] [PASSED] remove duplicates
[21:55:20] [PASSED] convert alpha formats
[21:55:20] [PASSED] random formats
[21:55:20] ======== [PASSED] drm_test_sysfb_build_fourcc_list =========
[21:55:20] ============= [PASSED] drm_sysfb_modeset_test ==============
[21:55:20] ================== drm_fixp (2 subtests) ===================
[21:55:20] [PASSED] drm_test_int2fixp
[21:55:20] [PASSED] drm_test_sm2fixp
[21:55:20] ==================== [PASSED] drm_fixp =====================
[21:55:20] ============================================================
[21:55:20] Testing complete. Ran 637 tests: passed: 637
[21:55:20] Elapsed time: 27.052s total, 1.763s configuring, 25.071s building, 0.194s running
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/gpu/drm/ttm/tests/.kunitconfig
[21:55:20] Configuring KUnit Kernel ...
Regenerating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[21:55:22] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=48
[21:55:32] Starting KUnit Kernel (1/1)...
[21:55:32] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[21:55:32] ================= ttm_device (5 subtests) ==================
[21:55:32] [PASSED] ttm_device_init_basic
[21:55:32] [PASSED] ttm_device_init_multiple
[21:55:32] [PASSED] ttm_device_fini_basic
[21:55:32] [PASSED] ttm_device_init_no_vma_man
[21:55:32] ================== ttm_device_init_pools ==================
[21:55:32] [PASSED] No DMA allocations, no DMA32 required
[21:55:32] [PASSED] DMA allocations, DMA32 required
[21:55:32] [PASSED] No DMA allocations, DMA32 required
[21:55:32] [PASSED] DMA allocations, no DMA32 required
[21:55:32] ============== [PASSED] ttm_device_init_pools ==============
[21:55:32] =================== [PASSED] ttm_device ====================
[21:55:32] ================== ttm_pool (8 subtests) ===================
[21:55:32] ================== ttm_pool_alloc_basic ===================
[21:55:32] [PASSED] One page
[21:55:32] [PASSED] More than one page
[21:55:32] [PASSED] Above the allocation limit
[21:55:32] [PASSED] One page, with coherent DMA mappings enabled
[21:55:32] [PASSED] Above the allocation limit, with coherent DMA mappings enabled
[21:55:32] ============== [PASSED] ttm_pool_alloc_basic ===============
[21:55:32] ============== ttm_pool_alloc_basic_dma_addr ==============
[21:55:32] [PASSED] One page
[21:55:32] [PASSED] More than one page
[21:55:32] [PASSED] Above the allocation limit
[21:55:32] [PASSED] One page, with coherent DMA mappings enabled
[21:55:32] [PASSED] Above the allocation limit, with coherent DMA mappings enabled
[21:55:32] ========== [PASSED] ttm_pool_alloc_basic_dma_addr ==========
[21:55:32] [PASSED] ttm_pool_alloc_order_caching_match
[21:55:32] [PASSED] ttm_pool_alloc_caching_mismatch
[21:55:32] [PASSED] ttm_pool_alloc_order_mismatch
[21:55:32] [PASSED] ttm_pool_free_dma_alloc
[21:55:32] [PASSED] ttm_pool_free_no_dma_alloc
[21:55:32] [PASSED] ttm_pool_fini_basic
[21:55:32] ==================== [PASSED] ttm_pool =====================
[21:55:32] ================ ttm_resource (8 subtests) =================
[21:55:32] ================= ttm_resource_init_basic =================
[21:55:32] [PASSED] Init resource in TTM_PL_SYSTEM
[21:55:32] [PASSED] Init resource in TTM_PL_VRAM
[21:55:32] [PASSED] Init resource in a private placement
[21:55:32] [PASSED] Init resource in TTM_PL_SYSTEM, set placement flags
[21:55:32] ============= [PASSED] ttm_resource_init_basic =============
[21:55:32] [PASSED] ttm_resource_init_pinned
[21:55:32] [PASSED] ttm_resource_fini_basic
[21:55:32] [PASSED] ttm_resource_manager_init_basic
[21:55:32] [PASSED] ttm_resource_manager_usage_basic
[21:55:32] [PASSED] ttm_resource_manager_set_used_basic
[21:55:32] [PASSED] ttm_sys_man_alloc_basic
[21:55:32] [PASSED] ttm_sys_man_free_basic
[21:55:32] ================== [PASSED] ttm_resource ===================
[21:55:32] =================== ttm_tt (15 subtests) ===================
[21:55:32] ==================== ttm_tt_init_basic ====================
[21:55:32] [PASSED] Page-aligned size
[21:55:32] [PASSED] Extra pages requested
[21:55:32] ================ [PASSED] ttm_tt_init_basic ================
[21:55:32] [PASSED] ttm_tt_init_misaligned
[21:55:32] [PASSED] ttm_tt_fini_basic
[21:55:32] [PASSED] ttm_tt_fini_sg
[21:55:32] [PASSED] ttm_tt_fini_shmem
[21:55:32] [PASSED] ttm_tt_create_basic
[21:55:32] [PASSED] ttm_tt_create_invalid_bo_type
[21:55:32] [PASSED] ttm_tt_create_ttm_exists
[21:55:32] [PASSED] ttm_tt_create_failed
[21:55:32] [PASSED] ttm_tt_destroy_basic
[21:55:32] [PASSED] ttm_tt_populate_null_ttm
[21:55:32] [PASSED] ttm_tt_populate_populated_ttm
[21:55:32] [PASSED] ttm_tt_unpopulate_basic
[21:55:32] [PASSED] ttm_tt_unpopulate_empty_ttm
[21:55:32] [PASSED] ttm_tt_swapin_basic
[21:55:32] ===================== [PASSED] ttm_tt ======================
[21:55:32] =================== ttm_bo (14 subtests) ===================
[21:55:32] =========== ttm_bo_reserve_optimistic_no_ticket ===========
[21:55:32] [PASSED] Cannot be interrupted and sleeps
[21:55:32] [PASSED] Cannot be interrupted, locks straight away
[21:55:32] [PASSED] Can be interrupted, sleeps
[21:55:32] ======= [PASSED] ttm_bo_reserve_optimistic_no_ticket =======
[21:55:32] [PASSED] ttm_bo_reserve_locked_no_sleep
[21:55:32] [PASSED] ttm_bo_reserve_no_wait_ticket
[21:55:32] [PASSED] ttm_bo_reserve_double_resv
[21:55:32] [PASSED] ttm_bo_reserve_interrupted
[21:55:32] [PASSED] ttm_bo_reserve_deadlock
[21:55:32] [PASSED] ttm_bo_unreserve_basic
[21:55:32] [PASSED] ttm_bo_unreserve_pinned
[21:55:32] [PASSED] ttm_bo_unreserve_bulk
[21:55:32] [PASSED] ttm_bo_fini_basic
[21:55:32] [PASSED] ttm_bo_fini_shared_resv
[21:55:32] [PASSED] ttm_bo_pin_basic
[21:55:32] [PASSED] ttm_bo_pin_unpin_resource
[21:55:32] [PASSED] ttm_bo_multiple_pin_one_unpin
[21:55:32] ===================== [PASSED] ttm_bo ======================
[21:55:32] ============== ttm_bo_validate (22 subtests) ===============
[21:55:32] ============== ttm_bo_init_reserved_sys_man ===============
[21:55:32] [PASSED] Buffer object for userspace
[21:55:32] [PASSED] Kernel buffer object
[21:55:32] [PASSED] Shared buffer object
[21:55:32] ========== [PASSED] ttm_bo_init_reserved_sys_man ===========
[21:55:32] ============== ttm_bo_init_reserved_mock_man ==============
[21:55:32] [PASSED] Buffer object for userspace
[21:55:32] [PASSED] Kernel buffer object
[21:55:32] [PASSED] Shared buffer object
[21:55:32] ========== [PASSED] ttm_bo_init_reserved_mock_man ==========
[21:55:32] [PASSED] ttm_bo_init_reserved_resv
[21:55:32] ================== ttm_bo_validate_basic ==================
[21:55:32] [PASSED] Buffer object for userspace
[21:55:32] [PASSED] Kernel buffer object
[21:55:32] [PASSED] Shared buffer object
[21:55:32] ============== [PASSED] ttm_bo_validate_basic ==============
[21:55:32] [PASSED] ttm_bo_validate_invalid_placement
[21:55:32] ============= ttm_bo_validate_same_placement ==============
[21:55:32] [PASSED] System manager
[21:55:32] [PASSED] VRAM manager
[21:55:32] ========= [PASSED] ttm_bo_validate_same_placement ==========
[21:55:32] [PASSED] ttm_bo_validate_failed_alloc
[21:55:32] [PASSED] ttm_bo_validate_pinned
[21:55:32] [PASSED] ttm_bo_validate_busy_placement
[21:55:32] ================ ttm_bo_validate_multihop =================
[21:55:32] [PASSED] Buffer object for userspace
[21:55:32] [PASSED] Kernel buffer object
[21:55:32] [PASSED] Shared buffer object
[21:55:32] ============ [PASSED] ttm_bo_validate_multihop =============
[21:55:32] ========== ttm_bo_validate_no_placement_signaled ==========
[21:55:32] [PASSED] Buffer object in system domain, no page vector
[21:55:32] [PASSED] Buffer object in system domain with an existing page vector
[21:55:32] ====== [PASSED] ttm_bo_validate_no_placement_signaled ======
[21:55:32] ======== ttm_bo_validate_no_placement_not_signaled ========
[21:55:32] [PASSED] Buffer object for userspace
[21:55:32] [PASSED] Kernel buffer object
[21:55:32] [PASSED] Shared buffer object
[21:55:32] ==== [PASSED] ttm_bo_validate_no_placement_not_signaled ====
[21:55:32] [PASSED] ttm_bo_validate_move_fence_signaled
[21:55:33] ========= ttm_bo_validate_move_fence_not_signaled =========
[21:55:33] [PASSED] Waits for GPU
[21:55:33] [PASSED] Tries to lock straight away
[21:55:33] ===== [PASSED] ttm_bo_validate_move_fence_not_signaled =====
[21:55:33] [PASSED] ttm_bo_validate_swapout
[21:55:33] [PASSED] ttm_bo_validate_happy_evict
[21:55:33] [PASSED] ttm_bo_validate_all_pinned_evict
[21:55:33] [PASSED] ttm_bo_validate_allowed_only_evict
[21:55:33] [PASSED] ttm_bo_validate_deleted_evict
[21:55:33] [PASSED] ttm_bo_validate_busy_domain_evict
[21:55:33] [PASSED] ttm_bo_validate_evict_gutting
[21:55:33] [PASSED] ttm_bo_validate_recrusive_evict
[21:55:33] ================= [PASSED] ttm_bo_validate =================
[21:55:33] ============================================================
[21:55:33] Testing complete. Ran 102 tests: passed: 102
[21:55:33] Elapsed time: 12.134s total, 1.793s configuring, 10.126s building, 0.185s running
+ cleanup
++ stat -c %u:%g /kernel
+ chown -R 1003:1003 /kernel
^ permalink raw reply [flat|nested] 16+ messages in thread* ✗ Xe.CI.BAT: failure for Fine grained fault locking, threaded prefetch, storm cache (rev5)
2026-07-23 21:47 [PATCH v5 00/12] Fine grained fault locking, threaded prefetch, storm cache Matthew Brost
` (13 preceding siblings ...)
2026-07-23 21:55 ` ✓ CI.KUnit: success " Patchwork
@ 2026-07-23 22:47 ` Patchwork
14 siblings, 0 replies; 16+ messages in thread
From: Patchwork @ 2026-07-23 22:47 UTC (permalink / raw)
To: Matthew Brost; +Cc: intel-xe
[-- Attachment #1: Type: text/plain, Size: 8937 bytes --]
== Series Details ==
Series: Fine grained fault locking, threaded prefetch, storm cache (rev5)
URL : https://patchwork.freedesktop.org/series/162167/
State : failure
== Summary ==
CI Bug Log - changes from xe-5468-1b41172259f1c761714ee4d65a4386b42181c492_BAT -> xe-pw-162167v5_BAT
====================================================
Summary
-------
**FAILURE**
Serious unknown changes coming with xe-pw-162167v5_BAT absolutely need to be
verified manually.
If you think the reported changes have nothing to do with the changes
introduced in xe-pw-162167v5_BAT, please notify your bug team (I915-ci-infra@lists.freedesktop.org) to allow them
to document this new failure mode, which will reduce false positives in CI.
Participating hosts (12 -> 13)
------------------------------
Additional (1): bat-bmg-2
Possible new issues
-------------------
Here are the unknown changes that may have been introduced in xe-pw-162167v5_BAT:
### IGT changes ###
#### Possible regressions ####
* igt@xe_exec_system_allocator@eu-fault-2m-range-device-host:
- bat-wcl-2: [PASS][1] -> [ABORT][2]
[1]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5468-1b41172259f1c761714ee4d65a4386b42181c492/bat-wcl-2/igt@xe_exec_system_allocator@eu-fault-2m-range-device-host.html
[2]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-162167v5/bat-wcl-2/igt@xe_exec_system_allocator@eu-fault-2m-range-device-host.html
- bat-bmg-1: [PASS][3] -> [ABORT][4]
[3]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5468-1b41172259f1c761714ee4d65a4386b42181c492/bat-bmg-1/igt@xe_exec_system_allocator@eu-fault-2m-range-device-host.html
[4]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-162167v5/bat-bmg-1/igt@xe_exec_system_allocator@eu-fault-2m-range-device-host.html
- bat-lnl-2: [PASS][5] -> [ABORT][6]
[5]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5468-1b41172259f1c761714ee4d65a4386b42181c492/bat-lnl-2/igt@xe_exec_system_allocator@eu-fault-2m-range-device-host.html
[6]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-162167v5/bat-lnl-2/igt@xe_exec_system_allocator@eu-fault-2m-range-device-host.html
- bat-bmg-vm: [PASS][7] -> [ABORT][8]
[7]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5468-1b41172259f1c761714ee4d65a4386b42181c492/bat-bmg-vm/igt@xe_exec_system_allocator@eu-fault-2m-range-device-host.html
[8]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-162167v5/bat-bmg-vm/igt@xe_exec_system_allocator@eu-fault-2m-range-device-host.html
- bat-ptl-2: [PASS][9] -> [ABORT][10]
[9]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5468-1b41172259f1c761714ee4d65a4386b42181c492/bat-ptl-2/igt@xe_exec_system_allocator@eu-fault-2m-range-device-host.html
[10]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-162167v5/bat-ptl-2/igt@xe_exec_system_allocator@eu-fault-2m-range-device-host.html
- bat-wcl-1: [PASS][11] -> [ABORT][12]
[11]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5468-1b41172259f1c761714ee4d65a4386b42181c492/bat-wcl-1/igt@xe_exec_system_allocator@eu-fault-2m-range-device-host.html
[12]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-162167v5/bat-wcl-1/igt@xe_exec_system_allocator@eu-fault-2m-range-device-host.html
- bat-ptl-1: [PASS][13] -> [ABORT][14]
[13]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5468-1b41172259f1c761714ee4d65a4386b42181c492/bat-ptl-1/igt@xe_exec_system_allocator@eu-fault-2m-range-device-host.html
[14]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-162167v5/bat-ptl-1/igt@xe_exec_system_allocator@eu-fault-2m-range-device-host.html
- bat-ptl-vm: [PASS][15] -> [ABORT][16]
[15]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5468-1b41172259f1c761714ee4d65a4386b42181c492/bat-ptl-vm/igt@xe_exec_system_allocator@eu-fault-2m-range-device-host.html
[16]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-162167v5/bat-ptl-vm/igt@xe_exec_system_allocator@eu-fault-2m-range-device-host.html
- bat-lnl-1: [PASS][17] -> [ABORT][18]
[17]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5468-1b41172259f1c761714ee4d65a4386b42181c492/bat-lnl-1/igt@xe_exec_system_allocator@eu-fault-2m-range-device-host.html
[18]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-162167v5/bat-lnl-1/igt@xe_exec_system_allocator@eu-fault-2m-range-device-host.html
- bat-bmg-2: NOTRUN -> [ABORT][19]
[19]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-162167v5/bat-bmg-2/igt@xe_exec_system_allocator@eu-fault-2m-range-device-host.html
* igt@xe_multigpu_svm@mgpu-xgpu-access-basic:
- bat-bmg-3: [PASS][20] -> [DMESG-FAIL][21]
[20]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5468-1b41172259f1c761714ee4d65a4386b42181c492/bat-bmg-3/igt@xe_multigpu_svm@mgpu-xgpu-access-basic.html
[21]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-162167v5/bat-bmg-3/igt@xe_multigpu_svm@mgpu-xgpu-access-basic.html
Known issues
------------
Here are the changes found in xe-pw-162167v5_BAT that come from known issues:
### IGT changes ###
#### Issues hit ####
* igt@fbdev@write:
- bat-bmg-2: NOTRUN -> [SKIP][22] ([Intel XE#2134]) +4 other tests skip
[22]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-162167v5/bat-bmg-2/igt@fbdev@write.html
* igt@kms_addfb_basic@addfb25-y-tiled-small-legacy:
- bat-bmg-2: NOTRUN -> [SKIP][23] ([Intel XE#2233])
[23]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-162167v5/bat-bmg-2/igt@kms_addfb_basic@addfb25-y-tiled-small-legacy.html
* igt@kms_cursor_legacy@basic-flip-after-cursor-legacy:
- bat-bmg-2: NOTRUN -> [SKIP][24] ([Intel XE#2489] / [Intel XE#3419]) +13 other tests skip
[24]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-162167v5/bat-bmg-2/igt@kms_cursor_legacy@basic-flip-after-cursor-legacy.html
* igt@kms_flip@basic-flip-vs-modeset:
- bat-bmg-2: NOTRUN -> [SKIP][25] ([Intel XE#2482]) +3 other tests skip
[25]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-162167v5/bat-bmg-2/igt@kms_flip@basic-flip-vs-modeset.html
* igt@kms_frontbuffer_tracking@basic:
- bat-bmg-2: NOTRUN -> [SKIP][26] ([Intel XE#2434] / [Intel XE#2548] / [Intel XE#6314])
[26]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-162167v5/bat-bmg-2/igt@kms_frontbuffer_tracking@basic.html
* igt@kms_psr@psr-sprite-plane-onoff:
- bat-bmg-2: NOTRUN -> [SKIP][27] ([Intel XE#2234] / [Intel XE#2850]) +2 other tests skip
[27]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-162167v5/bat-bmg-2/igt@kms_psr@psr-sprite-plane-onoff.html
* igt@xe_exec_multi_queue@priority:
- bat-bmg-2: NOTRUN -> [SKIP][28] ([Intel XE#8364]) +13 other tests skip
[28]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-162167v5/bat-bmg-2/igt@xe_exec_multi_queue@priority.html
* igt@xe_multigpu_svm@mgpu-atomic-op-basic:
- bat-bmg-3: [PASS][29] -> [DMESG-FAIL][30] ([Intel XE#8300]) +1 other test dmesg-fail
[29]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5468-1b41172259f1c761714ee4d65a4386b42181c492/bat-bmg-3/igt@xe_multigpu_svm@mgpu-atomic-op-basic.html
[30]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-162167v5/bat-bmg-3/igt@xe_multigpu_svm@mgpu-atomic-op-basic.html
* igt@xe_multigpu_svm@mgpu-atomic-op-prefetch:
- bat-bmg-3: [PASS][31] -> [ABORT][32] ([Intel XE#8300])
[31]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5468-1b41172259f1c761714ee4d65a4386b42181c492/bat-bmg-3/igt@xe_multigpu_svm@mgpu-atomic-op-prefetch.html
[32]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-162167v5/bat-bmg-3/igt@xe_multigpu_svm@mgpu-atomic-op-prefetch.html
[Intel XE#2134]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2134
[Intel XE#2233]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2233
[Intel XE#2234]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2234
[Intel XE#2434]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2434
[Intel XE#2482]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2482
[Intel XE#2489]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2489
[Intel XE#2548]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2548
[Intel XE#2850]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2850
[Intel XE#3419]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3419
[Intel XE#6314]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6314
[Intel XE#8300]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8300
[Intel XE#8364]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8364
Build changes
-------------
* Linux: xe-5468-1b41172259f1c761714ee4d65a4386b42181c492 -> xe-pw-162167v5
IGT_9022: 9022
xe-5468-1b41172259f1c761714ee4d65a4386b42181c492: 1b41172259f1c761714ee4d65a4386b42181c492
xe-pw-162167v5: 162167v5
== Logs ==
For more details see: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-162167v5/index.html
[-- Attachment #2: Type: text/html, Size: 9859 bytes --]
^ permalink raw reply [flat|nested] 16+ messages in thread