Re: [WIP RFC v2 02/35] WIP: rust: drm: Add traits for registering KMS devices

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Lyude,

> On 27 Nov 2024, at 18:21, Lyude Paul <lyude@xxxxxxxxxx> wrote:
> 
> On Tue, 2024-11-26 at 15:18 -0300, Daniel Almeida wrote:
>> Hi Lyude,
>> 
>>> On 30 Sep 2024, at 20:09, Lyude Paul <lyude@xxxxxxxxxx> wrote:
>>> 
>>> This commit adds some traits for registering DRM devices with KMS support,
>>> implemented through the kernel::drm::kms::Kms trait. Devices which don't
>>> have KMS support can simply use PhantomData<Self>.
>>> 
>>> Signed-off-by: Lyude Paul <lyude@xxxxxxxxxx>
>>> 
>>> ---
>>> 
>>> TODO:
>>> * Generate feature flags automatically, these shouldn't need to be
>>> specified by the user
>>> 
>>> Signed-off-by: Lyude Paul <lyude@xxxxxxxxxx>
>>> ---
>>> rust/bindings/bindings_helper.h |   4 +
>>> rust/kernel/drm/device.rs       |  18 ++-
>>> rust/kernel/drm/drv.rs          |  45 ++++++-
>>> rust/kernel/drm/kms.rs          | 230 ++++++++++++++++++++++++++++++++
>>> rust/kernel/drm/kms/fbdev.rs    |  45 +++++++
>>> rust/kernel/drm/mod.rs          |   1 +
>>> 6 files changed, 335 insertions(+), 8 deletions(-)
>>> create mode 100644 rust/kernel/drm/kms.rs
>>> create mode 100644 rust/kernel/drm/kms/fbdev.rs
>>> 
>>> diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
>>> index 04898f70ef1b8..4a8e44e11c96a 100644
>>> --- a/rust/bindings/bindings_helper.h
>>> +++ b/rust/bindings/bindings_helper.h
>>> @@ -6,11 +6,15 @@
>>> * Sorted alphabetically.
>>> */
>>> 
>>> +#include <drm/drm_atomic.h>
>>> +#include <drm/drm_atomic_helper.h>
>>> #include <drm/drm_device.h>
>>> #include <drm/drm_drv.h>
>>> #include <drm/drm_file.h>
>>> #include <drm/drm_fourcc.h>
>>> +#include <drm/drm_fbdev_dma.h>
>>> #include <drm/drm_gem.h>
>>> +#include <drm/drm_gem_framebuffer_helper.h>
>>> #include <drm/drm_gem_shmem_helper.h>
>>> #include <drm/drm_ioctl.h>
>>> #include <kunit/test.h>
>>> diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs
>>> index 2b687033caa2d..d4d6b1185f6a6 100644
>>> --- a/rust/kernel/drm/device.rs
>>> +++ b/rust/kernel/drm/device.rs
>>> @@ -5,14 +5,22 @@
>>> //! C header: [`include/linux/drm/drm_device.h`](srctree/include/linux/drm/drm_device.h)
>>> 
>>> use crate::{
>>> -    bindings, device, drm,
>>> -    drm::drv::AllocImpl,
>>> +    bindings, device,
>>> +    drm::{
>>> +        drv::AllocImpl,
>>> +        self,
>>> +        kms::{KmsImpl, private::KmsImpl as KmsImplPrivate}
>>> +    },
>>>    error::code::*,
>>>    error::from_err_ptr,
>>>    error::Result,
>>>    types::{ARef, AlwaysRefCounted, ForeignOwnable, Opaque},
>>> };
>>> -use core::{ffi::c_void, marker::PhantomData, ptr::NonNull};
>>> +use core::{
>>> +    ffi::c_void,
>>> +    marker::PhantomData,
>>> +    ptr::NonNull
>>> +};
>>> 
>>> #[cfg(CONFIG_DRM_LEGACY)]
>>> macro_rules! drm_legacy_fields {
>>> @@ -150,6 +158,10 @@ pub fn data(&self) -> <T::Data as ForeignOwnable>::Borrowed<'_> {
>>>        // SAFETY: `Self::data` is always converted and set on device creation.
>>>        unsafe { <T::Data as ForeignOwnable>::from_foreign(drm.raw_data()) };
>>>    }
>>> +
>>> +    pub(crate) const fn has_kms() -> bool {
>>> +        <T::Kms as KmsImplPrivate>::MODE_CONFIG_OPS.is_some()
>>> +    }
>>> }
>>> 
>>> // SAFETY: DRM device objects are always reference counted and the get/put functions
>>> diff --git a/rust/kernel/drm/drv.rs b/rust/kernel/drm/drv.rs
>>> index 0cf3fb1cea53c..6b61f2755ba79 100644
>>> --- a/rust/kernel/drm/drv.rs
>>> +++ b/rust/kernel/drm/drv.rs
>>> @@ -8,7 +8,15 @@
>>>    alloc::flags::*,
>>>    bindings,
>>>    devres::Devres,
>>> -    drm,
>>> +    drm::{
>>> +        self,
>>> +        kms::{
>>> +            KmsImpl,
>>> +            private::KmsImpl as KmsImplPrivate,
>>> +            Kms
>>> +        }
>>> +    },
>>> +    device,
>>>    error::{Error, Result},
>>>    private::Sealed,
>>>    str::CStr,
>>> @@ -142,6 +150,12 @@ pub trait Driver {
>>>    /// The type used to represent a DRM File (client)
>>>    type File: drm::file::DriverFile;
>>> 
>>> +    /// The KMS implementation for this driver.
>>> +    ///
>>> +    /// Drivers that wish to support KMS should pass their implementation of `drm::kms::KmsDriver`
>>> +    /// here. Drivers which do not have KMS support can simply pass `drm::kms::NoKms` here.

By the way, below you said you “had” a `NoKms` type, but the old docs seem to remain in place.

>>> +    type Kms: drm::kms::KmsImpl<Driver = Self> where Self: Sized;
>>> +
>>>    /// Driver metadata
>>>    const INFO: DriverInfo;
>>> 
>>> @@ -159,21 +173,36 @@ pub trait Driver {
>>> 
>>> impl<T: Driver> Registration<T> {
>>>    /// Creates a new [`Registration`] and registers it.
>>> -    pub fn new(drm: ARef<drm::device::Device<T>>, flags: usize) -> Result<Self> {
>>> +    pub fn new(dev: &device::Device, data: T::Data, flags: usize) -> Result<Self> {
>>> +        let drm = drm::device::Device::<T>::new(dev, data)?;
>>> +        let has_kms = drm::device::Device::<T>::has_kms();
>>> +
>>> +        let mode_config_info = if has_kms {
>>> +            // SAFETY: We have yet to register this device
>>> +            Some(unsafe { T::Kms::setup_kms(&drm)? })
>>> +        } else {
>>> +            None
>>> +        };
>>> +
>>>        // SAFETY: Safe by the invariants of `drm::device::Device`.
>>>        let ret = unsafe { bindings::drm_dev_register(drm.as_raw(), flags as u64) };
>>>        if ret < 0 {
>>>            return Err(Error::from_errno(ret));
>>>        }
>>> 
>>> +        if let Some(ref info) = mode_config_info {
>>> +            // SAFETY: We just registered the device above
>>> +            unsafe { T::Kms::setup_fbdev(&drm, info) };
>>> +        }
>>> +
>>>        Ok(Self(drm))
>>>    }
>>> 
>>>    /// Same as [`Registration::new`}, but transfers ownership of the [`Registration`] to `Devres`.
>>> -    pub fn new_foreign_owned(drm: ARef<drm::device::Device<T>>, flags: usize) -> Result {
>>> -        let reg = Registration::<T>::new(drm.clone(), flags)?;
>>> +    pub fn new_foreign_owned(dev: &device::Device, data: T::Data, flags: usize) -> Result {
>>> +        let reg = Registration::<T>::new(dev, data, flags)?;
>>> 
>>> -        Devres::new_foreign_owned(drm.as_ref(), reg, GFP_KERNEL)
>>> +        Devres::new_foreign_owned(dev, reg, GFP_KERNEL)
>>>    }
>>> 
>>>    /// Returns a reference to the `Device` instance for this registration.
>>> @@ -195,5 +224,11 @@ fn drop(&mut self) {
>>>        // SAFETY: Safe by the invariant of `ARef<drm::device::Device<T>>`. The existance of this
>>>        // `Registration` also guarantees the this `drm::device::Device` is actually registered.
>>>        unsafe { bindings::drm_dev_unregister(self.0.as_raw()) };
>>> +
>>> +        if drm::device::Device::<T>::has_kms() {
>>> +            // SAFETY: We just checked above that KMS was setup for this device, so this is safe to
>>> +            // call
>>> +            unsafe { bindings::drm_atomic_helper_shutdown(self.0.as_raw()) }
>>> +        }
>>>    }
>>> }
>>> diff --git a/rust/kernel/drm/kms.rs b/rust/kernel/drm/kms.rs
>>> new file mode 100644
>>> index 0000000000000..d3558a5eccc54
>>> --- /dev/null
>>> +++ b/rust/kernel/drm/kms.rs
>>> @@ -0,0 +1,230 @@
>>> +// SPDX-License-Identifier: GPL-2.0 OR MIT
>>> +
>>> +//! KMS driver abstractions for rust.
>>> +
>>> +pub mod fbdev;
>>> +
>>> +use crate::{
>>> +    drm::{
>>> +        drv::Driver,
>>> +        device::Device
>>> +    },
>>> +    device,
>>> +    prelude::*,
>>> +    types::*,
>>> +    error::to_result,
>>> +    private::Sealed,
>>> +};
>>> +use core::{
>>> +    ops::Deref,
>>> +    ptr::{self, NonNull},
>>> +    mem::{self, ManuallyDrop},
>>> +    marker::PhantomData,
>>> +};
>>> +use bindings;
>>> +
>>> +/// The C vtable for a [`Device`].
>>> +///
>>> +/// This is created internally by DRM.
>>> +pub(crate) struct ModeConfigOps {
>>> +    pub(crate) kms_vtable: bindings::drm_mode_config_funcs,
>>> +    pub(crate) kms_helper_vtable: bindings::drm_mode_config_helper_funcs
>>> +}
>>> +
>>> +/// A trait representing a type that can be used for setting up KMS, or a stub.
>>> +///
>>> +/// For drivers which don't have KMS support, the methods provided by this trait may be stubs. It is
>>> +/// implemented internally by DRM.
>>> +pub trait KmsImpl: private::KmsImpl {}
>>> +
>>> +pub(crate) mod private {
>>> +    use super::*;
>>> +
>>> +    /// Private callback implemented internally by DRM for setting up KMS on a device, or stubbing
>>> +    /// the KMS setup for devices which don't have KMS support can just use [`PhantomData`].
>> 
>> This comment is a bit hard to parse. Also, I wonder if we can find a better solution than just using
>> PhantomData.
> 
> FWIW I previously had a dedicated type to this, NoKms, but I figured since
> this seems like a rather new pattern I haven't seen in any other rust bindings
> (granted, I don't think I looked too hard) it might be less confusing to have
> all associated types like this follow the same pattern and use the same type
> to indicate there's no support.


Even this `NoKms` type seems a bit better than just PhantomData, although ideally
others could chime in with a better solution.

IMHO, the problem is that you’re adding extra semantics on top of a fairly well-known type.


[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux