* [PATCH 0/6] rust: drm: Higher-Ranked Lifetime private data
@ 2026-05-06 22:05 Danilo Krummrich
2026-05-06 22:05 ` [PATCH 1/6] rust: drm: Add Driver::ParentDevice associated type Danilo Krummrich
` (6 more replies)
0 siblings, 7 replies; 9+ messages in thread
From: Danilo Krummrich @ 2026-05-06 22:05 UTC (permalink / raw)
To: aliceryhl, airlied, simona, daniel.almeida, acourbot, apopple,
ecourtney, deborah.brouwer, lyude, ojeda, boqun, gary, bjorn3_gh,
lossin, a.hindborg, tmgross
Cc: driver-core, nova-gpu, dri-devel, linux-kernel, rust-for-linux,
Danilo Krummrich
DRM ioctls run in process context without any guarantee that the parent
bus device is still bound. This series solves the problem by introducing
UnbindGuard -- a guard representing a drm_dev_enter/exit SRCU critical
section that proves the parent bus device is bound for the lifetime of
the guard.
On top of that, add RegistrationData as a ForLt associated type on
drm::Driver, allowing drivers to store data whose lifetime is tied to
the parent bus device binding scope. The data is allocated in
Registration::new(), lifetime-erased to 'static for storage, and made
accessible through UnbindGuard::registration_data() with the lifetime
shortened back via ForLt::cast_ref.
Also update the ioctl dispatch macro to wrap every handler in an
UnbindGuard, returning ENODEV if the device has been unplugged, and
pass both the bound parent bus device and the registration data as
arguments to handlers.
This series is based on [1], as well as Lyudes drm::DeviceContext work;
a branch with all patches can be found in [2].
[1] https://lore.kernel.org/driver-core/20260506220012.855173-1-dakr@kernel.org/
[2] https://git.kernel.org/pub/scm/linux/kernel/git/dakr/linux.git/log/?h=drm-lifetime
Danilo Krummrich (6):
rust: drm: Add Driver::ParentDevice associated type
rust: drm: Add UnbindGuard for drm_dev_enter/exit critical sections
rust: drm: Add RegistrationData to drm::Driver
rust: drm: Wrap ioctl dispatch in UnbindGuard
rust: drm: Pass registration data to ioctl handlers
rust: drm: Pass bound parent device to ioctl handlers
drivers/gpu/drm/nova/driver.rs | 14 +++-
drivers/gpu/drm/nova/file.rs | 8 ++
drivers/gpu/drm/tyr/driver.rs | 12 ++-
drivers/gpu/drm/tyr/file.rs | 4 +
rust/kernel/drm/device.rs | 134 ++++++++++++++++++++++++++++++++-
rust/kernel/drm/driver.rs | 100 +++++++++++++++++++-----
rust/kernel/drm/ioctl.rs | 17 ++++-
rust/kernel/drm/mod.rs | 1 +
8 files changed, 258 insertions(+), 32 deletions(-)
--
2.54.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/6] rust: drm: Add Driver::ParentDevice associated type
2026-05-06 22:05 [PATCH 0/6] rust: drm: Higher-Ranked Lifetime private data Danilo Krummrich
@ 2026-05-06 22:05 ` Danilo Krummrich
2026-05-08 21:49 ` lyude
2026-05-06 22:06 ` [PATCH 2/6] rust: drm: Add UnbindGuard for drm_dev_enter/exit critical sections Danilo Krummrich
` (5 subsequent siblings)
6 siblings, 1 reply; 9+ messages in thread
From: Danilo Krummrich @ 2026-05-06 22:05 UTC (permalink / raw)
To: aliceryhl, airlied, simona, daniel.almeida, acourbot, apopple,
ecourtney, deborah.brouwer, lyude, ojeda, boqun, gary, bjorn3_gh,
lossin, a.hindborg, tmgross
Cc: driver-core, nova-gpu, dri-devel, linux-kernel, rust-for-linux,
Danilo Krummrich
Add a ParentDevice associated type to the Driver trait, allowing each
DRM driver to declare its parent bus device type (e.g.
auxiliary::Device, platform::Device).
Change UnregisteredDevice::new() to take &T::ParentDevice<Bound>,
ensuring at the type level that the DRM device's parent matches the
declared bus device type.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
drivers/gpu/drm/nova/driver.rs | 8 ++++++--
drivers/gpu/drm/tyr/driver.rs | 6 ++++--
rust/kernel/drm/device.rs | 7 +++++--
rust/kernel/drm/driver.rs | 3 +++
4 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/nova/driver.rs b/drivers/gpu/drm/nova/driver.rs
index 9eef28b506bb..9d4100f01ea7 100644
--- a/drivers/gpu/drm/nova/driver.rs
+++ b/drivers/gpu/drm/nova/driver.rs
@@ -2,7 +2,10 @@
use kernel::{
auxiliary,
- device::Core,
+ device::{
+ Core,
+ DeviceContext, //
+ },
drm::{
self,
gem,
@@ -59,7 +62,7 @@ fn probe(
) -> impl PinInit<Self, Error> + 'bound {
let data = try_pin_init!(NovaData { adev: adev.into() });
- let drm = drm::UnregisteredDevice::<Self>::new(adev.as_ref(), data)?;
+ let drm = drm::UnregisteredDevice::<Self>::new(adev, data)?;
let drm = drm::Registration::new_foreign_owned(drm, adev.as_ref(), 0)?;
Ok(Self { drm: drm.into() })
@@ -71,6 +74,7 @@ impl drm::Driver for NovaDriver {
type Data = NovaData;
type File = File;
type Object<Ctx: drm::DeviceContext> = gem::Object<NovaObject, Ctx>;
+ type ParentDevice<Ctx: DeviceContext> = auxiliary::Device<Ctx>;
const INFO: drm::DriverInfo = INFO;
diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
index 2743178af325..747745d23f31 100644
--- a/drivers/gpu/drm/tyr/driver.rs
+++ b/drivers/gpu/drm/tyr/driver.rs
@@ -8,7 +8,8 @@
device::{
Bound,
Core,
- Device, //
+ Device,
+ DeviceContext, //
},
drm,
drm::ioctl,
@@ -131,7 +132,7 @@ fn probe(
gpu_info,
});
- let tdev = drm::UnregisteredDevice::<TyrDrmDriver>::new(pdev.as_ref(), data)?;
+ let tdev = drm::UnregisteredDevice::<TyrDrmDriver>::new(pdev, data)?;
let tdev = drm::driver::Registration::new_foreign_owned(tdev, pdev.as_ref(), 0)?;
let driver = TyrPlatformDriverData {
@@ -176,6 +177,7 @@ impl drm::Driver for TyrDrmDriver {
type Data = TyrDrmDeviceData;
type File = TyrDrmFileData;
type Object<R: drm::DeviceContext> = drm::gem::Object<TyrObject, R>;
+ type ParentDevice<Ctx: DeviceContext> = platform::Device<Ctx>;
const INFO: drm::DriverInfo = INFO;
diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs
index d91f19dcc375..492c2f2c7ca4 100644
--- a/rust/kernel/drm/device.rs
+++ b/rust/kernel/drm/device.rs
@@ -197,7 +197,10 @@ impl<T: drm::Driver> UnregisteredDevice<T> {
/// Create a new `UnregisteredDevice` for a `drm::Driver`.
///
/// This can be used to create a [`Registration`](kernel::drm::Registration).
- pub fn new(dev: &device::Device, data: impl PinInit<T::Data, Error>) -> Result<Self> {
+ pub fn new(
+ dev: &T::ParentDevice<device::Bound>,
+ data: impl PinInit<T::Data, Error>,
+ ) -> Result<Self> {
// `__drm_dev_alloc` uses `kmalloc()` to allocate memory, hence ensure a `kmalloc()`
// compatible `Layout`.
let layout = Kmalloc::aligned_layout(Layout::new::<Device<T, Uninit>>());
@@ -207,7 +210,7 @@ pub fn new(dev: &device::Device, data: impl PinInit<T::Data, Error>) -> Result<S
// - `dev` is valid by its type invarants,
let raw_drm: *mut Device<T, Uninit> = unsafe {
bindings::__drm_dev_alloc(
- dev.as_raw(),
+ dev.as_ref().as_raw(),
&Self::VTABLE,
layout.size(),
mem::offset_of!(Device<T, Uninit>, dev),
diff --git a/rust/kernel/drm/driver.rs b/rust/kernel/drm/driver.rs
index 294e17af86a3..9d06f8c5b2da 100644
--- a/rust/kernel/drm/driver.rs
+++ b/rust/kernel/drm/driver.rs
@@ -114,6 +114,9 @@ pub trait Driver {
/// The type used to represent a DRM File (client)
type File: drm::file::DriverFile;
+ /// The bus device type of the parent device that the DRM device is associated with.
+ type ParentDevice<Ctx: device::DeviceContext>: device::AsBusDevice<Ctx>;
+
/// Driver metadata
const INFO: DriverInfo;
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 2/6] rust: drm: Add UnbindGuard for drm_dev_enter/exit critical sections
2026-05-06 22:05 [PATCH 0/6] rust: drm: Higher-Ranked Lifetime private data Danilo Krummrich
2026-05-06 22:05 ` [PATCH 1/6] rust: drm: Add Driver::ParentDevice associated type Danilo Krummrich
@ 2026-05-06 22:06 ` Danilo Krummrich
2026-05-06 22:06 ` [PATCH 3/6] rust: drm: Add RegistrationData to drm::Driver Danilo Krummrich
` (4 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Danilo Krummrich @ 2026-05-06 22:06 UTC (permalink / raw)
To: aliceryhl, airlied, simona, daniel.almeida, acourbot, apopple,
ecourtney, deborah.brouwer, lyude, ojeda, boqun, gary, bjorn3_gh,
lossin, a.hindborg, tmgross
Cc: driver-core, nova-gpu, dri-devel, linux-kernel, rust-for-linux,
Danilo Krummrich
DRM ioctls do not guarantee that the parent bus device is still bound.
However, since DRM device registration is managed through Devres, using
drm_dev_unplug() on unregistration ensures that between drm_dev_enter()
and drm_dev_exit() the parent device must be bound.
Add UnbindGuard, a guard object representing a drm_dev_enter/exit SRCU
critical section that dereferences to &Device<Bound> of the parent bus
device. The guard is only available on Device<T, Registered>, ensuring
it cannot be used on unregistered devices.
Also add with_unbind_guard() as a convenience helper that executes a
closure with the bound device reference.
Switch Registration::drop from drm_dev_unregister() to drm_dev_unplug()
to provide the SRCU barrier that UnbindGuard's safety argument relies on.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
rust/kernel/drm/device.rs | 80 ++++++++++++++++++++++++++++++++++++++-
rust/kernel/drm/driver.rs | 10 ++++-
2 files changed, 87 insertions(+), 3 deletions(-)
diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs
index 492c2f2c7ca4..bb685165032d 100644
--- a/rust/kernel/drm/device.rs
+++ b/rust/kernel/drm/device.rs
@@ -6,7 +6,11 @@
use crate::{
alloc::allocator::Kmalloc,
- bindings, device,
+ bindings,
+ device::{
+ self,
+ AsBusDevice as _, //
+ },
drm::{
self,
driver::AllocImpl,
@@ -334,6 +338,80 @@ pub(crate) unsafe fn assume_ctx<NewCtx: DeviceContext>(&self) -> &Device<T, NewC
}
}
+impl<T: drm::Driver> Device<T, Registered> {
+ /// Guard against the parent bus device being unbound.
+ ///
+ /// Returns an [`UnbindGuard`] if the device has not been unplugged, [`None`] otherwise.
+ ///
+ /// The returned guard dereferences to the parent bus device in the [`device::Bound`] context
+ /// (see [`Driver::ParentDevice`](drm::Driver::ParentDevice)).
+ /// Between `drm_dev_enter()` and `drm_dev_exit()` the parent device is guaranteed to be bound.
+ #[must_use]
+ pub fn unbind_guard(&self) -> Option<UnbindGuard<'_, T>> {
+ let mut idx: i32 = 0;
+ // SAFETY: `self.as_raw()` is a valid pointer to a `struct drm_device` by the type
+ // invariants of `Device<T, Registered>`.
+ if unsafe { bindings::drm_dev_enter(self.as_raw(), &mut idx) } {
+ Some(UnbindGuard { dev: self, idx })
+ } else {
+ None
+ }
+ }
+
+ /// Execute a closure while the parent bus device is guaranteed to be bound.
+ ///
+ /// Acquires the [`UnbindGuard`] and, if the device has not been unplugged, calls `f` with the
+ /// parent bus device. Returns `None` if the device has been unplugged.
+ pub fn with_unbind_guard<R>(
+ &self,
+ f: impl FnOnce(&T::ParentDevice<device::Bound>) -> R,
+ ) -> Option<R> {
+ let guard = self.unbind_guard()?;
+ Some(f(&guard))
+ }
+}
+
+/// A guard preventing the parent bus device from being unbound.
+///
+/// The guard dereferences to [`Driver::ParentDevice<Bound>`](drm::Driver::ParentDevice), providing
+/// access to the parent bus device with the guarantee that it is bound for the entire duration of
+/// the critical section.
+///
+/// Internally this is backed by a `drm_dev_enter()` / `drm_dev_exit()` SRCU critical section.
+///
+/// See [`Device::unbind_guard`] for details on the safety argument.
+///
+/// # Invariants
+///
+/// - `idx` is the SRCU read lock index returned by a successful `drm_dev_enter()` call.
+/// - The parent bus device of `dev` is bound for the lifetime of this guard.
+#[must_use]
+pub struct UnbindGuard<'a, T: drm::Driver> {
+ dev: &'a Device<T, Registered>,
+ idx: i32,
+}
+
+impl<T: drm::Driver> Deref for UnbindGuard<'_, T> {
+ type Target = T::ParentDevice<device::Bound>;
+
+ fn deref(&self) -> &Self::Target {
+ // SAFETY:
+ // - The parent `struct device` is embedded in a `T::ParentDevice`, as guaranteed by
+ // `UnregisteredDevice::new` taking a `&T::ParentDevice<device::Bound>`.
+ // - By the type invariants of `UnbindGuard`, the parent device is bound for the lifetime
+ // of this guard.
+ unsafe { T::ParentDevice::from_device(self.dev.as_ref().as_bound()) }
+ }
+}
+
+impl<T: drm::Driver> Drop for UnbindGuard<'_, T> {
+ fn drop(&mut self) {
+ // SAFETY: `self.idx` was returned by a successful `drm_dev_enter()` call, as guaranteed
+ // by the type invariants of `UnbindGuard`.
+ unsafe { bindings::drm_dev_exit(self.idx) };
+ }
+}
+
impl<T: drm::Driver, C: DeviceContext> Deref for Device<T, C> {
type Target = T::Data;
diff --git a/rust/kernel/drm/driver.rs b/rust/kernel/drm/driver.rs
index 9d06f8c5b2da..751a68bb27e1 100644
--- a/rust/kernel/drm/driver.rs
+++ b/rust/kernel/drm/driver.rs
@@ -187,8 +187,14 @@ unsafe impl<T: Driver> Send for Registration<T> {}
impl<T: Driver> Drop for Registration<T> {
fn drop(&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 `UnbindGuard`, which relies on the SRCU barrier in
+ // `drm_dev_unplug()` to guarantee that the parent device is still bound within the
+ // critical section.
+ //
// 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()) };
+ // `Registration` also guarantees that this `drm::Device` is actually registered.
+ unsafe { bindings::drm_dev_unplug(self.0.as_raw()) };
}
}
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 3/6] rust: drm: Add RegistrationData to drm::Driver
2026-05-06 22:05 [PATCH 0/6] rust: drm: Higher-Ranked Lifetime private data Danilo Krummrich
2026-05-06 22:05 ` [PATCH 1/6] rust: drm: Add Driver::ParentDevice associated type Danilo Krummrich
2026-05-06 22:06 ` [PATCH 2/6] rust: drm: Add UnbindGuard for drm_dev_enter/exit critical sections Danilo Krummrich
@ 2026-05-06 22:06 ` Danilo Krummrich
2026-05-06 22:06 ` [PATCH 4/6] rust: drm: Wrap ioctl dispatch in UnbindGuard Danilo Krummrich
` (3 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Danilo Krummrich @ 2026-05-06 22:06 UTC (permalink / raw)
To: aliceryhl, airlied, simona, daniel.almeida, acourbot, apopple,
ecourtney, deborah.brouwer, lyude, ojeda, boqun, gary, bjorn3_gh,
lossin, a.hindborg, tmgross
Cc: driver-core, nova-gpu, dri-devel, linux-kernel, rust-for-linux,
Danilo Krummrich
Add a RegistrationData associated type to drm::Driver. This is a ForLt
type whose lifetime is tied to the parent bus device binding scope.
Registration<T> takes ownership of the data via Pin<KBox<_>>, erasing
the lifetime to 'static for storage. The pointer is written to
drm::Device before drm_dev_register() to ensure it is already in place
when ioctls arrive.
UnbindGuard::registration_data() provides access with the lifetime
shortened from 'static via ForLt::cast_ref. Since Registration::drop()
calls drm_dev_unplug() -- which performs an SRCU barrier waiting for all
drm_dev_enter() critical sections to complete -- the data is guaranteed
to remain valid for the duration of any UnbindGuard.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
drivers/gpu/drm/nova/driver.rs | 6 ++-
drivers/gpu/drm/tyr/driver.rs | 6 ++-
rust/kernel/drm/device.rs | 40 +++++++++++++++
rust/kernel/drm/driver.rs | 89 +++++++++++++++++++++++++++-------
rust/kernel/drm/mod.rs | 1 +
5 files changed, 121 insertions(+), 21 deletions(-)
diff --git a/drivers/gpu/drm/nova/driver.rs b/drivers/gpu/drm/nova/driver.rs
index 9d4100f01ea7..54a3391371ba 100644
--- a/drivers/gpu/drm/nova/driver.rs
+++ b/drivers/gpu/drm/nova/driver.rs
@@ -12,7 +12,8 @@
ioctl, //
},
prelude::*,
- sync::aref::ARef, //
+ sync::aref::ARef,
+ types::ForLt, //
};
use crate::file::File;
@@ -63,7 +64,7 @@ fn probe(
let data = try_pin_init!(NovaData { adev: adev.into() });
let drm = drm::UnregisteredDevice::<Self>::new(adev, data)?;
- let drm = drm::Registration::new_foreign_owned(drm, adev.as_ref(), 0)?;
+ let drm = drm::Registration::new_foreign_owned(drm, adev.as_ref(), (), 0)?;
Ok(Self { drm: drm.into() })
}
@@ -72,6 +73,7 @@ fn probe(
#[vtable]
impl drm::Driver for NovaDriver {
type Data = NovaData;
+ type RegistrationData = ForLt!(());
type File = File;
type Object<Ctx: drm::DeviceContext> = gem::Object<NovaObject, Ctx>;
type ParentDevice<Ctx: DeviceContext> = auxiliary::Device<Ctx>;
diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
index 747745d23f31..7ac3707823b6 100644
--- a/drivers/gpu/drm/tyr/driver.rs
+++ b/drivers/gpu/drm/tyr/driver.rs
@@ -25,7 +25,8 @@
aref::ARef,
Mutex, //
},
- time, //
+ time,
+ types::ForLt, //
};
use crate::{
@@ -133,7 +134,7 @@ fn probe(
});
let tdev = drm::UnregisteredDevice::<TyrDrmDriver>::new(pdev, data)?;
- let tdev = drm::driver::Registration::new_foreign_owned(tdev, pdev.as_ref(), 0)?;
+ let tdev = drm::driver::Registration::new_foreign_owned(tdev, pdev.as_ref(), (), 0)?;
let driver = TyrPlatformDriverData {
_device: tdev.into(),
@@ -175,6 +176,7 @@ fn drop(self: Pin<&mut Self>) {
#[vtable]
impl drm::Driver for TyrDrmDriver {
type Data = TyrDrmDeviceData;
+ type RegistrationData = ForLt!(());
type File = TyrDrmFileData;
type Object<R: drm::DeviceContext> = drm::gem::Object<TyrObject, R>;
type ParentDevice<Ctx: DeviceContext> = platform::Device<Ctx>;
diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs
index bb685165032d..11edbe6f9f42 100644
--- a/rust/kernel/drm/device.rs
+++ b/rust/kernel/drm/device.rs
@@ -23,6 +23,7 @@
AlwaysRefCounted, //
},
types::{
+ ForLt,
NotThreadSafe,
Opaque, //
},
@@ -35,6 +36,7 @@
};
use core::{
alloc::Layout,
+ cell::UnsafeCell,
marker::PhantomData,
mem,
ops::Deref,
@@ -239,6 +241,9 @@ pub fn new(
unsafe { bindings::drm_dev_put(drm_dev) };
})?;
+ // SAFETY: `raw_drm` is valid; no concurrent access before registration.
+ unsafe { (*raw_drm.as_ptr()).registration_data = UnsafeCell::new(NonNull::dangling()) };
+
// SAFETY: The reference count is one, and now we take ownership of that reference as a
// `drm::Device`.
// INVARIANT: We just created the device above, but have yet to call `drm_dev_register`.
@@ -270,6 +275,7 @@ pub fn new(
pub struct Device<T: drm::Driver, C: DeviceContext = Registered> {
dev: Opaque<bindings::drm_device>,
data: T::Data,
+ pub(super) registration_data: UnsafeCell<NonNull<<T::RegistrationData as ForLt>::Of<'static>>>,
_ctx: PhantomData<C>,
}
@@ -278,6 +284,23 @@ pub(crate) fn as_raw(&self) -> *mut bindings::drm_device {
self.dev.get()
}
+ /// Returns a reference to the registration data with lifetime shortened
+ /// from `'static`.
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure the parent bus device is bound. This is
+ /// typically guaranteed by holding an active `drm_dev_enter()` critical
+ /// section (e.g. via [`UnbindGuard`]).
+ #[doc(hidden)]
+ pub unsafe fn raw_registration_data(&self) -> &<T::RegistrationData as ForLt>::Of<'_> {
+ // SAFETY: Caller guarantees the parent bus device is bound, hence
+ // the pointer is valid.
+ let static_ref = unsafe { (*self.registration_data.get()).as_ref() };
+
+ T::RegistrationData::cast_ref(static_ref)
+ }
+
/// # Safety
///
/// `ptr` must be a valid pointer to a `struct device` embedded in `Self`.
@@ -391,6 +414,23 @@ pub struct UnbindGuard<'a, T: drm::Driver> {
idx: i32,
}
+impl<T: drm::Driver> UnbindGuard<'_, T> {
+ /// Returns a reference to the registration data with its lifetime shortened from `'static`
+ /// to the guard's borrow lifetime.
+ ///
+ /// The data is owned by [`Registration`](drm::driver::Registration) and is guaranteed to
+ /// remain valid for the duration of this guard, since
+ /// [`Registration`](drm::driver::Registration)'s `drop` calls
+ /// `drm_dev_unplug()` which waits for all `drm_dev_enter()` critical sections to complete.
+ pub fn registration_data(&self) -> &<T::RegistrationData as ForLt>::Of<'_> {
+ // SAFETY: The pointer was set in `Registration::new()` before `drm_dev_register()`, and
+ // is only invalidated after `drm_dev_unplug()` in `Registration::drop()`. Since we hold
+ // an active `drm_dev_enter()` critical section, the SRCU barrier in `drm_dev_unplug()`
+ // guarantees the pointer is still valid.
+ unsafe { self.dev.raw_registration_data() }
+ }
+}
+
impl<T: drm::Driver> Deref for UnbindGuard<'_, T> {
type Target = T::ParentDevice<device::Bound>;
diff --git a/rust/kernel/drm/driver.rs b/rust/kernel/drm/driver.rs
index 751a68bb27e1..3a49ef324ada 100644
--- a/rust/kernel/drm/driver.rs
+++ b/rust/kernel/drm/driver.rs
@@ -11,7 +11,8 @@
drm,
error::to_result,
prelude::*,
- sync::aref::ARef, //
+ sync::aref::ARef,
+ types::ForLt, //
};
use core::{
mem,
@@ -108,6 +109,16 @@ pub trait Driver {
/// Context data associated with the DRM driver
type Data: Sync + Send;
+ /// Data owned by the [`Registration`] and accessible through [`drm::device::UnbindGuard`].
+ ///
+ /// This is a [`ForLt`](trait@ForLt) type whose lifetime is tied to the parent bus
+ /// device binding scope.
+ /// The data is only accessible while the parent bus device is bound (i.e. within a
+ /// `drm_dev_enter/exit` critical section), and references handed out by
+ /// [`UnbindGuard::registration_data()`](drm::device::UnbindGuard::registration_data) have
+ /// their lifetime shortened accordingly via [`ForLt::cast_ref`].
+ type RegistrationData: ForLt;
+
/// The type used to manage memory for this driver.
type Object<Ctx: drm::DeviceContext>: AllocImpl;
@@ -127,12 +138,44 @@ pub trait Driver {
/// 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>>);
+pub struct Registration<T: Driver> {
+ drm: ARef<drm::Device<T>>,
+ #[allow(dead_code)]
+ reg_data: Pin<KBox<<T::RegistrationData as ForLt>::Of<'static>>>,
+}
-impl<T: Driver> Registration<T> {
- fn new(drm: drm::UnregisteredDevice<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) })?;
+impl<T: Driver> Registration<T>
+where
+ for<'a> <T::RegistrationData as ForLt>::Of<'a>: Send,
+{
+ fn new<'bound, E>(
+ drm: drm::UnregisteredDevice<T>,
+ reg_data: impl PinInit<<T::RegistrationData as ForLt>::Of<'bound>, E>,
+ flags: usize,
+ ) -> Result<Self>
+ where
+ Error: From<E>,
+ {
+ let reg_data: Pin<KBox<<T::RegistrationData as ForLt>::Of<'bound>>> =
+ KBox::pin_init(reg_data, GFP_KERNEL)?;
+
+ // SAFETY: `ForLt` guarantees covariance; lifetimes do not affect layout.
+ let reg_data: Pin<KBox<<T::RegistrationData as ForLt>::Of<'static>>> =
+ unsafe { mem::transmute(reg_data) };
+
+ // Store the registration data pointer in the device before registration, so that it is
+ // visible once ioctls can be called.
+ //
+ // SAFETY: No concurrent access; the device is not yet registered.
+ unsafe { *drm.registration_data.get() = NonNull::from(Pin::get_ref(reg_data.as_ref())) }
+
+ // 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: No concurrent access; registration failed.
+ unsafe { *drm.registration_data.get() = NonNull::dangling() };
+ return Err(e);
+ }
// SAFETY: We just called `drm_dev_register` above
let new = NonNull::from(unsafe { drm.assume_ctx() });
@@ -144,46 +187,55 @@ fn new(drm: drm::UnregisteredDevice<T>, flags: usize) -> Result<Self> {
// one reference to the device - which we take ownership over here.
let new = unsafe { ARef::from_raw(new) };
- Ok(Self(new))
+ Ok(Self { drm: new, reg_data })
}
/// Registers a new [`UnregisteredDevice`](drm::UnregisteredDevice) with userspace.
///
/// Ownership of the [`Registration`] object is passed to [`devres::register`].
- pub fn new_foreign_owned<'a>(
+ pub fn new_foreign_owned<'bound, E>(
drm: drm::UnregisteredDevice<T>,
- dev: &'a device::Device<device::Bound>,
+ dev: &'bound device::Device<device::Bound>,
+ reg_data: impl PinInit<<T::RegistrationData as ForLt>::Of<'bound>, E>,
flags: usize,
- ) -> Result<&'a drm::Device<T>>
+ ) -> Result<&'bound drm::Device<T>>
where
T: 'static,
+ Error: From<E>,
{
if drm.as_ref().as_raw() != dev.as_raw() {
return Err(EINVAL);
}
- let reg = Registration::<T>::new(drm, flags)?;
+ let reg = Registration::<T>::new(drm, reg_data, flags)?;
let drm = NonNull::from(reg.device());
- devres::register(dev, reg, GFP_KERNEL)?;
+ devres::register::<_, core::convert::Infallible>(dev, reg, GFP_KERNEL)?;
// SAFETY: Since `reg` was passed to devres::register(), the device now owns the lifetime
- // of the DRM registration - ensuring that this references lives for at least as long as 'a.
+ // of the DRM registration - ensuring that this reference lives for
+ // at least as long as 'bound.
Ok(unsafe { drm.as_ref() })
}
/// Returns a reference to the `Device` instance for this registration.
pub fn device(&self) -> &drm::Device<T> {
- &self.0
+ &self.drm
}
}
// 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> {}
+unsafe impl<T: Driver> Sync for Registration<T> where
+ for<'a> <T::RegistrationData as ForLt>::Of<'a>: Send
+{
+}
// SAFETY: Registration with and unregistration from the DRM subsystem can happen from any thread.
-unsafe impl<T: Driver> Send for Registration<T> {}
+unsafe impl<T: Driver> Send for Registration<T> where
+ for<'a> <T::RegistrationData as ForLt>::Of<'a>: Send
+{
+}
impl<T: Driver> Drop for Registration<T> {
fn drop(&mut self) {
@@ -195,6 +247,9 @@ fn drop(&mut self) {
//
// SAFETY: Safe by the invariant of `ARef<drm::Device<T>>`. The existence of this
// `Registration` also guarantees that this `drm::Device` is actually registered.
- unsafe { bindings::drm_dev_unplug(self.0.as_raw()) };
+ unsafe { bindings::drm_dev_unplug(self.drm.as_raw()) };
+ // After drm_dev_unplug(), the SRCU barrier guarantees that all UnbindGuard critical
+ // sections have completed, so no one holds a reference to reg_data anymore.
+ // reg_data is dropped here automatically.
}
}
diff --git a/rust/kernel/drm/mod.rs b/rust/kernel/drm/mod.rs
index 64a43cb0fe57..6c0ba9c82b92 100644
--- a/rust/kernel/drm/mod.rs
+++ b/rust/kernel/drm/mod.rs
@@ -11,6 +11,7 @@
pub use self::device::Device;
pub use self::device::DeviceContext;
pub use self::device::Registered;
+pub use self::device::UnbindGuard;
pub use self::device::Uninit;
pub use self::device::UnregisteredDevice;
pub use self::driver::Driver;
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 4/6] rust: drm: Wrap ioctl dispatch in UnbindGuard
2026-05-06 22:05 [PATCH 0/6] rust: drm: Higher-Ranked Lifetime private data Danilo Krummrich
` (2 preceding siblings ...)
2026-05-06 22:06 ` [PATCH 3/6] rust: drm: Add RegistrationData to drm::Driver Danilo Krummrich
@ 2026-05-06 22:06 ` Danilo Krummrich
2026-05-06 22:06 ` [PATCH 5/6] rust: drm: Pass registration data to ioctl handlers Danilo Krummrich
` (2 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Danilo Krummrich @ 2026-05-06 22:06 UTC (permalink / raw)
To: aliceryhl, airlied, simona, daniel.almeida, acourbot, apopple,
ecourtney, deborah.brouwer, lyude, ojeda, boqun, gary, bjorn3_gh,
lossin, a.hindborg, tmgross
Cc: driver-core, nova-gpu, dri-devel, linux-kernel, rust-for-linux,
Danilo Krummrich
Run every ioctl handler inside a drm_dev_enter/exit critical section via
UnbindGuard. If the device has been unplugged, the ioctl returns ENODEV
without calling the handler.
A free-function wrapper is added because the macro context prevents
method resolution from inferring the driver type.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
rust/kernel/drm/device.rs | 7 +++++++
rust/kernel/drm/ioctl.rs | 13 +++++++++++--
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs
index 11edbe6f9f42..0049ea69f716 100644
--- a/rust/kernel/drm/device.rs
+++ b/rust/kernel/drm/device.rs
@@ -452,6 +452,13 @@ fn drop(&mut self) {
}
}
+/// Free-function equivalent of [`Device::unbind_guard()`] for use in macro contexts where method
+/// resolution cannot infer the driver type.
+#[doc(hidden)]
+pub fn unbind_guard<T: drm::Driver>(dev: &Device<T, Registered>) -> Option<UnbindGuard<'_, T>> {
+ dev.unbind_guard()
+}
+
impl<T: drm::Driver, C: DeviceContext> Deref for Device<T, C> {
type Target = T::Data;
diff --git a/rust/kernel/drm/ioctl.rs b/rust/kernel/drm/ioctl.rs
index cf328101dde4..aa72b44f645d 100644
--- a/rust/kernel/drm/ioctl.rs
+++ b/rust/kernel/drm/ioctl.rs
@@ -87,7 +87,10 @@ pub mod internal {
/// file: &kernel::drm::File<Self::File>,
/// ) -> Result<u32>
/// ```
-/// where `Self` is the drm::drv::Driver implementation these ioctls are being declared within.
+/// where `Self` is the `drm::Driver` implementation these ioctls are being declared within.
+///
+/// The ioctl runs inside a `drm_dev_enter/exit` critical section. If the device has been
+/// unplugged, the ioctl returns `ENODEV` without calling the handler.
///
/// # Examples
///
@@ -134,7 +137,13 @@ macro_rules! declare_drm_ioctls {
// FIXME: Currently there is nothing enforcing that the types of the
// dev/file match the current driver these ioctls are being declared
// for, and it's not clear how to enforce this within the type system.
- let dev = $crate::drm::device::Device::from_raw(raw_dev);
+ let dev = unsafe {
+ $crate::drm::device::Device::from_raw(raw_dev)
+ };
+ let _guard = match $crate::drm::device::unbind_guard(dev) {
+ Some(g) => g,
+ None => return $crate::error::code::ENODEV.to_errno(),
+ };
// SAFETY: The ioctl argument has size `_IOC_SIZE(cmd)`, which we
// asserted above matches the size of this type, and all bit patterns of
// UAPI structs must be valid.
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 5/6] rust: drm: Pass registration data to ioctl handlers
2026-05-06 22:05 [PATCH 0/6] rust: drm: Higher-Ranked Lifetime private data Danilo Krummrich
` (3 preceding siblings ...)
2026-05-06 22:06 ` [PATCH 4/6] rust: drm: Wrap ioctl dispatch in UnbindGuard Danilo Krummrich
@ 2026-05-06 22:06 ` Danilo Krummrich
2026-05-06 22:06 ` [PATCH 6/6] rust: drm: Pass bound parent device " Danilo Krummrich
2026-05-07 9:38 ` [PATCH 0/6] rust: drm: Higher-Ranked Lifetime private data Danilo Krummrich
6 siblings, 0 replies; 9+ messages in thread
From: Danilo Krummrich @ 2026-05-06 22:06 UTC (permalink / raw)
To: aliceryhl, airlied, simona, daniel.almeida, acourbot, apopple,
ecourtney, deborah.brouwer, lyude, ojeda, boqun, gary, bjorn3_gh,
lossin, a.hindborg, tmgross
Cc: driver-core, nova-gpu, dri-devel, linux-kernel, rust-for-linux,
Danilo Krummrich
Pass &<Self::RegistrationData as ForLt>::Of<'_> after the device
argument to ioctl handlers. The lifetime is shortened from 'static via
ForLt::cast_ref; the reference is valid for the duration of the
drm_dev_enter/exit critical section held by UnbindGuard.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
drivers/gpu/drm/nova/file.rs | 3 +++
drivers/gpu/drm/tyr/file.rs | 1 +
rust/kernel/drm/ioctl.rs | 5 +++--
3 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/nova/file.rs b/drivers/gpu/drm/nova/file.rs
index a3b7bd36792c..4c9fa409a8be 100644
--- a/drivers/gpu/drm/nova/file.rs
+++ b/drivers/gpu/drm/nova/file.rs
@@ -24,6 +24,7 @@ impl File {
/// IOCTL: get_param: Query GPU / driver metadata.
pub(crate) fn get_param(
dev: &NovaDevice,
+ _reg_data: &(),
getparam: &mut uapi::drm_nova_getparam,
_file: &drm::File<File>,
) -> Result<u32> {
@@ -44,6 +45,7 @@ pub(crate) fn get_param(
/// IOCTL: gem_create: Create a new DRM GEM object.
pub(crate) fn gem_create(
dev: &NovaDevice,
+ _reg_data: &(),
req: &mut uapi::drm_nova_gem_create,
file: &drm::File<File>,
) -> Result<u32> {
@@ -57,6 +59,7 @@ pub(crate) fn gem_create(
/// IOCTL: gem_info: Query GEM metadata.
pub(crate) fn gem_info(
_dev: &NovaDevice,
+ _reg_data: &(),
req: &mut uapi::drm_nova_gem_info,
file: &drm::File<File>,
) -> Result<u32> {
diff --git a/drivers/gpu/drm/tyr/file.rs b/drivers/gpu/drm/tyr/file.rs
index 31411da203c5..6262114c6a8d 100644
--- a/drivers/gpu/drm/tyr/file.rs
+++ b/drivers/gpu/drm/tyr/file.rs
@@ -29,6 +29,7 @@ fn open(_dev: &drm::Device<Self::Driver>) -> Result<Pin<KBox<Self>>> {
impl TyrDrmFileData {
pub(crate) fn dev_query(
ddev: &TyrDrmDevice,
+ _reg_data: &(),
devquery: &mut uapi::drm_panthor_dev_query,
_file: &TyrDrmFile,
) -> Result<u32> {
diff --git a/rust/kernel/drm/ioctl.rs b/rust/kernel/drm/ioctl.rs
index aa72b44f645d..dd177bc399b2 100644
--- a/rust/kernel/drm/ioctl.rs
+++ b/rust/kernel/drm/ioctl.rs
@@ -83,6 +83,7 @@ pub mod internal {
///
/// ```ignore
/// fn foo(device: &kernel::drm::Device<Self>,
+/// reg_data: &<Self::RegistrationData as kernel::types::ForLt>::Of<'_>,
/// data: &mut uapi::argument_type,
/// file: &kernel::drm::File<Self::File>,
/// ) -> Result<u32>
@@ -140,7 +141,7 @@ macro_rules! declare_drm_ioctls {
let dev = unsafe {
$crate::drm::device::Device::from_raw(raw_dev)
};
- let _guard = match $crate::drm::device::unbind_guard(dev) {
+ let guard = match $crate::drm::device::unbind_guard(dev) {
Some(g) => g,
None => return $crate::error::code::ENODEV.to_errno(),
};
@@ -156,7 +157,7 @@ macro_rules! declare_drm_ioctls {
// SAFETY: This is just the DRM file structure
let file = unsafe { $crate::drm::File::from_raw(raw_file) };
- match $func(dev, data, file) {
+ match $func(dev, guard.registration_data(), data, file) {
Err(e) => e.to_errno(),
Ok(i) => i.try_into()
.unwrap_or($crate::error::code::ERANGE.to_errno()),
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 6/6] rust: drm: Pass bound parent device to ioctl handlers
2026-05-06 22:05 [PATCH 0/6] rust: drm: Higher-Ranked Lifetime private data Danilo Krummrich
` (4 preceding siblings ...)
2026-05-06 22:06 ` [PATCH 5/6] rust: drm: Pass registration data to ioctl handlers Danilo Krummrich
@ 2026-05-06 22:06 ` Danilo Krummrich
2026-05-07 9:38 ` [PATCH 0/6] rust: drm: Higher-Ranked Lifetime private data Danilo Krummrich
6 siblings, 0 replies; 9+ messages in thread
From: Danilo Krummrich @ 2026-05-06 22:06 UTC (permalink / raw)
To: aliceryhl, airlied, simona, daniel.almeida, acourbot, apopple,
ecourtney, deborah.brouwer, lyude, ojeda, boqun, gary, bjorn3_gh,
lossin, a.hindborg, tmgross
Cc: driver-core, nova-gpu, dri-devel, linux-kernel, rust-for-linux,
Danilo Krummrich
Pass &Self::ParentDevice<Bound> as the second argument to ioctl
handlers, obtained from the UnbindGuard via Deref. This gives ioctl
handlers direct access to the bound parent bus device.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
drivers/gpu/drm/nova/file.rs | 5 +++++
drivers/gpu/drm/tyr/file.rs | 3 +++
rust/kernel/drm/ioctl.rs | 3 ++-
3 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/nova/file.rs b/drivers/gpu/drm/nova/file.rs
index 4c9fa409a8be..df9760947d58 100644
--- a/drivers/gpu/drm/nova/file.rs
+++ b/drivers/gpu/drm/nova/file.rs
@@ -4,6 +4,8 @@
use crate::gem::NovaObject;
use kernel::{
alloc::flags::*,
+ auxiliary,
+ device::Bound,
drm::{self, gem::BaseObject},
pci,
prelude::*,
@@ -24,6 +26,7 @@ impl File {
/// IOCTL: get_param: Query GPU / driver metadata.
pub(crate) fn get_param(
dev: &NovaDevice,
+ _adev: &auxiliary::Device<Bound>,
_reg_data: &(),
getparam: &mut uapi::drm_nova_getparam,
_file: &drm::File<File>,
@@ -45,6 +48,7 @@ pub(crate) fn get_param(
/// IOCTL: gem_create: Create a new DRM GEM object.
pub(crate) fn gem_create(
dev: &NovaDevice,
+ _adev: &auxiliary::Device<Bound>,
_reg_data: &(),
req: &mut uapi::drm_nova_gem_create,
file: &drm::File<File>,
@@ -59,6 +63,7 @@ pub(crate) fn gem_create(
/// IOCTL: gem_info: Query GEM metadata.
pub(crate) fn gem_info(
_dev: &NovaDevice,
+ _adev: &auxiliary::Device<Bound>,
_reg_data: &(),
req: &mut uapi::drm_nova_gem_info,
file: &drm::File<File>,
diff --git a/drivers/gpu/drm/tyr/file.rs b/drivers/gpu/drm/tyr/file.rs
index 6262114c6a8d..9f53da7633ab 100644
--- a/drivers/gpu/drm/tyr/file.rs
+++ b/drivers/gpu/drm/tyr/file.rs
@@ -1,7 +1,9 @@
// SPDX-License-Identifier: GPL-2.0 or MIT
use kernel::{
+ device,
drm,
+ platform,
prelude::*,
uaccess::UserSlice,
uapi, //
@@ -29,6 +31,7 @@ fn open(_dev: &drm::Device<Self::Driver>) -> Result<Pin<KBox<Self>>> {
impl TyrDrmFileData {
pub(crate) fn dev_query(
ddev: &TyrDrmDevice,
+ _pdev: &platform::Device<device::Bound>,
_reg_data: &(),
devquery: &mut uapi::drm_panthor_dev_query,
_file: &TyrDrmFile,
diff --git a/rust/kernel/drm/ioctl.rs b/rust/kernel/drm/ioctl.rs
index dd177bc399b2..181918303f2f 100644
--- a/rust/kernel/drm/ioctl.rs
+++ b/rust/kernel/drm/ioctl.rs
@@ -83,6 +83,7 @@ pub mod internal {
///
/// ```ignore
/// fn foo(device: &kernel::drm::Device<Self>,
+/// parent: &Self::ParentDevice<kernel::device::Bound>,
/// reg_data: &<Self::RegistrationData as kernel::types::ForLt>::Of<'_>,
/// data: &mut uapi::argument_type,
/// file: &kernel::drm::File<Self::File>,
@@ -157,7 +158,7 @@ macro_rules! declare_drm_ioctls {
// SAFETY: This is just the DRM file structure
let file = unsafe { $crate::drm::File::from_raw(raw_file) };
- match $func(dev, guard.registration_data(), data, file) {
+ match $func(dev, &*guard, guard.registration_data(), data, file) {
Err(e) => e.to_errno(),
Ok(i) => i.try_into()
.unwrap_or($crate::error::code::ERANGE.to_errno()),
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 0/6] rust: drm: Higher-Ranked Lifetime private data
2026-05-06 22:05 [PATCH 0/6] rust: drm: Higher-Ranked Lifetime private data Danilo Krummrich
` (5 preceding siblings ...)
2026-05-06 22:06 ` [PATCH 6/6] rust: drm: Pass bound parent device " Danilo Krummrich
@ 2026-05-07 9:38 ` Danilo Krummrich
6 siblings, 0 replies; 9+ messages in thread
From: Danilo Krummrich @ 2026-05-07 9:38 UTC (permalink / raw)
To: deborah.brouwer
Cc: aliceryhl, airlied, simona, daniel.almeida, acourbot, apopple,
ecourtney, lyude, ojeda, boqun, gary, bjorn3_gh, lossin,
a.hindborg, tmgross, driver-core, nova-gpu, dri-devel,
linux-kernel, rust-for-linux
On Thu May 7, 2026 at 12:05 AM CEST, Danilo Krummrich wrote:
> Danilo Krummrich (6):
> rust: drm: Add Driver::ParentDevice associated type
> rust: drm: Add UnbindGuard for drm_dev_enter/exit critical sections
> rust: drm: Add RegistrationData to drm::Driver
> rust: drm: Wrap ioctl dispatch in UnbindGuard
> rust: drm: Pass registration data to ioctl handlers
> rust: drm: Pass bound parent device to ioctl handlers
Deborah, following up on your question in the other thread, this is roughly how
you'd use this in Tyr.
diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
index 7ac3707823b6..447e53c0eecf 100644
--- a/drivers/gpu/drm/tyr/driver.rs
+++ b/drivers/gpu/drm/tyr/driver.rs
@@ -37,13 +37,17 @@
regs, //
};
-pub(crate) type IoMem = kernel::io::Mmio<SZ_2M>;
+pub(crate) type IoMem<'bound> = kernel::io::mem::IoMem<'bound, SZ_2M>;
pub(crate) struct TyrDrmDriver;
/// Convenience type alias for the DRM device type for this driver.
pub(crate) type TyrDrmDevice<Ctx = drm::Registered> = drm::Device<TyrDrmDriver, Ctx>;
+pub(crate) struct RegData<'bound> {
+ pub(crate) iomem: IoMem<'bound>,
+}
+
#[pin_data(PinnedDrop)]
pub(crate) struct TyrPlatformDriverData {
_device: ARef<TyrDrmDevice>,
@@ -65,7 +69,7 @@ pub(crate) struct TyrDrmDeviceData {
pub(crate) gpu_info: GpuInfo,
}
-fn issue_soft_reset(dev: &Device<Bound>, iomem: &IoMem) -> Result {
+fn issue_soft_reset(dev: &Device<Bound>, iomem: &IoMem<'_>) -> Result {
regs::GPU_CMD.write(iomem, regs::GPU_CMD_SOFT_RESET);
poll::read_poll_timeout(
@@ -133,8 +137,10 @@ fn probe(
gpu_info,
});
+ let reg_data = RegData { iomem };
+
let tdev = drm::UnregisteredDevice::<TyrDrmDriver>::new(pdev, data)?;
- let tdev = drm::driver::Registration::new_foreign_owned(tdev, pdev.as_ref(), (), 0)?;
+ let tdev = drm::driver::Registration::new_foreign_owned(tdev, pdev.as_ref(), reg_data, 0)?;
let driver = TyrPlatformDriverData {
_device: tdev.into(),
@@ -176,7 +182,7 @@ fn drop(self: Pin<&mut Self>) {
#[vtable]
impl drm::Driver for TyrDrmDriver {
type Data = TyrDrmDeviceData;
- type RegistrationData = ForLt!(());
+ type RegistrationData = ForLt!(for<'a> RegData<'a>);
type File = TyrDrmFileData;
type Object<R: drm::DeviceContext> = drm::gem::Object<TyrObject, R>;
type ParentDevice<Ctx: DeviceContext> = platform::Device<Ctx>;
diff --git a/drivers/gpu/drm/tyr/file.rs b/drivers/gpu/drm/tyr/file.rs
index 9f53da7633ab..30efdf924cc2 100644
--- a/drivers/gpu/drm/tyr/file.rs
+++ b/drivers/gpu/drm/tyr/file.rs
@@ -10,6 +10,7 @@
};
use crate::driver::{
+ RegData,
TyrDrmDevice,
TyrDrmDriver, //
};
@@ -32,10 +33,12 @@ impl TyrDrmFileData {
pub(crate) fn dev_query(
ddev: &TyrDrmDevice,
_pdev: &platform::Device<device::Bound>,
- _reg_data: &(),
+ reg_data: &RegData<'_>,
devquery: &mut uapi::drm_panthor_dev_query,
_file: &TyrDrmFile,
) -> Result<u32> {
+ let _iomem = reg_data.iomem;
+
if devquery.pointer == 0 {
match devquery.type_ {
uapi::drm_panthor_dev_query_type_DRM_PANTHOR_DEV_QUERY_GPU_INFO => {
diff --git a/drivers/gpu/drm/tyr/gpu.rs b/drivers/gpu/drm/tyr/gpu.rs
index bb0473c85bf7..f169fb1ccc03 100644
--- a/drivers/gpu/drm/tyr/gpu.rs
+++ b/drivers/gpu/drm/tyr/gpu.rs
@@ -34,7 +34,7 @@
pub(crate) struct GpuInfo(pub(crate) uapi::drm_panthor_gpu_info);
impl GpuInfo {
- pub(crate) fn new(iomem: &IoMem) -> Self {
+ pub(crate) fn new(iomem: &IoMem<'_>) -> Self {
let gpu_id = regs::GPU_ID.read(iomem);
let csf_id = regs::GPU_CSF_ID.read(iomem);
let gpu_rev = regs::GPU_REVID.read(iomem);
@@ -206,7 +206,7 @@ fn from(value: u32) -> Self {
}
/// Powers on the l2 block.
-pub(crate) fn l2_power_on(dev: &Device<Bound>, iomem: &IoMem) -> Result {
+pub(crate) fn l2_power_on(dev: &Device<Bound>, iomem: &IoMem<'_>) -> Result {
regs::L2_PWRON_LO.write(iomem, 1);
poll::read_poll_timeout(
diff --git a/drivers/gpu/drm/tyr/regs.rs b/drivers/gpu/drm/tyr/regs.rs
index 0881b3812afd..2b0da6019512 100644
--- a/drivers/gpu/drm/tyr/regs.rs
+++ b/drivers/gpu/drm/tyr/regs.rs
@@ -20,12 +20,12 @@
impl<const OFFSET: usize> Register<OFFSET> {
#[inline]
- pub(crate) fn read(&self, iomem: &IoMem) -> u32 {
+ pub(crate) fn read(&self, iomem: &IoMem<'_>) -> u32 {
iomem.read32(OFFSET)
}
#[inline]
- pub(crate) fn write(&self, iomem: &IoMem, value: u32) {
+ pub(crate) fn write(&self, iomem: &IoMem<'_>, value: u32) {
iomem.write32(value, OFFSET);
}
}
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 1/6] rust: drm: Add Driver::ParentDevice associated type
2026-05-06 22:05 ` [PATCH 1/6] rust: drm: Add Driver::ParentDevice associated type Danilo Krummrich
@ 2026-05-08 21:49 ` lyude
0 siblings, 0 replies; 9+ messages in thread
From: lyude @ 2026-05-08 21:49 UTC (permalink / raw)
To: Danilo Krummrich, aliceryhl, airlied, simona, daniel.almeida,
acourbot, apopple, ecourtney, deborah.brouwer, ojeda, boqun, gary,
bjorn3_gh, lossin, a.hindborg, tmgross
Cc: driver-core, nova-gpu, dri-devel, linux-kernel, rust-for-linux
Reviewed-by: Lyude Paul <lyude@redhat.com>
On Thu, 2026-05-07 at 00:05 +0200, Danilo Krummrich wrote:
> Add a ParentDevice associated type to the Driver trait, allowing each
> DRM driver to declare its parent bus device type (e.g.
> auxiliary::Device, platform::Device).
>
> Change UnregisteredDevice::new() to take &T::ParentDevice<Bound>,
> ensuring at the type level that the DRM device's parent matches the
> declared bus device type.
>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> ---
> drivers/gpu/drm/nova/driver.rs | 8 ++++++--
> drivers/gpu/drm/tyr/driver.rs | 6 ++++--
> rust/kernel/drm/device.rs | 7 +++++--
> rust/kernel/drm/driver.rs | 3 +++
> 4 files changed, 18 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/gpu/drm/nova/driver.rs
> b/drivers/gpu/drm/nova/driver.rs
> index 9eef28b506bb..9d4100f01ea7 100644
> --- a/drivers/gpu/drm/nova/driver.rs
> +++ b/drivers/gpu/drm/nova/driver.rs
> @@ -2,7 +2,10 @@
>
> use kernel::{
> auxiliary,
> - device::Core,
> + device::{
> + Core,
> + DeviceContext, //
> + },
> drm::{
> self,
> gem,
> @@ -59,7 +62,7 @@ fn probe(
> ) -> impl PinInit<Self, Error> + 'bound {
> let data = try_pin_init!(NovaData { adev: adev.into() });
>
> - let drm =
> drm::UnregisteredDevice::<Self>::new(adev.as_ref(), data)?;
> + let drm = drm::UnregisteredDevice::<Self>::new(adev, data)?;
> let drm = drm::Registration::new_foreign_owned(drm,
> adev.as_ref(), 0)?;
>
> Ok(Self { drm: drm.into() })
> @@ -71,6 +74,7 @@ impl drm::Driver for NovaDriver {
> type Data = NovaData;
> type File = File;
> type Object<Ctx: drm::DeviceContext> = gem::Object<NovaObject,
> Ctx>;
> + type ParentDevice<Ctx: DeviceContext> = auxiliary::Device<Ctx>;
>
> const INFO: drm::DriverInfo = INFO;
>
> diff --git a/drivers/gpu/drm/tyr/driver.rs
> b/drivers/gpu/drm/tyr/driver.rs
> index 2743178af325..747745d23f31 100644
> --- a/drivers/gpu/drm/tyr/driver.rs
> +++ b/drivers/gpu/drm/tyr/driver.rs
> @@ -8,7 +8,8 @@
> device::{
> Bound,
> Core,
> - Device, //
> + Device,
> + DeviceContext, //
> },
> drm,
> drm::ioctl,
> @@ -131,7 +132,7 @@ fn probe(
> gpu_info,
> });
>
> - let tdev =
> drm::UnregisteredDevice::<TyrDrmDriver>::new(pdev.as_ref(), data)?;
> + let tdev =
> drm::UnregisteredDevice::<TyrDrmDriver>::new(pdev, data)?;
> let tdev =
> drm::driver::Registration::new_foreign_owned(tdev, pdev.as_ref(),
> 0)?;
>
> let driver = TyrPlatformDriverData {
> @@ -176,6 +177,7 @@ impl drm::Driver for TyrDrmDriver {
> type Data = TyrDrmDeviceData;
> type File = TyrDrmFileData;
> type Object<R: drm::DeviceContext> = drm::gem::Object<TyrObject,
> R>;
> + type ParentDevice<Ctx: DeviceContext> = platform::Device<Ctx>;
>
> const INFO: drm::DriverInfo = INFO;
>
> diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs
> index d91f19dcc375..492c2f2c7ca4 100644
> --- a/rust/kernel/drm/device.rs
> +++ b/rust/kernel/drm/device.rs
> @@ -197,7 +197,10 @@ impl<T: drm::Driver> UnregisteredDevice<T> {
> /// Create a new `UnregisteredDevice` for a `drm::Driver`.
> ///
> /// This can be used to create a
> [`Registration`](kernel::drm::Registration).
> - pub fn new(dev: &device::Device, data: impl PinInit<T::Data,
> Error>) -> Result<Self> {
> + pub fn new(
> + dev: &T::ParentDevice<device::Bound>,
> + data: impl PinInit<T::Data, Error>,
> + ) -> Result<Self> {
> // `__drm_dev_alloc` uses `kmalloc()` to allocate memory,
> hence ensure a `kmalloc()`
> // compatible `Layout`.
> let layout = Kmalloc::aligned_layout(Layout::new::<Device<T,
> Uninit>>());
> @@ -207,7 +210,7 @@ pub fn new(dev: &device::Device, data: impl
> PinInit<T::Data, Error>) -> Result<S
> // - `dev` is valid by its type invarants,
> let raw_drm: *mut Device<T, Uninit> = unsafe {
> bindings::__drm_dev_alloc(
> - dev.as_raw(),
> + dev.as_ref().as_raw(),
> &Self::VTABLE,
> layout.size(),
> mem::offset_of!(Device<T, Uninit>, dev),
> diff --git a/rust/kernel/drm/driver.rs b/rust/kernel/drm/driver.rs
> index 294e17af86a3..9d06f8c5b2da 100644
> --- a/rust/kernel/drm/driver.rs
> +++ b/rust/kernel/drm/driver.rs
> @@ -114,6 +114,9 @@ pub trait Driver {
> /// The type used to represent a DRM File (client)
> type File: drm::file::DriverFile;
>
> + /// The bus device type of the parent device that the DRM device
> is associated with.
> + type ParentDevice<Ctx: device::DeviceContext>:
> device::AsBusDevice<Ctx>;
> +
> /// Driver metadata
> const INFO: DriverInfo;
>
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-05-08 21:49 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-06 22:05 [PATCH 0/6] rust: drm: Higher-Ranked Lifetime private data Danilo Krummrich
2026-05-06 22:05 ` [PATCH 1/6] rust: drm: Add Driver::ParentDevice associated type Danilo Krummrich
2026-05-08 21:49 ` lyude
2026-05-06 22:06 ` [PATCH 2/6] rust: drm: Add UnbindGuard for drm_dev_enter/exit critical sections Danilo Krummrich
2026-05-06 22:06 ` [PATCH 3/6] rust: drm: Add RegistrationData to drm::Driver Danilo Krummrich
2026-05-06 22:06 ` [PATCH 4/6] rust: drm: Wrap ioctl dispatch in UnbindGuard Danilo Krummrich
2026-05-06 22:06 ` [PATCH 5/6] rust: drm: Pass registration data to ioctl handlers Danilo Krummrich
2026-05-06 22:06 ` [PATCH 6/6] rust: drm: Pass bound parent device " Danilo Krummrich
2026-05-07 9:38 ` [PATCH 0/6] rust: drm: Higher-Ranked Lifetime private data Danilo Krummrich
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox