xref: /linux/rust/kernel/drm/gem/shmem.rs (revision d317e4585fa39bcee4d075f5c485494b0f238713)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 //! DRM GEM shmem helper objects
4 //!
5 //! C header: [`include/linux/drm/drm_gem_shmem_helper.h`](srctree/include/drm/drm_gem_shmem_helper.h)
6 
7 // TODO:
8 // - There are a number of spots here that manually acquire/release the DMA reservation lock using
9 //   dma_resv_(un)lock(). In the future we should add support for ww mutex, expose a method to
10 //   acquire a reference to the WwMutex, and then use that directly instead of the C functions here.
11 
12 use crate::{
13     container_of,
14     drm::{
15         driver,
16         gem,
17         private::Sealed,
18         Device,
19         DeviceContext,
20         Registered, //
21     },
22     error::to_result,
23     prelude::*,
24     sync::aref::ARef,
25     types::Opaque, //
26 };
27 use core::{
28     marker::PhantomData,
29     ops::{
30         Deref,
31         DerefMut, //
32     },
33     ptr::NonNull, //
34 };
35 use gem::{
36     BaseObjectPrivate,
37     DriverObject,
38     IntoGEMObject, //
39 };
40 
41 /// A struct for controlling the creation of shmem-backed GEM objects.
42 ///
43 /// This is used with [`Object::new()`] to control various properties that can only be set when
44 /// initially creating a shmem-backed GEM object.
45 #[derive(Default)]
46 pub struct ObjectConfig<'a, T: DriverObject, C: DeviceContext = Registered> {
47     /// Whether to set the write-combine map flag.
48     pub map_wc: bool,
49 
50     /// Reuse the DMA reservation from another GEM object.
51     ///
52     /// The newly created [`Object`] will hold an owned refcount to `parent_resv_obj` if specified.
53     pub parent_resv_obj: Option<&'a Object<T, C>>,
54 }
55 
56 /// A shmem-backed GEM object.
57 ///
58 /// # Invariants
59 ///
60 /// - `obj` contains a valid initialized `struct drm_gem_shmem_object` for the lifetime of this
61 ///   object.
62 /// - Any type invariants of `C` apply to the parent DRM device for this GEM object.
63 #[repr(C)]
64 #[pin_data]
65 pub struct Object<T: DriverObject, C: DeviceContext = Registered> {
66     #[pin]
67     obj: Opaque<bindings::drm_gem_shmem_object>,
68     /// Parent object that owns this object's DMA reservation object.
69     parent_resv_obj: Option<ARef<Object<T, C>>>,
70     #[pin]
71     inner: T,
72     _ctx: PhantomData<C>,
73 }
74 
75 super::impl_aref_for_gem_obj! {
76     impl<T, C> for Object<T, C>
77     where
78         T: DriverObject,
79         C: DeviceContext
80 }
81 
82 // SAFETY: All GEM objects are thread-safe.
83 unsafe impl<T: DriverObject, C: DeviceContext> Send for Object<T, C> {}
84 
85 // SAFETY: All GEM objects are thread-safe.
86 unsafe impl<T: DriverObject, C: DeviceContext> Sync for Object<T, C> {}
87 
88 impl<T: DriverObject, C: DeviceContext> Object<T, C> {
89     /// `drm_gem_object_funcs` vtable suitable for GEM shmem objects.
90     const VTABLE: bindings::drm_gem_object_funcs = bindings::drm_gem_object_funcs {
91         free: Some(Self::free_callback),
92         open: Some(super::open_callback::<T>),
93         close: Some(super::close_callback::<T>),
94         print_info: Some(bindings::drm_gem_shmem_object_print_info),
95         export: None,
96         pin: Some(bindings::drm_gem_shmem_object_pin),
97         unpin: Some(bindings::drm_gem_shmem_object_unpin),
98         get_sg_table: Some(bindings::drm_gem_shmem_object_get_sg_table),
99         vmap: Some(bindings::drm_gem_shmem_object_vmap),
100         vunmap: Some(bindings::drm_gem_shmem_object_vunmap),
101         mmap: Some(bindings::drm_gem_shmem_object_mmap),
102         status: None,
103         rss: None,
104         #[allow(unused_unsafe, reason = "Safe since Rust 1.82.0")]
105         // SAFETY: `drm_gem_shmem_vm_ops` is a valid, static const on the C side.
106         vm_ops: unsafe { &raw const bindings::drm_gem_shmem_vm_ops },
107         evict: None,
108     };
109 
110     /// Return a raw pointer to the embedded drm_gem_shmem_object.
111     fn as_raw_shmem(&self) -> *mut bindings::drm_gem_shmem_object {
112         self.obj.get()
113     }
114 
115     /// Create a new shmem-backed DRM object of the given size.
116     ///
117     /// Additional config options can be specified using `config`.
118     pub fn new(
119         dev: &Device<T::Driver, C>,
120         size: usize,
121         config: ObjectConfig<'_, T, C>,
122         args: T::Args,
123     ) -> Result<ARef<Self>> {
124         let new: Pin<KBox<Self>> = KBox::try_pin_init(
125             try_pin_init!(Self {
126                 obj <- Opaque::init_zeroed(),
127                 parent_resv_obj: config.parent_resv_obj.map(|p| p.into()),
128                 inner <- T::new(dev, size, args),
129                 _ctx: PhantomData::<C>,
130             }),
131             GFP_KERNEL,
132         )?;
133 
134         // SAFETY: `obj.as_raw()` is guaranteed to be valid by the initialization above.
135         unsafe { (*new.as_raw()).funcs = &Self::VTABLE };
136 
137         // SAFETY: The arguments are all valid via the type invariants.
138         to_result(unsafe { bindings::drm_gem_shmem_init(dev.as_raw(), new.as_raw_shmem(), size) })?;
139 
140         // SAFETY: We never move out of `self`.
141         let new = KBox::into_raw(unsafe { Pin::into_inner_unchecked(new) });
142 
143         // SAFETY: We're taking over the owned refcount from `drm_gem_shmem_init`.
144         let obj = unsafe { ARef::from_raw(NonNull::new_unchecked(new)) };
145 
146         // Start filling out values from `config`
147         if let Some(parent_resv) = config.parent_resv_obj {
148             // SAFETY: We have yet to expose the new gem object outside of this function, so it is
149             // safe to modify this field.
150             unsafe { (*obj.obj.get()).base.resv = parent_resv.raw_dma_resv() };
151         }
152 
153         // SAFETY: We have yet to expose this object outside of this function, so we're guaranteed
154         // to have exclusive access - thus making this safe to hold a mutable reference to.
155         let shmem = unsafe { &mut *obj.as_raw_shmem() };
156         shmem.set_map_wc(config.map_wc);
157 
158         Ok(obj)
159     }
160 
161     /// Returns the `Device` that owns this GEM object.
162     pub fn dev(&self) -> &Device<T::Driver, C> {
163         // SAFETY: `dev` will have been initialized in `Self::new()` by `drm_gem_shmem_init()`.
164         unsafe { Device::from_raw((*self.as_raw()).dev) }
165     }
166 
167     extern "C" fn free_callback(obj: *mut bindings::drm_gem_object) {
168         // SAFETY:
169         // - DRM always passes a valid gem object here
170         // - We used drm_gem_shmem_create() in our create_gem_object callback, so we know that
171         //   `obj` is contained within a drm_gem_shmem_object
172         let this = unsafe { container_of!(obj, bindings::drm_gem_shmem_object, base) };
173 
174         // SAFETY:
175         // - We're in free_callback - so this function is safe to call.
176         // - We won't be using the gem resources on `this` after this call.
177         unsafe { bindings::drm_gem_shmem_release(this) };
178 
179         // SAFETY:
180         // - We verified above that `obj` is valid, which makes `this` valid
181         // - This function is set in AllocOps, so we know that `this` is contained within a
182         //   `Object<T, C>`
183         let this = unsafe { container_of!(Opaque::cast_from(this), Self, obj) }.cast_mut();
184 
185         // SAFETY: We're recovering the Kbox<> we created in gem_create_object()
186         let _ = unsafe { KBox::from_raw(this) };
187     }
188 }
189 
190 impl<T: DriverObject, C: DeviceContext> Deref for Object<T, C> {
191     type Target = T;
192 
193     fn deref(&self) -> &Self::Target {
194         &self.inner
195     }
196 }
197 
198 impl<T: DriverObject, C: DeviceContext> DerefMut for Object<T, C> {
199     fn deref_mut(&mut self) -> &mut Self::Target {
200         &mut self.inner
201     }
202 }
203 
204 impl<T: DriverObject, C: DeviceContext> Sealed for Object<T, C> {}
205 
206 impl<T: DriverObject, C: DeviceContext> gem::IntoGEMObject for Object<T, C> {
207     fn as_raw(&self) -> *mut bindings::drm_gem_object {
208         // SAFETY:
209         // - Our immutable reference is proof that this is safe to dereference.
210         // - `obj` is always a valid drm_gem_shmem_object via our type invariants.
211         unsafe { &raw mut (*self.obj.get()).base }
212     }
213 
214     unsafe fn from_raw<'a>(obj: *mut bindings::drm_gem_object) -> &'a Self {
215         // SAFETY: The safety contract of from_gem_obj() guarantees that `obj` is contained within
216         // `Self`
217         unsafe {
218             let obj = Opaque::cast_from(container_of!(obj, bindings::drm_gem_shmem_object, base));
219 
220             &*container_of!(obj, Self, obj)
221         }
222     }
223 }
224 
225 impl<T: DriverObject, C: DeviceContext> driver::AllocImpl for Object<T, C> {
226     type Driver = T::Driver;
227 
228     const ALLOC_OPS: driver::AllocOps = driver::AllocOps {
229         gem_create_object: None,
230         prime_handle_to_fd: None,
231         prime_fd_to_handle: None,
232         gem_prime_import: None,
233         gem_prime_import_sg_table: Some(bindings::drm_gem_shmem_prime_import_sg_table),
234         dumb_create: Some(bindings::drm_gem_shmem_dumb_create),
235         dumb_map_offset: None,
236     };
237 }
238