From: Alok Kumar <alkumar@nvidia.com>
To: <dakr@kernel.org>, <acourbot@nvidia.com>, <kvm@vger.kernel.org>,
<rust-for-linux@vger.kernel.org>, <nova-gpu@lists.linux.dev>,
<linux-pci@vger.kernel.org>
Cc: <alex@shazbot.org>, <jgg@nvidia.com>, <yishaih@nvidia.com>,
<skolothumtho@nvidia.com>, <kevin.tian@intel.com>,
<airlied@gmail.com>, <simona@ffwll.ch>, <ojeda@kernel.org>,
<alex.gaynor@gmail.com>, <boqun.feng@gmail.com>,
<gary@garyguo.net>, <bjorn3_gh@protonmail.com>,
<lossin@kernel.org>, <a.hindborg@kernel.org>,
<aliceryhl@google.com>, <tmgross@umich.edu>,
<markus.probst@posteo.de>, <jhubbard@nvidia.com>,
<apopple@nvidia.com>, <joelagnelf@nvidia.com>,
<ecourtney@nvidia.com>, <cjia@nvidia.com>, <smitra@nvidia.com>,
<kjaju@nvidia.com>, <alkumar@nvidia.com>, <ankita@nvidia.com>,
<aniketa@nvidia.com>, <kwankhede@nvidia.com>,
<targupta@nvidia.com>, <linux-kernel@vger.kernel.org>,
<zhiwang@kernel.org>, <zhiw@nvidia.com>, <boqun@kernel.org>,
<daniel.almeida@collabora.com>, <tamird@kernel.org>,
<work@onurozkan.dev>, <jgg@ziepe.ca>, <bhelgaas@google.com>,
<kwilczynski@kernel.org>, <dri-devel@lists.freedesktop.org>,
<peter@colberg.org>, <xinmengs@nvidia.com>
Subject: [PATCH v4 23/32] gpu: nova-core: vgpu: add instance shutdown
Date: Fri, 6 Nov 2026 11:09:56 +0530 [thread overview]
Message-ID: <33da25f031dd9a32cc52bafd3d44b69b250d4cfd.1793906667.git.alkumar@nvidia.com> (raw)
In-Reply-To: <cover.1793906667.git.alkumar@nvidia.com>
From: Zhi Wang <zhiw@nvidia.com>
Stop the GSP plugin, wait for SHUTDOWN completion, and release its
firmware resources with CLEANUP before unmapping the communication
buffers.
Add PendingInstance rollback and manager teardown. Register host resources
before firmware work, and retain them until device removal if firmware
state is uncertain or teardown fails. Keep the manager's dependencies
alive until cleanup finishes.
Signed-off-by: Zhi Wang <zhiw@nvidia.com>
Co-developed-by: Alok Kumar <alkumar@nvidia.com>
Signed-off-by: Alok Kumar <alkumar@nvidia.com>
---
drivers/gpu/nova-core/gsp/cmdq/gmc.rs | 1 -
drivers/gpu/nova-core/vgpu.rs | 9 +-
drivers/gpu/nova-core/vgpu/commands.rs | 55 +++++++-
drivers/gpu/nova-core/vgpu/fw.rs | 9 ++
drivers/gpu/nova-core/vgpu/gsp_plugin_comm.rs | 1 -
drivers/gpu/nova-core/vgpu/instance.rs | 118 +++++++++++++++++-
6 files changed, 182 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/nova-core/gsp/cmdq/gmc.rs b/drivers/gpu/nova-core/gsp/cmdq/gmc.rs
index d41d5e533cf7..3bceb080f9a9 100644
--- a/drivers/gpu/nova-core/gsp/cmdq/gmc.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq/gmc.rs
@@ -469,7 +469,6 @@ pub(crate) fn send_gmc_and_receive_timeout(
///
/// Errors from initializing the request headers and from either callback are propagated
/// as-is. The current valid element is consumed before a callback error is returned.
- #[expect(dead_code)]
pub(crate) fn send_gmc_and_wait_event(
&self,
command_id: u32,
diff --git a/drivers/gpu/nova-core/vgpu.rs b/drivers/gpu/nova-core/vgpu.rs
index 84c4d0b3839d..f7184e7009a5 100644
--- a/drivers/gpu/nova-core/vgpu.rs
+++ b/drivers/gpu/nova-core/vgpu.rs
@@ -105,7 +105,7 @@ fn query_state(
use self::instance::VgpuInstances;
/// Runtime resources for an enabled vGPU boot.
-#[pin_data]
+#[pin_data(PinnedDrop)]
pub(crate) struct VgpuManager<'gpu> {
#[pin]
instances: Mutex<VgpuInstances<'gpu>>,
@@ -146,3 +146,10 @@ pub(crate) fn new(
})
}
}
+
+#[pinned_drop]
+impl PinnedDrop for VgpuManager<'_> {
+ fn drop(self: Pin<&mut Self>) {
+ self.instances.lock().release_all(&self);
+ }
+}
diff --git a/drivers/gpu/nova-core/vgpu/commands.rs b/drivers/gpu/nova-core/vgpu/commands.rs
index 6207211d7f9d..00da8fa4f910 100644
--- a/drivers/gpu/nova-core/vgpu/commands.rs
+++ b/drivers/gpu/nova-core/vgpu/commands.rs
@@ -29,9 +29,13 @@
VgpuPropertiesSchema, //
},
GMCAPI_CMD_BOOTLOAD_GSP_VGPU_PLUGIN_TASK,
+ GMCAPI_CMD_CLEANUP_GSP_VGPU_PLUGIN_RESOURCES,
GMCAPI_CMD_QUERY_ASSIGNED_VF_VGPU_TYPE,
- GMCAPI_CMD_QUERY_VGPU_PROPERTIES, //
- }, //
+ GMCAPI_CMD_QUERY_VGPU_PROPERTIES,
+ GMCAPI_CMD_SHUTDOWN_GSP_VGPU_PLUGIN_TASK,
+ GMCAPI_CMD_SHUTDOWN_GSP_VGPU_PLUGIN_TASK_COMPLETE, //
+ },
+ instance::Gfid, //
};
pub(super) use super::fw::commands::{
@@ -109,3 +113,50 @@ pub(super) fn send_bootload(
)?;
check_status(dev, command_id, response.status)
}
+
+/// Shut down a vGPU plugin task and wait for its completion event.
+pub(super) fn send_shutdown(
+ dev: &device::Device<device::Bound>,
+ cmdq: &Cmdq<'_>,
+ gfid: Gfid,
+) -> Result {
+ let payload = u32::from(gfid.get()).to_le_bytes();
+ cmdq.send_gmc_and_wait_event(
+ GMCAPI_CMD_SHUTDOWN_GSP_VGPU_PLUGIN_TASK,
+ &payload,
+ Delta::from_secs(10),
+ |command_id, _max_response_size, _sequence, payload_0, payload_1| {
+ Ok(
+ command_id == GMCAPI_CMD_SHUTDOWN_GSP_VGPU_PLUGIN_TASK_COMPLETE
+ && payload
+ .iter()
+ .copied()
+ .eq(Iterator::chain(payload_0.iter(), payload_1)
+ .take(payload.len())
+ .copied()),
+ )
+ },
+ |command_id, _max_response_size, _sequence, _payload_0, _payload_1| {
+ dev_dbg!(
+ dev,
+ "shutdown: ignoring unrelated event command={:#x}\n",
+ command_id,
+ );
+ Ok(())
+ },
+ )
+}
+
+/// Release firmware resources after a plugin task has stopped.
+pub(super) fn send_cleanup(
+ dev: &device::Device<device::Bound>,
+ cmdq: &Cmdq<'_>,
+ gfid: Gfid,
+) -> Result {
+ let command_id = GMCAPI_CMD_CLEANUP_GSP_VGPU_PLUGIN_RESOURCES;
+ let response =
+ cmdq.send_gmc_and_receive(command_id, &u32::from(gfid.get()).to_le_bytes(), 0)?;
+ check_status(dev, command_id, response.status)?;
+ dev_dbg!(dev, "cleanup: gfid={} done\n", gfid.get());
+ Ok(())
+}
diff --git a/drivers/gpu/nova-core/vgpu/fw.rs b/drivers/gpu/nova-core/vgpu/fw.rs
index 82c29dfb467a..1528cc56ce74 100644
--- a/drivers/gpu/nova-core/vgpu/fw.rs
+++ b/drivers/gpu/nova-core/vgpu/fw.rs
@@ -33,3 +33,12 @@
pub(super) const GMCAPI_CMD_BOOTLOAD_GSP_VGPU_PLUGIN_TASK: u32 =
bindings::GMCAPI_COMMANDS_GMCAPI_CMD_BOOTLOAD_GSP_VGPU_PLUGIN_TASK;
+
+pub(super) const GMCAPI_CMD_SHUTDOWN_GSP_VGPU_PLUGIN_TASK: u32 =
+ bindings::GMCAPI_COMMANDS_GMCAPI_CMD_SHUTDOWN_GSP_VGPU_PLUGIN_TASK;
+
+pub(super) const GMCAPI_CMD_SHUTDOWN_GSP_VGPU_PLUGIN_TASK_COMPLETE: u32 =
+ bindings::GMCAPI_COMMANDS_GMCAPI_CMD_SHUTDOWN_GSP_VGPU_PLUGIN_TASK_COMPLETE;
+
+pub(super) const GMCAPI_CMD_CLEANUP_GSP_VGPU_PLUGIN_RESOURCES: u32 =
+ bindings::GMCAPI_COMMANDS_GMCAPI_CMD_CLEANUP_GSP_VGPU_PLUGIN_RESOURCES;
diff --git a/drivers/gpu/nova-core/vgpu/gsp_plugin_comm.rs b/drivers/gpu/nova-core/vgpu/gsp_plugin_comm.rs
index 0b4d03c5f0fc..a00f4d2affc7 100644
--- a/drivers/gpu/nova-core/vgpu/gsp_plugin_comm.rs
+++ b/drivers/gpu/nova-core/vgpu/gsp_plugin_comm.rs
@@ -210,7 +210,6 @@ pub(super) fn is_plugin_ready(&self) -> Result<bool> {
}
/// Invalidate the PTEs and release the communication mapping.
- #[expect(dead_code)]
pub(super) fn unmap(&mut self) -> Result {
self.map.unmap()
}
diff --git a/drivers/gpu/nova-core/vgpu/instance.rs b/drivers/gpu/nova-core/vgpu/instance.rs
index b2a0b25c0e15..bf02595590e1 100644
--- a/drivers/gpu/nova-core/vgpu/instance.rs
+++ b/drivers/gpu/nova-core/vgpu/instance.rs
@@ -31,6 +31,8 @@
use super::{
commands::{
send_bootload,
+ send_cleanup,
+ send_shutdown,
Dbdf, //
},
fw::commands::{
@@ -143,10 +145,12 @@ struct VgpuInstance<'gpu> {
// Unmap the communication region before returning its slot and channel IDs.
vram_slot: VgpuVramSlot,
chids: ChannelIdReservation<'gpu>,
+ needs_teardown: bool,
+ /// An uncertain or failed operation retains resources until device removal.
+ failure: Option<Error>,
}
impl<'gpu> VgpuInstance<'gpu> {
- #[expect(dead_code)]
fn activate(&mut self, vgpu: &VgpuManager<'gpu>) -> Result {
let dev = vgpu.dev;
self.bootload(dev, vgpu.cmdq, &vgpu.fifo_engine_list)?;
@@ -154,6 +158,26 @@ fn activate(&mut self, vgpu: &VgpuManager<'gpu>) -> Result {
Ok(())
}
+ /// Tear down once, retaining all remaining resources if an operation fails.
+ fn teardown(&mut self, vgpu: &VgpuManager<'gpu>) -> Result {
+ if let Some(error) = self.failure {
+ return Err(error);
+ }
+ let result = (|| {
+ self.shutdown(vgpu.dev, vgpu.cmdq)?;
+
+ if self.needs_teardown {
+ send_cleanup(vgpu.dev, vgpu.cmdq, self.gfid)?;
+ self.needs_teardown = false;
+ }
+ self.comm.unmap()
+ })();
+ if let Err(error) = result {
+ self.failure = Some(error);
+ }
+ result
+ }
+
/// Bootload the GSP vGPU plugin and wait for its BAR1 ready indication.
fn bootload(
&mut self,
@@ -192,6 +216,7 @@ fn bootload(
);
self.comm.clear_plugin_ready()?;
+ self.needs_teardown = true;
send_bootload(dev, cmdq, &payload)?;
wait_plugin_ready(dev, &self.comm)?;
@@ -199,6 +224,15 @@ fn bootload(
dev_dbg!(dev, "bootload: gfid={} plugin ready\n", self.gfid.get());
Ok(())
}
+
+ /// Stop the plugin when firmware may own instance resources.
+ fn shutdown(&mut self, dev: &device::Device<device::Bound>, cmdq: &Cmdq<'_>) -> Result {
+ if self.needs_teardown {
+ send_shutdown(dev, cmdq, self.gfid)?;
+ dev_dbg!(dev, "shutdown: gfid={} stopped\n", self.gfid.get());
+ }
+ Ok(())
+ }
}
/// Identity and firmware profile used to allocate an instance.
@@ -255,8 +289,12 @@ fn alloc_vram_slot(&mut self, mm: &GpuMm<'_>, layout: VgpuVramLayout) -> Result<
Ok(slot)
}
- /// Allocate resources and register a new inactive vGPU instance.
- fn allocate_instance(&mut self, vgpu: &VgpuManager<'gpu>, info: InstanceInfo) -> Result<Gfid> {
+ /// Register host resources before submitting any firmware work.
+ fn allocate_instance<'a>(
+ &'a mut self,
+ vgpu: &'a VgpuManager<'gpu>,
+ info: InstanceInfo,
+ ) -> Result<PendingInstance<'a, 'gpu>> {
let InstanceInfo {
gfid,
dbdf,
@@ -316,23 +354,91 @@ fn allocate_instance(&mut self, vgpu: &VgpuManager<'gpu>, info: InstanceInfo) ->
comm,
vram_slot,
chids,
+ needs_teardown: false,
+ failure: None,
};
self.instances
.push_within_capacity(instance)
.map_err(|_| EIO)?;
- Ok(gfid)
+ Ok(PendingInstance {
+ instances: self,
+ vgpu,
+ gfid,
+ committed: false,
+ })
}
- /// Remove an instance and release its channel and VRAM reservations.
- fn destroy_instance(&mut self, gfid: Gfid) -> Result {
+ /// Remove an instance only after firmware and mapping teardown have succeeded.
+ fn destroy_instance(&mut self, vgpu: &VgpuManager<'gpu>, gfid: Gfid) -> Result {
let instance_index = self
.instances
.iter()
.position(|instance| instance.gfid == gfid)
.ok_or(ENOENT)?;
+ let instance = self.instances.get_mut(instance_index).ok_or(EIO)?;
+ instance.teardown(vgpu)?;
+
let instance = self.instances.remove(instance_index).map_err(|_| EIO)?;
drop(instance);
Ok(())
}
+
+ /// Release the registry while the manager's MM and firmware dependencies remain available.
+ pub(super) fn release_all(&mut self, vgpu: &VgpuManager<'gpu>) {
+ for instance in &mut self.instances {
+ // Failed operations retain their resources until this final device removal.
+ // Do not resubmit commands whose firmware outcome was uncertain.
+ if instance.failure.is_none() {
+ if let Err(error) = instance.teardown(vgpu) {
+ dev_err!(
+ vgpu.dev,
+ "vGPU teardown failed for gfid={}: {:?}\n",
+ instance.gfid.get(),
+ error,
+ );
+ }
+ }
+ }
+ self.instances.clear();
+ }
+}
+
+/// Rolls back this creation attempt unless ownership has passed to the caller.
+struct PendingInstance<'a, 'gpu> {
+ instances: &'a mut VgpuInstances<'gpu>,
+ vgpu: &'a VgpuManager<'gpu>,
+ gfid: Gfid,
+ committed: bool,
+}
+
+#[expect(dead_code)]
+impl PendingInstance<'_, '_> {
+ fn activate(mut self) -> Result {
+ let instance = self
+ .instances
+ .instances
+ .iter_mut()
+ .find(|instance| instance.gfid == self.gfid)
+ .ok_or(EIO)?;
+ instance.activate(self.vgpu)?;
+ self.committed = true;
+ Ok(())
+ }
+}
+
+impl Drop for PendingInstance<'_, '_> {
+ fn drop(&mut self) {
+ if self.committed {
+ return;
+ }
+ if let Err(error) = self.instances.destroy_instance(self.vgpu, self.gfid) {
+ dev_err!(
+ self.vgpu.dev,
+ "vGPU creation could not release gfid={}: {:?}; resources retained until removal\n",
+ self.gfid.get(),
+ error,
+ );
+ }
+ }
}
--
2.53.0
next prev parent reply other threads:[~2026-11-06 5:46 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-06 5:39 [PATCH v4 00/32] Introduce NVIDIA vGPU manager Alok Kumar
2026-11-06 5:39 ` [PATCH v4 01/32] gpu: nova-core: mm: retain BAR1 reservations after unmap failure Alok Kumar
2026-11-06 5:39 ` [PATCH v4 02/32] gpu: nova-core: gsp: pass boot context through setup helpers Alok Kumar
2026-11-06 5:39 ` [PATCH v4 03/32] gpu: nova-core: gsp: decouple boot context from VgpuManager Alok Kumar
2026-11-06 5:39 ` [PATCH v4 04/32] gpu: nova-core: vgpu: detect boot state independently Alok Kumar
2026-11-06 5:39 ` [PATCH v4 05/32] gpu: nova-core: gpu: add a channel ID pool for vGPU Alok Kumar
2026-11-06 5:39 ` [PATCH v4 06/32] gpu: nova-core: gsp: decode the FIFO engine table Alok Kumar
2026-11-06 5:39 ` [PATCH v4 07/32] gpu: nova-core: vgpu: initialize runtime parameters after GSP boot Alok Kumar
2026-11-06 5:39 ` [PATCH v4 08/32] gpu: nova-core: vgpu: reserve the 48-VM WPR2 heap Alok Kumar
2026-11-06 5:39 ` [PATCH v4 09/32] gpu: nova-core: mm: borrow BarUser for temporary BAR1 access Alok Kumar
2026-11-06 5:39 ` [PATCH v4 10/32] gpu: nova-core: mm: add VramBlock Alok Kumar
2026-11-06 5:39 ` [PATCH v4 11/32] gpu: nova-core: mm: add VramRegion Alok Kumar
2026-11-06 5:39 ` [PATCH v4 12/32] gpu: nova-core: mm: add BarMapping Alok Kumar
2026-11-06 5:39 ` [PATCH v4 13/32] gpu: nova-core: gsp: add synchronous GMC transactions Alok Kumar
2026-11-06 5:39 ` [PATCH v4 14/32] gpu: nova-core: gsp: wait for GMC completion events Alok Kumar
2026-11-06 5:39 ` [PATCH v4 15/32] gpu: nova-core: vgpu: add r000 plugin bindings Alok Kumar
2026-11-06 5:39 ` [PATCH v4 16/32] gpu: nova-core: vgpu: add VRAM slot allocator Alok Kumar
2026-11-06 5:39 ` [PATCH v4 17/32] gpu: nova-core: gsp: factor out NVKV payload conversion Alok Kumar
2026-11-06 5:39 ` [PATCH v4 18/32] gpu: nova-core: vgpu: query VF assignments and properties Alok Kumar
2026-11-06 5:39 ` [PATCH v4 19/32] gpu: nova-core: vgpu: add instance create/destroy Alok Kumar
2026-11-06 5:39 ` [PATCH v4 20/32] gpu: nova-core: vgpu: encode vGPU boot requests Alok Kumar
2026-11-06 5:39 ` [PATCH v4 21/32] gpu: nova-core: vgpu: add GSP plugin communication buffers Alok Kumar
2026-11-06 5:39 ` [PATCH v4 22/32] gpu: nova-core: vgpu: add instance boot Alok Kumar
2026-11-06 5:39 ` Alok Kumar [this message]
2026-11-06 5:39 ` [PATCH v4 24/32] gpu: nova-core: vgpu: initialize GSP plugin RPC buffers Alok Kumar
2026-11-06 5:39 ` [PATCH v4 25/32] gpu: nova-core: vgpu: add GSP plugin RPC transactions Alok Kumar
2026-11-06 5:39 ` [PATCH v4 26/32] gpu: nova-core: vgpu: negotiate the GSP plugin RPC version Alok Kumar
2026-11-06 5:40 ` [PATCH v4 27/32] gpu: nova-core: vgpu: send GSP plugin configuration parameters Alok Kumar
2026-11-06 5:40 ` [PATCH v4 28/32] gpu: nova-core: vgpu: update the GSP plugin BME state Alok Kumar
2026-11-06 5:40 ` [PATCH v4 29/32] gpu: nova-core: vgpu: add CeUtils commands Alok Kumar
2026-11-06 5:40 ` [PATCH v4 30/32] gpu: nova-core: vgpu: scrub guest VRAM with CeUtils Alok Kumar
2026-11-06 5:40 ` [PATCH v4 31/32] gpu: nova-core: vgpu: export plugin log buffers via debugfs Alok Kumar
2026-11-06 5:40 ` [PATCH v4 32/32] gpu: nova-core: vgpu: introduce SR-IOV PF APIs Alok Kumar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=33da25f031dd9a32cc52bafd3d44b69b250d4cfd.1793906667.git.alkumar@nvidia.com \
--to=alkumar@nvidia.com \
--cc=a.hindborg@kernel.org \
--cc=acourbot@nvidia.com \
--cc=airlied@gmail.com \
--cc=alex.gaynor@gmail.com \
--cc=alex@shazbot.org \
--cc=aliceryhl@google.com \
--cc=aniketa@nvidia.com \
--cc=ankita@nvidia.com \
--cc=apopple@nvidia.com \
--cc=bhelgaas@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=boqun@kernel.org \
--cc=cjia@nvidia.com \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=ecourtney@nvidia.com \
--cc=gary@garyguo.net \
--cc=jgg@nvidia.com \
--cc=jgg@ziepe.ca \
--cc=jhubbard@nvidia.com \
--cc=joelagnelf@nvidia.com \
--cc=kevin.tian@intel.com \
--cc=kjaju@nvidia.com \
--cc=kvm@vger.kernel.org \
--cc=kwankhede@nvidia.com \
--cc=kwilczynski@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=markus.probst@posteo.de \
--cc=nova-gpu@lists.linux.dev \
--cc=ojeda@kernel.org \
--cc=peter@colberg.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=simona@ffwll.ch \
--cc=skolothumtho@nvidia.com \
--cc=smitra@nvidia.com \
--cc=tamird@kernel.org \
--cc=targupta@nvidia.com \
--cc=tmgross@umich.edu \
--cc=work@onurozkan.dev \
--cc=xinmengs@nvidia.com \
--cc=yishaih@nvidia.com \
--cc=zhiw@nvidia.com \
--cc=zhiwang@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®