All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] gpu: nova-core: complete conversion to kernel `num` module
@ 2026-08-28  5:33 Alexandre Courbot
  2026-08-28  5:33 ` [PATCH 1/2] gpu: nova-core: use kernel lossless integer conversion module Alexandre Courbot
  2026-08-28  5:33 ` [PATCH 2/2] gpu: nova-core: use FromSafeCast wherever possible Alexandre Courbot
  0 siblings, 2 replies; 10+ messages in thread
From: Alexandre Courbot @ 2026-08-28  5:33 UTC (permalink / raw)
  To: Danilo Krummrich, Alice Ryhl, David Airlie, Simona Vetter
  Cc: John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney,
	Zhi Wang, nova-gpu, dri-devel, rust-for-linux, linux-kernel,
	Alexandre Courbot

This is extracted from the now-defunct `const_as` series [1] and
does the groundwork required to eventually convert nova-core to use the
`cv!` macro [2].

Patch 1 does the minimum necessary to convert nova-core to the kernel's
num module and removes its local copy. Patch 2 broadens the use of
`FromSafeCast` to avoid having to refer the `casts` module at every
conversion. After it, the only references left to `casts` are the
conversions done in const context, that will eventually be replaced by
the `cv!` macro.

This series is based on `master` and should be mergeable after `-rc1`
has been tagged.

[1] https://lore.kernel.org/all/20260825-const_as-v1-0-1ce712225fe2@nvidia.com/
[2] https://lore.kernel.org/all/DL051FB1HOBY.2UC911T3M9AIS@nvidia.com/

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
Alexandre Courbot (2):
      gpu: nova-core: use kernel lossless integer conversion module
      gpu: nova-core: use FromSafeCast wherever possible

 drivers/gpu/nova-core/falcon.rs                    |  12 +-
 drivers/gpu/nova-core/falcon/fsp.rs                |   4 +-
 drivers/gpu/nova-core/fb.rs                        |   2 +-
 drivers/gpu/nova-core/fb/hal/gb100.rs              |   6 +-
 drivers/gpu/nova-core/firmware.rs                  |   4 +-
 drivers/gpu/nova-core/firmware/booter.rs           |   4 +-
 drivers/gpu/nova-core/firmware/fwsec.rs            |   2 +-
 drivers/gpu/nova-core/firmware/fwsec/bootloader.rs |   4 +-
 drivers/gpu/nova-core/firmware/gsp.rs              |   9 +-
 drivers/gpu/nova-core/firmware/tlv.rs              |  11 +-
 drivers/gpu/nova-core/fsp.rs                       |   8 +-
 drivers/gpu/nova-core/gsp.rs                       |   4 +-
 drivers/gpu/nova-core/gsp/cmdq.rs                  |  25 +--
 drivers/gpu/nova-core/gsp/fw.rs                    |  42 ++--
 drivers/gpu/nova-core/gsp/fw/commands.rs           |   4 +-
 drivers/gpu/nova-core/gsp/sequencer.rs             |   2 +-
 drivers/gpu/nova-core/mctp.rs                      |   8 +-
 drivers/gpu/nova-core/num.rs                       | 211 ---------------------
 drivers/gpu/nova-core/vbios.rs                     |   2 +-
 19 files changed, 81 insertions(+), 283 deletions(-)
---
base-commit: 1b78070aaef63512688aebfbc82365ef9d6660f1
change-id: 20260828-nova_num-64e1b2e84f77

Best regards,
--  
Alexandre Courbot <acourbot@nvidia.com>


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/2] gpu: nova-core: use kernel lossless integer conversion module
  2026-08-28  5:33 [PATCH 0/2] gpu: nova-core: complete conversion to kernel `num` module Alexandre Courbot
@ 2026-08-28  5:33 ` Alexandre Courbot
  2026-08-28  5:43   ` sashiko-bot
  2026-08-28 12:09   ` Danilo Krummrich
  2026-08-28  5:33 ` [PATCH 2/2] gpu: nova-core: use FromSafeCast wherever possible Alexandre Courbot
  1 sibling, 2 replies; 10+ messages in thread
From: Alexandre Courbot @ 2026-08-28  5:33 UTC (permalink / raw)
  To: Danilo Krummrich, Alice Ryhl, David Airlie, Simona Vetter
  Cc: John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney,
	Zhi Wang, nova-gpu, dri-devel, rust-for-linux, linux-kernel,
	Alexandre Courbot

The `kernel` crate now features a replacement for our lossless integer
conversion routines. Switch to the kernel version and remove our own.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Reviewed-by: Danilo Krummrich <dakr@kernel.org>
Reviewed-by: Eliot Courtney <ecourtney@nvidia.com>
---
 drivers/gpu/nova-core/falcon.rs                    |  12 +-
 drivers/gpu/nova-core/falcon/fsp.rs                |   4 +-
 drivers/gpu/nova-core/fb.rs                        |   2 +-
 drivers/gpu/nova-core/fb/hal/gb100.rs              |   6 +-
 drivers/gpu/nova-core/firmware.rs                  |   4 +-
 drivers/gpu/nova-core/firmware/booter.rs           |   4 +-
 drivers/gpu/nova-core/firmware/fwsec.rs            |   2 +-
 drivers/gpu/nova-core/firmware/fwsec/bootloader.rs |   4 +-
 drivers/gpu/nova-core/firmware/gsp.rs              |   9 +-
 drivers/gpu/nova-core/firmware/tlv.rs              |  11 +-
 drivers/gpu/nova-core/fsp.rs                       |   8 +-
 drivers/gpu/nova-core/gsp.rs                       |   4 +-
 drivers/gpu/nova-core/gsp/cmdq.rs                  |  22 +--
 drivers/gpu/nova-core/gsp/fw.rs                    |  42 ++--
 drivers/gpu/nova-core/gsp/fw/commands.rs           |   4 +-
 drivers/gpu/nova-core/gsp/sequencer.rs             |   2 +-
 drivers/gpu/nova-core/mctp.rs                      |   8 +-
 drivers/gpu/nova-core/num.rs                       | 211 ---------------------
 drivers/gpu/nova-core/vbios.rs                     |   2 +-
 19 files changed, 78 insertions(+), 283 deletions(-)

diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
index 65cb12d26e2b..dfe4d2e6f82e 100644
--- a/drivers/gpu/nova-core/falcon.rs
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -20,6 +20,10 @@
         },
         Io,
     },
+    num::casts::{
+        self,
+        FromSafeCast, //
+    },
     prelude::*,
     time::Delta,
 };
@@ -29,11 +33,7 @@
     driver::Bar0,
     falcon::hal::LoadMethod,
     gpu::Chipset,
-    num::{
-        self,
-        FromSafeCast, //
-    },
-    regs,
+    regs, //
 };
 
 pub(crate) mod fsp;
@@ -510,7 +510,7 @@ fn dma_wr(
         target_mem: FalconMem,
         load_offsets: FalconDmaLoadTarget,
     ) -> Result {
-        const DMA_LEN: u32 = num::usize_into_u32::<{ MEM_BLOCK_ALIGNMENT }>();
+        const DMA_LEN: u32 = casts::usize_into_u32::<{ 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/falcon/fsp.rs b/drivers/gpu/nova-core/falcon/fsp.rs
index 0437180b8829..2470ac511c98 100644
--- a/drivers/gpu/nova-core/falcon/fsp.rs
+++ b/drivers/gpu/nova-core/falcon/fsp.rs
@@ -16,6 +16,7 @@
         },
         Io, //
     },
+    num::casts,
     prelude::*,
     sizes::SZ_1K,
     time::Delta,
@@ -28,7 +29,6 @@
         PFalcon2Base,
         PFalconBase, //
     },
-    num,
     regs, //
 };
 
@@ -165,7 +165,7 @@ pub(crate) fn recv_msg(&mut self) -> Result<KVec<u8>> {
             Delta::from_millis(10),
             Delta::from_millis(FSP_MSG_TIMEOUT_MS),
         )
-        .map(num::u32_as_usize)?;
+        .map(casts::u32_as_usize)?;
 
         // Don't blindly allocate more than the maximum we expect from FSP.
         if msg_size > FSP_EMEM_CHANNEL_0_SIZE {
diff --git a/drivers/gpu/nova-core/fb.rs b/drivers/gpu/nova-core/fb.rs
index 1576399389b1..8d5d9480378f 100644
--- a/drivers/gpu/nova-core/fb.rs
+++ b/drivers/gpu/nova-core/fb.rs
@@ -10,6 +10,7 @@
     dma::CoherentHandle,
     fmt,
     io::Io,
+    num::casts::FromSafeCast,
     prelude::*,
     ptr::{
         Alignable,
@@ -23,7 +24,6 @@
     firmware::gsp::GspFirmware,
     gpu::Chipset,
     gsp,
-    num::FromSafeCast,
     vgpu::VgpuState, //
 };
 
diff --git a/drivers/gpu/nova-core/fb/hal/gb100.rs b/drivers/gpu/nova-core/fb/hal/gb100.rs
index d9e4d62ae632..a53d8b435dc2 100644
--- a/drivers/gpu/nova-core/fb/hal/gb100.rs
+++ b/drivers/gpu/nova-core/fb/hal/gb100.rs
@@ -11,7 +11,10 @@
         },
         Io, //
     },
-    num::Bounded,
+    num::{
+        casts::usize_into_u32,
+        Bounded, //
+    },
     prelude::*,
     ptr::{
         const_align_up,
@@ -26,7 +29,6 @@
         hal::FbHal,
         regs, //
     },
-    num::usize_into_u32,
 };
 
 struct Gb100;
diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs
index b49613a90bf0..19f13779bb30 100644
--- a/drivers/gpu/nova-core/firmware.rs
+++ b/drivers/gpu/nova-core/firmware.rs
@@ -9,6 +9,7 @@
 
 use kernel::{
     firmware,
+    num::casts::IntoSafeCast,
     prelude::*, //
 };
 
@@ -18,8 +19,7 @@
         FalconFirmware, //
     },
     gpu,
-    gsp::boot_firmware_files,
-    num::IntoSafeCast, //
+    gsp::boot_firmware_files, //
 };
 
 pub(crate) mod booter;
diff --git a/drivers/gpu/nova-core/firmware/booter.rs b/drivers/gpu/nova-core/firmware/booter.rs
index dc071edba331..aa830455b7e7 100644
--- a/drivers/gpu/nova-core/firmware/booter.rs
+++ b/drivers/gpu/nova-core/firmware/booter.rs
@@ -10,6 +10,7 @@
 use kernel::{
     device,
     dma::Coherent,
+    num::casts::IntoSafeCast,
     prelude::*, //
 };
 
@@ -32,8 +33,7 @@
         Signed,
         Unsigned, //
     },
-    gpu::Chipset,
-    num::IntoSafeCast,
+    gpu::Chipset, //
 };
 
 /// Signature for Booter firmware. Their size is encoded into the header and not known a compile
diff --git a/drivers/gpu/nova-core/firmware/fwsec.rs b/drivers/gpu/nova-core/firmware/fwsec.rs
index 7a931f22f629..7f7ca3ba2298 100644
--- a/drivers/gpu/nova-core/firmware/fwsec.rs
+++ b/drivers/gpu/nova-core/firmware/fwsec.rs
@@ -19,6 +19,7 @@
         self,
         Device, //
     },
+    num::casts::FromSafeCast,
     prelude::*,
     transmute::{
         AsBytes,
@@ -42,7 +43,6 @@
         Signed,
         Unsigned, //
     },
-    num::FromSafeCast,
     vbios::Vbios,
 };
 
diff --git a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
index ec4d92317a93..d1fb7d2d7480 100644
--- a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
+++ b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
@@ -13,6 +13,7 @@
     },
     dma::Coherent,
     io::{register::WithBase, Io},
+    num::casts::FromSafeCast,
     prelude::*,
     ptr::{
         Alignable,
@@ -45,8 +46,7 @@
         },
     },
     gpu::Chipset,
-    num::FromSafeCast, //
-    regs,
+    regs, //
 };
 
 /// Structure used by the boot-loader to load the rest of the code.
diff --git a/drivers/gpu/nova-core/firmware/gsp.rs b/drivers/gpu/nova-core/firmware/gsp.rs
index e8f9491e84cc..e75ce6fe47d8 100644
--- a/drivers/gpu/nova-core/firmware/gsp.rs
+++ b/drivers/gpu/nova-core/firmware/gsp.rs
@@ -9,6 +9,10 @@
         DmaAddress, //
     },
     firmware,
+    num::casts::{
+        arch::FromSafeCastArch,
+        FromSafeCast, //
+    },
     prelude::*,
     scatterlist::{
         Owned,
@@ -26,8 +30,7 @@
         },
     },
     gpu::Chipset,
-    gsp::GSP_PAGE_SIZE,
-    num::FromSafeCast,
+    gsp::GSP_PAGE_SIZE, //
 };
 
 /// GSP firmware with 3-level radix page tables for the GSP bootloader.
@@ -154,7 +157,7 @@ pub(crate) fn radix3_dma_address(&self) -> DmaAddress {
 fn map_into_lvl(sg_table: &SGTable<Owned<VVec<u8>>>, mut dst: VVec<u8>) -> Result<VVec<u8>> {
     for sg_entry in sg_table.iter() {
         // Number of pages we need to map.
-        let num_pages = usize::from_safe_cast(sg_entry.dma_len()).div_ceil(GSP_PAGE_SIZE);
+        let num_pages = usize::from_safe_cast_arch(sg_entry.dma_len()).div_ceil(GSP_PAGE_SIZE);
 
         for i in 0..num_pages {
             let entry = sg_entry.dma_address()
diff --git a/drivers/gpu/nova-core/firmware/tlv.rs b/drivers/gpu/nova-core/firmware/tlv.rs
index 7b879f13a61e..6653c10e3e0a 100644
--- a/drivers/gpu/nova-core/firmware/tlv.rs
+++ b/drivers/gpu/nova-core/firmware/tlv.rs
@@ -4,14 +4,15 @@
 use kernel::{
     device,
     firmware,
+    num::casts::{
+        self,
+        IntoSafeCast, //
+    },
     prelude::*,
     str::CString, //
 };
 
-use crate::{
-    gpu,
-    num::*, //
-};
+use crate::gpu;
 
 /// Requests the GPU firmware TLV `name` suitable for `chipset`.
 pub(crate) fn request_tlv(
@@ -51,7 +52,7 @@ fn parse(hdr: &[u8]) -> Option<Self> {
             return None;
         }
         let len_arr = <[u8; 4]>::try_from(hdr.get(4..Self::SIZE)?).ok()?;
-        let length = u32_as_usize(u32::from_le_bytes(len_arr));
+        let length = casts::u32_as_usize(u32::from_le_bytes(len_arr));
         Some(Self { tag, length })
     }
 }
diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs
index ab685fb4168f..b9ca298dc97f 100644
--- a/drivers/gpu/nova-core/fsp.rs
+++ b/drivers/gpu/nova-core/fsp.rs
@@ -11,7 +11,10 @@
     device,
     dma::Coherent,
     io::poll::read_poll_timeout,
-    num::TryIntoBounded,
+    num::{
+        casts,
+        TryIntoBounded, //
+    },
     prelude::*,
     ptr::{
         Alignable,
@@ -47,7 +50,6 @@
         NvdmHeader,
         NvdmType, //
     },
-    num,
     regs, //
 };
 
@@ -285,7 +287,7 @@ fn new<'a>(
         };
 
         let version = hal.cot_version();
-        let size = num::usize_into_u16::<{ core::mem::size_of::<NvdmPayloadCot>() }>();
+        let size = casts::usize_into_u16::<{ core::mem::size_of::<NvdmPayloadCot>() }>();
 
         Ok(init!(Self {
             header: FspMessageHeader::new(NvdmType::Cot),
diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
index 13f361406a6c..fc8648de84c2 100644
--- a/drivers/gpu/nova-core/gsp.rs
+++ b/drivers/gpu/nova-core/gsp.rs
@@ -17,6 +17,7 @@
         io_write,
         Io, //
     },
+    num::casts,
     pci,
     prelude::*, //
 };
@@ -48,7 +49,6 @@
         cmdq::Cmdq,
         fw::GspArgumentsPadded, //
     },
-    num,
     vgpu::VgpuManager, //
 };
 
@@ -92,7 +92,7 @@ fn init(view: CoherentView<'_, Self>, start: DmaAddress) -> Result<()> {
         for i in 0..NUM_PAGES {
             io_write!(view, .0[build: i],
                 start
-                    .checked_add(num::usize_as_u64(i) << GSP_PAGE_SHIFT)
+                    .checked_add(casts::usize_as_u64(i) << GSP_PAGE_SHIFT)
                     .ok_or(EOVERFLOW)?
             );
         }
diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index 6da728201281..f85fde09aa6e 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -23,6 +23,7 @@
         Io, //
     },
     new_mutex,
+    num::casts,
     prelude::*,
     ptr,
     sync::{
@@ -57,7 +58,6 @@
         GSP_PAGE_SHIFT,
         GSP_PAGE_SIZE, //
     },
-    num,
     sbuffer::SBufferIter, //
 };
 
@@ -162,7 +162,7 @@ fn read(
 #[repr(C, align(0x1000))]
 #[derive(Debug)]
 struct MsgqData {
-    data: [[u8; GSP_PAGE_SIZE]; num::u32_as_usize(MSGQ_NUM_PAGES)],
+    data: [[u8; GSP_PAGE_SIZE]; casts::u32_as_usize(MSGQ_NUM_PAGES)],
 }
 
 // Annoyingly we are forced to use a literal to specify the alignment of
@@ -235,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 = num::usize_into_u32::<{ size_of::<Msgq>() }>();
-        const RX_HDR_OFF: u32 = num::usize_into_u32::<{ mem::offset_of!(Msgq, rx) }>();
+        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) }>();
 
         let mut gsp_mem = CoherentBox::<GspMem>::zeroed(dev, GFP_KERNEL)?;
         gsp_mem.cpuq.tx = MsgqTxHeader::new(MSGQ_SIZE, RX_HDR_OFF, MSGQ_NUM_PAGES);
@@ -289,10 +289,10 @@ fn new(dev: &device::Device<device::Bound>) -> Result<Self> {
         unsafe {
             (
                 core::slice::from_raw_parts_mut(
-                    data.add(num::u32_as_usize(tx)),
-                    num::u32_as_usize(tail_end - tx),
+                    data.add(casts::u32_as_usize(tx)),
+                    casts::u32_as_usize(tail_end - tx),
                 ),
-                core::slice::from_raw_parts_mut(data, num::u32_as_usize(wrap_end)),
+                core::slice::from_raw_parts_mut(data, casts::u32_as_usize(wrap_end)),
             )
         }
     }
@@ -307,7 +307,7 @@ fn driver_write_area_size(&self) -> usize {
         // `cpu_write_ptr`. The minimum value case is where `rx == 0` and `tx == MSGQ_NUM_PAGES -
         // 1`, which gives `0 + MSGQ_NUM_PAGES - (MSGQ_NUM_PAGES - 1) - 1 == 0`.
         let slots = (rx + MSGQ_NUM_PAGES - tx - 1) % MSGQ_NUM_PAGES;
-        num::u32_as_usize(slots) * GSP_PAGE_SIZE
+        casts::u32_as_usize(slots) * GSP_PAGE_SIZE
     }
 
     /// Returns the region of the GSP message queue that the driver is currently allowed to read
@@ -343,10 +343,10 @@ fn driver_write_area_size(&self) -> usize {
         unsafe {
             (
                 core::slice::from_raw_parts(
-                    data.add(num::u32_as_usize(rx)),
-                    num::u32_as_usize(tail_end - rx),
+                    data.add(casts::u32_as_usize(rx)),
+                    casts::u32_as_usize(tail_end - rx),
                 ),
-                core::slice::from_raw_parts(data, num::u32_as_usize(wrap_end)),
+                core::slice::from_raw_parts(data, casts::u32_as_usize(wrap_end)),
             )
         }
     }
diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs
index 05f54fee6186..88f083ff1f13 100644
--- a/drivers/gpu/nova-core/gsp/fw.rs
+++ b/drivers/gpu/nova-core/gsp/fw.rs
@@ -19,6 +19,10 @@
         io_read,
         io_write, //
     },
+    num::casts::{
+        self,
+        FromSafeCast, //
+    },
     prelude::*,
     ptr::{
         Alignable,
@@ -49,15 +53,11 @@
         cmdq::Cmdq, //
         GSP_PAGE_SIZE,
     },
-    num::{
-        self,
-        FromSafeCast, //
-    },
 };
 
 /// Maximum size of a single GSP message queue element in bytes.
 pub(crate) const GSP_MSG_QUEUE_ELEMENT_SIZE_MAX: usize =
-    num::u32_as_usize(bindings::GSP_MSG_QUEUE_ELEMENT_SIZE_MAX);
+    casts::u32_as_usize(bindings::GSP_MSG_QUEUE_ELEMENT_SIZE_MAX);
 
 /// Empty type to group methods related to heap parameters for running the GSP firmware.
 enum GspFwHeapParams {}
@@ -110,19 +110,19 @@ pub(crate) struct LibosParams {
 impl LibosParams {
     /// Version 2 of the GSP LIBOS (Turing and GA100)
     const LIBOS2: LibosParams = LibosParams {
-        carveout_size: num::u32_as_u64(bindings::GSP_FW_HEAP_PARAM_OS_SIZE_LIBOS2),
-        allowed_heap_size: num::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_MIN_MB)
+        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)
             * u64::SZ_1M
-            ..num::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_MAX_MB) * u64::SZ_1M,
+            ..casts::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_MAX_MB) * u64::SZ_1M,
     };
 
     /// Version 3 of the GSP LIBOS (GA102+)
     const LIBOS3: LibosParams = LibosParams {
-        carveout_size: num::u32_as_u64(bindings::GSP_FW_HEAP_PARAM_OS_SIZE_LIBOS3_BAREMETAL),
-        allowed_heap_size: num::u32_as_u64(
+        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
-            ..num::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MAX_MB)
+            ..casts::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MAX_MB)
                 * u64::SZ_1M,
     };
 
@@ -681,11 +681,11 @@ fn id8(name: &str) -> u64 {
         let init_inner = init!(bindings::LibosMemoryRegionInitArgument {
             id8: id8(name),
             pa: obj.dma_address(),
-            size: num::usize_as_u64(obj.size()),
-            kind: num::u32_into_u8::<
+            size: casts::usize_as_u64(obj.size()),
+            kind: casts::u32_into_u8::<
                 { bindings::LibosMemoryRegionKind_LIBOS_MEMORY_REGION_CONTIGUOUS },
             >(),
-            loc: num::u32_into_u8::<
+            loc: casts::u32_into_u8::<
                 { bindings::LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_SYSMEM },
             >(),
             ..Zeroable::init_zeroed()
@@ -715,12 +715,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: num::usize_into_u32::<GSP_PAGE_SIZE>(),
+            msgSize: casts::usize_into_u32::<GSP_PAGE_SIZE>(),
             msgCount: msg_count,
             writePtr: 0,
             flags: 1,
             rxHdrOff: rx_hdr_offset,
-            entryOff: num::usize_into_u32::<GSP_PAGE_SIZE>(),
+            entryOff: casts::usize_into_u32::<GSP_PAGE_SIZE>(),
         })
     }
 
@@ -851,7 +851,7 @@ pub(crate) fn set_checksum(&mut self, checksum: u32) {
     /// Returns the length of the message's payload.
     pub(crate) fn payload_length(&self) -> usize {
         // `rpc.length` includes the length of the RPC message header.
-        num::u32_as_usize(self.inner.rpc.length)
+        casts::u32_as_usize(self.inner.rpc.length)
             .saturating_sub(size_of::<bindings::rpc_message_header_v>())
     }
 
@@ -947,9 +947,9 @@ impl MessageQueueInitArguments {
     fn new(cmdq: &Cmdq) -> impl Init<Self> + '_ {
         init!(MessageQueueInitArguments {
             sharedMemPhysAddr: cmdq.dma_addr,
-            pageTableEntryCount: num::usize_into_u32::<{ Cmdq::NUM_PTES }>(),
-            cmdQueueOffset: num::usize_as_u64(Cmdq::CMDQ_OFFSET),
-            statQueueOffset: num::usize_as_u64(Cmdq::STATQ_OFFSET),
+            pageTableEntryCount: casts::usize_into_u32::<{ Cmdq::NUM_PTES }>(),
+            cmdQueueOffset: casts::usize_as_u64(Cmdq::CMDQ_OFFSET),
+            statQueueOffset: casts::usize_as_u64(Cmdq::STATQ_OFFSET),
             ..Zeroable::init_zeroed()
         })
     }
@@ -969,7 +969,7 @@ impl GspAcrBootGspRmParams {
     fn new(target: GspDmaTarget, wpr_meta_addr: u64) -> impl Init<Self> {
         let params = init!(Self {
             target: target as u32,
-            gspRmDescSize: num::usize_into_u32::<{ size_of::<GspFwWprMeta>() }>(),
+            gspRmDescSize: casts::usize_into_u32::<{ 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 6dc31d1bf5ae..201594fa437b 100644
--- a/drivers/gpu/nova-core/gsp/fw/commands.rs
+++ b/drivers/gpu/nova-core/gsp/fw/commands.rs
@@ -5,6 +5,7 @@
 
 use kernel::{
     device,
+    num::casts::IntoSafeCast,
     pci,
     prelude::*,
     transmute::{
@@ -15,8 +16,7 @@
 
 use crate::{
     gpu::Chipset,
-    gsp::GSP_PAGE_SIZE,
-    num::IntoSafeCast, //
+    gsp::GSP_PAGE_SIZE, //
 };
 
 use super::bindings;
diff --git a/drivers/gpu/nova-core/gsp/sequencer.rs b/drivers/gpu/nova-core/gsp/sequencer.rs
index bcad1421953a..fed881ba80b0 100644
--- a/drivers/gpu/nova-core/gsp/sequencer.rs
+++ b/drivers/gpu/nova-core/gsp/sequencer.rs
@@ -11,6 +11,7 @@
         poll::read_poll_timeout,
         Io, //
     },
+    num::casts::FromSafeCast,
     prelude::*,
     time::{
         delay::fsleep,
@@ -35,7 +36,6 @@
         GspBootContext,
         LibosMemoryRegionInitArgument, //
     },
-    num::FromSafeCast,
     sbuffer::SBufferIter,
 };
 
diff --git a/drivers/gpu/nova-core/mctp.rs b/drivers/gpu/nova-core/mctp.rs
index 90c642c91a72..67f64ac2b8d1 100644
--- a/drivers/gpu/nova-core/mctp.rs
+++ b/drivers/gpu/nova-core/mctp.rs
@@ -9,14 +9,12 @@
 
 use kernel::{
     bitfield,
+    num::casts,
     pci::Vendor,
     prelude::*, //
 };
 
-use crate::{
-    bounded_enum,
-    num, //
-};
+use crate::bounded_enum;
 
 bounded_enum! {
     /// NVDM message type identifiers carried over MCTP.
@@ -76,7 +74,7 @@ impl NvdmHeader {
     /// Builds an NVDM header for the given message type.
     pub(crate) fn new(nvdm_type: NvdmType) -> Self {
         Self::zeroed()
-            .with_const_msg_type::<{ num::u8_as_u32(MSG_TYPE_VENDOR_PCI) }>()
+            .with_const_msg_type::<{ casts::u8_as_u32(MSG_TYPE_VENDOR_PCI) }>()
             .with_vendor_id(Vendor::NVIDIA.as_raw())
             .with_nvdm_type(nvdm_type)
     }
diff --git a/drivers/gpu/nova-core/num.rs b/drivers/gpu/nova-core/num.rs
index 6eb174d136ab..3921ef6f238e 100644
--- a/drivers/gpu/nova-core/num.rs
+++ b/drivers/gpu/nova-core/num.rs
@@ -5,217 +5,6 @@
 //! This is essentially a staging module for code to mature until it can be moved to the `kernel`
 //! crate.
 
-use kernel::{
-    macros::paste,
-    prelude::*, //
-};
-
-/// Implements safe `as` conversion functions from a given type into a series of target types.
-///
-/// These functions can be used in place of `as`, with the guarantee that they will be lossless.
-macro_rules! impl_safe_as {
-    ($from:ty as { $($into:ty),* }) => {
-        $(
-        paste! {
-            #[doc = ::core::concat!(
-                "Losslessly converts a [`",
-                ::core::stringify!($from),
-                "`] into a [`",
-                ::core::stringify!($into),
-                "`].")]
-            ///
-            /// This conversion is allowed as it is always lossless. Prefer this over the `as`
-            /// keyword to ensure no lossy casts are performed.
-            ///
-            /// This is for use from a `const` context. For non `const` use, prefer the
-            /// [`FromSafeCast`] and [`IntoSafeCast`] traits.
-            ///
-            /// # Examples
-            ///
-            /// ```
-            /// use crate::num;
-            ///
-            #[doc = ::core::concat!(
-                "assert_eq!(num::",
-                ::core::stringify!($from),
-                "_as_",
-                ::core::stringify!($into),
-                "(1",
-                ::core::stringify!($from),
-                "), 1",
-                ::core::stringify!($into),
-                ");")]
-            /// ```
-            #[allow(unused)]
-            #[inline(always)]
-            pub(crate) const fn [<$from _as_ $into>](value: $from) -> $into {
-                ::kernel::build_assert::static_assert!(size_of::<$into>() >= size_of::<$from>());
-
-                value as $into
-            }
-        }
-        )*
-    };
-}
-
-impl_safe_as!(u8 as { u16, u32, u64, usize });
-impl_safe_as!(u16 as { u32, u64, usize });
-impl_safe_as!(u32 as { u64, usize } );
-// `u64` and `usize` have the same size on 64-bit platforms.
-#[cfg(CONFIG_64BIT)]
-impl_safe_as!(u64 as { usize } );
-
-// A `usize` fits into a `u64` on 32 and 64-bit platforms.
-#[cfg(any(CONFIG_32BIT, CONFIG_64BIT))]
-impl_safe_as!(usize as { u64 });
-
-// A `usize` fits into a `u32` on 32-bit platforms.
-#[cfg(CONFIG_32BIT)]
-impl_safe_as!(usize as { u32 });
-
-/// Extension trait providing guaranteed lossless cast to `Self` from `T`.
-///
-/// The standard library's `From` implementations do not cover conversions that are not portable or
-/// future-proof. For instance, even though it is safe today, `From<usize>` is not implemented for
-/// [`u64`] because of the possibility to support larger-than-64bit architectures in the future.
-///
-/// The workaround is to either deal with the error handling of [`TryFrom`] for an operation that
-/// technically cannot fail, or to use the `as` keyword, which can silently strip data if the
-/// destination type is smaller than the source.
-///
-/// Both options are hardly acceptable for the kernel. It is also a much more architecture
-/// dependent environment, supporting only 32 and 64 bit architectures, with some modules
-/// explicitly depending on a specific bus width that could greatly benefit from infallible
-/// conversion operations.
-///
-/// Thus this extension trait that provides, for the architecture the kernel is built for, safe
-/// conversion between types for which such cast is lossless.
-///
-/// In other words, this trait is implemented if, for the current build target and with `t: T`, the
-/// `t as Self` operation is completely lossless.
-///
-/// Prefer this over the `as` keyword to ensure no lossy casts are performed.
-///
-/// If you need to perform a conversion in `const` context, use [`u64_as_usize`], [`u32_as_usize`],
-/// [`usize_as_u64`], etc.
-///
-/// # Examples
-///
-/// ```
-/// use crate::num::FromSafeCast;
-///
-/// assert_eq!(usize::from_safe_cast(0xf00u32), 0xf00u32 as usize);
-/// ```
-pub(crate) trait FromSafeCast<T> {
-    /// Create a `Self` from `value`. This operation is guaranteed to be lossless.
-    fn from_safe_cast(value: T) -> Self;
-}
-
-impl FromSafeCast<usize> for u64 {
-    fn from_safe_cast(value: usize) -> Self {
-        usize_as_u64(value)
-    }
-}
-
-#[cfg(CONFIG_32BIT)]
-impl FromSafeCast<usize> for u32 {
-    fn from_safe_cast(value: usize) -> Self {
-        usize_as_u32(value)
-    }
-}
-
-impl FromSafeCast<u32> for usize {
-    fn from_safe_cast(value: u32) -> Self {
-        u32_as_usize(value)
-    }
-}
-
-#[cfg(CONFIG_64BIT)]
-impl FromSafeCast<u64> for usize {
-    fn from_safe_cast(value: u64) -> Self {
-        u64_as_usize(value)
-    }
-}
-
-/// Counterpart to the [`FromSafeCast`] trait, i.e. this trait is to [`FromSafeCast`] what [`Into`]
-/// is to [`From`].
-///
-/// See the documentation of [`FromSafeCast`] for the motivation.
-///
-/// # Examples
-///
-/// ```
-/// use crate::num::IntoSafeCast;
-///
-/// assert_eq!(0xf00u32.into_safe_cast(), 0xf00u32 as usize);
-/// ```
-pub(crate) trait IntoSafeCast<T> {
-    /// Convert `self` into a `T`. This operation is guaranteed to be lossless.
-    fn into_safe_cast(self) -> T;
-}
-
-/// Reverse operation for types implementing [`FromSafeCast`].
-impl<S, T> IntoSafeCast<T> for S
-where
-    T: FromSafeCast<S>,
-{
-    fn into_safe_cast(self) -> T {
-        T::from_safe_cast(self)
-    }
-}
-
-/// Implements lossless conversion of a constant from a larger type into a smaller one.
-macro_rules! impl_const_into {
-    ($from:ty => { $($into:ty),* }) => {
-        $(
-        paste! {
-            #[doc = ::core::concat!(
-                "Performs a build-time safe conversion of a [`",
-                ::core::stringify!($from),
-                "`] constant value into a [`",
-                ::core::stringify!($into),
-                "`].")]
-            ///
-            /// This checks at compile-time that the conversion is lossless, and triggers a build
-            /// error if it isn't.
-            ///
-            /// # Examples
-            ///
-            /// ```
-            /// use crate::num;
-            ///
-            /// // Succeeds because the value of the source fits into the destination's type.
-            #[doc = ::core::concat!(
-                "assert_eq!(num::",
-                ::core::stringify!($from),
-                "_into_",
-                ::core::stringify!($into),
-                "::<1",
-                ::core::stringify!($from),
-                ">(), 1",
-                ::core::stringify!($into),
-                ");")]
-            /// ```
-            #[allow(unused)]
-            pub(crate) const fn [<$from _into_ $into>]<const N: $from>() -> $into {
-                // Make sure that the target type is smaller than the source one.
-                static_assert!($from::BITS >= $into::BITS);
-                // CAST: we statically enforced above that `$from` is larger than `$into`, so the
-                // `as` conversion will be lossless.
-                build_assert!(N >= $into::MIN as $from && N <= $into::MAX as $from);
-
-                N as $into
-            }
-        }
-        )*
-    };
-}
-
-impl_const_into!(usize => { u8, u16, u32 });
-impl_const_into!(u64 => { u8, u16, u32 });
-impl_const_into!(u32 => { u8, u16 });
-impl_const_into!(u16 => { u8 });
-
 /// Creates an enum type associated to a [`Bounded`](kernel::num::Bounded), with a [`From`]
 /// conversion to the associated `Bounded` and either a [`TryFrom`] or `From` conversion from the
 /// associated `Bounded`.
diff --git a/drivers/gpu/nova-core/vbios.rs b/drivers/gpu/nova-core/vbios.rs
index c03650ee5226..7a2ee29cbb91 100644
--- a/drivers/gpu/nova-core/vbios.rs
+++ b/drivers/gpu/nova-core/vbios.rs
@@ -5,6 +5,7 @@
 use kernel::{
     device,
     io::Io,
+    num::casts::FromSafeCast,
     prelude::*,
     ptr::{
         Alignable,
@@ -23,7 +24,6 @@
         FalconUCodeDescV2,
         FalconUCodeDescV3, //
     },
-    num::FromSafeCast,
 };
 
 /// BIOS Image Type from PCI Data Structure code_type field.

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/2] gpu: nova-core: use FromSafeCast wherever possible
  2026-08-28  5:33 [PATCH 0/2] gpu: nova-core: complete conversion to kernel `num` module Alexandre Courbot
  2026-08-28  5:33 ` [PATCH 1/2] gpu: nova-core: use kernel lossless integer conversion module Alexandre Courbot
@ 2026-08-28  5:33 ` Alexandre Courbot
  2026-08-28  5:42   ` Eliot Courtney
  2026-08-28  5:49   ` sashiko-bot
  1 sibling, 2 replies; 10+ messages in thread
From: Alexandre Courbot @ 2026-08-28  5:33 UTC (permalink / raw)
  To: Danilo Krummrich, Alice Ryhl, David Airlie, Simona Vetter
  Cc: John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney,
	Zhi Wang, nova-gpu, dri-devel, rust-for-linux, linux-kernel,
	Alexandre Courbot

`FromSafeCast` should be preferred to the `*_as_*` family of functions
when it can be used (i.e. in non-const contexts), as it requires a
single import to perform all valid conversions.

After this patch, the only remaining references to the `casts` module
are those done in const context, which means the `casts` import can be
removed once these are converted to use the `cv!` macro.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
 drivers/gpu/nova-core/falcon/fsp.rs   |  4 ++--
 drivers/gpu/nova-core/firmware/tlv.rs |  4 ++--
 drivers/gpu/nova-core/gsp.rs          |  4 ++--
 drivers/gpu/nova-core/gsp/cmdq.rs     | 19 +++++++++++--------
 drivers/gpu/nova-core/gsp/fw.rs       |  8 ++++----
 5 files changed, 21 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/nova-core/falcon/fsp.rs b/drivers/gpu/nova-core/falcon/fsp.rs
index 2470ac511c98..ece95b1ea8cb 100644
--- a/drivers/gpu/nova-core/falcon/fsp.rs
+++ b/drivers/gpu/nova-core/falcon/fsp.rs
@@ -16,7 +16,7 @@
         },
         Io, //
     },
-    num::casts,
+    num::casts::FromSafeCast,
     prelude::*,
     sizes::SZ_1K,
     time::Delta,
@@ -165,7 +165,7 @@ pub(crate) fn recv_msg(&mut self) -> Result<KVec<u8>> {
             Delta::from_millis(10),
             Delta::from_millis(FSP_MSG_TIMEOUT_MS),
         )
-        .map(casts::u32_as_usize)?;
+        .map(usize::from_safe_cast)?;
 
         // Don't blindly allocate more than the maximum we expect from FSP.
         if msg_size > FSP_EMEM_CHANNEL_0_SIZE {
diff --git a/drivers/gpu/nova-core/firmware/tlv.rs b/drivers/gpu/nova-core/firmware/tlv.rs
index 6653c10e3e0a..7dff8871e338 100644
--- a/drivers/gpu/nova-core/firmware/tlv.rs
+++ b/drivers/gpu/nova-core/firmware/tlv.rs
@@ -5,7 +5,7 @@
     device,
     firmware,
     num::casts::{
-        self,
+        FromSafeCast,
         IntoSafeCast, //
     },
     prelude::*,
@@ -52,7 +52,7 @@ fn parse(hdr: &[u8]) -> Option<Self> {
             return None;
         }
         let len_arr = <[u8; 4]>::try_from(hdr.get(4..Self::SIZE)?).ok()?;
-        let length = casts::u32_as_usize(u32::from_le_bytes(len_arr));
+        let length = usize::from_safe_cast(u32::from_le_bytes(len_arr));
         Some(Self { tag, length })
     }
 }
diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
index fc8648de84c2..0f5275dcb41c 100644
--- a/drivers/gpu/nova-core/gsp.rs
+++ b/drivers/gpu/nova-core/gsp.rs
@@ -17,7 +17,7 @@
         io_write,
         Io, //
     },
-    num::casts,
+    num::casts::FromSafeCast,
     pci,
     prelude::*, //
 };
@@ -92,7 +92,7 @@ fn init(view: CoherentView<'_, Self>, start: DmaAddress) -> Result<()> {
         for i in 0..NUM_PAGES {
             io_write!(view, .0[build: i],
                 start
-                    .checked_add(casts::usize_as_u64(i) << GSP_PAGE_SHIFT)
+                    .checked_add(u64::from_safe_cast(i) << GSP_PAGE_SHIFT)
                     .ok_or(EOVERFLOW)?
             );
         }
diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index f85fde09aa6e..658d0a9b2cfb 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -23,7 +23,10 @@
         Io, //
     },
     new_mutex,
-    num::casts,
+    num::casts::{
+        self,
+        FromSafeCast, //
+    },
     prelude::*,
     ptr,
     sync::{
@@ -289,10 +292,10 @@ fn new(dev: &device::Device<device::Bound>) -> Result<Self> {
         unsafe {
             (
                 core::slice::from_raw_parts_mut(
-                    data.add(casts::u32_as_usize(tx)),
-                    casts::u32_as_usize(tail_end - tx),
+                    data.add(usize::from_safe_cast(tx)),
+                    usize::from_safe_cast(tail_end - tx),
                 ),
-                core::slice::from_raw_parts_mut(data, casts::u32_as_usize(wrap_end)),
+                core::slice::from_raw_parts_mut(data, usize::from_safe_cast(wrap_end)),
             )
         }
     }
@@ -307,7 +310,7 @@ fn driver_write_area_size(&self) -> usize {
         // `cpu_write_ptr`. The minimum value case is where `rx == 0` and `tx == MSGQ_NUM_PAGES -
         // 1`, which gives `0 + MSGQ_NUM_PAGES - (MSGQ_NUM_PAGES - 1) - 1 == 0`.
         let slots = (rx + MSGQ_NUM_PAGES - tx - 1) % MSGQ_NUM_PAGES;
-        casts::u32_as_usize(slots) * GSP_PAGE_SIZE
+        usize::from_safe_cast(slots) * GSP_PAGE_SIZE
     }
 
     /// Returns the region of the GSP message queue that the driver is currently allowed to read
@@ -343,10 +346,10 @@ fn driver_write_area_size(&self) -> usize {
         unsafe {
             (
                 core::slice::from_raw_parts(
-                    data.add(casts::u32_as_usize(rx)),
-                    casts::u32_as_usize(tail_end - rx),
+                    data.add(usize::from_safe_cast(rx)),
+                    usize::from_safe_cast(tail_end - rx),
                 ),
-                core::slice::from_raw_parts(data, casts::u32_as_usize(wrap_end)),
+                core::slice::from_raw_parts(data, usize::from_safe_cast(wrap_end)),
             )
         }
     }
diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs
index 88f083ff1f13..61064b6a251b 100644
--- a/drivers/gpu/nova-core/gsp/fw.rs
+++ b/drivers/gpu/nova-core/gsp/fw.rs
@@ -681,7 +681,7 @@ fn id8(name: &str) -> u64 {
         let init_inner = init!(bindings::LibosMemoryRegionInitArgument {
             id8: id8(name),
             pa: obj.dma_address(),
-            size: casts::usize_as_u64(obj.size()),
+            size: u64::from_safe_cast(obj.size()),
             kind: casts::u32_into_u8::<
                 { bindings::LibosMemoryRegionKind_LIBOS_MEMORY_REGION_CONTIGUOUS },
             >(),
@@ -851,7 +851,7 @@ pub(crate) fn set_checksum(&mut self, checksum: u32) {
     /// Returns the length of the message's payload.
     pub(crate) fn payload_length(&self) -> usize {
         // `rpc.length` includes the length of the RPC message header.
-        casts::u32_as_usize(self.inner.rpc.length)
+        usize::from_safe_cast(self.inner.rpc.length)
             .saturating_sub(size_of::<bindings::rpc_message_header_v>())
     }
 
@@ -948,8 +948,8 @@ fn new(cmdq: &Cmdq) -> impl Init<Self> + '_ {
         init!(MessageQueueInitArguments {
             sharedMemPhysAddr: cmdq.dma_addr,
             pageTableEntryCount: casts::usize_into_u32::<{ Cmdq::NUM_PTES }>(),
-            cmdQueueOffset: casts::usize_as_u64(Cmdq::CMDQ_OFFSET),
-            statQueueOffset: casts::usize_as_u64(Cmdq::STATQ_OFFSET),
+            cmdQueueOffset: u64::from_safe_cast(Cmdq::CMDQ_OFFSET),
+            statQueueOffset: u64::from_safe_cast(Cmdq::STATQ_OFFSET),
             ..Zeroable::init_zeroed()
         })
     }

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/2] gpu: nova-core: use FromSafeCast wherever possible
  2026-08-28  5:33 ` [PATCH 2/2] gpu: nova-core: use FromSafeCast wherever possible Alexandre Courbot
@ 2026-08-28  5:42   ` Eliot Courtney
  2026-08-28  5:49   ` sashiko-bot
  1 sibling, 0 replies; 10+ messages in thread
From: Eliot Courtney @ 2026-08-28  5:42 UTC (permalink / raw)
  To: Alexandre Courbot, Danilo Krummrich, Alice Ryhl, David Airlie,
	Simona Vetter
  Cc: John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney,
	Zhi Wang, nova-gpu, dri-devel, rust-for-linux, linux-kernel,
	dri-devel

On Fri Aug 28, 2026 at 2:33 PM JST, Alexandre Courbot wrote:
> `FromSafeCast` should be preferred to the `*_as_*` family of functions
> when it can be used (i.e. in non-const contexts), as it requires a
> single import to perform all valid conversions.
>
> After this patch, the only remaining references to the `casts` module
> are those done in const context, which means the `casts` import can be
> removed once these are converted to use the `cv!` macro.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> ---

Reviewed-by: Eliot Courtney <ecourtney@nvidia.com>


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] gpu: nova-core: use kernel lossless integer conversion module
  2026-08-28  5:33 ` [PATCH 1/2] gpu: nova-core: use kernel lossless integer conversion module Alexandre Courbot
@ 2026-08-28  5:43   ` sashiko-bot
  2026-08-28 12:09   ` Danilo Krummrich
  1 sibling, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-08-28  5:43 UTC (permalink / raw)
  To: Alexandre Courbot; +Cc: Danilo Krummrich, dri-devel, Alexandre Courbot, ojeda

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] A TOCTOU double-fetch vulnerability in GSP message parsing allows compromised or malicious GSP firmware to corrupt the CPU's message queue read pointer, causing desynchronization and potential denial of service.
--

commit eaaa0723c196a2c00643733ca548b4c1354725ff
Author: Alexandre Courbot <acourbot@nvidia.com>

gpu: nova-core: use kernel lossless integer conversion module

The kernel crate now features a replacement for our lossless integer
conversion routines. Switch to the kernel version and remove our own.

> diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
> index 6da728201281b..f85fde09aa6e3 100644
> --- a/drivers/gpu/nova-core/gsp/cmdq.rs
> +++ b/drivers/gpu/nova-core/gsp/cmdq.rs

[ ... ]

> @@ -162,7 +162,7 @@ fn read(
>  #[repr(C, align(0x1000))]
>  #[derive(Debug)]
>  struct MsgqData {
> -    data: [[u8; GSP_PAGE_SIZE]; num::u32_as_usize(MSGQ_NUM_PAGES)],
> +    data: [[u8; GSP_PAGE_SIZE]; casts::u32_as_usize(MSGQ_NUM_PAGES)],
>  }

[Severity: High]
This isn't a bug introduced by this patch, but while reviewing cmdq.rs, I
noticed a pre-existing double-fetch issue that could allow a compromised GSP
firmware to desynchronize the message queue.

Could the GSP modify the message length in DMA memory after it has been
validated, causing the host to corrupt its CPU read pointer?

In CmdqInner::wait_for_msg(), the message length is fetched from DMA memory
and validated against the available buffer size to ensure it is safe:

CmdqInner::wait_for_msg() {
    ...
    let payload_length = header.payload_length();

    // Check that the driver read area is large enough for the message.
    if slice_1.len() + slice_2.len() < payload_length {
        return Err(EIO);
    }
    ...
}

However, upon returning to CmdqInner::receive_msg(), the length is fetched
a second time directly from the shared memory when advancing the queue read
pointer:

CmdqInner::receive_msg() {
    ...
    let message = self.wait_for_msg(timeout)?;
    ...
    // Advance the read pointer past this message.
    self.gsp_mem.advance_cpu_read_ptr(u32::try_from(
        message.header.length().div_ceil(GSP_PAGE_SIZE),
    )?);
    ...
}

Because message.header is a reference into DMA memory, this second fetch
uses an unvalidated value. If the GSP modifies the length field in DMA
memory between these two reads, the kernel will advance its read pointer by
an unvalidated amount. This could cause the kernel to misinterpret queue
memory, fail subsequent validations, and lose communication with the GSP.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260828-nova_num-v1-0-e21f17ba4127@nvidia.com?part=1

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/2] gpu: nova-core: use FromSafeCast wherever possible
  2026-08-28  5:33 ` [PATCH 2/2] gpu: nova-core: use FromSafeCast wherever possible Alexandre Courbot
  2026-08-28  5:42   ` Eliot Courtney
@ 2026-08-28  5:49   ` sashiko-bot
  1 sibling, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-08-28  5:49 UTC (permalink / raw)
  To: Alexandre Courbot; +Cc: Alexandre Courbot, dri-devel, ojeda, Danilo Krummrich

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [High] Missing DMA write memory barrier before updating the GSP command queue write pointer.
- [High] Missing DMA read memory barrier after reading the GSP message queue write pointer.
--

commit 899e3ba6af7f4cc7e2c28b0f4f3f73db18de1f16
Author: Alexandre Courbot <acourbot@nvidia.com>

gpu: nova-core: use FromSafeCast wherever possible

Replaces various *_as_* casting functions with FromSafeCast in
non-const contexts to simplify conversions.

> diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
> index f85fde09aa6e3..658d0a9b2cfb2 100644
> --- a/drivers/gpu/nova-core/gsp/cmdq.rs
> +++ b/drivers/gpu/nova-core/gsp/cmdq.rs

[ ... ]

> @@ -343,10 +346,10 @@ fn driver_write_area_size(&self) -> usize {
>          unsafe {
>              (
>                  core::slice::from_raw_parts(
> -                    data.add(casts::u32_as_usize(rx)),
> -                    casts::u32_as_usize(tail_end - rx),
> +                    data.add(usize::from_safe_cast(rx)),
> +                    usize::from_safe_cast(tail_end - rx),
>                  ),
> -                core::slice::from_raw_parts(data, casts::u32_as_usize(wrap_end)),
> +                core::slice::from_raw_parts(data, usize::from_safe_cast(wrap_end)),
>              )
>          }
>      }

[Severity: High]
This isn't a bug introduced by this patch, but while reviewing this
file I noticed a potential memory barrier issue in advance_cpu_write_ptr():

>     fn advance_cpu_write_ptr(&mut self, elem_count: u32) {
>         let tx = io_project!(self.0, .cpuq.tx);
>         let wptr = MsgqTxHeader::write_ptr(tx).wrapping_add(elem_count) % MSGQ_NUM_PAGES;
>         MsgqTxHeader::set_write_ptr(tx, wptr);
> 
>         // Ensure all command data is visible before triggering the GSP read.
>         fence(Ordering::SeqCst);
>     }

Because there is no memory barrier between the payload writes (done prior
to calling this function) and the write pointer volatile write in
MsgqTxHeader::set_write_ptr(), the CPU can reorder them.

If the GSP observes the updated write pointer before the payload writes
are globally visible, could it read stale command data?

[Severity: High]
This is also a pre-existing issue, but is there a missing read memory
barrier after reading the message queue write pointer in wait_for_msg()?

>     fn wait_for_msg(&self, timeout: Delta) -> Result<GspMessage<'_>> {
>         // Wait for a message to arrive from the GSP.
>         let (slice_1, slice_2) = read_poll_timeout(
>             || Ok(self.gsp_mem.driver_read_area()),
>             |driver_area| !driver_area.0.is_empty(),
>             Delta::from_millis(1),
>             timeout,
>         )
>         .map(|(slice_1, slice_2)| (slice_1.as_flattened(), slice_2.as_flattened()))?;
> 
>         // Extract the `GspMsgElement`.
>         let (header, slice_1) = GspMsgElement::from_bytes_prefix(slice_1).ok_or(EIO)?;

When polling for a new message, read_poll_timeout repeatedly evaluates
driver_read_area(), which performs a volatile read of the GSP write
pointer.

Once a new message is indicated, the payload memory slices are immediately
accessed.

Since there is no read memory barrier between the volatile read of the
write pointer and the payload access, could modern CPUs speculatively
execute the data loads before the write pointer read completes, causing
the driver to read stale payload data?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260828-nova_num-v1-0-e21f17ba4127@nvidia.com?part=2

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] gpu: nova-core: use kernel lossless integer conversion module
  2026-08-28  5:33 ` [PATCH 1/2] gpu: nova-core: use kernel lossless integer conversion module Alexandre Courbot
  2026-08-28  5:43   ` sashiko-bot
@ 2026-08-28 12:09   ` Danilo Krummrich
  2026-08-28 12:16     ` Miguel Ojeda
  2026-08-29  3:34     ` Alexandre Courbot
  1 sibling, 2 replies; 10+ messages in thread
From: Danilo Krummrich @ 2026-08-28 12:09 UTC (permalink / raw)
  To: Alexandre Courbot, ojeda
  Cc: Alice Ryhl, David Airlie, Simona Vetter, John Hubbard,
	Alistair Popple, Timur Tabi, Eliot Courtney, Zhi Wang, nova-gpu,
	dri-devel, rust-for-linux, linux-kernel

(Cc: Miguel)

On Fri Aug 28, 2026 at 7:33 AM CEST, Alexandre Courbot wrote:
> The `kernel` crate now features a replacement for our lossless integer
> conversion routines. Switch to the kernel version and remove our own.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> Reviewed-by: Danilo Krummrich <dakr@kernel.org>
> Reviewed-by: Eliot Courtney <ecourtney@nvidia.com>
> ---
>  drivers/gpu/nova-core/falcon.rs                    |  12 +-
>  drivers/gpu/nova-core/falcon/fsp.rs                |   4 +-
>  drivers/gpu/nova-core/fb.rs                        |   2 +-
>  drivers/gpu/nova-core/fb/hal/gb100.rs              |   6 +-
>  drivers/gpu/nova-core/firmware.rs                  |   4 +-
>  drivers/gpu/nova-core/firmware/booter.rs           |   4 +-
>  drivers/gpu/nova-core/firmware/fwsec.rs            |   2 +-
>  drivers/gpu/nova-core/firmware/fwsec/bootloader.rs |   4 +-
>  drivers/gpu/nova-core/firmware/gsp.rs              |   9 +-
>  drivers/gpu/nova-core/firmware/tlv.rs              |  11 +-
>  drivers/gpu/nova-core/fsp.rs                       |   8 +-
>  drivers/gpu/nova-core/gsp.rs                       |   4 +-
>  drivers/gpu/nova-core/gsp/cmdq.rs                  |  22 +--
>  drivers/gpu/nova-core/gsp/fw.rs                    |  42 ++--
>  drivers/gpu/nova-core/gsp/fw/commands.rs           |   4 +-
>  drivers/gpu/nova-core/gsp/sequencer.rs             |   2 +-
>  drivers/gpu/nova-core/mctp.rs                      |   8 +-
>  drivers/gpu/nova-core/num.rs                       | 211 ---------------------
>  drivers/gpu/nova-core/vbios.rs                     |   2 +-
>  19 files changed, 78 insertions(+), 283 deletions(-)

Please see the discussion in [1].

If we make this change, then the subsequent conversion to const_as!() would need
to go through the Rust tree next cycle, which could be a bit of a mess, as I'd
expect a bunch of conflicts.

Alternatively, we could the the full three cycle dance, or have a signed tag for
const_as!() and use it right away.

But honestly, the former would just be unnecessary noise. If we don't do the
latter, let's just keep the nova-core num module until the dust has been
settled.

[1] https://lore.kernel.org/all/CANiq72k+-fNWZCwGuQ=FTchxgm-X-f6WR=tG=Ercn19ic1edQg@mail.gmail.com/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] gpu: nova-core: use kernel lossless integer conversion module
  2026-08-28 12:09   ` Danilo Krummrich
@ 2026-08-28 12:16     ` Miguel Ojeda
  2026-08-29  3:34     ` Alexandre Courbot
  1 sibling, 0 replies; 10+ messages in thread
From: Miguel Ojeda @ 2026-08-28 12:16 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: Alexandre Courbot, ojeda, Alice Ryhl, David Airlie, Simona Vetter,
	John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney,
	Zhi Wang, nova-gpu, dri-devel, rust-for-linux, linux-kernel

On Fri, Aug 28, 2026 at 2:09 PM Danilo Krummrich <dakr@kernel.org> wrote:
>
> But honestly, the former would just be unnecessary noise. If we don't do the
> latter, let's just keep the nova-core num module until the dust has been
> settled.

Yeah, keeping the nova `num` for a bit sounds fine.

Cheers,
Miguel

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] gpu: nova-core: use kernel lossless integer conversion module
  2026-08-28 12:09   ` Danilo Krummrich
  2026-08-28 12:16     ` Miguel Ojeda
@ 2026-08-29  3:34     ` Alexandre Courbot
  2026-08-29 19:14       ` Danilo Krummrich
  1 sibling, 1 reply; 10+ messages in thread
From: Alexandre Courbot @ 2026-08-29  3:34 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, Alice Ryhl, David Airlie, Simona Vetter, John Hubbard,
	Alistair Popple, Timur Tabi, Eliot Courtney, Zhi Wang, nova-gpu,
	dri-devel, rust-for-linux, linux-kernel

On Fri Aug 28, 2026 at 9:09 PM JST, Danilo Krummrich wrote:
> (Cc: Miguel)
>
> On Fri Aug 28, 2026 at 7:33 AM CEST, Alexandre Courbot wrote:
>> The `kernel` crate now features a replacement for our lossless integer
>> conversion routines. Switch to the kernel version and remove our own.
>>
>> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
>> Reviewed-by: Danilo Krummrich <dakr@kernel.org>
>> Reviewed-by: Eliot Courtney <ecourtney@nvidia.com>
>> ---
>>  drivers/gpu/nova-core/falcon.rs                    |  12 +-
>>  drivers/gpu/nova-core/falcon/fsp.rs                |   4 +-
>>  drivers/gpu/nova-core/fb.rs                        |   2 +-
>>  drivers/gpu/nova-core/fb/hal/gb100.rs              |   6 +-
>>  drivers/gpu/nova-core/firmware.rs                  |   4 +-
>>  drivers/gpu/nova-core/firmware/booter.rs           |   4 +-
>>  drivers/gpu/nova-core/firmware/fwsec.rs            |   2 +-
>>  drivers/gpu/nova-core/firmware/fwsec/bootloader.rs |   4 +-
>>  drivers/gpu/nova-core/firmware/gsp.rs              |   9 +-
>>  drivers/gpu/nova-core/firmware/tlv.rs              |  11 +-
>>  drivers/gpu/nova-core/fsp.rs                       |   8 +-
>>  drivers/gpu/nova-core/gsp.rs                       |   4 +-
>>  drivers/gpu/nova-core/gsp/cmdq.rs                  |  22 +--
>>  drivers/gpu/nova-core/gsp/fw.rs                    |  42 ++--
>>  drivers/gpu/nova-core/gsp/fw/commands.rs           |   4 +-
>>  drivers/gpu/nova-core/gsp/sequencer.rs             |   2 +-
>>  drivers/gpu/nova-core/mctp.rs                      |   8 +-
>>  drivers/gpu/nova-core/num.rs                       | 211 ---------------------
>>  drivers/gpu/nova-core/vbios.rs                     |   2 +-
>>  19 files changed, 78 insertions(+), 283 deletions(-)
>
> Please see the discussion in [1].
>
> If we make this change, then the subsequent conversion to const_as!() would need
> to go through the Rust tree next cycle, which could be a bit of a mess, as I'd
> expect a bunch of conflicts.
>
> Alternatively, we could the the full three cycle dance, or have a signed tag for
> const_as!() and use it right away.
>
> But honestly, the former would just be unnecessary noise. If we don't do the
> latter, let's just keep the nova-core num module until the dust has been
> settled.
>
> [1] https://lore.kernel.org/all/CANiq72k+-fNWZCwGuQ=FTchxgm-X-f6WR=tG=Ercn19ic1edQg@mail.gmail.com/

Maybe I am missing something, but wouldn't the following work?

- rc1 gets tagged, `drm-rust-next` gets the `num::casts` module,
- This series gets applied to `drm-rust-next`, then `cv!` (without the
  nova-core conversion patch) in `rust-next`,
- We wait one cycle for `cv!` to trickle down to `drm-rust-next` before
  converting nova-core to use `cv!`.

Would that work? This series doesn't overlap with the const conversions
that `cv!` covers on purpose, and it would have the benefit of getting
rid of the local `num` module in nova-core quickly.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] gpu: nova-core: use kernel lossless integer conversion module
  2026-08-29  3:34     ` Alexandre Courbot
@ 2026-08-29 19:14       ` Danilo Krummrich
  0 siblings, 0 replies; 10+ messages in thread
From: Danilo Krummrich @ 2026-08-29 19:14 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: ojeda, Alice Ryhl, David Airlie, Simona Vetter, John Hubbard,
	Alistair Popple, Timur Tabi, Eliot Courtney, Zhi Wang, nova-gpu,
	dri-devel, rust-for-linux, linux-kernel

On Sat Aug 29, 2026 at 5:34 AM CEST, Alexandre Courbot wrote:
> On Fri Aug 28, 2026 at 9:09 PM JST, Danilo Krummrich wrote:
>> (Cc: Miguel)
>>
>> On Fri Aug 28, 2026 at 7:33 AM CEST, Alexandre Courbot wrote:
>>> The `kernel` crate now features a replacement for our lossless integer
>>> conversion routines. Switch to the kernel version and remove our own.
>>>
>>> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
>>> Reviewed-by: Danilo Krummrich <dakr@kernel.org>
>>> Reviewed-by: Eliot Courtney <ecourtney@nvidia.com>
>>> ---
>>>  drivers/gpu/nova-core/falcon.rs                    |  12 +-
>>>  drivers/gpu/nova-core/falcon/fsp.rs                |   4 +-
>>>  drivers/gpu/nova-core/fb.rs                        |   2 +-
>>>  drivers/gpu/nova-core/fb/hal/gb100.rs              |   6 +-
>>>  drivers/gpu/nova-core/firmware.rs                  |   4 +-
>>>  drivers/gpu/nova-core/firmware/booter.rs           |   4 +-
>>>  drivers/gpu/nova-core/firmware/fwsec.rs            |   2 +-
>>>  drivers/gpu/nova-core/firmware/fwsec/bootloader.rs |   4 +-
>>>  drivers/gpu/nova-core/firmware/gsp.rs              |   9 +-
>>>  drivers/gpu/nova-core/firmware/tlv.rs              |  11 +-
>>>  drivers/gpu/nova-core/fsp.rs                       |   8 +-
>>>  drivers/gpu/nova-core/gsp.rs                       |   4 +-
>>>  drivers/gpu/nova-core/gsp/cmdq.rs                  |  22 +--
>>>  drivers/gpu/nova-core/gsp/fw.rs                    |  42 ++--
>>>  drivers/gpu/nova-core/gsp/fw/commands.rs           |   4 +-
>>>  drivers/gpu/nova-core/gsp/sequencer.rs             |   2 +-
>>>  drivers/gpu/nova-core/mctp.rs                      |   8 +-
>>>  drivers/gpu/nova-core/num.rs                       | 211 ---------------------
>>>  drivers/gpu/nova-core/vbios.rs                     |   2 +-
>>>  19 files changed, 78 insertions(+), 283 deletions(-)
>>
>> Please see the discussion in [1].
>>
>> If we make this change, then the subsequent conversion to const_as!() would need
>> to go through the Rust tree next cycle, which could be a bit of a mess, as I'd
>> expect a bunch of conflicts.
>>
>> Alternatively, we could the the full three cycle dance, or have a signed tag for
>> const_as!() and use it right away.
>>
>> But honestly, the former would just be unnecessary noise. If we don't do the
>> latter, let's just keep the nova-core num module until the dust has been
>> settled.
>>
>> [1] https://lore.kernel.org/all/CANiq72k+-fNWZCwGuQ=FTchxgm-X-f6WR=tG=Ercn19ic1edQg@mail.gmail.com/
>
> Maybe I am missing something, but wouldn't the following work?
>
> - rc1 gets tagged, `drm-rust-next` gets the `num::casts` module,
> - This series gets applied to `drm-rust-next`, then `cv!` (without the
>   nova-core conversion patch) in `rust-next`,
> - We wait one cycle for `cv!` to trickle down to `drm-rust-next` before
>   converting nova-core to use `cv!`.
>
> Would that work? This series doesn't overlap with the const conversions
> that `cv!` covers on purpose, and it would have the benefit of getting
> rid of the local `num` module in nova-core quickly.

Take casts::usize_into_u32() for instance, drm-rust-next replaces the usage of
it next cycle, but rust-next wants to remove the API from
rust/kernel/num/casts.rs.

In this case rust-next would need to get rid of the users (including nova-core),
but drm-rust-next will likely do different changes, so we'd get unnecessary
merge conflicts.

You can resolve this either by keeping casts::usize_into_u32 and friends around
for one additional cycle, so that all users we introduce now are gone. Or, since
there's no rush anyways, we just wait one cycle and use the real thing right
away.

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-08-29 19:14 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-28  5:33 [PATCH 0/2] gpu: nova-core: complete conversion to kernel `num` module Alexandre Courbot
2026-08-28  5:33 ` [PATCH 1/2] gpu: nova-core: use kernel lossless integer conversion module Alexandre Courbot
2026-08-28  5:43   ` sashiko-bot
2026-08-28 12:09   ` Danilo Krummrich
2026-08-28 12:16     ` Miguel Ojeda
2026-08-29  3:34     ` Alexandre Courbot
2026-08-29 19:14       ` Danilo Krummrich
2026-08-28  5:33 ` [PATCH 2/2] gpu: nova-core: use FromSafeCast wherever possible Alexandre Courbot
2026-08-28  5:42   ` Eliot Courtney
2026-08-28  5:49   ` sashiko-bot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.