Skip to main content

kernel/drm/
device.rs

1// SPDX-License-Identifier: GPL-2.0 OR MIT
2
3//! DRM device.
4//!
5//! C header: [`include/drm/drm_device.h`](srctree/include/drm/drm_device.h)
6
7use crate::{
8    alloc::allocator::Kmalloc,
9    bindings,
10    device,
11    drm::{
12        self,
13        driver::AllocImpl,
14        private::Sealed, //
15    },
16    error::from_err_ptr,
17    prelude::*,
18    sync::aref::{
19        ARef,
20        AlwaysRefCounted, //
21    },
22    types::{
23        NotThreadSafe,
24        Opaque, //
25    },
26    workqueue::{
27        HasDelayedWork,
28        HasWork,
29        Work,
30        WorkItem, //
31    }, //
32};
33use core::{
34    alloc::Layout,
35    marker::PhantomData,
36    mem,
37    ops::Deref,
38    ptr::{
39        self,
40        NonNull, //
41    },
42};
43
44#[cfg(CONFIG_DRM_LEGACY)]
45macro_rules! drm_legacy_fields {
46    ( $($field:ident: $val:expr),* $(,)? ) => {
47        bindings::drm_driver {
48            $( $field: $val ),*,
49            firstopen: None,
50            preclose: None,
51            dma_ioctl: None,
52            dma_quiescent: None,
53            context_dtor: None,
54            irq_handler: None,
55            irq_preinstall: None,
56            irq_postinstall: None,
57            irq_uninstall: None,
58            get_vblank_counter: None,
59            enable_vblank: None,
60            disable_vblank: None,
61            dev_priv_size: 0,
62        }
63    }
64}
65
66#[cfg(not(CONFIG_DRM_LEGACY))]
67macro_rules! drm_legacy_fields {
68    ( $($field:ident: $val:expr),* $(,)? ) => {
69        bindings::drm_driver {
70            $( $field: $val ),*
71        }
72    }
73}
74
75/// A trait implemented by all possible contexts a [`Device`] can be used in.
76///
77/// Setting up a new [`Device`] is a multi-stage process. Each step of the process that a user
78/// interacts with in Rust has a respective [`DeviceContext`] typestate. For example,
79/// `Device<T, Registered>` would be a [`Device`] that reached the [`Registered`] [`DeviceContext`].
80///
81/// Each stage of this process is described below:
82///
83/// ```text
84///        1                     2                         3
85/// +--------------+   +------------------+   +-----------------------+
86/// |Device created| → |Device initialized| → |Registered w/ userspace|
87/// +--------------+   +------------------+   +-----------------------+
88///    (Uninit)                                      (Registered)
89/// ```
90///
91/// 1. The [`Device`] is in the [`Uninit`] context and is not guaranteed to be initialized or
92///    registered with userspace. Only a limited subset of DRM core functionality is available.
93/// 2. The [`Device`] is guaranteed to be fully initialized, but is not guaranteed to be registered
94///    with userspace. All DRM core functionality which doesn't interact with userspace is
95///    available. We currently don't have a context for representing this.
96/// 3. The [`Device`] is guaranteed to be fully initialized, and is guaranteed to have been
97///    registered with userspace at some point - thus putting it in the [`Registered`] context.
98///
99/// An important caveat of [`DeviceContext`] which must be kept in mind: when used as a typestate
100/// for a reference type, it can only guarantee that a [`Device`] reached a particular stage in the
101/// initialization process _at the time the reference was taken_. No guarantee is made in regards to
102/// what stage of the process the [`Device`] is currently in. This means for instance that a
103/// `&Device<T, Uninit>` may actually be registered with userspace, it just wasn't known to be
104/// registered at the time the reference was taken.
105pub trait DeviceContext: Sealed + Send + Sync {}
106
107/// The [`DeviceContext`] of a [`Device`] that was registered with userspace at some point.
108///
109/// This represents a [`Device`] which is guaranteed to have been registered with userspace at
110/// some point in time. Such a DRM device is guaranteed to have been fully-initialized.
111///
112/// Note: A device in this context is not guaranteed to remain registered with userspace for its
113/// entire lifetime, as this is impossible to guarantee at compile-time.
114///
115/// # Invariants
116///
117/// A [`Device`] in this [`DeviceContext`] is guaranteed to have been registered with userspace
118/// at some point in time.
119pub struct Registered;
120
121impl Sealed for Registered {}
122impl DeviceContext for Registered {}
123
124/// The [`DeviceContext`] of a [`Device`] that may be unregistered and partly uninitialized.
125///
126/// A [`Device`] in this context is only guaranteed to be partly initialized, and may or may not
127/// be registered with userspace. Thus operations which depend on the [`Device`] being fully
128/// initialized, or which depend on the [`Device`] being registered with userspace are not
129/// available through this [`DeviceContext`].
130///
131/// A [`Device`] in this context can be used to create a
132/// [`Registration`](drm::driver::Registration).
133pub struct Uninit;
134
135impl Sealed for Uninit {}
136impl DeviceContext for Uninit {}
137
138/// A [`Device`] which is known at compile-time to be unregistered with userspace.
139///
140/// This type allows performing operations which are only safe to do before userspace registration,
141/// and can be used to create a [`Registration`](drm::driver::Registration) once the driver is ready
142/// to register the device with userspace.
143///
144/// Since DRM device initialization must be single-threaded, this object is not thread-safe.
145///
146/// # Invariants
147///
148/// The device in `self.0` is guaranteed to be a newly created [`Device`] that has not yet been
149/// registered with userspace until this type is dropped.
150pub struct UnregisteredDevice<T: drm::Driver>(ARef<Device<T, Uninit>>, NotThreadSafe);
151
152impl<T: drm::Driver> Deref for UnregisteredDevice<T> {
153    type Target = Device<T, Uninit>;
154
155    fn deref(&self) -> &Self::Target {
156        &self.0
157    }
158}
159
160impl<T: drm::Driver> UnregisteredDevice<T> {
161    const fn compute_features() -> u32 {
162        let mut features = drm::driver::FEAT_GEM;
163
164        if T::FEAT_RENDER {
165            features |= drm::driver::FEAT_RENDER;
166        }
167
168        features
169    }
170
171    const VTABLE: bindings::drm_driver = drm_legacy_fields! {
172        load: None,
173        open: Some(drm::File::<T::File>::open_callback),
174        postclose: Some(drm::File::<T::File>::postclose_callback),
175        unload: None,
176        release: Some(Device::<T>::release),
177        master_set: None,
178        master_drop: None,
179        debugfs_init: None,
180
181        // Ignore the Uninit DeviceContext below. It is only provided because it is required by the
182        // compiler, and it is not actually used by these functions.
183        gem_create_object: T::Object::<Uninit>::ALLOC_OPS.gem_create_object,
184        prime_handle_to_fd: T::Object::<Uninit>::ALLOC_OPS.prime_handle_to_fd,
185        prime_fd_to_handle: T::Object::<Uninit>::ALLOC_OPS.prime_fd_to_handle,
186        gem_prime_import: T::Object::<Uninit>::ALLOC_OPS.gem_prime_import,
187        gem_prime_import_sg_table: T::Object::<Uninit>::ALLOC_OPS.gem_prime_import_sg_table,
188        dumb_create: T::Object::<Uninit>::ALLOC_OPS.dumb_create,
189        dumb_map_offset: T::Object::<Uninit>::ALLOC_OPS.dumb_map_offset,
190
191        show_fdinfo: None,
192        fbdev_probe: None,
193
194        major: T::INFO.major,
195        minor: T::INFO.minor,
196        patchlevel: T::INFO.patchlevel,
197        name: crate::str::as_char_ptr_in_const_context(T::INFO.name).cast_mut(),
198        desc: crate::str::as_char_ptr_in_const_context(T::INFO.desc).cast_mut(),
199
200        driver_features: Self::compute_features(),
201        ioctls: T::IOCTLS.as_ptr(),
202        num_ioctls: T::IOCTLS.len() as i32,
203        fops: &Self::GEM_FOPS,
204    };
205
206    const GEM_FOPS: bindings::file_operations = drm::gem::create_fops();
207
208    /// Create a new `UnregisteredDevice` for a `drm::Driver`.
209    ///
210    /// This can be used to create a [`Registration`](kernel::drm::Registration).
211    pub fn new(dev: &device::Device, data: impl PinInit<T::Data, Error>) -> Result<Self> {
212        // `__drm_dev_alloc` uses `kmalloc()` to allocate memory, hence ensure a `kmalloc()`
213        // compatible `Layout`.
214        let layout = Kmalloc::aligned_layout(Layout::new::<Device<T, Uninit>>());
215
216        // Use a temporary vtable without a `release` callback until `data` is initialized, so
217        // init failure can release the DRM device without dropping uninitialized fields.
218        let alloc_vtable = bindings::drm_driver {
219            release: None,
220            ..Self::VTABLE
221        };
222
223        // SAFETY:
224        // - `alloc_vtable` reference remains valid until no longer used,
225        // - `dev` is valid by its type invarants,
226        let raw_drm: *mut Device<T, Uninit> = unsafe {
227            bindings::__drm_dev_alloc(
228                dev.as_raw(),
229                &alloc_vtable,
230                layout.size(),
231                mem::offset_of!(Device<T, Uninit>, dev),
232            )
233        }
234        .cast();
235        let raw_drm = NonNull::new(from_err_ptr(raw_drm)?).ok_or(ENOMEM)?;
236
237        // SAFETY: `raw_drm` is a valid pointer to `Self`, given that `__drm_dev_alloc` was
238        // successful.
239        let drm_dev = unsafe { Device::into_drm_device(raw_drm) };
240
241        // SAFETY: `raw_drm` is a valid pointer to `Self`.
242        let raw_data = unsafe { ptr::addr_of_mut!((*raw_drm.as_ptr()).data) };
243
244        // SAFETY:
245        // - `raw_data` is a valid pointer to uninitialized memory.
246        // - `raw_data` will not move until it is dropped.
247        unsafe { data.__pinned_init(raw_data) }.inspect_err(|_| {
248            // SAFETY: `__drm_dev_alloc()` was successful, hence `drm_dev` must be valid and the
249            // refcount must be non-zero.
250            unsafe { bindings::drm_dev_put(drm_dev) };
251        })?;
252
253        // SAFETY: `drm_dev` is still private to this function.
254        unsafe { (*drm_dev).driver = const { &Self::VTABLE } };
255
256        // SAFETY: The reference count is one, and now we take ownership of that reference as a
257        // `drm::Device`.
258        // INVARIANT: We just created the device above, but have yet to call `drm_dev_register`.
259        // `Self` cannot be copied or sent to another thread - ensuring that `drm_dev_register`
260        // won't be called during its lifetime and that the device is unregistered.
261        Ok(Self(unsafe { ARef::from_raw(raw_drm) }, NotThreadSafe))
262    }
263}
264
265/// A typed DRM device with a specific [`drm::Driver`] implementation and [`DeviceContext`].
266///
267/// Since DRM devices can be used before being fully initialized and registered with userspace, `C`
268/// represents the furthest [`DeviceContext`] we can guarantee that this [`Device`] has reached.
269///
270/// Keep in mind: this means that an unregistered device can still have the registration state
271/// [`Registered`] as long as it was registered with userspace once in the past, and that the
272/// behavior of such a device is still well-defined. Additionally, a device with the registration
273/// state [`Uninit`] simply does not have a guaranteed registration state at compile time, and could
274/// be either registered or unregistered. Since there is no way to guarantee a long-lived reference
275/// to an unregistered device would remain unregistered, we do not provide a [`DeviceContext`] for
276/// this.
277///
278/// # Invariants
279///
280/// * `self.dev` is a valid instance of a `struct device`.
281/// * The data layout of `Self` remains the same across all implementations of `C`.
282/// * Any invariants for `C` also apply.
283#[repr(C)]
284pub struct Device<T: drm::Driver, C: DeviceContext = Registered> {
285    dev: Opaque<bindings::drm_device>,
286    data: T::Data,
287    _ctx: PhantomData<C>,
288}
289
290impl<T: drm::Driver, C: DeviceContext> Device<T, C> {
291    pub(crate) fn as_raw(&self) -> *mut bindings::drm_device {
292        self.dev.get()
293    }
294
295    /// # Safety
296    ///
297    /// `ptr` must be a valid pointer to a `struct device` embedded in `Self`.
298    unsafe fn from_drm_device(ptr: *const bindings::drm_device) -> *mut Self {
299        // SAFETY: By the safety requirements of this function `ptr` is a valid pointer to a
300        // `struct drm_device` embedded in `Self`.
301        unsafe { crate::container_of!(Opaque::cast_from(ptr), Self, dev) }.cast_mut()
302    }
303
304    /// # Safety
305    ///
306    /// `ptr` must be a valid pointer to `Self`.
307    unsafe fn into_drm_device(ptr: NonNull<Self>) -> *mut bindings::drm_device {
308        // SAFETY: By the safety requirements of this function, `ptr` is a valid pointer to `Self`.
309        unsafe { &raw mut (*ptr.as_ptr()).dev }.cast()
310    }
311
312    /// Not intended to be called externally, except via declare_drm_ioctls!()
313    ///
314    /// # Safety
315    ///
316    /// * Callers must ensure that `ptr` is valid, non-null, and has a non-zero reference count,
317    ///   i.e. it must be ensured that the reference count of the C `struct drm_device` `ptr` points
318    ///   to can't drop to zero, for the duration of this function call and the entire duration when
319    ///   the returned reference exists.
320    /// * Additionally, callers must ensure that the `struct device`, `ptr` is pointing to, is
321    ///   embedded in `Self`.
322    /// * Callers promise that any type invariants of `C` will be upheld.
323    #[doc(hidden)]
324    pub unsafe fn from_raw<'a>(ptr: *const bindings::drm_device) -> &'a Self {
325        // SAFETY: By the safety requirements of this function `ptr` is a valid pointer to a
326        // `struct drm_device` embedded in `Self`.
327        let ptr = unsafe { Self::from_drm_device(ptr) };
328
329        // SAFETY: `ptr` is valid by the safety requirements of this function.
330        unsafe { &*ptr.cast() }
331    }
332
333    extern "C" fn release(ptr: *mut bindings::drm_device) {
334        // SAFETY: `ptr` is a valid pointer to a `struct drm_device` and embedded in `Self`.
335        let this = unsafe { Self::from_drm_device(ptr) };
336
337        // SAFETY:
338        // - When `release` runs it is guaranteed that there is no further access to `this`.
339        // - `this` is valid for dropping.
340        unsafe { core::ptr::drop_in_place(this) };
341    }
342
343    /// Change the [`DeviceContext`] for a [`Device`].
344    ///
345    /// # Safety
346    ///
347    /// The caller promises that `self` fulfills all of the guarantees provided by the given
348    /// [`DeviceContext`].
349    pub(crate) unsafe fn assume_ctx<NewCtx: DeviceContext>(&self) -> &Device<T, NewCtx> {
350        // SAFETY: The data layout is identical via our type invariants.
351        unsafe { mem::transmute(self) }
352    }
353}
354
355impl<T: drm::Driver, C: DeviceContext> Deref for Device<T, C> {
356    type Target = T::Data;
357
358    fn deref(&self) -> &Self::Target {
359        &self.data
360    }
361}
362
363// SAFETY: DRM device objects are always reference counted and the get/put functions
364// satisfy the requirements.
365unsafe impl<T: drm::Driver, C: DeviceContext> AlwaysRefCounted for Device<T, C> {
366    fn inc_ref(&self) {
367        // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
368        unsafe { bindings::drm_dev_get(self.as_raw()) };
369    }
370
371    unsafe fn dec_ref(obj: NonNull<Self>) {
372        // SAFETY: `obj` is a valid pointer to `Self`.
373        let drm_dev = unsafe { Self::into_drm_device(obj) };
374
375        // SAFETY: The safety requirements guarantee that the refcount is non-zero.
376        unsafe { bindings::drm_dev_put(drm_dev) };
377    }
378}
379
380impl<T: drm::Driver, C: DeviceContext> AsRef<device::Device> for Device<T, C> {
381    fn as_ref(&self) -> &device::Device {
382        // SAFETY: `bindings::drm_device::dev` is valid as long as the DRM device itself is valid,
383        // which is guaranteed by the type invariant.
384        unsafe { device::Device::from_raw((*self.as_raw()).dev) }
385    }
386}
387
388// SAFETY: A `drm::Device` can be released from any thread.
389unsafe impl<T: drm::Driver, C: DeviceContext> Send for Device<T, C> {}
390
391// SAFETY: A `drm::Device` can be shared among threads because all immutable methods are protected
392// by the synchronization in `struct drm_device`.
393unsafe impl<T: drm::Driver, C: DeviceContext> Sync for Device<T, C> {}
394
395impl<T, C, const ID: u64> WorkItem<ID> for Device<T, C>
396where
397    T: drm::Driver,
398    T::Data: WorkItem<ID, Pointer = ARef<Self>>,
399    T::Data: HasWork<Self, ID>,
400    C: DeviceContext,
401{
402    type Pointer = ARef<Self>;
403
404    fn run(ptr: ARef<Self>) {
405        T::Data::run(ptr);
406    }
407}
408
409// SAFETY:
410//
411// - `raw_get_work` and `work_container_of` return valid pointers by relying on
412// `T::Data::raw_get_work` and `container_of`. In particular, `T::Data` is
413// stored inline in `drm::Device`, so the `container_of` call is valid.
414//
415// - The two methods are true inverses of each other: given `ptr: *mut
416// Device<T, C>`, `raw_get_work` will return a `*mut Work<Device<T, C>, ID>` through
417// `T::Data::raw_get_work` and given a `ptr: *mut Work<Device<T, C>, ID>`,
418// `work_container_of` will return a `*mut Device<T, C>` through `container_of`.
419unsafe impl<T, C, const ID: u64> HasWork<Self, ID> for Device<T, C>
420where
421    T: drm::Driver,
422    T::Data: HasWork<Self, ID>,
423    C: DeviceContext,
424{
425    unsafe fn raw_get_work(ptr: *mut Self) -> *mut Work<Self, ID> {
426        // SAFETY: The caller promises that `ptr` points to a valid `Device<T, C>`.
427        let data_ptr = unsafe { &raw mut (*ptr).data };
428
429        // SAFETY: `data_ptr` is a valid pointer to `T::Data`.
430        unsafe { T::Data::raw_get_work(data_ptr) }
431    }
432
433    unsafe fn work_container_of(ptr: *mut Work<Self, ID>) -> *mut Self {
434        // SAFETY: The caller promises that `ptr` points at a `Work` field in
435        // `T::Data`.
436        let data_ptr = unsafe { T::Data::work_container_of(ptr) };
437
438        // SAFETY: `T::Data` is stored as the `data` field in `Device<T, C>`.
439        unsafe { crate::container_of!(data_ptr, Self, data) }
440    }
441}
442
443// SAFETY: Our `HasWork<T, ID>` implementation returns a `work_struct` that is
444// stored in the `work` field of a `delayed_work` with the same access rules as
445// the `work_struct` owing to the bound on `T::Data: HasDelayedWork<Device<T, C>,
446// ID>`, which requires that `T::Data::raw_get_work` return a `work_struct` that
447// is inside a `delayed_work`.
448unsafe impl<T, C, const ID: u64> HasDelayedWork<Self, ID> for Device<T, C>
449where
450    T: drm::Driver,
451    T::Data: HasDelayedWork<Self, ID>,
452    C: DeviceContext,
453{
454}