Igt-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] tests/core_hotunplug: add *-with-load subtests exercising GPU workload during hotplug
@ 2026-05-18 12:01 Nitin Gote
  2026-05-18 12:53 ` Janusz Krzysztofik
  0 siblings, 1 reply; 10+ messages in thread
From: Nitin Gote @ 2026-05-18 12:01 UTC (permalink / raw)
  To: igt-dev, janusz.krzysztofik, kamil.konieczny; +Cc: matthew.auld, nitin.r.gote

The six fd-holding hot* subtests keep a DRM fd open across unbind/unplug
but leave the GPU idle, so the kernel hotplug path is never exercised
against an active VM, exec queue and BOs.

Add six new dedicated *-with-load subtests that run a GPU spinner across
the unbind/unplug sequence so the device is removed while a workload is
actively using it.

The workload helpers use an explicit chipset dispatch block in
workload_start()/stop() so that other vendors can contribute
support by adding an else-if branch. New subtests are gated on
workload_available(), which currently covers DRIVER_XE and DRIVER_INTEL,
and returns false (SKIP) on any other driver.

igt_spin_free() is avoided in workload_stop() since the device may be
gone by then — igt_spin_end() writes the stop condition via a userspace
mmap and lets the DRM fd close reclaim kernel-side resources.

Validated on BMG and DG2 with a KASAN-enabled kernel:
all six new subtests pass with no KASAN reports.

v2: Pass the hotunplug priv struct to workload_start()/stop()
    and dispatch via an explicit if/else-if chipset block to invite
    other vendors to contribute. (Janusz)

Cc: Matthew Auld <matthew.auld@intel.com>
Cc: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
Cc: Kamil Konieczny <kamil.konieczny@linux.intel.com>
Assisted-by: Copilot:claude-opus-4.7
Signed-off-by: Nitin Gote <nitin.r.gote@intel.com>
---
 tests/core_hotunplug.c | 290 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 290 insertions(+)

diff --git a/tests/core_hotunplug.c b/tests/core_hotunplug.c
index 7c9dae1bf..38dcbb97d 100644
--- a/tests/core_hotunplug.c
+++ b/tests/core_hotunplug.c
@@ -80,6 +80,34 @@
  * SUBTEST: unplug-rescan
  * Description: Check if a device believed to be closed can be cleanly
  *		unplugged, then restored
+ *
+ * SUBTEST: hotunbind-rebind-with-load
+ * Description: Check if the driver can be cleanly unbound from an open device
+ *		with a background GPU workload in flight, then released and
+ *		rebound
+ *
+ * SUBTEST: hotunplug-rescan-with-load
+ * Description: Check if an open device with a background GPU workload in
+ *		flight can be cleanly unplugged, then released and restored
+ *
+ * SUBTEST: hotrebind-with-load
+ * Description: Check if the driver can be cleanly rebound to a device with a
+ *		still open hot unbound driver instance while a background GPU
+ *		workload is in flight
+ *
+ * SUBTEST: hotreplug-with-load
+ * Description: Check if a hot unplugged and still open device can be cleanly
+ *		restored while a background GPU workload is in flight
+ *
+ * SUBTEST: hotrebind-lateclose-with-load
+ * Description: Check if a hot unbound driver instance still open after hot
+ *		rebind with a background GPU workload in flight can be cleanly
+ *		released
+ *
+ * SUBTEST: hotreplug-lateclose-with-load
+ * Description: Check if an instance of a still open while hot replugged
+ *		device with a background GPU workload in flight can be cleanly
+ *		released
  */
 
 IGT_TEST_DESCRIPTION("Examine behavior of a driver on device hot unplug");
@@ -565,6 +593,52 @@ static void set_filter_from_device(int fd)
 	igt_assert_eq(igt_device_filter_add(filter), 1);
 }
 
+/* GPU workload helpers */
+
+struct gpu_workload {
+	igt_spin_t *spin;
+	uint64_t ahnd;
+};
+
+static bool workload_available(int chipset)
+{
+	return chipset == DRIVER_XE || chipset == DRIVER_INTEL;
+}
+
+static void workload_start(struct hotunplug *priv, int fd,
+			   struct gpu_workload *w)
+{
+	if (priv->chipset == DRIVER_XE || priv->chipset == DRIVER_INTEL) {
+		local_debug("%s\n", "starting GPU spinner");
+		priv->failure = "GPU workload start failure!";
+		w->ahnd = intel_allocator_open(fd, 0, INTEL_ALLOCATOR_RELOC);
+		w->spin = igt_spin_new(fd, .ahnd = w->ahnd);
+		priv->failure = NULL;
+	}
+}
+
+static void workload_stop(struct hotunplug *priv, struct gpu_workload *w)
+{
+	if (priv->chipset == DRIVER_XE || priv->chipset == DRIVER_INTEL) {
+		if (!w->spin)
+			return;
+
+		/*
+		 * The device may be gone (unbind/unplug), so avoid
+		 * igt_spin_free(): on Xe it would wait forever on a syncobj
+		 * that never signals; on i915 it would touch the dead fd via
+		 * gem_munmap()/gem_close(). Instead, end the spinner via a
+		 * userspace mmap write and let the DRM fd close reclaim the
+		 * kernel-side resources.
+		 */
+		local_debug("%s\n", "stopping GPU spinner");
+		igt_spin_end(w->spin);
+		put_ahnd(w->ahnd);
+		w->spin = NULL;
+		w->ahnd = 0;
+	}
+}
+
 /* Subtests */
 
 static void unbind_rebind(struct hotunplug *priv)
@@ -679,6 +753,150 @@ static void hotreplug_lateclose(struct hotunplug *priv)
 	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
 }
 
+static void hotunbind_rebind_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot unbind");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	driver_unbind(priv, "hot ", 0);
+
+	workload_stop(priv, &w);
+
+	priv->fd.drm = close_device(priv->fd.drm, "late ", "unbound ");
+	igt_assert_eq(priv->fd.drm, -1);
+
+	driver_bind(priv, 0);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
+static void hotunplug_rescan_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot unplug");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	device_unplug(priv, "hot ", 0);
+
+	workload_stop(priv, &w);
+
+	priv->fd.drm = close_device(priv->fd.drm, "late ", "removed ");
+	igt_assert_eq(priv->fd.drm, -1);
+
+	bus_rescan(priv, 0);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
+static void hotrebind_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot rebind");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	driver_unbind(priv, "hot ", 60);
+
+	driver_bind(priv, 0);
+
+	workload_stop(priv, &w);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
+static void hotreplug_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot replug");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	device_unplug(priv, "hot ", 60);
+
+	bus_rescan(priv, 0);
+
+	workload_stop(priv, &w);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
+static void hotrebind_lateclose_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot rebind");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	driver_unbind(priv, "hot ", 60);
+
+	driver_bind(priv, 0);
+
+	workload_stop(priv, &w);
+
+	priv->fd.drm = close_device(priv->fd.drm, "late ", "unbound ");
+	igt_assert_eq(priv->fd.drm, -1);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
+static void hotreplug_lateclose_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot replug");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	device_unplug(priv, "hot ", 60);
+
+	bus_rescan(priv, 0);
+
+	workload_stop(priv, &w);
+
+	priv->fd.drm = close_device(priv->fd.drm, "late ", "removed ");
+	igt_assert_eq(priv->fd.drm, -1);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
 /* Main */
 
 int igt_main()
@@ -817,6 +1035,78 @@ int igt_main()
 			recover(&priv);
 	}
 
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if the driver can be cleanly unbound from an open device with a background GPU workload in flight, then released and rebound");
+		igt_subtest("hotunbind-rebind-with-load")
+			hotunbind_rebind_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if an open device with a background GPU workload in flight can be cleanly unplugged, then released and restored");
+		igt_subtest("hotunplug-rescan-with-load")
+			hotunplug_rescan_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if the driver can be cleanly rebound to a device with a still open hot unbound driver instance while a background GPU workload is in flight");
+		igt_subtest("hotrebind-with-load")
+			hotrebind_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if a hot unplugged and still open device can be cleanly restored while a background GPU workload is in flight");
+		igt_subtest("hotreplug-with-load")
+			hotreplug_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if a hot unbound driver instance still open after hot rebind with a background GPU workload in flight can be cleanly released");
+		igt_subtest("hotrebind-lateclose-with-load")
+			hotrebind_lateclose_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if an instance of a still open while hot replugged device with a background GPU workload in flight can be cleanly released");
+		igt_subtest("hotreplug-lateclose-with-load")
+			hotreplug_lateclose_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
 	igt_fixture() {
 		post_healthcheck(&priv);
 
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread
* [PATCH] tests/core_hotunplug: add *-with-load subtests exercising GPU workload during hotplug
@ 2026-08-21  6:58 Nitin Gote
  2026-08-21  9:43 ` Janusz Krzysztofik
  0 siblings, 1 reply; 10+ messages in thread
From: Nitin Gote @ 2026-08-21  6:58 UTC (permalink / raw)
  To: igt-dev; +Cc: Nitin Gote, Matthew Auld, Janusz Krzysztofik, Kamil Konieczny

The six fd-holding hot* subtests keep a DRM fd open across unbind/unplug
but leave the GPU idle, so the kernel hotplug path is never exercised
against an active workload.

Add six new dedicated *-with-load subtests that run a GPU spinner across
the unbind/unplug sequence so the device is removed while a workload is
actively using it.

The workload helpers use an explicit chipset dispatch block in
workload_start()/stop() so that other vendors can contribute
support by adding an else-if branch. New subtests are gated on
workload_available(), which currently covers DRIVER_XE and DRIVER_INTEL,
and returns false (SKIP) on any other driver.

igt_spin_free() is avoided in workload_stop() since the device may be
gone by then -- igt_spin_end() writes the stop condition via a userspace
mmap and lets the DRM fd close reclaim kernel-side resources.

Validated on BMG and DG2 with a KASAN-enabled kernel:
all six new subtests pass with no KASAN reports.

v4: Rebase to latest igt.
    Also the failure seen with the new core_hotunplug "with-load"
    IGT subtests is fixed by kmd patch:
    https://patchwork.freedesktop.org/series/171989/

v3: Extend struct gpu_workload with a union of vendor-named members
    to match the chipset dispatch in workload_start()/stop(). (Janusz)

v2: Pass the hotunplug priv struct to workload_start()/stop()
    and dispatch via an explicit if/else-if chipset block to invite
    other vendors to contribute. (Janusz)

Cc: Matthew Auld <matthew.auld@intel.com>
Cc: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
Cc: Kamil Konieczny <kamil.konieczny@linux.intel.com>
Reviewed-by: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
Signed-off-by: Nitin Gote <nitin.r.gote@intel.com>
---
 tests/core_hotunplug.c | 294 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 294 insertions(+)

diff --git a/tests/core_hotunplug.c b/tests/core_hotunplug.c
index 33de65369..b11a4231b 100644
--- a/tests/core_hotunplug.c
+++ b/tests/core_hotunplug.c
@@ -80,6 +80,34 @@
  * SUBTEST: unplug-rescan
  * Description: Check if a device believed to be closed can be cleanly
  *		unplugged, then restored
+ *
+ * SUBTEST: hotunbind-rebind-with-load
+ * Description: Check if the driver can be cleanly unbound from an open device
+ *		with a background GPU workload in flight, then released and
+ *		rebound
+ *
+ * SUBTEST: hotunplug-rescan-with-load
+ * Description: Check if an open device with a background GPU workload in
+ *		flight can be cleanly unplugged, then released and restored
+ *
+ * SUBTEST: hotrebind-with-load
+ * Description: Check if the driver can be cleanly rebound to a device with a
+ *		still open hot unbound driver instance while a background GPU
+ *		workload is in flight
+ *
+ * SUBTEST: hotreplug-with-load
+ * Description: Check if a hot unplugged and still open device can be cleanly
+ *		restored while a background GPU workload is in flight
+ *
+ * SUBTEST: hotrebind-lateclose-with-load
+ * Description: Check if a hot unbound driver instance still open after hot
+ *		rebind with a background GPU workload in flight can be cleanly
+ *		released
+ *
+ * SUBTEST: hotreplug-lateclose-with-load
+ * Description: Check if an instance of a still open while hot replugged
+ *		device with a background GPU workload in flight can be cleanly
+ *		released
  */
 
 IGT_TEST_DESCRIPTION("Examine behavior of a driver on device hot unplug");
@@ -550,6 +578,56 @@ static void post_healthcheck(struct hotunplug *priv)
 	cleanup(priv);
 }
 
+/* GPU workload helpers */
+
+struct gpu_workload {
+	union {
+		struct {
+			igt_spin_t *spin;
+			uint64_t ahnd;
+		} intel; /* Xe and i915 */
+	};
+};
+
+static bool workload_available(int chipset)
+{
+	return chipset == DRIVER_XE || chipset == DRIVER_INTEL;
+}
+
+static void workload_start(struct hotunplug *priv, int fd,
+			   struct gpu_workload *w)
+{
+	if (priv->chipset == DRIVER_XE || priv->chipset == DRIVER_INTEL) {
+		local_debug("%s\n", "starting GPU spinner");
+		priv->failure = "GPU workload start failure!";
+		w->intel.ahnd = intel_allocator_open(fd, 0, INTEL_ALLOCATOR_RELOC);
+		w->intel.spin = igt_spin_new(fd, .ahnd = w->intel.ahnd);
+		priv->failure = NULL;
+	}
+}
+
+static void workload_stop(struct hotunplug *priv, struct gpu_workload *w)
+{
+	if (priv->chipset == DRIVER_XE || priv->chipset == DRIVER_INTEL) {
+		if (!w->intel.spin)
+			return;
+
+		/*
+		 * The device may be gone (unbind/unplug), so avoid
+		 * igt_spin_free(): on Xe it would wait forever on a syncobj
+		 * that never signals; on i915 it would touch the dead fd via
+		 * gem_munmap()/gem_close(). Instead, end the spinner via a
+		 * userspace mmap write and let the DRM fd close reclaim the
+		 * kernel-side resources.
+		 */
+		local_debug("%s\n", "stopping GPU spinner");
+		igt_spin_end(w->intel.spin);
+		put_ahnd(w->intel.ahnd);
+		w->intel.spin = NULL;
+		w->intel.ahnd = 0;
+	}
+}
+
 /* Subtests */
 
 static void unbind_rebind(struct hotunplug *priv)
@@ -664,6 +742,150 @@ static void hotreplug_lateclose(struct hotunplug *priv)
 	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
 }
 
+static void hotunbind_rebind_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot unbind");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	driver_unbind(priv, "hot ", 0);
+
+	workload_stop(priv, &w);
+
+	priv->fd.drm = close_device(priv->fd.drm, "late ", "unbound ");
+	igt_assert_eq(priv->fd.drm, -1);
+
+	driver_bind(priv, 0);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
+static void hotunplug_rescan_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot unplug");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	device_unplug(priv, "hot ", 0);
+
+	workload_stop(priv, &w);
+
+	priv->fd.drm = close_device(priv->fd.drm, "late ", "removed ");
+	igt_assert_eq(priv->fd.drm, -1);
+
+	bus_rescan(priv, 0);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
+static void hotrebind_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot rebind");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	driver_unbind(priv, "hot ", 60);
+
+	driver_bind(priv, 0);
+
+	workload_stop(priv, &w);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
+static void hotreplug_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot replug");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	device_unplug(priv, "hot ", 60);
+
+	bus_rescan(priv, 0);
+
+	workload_stop(priv, &w);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
+static void hotrebind_lateclose_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot rebind");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	driver_unbind(priv, "hot ", 60);
+
+	driver_bind(priv, 0);
+
+	workload_stop(priv, &w);
+
+	priv->fd.drm = close_device(priv->fd.drm, "late ", "unbound ");
+	igt_assert_eq(priv->fd.drm, -1);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
+static void hotreplug_lateclose_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot replug");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	device_unplug(priv, "hot ", 60);
+
+	bus_rescan(priv, 0);
+
+	workload_stop(priv, &w);
+
+	priv->fd.drm = close_device(priv->fd.drm, "late ", "removed ");
+	igt_assert_eq(priv->fd.drm, -1);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
 /* Main */
 
 int igt_main()
@@ -802,6 +1024,78 @@ int igt_main()
 			recover(&priv);
 	}
 
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if the driver can be cleanly unbound from an open device with a background GPU workload in flight, then released and rebound");
+		igt_subtest("hotunbind-rebind-with-load")
+			hotunbind_rebind_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if an open device with a background GPU workload in flight can be cleanly unplugged, then released and restored");
+		igt_subtest("hotunplug-rescan-with-load")
+			hotunplug_rescan_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if the driver can be cleanly rebound to a device with a still open hot unbound driver instance while a background GPU workload is in flight");
+		igt_subtest("hotrebind-with-load")
+			hotrebind_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if a hot unplugged and still open device can be cleanly restored while a background GPU workload is in flight");
+		igt_subtest("hotreplug-with-load")
+			hotreplug_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if a hot unbound driver instance still open after hot rebind with a background GPU workload in flight can be cleanly released");
+		igt_subtest("hotrebind-lateclose-with-load")
+			hotrebind_lateclose_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if an instance of a still open while hot replugged device with a background GPU workload in flight can be cleanly released");
+		igt_subtest("hotreplug-lateclose-with-load")
+			hotreplug_lateclose_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
 	igt_fixture() {
 		post_healthcheck(&priv);
 
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread
* [PATCH] tests/core_hotunplug: add *-with-load subtests exercising GPU workload during hotplug
@ 2026-05-18 15:48 Nitin Gote
  2026-05-20 13:38 ` Janusz Krzysztofik
  2026-05-21 12:46 ` Kamil Konieczny
  0 siblings, 2 replies; 10+ messages in thread
From: Nitin Gote @ 2026-05-18 15:48 UTC (permalink / raw)
  To: igt-dev, janusz.krzysztofik; +Cc: kamil.konieczny, matthew.auld, nitin.r.gote

The six fd-holding hot* subtests keep a DRM fd open across unbind/unplug
but leave the GPU idle, so the kernel hotplug path is never exercised
against an active workload.

Add six new dedicated *-with-load subtests that run a GPU spinner across
the unbind/unplug sequence so the device is removed while a workload is
actively using it.

The workload helpers use an explicit chipset dispatch block in
workload_start()/stop() so that other vendors can contribute
support by adding an else-if branch. New subtests are gated on
workload_available(), which currently covers DRIVER_XE and DRIVER_INTEL,
and returns false (SKIP) on any other driver.

igt_spin_free() is avoided in workload_stop() since the device may be
gone by then -- igt_spin_end() writes the stop condition via a userspace
mmap and lets the DRM fd close reclaim kernel-side resources.

Validated on BMG and DG2 with a KASAN-enabled kernel:
all six new subtests pass with no KASAN reports.

v3: Extend struct gpu_workload with a union of vendor-named members
    to match the chipset dispatch in workload_start()/stop(). (Janusz)

v2: Pass the hotunplug priv struct to workload_start()/stop()
    and dispatch via an explicit if/else-if chipset block to invite
    other vendors to contribute. (Janusz)

Cc: Matthew Auld <matthew.auld@intel.com>
Cc: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
Cc: Kamil Konieczny <kamil.konieczny@linux.intel.com>
Signed-off-by: Nitin Gote <nitin.r.gote@intel.com>
---
Hi Janusz,

Extended the struct gpu_workload with a union of vendor-named members
to make a room for other vendors data.

Thanks,
Nitin

 tests/core_hotunplug.c | 294 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 294 insertions(+)

diff --git a/tests/core_hotunplug.c b/tests/core_hotunplug.c
index 7c9dae1bf..2c54af628 100644
--- a/tests/core_hotunplug.c
+++ b/tests/core_hotunplug.c
@@ -80,6 +80,34 @@
  * SUBTEST: unplug-rescan
  * Description: Check if a device believed to be closed can be cleanly
  *		unplugged, then restored
+ *
+ * SUBTEST: hotunbind-rebind-with-load
+ * Description: Check if the driver can be cleanly unbound from an open device
+ *		with a background GPU workload in flight, then released and
+ *		rebound
+ *
+ * SUBTEST: hotunplug-rescan-with-load
+ * Description: Check if an open device with a background GPU workload in
+ *		flight can be cleanly unplugged, then released and restored
+ *
+ * SUBTEST: hotrebind-with-load
+ * Description: Check if the driver can be cleanly rebound to a device with a
+ *		still open hot unbound driver instance while a background GPU
+ *		workload is in flight
+ *
+ * SUBTEST: hotreplug-with-load
+ * Description: Check if a hot unplugged and still open device can be cleanly
+ *		restored while a background GPU workload is in flight
+ *
+ * SUBTEST: hotrebind-lateclose-with-load
+ * Description: Check if a hot unbound driver instance still open after hot
+ *		rebind with a background GPU workload in flight can be cleanly
+ *		released
+ *
+ * SUBTEST: hotreplug-lateclose-with-load
+ * Description: Check if an instance of a still open while hot replugged
+ *		device with a background GPU workload in flight can be cleanly
+ *		released
  */
 
 IGT_TEST_DESCRIPTION("Examine behavior of a driver on device hot unplug");
@@ -565,6 +593,56 @@ static void set_filter_from_device(int fd)
 	igt_assert_eq(igt_device_filter_add(filter), 1);
 }
 
+/* GPU workload helpers */
+
+struct gpu_workload {
+	union {
+		struct {
+			igt_spin_t *spin;
+			uint64_t ahnd;
+		} intel; /* Xe and i915 */
+	};
+};
+
+static bool workload_available(int chipset)
+{
+	return chipset == DRIVER_XE || chipset == DRIVER_INTEL;
+}
+
+static void workload_start(struct hotunplug *priv, int fd,
+			   struct gpu_workload *w)
+{
+	if (priv->chipset == DRIVER_XE || priv->chipset == DRIVER_INTEL) {
+		local_debug("%s\n", "starting GPU spinner");
+		priv->failure = "GPU workload start failure!";
+		w->intel.ahnd = intel_allocator_open(fd, 0, INTEL_ALLOCATOR_RELOC);
+		w->intel.spin = igt_spin_new(fd, .ahnd = w->intel.ahnd);
+		priv->failure = NULL;
+	}
+}
+
+static void workload_stop(struct hotunplug *priv, struct gpu_workload *w)
+{
+	if (priv->chipset == DRIVER_XE || priv->chipset == DRIVER_INTEL) {
+		if (!w->intel.spin)
+			return;
+
+		/*
+		 * The device may be gone (unbind/unplug), so avoid
+		 * igt_spin_free(): on Xe it would wait forever on a syncobj
+		 * that never signals; on i915 it would touch the dead fd via
+		 * gem_munmap()/gem_close(). Instead, end the spinner via a
+		 * userspace mmap write and let the DRM fd close reclaim the
+		 * kernel-side resources.
+		 */
+		local_debug("%s\n", "stopping GPU spinner");
+		igt_spin_end(w->intel.spin);
+		put_ahnd(w->intel.ahnd);
+		w->intel.spin = NULL;
+		w->intel.ahnd = 0;
+	}
+}
+
 /* Subtests */
 
 static void unbind_rebind(struct hotunplug *priv)
@@ -679,6 +757,150 @@ static void hotreplug_lateclose(struct hotunplug *priv)
 	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
 }
 
+static void hotunbind_rebind_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot unbind");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	driver_unbind(priv, "hot ", 0);
+
+	workload_stop(priv, &w);
+
+	priv->fd.drm = close_device(priv->fd.drm, "late ", "unbound ");
+	igt_assert_eq(priv->fd.drm, -1);
+
+	driver_bind(priv, 0);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
+static void hotunplug_rescan_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot unplug");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	device_unplug(priv, "hot ", 0);
+
+	workload_stop(priv, &w);
+
+	priv->fd.drm = close_device(priv->fd.drm, "late ", "removed ");
+	igt_assert_eq(priv->fd.drm, -1);
+
+	bus_rescan(priv, 0);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
+static void hotrebind_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot rebind");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	driver_unbind(priv, "hot ", 60);
+
+	driver_bind(priv, 0);
+
+	workload_stop(priv, &w);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
+static void hotreplug_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot replug");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	device_unplug(priv, "hot ", 60);
+
+	bus_rescan(priv, 0);
+
+	workload_stop(priv, &w);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
+static void hotrebind_lateclose_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot rebind");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	driver_unbind(priv, "hot ", 60);
+
+	driver_bind(priv, 0);
+
+	workload_stop(priv, &w);
+
+	priv->fd.drm = close_device(priv->fd.drm, "late ", "unbound ");
+	igt_assert_eq(priv->fd.drm, -1);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
+static void hotreplug_lateclose_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot replug");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	device_unplug(priv, "hot ", 60);
+
+	bus_rescan(priv, 0);
+
+	workload_stop(priv, &w);
+
+	priv->fd.drm = close_device(priv->fd.drm, "late ", "removed ");
+	igt_assert_eq(priv->fd.drm, -1);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
 /* Main */
 
 int igt_main()
@@ -817,6 +1039,78 @@ int igt_main()
 			recover(&priv);
 	}
 
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if the driver can be cleanly unbound from an open device with a background GPU workload in flight, then released and rebound");
+		igt_subtest("hotunbind-rebind-with-load")
+			hotunbind_rebind_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if an open device with a background GPU workload in flight can be cleanly unplugged, then released and restored");
+		igt_subtest("hotunplug-rescan-with-load")
+			hotunplug_rescan_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if the driver can be cleanly rebound to a device with a still open hot unbound driver instance while a background GPU workload is in flight");
+		igt_subtest("hotrebind-with-load")
+			hotrebind_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if a hot unplugged and still open device can be cleanly restored while a background GPU workload is in flight");
+		igt_subtest("hotreplug-with-load")
+			hotreplug_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if a hot unbound driver instance still open after hot rebind with a background GPU workload in flight can be cleanly released");
+		igt_subtest("hotrebind-lateclose-with-load")
+			hotrebind_lateclose_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if an instance of a still open while hot replugged device with a background GPU workload in flight can be cleanly released");
+		igt_subtest("hotreplug-lateclose-with-load")
+			hotreplug_lateclose_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
 	igt_fixture() {
 		post_healthcheck(&priv);
 
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread
* [PATCH] tests/core_hotunplug: add *-with-load subtests exercising GPU workload during hotplug
@ 2026-05-18  8:27 Nitin Gote
  2026-05-18  8:48 ` Janusz Krzysztofik
  0 siblings, 1 reply; 10+ messages in thread
From: Nitin Gote @ 2026-05-18  8:27 UTC (permalink / raw)
  To: igt-dev, janusz.krzysztofik, kamil.konieczny; +Cc: matthew.auld, nitin.r.gote

The six fd-holding hot* subtests keep a DRM fd open across unbind/unplug
but leave the GPU idle, so the kernel hotplug path is never exercised
against an active VM, exec queue and BOs.

Add six new dedicated *-with-load subtests that run a GPU spinner across
the unbind/unplug sequence so the device is removed while a workload is
actively using it.

The workload helpers are driver-agnostic: igt_spin_new() dispatches
transparently for both Xe and i915. New subtests are gated on
workload_available(), which covers DRIVER_XE and DRIVER_INTEL, and
returns false (SKIP) on any other driver.

igt_spin_free() is avoided in workload_stop() since the device may be
gone by then — igt_spin_end() writes the stop condition via a userspace
mmap and lets the DRM fd close reclaim kernel-side resources.

Validated on BMG and DG2 with a KASAN-enabled kernel:
all six new subtests pass with no KASAN reports.

Cc: Matthew Auld <matthew.auld@intel.com>
Cc: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
Cc: Kamil Konieczny <kamil.konieczny@linux.intel.com>
Assisted-by: Copilot:claude-opus-4.7
Signed-off-by: Nitin Gote <nitin.r.gote@intel.com>
---
Hi Janusz/Kamil,
I have introduced new subtests as per review comments in
https://patchwork.freedesktop.org/series/166056/ 
instead of modifying existing ones to avoid changing their scope.
Also used driver-agnostic helper names throughout.

Thanks,
Nitin


 tests/core_hotunplug.c | 285 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 285 insertions(+)

diff --git a/tests/core_hotunplug.c b/tests/core_hotunplug.c
index 7c9dae1bf..85a96294e 100644
--- a/tests/core_hotunplug.c
+++ b/tests/core_hotunplug.c
@@ -80,6 +80,34 @@
  * SUBTEST: unplug-rescan
  * Description: Check if a device believed to be closed can be cleanly
  *		unplugged, then restored
+ *
+ * SUBTEST: hotunbind-rebind-with-load
+ * Description: Check if the driver can be cleanly unbound from an open device
+ *		with a background GPU workload in flight, then released and
+ *		rebound
+ *
+ * SUBTEST: hotunplug-rescan-with-load
+ * Description: Check if an open device with a background GPU workload in
+ *		flight can be cleanly unplugged, then released and restored
+ *
+ * SUBTEST: hotrebind-with-load
+ * Description: Check if the driver can be cleanly rebound to a device with a
+ *		still open hot unbound driver instance while a background GPU
+ *		workload is in flight
+ *
+ * SUBTEST: hotreplug-with-load
+ * Description: Check if a hot unplugged and still open device can be cleanly
+ *		restored while a background GPU workload is in flight
+ *
+ * SUBTEST: hotrebind-lateclose-with-load
+ * Description: Check if a hot unbound driver instance still open after hot
+ *		rebind with a background GPU workload in flight can be cleanly
+ *		released
+ *
+ * SUBTEST: hotreplug-lateclose-with-load
+ * Description: Check if an instance of a still open while hot replugged
+ *		device with a background GPU workload in flight can be cleanly
+ *		released
  */
 
 IGT_TEST_DESCRIPTION("Examine behavior of a driver on device hot unplug");
@@ -565,6 +593,47 @@ static void set_filter_from_device(int fd)
 	igt_assert_eq(igt_device_filter_add(filter), 1);
 }
 
+/* GPU workload helpers */
+
+struct gpu_workload {
+	igt_spin_t *spin;
+	uint64_t ahnd;
+};
+
+static bool workload_available(int chipset)
+{
+	return chipset == DRIVER_XE || chipset == DRIVER_INTEL;
+}
+
+static void workload_start(struct hotunplug *priv, int fd,
+			   struct gpu_workload *w)
+{
+	local_debug("%s\n", "starting GPU spinner");
+	priv->failure = "GPU workload start failure!";
+	w->ahnd = intel_allocator_open(fd, 0, INTEL_ALLOCATOR_RELOC);
+	w->spin = igt_spin_new(fd, .ahnd = w->ahnd);
+	priv->failure = NULL;
+}
+
+static void workload_stop(struct gpu_workload *w)
+{
+	if (!w->spin)
+		return;
+
+	/*
+	 * The device may be gone (unbind/unplug), so avoid igt_spin_free():
+	 * on Xe it would wait forever on a syncobj that never signals; on i915
+	 * it would touch the dead fd via gem_munmap()/gem_close(). Instead, end
+	 * the spinner via a userspace mmap write and let the DRM fd close
+	 * reclaim the kernel-side resources.
+	 */
+	local_debug("%s\n", "stopping GPU spinner");
+	igt_spin_end(w->spin);
+	put_ahnd(w->ahnd);
+	w->spin = NULL;
+	w->ahnd = 0;
+}
+
 /* Subtests */
 
 static void unbind_rebind(struct hotunplug *priv)
@@ -679,6 +748,150 @@ static void hotreplug_lateclose(struct hotunplug *priv)
 	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
 }
 
+static void hotunbind_rebind_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot unbind");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	driver_unbind(priv, "hot ", 0);
+
+	workload_stop(&w);
+
+	priv->fd.drm = close_device(priv->fd.drm, "late ", "unbound ");
+	igt_assert_eq(priv->fd.drm, -1);
+
+	driver_bind(priv, 0);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
+static void hotunplug_rescan_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot unplug");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	device_unplug(priv, "hot ", 0);
+
+	workload_stop(&w);
+
+	priv->fd.drm = close_device(priv->fd.drm, "late ", "removed ");
+	igt_assert_eq(priv->fd.drm, -1);
+
+	bus_rescan(priv, 0);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
+static void hotrebind_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot rebind");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	driver_unbind(priv, "hot ", 60);
+
+	driver_bind(priv, 0);
+
+	workload_stop(&w);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
+static void hotreplug_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot replug");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	device_unplug(priv, "hot ", 60);
+
+	bus_rescan(priv, 0);
+
+	workload_stop(&w);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
+static void hotrebind_lateclose_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot rebind");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	driver_unbind(priv, "hot ", 60);
+
+	driver_bind(priv, 0);
+
+	workload_stop(&w);
+
+	priv->fd.drm = close_device(priv->fd.drm, "late ", "unbound ");
+	igt_assert_eq(priv->fd.drm, -1);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
+static void hotreplug_lateclose_with_load(struct hotunplug *priv)
+{
+	struct gpu_workload w = { 0 };
+
+	pre_check(priv);
+
+	igt_require_f(workload_available(priv->chipset),
+		      "No GPU workload support for this driver\n");
+
+	priv->fd.drm = local_drm_open_driver(false, "", " for hot replug");
+
+	workload_start(priv, priv->fd.drm, &w);
+
+	device_unplug(priv, "hot ", 60);
+
+	bus_rescan(priv, 0);
+
+	workload_stop(&w);
+
+	priv->fd.drm = close_device(priv->fd.drm, "late ", "removed ");
+	igt_assert_eq(priv->fd.drm, -1);
+
+	igt_assert_f(healthcheck(priv, false), "%s\n", priv->failure);
+}
+
 /* Main */
 
 int igt_main()
@@ -817,6 +1030,78 @@ int igt_main()
 			recover(&priv);
 	}
 
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if the driver can be cleanly unbound from an open device with a background GPU workload in flight, then released and rebound");
+		igt_subtest("hotunbind-rebind-with-load")
+			hotunbind_rebind_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if an open device with a background GPU workload in flight can be cleanly unplugged, then released and restored");
+		igt_subtest("hotunplug-rescan-with-load")
+			hotunplug_rescan_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if the driver can be cleanly rebound to a device with a still open hot unbound driver instance while a background GPU workload is in flight");
+		igt_subtest("hotrebind-with-load")
+			hotrebind_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if a hot unplugged and still open device can be cleanly restored while a background GPU workload is in flight");
+		igt_subtest("hotreplug-with-load")
+			hotreplug_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if a hot unbound driver instance still open after hot rebind with a background GPU workload in flight can be cleanly released");
+		igt_subtest("hotrebind-lateclose-with-load")
+			hotrebind_lateclose_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
+	igt_fixture()
+		post_healthcheck(&priv);
+
+	igt_subtest_group() {
+		igt_describe("Check if an instance of a still open while hot replugged device with a background GPU workload in flight can be cleanly released");
+		igt_subtest("hotreplug-lateclose-with-load")
+			hotreplug_lateclose_with_load(&priv);
+
+		igt_fixture()
+			recover(&priv);
+	}
+
 	igt_fixture() {
 		post_healthcheck(&priv);
 
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-08-21  9:43 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-18 12:01 [PATCH] tests/core_hotunplug: add *-with-load subtests exercising GPU workload during hotplug Nitin Gote
2026-05-18 12:53 ` Janusz Krzysztofik
  -- strict thread matches above, loose matches on Subject: below --
2026-08-21  6:58 Nitin Gote
2026-08-21  9:43 ` Janusz Krzysztofik
2026-05-18 15:48 Nitin Gote
2026-05-20 13:38 ` Janusz Krzysztofik
2026-05-21 12:46 ` Kamil Konieczny
2026-05-18  8:27 Nitin Gote
2026-05-18  8:48 ` Janusz Krzysztofik
2026-05-18  9:59   ` Gote, Nitin R

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox