[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251008001253.437911-11-apopple@nvidia.com>
Date: Wed, 8 Oct 2025 11:12:49 +1100
From: Alistair Popple <apopple@...dia.com>
To: rust-for-linux@...r.kernel.org,
dri-devel@...ts.freedesktop.org,
dakr@...nel.org,
acourbot@...dia.com
Cc: Alistair Popple <apopple@...dia.com>,
Miguel Ojeda <ojeda@...nel.org>,
Alex Gaynor <alex.gaynor@...il.com>,
Boqun Feng <boqun.feng@...il.com>,
Gary Guo <gary@...yguo.net>,
Björn Roy Baron <bjorn3_gh@...tonmail.com>,
Benno Lossin <lossin@...nel.org>,
Andreas Hindborg <a.hindborg@...nel.org>,
Alice Ryhl <aliceryhl@...gle.com>,
Trevor Gross <tmgross@...ch.edu>,
David Airlie <airlied@...il.com>,
Simona Vetter <simona@...ll.ch>,
Maarten Lankhorst <maarten.lankhorst@...ux.intel.com>,
Maxime Ripard <mripard@...nel.org>,
Thomas Zimmermann <tzimmermann@...e.de>,
John Hubbard <jhubbard@...dia.com>,
Joel Fernandes <joelagnelf@...dia.com>,
Timur Tabi <ttabi@...dia.com>,
linux-kernel@...r.kernel.org,
nouveau@...ts.freedesktop.org,
Lyude Paul <lyude@...hat.com>
Subject: [PATCH v4 10/13] gpu: nova-core: gsp: Create RM registry and sysinfo commands
Add the RM registry and system information commands that enable the host
driver to configure GSP firmware parameters during initialization.
The RM registry is serialized into a packed format and sent via the
command queue. For now only two parameters which are required to boot
GSP are hardcoded. In future a kernel module parameter will be added to
enable other parameters to be added.
Also add the system info command, which provides required hardware
information to the GSP. These commands use the GSP command queue
infrastructure to issue commands to the GSP which is read during GSP
boot.
Signed-off-by: Alistair Popple <apopple@...dia.com>
Reviewed-by: Lyude Paul <lyude@...hat.com>
---
Changes for v4:
- Use `init!` macros
- Update to use send_gsp_command_with_payload() for the registry
- Add RMDevidCheckIgnore registry setting (thanks Timur)
Changes for v3:
- Use MsgFunction enum
- Rename GspCmdq to Cmdq
- Rename GspCommandToGsp to CommandToGsp
- Rename GspMessageFromGsp to MessageFromGsp
- Split bindings into separate patch
Changes for v2:
- Rebased on Alex's latest tree
---
drivers/gpu/nova-core/gsp.rs | 1 +
drivers/gpu/nova-core/gsp/boot.rs | 6 +-
drivers/gpu/nova-core/gsp/cmdq.rs | 2 -
drivers/gpu/nova-core/gsp/commands.rs | 115 ++++++++++++++++++++++++++
drivers/gpu/nova-core/sbuffer.rs | 1 -
5 files changed, 121 insertions(+), 4 deletions(-)
create mode 100644 drivers/gpu/nova-core/gsp/commands.rs
diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
index ef48da6afacd..9b6abb9755ba 100644
--- a/drivers/gpu/nova-core/gsp.rs
+++ b/drivers/gpu/nova-core/gsp.rs
@@ -23,6 +23,7 @@
use fw::GspArgumentsCached;
pub(crate) mod cmdq;
+pub(crate) mod commands;
pub(crate) const GSP_PAGE_SHIFT: usize = 12;
pub(crate) const GSP_PAGE_SIZE: usize = 1 << GSP_PAGE_SHIFT;
diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs
index 1d2448331d7a..0b306313ec53 100644
--- a/drivers/gpu/nova-core/gsp/boot.rs
+++ b/drivers/gpu/nova-core/gsp/boot.rs
@@ -16,6 +16,7 @@
FIRMWARE_VERSION,
};
use crate::gpu::Chipset;
+use crate::gsp::commands::{build_registry, set_system_info};
use crate::gsp::GspFwWprMeta;
use crate::regs;
use crate::vbios::Vbios;
@@ -105,7 +106,7 @@ fn run_fwsec_frts(
///
/// Upon return, the GSP is up and running, and its runtime object given as return value.
pub(crate) fn boot(
- self: Pin<&mut Self>,
+ mut self: Pin<&mut Self>,
pdev: &pci::Device<device::Bound>,
bar: &Bar0,
chipset: Chipset,
@@ -139,6 +140,9 @@ pub(crate) fn boot(
CoherentAllocation::<GspFwWprMeta>::alloc_coherent(dev, 1, GFP_KERNEL | __GFP_ZERO)?;
dma_write!(wpr_meta[0] = GspFwWprMeta::new(&gsp_fw, &fb_layout))?;
+ set_system_info(&mut self.cmdq, pdev, bar)?;
+ build_registry(&mut self.cmdq, bar)?;
+
Ok(())
}
}
diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index 317767d8f521..389f78c7e6e1 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -292,7 +292,6 @@ fn notify_gsp(bar: &Bar0) {
NV_PGSP_QUEUE_HEAD::default().set_address(0).write(bar);
}
- #[expect(unused)]
pub(crate) fn send_gsp_command<M, E>(&mut self, bar: &Bar0, init: impl Init<M, E>) -> Result
where
M: CommandToGsp,
@@ -345,7 +344,6 @@ struct FullCommand<M> {
Ok(())
}
- #[expect(unused)]
pub(crate) fn send_gsp_command_with_payload<M, E>(
&mut self,
bar: &Bar0,
diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
new file mode 100644
index 000000000000..92fbafeaf69c
--- /dev/null
+++ b/drivers/gpu/nova-core/gsp/commands.rs
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use kernel::build_assert;
+use kernel::device;
+use kernel::pci;
+use kernel::prelude::*;
+use kernel::transmute::AsBytes;
+
+use super::fw::commands::*;
+use super::fw::MsgFunction;
+use crate::driver::Bar0;
+use crate::gsp::cmdq::Cmdq;
+use crate::gsp::cmdq::{CommandToGsp, CommandToGspWithPayload};
+use crate::gsp::GSP_PAGE_SIZE;
+use crate::sbuffer::SBuffer;
+
+// For now we hard-code the registry entries. Future work will allow others to
+// be added as module parameters.
+const GSP_REGISTRY_NUM_ENTRIES: usize = 3;
+pub(crate) struct RegistryEntry {
+ key: &'static str,
+ value: u32,
+}
+
+pub(crate) struct RegistryTable {
+ entries: [RegistryEntry; GSP_REGISTRY_NUM_ENTRIES],
+}
+
+impl CommandToGsp for PackedRegistryTable {
+ const FUNCTION: MsgFunction = MsgFunction::SetRegistry;
+}
+impl CommandToGspWithPayload for PackedRegistryTable {}
+
+impl RegistryTable {
+ fn write_payload<'a, I: Iterator<Item = &'a mut [u8]>>(
+ &self,
+ mut sbuffer: SBuffer<I>,
+ ) -> Result {
+ let string_data_start_offset = size_of::<PackedRegistryTable>()
+ + GSP_REGISTRY_NUM_ENTRIES * size_of::<PackedRegistryEntry>();
+
+ // Array for string data.
+ let mut string_data = KVec::new();
+
+ for entry in self.entries.iter().take(GSP_REGISTRY_NUM_ENTRIES) {
+ sbuffer.write_all(
+ PackedRegistryEntry::new(
+ (string_data_start_offset + string_data.len()) as u32,
+ entry.value,
+ )
+ .as_bytes(),
+ )?;
+
+ let key_bytes = entry.key.as_bytes();
+ string_data.extend_from_slice(key_bytes, GFP_KERNEL)?;
+ string_data.push(0, GFP_KERNEL)?;
+ }
+
+ sbuffer.write_all(string_data.as_slice())
+ }
+
+ fn size(&self) -> usize {
+ let mut key_size = 0;
+ for i in 0..GSP_REGISTRY_NUM_ENTRIES {
+ key_size += self.entries[i].key.len() + 1; // +1 for NULL terminator
+ }
+ GSP_REGISTRY_NUM_ENTRIES * size_of::<PackedRegistryEntry>() + key_size
+ }
+}
+
+pub(crate) fn build_registry(cmdq: &mut Cmdq, bar: &Bar0) -> Result {
+ let registry = RegistryTable {
+ 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,
+ },
+ ],
+ };
+
+ cmdq.send_gsp_command_with_payload(
+ bar,
+ registry.size(),
+ PackedRegistryTable::init(GSP_REGISTRY_NUM_ENTRIES as u32, registry.size() as u32),
+ |sbuffer| registry.write_payload(sbuffer),
+ )
+}
+
+impl CommandToGsp for GspSystemInfo {
+ const FUNCTION: MsgFunction = MsgFunction::GspSetSystemInfo;
+}
+
+pub(crate) fn set_system_info(
+ cmdq: &mut Cmdq,
+ dev: &pci::Device<device::Bound>,
+ bar: &Bar0,
+) -> Result {
+ build_assert!(size_of::<GspSystemInfo>() < GSP_PAGE_SIZE);
+ cmdq.send_gsp_command(bar, GspSystemInfo::init(dev))?;
+
+ Ok(())
+}
diff --git a/drivers/gpu/nova-core/sbuffer.rs b/drivers/gpu/nova-core/sbuffer.rs
index bde80cc3fa63..5acfd005a86b 100644
--- a/drivers/gpu/nova-core/sbuffer.rs
+++ b/drivers/gpu/nova-core/sbuffer.rs
@@ -159,7 +159,6 @@ fn get_slice_mut(&mut self, len: usize) -> Option<&'a mut [u8]> {
/// Ideally we would implement `Write`, but it is not available in `core`.
/// So mimic `std::io::Write::write_all`.
- #[expect(unused)]
pub(crate) fn write_all(&mut self, mut src: &[u8]) -> Result {
while !src.is_empty() {
match self.get_slice_mut(src.len()) {
--
2.50.1
Powered by blists - more mailing lists