diff --git a/lib/igt_dummyload.c b/lib/igt_dummyload.c
index 47f6b92b..064a0246 100644
--- a/lib/igt_dummyload.c
+++ b/lib/igt_dummyload.c
@@ -67,11 +67,13 @@ static pthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER;
 
 static void
 fill_reloc(struct drm_i915_gem_relocation_entry *reloc,
-	   uint32_t gem_handle, uint32_t offset,
+	   uint32_t gem_handle, uint32_t offset, uint32_t delta,
 	   uint32_t read_domains, uint32_t write_domains)
 {
+	reloc->presumed_offset = 0;
 	reloc->target_handle = gem_handle;
 	reloc->offset = offset * sizeof(uint32_t);
+	reloc->delta = delta * sizeof(uint32_t);
 	reloc->read_domains = read_domains;
 	reloc->write_domain = write_domains;
 }
@@ -131,11 +133,13 @@ emit_recursive_batch(igt_spin_t *spin,
 		/* dummy write to dependency */
 		obj[SCRATCH].handle = opts->dependency;
 		fill_reloc(&relocs[obj[BATCH].relocation_count++],
-			   opts->dependency, 1020,
+			   opts->dependency, 1020, 0,
 			   I915_GEM_DOMAIN_RENDER,
 			   I915_GEM_DOMAIN_RENDER);
 		execbuf->buffer_count++;
 	} else if (opts->flags & IGT_SPIN_POLL_RUN) {
+		const unsigned int start_idx_offset =
+			SPIN_POLL_START_IDX * sizeof(uint32_t);
 		unsigned int offset;
 
 		igt_assert(!opts->dependency);
@@ -149,36 +153,37 @@ emit_recursive_batch(igt_spin_t *spin,
 
 		if (__gem_set_caching(fd, spin->poll_handle,
 				      I915_CACHING_CACHED) == 0)
-			spin->running = gem_mmap__cpu(fd, spin->poll_handle,
-						      0, 4096,
-						      PROT_READ | PROT_WRITE);
+			spin->poll = gem_mmap__cpu(fd, spin->poll_handle,
+						   0, 4096,
+						   PROT_READ | PROT_WRITE);
 		else
-			spin->running = gem_mmap__wc(fd, spin->poll_handle,
-						     0, 4096,
-						     PROT_READ | PROT_WRITE);
-		igt_assert_eq(*spin->running, 0);
+			spin->poll = gem_mmap__wc(fd, spin->poll_handle,
+						  0, 4096,
+						  PROT_READ | PROT_WRITE);
+		igt_assert_eq(spin->poll[SPIN_POLL_START_IDX], 0);
 
 		*batch++ = MI_STORE_DWORD_IMM | (gen < 6 ? 1 << 22 : 0);
 
 		if (gen >= 8) {
 			offset = 1;
-			*batch++ = 0;
+			*batch++ = start_idx_offset;
 			*batch++ = 0;
 		} else if (gen >= 4) {
 			offset = 2;
 			*batch++ = 0;
-			*batch++ = 0;
+			*batch++ = start_idx_offset;
 		} else {
 			offset = 1;
 			batch[-1]--;
-			*batch++ = 0;
+			*batch++ = start_idx_offset;
 		}
 
 		*batch++ = 1;
 
 		obj[SCRATCH].handle = spin->poll_handle;
 		fill_reloc(&relocs[obj[BATCH].relocation_count++],
-			   spin->poll_handle, offset, 0, 0);
+			   spin->poll_handle, offset,
+			   SPIN_POLL_START_IDX, 0, 0);
 		execbuf->buffer_count++;
 	}
 
@@ -408,8 +413,8 @@ void igt_spin_batch_free(int fd, igt_spin_t *spin)
 	gem_munmap((void *)((unsigned long)spin->batch & (~4095UL)),
 		   BATCH_SIZE);
 
-	if (spin->running) {
-		gem_munmap(spin->running, 4096);
+	if (spin->poll) {
+		gem_munmap(spin->poll, 4096);
 		gem_close(fd, spin->poll_handle);
 	}
 
diff --git a/lib/igt_dummyload.h b/lib/igt_dummyload.h
index 73bd035b..3793bf7f 100644
--- a/lib/igt_dummyload.h
+++ b/lib/igt_dummyload.h
@@ -41,7 +41,8 @@ typedef struct igt_spin {
 	struct drm_i915_gem_exec_object2 obj[2];
 	struct drm_i915_gem_execbuffer2 execbuf;
 	uint32_t poll_handle;
-	bool *running;
+	uint32_t *poll;
+#define SPIN_POLL_START_IDX 0
 } igt_spin_t;
 
 struct igt_spin_factory {
@@ -70,9 +71,19 @@ void igt_spin_batch_set_timeout(igt_spin_t *spin, int64_t ns);
 void igt_spin_batch_end(igt_spin_t *spin);
 void igt_spin_batch_free(int fd, igt_spin_t *spin);
 
-static inline void igt_spin_busywait_until_running(igt_spin_t *spin)
+static inline bool igt_spin_has_poll(const igt_spin_t *spin)
 {
-	while (!READ_ONCE(*spin->running))
+	return spin->poll;
+}
+
+static inline bool igt_spin_has_started(igt_spin_t *spin)
+{
+	return READ_ONCE(spin->poll[SPIN_POLL_START_IDX]);
+}
+
+static inline void igt_spin_busywait_until_started(igt_spin_t *spin)
+{
+	while (!igt_spin_has_started(spin))
 		;
 }
 
diff --git a/tests/i915/gem_ctx_exec.c b/tests/i915/gem_ctx_exec.c
index d67d0ec2..f37e6f28 100644
--- a/tests/i915/gem_ctx_exec.c
+++ b/tests/i915/gem_ctx_exec.c
@@ -181,10 +181,8 @@ static void norecovery(int i915)
 		spin = __igt_spin_batch_new(i915,
 					    .ctx = param.ctx_id,
 					    .flags = IGT_SPIN_POLL_RUN);
-		igt_assert(spin->running);
+		igt_spin_busywait_until_started(spin);
 
-		while (!READ_ONCE(*spin->running))
-			;
 		igt_force_gpu_reset(i915);
 
 		igt_spin_batch_end(spin);
diff --git a/tests/i915/gem_ctx_isolation.c b/tests/i915/gem_ctx_isolation.c
index f1000458..bed71c2b 100644
--- a/tests/i915/gem_ctx_isolation.c
+++ b/tests/i915/gem_ctx_isolation.c
@@ -704,8 +704,8 @@ static void inject_reset_context(int fd, unsigned int engine)
 
 	spin = __igt_spin_batch_factory(fd, &opts);
 
-	if (spin->running)
-		igt_spin_busywait_until_running(spin);
+	if (igt_spin_has_poll(spin))
+		igt_spin_busywait_until_started(spin);
 	else
 		usleep(1000); /* better than nothing */
 
diff --git a/tests/i915/gem_eio.c b/tests/i915/gem_eio.c
index 29250852..07bbdeb1 100644
--- a/tests/i915/gem_eio.c
+++ b/tests/i915/gem_eio.c
@@ -186,8 +186,8 @@ static igt_spin_t * __spin_poll(int fd, uint32_t ctx, unsigned long flags)
 
 static void __spin_wait(int fd, igt_spin_t *spin)
 {
-	if (spin->running) {
-		igt_spin_busywait_until_running(spin);
+	if (igt_spin_has_poll(spin)) {
+		igt_spin_busywait_until_started(spin);
 	} else {
 		igt_debug("__spin_wait - usleep mode\n");
 		usleep(500e3); /* Better than nothing! */
diff --git a/tests/i915/gem_exec_latency.c b/tests/i915/gem_exec_latency.c
index 39f441d2..fc1040c3 100644
--- a/tests/i915/gem_exec_latency.c
+++ b/tests/i915/gem_exec_latency.c
@@ -79,29 +79,29 @@ poll_ring(int fd, unsigned ring, const char *name)
 	igt_require(gem_can_store_dword(fd, ring));
 
 	spin[0] = __igt_spin_batch_factory(fd, &opts);
-	igt_assert(spin[0]->running);
+	igt_assert(igt_spin_has_poll(spin[0]));
 	cmd = *spin[0]->batch;
 
 	spin[1] = __igt_spin_batch_factory(fd, &opts);
-	igt_assert(spin[1]->running);
+	igt_assert(igt_spin_has_poll(spin[1]));
+
 	igt_assert(cmd == *spin[1]->batch);
 
 	igt_spin_batch_end(spin[0]);
-	while (!READ_ONCE(*spin[1]->running))
-		;
+	igt_spin_busywait_until_started(spin[1]);
+
 	igt_assert(!gem_bo_busy(fd, spin[0]->handle));
 
 	cycles = 0;
 	while ((elapsed = igt_nsec_elapsed(&tv)) < 2ull << 30) {
-		unsigned int idx = cycles++ & 1;
+		const unsigned int idx = cycles++ & 1;
 
 		*spin[idx]->batch = cmd;
-		*spin[idx]->running = 0;
+		spin[idx]->poll[SPIN_POLL_START_IDX] = 0;
 		gem_execbuf(fd, &spin[idx]->execbuf);
 
 		igt_spin_batch_end(spin[!idx]);
-		while (!READ_ONCE(*spin[idx]->running))
-			;
+		igt_spin_busywait_until_started(spin[idx]);
 	}
 
 	igt_info("%s completed %ld cycles: %.3f us\n",
@@ -419,7 +419,7 @@ static void __rearm_spin_batch(igt_spin_t *spin)
 	const uint32_t mi_arb_chk = 0x5 << 23;
 
        *spin->batch = mi_arb_chk;
-       *spin->running = 0;
+       spin->poll[SPIN_POLL_START_IDX] = 0;
        __sync_synchronize();
 }
 
@@ -441,7 +441,7 @@ struct rt_pkt {
 
 static bool __spin_wait(int fd, igt_spin_t *spin)
 {
-	while (!READ_ONCE(*spin->running)) {
+	while (!igt_spin_has_started(spin)) {
 		if (!gem_bo_busy(fd, spin->handle))
 			return false;
 	}
@@ -537,7 +537,7 @@ rthog_latency_on_ring(int fd, unsigned int engine, const char *name, unsigned in
 					 passname[pass]);
 				break;
 			}
-			igt_spin_busywait_until_running(spin);
+			igt_spin_busywait_until_started(spin);
 
 			igt_until_timeout(pass > 0 ? 5 : 2) {
 				struct timespec ts = { };
diff --git a/tests/i915/gem_exec_schedule.c b/tests/i915/gem_exec_schedule.c
index 6f3f52d2..718a1935 100644
--- a/tests/i915/gem_exec_schedule.c
+++ b/tests/i915/gem_exec_schedule.c
@@ -436,7 +436,7 @@ static void semaphore_codependency(int i915)
 					     .ctx = ctx,
 					     .engine = engine,
 					     .flags = IGT_SPIN_POLL_RUN);
-		igt_spin_busywait_until_running(task[i].xcs);
+		igt_spin_busywait_until_started(task[i].xcs);
 
 		/* Common rcs tasks will be queued in FIFO */
 		task[i].rcs =
@@ -1361,8 +1361,7 @@ static void measure_semaphore_power(int i915)
 					    .engine = signaler,
 					    .flags = IGT_SPIN_POLL_RUN);
 		gem_wait(i915, spin->handle, &jiffie); /* waitboost */
-		igt_assert(spin->running);
-		igt_spin_busywait_until_running(spin);
+		igt_spin_busywait_until_started(spin);
 
 		gpu_power_read(&power, &s_spin[0]);
 		usleep(100*1000);
diff --git a/tests/i915/gem_sync.c b/tests/i915/gem_sync.c
index 3e4feff3..0a0ed2a1 100644
--- a/tests/i915/gem_sync.c
+++ b/tests/i915/gem_sync.c
@@ -225,7 +225,7 @@ wakeup_ring(int fd, unsigned ring, int timeout, int wlen)
 					    .engine = execbuf.flags,
 					    .flags = (IGT_SPIN_POLL_RUN |
 						      IGT_SPIN_FAST));
-		igt_assert(spin->running);
+		igt_assert(igt_spin_has_poll(spin));
 		cmd = *spin->batch;
 
 		gem_execbuf(fd, &execbuf);
@@ -239,10 +239,9 @@ wakeup_ring(int fd, unsigned ring, int timeout, int wlen)
 			cycles = 0;
 			do {
 				*spin->batch = cmd;
-				*spin->running = 0;
+				spin->poll[SPIN_POLL_START_IDX] = 0;
 				gem_execbuf(fd, &spin->execbuf);
-				while (!READ_ONCE(*spin->running))
-					;
+				igt_spin_busywait_until_started(spin);
 
 				this = gettime();
 				igt_spin_batch_end(spin);
@@ -264,10 +263,9 @@ wakeup_ring(int fd, unsigned ring, int timeout, int wlen)
 		cycles = 0;
 		do {
 			*spin->batch = cmd;
-			*spin->running = 0;
+			spin->poll[SPIN_POLL_START_IDX] = 0;
 			gem_execbuf(fd, &spin->execbuf);
-			while (!READ_ONCE(*spin->running))
-				;
+			igt_spin_busywait_until_started(spin);
 
 			for (int n = 0; n < wlen; n++)
 				gem_execbuf(fd, &execbuf);
@@ -410,7 +408,7 @@ active_wakeup_ring(int fd, unsigned ring, int timeout, int wlen)
 					       .engine = execbuf.flags,
 					       .flags = (IGT_SPIN_POLL_RUN |
 							 IGT_SPIN_FAST));
-		igt_assert(spin[0]->running);
+		igt_assert(igt_spin_has_poll(spin[0]));
 		cmd = *spin[0]->batch;
 
 		spin[1] = __igt_spin_batch_new(fd,
@@ -426,18 +424,17 @@ active_wakeup_ring(int fd, unsigned ring, int timeout, int wlen)
 
 		for (int warmup = 0; warmup <= 1; warmup++) {
 			*spin[0]->batch = cmd;
-			*spin[0]->running = 0;
+			spin[0]->poll[SPIN_POLL_START_IDX] = 0;
 			gem_execbuf(fd, &spin[0]->execbuf);
 
 			end = gettime() + timeout/10.;
 			elapsed = 0;
 			cycles = 0;
 			do {
-				while (!READ_ONCE(*spin[0]->running))
-					;
+				igt_spin_busywait_until_started(spin[0]);
 
 				*spin[1]->batch = cmd;
-				*spin[1]->running = 0;
+				spin[1]->poll[SPIN_POLL_START_IDX] = 0;
 				gem_execbuf(fd, &spin[1]->execbuf);
 
 				this = gettime();
@@ -458,21 +455,20 @@ active_wakeup_ring(int fd, unsigned ring, int timeout, int wlen)
 			 cycles, elapsed*1e6/cycles);
 
 		*spin[0]->batch = cmd;
-		*spin[0]->running = 0;
+		spin[0]->poll[SPIN_POLL_START_IDX] = 0;
 		gem_execbuf(fd, &spin[0]->execbuf);
 
 		end = gettime() + timeout;
 		elapsed = 0;
 		cycles = 0;
 		do {
-			while (!READ_ONCE(*spin[0]->running))
-				;
+			igt_spin_busywait_until_started(spin[0]);
 
 			for (int n = 0; n < wlen; n++)
 				gem_execbuf(fd, &execbuf);
 
 			*spin[1]->batch = cmd;
-			*spin[1]->running = 0;
+			spin[1]->poll[SPIN_POLL_START_IDX] = 0;
 			gem_execbuf(fd, &spin[1]->execbuf);
 
 			this = gettime();
diff --git a/tests/perf_pmu.c b/tests/perf_pmu.c
index 4f552bc2..28f235b1 100644
--- a/tests/perf_pmu.c
+++ b/tests/perf_pmu.c
@@ -189,10 +189,10 @@ static unsigned long __spin_wait(int fd, igt_spin_t *spin)
 
 	igt_nsec_elapsed(&start);
 
-	if (spin->running) {
+	if (igt_spin_has_poll(spin)) {
 		unsigned long timeout = 0;
 
-		while (!READ_ONCE(*spin->running)) {
+		while (!igt_spin_has_started(spin)) {
 			unsigned long t = igt_nsec_elapsed(&start);
 
 			if ((t - timeout) > 250e6) {
