* [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* Re: [PATCH] tests/core_hotunplug: add *-with-load subtests exercising GPU workload during hotplug
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
0 siblings, 0 replies; 10+ messages in thread
From: Janusz Krzysztofik @ 2026-05-18 12:53 UTC (permalink / raw)
To: Nitin Gote, igt-dev, kamil.konieczny; +Cc: matthew.auld
Hi Nitin,
On Mon, 2026-05-18 at 17:31 +0530, Nitin Gote wrote:
> 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;
> +};
Sorry for not touching this before when asking you to make room for other
vendors in functions, but now as we have that in place, I think it would
be good to have the same also for data. A union maybe, with its members
named after vendors?
Thanks,
Janusz
> +
> +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);
>
^ permalink raw reply [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* Re: [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, 0 replies; 10+ messages in thread
From: Janusz Krzysztofik @ 2026-08-21 9:43 UTC (permalink / raw)
To: Nitin Gote, igt-dev; +Cc: Matthew Auld, Kamil Konieczny
Hi Nitin,
Good job, however, I think we still need some improvements.
On Fri, 2026-08-21 at 12:28 +0530, Nitin Gote wrote:
> 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;
NIT: I think a switch (chipset) { case DRIVER_XE: ... } construct, here
and consequently below in workload_start/stop, could be more effective and
more easily extendable with potential future additions from other vendors,
but that can be refactored later, on a first such addition.
> +}
> +
> +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;
Since igt_fail() can be called from inside igt_spin_new(), workload_start()
can fail leaving an open ahnd but no spin. We need to handle that case.
> +
> + /*
> + * 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);
Since igt_fail() can be called from driver_unbind(), as well as from other
functions called between workload_start() and workload_stop() in other
subtests below, we need to address those cases to be on the safe side.
We could e.g.:
- embed struct gpu_workload inside struct hotunplug,
- extend cleanup() (or recover()) function with another workload_stop().
Thanks,
Janusz
> +
> + 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);
>
^ permalink raw reply [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* Re: [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
1 sibling, 0 replies; 10+ messages in thread
From: Janusz Krzysztofik @ 2026-05-20 13:38 UTC (permalink / raw)
To: Nitin Gote, igt-dev; +Cc: kamil.konieczny, matthew.auld
Hi Nitin,
On Mon, 2026-05-18 at 21:18 +0530, Nitin Gote wrote:
> 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>
Now it LGTM.
Reviewed-by: Janusz Krzysztofik <janusz.krzysztofik@linux.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);
>
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [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
1 sibling, 0 replies; 10+ messages in thread
From: Kamil Konieczny @ 2026-05-21 12:46 UTC (permalink / raw)
To: Nitin Gote; +Cc: igt-dev, janusz.krzysztofik, matthew.auld
Hi Nitin,
On 2026-05-18 at 21:18:09 +0530, Nitin Gote wrote:
> 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.
Please reply to Xe.FULL CI failure with cc to CI-bug filling team.
There are few fails from these new ones. Also please cut reply
after 'Known failures' to keep mail short.
Regards,
Kamil
>
> 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");
[cut]
^ permalink raw reply [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* Re: [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
2026-05-18 9:59 ` Gote, Nitin R
0 siblings, 1 reply; 10+ messages in thread
From: Janusz Krzysztofik @ 2026-05-18 8:48 UTC (permalink / raw)
To: Nitin Gote, igt-dev, kamil.konieczny; +Cc: matthew.auld
Hi Nitin,
On Mon, 2026-05-18 at 13:57 +0530, Nitin Gote wrote:
> 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.
While that's a good idea to skip early, I'd still pass the chipset argument
to workload_start/end() and process it with a case or if block that calls
vendor specific workload functions. That way we invite other vendors to
contribute to this test instead of creating their own implementations.
Thanks,
Janusz
>
> 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);
>
^ permalink raw reply [flat|nested] 10+ messages in thread* RE: [PATCH] tests/core_hotunplug: add *-with-load subtests exercising GPU workload during hotplug
2026-05-18 8:48 ` Janusz Krzysztofik
@ 2026-05-18 9:59 ` Gote, Nitin R
0 siblings, 0 replies; 10+ messages in thread
From: Gote, Nitin R @ 2026-05-18 9:59 UTC (permalink / raw)
To: Janusz Krzysztofik, igt-dev@lists.freedesktop.org,
kamil.konieczny@linux.intel.com
Cc: Auld, Matthew
Hi Janusz,
> -----Original Message-----
> From: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
> Sent: Monday, May 18, 2026 2:18 PM
> To: Gote, Nitin R <nitin.r.gote@intel.com>; igt-dev@lists.freedesktop.org;
> kamil.konieczny@linux.intel.com
> Cc: Auld, Matthew <matthew.auld@intel.com>
> Subject: Re: [PATCH] tests/core_hotunplug: add *-with-load subtests exercising
> GPU workload during hotplug
>
> Hi Nitin,
>
> On Mon, 2026-05-18 at 13:57 +0530, Nitin Gote wrote:
> > 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.
>
> While that's a good idea to skip early, I'd still pass the chipset argument to
> workload_start/end() and process it with a case or if block that calls vendor
> specific workload functions. That way we invite other vendors to contribute to
> this test instead of creating their own implementations.
>
Good point. Thanks, will fix in new version.
- Nitin
> Thanks,
> Janusz
>
> >
> > 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);
> >
^ permalink raw reply [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