[PATCH v3 6/8] gpu: nova-core: build SetRegistry entries dynamically

From: Zhi Wang

Date: Wed Jul 01 2026 - 02:32:19 EST


The GSP SetRegistry command currently stores its registry entries in a
fixed-size array. That makes every additional runtime-dependent registry
object require reshaping the command data structure at the same time as the
feature that needs the new entry.

Keep the existing registry contents unchanged, but store them in a KVec so
SetRegistry can be constructed dynamically. The constructor now returns a
Result to propagate allocation failures while the command payload layout is
still computed from the final entry list.

Cc: Alexandre Courbot <acourbot@xxxxxxxxxx>
Signed-off-by: Zhi Wang <zhiw@xxxxxxxxxx>
---
drivers/gpu/nova-core/gsp/boot.rs | 2 +-
drivers/gpu/nova-core/gsp/commands.rs | 74 ++++++++++++++++-----------
2 files changed, 44 insertions(+), 32 deletions(-)

diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs
index 5abab54639a4..139cedacffd2 100644
--- a/drivers/gpu/nova-core/gsp/boot.rs
+++ b/drivers/gpu/nova-core/gsp/boot.rs
@@ -102,7 +102,7 @@ pub(crate) fn boot(
self.cmdq
.send_command_no_wait(bar, commands::SetSystemInfo::new(pdev, chipset))?;
self.cmdq
- .send_command_no_wait(bar, commands::SetRegistry::new())?;
+ .send_command_no_wait(bar, commands::SetRegistry::new()?)?;

hal.post_boot(&self, ctx, &gsp_fw)?;

diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
index 86a3747cd31c..dfb9f04e284d 100644
--- a/drivers/gpu/nova-core/gsp/commands.rs
+++ b/drivers/gpu/nova-core/gsp/commands.rs
@@ -67,37 +67,46 @@ struct RegistryEntry {

/// The `SetRegistry` command.
pub(crate) struct SetRegistry {
- entries: [RegistryEntry; Self::NUM_ENTRIES],
+ entries: KVec<RegistryEntry>,
}

impl SetRegistry {
// For now we hard-code the registry entries. Future work will allow others to
// be added as module parameters.
- const NUM_ENTRIES: usize = 3;
-
/// Creates a new `SetRegistry` command, using a set of hardcoded entries.
- pub(crate) fn new() -> Self {
- Self {
- entries: [
- // RMSecBusResetEnable - enables PCI secondary bus reset
- RegistryEntry {
- key: "RMSecBusResetEnable",
- value: 1,
- },
- // RMForcePcieConfigSave - forces GSP-RM to preserve PCI configuration registers on
- // any PCI reset.
- RegistryEntry {
- key: "RMForcePcieConfigSave",
- value: 1,
- },
- // RMDevidCheckIgnore - allows GSP-RM to boot even if the PCI dev ID is not found
- // in the internal product name database.
- RegistryEntry {
- key: "RMDevidCheckIgnore",
- value: 1,
- },
- ],
- }
+ pub(crate) fn new() -> Result<Self> {
+ let mut entries = KVec::new();
+
+ // RMSecBusResetEnable - enables PCI secondary bus reset
+ entries.push(
+ RegistryEntry {
+ key: "RMSecBusResetEnable",
+ value: 1,
+ },
+ GFP_KERNEL,
+ )?;
+
+ // RMForcePcieConfigSave - forces GSP-RM to preserve PCI configuration registers on
+ // any PCI reset.
+ entries.push(
+ RegistryEntry {
+ key: "RMForcePcieConfigSave",
+ value: 1,
+ },
+ GFP_KERNEL,
+ )?;
+
+ // RMDevidCheckIgnore - allows GSP-RM to boot even if the PCI dev ID is not found
+ // in the internal product name database.
+ entries.push(
+ RegistryEntry {
+ key: "RMDevidCheckIgnore",
+ value: 1,
+ },
+ GFP_KERNEL,
+ )?;
+
+ Ok(Self { entries })
}
}

@@ -108,15 +117,18 @@ impl CommandToGsp for SetRegistry {
type InitError = Infallible;

fn init(&self) -> impl Init<Self::Command, Self::InitError> {
- Self::Command::init(Self::NUM_ENTRIES as u32, self.variable_payload_len() as u32)
+ Self::Command::init(
+ self.entries.len() as u32,
+ self.variable_payload_len() as u32,
+ )
}

fn variable_payload_len(&self) -> usize {
let mut key_size = 0;
- for i in 0..Self::NUM_ENTRIES {
- key_size += self.entries[i].key.len() + 1; // +1 for NULL terminator
+ for entry in self.entries.iter() {
+ key_size += entry.key.len() + 1; // +1 for NULL terminator
}
- Self::NUM_ENTRIES * size_of::<fw::commands::PackedRegistryEntry>() + key_size
+ self.entries.len() * size_of::<fw::commands::PackedRegistryEntry>() + key_size
}

fn init_variable_payload(
@@ -124,12 +136,12 @@ fn init_variable_payload(
dst: &mut SBufferIter<core::array::IntoIter<&mut [u8], 2>>,
) -> Result {
let string_data_start_offset = size_of::<Self::Command>()
- + Self::NUM_ENTRIES * size_of::<fw::commands::PackedRegistryEntry>();
+ + self.entries.len() * size_of::<fw::commands::PackedRegistryEntry>();

// Array for string data.
let mut string_data = KVec::new();

- for entry in self.entries.iter().take(Self::NUM_ENTRIES) {
+ for entry in self.entries.iter() {
dst.write_all(
fw::commands::PackedRegistryEntry::new(
(string_data_start_offset + string_data.len()) as u32,
--
2.51.0