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@xxxxxxxxxx> --- 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@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@+0x00000004; + 4:4 halt as_bit (bool); + 6:6 swgen0 as_bit (bool); +); + +nv_reg!(FalconMailbox0@+0x00000040; + 31:0 mailbox0 as (u32) +); +nv_reg!(FalconMailbox1@+0x00000044; + 31:0 mailbox1 as (u32) +); + +nv_reg!(FalconCpuCtl@+0x00000100; + 1:1 start_cpu as_bit (bool); + 4:4 halted as_bit (bool); + 6:6 alias_en as_bit (bool); +); +nv_reg!(FalconBootVec@+0x00000104; + 31:0 boot_vec as (u32) +); + +nv_reg!(FalconHwCfg@+0x00000108; + 8:0 imem_size as (u32); + 17:9 dmem_size as (u32); +); + +nv_reg!(FalconDmaCtl@+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@+0x00000110; + 31:0 base as (u32); +); + +nv_reg!(FalconDmaTrfMOffs@+0x00000114; + 23:0 offs as (u32); +); + +nv_reg!(FalconDmaTrfCmd@+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@+0x0000011c; + 31:0 offs as (u32); +); + +nv_reg!(FalconDmaTrfBase1@+0x00000128; + 8:0 base as (u16); +); + +nv_reg!(FalconHwCfg1@+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@+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@+0x00000184; + 31:0 data as (u32); +); + +nv_reg!(FalconImemT@+0x00000188; + 15:0 data as (u16); +); + +nv_reg!(FalconDmemC@+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@+0x000001c4; + 31:0 data as (u32); +); -- 2.48.1