From: John Hubbard Date: Wed, 3 Jun 2026 07:30:18 +0000 (+0900) Subject: gpu: nova-core: Hopper/Blackwell: add FSP falcon EMEM operations X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6d6c3189f9b2b143efe1f536e8ea8b082e054a01;p=thirdparty%2Fkernel%2Fstable.git gpu: nova-core: Hopper/Blackwell: add FSP falcon EMEM operations 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 Reviewed-by: Eliot Courtney Link: https://patch.msgid.link/20260603-b4-blackwell-v13-1-d9f3a06939e0@nvidia.com Signed-off-by: Alexandre Courbot --- diff --git a/drivers/gpu/nova-core/falcon/fsp.rs b/drivers/gpu/nova-core/falcon/fsp.rs index d9f87262e8b1..0956a75ef7aa 100644 --- a/drivers/gpu/nova-core/falcon/fsp.rs +++ b/drivers/gpu/nova-core/falcon/fsp.rs @@ -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 for Fsp { } impl FalconEngine for Fsp {} + +impl Falcon { + /// 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::(), + 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::(), + 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::(), + 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::()).data(); + chunk.copy_from_slice(&value.to_le_bytes()); + } + + Ok(()) + } +} diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index 2cb1f02f35a4..e602c7860459 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -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 {