linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/17] nova-core: Complete GSP boot and begin RPC communication
@ 2025-08-29 17:32 Joel Fernandes
  2025-08-29 17:32 ` [PATCH 01/17] nova-core: falcon: Move waiting until halted to a helper Joel Fernandes
                   ` (16 more replies)
  0 siblings, 17 replies; 20+ messages in thread
From: Joel Fernandes @ 2025-08-29 17:32 UTC (permalink / raw)
  To: linux-kernel, dri-devel, dakr, acourbot
  Cc: Alistair Popple, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	bjorn3_gh, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, David Airlie, Simona Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, John Hubbard, Joel Fernandes,
	Timur Tabi, joel, nouveau, rust-for-linux

This series builds on top of Alistair's series [1] to complete the GSP boot
process and get us to a point of making the GSP actual responding with useful
command responses (GspStaticInfo command successfully gets us useful
information about the GPU). The main addition is the sequencer required
to boot pre-Hopper Nvidia GPUs (tested on Ampere GA102).

A full tree including the prerequisites for this patch series is available at the tag:
https://git.kernel.org/pub/scm/linux/kernel/git/jfern/linux.git/tag/?h=nova/upstream-submit-8.29.2025-v5

Alex's series Alistair based [1] off of is at [2].

[1] https://lore.kernel.org/all/20250827082015.959430-1-apopple@nvidia.com/
[2] https://lore.kernel.org/rust-for-linux/dc18894e-09d3-4088-9be0-22c2070b61f4@nvidia.com/T/

Alistair Popple (2):
  gpu: nova-core: gsp: Wait for gsp initialisation to complete
  gpu: nova-core: Add get_gsp_info() command

Joel Fernandes (11):
  nova-core: falcon: Move waiting until halted to a helper
  nova-core: falcon: Move start functionality into separate helper
  nova-core: falcon: Move mbox functionalities into helper
  nova-core: falcon: Move dma_reset functionality into helper
  nova-core: gsp: Add support for checking if GSP reloaded
  nova-core: Add bindings required by GSP sequencer
  nova-core: Implement the GSP sequencer
  nova-core: sequencer: Add register opcodes
  nova-core: sequencer: Add delay opcode support
  nova-core: sequencer: Implement basic core operations
  nova-core: sequencer: Implement core resume operation

John Hubbard (4):
  nova-core: clear MBOX0 before waiting for scrubber completion
  nova-core: Ada: basic GPU identification
  nova-core: remove an unnecessary register read: HWCFG1
  nova-core: remove unnecessary need_riscv, bar parameters

 drivers/gpu/nova-core/falcon.rs               | 137 +++---
 drivers/gpu/nova-core/falcon/gsp.rs           |  16 +
 drivers/gpu/nova-core/falcon/hal.rs           |   2 +-
 drivers/gpu/nova-core/firmware.rs             |   1 +
 drivers/gpu/nova-core/gpu.rs                  |  34 +-
 drivers/gpu/nova-core/gsp.rs                  |   2 +
 drivers/gpu/nova-core/gsp/cmdq.rs             |   4 -
 drivers/gpu/nova-core/gsp/commands.rs         |  83 +++-
 drivers/gpu/nova-core/gsp/sequencer.rs        | 431 ++++++++++++++++++
 drivers/gpu/nova-core/nvfw.rs                 |  26 ++
 .../gpu/nova-core/nvfw/r570_144_bindings.rs   | 247 ++++++++++
 drivers/gpu/nova-core/regs.rs                 |   6 +
 drivers/gpu/nova-core/sbuffer.rs              |   1 -
 drivers/gpu/nova-core/util.rs                 |  15 +
 14 files changed, 930 insertions(+), 75 deletions(-)
 create mode 100644 drivers/gpu/nova-core/gsp/sequencer.rs

-- 
2.34.1


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 01/17] nova-core: falcon: Move waiting until halted to a helper
  2025-08-29 17:32 [PATCH 00/17] nova-core: Complete GSP boot and begin RPC communication Joel Fernandes
@ 2025-08-29 17:32 ` Joel Fernandes
  2025-08-29 17:32 ` [PATCH 02/17] nova-core: falcon: Move start functionality into separate helper Joel Fernandes
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: Joel Fernandes @ 2025-08-29 17:32 UTC (permalink / raw)
  To: linux-kernel, dri-devel, dakr, acourbot
  Cc: Alistair Popple, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	bjorn3_gh, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, David Airlie, Simona Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, John Hubbard, Joel Fernandes,
	Timur Tabi, joel, nouveau, rust-for-linux

Move the "waiting until halted" functionality into a helper so that we
can use it in the sequencer, which is a separate sequencer operation.

Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
---
 drivers/gpu/nova-core/falcon.rs | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
index 0c8ee7761f70..83e40a7abde0 100644
--- a/drivers/gpu/nova-core/falcon.rs
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -547,6 +547,21 @@ pub(crate) fn dma_load<F: FalconFirmware<Target = E>>(&self, bar: &Bar0, fw: &F)
         Ok(())
     }
 
+    /// Wait until the falcon CPU is halted.
+    pub(crate) fn wait_till_halted(&self, bar: &Bar0) -> Result<()> {
+        // TIMEOUT: arbitrarily large value, firmwares should complete in less than 2 seconds.
+        util::wait_on(Delta::from_secs(2), || {
+            let r = regs::NV_PFALCON_FALCON_CPUCTL::read(bar, &E::ID);
+            if r.halted() {
+                Some(())
+            } else {
+                None
+            }
+        })?;
+
+        Ok(())
+    }
+
     /// Runs the loaded firmware and waits for its completion.
     ///
     /// `mbox0` and `mbox1` are optional parameters to write into the `MBOX0` and `MBOX1` registers
@@ -581,15 +596,7 @@ pub(crate) fn boot(
                 .write(bar, &E::ID),
         }
 
-        // TIMEOUT: arbitrarily large value, firmwares should complete in less than 2 seconds.
-        util::wait_on(Delta::from_secs(2), || {
-            let r = regs::NV_PFALCON_FALCON_CPUCTL::read(bar, &E::ID);
-            if r.halted() {
-                Some(())
-            } else {
-                None
-            }
-        })?;
+        self.wait_till_halted(bar)?;
 
         let (mbox0, mbox1) = (
             regs::NV_PFALCON_FALCON_MAILBOX0::read(bar, &E::ID).value(),
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 02/17] nova-core: falcon: Move start functionality into separate helper
  2025-08-29 17:32 [PATCH 00/17] nova-core: Complete GSP boot and begin RPC communication Joel Fernandes
  2025-08-29 17:32 ` [PATCH 01/17] nova-core: falcon: Move waiting until halted to a helper Joel Fernandes
@ 2025-08-29 17:32 ` Joel Fernandes
  2025-08-29 17:32 ` [PATCH 03/17] nova-core: falcon: Move mbox functionalities into helper Joel Fernandes
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: Joel Fernandes @ 2025-08-29 17:32 UTC (permalink / raw)
  To: linux-kernel, dri-devel, dakr, acourbot
  Cc: Alistair Popple, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	bjorn3_gh, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, David Airlie, Simona Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, John Hubbard, Joel Fernandes,
	Timur Tabi, joel, nouveau, rust-for-linux

Move start functionality into a separate helper so we can use it from
the sequencer.

Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
---
 drivers/gpu/nova-core/falcon.rs | 26 ++++++++++++++++----------
 1 file changed, 16 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
index 83e40a7abde0..e51f4d7469c0 100644
--- a/drivers/gpu/nova-core/falcon.rs
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -562,7 +562,21 @@ pub(crate) fn wait_till_halted(&self, bar: &Bar0) -> Result<()> {
         Ok(())
     }
 
-    /// Runs the loaded firmware and waits for its completion.
+    /// Start the falcon CPU.
+    pub(crate) fn start(&self, bar: &Bar0) -> Result<()> {
+        match regs::NV_PFALCON_FALCON_CPUCTL::read(bar, &E::ID).alias_en() {
+            true => regs::NV_PFALCON_FALCON_CPUCTL_ALIAS::default()
+                .set_startcpu(true)
+                .write(bar, &E::ID),
+            false => regs::NV_PFALCON_FALCON_CPUCTL::default()
+                .set_startcpu(true)
+                .write(bar, &E::ID),
+        }
+
+        Ok(())
+    }
+
+    /// Start running the loaded firmware.
     ///
     /// `mbox0` and `mbox1` are optional parameters to write into the `MBOX0` and `MBOX1` registers
     /// prior to running.
@@ -587,15 +601,7 @@ pub(crate) fn boot(
                 .write(bar, &E::ID);
         }
 
-        match regs::NV_PFALCON_FALCON_CPUCTL::read(bar, &E::ID).alias_en() {
-            true => regs::NV_PFALCON_FALCON_CPUCTL_ALIAS::default()
-                .set_startcpu(true)
-                .write(bar, &E::ID),
-            false => regs::NV_PFALCON_FALCON_CPUCTL::default()
-                .set_startcpu(true)
-                .write(bar, &E::ID),
-        }
-
+        self.start(bar)?;
         self.wait_till_halted(bar)?;
 
         let (mbox0, mbox1) = (
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 03/17] nova-core: falcon: Move mbox functionalities into helper
  2025-08-29 17:32 [PATCH 00/17] nova-core: Complete GSP boot and begin RPC communication Joel Fernandes
  2025-08-29 17:32 ` [PATCH 01/17] nova-core: falcon: Move waiting until halted to a helper Joel Fernandes
  2025-08-29 17:32 ` [PATCH 02/17] nova-core: falcon: Move start functionality into separate helper Joel Fernandes
@ 2025-08-29 17:32 ` Joel Fernandes
  2025-08-29 17:32 ` [PATCH 04/17] nova-core: falcon: Move dma_reset functionality " Joel Fernandes
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: Joel Fernandes @ 2025-08-29 17:32 UTC (permalink / raw)
  To: linux-kernel, dri-devel, dakr, acourbot
  Cc: Alistair Popple, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	bjorn3_gh, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, David Airlie, Simona Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, John Hubbard, Joel Fernandes,
	Timur Tabi, joel, nouveau, rust-for-linux

Move falcon reading/writing to mbox functionality into helper so we can
use it from the sequencer resume flow.

Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
---
 drivers/gpu/nova-core/falcon.rs | 51 +++++++++++++++++++++++----------
 1 file changed, 36 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
index e51f4d7469c0..054be6c094ba 100644
--- a/drivers/gpu/nova-core/falcon.rs
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -576,19 +576,13 @@ pub(crate) fn start(&self, bar: &Bar0) -> Result<()> {
         Ok(())
     }
 
-    /// Start running the loaded firmware.
-    ///
-    /// `mbox0` and `mbox1` are optional parameters to write into the `MBOX0` and `MBOX1` registers
-    /// prior to running.
-    ///
-    /// Wait up to two seconds for the firmware to complete, and return its exit status read from
-    /// the `MBOX0` and `MBOX1` registers.
-    pub(crate) fn boot(
+    /// Write values to the mailbox registers if provided.
+    pub(crate) fn write_mailboxes(
         &self,
         bar: &Bar0,
         mbox0: Option<u32>,
         mbox1: Option<u32>,
-    ) -> Result<(u32, u32)> {
+    ) -> Result<()> {
         if let Some(mbox0) = mbox0 {
             regs::NV_PFALCON_FALCON_MAILBOX0::default()
                 .set_value(mbox0)
@@ -600,18 +594,45 @@ pub(crate) fn boot(
                 .set_value(mbox1)
                 .write(bar, &E::ID);
         }
+        Ok(())
+    }
 
-        self.start(bar)?;
-        self.wait_till_halted(bar)?;
+    /// Read the value from mbox0 register.
+    pub(crate) fn read_mailbox0(&self, bar: &Bar0) -> Result<u32> {
+        Ok(regs::NV_PFALCON_FALCON_MAILBOX0::read(bar, &E::ID).value())
+    }
 
-        let (mbox0, mbox1) = (
-            regs::NV_PFALCON_FALCON_MAILBOX0::read(bar, &E::ID).value(),
-            regs::NV_PFALCON_FALCON_MAILBOX1::read(bar, &E::ID).value(),
-        );
+    /// Read the value from mbox1 register.
+    pub(crate) fn read_mailbox1(&self, bar: &Bar0) -> Result<u32> {
+        Ok(regs::NV_PFALCON_FALCON_MAILBOX1::read(bar, &E::ID).value())
+    }
 
+    /// Read values from both mailbox registers.
+    pub(crate) fn read_mailboxes(&self, bar: &Bar0) -> Result<(u32, u32)> {
+        let mbox0 = self.read_mailbox0(bar)?;
+        let mbox1 = self.read_mailbox1(bar)?;
         Ok((mbox0, mbox1))
     }
 
+    /// Start running the loaded firmware.
+    ///
+    /// `mbox0` and `mbox1` are optional parameters to write into the `MBOX0` and `MBOX1` registers
+    /// prior to running.
+    ///
+    /// Wait up to two seconds for the firmware to complete, and return its exit status read from
+    /// the `MBOX0` and `MBOX1` registers.
+    pub(crate) fn boot(
+        &self,
+        bar: &Bar0,
+        mbox0: Option<u32>,
+        mbox1: Option<u32>,
+    ) -> Result<(u32, u32)> {
+        self.write_mailboxes(bar, mbox0, mbox1)?;
+        self.start(bar)?;
+        self.wait_till_halted(bar)?;
+        self.read_mailboxes(bar)
+    }
+
     /// Returns the fused version of the signature to use in order to run a HS firmware on this
     /// falcon instance. `engine_id_mask` and `ucode_id` are obtained from the firmware header.
     pub(crate) fn signature_reg_fuse_version(
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 04/17] nova-core: falcon: Move dma_reset functionality into helper
  2025-08-29 17:32 [PATCH 00/17] nova-core: Complete GSP boot and begin RPC communication Joel Fernandes
                   ` (2 preceding siblings ...)
  2025-08-29 17:32 ` [PATCH 03/17] nova-core: falcon: Move mbox functionalities into helper Joel Fernandes
@ 2025-08-29 17:32 ` Joel Fernandes
  2025-08-29 17:32 ` [PATCH 05/17] nova-core: gsp: Add support for checking if GSP reloaded Joel Fernandes
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: Joel Fernandes @ 2025-08-29 17:32 UTC (permalink / raw)
  To: linux-kernel, dri-devel, dakr, acourbot
  Cc: Alistair Popple, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	bjorn3_gh, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, David Airlie, Simona Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, John Hubbard, Joel Fernandes,
	Timur Tabi, joel, nouveau, rust-for-linux

Move dma_reset so we can use it for the upcoming sequencer
functionality.

Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
---
 drivers/gpu/nova-core/falcon.rs | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
index 054be6c094ba..7fbf909cae08 100644
--- a/drivers/gpu/nova-core/falcon.rs
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -377,6 +377,12 @@ pub(crate) fn new(
         })
     }
 
+    /// Reset DMA-related registers.
+    pub(crate) fn dma_reset(&self, bar: &Bar0) {
+        regs::NV_PFALCON_FBIF_CTL::alter(bar, &E::ID, |v| v.set_allow_phys_no_ctx(true));
+        regs::NV_PFALCON_FALCON_DMACTL::default().write(bar, &E::ID);
+    }
+
     /// Wait for memory scrubbing to complete.
     fn reset_wait_mem_scrubbing(&self, bar: &Bar0) -> Result {
         // TIMEOUT: memory scrubbing should complete in less than 20ms.
@@ -527,8 +533,7 @@ fn dma_wr<F: FalconFirmware<Target = E>>(
 
     /// Perform a DMA load into `IMEM` and `DMEM` of `fw`, and prepare the falcon to run it.
     pub(crate) fn dma_load<F: FalconFirmware<Target = E>>(&self, bar: &Bar0, fw: &F) -> Result {
-        regs::NV_PFALCON_FBIF_CTL::alter(bar, &E::ID, |v| v.set_allow_phys_no_ctx(true));
-        regs::NV_PFALCON_FALCON_DMACTL::default().write(bar, &E::ID);
+        self.dma_reset(bar);
         regs::NV_PFALCON_FBIF_TRANSCFG::alter(bar, &E::ID, 0, |v| {
             v.set_target(FalconFbifTarget::CoherentSysmem)
                 .set_mem_type(FalconFbifMemType::Physical)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 05/17] nova-core: gsp: Add support for checking if GSP reloaded
  2025-08-29 17:32 [PATCH 00/17] nova-core: Complete GSP boot and begin RPC communication Joel Fernandes
                   ` (3 preceding siblings ...)
  2025-08-29 17:32 ` [PATCH 04/17] nova-core: falcon: Move dma_reset functionality " Joel Fernandes
@ 2025-08-29 17:32 ` Joel Fernandes
  2025-08-29 18:44   ` Timur Tabi
  2025-08-29 17:32 ` [PATCH 06/17] nova-core: Add bindings required by GSP sequencer Joel Fernandes
                   ` (11 subsequent siblings)
  16 siblings, 1 reply; 20+ messages in thread
From: Joel Fernandes @ 2025-08-29 17:32 UTC (permalink / raw)
  To: linux-kernel, dri-devel, dakr, acourbot
  Cc: Alistair Popple, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	bjorn3_gh, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, David Airlie, Simona Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, John Hubbard, Joel Fernandes,
	Timur Tabi, joel, nouveau, rust-for-linux

During the sequencer process, we need to check if GSP was successfully
reloaded. Add functionality to check for the same.

Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
---
 drivers/gpu/nova-core/falcon/gsp.rs | 17 +++++++++++++++++
 drivers/gpu/nova-core/regs.rs       |  6 ++++++
 2 files changed, 23 insertions(+)

diff --git a/drivers/gpu/nova-core/falcon/gsp.rs b/drivers/gpu/nova-core/falcon/gsp.rs
index f17599cb49fa..58478ada6d3e 100644
--- a/drivers/gpu/nova-core/falcon/gsp.rs
+++ b/drivers/gpu/nova-core/falcon/gsp.rs
@@ -1,9 +1,13 @@
 // SPDX-License-Identifier: GPL-2.0
 
+use kernel::prelude::*;
+use kernel::time::Delta;
+
 use crate::{
     driver::Bar0,
     falcon::{Falcon, FalconEngine, PFalcon2Base, PFalconBase},
     regs::{self, macros::RegisterBase},
+    util::wait_on,
 };
 
 /// Type specifying the `Gsp` falcon engine. Cannot be instantiated.
@@ -29,4 +33,17 @@ pub(crate) fn clear_swgen0_intr(&self, bar: &Bar0) {
             .set_swgen0(true)
             .write(bar, &Gsp::ID);
     }
+
+    /// Function to check if GSP reload/resume has completed during the boot process.
+    #[expect(dead_code)]
+    pub(crate) fn check_reload_completed(&self, bar: &Bar0, timeout: Delta) -> Result<bool> {
+        wait_on(timeout, || {
+            let val = regs::NV_PGC6_BSI_SECURE_SCRATCH_14::read(bar);
+            if val.boot_stage_3_handoff() {
+                Some(true)
+            } else {
+                None
+            }
+        })
+    }
 }
diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs
index d9212fa50197..c214f8056d6e 100644
--- a/drivers/gpu/nova-core/regs.rs
+++ b/drivers/gpu/nova-core/regs.rs
@@ -123,6 +123,12 @@ pub(crate) fn higher_bound(self) -> u64 {
 // These scratch registers remain powered on even in a low-power state and have a designated group
 // number.
 
+// Boot Sequence Interface (BSI) register used to determine
+// if GSP reload/resume has completed during the boot process.
+register!(NV_PGC6_BSI_SECURE_SCRATCH_14 @ 0x001180f8 {
+    26:26   boot_stage_3_handoff as bool;
+});
+
 // Privilege level mask register. It dictates whether the host CPU has privilege to access the
 // `PGC6_AON_SECURE_SCRATCH_GROUP_05` register (which it needs to read GFW_BOOT).
 register!(NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK @ 0x00118128,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 06/17] nova-core: Add bindings required by GSP sequencer
  2025-08-29 17:32 [PATCH 00/17] nova-core: Complete GSP boot and begin RPC communication Joel Fernandes
                   ` (4 preceding siblings ...)
  2025-08-29 17:32 ` [PATCH 05/17] nova-core: gsp: Add support for checking if GSP reloaded Joel Fernandes
@ 2025-08-29 17:32 ` Joel Fernandes
  2025-08-29 17:32 ` [PATCH 07/17] nova-core: Implement the " Joel Fernandes
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: Joel Fernandes @ 2025-08-29 17:32 UTC (permalink / raw)
  To: linux-kernel, dri-devel, dakr, acourbot
  Cc: Alistair Popple, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	bjorn3_gh, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, David Airlie, Simona Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, John Hubbard, Joel Fernandes,
	Timur Tabi, joel, nouveau, rust-for-linux

Add several firmware bindings required by GSP sequencer code.

Co-developed-by: Alistair Popple <apopple@nvidia.com>
Signed-off-by: Alistair Popple <apopple@nvidia.com>
Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
---
 drivers/gpu/nova-core/nvfw.rs                 | 25 ++++++
 .../gpu/nova-core/nvfw/r570_144_bindings.rs   | 84 +++++++++++++++++++
 2 files changed, 109 insertions(+)

diff --git a/drivers/gpu/nova-core/nvfw.rs b/drivers/gpu/nova-core/nvfw.rs
index aa883d458838..0b44a922fe5d 100644
--- a/drivers/gpu/nova-core/nvfw.rs
+++ b/drivers/gpu/nova-core/nvfw.rs
@@ -41,7 +41,9 @@ pub(crate) struct LibosParams {
 /// addresses of the GSP bootloader and firmware.
 pub(crate) use r570_144::GspFwWprMeta;
 
+#[expect(unused_imports)]
 pub(crate) use r570_144::{
+    rpc_run_cpu_sequencer_v17_00,
     // Core GSP structures
     GspSystemInfo,
 
@@ -55,6 +57,29 @@ pub(crate) struct LibosParams {
     // GSP firmware constants
     GSP_FW_WPR_META_MAGIC,
     GSP_FW_WPR_META_REVISION,
+
+    // GSP sequencer structures
+    GSP_SEQUENCER_BUFFER_CMD,
+    GSP_SEQ_BUF_OPCODE,
+
+    GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_RESET,
+    GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_RESUME,
+
+    GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_START,
+    GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_WAIT_FOR_HALT,
+    // GSP sequencer opcode constants
+    GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_DELAY_US,
+    GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_MODIFY,
+    GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_POLL,
+    GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_STORE,
+    GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_WRITE,
+    // GSP sequencer payload structures
+    GSP_SEQ_BUF_PAYLOAD_DELAY_US,
+    GSP_SEQ_BUF_PAYLOAD_REG_MODIFY,
+    GSP_SEQ_BUF_PAYLOAD_REG_POLL,
+    GSP_SEQ_BUF_PAYLOAD_REG_STORE,
+    GSP_SEQ_BUF_PAYLOAD_REG_WRITE,
+
     GSP_SR_INIT_ARGUMENTS,
 
     // RM message queue parameters
diff --git a/drivers/gpu/nova-core/nvfw/r570_144_bindings.rs b/drivers/gpu/nova-core/nvfw/r570_144_bindings.rs
index 3832d0b7a0b9..607d99ac2221 100644
--- a/drivers/gpu/nova-core/nvfw/r570_144_bindings.rs
+++ b/drivers/gpu/nova-core/nvfw/r570_144_bindings.rs
@@ -625,3 +625,87 @@ pub struct PACKED_REGISTRY_TABLE {
     pub numEntries: u32_,
     pub entries: __IncompleteArrayField<PACKED_REGISTRY_ENTRY>,
 }
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct rpc_run_cpu_sequencer_v17_00 {
+    pub bufferSizeDWord: u32_,
+    pub cmdIndex: u32_,
+    pub regSaveArea: [u32_; 8usize],
+    pub commandBuffer: __IncompleteArrayField<u32_>,
+}
+pub const GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_WRITE: GSP_SEQ_BUF_OPCODE = 0;
+pub const GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_MODIFY: GSP_SEQ_BUF_OPCODE = 1;
+pub const GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_POLL: GSP_SEQ_BUF_OPCODE = 2;
+pub const GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_DELAY_US: GSP_SEQ_BUF_OPCODE = 3;
+pub const GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_STORE: GSP_SEQ_BUF_OPCODE = 4;
+pub const GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_RESET: GSP_SEQ_BUF_OPCODE = 5;
+pub const GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_START: GSP_SEQ_BUF_OPCODE = 6;
+pub const GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_WAIT_FOR_HALT: GSP_SEQ_BUF_OPCODE = 7;
+pub const GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_RESUME: GSP_SEQ_BUF_OPCODE = 8;
+pub type GSP_SEQ_BUF_OPCODE = ffi::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct GSP_SEQ_BUF_PAYLOAD_REG_WRITE {
+    pub addr: u32_,
+    pub val: u32_,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct GSP_SEQ_BUF_PAYLOAD_REG_MODIFY {
+    pub addr: u32_,
+    pub mask: u32_,
+    pub val: u32_,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct GSP_SEQ_BUF_PAYLOAD_REG_POLL {
+    pub addr: u32_,
+    pub mask: u32_,
+    pub val: u32_,
+    pub timeout: u32_,
+    pub error: u32_,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct GSP_SEQ_BUF_PAYLOAD_DELAY_US {
+    pub val: u32_,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct GSP_SEQ_BUF_PAYLOAD_REG_STORE {
+    pub addr: u32_,
+    pub index: u32_,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct GSP_SEQUENCER_BUFFER_CMD {
+    pub opCode: GSP_SEQ_BUF_OPCODE,
+    pub payload: GSP_SEQUENCER_BUFFER_CMD__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union GSP_SEQUENCER_BUFFER_CMD__bindgen_ty_1 {
+    pub regWrite: GSP_SEQ_BUF_PAYLOAD_REG_WRITE,
+    pub regModify: GSP_SEQ_BUF_PAYLOAD_REG_MODIFY,
+    pub regPoll: GSP_SEQ_BUF_PAYLOAD_REG_POLL,
+    pub delayUs: GSP_SEQ_BUF_PAYLOAD_DELAY_US,
+    pub regStore: GSP_SEQ_BUF_PAYLOAD_REG_STORE,
+}
+impl Default for GSP_SEQUENCER_BUFFER_CMD__bindgen_ty_1 {
+    fn default() -> Self {
+        let mut s = ::core::mem::MaybeUninit::<Self>::uninit();
+        unsafe {
+            ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+            s.assume_init()
+        }
+    }
+}
+impl Default for GSP_SEQUENCER_BUFFER_CMD {
+    fn default() -> Self {
+        let mut s = ::core::mem::MaybeUninit::<Self>::uninit();
+        unsafe {
+            ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+            s.assume_init()
+        }
+    }
+}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 07/17] nova-core: Implement the GSP sequencer
  2025-08-29 17:32 [PATCH 00/17] nova-core: Complete GSP boot and begin RPC communication Joel Fernandes
                   ` (5 preceding siblings ...)
  2025-08-29 17:32 ` [PATCH 06/17] nova-core: Add bindings required by GSP sequencer Joel Fernandes
@ 2025-08-29 17:32 ` Joel Fernandes
  2025-08-29 17:32 ` [PATCH 08/17] nova-core: sequencer: Add register opcodes Joel Fernandes
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: Joel Fernandes @ 2025-08-29 17:32 UTC (permalink / raw)
  To: linux-kernel, dri-devel, dakr, acourbot
  Cc: Alistair Popple, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	bjorn3_gh, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, David Airlie, Simona Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, John Hubbard, Joel Fernandes,
	Timur Tabi, joel, nouveau, rust-for-linux

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@nvidia.com>
---
 drivers/gpu/nova-core/gpu.rs           |  16 +-
 drivers/gpu/nova-core/gsp.rs           |   2 +
 drivers/gpu/nova-core/gsp/cmdq.rs      |   4 -
 drivers/gpu/nova-core/gsp/sequencer.rs | 212 +++++++++++++++++++++++++
 drivers/gpu/nova-core/sbuffer.rs       |   1 -
 5 files changed, 229 insertions(+), 6 deletions(-)
 create mode 100644 drivers/gpu/nova-core/gsp/sequencer.rs

diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index f86221a681e2..bf670f6b6773 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -312,7 +312,7 @@ pub(crate) fn new(
 
         Self::run_fwsec_frts(pdev.as_ref(), &gsp_falcon, bar, &bios, &fb_layout)?;
 
-        let libos = gsp::GspMemObjects::new(pdev, bar, &fw, &fb_layout)?;
+        let mut libos = gsp::GspMemObjects::new(pdev, bar, &fw, &fb_layout)?;
         let libos_handle = libos.libos_dma_handle();
         let wpr_handle = libos.wpr_meta.dma_handle();
 
@@ -366,6 +366,20 @@ pub(crate) fn new(
             gsp_falcon.is_riscv_active(bar)?,
         );
 
+        let libos_dma_handle = libos.libos_dma_handle();
+
+        // Create and run the GSP sequencer
+        gsp::sequencer::GspSequencer::run(
+            &mut libos.cmdq,
+            &fw,
+            libos_dma_handle,
+            &gsp_falcon,
+            &sec2_falcon,
+            pdev.as_ref(),
+            &bar,
+            Delta::from_secs(10),
+        )?;
+
         Ok(pin_init!(Self {
             spec,
             bar: devres_bar,
diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
index 9776c643f527..467d0453130a 100644
--- a/drivers/gpu/nova-core/gsp.rs
+++ b/drivers/gpu/nova-core/gsp.rs
@@ -27,6 +27,8 @@
 pub(crate) mod cmdq;
 pub(crate) mod commands;
 
+pub(crate) mod sequencer;
+
 pub(crate) const GSP_PAGE_SHIFT: usize = 12;
 pub(crate) const GSP_PAGE_SIZE: usize = 1 << GSP_PAGE_SHIFT;
 pub(crate) const GSP_HEAP_ALIGNMENT: Alignment = Alignment::new(1 << 20);
diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index 4e4fbaa81e8e..1a7785627af3 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -182,7 +182,6 @@ pub(crate) struct GspQueueMessage<'a> {
 type GspQueueMessageData<'a, M> = (&'a M, Option<SBuffer<core::array::IntoIter<&'a [u8], 2>>>);
 
 impl<'a> GspQueueMessage<'a> {
-    #[expect(unused)]
     pub(crate) fn try_as<M: GspMessageFromGsp>(&'a self) -> Result<GspQueueMessageData<'a, M>> {
         if self.rpc_header.function != M::FUNCTION {
             return Err(ERANGE);
@@ -204,7 +203,6 @@ pub(crate) fn try_as<M: GspMessageFromGsp>(&'a self) -> Result<GspQueueMessageDa
         Ok((msg, sbuf))
     }
 
-    #[expect(unused)]
     pub(crate) fn ack(self) -> Result {
         self.cmdq.ack_msg(self.rpc_header.length)?;
 
@@ -519,7 +517,6 @@ pub(crate) fn msg_from_gsp_available(&self) -> bool {
         true
     }
 
-    #[expect(unused)]
     pub(crate) fn wait_for_msg_from_gsp(&self, timeout: Delta) -> Result {
         wait_on(timeout, || {
             if self.msg_from_gsp_available() {
@@ -530,7 +527,6 @@ pub(crate) fn wait_for_msg_from_gsp(&self, timeout: Delta) -> Result {
         })
     }
 
-    #[expect(unused)]
     pub(crate) fn receive_msg_from_gsp<'a>(&'a mut self) -> Result<GspQueueMessage<'a>> {
         const HEADER_SIZE: u32 = (size_of::<GspMsgHeader>() + size_of::<GspRpcHeader>()) as u32;
 
diff --git a/drivers/gpu/nova-core/gsp/sequencer.rs b/drivers/gpu/nova-core/gsp/sequencer.rs
new file mode 100644
index 000000000000..918c3405b33c
--- /dev/null
+++ b/drivers/gpu/nova-core/gsp/sequencer.rs
@@ -0,0 +1,212 @@
+// 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 crate::driver::Bar0;
+use crate::falcon::{gsp::Gsp, sec2::Sec2, Falcon};
+use crate::firmware::Firmware;
+use crate::gsp::cmdq::{GspCmdq, GspMessageFromGsp};
+use crate::nvfw as fw;
+
+use kernel::transmute::FromBytes;
+use kernel::{dev_dbg, dev_err};
+
+unsafe impl FromBytes for fw::GSP_SEQUENCER_BUFFER_CMD {}
+unsafe impl FromBytes for fw::rpc_run_cpu_sequencer_v17_00 {}
+impl GspMessageFromGsp for fw::rpc_run_cpu_sequencer_v17_00 {
+    const FUNCTION: u32 = fw::NV_VGPU_MSG_EVENT_GSP_RUN_CPU_SEQUENCER;
+}
+
+const CMD_SIZE: usize = size_of::<fw::GSP_SEQUENCER_BUFFER_CMD>();
+
+pub(crate) struct GspSequencerInfo<'a> {
+    pub info: &'a fw::rpc_run_cpu_sequencer_v17_00,
+    pub cmd_data: KVec<u8>,
+}
+
+/// GSP Sequencer Command types with payload data
+/// Commands have an opcode and a opcode-dependent struct.
+#[expect(dead_code)]
+pub(crate) enum GspSeqCmd {
+    RegWrite(fw::GSP_SEQ_BUF_PAYLOAD_REG_WRITE),
+    RegModify(fw::GSP_SEQ_BUF_PAYLOAD_REG_MODIFY),
+    RegPoll(fw::GSP_SEQ_BUF_PAYLOAD_REG_POLL),
+    RegStore(fw::GSP_SEQ_BUF_PAYLOAD_REG_STORE),
+}
+
+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> {
+        match cmd.opCode {
+            _ => 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.\n");
+            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> {
+    pub seq_info: GspSequencerInfo<'a>,
+    pub bar: &'a Bar0,
+    pub sec2_falcon: &'a Falcon<Sec2>,
+    pub gsp_falcon: &'a Falcon<Gsp>,
+    pub libos_dma_handle: u64,
+    pub fw: &'a Firmware,
+    pub 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,
+        }
+    }
+}
+
+impl<'a> GspSequencer<'a> {
+    pub(crate) fn run(
+        cmdq: &mut GspCmdq,
+        fw: &'a Firmware,
+        libos_dma_handle: u64,
+        gsp_falcon: &'a Falcon<Gsp>,
+        sec2_falcon: &'a Falcon<Sec2>,
+        dev: &'a device::Device<device::Bound>,
+        bar: &'a Bar0,
+        timeout: Delta,
+    ) -> Result {
+        cmdq.wait_for_msg_from_gsp(timeout)?;
+        let msg = cmdq.receive_msg_from_gsp()?;
+
+        let (info, mut sbuf) = msg.try_as::<fw::rpc_run_cpu_sequencer_v17_00>()?;
+        let cmd_data = match sbuf {
+            Some(ref mut sbuf) => sbuf.read_into_kvec(GFP_KERNEL),
+            _ => Err(EINVAL),
+        }?;
+        let seq_info = GspSequencerInfo { info, cmd_data };
+
+        let sequencer = GspSequencer {
+            seq_info,
+            bar,
+            sec2_falcon,
+            gsp_falcon,
+            libos_dma_handle,
+            fw,
+            dev,
+        };
+
+        dev_dbg!(dev, "Running CPU Sequencer commands\n");
+
+        for cmd_result in &sequencer {
+            match cmd_result {
+                Ok(cmd) => cmd.run(&sequencer)?,
+                Err(e) => {
+                    dev_err!(
+                        dev,
+                        "Error running command at index {}\n",
+                        sequencer.seq_info.info.cmdIndex
+                    );
+                    return Err(e);
+                }
+            }
+        }
+
+        dev_dbg!(dev, "CPU Sequencer commands completed successfully\n");
+
+        drop(sbuf);
+        msg.ack()?;
+
+        Ok(())
+    }
+}
diff --git a/drivers/gpu/nova-core/sbuffer.rs b/drivers/gpu/nova-core/sbuffer.rs
index b1b8c4536d2f..528ff8dc6062 100644
--- a/drivers/gpu/nova-core/sbuffer.rs
+++ b/drivers/gpu/nova-core/sbuffer.rs
@@ -129,7 +129,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 read_into_kvec(&mut self, flags: kernel::alloc::Flags) -> Result<KVec<u8>> {
         let mut buf = KVec::<u8>::new();
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 08/17] nova-core: sequencer: Add register opcodes
  2025-08-29 17:32 [PATCH 00/17] nova-core: Complete GSP boot and begin RPC communication Joel Fernandes
                   ` (6 preceding siblings ...)
  2025-08-29 17:32 ` [PATCH 07/17] nova-core: Implement the " Joel Fernandes
@ 2025-08-29 17:32 ` Joel Fernandes
  2025-08-29 17:32 ` [PATCH 09/17] nova-core: sequencer: Add delay opcode support Joel Fernandes
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: Joel Fernandes @ 2025-08-29 17:32 UTC (permalink / raw)
  To: linux-kernel, dri-devel, dakr, acourbot
  Cc: Alistair Popple, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	bjorn3_gh, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, David Airlie, Simona Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, John Hubbard, Joel Fernandes,
	Timur Tabi, joel, nouveau, rust-for-linux

These opcodes are used for regiter write, modify, poll and store (save).

Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
---
 drivers/gpu/nova-core/gsp/sequencer.rs | 127 ++++++++++++++++++++++++-
 1 file changed, 123 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/nova-core/gsp/sequencer.rs b/drivers/gpu/nova-core/gsp/sequencer.rs
index 918c3405b33c..75672ae0a687 100644
--- a/drivers/gpu/nova-core/gsp/sequencer.rs
+++ b/drivers/gpu/nova-core/gsp/sequencer.rs
@@ -13,6 +13,7 @@
 use crate::firmware::Firmware;
 use crate::gsp::cmdq::{GspCmdq, GspMessageFromGsp};
 use crate::nvfw as fw;
+use crate::util::wait_on;
 
 use kernel::transmute::FromBytes;
 use kernel::{dev_dbg, dev_err};
@@ -32,7 +33,6 @@ pub(crate) struct GspSequencerInfo<'a> {
 
 /// GSP Sequencer Command types with payload data
 /// Commands have an opcode and a opcode-dependent struct.
-#[expect(dead_code)]
 pub(crate) enum GspSeqCmd {
     RegWrite(fw::GSP_SEQ_BUF_PAYLOAD_REG_WRITE),
     RegModify(fw::GSP_SEQ_BUF_PAYLOAD_REG_MODIFY),
@@ -44,6 +44,20 @@ 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> {
         match cmd.opCode {
+            // SAFETY: In the below unsafe accesses, we're using the union field
+            //         that corresponds to the opCode
+            fw::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_WRITE => {
+                Ok(GspSeqCmd::RegWrite(unsafe { cmd.payload.regWrite }))
+            }
+            fw::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_MODIFY => {
+                Ok(GspSeqCmd::RegModify(unsafe { cmd.payload.regModify }))
+            }
+            fw::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_POLL => {
+                Ok(GspSeqCmd::RegPoll(unsafe { cmd.payload.regPoll }))
+            }
+            fw::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_STORE => {
+                Ok(GspSeqCmd::RegStore(unsafe { cmd.payload.regStore }))
+            }
             _ => Err(EINVAL),
         }
     }
@@ -63,7 +77,16 @@ pub(crate) fn new(data: &[u8], dev: &device::Device<device::Bound>) -> Result<Se
     /// 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
+        let opcode_size = size_of::<fw::GSP_SEQ_BUF_OPCODE>();
+        match self {
+            // For commands with payloads, add the payload size in bytes
+            GspSeqCmd::RegWrite(_) => opcode_size + size_of::<fw::GSP_SEQ_BUF_PAYLOAD_REG_WRITE>(),
+            GspSeqCmd::RegModify(_) => {
+                opcode_size + size_of::<fw::GSP_SEQ_BUF_PAYLOAD_REG_MODIFY>()
+            }
+            GspSeqCmd::RegPoll(_) => opcode_size + size_of::<fw::GSP_SEQ_BUF_PAYLOAD_REG_POLL>(),
+            GspSeqCmd::RegStore(_) => opcode_size + size_of::<fw::GSP_SEQ_BUF_PAYLOAD_REG_STORE>(),
+        }
     }
 }
 
@@ -82,12 +105,108 @@ pub(crate) trait GspSeqCmdRunner {
     fn run(&self, sequencer: &GspSequencer<'_>) -> Result;
 }
 
-impl GspSeqCmdRunner for GspSeqCmd {
-    fn run(&self, _seq: &GspSequencer<'_>) -> Result {
+impl GspSeqCmdRunner for fw::GSP_SEQ_BUF_PAYLOAD_REG_WRITE {
+    fn run(&self, sequencer: &GspSequencer<'_>) -> Result {
+        dev_dbg!(
+            sequencer.dev,
+            "RegWrite: addr=0x{:x}, val=0x{:x}\n",
+            self.addr,
+            self.val
+        );
+        let addr = self.addr as usize;
+        let val = self.val;
+        let _ = sequencer.bar.try_write32(val, addr);
+        Ok(())
+    }
+}
+
+impl GspSeqCmdRunner for fw::GSP_SEQ_BUF_PAYLOAD_REG_MODIFY {
+    fn run(&self, sequencer: &GspSequencer<'_>) -> Result {
+        dev_dbg!(
+            sequencer.dev,
+            "RegModify: addr=0x{:x}, mask=0x{:x}, val=0x{:x}\n",
+            self.addr,
+            self.mask,
+            self.val
+        );
+
+        let addr = self.addr as usize;
+        if let Ok(temp) = sequencer.bar.try_read32(addr) {
+            let _ = sequencer
+                .bar
+                .try_write32((temp & !self.mask) | self.val, addr);
+        }
         Ok(())
     }
 }
 
+impl GspSeqCmdRunner for fw::GSP_SEQ_BUF_PAYLOAD_REG_POLL {
+    fn run(&self, sequencer: &GspSequencer<'_>) -> Result {
+        dev_dbg!(
+            sequencer.dev,
+            "RegPoll: addr=0x{:x}, mask=0x{:x}, val=0x{:x}, timeout=0x{:x}, error=0x{:x}\n",
+            self.addr,
+            self.mask,
+            self.val,
+            self.timeout,
+            self.error
+        );
+
+        let addr = self.addr as usize;
+        let mut timeout_us = self.timeout as i64;
+
+        // Default timeout to 4 seconds
+        timeout_us = if timeout_us == 0 { 4000000 } else { timeout_us };
+
+        // First read
+        sequencer.bar.try_read32(addr)?;
+
+        // Poll the requested register with requested timeout.
+        // wait_on() unwraps the closure's Option<R> return value
+        // and returns a Result<R>.
+        wait_on(Delta::from_micros(timeout_us), || {
+            sequencer.bar.try_read32(addr).ok().and_then(|current| {
+                if (current & self.mask) == self.val {
+                    Some(())
+                } else {
+                    None
+                }
+            })
+        })?;
+        Ok(())
+    }
+}
+
+impl GspSeqCmdRunner for fw::GSP_SEQ_BUF_PAYLOAD_REG_STORE {
+    fn run(&self, sequencer: &GspSequencer<'_>) -> Result {
+        let addr = self.addr as usize;
+        let _index = self.index;
+
+        let val = sequencer.bar.try_read32(addr)?;
+
+        dev_dbg!(
+            sequencer.dev,
+            "RegStore: addr=0x{:x}, index=0x{:x}, value={:?}\n",
+            self.addr,
+            self.index,
+            val
+        );
+
+        Ok(())
+    }
+}
+
+impl GspSeqCmdRunner for GspSeqCmd {
+    fn run(&self, seq: &GspSequencer<'_>) -> Result {
+        match self {
+            GspSeqCmd::RegWrite(cmd) => cmd.run(seq),
+            GspSeqCmd::RegModify(cmd) => cmd.run(seq),
+            GspSeqCmd::RegPoll(cmd) => cmd.run(seq),
+            GspSeqCmd::RegStore(cmd) => cmd.run(seq),
+        }
+    }
+}
+
 pub(crate) struct GspSeqIter<'a> {
     cmd_data: &'a [u8],
     current_offset: usize, // Tracking the current position
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 09/17] nova-core: sequencer: Add delay opcode support
  2025-08-29 17:32 [PATCH 00/17] nova-core: Complete GSP boot and begin RPC communication Joel Fernandes
                   ` (7 preceding siblings ...)
  2025-08-29 17:32 ` [PATCH 08/17] nova-core: sequencer: Add register opcodes Joel Fernandes
@ 2025-08-29 17:32 ` Joel Fernandes
  2025-08-29 17:32 ` [PATCH 10/17] nova-core: sequencer: Implement basic core operations Joel Fernandes
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: Joel Fernandes @ 2025-08-29 17:32 UTC (permalink / raw)
  To: linux-kernel, dri-devel, dakr, acourbot
  Cc: Alistair Popple, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	bjorn3_gh, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, David Airlie, Simona Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, John Hubbard, Joel Fernandes,
	Timur Tabi, joel, nouveau, rust-for-linux

Implement a sequencer opcode which for delay operations.

Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
---
 drivers/gpu/nova-core/gsp/sequencer.rs | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/drivers/gpu/nova-core/gsp/sequencer.rs b/drivers/gpu/nova-core/gsp/sequencer.rs
index 75672ae0a687..803956a74c8c 100644
--- a/drivers/gpu/nova-core/gsp/sequencer.rs
+++ b/drivers/gpu/nova-core/gsp/sequencer.rs
@@ -4,6 +4,7 @@
 
 use core::mem::size_of;
 use kernel::alloc::flags::GFP_KERNEL;
+use kernel::bindings;
 use kernel::device;
 use kernel::prelude::*;
 use kernel::time::Delta;
@@ -37,6 +38,7 @@ pub(crate) enum GspSeqCmd {
     RegWrite(fw::GSP_SEQ_BUF_PAYLOAD_REG_WRITE),
     RegModify(fw::GSP_SEQ_BUF_PAYLOAD_REG_MODIFY),
     RegPoll(fw::GSP_SEQ_BUF_PAYLOAD_REG_POLL),
+    DelayUs(fw::GSP_SEQ_BUF_PAYLOAD_DELAY_US),
     RegStore(fw::GSP_SEQ_BUF_PAYLOAD_REG_STORE),
 }
 
@@ -55,6 +57,9 @@ pub(crate) fn from_fw_cmd(cmd: &fw::GSP_SEQUENCER_BUFFER_CMD) -> Result<Self> {
             fw::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_POLL => {
                 Ok(GspSeqCmd::RegPoll(unsafe { cmd.payload.regPoll }))
             }
+            fw::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_DELAY_US => {
+                Ok(GspSeqCmd::DelayUs(unsafe { cmd.payload.delayUs }))
+            }
             fw::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_STORE => {
                 Ok(GspSeqCmd::RegStore(unsafe { cmd.payload.regStore }))
             }
@@ -85,6 +90,7 @@ pub(crate) fn size_bytes(&self) -> usize {
                 opcode_size + size_of::<fw::GSP_SEQ_BUF_PAYLOAD_REG_MODIFY>()
             }
             GspSeqCmd::RegPoll(_) => opcode_size + size_of::<fw::GSP_SEQ_BUF_PAYLOAD_REG_POLL>(),
+            GspSeqCmd::DelayUs(_) => opcode_size + size_of::<fw::GSP_SEQ_BUF_PAYLOAD_DELAY_US>(),
             GspSeqCmd::RegStore(_) => opcode_size + size_of::<fw::GSP_SEQ_BUF_PAYLOAD_REG_STORE>(),
         }
     }
@@ -177,6 +183,21 @@ fn run(&self, sequencer: &GspSequencer<'_>) -> Result {
     }
 }
 
+impl GspSeqCmdRunner for fw::GSP_SEQ_BUF_PAYLOAD_DELAY_US {
+    fn run(&self, sequencer: &GspSequencer<'_>) -> Result {
+        dev_dbg!(sequencer.dev, "DelayUs: val=0x{:x}\n", self.val);
+        // SAFETY: `usleep_range_state` is safe to call with any parameter.
+        unsafe {
+            bindings::usleep_range_state(
+                self.val as usize,
+                self.val as usize,
+                bindings::TASK_UNINTERRUPTIBLE as u32,
+            )
+        };
+        Ok(())
+    }
+}
+
 impl GspSeqCmdRunner for fw::GSP_SEQ_BUF_PAYLOAD_REG_STORE {
     fn run(&self, sequencer: &GspSequencer<'_>) -> Result {
         let addr = self.addr as usize;
@@ -202,6 +223,7 @@ fn run(&self, seq: &GspSequencer<'_>) -> Result {
             GspSeqCmd::RegWrite(cmd) => cmd.run(seq),
             GspSeqCmd::RegModify(cmd) => cmd.run(seq),
             GspSeqCmd::RegPoll(cmd) => cmd.run(seq),
+            GspSeqCmd::DelayUs(cmd) => cmd.run(seq),
             GspSeqCmd::RegStore(cmd) => cmd.run(seq),
         }
     }
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 10/17] nova-core: sequencer: Implement basic core operations
  2025-08-29 17:32 [PATCH 00/17] nova-core: Complete GSP boot and begin RPC communication Joel Fernandes
                   ` (8 preceding siblings ...)
  2025-08-29 17:32 ` [PATCH 09/17] nova-core: sequencer: Add delay opcode support Joel Fernandes
@ 2025-08-29 17:32 ` Joel Fernandes
  2025-08-29 17:32 ` [PATCH 11/17] nova-core: sequencer: Implement core resume operation Joel Fernandes
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: Joel Fernandes @ 2025-08-29 17:32 UTC (permalink / raw)
  To: linux-kernel, dri-devel, dakr, acourbot
  Cc: Alistair Popple, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	bjorn3_gh, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, David Airlie, Simona Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, John Hubbard, Joel Fernandes,
	Timur Tabi, joel, nouveau, rust-for-linux

These opcodes implement various falcon-related boot operations: reset,
start, wait-for-halt.

Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
---
 drivers/gpu/nova-core/gsp/sequencer.rs | 27 ++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/drivers/gpu/nova-core/gsp/sequencer.rs b/drivers/gpu/nova-core/gsp/sequencer.rs
index 803956a74c8c..826c06041e41 100644
--- a/drivers/gpu/nova-core/gsp/sequencer.rs
+++ b/drivers/gpu/nova-core/gsp/sequencer.rs
@@ -40,6 +40,9 @@ pub(crate) enum GspSeqCmd {
     RegPoll(fw::GSP_SEQ_BUF_PAYLOAD_REG_POLL),
     DelayUs(fw::GSP_SEQ_BUF_PAYLOAD_DELAY_US),
     RegStore(fw::GSP_SEQ_BUF_PAYLOAD_REG_STORE),
+    CoreReset,
+    CoreStart,
+    CoreWaitForHalt,
 }
 
 impl GspSeqCmd {
@@ -63,6 +66,11 @@ pub(crate) fn from_fw_cmd(cmd: &fw::GSP_SEQUENCER_BUFFER_CMD) -> Result<Self> {
             fw::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_STORE => {
                 Ok(GspSeqCmd::RegStore(unsafe { cmd.payload.regStore }))
             }
+            fw::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_RESET => Ok(GspSeqCmd::CoreReset),
+            fw::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_START => Ok(GspSeqCmd::CoreStart),
+            fw::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_WAIT_FOR_HALT => {
+                Ok(GspSeqCmd::CoreWaitForHalt)
+            }
             _ => Err(EINVAL),
         }
     }
@@ -84,6 +92,9 @@ pub(crate) fn new(data: &[u8], dev: &device::Device<device::Bound>) -> Result<Se
     pub(crate) fn size_bytes(&self) -> usize {
         let opcode_size = size_of::<fw::GSP_SEQ_BUF_OPCODE>();
         match self {
+            // Each simple command type just adds 4 bytes (opcode_size) for the header
+            GspSeqCmd::CoreReset | GspSeqCmd::CoreStart | GspSeqCmd::CoreWaitForHalt => opcode_size,
+
             // For commands with payloads, add the payload size in bytes
             GspSeqCmd::RegWrite(_) => opcode_size + size_of::<fw::GSP_SEQ_BUF_PAYLOAD_REG_WRITE>(),
             GspSeqCmd::RegModify(_) => {
@@ -225,6 +236,22 @@ fn run(&self, seq: &GspSequencer<'_>) -> Result {
             GspSeqCmd::RegPoll(cmd) => cmd.run(seq),
             GspSeqCmd::DelayUs(cmd) => cmd.run(seq),
             GspSeqCmd::RegStore(cmd) => cmd.run(seq),
+            GspSeqCmd::CoreReset => {
+                dev_dbg!(seq.dev, "CoreReset\n");
+                seq.gsp_falcon.reset(seq.bar)?;
+                seq.gsp_falcon.dma_reset(seq.bar);
+                Ok(())
+            }
+            GspSeqCmd::CoreStart => {
+                dev_dbg!(seq.dev, "CoreStart\n");
+                seq.gsp_falcon.start(seq.bar)?;
+                Ok(())
+            }
+            GspSeqCmd::CoreWaitForHalt => {
+                dev_dbg!(seq.dev, "CoreWaitForHalt\n");
+                seq.gsp_falcon.wait_till_halted(seq.bar)?;
+                Ok(())
+            }
         }
     }
 }
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 11/17] nova-core: sequencer: Implement core resume operation
  2025-08-29 17:32 [PATCH 00/17] nova-core: Complete GSP boot and begin RPC communication Joel Fernandes
                   ` (9 preceding siblings ...)
  2025-08-29 17:32 ` [PATCH 10/17] nova-core: sequencer: Implement basic core operations Joel Fernandes
@ 2025-08-29 17:32 ` Joel Fernandes
  2025-08-29 17:32 ` [PATCH 12/17] nova-core: clear MBOX0 before waiting for scrubber completion Joel Fernandes
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: Joel Fernandes @ 2025-08-29 17:32 UTC (permalink / raw)
  To: linux-kernel, dri-devel, dakr, acourbot
  Cc: Alistair Popple, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	bjorn3_gh, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, David Airlie, Simona Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, John Hubbard, Joel Fernandes,
	Timur Tabi, joel, nouveau, rust-for-linux

Implement core resume operation. This is the last step of the sequencer
resulting in resume of the GSP and proceeding to INIT_DONE stage of GSP
boot.

Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
---
 drivers/gpu/nova-core/falcon/gsp.rs    |  1 -
 drivers/gpu/nova-core/gsp/sequencer.rs | 47 ++++++++++++++++++++++++--
 drivers/gpu/nova-core/nvfw.rs          |  1 -
 3 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/nova-core/falcon/gsp.rs b/drivers/gpu/nova-core/falcon/gsp.rs
index 58478ada6d3e..c9ab375fd8a1 100644
--- a/drivers/gpu/nova-core/falcon/gsp.rs
+++ b/drivers/gpu/nova-core/falcon/gsp.rs
@@ -35,7 +35,6 @@ pub(crate) fn clear_swgen0_intr(&self, bar: &Bar0) {
     }
 
     /// Function to check if GSP reload/resume has completed during the boot process.
-    #[expect(dead_code)]
     pub(crate) fn check_reload_completed(&self, bar: &Bar0, timeout: Delta) -> Result<bool> {
         wait_on(timeout, || {
             let val = regs::NV_PGC6_BSI_SECURE_SCRATCH_14::read(bar);
diff --git a/drivers/gpu/nova-core/gsp/sequencer.rs b/drivers/gpu/nova-core/gsp/sequencer.rs
index 826c06041e41..cb21c060e09b 100644
--- a/drivers/gpu/nova-core/gsp/sequencer.rs
+++ b/drivers/gpu/nova-core/gsp/sequencer.rs
@@ -43,6 +43,7 @@ pub(crate) enum GspSeqCmd {
     CoreReset,
     CoreStart,
     CoreWaitForHalt,
+    CoreResume,
 }
 
 impl GspSeqCmd {
@@ -71,6 +72,7 @@ pub(crate) fn from_fw_cmd(cmd: &fw::GSP_SEQUENCER_BUFFER_CMD) -> Result<Self> {
             fw::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_WAIT_FOR_HALT => {
                 Ok(GspSeqCmd::CoreWaitForHalt)
             }
+            fw::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_RESUME => Ok(GspSeqCmd::CoreResume),
             _ => Err(EINVAL),
         }
     }
@@ -93,7 +95,10 @@ pub(crate) fn size_bytes(&self) -> usize {
         let opcode_size = size_of::<fw::GSP_SEQ_BUF_OPCODE>();
         match self {
             // Each simple command type just adds 4 bytes (opcode_size) for the header
-            GspSeqCmd::CoreReset | GspSeqCmd::CoreStart | GspSeqCmd::CoreWaitForHalt => opcode_size,
+            GspSeqCmd::CoreReset
+            | GspSeqCmd::CoreStart
+            | GspSeqCmd::CoreWaitForHalt
+            | GspSeqCmd::CoreResume => opcode_size,
 
             // For commands with payloads, add the payload size in bytes
             GspSeqCmd::RegWrite(_) => opcode_size + size_of::<fw::GSP_SEQ_BUF_PAYLOAD_REG_WRITE>(),
@@ -107,7 +112,6 @@ pub(crate) fn size_bytes(&self) -> usize {
     }
 }
 
-#[expect(dead_code)]
 pub(crate) struct GspSequencer<'a> {
     pub seq_info: GspSequencerInfo<'a>,
     pub bar: &'a Bar0,
@@ -252,6 +256,45 @@ fn run(&self, seq: &GspSequencer<'_>) -> Result {
                 seq.gsp_falcon.wait_till_halted(seq.bar)?;
                 Ok(())
             }
+            GspSeqCmd::CoreResume => {
+                dev_dbg!(seq.dev, "CoreResume\n");
+                // At this point, 'SEC2-RTOS' has been loaded into SEC2 by the sequencer
+                // but neither SEC2-RTOS nor GSP-RM is running yet. This part of the
+                // sequencer will start both.
+
+                // First prepare the GSP for resume.
+                seq.gsp_falcon.reset(seq.bar)?;
+                seq.gsp_falcon.write_mailboxes(
+                    seq.bar,
+                    Some(seq.libos_dma_handle as u32),
+                    Some((seq.libos_dma_handle >> 32) as u32),
+                )?;
+
+                // Now start the SEC2, this will resume GSP-RM on the GSP.
+                seq.sec2_falcon.start(seq.bar)?;
+
+                // Check if GSP-RM resumed.
+                seq.gsp_falcon
+                    .check_reload_completed(seq.bar, Delta::from_secs(2))?;
+
+                // Check for any errors in the SEC2 mailbox registers.
+                let mbox0 = seq.sec2_falcon.read_mailbox0(seq.bar)?;
+                if mbox0 != 0 {
+                    dev_err!(seq.dev, "Sequencer: sec2 errors: {:?}\n", mbox0);
+                    return Err(EIO);
+                }
+
+                // Write the OS version to the GSP falcon.
+                seq.gsp_falcon
+                    .write_os_version(seq.bar, seq.fw.gsp_bootloader.app_version)?;
+
+                // Check if the RISC-V core is active, return error if not
+                if !seq.gsp_falcon.is_riscv_active(seq.bar)? {
+                    dev_err!(seq.dev, "Sequencer: RISC-V core is not active\n");
+                    return Err(EIO);
+                }
+                Ok(())
+            }
         }
     }
 }
diff --git a/drivers/gpu/nova-core/nvfw.rs b/drivers/gpu/nova-core/nvfw.rs
index 0b44a922fe5d..39e5f3d5b432 100644
--- a/drivers/gpu/nova-core/nvfw.rs
+++ b/drivers/gpu/nova-core/nvfw.rs
@@ -41,7 +41,6 @@ pub(crate) struct LibosParams {
 /// addresses of the GSP bootloader and firmware.
 pub(crate) use r570_144::GspFwWprMeta;
 
-#[expect(unused_imports)]
 pub(crate) use r570_144::{
     rpc_run_cpu_sequencer_v17_00,
     // Core GSP structures
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 12/17] nova-core: clear MBOX0 before waiting for scrubber completion
  2025-08-29 17:32 [PATCH 00/17] nova-core: Complete GSP boot and begin RPC communication Joel Fernandes
                   ` (10 preceding siblings ...)
  2025-08-29 17:32 ` [PATCH 11/17] nova-core: sequencer: Implement core resume operation Joel Fernandes
@ 2025-08-29 17:32 ` Joel Fernandes
  2025-08-29 17:32 ` [PATCH 13/17] nova-core: Ada: basic GPU identification Joel Fernandes
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: Joel Fernandes @ 2025-08-29 17:32 UTC (permalink / raw)
  To: linux-kernel, dri-devel, dakr, acourbot
  Cc: Alistair Popple, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	bjorn3_gh, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, David Airlie, Simona Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, John Hubbard, Joel Fernandes,
	Timur Tabi, joel, nouveau, rust-for-linux

From: John Hubbard <jhubbard@nvidia.com>

Otherwise, you'll never reach Riscv==true, much less GSP's INIT_DONE
message.

This is how Nouveau does it.

Signed-off-by: John Hubbard <jhubbard@nvidia.com>
---
 drivers/gpu/nova-core/falcon.rs | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
index 7fbf909cae08..05bde1f161ea 100644
--- a/drivers/gpu/nova-core/falcon.rs
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -385,7 +385,11 @@ pub(crate) fn dma_reset(&self, bar: &Bar0) {
 
     /// Wait for memory scrubbing to complete.
     fn reset_wait_mem_scrubbing(&self, bar: &Bar0) -> Result {
-        // TIMEOUT: memory scrubbing should complete in less than 20ms.
+        // Clear MAILBOX0 before waiting for memory scrubbing
+        regs::NV_PFALCON_FALCON_MAILBOX0::default()
+            .set_value(0)
+            .write(bar, &E::ID);
+
         util::wait_on(Delta::from_millis(20), || {
             if regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID).mem_scrubbing_done() {
                 Some(())
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 13/17] nova-core: Ada: basic GPU identification
  2025-08-29 17:32 [PATCH 00/17] nova-core: Complete GSP boot and begin RPC communication Joel Fernandes
                   ` (11 preceding siblings ...)
  2025-08-29 17:32 ` [PATCH 12/17] nova-core: clear MBOX0 before waiting for scrubber completion Joel Fernandes
@ 2025-08-29 17:32 ` Joel Fernandes
  2025-08-29 17:32 ` [PATCH 14/17] nova-core: remove an unnecessary register read: HWCFG1 Joel Fernandes
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: Joel Fernandes @ 2025-08-29 17:32 UTC (permalink / raw)
  To: linux-kernel, dri-devel, dakr, acourbot
  Cc: Alistair Popple, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	bjorn3_gh, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, David Airlie, Simona Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, John Hubbard, Joel Fernandes,
	Timur Tabi, joel, nouveau, rust-for-linux

From: John Hubbard <jhubbard@nvidia.com>

...which is sufficient to make Ada GPUs work, because they use the
pre-existing Ampere GPU code, unmodified.

Tested on AD102 (RTX 6000 Ada).

Signed-off-by: John Hubbard <jhubbard@nvidia.com>
---
 drivers/gpu/nova-core/falcon/hal.rs | 2 +-
 drivers/gpu/nova-core/firmware.rs   | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/nova-core/falcon/hal.rs b/drivers/gpu/nova-core/falcon/hal.rs
index b233bc365882..f061f67f1072 100644
--- a/drivers/gpu/nova-core/falcon/hal.rs
+++ b/drivers/gpu/nova-core/falcon/hal.rs
@@ -44,7 +44,7 @@ pub(super) fn falcon_hal<E: FalconEngine + 'static>(
     use Chipset::*;
 
     let hal = match chipset {
-        GA102 | GA103 | GA104 | GA106 | GA107 => {
+        GA102 | GA103 | GA104 | GA106 | GA107 | AD102 | AD103 | AD104 | AD106 | AD107 => {
             KBox::new(ga102::Ga102::<E>::new(), GFP_KERNEL)? as KBox<dyn FalconHal<E>>
         }
         _ => return Err(ENOTSUPP),
diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs
index d35f1affaa28..4da3c94f50d0 100644
--- a/drivers/gpu/nova-core/firmware.rs
+++ b/drivers/gpu/nova-core/firmware.rs
@@ -153,6 +153,7 @@ pub(crate) fn new(
 
         let gsp_sigs_section = match chipset.arch() {
             Architecture::Ampere => ".fwsignature_ga10x",
+            Architecture::Ada => ".fwsignature_ad10x",
             _ => return Err(ENOTSUPP),
         };
         let gsp_sigs = elf::elf64_section(gsp_fw.data(), gsp_sigs_section)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 14/17] nova-core: remove an unnecessary register read: HWCFG1
  2025-08-29 17:32 [PATCH 00/17] nova-core: Complete GSP boot and begin RPC communication Joel Fernandes
                   ` (12 preceding siblings ...)
  2025-08-29 17:32 ` [PATCH 13/17] nova-core: Ada: basic GPU identification Joel Fernandes
@ 2025-08-29 17:32 ` Joel Fernandes
  2025-08-29 17:32 ` [PATCH 15/17] nova-core: remove unnecessary need_riscv, bar parameters Joel Fernandes
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: Joel Fernandes @ 2025-08-29 17:32 UTC (permalink / raw)
  To: linux-kernel, dri-devel, dakr, acourbot
  Cc: Alistair Popple, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	bjorn3_gh, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, David Airlie, Simona Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, John Hubbard, Joel Fernandes,
	Timur Tabi, joel, nouveau, rust-for-linux

From: John Hubbard <jhubbard@nvidia.com>

This register read is not required in order to bring up any of the GPUs,
and it is read too early on Hopper/Blackwell+ GPUs anyway. So just stop
doing this.

Signed-off-by: John Hubbard <jhubbard@nvidia.com>
---
 drivers/gpu/nova-core/falcon.rs | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
index 05bde1f161ea..023f9b575a5d 100644
--- a/drivers/gpu/nova-core/falcon.rs
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -355,11 +355,6 @@ pub(crate) fn new(
         bar: &Bar0,
         need_riscv: bool,
     ) -> Result<Self> {
-        let hwcfg1 = regs::NV_PFALCON_FALCON_HWCFG1::read(bar, &E::ID);
-        // Check that the revision and security model contain valid values.
-        let _ = hwcfg1.core_rev()?;
-        let _ = hwcfg1.security_model()?;
-
         if need_riscv {
             let hwcfg2 = regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID);
             if !hwcfg2.riscv() {
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 15/17] nova-core: remove unnecessary need_riscv, bar parameters
  2025-08-29 17:32 [PATCH 00/17] nova-core: Complete GSP boot and begin RPC communication Joel Fernandes
                   ` (13 preceding siblings ...)
  2025-08-29 17:32 ` [PATCH 14/17] nova-core: remove an unnecessary register read: HWCFG1 Joel Fernandes
@ 2025-08-29 17:32 ` Joel Fernandes
  2025-08-29 17:32 ` [PATCH 16/17] gpu: nova-core: gsp: Wait for gsp initialisation to complete Joel Fernandes
  2025-08-29 17:32 ` [PATCH 17/17] gpu: nova-core: Add get_gsp_info() command Joel Fernandes
  16 siblings, 0 replies; 20+ messages in thread
From: Joel Fernandes @ 2025-08-29 17:32 UTC (permalink / raw)
  To: linux-kernel, dri-devel, dakr, acourbot
  Cc: Alistair Popple, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	bjorn3_gh, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, David Airlie, Simona Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, John Hubbard, Joel Fernandes,
	Timur Tabi, joel, nouveau, rust-for-linux

From: John Hubbard <jhubbard@nvidia.com>

The need_riscv parameter and its associated RISCV validation logic are
are actually unnecessary for correct operation. Remove it, along with
the now-unused bar parameter as well.

Signed-off-by: John Hubbard <jhubbard@nvidia.com>
---
 drivers/gpu/nova-core/falcon.rs | 21 +--------------------
 drivers/gpu/nova-core/gpu.rs    |  9 ++-------
 2 files changed, 3 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
index 023f9b575a5d..938f25b556a8 100644
--- a/drivers/gpu/nova-core/falcon.rs
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -346,26 +346,7 @@ pub(crate) struct Falcon<E: FalconEngine> {
 
 impl<E: FalconEngine + 'static> Falcon<E> {
     /// Create a new falcon instance.
-    ///
-    /// `need_riscv` is set to `true` if the caller expects the falcon to be a dual falcon/riscv
-    /// controller.
-    pub(crate) fn new(
-        dev: &device::Device,
-        chipset: Chipset,
-        bar: &Bar0,
-        need_riscv: bool,
-    ) -> Result<Self> {
-        if need_riscv {
-            let hwcfg2 = regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID);
-            if !hwcfg2.riscv() {
-                dev_err!(
-                    dev,
-                    "riscv support requested on a controller that does not support it\n"
-                );
-                return Err(EINVAL);
-            }
-        }
-
+    pub(crate) fn new(dev: &device::Device, chipset: Chipset) -> Result<Self> {
         Ok(Self {
             hal: hal::falcon_hal(chipset)?,
             dev: dev.into(),
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index bf670f6b6773..c2a9cb32837f 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -287,15 +287,10 @@ pub(crate) fn new(
 
         let sysmem_flush = SysmemFlush::register(pdev.as_ref(), bar, spec.chipset)?;
 
-        let gsp_falcon = Falcon::<Gsp>::new(
-            pdev.as_ref(),
-            spec.chipset,
-            bar,
-            spec.chipset > Chipset::GA100,
-        )?;
+        let gsp_falcon = Falcon::<Gsp>::new(pdev.as_ref(), spec.chipset)?;
         gsp_falcon.clear_swgen0_intr(bar);
 
-        let sec2_falcon = Falcon::<Sec2>::new(pdev.as_ref(), spec.chipset, bar, true)?;
+        let sec2_falcon = Falcon::<Sec2>::new(pdev.as_ref(), spec.chipset)?;
 
         let fw = Firmware::new(
             pdev.as_ref(),
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 16/17] gpu: nova-core: gsp: Wait for gsp initialisation to complete
  2025-08-29 17:32 [PATCH 00/17] nova-core: Complete GSP boot and begin RPC communication Joel Fernandes
                   ` (14 preceding siblings ...)
  2025-08-29 17:32 ` [PATCH 15/17] nova-core: remove unnecessary need_riscv, bar parameters Joel Fernandes
@ 2025-08-29 17:32 ` Joel Fernandes
  2025-08-29 17:32 ` [PATCH 17/17] gpu: nova-core: Add get_gsp_info() command Joel Fernandes
  16 siblings, 0 replies; 20+ messages in thread
From: Joel Fernandes @ 2025-08-29 17:32 UTC (permalink / raw)
  To: linux-kernel, dri-devel, dakr, acourbot
  Cc: Alistair Popple, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	bjorn3_gh, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, David Airlie, Simona Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, John Hubbard, Joel Fernandes,
	Timur Tabi, joel, nouveau, rust-for-linux

From: Alistair Popple <apopple@nvidia.com>

This adds the GSP init done command to wait for GSP initialisation
to complete. Once this command has been received the GSP is fully
operational and will respond properly to normal RPC commands.

Co-developed-by: Joel Fernandes <joelagnelf@nvidia.com>
Signed-off-by: Alistair Popple <apopple@nvidia.com>
---
 drivers/gpu/nova-core/gpu.rs          |  3 +++
 drivers/gpu/nova-core/gsp/commands.rs | 34 +++++++++++++++++++++++++--
 2 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index c2a9cb32837f..023bafc85f58 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -10,6 +10,7 @@
 use crate::firmware::{Firmware, FIRMWARE_VERSION};
 use crate::gfw;
 use crate::gsp;
+use crate::gsp::commands::gsp_init_done;
 use crate::regs;
 use crate::util;
 use crate::vbios::Vbios;
@@ -375,6 +376,8 @@ pub(crate) fn new(
             Delta::from_secs(10),
         )?;
 
+        gsp_init_done(&mut libos.cmdq, Delta::from_secs(10))?;
+
         Ok(pin_init!(Self {
             spec,
             bar: devres_bar,
diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
index 12ea8cdec21d..9f858aedf853 100644
--- a/drivers/gpu/nova-core/gsp/commands.rs
+++ b/drivers/gpu/nova-core/gsp/commands.rs
@@ -8,13 +8,15 @@
 use kernel::device;
 use kernel::pci;
 use kernel::prelude::*;
+use kernel::time::Delta;
 use kernel::transmute::{AsBytes, FromBytes};
 
 use crate::driver::Bar0;
-use crate::gsp::cmdq::GspCommandToGsp;
-use crate::gsp::cmdq::GspCmdq;
+use crate::gsp::cmdq::{GspCommandToGsp, GspMessageFromGsp};
+use crate::gsp::GspCmdq;
 use crate::gsp::GSP_PAGE_SIZE;
 use crate::nvfw::{
+    NV_VGPU_MSG_EVENT_GSP_INIT_DONE,
     NV_VGPU_MSG_FUNCTION_SET_REGISTRY,
     NV_VGPU_MSG_FUNCTION_GSP_SET_SYSTEM_INFO,
     GspSystemInfo,
@@ -32,6 +34,34 @@ unsafe impl AsBytes for GspSystemInfo {}
 //         that is not a problem because they are not used outside the kernel.
 unsafe impl FromBytes for GspSystemInfo {}
 
+struct GspInitDone {}
+impl GspMessageFromGsp for GspInitDone {
+    const FUNCTION: u32 = NV_VGPU_MSG_EVENT_GSP_INIT_DONE;
+}
+
+pub(crate) fn gsp_init_done(cmdq: &mut GspCmdq, timeout: Delta) -> Result {
+    loop {
+        cmdq.wait_for_msg_from_gsp(timeout)?;
+        let msg = loop {
+            match cmdq.receive_msg_from_gsp() {
+                Ok(x) => break Ok(x),
+                Err(EAGAIN) => continue,
+                Err(x) => break Err(x),
+            };
+        }?;
+
+        let init_done = msg.try_as::<GspInitDone>().map(|_| ());
+
+        msg.ack()?;
+
+        match init_done {
+            Ok(()) => break Ok(()),
+            Err(ERANGE) => continue,
+            Err(e) => break Err(e),
+        };
+    }
+}
+
 const GSP_REGISTRY_NUM_ENTRIES: usize = 2;
 struct RegistryEntry {
     key: &'static str,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 17/17] gpu: nova-core: Add get_gsp_info() command
  2025-08-29 17:32 [PATCH 00/17] nova-core: Complete GSP boot and begin RPC communication Joel Fernandes
                   ` (15 preceding siblings ...)
  2025-08-29 17:32 ` [PATCH 16/17] gpu: nova-core: gsp: Wait for gsp initialisation to complete Joel Fernandes
@ 2025-08-29 17:32 ` Joel Fernandes
  16 siblings, 0 replies; 20+ messages in thread
From: Joel Fernandes @ 2025-08-29 17:32 UTC (permalink / raw)
  To: linux-kernel, dri-devel, dakr, acourbot
  Cc: Alistair Popple, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	bjorn3_gh, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, David Airlie, Simona Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, John Hubbard, Joel Fernandes,
	Timur Tabi, joel, nouveau, rust-for-linux

From: Alistair Popple <apopple@nvidia.com>

Introduce the get_gsp_info() command. This is a basic command which is
sent to the GSP to get some information about the GPU. In particular
it gets the model number of the GPU which is printed to the kernel log.
This proves that the GSP is fully initialised and that the command queue
is functional.

It also serves to demonstrate how interactions and data from the GSP
will be handled. GSP specific data structures will not be used outside
of the GSP command parsing layer. Instead data will be converted to
Nova specific structures (in this case the GspStaticConfigInfo struct)
for consumption by the rest of the driver. This ensures the rest of the
driver is isolated from any changes that may occur to GSP interaction.

Signed-off-by: Alistair Popple <apopple@nvidia.com>
---
 drivers/gpu/nova-core/gpu.rs                  |   8 +-
 drivers/gpu/nova-core/gsp/commands.rs         |  49 ++++++
 drivers/gpu/nova-core/nvfw.rs                 |   2 +
 .../gpu/nova-core/nvfw/r570_144_bindings.rs   | 163 ++++++++++++++++++
 drivers/gpu/nova-core/util.rs                 |  15 ++
 5 files changed, 236 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index 023bafc85f58..7aeecdb0dd28 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -10,7 +10,7 @@
 use crate::firmware::{Firmware, FIRMWARE_VERSION};
 use crate::gfw;
 use crate::gsp;
-use crate::gsp::commands::gsp_init_done;
+use crate::gsp::commands::{get_gsp_info, gsp_init_done};
 use crate::regs;
 use crate::util;
 use crate::vbios::Vbios;
@@ -377,6 +377,12 @@ pub(crate) fn new(
         )?;
 
         gsp_init_done(&mut libos.cmdq, Delta::from_secs(10))?;
+        let info = get_gsp_info(&mut libos.cmdq, bar)?;
+        dev_info!(
+            pdev.as_ref(),
+            "GPU name: {}\n",
+            util::str_from_null_terminated(&info.gpu_name)
+        );
 
         Ok(pin_init!(Self {
             spec,
diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
index 9f858aedf853..3491f8edef0a 100644
--- a/drivers/gpu/nova-core/gsp/commands.rs
+++ b/drivers/gpu/nova-core/gsp/commands.rs
@@ -19,6 +19,8 @@
     NV_VGPU_MSG_EVENT_GSP_INIT_DONE,
     NV_VGPU_MSG_FUNCTION_SET_REGISTRY,
     NV_VGPU_MSG_FUNCTION_GSP_SET_SYSTEM_INFO,
+    NV_VGPU_MSG_FUNCTION_GET_GSP_STATIC_INFO,
+    GspStaticConfigInfo_t,
     GspSystemInfo,
     PACKED_REGISTRY_TABLE,
     PACKED_REGISTRY_ENTRY,
@@ -34,6 +36,12 @@ unsafe impl AsBytes for GspSystemInfo {}
 //         that is not a problem because they are not used outside the kernel.
 unsafe impl FromBytes for GspSystemInfo {}
 
+unsafe impl FromBytes for GspStaticConfigInfo_t {}
+
+pub(crate) struct GspStaticConfigInfo {
+    pub gpu_name: [u8; 40],
+}
+
 struct GspInitDone {}
 impl GspMessageFromGsp for GspInitDone {
     const FUNCTION: u32 = NV_VGPU_MSG_EVENT_GSP_INIT_DONE;
@@ -62,6 +70,47 @@ pub(crate) fn gsp_init_done(cmdq: &mut GspCmdq, timeout: Delta) -> Result {
     }
 }
 
+impl GspMessageFromGsp for GspStaticConfigInfo_t {
+    const FUNCTION: u32 = NV_VGPU_MSG_FUNCTION_GET_GSP_STATIC_INFO;
+}
+
+impl GspCommandToGsp for GspStaticConfigInfo_t {
+    const FUNCTION: u32 = NV_VGPU_MSG_FUNCTION_GET_GSP_STATIC_INFO;
+}
+
+pub(crate) fn get_gsp_info(cmdq: &mut GspCmdq, bar: &Bar0) -> Result<GspStaticConfigInfo> {
+    let mut msg = cmdq.alloc_gsp_queue_command(size_of::<GspStaticConfigInfo_t>())?;
+    msg.try_as::<GspStaticConfigInfo_t>();
+    msg.send_to_gsp(bar)?;
+    cmdq.wait_for_msg_from_gsp(Delta::from_secs(5))?;
+    let msg = cmdq.receive_msg_from_gsp()?;
+    let info = msg.try_as::<GspStaticConfigInfo_t>().map(|(x, _)| x)?;
+
+    let gpu_name_str = info
+        .gpuNameString
+        .get(
+            0..=info
+                .gpuNameString
+                .iter()
+                .position(|&b| b == 0)
+                .unwrap_or(info.gpuNameString.len() - 1),
+        )
+        .and_then(|bytes| CStr::from_bytes_with_nul(bytes).ok())
+        .and_then(|cstr| cstr.to_str().ok())
+        .unwrap_or("invalid utf8");
+
+    let mut gpu_name = [0u8; 40];
+    let bytes = gpu_name_str.as_bytes();
+    let copy_len = core::cmp::min(bytes.len(), gpu_name.len());
+    gpu_name[..copy_len].copy_from_slice(&bytes[..copy_len]);
+    gpu_name[copy_len] = b'\0';
+
+    let config_info = GspStaticConfigInfo { gpu_name };
+
+    msg.ack()?;
+    Ok(config_info)
+}
+
 const GSP_REGISTRY_NUM_ENTRIES: usize = 2;
 struct RegistryEntry {
     key: &'static str,
diff --git a/drivers/gpu/nova-core/nvfw.rs b/drivers/gpu/nova-core/nvfw.rs
index 39e5f3d5b432..d51a697e6c27 100644
--- a/drivers/gpu/nova-core/nvfw.rs
+++ b/drivers/gpu/nova-core/nvfw.rs
@@ -43,6 +43,8 @@ pub(crate) struct LibosParams {
 
 pub(crate) use r570_144::{
     rpc_run_cpu_sequencer_v17_00,
+    GspStaticConfigInfo_t,
+
     // Core GSP structures
     GspSystemInfo,
 
diff --git a/drivers/gpu/nova-core/nvfw/r570_144_bindings.rs b/drivers/gpu/nova-core/nvfw/r570_144_bindings.rs
index 607d99ac2221..4aaa381749ae 100644
--- a/drivers/gpu/nova-core/nvfw/r570_144_bindings.rs
+++ b/drivers/gpu/nova-core/nvfw/r570_144_bindings.rs
@@ -320,6 +320,77 @@ fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
 pub type _bindgen_ty_3 = ffi::c_uint;
 #[repr(C)]
 #[derive(Debug, Default, Copy, Clone)]
+pub struct NV0080_CTRL_GPU_GET_SRIOV_CAPS_PARAMS {
+    pub totalVFs: u32_,
+    pub firstVfOffset: u32_,
+    pub vfFeatureMask: u32_,
+    pub FirstVFBar0Address: u64_,
+    pub FirstVFBar1Address: u64_,
+    pub FirstVFBar2Address: u64_,
+    pub bar0Size: u64_,
+    pub bar1Size: u64_,
+    pub bar2Size: u64_,
+    pub b64bitBar0: u8_,
+    pub b64bitBar1: u8_,
+    pub b64bitBar2: u8_,
+    pub bSriovEnabled: u8_,
+    pub bSriovHeavyEnabled: u8_,
+    pub bEmulateVFBar0TlbInvalidationRegister: u8_,
+    pub bClientRmAllocatedCtxBuffer: u8_,
+    pub bNonPowerOf2ChannelCountSupported: u8_,
+    pub bVfResizableBAR1Supported: u8_,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct NV2080_CTRL_BIOS_GET_SKU_INFO_PARAMS {
+    pub BoardID: u32_,
+    pub chipSKU: [ffi::c_char; 9usize],
+    pub chipSKUMod: [ffi::c_char; 5usize],
+    pub skuConfigVersion: u32_,
+    pub project: [ffi::c_char; 5usize],
+    pub projectSKU: [ffi::c_char; 5usize],
+    pub CDP: [ffi::c_char; 6usize],
+    pub projectSKUMod: [ffi::c_char; 2usize],
+    pub businessCycle: u32_,
+}
+pub type NV2080_CTRL_CMD_FB_GET_FB_REGION_SURFACE_MEM_TYPE_FLAG = [u8_; 17usize];
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct NV2080_CTRL_CMD_FB_GET_FB_REGION_FB_REGION_INFO {
+    pub base: u64_,
+    pub limit: u64_,
+    pub reserved: u64_,
+    pub performance: u32_,
+    pub supportCompressed: u8_,
+    pub supportISO: u8_,
+    pub bProtected: u8_,
+    pub blackList: NV2080_CTRL_CMD_FB_GET_FB_REGION_SURFACE_MEM_TYPE_FLAG,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct NV2080_CTRL_CMD_FB_GET_FB_REGION_INFO_PARAMS {
+    pub numFBRegions: u32_,
+    pub fbRegion: [NV2080_CTRL_CMD_FB_GET_FB_REGION_FB_REGION_INFO; 16usize],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct NV2080_CTRL_GPU_GET_GID_INFO_PARAMS {
+    pub index: u32_,
+    pub flags: u32_,
+    pub length: u32_,
+    pub data: [u8_; 256usize],
+}
+impl Default for NV2080_CTRL_GPU_GET_GID_INFO_PARAMS {
+    fn default() -> Self {
+        let mut s = ::core::mem::MaybeUninit::<Self>::uninit();
+        unsafe {
+            ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+            s.assume_init()
+        }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
 pub struct DOD_METHOD_DATA {
     pub status: u32_,
     pub acpiIdListLen: u32_,
@@ -367,6 +438,19 @@ pub struct ACPI_METHOD_DATA {
 }
 #[repr(C)]
 #[derive(Debug, Default, Copy, Clone)]
+pub struct VIRTUAL_DISPLAY_GET_MAX_RESOLUTION_PARAMS {
+    pub headIndex: u32_,
+    pub maxHResolution: u32_,
+    pub maxVResolution: u32_,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct VIRTUAL_DISPLAY_GET_NUM_HEADS_PARAMS {
+    pub numHeads: u32_,
+    pub maxNumHeads: u32_,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
 pub struct BUSINFO {
     pub deviceID: u16_,
     pub vendorID: u16_,
@@ -395,6 +479,85 @@ pub struct GSP_PCIE_CONFIG_REG {
 }
 #[repr(C)]
 #[derive(Debug, Default, Copy, Clone)]
+pub struct EcidManufacturingInfo {
+    pub ecidLow: u32_,
+    pub ecidHigh: u32_,
+    pub ecidExtended: u32_,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct FW_WPR_LAYOUT_OFFSET {
+    pub nonWprHeapOffset: u64_,
+    pub frtsOffset: u64_,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct GspStaticConfigInfo_t {
+    pub grCapsBits: [u8_; 23usize],
+    pub gidInfo: NV2080_CTRL_GPU_GET_GID_INFO_PARAMS,
+    pub SKUInfo: NV2080_CTRL_BIOS_GET_SKU_INFO_PARAMS,
+    pub fbRegionInfoParams: NV2080_CTRL_CMD_FB_GET_FB_REGION_INFO_PARAMS,
+    pub sriovCaps: NV0080_CTRL_GPU_GET_SRIOV_CAPS_PARAMS,
+    pub sriovMaxGfid: u32_,
+    pub engineCaps: [u32_; 3usize],
+    pub poisonFuseEnabled: u8_,
+    pub fb_length: u64_,
+    pub fbio_mask: u64_,
+    pub fb_bus_width: u32_,
+    pub fb_ram_type: u32_,
+    pub fbp_mask: u64_,
+    pub l2_cache_size: u32_,
+    pub gpuNameString: [u8_; 64usize],
+    pub gpuShortNameString: [u8_; 64usize],
+    pub gpuNameString_Unicode: [u16_; 64usize],
+    pub bGpuInternalSku: u8_,
+    pub bIsQuadroGeneric: u8_,
+    pub bIsQuadroAd: u8_,
+    pub bIsNvidiaNvs: u8_,
+    pub bIsVgx: u8_,
+    pub bGeforceSmb: u8_,
+    pub bIsTitan: u8_,
+    pub bIsTesla: u8_,
+    pub bIsMobile: u8_,
+    pub bIsGc6Rtd3Allowed: u8_,
+    pub bIsGc8Rtd3Allowed: u8_,
+    pub bIsGcOffRtd3Allowed: u8_,
+    pub bIsGcoffLegacyAllowed: u8_,
+    pub bIsMigSupported: u8_,
+    pub RTD3GC6TotalBoardPower: u16_,
+    pub RTD3GC6PerstDelay: u16_,
+    pub bar1PdeBase: u64_,
+    pub bar2PdeBase: u64_,
+    pub bVbiosValid: u8_,
+    pub vbiosSubVendor: u32_,
+    pub vbiosSubDevice: u32_,
+    pub bPageRetirementSupported: u8_,
+    pub bSplitVasBetweenServerClientRm: u8_,
+    pub bClRootportNeedsNosnoopWAR: u8_,
+    pub displaylessMaxHeads: VIRTUAL_DISPLAY_GET_NUM_HEADS_PARAMS,
+    pub displaylessMaxResolution: VIRTUAL_DISPLAY_GET_MAX_RESOLUTION_PARAMS,
+    pub displaylessMaxPixels: u64_,
+    pub hInternalClient: u32_,
+    pub hInternalDevice: u32_,
+    pub hInternalSubdevice: u32_,
+    pub bSelfHostedMode: u8_,
+    pub bAtsSupported: u8_,
+    pub bIsGpuUefi: u8_,
+    pub bIsEfiInit: u8_,
+    pub ecidInfo: [EcidManufacturingInfo; 2usize],
+    pub fwWprLayoutOffset: FW_WPR_LAYOUT_OFFSET,
+}
+impl Default for GspStaticConfigInfo_t {
+    fn default() -> Self {
+        let mut s = ::core::mem::MaybeUninit::<Self>::uninit();
+        unsafe {
+            ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+            s.assume_init()
+        }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
 pub struct GspSystemInfo {
     pub gpuPhysAddr: u64_,
     pub gpuPhysFbAddr: u64_,
diff --git a/drivers/gpu/nova-core/util.rs b/drivers/gpu/nova-core/util.rs
index 76cedf3710d7..1709a5d50e54 100644
--- a/drivers/gpu/nova-core/util.rs
+++ b/drivers/gpu/nova-core/util.rs
@@ -45,3 +45,18 @@ pub(crate) fn wait_on<R, F: Fn() -> Option<R>>(timeout: Delta, cond: F) -> Resul
         }
     }
 }
+
+/// Converts a null-terminated byte array to a string slice.
+///
+/// Returns "invalid" if the bytes are not valid UTF-8 or not null-terminated.
+pub(crate) fn str_from_null_terminated(bytes: &[u8]) -> &str {
+    use kernel::str::CStr;
+
+    // Find the first null byte, then create a slice that includes it
+    bytes
+        .iter()
+        .position(|&b| b == 0)
+        .and_then(|null_pos| CStr::from_bytes_with_nul(&bytes[..=null_pos]).ok())
+        .and_then(|cstr| cstr.to_str().ok())
+        .unwrap_or("invalid")
+}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH 05/17] nova-core: gsp: Add support for checking if GSP reloaded
  2025-08-29 17:32 ` [PATCH 05/17] nova-core: gsp: Add support for checking if GSP reloaded Joel Fernandes
@ 2025-08-29 18:44   ` Timur Tabi
  2025-08-29 22:43     ` Joel Fernandes
  0 siblings, 1 reply; 20+ messages in thread
From: Timur Tabi @ 2025-08-29 18:44 UTC (permalink / raw)
  To: dri-devel@lists.freedesktop.org, Joel Fernandes, dakr@kernel.org,
	linux-kernel@vger.kernel.org, Alexandre Courbot
  Cc: joel@joelfernandes.org, lossin@kernel.org, ojeda@kernel.org,
	boqun.feng@gmail.com, a.hindborg@kernel.org, simona@ffwll.ch,
	tmgross@umich.edu, alex.gaynor@gmail.com, tzimmermann@suse.de,
	mripard@kernel.org, maarten.lankhorst@linux.intel.com,
	nouveau@lists.freedesktop.org, John Hubbard,
	rust-for-linux@vger.kernel.org, bjorn3_gh@protonmail.com,
	airlied@gmail.com, aliceryhl@google.com, gary@garyguo.net,
	Alistair Popple

On Fri, 2025-08-29 at 13:32 -0400, Joel Fernandes wrote:
> +    /// Function to check if GSP reload/resume has completed during the boot process.
> +    #[expect(dead_code)]
> +    pub(crate) fn check_reload_completed(&self, bar: &Bar0, timeout: Delta) -> Result<bool> {

I think this should be renamed to is_reload_completed() and return just bool instead of Result<bool>

> +        wait_on(timeout, || {
> +            let val = regs::NV_PGC6_BSI_SECURE_SCRATCH_14::read(bar);
> +            if val.boot_stage_3_handoff() {
> +                Some(true)
> +            } else {
> +                None
> +            }
> +        })

And if you insist on returning Result<bool>, at least have this return Some(false) or
Some(val.boot_stage_3_handoff()) instead.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 05/17] nova-core: gsp: Add support for checking if GSP reloaded
  2025-08-29 18:44   ` Timur Tabi
@ 2025-08-29 22:43     ` Joel Fernandes
  0 siblings, 0 replies; 20+ messages in thread
From: Joel Fernandes @ 2025-08-29 22:43 UTC (permalink / raw)
  To: Timur Tabi
  Cc: dri-devel@lists.freedesktop.org, dakr@kernel.org,
	linux-kernel@vger.kernel.org, Alexandre Courbot,
	joel@joelfernandes.org, lossin@kernel.org, ojeda@kernel.org,
	boqun.feng@gmail.com, a.hindborg@kernel.org, simona@ffwll.ch,
	tmgross@umich.edu, alex.gaynor@gmail.com, tzimmermann@suse.de,
	mripard@kernel.org, maarten.lankhorst@linux.intel.com,
	nouveau@lists.freedesktop.org, John Hubbard,
	rust-for-linux@vger.kernel.org, bjorn3_gh@protonmail.com,
	airlied@gmail.com, aliceryhl@google.com, gary@garyguo.net,
	Alistair Popple

On Fri, Aug 29, 2025 at 06:44:53PM +0000, Timur Tabi wrote:
> On Fri, 2025-08-29 at 13:32 -0400, Joel Fernandes wrote:
> > +    /// Function to check if GSP reload/resume has completed during the boot process.
> > +    #[expect(dead_code)]
> > +    pub(crate) fn check_reload_completed(&self, bar: &Bar0, timeout: Delta) -> Result<bool> {
> 
> I think this should be renamed to is_reload_completed() and return just bool instead of Result<bool>

This function can return Err(ETIMEDOUT).

> 
> > +        wait_on(timeout, || {
> > +            let val = regs::NV_PGC6_BSI_SECURE_SCRATCH_14::read(bar);
> > +            if val.boot_stage_3_handoff() {
> > +                Some(true)
> > +            } else {
> > +                None
> > +            }
> > +        })
> 
> And if you insist on returning Result<bool>, at least have this return Some(false) or
> Some(val.boot_stage_3_handoff()) instead.

Ok, so basically that means we would return False if a timeout occured.
That's fine with me, I can make that change.

thanks,

 - Joel


^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2025-08-29 22:44 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-29 17:32 [PATCH 00/17] nova-core: Complete GSP boot and begin RPC communication Joel Fernandes
2025-08-29 17:32 ` [PATCH 01/17] nova-core: falcon: Move waiting until halted to a helper Joel Fernandes
2025-08-29 17:32 ` [PATCH 02/17] nova-core: falcon: Move start functionality into separate helper Joel Fernandes
2025-08-29 17:32 ` [PATCH 03/17] nova-core: falcon: Move mbox functionalities into helper Joel Fernandes
2025-08-29 17:32 ` [PATCH 04/17] nova-core: falcon: Move dma_reset functionality " Joel Fernandes
2025-08-29 17:32 ` [PATCH 05/17] nova-core: gsp: Add support for checking if GSP reloaded Joel Fernandes
2025-08-29 18:44   ` Timur Tabi
2025-08-29 22:43     ` Joel Fernandes
2025-08-29 17:32 ` [PATCH 06/17] nova-core: Add bindings required by GSP sequencer Joel Fernandes
2025-08-29 17:32 ` [PATCH 07/17] nova-core: Implement the " Joel Fernandes
2025-08-29 17:32 ` [PATCH 08/17] nova-core: sequencer: Add register opcodes Joel Fernandes
2025-08-29 17:32 ` [PATCH 09/17] nova-core: sequencer: Add delay opcode support Joel Fernandes
2025-08-29 17:32 ` [PATCH 10/17] nova-core: sequencer: Implement basic core operations Joel Fernandes
2025-08-29 17:32 ` [PATCH 11/17] nova-core: sequencer: Implement core resume operation Joel Fernandes
2025-08-29 17:32 ` [PATCH 12/17] nova-core: clear MBOX0 before waiting for scrubber completion Joel Fernandes
2025-08-29 17:32 ` [PATCH 13/17] nova-core: Ada: basic GPU identification Joel Fernandes
2025-08-29 17:32 ` [PATCH 14/17] nova-core: remove an unnecessary register read: HWCFG1 Joel Fernandes
2025-08-29 17:32 ` [PATCH 15/17] nova-core: remove unnecessary need_riscv, bar parameters Joel Fernandes
2025-08-29 17:32 ` [PATCH 16/17] gpu: nova-core: gsp: Wait for gsp initialisation to complete Joel Fernandes
2025-08-29 17:32 ` [PATCH 17/17] gpu: nova-core: Add get_gsp_info() command Joel Fernandes

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).