]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
gpu: nova-core: Hopper/Blackwell: add FSP falcon EMEM operations
authorJohn Hubbard <jhubbard@nvidia.com>
Wed, 3 Jun 2026 07:30:18 +0000 (16:30 +0900)
committerAlexandre Courbot <acourbot@nvidia.com>
Wed, 3 Jun 2026 13:11:07 +0000 (22:11 +0900)
Add external memory (EMEM) read/write operations to the GPU's FSP falcon
engine. These operations use Falcon PIO (Programmed I/O) to communicate
with the FSP through indirect memory access.

Signed-off-by: John Hubbard <jhubbard@nvidia.com>
Reviewed-by: Eliot Courtney <ecourtney@nvidia.com>
Link: https://patch.msgid.link/20260603-b4-blackwell-v13-1-d9f3a06939e0@nvidia.com
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
drivers/gpu/nova-core/falcon/fsp.rs
drivers/gpu/nova-core/regs.rs

index d9f87262e8b13dc762ab0c2ff4245f7261f5465e..0956a75ef7aa5467c1bb22fdb2147a251b386cf4 100644 (file)
@@ -6,12 +6,26 @@
 //! The FSP falcon handles secure boot and Chain of Trust operations
 //! on Hopper and Blackwell architectures, replacing SEC2's role.
 
-use kernel::io::register::RegisterBase;
+use kernel::{
+    io::{
+        register::{
+            RegisterBase,
+            WithBase, //
+        },
+        Io, //
+    },
+    prelude::*,
+};
 
-use crate::falcon::{
-    FalconEngine,
-    PFalcon2Base,
-    PFalconBase, //
+use crate::{
+    driver::Bar0,
+    falcon::{
+        Falcon,
+        FalconEngine,
+        PFalcon2Base,
+        PFalconBase, //
+    },
+    regs,
 };
 
 /// Type specifying the `Fsp` falcon engine. Cannot be instantiated.
@@ -26,3 +40,59 @@ impl RegisterBase<PFalcon2Base> for Fsp {
 }
 
 impl FalconEngine for Fsp {}
+
+impl Falcon<Fsp> {
+    /// Writes `data` to FSP external memory at offset `0`.
+    ///
+    /// `data` is interpreted as little-endian 32-bit words. Returns `EINVAL`
+    /// if the `data` length is not 4-byte aligned.
+    #[expect(dead_code)]
+    fn write_emem(&mut self, bar: &Bar0, data: &[u8]) -> Result {
+        if data.len() % 4 != 0 {
+            return Err(EINVAL);
+        }
+
+        // Begin a write burst at offset `0`, auto-incrementing on each write.
+        bar.write(
+            WithBase::of::<Fsp>(),
+            regs::NV_PFALCON_FALCON_EMEMC::zeroed().with_aincw(true),
+        );
+
+        for chunk in data.chunks_exact(4) {
+            let value = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
+
+            // Write the next 32-bit `value`; hardware advances the offset.
+            bar.write(
+                WithBase::of::<Fsp>(),
+                regs::NV_PFALCON_FALCON_EMEMD::zeroed().with_data(value),
+            );
+        }
+
+        Ok(())
+    }
+
+    /// Reads FSP external memory from offset `0` into `data`.
+    ///
+    /// `data` is stored as little-endian 32-bit words. Returns `EINVAL` if
+    /// the `data` length is not 4-byte aligned.
+    #[expect(dead_code)]
+    fn read_emem(&mut self, bar: &Bar0, data: &mut [u8]) -> Result {
+        if data.len() % 4 != 0 {
+            return Err(EINVAL);
+        }
+
+        // Begin a read burst at offset `0`, auto-incrementing on each read.
+        bar.write(
+            WithBase::of::<Fsp>(),
+            regs::NV_PFALCON_FALCON_EMEMC::zeroed().with_aincr(true),
+        );
+
+        for chunk in data.chunks_exact_mut(4) {
+            // Read the next 32-bit word; hardware advances the offset.
+            let value = bar.read(regs::NV_PFALCON_FALCON_EMEMD::of::<Fsp>()).data();
+            chunk.copy_from_slice(&value.to_le_bytes());
+        }
+
+        Ok(())
+    }
+}
index 2cb1f02f35a4f730aa821385b4f8215744e3901b..e602c7860459c6bb60665a356fa9b9ac25342716 100644 (file)
@@ -475,6 +475,24 @@ register! {
     pub(crate) NV_PFALCON_FBIF_CTL(u32) @ PFalconBase + 0x00000624 {
         7:7     allow_phys_no_ctx => bool;
     }
+
+    // Falcon EMEM PIO registers (used by FSP on Hopper/Blackwell).
+    // These provide the falcon external memory communication interface.
+
+    pub(crate) NV_PFALCON_FALCON_EMEMC(u32) @ PFalconBase + 0x00000ac0 {
+        /// EMEM byte offset (4-byte aligned) within the block.
+        7:2     offs;
+        /// EMEM block to access.
+        15:8    blk;
+        /// Auto-increment the offset after each write.
+        24:24   aincw => bool;
+        /// Auto-increment the offset after each read.
+        25:25   aincr => bool;
+    }
+
+    pub(crate) NV_PFALCON_FALCON_EMEMD(u32) @ PFalconBase + 0x00000ac4 {
+        31:0    data => u32;
+    }
 }
 
 impl NV_PFALCON_FALCON_DMACTL {