From: Maxime Ripard <mripard@kernel.org>
To: Lyude Paul <lyude@redhat.com>
Cc: dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org,
"Danilo Krummrich" <dakr@kernel.org>,
mcanal@igalia.com, "Alice Ryhl" <aliceryhl@google.com>,
"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>,
"Asahi Lina" <lina@asahilina.net>,
"Wedson Almeida Filho" <wedsonaf@gmail.com>,
"open list" <linux-kernel@vger.kernel.org>
Subject: Re: [RFC v3 09/33] rust: drm/kms: Add DriverConnector::get_mode callback
Date: Fri, 14 Mar 2025 12:57:13 +0100 [thread overview]
Message-ID: <20250314-gigantic-frisky-condor-9b35c8@houat> (raw)
In-Reply-To: <20250305230406.567126-10-lyude@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 9921 bytes --]
On Wed, Mar 05, 2025 at 05:59:25PM -0500, Lyude Paul wrote:
> Next up is filling out some of the basic connector hotplugging callbacks -
> which we'll need for setting up the fbdev helpers for KMS devices. Note
> that connector hotplugging in DRM follows a BFL scheme: pretty much all
> probing is protected under the mighty drm_device->mode_config.lock, which
> of course is a bit counter-intuitive to rust's locking schemes where data
> is always associated with its lock.
>
> Since that lock is embedded in an FFI type and not a rust type, we need to
> introduce our own wrapper type that acts as a lock acquisition for this.
> This brings us to introducing a few new types:
>
> * ModeConfigGuard - the most basic lock guard, as long as this object is
> alive we are guaranteed to be holding drm_device->mode_config.lock. This
> object doesn't do much else on its own currently.
> * ConnectorGuard - an object which corresponds to a specific typed DRM
> connector. This can only be acquired with a ModeConfigGuard, and will be
> used to allow calling methods that are only safe to call with
> drm_device->mode_config.lock held. Since it implements
> Deref<Target=Connector<T>> as well, it can also be used for any other
> operations that would normally be available on a DRM connector.
>
> And finally, we add the DriverConnector::get_modes() trait method which
> drivers can use to implement the drm_connector_helper_funcs.get_modes
> callback. Note that while we make this trait method mandatory, we only do
> so for the time being since VKMS doesn't do very much with DRM connectors -
> and as such we have no need yet to implement alternative connector probing
> schemes outside of get_modes().
>
> Signed-off-by: Lyude Paul <lyude@redhat.com>
>
> ---
> V3:
> * Document uses of ManuallyDrop
> * Use addr_of_mut!() instead of &mut
> * Add some missing invariant comments
>
> Signed-off-by: Lyude Paul <lyude@redhat.com>
> ---
> rust/bindings/bindings_helper.h | 1 +
> rust/kernel/drm/kms.rs | 90 +++++++++++++++++++++++++++++++-
> rust/kernel/drm/kms/connector.rs | 62 ++++++++++++++++++++--
> 3 files changed, 147 insertions(+), 6 deletions(-)
>
> diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
> index a6735f6fba947..27828dd36d4f2 100644
> --- a/rust/bindings/bindings_helper.h
> +++ b/rust/bindings/bindings_helper.h
> @@ -21,6 +21,7 @@
> #include <drm/drm_gem_framebuffer_helper.h>
> #include <drm/drm_gem_shmem_helper.h>
> #include <drm/drm_plane.h>
> +#include <drm/drm_probe_helper.h>
> #include <drm/drm_ioctl.h>
> #include <kunit/test.h>
> #include <linux/blk-mq.h>
> diff --git a/rust/kernel/drm/kms.rs b/rust/kernel/drm/kms.rs
> index f0044d396e1eb..7935e935f9975 100644
> --- a/rust/kernel/drm/kms.rs
> +++ b/rust/kernel/drm/kms.rs
> @@ -8,15 +8,20 @@
> pub mod plane;
>
> use crate::{
> - device,
> + container_of, device,
> drm::{device::Device, drv::Driver},
> error::to_result,
> prelude::*,
> private::Sealed,
> + sync::{Mutex, MutexGuard},
> types::*,
> };
> use bindings;
> -use core::{marker::PhantomData, ops::Deref, ptr::NonNull};
> +use core::{
> + marker::PhantomData,
> + ops::Deref,
> + ptr::{self, addr_of_mut, NonNull},
> +};
>
> /// The C vtable for a [`Device`].
> ///
> @@ -191,6 +196,23 @@ pub struct ModeConfigInfo {
> pub preferred_fourcc: Option<u32>,
> }
>
> +impl<T: KmsDriver> Device<T> {
> + /// Retrieve a pointer to the mode_config mutex
> + #[inline]
> + pub(crate) fn mode_config_mutex(&self) -> &Mutex<()> {
> + // SAFETY: This lock is initialized for as long as `Device<T>` is exposed to users
> + unsafe { Mutex::from_raw(addr_of_mut!((*self.as_raw()).mode_config.mutex)) }
> + }
> +
> + /// Acquire the [`mode_config.mutex`] for this [`Device`].
> + #[inline]
> + pub fn mode_config_lock(&self) -> ModeConfigGuard<'_, T> {
> + // INVARIANT: We're locking mode_config.mutex, fulfilling our invariant that this lock is
> + // held throughout ModeConfigGuard's lifetime.
> + ModeConfigGuard(self.mode_config_mutex().lock(), PhantomData)
> + }
> +}
> +
Again, I think the introduction of ModeConfigGuard, the new API to get
the mutex and guard from the DRM device, etc, while obviously called
for, would be better in separate patches.
> /// A modesetting object in DRM.
> ///
> /// This is any type of object where the underlying C object contains a [`struct drm_mode_object`].
> @@ -314,3 +336,67 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
> unsafe { bindings::drm_mode_object_put(obj.as_ref().raw_mode_obj()) }
> }
> }
> +
> +/// A mode config guard.
> +///
> +/// This is an exclusive primitive that represents when [`drm_device.mode_config.mutex`] is held - as
> +/// some modesetting operations (particularly ones related to [`connectors`](connector)) are still
> +/// protected under this single lock. The lock will be dropped once this object is dropped.
> +///
> +/// # Invariants
> +///
> +/// - `self.0` is contained within a [`struct drm_mode_config`], which is contained within a
> +/// [`struct drm_device`].
> +/// - The [`KmsDriver`] implementation of that [`struct drm_device`] is always `T`.
> +/// - This type proves that [`drm_device.mode_config.mutex`] is acquired.
> +///
> +/// [`struct drm_mode_config`]: (srctree/include/drm/drm_device.h)
> +/// [`drm_device.mode_config.mutex`]: (srctree/include/drm/drm_device.h)
> +/// [`struct drm_device`]: (srctree/include/drm/drm_device.h)
> +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.
> + ///
> + /// [`drm_device.mode_config.mutex`]: (srctree/include/drm/drm_device.h)
> + pub(crate) unsafe fn new(drm: &'a Device<T>) -> Self {
> + // SAFETY: Our safety contract fulfills the requirements of `MutexGuard::new()`
> + // INVARIANT: And our safety contract ensures that this type proves that
> + // `drm_device.mode_config.mutex` is acquired.
> + 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> {
> + // SAFETY:
> + // - `self` is embedded within a `drm_mode_config` via our type invariants
> + // - `self.0.lock` has an equivalent data type to `mutex` via its type invariants.
> + let mode_config = unsafe { container_of!(self.0.lock, bindings::drm_mode_config, mutex) };
> +
> + // SAFETY: And that `drm_mode_config` lives in a `drm_device` via type invariants.
> + unsafe {
> + Device::borrow(container_of!(
> + mode_config,
> + bindings::drm_device,
> + mode_config
> + ))
> + }
> + }
> +
> + /// Assert that the given device is the owner of this mode config guard.
> + ///
> + /// # Panics
> + ///
> + /// Panics if `dev` is different from the owning device for this mode config guard.
> + #[inline]
> + pub(crate) fn assert_owner(&self, dev: &Device<T>) {
> + assert!(ptr::eq(self.drm_dev(), dev));
> + }
> +}
> diff --git a/rust/kernel/drm/kms/connector.rs b/rust/kernel/drm/kms/connector.rs
> index 6fe0a7517bd55..14de3b0529f89 100644
> --- a/rust/kernel/drm/kms/connector.rs
> +++ b/rust/kernel/drm/kms/connector.rs
> @@ -4,7 +4,7 @@
> //!
> //! C header: [`include/drm/drm_connector.h`](srctree/include/drm/drm_connector.h)
>
> -use super::{encoder::*, KmsDriver, ModeObject, RcModeObject};
> +use super::{encoder::*, KmsDriver, ModeConfigGuard, ModeObject, RcModeObject};
> use crate::{
> alloc::KBox,
> bindings,
> @@ -17,7 +17,7 @@
> };
> use core::{
> marker::*,
> - mem,
> + mem::{self, ManuallyDrop},
> ops::*,
> ptr::{addr_of_mut, null_mut},
> stringify,
> @@ -106,7 +106,7 @@ pub trait DriverConnector: Send + Sync + Sized {
> destroy: Some(connector_destroy_callback::<Self>),
> force: None,
> detect: None,
> - fill_modes: None,
> + fill_modes: Some(bindings::drm_helper_probe_single_connector_modes),
It's kind of what I wanted to express in my earlier statements I guess,
but I'm not really sure we should force down helpers on drivers. The
larger approach KMS has taken over the years was to provide hooks and
default implementations, with the drivers allowed to use different
implementations if they wanted to.
That approach largely worked for us I think, so I'm a bit worried about
changing that.
> debugfs_init: None,
> oob_hotplug_event: None,
> atomic_duplicate_state: Some(atomic_duplicate_state_callback::<Self::State>),
> @@ -114,7 +114,7 @@ pub trait DriverConnector: Send + Sync + Sized {
> helper_funcs: bindings::drm_connector_helper_funcs {
> mode_valid: None,
> atomic_check: None,
> - get_modes: None,
> + get_modes: Some(get_modes_callback::<Self>),
> detect_ctx: None,
Since you pass (the equivalent of) the locking context to get_modes, I'd
rather keep the convention you have with detect here and use the _ctx
suffix, or drop the one from detect_ctx, and pass the context
everywhere. But we should be consistent there at least.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
next prev parent reply other threads:[~2025-03-14 11:57 UTC|newest]
Thread overview: 71+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-03-05 22:59 [RFC v3 00/33] Rust bindings for KMS + RVKMS Lyude Paul
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 ` [RFC v3 03/33] rust: drm/kms: Introduce the main ModeConfigObject traits Lyude Paul
2025-03-14 10:44 ` 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 [this message]
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=20250314-gigantic-frisky-condor-9b35c8@houat \
--to=mripard@kernel.org \
--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=lina@asahilina.net \
--cc=linux-kernel@vger.kernel.org \
--cc=lyude@redhat.com \
--cc=mcanal@igalia.com \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=sima@ffwll.ch \
--cc=tmgross@umich.edu \
--cc=wedsonaf@gmail.com \
/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