xref: /linux/rust/kernel/drm/gpuvm/mod.rs (revision 9611c0ce215a66770ccbe5c126bf57ba8c31bcad)
182b78182SAsahi Lina // SPDX-License-Identifier: GPL-2.0 OR MIT
282b78182SAsahi Lina 
3*37f748edSAlice Ryhl #![cfg(CONFIG_RUST_DRM_GPUVM)]
482b78182SAsahi Lina 
582b78182SAsahi Lina //! DRM GPUVM in immediate mode
682b78182SAsahi Lina //!
782b78182SAsahi Lina //! Rust abstractions for using GPUVM in immediate mode. This is when the GPUVM state is updated
882b78182SAsahi Lina //! during `run_job()`, i.e., in the DMA fence signalling critical path, to ensure that the GPUVM
982b78182SAsahi Lina //! and the GPU's virtual address space has the same state at all times.
1082b78182SAsahi Lina //!
1182b78182SAsahi Lina //! C header: [`include/drm/drm_gpuvm.h`](srctree/include/drm/drm_gpuvm.h)
1282b78182SAsahi Lina 
1382b78182SAsahi Lina use kernel::{
145540a9c7SAlice Ryhl     alloc::{
155540a9c7SAlice Ryhl         AllocError,
165540a9c7SAlice Ryhl         Flags as AllocFlags, //
175540a9c7SAlice Ryhl     },
1882b78182SAsahi Lina     bindings,
1982b78182SAsahi Lina     drm,
2082b78182SAsahi Lina     drm::gem::IntoGEMObject,
21dc384604SAlice Ryhl     error::to_result,
2282b78182SAsahi Lina     prelude::*,
2382b78182SAsahi Lina     sync::aref::{
2482b78182SAsahi Lina         ARef,
2582b78182SAsahi Lina         AlwaysRefCounted, //
2682b78182SAsahi Lina     },
2782b78182SAsahi Lina     types::Opaque, //
2882b78182SAsahi Lina };
2982b78182SAsahi Lina 
3082b78182SAsahi Lina use core::{
3182b78182SAsahi Lina     cell::UnsafeCell,
32dc384604SAlice Ryhl     marker::PhantomData,
335540a9c7SAlice Ryhl     mem::{
345540a9c7SAlice Ryhl         ManuallyDrop,
355540a9c7SAlice Ryhl         MaybeUninit, //
365540a9c7SAlice Ryhl     },
3782b78182SAsahi Lina     ops::{
3882b78182SAsahi Lina         Deref,
395540a9c7SAlice Ryhl         DerefMut,
4082b78182SAsahi Lina         Range, //
4182b78182SAsahi Lina     },
4271a39211SAlice Ryhl     ptr::{
4371a39211SAlice Ryhl         self,
4471a39211SAlice Ryhl         NonNull, //
4571a39211SAlice Ryhl     }, //
4682b78182SAsahi Lina };
4782b78182SAsahi Lina 
48dc384604SAlice Ryhl mod sm_ops;
49dc384604SAlice Ryhl pub use self::sm_ops::*;
505540a9c7SAlice Ryhl 
5171a39211SAlice Ryhl mod vm_bo;
5271a39211SAlice Ryhl pub use self::vm_bo::*;
5371a39211SAlice Ryhl 
54dc384604SAlice Ryhl mod va;
55dc384604SAlice Ryhl pub use self::va::*;
56dc384604SAlice Ryhl 
5782b78182SAsahi Lina /// A DRM GPU VA manager.
5882b78182SAsahi Lina ///
5982b78182SAsahi Lina /// This object is refcounted, but the locations of mapped ranges may only be accessed or changed
6082b78182SAsahi Lina /// via the special unique handle [`UniqueRefGpuVm`].
6182b78182SAsahi Lina ///
6282b78182SAsahi Lina /// # Invariants
6382b78182SAsahi Lina ///
6482b78182SAsahi Lina /// * Stored in an allocation managed by the refcount in `self.vm`.
6582b78182SAsahi Lina /// * Access to `data` and the gpuvm interval tree is controlled via the [`UniqueRefGpuVm`] type.
665540a9c7SAlice Ryhl /// * Does not contain any sparse [`GpuVa<T>`] instances.
6782b78182SAsahi Lina #[pin_data]
6882b78182SAsahi Lina pub struct GpuVm<T: DriverGpuVm> {
6982b78182SAsahi Lina     #[pin]
7082b78182SAsahi Lina     vm: Opaque<bindings::drm_gpuvm>,
7182b78182SAsahi Lina     /// Accessed only through the [`UniqueRefGpuVm`] reference.
7282b78182SAsahi Lina     data: UnsafeCell<T>,
7382b78182SAsahi Lina }
7482b78182SAsahi Lina 
7582b78182SAsahi Lina // SAFETY: The GPUVM api does not assume that it is tied to a specific thread. The destructor will
7682b78182SAsahi Lina // drop the `data` field, which is okay because it is guaranteed `Send` by the `DriverGpuVm` trait.
7782b78182SAsahi Lina unsafe impl<T: DriverGpuVm> Send for GpuVm<T> {}
7882b78182SAsahi Lina // SAFETY: The GPUVM api is designed to allow &self methods to be called in parallel.
7982b78182SAsahi Lina unsafe impl<T: DriverGpuVm> Sync for GpuVm<T> {}
8082b78182SAsahi Lina 
8182b78182SAsahi Lina // SAFETY: By type invariants, the allocation is managed by the refcount in `self.vm`.
8282b78182SAsahi Lina unsafe impl<T: DriverGpuVm> AlwaysRefCounted for GpuVm<T> {
8382b78182SAsahi Lina     fn inc_ref(&self) {
8482b78182SAsahi Lina         // SAFETY: By type invariants, the allocation is managed by the refcount in `self.vm`.
8582b78182SAsahi Lina         unsafe { bindings::drm_gpuvm_get(self.vm.get()) };
8682b78182SAsahi Lina     }
8782b78182SAsahi Lina 
8882b78182SAsahi Lina     unsafe fn dec_ref(obj: NonNull<Self>) {
8982b78182SAsahi Lina         // SAFETY: By type invariants, the allocation is managed by the refcount in `self.vm`.
9082b78182SAsahi Lina         unsafe { bindings::drm_gpuvm_put((*obj.as_ptr()).vm.get()) };
9182b78182SAsahi Lina     }
9282b78182SAsahi Lina }
9382b78182SAsahi Lina 
9482b78182SAsahi Lina impl<T: DriverGpuVm> PartialEq for GpuVm<T> {
9582b78182SAsahi Lina     #[inline]
9682b78182SAsahi Lina     fn eq(&self, other: &Self) -> bool {
9782b78182SAsahi Lina         core::ptr::eq(self.as_raw(), other.as_raw())
9882b78182SAsahi Lina     }
9982b78182SAsahi Lina }
10082b78182SAsahi Lina impl<T: DriverGpuVm> Eq for GpuVm<T> {}
10182b78182SAsahi Lina 
10282b78182SAsahi Lina impl<T: DriverGpuVm> GpuVm<T> {
10382b78182SAsahi Lina     const fn vtable() -> &'static bindings::drm_gpuvm_ops {
10482b78182SAsahi Lina         &bindings::drm_gpuvm_ops {
10582b78182SAsahi Lina             vm_free: Some(Self::vm_free),
10682b78182SAsahi Lina             op_alloc: None,
10782b78182SAsahi Lina             op_free: None,
10871a39211SAlice Ryhl             vm_bo_alloc: GpuVmBo::<T>::ALLOC_FN,
10971a39211SAlice Ryhl             vm_bo_free: GpuVmBo::<T>::FREE_FN,
11082b78182SAsahi Lina             vm_bo_validate: None,
1110b715b1eSAlice Ryhl             sm_step_map: Some(Self::sm_step_map),
112dc384604SAlice Ryhl             sm_step_unmap: Some(Self::sm_step_unmap),
113dc384604SAlice Ryhl             sm_step_remap: Some(Self::sm_step_remap),
11482b78182SAsahi Lina         }
11582b78182SAsahi Lina     }
11682b78182SAsahi Lina 
11782b78182SAsahi Lina     /// Creates a GPUVM instance.
11882b78182SAsahi Lina     #[expect(clippy::new_ret_no_self)]
11982b78182SAsahi Lina     pub fn new<E>(
12082b78182SAsahi Lina         name: &'static CStr,
12182b78182SAsahi Lina         dev: &drm::Device<T::Driver>,
12282b78182SAsahi Lina         r_obj: &T::Object,
12382b78182SAsahi Lina         range: Range<u64>,
12482b78182SAsahi Lina         reserve_range: Range<u64>,
12582b78182SAsahi Lina         data: T,
12682b78182SAsahi Lina     ) -> Result<UniqueRefGpuVm<T>, E>
12782b78182SAsahi Lina     where
12882b78182SAsahi Lina         E: From<AllocError>,
12982b78182SAsahi Lina         E: From<core::convert::Infallible>,
13082b78182SAsahi Lina     {
13182b78182SAsahi Lina         let obj = KBox::try_pin_init::<E>(
13282b78182SAsahi Lina             try_pin_init!(Self {
13382b78182SAsahi Lina                 data: UnsafeCell::new(data),
13482b78182SAsahi Lina                 vm <- Opaque::ffi_init(|vm| {
13582b78182SAsahi Lina                     // SAFETY: These arguments are valid. `vm` is valid until refcount drops to
13682b78182SAsahi Lina                     // zero. The `vm` is zeroed before calling this method by `__GFP_ZERO` flag
13782b78182SAsahi Lina                     // below.
13882b78182SAsahi Lina                     unsafe {
13982b78182SAsahi Lina                         bindings::drm_gpuvm_init(
14082b78182SAsahi Lina                             vm,
14182b78182SAsahi Lina                             name.as_char_ptr(),
14282b78182SAsahi Lina                             bindings::drm_gpuvm_flags_DRM_GPUVM_IMMEDIATE_MODE
14382b78182SAsahi Lina                                 | bindings::drm_gpuvm_flags_DRM_GPUVM_RESV_PROTECTED,
14482b78182SAsahi Lina                             dev.as_raw(),
14582b78182SAsahi Lina                             r_obj.as_raw(),
14682b78182SAsahi Lina                             range.start,
14782b78182SAsahi Lina                             range.end - range.start,
14882b78182SAsahi Lina                             reserve_range.start,
14982b78182SAsahi Lina                             reserve_range.end - reserve_range.start,
15082b78182SAsahi Lina                             const { Self::vtable() },
15182b78182SAsahi Lina                         )
15282b78182SAsahi Lina                     }
15382b78182SAsahi Lina                 }),
15482b78182SAsahi Lina             }? E),
15582b78182SAsahi Lina             GFP_KERNEL | __GFP_ZERO,
15682b78182SAsahi Lina         )?;
15782b78182SAsahi Lina         // SAFETY: This transfers the initial refcount to the ARef.
15882b78182SAsahi Lina         let aref = unsafe {
15982b78182SAsahi Lina             ARef::from_raw(NonNull::new_unchecked(KBox::into_raw(
16082b78182SAsahi Lina                 Pin::into_inner_unchecked(obj),
16182b78182SAsahi Lina             )))
16282b78182SAsahi Lina         };
16382b78182SAsahi Lina         // INVARIANT: This reference is unique.
16482b78182SAsahi Lina         Ok(UniqueRefGpuVm(aref))
16582b78182SAsahi Lina     }
16682b78182SAsahi Lina 
16782b78182SAsahi Lina     /// Access this [`GpuVm`] from a raw pointer.
16882b78182SAsahi Lina     ///
16982b78182SAsahi Lina     /// # Safety
17082b78182SAsahi Lina     ///
17182b78182SAsahi Lina     /// The pointer must reference the `struct drm_gpuvm` in a valid [`GpuVm<T>`] that remains
17282b78182SAsahi Lina     /// valid for at least `'a`.
17382b78182SAsahi Lina     #[inline]
17482b78182SAsahi Lina     pub unsafe fn from_raw<'a>(ptr: *mut bindings::drm_gpuvm) -> &'a Self {
17582b78182SAsahi Lina         // SAFETY: Caller passes a pointer to the `drm_gpuvm` in a `GpuVm<T>`. Caller ensures the
17682b78182SAsahi Lina         // pointer is valid for 'a.
17782b78182SAsahi Lina         unsafe { &*kernel::container_of!(Opaque::cast_from(ptr), Self, vm) }
17882b78182SAsahi Lina     }
17982b78182SAsahi Lina 
18082b78182SAsahi Lina     /// Returns a raw pointer to the embedded `struct drm_gpuvm`.
18182b78182SAsahi Lina     #[inline]
18282b78182SAsahi Lina     pub fn as_raw(&self) -> *mut bindings::drm_gpuvm {
18382b78182SAsahi Lina         self.vm.get()
18482b78182SAsahi Lina     }
18582b78182SAsahi Lina 
18682b78182SAsahi Lina     /// The start of the VA space.
18782b78182SAsahi Lina     #[inline]
18882b78182SAsahi Lina     pub fn va_start(&self) -> u64 {
18982b78182SAsahi Lina         // SAFETY: The `mm_start` field is immutable.
19082b78182SAsahi Lina         unsafe { (*self.as_raw()).mm_start }
19182b78182SAsahi Lina     }
19282b78182SAsahi Lina 
19382b78182SAsahi Lina     /// The length of the GPU's virtual address space.
19482b78182SAsahi Lina     #[inline]
19582b78182SAsahi Lina     pub fn va_length(&self) -> u64 {
19682b78182SAsahi Lina         // SAFETY: The `mm_range` field is immutable.
19782b78182SAsahi Lina         unsafe { (*self.as_raw()).mm_range }
19882b78182SAsahi Lina     }
19982b78182SAsahi Lina 
20082b78182SAsahi Lina     /// Returns the range of the GPU virtual address space.
20182b78182SAsahi Lina     #[inline]
20282b78182SAsahi Lina     pub fn va_range(&self) -> Range<u64> {
20382b78182SAsahi Lina         let start = self.va_start();
20482b78182SAsahi Lina         // OVERFLOW: This reconstructs the Range<u64> passed to the constructor, so it won't fail.
20582b78182SAsahi Lina         let end = start + self.va_length();
20682b78182SAsahi Lina         Range { start, end }
20782b78182SAsahi Lina     }
20882b78182SAsahi Lina 
20971a39211SAlice Ryhl     /// Get or create the [`GpuVmBo`] for this gem object.
21071a39211SAlice Ryhl     #[inline]
21171a39211SAlice Ryhl     pub fn obtain(
21271a39211SAlice Ryhl         &self,
21371a39211SAlice Ryhl         obj: &T::Object,
21471a39211SAlice Ryhl         data: impl PinInit<T::VmBoData>,
21571a39211SAlice Ryhl     ) -> Result<ARef<GpuVmBo<T>>, AllocError> {
21671a39211SAlice Ryhl         Ok(GpuVmBoAlloc::new(self, obj, data)?.obtain())
21771a39211SAlice Ryhl     }
21871a39211SAlice Ryhl 
21982b78182SAsahi Lina     /// Clean up buffer objects that are no longer used.
22082b78182SAsahi Lina     #[inline]
22182b78182SAsahi Lina     pub fn deferred_cleanup(&self) {
22282b78182SAsahi Lina         // SAFETY: This GPUVM uses immediate mode.
22382b78182SAsahi Lina         unsafe { bindings::drm_gpuvm_bo_deferred_cleanup(self.as_raw()) }
22482b78182SAsahi Lina     }
22582b78182SAsahi Lina 
22682b78182SAsahi Lina     /// Check if this GEM object is an external object for this GPUVM.
22782b78182SAsahi Lina     #[inline]
22882b78182SAsahi Lina     pub fn is_extobj(&self, obj: &T::Object) -> bool {
22982b78182SAsahi Lina         // SAFETY: We may call this with any GPUVM and GEM object.
23082b78182SAsahi Lina         unsafe { bindings::drm_gpuvm_is_extobj(self.as_raw(), obj.as_raw()) }
23182b78182SAsahi Lina     }
23282b78182SAsahi Lina 
23382b78182SAsahi Lina     /// Free this GPUVM.
23482b78182SAsahi Lina     ///
23582b78182SAsahi Lina     /// # Safety
23682b78182SAsahi Lina     ///
23782b78182SAsahi Lina     /// Called when refcount hits zero.
23882b78182SAsahi Lina     unsafe extern "C" fn vm_free(me: *mut bindings::drm_gpuvm) {
23982b78182SAsahi Lina         // SAFETY: Caller passes a pointer to the `drm_gpuvm` in a `GpuVm<T>`.
24082b78182SAsahi Lina         let me = unsafe { kernel::container_of!(Opaque::cast_from(me), Self, vm).cast_mut() };
24182b78182SAsahi Lina         // SAFETY: By type invariants we can free it when refcount hits zero.
24282b78182SAsahi Lina         drop(unsafe { KBox::from_raw(me) })
24382b78182SAsahi Lina     }
24471a39211SAlice Ryhl 
24571a39211SAlice Ryhl     #[inline]
24671a39211SAlice Ryhl     fn raw_resv(&self) -> *mut bindings::dma_resv {
24771a39211SAlice Ryhl         // SAFETY: `r_obj` is immutable and valid for duration of GPUVM.
24871a39211SAlice Ryhl         unsafe { (*(*self.as_raw()).r_obj).resv }
24971a39211SAlice Ryhl     }
25082b78182SAsahi Lina }
25182b78182SAsahi Lina 
25282b78182SAsahi Lina /// The manager for a GPUVM.
25382b78182SAsahi Lina pub trait DriverGpuVm: Sized + Send {
25482b78182SAsahi Lina     /// Parent `Driver` for this object.
25582b78182SAsahi Lina     type Driver: drm::Driver<Object = Self::Object>;
25682b78182SAsahi Lina 
25782b78182SAsahi Lina     /// The kind of GEM object stored in this GPUVM.
25882b78182SAsahi Lina     type Object: IntoGEMObject;
25971a39211SAlice Ryhl 
2605540a9c7SAlice Ryhl     /// Data stored with each [`struct drm_gpuva`](struct@GpuVa).
2615540a9c7SAlice Ryhl     type VaData;
2625540a9c7SAlice Ryhl 
26371a39211SAlice Ryhl     /// Data stored with each [`struct drm_gpuvm_bo`](struct@GpuVmBo).
26471a39211SAlice Ryhl     type VmBoData;
265dc384604SAlice Ryhl 
266dc384604SAlice Ryhl     /// The private data passed to callbacks.
267dc384604SAlice Ryhl     type SmContext<'ctx>;
268dc384604SAlice Ryhl 
2690b715b1eSAlice Ryhl     /// Indicates that a new mapping should be created.
2700b715b1eSAlice Ryhl     fn sm_step_map<'op, 'ctx>(
2710b715b1eSAlice Ryhl         &mut self,
2720b715b1eSAlice Ryhl         op: OpMap<'op, Self>,
2730b715b1eSAlice Ryhl         context: &mut Self::SmContext<'ctx>,
2740b715b1eSAlice Ryhl     ) -> Result<OpMapped<'op, Self>, Error>;
2750b715b1eSAlice Ryhl 
276dc384604SAlice Ryhl     /// Indicates that an existing mapping should be removed.
277dc384604SAlice Ryhl     fn sm_step_unmap<'op, 'ctx>(
278dc384604SAlice Ryhl         &mut self,
279dc384604SAlice Ryhl         op: OpUnmap<'op, Self>,
280dc384604SAlice Ryhl         context: &mut Self::SmContext<'ctx>,
281dc384604SAlice Ryhl     ) -> Result<OpUnmapped<'op, Self>, Error>;
282dc384604SAlice Ryhl 
283dc384604SAlice Ryhl     /// Indicates that an existing mapping should be split up.
284dc384604SAlice Ryhl     fn sm_step_remap<'op, 'ctx>(
285dc384604SAlice Ryhl         &mut self,
286dc384604SAlice Ryhl         op: OpRemap<'op, Self>,
287dc384604SAlice Ryhl         context: &mut Self::SmContext<'ctx>,
288dc384604SAlice Ryhl     ) -> Result<OpRemapped<'op, Self>, Error>;
28982b78182SAsahi Lina }
29082b78182SAsahi Lina 
29182b78182SAsahi Lina /// The core of the DRM GPU VA manager.
29282b78182SAsahi Lina ///
29382b78182SAsahi Lina /// This object is a unique reference to the VM that can access the interval tree and the Rust
29482b78182SAsahi Lina /// `data` field.
29582b78182SAsahi Lina ///
29682b78182SAsahi Lina /// # Invariants
29782b78182SAsahi Lina ///
29882b78182SAsahi Lina /// Each `GpuVm` instance has at most one `UniqueRefGpuVm` reference.
29982b78182SAsahi Lina pub struct UniqueRefGpuVm<T: DriverGpuVm>(ARef<GpuVm<T>>);
30082b78182SAsahi Lina 
30182b78182SAsahi Lina // SAFETY: The GPUVM api is designed to allow &self methods to be called in parallel, and
30282b78182SAsahi Lina // concurrent access to `data` is safe due to the `T: Sync` requirement.
30382b78182SAsahi Lina unsafe impl<T: DriverGpuVm + Sync> Sync for UniqueRefGpuVm<T> {}
30482b78182SAsahi Lina 
30582b78182SAsahi Lina impl<T: DriverGpuVm> UniqueRefGpuVm<T> {
30682b78182SAsahi Lina     /// Access the data owned by this `UniqueRefGpuVm` immutably.
30782b78182SAsahi Lina     #[inline]
30882b78182SAsahi Lina     pub fn data_ref(&self) -> &T {
30982b78182SAsahi Lina         // SAFETY: By the type invariants we may access `data`.
31082b78182SAsahi Lina         unsafe { &*self.0.data.get() }
31182b78182SAsahi Lina     }
31282b78182SAsahi Lina 
31382b78182SAsahi Lina     /// Access the data owned by this `UniqueRefGpuVm` mutably.
31482b78182SAsahi Lina     #[inline]
31582b78182SAsahi Lina     pub fn data(&mut self) -> &mut T {
31682b78182SAsahi Lina         // SAFETY: By the type invariants we may access `data`.
31782b78182SAsahi Lina         unsafe { &mut *self.0.data.get() }
31882b78182SAsahi Lina     }
31982b78182SAsahi Lina }
32082b78182SAsahi Lina 
32182b78182SAsahi Lina impl<T: DriverGpuVm> Deref for UniqueRefGpuVm<T> {
32282b78182SAsahi Lina     type Target = GpuVm<T>;
32382b78182SAsahi Lina 
32482b78182SAsahi Lina     #[inline]
32582b78182SAsahi Lina     fn deref(&self) -> &GpuVm<T> {
32682b78182SAsahi Lina         &self.0
32782b78182SAsahi Lina     }
32882b78182SAsahi Lina }
329