[PATCH 3/3] gpu: nova-core: use cv! for constant casts

From: Eliot Courtney

Date: Fri Aug 28 2026 - 05:23:49 EST


The new `cv!` macro allows safe casting of constant expressions in a
const context. Update code in nova-core to use it.

Signed-off-by: Eliot Courtney <ecourtney@xxxxxxxxxx>
---
drivers/gpu/nova-core/falcon.rs | 7 ++--
drivers/gpu/nova-core/fb/hal/gb100.rs | 8 ++---
drivers/gpu/nova-core/firmware/fwsec/bootloader.rs | 7 ++--
drivers/gpu/nova-core/fsp.rs | 7 ++--
drivers/gpu/nova-core/gsp/cmdq.rs | 11 +++---
drivers/gpu/nova-core/gsp/fw.rs | 39 +++++++++-------------
drivers/gpu/nova-core/gsp/fw/commands.rs | 2 +-
7 files changed, 28 insertions(+), 53 deletions(-)

diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
index dfe4d2e6f82e..e07537346ec5 100644
--- a/drivers/gpu/nova-core/falcon.rs
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -20,10 +20,7 @@
},
Io,
},
- num::casts::{
- self,
- FromSafeCast, //
- },
+ num::casts::FromSafeCast,
prelude::*,
time::Delta,
};
@@ -510,7 +507,7 @@ fn dma_wr(
target_mem: FalconMem,
load_offsets: FalconDmaLoadTarget,
) -> Result {
- const DMA_LEN: u32 = casts::usize_into_u32::<{ MEM_BLOCK_ALIGNMENT }>();
+ const DMA_LEN: u32 = cv!(MEM_BLOCK_ALIGNMENT);

// DMA transfers can only be done in units of 256 bytes. Compute how many such transfers we
// need to perform.
diff --git a/drivers/gpu/nova-core/fb/hal/gb100.rs b/drivers/gpu/nova-core/fb/hal/gb100.rs
index a53d8b435dc2..0bf00d381607 100644
--- a/drivers/gpu/nova-core/fb/hal/gb100.rs
+++ b/drivers/gpu/nova-core/fb/hal/gb100.rs
@@ -11,10 +11,7 @@
},
Io, //
},
- num::{
- casts::usize_into_u32,
- Bounded, //
- },
+ num::Bounded,
prelude::*,
ptr::{
const_align_up,
@@ -84,8 +81,7 @@ fn write_sysmem_flush_page_gb100(bar: Bar0<'_>, addr: Bounded<u64, 52>) {

// This PMU reservation size is r570-specific.
pub(super) const fn pmu_reserved_size_gb100() -> u32 {
- usize_into_u32::<{ const_align_up(SZ_8M + SZ_16M + SZ_4K, Alignment::new::<SZ_128K>()).unwrap() }>(
- )
+ cv!(const_align_up(SZ_8M + SZ_16M + SZ_4K, Alignment::new::<SZ_128K>()).unwrap())
}

impl FbHal for Gb100 {
diff --git a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
index d1fb7d2d7480..d637cc4ce312 100644
--- a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
+++ b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
@@ -15,10 +15,7 @@
io::{register::WithBase, Io},
num::casts::FromSafeCast,
prelude::*,
- ptr::{
- Alignable,
- Alignment, //
- },
+ ptr::Alignable,
sizes,
transmute::AsBytes,
};
@@ -134,7 +131,7 @@ pub(crate) fn new(
let code_size = usize::from_safe_cast(tlv.get_u32(b"CDSZ")?);
let code = blob.get(..code_size).ok_or(EINVAL)?;
let aligned_code_size = code_size
- .align_up(Alignment::new::<{ falcon::MEM_BLOCK_ALIGNMENT }>())
+ .align_up(cv!(falcon::MEM_BLOCK_ALIGNMENT))
.ok_or(EINVAL)?;

let mut ucode = KVec::with_capacity(aligned_code_size, GFP_KERNEL)?;
diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs
index b9ca298dc97f..e15d0af95499 100644
--- a/drivers/gpu/nova-core/fsp.rs
+++ b/drivers/gpu/nova-core/fsp.rs
@@ -11,10 +11,7 @@
device,
dma::Coherent,
io::poll::read_poll_timeout,
- num::{
- casts,
- TryIntoBounded, //
- },
+ num::TryIntoBounded,
prelude::*,
ptr::{
Alignable,
@@ -287,7 +284,7 @@ fn new<'a>(
};

let version = hal.cot_version();
- let size = casts::usize_into_u16::<{ core::mem::size_of::<NvdmPayloadCot>() }>();
+ let size = cv!(core::mem::size_of::<NvdmPayloadCot>() => u16);

Ok(init!(Self {
header: FspMessageHeader::new(NvdmType::Cot),
diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index 658d0a9b2cfb..4a471efe237c 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -23,10 +23,7 @@
Io, //
},
new_mutex,
- num::casts::{
- self,
- FromSafeCast, //
- },
+ num::casts::FromSafeCast,
prelude::*,
ptr,
sync::{
@@ -165,7 +162,7 @@ fn read(
#[repr(C, align(0x1000))]
#[derive(Debug)]
struct MsgqData {
- data: [[u8; GSP_PAGE_SIZE]; casts::u32_as_usize(MSGQ_NUM_PAGES)],
+ data: [[u8; GSP_PAGE_SIZE]; cv!(MSGQ_NUM_PAGES)],
}

// Annoyingly we are forced to use a literal to specify the alignment of
@@ -238,8 +235,8 @@ unsafe impl FromBytes for GspMem {}
impl DmaGspMem {
/// Allocate a new instance and map it for `dev`.
fn new(dev: &device::Device<device::Bound>) -> Result<Self> {
- const MSGQ_SIZE: u32 = casts::usize_into_u32::<{ size_of::<Msgq>() }>();
- const RX_HDR_OFF: u32 = casts::usize_into_u32::<{ mem::offset_of!(Msgq, rx) }>();
+ const MSGQ_SIZE: u32 = cv!(size_of::<Msgq>());
+ const RX_HDR_OFF: u32 = cv!(mem::offset_of!(Msgq, rx));

let mut gsp_mem = CoherentBox::<GspMem>::zeroed(dev, GFP_KERNEL)?;
gsp_mem.cpuq.tx = MsgqTxHeader::new(MSGQ_SIZE, RX_HDR_OFF, MSGQ_NUM_PAGES);
diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs
index 61064b6a251b..880764c2e5b1 100644
--- a/drivers/gpu/nova-core/gsp/fw.rs
+++ b/drivers/gpu/nova-core/gsp/fw.rs
@@ -19,10 +19,7 @@
io_read,
io_write, //
},
- num::casts::{
- self,
- FromSafeCast, //
- },
+ num::casts::FromSafeCast,
prelude::*,
ptr::{
Alignable,
@@ -57,7 +54,7 @@

/// Maximum size of a single GSP message queue element in bytes.
pub(crate) const GSP_MSG_QUEUE_ELEMENT_SIZE_MAX: usize =
- casts::u32_as_usize(bindings::GSP_MSG_QUEUE_ELEMENT_SIZE_MAX);
+ cv!(bindings::GSP_MSG_QUEUE_ELEMENT_SIZE_MAX);

/// Empty type to group methods related to heap parameters for running the GSP firmware.
enum GspFwHeapParams {}
@@ -110,20 +107,18 @@ pub(crate) struct LibosParams {
impl LibosParams {
/// Version 2 of the GSP LIBOS (Turing and GA100)
const LIBOS2: LibosParams = LibosParams {
- carveout_size: casts::u32_as_u64(bindings::GSP_FW_HEAP_PARAM_OS_SIZE_LIBOS2),
- allowed_heap_size: casts::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_MIN_MB)
+ carveout_size: cv!(bindings::GSP_FW_HEAP_PARAM_OS_SIZE_LIBOS2),
+ allowed_heap_size: cv!(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_MIN_MB => u64)
* u64::SZ_1M
- ..casts::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_MAX_MB) * u64::SZ_1M,
+ ..cv!(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_MAX_MB => u64) * u64::SZ_1M,
};

/// Version 3 of the GSP LIBOS (GA102+)
const LIBOS3: LibosParams = LibosParams {
- carveout_size: casts::u32_as_u64(bindings::GSP_FW_HEAP_PARAM_OS_SIZE_LIBOS3_BAREMETAL),
- allowed_heap_size: casts::u32_as_u64(
- bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MIN_MB,
- ) * u64::SZ_1M
- ..casts::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MAX_MB)
- * u64::SZ_1M,
+ carveout_size: cv!(bindings::GSP_FW_HEAP_PARAM_OS_SIZE_LIBOS3_BAREMETAL),
+ allowed_heap_size: cv!(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MIN_MB => u64)
+ * u64::SZ_1M
+ ..cv!(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MAX_MB => u64) * u64::SZ_1M,
};

/// Returns the libos parameters corresponding to `chipset`.
@@ -682,12 +677,8 @@ fn id8(name: &str) -> u64 {
id8: id8(name),
pa: obj.dma_address(),
size: u64::from_safe_cast(obj.size()),
- kind: casts::u32_into_u8::<
- { bindings::LibosMemoryRegionKind_LIBOS_MEMORY_REGION_CONTIGUOUS },
- >(),
- loc: casts::u32_into_u8::<
- { bindings::LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_SYSMEM },
- >(),
+ kind: cv!(bindings::LibosMemoryRegionKind_LIBOS_MEMORY_REGION_CONTIGUOUS),
+ loc: cv!(bindings::LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_SYSMEM),
..Zeroable::init_zeroed()
});

@@ -715,12 +706,12 @@ pub(crate) fn new(msgq_size: u32, rx_hdr_offset: u32, msg_count: u32) -> Self {
Self(bindings::msgqTxHeader {
version: 0,
size: msgq_size,
- msgSize: casts::usize_into_u32::<GSP_PAGE_SIZE>(),
+ msgSize: cv!(GSP_PAGE_SIZE),
msgCount: msg_count,
writePtr: 0,
flags: 1,
rxHdrOff: rx_hdr_offset,
- entryOff: casts::usize_into_u32::<GSP_PAGE_SIZE>(),
+ entryOff: cv!(GSP_PAGE_SIZE),
})
}

@@ -947,7 +938,7 @@ impl MessageQueueInitArguments {
fn new(cmdq: &Cmdq) -> impl Init<Self> + '_ {
init!(MessageQueueInitArguments {
sharedMemPhysAddr: cmdq.dma_addr,
- pageTableEntryCount: casts::usize_into_u32::<{ Cmdq::NUM_PTES }>(),
+ pageTableEntryCount: cv!(Cmdq::NUM_PTES),
cmdQueueOffset: u64::from_safe_cast(Cmdq::CMDQ_OFFSET),
statQueueOffset: u64::from_safe_cast(Cmdq::STATQ_OFFSET),
..Zeroable::init_zeroed()
@@ -969,7 +960,7 @@ impl GspAcrBootGspRmParams {
fn new(target: GspDmaTarget, wpr_meta_addr: u64) -> impl Init<Self> {
let params = init!(Self {
target: target as u32,
- gspRmDescSize: casts::usize_into_u32::<{ size_of::<GspFwWprMeta>() }>(),
+ gspRmDescSize: cv!(size_of::<GspFwWprMeta>()),
gspRmDescOffset: wpr_meta_addr,
bIsGspRmBoot: 1,
wprCarveoutOffset: 0,
diff --git a/drivers/gpu/nova-core/gsp/fw/commands.rs b/drivers/gpu/nova-core/gsp/fw/commands.rs
index 201594fa437b..60b0355d1d2e 100644
--- a/drivers/gpu/nova-core/gsp/fw/commands.rs
+++ b/drivers/gpu/nova-core/gsp/fw/commands.rs
@@ -82,7 +82,7 @@ pub(crate) fn new(offset: u32, value: u32) -> Self {

// We only support DWORD types for now. Support for other types
// will come later if required.
- type_: bindings::REGISTRY_TABLE_ENTRY_TYPE_DWORD as u8,
+ type_: cv!(bindings::REGISTRY_TABLE_ENTRY_TYPE_DWORD),
__bindgen_padding_0: Default::default(),
data: value,
length: 0,

--
2.55.0