[PATCH RFC v2 5/5] gpu: nova-core: add falcon register definitions and probe code

Alexandre Courbot acourbot at nvidia.com
Tue Mar 4 13:54:01 UTC 2025


This is still very preliminary work, and is mostly designed to show how
register fields can be turned into safe types that force us to handle
invalid values.

Signed-off-by: Alexandre Courbot <acourbot at nvidia.com>
---
 drivers/gpu/nova-core/driver.rs    |   2 +-
 drivers/gpu/nova-core/falcon.rs    | 124 +++++++++++++++++++++++++++++++++++++
 drivers/gpu/nova-core/gpu.rs       |  10 +++
 drivers/gpu/nova-core/nova_core.rs |   1 +
 drivers/gpu/nova-core/regs.rs      | 108 ++++++++++++++++++++++++++++++++
 5 files changed, 244 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs
index 0cd23aa306e4082405f480afc0530a41131485e7..dee5fd22eecb2ce1f4ea765338b0c1b68853b2d3 100644
--- a/drivers/gpu/nova-core/driver.rs
+++ b/drivers/gpu/nova-core/driver.rs
@@ -10,7 +10,7 @@ pub(crate) struct NovaCore {
     pub(crate) gpu: Gpu,
 }
 
-const BAR0_SIZE: usize = 0x9500;
+const BAR0_SIZE: usize = 0x1000000;
 pub(crate) type Bar0 = pci::Bar<BAR0_SIZE>;
 
 kernel::pci_device_table!(
diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
new file mode 100644
index 0000000000000000000000000000000000000000..5f8496ed1f91ccd19c0c7716440cbc795a7a025f
--- /dev/null
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Falcon microprocessor base support
+
+use core::hint::unreachable_unchecked;
+use kernel::devres::Devres;
+use kernel::{pci, prelude::*};
+
+use crate::driver::Bar0;
+use crate::regs::{FalconCpuCtl, FalconHwCfg1};
+
+#[repr(u8)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub(crate) enum FalconCoreRev {
+    Rev1 = 1,
+    Rev2 = 2,
+    Rev3 = 3,
+    Rev4 = 4,
+    Rev5 = 5,
+    Rev6 = 6,
+    Rev7 = 7,
+}
+
+impl TryFrom<u32> for FalconCoreRev {
+    type Error = Error;
+
+    fn try_from(value: u32) -> core::result::Result<Self, Self::Error> {
+        use FalconCoreRev::*;
+
+        let rev = match value {
+            1 => Rev1,
+            2 => Rev2,
+            3 => Rev3,
+            4 => Rev4,
+            5 => Rev5,
+            6 => Rev6,
+            7 => Rev7,
+            _ => return Err(EINVAL),
+        };
+
+        Ok(rev)
+    }
+}
+
+#[repr(u8)]
+#[derive(Debug, Copy, Clone)]
+pub(crate) enum FalconSecurityModel {
+    None = 0,
+    Light = 2,
+    Heavy = 3,
+}
+
+impl TryFrom<u32> for FalconSecurityModel {
+    type Error = Error;
+
+    fn try_from(value: u32) -> core::result::Result<Self, Self::Error> {
+        use FalconSecurityModel::*;
+
+        let sec_model = match value {
+            0 => None,
+            2 => Light,
+            3 => Heavy,
+            _ => return Err(EINVAL),
+        };
+
+        Ok(sec_model)
+    }
+}
+
+#[repr(u8)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub(crate) enum FalconCoreRevSubversion {
+    Subversion0 = 0,
+    Subversion1 = 1,
+    Subversion2 = 2,
+    Subversion3 = 3,
+}
+
+impl From<u32> for FalconCoreRevSubversion {
+    fn from(value: u32) -> Self {
+        use FalconCoreRevSubversion::*;
+
+        match value & 0b11 {
+            0 => Subversion0,
+            1 => Subversion1,
+            2 => Subversion2,
+            3 => Subversion3,
+            // SAFETY: the `0b11` mask limits the possible values to `0..=3`.
+            4..=u32::MAX => unsafe { unreachable_unchecked() },
+        }
+    }
+}
+
+/// Contains the base parameters common to all Falcon instances.
+#[derive(Debug)]
+pub(crate) struct Falcon {
+    /// Base IO address.
+    base: usize,
+}
+
+impl Falcon {
+    pub(crate) fn new(pdev: &pci::Device, bar: &Devres<Bar0>, base: usize) -> Result<Self> {
+        let b = bar.try_access().ok_or(ENXIO)?;
+
+        let hwcfg1 = FalconHwCfg1::read(&b, base);
+        let rev = hwcfg1.core_rev()?;
+        let subver = hwcfg1.core_rev_subversion();
+        let sec_model = hwcfg1.security_model()?;
+
+        dev_info!(
+            pdev.as_ref(),
+            "new falcon: {:?} {:?} {:?}",
+            rev,
+            subver,
+            sec_model
+        );
+
+        Ok(Self { base })
+    }
+
+    pub(crate) fn cpu_ctl(&self, bar: &Bar0) -> FalconCpuCtl {
+        FalconCpuCtl::read(bar, self.base)
+    }
+}
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index 8fa8616c0deccc7297b090fcbe74f3cda5cc9741..8d8b5ee5c9444c4722d1025d4008fc5a8841a247 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -7,6 +7,7 @@
 };
 
 use crate::driver::Bar0;
+use crate::falcon::Falcon;
 use crate::regs;
 use crate::timer::Timer;
 use core::fmt;
@@ -228,6 +229,15 @@ pub(crate) fn new(pdev: &pci::Device, bar: Devres<Bar0>) -> Result<impl PinInit<
 
         let dev = pdev.as_ref().into();
         let timer = Timer::new();
+        let gsp_falcon = Falcon::new(pdev, &bar, regs::FALCON_GSP_BASE)?;
+        let sec2 = Falcon::new(pdev, &bar, regs::FALCON_SEC2_BASE)?;
+        let b = bar.try_access().ok_or(ENXIO)?;
+        dev_info!(
+            pdev.as_ref(),
+            "GSP Falcon CpuCtl: {:?}",
+            gsp_falcon.cpu_ctl(&b)
+        );
+        dev_info!(pdev.as_ref(), "SEC2 Falcon CpuCtl: {:?}", sec2.cpu_ctl(&b));
 
         Ok(pin_init!(Self {
             dev,
diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs
index 891a93ba7656d2aa5e1fa4357d1d84ee3a054942..a5817bda30185d4ec7021f3d3e881cd99230ca94 100644
--- a/drivers/gpu/nova-core/nova_core.rs
+++ b/drivers/gpu/nova-core/nova_core.rs
@@ -3,6 +3,7 @@
 //! Nova Core GPU Driver
 
 mod driver;
+mod falcon;
 mod firmware;
 mod gpu;
 mod regs;
diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs
index 35bbd3c0b58972de3a2478ef20f93f31c69940e7..12a889a785e0713c6041d50284c211352a39303b 100644
--- a/drivers/gpu/nova-core/regs.rs
+++ b/drivers/gpu/nova-core/regs.rs
@@ -3,6 +3,7 @@
 use core::{fmt::Debug, marker::PhantomData, ops::Deref};
 
 use crate::driver::Bar0;
+use crate::falcon::{FalconCoreRev, FalconCoreRevSubversion, FalconSecurityModel};
 use crate::gpu::Chipset;
 
 pub(crate) struct Builder<T>(T, PhantomData<T>);
@@ -180,3 +181,110 @@ impl Builder<$name> {
 nv_reg!(PtimerTime1 at 0x00009410;
     31:0    hi as (u32), "high 32 bits of the timer"
 );
+
+pub(crate) const FALCON_GSP_BASE: usize = 0x00110000;
+pub(crate) const FALCON_SEC2_BASE: usize = 0x00840000;
+
+nv_reg!(FalconIrqsClr at +0x00000004;
+    4:4     halt as_bit (bool);
+    6:6     swgen0 as_bit (bool);
+);
+
+nv_reg!(FalconMailbox0 at +0x00000040;
+    31:0    mailbox0 as (u32)
+);
+nv_reg!(FalconMailbox1 at +0x00000044;
+    31:0    mailbox1 as (u32)
+);
+
+nv_reg!(FalconCpuCtl at +0x00000100;
+    1:1     start_cpu as_bit (bool);
+    4:4     halted as_bit (bool);
+    6:6     alias_en as_bit (bool);
+);
+nv_reg!(FalconBootVec at +0x00000104;
+    31:0    boot_vec as (u32)
+);
+
+nv_reg!(FalconHwCfg at +0x00000108;
+    8:0     imem_size as (u32);
+    17:9    dmem_size as (u32);
+);
+
+nv_reg!(FalconDmaCtl at +0x0000010c;
+    0:0     require_ctx as_bit (bool);
+    1:1     dmem_scrubbing  as_bit (bool);
+    2:2     imem_scrubbing as_bit (bool);
+    6:3     dmaq_num as_bit (u8);
+    7:7     secure_stat as_bit (bool);
+);
+
+nv_reg!(FalconDmaTrfBase at +0x00000110;
+    31:0    base as (u32);
+);
+
+nv_reg!(FalconDmaTrfMOffs at +0x00000114;
+    23:0    offs as (u32);
+);
+
+nv_reg!(FalconDmaTrfCmd at +0x00000118;
+    0:0     full as_bit (bool);
+    1:1     idle as_bit (bool);
+    3:2     sec as_bit (u8);
+    4:4     imem as_bit (bool);
+    5:5     is_write as_bit (bool);
+    10:8    size as (u8);
+    14:12   ctxdma as (u8);
+    16:16   set_dmtag as (u8);
+);
+
+nv_reg!(FalconDmaTrfBOffs at +0x0000011c;
+    31:0    offs as (u32);
+);
+
+nv_reg!(FalconDmaTrfBase1 at +0x00000128;
+    8:0     base as (u16);
+);
+
+nv_reg!(FalconHwCfg1 at +0x0000012c;
+    3:0     core_rev try_into (FalconCoreRev), "core revision of the falcon";
+    5:4     security_model try_into (FalconSecurityModel), "security model of the falcon";
+    7:6     core_rev_subversion into (FalconCoreRevSubversion);
+    11:8    imem_ports as (u8);
+    15:12   dmem_ports as (u8);
+);
+
+// TODO: This should be able to take an index, like +0x180[16; 8]? Then the constructor or read
+// method take the port we want to address as argument.
+nv_reg!(FalconImemC at +0x00000180;
+    7:2     offs as (u8);
+    23:8    blk as (u8);
+    24:24   aincw as_bit (bool);
+    25:25   aincr as_bit (bool);
+    28:28   secure as_bit (bool);
+    29:29   sec_atomic  as_bit (bool);
+);
+
+nv_reg!(FalconImemD at +0x00000184;
+    31:0    data as (u32);
+);
+
+nv_reg!(FalconImemT at +0x00000188;
+    15:0    data as (u16);
+);
+
+nv_reg!(FalconDmemC at +0x000001c0;
+    23:0    addr as (u32);
+    7:2     offs as (u8);
+    23:8    blk as (u8);
+    24:24   aincw as_bit (bool);
+    25:25   aincr as_bit (bool);
+    26:26   settag as_bit (bool);
+    27:27   setlvl as_bit (bool);
+    28:28   va as_bit (bool);
+    29:29   miss  as_bit (bool);
+);
+
+nv_reg!(FalconDmemD at +0x000001c4;
+    31:0    data as (u32);
+);

-- 
2.48.1



More information about the dri-devel mailing list