Rust for Linux List
 help / color / mirror / Atom feed
From: Mike Lothian <mike@fireburn.co.uk>
To: rust-for-linux@vger.kernel.org
Cc: dri-devel@lists.freedesktop.org,
	"David Airlie" <airlied@gmail.com>,
	"Simona Vetter" <simona@ffwll.ch>,
	"Danilo Krummrich" <dakr@kernel.org>,
	"Lyude Paul" <lyude@redhat.com>,
	"Miguel Ojeda" <ojeda@kernel.org>,
	"Boqun Feng" <boqun@kernel.org>, "Gary Guo" <gary@garyguo.net>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Benno Lossin" <lossin@kernel.org>,
	"Andreas Hindborg" <a.hindborg@kernel.org>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Trevor Gross" <tmgross@umich.edu>,
	linux-kernel@vger.kernel.org,
	"Mike Lothian" <mike@fireburn.co.uk>
Subject: [RFC PATCH v2 04/18] rust: drm: kms: build the kernel crate clean under -Znext-solver
Date: Fri,  3 Jul 2026 04:00:51 +0100	[thread overview]
Message-ID: <20260703030123.2814-5-mike@fireburn.co.uk> (raw)
In-Reply-To: <20260703030123.2814-1-mike@fireburn.co.uk>

The coinductive cycle from the previous commit isn't a bug in this
port -- it's inherent to the mutual type Driver / type State / type
Crtc references in the mode-object traits, and the current trait
solver can't evaluate a coinductive obligation without unbounded
memory, regardless of where the bounds are placed. Disabling the
unused from_opaque-on-state impls doesn't help either: their errors
were masking the same explosion one level down.

The next-generation trait solver (-Znext-solver) does handle it. Scope
it to the kernel crate only in rust/Makefile rather than globally, so
core/alloc/etc. stay on the old solver -- core.o ICEs under
-Znext-solver on this toolchain, and there's no reason to pay that
cost crate-wide when only kernel/ needs the new solver's coinductive
support.

rust/kernel.o now builds with 0 errors, safe KMS layer included. Fixes
needed to get there once the solver could actually evaluate the web:
restore the pinned associated-type bounds (no back-edge cuts needed
under the new solver); add Device::event_lock(), ModeConfigGuard::new();
import AlwaysRefCounted/SpinLockIrq; Driver*::new() takes
&Device<.., Uninit> since objects are created during probe; base drift
in drm_crtc_helper_funcs (drop mode_set_base_atomic, add
handle_vblank_timeout); device.rs T::Object::<Uninit>::ALLOC_OPS and a
probe_kms Option rewrite; driver.rs captures preferred_fourcc and uses
the registered device after mem::forget(drm); unused imports dropped;
allow(dead_code) on the not-yet-used ModeObjectVtable.

Signed-off-by: Mike Lothian <mike@fireburn.co.uk>
Assisted-by: Claude:claude-sonnet-5 [Claude-Code]
---
 rust/Makefile                    |  6 ++--
 rust/kernel/drm/device.rs        | 12 ++++----
 rust/kernel/drm/driver.rs        |  8 ++---
 rust/kernel/drm/kms.rs           | 51 +++++++++++++++++++++++---------
 rust/kernel/drm/kms/connector.rs | 31 ++++++-------------
 rust/kernel/drm/kms/crtc.rs      | 35 ++++++++--------------
 rust/kernel/drm/kms/encoder.rs   |  4 +--
 rust/kernel/drm/kms/modes.rs     |  5 ++++
 rust/kernel/drm/kms/plane.rs     | 31 ++++++-------------
 rust/kernel/drm/kms/vblank.rs    |  7 ++---
 10 files changed, 91 insertions(+), 99 deletions(-)

diff --git a/rust/Makefile b/rust/Makefile
index a870d1616c71..9aa985e21905 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -270,7 +270,7 @@ rustdoc-kernel: private is-kernel-object := y
 rustdoc-kernel: private rustc_target_flags = --extern ffi --extern pin_init \
     --extern build_error --extern macros \
     --extern bindings --extern uapi \
-    --extern zerocopy --extern zerocopy_derive
+    --extern zerocopy --extern zerocopy_derive -Znext-solver
 rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-ffi rustdoc-macros \
     rustdoc-pin_init rustdoc-compiler_builtins $(obj)/$(libmacros_name) \
     $(obj)/bindings.o FORCE
@@ -342,7 +342,7 @@ rusttestlib-pin_init: $(src)/pin-init/src/lib.rs rusttestlib-macros \
 rusttestlib-kernel: private rustc_target_flags = --extern ffi \
     --extern build_error --extern macros --extern pin_init \
     --extern bindings --extern uapi \
-    --extern zerocopy --extern zerocopy_derive
+    --extern zerocopy --extern zerocopy_derive -Znext-solver
 rusttestlib-kernel: $(src)/kernel/lib.rs rusttestlib-bindings rusttestlib-uapi \
     rusttestlib-build_error rusttestlib-pin_init $(obj)/$(libmacros_name) \
     $(obj)/bindings.o rusttestlib-zerocopy rusttestlib-zerocopy_derive FORCE
@@ -764,7 +764,7 @@ $(obj)/uapi.o: $(src)/uapi/lib.rs \
 
 $(obj)/kernel.o: private rustc_target_flags = --extern ffi --extern pin_init \
     --extern build_error --extern macros --extern bindings --extern uapi \
-    --extern zerocopy --extern zerocopy_derive
+    --extern zerocopy --extern zerocopy_derive -Znext-solver
 $(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/build_error.o $(obj)/pin_init.o \
     $(obj)/$(libmacros_name) $(obj)/bindings.o $(obj)/uapi.o \
     $(obj)/zerocopy.o $(obj)/$(libzerocopy_derive_name) FORCE
diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs
index 9641102bd87f..5b84ce18fb29 100644
--- a/rust/kernel/drm/device.rs
+++ b/rust/kernel/drm/device.rs
@@ -229,7 +229,7 @@ const fn compute_features() -> u32 {
         dumb_map_offset: T::Object::<Uninit>::ALLOC_OPS.dumb_map_offset,
 
         show_fdinfo: None,
-        fbdev_probe: T::Object::ALLOC_OPS.fbdev_probe,
+        fbdev_probe: T::Object::<Uninit>::ALLOC_OPS.fbdev_probe,
 
         major: T::INFO.major,
         minor: T::INFO.minor,
@@ -306,15 +306,17 @@ pub fn new(
         // won't be called during its lifetime and that the device is unregistered.
         let drm_dev = unsafe { ARef::from_raw(raw_drm) };
 
-        let mode_config_info = drm::Device::<T>::has_kms().then(|| {
+        let mode_config_info = if drm::Device::<T>::has_kms() {
             // SAFETY: This is the only place that we call probe_kms
-            unsafe { T::Kms::probe_kms(&drm_dev)? }
-        });
+            Some(unsafe { T::Kms::probe_kms(&drm_dev)? })
+        } else {
+            None
+        };
 
         Ok(Self {
             // SAFETY: We just completed all of the initialization steps for this device.
             dev: unsafe { mem::transmute(drm_dev) },
-            preferred_fourcc: mode_config_info.preferred_fourcc,
+            preferred_fourcc: mode_config_info.and_then(|i| i.preferred_fourcc),
             _p: NotThreadSafe,
         })
     }
diff --git a/rust/kernel/drm/driver.rs b/rust/kernel/drm/driver.rs
index c7716afabcb0..b7e80df6289e 100644
--- a/rust/kernel/drm/driver.rs
+++ b/rust/kernel/drm/driver.rs
@@ -10,7 +10,6 @@
     devres,
     drm::{
         self,
-        kms::private::KmsImpl as KmsImplPrivate,
     },
     error::to_result,
     prelude::*,
@@ -214,6 +213,7 @@ fn new<'bound, E>(
             return Err(e);
         }
 
+        let preferred_fourcc = drm.preferred_fourcc;
         // SAFETY: We just called `drm_dev_register` above
         let new = NonNull::from(unsafe { drm.assume_ctx() });
 
@@ -226,12 +226,12 @@ fn new<'bound, E>(
 
         #[cfg(CONFIG_DRM_CLIENT = "y")]
         if drm::Device::<T>::has_kms() {
-            if let Some(fourcc) = drm.preferred_fourcc {
+            if let Some(fourcc) = preferred_fourcc {
                 // SAFETY: We just registered `drm` above, fulfilling the C API requirements
-                unsafe { bindings::drm_client_setup_with_fourcc(drm.as_raw(), fourcc) }
+                unsafe { bindings::drm_client_setup_with_fourcc(new.as_raw(), fourcc) }
             } else {
                 // SAFETY: We just registered `drm` above, fulfilling the C API requirements
-                unsafe { bindings::drm_client_setup(drm.as_raw(), ptr::null()) }
+                unsafe { bindings::drm_client_setup(new.as_raw(), ptr::null()) }
             }
         }
 
diff --git a/rust/kernel/drm/kms.rs b/rust/kernel/drm/kms.rs
index d07389fd510c..7c7e1d59c892 100644
--- a/rust/kernel/drm/kms.rs
+++ b/rust/kernel/drm/kms.rs
@@ -12,7 +12,7 @@
     },
     error::to_result,
     prelude::*,
-    sync::{aref::ARef, Mutex, MutexGuard},
+    sync::{aref::{ARef, AlwaysRefCounted}, Mutex, MutexGuard, SpinLockIrq},
 };
 use bindings;
 use core::{
@@ -122,23 +122,25 @@ fn deref(&self) -> &Self::Target {
 /// [`PhantomData<Self>`]: PhantomData
 #[vtable]
 pub trait KmsDriver: Driver {
-    // The driver's mode-object implementations. Left *unbounded* to break a trait
-    // well-formedness cycle: the natural bound (`type Crtc: DriverCrtc<Driver = Self>`, etc.)
-    // makes every `T: KmsDriver` obligation pull in the mutually-recursive Driver* web, which
-    // the compiler cannot evaluate (it loops in obligation processing and exhausts memory). The
-    // `DriverConnector`/`DriverCrtc`/... bounds are required at the use sites as `where`-clauses
-    // instead (an assumption, not an eagerly WF-checked trait-definition obligation).
-    //
-    // TODO: unneeded once we support multiple `Driver*` implementations per driver.
-
     /// The driver's [`DriverConnector`](connector::DriverConnector) implementation.
-    type Connector;
+    ///
+    /// TODO: This will be unneeded once we support multiple `DriverConnector` implementations.
+    type Connector: connector::DriverConnector<Driver = Self>;
+
     /// The driver's [`DriverPlane`](plane::DriverPlane) implementation.
-    type Plane;
+    ///
+    /// TODO: This will be unneeded once we support multiple `DriverPlane` implementations.
+    type Plane: plane::DriverPlane<Driver = Self>;
+
     /// The driver's [`DriverCrtc`](crtc::DriverCrtc) implementation.
-    type Crtc;
+    ///
+    /// TODO: This will be unneeded once we support multiple `DriverCrtc` implementations.
+    type Crtc: crtc::DriverCrtc<Driver = Self>;
+
     /// The driver's [`DriverEncoder`](encoder::DriverEncoder) implementation.
-    type Encoder;
+    ///
+    /// TODO: This will be unneeded once we support multiple `DriverEncoder` implementations.
+    type Encoder: encoder::DriverEncoder<Driver = Self>;
 
     /// Return a [`ModeConfigInfo`] structure for this [`device::Device`].
     fn mode_config_info(dev: &Device<Self, Uninit>) -> Result<ModeConfigInfo>
@@ -372,6 +374,13 @@ pub fn num_crtcs(&self) -> u32 {
         // * num_crtc is always >= 0, so casting to u32 is fine
         unsafe { (*self.as_raw()).mode_config.num_crtc as u32 }
     }
+
+    /// Returns a reference to the `event` spinlock for this [`Device`].
+    #[inline]
+    pub(crate) fn event_lock(&self) -> &SpinLockIrq<()> {
+        // SAFETY: `event_lock` is initialized for as long as `self` is exposed to users.
+        unsafe { SpinLockIrq::from_raw(addr_of_mut!((*self.as_raw()).event_lock)) }
+    }
 }
 
 impl<T: KmsDriver> Device<T> {
@@ -512,6 +521,7 @@ unsafe fn dec_ref(obj: core::ptr::NonNull<Self>) {
 ///
 /// `ModeObjectVtable::vtable()` must always return a valid pointer to the relevant mode object's
 /// vtable.
+#[allow(dead_code)] // Scaffolding for future vtable-pointer comparison; see doc above.
 pub(crate) unsafe trait ModeObjectVtable {
     /// The type for the auto-generated vtable.
     type Vtable;
@@ -539,6 +549,19 @@ pub(crate) unsafe trait ModeObjectVtable {
 pub struct ModeConfigGuard<'a, T: KmsDriver>(MutexGuard<'a, ()>, PhantomData<T>);
 
 impl<'a, T: KmsDriver> ModeConfigGuard<'a, T> {
+    /// Construct a new [`ModeConfigGuard`].
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `drm_device.mode_config.mutex` is acquired.
+    pub(crate) unsafe fn new(drm: &'a Device<T>) -> Self {
+        // SAFETY: Our safety contract fulfills the requirements of `MutexGuard::new()`.
+        Self(
+            unsafe { MutexGuard::new(drm.mode_config_mutex(), ()) },
+            PhantomData,
+        )
+    }
+
     /// Return the [`Device`] that this [`ModeConfigGuard`] belongs to.
     pub fn drm_dev(&self) -> &'a Device<T> {
         let lock: *mut bindings::mutex = ptr::from_ref(self.0.lock_ref()).cast_mut().cast();
diff --git a/rust/kernel/drm/kms/connector.rs b/rust/kernel/drm/kms/connector.rs
index aca7be50e583..1c7c7b586340 100644
--- a/rust/kernel/drm/kms/connector.rs
+++ b/rust/kernel/drm/kms/connector.rs
@@ -10,7 +10,7 @@
 use crate::{
     alloc::KBox,
     bindings,
-    drm::{device::Device, kms::{NewKmsDevice, Probing}},
+    drm::{device::{Device, Uninit}, kms::{NewKmsDevice, Probing}},
     error::to_result,
     prelude::*,
     types::{NotThreadSafe, Opaque},
@@ -139,12 +139,12 @@ pub trait DriverConnector: Send + Sync + Sized {
     /// The [`DriverConnectorState`] implementation for this [`DriverConnector`].
     ///
     /// See [`DriverConnectorState`] for more info.
-    type State: DriverConnectorState<Connector = Self>;
+    type State: DriverConnectorState;
 
     /// The constructor for creating a [`Connector`] using this [`DriverConnector`] implementation.
     ///
     /// Drivers may use this to instantiate their [`DriverConnector`] object.
-    fn new(device: &Device<Self::Driver>, args: Self::Args) -> impl PinInit<Self, Error>;
+    fn new(device: &Device<Self::Driver, Uninit>, args: Self::Args) -> impl PinInit<Self, Error>;
 
     /// Retrieve a list of available display modes for this [`Connector`].
     fn get_modes<'a>(
@@ -700,17 +700,13 @@ pub struct ConnectorState<T: DriverConnectorState> {
 /// [`struct drm_connector`]: srctree/include/drm_connector.h
 /// [`struct drm_connector_state`]: srctree/include/drm_connector.h
 pub trait DriverConnectorState: Clone + Default + Sized {
-    /// The parent [`DriverConnector`]. Unbounded to break the trait WF cycle; the
-    /// `DriverConnector` bound is required at use sites instead.
-    type Connector;
+    /// The parent [`DriverConnector`].
+    type Connector: DriverConnector;
 }
 
 impl<T: DriverConnectorState> Sealed for ConnectorState<T> {}
 
-impl<T: DriverConnectorState> AsRawConnectorState for ConnectorState<T>
-where
-    T::Connector: DriverConnector,
-{
+impl<T: DriverConnectorState> AsRawConnectorState for ConnectorState<T> {
     type Connector = Connector<T::Connector>;
 }
 
@@ -724,10 +720,7 @@ unsafe fn as_raw_mut(&mut self) -> &mut bindings::drm_connector_state {
     }
 }
 
-impl<T: DriverConnectorState> FromRawConnectorState for ConnectorState<T>
-where
-    T::Connector: DriverConnector,
-{
+impl<T: DriverConnectorState> FromRawConnectorState for ConnectorState<T> {
     unsafe fn from_raw<'a>(ptr: *const bindings::drm_connector_state) -> &'a Self {
         // Our data layout starts with `bindings::drm_connector_state`.
         let ptr: *const Self = ptr.cast();
@@ -866,10 +859,7 @@ pub(super) fn new<D: KmsDriver>(
     }
 }
 
-impl<'a, T: DriverConnectorState> Deref for ConnectorStateMutator<'a, ConnectorState<T>>
-where
-    T::Connector: DriverConnector,
-{
+impl<'a, T: DriverConnectorState> Deref for ConnectorStateMutator<'a, ConnectorState<T>> {
     type Target = T;
 
     fn deref(&self) -> &Self::Target {
@@ -877,10 +867,7 @@ fn deref(&self) -> &Self::Target {
     }
 }
 
-impl<'a, T: DriverConnectorState> DerefMut for ConnectorStateMutator<'a, ConnectorState<T>>
-where
-    T::Connector: DriverConnector,
-{
+impl<'a, T: DriverConnectorState> DerefMut for ConnectorStateMutator<'a, ConnectorState<T>> {
     fn deref_mut(&mut self) -> &mut Self::Target {
         &mut self.state.inner
     }
diff --git a/rust/kernel/drm/kms/crtc.rs b/rust/kernel/drm/kms/crtc.rs
index 4c6cb6bbdcb8..9b43501bfb58 100644
--- a/rust/kernel/drm/kms/crtc.rs
+++ b/rust/kernel/drm/kms/crtc.rs
@@ -11,7 +11,7 @@
 use crate::{
     alloc::KBox,
     bindings,
-    drm::device::Device,
+    drm::device::{Device, Uninit},
     error::{from_result, to_result},
     prelude::*,
     types::{NotThreadSafe, Opaque},
@@ -107,8 +107,8 @@ pub trait DriverCrtc: Send + Sync + Sized {
             },
             mode_set_nofb: None,
             mode_set_base: None,
-            mode_set_base_atomic: None,
             get_scanout_position: None,
+            handle_vblank_timeout: None,
         },
     };
 
@@ -124,7 +124,7 @@ pub trait DriverCrtc: Send + Sync + Sized {
     /// The [`DriverCrtcState`] implementation for this [`DriverCrtc`].
     ///
     /// See [`DriverCrtcState`] for more info.
-    type State: DriverCrtcState<Crtc = Self>;
+    type State: DriverCrtcState;
 
     /// The driver's optional hardware vblank implementation
     ///
@@ -135,7 +135,7 @@ pub trait DriverCrtc: Send + Sync + Sized {
     /// The constructor for creating a [`Crtc`] using this [`DriverCrtc`] implementation.
     ///
     /// Drivers may use this to instantiate their [`DriverCrtc`] object.
-    fn new(device: &Device<Self::Driver>, args: &Self::Args) -> impl PinInit<Self, Error>;
+    fn new(device: &Device<Self::Driver, Uninit>, args: &Self::Args) -> impl PinInit<Self, Error>;
 
     /// The optional [`drm_crtc_helper_funcs.atomic_check`] hook for this crtc.
     ///
@@ -561,9 +561,10 @@ impl<T: DriverCrtcState> Sealed for CrtcState<T> {}
 /// [`struct drm_crtc`]: srctree/include/drm_crtc.h
 /// [`struct drm_crtc_state`]: srctree/include/drm_crtc.h
 pub trait DriverCrtcState: Clone + Default + Unpin {
-    /// The parent CRTC driver for this CRTC state. Unbounded to break the trait WF cycle;
-    /// the `DriverCrtc` bound is required at use sites instead.
-    type Crtc;
+    /// The parent CRTC driver for this CRTC state
+    type Crtc: DriverCrtc<State = Self>
+    where
+        Self: Sized;
 }
 
 /// The main interface for a [`struct drm_crtc_state`].
@@ -701,17 +702,11 @@ fn as_raw(&self) -> *mut bindings::drm_crtc_state {
     }
 }
 
-impl<T: DriverCrtcState> AsRawCrtcState for CrtcState<T>
-where
-    T::Crtc: DriverCrtc,
-{
+impl<T: DriverCrtcState> AsRawCrtcState for CrtcState<T> {
     type Crtc = Crtc<T::Crtc>;
 }
 
-impl<T: DriverCrtcState> FromRawCrtcState for CrtcState<T>
-where
-    T::Crtc: DriverCrtc,
-{
+impl<T: DriverCrtcState> FromRawCrtcState for CrtcState<T> {
     unsafe fn from_raw<'a>(ptr: *const bindings::drm_crtc_state) -> &'a Self {
         // SAFETY: Our data layout starts with `bindings::drm_crtc_state`
         unsafe { &*(ptr.cast()) }
@@ -818,10 +813,7 @@ fn drop(&mut self) {
     }
 }
 
-impl<'a, T: DriverCrtcState> Deref for CrtcStateMutator<'a, CrtcState<T>>
-where
-    T::Crtc: DriverCrtc,
-{
+impl<'a, T: DriverCrtcState> Deref for CrtcStateMutator<'a, CrtcState<T>> {
     type Target = T;
 
     fn deref(&self) -> &Self::Target {
@@ -831,10 +823,7 @@ fn deref(&self) -> &Self::Target {
     }
 }
 
-impl<'a, T: DriverCrtcState> DerefMut for CrtcStateMutator<'a, CrtcState<T>>
-where
-    T::Crtc: DriverCrtc,
-{
+impl<'a, T: DriverCrtcState> DerefMut for CrtcStateMutator<'a, CrtcState<T>> {
     fn deref_mut(&mut self) -> &mut Self::Target {
         // SAFETY: Our interface ensures that `self.state.inner` follows rust's data-aliasing rules,
         // so this is safe
diff --git a/rust/kernel/drm/kms/encoder.rs b/rust/kernel/drm/kms/encoder.rs
index 5f860faf8b61..47fd223a4d3a 100644
--- a/rust/kernel/drm/kms/encoder.rs
+++ b/rust/kernel/drm/kms/encoder.rs
@@ -9,7 +9,7 @@
 };
 use crate::{
     alloc::KBox,
-    drm::device::Device,
+    drm::device::{Device, Uninit},
     error::to_result,
     prelude::*,
     types::{NotThreadSafe, Opaque},
@@ -105,7 +105,7 @@ pub trait DriverEncoder: Send + Sync + Sized {
     /// The constructor for creating a [`Encoder`] using this [`DriverEncoder`] implementation.
     ///
     /// Drivers may use this to instantiate their [`DriverEncoder`] object.
-    fn new(device: &Device<Self::Driver>, args: Self::Args) -> impl PinInit<Self, Error>;
+    fn new(device: &Device<Self::Driver, Uninit>, args: Self::Args) -> impl PinInit<Self, Error>;
 }
 
 /// The generated C vtable for a [`DriverEncoder`].
diff --git a/rust/kernel/drm/kms/modes.rs b/rust/kernel/drm/kms/modes.rs
index 0e8dc434487d..88ea27729212 100644
--- a/rust/kernel/drm/kms/modes.rs
+++ b/rust/kernel/drm/kms/modes.rs
@@ -1,4 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0
+
+//! DRM display mode definitions ([`struct drm_display_mode`]).
+//!
+//! [`struct drm_display_mode`]: srctree/include/drm/drm_modes.h
+
 use bindings;
 
 use crate::types::Opaque;
diff --git a/rust/kernel/drm/kms/plane.rs b/rust/kernel/drm/kms/plane.rs
index 47e05fe6bee1..375f79bd3ceb 100644
--- a/rust/kernel/drm/kms/plane.rs
+++ b/rust/kernel/drm/kms/plane.rs
@@ -11,7 +11,7 @@
 use crate::{
     alloc::KBox,
     bindings,
-    drm::{device::Device, fourcc::*},
+    drm::{device::{Device, Uninit}, fourcc::*},
     error::{from_result, to_result, Error},
     prelude::*,
     types::{NotThreadSafe, Opaque},
@@ -98,12 +98,12 @@ pub trait DriverPlane: Send + Sync + Sized {
     /// The [`DriverPlaneState`] implementation for this [`DriverPlane`].
     ///
     /// See [`DriverPlaneState`] for more info.
-    type State: DriverPlaneState<Plane = Self>;
+    type State: DriverPlaneState;
 
     /// The constructor for creating a [`Plane`] using this [`DriverPlane`] implementation.
     ///
     /// Drivers may use this to instantiate their [`DriverPlane`] object.
-    fn new(device: &Device<Self::Driver>, args: Self::Args) -> impl PinInit<Self, Error>;
+    fn new(device: &Device<Self::Driver, Uninit>, args: Self::Args) -> impl PinInit<Self, Error>;
 
     /// The optional [`drm_plane_helper_funcs.atomic_update`] hook for this plane.
     ///
@@ -689,17 +689,13 @@ pub struct PlaneState<T: DriverPlaneState> {
 /// [`struct drm_plane`]: srctree/include/drm_plane.h
 /// [`struct drm_plane_state`]: srctree/include/drm_plane.h
 pub trait DriverPlaneState: Clone + Default + Sized {
-    /// The type for this driver's drm_plane implementation. Unbounded to break the trait WF
-    /// cycle; the `DriverPlane` bound is required at use sites instead.
-    type Plane;
+    /// The type for this driver's drm_plane implementation
+    type Plane: DriverPlane;
 }
 
 impl<T: DriverPlaneState> Sealed for PlaneState<T> {}
 
-impl<T: DriverPlaneState> AsRawPlaneState for PlaneState<T>
-where
-    T::Plane: DriverPlane,
-{
+impl<T: DriverPlaneState> AsRawPlaneState for PlaneState<T> {
     type Plane = Plane<T::Plane>;
 }
 
@@ -713,10 +709,7 @@ unsafe fn as_raw_mut(&mut self) -> &mut bindings::drm_plane_state {
     }
 }
 
-impl<T: DriverPlaneState> FromRawPlaneState for PlaneState<T>
-where
-    T::Plane: DriverPlane,
-{
+impl<T: DriverPlaneState> FromRawPlaneState for PlaneState<T> {
     unsafe fn from_raw<'a>(ptr: *const bindings::drm_plane_state) -> &'a Self {
         // Our data layout starts with `bindings::drm_plane_state`.
         let ptr: *const Self = ptr.cast();
@@ -892,10 +885,7 @@ unsafe fn as_raw_mut(&mut self) -> &mut bindings::drm_plane_state {
 
 impl<'a, T: FromRawPlaneState> Sealed for PlaneStateMutator<'a, T> {}
 
-impl<'a, T: DriverPlaneState> Deref for PlaneStateMutator<'a, PlaneState<T>>
-where
-    T::Plane: DriverPlane,
-{
+impl<'a, T: DriverPlaneState> Deref for PlaneStateMutator<'a, PlaneState<T>> {
     type Target = T;
 
     fn deref(&self) -> &Self::Target {
@@ -903,10 +893,7 @@ fn deref(&self) -> &Self::Target {
     }
 }
 
-impl<'a, T: DriverPlaneState> DerefMut for PlaneStateMutator<'a, PlaneState<T>>
-where
-    T::Plane: DriverPlane,
-{
+impl<'a, T: DriverPlaneState> DerefMut for PlaneStateMutator<'a, PlaneState<T>> {
     fn deref_mut(&mut self) -> &mut Self::Target {
         &mut self.state.inner
     }
diff --git a/rust/kernel/drm/kms/vblank.rs b/rust/kernel/drm/kms/vblank.rs
index 534fd18f63b4..84e5cbbe923d 100644
--- a/rust/kernel/drm/kms/vblank.rs
+++ b/rust/kernel/drm/kms/vblank.rs
@@ -4,7 +4,7 @@
 //!
 //! C header: [`include/drm/drm_vblank.h`](srcfree/include/drm/drm_vblank.h)
 
-use super::{crtc::*, ModeObject, modes::*, Sealed};
+use super::{crtc::*, ModeObject, modes::*};
 use bindings;
 use core::{
     marker::*,
@@ -62,9 +62,8 @@ fn get_vblank_timestamp(
 /// Drivers interested in implementing vblank support should refer to [`VblankSupport`], drivers
 /// that don't have vblank support can use [`PhantomData`].
 pub trait VblankImpl {
-    /// The parent [`DriverCrtc`]. Unbounded to break the trait WF cycle; the `DriverCrtc`
-    /// bound is required at use sites instead.
-    type Crtc;
+    /// The parent [`DriverCrtc`].
+    type Crtc: DriverCrtc<VblankImpl = Self>;
 
     /// The generated [`VblankOps`].
     const VBLANK_OPS: VblankOps;
-- 
2.55.0


  parent reply	other threads:[~2026-07-03  3:01 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-17 15:02 [RFC PATCH 0/5] rust: drm: minimal KMS bindings, EDID read, rotation, HDCP defs Mike Lothian
2026-06-17 15:02 ` [RFC PATCH 1/4] rust: drm: add minimal KMS bindings for simple-display-pipe drivers Mike Lothian
2026-06-17 15:02 ` [RFC PATCH 2/4] rust: drm: expose drm_edid.h for reading connector EDID Mike Lothian
2026-06-17 15:02 ` [RFC PATCH 3/4] rust: drm: expose drm::Device::as_raw() Mike Lothian
2026-06-17 15:02 ` [RFC PATCH 4/4] rust: drm: expose drm_blend.h and the atomic new-CRTC-state accessor Mike Lothian
2026-06-17 15:11 ` [RFC PATCH 0/5] rust: drm: minimal KMS bindings, EDID read, rotation, HDCP defs Miguel Ojeda
2026-06-17 15:29   ` Mike Lothian
2026-07-03  3:00 ` [RFC PATCH v2 00/18] rust: drm: safe KMS mode-object layer + evdi bindings Mike Lothian
2026-07-03  3:00   ` [RFC PATCH v2 01/18] rust: drm: kms: forward-port the safe mode-object layer onto the typestate device Mike Lothian
2026-07-07 21:46     ` lyude
2026-07-07 22:21     ` lyude
2026-07-03  3:00   ` [RFC PATCH v2 02/18] rust: drm: kms: adapt the port to current drm-next Mike Lothian
2026-07-03  3:00   ` [RFC PATCH v2 03/18] rust: drm: kms: break the Driver* trait well-formedness cycle Mike Lothian
2026-07-03  3:00   ` Mike Lothian [this message]
2026-07-03  3:00   ` [RFC PATCH v2 05/18] rust: drm: expose <drm/display/drm_hdcp.h> HDCP 2.2 message definitions Mike Lothian
2026-07-03  3:00   ` [RFC PATCH v2 06/18] rust: drm: kms: add a Framebuffer::vmap() guard Mike Lothian
2026-07-07 21:51     ` lyude
2026-07-03  3:00   ` [RFC PATCH v2 07/18] rust: drm: kms: add safe accessors for common state and connector modes Mike Lothian
2026-07-03  3:00   ` [RFC PATCH v2 08/18] rust: drm: tyr: add the Kms associated type Mike Lothian
2026-07-03  3:00   ` [RFC PATCH v2 09/18] rust: drm: add drm_event delivery Mike Lothian
2026-07-03  3:00   ` [RFC PATCH v2 10/18] rust: drm: allow drivers to declare ioctls from their own uAPI module Mike Lothian
2026-07-03  3:00   ` [RFC PATCH v2 11/18] rust: platform: add runtime platform device creation Mike Lothian
2026-07-03  3:00   ` [RFC PATCH v2 12/18] rust: drm: framebuffer: add geometry accessors, refcounting and a byte-slice vmap Mike Lothian
2026-07-03  3:01   ` [RFC PATCH v2 13/18] rust: i2c: add adapter-provider (bus controller) registration Mike Lothian
2026-07-03  3:01   ` [RFC PATCH v2 14/18] rust: add sysfs device attribute groups Mike Lothian
2026-07-03  3:01   ` [RFC PATCH v2 15/18] rust: drm: support hardware cursor planes with sleepable event delivery Mike Lothian
2026-07-03  3:01   ` [RFC PATCH v2 16/18] rust: drm: add CRTC gamma LUT and plane rotation property bindings Mike Lothian
2026-07-03  3:01   ` [RFC PATCH v2 17/18] rust: drm: kms: add connector detect() and mode_valid() hooks Mike Lothian
2026-07-03  3:01   ` [RFC PATCH v2 18/18] rust: drm: kms: add plane damage-clip accessors Mike Lothian

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260703030123.2814-5-mike@fireburn.co.uk \
    --to=mike@fireburn.co.uk \
    --cc=a.hindborg@kernel.org \
    --cc=airlied@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun@kernel.org \
    --cc=dakr@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=gary@garyguo.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lossin@kernel.org \
    --cc=lyude@redhat.com \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=simona@ffwll.ch \
    --cc=tmgross@umich.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox