summaryrefslogtreecommitdiff
path: root/rust/kernel/drm
diff options
context:
space:
mode:
Diffstat (limited to 'rust/kernel/drm')
-rw-r--r--rust/kernel/drm/driver.rs77
-rw-r--r--rust/kernel/drm/gem/mod.rs13
-rw-r--r--rust/kernel/drm/gem/shmem.rs5
3 files changed, 46 insertions, 49 deletions
diff --git a/rust/kernel/drm/driver.rs b/rust/kernel/drm/driver.rs
index 74f6ed690d8b..f6db91e81e79 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,40 @@ 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>,
- flags: usize,
- ) -> Result<Self>
+ data: impl PinInit<T::RegistrationData<'a>, E>,
+ ) -> 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(), 0) };
+ 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 +218,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
diff --git a/rust/kernel/drm/gem/mod.rs b/rust/kernel/drm/gem/mod.rs
index e1ebad77ebe2..85657a39e146 100644
--- a/rust/kernel/drm/gem/mod.rs
+++ b/rust/kernel/drm/gem/mod.rs
@@ -266,18 +266,7 @@ impl<T: DriverObject, Ctx: DeviceContext> Object<T, Ctx> {
free: Some(Self::free_callback),
open: Some(open_callback::<T>),
close: Some(close_callback::<T>),
- print_info: None,
- export: None,
- pin: None,
- unpin: None,
- get_sg_table: None,
- vmap: None,
- vunmap: None,
- mmap: None,
- status: None,
- vm_ops: core::ptr::null_mut(),
- evict: None,
- rss: None,
+ ..pin_init::zeroed()
};
/// Returns the `Device` that owns this GEM object.
diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs
index a687d46d170d..24cb5343e0db 100644
--- a/rust/kernel/drm/gem/shmem.rs
+++ b/rust/kernel/drm/gem/shmem.rs
@@ -132,19 +132,16 @@ impl<T: DriverObject> Object<T> {
open: Some(super::open_callback::<T>),
close: Some(super::close_callback::<T>),
print_info: Some(bindings::drm_gem_shmem_object_print_info),
- export: None,
pin: Some(bindings::drm_gem_shmem_object_pin),
unpin: Some(bindings::drm_gem_shmem_object_unpin),
get_sg_table: Some(bindings::drm_gem_shmem_object_get_sg_table),
vmap: Some(bindings::drm_gem_shmem_object_vmap),
vunmap: Some(bindings::drm_gem_shmem_object_vunmap),
mmap: Some(bindings::drm_gem_shmem_object_mmap),
- status: None,
- rss: None,
#[allow(unused_unsafe, reason = "Safe since Rust 1.82.0")]
// SAFETY: `drm_gem_shmem_vm_ops` is a valid, static const on the C side.
vm_ops: unsafe { &raw const bindings::drm_gem_shmem_vm_ops },
- evict: None,
+ ..pin_init::zeroed()
};
/// Return a raw pointer to the embedded drm_gem_shmem_object.