* [PATCH 0/2] rust: add functions and traits for lossless integer conversions
@ 2026-07-27 10:15 Alexandre Courbot
2026-07-27 10:15 ` [PATCH 1/2] " Alexandre Courbot
2026-07-27 10:15 ` [PATCH 2/2] gpu: nova-core: use kernel lossless integer conversion module Alexandre Courbot
0 siblings, 2 replies; 8+ messages in thread
From: Alexandre Courbot @ 2026-07-27 10:15 UTC (permalink / raw)
To: Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Onur Özkan, David Airlie, Simona Vetter
Cc: Alexandre Courbot, John Hubbard, Alistair Popple, Timur Tabi,
Eliot Courtney, Zhi Wang, linux-kernel, rust-for-linux, nova-gpu,
dri-devel
This series introduces a copy of the lossless integer conversion
functions/traits of `nova-core` into the `kernel` crate, and makes
`nova-core` use them.
It is way overdue since its RFC [1]; recent dicussions [2] that have
suggested that it might become useful have triggered this posting.
This series is based on `rust-next`.
[1] https://lore.kernel.org/r/20251104-as_casts-v1-1-0a0e95bd2a9f@nvidia.com
[2] https://lore.kernel.org/all/DK82VNBOLWA7.1RFTZQWWNHIEH@nvidia.com/
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
Changes in v1:
- Update to latest version in `nova-core`.
- Make `nova-core` use the kernel crate implementation and remove its
own.
- Link to RFC: https://lore.kernel.org/r/20251104-as_casts-v1-1-0a0e95bd2a9f@nvidia.com
To: Alexandre Courbot <acourbot@nvidia.com>
To: Yury Norov <yury.norov@gmail.com>
To: Miguel Ojeda <ojeda@kernel.org>
To: Boqun Feng <boqun@kernel.org>
To: Gary Guo <gary@garyguo.net>
To: Björn Roy Baron <bjorn3_gh@protonmail.com>
To: Benno Lossin <lossin@kernel.org>
To: Andreas Hindborg <a.hindborg@kernel.org>
To: Alice Ryhl <aliceryhl@google.com>
To: Trevor Gross <tmgross@umich.edu>
To: Danilo Krummrich <dakr@kernel.org>
To: Daniel Almeida <daniel.almeida@collabora.com>
To: Tamir Duberstein <tamird@kernel.org>
To: Onur Özkan <work@onurozkan.dev>
To: David Airlie <airlied@gmail.com>
To: Simona Vetter <simona@ffwll.ch>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Timur Tabi <ttabi@nvidia.com>
Cc: Eliot Courtney <ecourtney@nvidia.com>
Cc: Zhi Wang <zhiw@nvidia.com>
Cc: linux-kernel@vger.kernel.org
Cc: rust-for-linux@vger.kernel.org
Cc: nova-gpu@lists.linux.dev
Cc: dri-devel@lists.freedesktop.org
---
Alexandre Courbot (2):
rust: add functions and traits for lossless integer conversions
gpu: nova-core: use kernel lossless integer conversion module
drivers/gpu/nova-core/falcon.rs | 10 +-
drivers/gpu/nova-core/falcon/fsp.rs | 2 +-
drivers/gpu/nova-core/fb.rs | 2 +-
drivers/gpu/nova-core/fb/hal/gb100.rs | 6 +-
drivers/gpu/nova-core/firmware.rs | 8 +-
drivers/gpu/nova-core/firmware/booter.rs | 10 +-
drivers/gpu/nova-core/firmware/fwsec.rs | 2 +-
drivers/gpu/nova-core/firmware/fwsec/bootloader.rs | 2 +-
drivers/gpu/nova-core/firmware/gsp.rs | 2 +-
drivers/gpu/nova-core/firmware/riscv.rs | 6 +-
drivers/gpu/nova-core/fsp.rs | 2 +-
drivers/gpu/nova-core/gsp.rs | 2 +-
drivers/gpu/nova-core/gsp/cmdq.rs | 4 +-
drivers/gpu/nova-core/gsp/fw.rs | 8 +-
drivers/gpu/nova-core/gsp/sequencer.rs | 2 +-
drivers/gpu/nova-core/num.rs | 211 ------------------
drivers/gpu/nova-core/vbios.rs | 2 +-
rust/kernel/num.rs | 3 +
rust/kernel/num/casts.rs | 248 +++++++++++++++++++++
19 files changed, 286 insertions(+), 246 deletions(-)
---
base-commit: 3dab139d4795f688e4f243e40c7474df00d329d9
change-id: 20251104-as_casts-6a8882ac0192
Best regards,
--
Alexandre Courbot <acourbot@nvidia.com>
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH 1/2] rust: add functions and traits for lossless integer conversions 2026-07-27 10:15 [PATCH 0/2] rust: add functions and traits for lossless integer conversions Alexandre Courbot @ 2026-07-27 10:15 ` Alexandre Courbot 2026-07-27 10:28 ` Gary Guo 2026-07-27 10:15 ` [PATCH 2/2] gpu: nova-core: use kernel lossless integer conversion module Alexandre Courbot 1 sibling, 1 reply; 8+ messages in thread From: Alexandre Courbot @ 2026-07-27 10:15 UTC (permalink / raw) To: Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein, Onur Özkan, David Airlie, Simona Vetter Cc: Alexandre Courbot, John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney, Zhi Wang, linux-kernel, rust-for-linux, nova-gpu, dri-devel The core 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 of supporting larger-than-64bit architectures in the future. However, the kernel supports a narrower set of architectures, with a considerable amount of code that is architecture-specific. This makes it helpful and desirable to provide more infallible conversions, lest we need to rely on the `as` keyword and carry the risk of silently losing data. Thus, introduce a new module `num::casts` that provides safe const functions performing more conversions allowed by the build target, as well as `FromSafeCast` and `IntoSafeCast` traits that are just extensions of `From` and `Into` to conversions that are known to be lossless. Suggested-by: Danilo Krummrich <dakr@kernel.org> Link: https://lore.kernel.org/rust-for-linux/DDK4KADWJHMG.1FUPL3SDR26XF@kernel.org/ Signed-off-by: Alexandre Courbot <acourbot@nvidia.com> --- rust/kernel/num.rs | 3 + rust/kernel/num/casts.rs | 248 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 251 insertions(+) diff --git a/rust/kernel/num.rs b/rust/kernel/num.rs index 8532b511384c..0788c153916c 100644 --- a/rust/kernel/num.rs +++ b/rust/kernel/num.rs @@ -5,7 +5,10 @@ use core::ops; pub mod bounded; +pub mod casts; + pub use bounded::*; +pub use casts::*; /// Designates unsigned primitive types. pub enum Unsigned {} diff --git a/rust/kernel/num/casts.rs b/rust/kernel/num/casts.rs new file mode 100644 index 000000000000..56feda78f0a8 --- /dev/null +++ b/rust/kernel/num/casts.rs @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Helpers for performing lossless integer casts. +//! +//! The `as` keyword can be used to perform casts between integer types, but it unfortunately makes +//! no distinction between casts that are lossless, and casts from a larger type into a smaller one +//! that might silently strip data away. Thus, its use in the kernel is discouraged in favor of +//! [`From`] implementations. +//! +//! Conversely, there are casts that are lossless depending on the build architecture (such as +//! casting [`usize`] to [`u64`] on 32 or 64 bit archs), but not supported by [`From`] +//! implementations in the standard library because they are not portable. It does however make +//! sense for the kernel to support these, if only for code that is architecture-specific. +//! +//! This module provides ways to perform such conversions safely: +//! +//! - A series of const functions (e.g. [`usize_as_u64`]) supporting safe conversions in const +//! context. Conversions supported by [`From`] implementations in the standard library are also +//! covered as the [`From`] trait cannot be used in const context. +//! - Two extension traits, [`FromSafeCast`] and [`IntoSafeCast`], providing conversion methods +//! similar to [`From`] and [`Into`] for conversions that are safe to perform on the current +//! architecture, but not supported by the standard library. +//! - Another series of const functions (e.g. [`u64_into_u8`]) supporting the conversion of a const +//! value from a larger type into a smaller one. This is useful if a constant is available in a +//! larger type, but needs to be used as a smaller one that can accommodate its value. +//! +//! # Examples +//! +//! ``` +//! use kernel::num::{self, FromSafeCast, IntoSafeCast}; +//! +//! // Conversion from const context. +//! const USIZED_CONST: usize = num::u8_as_usize(255u8); +//! +//! // Non-const conversions. +//! let a = u64::from_safe_cast(4096usize); +//! let b: u64 = 4096usize.into_safe_cast(); +//! ``` + +use kernel::macros::paste; +use kernel::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 kernel::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 const fn [<$from _as_ $into>](value: $from) -> $into { + ::kernel::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 of needing 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 kernel::num::FromSafeCast; +/// +/// assert_eq!(usize::from_safe_cast(0xf00u32), 0xf00usize); +/// ``` +pub 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 kernel::num::IntoSafeCast; +/// +/// assert_eq!(0xf00usize, 0xf00u32.into_safe_cast()); +/// ``` +pub 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 kernel::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 const fn [<$from _into_ $into>]<const N: $from>() -> $into { + // Make sure that the target type is smaller than the source one. + ::kernel::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 }); -- 2.55.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] rust: add functions and traits for lossless integer conversions 2026-07-27 10:15 ` [PATCH 1/2] " Alexandre Courbot @ 2026-07-27 10:28 ` Gary Guo 2026-07-27 11:10 ` Miguel Ojeda 2026-07-27 11:19 ` Danilo Krummrich 0 siblings, 2 replies; 8+ messages in thread From: Gary Guo @ 2026-07-27 10:28 UTC (permalink / raw) To: Alexandre Courbot, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein, Onur Özkan, David Airlie, Simona Vetter Cc: John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney, Zhi Wang, linux-kernel, rust-for-linux, nova-gpu, dri-devel On Mon Jul 27, 2026 at 11:15 AM BST, Alexandre Courbot wrote: > The core 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 of supporting larger-than-64bit architectures in the future. > > However, the kernel supports a narrower set of architectures, with a > considerable amount of code that is architecture-specific. This makes it > helpful and desirable to provide more infallible conversions, lest we > need to rely on the `as` keyword and carry the risk of silently losing > data. > > Thus, introduce a new module `num::casts` that provides safe const > functions performing more conversions allowed by the build target, as > well as `FromSafeCast` and `IntoSafeCast` traits that are just > extensions of `From` and `Into` to conversions that are known to be > lossless. I'm okay with having u32 -> usize casts and usize -> u64 casts, but having usize -> u32 and u64 -> usize casts like this series do is worrying as it can be misused from drivers that are supposed to be supporting multiple platforms or core subsystems. Pointer-size dependent drivers that need these casts should define them locally. Best, Gary > > Suggested-by: Danilo Krummrich <dakr@kernel.org> > Link: https://lore.kernel.org/rust-for-linux/DDK4KADWJHMG.1FUPL3SDR26XF@kernel.org/ > Signed-off-by: Alexandre Courbot <acourbot@nvidia.com> > --- > rust/kernel/num.rs | 3 + > rust/kernel/num/casts.rs | 248 +++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 251 insertions(+) ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] rust: add functions and traits for lossless integer conversions 2026-07-27 10:28 ` Gary Guo @ 2026-07-27 11:10 ` Miguel Ojeda 2026-07-27 11:19 ` Danilo Krummrich 1 sibling, 0 replies; 8+ messages in thread From: Miguel Ojeda @ 2026-07-27 11:10 UTC (permalink / raw) To: Gary Guo Cc: Alexandre Courbot, Yury Norov, Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein, Onur Özkan, David Airlie, Simona Vetter, John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney, Zhi Wang, linux-kernel, rust-for-linux, nova-gpu, dri-devel On Mon, Jul 27, 2026 at 12:28 PM Gary Guo <gary@garyguo.net> wrote: > > I'm okay with having u32 -> usize casts and usize -> u64 casts, but having > usize -> u32 and u64 -> usize casts like this series do is worrying as it can be > misused from drivers that are supposed to be supporting multiple platforms or > core subsystems. > > Pointer-size dependent drivers that need these casts should define them locally. Ideally we would define it once, but nevertheless make it explicit enough (somehow) that this makes one not build in certain configs, so that we get no repetition and no confusion. Something like splitting the non-portable ones into a different trait/`mod`/method name/... so that it is very clear that it makes you (i.e. the user) user pointer-size dependent just by e.g. `grep`ing for it. Cheers, Miguel ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] rust: add functions and traits for lossless integer conversions 2026-07-27 10:28 ` Gary Guo 2026-07-27 11:10 ` Miguel Ojeda @ 2026-07-27 11:19 ` Danilo Krummrich 1 sibling, 0 replies; 8+ messages in thread From: Danilo Krummrich @ 2026-07-27 11:19 UTC (permalink / raw) To: Gary Guo Cc: Alexandre Courbot, Yury Norov, Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Daniel Almeida, Tamir Duberstein, Onur Özkan, David Airlie, Simona Vetter, John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney, Zhi Wang, linux-kernel, rust-for-linux, nova-gpu, dri-devel On Mon Jul 27, 2026 at 12:28 PM CEST, Gary Guo wrote: > On Mon Jul 27, 2026 at 11:15 AM BST, Alexandre Courbot wrote: >> The core 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 of supporting larger-than-64bit architectures in the future. >> >> However, the kernel supports a narrower set of architectures, with a >> considerable amount of code that is architecture-specific. This makes it >> helpful and desirable to provide more infallible conversions, lest we >> need to rely on the `as` keyword and carry the risk of silently losing >> data. >> >> Thus, introduce a new module `num::casts` that provides safe const >> functions performing more conversions allowed by the build target, as >> well as `FromSafeCast` and `IntoSafeCast` traits that are just >> extensions of `From` and `Into` to conversions that are known to be >> lossless. > > I'm okay with having u32 -> usize casts and usize -> u64 casts, but having > usize -> u32 and u64 -> usize casts like this series do is worrying as it can be > misused from drivers that are supposed to be supporting multiple platforms or > core subsystems. > > Pointer-size dependent drivers that need these casts should define them locally. I also raised this concern in the context of [1]. On the other hand, it is not as if this can "randomly" break with exotic or niche kernel configs; 32bit vs. 64bit compile tests are well covered. So, as long as we are explicit about it, I think it should be fine. Maybe we can export the non-portable ones with a different name? [1] https://lore.kernel.org/driver-core/DK0BPAHR8IS3.2KLSLH7K448RJ@kernel.org/ ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/2] gpu: nova-core: use kernel lossless integer conversion module 2026-07-27 10:15 [PATCH 0/2] rust: add functions and traits for lossless integer conversions Alexandre Courbot 2026-07-27 10:15 ` [PATCH 1/2] " Alexandre Courbot @ 2026-07-27 10:15 ` Alexandre Courbot 1 sibling, 0 replies; 8+ messages in thread From: Alexandre Courbot @ 2026-07-27 10:15 UTC (permalink / raw) To: Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein, Onur Özkan, David Airlie, Simona Vetter Cc: Alexandre Courbot, John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney, Zhi Wang, linux-kernel, rust-for-linux, nova-gpu, dri-devel The `kernel` crate now features a copy of our lossless integer conversion routines. Switch to the kernel version and remove our own. Signed-off-by: Alexandre Courbot <acourbot@nvidia.com> --- drivers/gpu/nova-core/falcon.rs | 10 +- drivers/gpu/nova-core/falcon/fsp.rs | 2 +- drivers/gpu/nova-core/fb.rs | 2 +- drivers/gpu/nova-core/fb/hal/gb100.rs | 6 +- drivers/gpu/nova-core/firmware.rs | 8 +- drivers/gpu/nova-core/firmware/booter.rs | 10 +- drivers/gpu/nova-core/firmware/fwsec.rs | 2 +- drivers/gpu/nova-core/firmware/fwsec/bootloader.rs | 2 +- drivers/gpu/nova-core/firmware/gsp.rs | 2 +- drivers/gpu/nova-core/firmware/riscv.rs | 6 +- drivers/gpu/nova-core/fsp.rs | 2 +- drivers/gpu/nova-core/gsp.rs | 2 +- drivers/gpu/nova-core/gsp/cmdq.rs | 4 +- drivers/gpu/nova-core/gsp/fw.rs | 8 +- drivers/gpu/nova-core/gsp/sequencer.rs | 2 +- drivers/gpu/nova-core/num.rs | 211 --------------------- drivers/gpu/nova-core/vbios.rs | 2 +- 17 files changed, 35 insertions(+), 246 deletions(-) diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs index 94c7696a6493..3133c6e2f229 100644 --- a/drivers/gpu/nova-core/falcon.rs +++ b/drivers/gpu/nova-core/falcon.rs @@ -23,6 +23,10 @@ }, Io, }, + num::{ + self, + FromSafeCast, // + }, prelude::*, sync::aref::ARef, time::Delta, @@ -33,11 +37,7 @@ driver::Bar0, falcon::hal::LoadMethod, gpu::Chipset, - num::{ - self, - FromSafeCast, // - }, - regs, + regs, // }; pub(crate) mod fsp; diff --git a/drivers/gpu/nova-core/falcon/fsp.rs b/drivers/gpu/nova-core/falcon/fsp.rs index 52cdb84ef0e8..aad919c8471d 100644 --- a/drivers/gpu/nova-core/falcon/fsp.rs +++ b/drivers/gpu/nova-core/falcon/fsp.rs @@ -16,6 +16,7 @@ }, Io, // }, + num, prelude::*, time::Delta, }; @@ -28,7 +29,6 @@ PFalcon2Base, PFalconBase, // }, - num, regs, // }; diff --git a/drivers/gpu/nova-core/fb.rs b/drivers/gpu/nova-core/fb.rs index 725e428154cf..a635be13d0d0 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::FromSafeCast, prelude::*, ptr::{ Alignable, @@ -23,7 +24,6 @@ firmware::gsp::GspFirmware, gpu::Chipset, gsp, - num::FromSafeCast, regs, // }; diff --git a/drivers/gpu/nova-core/fb/hal/gb100.rs b/drivers/gpu/nova-core/fb/hal/gb100.rs index 6e0eba101ca1..91461433c5d0 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::{ + usize_into_u32, + Bounded, // + }, prelude::*, ptr::{ const_align_up, @@ -23,7 +26,6 @@ use crate::{ driver::Bar0, fb::hal::FbHal, - num::usize_into_u32, regs, // }; diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs index 1e89390209f5..03571251b490 100644 --- a/drivers/gpu/nova-core/firmware.rs +++ b/drivers/gpu/nova-core/firmware.rs @@ -10,6 +10,10 @@ use kernel::{ device, firmware, + num::{ + FromSafeCast, + IntoSafeCast, // + }, prelude::*, str::CString, transmute::FromBytes, // @@ -21,10 +25,6 @@ FalconFirmware, // }, gpu, - num::{ - FromSafeCast, - IntoSafeCast, // - }, }; pub(crate) mod booter; diff --git a/drivers/gpu/nova-core/firmware/booter.rs b/drivers/gpu/nova-core/firmware/booter.rs index d9313ac361af..0645677dcc30 100644 --- a/drivers/gpu/nova-core/firmware/booter.rs +++ b/drivers/gpu/nova-core/firmware/booter.rs @@ -10,6 +10,10 @@ use kernel::{ device, dma::Coherent, + num::{ + FromSafeCast, + IntoSafeCast, // + }, prelude::*, transmute::FromBytes, // }; @@ -31,11 +35,7 @@ Signed, Unsigned, // }, - gpu::Chipset, - num::{ - FromSafeCast, - IntoSafeCast, // - }, + gpu::Chipset, // }; /// Local convenience function to return a copy of `S` by reinterpreting the bytes starting at diff --git a/drivers/gpu/nova-core/firmware/fwsec.rs b/drivers/gpu/nova-core/firmware/fwsec.rs index 199ae2adb664..e856eb698300 100644 --- a/drivers/gpu/nova-core/firmware/fwsec.rs +++ b/drivers/gpu/nova-core/firmware/fwsec.rs @@ -19,6 +19,7 @@ self, Device, // }, + num::FromSafeCast, prelude::*, transmute::{ AsBytes, @@ -43,7 +44,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 039920dc340b..7d82c0ca33a5 100644 --- a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs +++ b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs @@ -17,6 +17,7 @@ register::WithBase, // Io, }, + num::FromSafeCast, prelude::*, ptr::{ Alignable, @@ -51,7 +52,6 @@ FIRMWARE_VERSION, // }, gpu::Chipset, - num::FromSafeCast, regs, }; diff --git a/drivers/gpu/nova-core/firmware/gsp.rs b/drivers/gpu/nova-core/firmware/gsp.rs index 99a302bae567..87ed9d4ede08 100644 --- a/drivers/gpu/nova-core/firmware/gsp.rs +++ b/drivers/gpu/nova-core/firmware/gsp.rs @@ -8,6 +8,7 @@ DataDirection, DmaAddress, // }, + num::FromSafeCast, prelude::*, scatterlist::{ Owned, @@ -25,7 +26,6 @@ Chipset, // }, gsp::GSP_PAGE_SIZE, - num::FromSafeCast, }; /// GSP firmware with 3-level radix page tables for the GSP bootloader. diff --git a/drivers/gpu/nova-core/firmware/riscv.rs b/drivers/gpu/nova-core/firmware/riscv.rs index 2afa7f36404e..572c2815a053 100644 --- a/drivers/gpu/nova-core/firmware/riscv.rs +++ b/drivers/gpu/nova-core/firmware/riscv.rs @@ -7,14 +7,12 @@ device, dma::Coherent, firmware::Firmware, + num::FromSafeCast, prelude::*, transmute::FromBytes, // }; -use crate::{ - firmware::BinFirmware, - num::FromSafeCast, // -}; +use crate::firmware::BinFirmware; /// Descriptor for microcode running on a RISC-V core. #[repr(C)] diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs index 8fc243c66e35..ae529652b3eb 100644 --- a/drivers/gpu/nova-core/fsp.rs +++ b/drivers/gpu/nova-core/fsp.rs @@ -11,6 +11,7 @@ device, dma::Coherent, io::poll::read_poll_timeout, + num, prelude::*, ptr::{ Alignable, @@ -42,7 +43,6 @@ NvdmHeader, NvdmType, // }, - num, regs, // }; diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs index 69175ca3315c..75f7bfe50976 100644 --- a/drivers/gpu/nova-core/gsp.rs +++ b/drivers/gpu/nova-core/gsp.rs @@ -11,6 +11,7 @@ CoherentBox, DmaAddress, // }, + num, pci, prelude::*, transmute::{ @@ -36,7 +37,6 @@ GspArgumentsPadded, LibosMemoryRegionInitArgument, // }, - num, }; pub(crate) const GSP_PAGE_SHIFT: usize = 12; diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs index 070de0731e95..513542ed7924 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -16,6 +16,7 @@ Io, // }, new_mutex, + num, prelude::*, ptr, sync::{ @@ -26,7 +27,7 @@ transmute::{ AsBytes, FromBytes, // - }, + }, // }; use continuation::{ @@ -50,7 +51,6 @@ GSP_PAGE_SHIFT, GSP_PAGE_SIZE, // }, - num, regs, sbuffer::SBufferIter, // }; diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs index 4db0cfa4dc4d..755015a2eff1 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -11,6 +11,10 @@ use kernel::{ dma::Coherent, + num::{ + self, + FromSafeCast, // + }, prelude::*, ptr::{ Alignable, @@ -38,10 +42,6 @@ cmdq::Cmdq, // GSP_PAGE_SIZE, }, - num::{ - self, - FromSafeCast, // - }, }; // TODO: Replace with `IoView` projections once available. diff --git a/drivers/gpu/nova-core/gsp/sequencer.rs b/drivers/gpu/nova-core/gsp/sequencer.rs index e0850d21adca..2ee84178628f 100644 --- a/drivers/gpu/nova-core/gsp/sequencer.rs +++ b/drivers/gpu/nova-core/gsp/sequencer.rs @@ -10,6 +10,7 @@ poll::read_poll_timeout, Io, // }, + num::FromSafeCast, prelude::*, time::{ delay::fsleep, @@ -32,7 +33,6 @@ }, fw, }, - num::FromSafeCast, sbuffer::SBufferIter, }; 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 c6e6bfcd6a1f..9bce9a4b2286 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::FromSafeCast, prelude::*, ptr::{ Alignable, @@ -26,7 +27,6 @@ FalconUCodeDescV2, FalconUCodeDescV3, // }, - num::FromSafeCast, }; /// BIOS Image Type from PCI Data Structure code_type field. -- 2.55.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 0/2] rust: num: casts: replace const type narrowing methods with a macro
@ 2026-08-25 2:44 Alexandre Courbot
2026-08-25 2:44 ` [PATCH 2/2] gpu: nova-core: use kernel lossless integer conversion module Alexandre Courbot
0 siblings, 1 reply; 8+ messages in thread
From: Alexandre Courbot @ 2026-08-25 2:44 UTC (permalink / raw)
To: Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Onur Özkan
Cc: John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney,
Zhi Wang, rust-for-linux, linux-kernel, nova-gpu,
Alexandre Courbot
The `casts` module includes lossless const converter functions, as it is
sometimes necessary to cast a bindgen-generated constant into a narrower
type. Such conversions are known to be lossless at compile-time, but
using `as` for them still requires a `CAST` comment and carries the risk
of the conversion becoming lossy should the value of the constant
change.
Since these functions need to be evaluated at compile-time, they take
the expression to narrow as a generic const argument, requiring the use
of the turbofish syntax by callers. Also, a dedicated function is needed
per type conversion, resulting in 9 functions generated by a single
macro. All these factors make them hard to discover and a bit cumbersome
to use.
This series replaces these functions with a single `const_as` macro that
ensures an `as` conversion is lossless at build-time. Since it is unique
and not generated, it is easy to discover, and its syntax also looks
more accessible than the turbofish one.
Patch 2 then performs the conversion of nova-core to use these
conversion helpers in the process of removing its own superseded `num`
module.
This series is based on today's `master`.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
Alexandre Courbot (2):
rust: num: casts: replace const type narrowing methods with a macro
gpu: nova-core: use kernel lossless integer conversion module
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 | 9 +-
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 | 50 ++---
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 +-
rust/kernel/num/casts.rs | 129 ++++++++-----
20 files changed, 163 insertions(+), 338 deletions(-)
---
base-commit: 66498c75b4f8017f62d720d9b59675bdf3abce91
change-id: 20260825-const_as-a792dad39943
Best regards,
--
Alexandre Courbot <acourbot@nvidia.com>
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH 2/2] gpu: nova-core: use kernel lossless integer conversion module 2026-08-25 2:44 [PATCH 0/2] rust: num: casts: replace const type narrowing methods with a macro Alexandre Courbot @ 2026-08-25 2:44 ` Alexandre Courbot 2026-08-25 5:27 ` Eliot Courtney 0 siblings, 1 reply; 8+ messages in thread From: Alexandre Courbot @ 2026-08-25 2:44 UTC (permalink / raw) To: Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein, Onur Özkan Cc: John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney, Zhi Wang, rust-for-linux, linux-kernel, nova-gpu, 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> --- 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 | 9 +- 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 | 50 ++--- 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, 84 insertions(+), 288 deletions(-) diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs index 65cb12d26e2b..eb54aa41e8bf 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::const_as!(MEM_BLOCK_ALIGNMENT => u32); // 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..8fb94696c715 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, + Bounded, // + }, prelude::*, ptr::{ const_align_up, @@ -26,7 +29,6 @@ hal::FbHal, regs, // }, - num::usize_into_u32, }; struct Gb100; @@ -82,7 +84,8 @@ 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() }>( + casts::const_as!( + const_align_up(SZ_8M + SZ_16M + SZ_4K, Alignment::new::<SZ_128K>()).unwrap() => u32 ) } 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..bd8505addd25 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::const_as!(core::mem::size_of::<NvdmPayloadCot>() => u16); 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..99e775f6071e 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::const_as!(size_of::<Msgq>() => u32); + const RX_HDR_OFF: u32 = casts::const_as!(mem::offset_of!(Msgq, rx) => u32); 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..c05991a72e48 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,13 +681,13 @@ 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::< - { bindings::LibosMemoryRegionKind_LIBOS_MEMORY_REGION_CONTIGUOUS }, - >(), - loc: num::u32_into_u8::< - { bindings::LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_SYSMEM }, - >(), + size: casts::usize_as_u64(obj.size()), + kind: casts::const_as!( + bindings::LibosMemoryRegionKind_LIBOS_MEMORY_REGION_CONTIGUOUS => u8 + ), + loc: casts::const_as!( + bindings::LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_SYSMEM => u8 + ), ..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::const_as!(GSP_PAGE_SIZE => u32), msgCount: msg_count, writePtr: 0, flags: 1, rxHdrOff: rx_hdr_offset, - entryOff: num::usize_into_u32::<GSP_PAGE_SIZE>(), + entryOff: casts::const_as!(GSP_PAGE_SIZE => u32), }) } @@ -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::const_as!(Cmdq::NUM_PTES => u32), + 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::const_as!(size_of::<GspFwWprMeta>() => u32), 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] 8+ messages in thread
* Re: [PATCH 2/2] gpu: nova-core: use kernel lossless integer conversion module 2026-08-25 2:44 ` [PATCH 2/2] gpu: nova-core: use kernel lossless integer conversion module Alexandre Courbot @ 2026-08-25 5:27 ` Eliot Courtney 0 siblings, 0 replies; 8+ messages in thread From: Eliot Courtney @ 2026-08-25 5:27 UTC (permalink / raw) To: Alexandre Courbot, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein, Onur Özkan Cc: John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney, Zhi Wang, rust-for-linux, linux-kernel, nova-gpu On Tue Aug 25, 2026 at 11:44 AM JST, 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> > --- nit: casts:: prefix feels noisy to me in actual usages - just import const_as!, etc and use them directly? Reviewed-by: Eliot Courtney <ecourtney@nvidia.com> ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-08-25 5:27 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-27 10:15 [PATCH 0/2] rust: add functions and traits for lossless integer conversions Alexandre Courbot 2026-07-27 10:15 ` [PATCH 1/2] " Alexandre Courbot 2026-07-27 10:28 ` Gary Guo 2026-07-27 11:10 ` Miguel Ojeda 2026-07-27 11:19 ` Danilo Krummrich 2026-07-27 10:15 ` [PATCH 2/2] gpu: nova-core: use kernel lossless integer conversion module Alexandre Courbot -- strict thread matches above, loose matches on Subject: below -- 2026-08-25 2:44 [PATCH 0/2] rust: num: casts: replace const type narrowing methods with a macro Alexandre Courbot 2026-08-25 2:44 ` [PATCH 2/2] gpu: nova-core: use kernel lossless integer conversion module Alexandre Courbot 2026-08-25 5:27 ` Eliot Courtney
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox