Received: by 2002:ab2:6857:0:b0:1ef:ffd0:ce49 with SMTP id l23csp1439868lqp; Fri, 22 Mar 2024 15:18:44 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCUPcbgGiK1DwHjhtmmnUXZA38D1rXu8R6B/V0Q1oamNymdFZZAmKGyu1jX9gdasu9+LqPORG8qb0GUxaj2L/DY9zJAQorxtQIwkpPeXig== X-Google-Smtp-Source: AGHT+IGhDktjtXYaiTul5l2VbLSUQLyVbgFAIDvC18t1m9K4JCLWUjdBrKhaRgpoFTAby7uogBg6 X-Received: by 2002:a17:902:d488:b0:1de:fa9b:7f99 with SMTP id c8-20020a170902d48800b001defa9b7f99mr1139580plg.10.1711145923755; Fri, 22 Mar 2024 15:18:43 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1711145923; cv=pass; d=google.com; s=arc-20160816; b=X9n3DPRj3LSjkd6XIfWMOreSMCTA/38BK05lSRyvsE8VViZbxQga81iQ5UVbooJvwR 9VW1XmeSdVayOL1JhgphNpSUBRBuB4d58600PjwiDIChu1x30Ue33zsOUDQC/PQ2o2R8 HBZBatYYVrumQNgX8cwl3TvuTjE5KJYI5dis9+FTmKCSVJf3gqGEF+KDVag/5N3ZiEbt VyyqbtqXw+GhCcQE1T4dym43/8ldbU46J9EZIjAUDQR/NBGfNetCuBd0mITiCHU2zMi+ 6Q0CObySAniqWK9w9Sfmuezl326VMwbSpTLyrnVE3+mviTkJb/sB3/5gBwQNdkiuYljl qpZw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=g7GQ3fPHiJFc4OvZ+/3sVtCU8QWBFnwHWiIOmeagJEg=; fh=4l7GCQ8aVUCRBVZlOStt4fJQO48yshMeHzBLePkbXHo=; b=TmFdL6qIsUIvLc6ORtNCb6/qASBqgmVFngdD/tCwl3dgTiRC6gOqfSVMmN5SWj1aH1 bMr6Dabp9pPcRXxWNSQdr0JlYbQEAZV0xEL74vcpinYYSqM5sypk4nAZyNChg565nVet sXgbJ3qBH/VkwZiERQMyutjR8ngjR/kigRDxMUCadG/jejeKAk1MWV0NnrVYU8adiu/L vZcQMK9ehLOXGFXXx8hcLXhHKQL/9wIUObnKLhDjvMGyhPr/JN+PB8rpDTm0Yctf//jW gto040sR+LRgJ7xT+/nnjJ+FHMhPraOwsu5uIlG+ydOmdKTNv7e67kOcXcwKLPNTPKx/ WoGQ==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b="Wd0GLu/A"; arc=pass (i=1 spf=pass spfdomain=redhat.com dkim=pass dkdomain=redhat.com dmarc=pass fromdomain=redhat.com); spf=pass (google.com: domain of linux-kernel+bounces-112064-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.48.161 as permitted sender) smtp.mailfrom="linux-kernel+bounces-112064-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from sy.mirrors.kernel.org (sy.mirrors.kernel.org. [147.75.48.161]) by mx.google.com with ESMTPS id m1-20020a170902db0100b001e087fe28c8si395930plx.484.2024.03.22.15.18.43 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 Mar 2024 15:18:43 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel+bounces-112064-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.48.161 as permitted sender) client-ip=147.75.48.161; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b="Wd0GLu/A"; arc=pass (i=1 spf=pass spfdomain=redhat.com dkim=pass dkdomain=redhat.com dmarc=pass fromdomain=redhat.com); spf=pass (google.com: domain of linux-kernel+bounces-112064-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.48.161 as permitted sender) smtp.mailfrom="linux-kernel+bounces-112064-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sy.mirrors.kernel.org (Postfix) with ESMTPS id ABF22B2283E for ; Fri, 22 Mar 2024 22:15:57 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 69FB981ADC; Fri, 22 Mar 2024 22:15:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Wd0GLu/A" Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 219DD81753 for ; Fri, 22 Mar 2024 22:15:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711145737; cv=none; b=P7UBgDYwVVINr95siY5qmQDuwdDyfp9fg1iurmjV501k644wXbrpMlIhExL4IThX/YVkrjIgNUQfxBBo5C+e+wkmnxy+vsZc7Lq93IDHN45LFVHwdUJOKXU1gLOueSBDoxpi3Xr6O7qRNZps7/h/7fPae+sU5YzmAa9ASsxZeVU= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711145737; c=relaxed/simple; bh=c2AVaRtzw9AmK9VQiEAlKmtPt8C+9TBdsnJ0BLPlDts=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=G+Ho5QuZljho/IkfNQmegavo47fXNhf2hxn4qDviGOF6ZKm6jIomQcaKR2LwhGUHhbFwEwl4NQ9Qm1f21jU//ti9rRi5q932alBIzWLBuuh/JGrX/ZylmOooBXi21RbJZ1VWOvQqZjIHr4BXVhoVvhDaM3rQ7TacCdvUvFE/2EU= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=Wd0GLu/A; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1711145734; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=g7GQ3fPHiJFc4OvZ+/3sVtCU8QWBFnwHWiIOmeagJEg=; b=Wd0GLu/ApdrF2sXYC1nYkEWH+32onPFYL1XXoQh4QAHQOll0r5WpQ9Glrf+5XyJp56DHT5 7VsAloUSwe6O0j0lgg11PE0+vgPgwYYgG/emPJSjvAon9siugqTW3dNVnil0yMGuxy+Om6 20H8jeC/I5GnEKTWBD2y6xXw/3nsCjY= Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-176-g5IWk4NQOAK7b87urW2VgQ-1; Fri, 22 Mar 2024 18:15:27 -0400 X-MC-Unique: g5IWk4NQOAK7b87urW2VgQ-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id BD0CD3C02454; Fri, 22 Mar 2024 22:15:26 +0000 (UTC) Received: from emerald.redhat.com (unknown [10.22.8.130]) by smtp.corp.redhat.com (Postfix) with ESMTP id 28DA81074E; Fri, 22 Mar 2024 22:15:26 +0000 (UTC) From: Lyude Paul To: dri-devel@lists.freedesktop.org Cc: Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Daniel Vetter , Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , linux-kernel@vger.kernel.org (open list), rust-for-linux@vger.kernel.org (open list:RUST) Subject: [PATCH 3/4] rust/drm/kms: Extract PlaneState into IntoPlaneState Date: Fri, 22 Mar 2024 18:03:35 -0400 Message-ID: <20240322221305.1403600-4-lyude@redhat.com> In-Reply-To: <20240322221305.1403600-1-lyude@redhat.com> References: <20240322221305.1403600-1-lyude@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.5 DRM actually has a number of helpers that wrap drm_plane_state, one of which is actually needed by VKMS - drm_shadow_plane_state. So, let's start preparing to write bindings for this by first extracting PlaneState into the IntoPlaneState trait - which all DRM structs which wrap drm_plane_state will implement. This is basically the same idea as the GEM ops - but for plane states. Signed-off-by: Lyude Paul --- drivers/gpu/drm/rvkms/plane.rs | 2 +- rust/kernel/drm/kms/plane.rs | 165 ++++++++++++++++++++------------- 2 files changed, 103 insertions(+), 64 deletions(-) diff --git a/drivers/gpu/drm/rvkms/plane.rs b/drivers/gpu/drm/rvkms/plane.rs index 54c4bbda64d8e..d98a1f7bf79e2 100644 --- a/drivers/gpu/drm/rvkms/plane.rs +++ b/drivers/gpu/drm/rvkms/plane.rs @@ -20,7 +20,7 @@ pub(crate) struct DriverPlane { impl plane::DriverPlane for DriverPlane { type Initializer = impl PinInit; - type State = RvkmsPlaneState; + type State = PlaneState; type Driver = RvkmsDriver; diff --git a/rust/kernel/drm/kms/plane.rs b/rust/kernel/drm/kms/plane.rs index 78c8e370b997c..73c285445be63 100644 --- a/rust/kernel/drm/kms/plane.rs +++ b/rust/kernel/drm/kms/plane.rs @@ -13,6 +13,7 @@ sync::{Arc, ArcBorrow}, init::InPlaceInit, offset_of, + private::Sealed, }; use core::{ cell::UnsafeCell, @@ -62,14 +63,16 @@ pub trait DriverPlane: Send + Sync + Sized { /// The parent driver implementation type Driver: KmsDriver; - /// The type for this driver's drm_plane_state implementation - type State: DriverPlaneState; + /// The full type for this driver's drm_plane_state implementation. Drivers which don't need + /// special DRM helpers for their plane states may just use `PlaneState` here, where `T` is + /// their private state struct which implements `DriverPlaneState` + type State: IntoPlaneState; /// Create a new plane for this driver fn new(device: &Device, args: Self::Args) -> Self::Initializer; } -impl crate::private::Sealed for Plane {} +impl Sealed for Plane {} impl ModeObject for Plane { type Driver = T::Driver; @@ -177,6 +180,70 @@ pub(super) fn raw_mut_ptr(&self) -> *mut bindings::drm_plane { unsafe { drop(Box::from_raw(plane as *mut Plane)) }; } +/// Operations implemented by any base atomic plane state. These are implemented by DRM to provide +/// wrappers around the generic atomic plane state, along with various plane state helpers. +/// +/// SAFETY: Incorrect implementation of these methods will result in UB, users should take care to +/// read through the documentation of each method - especially the provided methods. +pub unsafe trait IntoPlaneState: Default + Sealed { + /// Consume the box for this plane state without dropping its contents, and return a reference + /// to it's base plane state to hand off to DRM + /// + /// Implementors must override this if their data layout does not start with + /// `bindings::drm_plane_state`. + fn into_raw(self: Box) -> *mut bindings::drm_plane_state { + // Our data layout starts with drm_plane_state + Box::into_raw(self).cast() + } + + /// Reconstruct the box for this plate state for deallocation + /// + /// Implementors must override this if their data layout does not start with + /// `bindings::drm_plane_state`. + unsafe fn from_raw(ptr: *mut bindings::drm_plane_state) -> Box { + // SAFETY: Users of this default promise their data layout starts with drm_plane_state + unsafe { Box::from_raw(ptr.cast()) } + } + + /// Get a mutable reference to the raw `bindings::drm_plane_state` contained within this type + /// that we can pass to DRM + fn as_raw_mut(&mut self) -> &mut bindings::drm_plane_state { + // SAFETY: Users of this default promise their data layout starts with drm_plane_state + unsafe { mem::transmute(self) } + } + + /// Get an immutable reference to this type from the given raw `bindings::drm_plane_state` + /// pointer + /// + /// Implementors must override this if their data layout does not start with + /// `bindings::drm_plane_state`. + /// + /// SAFETY: The caller guarantees `ptr` is contained within a valid instance of `Self` + unsafe fn ref_from_raw<'a>(ptr: *const bindings::drm_plane_state) -> &'a Self { + // SAFETY: Users of this default promise their data layout starts with drm_plane_state + unsafe { &*ptr.cast() } + } + + /// Get a mutable reference to this type from the given raw `bindings::drm_plane_state` pointer + /// + /// SAFETY: The caller guarantees `ptr` is contained within a valid instance of `Self` + unsafe fn ref_from_raw_mut<'a>(ptr: *mut bindings::drm_plane_state) -> &'a mut Self { + // SAFETY: Users of this default promise their data layout starts with drm_plane_state + unsafe { &mut (*ptr.cast()) } + } + + // Allocate a "duplicated" copy of this state, which usually involves calling DRM's helper + // function for this plane state type + fn __duplicate_state(&self, plane: *mut bindings::drm_plane) -> Result>; + + // Call DRM's destroy helper for this type of plane state. Note this only cleans up the base DRM + // state struct and does not de-allocate its `Box`. + fn __destroy_state(state: *mut bindings::drm_plane_state); + + // Call DRM's reset helper for this type of plane state. + fn __reset_state(plane: *mut bindings::drm_plane, state: *mut bindings::drm_plane_state); +} + #[derive(Default)] #[repr(C)] pub struct PlaneState { @@ -190,46 +257,35 @@ pub trait DriverPlaneState: Clone + Default + Sized { type Plane: DriverPlane; } -impl PlaneState { - /// Consume this struct without dropping it, and return a pointer to its base `drm_plane_state` - /// which can be handed off to DRM. - fn into_raw(self: Box) -> *mut bindings::drm_plane_state { - let this = Box::into_raw(self); +impl Sealed for PlaneState {} - unsafe { &mut (*this).state } - } +// SAFETY: Our data layout starts with drm_plane_state +unsafe impl IntoPlaneState for PlaneState { + fn __duplicate_state(&self, plane: *mut bindings::drm_plane) -> Result> { + let mut new: Box = Box::try_init(try_init!(Self { + state: bindings::drm_plane_state { ..Default::default() }, + inner: self.inner.clone() + }))?; - /// Consume a raw pointer and recover the original `Box>` - /// - /// SAFETY: Callers must ensure that ptr contains a valid instance of `PlaneState` - unsafe fn from_raw(ptr: *mut bindings::drm_plane_state) -> Box { - unsafe { Box::from_raw(ptr as *mut _) } - } + // SAFETY: FFI call with no special requirements + unsafe { bindings::__drm_atomic_helper_plane_duplicate_state(plane, new.as_raw_mut()) }; - /// Obtain a reference back to the `PlaneState` - /// - /// SAFETY: Callers must ensure that ptr contains a valid instance of `PlaneState`. - unsafe fn as_ref<'a>(ptr: *const bindings::drm_plane_state) -> &'a Self { - unsafe { &*(ptr as *const _) } + Ok(new) } - /// Obtain a mutable reference back to the PlaneState - /// - /// SAFETY: Callers must ensure that ptr contains a valid instance of `PlaneState`, and that - /// no other references to this `PlaneState` exist for the lifetime of this reference - unsafe fn as_mut_ref<'a>(ptr: *mut bindings::drm_plane_state) -> &'a mut Self { - unsafe { &mut *(ptr as *mut _) } + fn __destroy_state(state: *mut bindings::drm_plane_state) { + // SAFETY: This would not be called without a plane state to destroy + unsafe { bindings::__drm_atomic_helper_plane_destroy_state(state) }; } - /// Obtain a mutable pointer to the base plane state, for use in FFI calls - unsafe fn as_mut_ptr(&mut self) -> *mut bindings::drm_plane_state { - &mut self.state + fn __reset_state(plane: *mut bindings::drm_plane, state: *mut bindings::drm_plane_state) { + unsafe { bindings::__drm_atomic_helper_plane_reset(plane, state) } } } unsafe impl Zeroable for bindings::drm_plane_state { } -unsafe extern "C" fn atomic_duplicate_state_callback( +unsafe extern "C" fn atomic_duplicate_state_callback( plane: *mut bindings::drm_plane ) -> *mut bindings::drm_plane_state { @@ -240,55 +296,38 @@ unsafe impl Zeroable for bindings::drm_plane_state { } return null_mut(); } - // SAFETY: We just verified that `state` is non-null, and we're guaranteed by our bindings that - // `state` is of type `PlaneState`. - let state = unsafe { PlaneState::::as_ref(state) }; - - let mut new: Result>> = Box::try_init(try_init!(PlaneState:: { - state: bindings::drm_plane_state { ..Default::default() }, - inner: state.inner.clone() - })); - - if let Ok(mut new) = new { - // SAFETY: Just a lil' FFI call, nothing special here - unsafe { bindings::__drm_atomic_helper_plane_duplicate_state(plane, new.as_mut_ptr()) }; - - new.into_raw() - } else { - null_mut() - } + // SAFETY: We just checked that the state is non-null, and we're guaranteed this operation is + // safe via type invariance + unsafe { T::ref_from_raw(state) }.__duplicate_state(plane).map_or(null_mut(), T::into_raw) } -unsafe extern "C" fn atomic_destroy_state_callback( +unsafe extern "C" fn atomic_destroy_state_callback( _plane: *mut bindings::drm_plane, - plane_state: *mut bindings::drm_plane_state + state: *mut bindings::drm_plane_state ) { - // SAFETY: This callback wouldn't be called unless there a plane state to destroy - unsafe { bindings::__drm_atomic_helper_plane_destroy_state(plane_state) }; + T::__destroy_state(state); - // SAFETY: We're guaranteed by type invariants that plane_state is of type PlaneState, and - // since this is the destructor callback for DRM - we're guaranteed to hold the only remaining - // reference to this state - unsafe { drop(PlaneState::::from_raw(plane_state)) }; + // SAFETY: We're guaranteed by type invariance that state of type T, and __destroy_state() does + // not perform any deallocations + drop(unsafe { T::from_raw(state) }); } -unsafe extern "C" fn plane_reset_callback( +unsafe extern "C" fn plane_reset_callback( plane: *mut bindings::drm_plane, ) { - // SAFETY: The only entrypoint to this function lives in `plane` so it must be valid, and + // SAFETY: The only entrypoint to this function lives in `plane` so it must be valid let state = unsafe { (*plane).state }; if !state.is_null() { - // SAFETY: We're guaranteed by type invariance that this plane's state is of type - // DriverPlaneState + // SAFETY: We're guaranteed by type invariance that this planes state is of type T unsafe { atomic_destroy_state_callback::(plane, state) } } // Unfortunately, this is the best we can do at the moment as this FFI callback was mistakenly // presumed to be infallible :( - let new = Box::try_new(PlaneState::::default()).expect("Blame the API, sorry!"); + let new = Box::try_new(T::default()).expect("Blame the API, sorry!"); - // SAFETY: DRM takes ownership of the state from here and assigns it to the plane - unsafe { bindings::__drm_atomic_helper_plane_reset(plane, new.into_raw()) }; + // DRM takes ownership of the state from here, resets it, and then assigns it to the plane + T::__reset_state(plane, new.into_raw()); } #[derive(Copy, Clone, Debug, PartialEq, Eq)] -- 2.43.0