summaryrefslogtreecommitdiff
path: root/rust/kernel/drm
diff options
context:
space:
mode:
authorDanilo Krummrich <dakr@kernel.org>2026-09-29 20:59:30 +0200
committerDanilo Krummrich <dakr@kernel.org>2026-10-10 22:15:45 +0200
commit700eed1364e8a5ec4318d457cf700611decdb175 (patch)
tree177a3b320b1f6cc84b5216c6631787547e54a5b4 /rust/kernel/drm
parent3e3404c52370595e37eb5b942df169884f38a124 (diff)
rust: drm: Return impl PinInit from drm::Registration::new()
Convert drm::Registration to return an impl PinInit<Self, Error> rather than creating a separate allocation. This removes an otherwise unnecessary allocation. Update both in-tree callers (nova, tyr) to construct their bus device private data using try_pin_init!(). Reviewed-by: Alice Ryhl <aliceryhl@google.com> Link: https://patch.msgid.link/20260929190024.2248099-1-dakr@kernel.org Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Diffstat (limited to 'rust/kernel/drm')
-rw-r--r--rust/kernel/drm/driver.rs76
1 files changed, 44 insertions, 32 deletions
diff --git a/rust/kernel/drm/driver.rs b/rust/kernel/drm/driver.rs
index 74f6ed690d8b..13aa609350b1 100644
--- a/rust/kernel/drm/driver.rs
+++ b/rust/kernel/drm/driver.rs
@@ -12,7 +12,10 @@ use crate::{
prelude::*,
sync::aref::ARef, //
};
-use core::ptr::NonNull;
+use core::{
+ marker::PhantomPinned,
+ ptr::NonNull, //
+};
/// Driver use the GEM memory manager. This should be set for all modern drivers.
pub(crate) const FEAT_GEM: u32 = bindings::drm_driver_feature_DRIVER_GEM;
@@ -143,9 +146,15 @@ pub trait Driver {
/// The registration type of a `drm::Device`.
///
/// Once the `Registration` structure is dropped, the device is unregistered.
+#[pin_data(PinnedDrop)]
pub struct Registration<'a, T: Driver> {
drm: ARef<drm::Device<T>>,
- _reg_data: Pin<KBox<T::RegistrationData<'a>>>,
+ #[pin]
+ data: T::RegistrationData<'a>,
+ /// Even if `T::RegistrationData` is `Unpin`, the registration must not be moved because a
+ /// pointer to `data` is stored in the DRM device.
+ #[pin]
+ _pin: PhantomPinned,
}
impl<'a, T: Driver> Registration<'a, T> {
@@ -159,39 +168,41 @@ impl<'a, T: Driver> Registration<'a, T> {
pub unsafe fn new<E>(
dev: &'a device::Device<device::Bound>,
drm: drm::UnregisteredDevice<T>,
- reg_data: impl PinInit<T::RegistrationData<'a>, E>,
+ data: impl PinInit<T::RegistrationData<'a>, E>,
flags: usize,
- ) -> Result<Self>
+ ) -> impl PinInit<Self, Error>
where
Error: From<E>,
{
- let parent = drm.as_ref();
- if parent.as_ref().as_raw() != dev.as_raw() {
- return Err(EINVAL);
- }
-
- let reg_data: Pin<KBox<T::RegistrationData<'a>>> = KBox::pin_init(reg_data, GFP_KERNEL)?;
-
- // Store the registration data pointer in the device before registration, so that it is
- // visible once ioctls can be called.
- let ptr: NonNull<T::RegistrationData<'static>> =
- NonNull::from(Pin::get_ref(reg_data.as_ref())).cast();
-
- // SAFETY: No concurrent access; the device is not yet registered.
- unsafe { *drm.registration_data.get() = ptr };
-
- // SAFETY: `drm` is a valid, initialized but not yet registered DRM device.
- let ret = unsafe { bindings::drm_dev_register(drm.as_raw(), flags) };
- if let Err(e) = to_result(ret) {
- // SAFETY: `drm_dev_register()` synchronizes SRCU on failure, so no concurrent
- // access to `registration_data` is possible at this point.
- unsafe { *drm.registration_data.get() = NonNull::dangling() };
- return Err(e);
- }
-
- Ok(Self {
+ try_pin_init!(Self {
+ _: {
+ let parent = drm.as_ref();
+ if parent.as_ref().as_raw() != dev.as_raw() {
+ return Err(EINVAL);
+ }
+ },
+
+ data <- data,
drm: (&*drm).into(),
- _reg_data: reg_data,
+ _pin: PhantomPinned,
+
+ _: {
+ // Store the registration data pointer in the device before registration, so
+ // that it is visible once ioctls can be called.
+ let ptr: NonNull<T::RegistrationData<'static>> =
+ NonNull::from(data.as_ref().get_ref()).cast();
+
+ // SAFETY: No concurrent access; the device is not yet registered.
+ unsafe { *drm.registration_data.get() = ptr };
+
+ // SAFETY: `drm` is a valid, initialized but not yet registered DRM device.
+ let ret = unsafe { bindings::drm_dev_register(drm.as_raw(), flags) };
+ to_result(ret).inspect_err(|_| {
+ // SAFETY: `drm_dev_register()` synchronizes SRCU on failure, so no
+ // concurrent access to `registration_data` is possible at this point.
+ unsafe { *drm.registration_data.get() = NonNull::dangling() };
+ })?;
+ },
})
}
@@ -208,8 +219,9 @@ 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) {
+#[pinned_drop]
+impl<T: Driver> PinnedDrop for Registration<'_, T> {
+ fn drop(self: Pin<&mut Self>) {
// Use `drm_dev_unplug` rather than `drm_dev_unregister` to ensure that existing
// `drm_dev_enter()` critical sections complete before unregistration proceeds. This
// is required for the safety of `RegistrationGuard`, which relies on the SRCU barrier in