diff --git a/rust/kernel/drm/kms/crtc.rs b/rust/kernel/drm/kms/crtc.rs index 14e0822db73fd1f7110b03a91d65746d20471695..815c6fae398efad0f811ba58813e204c5ffd3036 100644 --- a/rust/kernel/drm/kms/crtc.rs +++ b/rust/kernel/drm/kms/crtc.rs @@ -120,6 +120,13 @@ pub trait DriverCrtc: Send + Sync + Sized { /// [`PhantomData<Self>`]. type VblankImpl: VblankImpl<Crtc = Self>; + /// The optional data type for this driver's ephemeral mutable state + /// + /// This can be used for storing private driver data that persists between atomic commits. It + /// can only be mutated and accessed from the context of an atomic commit. Drivers which don't + /// care about this can just pass `()` here + type EphemeralState: DriverCrtcEphemeralState<Crtc = Self>; + /// The constructor for creating a [`Crtc`] using this [`DriverCrtc`] implementation. /// /// Drivers may use this to instantiate their [`DriverCrtc`] object. @@ -199,6 +206,35 @@ pub trait DriverCrtc: Send + Sync + Sized { } } +/// A trait implemented by a driver's private ephemeral modesetting state +/// +/// Drivers which don't need this should simply use [`NoCrtcEphemeralState`] instead of implementing +/// this +pub trait DriverCrtcEphemeralState { + /// The type of the parent [`DriverCrtc`] + type Crtc: DriverCrtc; + + /// Create a new instance of [`Self`] for this CRTC + fn new( + dev: &Device<<Self::Crtc as DriverCrtc>::Driver>, + args: &<Self::Crtc as DriverCrtc>::Args, + ) -> Result<Self> where Self: Sized; +} + +impl<T: DriverCrtc> DriverCrtcEphemeralState for PhantomData<T> { + type Crtc = T; + + fn new( + dev: &Device<<Self::Crtc as DriverCrtc>::Driver>, + args: &<Self::Crtc as DriverCrtc>::Args, + ) -> Result<Self> + where + Self: Sized + { + Ok(PhantomData) + } +} + /// The generated C vtable for a [`DriverCrtc`]. /// /// This type is created internally by DRM. @@ -228,6 +264,8 @@ pub struct Crtc<T: DriverCrtc> { /// The driver's private inner data #[pin] inner: T, + /// The driver's optional private ephemeral modeset state + ephemeral_state: UnsafeCell<T::EphemeralState>, #[pin] _p: PhantomPinned, } @@ -292,6 +330,10 @@ impl<T: DriverCrtc> Crtc<T> { dev.has_vblanks.set(true) } + // try_pin_init!() has a move closure, so get our pointers beforehand so we don't upset the + // borrow checker + let dev_ptr = dev.as_raw(); + let this = Box::try_pin_init( try_pin_init!(Self { crtc: Opaque::new(bindings::drm_crtc { @@ -299,6 +341,9 @@ impl<T: DriverCrtc> Crtc<T> { ..Default::default() }), inner <- T::new(dev, &args), + ephemeral_state: UnsafeCell::new( + <T::EphemeralState as DriverCrtcEphemeralState>::new(dev, &args)? + ), _p: PhantomPinned, }), GFP_KERNEL @@ -306,7 +351,7 @@ impl<T: DriverCrtc> Crtc<T> { to_result(unsafe { bindings::drm_crtc_init_with_planes( - dev.as_raw(), + dev_ptr, this.as_raw(), primary.as_raw(), cursor.map_or(null_mut(), |c| c.as_raw()),