Re: [i-g-t, v2] tests/intel/xe_exec_mix_modes: Add multi-queue LR spinner switch subtest

Niranjana Vishwanathapura <[email protected]>
Newsgroups org.freedesktop.lists.igt-dev
Message-ID <aoZQMe_KU3vF33hI@nvishwa1-desk>
On Wed, Aug 19, 2026 at 07:39:26PM +0000, Jagmeet Randhawa wrote:
>Add exec-multi-queue-spinner-interrupted-lr, which runs preemptible
>spinners on every queue in a multi-queue exec queue group in long
>running mode, then submits a dma-fence job on the same engine to force
>the group from FAULT into DMA_FENCE mode.
>
>Each spinner uses a multi-queue switch point (multi_queue_switch) so it
>yields the shared engine to its sibling once scheduled, instead of
>busy-looping and starving the rest of the group. This lets every queue
>in the group be genuinely resident when the interrupting job forces the
>mode switch, exercising suspend/resume of the secondary queues rather
>than just the primary.
>
>The dma-fence and LR (preempt) multi-queue suspend/resume paths are
>already covered by the userptr-invalidation tests; this adds the
>missing FAULT-mode coverage.
>
>v2: (Niranjana)
>- Use a plain multi_queue_switch point; drop xe_spin_preempt_wait/nowait().
>- Drop the redundant "still pending" ufence check before ending the spinners.
>- Move the capability check to test_exec() and assert FLAG_EXEC_MODE_LR.
>
>Signed-off-by: Jagmeet Randhawa <[email protected]>

Reviewed-by: Niranjana Vishwanathapura <[email protected]>

>---
> tests/intel/xe_exec_mix_modes.c | 101 ++++++++++++++++++++++++++++++++
> 1 file changed, 101 insertions(+)
>
>diff --git a/tests/intel/xe_exec_mix_modes.c b/tests/intel/xe_exec_mix_modes.c
>index 209825f58..373058277 100644
>--- a/tests/intel/xe_exec_mix_modes.c
>+++ b/tests/intel/xe_exec_mix_modes.c
>@@ -27,6 +27,7 @@
>
> #define FLAG_EXEC_MODE_LR	(0x1 << 0)
> #define FLAG_JOB_TYPE_SIMPLE	(0x1 << 1)
>+#define FLAG_MULTI_QUEUE	(0x1 << 2)
>
> #define NUM_INTERRUPTING_JOBS	1
> #define USER_FENCE_VALUE	0xdeadbeefdeadbeefull
>@@ -34,6 +35,7 @@
> #define SPIN_DATA		1
> #define EXEC_DATA		2
> #define DATA_COUNT		3
>+#define N_GROUP_QUEUES		2
>
> struct data {
> 	struct xe_spin spin;
>@@ -221,6 +223,92 @@ run_job(int fd, struct drm_xe_engine_class_instance *hwe,
> 	xe_vm_destroy(fd, vm);
> }
>
>+static void
>+run_job_multi_queue(int fd, struct drm_xe_engine_class_instance *hwe)
>+{
>+	struct drm_xe_sync sync = {
>+		.flags = DRM_XE_SYNC_FLAG_SIGNAL,
>+		.type = DRM_XE_SYNC_TYPE_USER_FENCE,
>+		.timeline_value = USER_FENCE_VALUE,
>+	};
>+	struct drm_xe_exec exec = {
>+		.num_batch_buffer = 1,
>+		.num_syncs = 1,
>+		.syncs = to_user_pointer(&sync),
>+	};
>+	uint32_t exec_queues[N_GROUP_QUEUES];
>+	struct xe_spin *spin[N_GROUP_QUEUES];
>+	uint64_t addr[N_GROUP_QUEUES];
>+	uint64_t base_addr = 0x1a0000;
>+	int64_t fence_timeout = NSEC_PER_SEC;
>+	uint64_t vm_sync = 0;
>+	size_t bo_size, spin_size;
>+	uint32_t vm, bo;
>+	void *map;
>+	int i;
>+
>+	vm = xe_vm_create(fd, DRM_XE_VM_CREATE_FLAG_LR_MODE |
>+			      DRM_XE_VM_CREATE_FLAG_FAULT_MODE, 0);
>+
>+	/* exec_queues[0] is the primary, the rest join its group. */
>+	for (i = 0; i < N_GROUP_QUEUES; i++) {
>+		struct drm_xe_ext_set_property multi_queue = {
>+			.base.name = DRM_XE_EXEC_QUEUE_EXTENSION_SET_PROPERTY,
>+			.property = DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_GROUP,
>+		};
>+		uint64_t ext = to_user_pointer(&multi_queue);
>+
>+		multi_queue.value = i ? exec_queues[0] : DRM_XE_MULTI_GROUP_CREATE;
>+		exec_queues[i] = xe_exec_queue_create(fd, vm, hwe, ext);
>+	}
>+
>+	spin_size = xe_bb_size(fd, sizeof(struct xe_spin));
>+	bo_size = spin_size * N_GROUP_QUEUES;
>+	bo = xe_bo_create(fd, vm, bo_size, vram_if_possible(fd, hwe->gt_id),
>+			  DRM_XE_GEM_CREATE_FLAG_NEEDS_VISIBLE_VRAM);
>+	map = xe_bo_map(fd, bo, bo_size);
>+	for (i = 0; i < N_GROUP_QUEUES; i++) {
>+		spin[i] = (struct xe_spin *)((char *)map + i * spin_size);
>+		addr[i] = base_addr + i * spin_size;
>+	}
>+
>+	sync.addr = to_user_pointer(&vm_sync);
>+	xe_vm_bind_async(fd, vm, 0, bo, 0, base_addr, bo_size, &sync, 1);
>+	xe_wait_ufence(fd, &vm_sync, USER_FENCE_VALUE, 0, fence_timeout);
>+	vm_sync = 0;
>+
>+	for (i = 0; i < N_GROUP_QUEUES; i++) {
>+		/* Yield the shared engine at a switch point instead of busy-spinning. */
>+		xe_spin_init_opts(spin[i], .addr = addr[i], .preempt = true,
>+				  .multi_queue_switch = true);
>+		sync.addr = addr[i] + (char *)&spin[i]->exec_sync - (char *)spin[i];
>+		exec.exec_queue_id = exec_queues[i];
>+		exec.address = addr[i];
>+		xe_exec(fd, &exec);
>+		xe_spin_wait_started(spin[i]);
>+	}
>+
>+	/* Force the group from FAULT into DMA_FENCE mode. */
>+	run_job(fd, hwe, EXEC_MODE_DMA_FENCE, SIMPLE_BATCH_STORE, false, NULL);
>+
>+	for (i = 0; i < N_GROUP_QUEUES; i++)
>+		xe_spin_end(spin[i]);
>+
>+	for (i = 0; i < N_GROUP_QUEUES; i++)
>+		xe_wait_ufence(fd, &spin[i]->exec_sync, USER_FENCE_VALUE,
>+			       exec_queues[i], fence_timeout);
>+
>+	sync.addr = to_user_pointer(&vm_sync);
>+	xe_vm_unbind_async(fd, vm, 0, 0, base_addr, bo_size, &sync, 1);
>+	xe_wait_ufence(fd, &vm_sync, USER_FENCE_VALUE, 0, fence_timeout);
>+
>+	for (i = 0; i < N_GROUP_QUEUES; i++)
>+		xe_exec_queue_destroy(fd, exec_queues[i]);
>+	munmap(map, bo_size);
>+	gem_close(fd, bo);
>+	xe_vm_destroy(fd, vm);
>+}
>+
> /**
>  * SUBTEST: exec-simple-batch-store-lr
>  * Description: Execute a simple batch store job in long running mode
>@@ -235,6 +323,11 @@ run_job(int fd, struct drm_xe_engine_class_instance *hwe,
>  * SUBTEST: exec-spinner-interrupted-dma-fence
>  * Description: Spin in dma fence mode then get interrupted by a simple
>  *              batch store job in long running mode
>+ *
>+ * SUBTEST: exec-multi-queue-spinner-interrupted-lr
>+ * Description: Run preemptible spinners on a multi-queue exec queue group
>+ *              in long running mode, then get interrupted by a simple
>+ *              batch store job in dma fence mode
>  */
> static void
> test_exec(int fd, struct drm_xe_engine_class_instance *hwe,
>@@ -243,6 +336,13 @@ test_exec(int fd, struct drm_xe_engine_class_instance *hwe,
> 	enum engine_execution_mode engine_execution_mode;
> 	enum job_type job_type;
>
>+	if (flags & FLAG_MULTI_QUEUE) {
>+		igt_assert(flags & FLAG_EXEC_MODE_LR);
>+		igt_require(xe_engine_class_supports_multi_queue(fd, hwe->engine_class));
>+		run_job_multi_queue(fd, hwe);
>+		return;
>+	}
>+
> 	if (flags & FLAG_EXEC_MODE_LR)
> 		engine_execution_mode = EXEC_MODE_LR;
> 	else
>@@ -267,6 +367,7 @@ int igt_main()
> 		{ "simple-batch-store-dma-fence", FLAG_JOB_TYPE_SIMPLE },
> 		{ "spinner-interrupted-lr", FLAG_EXEC_MODE_LR },
> 		{ "spinner-interrupted-dma-fence", 0 },
>+		{ "multi-queue-spinner-interrupted-lr", FLAG_EXEC_MODE_LR | FLAG_MULTI_QUEUE },
> 		{ NULL },
> 	};
> 	int fd;
>-- 
>2.43.0
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.