diff --git a/tests/gem_exec_schedule.c b/tests/gem_exec_schedule.c
index d8454d5..87d5a85 100644
--- a/tests/gem_exec_schedule.c
+++ b/tests/gem_exec_schedule.c
@@ -106,96 +106,6 @@ static void store_dword(int fd, uint32_t ctx, unsigned ring,
 	gem_close(fd, obj[2].handle);
 }
 
-static uint32_t *make_busy(int fd, uint32_t target, unsigned ring)
-{
-	const int gen = intel_gen(intel_get_drm_devid(fd));
-	struct drm_i915_gem_exec_object2 obj[2];
-	struct drm_i915_gem_relocation_entry reloc[2];
-	struct drm_i915_gem_execbuffer2 execbuf;
-	uint32_t *batch;
-	int i;
-
-	memset(&execbuf, 0, sizeof(execbuf));
-	execbuf.buffers_ptr = to_user_pointer(obj + !target);
-	execbuf.buffer_count = 1 + !!target;
-
-	memset(obj, 0, sizeof(obj));
-	obj[0].handle = target;
-	obj[1].handle = gem_create(fd, 4096);
-	batch = gem_mmap__wc(fd, obj[1].handle, 0, 4096, PROT_WRITE);
-	gem_set_domain(fd, obj[1].handle,
-			I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
-
-	obj[1].relocs_ptr = to_user_pointer(reloc);
-	obj[1].relocation_count = 1 + !!target;
-	memset(reloc, 0, sizeof(reloc));
-
-	reloc[0].target_handle = obj[1].handle; /* recurse */
-	reloc[0].presumed_offset = 0;
-	reloc[0].offset = sizeof(uint32_t);
-	reloc[0].delta = 0;
-	reloc[0].read_domains = I915_GEM_DOMAIN_COMMAND;
-	reloc[0].write_domain = 0;
-
-	reloc[1].target_handle = target;
-	reloc[1].presumed_offset = 0;
-	reloc[1].offset = 1024;
-	reloc[1].delta = 0;
-	reloc[1].read_domains = I915_GEM_DOMAIN_COMMAND;
-	reloc[1].write_domain = 0;
-
-	i = 0;
-	batch[i] = MI_BATCH_BUFFER_START;
-	if (gen >= 8) {
-		batch[i] |= 1 << 8 | 1;
-		batch[++i] = 0;
-		batch[++i] = 0;
-	} else if (gen >= 6) {
-		batch[i] |= 1 << 8;
-		batch[++i] = 0;
-	} else {
-		batch[i] |= 2 << 6;
-		batch[++i] = 0;
-		if (gen < 4) {
-			batch[i] |= 1;
-			reloc[0].delta = 1;
-		}
-	}
-	i++;
-
-	if (ring != -1) {
-		execbuf.flags = ring;
-		for (int n = 0; n < BUSY_QLEN; n++)
-			gem_execbuf(fd, &execbuf);
-	} else {
-		for_each_engine(fd, ring) {
-			if (ring == 0)
-				continue;
-
-			execbuf.flags = ring;
-			for (int n = 0; n < BUSY_QLEN; n++)
-				gem_execbuf(fd, &execbuf);
-			igt_assert(execbuf.flags == ring);
-		}
-	}
-
-	if (target) {
-		execbuf.flags = 0;
-		reloc[1].write_domain = I915_GEM_DOMAIN_COMMAND;
-		gem_execbuf(fd, &execbuf);
-	}
-
-	gem_close(fd, obj[1].handle);
-
-	return batch;
-}
-
-static void finish_busy(uint32_t *busy)
-{
-	*busy = MI_BATCH_BUFFER_END;
-	munmap(busy, 4096);
-}
-
 struct cork {
 	int device;
 	uint32_t handle;
@@ -228,13 +138,13 @@ static void unplug(struct cork *c)
 static void fifo(int fd, unsigned ring)
 {
 	struct cork cork;
-	uint32_t *busy;
+	igt_spin_t *busy;
 	uint32_t scratch;
 	uint32_t *ptr;
 
 	scratch = gem_create(fd, 4096);
 
-	busy = make_busy(fd, scratch, ring);
+	busy = igt_spin_batch_new(fd, ring, scratch);
 	plug(fd, &cork);
 
 	/* Same priority, same timeline, final result will be the second eb */
@@ -243,12 +153,12 @@ static void fifo(int fd, unsigned ring)
 
 	unplug(&cork); /* only now submit our batches */
 	igt_debugfs_dump(fd, "i915_engine_info");
-	finish_busy(busy);
+	igt_spin_batch_end(busy);
 
 	ptr = gem_mmap__gtt(fd, scratch, 4096, PROT_READ);
 	gem_set_domain(fd, scratch, /* no write hazard lies! */
 			I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
-	gem_close(fd, scratch);
+	igt_spin_batch_free(fd, busy);
 
 	igt_assert_eq_u32(ptr[0], 2);
 	munmap(ptr, 4096);
@@ -259,7 +169,7 @@ static void reorder(int fd, unsigned ring, unsigned flags)
 {
 	struct cork cork;
 	uint32_t scratch;
-	uint32_t *busy;
+	igt_spin_t *busy;
 	uint32_t *ptr;
 	uint32_t ctx[2];
 
@@ -271,7 +181,7 @@ static void reorder(int fd, unsigned ring, unsigned flags)
 
 	scratch = gem_create(fd, 4096);
 
-	busy = make_busy(fd, scratch, ring);
+	busy = igt_spin_batch_new(fd, ring, scratch);
 	plug(fd, &cork);
 
 	/* We expect the high priority context to be executed first, and
@@ -282,7 +192,7 @@ static void reorder(int fd, unsigned ring, unsigned flags)
 
 	unplug(&cork); /* only now submit our batches */
 	igt_debugfs_dump(fd, "i915_engine_info");
-	finish_busy(busy);
+	igt_spin_batch_end(busy);
 
 	gem_context_destroy(fd, ctx[LO]);
 	gem_context_destroy(fd, ctx[HI]);
@@ -290,7 +200,7 @@ static void reorder(int fd, unsigned ring, unsigned flags)
 	ptr = gem_mmap__gtt(fd, scratch, 4096, PROT_READ);
 	gem_set_domain(fd, scratch, /* no write hazard lies! */
 			I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
-	gem_close(fd, scratch);
+	igt_spin_batch_free(fd, busy);
 
 	if (flags & EQUAL) /* equal priority, result will be fifo */
 		igt_assert_eq_u32(ptr[0], ctx[HI]);
@@ -303,7 +213,7 @@ static void promotion(int fd, unsigned ring)
 {
 	struct cork cork;
 	uint32_t result, dep;
-	uint32_t *busy;
+	igt_spin_t *busy;
 	uint32_t *ptr;
 	uint32_t ctx[3];
 
@@ -319,7 +229,7 @@ static void promotion(int fd, unsigned ring)
 	result = gem_create(fd, 4096);
 	dep = gem_create(fd, 4096);
 
-	busy = make_busy(fd, result, ring);
+	busy = igt_spin_batch_new(fd, ring, result);
 	plug(fd, &cork);
 
 	/* Expect that HI promotes LO, so the order will be LO, HI, NOISE.
@@ -338,7 +248,7 @@ static void promotion(int fd, unsigned ring)
 
 	unplug(&cork); /* only now submit our batches */
 	igt_debugfs_dump(fd, "i915_engine_info");
-	finish_busy(busy);
+	igt_spin_batch_end(busy);
 
 	gem_context_destroy(fd, ctx[NOISE]);
 	gem_context_destroy(fd, ctx[LO]);
@@ -355,7 +265,7 @@ static void promotion(int fd, unsigned ring)
 	ptr = gem_mmap__gtt(fd, result, 4096, PROT_READ);
 	gem_set_domain(fd, result, /* no write hazard lies! */
 			I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
-	gem_close(fd, result);
+	igt_spin_batch_free(fd, busy);
 
 	igt_assert_eq_u32(ptr[0], ctx[NOISE]);
 	munmap(ptr, 4096);
@@ -366,7 +276,7 @@ static void deep(int fd, unsigned ring)
 #define XS 8
 	struct cork cork;
 	uint32_t result, dep[XS];
-	uint32_t *busy;
+	igt_spin_t *busy;
 	uint32_t *ptr;
 	uint32_t *ctx;
 
@@ -380,7 +290,7 @@ static void deep(int fd, unsigned ring)
 	for (int m = 0; m < XS; m ++)
 		dep[m] = gem_create(fd, 4096);
 
-	busy = make_busy(fd, result, ring);
+	busy = igt_spin_batch_new(fd, ring, result);
 	plug(fd, &cork);
 
 	/* Create a deep dependency chain, with a few branches */
@@ -398,7 +308,7 @@ static void deep(int fd, unsigned ring)
 	igt_assert(gem_bo_busy(fd, result));
 	unplug(&cork); /* only now submit our batches */
 	igt_debugfs_dump(fd, "i915_engine_info");
-	finish_busy(busy);
+	igt_spin_batch_end(busy);
 
 	for (int n = 0; n <= MAX_PRIO; n++)
 		gem_context_destroy(fd, ctx[n]);
