summaryrefslogtreecommitdiffstats
path: root/kernel/main.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-01 22:22:21 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-01 22:22:21 -0400
commitbf63a7dfef0b31c233d21d8f49f81dc40702e9c7 (patch)
tree09c4e1178b2335549ddd7692774001c96d6dd28b /kernel/main.c
parentbc4a3de674c1a93030186fc627e05e9a3c81b519 (diff)
downloadopen-iov-bf63a7dfef0b31c233d21d8f49f81dc40702e9c7.tar.gz
open-iov-bf63a7dfef0b31c233d21d8f49f81dc40702e9c7.zip
gsp-phys: mdev-owned backend lifecycle (P1)
Add the gsp_phys_mdev_owned ownership selector (default 0: unchanged load-time module-owned claim/boot). With 1, module load claims nothing; the first mdev create starts a refcounted backend session whose claim+boot runs asynchronously from a work item, so mdev create and init_work never block. The last mdev remove releases after the emulation thread is stopped. Failures are fail-open: the backend stays OFF and the mdev keeps serving the emulation path. nv_vgpu_exit now gates the session STOPPING under the session lock, drains the emulation threads via mdev_unregister_driver(), and only then releases the claim; the module-owned path keeps its previous release position. A start while STOPPING is refused and a concurrent second stopper cannot release twice. No forwarding is added.
Diffstat (limited to 'kernel/main.c')
-rw-r--r--kernel/main.c75
1 files changed, 72 insertions, 3 deletions
diff --git a/kernel/main.c b/kernel/main.c
index babcc22..f47ef69 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -553,6 +553,9 @@ static int nv_vgpu_mdev_create(struct mdev_device *mdev)
/* Initialize VFIO device registration state */
vgpu->vfio_dev_registered = false;
+ /* No physical backend reference until init_work starts one */
+ vgpu->phys_backend_ref = false;
+
/* Initialize VFIO device open/close tracking */
atomic_set(&vgpu->vfio_dev_open_count, 0);
init_waitqueue_head(&vgpu->vfio_dev_close_wait);
@@ -1447,11 +1450,15 @@ static int __init nv_vgpu_init(void)
}
pr_info("gsp-resman-vfio: VFIO ops set\n");
- if (gsp_phys_gpu_param) {
+ if (gsp_phys_gpu_param && !gsp_phys_mdev_owned_enabled()) {
ret = gsp_phys_gpu_claim();
if (ret)
pr_warn("gsp-resman-vfio: physical GPU claim failed: %d\n",
ret);
+ } else if (gsp_phys_gpu_param) {
+ pr_info("gsp-resman-vfio: gsp_phys_mdev_owned=1: physical GPU claim+boot deferred to the first mdev create\n");
+ } else if (gsp_phys_mdev_owned_enabled()) {
+ pr_warn("gsp-resman-vfio: gsp_phys_mdev_owned=1 requires gsp_phys_gpu=1; physical backend stays off\n");
}
/* Test-enabling trigger for the GSP-RM unload RPC plus the read-only
@@ -1487,6 +1494,7 @@ err_class:
static void __exit nv_vgpu_exit(void)
{
struct pci_dev *pdev = NULL;
+ bool mdev_owned = gsp_phys_mdev_owned_enabled();
pr_info("gsp-resman-vfio: nv_vgpu_exit: starting cleanup\n");
@@ -1497,7 +1505,25 @@ static void __exit nv_vgpu_exit(void)
g_vgpu_vfio_ops = NULL;
gsp_phys_boot_debugfs_fini();
- gsp_phys_gpu_release();
+
+ if (mdev_owned) {
+ /*
+ * Mdev-owned session: gate every live forward first (STOPPING
+ * under the session lock, generation bump), drain the
+ * emulation threads with the mdev unregistration below, and
+ * only then release the claim - release must not race a live
+ * forward. The mdev remove path releases when live mdevs
+ * exist; end_stop() below covers the no-mdev case.
+ */
+ gsp_phys_backend_begin_stop();
+ } else {
+ /*
+ * Module-owned claim (gsp_phys_gpu=1, mdev_owned=0): keep
+ * today's position relative to the debugfs teardown and the
+ * emulation threads; module-owned sessions never forward live.
+ */
+ gsp_phys_gpu_release();
+ }
if (nv_vgpu_driver.device_count > 0) {
struct nv_vgpu_device *vgpu;
@@ -1526,10 +1552,17 @@ static void __exit nv_vgpu_exit(void)
pr_info("gsp-resman-vfio: nv_vgpu_exit: sema service stopped\n");
pr_info("gsp-resman-vfio: nv_vgpu_exit: unregistering mdev driver\n");
- /* Unregister mdev driver FIRST, then mdev parent */
+ /* Unregister mdev driver FIRST, then mdev parent. This drains the
+ * mdev remove callbacks, hence the emulation threads. */
mdev_unregister_driver(&nv_vgpu_mdev_driver);
pr_info("gsp-resman-vfio: nv_vgpu_exit: mdev driver unregistered\n");
+ if (mdev_owned) {
+ /* Drain complete: release the mdev-owned claim (no-op when
+ * the mdev remove path already released it). */
+ gsp_phys_backend_end_stop();
+ }
+
/* Unregister mdev parent via nvidia.ko */
if (pdev) {
pr_info("gsp-resman-vfio: nv_vgpu_exit: unregistering mdev parent\n");
@@ -1592,6 +1625,23 @@ static void nv_vgpu_device_init_work(struct work_struct *work)
nv_vgpu_warn(vgpu, "Migration init failed: %d", ret);
}
+ /*
+ * mdev-owned physical backend: the first mdev create (refcount 0 -> 1)
+ * claims and boots the real GPU asynchronously (gsp_phys_backend_start()
+ * only schedules the claim/boot work item, so this never blocks). Any
+ * failure is fail-open: log it, leave the backend OFF and keep serving
+ * the guest from the emulation path.
+ */
+ if (gsp_phys_mdev_owned_enabled()) {
+ ret = gsp_phys_backend_start();
+ if (ret) {
+ nv_vgpu_warn(vgpu, "Physical backend start refused/failed: %d; continuing on the emulation path",
+ ret);
+ } else {
+ vgpu->phys_backend_ref = true;
+ }
+ }
+
mutex_lock(&vgpu->lock);
vgpu->state = NV_VGPU_STATE_READY;
mutex_unlock(&vgpu->lock);
@@ -1617,6 +1667,18 @@ static void nv_vgpu_device_cleanup_work(struct work_struct *work)
nv_vgpu_migration_cleanup(vgpu);
gsp_emu_cleanup(vgpu);
+
+ /*
+ * Last-reference backend teardown: gsp_emu_cleanup() above has stopped
+ * this mdev's emulation thread, so no forward can be in flight when the
+ * claim is released. The backend session stays up until the last mdev
+ * removes (refcount 1 -> 0).
+ */
+ if (vgpu->phys_backend_ref) {
+ vgpu->phys_backend_ref = false;
+ gsp_phys_backend_stop();
+ }
+
nv_vgpu_memory_cleanup(vgpu);
nv_vgpu_irq_cleanup(vgpu);
nv_vgpu_bar_cleanup(vgpu);
@@ -2457,6 +2519,13 @@ MODULE_PARM_DESC(chan_dump, "Dump the sema service channel table (any value)");
module_param_named(gsp_phys_gpu, gsp_phys_gpu_param, bool, 0644);
MODULE_PARM_DESC(gsp_phys_gpu, "Claim the physical GPU for the real-GSP backend (default 0)");
+/* Read by the backend session (gsp_phys_gpu.c) to enforce the mdev-owned
+ * start gate; the parameter itself stays owned here. */
+bool gsp_phys_gpu_enabled(void)
+{
+ return gsp_phys_gpu_param;
+}
+
/*
* GR ring discovery: pin the compute channels' rings/USERDs, which follow the
* CE rings in the channel video-memory allocation. Default on; set 0 to leave