From: Lyude Paul <lyude@redhat.com>
To: dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org
Cc: "Danilo Krummrich" <dakr@kernel.org>,
mcanal@igalia.com, "Alice Ryhl" <aliceryhl@google.com>,
"Maxime Ripard" <mripard@kernel.org>,
"Simona Vetter" <sima@ffwll.ch>,
"Daniel Almeida" <daniel.almeida@collabora.com>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <benno.lossin@proton.me>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Trevor Gross" <tmgross@umich.edu>,
linux-kernel@vger.kernel.org (open list)
Subject: [RFC v3 03/33] rust: drm/kms: Introduce the main ModeConfigObject traits
Date: Wed, 5 Mar 2025 17:59:19 -0500 [thread overview]
Message-ID: <20250305230406.567126-4-lyude@redhat.com> (raw)
In-Reply-To: <20250305230406.567126-1-lyude@redhat.com>
The KMS API has a very consistent idea of a "mode config object", which
includes any object with a drm_mode_object struct embedded in it. These
objects have their own object IDs which DRM exposes to userspace, and we
introduce the ModeConfigObject trait to represent any object matching these
characteristics.
One slightly less consistent trait of these objects however: some mode
objects have a reference count, while others don't. Since rust requires
that we are able to define the lifetime of an object up-front, we introduce
two other super-traits of ModeConfigObject for this:
* StaticModeObject - this trait represents any mode object which does not
have a reference count of its own. Such objects can be considered to
share the lifetime of their parent KMS device
* RcModeObject - this trait represents any mode object which does have its
own reference count. Objects implementing this trait get a free blanket
implementation of AlwaysRefCounted, and as such can be used with the ARef
container without us having to implement AlwaysRefCounted for each
individual mode object.
This will be able to handle most lifetimes we'll need with one exception:
it's entirely possible a driver may want to hold a "owned" reference to a
static mode object. We allow for this by introducing the KmsRef container,
which grabs an owned refcount to the parent KMS device of a
StaticModeObject and holds a pointer to said object - essentially allowing
it to act identically to an owned refcount by preventing the device's
lifetime from ending until the KmsRef is dropped. I choose not to use
AlwaysRefCounted for this as holding a refcount to the device has its own
set of implications since if you forget to drop the KmsRef the device will
never be destroyed.
Signed-off-by: Lyude Paul <lyude@redhat.com>
---
V3:
* Document why modesetting objects require Send + Sync
* Make `ModeObject` an unsafe trait
I was prompted to make this change in response to one of Daniel's
comments, as it occurred to me that we need something that ensures that
implementers are only returning valid `drm_mode_object` pointers so we
have something to put down for the various related safety comments in
RcModeObject.
Also, update the safety comments there.
Signed-off-by: Lyude Paul <lyude@redhat.com>
---
rust/kernel/drm/kms.rs | 127 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 126 insertions(+), 1 deletion(-)
diff --git a/rust/kernel/drm/kms.rs b/rust/kernel/drm/kms.rs
index 78970c69f4cda..885bd5266a2d7 100644
--- a/rust/kernel/drm/kms.rs
+++ b/rust/kernel/drm/kms.rs
@@ -7,10 +7,11 @@
drm::{device::Device, drv::Driver},
error::to_result,
prelude::*,
+ private::Sealed,
types::*,
};
use bindings;
-use core::{marker::PhantomData, ops::Deref};
+use core::{marker::PhantomData, ops::Deref, ptr::NonNull};
/// The C vtable for a [`Device`].
///
@@ -184,3 +185,127 @@ pub struct ModeConfigInfo {
/// An optional default fourcc format code to be preferred for clients.
pub preferred_fourcc: Option<u32>,
}
+
+/// A modesetting object in DRM.
+///
+/// This is any type of object where the underlying C object contains a [`struct drm_mode_object`].
+/// This type requires [`Send`] + [`Sync`] as all modesetting objects in DRM are able to be sent
+/// between threads.
+///
+/// This type is only implemented by the DRM crate itself.
+///
+/// # Safety
+///
+/// [`raw_mode_obj()`] must always return a valid pointer to an initialized
+/// [`struct drm_mode_object`].
+///
+/// [`struct drm_mode_object`]: srctree/include/drm/drm_mode_object.h
+/// [`raw_mode_obj()`]: ModeObject::raw_mode_obj()
+pub unsafe trait ModeObject: Sealed + Send + Sync {
+ /// The parent driver for this [`ModeObject`].
+ type Driver: KmsDriver;
+
+ /// Return the [`Device`] for this [`ModeObject`].
+ fn drm_dev(&self) -> &Device<Self::Driver>;
+
+ /// Return a pointer to the [`struct drm_mode_object`] for this [`ModeObject`].
+ ///
+ /// [`struct drm_mode_object`]: (srctree/include/drm/drm_mode_object.h)
+ fn raw_mode_obj(&self) -> *mut bindings::drm_mode_object;
+}
+
+/// A trait for modesetting objects which don't come with their own reference-counting.
+///
+/// Some [`ModeObject`] types in DRM do not have a reference count. These types are considered
+/// "static" and share the lifetime of their parent [`Device`]. To retrieve an owned reference to
+/// such types, see [`KmsRef`].
+///
+/// # Safety
+///
+/// This trait must only be implemented for modesetting objects which do not have a refcount within
+/// their [`struct drm_mode_object`], otherwise [`KmsRef`] can't guarantee the object will stay
+/// alive.
+///
+/// [`struct drm_mode_object`]: (srctree/include/drm/drm_mode_object.h)
+pub unsafe trait StaticModeObject: ModeObject {}
+
+/// An owned reference to a [`StaticModeObject`].
+///
+/// Note that since [`StaticModeObject`] types share the lifetime of their parent [`Device`], the
+/// parent [`Device`] will stay alive as long as this type exists. Thus, users should be aware that
+/// storing a [`KmsRef`] within a [`ModeObject`] is a circular reference.
+///
+/// # Invariants
+///
+/// `self.0` points to a valid instance of `T` throughout the lifetime of this type.
+pub struct KmsRef<T: StaticModeObject>(NonNull<T>);
+
+// SAFETY: Owned references to DRM device are thread-safe.
+unsafe impl<T: StaticModeObject> Send for KmsRef<T> {}
+// SAFETY: Owned references to DRM device are thread-safe.
+unsafe impl<T: StaticModeObject> Sync for KmsRef<T> {}
+
+impl<T: StaticModeObject> From<&T> for KmsRef<T> {
+ fn from(value: &T) -> Self {
+ // INVARIANT: Because the lifetime of the StaticModeObject is the same as the lifetime of
+ // its parent device, we can ensure that `value` remains alive by incrementing the device's
+ // reference count. The device will only disappear once we drop this reference in `Drop`.
+ value.drm_dev().inc_ref();
+
+ Self(value.into())
+ }
+}
+
+impl<T: StaticModeObject> Drop for KmsRef<T> {
+ fn drop(&mut self) {
+ // SAFETY: We're reclaiming the reference we leaked in From<&T>
+ drop(unsafe { ARef::from_raw(self.drm_dev().into()) })
+ }
+}
+
+impl<T: StaticModeObject> Deref for KmsRef<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ // SAFETY: We're guaranteed object will point to a valid object as long as we hold dev
+ unsafe { self.0.as_ref() }
+ }
+}
+
+impl<T: StaticModeObject> Clone for KmsRef<T> {
+ fn clone(&self) -> Self {
+ // INVARIANT: Because the lifetime of the StaticModeObject is the same as the lifetime of
+ // its parent device, we can ensure that `value` remains alive by incrementing the device's
+ // reference count. The device will only disappear once we drop this reference in `Drop`.
+ self.drm_dev().inc_ref();
+
+ Self(self.0)
+ }
+}
+
+/// A trait for [`ModeObject`] which is reference counted.
+///
+/// This trait is implemented by DRM for any [`ModeObject`] which has a reference count provided by
+/// [`struct drm_mode_object`]. It provides a common implementation of [`AlwaysRefCounted`], since
+/// all [`RcModeObject`] types use the same functions for refcounting.
+///
+/// # Safety
+///
+/// The [`ModeObject`] must initialize the refcount in its [`struct drm_mode_object`] field.
+///
+/// [`struct drm_mode_object`]: (srctree/include/drm/drm_mode_object.h)
+pub unsafe trait RcModeObject: ModeObject {}
+
+unsafe impl<T: RcModeObject> AlwaysRefCounted for T {
+ fn inc_ref(&self) {
+ // SAFETY: We're guaranteed by the safety contract of `ModeObject` that `raw_mode_obj()`
+ // always returns a pointer to an initialized `drm_mode_object`.
+ unsafe { bindings::drm_mode_object_get(self.raw_mode_obj()) }
+ }
+
+ unsafe fn dec_ref(obj: NonNull<Self>) {
+ // SAFETY: We're guaranteed by the safety contract of `ModeObject` that `raw_mode_obj()`
+ // always returns a pointer to an initialized `drm_mode_object`.
+ unsafe { bindings::drm_mode_object_put(obj.as_ref().raw_mode_obj()) }
+ }
+}
--
2.48.1
next prev parent reply other threads:[~2025-03-05 23:05 UTC|newest]
Thread overview: 70+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20250305230406.567126-1-lyude@redhat.com>
2025-03-05 22:59 ` [RFC v3 01/33] rust: drm: Add a small handful of fourcc bindings Lyude Paul
2025-03-07 16:32 ` Maxime Ripard
2025-05-12 11:49 ` Daniel Almeida
2025-05-13 7:11 ` Louis Chauvet
2025-03-05 22:59 ` [RFC v3 02/33] rust: drm: Add traits for registering KMS devices Lyude Paul
2025-03-14 10:05 ` Maxime Ripard
2025-03-21 22:00 ` Lyude Paul
2025-04-04 19:39 ` Louis Chauvet
2025-05-12 12:50 ` Daniel Almeida
2025-03-05 22:59 ` Lyude Paul [this message]
2025-03-14 10:44 ` [RFC v3 03/33] rust: drm/kms: Introduce the main ModeConfigObject traits Maxime Ripard
2025-03-21 23:23 ` Lyude Paul
2025-03-05 22:59 ` [RFC v3 04/33] rust: drm/kms: Add drm_connector bindings Lyude Paul
2025-03-14 11:02 ` Maxime Ripard
2025-03-21 23:35 ` Lyude Paul
2025-05-12 14:39 ` Louis Chauvet
2025-05-12 16:15 ` Daniel Almeida
2025-03-05 22:59 ` [RFC v3 05/33] rust: drm/kms: Add drm_plane bindings Lyude Paul
2025-03-14 11:37 ` Maxime Ripard
2025-03-21 23:38 ` Lyude Paul
2025-05-12 16:29 ` Daniel Almeida
2025-03-05 22:59 ` [RFC v3 06/33] rust: drm/kms: Add drm_crtc bindings Lyude Paul
2025-03-05 22:59 ` [RFC v3 07/33] rust: drm/kms: Add drm_encoder bindings Lyude Paul
2025-03-14 11:48 ` Maxime Ripard
2025-03-21 23:42 ` Lyude Paul
2025-03-05 22:59 ` [RFC v3 08/33] rust: drm/kms: Add UnregisteredConnector::attach_encoder() Lyude Paul
2025-03-05 22:59 ` [RFC v3 09/33] rust: drm/kms: Add DriverConnector::get_mode callback Lyude Paul
2025-03-14 11:57 ` Maxime Ripard
2025-03-21 23:47 ` Lyude Paul
2025-05-12 19:39 ` Daniel Almeida
2025-03-05 22:59 ` [RFC v3 10/33] rust: drm/kms: Add ConnectorGuard::add_modes_noedid() Lyude Paul
2025-03-14 12:02 ` Maxime Ripard
2025-03-21 23:50 ` Lyude Paul
2025-03-21 23:52 ` Lyude Paul
2025-03-22 3:31 ` Greg Kroah-Hartman
2025-03-25 9:43 ` Maxime Ripard
2025-03-05 22:59 ` [RFC v3 11/33] rust: drm/kms: Add ConnectorGuard::set_preferred_mode Lyude Paul
2025-03-05 22:59 ` [RFC v3 12/33] rust: drm/kms: Add RawConnector and RawConnectorState Lyude Paul
2025-03-14 12:04 ` Maxime Ripard
2025-03-25 21:55 ` Lyude Paul
2025-03-05 22:59 ` [RFC v3 13/33] rust: drm/kms: Add RawPlane and RawPlaneState Lyude Paul
2025-03-05 22:59 ` [RFC v3 14/33] rust: drm/kms: Add OpaqueConnector and OpaqueConnectorState Lyude Paul
2025-03-14 12:08 ` Maxime Ripard
2025-03-25 22:20 ` Lyude Paul
2025-03-05 22:59 ` [RFC v3 15/33] rust: drm/kms: Add OpaqueCrtc and OpaqueCrtcState Lyude Paul
2025-03-05 22:59 ` [RFC v3 16/33] rust: drm/kms: Add OpaquePlane and OpaquePlaneState Lyude Paul
2025-03-05 22:59 ` [RFC v3 17/33] rust: drm/kms: Add OpaqueEncoder Lyude Paul
2025-03-05 22:59 ` [RFC v3 18/33] rust: drm/kms: Add drm_atomic_state bindings Lyude Paul
2025-03-14 12:18 ` Maxime Ripard
2025-03-05 22:59 ` [RFC v3 19/33] rust: drm/kms: Add DriverCrtc::atomic_check() Lyude Paul
2025-03-14 12:21 ` Maxime Ripard
2025-03-26 21:18 ` Lyude Paul
2025-03-05 22:59 ` [RFC v3 20/33] rust: drm/kms: Add DriverPlane::atomic_update() Lyude Paul
2025-03-05 22:59 ` [RFC v3 21/33] rust: drm/kms: Add DriverPlane::atomic_check() Lyude Paul
2025-03-14 12:22 ` Maxime Ripard
2025-03-05 22:59 ` [RFC v3 22/33] rust: drm/kms: Add RawCrtcState::active() Lyude Paul
2025-03-05 22:59 ` [RFC v3 23/33] rust: drm/kms: Add RawPlaneState::crtc() Lyude Paul
2025-03-05 22:59 ` [RFC v3 24/33] rust: drm/kms: Add RawPlaneState::atomic_helper_check() Lyude Paul
2025-03-05 22:59 ` [RFC v3 25/33] rust: drm/kms: Add drm_framebuffer bindings Lyude Paul
2025-03-05 22:59 ` [RFC v3 26/33] rust: drm/kms: Add RawPlane::framebuffer() Lyude Paul
2025-03-05 22:59 ` [RFC v3 27/33] rust: drm/kms: Add DriverCrtc::atomic_begin() and atomic_flush() Lyude Paul
2025-03-14 12:25 ` Maxime Ripard
2025-03-05 22:59 ` [RFC v3 28/33] rust: drm/kms: Add DriverCrtc::atomic_enable() and atomic_disable() Lyude Paul
2025-03-05 22:59 ` [RFC v3 29/33] rust: drm: Add Device::event_lock() Lyude Paul
2025-03-05 22:59 ` [RFC v3 30/33] rust: drm/kms: Add Device::num_crtcs() Lyude Paul
2025-03-07 17:38 ` Maxime Ripard
2025-03-05 22:59 ` [RFC v3 31/33] rust: drm/kms: Add VblankSupport Lyude Paul
2025-03-14 12:37 ` Maxime Ripard
2025-03-05 22:59 ` [RFC v3 32/33] rust: drm/kms: Add Kms::atomic_commit_tail Lyude Paul
2025-03-05 22:59 ` [RFC v3 33/33] drm: Introduce RVKMS! Lyude Paul
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=20250305230406.567126-4-lyude@redhat.com \
--to=lyude@redhat.com \
--cc=a.hindborg@kernel.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=benno.lossin@proton.me \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=gary@garyguo.net \
--cc=linux-kernel@vger.kernel.org \
--cc=mcanal@igalia.com \
--cc=mripard@kernel.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=sima@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
all inboxes | Powered by JetHome®