diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-01 22:22:21 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-01 22:22:21 -0400 |
| commit | 2cecb0c172375e45ab554a42c0693135238c03ed (patch) | |
| tree | 393179d97eeb617e49b2da02aa284a774d09383f /kernel/main.c | |
| parent | aa4cf303dd028b24ca29edbc0a5f3c237ab98e3f (diff) | |
| download | open-iov-2cecb0c172375e45ab554a42c0693135238c03ed.tar.gz open-iov-2cecb0c172375e45ab554a42c0693135238c03ed.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.c | 75 |
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 |
