lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20251106231153.2925637-8-joelagnelf@nvidia.com>
Date: Thu,  6 Nov 2025 18:11:46 -0500
From: Joel Fernandes <joelagnelf@...dia.com>
To: linux-kernel@...r.kernel.org,
	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>,
	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>,
	joel@...lfernandes.org,
	Daniel Almeida <daniel.almeida@...labora.com>,
	nouveau@...ts.freedesktop.org
Subject: [PATCH v3 07/14] gpu: nova-core: Implement the GSP sequencer

Implement the GSP sequencer which culminates in INIT_DONE message being
received from the GSP indicating that the GSP has successfully booted.

This is just initial sequencer support, the actual commands will be
added in the next patches.

Signed-off-by: Joel Fernandes <joelagnelf@...dia.com>
---
 drivers/gpu/nova-core/gsp.rs           |   1 +
 drivers/gpu/nova-core/gsp/boot.rs      |  19 ++-
 drivers/gpu/nova-core/gsp/cmdq.rs      |   1 -
 drivers/gpu/nova-core/gsp/sequencer.rs | 205 +++++++++++++++++++++++++
 drivers/gpu/nova-core/sbuffer.rs       |   1 -
 5 files changed, 224 insertions(+), 3 deletions(-)
 create mode 100644 drivers/gpu/nova-core/gsp/sequencer.rs

diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
index 36175eafaf2e..9d62aea3c782 100644
--- a/drivers/gpu/nova-core/gsp.rs
+++ b/drivers/gpu/nova-core/gsp.rs
@@ -16,6 +16,7 @@
 pub(crate) mod cmdq;
 pub(crate) mod commands;
 mod fw;
+mod sequencer;
 
 use fw::GspArgumentsCached;
 use fw::LibosMemoryRegionInitArgument;
diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs
index 649c758eda70..761020a11153 100644
--- a/drivers/gpu/nova-core/gsp/boot.rs
+++ b/drivers/gpu/nova-core/gsp/boot.rs
@@ -19,7 +19,13 @@
 };
 use crate::gpu::Chipset;
 use crate::gsp::commands::{build_registry, set_system_info};
-use crate::gsp::GspFwWprMeta;
+use crate::gsp::{
+    sequencer::{
+        GspSequencer,
+        GspSequencerParams, //
+    },
+    GspFwWprMeta, //
+};
 use crate::regs;
 use crate::vbios::Vbios;
 
@@ -204,6 +210,17 @@ pub(crate) fn boot(
             gsp_falcon.is_riscv_active(bar),
         );
 
+        // Create and run the GSP sequencer.
+        let seq_params = GspSequencerParams {
+            gsp_fw: &gsp_fw,
+            libos_dma_handle: libos_handle,
+            gsp_falcon,
+            sec2_falcon,
+            dev: pdev.as_ref(),
+            bar,
+        };
+        GspSequencer::run(&mut self.cmdq, seq_params, Delta::from_secs(10))?;
+
         Ok(())
     }
 }
diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index 0fb8ff26ba2f..0185629a3b5c 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -418,7 +418,6 @@ struct FullCommand<M> {
         Ok(())
     }
 
-    #[expect(unused)]
     pub(crate) fn receive_msg_from_gsp<M: MessageFromGsp, R>(
         &mut self,
         timeout: Delta,
diff --git a/drivers/gpu/nova-core/gsp/sequencer.rs b/drivers/gpu/nova-core/gsp/sequencer.rs
new file mode 100644
index 000000000000..ee096c04d9eb
--- /dev/null
+++ b/drivers/gpu/nova-core/gsp/sequencer.rs
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! GSP Sequencer implementation for Pre-hopper GSP boot sequence.
+
+use core::mem::size_of;
+use kernel::alloc::flags::GFP_KERNEL;
+use kernel::device;
+use kernel::prelude::*;
+use kernel::time::Delta;
+use kernel::transmute::FromBytes;
+
+use crate::driver::Bar0;
+use crate::falcon::{
+    gsp::Gsp,
+    sec2::Sec2,
+    Falcon, //
+};
+use crate::firmware::gsp::GspFirmware;
+use crate::gsp::cmdq::{
+    Cmdq,
+    MessageFromGsp, //
+};
+use crate::gsp::fw;
+
+use kernel::{
+    dev_dbg,
+    dev_err, //
+};
+
+impl MessageFromGsp for fw::rpc_run_cpu_sequencer_v17_00 {
+    const FUNCTION: fw::MsgFunction = fw::MsgFunction::GspRunCpuSequencer;
+}
+
+const CMD_SIZE: usize = size_of::<fw::GSP_SEQUENCER_BUFFER_CMD>();
+
+struct GspSequencerInfo<'a> {
+    info: &'a fw::rpc_run_cpu_sequencer_v17_00,
+    cmd_data: KVec<u8>,
+}
+
+/// GSP Sequencer Command types with payload data.
+/// Commands have an opcode and a opcode-dependent struct.
+#[allow(dead_code)]
+pub(crate) enum GspSeqCmd {}
+
+impl GspSeqCmd {
+    /// Creates a new GspSeqCmd from a firmware GSP_SEQUENCER_BUFFER_CMD.
+    pub(crate) fn from_fw_cmd(_cmd: &fw::GSP_SEQUENCER_BUFFER_CMD) -> Result<Self> {
+        Err(EINVAL)
+    }
+
+    pub(crate) fn new(data: &[u8], dev: &device::Device<device::Bound>) -> Result<Self> {
+        let fw_cmd = fw::GSP_SEQUENCER_BUFFER_CMD::from_bytes(data).ok_or(EINVAL)?;
+        let cmd = Self::from_fw_cmd(fw_cmd)?;
+
+        if data.len() < cmd.size_bytes() {
+            dev_err!(dev, "data is not enough for command");
+            return Err(EINVAL);
+        }
+
+        Ok(cmd)
+    }
+
+    /// Get the size of this command in bytes, the command consists of
+    /// a 4-byte opcode, and a variable-sized payload.
+    pub(crate) fn size_bytes(&self) -> usize {
+        0
+    }
+}
+
+#[expect(dead_code)]
+pub(crate) struct GspSequencer<'a> {
+    seq_info: GspSequencerInfo<'a>,
+    bar: &'a Bar0,
+    sec2_falcon: &'a Falcon<Sec2>,
+    gsp_falcon: &'a Falcon<Gsp>,
+    libos_dma_handle: u64,
+    gsp_fw: &'a GspFirmware,
+    dev: &'a device::Device<device::Bound>,
+}
+
+pub(crate) trait GspSeqCmdRunner {
+    fn run(&self, sequencer: &GspSequencer<'_>) -> Result;
+}
+
+impl GspSeqCmdRunner for GspSeqCmd {
+    fn run(&self, _seq: &GspSequencer<'_>) -> Result {
+        Ok(())
+    }
+}
+
+pub(crate) struct GspSeqIter<'a> {
+    cmd_data: &'a [u8],
+    current_offset: usize, // Tracking the current position.
+    total_cmds: u32,
+    cmds_processed: u32,
+    dev: &'a device::Device<device::Bound>,
+}
+
+impl<'a> Iterator for GspSeqIter<'a> {
+    type Item = Result<GspSeqCmd>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        // Stop if we've processed all commands or reached the end of data.
+        if self.cmds_processed >= self.total_cmds || self.current_offset >= self.cmd_data.len() {
+            return None;
+        }
+
+        // Check if we have enough data for opcode.
+        let opcode_size = size_of::<fw::GSP_SEQ_BUF_OPCODE>();
+        if self.current_offset + opcode_size > self.cmd_data.len() {
+            return Some(Err(EINVAL));
+        }
+
+        let offset = self.current_offset;
+
+        // Handle command creation based on available data,
+        // zero-pad if necessary (since last command may not be full size).
+        let mut buffer = [0u8; CMD_SIZE];
+        let copy_len = if offset + CMD_SIZE <= self.cmd_data.len() {
+            CMD_SIZE
+        } else {
+            self.cmd_data.len() - offset
+        };
+        buffer[..copy_len].copy_from_slice(&self.cmd_data[offset..offset + copy_len]);
+        let cmd_result = GspSeqCmd::new(&buffer, self.dev);
+
+        cmd_result.map_or_else(
+            |_err| {
+                dev_err!(self.dev, "Error parsing command at offset {}", offset);
+                None
+            },
+            |cmd| {
+                self.current_offset += cmd.size_bytes();
+                self.cmds_processed += 1;
+                Some(Ok(cmd))
+            },
+        )
+    }
+}
+
+impl<'a, 'b> IntoIterator for &'b GspSequencer<'a> {
+    type Item = Result<GspSeqCmd>;
+    type IntoIter = GspSeqIter<'b>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        let cmd_data = &self.seq_info.cmd_data[..];
+
+        GspSeqIter {
+            cmd_data,
+            current_offset: 0,
+            total_cmds: self.seq_info.info.cmdIndex,
+            cmds_processed: 0,
+            dev: self.dev,
+        }
+    }
+}
+
+/// Parameters for running the GSP sequencer.
+pub(crate) struct GspSequencerParams<'a> {
+    pub(crate) gsp_fw: &'a GspFirmware,
+    pub(crate) libos_dma_handle: u64,
+    pub(crate) gsp_falcon: &'a Falcon<Gsp>,
+    pub(crate) sec2_falcon: &'a Falcon<Sec2>,
+    pub(crate) dev: &'a device::Device<device::Bound>,
+    pub(crate) bar: &'a Bar0,
+}
+
+impl<'a> GspSequencer<'a> {
+    pub(crate) fn run(cmdq: &mut Cmdq, params: GspSequencerParams<'a>, timeout: Delta) -> Result {
+        cmdq.receive_msg_from_gsp(timeout, |info, mut sbuf| {
+            let cmd_data = sbuf.flush_into_kvec(GFP_KERNEL)?;
+            let seq_info = GspSequencerInfo { info, cmd_data };
+
+            let sequencer = GspSequencer {
+                seq_info,
+                bar: params.bar,
+                sec2_falcon: params.sec2_falcon,
+                gsp_falcon: params.gsp_falcon,
+                libos_dma_handle: params.libos_dma_handle,
+                gsp_fw: params.gsp_fw,
+                dev: params.dev,
+            };
+
+            dev_dbg!(params.dev, "Running CPU Sequencer commands");
+
+            for cmd_result in &sequencer {
+                match cmd_result {
+                    Ok(cmd) => cmd.run(&sequencer)?,
+                    Err(e) => {
+                        dev_err!(
+                            params.dev,
+                            "Error running command at index {}",
+                            sequencer.seq_info.info.cmdIndex
+                        );
+                        return Err(e);
+                    }
+                }
+            }
+
+            dev_dbg!(params.dev, "CPU Sequencer commands completed successfully");
+            Ok(())
+        })
+    }
+}
diff --git a/drivers/gpu/nova-core/sbuffer.rs b/drivers/gpu/nova-core/sbuffer.rs
index 4d7cbc4bd060..36890c8610c2 100644
--- a/drivers/gpu/nova-core/sbuffer.rs
+++ b/drivers/gpu/nova-core/sbuffer.rs
@@ -162,7 +162,6 @@ pub(crate) fn read_exact(&mut self, mut dst: &mut [u8]) -> Result {
     /// Read all the remaining data into a [`KVec`].
     ///
     /// `self` will be empty after this operation.
-    #[expect(unused)]
     pub(crate) fn flush_into_kvec(&mut self, flags: kernel::alloc::Flags) -> Result<KVec<u8>> {
         let mut buf = KVec::<u8>::new();
 
-- 
2.34.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ