On 1/21/2026 6:53 PM, Timur Tabi wrote:
> The FRTS firmware in Turing and GA100 VBIOS has an older header
> format (v2 instead of v3).  To support both v2 and v3 at runtime,
> add the FalconUCodeDescV2 struct, and update code that references
> the FalconUCodeDescV3 directly with a FalconUCodeDesc enum that
> encapsulates both.
> 
> Signed-off-by: Timur Tabi <[email protected]>
> ---
>  drivers/gpu/nova-core/firmware.rs       |  203 ++++-
>  drivers/gpu/nova-core/firmware/fwsec.rs |   46 +-
>  drivers/gpu/nova-core/vbios.rs          |   64 +-
>  drivers/gpu/nova-core/vbios.rs.orig     | 1105 +++++++++++++++++++++++
>  4 files changed, 1354 insertions(+), 64 deletions(-)
>  create mode 100644 drivers/gpu/nova-core/vbios.rs.orig
> 
> diff --git a/drivers/gpu/nova-core/firmware.rs 
> b/drivers/gpu/nova-core/firmware.rs
> index 2d2008b33fb4..68779540aa28 100644
> --- a/drivers/gpu/nova-core/firmware.rs
> +++ b/drivers/gpu/nova-core/firmware.rs
> @@ -4,6 +4,7 @@
>  //! to be loaded into a given execution unit.
>  
>  use core::marker::PhantomData;
> +use core::ops::Deref;
>  
>  use kernel::{
>      device,
> @@ -15,7 +16,10 @@
>  
>  use crate::{
>      dma::DmaObject,
> -    falcon::FalconFirmware,
> +    falcon::{
> +        FalconFirmware,
> +        FalconLoadTarget, //
> +    },
>      gpu,
>      num::{
>          FromSafeCast,
> @@ -43,6 +47,46 @@ fn request_firmware(
>          .and_then(|path| firmware::Firmware::request(&path, dev))
>  }
>  
> +/// Structure used to describe some firmwares, notably FWSEC-FRTS.
> +#[repr(C)]
> +#[derive(Debug, Clone)]
> +pub(crate) struct FalconUCodeDescV2 {
> +    /// Header defined by 'NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC*' in OpenRM.
> +    hdr: u32,
> +    /// Stored size of the ucode after the header, compressed or uncompressed
> +    stored_size: u32,
> +    /// Uncompressed size of the ucode.  If store_size == uncompressed_size, 
> then the ucode
> +    /// is not compressed.
> +    pub(crate) uncompressed_size: u32,
> +    /// Code entry point
> +    pub(crate) virtual_entry: u32,
> +    /// Offset after the code segment at which the Application Interface 
> Table headers are located.
> +    pub(crate) interface_offset: u32,
> +    /// Base address at which to load the code segment into 'IMEM'.
> +    pub(crate) imem_phys_base: u32,
> +    /// Size in bytes of the code to copy into 'IMEM'.
> +    pub(crate) imem_load_size: u32,
> +    /// Virtual 'IMEM' address (i.e. 'tag') at which the code should start.
> +    pub(crate) imem_virt_base: u32,
> +    /// Virtual address of secure IMEM segment.
> +    pub(crate) imem_sec_base: u32,
> +    /// Size of secure IMEM segment.
> +    pub(crate) imem_sec_size: u32,
> +    /// Offset into stored (uncompressed) image at which DMEM begins.
> +    pub(crate) dmem_offset: u32,
> +    /// Base address at which to load the data segment into 'DMEM'.
> +    pub(crate) dmem_phys_base: u32,
> +    /// Size in bytes of the data to copy into 'DMEM'.
> +    pub(crate) dmem_load_size: u32,
> +    /// "Alternate" Size of data to load into IMEM.
> +    pub(crate) alt_imem_load_size: u32,
> +    /// "Alternate" Size of data to load into DMEM.
> +    pub(crate) alt_dmem_load_size: u32,
> +}
> +
> +// SAFETY: all bit patterns are valid for this type, and it doesn't use 
> interior mutability.
> +unsafe impl FromBytes for FalconUCodeDescV2 {}
> +
>  /// Structure used to describe some firmwares, notably FWSEC-FRTS.
>  #[repr(C)]
>  #[derive(Debug, Clone)]
> @@ -76,13 +120,164 @@ pub(crate) struct FalconUCodeDescV3 {
>      _reserved: u16,
>  }
>  
> -impl FalconUCodeDescV3 {
> +// SAFETY: all bit patterns are valid for this type, and it doesn't use
> +// interior mutability.
> +unsafe impl FromBytes for FalconUCodeDescV3 {}
> +
> +/// Enum wrapping the different versions of Falcon microcode descriptors.
> +///
> +/// This allows handling both V2 and V3 descriptor formats through a
> +/// unified type, providing version-agnostic access to firmware metadata
> +/// via the [`FalconUCodeDescriptor`] trait.
> +#[derive(Debug, Clone)]
> +pub(crate) enum FalconUCodeDesc {
> +    V2(FalconUCodeDescV2),
> +    V3(FalconUCodeDescV3),
> +}
> +
> +impl Deref for FalconUCodeDesc {
> +    type Target = dyn FalconUCodeDescriptor;
> +
> +    fn deref(&self) -> &Self::Target {
> +        match self {
> +            FalconUCodeDesc::V2(v2) => v2,
> +            FalconUCodeDesc::V3(v3) => v3,
> +        }
> +    }

I guess we still need to decide if we want to use 'dyn' for
FalconUCodeDescriptor or function wrappers with separate match statements. John
also recently felt, I think, that 'dyn' here is more complicated (I was the one
who suggested 'dyn' in v2 or so, but hey - in my defense, I am learning Rust too
;-)).

After seeing this patch, I think I realized 'dyn' *for this case* does add more
boilerplate, because now you have duplicated functions which almost do exactly
the same thing (seems much worse than duplicate match arms).

'dyn' would benefit a lot though if the match arms were large. But in this
patch, most of the match arms are just accessing fields.

For my -mm patches, where I am routing between version 2 and version 3 of the
page table/directory formats, I actually went with match arms instead of dyn
which was cleaner.

-- 
Joel Fernandes

Reply via email to