From patchwork Mon May 20 17:20:48 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 13668497 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 19554C25B79 for ; Mon, 20 May 2024 17:21:24 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 2F18310E4D9; Mon, 20 May 2024 17:21:23 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="PpfLqUu/"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by gabe.freedesktop.org (Postfix) with ESMTPS id 0477D10E4D9 for ; Mon, 20 May 2024 17:21:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1716225679; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/yDyFo5QAsShU2UXMrrT4xAbvXT6OnwazMreT8PcbZM=; b=PpfLqUu/pZ2J2Ad4Wy1aQVOXwBpYSbCcpJ2st25dWFzoIZc7mf54DJYlE6mVI5ZdYXZXbm kNij2GeOivMVsGW0Z+X0sULCDh5a42bqpPahIICSQGMbOzQ9Q1iQS/sQUzA7Frfafc8D3p +dxSf4Ge6i5I3t4XnICThTNNwgKPjmc= Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-156-7FjW0C09OgKUjhxcyJnu1Q-1; Mon, 20 May 2024 13:21:18 -0400 X-MC-Unique: 7FjW0C09OgKUjhxcyJnu1Q-1 Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-41feab38d16so47801115e9.3 for ; Mon, 20 May 2024 10:21:18 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1716225676; x=1716830476; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=/yDyFo5QAsShU2UXMrrT4xAbvXT6OnwazMreT8PcbZM=; b=NEGUkUXFaqL9vGGQE8g1QrVNZpg6PcBTFRqFyCi6gSZKKaGsgISyaktavjyPWNB+78 ASjoUQeH6y2w8455pBwCpo1vpm6aSy+ApePAKI/1Q5tqSpYcldzlc/zNEmRfC+Jvd0Kh 52bch+BIzaQGdRz7KxVONHuWDX1NdRR7umktZ/oKzurLCTHYPf5ew3QpJc0+Iyok8vcW ZaTkuM8KpBFr/JRWP8neVd46dKr5rsNwWU2XF1q6BcDkhHa94p/wmNWOH4QXdrLTAGme ACA3T9pI+Z8X3hGVHf0ncFOBM7PdEa02gIkkaLyoCcjk3YMgUguxpeC0PgcjqyKv2cvi 0cSA== X-Forwarded-Encrypted: i=1; AJvYcCVlbx63EEcG/5gJdp2/2in3S5bryrrbed0FHjpHrqdRdDZrsd3Osw9d4r1uvwIWGdTrQeGSiRJmdzec4MGUDxnoJ/jZd1GUAov02Dqk7iBe X-Gm-Message-State: AOJu0YxPCgEDeFndcs4+KNpgAcO78QyC+DIi/Lk8CX1l6Npjx269MNWa g7U87tBnCcxABc+7dHX1SX6K7jElBI6nSPQnrEGO6Tz554HwT0hy4madcnQNM/mg6Tc2YRaTg2T DhEGyOqt85RinycB8nmtzbjkM2OQ0ViBGvsjy/XyAX+xMRUqlAzgDAL//+4DgL7Wfsw== X-Received: by 2002:a05:600c:4f42:b0:41b:a670:a9f1 with SMTP id 5b1f17b1804b1-41feaa2f409mr202751915e9.7.1716225675948; Mon, 20 May 2024 10:21:15 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHfuWyiq6rqJZ4UVuzu/rSymC+StzNm4hbcpBUY0IqZsQhhXqZBG4ZtoNnNxU/lFlphDCd8rw== X-Received: by 2002:a05:600c:4f42:b0:41b:a670:a9f1 with SMTP id 5b1f17b1804b1-41feaa2f409mr202751525e9.7.1716225675040; Mon, 20 May 2024 10:21:15 -0700 (PDT) Received: from cassiopeiae.. ([2a02:810d:4b3f:ee94:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-41f88110f3esm466021575e9.29.2024.05.20.10.21.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 20 May 2024 10:21:14 -0700 (PDT) From: Danilo Krummrich To: maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, ojeda@kernel.org, alex.gaynor@gmail.com, wedsonaf@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@samsung.com, aliceryhl@google.com, fujita.tomonori@gmail.com, lina@asahilina.net, pstanner@redhat.com, ajanulgu@redhat.com, lyude@redhat.com, gregkh@linuxfoundation.org Cc: rust-for-linux@vger.kernel.org, dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, Danilo Krummrich Subject: [RFC PATCH 1/8] rust: drm: ioctl: Add DRM ioctl abstraction Date: Mon, 20 May 2024 19:20:48 +0200 Message-ID: <20240520172059.181256-2-dakr@redhat.com> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240520172059.181256-1-dakr@redhat.com> References: <20240520172059.181256-1-dakr@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Asahi Lina DRM drivers need to be able to declare which driver-specific ioctls they support. Add an abstraction implementing the required types and a helper macro to generate the ioctl definition inside the DRM driver. Note that this macro is not usable until further bits of the abstraction are in place (but it will not fail to compile on its own, if not called). Signed-off-by: Asahi Lina Signed-off-by: Danilo Krummrich --- rust/bindings/bindings_helper.h | 1 + rust/kernel/drm/ioctl.rs | 153 ++++++++++++++++++++++++++++++++ rust/kernel/drm/mod.rs | 5 ++ rust/kernel/lib.rs | 2 + rust/uapi/uapi_helper.h | 1 + 5 files changed, 162 insertions(+) create mode 100644 rust/kernel/drm/ioctl.rs create mode 100644 rust/kernel/drm/mod.rs diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 32221de16e57..14188034285a 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -6,6 +6,7 @@ * Sorted alphabetically. */ +#include #include #include #include diff --git a/rust/kernel/drm/ioctl.rs b/rust/kernel/drm/ioctl.rs new file mode 100644 index 000000000000..79d720e9d18e --- /dev/null +++ b/rust/kernel/drm/ioctl.rs @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +#![allow(non_snake_case)] + +//! DRM IOCTL definitions. +//! +//! C header: [`include/linux/drm/drm_ioctl.h`](../../../../include/linux/drm/drm_ioctl.h) + +use crate::ioctl; + +const BASE: u32 = uapi::DRM_IOCTL_BASE as u32; + +/// Construct a DRM ioctl number with no argument. +#[inline(always)] +pub const fn IO(nr: u32) -> u32 { + ioctl::_IO(BASE, nr) +} + +/// Construct a DRM ioctl number with a read-only argument. +#[inline(always)] +pub const fn IOR(nr: u32) -> u32 { + ioctl::_IOR::(BASE, nr) +} + +/// Construct a DRM ioctl number with a write-only argument. +#[inline(always)] +pub const fn IOW(nr: u32) -> u32 { + ioctl::_IOW::(BASE, nr) +} + +/// Construct a DRM ioctl number with a read-write argument. +#[inline(always)] +pub const fn IOWR(nr: u32) -> u32 { + ioctl::_IOWR::(BASE, nr) +} + +/// Descriptor type for DRM ioctls. Use the `declare_drm_ioctls!{}` macro to construct them. +pub type DrmIoctlDescriptor = bindings::drm_ioctl_desc; + +/// This is for ioctl which are used for rendering, and require that the file descriptor is either +/// for a render node, or if it’s a legacy/primary node, then it must be authenticated. +pub const AUTH: u32 = bindings::drm_ioctl_flags_DRM_AUTH; + +/// This must be set for any ioctl which can change the modeset or display state. Userspace must +/// call the ioctl through a primary node, while it is the active master. +/// +/// Note that read-only modeset ioctl can also be called by unauthenticated clients, or when a +/// master is not the currently active one. +pub const MASTER: u32 = bindings::drm_ioctl_flags_DRM_MASTER; + +/// Anything that could potentially wreak a master file descriptor needs to have this flag set. +/// +/// Current that’s only for the SETMASTER and DROPMASTER ioctl, which e.g. logind can call to +/// force a non-behaving master (display compositor) into compliance. +/// +/// This is equivalent to callers with the SYSADMIN capability. +pub const ROOT_ONLY: u32 = bindings::drm_ioctl_flags_DRM_ROOT_ONLY; + +/// This is used for all ioctl needed for rendering only, for drivers which support render nodes. +/// This should be all new render drivers, and hence it should be always set for any ioctl with +/// `AUTH` set. Note though that read-only query ioctl might have this set, but have not set +/// DRM_AUTH because they do not require authentication. +pub const RENDER_ALLOW: u32 = bindings::drm_ioctl_flags_DRM_RENDER_ALLOW; + +/// Internal structures used by the [`declare_drm_ioctls!{}`] macro. Do not use directly. +#[doc(hidden)] +pub mod internal { + pub use bindings::drm_device; + pub use bindings::drm_file; + pub use bindings::drm_ioctl_desc; +} + +/// Declare the DRM ioctls for a driver. +/// +/// Each entry in the list should have the form: +/// +/// `(ioctl_number, argument_type, flags, user_callback),` +/// +/// `argument_type` is the type name within the `bindings` crate. +/// `user_callback` should have the following prototype: +/// +/// ``` +/// fn foo(device: &kernel::drm::device::Device, +/// data: &mut bindings::argument_type, +/// file: &kernel::drm::file::File, +/// ) +/// ``` +/// where `Self` is the drm::drv::Driver implementation these ioctls are being declared within. +/// +/// # Examples +/// +/// ``` +/// kernel::declare_drm_ioctls! { +/// (FOO_GET_PARAM, drm_foo_get_param, ioctl::RENDER_ALLOW, my_get_param_handler), +/// } +/// ``` +/// +#[macro_export] +macro_rules! declare_drm_ioctls { + ( $(($cmd:ident, $struct:ident, $flags:expr, $func:expr)),* $(,)? ) => { + const IOCTLS: &'static [$crate::drm::ioctl::DrmIoctlDescriptor] = { + use $crate::uapi::*; + const _:() = { + let i: u32 = $crate::uapi::DRM_COMMAND_BASE; + // Assert that all the IOCTLs are in the right order and there are no gaps, + // and that the sizeof of the specified type is correct. + $( + let cmd: u32 = $crate::macros::concat_idents!(DRM_IOCTL_, $cmd); + ::core::assert!(i == $crate::ioctl::_IOC_NR(cmd)); + ::core::assert!(core::mem::size_of::<$crate::uapi::$struct>() == + $crate::ioctl::_IOC_SIZE(cmd)); + let i: u32 = i + 1; + )* + }; + + let ioctls = &[$( + $crate::drm::ioctl::internal::drm_ioctl_desc { + cmd: $crate::macros::concat_idents!(DRM_IOCTL_, $cmd) as u32, + func: { + #[allow(non_snake_case)] + unsafe extern "C" fn $cmd( + raw_dev: *mut $crate::drm::ioctl::internal::drm_device, + raw_data: *mut ::core::ffi::c_void, + raw_file_priv: *mut $crate::drm::ioctl::internal::drm_file, + ) -> core::ffi::c_int { + // SAFETY: The DRM core ensures the device lives while callbacks are + // being called. + // + // FIXME: Currently there is nothing enforcing that the types of the + // dev/file match the current driver these ioctls are being declared + // for, and it's not clear how to enforce this within the type system. + let dev = $crate::drm::device::Device::borrow(raw_dev); + // SAFETY: This is just the ioctl argument, which hopefully has the + // right type (we've done our best checking the size). + let data = unsafe { &mut *(raw_data as *mut $crate::uapi::$struct) }; + // SAFETY: This is just the DRM file structure + let file = unsafe { $crate::drm::file::File::from_raw(raw_file_priv) }; + + match $func(dev, data, &file) { + Err(e) => e.to_errno(), + Ok(i) => i.try_into() + .unwrap_or($crate::error::code::ERANGE.to_errno()), + } + } + Some($cmd) + }, + flags: $flags, + name: $crate::c_str!(::core::stringify!($cmd)).as_char_ptr(), + } + ),*]; + ioctls + }; + }; +} diff --git a/rust/kernel/drm/mod.rs b/rust/kernel/drm/mod.rs new file mode 100644 index 000000000000..9ec6d7cbcaf3 --- /dev/null +++ b/rust/kernel/drm/mod.rs @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT + +//! DRM subsystem abstractions. + +pub mod ioctl; diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 15730deca822..cb0dd3d76729 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -32,6 +32,8 @@ pub mod device; pub mod devres; pub mod driver; +#[cfg(CONFIG_DRM = "y")] +pub mod drm; pub mod error; pub mod init; pub mod ioctl; diff --git a/rust/uapi/uapi_helper.h b/rust/uapi/uapi_helper.h index 08f5e9334c9e..ed42a456da2e 100644 --- a/rust/uapi/uapi_helper.h +++ b/rust/uapi/uapi_helper.h @@ -7,5 +7,6 @@ */ #include +#include #include #include From patchwork Mon May 20 17:20:49 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 13668498 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 9E2BBC04FFE for ; Mon, 20 May 2024 17:21:32 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id C373C10E5CE; Mon, 20 May 2024 17:21:31 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="hGp8eIZB"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by gabe.freedesktop.org (Postfix) with ESMTPS id 8E61810E524 for ; Mon, 20 May 2024 17:21:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1716225683; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=kKS6qhSk55pRZeAXjj0u08eGqfwnnqmzVscIpFm2Jrw=; b=hGp8eIZBxdmOFZ4oNKZKyzAbyWdxX6g/gDIPh0xZAEbDSyJoNwTdOdxcYjYxEJkdIJMzTZ myKbWhFy6DqZLm2wsLdqwILiW4Bs1Igl48nz1UvxJwdlkwlgPgAChKUg+2WofDEsCTzliF ysO8W+tPxnb6E3syhb7H9vpW4tQCeow= Received: from mail-lj1-f198.google.com (mail-lj1-f198.google.com [209.85.208.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-266-HBKo7QVxNym9hCwUUkPQwQ-1; Mon, 20 May 2024 13:21:22 -0400 X-MC-Unique: HBKo7QVxNym9hCwUUkPQwQ-1 Received: by mail-lj1-f198.google.com with SMTP id 38308e7fff4ca-2e2ec0c8807so85737901fa.1 for ; Mon, 20 May 2024 10:21:21 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1716225680; x=1716830480; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=kKS6qhSk55pRZeAXjj0u08eGqfwnnqmzVscIpFm2Jrw=; b=CaFUrJFnNvdocECQC48hqFjPw0whI5lnU8F4ESPlwBYbGwWemKS3Xvb8uj/nShoIpf FzuxLJEig+6rtpStKLgpJfShZLUAfUu/hn48NzGPruvGwegVIuKThAYCuK2TNP2ad7bg lz5Wbbg9H4DfgO1Cy6OqHYYnan00TIX/LiPfZVgq4gAtBl255p6eDsbJ33Lj29UuG+Ye twXxetUKnVN55FRIZ1F5V2Cbg2mCrcOPcS8qTWVySJIu+iDn5FFPEj7LH5Nd7NLKpkSH nxaSKiDaU7l/rnRm+om0k+KOuik9WCWaEIylBqqaR5GPDdcpS+zrJ01PTAqsDpg4mxCE JZbQ== X-Forwarded-Encrypted: i=1; AJvYcCVwFXWQbPUdfe1UKA6OaCWXpTCzU5aWGGOQEfztHMcwzleYu5o+X/XrO88wCU/erJ0CXDzViEwNkwCd+0q8nl+oIDh/vEHV6NLKMDEHVoJS X-Gm-Message-State: AOJu0Yx2cBcjG+fYcbgFoSyiMpCRjf2XGUpDrI0BOlqY2tMiENA+cOTe pZCjVgTSjER1l0n49YxVybWM8DqUuBohMQTlArH2Uv3OJ+ThyCiq6lDgR7RcTUzYgqkzXjNw9Lo HAR9FJcC1MJNAX4qRzz0Ebw0sGn+j8YYFLYbvGtR2nTL2q2hrB7zbawzXVpYudTHq5w== X-Received: by 2002:a2e:8794:0:b0:2d8:34ec:54e6 with SMTP id 38308e7fff4ca-2e5204ccd8fmr175153711fa.33.1716225680738; Mon, 20 May 2024 10:21:20 -0700 (PDT) X-Google-Smtp-Source: AGHT+IErF7q9FqAV3RyM+4sRTgS+83yJJodVaf9ir9uNQdpIiZzoq5t+t64rFKzgExXy9aAhHq+sdw== X-Received: by 2002:a2e:8794:0:b0:2d8:34ec:54e6 with SMTP id 38308e7fff4ca-2e5204ccd8fmr175153391fa.33.1716225680279; Mon, 20 May 2024 10:21:20 -0700 (PDT) Received: from cassiopeiae.. ([2a02:810d:4b3f:ee94:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-42014c21260sm315868065e9.3.2024.05.20.10.21.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 20 May 2024 10:21:18 -0700 (PDT) From: Danilo Krummrich To: maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, ojeda@kernel.org, alex.gaynor@gmail.com, wedsonaf@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@samsung.com, aliceryhl@google.com, fujita.tomonori@gmail.com, lina@asahilina.net, pstanner@redhat.com, ajanulgu@redhat.com, lyude@redhat.com, gregkh@linuxfoundation.org Cc: rust-for-linux@vger.kernel.org, dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, Danilo Krummrich Subject: [RFC PATCH 2/8] rust: Add a Sealed trait Date: Mon, 20 May 2024 19:20:49 +0200 Message-ID: <20240520172059.181256-3-dakr@redhat.com> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240520172059.181256-1-dakr@redhat.com> References: <20240520172059.181256-1-dakr@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Asahi Lina Some traits exposed by the kernel crate may not be intended to be implemented by downstream modules. Add a Sealed trait to allow avoiding this using the sealed trait pattern. Signed-off-by: Asahi Lina Signed-off-by: Danilo Krummrich --- rust/kernel/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index cb0dd3d76729..6415968ee3b8 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -65,6 +65,11 @@ #[doc(hidden)] pub use build_error::build_error; +pub(crate) mod private { + #[allow(unreachable_pub)] + pub trait Sealed {} +} + /// Prefix to appear before log messages printed from within the `kernel` crate. const __LOG_PREFIX: &[u8] = b"rust_kernel\0"; From patchwork Mon May 20 17:20:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 13668499 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id B9EB7C25B79 for ; Mon, 20 May 2024 17:21:40 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id A9D7010E786; Mon, 20 May 2024 17:21:39 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="PegofuR4"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by gabe.freedesktop.org (Postfix) with ESMTPS id 63B2C10E692 for ; Mon, 20 May 2024 17:21:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1716225691; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Zj0pa4Lx8ydM+bjFlhdM8zfotScwh9i9XwFO8f4TNqY=; b=PegofuR4cIs1KAzxt9mGV2pjr9GDJ0gEv7E263d7srxJ7zYG8fsxnx6mEf/dyGObVmqjW3 u8fFSDLE7gen2FO4X9BuJ0Ap1r5CsDDdwb0uMaHci2ff04RdnhP94aIBY7x7CIpLfaChpS CJvSu0tBHsvcMnLO9XBfUcl83gyjO00= Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-645-xA-2LALBNTGPzj9LZenSeg-1; Mon, 20 May 2024 13:21:30 -0400 X-MC-Unique: xA-2LALBNTGPzj9LZenSeg-1 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-41fc5c5cc95so51921515e9.0 for ; Mon, 20 May 2024 10:21:30 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1716225685; x=1716830485; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Zj0pa4Lx8ydM+bjFlhdM8zfotScwh9i9XwFO8f4TNqY=; b=xIipRrEtaqrTBx0cqE5uYVgnV3QztEBLon63tIbeep555N6wciBFZuQ2JL7aVMuhfZ o36r00RRwLaWZDQc3oVB8yOrXaLhFqNVJzNEp2n3uYt1WBoUAQK6mNBG1+U9Nxp0+R3l 5ymJKBZGKZQqYF61MZ4uT8EUI/tUgMtPzAaH0jIXiD7ZMZ+fTqd3uAqdaTE9OQQ6eliP S8ahzqXyxwcRTpzPARqVdNW0of9MHYJ0uIkFu7Wz/Qw3VzWcU56+NIacXvYs9+QLON0r ECMzKuNPf4eTP4/COjo/QazF/Q4Wqc9sTnCkR6ObDljcVQ4OwaTwrpq5HPRrw6bEIesZ Obgg== X-Forwarded-Encrypted: i=1; AJvYcCXc5oOqN2Lh4D/MTMAVPHdNFCfJzZCS3YDL6FMYdM91erfKRlKqGEemhl+Gk+PvBKodKeew1Kf7KLjJrkLa9f1d8k7wZNeyhFYPSqv4zYVT X-Gm-Message-State: AOJu0YyYnA0AsONqFebGcyUAO/2/nNKQE/Nadvv8N9e0KnisvMhzFtSM jbOk5zRwzQZIBO6oR0dj/roGLJ3KO8g8N1+7372teSGl+zg+NDln7tOzKt/za8MC6M96jF99fYq SCkAqPfA4EgfxZdbLa3EBRMA2AdSmQ9Z5E3qJFW1NYFNcqaMrhznocQrM/TgNN/v9rg== X-Received: by 2002:a05:600c:3108:b0:417:e00c:fdb8 with SMTP id 5b1f17b1804b1-41fea931b3dmr258312495e9.1.1716225684885; Mon, 20 May 2024 10:21:24 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFQFJ6w0yVF4BBNea+uNBBOsskLn0+4sjQAPGgBcBBWKGQlFyAaYRxflG8HwCyGxfYA/pwqlQ== X-Received: by 2002:a05:600c:3108:b0:417:e00c:fdb8 with SMTP id 5b1f17b1804b1-41fea931b3dmr258312175e9.1.1716225684310; Mon, 20 May 2024 10:21:24 -0700 (PDT) Received: from cassiopeiae.. ([2a02:810d:4b3f:ee94:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-42010b1076dsm345952935e9.41.2024.05.20.10.21.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 20 May 2024 10:21:23 -0700 (PDT) From: Danilo Krummrich To: maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, ojeda@kernel.org, alex.gaynor@gmail.com, wedsonaf@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@samsung.com, aliceryhl@google.com, fujita.tomonori@gmail.com, lina@asahilina.net, pstanner@redhat.com, ajanulgu@redhat.com, lyude@redhat.com, gregkh@linuxfoundation.org Cc: rust-for-linux@vger.kernel.org, dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, Danilo Krummrich Subject: [RFC PATCH 3/8] rust: drm: Add Device and Driver abstractions Date: Mon, 20 May 2024 19:20:50 +0200 Message-ID: <20240520172059.181256-4-dakr@redhat.com> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240520172059.181256-1-dakr@redhat.com> References: <20240520172059.181256-1-dakr@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Asahi Lina Add abstractions for DRM drivers and devices. These go together in one commit since both are fairly tightly coupled types. A few things have been stubbed out, to be implemented as further bits of the DRM subsystem are introduced. Signed-off-by: Asahi Lina Co-developed-by: Danilo Krummrich Signed-off-by: Danilo Krummrich --- rust/bindings/bindings_helper.h | 2 + rust/kernel/drm/device.rs | 87 +++++++++ rust/kernel/drm/drv.rs | 318 ++++++++++++++++++++++++++++++++ rust/kernel/drm/mod.rs | 2 + 4 files changed, 409 insertions(+) create mode 100644 rust/kernel/drm/device.rs create mode 100644 rust/kernel/drm/drv.rs diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 14188034285a..831fbfe03a47 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -6,6 +6,8 @@ * Sorted alphabetically. */ +#include +#include #include #include #include diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs new file mode 100644 index 000000000000..f72bab8dd42d --- /dev/null +++ b/rust/kernel/drm/device.rs @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT + +//! DRM device. +//! +//! C header: [`include/linux/drm/drm_device.h`](../../../../include/linux/drm/drm_device.h) + +use crate::{ + bindings, device, drm, + error::code::*, + error::from_err_ptr, + error::Result, + types::{ARef, AlwaysRefCounted, ForeignOwnable, Opaque}, +}; +use alloc::boxed::Box; +use core::{ffi::c_void, marker::PhantomData, pin::Pin, ptr::NonNull}; + +/// A typed DRM device with a specific driver. The device is always reference-counted. +#[repr(transparent)] +pub struct Device(Opaque, PhantomData); + +impl Device { + pub(crate) fn new( + dev: &device::Device, + vtable: &Pin>, + ) -> Result> { + let raw_drm = unsafe { bindings::drm_dev_alloc(&**vtable, dev.as_raw()) }; + let raw_drm = NonNull::new(from_err_ptr(raw_drm)? as *mut _).ok_or(ENOMEM)?; + + // SAFETY: The reference count is one, and now we take ownership of that reference as a + // drm::device::Device. + Ok(unsafe { ARef::from_raw(raw_drm) }) + } + + pub(crate) fn as_raw(&self) -> *mut bindings::drm_device { + self.0.get() + } + + // Not intended to be called externally, except via declare_drm_ioctls!() + #[doc(hidden)] + pub unsafe fn borrow<'a>(raw: *const bindings::drm_device) -> &'a Self { + unsafe { &*(raw as *const Self) } + } + + pub(crate) fn raw_data(&self) -> *const c_void { + // SAFETY: `self` is guaranteed to hold a valid `bindings::drm_device` pointer. + unsafe { *self.as_raw() }.dev_private + } + + // SAFETY: Must be called only once after device creation. + pub(crate) unsafe fn set_raw_data(&self, ptr: *const c_void) { + // SAFETY: Safe as by the safety precondition. + unsafe { &mut *self.as_raw() }.dev_private = ptr as _; + } + + /// Returns a borrowed reference to the user data associated with this Device. + pub fn data(&self) -> Option<::Borrowed<'_>> { + let dev_private = self.raw_data(); + + if dev_private.is_null() { + None + } else { + // SAFETY: `dev_private` is NULL before the DRM device is registered; after the DRM + // device has been registered dev_private is guaranteed to be valid. + Some(unsafe { T::Data::borrow(dev_private) }) + } + } +} + +// SAFETY: DRM device objects are always reference counted and the get/put functions +// satisfy the requirements. +unsafe impl AlwaysRefCounted for Device { + fn inc_ref(&self) { + unsafe { bindings::drm_dev_get(&self.as_raw() as *const _ as *mut _) }; + } + + unsafe fn dec_ref(obj: NonNull) { + // SAFETY: The Device type has the same layout as drm_device, so we can just cast. + unsafe { bindings::drm_dev_put(obj.as_ptr() as *mut _) }; + } +} + +// SAFETY: `Device` only holds a pointer to a C device, which is safe to be used from any thread. +unsafe impl Send for Device {} + +// SAFETY: `Device` only holds a pointer to a C device, references to which are safe to be used +// from any thread. +unsafe impl Sync for Device {} diff --git a/rust/kernel/drm/drv.rs b/rust/kernel/drm/drv.rs new file mode 100644 index 000000000000..5dd8f3f8df7c --- /dev/null +++ b/rust/kernel/drm/drv.rs @@ -0,0 +1,318 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT + +//! DRM driver core. +//! +//! C header: [`include/linux/drm/drm_drv.h`](../../../../include/linux/drm/drm_drv.h) + +use crate::{ + alloc::flags::*, + bindings, device, drm, + error::code::*, + error::{Error, Result}, + prelude::*, + private::Sealed, + str::CStr, + types::{ARef, ForeignOwnable}, + ThisModule, +}; +use core::{ + marker::{PhantomData, PhantomPinned}, + pin::Pin, +}; +use macros::vtable; + +/// Driver use the GEM memory manager. This should be set for all modern drivers. +pub const FEAT_GEM: u32 = bindings::drm_driver_feature_DRIVER_GEM; +/// Driver supports mode setting interfaces (KMS). +pub const FEAT_MODESET: u32 = bindings::drm_driver_feature_DRIVER_MODESET; +/// Driver supports dedicated render nodes. +pub const FEAT_RENDER: u32 = bindings::drm_driver_feature_DRIVER_RENDER; +/// Driver supports the full atomic modesetting userspace API. +/// +/// Drivers which only use atomic internally, but do not support the full userspace API (e.g. not +/// all properties converted to atomic, or multi-plane updates are not guaranteed to be tear-free) +/// should not set this flag. +pub const FEAT_ATOMIC: u32 = bindings::drm_driver_feature_DRIVER_ATOMIC; +/// Driver supports DRM sync objects for explicit synchronization of command submission. +pub const FEAT_SYNCOBJ: u32 = bindings::drm_driver_feature_DRIVER_SYNCOBJ; +/// Driver supports the timeline flavor of DRM sync objects for explicit synchronization of command +/// submission. +pub const FEAT_SYNCOBJ_TIMELINE: u32 = bindings::drm_driver_feature_DRIVER_SYNCOBJ_TIMELINE; + +/// Information data for a DRM Driver. +pub struct DriverInfo { + /// Driver major version. + pub major: i32, + /// Driver minor version. + pub minor: i32, + /// Driver patchlevel version. + pub patchlevel: i32, + /// Driver name. + pub name: &'static CStr, + /// Driver description. + pub desc: &'static CStr, + /// Driver date. + pub date: &'static CStr, +} + +/// Internal memory management operation set, normally created by memory managers (e.g. GEM). +/// +/// See `kernel::drm::gem` and `kernel::drm::gem::shmem`. +pub struct AllocOps { + pub(crate) gem_create_object: Option< + unsafe extern "C" fn( + dev: *mut bindings::drm_device, + size: usize, + ) -> *mut bindings::drm_gem_object, + >, + pub(crate) prime_handle_to_fd: Option< + unsafe extern "C" fn( + dev: *mut bindings::drm_device, + file_priv: *mut bindings::drm_file, + handle: u32, + flags: u32, + prime_fd: *mut core::ffi::c_int, + ) -> core::ffi::c_int, + >, + pub(crate) prime_fd_to_handle: Option< + unsafe extern "C" fn( + dev: *mut bindings::drm_device, + file_priv: *mut bindings::drm_file, + prime_fd: core::ffi::c_int, + handle: *mut u32, + ) -> core::ffi::c_int, + >, + pub(crate) gem_prime_import: Option< + unsafe extern "C" fn( + dev: *mut bindings::drm_device, + dma_buf: *mut bindings::dma_buf, + ) -> *mut bindings::drm_gem_object, + >, + pub(crate) gem_prime_import_sg_table: Option< + unsafe extern "C" fn( + dev: *mut bindings::drm_device, + attach: *mut bindings::dma_buf_attachment, + sgt: *mut bindings::sg_table, + ) -> *mut bindings::drm_gem_object, + >, + pub(crate) dumb_create: Option< + unsafe extern "C" fn( + file_priv: *mut bindings::drm_file, + dev: *mut bindings::drm_device, + args: *mut bindings::drm_mode_create_dumb, + ) -> core::ffi::c_int, + >, + pub(crate) dumb_map_offset: Option< + unsafe extern "C" fn( + file_priv: *mut bindings::drm_file, + dev: *mut bindings::drm_device, + handle: u32, + offset: *mut u64, + ) -> core::ffi::c_int, + >, +} + +/// Trait for memory manager implementations. Implemented internally. +pub trait AllocImpl: Sealed { + /// The C callback operations for this memory manager. + const ALLOC_OPS: AllocOps; +} + +/// A DRM driver implementation. +#[vtable] +pub trait Driver { + /// Context data associated with the DRM driver + /// + /// Determines the type of the context data passed to each of the methods of the trait. + type Data: ForeignOwnable + Sync + Send; + + /// The type used to manage memory for this driver. + /// + /// Should be either `drm::gem::Object` or `drm::gem::shmem::Object`. + type Object: AllocImpl; + + /// Driver metadata + const INFO: DriverInfo; + + /// Feature flags + const FEATURES: u32; + + /// IOCTL list. See `kernel::drm::ioctl::declare_drm_ioctls!{}`. + const IOCTLS: &'static [drm::ioctl::DrmIoctlDescriptor]; +} + +/// A registration of a DRM device +/// +/// # Invariants: +/// +/// drm is always a valid pointer to an allocated drm_device +pub struct Registration { + drm: ARef>, + registered: bool, + fops: bindings::file_operations, + vtable: Pin>, + _p: PhantomData, + _pin: PhantomPinned, +} + +#[cfg(CONFIG_DRM_LEGACY)] +macro_rules! drm_legacy_fields { + ( $($field:ident: $val:expr),* $(,)? ) => { + bindings::drm_driver { + $( $field: $val ),*, + firstopen: None, + preclose: None, + dma_ioctl: None, + dma_quiescent: None, + context_dtor: None, + irq_handler: None, + irq_preinstall: None, + irq_postinstall: None, + irq_uninstall: None, + get_vblank_counter: None, + enable_vblank: None, + disable_vblank: None, + dev_priv_size: 0, + } + } +} + +#[cfg(not(CONFIG_DRM_LEGACY))] +macro_rules! drm_legacy_fields { + ( $($field:ident: $val:expr),* $(,)? ) => { + bindings::drm_driver { + $( $field: $val ),* + } + } +} + +/// Registers a DRM device with the rest of the kernel. +/// +/// It automatically picks up THIS_MODULE. +#[allow(clippy::crate_in_macro_def)] +#[macro_export] +macro_rules! drm_device_register { + ($reg:expr, $data:expr, $flags:expr $(,)?) => {{ + $crate::drm::drv::Registration::register($reg, $data, $flags, &crate::THIS_MODULE) + }}; +} + +impl Registration { + const VTABLE: bindings::drm_driver = drm_legacy_fields! { + load: None, + open: None, // TODO: File abstraction + postclose: None, // TODO: File abstraction + lastclose: None, + unload: None, + release: None, + master_set: None, + master_drop: None, + debugfs_init: None, + gem_create_object: T::Object::ALLOC_OPS.gem_create_object, + prime_handle_to_fd: T::Object::ALLOC_OPS.prime_handle_to_fd, + prime_fd_to_handle: T::Object::ALLOC_OPS.prime_fd_to_handle, + gem_prime_import: T::Object::ALLOC_OPS.gem_prime_import, + gem_prime_import_sg_table: T::Object::ALLOC_OPS.gem_prime_import_sg_table, + dumb_create: T::Object::ALLOC_OPS.dumb_create, + dumb_map_offset: T::Object::ALLOC_OPS.dumb_map_offset, + show_fdinfo: None, + + major: T::INFO.major, + minor: T::INFO.minor, + patchlevel: T::INFO.patchlevel, + name: T::INFO.name.as_char_ptr() as *mut _, + desc: T::INFO.desc.as_char_ptr() as *mut _, + date: T::INFO.date.as_char_ptr() as *mut _, + + driver_features: T::FEATURES, + ioctls: T::IOCTLS.as_ptr(), + num_ioctls: T::IOCTLS.len() as i32, + fops: core::ptr::null_mut(), + }; + + /// Creates a new [`Registration`] but does not register it yet. + /// + /// It is allowed to move. + pub fn new(parent: &device::Device) -> Result { + let vtable = Pin::new(Box::new(Self::VTABLE, GFP_KERNEL)?); + + Ok(Self { + drm: drm::device::Device::new(parent, &vtable)?, + registered: false, + vtable, + fops: Default::default(), // TODO: GEM abstraction + _pin: PhantomPinned, + _p: PhantomData, + }) + } + + /// Registers a DRM device with the rest of the kernel. + /// + /// Users are encouraged to use the [`drm_device_register!()`] macro because it automatically + /// picks up the current module. + pub fn register( + self: Pin<&mut Self>, + data: T::Data, + flags: usize, + module: &'static ThisModule, + ) -> Result { + if self.registered { + // Already registered. + return Err(EINVAL); + } + + // SAFETY: We never move out of `this`. + let this = unsafe { self.get_unchecked_mut() }; + let data_pointer = ::into_foreign(data); + + // SAFETY: This is the only code touching a device' private data pointer. + unsafe { this.drm.set_raw_data(data_pointer) }; + + this.fops.owner = module.0; + this.vtable.fops = &this.fops; + + // SAFETY: The device is now initialized and ready to be registered. + let ret = unsafe { bindings::drm_dev_register(this.drm.as_raw(), flags as u64) }; + if ret < 0 { + // SAFETY: `data_pointer` was returned by `into_foreign` above. + unsafe { T::Data::from_foreign(data_pointer) }; + return Err(Error::from_errno(ret)); + } + + this.registered = true; + Ok(()) + } + + /// Returns a reference to the `Device` instance for this registration. + pub fn device(&self) -> &drm::device::Device { + &self.drm + } +} + +// SAFETY: `Registration` doesn't offer any methods or access to fields when shared between threads +// or CPUs, so it is safe to share it. +unsafe impl Sync for Registration {} + +// SAFETY: Registration with and unregistration from the drm subsystem can happen from any thread. +// Additionally, `T::Data` (which is dropped during unregistration) is `Send`, so it is ok to move +// `Registration` to different threads. +#[allow(clippy::non_send_fields_in_send_ty)] +unsafe impl Send for Registration {} + +impl Drop for Registration { + /// Removes the registration from the kernel if it has completed successfully before. + fn drop(&mut self) { + if self.registered { + // Get a pointer to the data stored in device before destroying it. + // SAFETY: `drm` is valid per the type invariant + let data_pointer = self.drm.raw_data(); + + // SAFETY: Since `registered` is true, `self.drm` is both valid and registered. + unsafe { bindings::drm_dev_unregister(self.drm.as_raw()) }; + + // Free data as well. + // SAFETY: `data_pointer` was returned by `into_foreign` during registration. + unsafe { ::from_foreign(data_pointer) }; + } + } +} diff --git a/rust/kernel/drm/mod.rs b/rust/kernel/drm/mod.rs index 9ec6d7cbcaf3..69376b3c6db9 100644 --- a/rust/kernel/drm/mod.rs +++ b/rust/kernel/drm/mod.rs @@ -2,4 +2,6 @@ //! DRM subsystem abstractions. +pub mod device; +pub mod drv; pub mod ioctl; From patchwork Mon May 20 17:20:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 13668500 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 7EBF3C25B79 for ; Mon, 20 May 2024 17:21:48 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 7963E10E690; Mon, 20 May 2024 17:21:47 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="K6mB9qZO"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by gabe.freedesktop.org (Postfix) with ESMTPS id C48EC10E690 for ; Mon, 20 May 2024 17:21:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1716225696; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Ieml4cQgLdOB6f1Tq+rgmDncA9spVWDVEosV1A4OpmA=; b=K6mB9qZOMfBH/2IW4JXa8B3L5GXokZVOvkQfJE3xCIAE6yvKTgOpjNoyCeu9IRasl09r3M zCVK2ldGpFZuRwO8VScJ5rB8ybI/w+lX1vFsQCWcP+8LW3f4yfGnWi5cnaFodp0khCqMSv 9HqWwbYYC+1O1eEOvjgXsnCH1gEIeM8= Received: from mail-lj1-f199.google.com (mail-lj1-f199.google.com [209.85.208.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-665-ytS4i4duNt6qUACPbYwh_g-1; Mon, 20 May 2024 13:21:31 -0400 X-MC-Unique: ytS4i4duNt6qUACPbYwh_g-1 Received: by mail-lj1-f199.google.com with SMTP id 38308e7fff4ca-2e41bd70238so107412331fa.1 for ; Mon, 20 May 2024 10:21:31 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1716225690; x=1716830490; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Ieml4cQgLdOB6f1Tq+rgmDncA9spVWDVEosV1A4OpmA=; b=v7NIwfm0Wi8cioH3ljU4sQ/xwsGHvgC/IcijeISGGOT1ISt3cmxs+8Dg5owrI1UFjY 2LmMj0jFgmruR0V39gXFqkEMDvIdR4O7gV6/G0OoAr8cvbnmbF2KMRX+COPKPjQgvrrP TSuxgynLI1vNp+YvP/MjneT6jfJJu2jvsjhgbJhivSqCYv2477X3wURDw8vtXAM6xfMv crpgdAj+1bcOJSmYYuHdWWNHDnzB5+S6g06gQGGNXLGelBqNN+UpHq8uUCh80Rd9hn1D bbOjSz94beexqjsNLGZrJNCNQ92r7Kl3XDFjnrXZNZJfc/s2XYNlxEwnKuUbK++DxUCJ yShA== X-Forwarded-Encrypted: i=1; AJvYcCXQphjmpYvVEe8YQ25WU3qzA2rDg1uKdPjrUPYjfysE23wOpNxca4BHpnzmaSYvzmjM2+ctwVkEHyeAXzSOQvLxW2gPPPql/DfgV0aTvwWI X-Gm-Message-State: AOJu0YwPHzcC2Xjs1tNemqd6Jmm8RVJbXOkLJ45qlk7UQlD9lY9SbfUM 5gqId3YTaJrJ1n9vx384KtoOaUFy+78vNJzOeQsRBllefCRhlEZ+FebTPywcBbd/L5YL3STjVsF 9/Yh+sLBe9nQzcBJ/pO7O7jHolQfYvbGiFvs8BPI93K99AeNl6KtE9tCzCXgVGHf5ng== X-Received: by 2002:a2e:d09:0:b0:2e5:2eaf:b095 with SMTP id 38308e7fff4ca-2e52eafb1f7mr191077721fa.39.1716225690430; Mon, 20 May 2024 10:21:30 -0700 (PDT) X-Google-Smtp-Source: AGHT+IG7q/RlyHXDaQZTvhlrA4Lq5+xbLf2b2bh7WpMR1SX2pe4dg+hi0hk9TL8lOhimdQzmJb/j0w== X-Received: by 2002:a2e:d09:0:b0:2e5:2eaf:b095 with SMTP id 38308e7fff4ca-2e52eafb1f7mr191077521fa.39.1716225690105; Mon, 20 May 2024 10:21:30 -0700 (PDT) Received: from cassiopeiae.. ([2a02:810d:4b3f:ee94:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-42013bf1a5dsm326293055e9.30.2024.05.20.10.21.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 20 May 2024 10:21:27 -0700 (PDT) From: Danilo Krummrich To: maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, ojeda@kernel.org, alex.gaynor@gmail.com, wedsonaf@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@samsung.com, aliceryhl@google.com, fujita.tomonori@gmail.com, lina@asahilina.net, pstanner@redhat.com, ajanulgu@redhat.com, lyude@redhat.com, gregkh@linuxfoundation.org Cc: rust-for-linux@vger.kernel.org, dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, Danilo Krummrich Subject: [RFC PATCH 4/8] rust: drm: implement `AsRef` for DRM device Date: Mon, 20 May 2024 19:20:51 +0200 Message-ID: <20240520172059.181256-5-dakr@redhat.com> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240520172059.181256-1-dakr@redhat.com> References: <20240520172059.181256-1-dakr@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Implement `AsRef` for `drm::device::Device` such that `dev_*` print macros can be used conveniently. Signed-off-by: Danilo Krummrich --- rust/kernel/drm/device.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs index f72bab8dd42d..aef947893dab 100644 --- a/rust/kernel/drm/device.rs +++ b/rust/kernel/drm/device.rs @@ -79,6 +79,14 @@ unsafe fn dec_ref(obj: NonNull) { } } +impl AsRef for Device { + fn as_ref(&self) -> &device::Device { + // SAFETY: `bindings::drm_device::dev` is valid as long as the DRM device itself is valid, + // which is guaranteed by the type invariant. + unsafe { device::Device::as_ref((*self.as_raw()).dev) } + } +} + // SAFETY: `Device` only holds a pointer to a C device, which is safe to be used from any thread. unsafe impl Send for Device {} From patchwork Mon May 20 17:24:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 13668502 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 77497C04FFE for ; Mon, 20 May 2024 17:24:40 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 7A4E110E521; Mon, 20 May 2024 17:24:39 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="WttHfd28"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by gabe.freedesktop.org (Postfix) with ESMTPS id 1BDE510E3CE for ; Mon, 20 May 2024 17:24:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1716225873; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=5P5B+YM/OjD534xio0dIE5yHPWEzGnlxEKEl3OyNZXU=; b=WttHfd28pSJKc0k2PDRhK4G13cTpmaZ5jDlGzYaPa7DnD5w8cjh1YJcEG/XCVITkjrIn6I e1xiAHXj9IMfXdYo7TW9IYd3nHlgBnsgPYkDvJQEW8JJimZF6YeflqZ3iv6oc/KdcOD9nt 9tVjw20FcfAUByBKM7TeHIKaDADBNLg= Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-692-sWFyZRiHN9i3x92bEEF_3Q-1; Mon, 20 May 2024 13:24:30 -0400 X-MC-Unique: sWFyZRiHN9i3x92bEEF_3Q-1 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-41fda32e6c0so58631285e9.1 for ; Mon, 20 May 2024 10:24:30 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1716225869; x=1716830669; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=5P5B+YM/OjD534xio0dIE5yHPWEzGnlxEKEl3OyNZXU=; b=YKoi19nCmyjzqQ2q36C9EnVLpaVpUsfGTnwdcBej0wD06wo6e1IO6JXzNB0FFmyd8/ 2PjyZnCgYNJNWb5AQmbjBgGzFD7cdHCgOuIfmyUFjtzyNrwdSQrUqGYwihF7aje7yj9L 9wY0LZjEXR2GyjDKWBUFsKian0KE08BRe1z9LwvxuKtVphkdjbKGizdC+8Hd5mcOnKhK ZI+nC/+/Rrp1/ybVSemPatn1jdgZfDJYiHhdLMKf3C7qEmG1B/9pprPAL6cwEZ9ga/lb Xk0y3vSpDrnjttLfyL1/W19TZtFspxs5nEGV44AvQsUjxFAZbtF3DwdN4IVlQDqPpJ2C a+Vg== X-Forwarded-Encrypted: i=1; AJvYcCVKGUGuf/fkuaf5HBZHDAy2I+ammLR8/HbgjRgQVYwDyeEB+URkEeen0PJdZWkQvgInttGZc4u/8YXj/p3xL6ZoQOW0ia7VINyKDRh3igPy X-Gm-Message-State: AOJu0Yz4ILLoccpu8od0z/urvsV7OSzNtm4/u82aGrk+bOSPlq5QeHM2 iYIRYv6UDFmczZpv7jEOwT9tKLfKtjeMWYLkyRbv1H3sqKCaCdRYN85F9OtbtDbm2RS9idRNFBN kNpWWTyvoDjcKt7bEMnu3C/UWg80odI3sWtHav3+YESV/fxU6mwRxX+6ZpB2PU6AY9g== X-Received: by 2002:a05:600c:5101:b0:419:f4d6:463b with SMTP id 5b1f17b1804b1-420e1a301f8mr50659845e9.14.1716225869684; Mon, 20 May 2024 10:24:29 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFD66DGPVTzcTg/uKLOomBnDurKshNpwlQP73J4t42qg3pUB6/sWqwv/uKUk7zNux5Kw2TyTw== X-Received: by 2002:a05:600c:5101:b0:419:f4d6:463b with SMTP id 5b1f17b1804b1-420e1a301f8mr50659645e9.14.1716225869295; Mon, 20 May 2024 10:24:29 -0700 (PDT) Received: from cassiopeiae.. ([2a02:810d:4b3f:ee94:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-41fccce24cdsm431781365e9.15.2024.05.20.10.24.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 20 May 2024 10:24:28 -0700 (PDT) From: Danilo Krummrich To: maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, ojeda@kernel.org, alex.gaynor@gmail.com, wedsonaf@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@samsung.com, aliceryhl@google.com, fujita.tomonori@gmail.com, lina@asahilina.net, pstanner@redhat.com, ajanulgu@redhat.com, lyude@redhat.com, gregkh@linuxfoundation.org Cc: rust-for-linux@vger.kernel.org, dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, Danilo Krummrich Subject: [RFC PATCH 5/8] rust: drm: file: Add File abstraction Date: Mon, 20 May 2024 19:24:17 +0200 Message-ID: <20240520172422.181763-2-dakr@redhat.com> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240520172059.181256-1-dakr@redhat.com> References: <20240520172059.181256-1-dakr@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Asahi Lina A DRM File is the DRM counterpart to a kernel file structure, representing an open DRM file descriptor. Add a Rust abstraction to allow drivers to implement their own File types that implement the DriverFile trait. Signed-off-by: Asahi Lina Signed-off-by: Danilo Krummrich --- rust/bindings/bindings_helper.h | 1 + rust/kernel/drm/drv.rs | 7 +- rust/kernel/drm/file.rs | 113 ++++++++++++++++++++++++++++++++ rust/kernel/drm/mod.rs | 1 + 4 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 rust/kernel/drm/file.rs diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 831fbfe03a47..c591811ccb67 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff --git a/rust/kernel/drm/drv.rs b/rust/kernel/drm/drv.rs index 5dd8f3f8df7c..c5a63663ea21 100644 --- a/rust/kernel/drm/drv.rs +++ b/rust/kernel/drm/drv.rs @@ -131,6 +131,9 @@ pub trait Driver { /// Should be either `drm::gem::Object` or `drm::gem::shmem::Object`. type Object: AllocImpl; + /// The type used to represent a DRM File (client) + type File: drm::file::DriverFile; + /// Driver metadata const INFO: DriverInfo; @@ -200,8 +203,8 @@ macro_rules! drm_device_register { impl Registration { const VTABLE: bindings::drm_driver = drm_legacy_fields! { load: None, - open: None, // TODO: File abstraction - postclose: None, // TODO: File abstraction + open: Some(drm::file::open_callback::), + postclose: Some(drm::file::postclose_callback::), lastclose: None, unload: None, release: None, diff --git a/rust/kernel/drm/file.rs b/rust/kernel/drm/file.rs new file mode 100644 index 000000000000..a25b8c61f4ee --- /dev/null +++ b/rust/kernel/drm/file.rs @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT + +//! DRM File objects. +//! +//! C header: [`include/linux/drm/drm_file.h`](../../../../include/linux/drm/drm_file.h) + +use crate::{bindings, drm, error::Result}; +use alloc::boxed::Box; +use core::marker::PhantomData; +use core::pin::Pin; + +/// Trait that must be implemented by DRM drivers to represent a DRM File (a client instance). +pub trait DriverFile { + /// The parent `Driver` implementation for this `DriverFile`. + type Driver: drm::drv::Driver; + + /// Open a new file (called when a client opens the DRM device). + fn open(device: &drm::device::Device) -> Result>>; +} + +/// An open DRM File. +/// +/// # Invariants +/// `raw` is a valid pointer to a `drm_file` struct. +#[repr(transparent)] +pub struct File { + raw: *mut bindings::drm_file, + _p: PhantomData, +} + +pub(super) unsafe extern "C" fn open_callback( + raw_dev: *mut bindings::drm_device, + raw_file: *mut bindings::drm_file, +) -> core::ffi::c_int { + let drm = unsafe { drm::device::Device::borrow(raw_dev) }; + // SAFETY: This reference won't escape this function + let file = unsafe { &mut *raw_file }; + + let inner = match T::open(drm) { + Err(e) => { + return e.to_errno(); + } + Ok(i) => i, + }; + + // SAFETY: This pointer is treated as pinned, and the Drop guarantee is upheld below. + file.driver_priv = Box::into_raw(unsafe { Pin::into_inner_unchecked(inner) }) as *mut _; + + 0 +} + +pub(super) unsafe extern "C" fn postclose_callback( + _dev: *mut bindings::drm_device, + raw_file: *mut bindings::drm_file, +) { + // SAFETY: This reference won't escape this function + let file = unsafe { &*raw_file }; + + // Drop the DriverFile + unsafe { + let _ = Box::from_raw(file.driver_priv as *mut T); + }; +} + +impl File { + // Not intended to be called externally, except via declare_drm_ioctls!() + #[doc(hidden)] + pub unsafe fn from_raw(raw_file: *mut bindings::drm_file) -> File { + File { + raw: raw_file, + _p: PhantomData, + } + } + + #[allow(dead_code)] + /// Return the raw pointer to the underlying `drm_file`. + pub(super) fn raw(&self) -> *const bindings::drm_file { + self.raw + } + + /// Return an immutable reference to the raw `drm_file` structure. + pub(super) fn file(&self) -> &bindings::drm_file { + unsafe { &*self.raw } + } + + /// Return a pinned reference to the driver file structure. + pub fn inner(&self) -> Pin<&T> { + unsafe { Pin::new_unchecked(&*(self.file().driver_priv as *const T)) } + } +} + +impl crate::private::Sealed for File {} + +/// Generic trait to allow users that don't care about driver specifics to accept any File. +/// +/// # Safety +/// Must only be implemented for File and return the pointer, following the normal invariants +/// of that type. +pub unsafe trait GenericFile: crate::private::Sealed { + /// Returns the raw const pointer to the `struct drm_file` + fn raw(&self) -> *const bindings::drm_file; + /// Returns the raw mut pointer to the `struct drm_file` + fn raw_mut(&mut self) -> *mut bindings::drm_file; +} + +unsafe impl GenericFile for File { + fn raw(&self) -> *const bindings::drm_file { + self.raw + } + fn raw_mut(&mut self) -> *mut bindings::drm_file { + self.raw + } +} diff --git a/rust/kernel/drm/mod.rs b/rust/kernel/drm/mod.rs index 69376b3c6db9..a767942d0b52 100644 --- a/rust/kernel/drm/mod.rs +++ b/rust/kernel/drm/mod.rs @@ -4,4 +4,5 @@ pub mod device; pub mod drv; +pub mod file; pub mod ioctl; From patchwork Mon May 20 17:24:18 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 13668503 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 7FB8EC25B7A for ; Mon, 20 May 2024 17:24:48 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 27C8310E7F1; Mon, 20 May 2024 17:24:47 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="eXfoiDdp"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by gabe.freedesktop.org (Postfix) with ESMTPS id 7A6CA10E641 for ; Mon, 20 May 2024 17:24:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1716225878; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ovufvIK9IZx+hrKKO7MDM2OoyOD/S78ikWT4tAzv95c=; b=eXfoiDdpRNTFQMw9cLn7q9/q9ac0OkDhh5Wfhw3glu9uBfijBSJrv/hkBMqdIrNzuY6CN6 YMIupYH+u7miuo4uxcYkBIO3ngZ4diGKfVNKaVVOmeFXPJLOHMWf/D/qCuLIBpVmv+qr+C KF5igv/3IV9EFiJnpVsb6bRWmR+ChYw= Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-594-FmdTRoUzNUeB-gAeF_o8wg-1; Mon, 20 May 2024 13:24:35 -0400 X-MC-Unique: FmdTRoUzNUeB-gAeF_o8wg-1 Received: by mail-wr1-f71.google.com with SMTP id ffacd0b85a97d-34d7a7585d7so8142367f8f.2 for ; Mon, 20 May 2024 10:24:35 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1716225874; x=1716830674; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ovufvIK9IZx+hrKKO7MDM2OoyOD/S78ikWT4tAzv95c=; b=fP0FInZ+AlTLJ4LQD2yRrreKgDwkPkk0gFxlUImCWREBTcCSxytNknQLKwWijIiD7l +O9g+zGp+oterhsDyoRiKqjIYSsWBIZeCRfdqw/0R44ppped7YnQGkJVKlfKWMu8/7+c yp4DlkhGHojf7qITa/DYjZJHL22tD/XztNUZTrhWzk5uKQxNQxNTrEevjJVMa9+O+w6l YgEBOkekG9vmt4/bMlHWdpG2wtSygyWFexN91Z7+LNBLtH3jk7UQTVlkRVZiPi2Pi79i 7waUsqja1efTAqjDHApqOFMX02uVH9NcU8ZH8r7xARmfbLuua9AExwrWjt4lTuks3dk2 s2dQ== X-Forwarded-Encrypted: i=1; AJvYcCVDbCHR8eznqd6FUAf02WCqFYUyPKM9clCHq0WdhTSq4k4jVS9U9kpfIzqcomEmO9JlDtM2V3STPbWYa2G5PlAq7MkvaBO7+EgmDWyrCeX6 X-Gm-Message-State: AOJu0YwnzQvWVkZJ9u86/JYJRgpxpGx4eAeXSU6taQi6N20g50bFfMWm nw5eU6hxwxY3SbgPJeFheBlSoSate5jaqc4ROlqyswQHs3cmXAioKHSAVZkHg2mc7NuYomPSJTP Iuw5nmNliiC4bT3t8iUz+SMW79e/xK3jtAKK6z8Hhf5wbWKqHAQN2XuEfjw5dZGzgaQ== X-Received: by 2002:a5d:430e:0:b0:351:d383:6326 with SMTP id ffacd0b85a97d-351d383640dmr9408244f8f.67.1716225873845; Mon, 20 May 2024 10:24:33 -0700 (PDT) X-Google-Smtp-Source: AGHT+IE6z0/LH7xpF3HWbJIQ6p05YEcdlywBGhpMAXeprKTRKNzgKuAjm09QWVJ3pkWCAXpGUUsdPg== X-Received: by 2002:a5d:430e:0:b0:351:d383:6326 with SMTP id ffacd0b85a97d-351d383640dmr9408223f8f.67.1716225873267; Mon, 20 May 2024 10:24:33 -0700 (PDT) Received: from cassiopeiae.. ([2a02:810d:4b3f:ee94:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-354cc15c56dsm1531354f8f.80.2024.05.20.10.24.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 20 May 2024 10:24:32 -0700 (PDT) From: Danilo Krummrich To: maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, ojeda@kernel.org, alex.gaynor@gmail.com, wedsonaf@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@samsung.com, aliceryhl@google.com, fujita.tomonori@gmail.com, lina@asahilina.net, pstanner@redhat.com, ajanulgu@redhat.com, lyude@redhat.com, gregkh@linuxfoundation.org Cc: rust-for-linux@vger.kernel.org, dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, Danilo Krummrich Subject: [RFC PATCH 6/8] rust: drm: gem: Add GEM object abstraction Date: Mon, 20 May 2024 19:24:18 +0200 Message-ID: <20240520172422.181763-3-dakr@redhat.com> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240520172059.181256-1-dakr@redhat.com> References: <20240520172059.181256-1-dakr@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Asahi Lina The DRM GEM subsystem is the DRM memory management subsystem used by most modern drivers. Add a Rust abstraction to allow Rust DRM driver implementations to use it. Signed-off-by: Asahi Lina Co-developed-by: Danilo Krummrich Signed-off-by: Danilo Krummrich Reviewed-by: Daniel Almeida --- rust/bindings/bindings_helper.h | 1 + rust/helpers.c | 23 ++ rust/kernel/drm/drv.rs | 4 +- rust/kernel/drm/gem/mod.rs | 406 ++++++++++++++++++++++++++++++++ rust/kernel/drm/mod.rs | 1 + 5 files changed, 433 insertions(+), 2 deletions(-) create mode 100644 rust/kernel/drm/gem/mod.rs diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index c591811ccb67..b245db8d5a87 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/helpers.c b/rust/helpers.c index dc2405772b1a..30e86bf00337 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -20,6 +20,7 @@ * Sorted alphabetically. */ +#include #include #include #include @@ -302,6 +303,28 @@ u64 rust_helper_pci_resource_len(struct pci_dev *pdev, int barnr) return pci_resource_len(pdev, barnr); } +#ifdef CONFIG_DRM + +void rust_helper_drm_gem_object_get(struct drm_gem_object *obj) +{ + drm_gem_object_get(obj); +} +EXPORT_SYMBOL_GPL(rust_helper_drm_gem_object_get); + +void rust_helper_drm_gem_object_put(struct drm_gem_object *obj) +{ + drm_gem_object_put(obj); +} +EXPORT_SYMBOL_GPL(rust_helper_drm_gem_object_put); + +__u64 rust_helper_drm_vma_node_offset_addr(struct drm_vma_offset_node *node) +{ + return drm_vma_node_offset_addr(node); +} +EXPORT_SYMBOL_GPL(rust_helper_drm_vma_node_offset_addr); + +#endif + /* * `bindgen` binds the C `size_t` type as the Rust `usize` type, so we can * use it in contexts where Rust expects a `usize` like slice (array) indices. diff --git a/rust/kernel/drm/drv.rs b/rust/kernel/drm/drv.rs index c5a63663ea21..063b420f57e5 100644 --- a/rust/kernel/drm/drv.rs +++ b/rust/kernel/drm/drv.rs @@ -113,7 +113,7 @@ pub struct AllocOps { } /// Trait for memory manager implementations. Implemented internally. -pub trait AllocImpl: Sealed { +pub trait AllocImpl: Sealed + drm::gem::IntoGEMObject { /// The C callback operations for this memory manager. const ALLOC_OPS: AllocOps; } @@ -243,7 +243,7 @@ pub fn new(parent: &device::Device) -> Result { drm: drm::device::Device::new(parent, &vtable)?, registered: false, vtable, - fops: Default::default(), // TODO: GEM abstraction + fops: drm::gem::create_fops(), _pin: PhantomPinned, _p: PhantomData, }) diff --git a/rust/kernel/drm/gem/mod.rs b/rust/kernel/drm/gem/mod.rs new file mode 100644 index 000000000000..4cd85d5f1df8 --- /dev/null +++ b/rust/kernel/drm/gem/mod.rs @@ -0,0 +1,406 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT + +//! DRM GEM API +//! +//! C header: [`include/linux/drm/drm_gem.h`](../../../../include/linux/drm/drm_gem.h) + +use alloc::boxed::Box; + +use crate::{ + alloc::flags::*, + bindings, + drm::{device, drv, file}, + error::{to_result, Result}, + prelude::*, +}; +use core::{marker::PhantomPinned, mem, ops::Deref, ops::DerefMut}; + +/// GEM object functions, which must be implemented by drivers. +pub trait BaseDriverObject: Sync + Send + Sized { + /// Create a new driver data object for a GEM object of a given size. + fn new(dev: &device::Device, size: usize) -> impl PinInit; + + /// Open a new handle to an existing object, associated with a File. + fn open( + _obj: &<::Driver as drv::Driver>::Object, + _file: &file::File<<::Driver as drv::Driver>::File>, + ) -> Result { + Ok(()) + } + + /// Close a handle to an existing object, associated with a File. + fn close( + _obj: &<::Driver as drv::Driver>::Object, + _file: &file::File<<::Driver as drv::Driver>::File>, + ) { + } +} + +/// Trait that represents a GEM object subtype +pub trait IntoGEMObject: Sized + crate::private::Sealed { + /// Owning driver for this type + type Driver: drv::Driver; + + /// Returns a reference to the raw `drm_gem_object` structure, which must be valid as long as + /// this owning object is valid. + fn gem_obj(&self) -> &bindings::drm_gem_object; + + /// Converts a pointer to a `drm_gem_object` into a pointer to this type. + fn from_gem_obj(obj: *mut bindings::drm_gem_object) -> *mut Self; +} + +/// Trait which must be implemented by drivers using base GEM objects. +pub trait DriverObject: BaseDriverObject> { + /// Parent `Driver` for this object. + type Driver: drv::Driver; +} + +unsafe extern "C" fn free_callback(obj: *mut bindings::drm_gem_object) { + // SAFETY: All of our objects are Object. + let this = unsafe { crate::container_of!(obj, Object, obj) } as *mut Object; + + // SAFETY: The pointer we got has to be valid + unsafe { bindings::drm_gem_object_release(obj) }; + + // SAFETY: All of our objects are allocated via Box<>, and we're in the + // free callback which guarantees this object has zero remaining references, + // so we can drop it + unsafe { + let _ = Box::from_raw(this); + }; +} + +unsafe extern "C" fn open_callback, U: BaseObject>( + raw_obj: *mut bindings::drm_gem_object, + raw_file: *mut bindings::drm_file, +) -> core::ffi::c_int { + // SAFETY: The pointer we got has to be valid. + let file = unsafe { + file::File::<<::Driver as drv::Driver>::File>::from_raw(raw_file) + }; + let obj = + <<::Driver as drv::Driver>::Object as IntoGEMObject>::from_gem_obj( + raw_obj, + ); + + // SAFETY: from_gem_obj() returns a valid pointer as long as the type is + // correct and the raw_obj we got is valid. + match T::open(unsafe { &*obj }, &file) { + Err(e) => e.to_errno(), + Ok(()) => 0, + } +} + +unsafe extern "C" fn close_callback, U: BaseObject>( + raw_obj: *mut bindings::drm_gem_object, + raw_file: *mut bindings::drm_file, +) { + // SAFETY: The pointer we got has to be valid. + let file = unsafe { + file::File::<<::Driver as drv::Driver>::File>::from_raw(raw_file) + }; + let obj = + <<::Driver as drv::Driver>::Object as IntoGEMObject>::from_gem_obj( + raw_obj, + ); + + // SAFETY: from_gem_obj() returns a valid pointer as long as the type is + // correct and the raw_obj we got is valid. + T::close(unsafe { &*obj }, &file); +} + +impl IntoGEMObject for Object { + type Driver = T::Driver; + + fn gem_obj(&self) -> &bindings::drm_gem_object { + &self.obj + } + + fn from_gem_obj(obj: *mut bindings::drm_gem_object) -> *mut Object { + unsafe { crate::container_of!(obj, Object, obj) as *mut Object } + } +} + +/// Base operations shared by all GEM object classes +pub trait BaseObject: IntoGEMObject { + /// Returns the size of the object in bytes. + fn size(&self) -> usize { + self.gem_obj().size + } + + /// Creates a new reference to the object. + fn reference(&self) -> ObjectRef { + // SAFETY: Having a reference to an Object implies holding a GEM reference + unsafe { + bindings::drm_gem_object_get(self.gem_obj() as *const _ as *mut _); + } + ObjectRef { + ptr: self as *const _, + } + } + + /// Creates a new handle for the object associated with a given `File` + /// (or returns an existing one). + fn create_handle( + &self, + file: &file::File<<::Driver as drv::Driver>::File>, + ) -> Result { + let mut handle: u32 = 0; + // SAFETY: The arguments are all valid per the type invariants. + to_result(unsafe { + bindings::drm_gem_handle_create( + file.raw() as *mut _, + self.gem_obj() as *const _ as *mut _, + &mut handle, + ) + })?; + Ok(handle) + } + + /// Looks up an object by its handle for a given `File`. + fn lookup_handle( + file: &file::File<<::Driver as drv::Driver>::File>, + handle: u32, + ) -> Result> { + // SAFETY: The arguments are all valid per the type invariants. + let ptr = unsafe { bindings::drm_gem_object_lookup(file.raw() as *mut _, handle) }; + + if ptr.is_null() { + Err(ENOENT) + } else { + Ok(ObjectRef { + ptr: ptr as *const _, + }) + } + } + + /// Creates an mmap offset to map the object from userspace. + fn create_mmap_offset(&self) -> Result { + // SAFETY: The arguments are valid per the type invariant. + to_result(unsafe { + bindings::drm_gem_create_mmap_offset(self.gem_obj() as *const _ as *mut _) + })?; + Ok(unsafe { + bindings::drm_vma_node_offset_addr(&self.gem_obj().vma_node as *const _ as *mut _) + }) + } +} + +impl BaseObject for T {} + +/// A base GEM object. +#[repr(C)] +#[pin_data] +pub struct Object { + obj: bindings::drm_gem_object, + // The DRM core ensures the Device exists as long as its objects exist, so we don't need to + // manage the reference count here. + dev: *const bindings::drm_device, + #[pin] + inner: T, + #[pin] + _p: PhantomPinned, +} + +// SAFETY: This struct is safe to zero-initialize +unsafe impl init::Zeroable for bindings::drm_gem_object {} + +impl Object { + /// The size of this object's structure. + pub const SIZE: usize = mem::size_of::(); + + const OBJECT_FUNCS: bindings::drm_gem_object_funcs = bindings::drm_gem_object_funcs { + free: Some(free_callback::), + open: Some(open_callback::>), + close: Some(close_callback::>), + print_info: None, + export: None, + pin: None, + unpin: None, + get_sg_table: None, + vmap: None, + vunmap: None, + mmap: None, + status: None, + vm_ops: core::ptr::null_mut(), + evict: None, + rss: None, + }; + + /// Create a new GEM object. + pub fn new(dev: &device::Device, size: usize) -> Result>> { + let obj: Pin> = Box::pin_init( + try_pin_init!(Self { + // SAFETY: This struct is expected to be zero-initialized + obj: bindings::drm_gem_object { + funcs: &Self::OBJECT_FUNCS, + ..Default::default() + }, + inner <- T::new(dev, size), + // SAFETY: The drm subsystem guarantees that the drm_device will live as long as + // the GEM object lives, so we can conjure a reference out of thin air. + dev: dev.as_raw(), + _p: PhantomPinned + }), + GFP_KERNEL, + )?; + + to_result(unsafe { + bindings::drm_gem_object_init(dev.as_raw(), &obj.obj as *const _ as *mut _, size) + })?; + + // SAFETY: We never move out of self + let obj_ref = unsafe { + Pin::new_unchecked(UniqueObjectRef { + // SAFETY: We never move out of the Box + ptr: Box::leak(Pin::into_inner_unchecked(obj)), + _p: PhantomPinned, + }) + }; + + Ok(obj_ref) + } + + /// Returns the `Device` that owns this GEM object. + pub fn dev(&self) -> &device::Device { + // SAFETY: The drm subsystem guarantees that the drm_device will live as long as + // the GEM object lives, so we can just borrow from the raw pointer. + unsafe { device::Device::borrow(self.dev) } + } +} + +impl crate::private::Sealed for Object {} + +impl Deref for Object { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for Object { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl drv::AllocImpl for Object { + const ALLOC_OPS: drv::AllocOps = drv::AllocOps { + gem_create_object: None, + prime_handle_to_fd: None, + prime_fd_to_handle: None, + gem_prime_import: None, + gem_prime_import_sg_table: None, + dumb_create: None, + dumb_map_offset: None, + }; +} + +/// A reference-counted shared reference to a base GEM object. +pub struct ObjectRef { + // Invariant: the pointer is valid and initialized, and this ObjectRef owns a reference to it. + ptr: *const T, +} + +impl ObjectRef { + /// Downgrade this reference to a shared reference. + pub fn from_pinned_unique(pin: Pin>) -> Self { + // SAFETY: A (shared) `ObjectRef` doesn't need to be pinned, since it doesn't allow us to + // optain a mutable reference. + let uq = unsafe { Pin::into_inner_unchecked(pin) }; + + uq.into_ref() + } +} + +/// SAFETY: GEM object references are safe to share between threads. +unsafe impl Send for ObjectRef {} +unsafe impl Sync for ObjectRef {} + +impl Clone for ObjectRef { + fn clone(&self) -> Self { + self.reference() + } +} + +impl Drop for ObjectRef { + fn drop(&mut self) { + // SAFETY: Having an ObjectRef implies holding a GEM reference. + // The free callback will take care of deallocation. + unsafe { + bindings::drm_gem_object_put((*self.ptr).gem_obj() as *const _ as *mut _); + } + } +} + +impl Deref for ObjectRef { + type Target = T; + + fn deref(&self) -> &Self::Target { + // SAFETY: The pointer is valid per the invariant + unsafe { &*self.ptr } + } +} + +/// A unique reference to a base GEM object. +pub struct UniqueObjectRef { + // Invariant: the pointer is valid and initialized, and this ObjectRef owns the only reference + // to it. + ptr: *mut T, + _p: PhantomPinned, +} + +impl UniqueObjectRef { + /// Downgrade this reference to a shared reference. + pub fn into_ref(self) -> ObjectRef { + let ptr = self.ptr as *const _; + core::mem::forget(self); + + ObjectRef { ptr } + } +} + +impl Drop for UniqueObjectRef { + fn drop(&mut self) { + // SAFETY: Having a UniqueObjectRef implies holding a GEM + // reference. The free callback will take care of deallocation. + unsafe { + bindings::drm_gem_object_put((*self.ptr).gem_obj() as *const _ as *mut _); + } + } +} + +impl Deref for UniqueObjectRef { + type Target = T; + + fn deref(&self) -> &Self::Target { + // SAFETY: The pointer is valid per the invariant + unsafe { &*self.ptr } + } +} + +impl DerefMut for UniqueObjectRef { + fn deref_mut(&mut self) -> &mut Self::Target { + // SAFETY: The pointer is valid per the invariant + unsafe { &mut *self.ptr } + } +} + +pub(super) fn create_fops() -> bindings::file_operations { + bindings::file_operations { + owner: core::ptr::null_mut(), + open: Some(bindings::drm_open), + release: Some(bindings::drm_release), + unlocked_ioctl: Some(bindings::drm_ioctl), + #[cfg(CONFIG_COMPAT)] + compat_ioctl: Some(bindings::drm_compat_ioctl), + #[cfg(not(CONFIG_COMPAT))] + compat_ioctl: None, + poll: Some(bindings::drm_poll), + read: Some(bindings::drm_read), + llseek: Some(bindings::noop_llseek), + mmap: Some(bindings::drm_gem_mmap), + ..Default::default() + } +} diff --git a/rust/kernel/drm/mod.rs b/rust/kernel/drm/mod.rs index a767942d0b52..c44760a1332f 100644 --- a/rust/kernel/drm/mod.rs +++ b/rust/kernel/drm/mod.rs @@ -5,4 +5,5 @@ pub mod device; pub mod drv; pub mod file; +pub mod gem; pub mod ioctl; From patchwork Mon May 20 17:24:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 13668504 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2BA23C25B79 for ; Mon, 20 May 2024 17:24:50 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 0503010E68C; Mon, 20 May 2024 17:24:48 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="IXUGSiwk"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by gabe.freedesktop.org (Postfix) with ESMTPS id 4AF8210E412 for ; Mon, 20 May 2024 17:24:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1716225880; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=R1uvJC2Mq9SvQNSQvh/w7bRnmCNYpn+qhaqdYh6qMzY=; b=IXUGSiwkwa+ebeM9b2p9a0Fe6A8xMODDbHDDkSm/AgPKSfEfX+4qYjUneXTs9nUApU5Gfn 32X7TIb9iIeL/LPdqyGA79DOwLbfUbAux0+zxIIhSIyJnDQg4fuNjYrxiC0eVmMuQEGhFN tzhJpoHOQ5YxkRSoid81NF8LKm5+j4o= Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-610-tgWbKyw8MNesOeSax1Ys8w-1; Mon, 20 May 2024 13:24:39 -0400 X-MC-Unique: tgWbKyw8MNesOeSax1Ys8w-1 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-34d9deebf38so7323879f8f.1 for ; Mon, 20 May 2024 10:24:38 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1716225878; x=1716830678; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=R1uvJC2Mq9SvQNSQvh/w7bRnmCNYpn+qhaqdYh6qMzY=; b=AueX/KW+5Of47F7oTiEblrmu0+kBc7E6vHxU/enALwja/vROcDgyn7MYTIMOZA0TgR 1xzsX/ClBFN4TIKqCvVIi6OvX6A0f7+IosLh7ph3zsQDFSOfv3PZ67bChCV1MC8U3GYj 4Jhe0uIBw/ovKplvCDdE1dvB6avLndonlWNOWLez1vbV2XPNI7HHAwU7sNsWUMyg7ZTa DE6Zt1EvScpnuqIksuwofpap3o8aolrCahswoujf4SGAfbUjnXGzAm3nDNW+zXedisRo 7zTm7p57uV1l62K3OLZT2Ecs3MCr7Wa0C6/3QRvp/DSJfWqE1N7nFF52F+7Zz5Zv1Oes NCxQ== X-Forwarded-Encrypted: i=1; AJvYcCX4hpSqsFdb9KNtsd/L0SnSdVfnGBjAxqizDdh0CjTWRIPE60WOrlv3ME2HEhST8aysIQ8hOGuhnrnsUIbwq5udf4d2TsvTf4W2wx6YK8pN X-Gm-Message-State: AOJu0YyZDqnmqPwqeVp33zfkvmVTe2vkpPDZhhIWKE5MWyMXMRF8iLmV /fXmFmXh26RCp+zOtEDwUc3IrNwZrNiRecnK2iRQj/TGWicf1gG0z+9heCq+bJcpfCPhYiK/SmQ dBn6lgU7M8Mb2hmiQ7+OY5T31RIwRIJp4BY+yNtrgcF9RSgRiBBWW9q4L/u+OW44Mtg== X-Received: by 2002:a05:6000:2a0d:b0:354:c786:ec45 with SMTP id ffacd0b85a97d-354c786ee7bmr4132800f8f.54.1716225877971; Mon, 20 May 2024 10:24:37 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGcWqcLANszjl04U+bkoNunNlSQySDkg7W2o6Ua7wxiL9y4ovZR1M87Rj5yMsP46zjxw1PslA== X-Received: by 2002:a05:6000:2a0d:b0:354:c786:ec45 with SMTP id ffacd0b85a97d-354c786ee7bmr4132777f8f.54.1716225877632; Mon, 20 May 2024 10:24:37 -0700 (PDT) Received: from cassiopeiae.. ([2a02:810d:4b3f:ee94:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3502b79bc6csm29555004f8f.21.2024.05.20.10.24.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 20 May 2024 10:24:36 -0700 (PDT) From: Danilo Krummrich To: maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, ojeda@kernel.org, alex.gaynor@gmail.com, wedsonaf@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@samsung.com, aliceryhl@google.com, fujita.tomonori@gmail.com, lina@asahilina.net, pstanner@redhat.com, ajanulgu@redhat.com, lyude@redhat.com, gregkh@linuxfoundation.org Cc: rust-for-linux@vger.kernel.org, dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, Danilo Krummrich Subject: [RFC PATCH 7/8] rust: add firmware abstractions Date: Mon, 20 May 2024 19:24:19 +0200 Message-ID: <20240520172422.181763-4-dakr@redhat.com> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240520172059.181256-1-dakr@redhat.com> References: <20240520172059.181256-1-dakr@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Add an abstraction around the kernels firmware API to request firmware images. The abstraction provides functions to access the firmware buffer and / or copy it to a new buffer allocated with a given allocator backend. The firmware is released once the abstraction is dropped. Signed-off-by: Danilo Krummrich Signed-off-by: Wedson Almeida Filho Signed-off-by: Danilo Krummrich Signed-off-by: FUJITA Tomonori Acked-by: Greg Kroah-Hartman --- rust/bindings/bindings_helper.h | 1 + rust/kernel/firmware.rs | 74 +++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 1 + 3 files changed, 76 insertions(+) create mode 100644 rust/kernel/firmware.rs diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index b245db8d5a87..e4ffc47da5ec 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/kernel/firmware.rs b/rust/kernel/firmware.rs new file mode 100644 index 000000000000..700504fb3c9c --- /dev/null +++ b/rust/kernel/firmware.rs @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Firmware abstraction +//! +//! C header: [`include/linux/firmware.h`](../../../../include/linux/firmware.h") + +use crate::{bindings, device::Device, error::Error, error::Result, str::CStr, types::Opaque}; + +/// Abstraction around a C firmware struct. +/// +/// This is a simple abstraction around the C firmware API. Just like with the C API, firmware can +/// be requested. Once requested the abstraction provides direct access to the firmware buffer as +/// `&[u8]`. Alternatively, the firmware can be copied to a new buffer using `Firmware::copy`. The +/// firmware is released once [`Firmware`] is dropped. +/// +/// # Examples +/// +/// ``` +/// let fw = Firmware::request("path/to/firmware.bin", dev.as_ref())?; +/// driver_load_firmware(fw.data()); +/// ``` +pub struct Firmware(Opaque<*const bindings::firmware>); + +impl Firmware { + /// Send a firmware request and wait for it. See also `bindings::request_firmware`. + pub fn request(name: &CStr, dev: &Device) -> Result { + let fw = Opaque::uninit(); + + let ret = unsafe { bindings::request_firmware(fw.get(), name.as_char_ptr(), dev.as_raw()) }; + if ret != 0 { + return Err(Error::from_errno(ret)); + } + + Ok(Firmware(fw)) + } + + /// Send a request for an optional fw module. See also `bindings::request_firmware_nowarn`. + pub fn request_nowarn(name: &CStr, dev: &Device) -> Result { + let fw = Opaque::uninit(); + + let ret = unsafe { + bindings::firmware_request_nowarn(fw.get(), name.as_char_ptr(), dev.as_raw()) + }; + if ret != 0 { + return Err(Error::from_errno(ret)); + } + + Ok(Firmware(fw)) + } + + /// Returns the size of the requested firmware in bytes. + pub fn size(&self) -> usize { + unsafe { (*(*self.0.get())).size } + } + + /// Returns the requested firmware as `&[u8]`. + pub fn data(&self) -> &[u8] { + unsafe { core::slice::from_raw_parts((*(*self.0.get())).data, self.size()) } + } +} + +impl Drop for Firmware { + fn drop(&mut self) { + unsafe { bindings::release_firmware(*self.0.get()) }; + } +} + +// SAFETY: `Firmware` only holds a pointer to a C firmware struct, which is safe to be used from any +// thread. +unsafe impl Send for Firmware {} + +// SAFETY: `Firmware` only holds a pointer to a C firmware struct, references to which are safe to +// be used from any thread. +unsafe impl Sync for Firmware {} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 6415968ee3b8..ed97d131661a 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -35,6 +35,7 @@ #[cfg(CONFIG_DRM = "y")] pub mod drm; pub mod error; +pub mod firmware; pub mod init; pub mod ioctl; #[cfg(CONFIG_KUNIT)] From patchwork Mon May 20 17:24:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 13668505 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D6A95C04FFE for ; Mon, 20 May 2024 17:24:51 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id A634310E819; Mon, 20 May 2024 17:24:49 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="jRNqXBqC"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by gabe.freedesktop.org (Postfix) with ESMTPS id CC46210E641 for ; Mon, 20 May 2024 17:24:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1716225886; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=82Vph+Q3j8BVvO/RuEAHK7JPrZ2ySneeAlIJaZohjIQ=; b=jRNqXBqCXJyMTD+v7DG85yJpYLQU03GQTyvTPOSsUy0RscEQG1Non7qqeAUJIfHffQQ4UO Yy8Nh5hTHHhX82wmpZNAy4R/oXumXQkUilajrTnVbdGGaaJ6VbQer+e+W0XFotFUCPz1mt caNF+uteH/o2cqJXeEwAhxbMu8puMO4= Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-274-dkfQpdiqOrCk3EJjXmMb9A-1; Mon, 20 May 2024 13:24:43 -0400 X-MC-Unique: dkfQpdiqOrCk3EJjXmMb9A-1 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-351c67dbc8dso4383495f8f.2 for ; Mon, 20 May 2024 10:24:43 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1716225882; x=1716830682; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=82Vph+Q3j8BVvO/RuEAHK7JPrZ2ySneeAlIJaZohjIQ=; b=mIuvZruAQtkDGgdtFqQ7+wlVUBxTuhRjGPArvw64XR4ebKRJuCeRmV526q/1jcdT5x OWvjNEI+03Puwxs9QSX1SipIL2nkW/6pRMOgqxInt9tqWu3kvvngqBszIu67d8fVAmZy NtpCj8/Re2lYwuYWQ5B8eisIMbB4Fww7H+6Vctbh0gac9AvFmfg7nvH+Of0t/f+JuoU8 7m1CqGuwSXC+MbUArBxVxw2j5i6bx142kwCGEM5/Hf2O9VU0FxMBuqK5U88rYDi/tPV3 kT9EKoSViVVGqXHYrhXsRUKlqC2d9T9dZDmAvmmOZZWcFe7fR8RJI6xgVJ1O45HWJ6aw sKzg== X-Forwarded-Encrypted: i=1; AJvYcCW8zkbbFH3048Oegf+XQGh4EFPuqS4ddKe2de59JPIxfAaKbQEjeRuC0AfrUJCJQhLrNFpBpOhK4Yk+t0EQXzqQvdLTU1a7bNVtEtC4f8Ew X-Gm-Message-State: AOJu0Ywn8PKwPaOcYhA3VkHvew/I81jHgPvly7ZaW2k/oQ1QFWkObG4n p0jqf2sQaaT6IP0cwDW1+bSAQFJ7CpECDVDPQJdxmORXGde/biDJB9i2d/+Ep61B35oWmcxOkZi R/+y5Wfq8NQqBcpeR1FQYGQSQp3q0+FMfCh3xavzZT/+tSdrD0ATPBekVEYCEMtiXWg== X-Received: by 2002:a5d:5450:0:b0:351:dd2d:f6ad with SMTP id ffacd0b85a97d-351dd2df934mr7531657f8f.67.1716225882038; Mon, 20 May 2024 10:24:42 -0700 (PDT) X-Google-Smtp-Source: AGHT+IG2QQOtaLaHDV4phxxm8NaIVRPTBK2ykMJJupK+1ptCW1PGIZFTGlFFUO7k02cx8LGlySQeJQ== X-Received: by 2002:a5d:5450:0:b0:351:dd2d:f6ad with SMTP id ffacd0b85a97d-351dd2df934mr7531624f8f.67.1716225881653; Mon, 20 May 2024 10:24:41 -0700 (PDT) Received: from cassiopeiae.. ([2a02:810d:4b3f:ee94:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-351d7861323sm12513280f8f.74.2024.05.20.10.24.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 20 May 2024 10:24:41 -0700 (PDT) From: Danilo Krummrich To: maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, ojeda@kernel.org, alex.gaynor@gmail.com, wedsonaf@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@samsung.com, aliceryhl@google.com, fujita.tomonori@gmail.com, lina@asahilina.net, pstanner@redhat.com, ajanulgu@redhat.com, lyude@redhat.com, gregkh@linuxfoundation.org Cc: rust-for-linux@vger.kernel.org, dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, Danilo Krummrich Subject: [RFC PATCH 8/8] nova: add initial driver stub Date: Mon, 20 May 2024 19:24:20 +0200 Message-ID: <20240520172422.181763-5-dakr@redhat.com> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240520172059.181256-1-dakr@redhat.com> References: <20240520172059.181256-1-dakr@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Add the initial driver stub of Nova, a Rust-based GSP-only driver for Nvidia GPUs. Nova, in the long term, is intended to serve as the successor of Nouveau for GSP-firmware-based GPUs. [1] As a stub driver Nova's focus is to make use of the most basic device / driver infrastructure required to build a DRM driver on the PCI bus and serve as demonstration example and justification for this infrastructure. In further consequence, the idea is to develop Nova continuously upstream, using those increments to lift further Rust abstractions and infrastructure upstream. Link: https://lore.kernel.org/dri-devel/Zfsj0_tb-0-tNrJy@cassiopeiae/T/#u [1] Signed-off-by: Danilo Krummrich --- MAINTAINERS | 10 ++ drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/nova/Kconfig | 11 +++ drivers/gpu/drm/nova/Makefile | 3 + drivers/gpu/drm/nova/driver.rs | 110 +++++++++++++++++++++ drivers/gpu/drm/nova/file.rs | 71 ++++++++++++++ drivers/gpu/drm/nova/gem.rs | 50 ++++++++++ drivers/gpu/drm/nova/gpu.rs | 172 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/nova/nova.rs | 20 ++++ include/uapi/drm/nova_drm.h | 101 +++++++++++++++++++ rust/uapi/uapi_helper.h | 1 + 12 files changed, 552 insertions(+) create mode 100644 drivers/gpu/drm/nova/Kconfig create mode 100644 drivers/gpu/drm/nova/Makefile create mode 100644 drivers/gpu/drm/nova/driver.rs create mode 100644 drivers/gpu/drm/nova/file.rs create mode 100644 drivers/gpu/drm/nova/gem.rs create mode 100644 drivers/gpu/drm/nova/gpu.rs create mode 100644 drivers/gpu/drm/nova/nova.rs create mode 100644 include/uapi/drm/nova_drm.h diff --git a/MAINTAINERS b/MAINTAINERS index aa3b947fb080..1ca0ea445e3f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6863,6 +6863,16 @@ T: git https://gitlab.freedesktop.org/drm/nouveau.git F: drivers/gpu/drm/nouveau/ F: include/uapi/drm/nouveau_drm.h +DRM DRIVER (STUB) FOR NVIDIA GSP GPUS [RUST] +M: Danilo Krummrich +L: dri-devel@lists.freedesktop.org +L: nouveau@lists.freedesktop.org +S: Supported +C: irc://irc.oftc.net/nouveau +T: git https://gitlab.freedesktop.org/drm/nova.git +F: drivers/gpu/drm/nova/ +F: include/uapi/drm/nova_drm.h + DRM DRIVER FOR OLIMEX LCD-OLINUXINO PANELS M: Stefan Mavrodiev S: Maintained diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 5a0c476361c3..0bb0442a252e 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -274,6 +274,8 @@ source "drivers/gpu/drm/amd/amdgpu/Kconfig" source "drivers/gpu/drm/nouveau/Kconfig" +source "drivers/gpu/drm/nova/Kconfig" + source "drivers/gpu/drm/i915/Kconfig" source "drivers/gpu/drm/xe/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 104b42df2e95..de6dc006cb7f 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -143,6 +143,7 @@ obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/ obj-$(CONFIG_DRM_VGEM) += vgem/ obj-$(CONFIG_DRM_VKMS) += vkms/ obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/ +obj-$(CONFIG_DRM_NOVA_STUB) += nova/ obj-$(CONFIG_DRM_EXYNOS) +=exynos/ obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/ obj-$(CONFIG_DRM_GMA500) += gma500/ diff --git a/drivers/gpu/drm/nova/Kconfig b/drivers/gpu/drm/nova/Kconfig new file mode 100644 index 000000000000..1ae2d1322a92 --- /dev/null +++ b/drivers/gpu/drm/nova/Kconfig @@ -0,0 +1,11 @@ +config DRM_NOVA_STUB + tristate "Nova GPU driver stub" + depends on DRM + depends on PCI + depends on RUST + default n + help + Choose this if you want to build the Nova stub driver for Nvidia + GSP-based GPUs. + + If M is selected, the module will be called nova. diff --git a/drivers/gpu/drm/nova/Makefile b/drivers/gpu/drm/nova/Makefile new file mode 100644 index 000000000000..733ac5fb9f4f --- /dev/null +++ b/drivers/gpu/drm/nova/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_DRM_NOVA_STUB) += nova.o diff --git a/drivers/gpu/drm/nova/driver.rs b/drivers/gpu/drm/nova/driver.rs new file mode 100644 index 000000000000..47eaa2eddf16 --- /dev/null +++ b/drivers/gpu/drm/nova/driver.rs @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-2.0 + +use alloc::boxed::Box; +use core::pin::Pin; +use kernel::{ + bindings, c_str, device, driver, drm, + drm::{drv, ioctl}, + pci, + pci::define_pci_id_table, + prelude::*, + sync::Arc, +}; + +use crate::{file::File, gpu::Gpu}; + +pub(crate) struct NovaDriver; + +/// Convienence type alias for the DRM device type for this driver +pub(crate) type NovaDevice = drm::device::Device; + +#[allow(dead_code)] +pub(crate) struct NovaData { + pub(crate) gpu: Arc, + pub(crate) pdev: pci::Device, +} + +type DeviceData = device::Data, NovaData>; + +const INFO: drm::drv::DriverInfo = drm::drv::DriverInfo { + major: 0, + minor: 0, + patchlevel: 0, + name: c_str!("nova"), + desc: c_str!("Nvidia Graphics"), + date: c_str!("20240227"), +}; + +impl pci::Driver for NovaDriver { + type Data = Arc; + + define_pci_id_table! { + (), + [ (pci::DeviceId::new(bindings::PCI_VENDOR_ID_NVIDIA, bindings::PCI_ANY_ID as u32), None) ] + } + + fn probe(pdev: &mut pci::Device, _id_info: Option<&Self::IdInfo>) -> Result> { + dev_dbg!(pdev.as_ref(), "Probe Nova GPU driver.\n"); + + let reg = drm::drv::Registration::::new(pdev.as_ref())?; + + pdev.enable_device_mem()?; + pdev.set_master(); + + let bar = pdev.iomap_region(0, c_str!("nova"))?; + + let gpu = Gpu::new(pdev, bar)?; + + let data = kernel::new_device_data!( + reg, + NovaData { + gpu, + pdev: pdev.clone(), + }, + "NovaData" + )?; + let data: Arc = data.into(); + + kernel::drm_device_register!( + data.registrations().ok_or(ENXIO)?.as_pinned_mut(), + data.clone(), + 0 + )?; + + Ok(data) + } + + fn remove(data: &Self::Data) { + dev_dbg!(data.pdev.as_ref(), "Remove Nova GPU driver.\n"); + } +} + +#[vtable] +impl drm::drv::Driver for NovaDriver { + type Data = Arc; + type File = File; + type Object = crate::gem::Object; + + const INFO: drm::drv::DriverInfo = INFO; + const FEATURES: u32 = drv::FEAT_GEM; + + kernel::declare_drm_ioctls! { + (NOVA_GETPARAM, drm_nova_getparam, ioctl::RENDER_ALLOW, File::get_param), + (NOVA_GEM_CREATE, drm_nova_gem_create, ioctl::AUTH | ioctl::RENDER_ALLOW, File::gem_create), + (NOVA_GEM_INFO, drm_nova_gem_info, ioctl::AUTH | ioctl::RENDER_ALLOW, File::gem_info), + } +} + +pub(crate) struct NovaModule { + _registration: Pin>>>, +} + +impl kernel::Module for NovaModule { + fn init(_name: &'static CStr, module: &'static ThisModule) -> Result { + let registration = driver::Registration::new_pinned(c_str!("nova"), module)?; + + Ok(Self { + _registration: registration, + }) + } +} diff --git a/drivers/gpu/drm/nova/file.rs b/drivers/gpu/drm/nova/file.rs new file mode 100644 index 000000000000..d649fa3973b5 --- /dev/null +++ b/drivers/gpu/drm/nova/file.rs @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0 + +use crate::driver::{NovaDevice, NovaDriver}; +use crate::gem; +use kernel::{ + alloc::flags::*, + drm::{self, device::Device as DrmDevice, gem::BaseObject}, + prelude::*, + uapi, +}; + +pub(crate) struct File(); + +/// Convenience type alias for our DRM `File` type +pub(crate) type DrmFile = drm::file::File; + +impl drm::file::DriverFile for File { + type Driver = NovaDriver; + + fn open(dev: &DrmDevice) -> Result>> { + dev_dbg!(dev.as_ref(), "drm::device::Device::open\n"); + + Ok(Box::into_pin(Box::new(Self(), GFP_KERNEL)?)) + } +} + +impl File { + /// IOCTL: get_param: Query GPU / driver metadata. + pub(crate) fn get_param( + dev: &NovaDevice, + getparam: &mut uapi::drm_nova_getparam, + _file: &DrmFile, + ) -> Result { + let data = dev.data().ok_or(ENODEV)?; + let pdev = &data.pdev; + + getparam.value = match getparam.param as u32 { + uapi::NOVA_GETPARAM_VRAM_BAR_SIZE => pdev.resource_len(1)?, + _ => return Err(EINVAL), + }; + + Ok(0) + } + + /// IOCTL: gem_create: Create a new DRM GEM object. + pub(crate) fn gem_create( + dev: &NovaDevice, + req: &mut uapi::drm_nova_gem_create, + file: &DrmFile, + ) -> Result { + let obj = gem::object_new(dev, req.size.try_into()?)?; + + let handle = obj.create_handle(file)?; + req.handle = handle; + + Ok(0) + } + + /// IOCTL: gem_info: Query GEM metadata. + pub(crate) fn gem_info( + _dev: &NovaDevice, + req: &mut uapi::drm_nova_gem_info, + file: &DrmFile, + ) -> Result { + let bo = gem::lookup_handle(file, req.handle)?; + + req.size = bo.size().try_into()?; + + Ok(0) + } +} diff --git a/drivers/gpu/drm/nova/gem.rs b/drivers/gpu/drm/nova/gem.rs new file mode 100644 index 000000000000..51bc30c226e2 --- /dev/null +++ b/drivers/gpu/drm/nova/gem.rs @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0 + +use kernel::{ + drm::{ + gem, + gem::{BaseObject, ObjectRef}, + }, + prelude::*, +}; + +use crate::{ + driver::{NovaDevice, NovaDriver}, + file::DrmFile, +}; + +/// GEM Object inner driver data +#[pin_data] +pub(crate) struct DriverObject {} + +/// Type alias for the GEM object tyoe for this driver. +pub(crate) type Object = gem::Object; + +impl gem::BaseDriverObject for DriverObject { + fn new(dev: &NovaDevice, _size: usize) -> impl PinInit { + dev_dbg!(dev.as_ref(), "DriverObject::new\n"); + DriverObject {} + } +} + +impl gem::DriverObject for DriverObject { + type Driver = NovaDriver; +} + +/// Create a new DRM GEM object. +pub(crate) fn object_new(dev: &NovaDevice, size: usize) -> Result> { + let aligned_size = size.next_multiple_of(1 << 12); + + if size == 0 || size > aligned_size { + return Err(EINVAL); + } + + let gem = Object::new(dev, aligned_size)?; + + Ok(ObjectRef::from_pinned_unique(gem)) +} + +/// Look up a GEM object handle for a `File` and return an `ObjectRef` for it. +pub(crate) fn lookup_handle(file: &DrmFile, handle: u32) -> Result> { + Object::lookup_handle(file, handle) +} diff --git a/drivers/gpu/drm/nova/gpu.rs b/drivers/gpu/drm/nova/gpu.rs new file mode 100644 index 000000000000..b35d055e5322 --- /dev/null +++ b/drivers/gpu/drm/nova/gpu.rs @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0 + +use kernel::{ + device, devres::Devres, error::code::*, firmware, fmt, pci, prelude::*, str::CString, sync::Arc, +}; + +use core::fmt::Debug; + +/// Enum representing the GPU chipset. +#[derive(Debug)] +pub(crate) enum Chipset { + TU102 = 0x162, + TU104 = 0x164, + TU106 = 0x166, + TU117 = 0x167, + TU116 = 0x168, + GA102 = 0x172, + GA103 = 0x173, + GA104 = 0x174, + GA106 = 0x176, + GA107 = 0x177, + AD102 = 0x192, + AD103 = 0x193, + AD104 = 0x194, + AD106 = 0x196, + AD107 = 0x197, +} + +/// Enum representing the GPU generation. +#[derive(Debug)] +pub(crate) enum CardType { + /// Turing + TU100 = 0x160, + /// Ampere + GA100 = 0x170, + /// Ada Lovelace + AD100 = 0x190, +} + +/// Structure holding the metadata of the GPU. +#[allow(dead_code)] +pub(crate) struct GpuSpec { + /// Contents of the boot0 register. + boot0: u64, + card_type: CardType, + chipset: Chipset, + /// The revision of the chipset. + chiprev: u8, +} + +/// Structure encapsulating the firmware blobs required for the GPU to operate. +#[allow(dead_code)] +pub(crate) struct Firmware { + booter_load: firmware::Firmware, + booter_unload: firmware::Firmware, + gsp: firmware::Firmware, +} + +/// Structure holding the resources required to operate the GPU. +#[allow(dead_code)] +#[pin_data] +pub(crate) struct Gpu { + spec: GpuSpec, + /// MMIO mapping of PCI BAR 0 + bar: Devres, + fw: Firmware, +} + +// TODO replace with something like derive(FromPrimitive) +impl Chipset { + fn from_u32(value: u32) -> Option { + match value { + 0x162 => Some(Chipset::TU102), + 0x164 => Some(Chipset::TU104), + 0x166 => Some(Chipset::TU106), + 0x167 => Some(Chipset::TU117), + 0x168 => Some(Chipset::TU116), + 0x172 => Some(Chipset::GA102), + 0x173 => Some(Chipset::GA103), + 0x174 => Some(Chipset::GA104), + 0x176 => Some(Chipset::GA106), + 0x177 => Some(Chipset::GA107), + 0x192 => Some(Chipset::AD102), + 0x193 => Some(Chipset::AD103), + 0x194 => Some(Chipset::AD104), + 0x196 => Some(Chipset::AD106), + 0x197 => Some(Chipset::AD107), + _ => None, + } + } +} + +// TODO replace with something like derive(FromPrimitive) +impl CardType { + fn from_u32(value: u32) -> Option { + match value { + 0x160 => Some(CardType::TU100), + 0x170 => Some(CardType::GA100), + 0x190 => Some(CardType::AD100), + _ => None, + } + } +} + +impl GpuSpec { + fn new(bar: &Devres) -> Result { + let bar = bar.try_access().ok_or(ENXIO)?; + let boot0 = u64::from_le(bar.readq(0)?); + let chip = ((boot0 & 0x1ff00000) >> 20) as u32; + + if boot0 & 0x1f000000 == 0 { + return Err(ENODEV); + } + + let chipset = match Chipset::from_u32(chip) { + Some(x) => x, + None => return Err(ENODEV), + }; + + let card_type = match CardType::from_u32(chip & 0x1f0) { + Some(x) => x, + None => return Err(ENODEV), + }; + + Ok(Self { + boot0, + card_type, + chipset, + chiprev: (boot0 & 0xff) as u8, + }) + } +} + +impl Firmware { + fn new(dev: &device::Device, spec: &GpuSpec, ver: &str) -> Result { + let mut chip_name = CString::try_from_fmt(fmt!("{:?}", spec.chipset))?; + chip_name.make_ascii_lowercase(); + + let fw_booter_load_path = + CString::try_from_fmt(fmt!("nvidia/{}/gsp/booter_load-{}.bin", &*chip_name, ver,))?; + let fw_booter_unload_path = + CString::try_from_fmt(fmt!("nvidia/{}/gsp/booter_unload-{}.bin", &*chip_name, ver))?; + let fw_gsp_path = + CString::try_from_fmt(fmt!("nvidia/{}/gsp/gsp-{}.bin", &*chip_name, ver))?; + + let booter_load = firmware::Firmware::request(&fw_booter_load_path, dev)?; + let booter_unload = firmware::Firmware::request(&fw_booter_unload_path, dev)?; + let gsp = firmware::Firmware::request(&fw_gsp_path, dev)?; + + Ok(Firmware { + booter_load, + booter_unload, + gsp, + }) + } +} + +impl Gpu { + pub(crate) fn new(pdev: &pci::Device, bar: Devres) -> Result> { + let spec = GpuSpec::new(&bar)?; + let fw = Firmware::new(pdev.as_ref(), &spec, "535.113.01")?; + + dev_info!( + pdev.as_ref(), + "NVIDIA {:?} ({:#x})", + spec.chipset, + spec.boot0 + ); + + Arc::pin_init(try_pin_init!(Self { spec, bar, fw }), GFP_KERNEL) + } +} diff --git a/drivers/gpu/drm/nova/nova.rs b/drivers/gpu/drm/nova/nova.rs new file mode 100644 index 000000000000..48420267bcc1 --- /dev/null +++ b/drivers/gpu/drm/nova/nova.rs @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Nova GPU Driver + +mod driver; +mod file; +mod gem; +mod gpu; + +use kernel::prelude::module; + +use driver::NovaModule; + +module! { + type: NovaModule, + name: "Nova", + author: "Danilo Krummrich", + description: "Nova GPU driver", + license: "GPL v2", +} diff --git a/include/uapi/drm/nova_drm.h b/include/uapi/drm/nova_drm.h new file mode 100644 index 000000000000..3ca90ed9d2bb --- /dev/null +++ b/include/uapi/drm/nova_drm.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: MIT */ + +#ifndef __NOVA_DRM_H__ +#define __NOVA_DRM_H__ + +#include "drm.h" + +/* DISCLAIMER: Do not use, this is not a stable uAPI. + * + * This uAPI serves only testing purposes as long as this driver is still in + * development. It is required to implement and test infrastructure which is + * upstreamed in the context of this driver. See also [1]. + * + * [1] https://lore.kernel.org/dri-devel/Zfsj0_tb-0-tNrJy@cassiopeiae/T/#u + */ + +#if defined(__cplusplus) +extern "C" { +#endif + +/* + * NOVA_GETPARAM_VRAM_BAR_SIZE + * + * Query the VRAM BAR size in bytes. + */ +#define NOVA_GETPARAM_VRAM_BAR_SIZE 0x1 + +/** + * struct drm_nova_getparam - query GPU and driver metadata + */ +struct drm_nova_getparam { + /** + * @param: The identifier of the parameter to query. + */ + __u64 param; + + /** + * @value: The value for the specified parameter. + */ + __u64 value; +}; + +/** + * struct drm_nova_gem_create - create a new DRM GEM object + */ +struct drm_nova_gem_create { + /** + * @handle: The handle of the new DRM GEM object. + */ + __u32 handle; + + /** + * @pad: 32 bit padding, should be 0. + */ + __u32 pad; + + /** + * @size: The size of the new DRM GEM object. + */ + __u64 size; +}; + +/** + * struct drm_nova_gem_info - query DRM GEM object metadata + */ +struct drm_nova_gem_info { + /** + * @handle: The handle of the DRM GEM object to query. + */ + __u32 handle; + + /** + * @pad: 32 bit padding, should be 0. + */ + __u32 pad; + + /** + * @size: The size of the DRM GEM obejct. + */ + __u64 size; +}; + +#define DRM_NOVA_GETPARAM 0x00 +#define DRM_NOVA_GEM_CREATE 0x01 +#define DRM_NOVA_GEM_INFO 0x02 + +/* Note: this is an enum so that it can be resolved by Rust bindgen. */ +enum { + DRM_IOCTL_NOVA_GETPARAM = DRM_IOWR(DRM_COMMAND_BASE + DRM_NOVA_GETPARAM, + struct drm_nova_getparam), + DRM_IOCTL_NOVA_GEM_CREATE = DRM_IOWR(DRM_COMMAND_BASE + DRM_NOVA_GEM_CREATE, + struct drm_nova_gem_create), + DRM_IOCTL_NOVA_GEM_INFO = DRM_IOWR(DRM_COMMAND_BASE + DRM_NOVA_GEM_INFO, + struct drm_nova_gem_info), +}; + +#if defined(__cplusplus) +} +#endif + +#endif /* __NOVA_DRM_H__ */ diff --git a/rust/uapi/uapi_helper.h b/rust/uapi/uapi_helper.h index ed42a456da2e..b9ab3406b2ce 100644 --- a/rust/uapi/uapi_helper.h +++ b/rust/uapi/uapi_helper.h @@ -8,5 +8,6 @@ #include #include +#include #include #include