Commit 0600032c authored by Asahi Lina's avatar Asahi Lina Committed by Danilo Krummrich
Browse files

rust: drm: add DRM driver registration



Implement the DRM driver `Registration`.

The `Registration` structure is responsible to register and unregister a
DRM driver. It makes use of the `Devres` container in order to allow the
`Registration` to be owned by devres, such that it is automatically
dropped (and the DRM driver unregistered) once the parent device is
unbound.

Signed-off-by: default avatarAsahi Lina <lina@asahilina.net>
Reviewed-by: default avatarAlyssa Rosenzweig <alyssa@rosenzweig.io>
Reviewed-by: default avatarLyude Paul <lyude@redhat.com>
Link: https://lore.kernel.org/r/20250410235546.43736-6-dakr@kernel.org
[ Rework of drm::Registration
    * move VTABLE to drm::Device to prevent use-after-free bugs; VTABLE
      needs to be bound to the lifetime of drm::Device, not the
      drm::Registration
    * combine new() and register() to get rid of the registered boolean
    * remove file_operations
    * move struct drm_device creation to drm::Device
    * introduce Devres
    * original source archive: https://archive.is/Pl9ys



  - Danilo ]
Signed-off-by: default avatarDanilo Krummrich <dakr@kernel.org>
parent 1e4b8896
Loading
Loading
Loading
Loading
+59 −1
Original line number Diff line number Diff line
@@ -4,7 +4,15 @@
//!
//! C header: [`include/linux/drm/drm_drv.h`](srctree/include/linux/drm/drm_drv.h)

use crate::{bindings, drm, str::CStr};
use crate::{
    bindings, device,
    devres::Devres,
    drm,
    error::{to_result, Result},
    prelude::*,
    str::CStr,
    types::ARef,
};
use macros::vtable;

/// Driver use the GEM memory manager. This should be set for all modern drivers.
@@ -103,3 +111,53 @@ pub trait Driver {
    /// IOCTL list. See `kernel::drm::ioctl::declare_drm_ioctls!{}`.
    const IOCTLS: &'static [drm::ioctl::DrmIoctlDescriptor];
}

/// The registration type of a `drm::Device`.
///
/// Once the `Registration` structure is dropped, the device is unregistered.
pub struct Registration<T: Driver>(ARef<drm::Device<T>>);

impl<T: Driver> Registration<T> {
    /// Creates a new [`Registration`] and registers it.
    fn new(drm: &drm::Device<T>, flags: usize) -> Result<Self> {
        // SAFETY: `drm.as_raw()` is valid by the invariants of `drm::Device`.
        to_result(unsafe { bindings::drm_dev_register(drm.as_raw(), flags) })?;

        Ok(Self(drm.into()))
    }

    /// Same as [`Registration::new`}, but transfers ownership of the [`Registration`] to
    /// [`Devres`].
    pub fn new_foreign_owned(
        drm: &drm::Device<T>,
        dev: &device::Device<device::Bound>,
        flags: usize,
    ) -> Result {
        if drm.as_ref().as_raw() != dev.as_raw() {
            return Err(EINVAL);
        }

        let reg = Registration::<T>::new(drm, flags)?;
        Devres::new_foreign_owned(dev, reg, GFP_KERNEL)
    }

    /// Returns a reference to the `Device` instance for this registration.
    pub fn device(&self) -> &drm::Device<T> {
        &self.0
    }
}

// SAFETY: `Registration` doesn't offer any methods or access to fields when shared between
// threads, hence it's safe to share it.
unsafe impl<T: Driver> Sync for Registration<T> {}

// SAFETY: Registration with and unregistration from the DRM subsystem can happen from any thread.
unsafe impl<T: Driver> Send for Registration<T> {}

impl<T: Driver> Drop for Registration<T> {
    fn drop(&mut self) {
        // SAFETY: Safe by the invariant of `ARef<drm::Device<T>>`. The existence of this
        // `Registration` also guarantees the this `drm::Device` is actually registered.
        unsafe { bindings::drm_dev_unregister(self.0.as_raw()) };
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
pub use self::device::Device;
pub use self::driver::Driver;
pub use self::driver::DriverInfo;
pub use self::driver::Registration;

pub(crate) mod private {
    pub trait Sealed {}