xref: /linux/rust/kernel/drm/gpuvm/mod.rs (revision 82b78182eacf82c1847c6f1fd93d91c15efb69cf)
1*82b78182SAsahi Lina // SPDX-License-Identifier: GPL-2.0 OR MIT
2*82b78182SAsahi Lina 
3*82b78182SAsahi Lina #![cfg(CONFIG_DRM_GPUVM = "y")]
4*82b78182SAsahi Lina 
5*82b78182SAsahi Lina //! DRM GPUVM in immediate mode
6*82b78182SAsahi Lina //!
7*82b78182SAsahi Lina //! Rust abstractions for using GPUVM in immediate mode. This is when the GPUVM state is updated
8*82b78182SAsahi Lina //! during `run_job()`, i.e., in the DMA fence signalling critical path, to ensure that the GPUVM
9*82b78182SAsahi Lina //! and the GPU's virtual address space has the same state at all times.
10*82b78182SAsahi Lina //!
11*82b78182SAsahi Lina //! C header: [`include/drm/drm_gpuvm.h`](srctree/include/drm/drm_gpuvm.h)
12*82b78182SAsahi Lina 
13*82b78182SAsahi Lina use kernel::{
14*82b78182SAsahi Lina     alloc::AllocError,
15*82b78182SAsahi Lina     bindings,
16*82b78182SAsahi Lina     drm,
17*82b78182SAsahi Lina     drm::gem::IntoGEMObject,
18*82b78182SAsahi Lina     prelude::*,
19*82b78182SAsahi Lina     sync::aref::{
20*82b78182SAsahi Lina         ARef,
21*82b78182SAsahi Lina         AlwaysRefCounted, //
22*82b78182SAsahi Lina     },
23*82b78182SAsahi Lina     types::Opaque, //
24*82b78182SAsahi Lina };
25*82b78182SAsahi Lina 
26*82b78182SAsahi Lina use core::{
27*82b78182SAsahi Lina     cell::UnsafeCell,
28*82b78182SAsahi Lina     ops::{
29*82b78182SAsahi Lina         Deref,
30*82b78182SAsahi Lina         Range, //
31*82b78182SAsahi Lina     },
32*82b78182SAsahi Lina     ptr::NonNull, //
33*82b78182SAsahi Lina };
34*82b78182SAsahi Lina 
35*82b78182SAsahi Lina /// A DRM GPU VA manager.
36*82b78182SAsahi Lina ///
37*82b78182SAsahi Lina /// This object is refcounted, but the locations of mapped ranges may only be accessed or changed
38*82b78182SAsahi Lina /// via the special unique handle [`UniqueRefGpuVm`].
39*82b78182SAsahi Lina ///
40*82b78182SAsahi Lina /// # Invariants
41*82b78182SAsahi Lina ///
42*82b78182SAsahi Lina /// * Stored in an allocation managed by the refcount in `self.vm`.
43*82b78182SAsahi Lina /// * Access to `data` and the gpuvm interval tree is controlled via the [`UniqueRefGpuVm`] type.
44*82b78182SAsahi Lina /// * Does not contain any sparse `GpuVa` instances.
45*82b78182SAsahi Lina #[pin_data]
46*82b78182SAsahi Lina pub struct GpuVm<T: DriverGpuVm> {
47*82b78182SAsahi Lina     #[pin]
48*82b78182SAsahi Lina     vm: Opaque<bindings::drm_gpuvm>,
49*82b78182SAsahi Lina     /// Accessed only through the [`UniqueRefGpuVm`] reference.
50*82b78182SAsahi Lina     data: UnsafeCell<T>,
51*82b78182SAsahi Lina }
52*82b78182SAsahi Lina 
53*82b78182SAsahi Lina // SAFETY: The GPUVM api does not assume that it is tied to a specific thread. The destructor will
54*82b78182SAsahi Lina // drop the `data` field, which is okay because it is guaranteed `Send` by the `DriverGpuVm` trait.
55*82b78182SAsahi Lina unsafe impl<T: DriverGpuVm> Send for GpuVm<T> {}
56*82b78182SAsahi Lina // SAFETY: The GPUVM api is designed to allow &self methods to be called in parallel.
57*82b78182SAsahi Lina unsafe impl<T: DriverGpuVm> Sync for GpuVm<T> {}
58*82b78182SAsahi Lina 
59*82b78182SAsahi Lina // SAFETY: By type invariants, the allocation is managed by the refcount in `self.vm`.
60*82b78182SAsahi Lina unsafe impl<T: DriverGpuVm> AlwaysRefCounted for GpuVm<T> {
61*82b78182SAsahi Lina     fn inc_ref(&self) {
62*82b78182SAsahi Lina         // SAFETY: By type invariants, the allocation is managed by the refcount in `self.vm`.
63*82b78182SAsahi Lina         unsafe { bindings::drm_gpuvm_get(self.vm.get()) };
64*82b78182SAsahi Lina     }
65*82b78182SAsahi Lina 
66*82b78182SAsahi Lina     unsafe fn dec_ref(obj: NonNull<Self>) {
67*82b78182SAsahi Lina         // SAFETY: By type invariants, the allocation is managed by the refcount in `self.vm`.
68*82b78182SAsahi Lina         unsafe { bindings::drm_gpuvm_put((*obj.as_ptr()).vm.get()) };
69*82b78182SAsahi Lina     }
70*82b78182SAsahi Lina }
71*82b78182SAsahi Lina 
72*82b78182SAsahi Lina impl<T: DriverGpuVm> PartialEq for GpuVm<T> {
73*82b78182SAsahi Lina     #[inline]
74*82b78182SAsahi Lina     fn eq(&self, other: &Self) -> bool {
75*82b78182SAsahi Lina         core::ptr::eq(self.as_raw(), other.as_raw())
76*82b78182SAsahi Lina     }
77*82b78182SAsahi Lina }
78*82b78182SAsahi Lina impl<T: DriverGpuVm> Eq for GpuVm<T> {}
79*82b78182SAsahi Lina 
80*82b78182SAsahi Lina impl<T: DriverGpuVm> GpuVm<T> {
81*82b78182SAsahi Lina     const fn vtable() -> &'static bindings::drm_gpuvm_ops {
82*82b78182SAsahi Lina         &bindings::drm_gpuvm_ops {
83*82b78182SAsahi Lina             vm_free: Some(Self::vm_free),
84*82b78182SAsahi Lina             op_alloc: None,
85*82b78182SAsahi Lina             op_free: None,
86*82b78182SAsahi Lina             vm_bo_alloc: None,
87*82b78182SAsahi Lina             vm_bo_free: None,
88*82b78182SAsahi Lina             vm_bo_validate: None,
89*82b78182SAsahi Lina             sm_step_map: None,
90*82b78182SAsahi Lina             sm_step_unmap: None,
91*82b78182SAsahi Lina             sm_step_remap: None,
92*82b78182SAsahi Lina         }
93*82b78182SAsahi Lina     }
94*82b78182SAsahi Lina 
95*82b78182SAsahi Lina     /// Creates a GPUVM instance.
96*82b78182SAsahi Lina     #[expect(clippy::new_ret_no_self)]
97*82b78182SAsahi Lina     pub fn new<E>(
98*82b78182SAsahi Lina         name: &'static CStr,
99*82b78182SAsahi Lina         dev: &drm::Device<T::Driver>,
100*82b78182SAsahi Lina         r_obj: &T::Object,
101*82b78182SAsahi Lina         range: Range<u64>,
102*82b78182SAsahi Lina         reserve_range: Range<u64>,
103*82b78182SAsahi Lina         data: T,
104*82b78182SAsahi Lina     ) -> Result<UniqueRefGpuVm<T>, E>
105*82b78182SAsahi Lina     where
106*82b78182SAsahi Lina         E: From<AllocError>,
107*82b78182SAsahi Lina         E: From<core::convert::Infallible>,
108*82b78182SAsahi Lina     {
109*82b78182SAsahi Lina         let obj = KBox::try_pin_init::<E>(
110*82b78182SAsahi Lina             try_pin_init!(Self {
111*82b78182SAsahi Lina                 data: UnsafeCell::new(data),
112*82b78182SAsahi Lina                 vm <- Opaque::ffi_init(|vm| {
113*82b78182SAsahi Lina                     // SAFETY: These arguments are valid. `vm` is valid until refcount drops to
114*82b78182SAsahi Lina                     // zero. The `vm` is zeroed before calling this method by `__GFP_ZERO` flag
115*82b78182SAsahi Lina                     // below.
116*82b78182SAsahi Lina                     unsafe {
117*82b78182SAsahi Lina                         bindings::drm_gpuvm_init(
118*82b78182SAsahi Lina                             vm,
119*82b78182SAsahi Lina                             name.as_char_ptr(),
120*82b78182SAsahi Lina                             bindings::drm_gpuvm_flags_DRM_GPUVM_IMMEDIATE_MODE
121*82b78182SAsahi Lina                                 | bindings::drm_gpuvm_flags_DRM_GPUVM_RESV_PROTECTED,
122*82b78182SAsahi Lina                             dev.as_raw(),
123*82b78182SAsahi Lina                             r_obj.as_raw(),
124*82b78182SAsahi Lina                             range.start,
125*82b78182SAsahi Lina                             range.end - range.start,
126*82b78182SAsahi Lina                             reserve_range.start,
127*82b78182SAsahi Lina                             reserve_range.end - reserve_range.start,
128*82b78182SAsahi Lina                             const { Self::vtable() },
129*82b78182SAsahi Lina                         )
130*82b78182SAsahi Lina                     }
131*82b78182SAsahi Lina                 }),
132*82b78182SAsahi Lina             }? E),
133*82b78182SAsahi Lina             GFP_KERNEL | __GFP_ZERO,
134*82b78182SAsahi Lina         )?;
135*82b78182SAsahi Lina         // SAFETY: This transfers the initial refcount to the ARef.
136*82b78182SAsahi Lina         let aref = unsafe {
137*82b78182SAsahi Lina             ARef::from_raw(NonNull::new_unchecked(KBox::into_raw(
138*82b78182SAsahi Lina                 Pin::into_inner_unchecked(obj),
139*82b78182SAsahi Lina             )))
140*82b78182SAsahi Lina         };
141*82b78182SAsahi Lina         // INVARIANT: This reference is unique.
142*82b78182SAsahi Lina         Ok(UniqueRefGpuVm(aref))
143*82b78182SAsahi Lina     }
144*82b78182SAsahi Lina 
145*82b78182SAsahi Lina     /// Access this [`GpuVm`] from a raw pointer.
146*82b78182SAsahi Lina     ///
147*82b78182SAsahi Lina     /// # Safety
148*82b78182SAsahi Lina     ///
149*82b78182SAsahi Lina     /// The pointer must reference the `struct drm_gpuvm` in a valid [`GpuVm<T>`] that remains
150*82b78182SAsahi Lina     /// valid for at least `'a`.
151*82b78182SAsahi Lina     #[inline]
152*82b78182SAsahi Lina     pub unsafe fn from_raw<'a>(ptr: *mut bindings::drm_gpuvm) -> &'a Self {
153*82b78182SAsahi Lina         // SAFETY: Caller passes a pointer to the `drm_gpuvm` in a `GpuVm<T>`. Caller ensures the
154*82b78182SAsahi Lina         // pointer is valid for 'a.
155*82b78182SAsahi Lina         unsafe { &*kernel::container_of!(Opaque::cast_from(ptr), Self, vm) }
156*82b78182SAsahi Lina     }
157*82b78182SAsahi Lina 
158*82b78182SAsahi Lina     /// Returns a raw pointer to the embedded `struct drm_gpuvm`.
159*82b78182SAsahi Lina     #[inline]
160*82b78182SAsahi Lina     pub fn as_raw(&self) -> *mut bindings::drm_gpuvm {
161*82b78182SAsahi Lina         self.vm.get()
162*82b78182SAsahi Lina     }
163*82b78182SAsahi Lina 
164*82b78182SAsahi Lina     /// The start of the VA space.
165*82b78182SAsahi Lina     #[inline]
166*82b78182SAsahi Lina     pub fn va_start(&self) -> u64 {
167*82b78182SAsahi Lina         // SAFETY: The `mm_start` field is immutable.
168*82b78182SAsahi Lina         unsafe { (*self.as_raw()).mm_start }
169*82b78182SAsahi Lina     }
170*82b78182SAsahi Lina 
171*82b78182SAsahi Lina     /// The length of the GPU's virtual address space.
172*82b78182SAsahi Lina     #[inline]
173*82b78182SAsahi Lina     pub fn va_length(&self) -> u64 {
174*82b78182SAsahi Lina         // SAFETY: The `mm_range` field is immutable.
175*82b78182SAsahi Lina         unsafe { (*self.as_raw()).mm_range }
176*82b78182SAsahi Lina     }
177*82b78182SAsahi Lina 
178*82b78182SAsahi Lina     /// Returns the range of the GPU virtual address space.
179*82b78182SAsahi Lina     #[inline]
180*82b78182SAsahi Lina     pub fn va_range(&self) -> Range<u64> {
181*82b78182SAsahi Lina         let start = self.va_start();
182*82b78182SAsahi Lina         // OVERFLOW: This reconstructs the Range<u64> passed to the constructor, so it won't fail.
183*82b78182SAsahi Lina         let end = start + self.va_length();
184*82b78182SAsahi Lina         Range { start, end }
185*82b78182SAsahi Lina     }
186*82b78182SAsahi Lina 
187*82b78182SAsahi Lina     /// Clean up buffer objects that are no longer used.
188*82b78182SAsahi Lina     #[inline]
189*82b78182SAsahi Lina     pub fn deferred_cleanup(&self) {
190*82b78182SAsahi Lina         // SAFETY: This GPUVM uses immediate mode.
191*82b78182SAsahi Lina         unsafe { bindings::drm_gpuvm_bo_deferred_cleanup(self.as_raw()) }
192*82b78182SAsahi Lina     }
193*82b78182SAsahi Lina 
194*82b78182SAsahi Lina     /// Check if this GEM object is an external object for this GPUVM.
195*82b78182SAsahi Lina     #[inline]
196*82b78182SAsahi Lina     pub fn is_extobj(&self, obj: &T::Object) -> bool {
197*82b78182SAsahi Lina         // SAFETY: We may call this with any GPUVM and GEM object.
198*82b78182SAsahi Lina         unsafe { bindings::drm_gpuvm_is_extobj(self.as_raw(), obj.as_raw()) }
199*82b78182SAsahi Lina     }
200*82b78182SAsahi Lina 
201*82b78182SAsahi Lina     /// Free this GPUVM.
202*82b78182SAsahi Lina     ///
203*82b78182SAsahi Lina     /// # Safety
204*82b78182SAsahi Lina     ///
205*82b78182SAsahi Lina     /// Called when refcount hits zero.
206*82b78182SAsahi Lina     unsafe extern "C" fn vm_free(me: *mut bindings::drm_gpuvm) {
207*82b78182SAsahi Lina         // SAFETY: Caller passes a pointer to the `drm_gpuvm` in a `GpuVm<T>`.
208*82b78182SAsahi Lina         let me = unsafe { kernel::container_of!(Opaque::cast_from(me), Self, vm).cast_mut() };
209*82b78182SAsahi Lina         // SAFETY: By type invariants we can free it when refcount hits zero.
210*82b78182SAsahi Lina         drop(unsafe { KBox::from_raw(me) })
211*82b78182SAsahi Lina     }
212*82b78182SAsahi Lina }
213*82b78182SAsahi Lina 
214*82b78182SAsahi Lina /// The manager for a GPUVM.
215*82b78182SAsahi Lina pub trait DriverGpuVm: Sized + Send {
216*82b78182SAsahi Lina     /// Parent `Driver` for this object.
217*82b78182SAsahi Lina     type Driver: drm::Driver<Object = Self::Object>;
218*82b78182SAsahi Lina 
219*82b78182SAsahi Lina     /// The kind of GEM object stored in this GPUVM.
220*82b78182SAsahi Lina     type Object: IntoGEMObject;
221*82b78182SAsahi Lina }
222*82b78182SAsahi Lina 
223*82b78182SAsahi Lina /// The core of the DRM GPU VA manager.
224*82b78182SAsahi Lina ///
225*82b78182SAsahi Lina /// This object is a unique reference to the VM that can access the interval tree and the Rust
226*82b78182SAsahi Lina /// `data` field.
227*82b78182SAsahi Lina ///
228*82b78182SAsahi Lina /// # Invariants
229*82b78182SAsahi Lina ///
230*82b78182SAsahi Lina /// Each `GpuVm` instance has at most one `UniqueRefGpuVm` reference.
231*82b78182SAsahi Lina pub struct UniqueRefGpuVm<T: DriverGpuVm>(ARef<GpuVm<T>>);
232*82b78182SAsahi Lina 
233*82b78182SAsahi Lina // SAFETY: The GPUVM api is designed to allow &self methods to be called in parallel, and
234*82b78182SAsahi Lina // concurrent access to `data` is safe due to the `T: Sync` requirement.
235*82b78182SAsahi Lina unsafe impl<T: DriverGpuVm + Sync> Sync for UniqueRefGpuVm<T> {}
236*82b78182SAsahi Lina 
237*82b78182SAsahi Lina impl<T: DriverGpuVm> UniqueRefGpuVm<T> {
238*82b78182SAsahi Lina     /// Access the data owned by this `UniqueRefGpuVm` immutably.
239*82b78182SAsahi Lina     #[inline]
240*82b78182SAsahi Lina     pub fn data_ref(&self) -> &T {
241*82b78182SAsahi Lina         // SAFETY: By the type invariants we may access `data`.
242*82b78182SAsahi Lina         unsafe { &*self.0.data.get() }
243*82b78182SAsahi Lina     }
244*82b78182SAsahi Lina 
245*82b78182SAsahi Lina     /// Access the data owned by this `UniqueRefGpuVm` mutably.
246*82b78182SAsahi Lina     #[inline]
247*82b78182SAsahi Lina     pub fn data(&mut self) -> &mut T {
248*82b78182SAsahi Lina         // SAFETY: By the type invariants we may access `data`.
249*82b78182SAsahi Lina         unsafe { &mut *self.0.data.get() }
250*82b78182SAsahi Lina     }
251*82b78182SAsahi Lina }
252*82b78182SAsahi Lina 
253*82b78182SAsahi Lina impl<T: DriverGpuVm> Deref for UniqueRefGpuVm<T> {
254*82b78182SAsahi Lina     type Target = GpuVm<T>;
255*82b78182SAsahi Lina 
256*82b78182SAsahi Lina     #[inline]
257*82b78182SAsahi Lina     fn deref(&self) -> &GpuVm<T> {
258*82b78182SAsahi Lina         &self.0
259*82b78182SAsahi Lina     }
260*82b78182SAsahi Lina }
261