[PATCH v5 7/7] gpu: nova-core: add NVKV GSP_INIT schemas
From: Eliot Courtney
Date: Tue Oct 27 2026 - 22:22:29 EST
Add the first user of NVKV encode/decode which is the request and
response for GSP init. Later patches will support GMCAPI in `Cmdq` and
use these messages.
Signed-off-by: Eliot Courtney <ecourtney@xxxxxxxxxx>
---
drivers/gpu/nova-core/gsp/fw/commands.rs | 157 ++++++++++++++++++++++++++++++-
drivers/gpu/nova-core/gsp/nvkv.rs | 2 -
drivers/gpu/nova-core/gsp/nvkv/decode.rs | 1 -
drivers/gpu/nova-core/gsp/nvkv/encode.rs | 2 +-
4 files changed, 157 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/nova-core/gsp/fw/commands.rs b/drivers/gpu/nova-core/gsp/fw/commands.rs
index 567c56fbbfe3..88111aec3ddb 100644
--- a/drivers/gpu/nova-core/gsp/fw/commands.rs
+++ b/drivers/gpu/nova-core/gsp/fw/commands.rs
@@ -4,6 +4,8 @@
use core::ops::Range;
use kernel::{
+ alloc::ArrayVec,
+ bitfield,
device,
pci,
prelude::*,
@@ -15,7 +17,19 @@
use crate::{
gpu::Chipset,
- gsp::GSP_PAGE_SIZE,
+ gsp::{
+ nvkv::{
+ nvkv_decode,
+ nvkv_encode,
+ Accumulated,
+ Encodable,
+ Encoder,
+ Key,
+ Required,
+ TruncatingArray, //
+ },
+ GSP_PAGE_SIZE, //
+ },
num::IntoSafeCast, //
};
@@ -245,3 +259,144 @@ unsafe impl AsBytes for UnloadingGuestDriver {}
// SAFETY: This struct only contains integer types for which all bit patterns
// are valid.
unsafe impl FromBytes for UnloadingGuestDriver {}
+
+/// The host CPU architecture.
+#[derive(Clone, Copy)]
+enum HostArch {
+ None = 0,
+ X86_64 = 1,
+ Ppc64le = 2,
+ Arm = 3,
+ Aarch64 = 4,
+ Riscv64 = 5,
+}
+
+// TODO[FPRI]: This is a temporary solution to be replaced with the corresponding derive macros once
+// they land.
+impl TryFrom<u32> for HostArch {
+ type Error = Error;
+
+ fn try_from(value: u32) -> Result<Self> {
+ match value {
+ 0 => Ok(Self::None),
+ 1 => Ok(Self::X86_64),
+ 2 => Ok(Self::Ppc64le),
+ 3 => Ok(Self::Arm),
+ 4 => Ok(Self::Aarch64),
+ 5 => Ok(Self::Riscv64),
+ _ => Err(EINVAL),
+ }
+ }
+}
+
+impl From<HostArch> for u32 {
+ fn from(value: HostArch) -> Self {
+ value as u32
+ }
+}
+
+nvkv_encode! {
+ /// A GSP registry entry.
+ struct RegKey {
+ key_name: Key<&'static [u8], 0x3070>,
+ key_value: Key<u32, 0x3071>,
+ }
+}
+
+impl Encodable for KVVec<RegKey> {
+ fn encode(&self, encoder: &mut Encoder) -> Result {
+ for regkey in self {
+ regkey.encode(encoder)?;
+ }
+ Ok(())
+ }
+}
+
+nvkv_encode! {
+ /// SR-IOV virtual function information.
+ struct VfInfo {
+ total_vfs: Key<u32, 0x0080>,
+ first_vf_offset: Key<u32, 0x0081>,
+ flags: Key<u64, 0x1003>,
+ first_bar0_address: Key<u64, 0x1050>,
+ first_bar1_address: Key<u64, 0x1051>,
+ first_bar2_address: Key<u64, 0x1052>,
+ }
+}
+
+nvkv_encode! {
+ /// Payload of the `GSP_INIT` command.
+ // TODO: expect() doesn't work here before rustc 1.97.0
+ // https://github.com/rust-lang/rust/pull/154377
+ #[allow(dead_code)]
+ struct GspInitRequest {
+ pci_device_id: Key<u32, 0x0001>,
+ pci_sub_device_id: Key<u32, 0x0002>,
+ pci_revision_id: Key<u32, 0x0003>,
+ pci_config_mirror_base: Key<u32, 0x0010>,
+ pci_config_mirror_size: Key<u32, 0x0011>,
+ host_arch: Key<HostArch, 0x0070, u32>,
+ bus_device_func: Key<u64, 0x1020>,
+ regkeys: KVVec<RegKey>,
+ vf_info: Option<VfInfo>,
+ }
+}
+
+// Decode:
+
+// Should decode with UnknownKeyPolicy::Ignore.
+nvkv_decode! {
+ /// Schema for the `GSP_INIT` response.
+ // TODO: expect() doesn't work here before rustc 1.97.0
+ // https://github.com/rust-lang/rust/pull/154377
+ #[allow(dead_code)]
+ struct GspInitResponseSchema => GspInitResponse {
+ gpu_name: TruncatingArray<u8, { GspInitResponse::MAX_GPU_NAME_LEN }, 0x2000>,
+ fb_regions: Accumulated<FbRegionSchema>,
+ bar1_pde_base: Required<Key<u64, 0x1020>>,
+ vmmu_segment_size: Key<u64, 0x1050>,
+ }
+}
+
+/// Payload of the `GSP_INIT` response.
+// TODO: expect() doesn't work here before rustc 1.97.0
+// https://github.com/rust-lang/rust/pull/154377
+#[allow(dead_code)]
+struct GspInitResponse {
+ gpu_name: ArrayVec<u8, { Self::MAX_GPU_NAME_LEN }>,
+ fb_regions: KVVec<FbRegion>,
+ bar1_pde_base: u64,
+ vmmu_segment_size: u64,
+}
+
+impl GspInitResponse {
+ const MAX_GPU_NAME_LEN: usize = 64;
+}
+
+nvkv_decode! {
+ /// Schema for one FB region of the `GSP_INIT` response.
+ struct FbRegionSchema => FbRegion {
+ base: Required<Key<u64, 0x1011>>,
+ limit: Required<Key<u64, 0x1012>>,
+ flags: Required<Key<FbRegionFlags, 0x0012, u32>>,
+ tag: Required<Key<u32, 0x0013>>,
+ }
+}
+
+bitfield! {
+ /// FB region attribute flags.
+ #[derive(Default)]
+ struct FbRegionFlags(u32) {
+ 0:0 support_compressed => bool;
+ 1:1 support_iso => bool;
+ 2:2 protected => bool;
+ }
+}
+
+/// One FB memory region.
+struct FbRegion {
+ base: u64,
+ limit: u64,
+ flags: FbRegionFlags,
+ tag: u32,
+}
diff --git a/drivers/gpu/nova-core/gsp/nvkv.rs b/drivers/gpu/nova-core/gsp/nvkv.rs
index 143746daf782..f81a9e60d89c 100644
--- a/drivers/gpu/nova-core/gsp/nvkv.rs
+++ b/drivers/gpu/nova-core/gsp/nvkv.rs
@@ -9,8 +9,6 @@
//! speaking, the function calls will map to some struct - for example, f(GPU_NAME_STRING_KEY, 0,
//! b"some gpu") naturally maps to storing a &str with the GPU name.
-#![cfg_attr(not(CONFIG_KUNIT = "y"), expect(unused_imports))]
-
use core::{
marker::PhantomData,
ops::{
diff --git a/drivers/gpu/nova-core/gsp/nvkv/decode.rs b/drivers/gpu/nova-core/gsp/nvkv/decode.rs
index 534056b97708..84c0c998b2c9 100644
--- a/drivers/gpu/nova-core/gsp/nvkv/decode.rs
+++ b/drivers/gpu/nova-core/gsp/nvkv/decode.rs
@@ -57,7 +57,6 @@
/// }
/// }
/// ```
-#[cfg_attr(not(CONFIG_KUNIT = "y"), expect(unused_macros))]
macro_rules! nvkv_decode {
// A schema which doesn't borrow from the stream. The macro uses a generic lifetime for the
// [`Visit`] implementation but not for the struct itself. This allows omitting the unused
diff --git a/drivers/gpu/nova-core/gsp/nvkv/encode.rs b/drivers/gpu/nova-core/gsp/nvkv/encode.rs
index a9d0420d0936..c6891c0441ff 100644
--- a/drivers/gpu/nova-core/gsp/nvkv/encode.rs
+++ b/drivers/gpu/nova-core/gsp/nvkv/encode.rs
@@ -38,7 +38,6 @@ pub(crate) trait Encodable {
/// }
/// }
/// ```
-#[cfg_attr(not(CONFIG_KUNIT = "y"), expect(unused_macros))]
macro_rules! nvkv_encode {
(
$(#[$attr:meta])*
@@ -65,6 +64,7 @@ fn encode(&self, encoder: &mut $crate::gsp::nvkv::Encoder) -> ::kernel::error::R
}
};
}
+pub(crate) use nvkv_encode;
impl<const KEY_ID: KeyId> Encodable for IndexedKey<u32, KEY_ID> {
fn encode(&self, encoder: &mut Encoder) -> Result {
--
2.56.0