* [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* 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
* [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