[igt-dev] [PATCH i-g-t] lib: Support writing arbitrary data from the start of a busy spinner

Chris Wilson chris at chris-wilson.co.uk
Fri Dec 18 14:25:20 UTC 2020


Allow the caller to specify a dword, or an arbitrary payload, to be
written by the busy spinner, just prior to starting its infinite loop.
This is similar to the dependency method, that makes a target busy
without writing anything.

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 lib/igt_dummyload.c         | 71 +++++++++++++++++++++++++++++++++++--
 lib/igt_dummyload.h         | 12 +++++++
 tests/i915/gem_spin_batch.c | 46 ++++++++++++++++++++++++
 3 files changed, 127 insertions(+), 2 deletions(-)

diff --git a/lib/igt_dummyload.c b/lib/igt_dummyload.c
index 28fcbf81f..d5a68a46c 100644
--- a/lib/igt_dummyload.c
+++ b/lib/igt_dummyload.c
@@ -63,7 +63,7 @@
 #define MI_ARB_CHK (0x5 << 23)
 
 static const int BATCH_SIZE = 4096;
-static const int LOOP_START_OFFSET = 64;
+static const int LOOP_START_OFFSET = 256;
 
 static IGT_LIST_HEAD(spin_list);
 static pthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER;
@@ -132,6 +132,11 @@ emit_recursive_batch(igt_spin_t *spin,
 			    !gem_class_can_store_dword(fd, engine->class))
 				continue;
 
+			if (opts->flags & (IGT_SPIN_STORE_DWORD |
+					   IGT_SPIN_STORE_DATA) &&
+			    !gem_class_can_store_dword(fd, engine->class))
+				continue;
+
 			flags[nengine++] = engine->flags;
 		}
 	} else {
@@ -160,6 +165,8 @@ emit_recursive_batch(igt_spin_t *spin,
 
 	if (opts->dependency) {
 		igt_assert(!(opts->flags & IGT_SPIN_POLL_RUN));
+		igt_assert(!(opts->flags & (IGT_SPIN_STORE_DWORD |
+					    IGT_SPIN_STORE_DATA)));
 
 		obj[SCRATCH].handle = opts->dependency;
 		obj[SCRATCH].offset = addr;
@@ -178,6 +185,9 @@ emit_recursive_batch(igt_spin_t *spin,
 
 		execbuf->buffer_count++;
 	} else if (opts->flags & IGT_SPIN_POLL_RUN) {
+		igt_assert(!(opts->flags & (IGT_SPIN_STORE_DWORD |
+					    IGT_SPIN_STORE_DATA)));
+
 		r = &relocs[obj[BATCH].relocation_count++];
 
 		igt_assert(!opts->dependency);
@@ -230,6 +240,63 @@ emit_recursive_batch(igt_spin_t *spin,
 
 		*cs++ = 1;
 
+		execbuf->buffer_count++;
+	} else if (opts->flags & (IGT_SPIN_STORE_DWORD | IGT_SPIN_STORE_DATA)) {
+		int len, cmd;
+
+		igt_assert(opts->store_handle);
+		igt_assert((opts->store_offset & 3) == 0);
+		if (opts->flags & IGT_SPIN_STORE_DATA) {
+			igt_assert(!(opts->flags & IGT_SPIN_STORE_DWORD));
+			igt_assert(opts->store_length < LOOP_START_OFFSET - 16);
+			igt_assert(opts->store_data);
+			len = opts->store_length;
+		} else {
+			len = sizeof(uint32_t);
+		}
+
+		addr += 4096; /* guard page */
+		obj[SCRATCH].offset = addr;
+		obj[SCRATCH].handle = opts->store_handle;
+		obj[SCRATCH].flags = EXEC_OBJECT_WRITE;
+
+		r = &relocs[obj[BATCH].relocation_count++];
+		r->read_domains = I915_GEM_DOMAIN_RENDER;
+		r->write_domain = I915_GEM_DOMAIN_RENDER;
+
+		if (gen == 4 || gen == 5) {
+			execbuf->flags |= I915_EXEC_SECURE;
+			igt_require(__igt_device_set_master(fd) == 0);
+		}
+
+		r->presumed_offset = obj[SCRATCH].offset;
+		r->target_handle = obj[SCRATCH].handle;
+		r->offset = sizeof(uint32_t) * 1;
+		r->delta = opts->store_offset;
+
+		cmd = len / sizeof(uint32_t) + 1;
+		if (gen >= 4)
+			cmd++;
+		*cs++ = 0x20 << 23 | (gen < 6 ? 1 << 22 : 0) | cmd;
+
+		if (gen >= 8) {
+			*cs++ = r->presumed_offset + r->delta;
+			*cs++ = 0;
+		} else if (gen >= 4) {
+			*cs++ = 0;
+			*cs++ = r->presumed_offset + r->delta;
+			r->offset += sizeof(uint32_t);
+		} else {
+			*cs++ = r->presumed_offset + r->delta;
+		}
+
+		if (opts->flags & IGT_SPIN_STORE_DWORD) {
+			*cs++ = opts->store_dw;
+		} else {
+			memcpy(cs, opts->store_data, len);
+			cs += len / sizeof(*cs);
+		}
+
 		execbuf->buffer_count++;
 	}
 
@@ -258,7 +325,7 @@ emit_recursive_batch(igt_spin_t *spin,
 	 * trouble. See https://bugs.freedesktop.org/show_bug.cgi?id=102262
 	 */
 	if (!(opts->flags & IGT_SPIN_FAST))
-		cs += 960;
+		cs = spin->batch + 1000;
 
 	/*
 	 * When using a cmdparser, the batch is copied into a read only location
diff --git a/lib/igt_dummyload.h b/lib/igt_dummyload.h
index 9e19ffabc..bc8e8ebb3 100644
--- a/lib/igt_dummyload.h
+++ b/lib/igt_dummyload.h
@@ -62,6 +62,16 @@ struct igt_spin_factory {
 	unsigned int engine;
 	unsigned int flags;
 	int fence;
+
+	uint32_t store_handle;
+	uint32_t store_offset;
+	union {
+		struct {
+			void *store_data;
+			uint32_t store_length;
+		};
+		uint32_t store_dw;
+	};
 };
 
 #define IGT_SPIN_FENCE_IN      (1 << 0)
@@ -73,6 +83,8 @@ struct igt_spin_factory {
 #define IGT_SPIN_INVALID_CS    (1 << 6)
 #define IGT_SPIN_USERPTR       (1 << 7)
 #define IGT_SPIN_SOFTDEP       (1 << 8)
+#define IGT_SPIN_STORE_DWORD   (1 << 9)
+#define IGT_SPIN_STORE_DATA    (1 << 10)
 
 igt_spin_t *
 __igt_spin_factory(int fd, const struct igt_spin_factory *opts);
diff --git a/tests/i915/gem_spin_batch.c b/tests/i915/gem_spin_batch.c
index 19bc4638d..1ce865d6d 100644
--- a/tests/i915/gem_spin_batch.c
+++ b/tests/i915/gem_spin_batch.c
@@ -71,6 +71,45 @@ static void spin(int fd,
 	assert_within_epsilon(timeout_100ms * loops, elapsed, MAX_ERROR);
 }
 
+static void store(int fd, const struct intel_execution_engine2 *e2)
+{
+	igt_spin_t *spin;
+	uint32_t handle;
+	uint32_t *map;
+	int i;
+
+	handle = gem_create(fd, 4096);
+	map = gem_mmap__device_coherent(fd, handle, 0, 4096, PROT_WRITE);
+
+	spin = igt_spin_new(fd,
+			    .engine = e2->flags,
+			    .store_handle = handle,
+			    .store_dw = 0xdeadbeef,
+			    .flags = IGT_SPIN_STORE_DWORD);
+	igt_spin_end(spin);
+	gem_sync(fd, spin->handle);
+	igt_spin_free(fd, spin);
+	igt_assert_eq(map[0], 0xdeadbeef);
+
+	for (i = 0; i < 16; i++)
+		map[i] = i;
+	spin = igt_spin_new(fd,
+			    .engine = e2->flags,
+			    .store_handle = handle,
+			    .store_offset = sizeof(uint32_t),
+			    .store_length = 16 * sizeof(uint32_t),
+			    .store_data = map,
+			    .flags = IGT_SPIN_STORE_DATA);
+	igt_spin_end(spin);
+	gem_sync(fd, spin->handle);
+	igt_spin_free(fd, spin);
+	for (i = 0; i < 16; i++)
+		igt_assert_eq(map[i + 1], i);
+
+	munmap(map, 4096);
+	gem_close(fd, handle);
+}
+
 #define RESUBMIT_NEW_CTX     (1 << 0)
 #define RESUBMIT_ALL_ENGINES (1 << 1)
 
@@ -204,6 +243,13 @@ igt_main
 	igt_subtest("spin-all-new")
 		spin_all(fd, PARALLEL_SPIN_NEW_CTX);
 
+	igt_subtest_with_dynamic("store"){
+		__for_each_physical_engine(fd, e2) {
+			igt_dynamic_f("%s", e2->name)
+				store(fd, e2);
+		}
+	}
+
 	__for_each_physical_engine(fd, e2) {
 		igt_subtest_f("%s", e2->name)
 			spin(fd, e2, 0, 3);
-- 
2.29.2



More information about the igt-dev mailing list