Drivers that operate on 64-bit address spaces (GPU framebuffer layouts,
DMA regions, etc.) frequently need these size constants as a u64 type.
Today this requires repeated usize-to-u64 conversion calls like
usize_as_u64(SZ_1M) or u64::from_safe_cast(SZ_1M), which adds
boilerplate without any safety benefit.
Add u64-typed constants (SZ_1K_U64 through SZ_2G_U64) alongside the
existing usize constants. Every value fits in u64 (actually, within a
u32 for that matter), so the as-cast is always lossless.
Signed-off-by: John Hubbard <jhubbard@nvidia.com>
---
rust/kernel/sizes.rs | 51 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 51 insertions(+)
diff --git a/rust/kernel/sizes.rs b/rust/kernel/sizes.rs
index 661e680d9330..a11c134be64e 100644
--- a/rust/kernel/sizes.rs
+++ b/rust/kernel/sizes.rs
@@ -48,3 +48,54 @@
pub const SZ_1G: usize = bindings::SZ_1G as usize;
/// 0x80000000
pub const SZ_2G: usize = bindings::SZ_2G as usize;
+
+// `u64` variants of the size constants. These are the same values as the
+// `usize` constants above, but typed as `u64` to avoid repeated conversion
+// boilerplate in code that operates on 64-bit address spaces.
+//
+// CAST: every SZ_* value below fits in u64, so `as u64` is always lossless.
+
+/// [`SZ_1K`] as a [`u64`].
+pub const SZ_1K_U64: u64 = SZ_1K as u64;
+/// [`SZ_2K`] as a [`u64`].
+pub const SZ_2K_U64: u64 = SZ_2K as u64;
+/// [`SZ_4K`] as a [`u64`].
+pub const SZ_4K_U64: u64 = SZ_4K as u64;
+/// [`SZ_8K`] as a [`u64`].
+pub const SZ_8K_U64: u64 = SZ_8K as u64;
+/// [`SZ_16K`] as a [`u64`].
+pub const SZ_16K_U64: u64 = SZ_16K as u64;
+/// [`SZ_32K`] as a [`u64`].
+pub const SZ_32K_U64: u64 = SZ_32K as u64;
+/// [`SZ_64K`] as a [`u64`].
+pub const SZ_64K_U64: u64 = SZ_64K as u64;
+/// [`SZ_128K`] as a [`u64`].
+pub const SZ_128K_U64: u64 = SZ_128K as u64;
+/// [`SZ_256K`] as a [`u64`].
+pub const SZ_256K_U64: u64 = SZ_256K as u64;
+/// [`SZ_512K`] as a [`u64`].
+pub const SZ_512K_U64: u64 = SZ_512K as u64;
+/// [`SZ_1M`] as a [`u64`].
+pub const SZ_1M_U64: u64 = SZ_1M as u64;
+/// [`SZ_2M`] as a [`u64`].
+pub const SZ_2M_U64: u64 = SZ_2M as u64;
+/// [`SZ_4M`] as a [`u64`].
+pub const SZ_4M_U64: u64 = SZ_4M as u64;
+/// [`SZ_8M`] as a [`u64`].
+pub const SZ_8M_U64: u64 = SZ_8M as u64;
+/// [`SZ_16M`] as a [`u64`].
+pub const SZ_16M_U64: u64 = SZ_16M as u64;
+/// [`SZ_32M`] as a [`u64`].
+pub const SZ_32M_U64: u64 = SZ_32M as u64;
+/// [`SZ_64M`] as a [`u64`].
+pub const SZ_64M_U64: u64 = SZ_64M as u64;
+/// [`SZ_128M`] as a [`u64`].
+pub const SZ_128M_U64: u64 = SZ_128M as u64;
+/// [`SZ_256M`] as a [`u64`].
+pub const SZ_256M_U64: u64 = SZ_256M as u64;
+/// [`SZ_512M`] as a [`u64`].
+pub const SZ_512M_U64: u64 = SZ_512M as u64;
+/// [`SZ_1G`] as a [`u64`].
+pub const SZ_1G_U64: u64 = SZ_1G as u64;
+/// [`SZ_2G`] as a [`u64`].
+pub const SZ_2G_U64: u64 = SZ_2G as u64;
--
2.53.0
On Tue Mar 10, 2026 at 3:31 AM CET, John Hubbard wrote: > Drivers that operate on 64-bit address spaces (GPU framebuffer layouts, > DMA regions, etc.) frequently need these size constants as a u64 type. > Today this requires repeated usize-to-u64 conversion calls like > usize_as_u64(SZ_1M) or u64::from_safe_cast(SZ_1M), which adds > boilerplate without any safety benefit. > > Add u64-typed constants (SZ_1K_U64 through SZ_2G_U64) alongside the > existing usize constants. Every value fits in u64 (actually, within a > u32 for that matter), so the as-cast is always lossless. > > Signed-off-by: John Hubbard <jhubbard@nvidia.com> Feel free to add: Suggested-by: Danilo Krummrich <dakr@kernel.org> Link: https://lore.kernel.org/all/DGB9G697GSWO.3VBFGU5MKFPMR@kernel.org/ Link: https://lore.kernel.org/all/DGHI8WRKBQS9.38910L6FIIZTE@kernel.org/ As mentioned in the other thread, we could also make this GPU infrastructure and have GPU specific usize / isize types.
On Tue, Mar 10, 2026 at 3:31 AM John Hubbard <jhubbard@nvidia.com> wrote:
>
> +// CAST: every SZ_* value below fits in u64, so `as u64` is always lossless.
Nit:
// CAST: Every `SZ_*` value below fits in `u64`, so `as u64` is
always lossless.
One alternative could be something like `sizes::u64::SZ_1M`, but if
you expect to mix `usize` and `u64` often then it may not be great.
Regarding adding the constants or not, I am ambivalent. On one hand, I
see the pain of repeating it; on the other hand, adding these only
works for particular values (i.e. we still need the safe casts around
anyway for other values).
By the way, why don't we use the safe cast here? They are `const fn`,
right? i.e. that would avoid the need to justify the cast and it would
serve to double-check the cast too.
By the way (x2), if we decide to go with the constants, we may want to
use a macro to generate most of the file, which could allow us to also
have the sizes as `u32` too, in case that is useful (in 32-bit
domains?).
Thanks!
Cheers,
Miguel
On Tue Mar 10, 2026 at 10:51 PM JST, Miguel Ojeda wrote: > On Tue, Mar 10, 2026 at 3:31 AM John Hubbard <jhubbard@nvidia.com> wrote: >> >> +// CAST: every SZ_* value below fits in u64, so `as u64` is always lossless. > > Nit: > > // CAST: Every `SZ_*` value below fits in `u64`, so `as u64` is > always lossless. > > One alternative could be something like `sizes::u64::SZ_1M`, but if > you expect to mix `usize` and `u64` often then it may not be great. How about an extension trait for integer types with all the `SZ_*` defined as constants? That would allow easy implementation for more integer types, like `Bounded`. Because "64 bit" address spaces are often actually less than that, and we might want to work with `Bounded` for them.
On 3/11/26 1:01 AM, Alexandre Courbot wrote: > On Tue Mar 10, 2026 at 10:51 PM JST, Miguel Ojeda wrote: >> On Tue, Mar 10, 2026 at 3:31 AM John Hubbard <jhubbard@nvidia.com> wrote: >>> >>> +// CAST: every SZ_* value below fits in u64, so `as u64` is always lossless. >> >> Nit: >> >> // CAST: Every `SZ_*` value below fits in `u64`, so `as u64` is >> always lossless. >> >> One alternative could be something like `sizes::u64::SZ_1M`, but if >> you expect to mix `usize` and `u64` often then it may not be great. > > How about an extension trait for integer types with all the `SZ_*` > defined as constants? I believe that's what I have locally, with DeviceSize, so I'll go ahead and post it as v2, and let's see how it looks. > > That would allow easy implementation for more integer types, like > `Bounded`. Because "64 bit" address spaces are often actually less than > that, and we might want to work with `Bounded` for them. thanks, -- John Hubbard
On Tue, Mar 10, 2026 at 2:51 PM Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> wrote: > > Regarding adding the constants or not, I am ambivalent. On one hand, I > see the pain of repeating it; on the other hand, adding these only > works for particular values (i.e. we still need the safe casts around > anyway for other values). I see both Daniel and Danilo would like to have them, so that is a strong indicator we likely want them. Thanks both for the replies! Whether we go for `u64::` or not, please feel free to add: Acked-by: Miguel Ojeda <ojeda@kernel.org> Either way, please consider the suggestion about using `const fn` in the definitions here -- or if you prefer, we can put it as a "good first issue" for a separate future improvement. Thanks! Cheers, Miguel
On Tue Mar 10, 2026 at 9:20 PM CET, Miguel Ojeda wrote: > Whether we go for `u64::` or not The more I think about it, the more I tend towards not going for u64::, at least not directly. The point really is that we differentiate between GPU (or more generally device) address space size and CPU address space size. So, I think what we really want is an abstraction of a usize type for GPUs (or devices in general). A corresponding implementation of SZ_* would just follow those. In any case, I think we should implement those with a macro.
On Tue Mar 10, 2026 at 9:47 PM CET, Danilo Krummrich wrote: > On Tue Mar 10, 2026 at 9:20 PM CET, Miguel Ojeda wrote: >> Whether we go for `u64::` or not > > The more I think about it, the more I tend towards not going for u64::, at least > not directly. > > The point really is that we differentiate between GPU (or more generally device) > address space size and CPU address space size. > > So, I think what we really want is an abstraction of a usize type for GPUs (or > devices in general). Forgot to mention, the background of this is that existing DRM components, such as GPUVM, Buddy, etc. just use u64 as a common denominator. However, this becomes annoying when the corresponding device is u32 (or even smaller outside of DRM). Because then we have all the fallible conversions on the other end where the driver interacts with the HW. So, on the Rust side I think we want to abstract this, such that drivers can choose the actual device size type and the corresponding APIs just work with this type and store the actual value in the backing u64 internally, but hand it out as the actual type the driver passed in originally. > A corresponding implementation of SZ_* would just follow those. > > In any case, I think we should implement those with a macro.
On Tue, Mar 10, 2026 at 9:55 PM Danilo Krummrich <dakr@kernel.org> wrote: > > Forgot to mention, the background of this is that existing DRM components, such > as GPUVM, Buddy, etc. just use u64 as a common denominator. However, this > becomes annoying when the corresponding device is u32 (or even smaller outside > of DRM). Because then we have all the fallible conversions on the other end > where the driver interacts with the HW. > > So, on the Rust side I think we want to abstract this, such that drivers can > choose the actual device size type and the corresponding APIs just work with > this type and store the actual value in the backing u64 internally, but hand it > out as the actual type the driver passed in originally. I see, thanks for that context -- yes, if the types are different and known, it would be better to abstract over the right one. (And perhaps it may even make sense to use newtypes too, depending on the details.) Cheers, Miguel
On 3/10/26 3:08 PM, Miguel Ojeda wrote: > On Tue, Mar 10, 2026 at 9:55 PM Danilo Krummrich <dakr@kernel.org> wrote: >> >> Forgot to mention, the background of this is that existing DRM components, such >> as GPUVM, Buddy, etc. just use u64 as a common denominator. However, this >> becomes annoying when the corresponding device is u32 (or even smaller outside >> of DRM). Because then we have all the fallible conversions on the other end >> where the driver interacts with the HW. >> >> So, on the Rust side I think we want to abstract this, such that drivers can >> choose the actual device size type and the corresponding APIs just work with >> this type and store the actual value in the backing u64 internally, but hand it >> out as the actual type the driver passed in originally. > > I see, thanks for that context -- yes, if the types are different and > known, it would be better to abstract over the right one. > > (And perhaps it may even make sense to use newtypes too, depending on > the details.) It might. Because GpuAddr is a bit vague, whereas FbAddr is always going to be u64. OK, I think a define_size!() macro that implements a DeviceSize trait works here. We still end up converting call sites to use sizes::u64::SZ_1M, once DeviceSize is in scope. And then later, one can build on top of that with things such as <T: DeviceSize>, and such. I'll post a v2, assuming that this sounds about right. thanks, -- John Hubbard
On 3/10/26 3:13 PM, John Hubbard wrote: > On 3/10/26 3:08 PM, Miguel Ojeda wrote: >> On Tue, Mar 10, 2026 at 9:55 PM Danilo Krummrich <dakr@kernel.org> wrote: >>> >>> Forgot to mention, the background of this is that existing DRM components, such >>> as GPUVM, Buddy, etc. just use u64 as a common denominator. However, this >>> becomes annoying when the corresponding device is u32 (or even smaller outside >>> of DRM). Because then we have all the fallible conversions on the other end >>> where the driver interacts with the HW. >>> >>> So, on the Rust side I think we want to abstract this, such that drivers can >>> choose the actual device size type and the corresponding APIs just work with >>> this type and store the actual value in the backing u64 internally, but hand it >>> out as the actual type the driver passed in originally. >> >> I see, thanks for that context -- yes, if the types are different and >> known, it would be better to abstract over the right one. >> >> (And perhaps it may even make sense to use newtypes too, depending on >> the details.) > > It might. Because GpuAddr is a bit vague, whereas FbAddr is always going > to be u64. > > OK, I think a define_size!() macro that implements a DeviceSize trait works > here. We still end up converting call sites to use sizes::u64::SZ_1M, once ah, correction, make that u64::SZ_1M, when DeviceSize is in scope. (No sizes:: prefix.) > DeviceSize is in scope. > > And then later, one can build on top of that with things such as > <T: DeviceSize>, and such. > > I'll post a v2, assuming that this sounds about right. > > thanks, thanks, -- John Hubbard
On Tue Mar 10, 2026 at 2:51 PM CET, Miguel Ojeda wrote: > On Tue, Mar 10, 2026 at 3:31 AM John Hubbard <jhubbard@nvidia.com> wrote: >> >> +// CAST: every SZ_* value below fits in u64, so `as u64` is always lossless. > > Nit: > > // CAST: Every `SZ_*` value below fits in `u64`, so `as u64` is > always lossless. > > One alternative could be something like `sizes::u64::SZ_1M`, but if > you expect to mix `usize` and `u64` often then it may not be great. I have a slight preference towards this. It also shoudn't be that bad if we need both, as we could just keep the prefix, i.e. u64::SZ_1M. > Regarding adding the constants or not, I am ambivalent. On one hand, I > see the pain of repeating it; on the other hand, adding these only > works for particular values (i.e. we still need the safe casts around > anyway for other values). In a lot of cases we won't need to go back and forth with those values, as all of the DRM infrastructure works with u64. So, there'd be quite a lot of overhead if everytime we want to initialize something in GPUVM, GPU Buddy, TTM, etc. with one of the SZ_* constants, i.e. we'd need to repeat u64::from_safe_cast(SZ_*) over and over again. This is the main reason why I proposed to have u64 variants in the first place. Technically, if they are not needed for anything else, we could also make them GPU infrastructure, e.g. gpu::SZ_*. Additionally, we could have GPU specific usize and isize types.
> On 10 Mar 2026, at 10:51, Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> wrote: > > On Tue, Mar 10, 2026 at 3:31 AM John Hubbard <jhubbard@nvidia.com> wrote: >> >> +// CAST: every SZ_* value below fits in u64, so `as u64` is always lossless. > > Nit: > > // CAST: Every `SZ_*` value below fits in `u64`, so `as u64` is > always lossless. > > One alternative could be something like `sizes::u64::SZ_1M`, but if > you expect to mix `usize` and `u64` often then it may not be great. > > Regarding adding the constants or not, I am ambivalent. On one hand, I > see the pain of repeating it; on the other hand, adding these only > works for particular values (i.e. we still need the safe casts around > anyway for other values). > I am not necessarily advocating one way or another, but as a further data point: we also have a bit of this boilerplate scattered throughout Tyr. It’d be nice to cut down on it, however it ends up being done in the end. I do think that sizes::u64::SZ_1M does look better than what’s been proposed in the patch, though. > By the way, why don't we use the safe cast here? They are `const fn`, > right? i.e. that would avoid the need to justify the cast and it would > serve to double-check the cast too. > > By the way (x2), if we decide to go with the constants, we may want to > use a macro to generate most of the file, which could allow us to also > have the sizes as `u32` too, in case that is useful (in 32-bit > domains?). > > Thanks! > > Cheers, > Miguel >
© 2016 - 2026 Red Hat, Inc.