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