[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <28ABEB7D-BE54-4625-AB9F-BB030FDD6723@collabora.com>
Date: Thu, 22 Jan 2026 19:09:03 -0300
From: Daniel Almeida <daniel.almeida@...labora.com>
To: Alice Ryhl <aliceryhl@...gle.com>
Cc: Danilo Krummrich <dakr@...nel.org>,
Boris Brezillon <boris.brezillon@...labora.com>,
Janne Grunau <j@...nau.net>,
Matthew Brost <matthew.brost@...el.com>,
Thomas Hellström <thomas.hellstrom@...ux.intel.com>,
Lyude Paul <lyude@...hat.com>,
Asahi Lina <lina+kernel@...hilina.net>,
dri-devel@...ts.freedesktop.org,
linux-kernel@...r.kernel.org,
rust-for-linux@...r.kernel.org
Subject: Re: [PATCH v3 4/6] rust: gpuvm: add GpuVa struct
> On 21 Jan 2026, at 08:31, Alice Ryhl <aliceryhl@...gle.com> wrote:
>
> This struct will be used to keep track of individual mapped ranges in
> the GPU's virtual memory.
>
> Co-developed-by: Asahi Lina <lina+kernel@...hilina.net>
> Signed-off-by: Asahi Lina <lina+kernel@...hilina.net>
> Co-developed-by: Daniel Almeida <daniel.almeida@...labora.com>
> Signed-off-by: Daniel Almeida <daniel.almeida@...labora.com>
> Signed-off-by: Alice Ryhl <aliceryhl@...gle.com>
> ---
> rust/kernel/drm/gpuvm/mod.rs | 17 ++++-
> rust/kernel/drm/gpuvm/va.rs | 149 +++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 164 insertions(+), 2 deletions(-)
>
> diff --git a/rust/kernel/drm/gpuvm/mod.rs b/rust/kernel/drm/gpuvm/mod.rs
> index cb576a7ffa07bc108704e008b7f87de52a837930..2179ddd717d8728bbe231bd94ea7b5d1e2652543 100644
> --- a/rust/kernel/drm/gpuvm/mod.rs
> +++ b/rust/kernel/drm/gpuvm/mod.rs
> @@ -11,7 +11,10 @@
> //! C header: [`include/drm/drm_gpuvm.h`](srctree/include/drm/drm_gpuvm.h)
>
> use kernel::{
> - alloc::AllocError,
> + alloc::{
> + AllocError,
> + Flags as AllocFlags, //
> + },
> bindings,
> drm,
> drm::gem::IntoGEMObject,
> @@ -25,9 +28,13 @@
>
> use core::{
> cell::UnsafeCell,
> - mem::ManuallyDrop,
> + mem::{
> + ManuallyDrop,
> + MaybeUninit, //
> + },
> ops::{
> Deref,
> + DerefMut,
> Range, //
> },
> ptr::{
> @@ -36,6 +43,9 @@
> }, //
> };
>
> +mod va;
> +pub use self::va::*;
> +
> mod vm_bo;
> pub use self::vm_bo::*;
>
> @@ -224,6 +234,9 @@ pub trait DriverGpuVm: Sized {
> /// The kind of GEM object stored in this GPUVM.
> type Object: IntoGEMObject;
>
> + /// Data stored with each `struct drm_gpuva`.
> + type VaData;
> +
> /// Data stored with each `struct drm_gpuvm_bo`.
> type VmBoData;
> }
> diff --git a/rust/kernel/drm/gpuvm/va.rs b/rust/kernel/drm/gpuvm/va.rs
> new file mode 100644
> index 0000000000000000000000000000000000000000..c96796a6b2c8c7c4b5475324562968ca0f07fd09
> --- /dev/null
> +++ b/rust/kernel/drm/gpuvm/va.rs
> @@ -0,0 +1,149 @@
> +// SPDX-License-Identifier: GPL-2.0 OR MIT
> +
> +#![expect(dead_code)]
> +use super::*;
> +
> +/// Represents that a range of a GEM object is mapped in this [`GpuVm`] instance.
> +///
> +/// Does not assume that GEM lock is held.
> +///
> +/// # Invariants
> +///
> +/// This is a valid `drm_gpuva` that is resident in the [`GpuVm`] instance.
> +#[repr(C)]
> +#[pin_data]
> +pub struct GpuVa<T: DriverGpuVm> {
> + #[pin]
> + inner: Opaque<bindings::drm_gpuva>,
> + #[pin]
> + data: T::VaData,
> +}
> +
> +impl<T: DriverGpuVm> GpuVa<T> {
> + /// Access this [`GpuVa`] from a raw pointer.
> + ///
> + /// # Safety
> + ///
> + /// For the duration of `'a`, the pointer must reference a valid `drm_gpuva` associated with a
> + /// [`GpuVm<T>`].
> + #[inline]
> + pub unsafe fn from_raw<'a>(ptr: *mut bindings::drm_gpuva) -> &'a Self {
> + // SAFETY: `drm_gpuva` is first field and `repr(C)`.
> + unsafe { &*ptr.cast() }
> + }
> +
> + /// Returns a raw pointer to underlying C value.
> + #[inline]
> + pub fn as_raw(&self) -> *mut bindings::drm_gpuva {
> + self.inner.get()
> + }
> +
> + /// Returns the address of this mapping in the GPU virtual address space.
> + #[inline]
> + pub fn addr(&self) -> u64 {
> + // SAFETY: The `va.addr` field of `drm_gpuva` is immutable.
> + unsafe { (*self.as_raw()).va.addr }
> + }
> +
> + /// Returns the length of this mapping.
> + #[inline]
> + pub fn length(&self) -> u64 {
> + // SAFETY: The `va.range` field of `drm_gpuva` is immutable.
> + unsafe { (*self.as_raw()).va.range }
> + }
> +
> + /// Returns `addr..addr+length`.
> + #[inline]
> + pub fn range(&self) -> Range<u64> {
> + let addr = self.addr();
> + addr..addr + self.length()
> + }
> +
> + /// Returns the offset within the GEM object.
> + #[inline]
> + pub fn gem_offset(&self) -> u64 {
> + // SAFETY: The `gem.offset` field of `drm_gpuva` is immutable.
> + unsafe { (*self.as_raw()).gem.offset }
> + }
> +
> + /// Returns the GEM object.
> + #[inline]
> + pub fn obj(&self) -> &T::Object {
> + // SAFETY: The `gem.offset` field of `drm_gpuva` is immutable.
> + unsafe { <T::Object as IntoGEMObject>::from_raw((*self.as_raw()).gem.obj) }
> + }
> +
> + /// Returns the underlying [`GpuVmBo`] object that backs this [`GpuVa`].
> + #[inline]
> + pub fn vm_bo(&self) -> &GpuVmBo<T> {
> + // SAFETY: The `vm_bo` field has been set and is immutable for the duration in which this
> + // `drm_gpuva` is resident in the VM.
> + unsafe { GpuVmBo::from_raw((*self.as_raw()).vm_bo) }
> + }
> +}
> +
> +/// A pre-allocated [`GpuVa`] object.
> +///
> +/// # Invariants
> +///
> +/// The memory is zeroed.
> +pub struct GpuVaAlloc<T: DriverGpuVm>(KBox<MaybeUninit<GpuVa<T>>>);
> +
> +impl<T: DriverGpuVm> GpuVaAlloc<T> {
> + /// Pre-allocate a [`GpuVa`] object.
> + pub fn new(flags: AllocFlags) -> Result<GpuVaAlloc<T>, AllocError> {
> + // INVARIANTS: Memory allocated with __GFP_ZERO.
> + Ok(GpuVaAlloc(KBox::new_uninit(flags | __GFP_ZERO)?))
> + }
> +
> + /// Prepare this `drm_gpuva` for insertion into the GPUVM.
> + pub(super) fn prepare(mut self, va_data: impl PinInit<T::VaData>) -> *mut bindings::drm_gpuva {
> + let va_ptr = MaybeUninit::as_mut_ptr(&mut self.0);
> + // SAFETY: The `data` field is pinned.
> + let Ok(()) = unsafe { va_data.__pinned_init(&raw mut (*va_ptr).data) };
> + KBox::into_raw(self.0).cast()
> + }
> +}
> +
> +/// A [`GpuVa`] object that has been removed.
> +///
> +/// # Invariants
> +///
> +/// The `drm_gpuva` is not resident in the [`GpuVm`].
> +pub struct GpuVaRemoved<T: DriverGpuVm>(KBox<GpuVa<T>>);
> +
> +impl<T: DriverGpuVm> GpuVaRemoved<T> {
> + /// Convert a raw pointer into a [`GpuVaRemoved`].
> + ///
> + /// # Safety
> + ///
> + /// Must have been removed from a [`GpuVm<T>`].
> + pub(super) unsafe fn from_raw(ptr: *mut bindings::drm_gpuva) -> Self {
> + // SAFETY: Since it has been removed we can take ownership of allocation.
> + GpuVaRemoved(unsafe { KBox::from_raw(ptr.cast()) })
> + }
> +
> + /// Take ownership of the VA data.
> + pub fn into_inner(self) -> T::VaData
> + where
> + T::VaData: Unpin,
> + {
> + KBox::into_inner(self.0).data
> + }
> +}
> +
> +impl<T: DriverGpuVm> Deref for GpuVaRemoved<T> {
> + type Target = T::VaData;
> + fn deref(&self) -> &T::VaData {
> + &self.0.data
> + }
> +}
> +
> +impl<T: DriverGpuVm> DerefMut for GpuVaRemoved<T>
> +where
> + T::VaData: Unpin,
> +{
> + fn deref_mut(&mut self) -> &mut T::VaData {
> + &mut self.0.data
> + }
> +}
>
> --
> 2.52.0.457.g6b5491de43-goog
>
Reviewed-by: Daniel Almeida <daniel.almeida@...labora.com>
Powered by blists - more mailing lists