[PATCH 5/8] rust: drm: add DRM driver registration
Maxime Ripard
mripard at kernel.org
Wed Mar 26 09:24:43 UTC 2025
Hi,
On Wed, Mar 26, 2025 at 12:54:32AM +0100, Danilo Krummrich wrote:
> 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.
The code looks correct, but the wording is confusing to me.
drm_dev_unregister does indeed unregister the device, but it's not freed
until the last reference is dropped, so it's not really "dropped once
the parent device is unbound", the reference is, and it's not active
anymore.
> Co-developed-by: Asahi Lina <lina at asahilina.net>
> Signed-off-by: Asahi Lina <lina at asahilina.net>
> Signed-off-by: Danilo Krummrich <dakr at kernel.org>
> ---
> rust/kernel/drm/driver.rs | 57 ++++++++++++++++++++++++++++++++++++++-
> rust/kernel/drm/mod.rs | 1 +
> 2 files changed, 57 insertions(+), 1 deletion(-)
>
> diff --git a/rust/kernel/drm/driver.rs b/rust/kernel/drm/driver.rs
> index 625cab7839a3..8d2b397018d1 100644
> --- a/rust/kernel/drm/driver.rs
> +++ b/rust/kernel/drm/driver.rs
> @@ -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,
> + devres::Devres,
> + drm,
> + error::{Error, Result},
> + prelude::*,
> + str::CStr,
> + types::ARef,
> +};
> use macros::vtable;
>
> /// Driver use the GEM memory manager. This should be set for all modern drivers.
> @@ -134,3 +142,50 @@ 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.
> + pub fn new(drm: ARef<drm::Device<T>>, flags: usize) -> Result<Self> {
> + // SAFETY: Safe by the invariants of `drm::Device`.
> + let ret = unsafe { bindings::drm_dev_register(drm.as_raw(), flags) };
> + if ret < 0 {
> + return Err(Error::from_errno(ret));
> + }
> +
> + Ok(Self(drm))
> + }
> +
> + /// Same as [`Registration::new`}, but transfers ownership of the [`Registration`] to
> + /// [`Devres`].
> + pub fn new_foreign_owned(drm: ARef<drm::device::Device<T>>, flags: usize) -> Result {
> + let reg = Registration::<T>::new(drm.clone(), flags)?;
> +
> + Devres::new_foreign_owned(drm.as_ref(), 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> {
> + /// Removes the registration from the kernel if it has completed successfully before.
> + 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()) };
> + }
> +}
drm_dev_unregister also have an hotplug-aware variant in
drm_dev_unplug(). However, most devices are hotpluggable, even if only
through sysfs. So drm_dev_unplug() is generally a better option. Should
we use it here, and / or should we provide multiple options still?
Another thing worth mentioning I think is that drm_dev_unplug() works by
setting a flag, and drivers are expected to check that their access to
device-bound resources (so registers mapping, clocks, regulators, etc.)
are still there through drm_dev_enter/drm_dev_exit. It's pretty fragile
overall, so I wonder if it's something we could abstract away in Rust.
Maxime
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <https://lists.freedesktop.org/archives/dri-devel/attachments/20250326/8701fb24/attachment.sig>
More information about the dri-devel
mailing list