On 1/21/2026 8:45 PM, Joel Fernandes wrote:
>
>
> 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.
>
Since this is not something we can easily fix though in a follow-up patch:
Reviewed-by: Joel Fernandes <[email protected]>
--
Joel Fernandes