[PATCH v3 16/31] gpu: nova-core: gsp: factor out NVKV payload conversion
From: Zhi Wang
Date: Mon Sep 28 2026 - 06:36:09 EST
Both GSP initialization and vGPU property queries decode their replies as
NVKV streams.
Move the byte-to-word conversion helper into the NVKV module and make
that module accessible to the vGPU firmware interface.
No functional change is intended.
Signed-off-by: Zhi Wang <zhiw@xxxxxxxxxx>
---
drivers/gpu/nova-core/gsp.rs | 2 +-
drivers/gpu/nova-core/gsp/commands.rs | 17 ++--------------
drivers/gpu/nova-core/gsp/nvkv.rs | 28 +++++++++++++++++++++++++++
3 files changed, 31 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
index 3dbc37a3b35b..25b4bf6eb848 100644
--- a/drivers/gpu/nova-core/gsp.rs
+++ b/drivers/gpu/nova-core/gsp.rs
@@ -28,7 +28,7 @@
pub(crate) mod cmdq;
pub(crate) mod commands;
mod fw;
-mod nvkv;
+pub(crate) mod nvkv;
mod regs;
pub(crate) use fw::{
diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
index 97e32f81a39b..742e46efd413 100644
--- a/drivers/gpu/nova-core/gsp/commands.rs
+++ b/drivers/gpu/nova-core/gsp/commands.rs
@@ -22,6 +22,7 @@
GMCAPI_CMD_GSP_SUSPEND, //
},
nvkv::{
+ nvkv_words,
Decoder,
Encodable,
EncodedStream,
@@ -30,7 +31,6 @@
},
GspBootContext, //
},
- sbuffer::SBufferIter,
vgpu::VgpuState, //
};
@@ -132,20 +132,7 @@ pub(crate) fn gsp_init(
/// or omits a required key, or the FIFO engine count exceeds the supported table capacity.
/// - `ENOMEM` if the words or the decoded regions cannot be allocated.
fn decode_gsp_init_reply(payload_0: &[u8], payload_1: &[u8]) -> Result<GspStaticInfo> {
- const WORD_SIZE: usize = size_of::<u64>();
-
- let len = payload_0.len() + payload_1.len();
- if len % WORD_SIZE != 0 {
- return Err(EINVAL);
- }
-
- let mut words = KVVec::with_capacity(len / WORD_SIZE, GFP_KERNEL)?;
- let mut bytes = SBufferIter::new_reader([payload_0, payload_1]);
- for _ in 0..len / WORD_SIZE {
- let mut word = [0u8; WORD_SIZE];
- bytes.read_exact(&mut word)?;
- words.push(u64::from_le_bytes(word), GFP_KERNEL)?;
- }
+ let words = nvkv_words(payload_0, payload_1)?;
let decoder = Decoder::new(&words, UnknownKeyPolicy::Ignore);
let mut schema = GspInitResponseSchema::default();
diff --git a/drivers/gpu/nova-core/gsp/nvkv.rs b/drivers/gpu/nova-core/gsp/nvkv.rs
index e7a9549919fb..05b1ba5a4f39 100644
--- a/drivers/gpu/nova-core/gsp/nvkv.rs
+++ b/drivers/gpu/nova-core/gsp/nvkv.rs
@@ -27,6 +27,34 @@
};
use zerocopy::Immutable;
+use crate::sbuffer::SBufferIter;
+
+/// Joins the two halves of a wrapped payload into the `u64` words an NVKV stream is made of.
+///
+/// # Errors
+///
+/// - `EINVAL` if the combined length is not a whole number of words.
+/// - `ENOMEM` if the buffer cannot be allocated.
+pub(crate) fn nvkv_words(payload_0: &[u8], payload_1: &[u8]) -> Result<KVVec<u64>> {
+ const WORD_SIZE: usize = size_of::<u64>();
+
+ // Each byte slice is at most `isize::MAX` bytes, so their sum fits in `usize`.
+ let len = payload_0.len() + payload_1.len();
+ if len % WORD_SIZE != 0 {
+ return Err(EINVAL);
+ }
+
+ let mut words = KVVec::with_capacity(len / WORD_SIZE, GFP_KERNEL)?;
+ let mut bytes = SBufferIter::new_reader([payload_0, payload_1]);
+ for _ in 0..len / WORD_SIZE {
+ let mut word = [0u8; WORD_SIZE];
+ bytes.read_exact(&mut word)?;
+ words.push(u64::from_le_bytes(word), GFP_KERNEL)?;
+ }
+
+ Ok(words)
+}
+
mod encode;
pub(crate) use encode::*;