[PATCH v2 27/32] gpu: nova-core: vgpu: negotiate the GSP plugin RPC version

From: Zhi Wang

Date: Mon Sep 14 2026 - 04:12:33 EST


The vGPU manager negotiates the RPC protocol with the booted GSP plugin
before sending configuration parameters.

Add the version-negotiation message ID and typed RPC submission.
Initialize the shared RPC buffers after the plugin reports ready, then
send the negotiation request.

Co-developed-by: Eliot Courtney <ecourtney@xxxxxxxxxx>
Signed-off-by: Eliot Courtney <ecourtney@xxxxxxxxxx>
Signed-off-by: Zhi Wang <zhiw@xxxxxxxxxx>
---
drivers/gpu/nova-core/vgpu/commands.rs | 18 +++++++++++++++++-
drivers/gpu/nova-core/vgpu/fw.rs | 2 ++
drivers/gpu/nova-core/vgpu/fw/commands.rs | 9 +++++++++
drivers/gpu/nova-core/vgpu/gsp_plugin_comm.rs | 5 +++--
drivers/gpu/nova-core/vgpu/gsp_plugin_rpc.rs | 11 ++++++-----
drivers/gpu/nova-core/vgpu/instance.rs | 10 ++++++++--
6 files changed, 45 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/nova-core/vgpu/commands.rs b/drivers/gpu/nova-core/vgpu/commands.rs
index a2df36b901a8..abc85b0365f2 100644
--- a/drivers/gpu/nova-core/vgpu/commands.rs
+++ b/drivers/gpu/nova-core/vgpu/commands.rs
@@ -22,7 +22,13 @@
},
};

-use super::instance::Gfid;
+use crate::driver::Bar0;
+
+use super::{
+ fw::RpcMessage,
+ gsp_plugin_rpc::PluginRpc,
+ instance::Gfid, //
+};

use super::fw::commands::VgpuPropertiesSchema;

@@ -144,3 +150,13 @@ pub(super) fn send_cleanup(
dev_dbg!(dev, "cleanup: gfid={} done\n", gfid.0);
Ok(())
}
+
+/// Negotiate the host protocol with a bootloaded GSP plugin.
+pub(super) fn negotiate_plugin_version(
+ dev: &device::Device<device::Bound>,
+ bar0: Bar0<'_>,
+ gfid: Gfid,
+ rpc: &mut PluginRpc<'_, '_>,
+) -> Result {
+ rpc.rpc_call(dev, bar0, gfid, RpcMessage::VersionNegotiation, &[])
+}
diff --git a/drivers/gpu/nova-core/vgpu/fw.rs b/drivers/gpu/nova-core/vgpu/fw.rs
index 9925d5ccf71f..6cec92c9b505 100644
--- a/drivers/gpu/nova-core/vgpu/fw.rs
+++ b/drivers/gpu/nova-core/vgpu/fw.rs
@@ -27,6 +27,8 @@
VGPU_CPU_GSP_VGPU_TASK_LOG_BUFF_REGION_SIZE, //
};

+pub(super) use commands::RpcMessage;
+
pub(super) const GMCAPI_CMD_QUERY_ASSIGNED_VF_VGPU_TYPE: u32 =
bindings::GMCAPI_COMMANDS_GMCAPI_CMD_QUERY_ASSIGNED_VF_VGPU_TYPE;

diff --git a/drivers/gpu/nova-core/vgpu/fw/commands.rs b/drivers/gpu/nova-core/vgpu/fw/commands.rs
index 2e6518e2460b..b765d30a1d61 100644
--- a/drivers/gpu/nova-core/vgpu/fw/commands.rs
+++ b/drivers/gpu/nova-core/vgpu/fw/commands.rs
@@ -25,6 +25,15 @@
Required, //
};

+use super::bindings;
+
+/// Message types supported by the nova-core plugin RPC channel.
+#[derive(Clone, Copy)]
+#[repr(u32)]
+pub(in crate::vgpu) enum RpcMessage {
+ VersionNegotiation = bindings::MESSAGE_NV_VGPU_CPU_RPC_MSG_VERSION_NEGOTIATION,
+}
+
bitfield! {
pub(in crate::vgpu) struct Dbdf(u32) {
2:0 function;
diff --git a/drivers/gpu/nova-core/vgpu/gsp_plugin_comm.rs b/drivers/gpu/nova-core/vgpu/gsp_plugin_comm.rs
index 20695929a58c..e385ecff43fa 100644
--- a/drivers/gpu/nova-core/vgpu/gsp_plugin_comm.rs
+++ b/drivers/gpu/nova-core/vgpu/gsp_plugin_comm.rs
@@ -18,6 +18,7 @@
self,
RawControlRegion,
RawResponseRegion,
+ RpcMessage,
RpcResponse, //
};

@@ -337,7 +338,7 @@ pub(super) fn initialize(&self) -> Result {
}

/// Copy and publish one RPC request to firmware.
- pub(super) fn submit(&self, message: u32, sequence: u32, data: &[u8]) -> Result {
+ pub(super) fn submit(&self, message: RpcMessage, sequence: u32, data: &[u8]) -> Result {
if u64::try_from(data.len()).map_err(|_| EOVERFLOW)? > self.message.size() {
return Err(E2BIG);
}
@@ -352,7 +353,7 @@ pub(super) fn submit(&self, message: u32, sequence: u32, data: &[u8]) -> Result
self.write_u32(
&self.control,
core::mem::offset_of!(RawControlRegion, __bindgen_anon_1.message_type),
- message,
+ message as u32,
)?;
self.write_u32(
&self.control,
diff --git a/drivers/gpu/nova-core/vgpu/gsp_plugin_rpc.rs b/drivers/gpu/nova-core/vgpu/gsp_plugin_rpc.rs
index bc5d576d8601..ff009f241c32 100644
--- a/drivers/gpu/nova-core/vgpu/gsp_plugin_rpc.rs
+++ b/drivers/gpu/nova-core/vgpu/gsp_plugin_rpc.rs
@@ -35,7 +35,10 @@
};

use super::{
- fw::RpcResponse,
+ fw::{
+ RpcMessage,
+ RpcResponse, //
+ },
gsp_plugin_comm::CommBufferRegion,
instance::Gfid, //
};
@@ -59,7 +62,6 @@ pub(super) fn comm(&self) -> &CommBufferRegion<'map, 'gpu> {
}

/// Initialize the control and response buffers for the first RPC.
- #[expect(dead_code)]
pub(super) fn init_rpc(&mut self) -> Result {
self.comm.initialize()?;
self.message_sequence = 0;
@@ -76,13 +78,12 @@ fn next_sequence(&self) -> u32 {
}

/// Write one RPC message, ring the VF doorbell, and wait for its response.
- #[expect(dead_code)]
pub(super) fn rpc_call(
&mut self,
dev: &device::Device<device::Bound>,
bar0: Bar0<'_>,
gfid: Gfid,
- message_type: u32,
+ message_type: RpcMessage,
data: &[u8],
) -> Result {
let sequence = self.next_sequence();
@@ -93,7 +94,7 @@ pub(super) fn rpc_call(
dev,
"vGPU RPC: gfid={} type={} bytes={} sequence={}\n",
gfid.0,
- message_type,
+ message_type as u32,
data.len(),
sequence,
);
diff --git a/drivers/gpu/nova-core/vgpu/instance.rs b/drivers/gpu/nova-core/vgpu/instance.rs
index 994b046802c1..a65b95d11f88 100644
--- a/drivers/gpu/nova-core/vgpu/instance.rs
+++ b/drivers/gpu/nova-core/vgpu/instance.rs
@@ -22,6 +22,7 @@
};

use crate::{
+ driver::Bar0,
gpu::ChannelIdReservation,
mm::{
bar_user::BarUser,
@@ -41,6 +42,7 @@
};

use super::commands::{
+ negotiate_plugin_version,
query_vgpu_properties,
send_bootload,
send_cleanup,
@@ -355,11 +357,12 @@ pub(super) fn allocate_instance(
}
}

- /// Bootload the GSP plugin for a registered instance.
+ /// Boot the GSP plugin and negotiate its RPC version.
pub(super) fn activate_instance(
&mut self,
dev: &device::Device<device::Bound>,
cmdq: &Cmdq<'_>,
+ bar0: Bar0<'_>,
gfid: Gfid,
fifo_engine_list: &FifoEngineList,
) -> Result {
@@ -368,7 +371,10 @@ pub(super) fn activate_instance(
.iter_mut()
.find(|instance| instance.gfid == gfid)
.ok_or(ENOENT)?;
- instance.bootload(dev, cmdq, fifo_engine_list)
+ instance.bootload(dev, cmdq, fifo_engine_list)?;
+
+ instance.plugin_rpc.init_rpc()?;
+ negotiate_plugin_version(dev, bar0, gfid, &mut instance.plugin_rpc)
}

/// Stop the plugin and release the instance's firmware and host resources.