Skip to content

Commit dbfb5aa

Browse files
ttabiGnurou
authored andcommitted
gpu: nova-core: add FalconUCodeDescV2 support
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 <ttabi@nvidia.com> Reviewed-by: Joel Fernandes <joelagnelf@nvidia.com> Reviewed-by: Gary Guo <gary@garyguo.net> Acked-by: Danilo Krummrich <dakr@kernel.org> Link: https://patch.msgid.link/20260122222848.2555890-11-ttabi@nvidia.com Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
1 parent ab2aad2 commit dbfb5aa

3 files changed

Lines changed: 249 additions & 64 deletions

File tree

drivers/gpu/nova-core/firmware.rs

Lines changed: 199 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//! to be loaded into a given execution unit.
55
66
use core::marker::PhantomData;
7+
use core::ops::Deref;
78

89
use kernel::{
910
device,
@@ -15,7 +16,10 @@ use kernel::{
1516

1617
use crate::{
1718
dma::DmaObject,
18-
falcon::FalconFirmware,
19+
falcon::{
20+
FalconFirmware,
21+
FalconLoadTarget, //
22+
},
1923
gpu,
2024
num::{
2125
FromSafeCast,
@@ -43,6 +47,46 @@ fn request_firmware(
4347
.and_then(|path| firmware::Firmware::request(&path, dev))
4448
}
4549

50+
/// Structure used to describe some firmwares, notably FWSEC-FRTS.
51+
#[repr(C)]
52+
#[derive(Debug, Clone)]
53+
pub(crate) struct FalconUCodeDescV2 {
54+
/// Header defined by 'NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC*' in OpenRM.
55+
hdr: u32,
56+
/// Stored size of the ucode after the header, compressed or uncompressed
57+
stored_size: u32,
58+
/// Uncompressed size of the ucode. If store_size == uncompressed_size, then the ucode
59+
/// is not compressed.
60+
pub(crate) uncompressed_size: u32,
61+
/// Code entry point
62+
pub(crate) virtual_entry: u32,
63+
/// Offset after the code segment at which the Application Interface Table headers are located.
64+
pub(crate) interface_offset: u32,
65+
/// Base address at which to load the code segment into 'IMEM'.
66+
pub(crate) imem_phys_base: u32,
67+
/// Size in bytes of the code to copy into 'IMEM'.
68+
pub(crate) imem_load_size: u32,
69+
/// Virtual 'IMEM' address (i.e. 'tag') at which the code should start.
70+
pub(crate) imem_virt_base: u32,
71+
/// Virtual address of secure IMEM segment.
72+
pub(crate) imem_sec_base: u32,
73+
/// Size of secure IMEM segment.
74+
pub(crate) imem_sec_size: u32,
75+
/// Offset into stored (uncompressed) image at which DMEM begins.
76+
pub(crate) dmem_offset: u32,
77+
/// Base address at which to load the data segment into 'DMEM'.
78+
pub(crate) dmem_phys_base: u32,
79+
/// Size in bytes of the data to copy into 'DMEM'.
80+
pub(crate) dmem_load_size: u32,
81+
/// "Alternate" Size of data to load into IMEM.
82+
pub(crate) alt_imem_load_size: u32,
83+
/// "Alternate" Size of data to load into DMEM.
84+
pub(crate) alt_dmem_load_size: u32,
85+
}
86+
87+
// SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability.
88+
unsafe impl FromBytes for FalconUCodeDescV2 {}
89+
4690
/// Structure used to describe some firmwares, notably FWSEC-FRTS.
4791
#[repr(C)]
4892
#[derive(Debug, Clone)]
@@ -76,13 +120,164 @@ pub(crate) struct FalconUCodeDescV3 {
76120
_reserved: u16,
77121
}
78122

79-
impl FalconUCodeDescV3 {
123+
// SAFETY: all bit patterns are valid for this type, and it doesn't use
124+
// interior mutability.
125+
unsafe impl FromBytes for FalconUCodeDescV3 {}
126+
127+
/// Enum wrapping the different versions of Falcon microcode descriptors.
128+
///
129+
/// This allows handling both V2 and V3 descriptor formats through a
130+
/// unified type, providing version-agnostic access to firmware metadata
131+
/// via the [`FalconUCodeDescriptor`] trait.
132+
#[derive(Debug, Clone)]
133+
pub(crate) enum FalconUCodeDesc {
134+
V2(FalconUCodeDescV2),
135+
V3(FalconUCodeDescV3),
136+
}
137+
138+
impl Deref for FalconUCodeDesc {
139+
type Target = dyn FalconUCodeDescriptor;
140+
141+
fn deref(&self) -> &Self::Target {
142+
match self {
143+
FalconUCodeDesc::V2(v2) => v2,
144+
FalconUCodeDesc::V3(v3) => v3,
145+
}
146+
}
147+
}
148+
149+
/// Trait providing a common interface for accessing Falcon microcode descriptor fields.
150+
///
151+
/// This trait abstracts over the different descriptor versions ([`FalconUCodeDescV2`] and
152+
/// [`FalconUCodeDescV3`]), allowing code to work with firmware metadata without needing to
153+
/// know the specific descriptor version. Fields not present return zero.
154+
pub(crate) trait FalconUCodeDescriptor {
155+
fn hdr(&self) -> u32;
156+
fn imem_load_size(&self) -> u32;
157+
fn interface_offset(&self) -> u32;
158+
fn dmem_load_size(&self) -> u32;
159+
fn pkc_data_offset(&self) -> u32;
160+
fn engine_id_mask(&self) -> u16;
161+
fn ucode_id(&self) -> u8;
162+
fn signature_count(&self) -> u8;
163+
fn signature_versions(&self) -> u16;
164+
80165
/// Returns the size in bytes of the header.
81-
pub(crate) fn size(&self) -> usize {
166+
fn size(&self) -> usize {
167+
let hdr = self.hdr();
168+
82169
const HDR_SIZE_SHIFT: u32 = 16;
83170
const HDR_SIZE_MASK: u32 = 0xffff0000;
171+
((hdr & HDR_SIZE_MASK) >> HDR_SIZE_SHIFT).into_safe_cast()
172+
}
84173

85-
((self.hdr & HDR_SIZE_MASK) >> HDR_SIZE_SHIFT).into_safe_cast()
174+
fn imem_sec_load_params(&self) -> FalconLoadTarget;
175+
fn imem_ns_load_params(&self) -> Option<FalconLoadTarget>;
176+
fn dmem_load_params(&self) -> FalconLoadTarget;
177+
}
178+
179+
impl FalconUCodeDescriptor for FalconUCodeDescV2 {
180+
fn hdr(&self) -> u32 {
181+
self.hdr
182+
}
183+
fn imem_load_size(&self) -> u32 {
184+
self.imem_load_size
185+
}
186+
fn interface_offset(&self) -> u32 {
187+
self.interface_offset
188+
}
189+
fn dmem_load_size(&self) -> u32 {
190+
self.dmem_load_size
191+
}
192+
fn pkc_data_offset(&self) -> u32 {
193+
0
194+
}
195+
fn engine_id_mask(&self) -> u16 {
196+
0
197+
}
198+
fn ucode_id(&self) -> u8 {
199+
0
200+
}
201+
fn signature_count(&self) -> u8 {
202+
0
203+
}
204+
fn signature_versions(&self) -> u16 {
205+
0
206+
}
207+
208+
fn imem_sec_load_params(&self) -> FalconLoadTarget {
209+
FalconLoadTarget {
210+
src_start: 0,
211+
dst_start: self.imem_sec_base,
212+
len: self.imem_sec_size,
213+
}
214+
}
215+
216+
fn imem_ns_load_params(&self) -> Option<FalconLoadTarget> {
217+
Some(FalconLoadTarget {
218+
src_start: 0,
219+
dst_start: self.imem_phys_base,
220+
len: self.imem_load_size.checked_sub(self.imem_sec_size)?,
221+
})
222+
}
223+
224+
fn dmem_load_params(&self) -> FalconLoadTarget {
225+
FalconLoadTarget {
226+
src_start: self.dmem_offset,
227+
dst_start: self.dmem_phys_base,
228+
len: self.dmem_load_size,
229+
}
230+
}
231+
}
232+
233+
impl FalconUCodeDescriptor for FalconUCodeDescV3 {
234+
fn hdr(&self) -> u32 {
235+
self.hdr
236+
}
237+
fn imem_load_size(&self) -> u32 {
238+
self.imem_load_size
239+
}
240+
fn interface_offset(&self) -> u32 {
241+
self.interface_offset
242+
}
243+
fn dmem_load_size(&self) -> u32 {
244+
self.dmem_load_size
245+
}
246+
fn pkc_data_offset(&self) -> u32 {
247+
self.pkc_data_offset
248+
}
249+
fn engine_id_mask(&self) -> u16 {
250+
self.engine_id_mask
251+
}
252+
fn ucode_id(&self) -> u8 {
253+
self.ucode_id
254+
}
255+
fn signature_count(&self) -> u8 {
256+
self.signature_count
257+
}
258+
fn signature_versions(&self) -> u16 {
259+
self.signature_versions
260+
}
261+
262+
fn imem_sec_load_params(&self) -> FalconLoadTarget {
263+
FalconLoadTarget {
264+
src_start: 0,
265+
dst_start: self.imem_phys_base,
266+
len: self.imem_load_size,
267+
}
268+
}
269+
270+
fn imem_ns_load_params(&self) -> Option<FalconLoadTarget> {
271+
// Not used on V3 platforms
272+
None
273+
}
274+
275+
fn dmem_load_params(&self) -> FalconLoadTarget {
276+
FalconLoadTarget {
277+
src_start: self.imem_load_size,
278+
dst_start: self.dmem_phys_base,
279+
len: self.dmem_load_size,
280+
}
86281
}
87282
}
88283

drivers/gpu/nova-core/firmware/fwsec.rs

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use crate::{
4040
FalconLoadTarget, //
4141
},
4242
firmware::{
43-
FalconUCodeDescV3,
43+
FalconUCodeDesc,
4444
FirmwareDmaObject,
4545
FirmwareSignature,
4646
Signed,
@@ -218,38 +218,29 @@ unsafe fn transmute_mut<T: Sized + FromBytes + AsBytes>(
218218
/// It is responsible for e.g. carving out the WPR2 region as the first step of the GSP bootflow.
219219
pub(crate) struct FwsecFirmware {
220220
/// Descriptor of the firmware.
221-
desc: FalconUCodeDescV3,
221+
desc: FalconUCodeDesc,
222222
/// GPU-accessible DMA object containing the firmware.
223223
ucode: FirmwareDmaObject<Self, Signed>,
224224
}
225225

226226
impl FalconLoadParams for FwsecFirmware {
227227
fn imem_sec_load_params(&self) -> FalconLoadTarget {
228-
FalconLoadTarget {
229-
src_start: 0,
230-
dst_start: self.desc.imem_phys_base,
231-
len: self.desc.imem_load_size,
232-
}
228+
self.desc.imem_sec_load_params()
233229
}
234230

235231
fn imem_ns_load_params(&self) -> Option<FalconLoadTarget> {
236-
// Only used on Turing and GA100, so return None for now
237-
None
232+
self.desc.imem_ns_load_params()
238233
}
239234

240235
fn dmem_load_params(&self) -> FalconLoadTarget {
241-
FalconLoadTarget {
242-
src_start: self.desc.imem_load_size,
243-
dst_start: self.desc.dmem_phys_base,
244-
len: self.desc.dmem_load_size,
245-
}
236+
self.desc.dmem_load_params()
246237
}
247238

248239
fn brom_params(&self) -> FalconBromParams {
249240
FalconBromParams {
250-
pkc_data_offset: self.desc.pkc_data_offset,
251-
engine_id_mask: self.desc.engine_id_mask,
252-
ucode_id: self.desc.ucode_id,
241+
pkc_data_offset: self.desc.pkc_data_offset(),
242+
engine_id_mask: self.desc.engine_id_mask(),
243+
ucode_id: self.desc.ucode_id(),
253244
}
254245
}
255246

@@ -273,10 +264,10 @@ impl FalconFirmware for FwsecFirmware {
273264
impl FirmwareDmaObject<FwsecFirmware, Unsigned> {
274265
fn new_fwsec(dev: &Device<device::Bound>, bios: &Vbios, cmd: FwsecCommand) -> Result<Self> {
275266
let desc = bios.fwsec_image().header()?;
276-
let ucode = bios.fwsec_image().ucode(desc)?;
267+
let ucode = bios.fwsec_image().ucode(&desc)?;
277268
let mut dma_object = DmaObject::from_data(dev, ucode)?;
278269

279-
let hdr_offset = usize::from_safe_cast(desc.imem_load_size + desc.interface_offset);
270+
let hdr_offset = usize::from_safe_cast(desc.imem_load_size() + desc.interface_offset());
280271
// SAFETY: we have exclusive access to `dma_object`.
281272
let hdr: &FalconAppifHdrV1 = unsafe { transmute(&dma_object, hdr_offset) }?;
282273

@@ -303,7 +294,7 @@ impl FirmwareDmaObject<FwsecFirmware, Unsigned> {
303294
let dmem_mapper: &mut FalconAppifDmemmapperV3 = unsafe {
304295
transmute_mut(
305296
&mut dma_object,
306-
(desc.imem_load_size + dmem_base).into_safe_cast(),
297+
(desc.imem_load_size() + dmem_base).into_safe_cast(),
307298
)
308299
}?;
309300

@@ -317,7 +308,7 @@ impl FirmwareDmaObject<FwsecFirmware, Unsigned> {
317308
let frts_cmd: &mut FrtsCmd = unsafe {
318309
transmute_mut(
319310
&mut dma_object,
320-
(desc.imem_load_size + cmd_in_buffer_offset).into_safe_cast(),
311+
(desc.imem_load_size() + cmd_in_buffer_offset).into_safe_cast(),
321312
)
322313
}?;
323314

@@ -364,11 +355,12 @@ impl FwsecFirmware {
364355

365356
// Patch signature if needed.
366357
let desc = bios.fwsec_image().header()?;
367-
let ucode_signed = if desc.signature_count != 0 {
368-
let sig_base_img = usize::from_safe_cast(desc.imem_load_size + desc.pkc_data_offset);
369-
let desc_sig_versions = u32::from(desc.signature_versions);
358+
let ucode_signed = if desc.signature_count() != 0 {
359+
let sig_base_img =
360+
usize::from_safe_cast(desc.imem_load_size() + desc.pkc_data_offset());
361+
let desc_sig_versions = u32::from(desc.signature_versions());
370362
let reg_fuse_version =
371-
falcon.signature_reg_fuse_version(bar, desc.engine_id_mask, desc.ucode_id)?;
363+
falcon.signature_reg_fuse_version(bar, desc.engine_id_mask(), desc.ucode_id())?;
372364
dev_dbg!(
373365
dev,
374366
"desc_sig_versions: {:#x}, reg_fuse_version: {}\n",
@@ -402,7 +394,7 @@ impl FwsecFirmware {
402394
dev_dbg!(dev, "patching signature with index {}\n", signature_idx);
403395
let signature = bios
404396
.fwsec_image()
405-
.sigs(desc)
397+
.sigs(&desc)
406398
.and_then(|sigs| sigs.get(signature_idx).ok_or(EINVAL))?;
407399

408400
ucode_dma.patch_signature(signature, sig_base_img)?
@@ -411,7 +403,7 @@ impl FwsecFirmware {
411403
};
412404

413405
Ok(FwsecFirmware {
414-
desc: desc.clone(),
406+
desc,
415407
ucode: ucode_signed,
416408
})
417409
}

0 commit comments

Comments
 (0)