> On Apr 22, 2025, at 10:45 AM, Danilo Krummrich <d...@kernel.org> wrote:
> […]
>> +
>> +    fn get_signature_reg_fuse_version(
>> +        &self,
>> +        bar: &Devres<Bar0>,
>> +        engine_id_mask: u16,
>> +        ucode_id: u8,
>> +    ) -> Result<u32>;
>> +
>> +    // Program the BROM registers prior to starting a secure firmware.
>> +    fn program_brom(&self, bar: &Devres<Bar0>, params: &FalconBromParams) 
>> -> Result<()>;
>> +}
>> +
>> +/// Returns a boxed falcon HAL adequate for the passed `chipset`.
>> +///
>> +/// We use this function and a heap-allocated trait object instead of 
>> statically defined trait
>> +/// objects because of the two-dimensional (Chipset, Engine) lookup 
>> required to return the
>> +/// requested HAL.
> 
> Do we really need the dynamic dispatch? AFAICS, there's only E::BASE that is
> relevant to FalconHal impls?
> 
> Can't we do something like I do in the following example [1]?
> 
> ```
> use std::marker::PhantomData;
> use std::ops::Deref;
> 
> trait Engine {
>    const BASE: u32;
> }
> 
> trait Hal<E: Engine> {
>    fn access(&self);
> }
> 
> struct Gsp;
> 
> impl Engine for Gsp {
>    const BASE: u32 = 0x1;
> }
> 
> struct Sec2;
> 
> impl Engine for Sec2 {
>    const BASE: u32 = 0x2;
> }
> 
> struct GA100<E: Engine>(PhantomData<E>);
> 
> impl<E: Engine> Hal<E> for GA100<E> {
>    fn access(&self) {
>        println!("Base: {}", E::BASE);
>    }
> }
> 
> impl<E: Engine> GA100<E> {
>    fn new() -> Self {
>        Self(PhantomData)
>    }
> }
> 
> //struct Falcon<E: Engine>(GA100<E>);
> 
> struct Falcon<H: Hal<E>, E: Engine>(H, PhantomData<E>);
> 
> impl<H: Hal<E>, E: Engine> Falcon<H, E> {
>    fn new(hal: H) -> Self {
>        Self(hal, PhantomData)
>    }
> }
> 
> impl<H: Hal<E>, E: Engine> Deref for Falcon<H, E> {
>    type Target = H;
> 
>    fn deref(&self) -> &Self::Target {
>        &self.0
>    }
> }
> 
> fn main() {
>    let gsp = Falcon::new(GA100::<Gsp>::new());
>    let sec2 = Falcon::new(GA100::<Sec2>::new());
> 
>    gsp.access();
>    sec2.access();
> }
> ```
> 
> [1] 
> https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=bf7035a07e79a4047fb6834eac03a9f2

I am still researching this idea from a rust point of view, but quick question 
- will this even work if the chip type (GAxxx) is determined at runtime? That 
does need runtime polymorphism.

Thanks,

 - Joel


> 
>> +///
>> +/// TODO: replace the return type with `KBox` once it gains the ability to 
>> host trait objects.
>> +pub(crate) fn create_falcon_hal<E: FalconEngine + 'static>(
>> +    chipset: Chipset,
>> +) -> Result<Arc<dyn FalconHal<E>>> {
>> +    let hal = match chipset {
>> +        Chipset::GA102 | Chipset::GA103 | Chipset::GA104 | Chipset::GA106 | 
>> Chipset::GA107 => {
>> +            Arc::new(ga102::Ga102::<E>::new(), GFP_KERNEL)? as Arc<dyn 
>> FalconHal<E>>
>> +        }
>> +        _ => return Err(ENOTSUPP),
>> +    };
>> +
>> +    Ok(hal)
>> +}
>> diff --git a/drivers/gpu/nova-core/falcon/hal/ga102.rs 
>> b/drivers/gpu/nova-core/falcon/hal/ga102.rs
>> new file mode 100644
>> index 
>> 0000000000000000000000000000000000000000..747b02ca671f7d4a97142665a9ba64807c87391e
>> --- /dev/null
>> +++ b/drivers/gpu/nova-core/falcon/hal/ga102.rs
>> @@ -0,0 +1,111 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +
>> +use core::marker::PhantomData;
>> +use core::time::Duration;
>> +
>> +use kernel::devres::Devres;
>> +use kernel::prelude::*;
>> +
>> +use crate::driver::Bar0;
>> +use crate::falcon::{FalconBromParams, FalconEngine, FalconModSelAlgo, 
>> RiscvCoreSelect};
>> +use crate::regs;
>> +use crate::timer::Timer;
>> +
>> +use super::FalconHal;
>> +
>> +fn select_core_ga102<E: FalconEngine>(bar: &Devres<Bar0>, timer: &Timer) -> 
>> Result<()> {
>> +    let bcr_ctrl = with_bar!(bar, |b| regs::RiscvBcrCtrl::read(b, 
>> E::BASE))?;
>> +    if bcr_ctrl.core_select() != RiscvCoreSelect::Falcon {
>> +        with_bar!(bar, |b| regs::RiscvBcrCtrl::default()
>> +            .set_core_select(RiscvCoreSelect::Falcon)
>> +            .write(b, E::BASE))?;
>> +
>> +        timer.wait_on(bar, Duration::from_millis(10), || {
>> +            bar.try_access_with(|b| regs::RiscvBcrCtrl::read(b, E::BASE))
>> +                .and_then(|v| if v.valid() { Some(()) } else { None })
>> +        })?;
>> +    }
>> +
>> +    Ok(())
>> +}
>> +
>> +fn get_signature_reg_fuse_version_ga102(
>> +    bar: &Devres<Bar0>,
>> +    engine_id_mask: u16,
>> +    ucode_id: u8,
>> +) -> Result<u32> {
>> +    // The ucode fuse versions are contained in the 
>> FUSE_OPT_FPF_<ENGINE>_UCODE<X>_VERSION
>> +    // registers, which are an array. Our register definition macros do not 
>> allow us to manage them
>> +    // properly, so we need to hardcode their addresses for now.
>> +
>> +    // Each engine has 16 ucode version registers numbered from 1 to 16.
>> +    if ucode_id == 0 || ucode_id > 16 {
>> +        pr_warn!("invalid ucode id {:#x}", ucode_id);
>> +        return Err(EINVAL);
>> +    }
>> +    let reg_fuse = if engine_id_mask & 0x0001 != 0 {
>> +        // NV_FUSE_OPT_FPF_SEC2_UCODE1_VERSION
>> +        0x824140
>> +    } else if engine_id_mask & 0x0004 != 0 {
>> +        // NV_FUSE_OPT_FPF_NVDEC_UCODE1_VERSION
>> +        0x824100
>> +    } else if engine_id_mask & 0x0400 != 0 {
>> +        // NV_FUSE_OPT_FPF_GSP_UCODE1_VERSION
>> +        0x8241c0
>> +    } else {
>> +        pr_warn!("unexpected engine_id_mask {:#x}", engine_id_mask);
>> +        return Err(EINVAL);
>> +    } + ((ucode_id - 1) as usize * core::mem::size_of::<u32>());
>> +
>> +    let reg_fuse_version = with_bar!(bar, |b| { b.read32(reg_fuse) })?;
>> +
>> +    // Equivalent of Find Last Set bit.
>> +    Ok(u32::BITS - reg_fuse_version.leading_zeros())
>> +}
>> +
>> +fn program_brom_ga102<E: FalconEngine>(
>> +    bar: &Devres<Bar0>,
>> +    params: &FalconBromParams,
>> +) -> Result<()> {
>> +    with_bar!(bar, |b| {
>> +        regs::FalconBromParaaddr0::default()
>> +            .set_addr(params.pkc_data_offset)
>> +            .write(b, E::BASE);
>> +        regs::FalconBromEngidmask::default()
>> +            .set_mask(params.engine_id_mask as u32)
>> +            .write(b, E::BASE);
>> +        regs::FalconBromCurrUcodeId::default()
>> +            .set_ucode_id(params.ucode_id as u32)
>> +            .write(b, E::BASE);
>> +        regs::FalconModSel::default()
>> +            .set_algo(FalconModSelAlgo::Rsa3k)
>> +            .write(b, E::BASE)
>> +    })
>> +}
>> +
>> +pub(super) struct Ga102<E: FalconEngine>(PhantomData<E>);
>> +
>> +impl<E: FalconEngine> Ga102<E> {
>> +    pub(super) fn new() -> Self {
>> +        Self(PhantomData)
>> +    }
>> +}
>> +
>> +impl<E: FalconEngine> FalconHal<E> for Ga102<E> {
>> +    fn select_core(&self, bar: &Devres<Bar0>, timer: &Timer) -> Result<()> {
>> +        select_core_ga102::<E>(bar, timer)
>> +    }
>> +
>> +    fn get_signature_reg_fuse_version(
>> +        &self,
>> +        bar: &Devres<Bar0>,
>> +        engine_id_mask: u16,
>> +        ucode_id: u8,
>> +    ) -> Result<u32> {
>> +        get_signature_reg_fuse_version_ga102(bar, engine_id_mask, ucode_id)
>> +    }
>> +
>> +    fn program_brom(&self, bar: &Devres<Bar0>, params: &FalconBromParams) 
>> -> Result<()> {
>> +        program_brom_ga102::<E>(bar, params)
>> +    }
>> +}
>> diff --git a/drivers/gpu/nova-core/falcon/sec2.rs 
>> b/drivers/gpu/nova-core/falcon/sec2.rs
>> new file mode 100644
>> index 
>> 0000000000000000000000000000000000000000..85dda3e8380a3d31d34c92c4236c6f81c63ce772
>> --- /dev/null
>> +++ b/drivers/gpu/nova-core/falcon/sec2.rs
>> @@ -0,0 +1,9 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +
>> +use crate::falcon::{Falcon, FalconEngine};
>> +
>> +pub(crate) struct Sec2;
>> +impl FalconEngine for Sec2 {
>> +    const BASE: usize = 0x00840000;
>> +}
>> +pub(crate) type Sec2Falcon = Falcon<Sec2>;
>> diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
>> index 
>> 1b3e43e0412e2a2ea178c7404ea647c9e38d4e04..ec4c648c6e8b4aa7d06c627ed59c0e66a08c679e
>>  100644
>> --- a/drivers/gpu/nova-core/gpu.rs
>> +++ b/drivers/gpu/nova-core/gpu.rs
>> @@ -5,6 +5,8 @@
>> use crate::devinit;
>> use crate::dma::DmaObject;
>> use crate::driver::Bar0;
>> +use crate::falcon::gsp::GspFalcon;
>> +use crate::falcon::sec2::Sec2Falcon;
>> use crate::firmware::Firmware;
>> use crate::regs;
>> use crate::timer::Timer;
>> @@ -221,6 +223,20 @@ pub(crate) fn new(
>> 
>>         let timer = Timer::new();
>> 
>> +        let gsp_falcon = GspFalcon::new(
>> +            pdev,
>> +            spec.chipset,
>> +            &bar,
>> +            if spec.chipset > Chipset::GA100 {
>> +                true
>> +            } else {
>> +                false
>> +            },
>> +        )?;
>> +        gsp_falcon.clear_swgen0_intr(&bar)?;
>> +
>> +        let _sec2_falcon = Sec2Falcon::new(pdev, spec.chipset, &bar, true)?;
>> +
>>         Ok(pin_init!(Self {
>>             spec,
>>             bar,
>> diff --git a/drivers/gpu/nova-core/nova_core.rs 
>> b/drivers/gpu/nova-core/nova_core.rs
>> index 
>> df3468c92c6081b3e2db218d92fbe1c40a0a75c3..4dde8004d24882c60669b5acd6af9d6988c66a9c
>>  100644
>> --- a/drivers/gpu/nova-core/nova_core.rs
>> +++ b/drivers/gpu/nova-core/nova_core.rs
>> @@ -23,6 +23,7 @@ macro_rules! with_bar {
>> mod devinit;
>> mod dma;
>> 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 
>> f191cf4eb44c2b950e5cfcc6d04f95c122ce29d3..c76a16dc8e7267a4eb54cb71e1cca6fb9e00188f
>>  100644
>> --- a/drivers/gpu/nova-core/regs.rs
>> +++ b/drivers/gpu/nova-core/regs.rs
>> @@ -6,6 +6,10 @@
>> #[macro_use]
>> mod macros;
>> 
>> +use crate::falcon::{
>> +    FalconCoreRev, FalconCoreRevSubversion, FalconFbifMemType, 
>> FalconFbifTarget, FalconModSelAlgo,
>> +    FalconSecurityModel, RiscvCoreSelect,
>> +};
>> use crate::gpu::Chipset;
>> 
>> register!(Boot0@0x00000000, "Basic revision information about the GPU";
>> @@ -44,3 +48,188 @@
>> register!(Pgc6AonSecureScratchGroup05@0x00118234;
>>     31:0    value => as u32
>> );
>> +
>> +/* PFALCON */
>> +
>> +register!(FalconIrqsclr@+0x00000004;
>> +    4:4     halt => as_bit bool;
>> +    6:6     swgen0 => as_bit bool;
>> +);
>> +
>> +register!(FalconIrqstat@+0x00000008;
>> +    4:4     halt => as_bit bool;
>> +    6:6     swgen0 => as_bit bool;
>> +);
>> +
>> +register!(FalconIrqmclr@+0x00000014;
>> +    31:0    val => as u32
>> +);
>> +
>> +register!(FalconIrqmask@+0x00000018;
>> +    31:0    val => as u32
>> +);
>> +
>> +register!(FalconRm@+0x00000084;
>> +    31:0    val => as u32
>> +);
>> +
>> +register!(FalconIrqdest@+0x0000001c;
>> +    31:0    val => as u32
>> +);
>> +
>> +register!(FalconMailbox0@+0x00000040;
>> +    31:0    mailbox0 => as u32
>> +);
>> +register!(FalconMailbox1@+0x00000044;
>> +    31:0    mailbox1 => as u32
>> +);
>> +
>> +register!(FalconHwcfg2@+0x000000f4;
>> +    10:10   riscv => as_bit bool;
>> +    12:12   mem_scrubbing => as_bit bool;
>> +    31:31   reset_ready => as_bit bool;
>> +);
>> +
>> +register!(FalconCpuCtl@+0x00000100;
>> +    1:1     start_cpu => as_bit bool;
>> +    4:4     halted => as_bit bool;
>> +    6:6     alias_en => as_bit bool;
>> +);
>> +
>> +register!(FalconBootVec@+0x00000104;
>> +    31:0    boot_vec => as u32
>> +);
>> +
>> +register!(FalconHwCfg@+0x00000108;
>> +    8:0     imem_size => as u32;
>> +    17:9    dmem_size => as u32;
>> +);
>> +
>> +register!(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;
>> +);
>> +
>> +register!(FalconDmaTrfBase@+0x00000110;
>> +    31:0    base => as u32;
>> +);
>> +
>> +register!(FalconDmaTrfMOffs@+0x00000114;
>> +    23:0    offs => as u32;
>> +);
>> +
>> +register!(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;
>> +);
>> +
>> +register!(FalconDmaTrfBOffs@+0x0000011c;
>> +    31:0    offs => as u32;
>> +);
>> +
>> +register!(FalconDmaTrfBase1@+0x00000128;
>> +    8:0     base => as u16;
>> +);
>> +
>> +register!(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;
>> +);
>> +
>> +register!(FalconCpuCtlAlias@+0x00000130;
>> +    1:1     start_cpu => as_bit bool;
>> +);
>> +
>> +/* TODO: this is an array of registers */
>> +register!(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;
>> +);
>> +
>> +register!(FalconImemD@+0x00000184;
>> +    31:0    data => as u32;
>> +);
>> +
>> +register!(FalconImemT@+0x00000188;
>> +    15:0    data => as u16;
>> +);
>> +
>> +register!(FalconDmemC@+0x000001c0;
>> +    7:2     offs => as u8;
>> +    23:0    addr => as u32;
>> +    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;
>> +);
>> +
>> +register!(FalconDmemD@+0x000001c4;
>> +    31:0    data => as u32;
>> +);
>> +
>> +register!(FalconModSel@+0x00001180;
>> +    7:0     algo => try_into FalconModSelAlgo;
>> +);
>> +register!(FalconBromCurrUcodeId@+0x00001198;
>> +    31:0    ucode_id => as u32;
>> +);
>> +register!(FalconBromEngidmask@+0x0000119c;
>> +    31:0    mask => as u32;
>> +);
>> +register!(FalconBromParaaddr0@+0x00001210;
>> +    31:0    addr => as u32;
>> +);
>> +
>> +register!(RiscvCpuctl@+0x00000388;
>> +    0:0     startcpu => as_bit bool;
>> +    4:4     halted => as_bit bool;
>> +    5:5     stopped => as_bit bool;
>> +    7:7     active_stat => as_bit bool;
>> +);
>> +
>> +register!(FalconEngine@+0x000003c0;
>> +    0:0     reset => as_bit bool;
>> +);
>> +
>> +register!(RiscvIrqmask@+0x00000528;
>> +    31:0    mask => as u32;
>> +);
>> +
>> +register!(RiscvIrqdest@+0x0000052c;
>> +    31:0    dest => as u32;
>> +);
>> +
>> +/* TODO: this is an array of registers */
>> +register!(FalconFbifTranscfg@+0x00000600;
>> +    1:0     target => try_into FalconFbifTarget;
>> +    2:2     mem_type => as_bit FalconFbifMemType;
>> +);
>> +
>> +register!(FalconFbifCtl@+0x00000624;
>> +    7:7     allow_phys_no_ctx => as_bit bool;
>> +);
>> +
>> +register!(RiscvBcrCtrl@+0x00001668;
>> +    0:0     valid => as_bit bool;
>> +    4:4     core_select => as_bit RiscvCoreSelect;
>> +    8:8     br_fetch => as_bit bool;
>> +);
>> diff --git a/drivers/gpu/nova-core/timer.rs b/drivers/gpu/nova-core/timer.rs
>> index 
>> 8987352f4192bc9b4b2fc0fb5f2e8e62ff27be68..c03a5c36d1230dfbf2bd6e02a793264280c6d509
>>  100644
>> --- a/drivers/gpu/nova-core/timer.rs
>> +++ b/drivers/gpu/nova-core/timer.rs
>> @@ -2,9 +2,6 @@
>> 
>> //! Nova Core Timer subdevice
>> 
>> -// To be removed when all code is used.
>> -#![allow(dead_code)]
>> -
>> use core::fmt::Display;
>> use core::ops::{Add, Sub};
>> use core::time::Duration;
>> 
>> --
>> 2.49.0
>> 

Reply via email to