From nobody Tue Dec 16 07:07:21 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1019E33981; Thu, 6 Mar 2025 22:23:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741299833; cv=none; b=WZq8B/ZQecvOmGMTWI/1vT9K1L8gMdIdDPUfCYuW9ApPzeetKZ+qZcpV+Hea8WuppTn1bArLKp21rv8+VCqQuE1mC7ylX1CfX/IBZ9e0sLGgjHkl42MX1oKoq82WGE2B6gM4OQ/uOEoK7SRCFZ1Ih7NKpJiUoY2JUVHfduCQTmQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741299833; c=relaxed/simple; bh=y3CZ8ZJK599hbiqH7CSxRE1Iiyt7j7EOyB3glexphq4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=VuluLw8GL8WEh+LOzVNLChhHz3BrS079i1epggkiBCdNAvDj6iutPYbYBAbXBsufyPkF8+zI2MscRsHKLiOGSJuTi8HeXWCO+JbIzhy0MOy5sj6wEj8bzD2mYGCHXny5sPRBnxFmaBD1Duk+V1wUei805uKrblM5SznFIvpZi5M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=LEDnF/vA; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="LEDnF/vA" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6C56EC4CEE9; Thu, 6 Mar 2025 22:23:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1741299832; bh=y3CZ8ZJK599hbiqH7CSxRE1Iiyt7j7EOyB3glexphq4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LEDnF/vAatuGoGS+jJ/f8Il9WWcjMiMR52s7GqhoM1H4CT+lNLEGSl/8twSncm9K9 VhHca6D76eqleQx4IeiIcOiKo78v8SEwd77XX44t1sIsI/siVVY8xh7JXCVcv/m1Os GKi62DLNuE9J7e+uiPAemMzd+tT9Kcz52TbrE62MJcVtBiG8ot2YDrbbKm9oqzSZI3 wYA8lWbI9M7DACASeAdo1E0303TcVmLEl1GtwhUspNlb+sX7BW0AzOOyTgZxrK6wjc DgdVys5kg1YAUSc3zuHdDCJethaX59mIgaGzpXXlPpb2Jqtt5ACy+G4PCM1QUY6VFY VPRgyxiKmzhTQ== From: Danilo Krummrich To: airlied@gmail.com, simona@ffwll.ch, corbet@lwn.net, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, ajanulgu@redhat.com, lyude@redhat.com, pstanner@redhat.com, zhiw@nvidia.com, cjia@nvidia.com, jhubbard@nvidia.com, bskeggs@nvidia.com, acurrid@nvidia.com Cc: ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, gregkh@linuxfoundation.org, mcgrof@kernel.org, russ.weight@linux.dev, dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, nouveau@lists.freedesktop.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v6 1/5] rust: module: add type `LocalModule` Date: Thu, 6 Mar 2025 23:23:27 +0100 Message-ID: <20250306222336.23482-2-dakr@kernel.org> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250306222336.23482-1-dakr@kernel.org> References: <20250306222336.23482-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The `LocalModule` type is the type of the module created by `module!`, `module_pci_driver!`, `module_platform_driver!`, etc. Since the exact type of the module is sometimes generated on the fly by the listed macros, provide an alias. This is first used by the `module_firmware!` macro. Acked-by: Miguel Ojeda Suggested-by: Alice Ryhl Signed-off-by: Danilo Krummrich --- rust/macros/module.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rust/macros/module.rs b/rust/macros/module.rs index cdf94f4982df..110e59c64197 100644 --- a/rust/macros/module.rs +++ b/rust/macros/module.rs @@ -228,6 +228,10 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream { kernel::ThisModule::from_ptr(core::ptr::null_mut()) }}; =20 + /// The `LocalModule` type is the type of the module created b= y `module!`, + /// `module_pci_driver!`, `module_platform_driver!`, etc. + type LocalModule =3D {type_}; + impl kernel::ModuleMetadata for {type_} {{ const NAME: &'static kernel::str::CStr =3D kernel::c_str!(= \"{name}\"); }} --=20 2.48.1 From nobody Tue Dec 16 07:07:21 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 92A2927C867; Thu, 6 Mar 2025 22:23:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741299839; cv=none; b=QCjSndDFmxn66bQIA4AwPX6Gy56CCtwBpW2WwzxI1s6kextZJTsqRAMPqLHAWK+QHXUBMjZoIA3YojbL4NAOLs1AoTEF3Zp1ZiVYCg+jlX8/kdT9KWAKWsSvGLdhhDiMNeOozBmnvrkvS3bd337Q4kBbW+LXgwaq0ukW+UkdbgY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741299839; c=relaxed/simple; bh=ILGJjKKo5nQZHxzXgwewCMckflvSqIeS3xmxKI0k4uM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=EI3POJgmeIfj3YF6fTAnP3CU6S3/VrISBOHuxK8QGFEXpENPLCL8UFGgY8hD9uelu9GaFk9YBcLc/OSP2M6KCW5Se6rII5agz5rcSIT5lgjH48fGS/Sh6hYRLM7Hzu8mCV+zInJxtH+QQu1d0ZlUdyrBKiSpcqXGv7cfj0dwofw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=MbcKDMn+; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="MbcKDMn+" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E7D4AC4CEEB; Thu, 6 Mar 2025 22:23:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1741299839; bh=ILGJjKKo5nQZHxzXgwewCMckflvSqIeS3xmxKI0k4uM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MbcKDMn+v17Jlhx7k1of1maIC3wGlRZRcgexU9K896QzxSROQEhd5YkuHiPaEKPfp YNd15lAFxZ5nEXsQtXTWFtQX4EbhZRYBZhw4UxQwHF4sDXrUGs18SHeJP5xTLZGQNn hAEOFNMyQWxy7wX7mBDL5FfHqozrd1QbipglcV6Xi0TafZxC01zX/71bJxfdXTe0E9 VUbQpWfSuyDow21BWdgx9ZScYZEgK9d7+ePkGYbHau+R6kL1vlhVoLkfEvIjJ1/Yka EhZNKq8Q6eaXv42yK9oZILxlBrXGKMonB+Gsk8TC1yKwd51UvPs6zN3kGcJGdysJan 59FwoY6ItGEkg== From: Danilo Krummrich To: airlied@gmail.com, simona@ffwll.ch, corbet@lwn.net, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, ajanulgu@redhat.com, lyude@redhat.com, pstanner@redhat.com, zhiw@nvidia.com, cjia@nvidia.com, jhubbard@nvidia.com, bskeggs@nvidia.com, acurrid@nvidia.com Cc: ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, gregkh@linuxfoundation.org, mcgrof@kernel.org, russ.weight@linux.dev, dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, nouveau@lists.freedesktop.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v6 2/5] rust: firmware: introduce `firmware::ModInfoBuilder` Date: Thu, 6 Mar 2025 23:23:28 +0100 Message-ID: <20250306222336.23482-3-dakr@kernel.org> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250306222336.23482-1-dakr@kernel.org> References: <20250306222336.23482-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The `firmware` field of the `module!` only accepts literal strings, which is due to the fact that it is implemented as a proc macro. Some drivers require a lot of firmware files (such as nova-core) and hence benefit from more flexibility composing firmware path strings. The `firmware::ModInfoBuilder` is a helper component to flexibly compose firmware path strings for the .modinfo section in const context. It is meant to be used in combination with `kernel::module_firmware!`. Co-developed-by: Alice Ryhl Signed-off-by: Alice Ryhl Signed-off-by: Danilo Krummrich --- rust/kernel/firmware.rs | 127 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/rust/kernel/firmware.rs b/rust/kernel/firmware.rs index c5162fdc95ff..6008b62f2de8 100644 --- a/rust/kernel/firmware.rs +++ b/rust/kernel/firmware.rs @@ -115,3 +115,130 @@ unsafe impl Send for Firmware {} // SAFETY: `Firmware` only holds a pointer to a C `struct firmware`, refer= ences to which are safe to // be used from any thread. unsafe impl Sync for Firmware {} + +/// Builder for firmware module info. +/// +/// [`ModInfoBuilder`] is a helper component to flexibly compose firmware = paths strings for the +/// .modinfo section in const context. +/// +/// Therefore the [`ModInfoBuilder`] provides the methods [`ModInfoBuilder= ::new_entry`] and +/// [`ModInfoBuilder::push`], where the latter is used to push path compon= ents and the former to +/// mark the beginning of a new path string. +/// +/// [`ModInfoBuilder`] is meant to be used in combination with `kernel::mo= dule_firmware!`. +/// +/// The const generic `N` as well as the `module_name` parameter of [`ModI= nfoBuilder::new`] is an +/// internal implementation detail and supplied through the above macro. +pub struct ModInfoBuilder { + buf: [u8; N], + n: usize, + module_name: &'static CStr, +} + +impl ModInfoBuilder { + /// Create an empty builder instance. + pub const fn new(module_name: &'static CStr) -> Self { + Self { + buf: [0; N], + n: 0, + module_name, + } + } + + const fn push_internal(mut self, bytes: &[u8]) -> Self { + let mut j =3D 0; + + if N =3D=3D 0 { + self.n +=3D bytes.len(); + return self; + } + + while j < bytes.len() { + if self.n < N { + self.buf[self.n] =3D bytes[j]; + } + self.n +=3D 1; + j +=3D 1; + } + self + } + + /// Push an additional path component. + /// + /// Append path components to the [`ModInfoBuilder`] instance. Paths n= eed to be separated + /// with [`ModInfoBuilder::new_entry`]. + /// + /// # Example + /// + /// ``` + /// use kernel::firmware::ModInfoBuilder; + /// + /// # const DIR: &str =3D "vendor/chip/"; + /// # const fn no_run(builder: ModInfoBuilder) { + /// let builder =3D builder.new_entry() + /// .push(DIR) + /// .push("foo.bin") + /// .new_entry() + /// .push(DIR) + /// .push("bar.bin"); + /// # } + /// ``` + pub const fn push(self, s: &str) -> Self { + // Check whether there has been an initial call to `next_entry()`. + if N !=3D 0 && self.n =3D=3D 0 { + crate::build_error!("Must call next_entry() before push()."); + } + + self.push_internal(s.as_bytes()) + } + + const fn push_module_name(self) -> Self { + let mut this =3D self; + let module_name =3D this.module_name; + + if !this.module_name.is_empty() { + this =3D this.push_internal(module_name.as_bytes_with_nul()); + + if N !=3D 0 { + // Re-use the space taken by the NULL terminator and swap = it with the '.' separator. + this.buf[this.n - 1] =3D b'.'; + } + } + + this + } + + /// Prepare the [`ModInfoBuilder`] for the next entry. + /// + /// This method acts as a separator between module firmware path entri= es. + /// + /// Must be called before constructing a new entry with subsequent cal= ls to + /// [`ModInfoBuilder::push`]. + /// + /// See [`ModInfoBuilder::push`] for an example. + pub const fn new_entry(self) -> Self { + self.push_internal(b"\0") + .push_module_name() + .push_internal(b"firmware=3D") + } + + /// Build the byte array. + pub const fn build(self) -> [u8; N] { + // Add the final NULL terminator. + let this =3D self.push_internal(b"\0"); + + if this.n =3D=3D N { + this.buf + } else { + crate::build_error!("Length mismatch."); + } + } +} + +impl ModInfoBuilder<0> { + /// Return the length of the byte array to build. + pub const fn build_length(self) -> usize { + // Compensate for the NULL terminator added by `build`. + self.n + 1 + } +} --=20 2.48.1 From nobody Tue Dec 16 07:07:21 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 442AA1FC11F; Thu, 6 Mar 2025 22:24:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741299847; cv=none; b=jK6LE1D+Clmb9OljMOqcIeFXLadojo9IDO2717p+kOJtyDbO+4wBCaKZ4JSApuHQFYX2IQsEaZsQIY4AcJOqthl4aMF6z95SQGszCM3GO/tjzOC5pZZCgJZrG3cG2ya085ILEig58CQDAXZd3k9DI+sKpqqnqhBNOb2K0BExSBk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741299847; c=relaxed/simple; bh=u2kt676m6q3TARHjfViZbJ5BSWVgsP9Th4fpQNehbLQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BD3MjDLEeQyZ8EXr3ixzONjEJd827qbufV89GGCZ0AVPgvPOyoOVn3+TYHmlOUNH5uKnDbnnOaPeUAdLsQXuVTV2/FMTZuoPs9c22CAB4Vj0vRu8dKsw/l3EmYjVfigSioHaMEd/789+TsxVCn5VId42QJuJrbVeYtXFSkldyMI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Y2Bww182; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Y2Bww182" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 71FD2C4CEE8; Thu, 6 Mar 2025 22:23:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1741299845; bh=u2kt676m6q3TARHjfViZbJ5BSWVgsP9Th4fpQNehbLQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Y2Bww182MnsJr568pd3TM8g3NyXTW+FMu4S97q+cFfIZs034Z+lq+z5we5mO5E92D p8Te4pb5dVHmq7VOH/YqaSIlyVk6udeyhi8VC8FK7E2FECYQ/2G+wRf8JG+ASCv13T SUiDonu/AuwbQAlyh6fERTZ0BSonbCsX3OGZyf4SuSHyB5cZCosvbDk6TS00Tgkvda sawXsM0vpW45BdLGlqEraSDrb/YvPNClCz2ABAjOVX2lUQnHKGUJfQyuZnjoac1BQP 5Xaw0J72FnKsn61NAeOvnsBsFoR2Tlnbytvx7F0IXRpU/ZksN9cSiW2QyEAOnlj0l2 cdFGtqE9M6t/g== From: Danilo Krummrich To: airlied@gmail.com, simona@ffwll.ch, corbet@lwn.net, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, ajanulgu@redhat.com, lyude@redhat.com, pstanner@redhat.com, zhiw@nvidia.com, cjia@nvidia.com, jhubbard@nvidia.com, bskeggs@nvidia.com, acurrid@nvidia.com Cc: ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, gregkh@linuxfoundation.org, mcgrof@kernel.org, russ.weight@linux.dev, dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, nouveau@lists.freedesktop.org, rust-for-linux@vger.kernel.org, Danilo Krummrich , Jarkko Sakkinen Subject: [PATCH v6 3/5] rust: firmware: add `module_firmware!` macro Date: Thu, 6 Mar 2025 23:23:29 +0100 Message-ID: <20250306222336.23482-4-dakr@kernel.org> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250306222336.23482-1-dakr@kernel.org> References: <20250306222336.23482-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Analogous to the `module!` macro `module_firmware!` adds additional firmware path strings to the .modinfo section. In contrast to `module!`, where path strings need to be string literals, path strings can be composed with the `firmware::ModInfoBuilder`. Some drivers require a lot of firmware files (such as nova-core) and hence benefit from more flexibility composing firmware path strings. Acked-by: Jarkko Sakkinen Signed-off-by: Danilo Krummrich --- rust/kernel/firmware.rs | 91 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-) diff --git a/rust/kernel/firmware.rs b/rust/kernel/firmware.rs index 6008b62f2de8..ae6a1ffdad3d 100644 --- a/rust/kernel/firmware.rs +++ b/rust/kernel/firmware.rs @@ -116,6 +116,95 @@ unsafe impl Send for Firmware {} // be used from any thread. unsafe impl Sync for Firmware {} =20 +/// Create firmware .modinfo entries. +/// +/// This macro is the counterpart of the C macro `MODULE_FIRMWARE()`, but = instead of taking a +/// simple string literals, which is already covered by the `firmware` fie= ld of +/// [`crate::prelude::module!`], it allows the caller to pass a builder ty= pe, based on the +/// [`ModInfoBuilder`], which can create the firmware modinfo strings in a= more flexible way. +/// +/// Drivers should extend the [`ModInfoBuilder`] with their own driver spe= cific builder type. +/// +/// The `builder` argument must be a type which implements the following f= unction. +/// +/// `const fn create(module_name: &'static CStr) -> ModInfoBuilder` +/// +/// `create` should pass the `module_name` to the [`ModInfoBuilder`] and, = with the help of +/// it construct the corresponding firmware modinfo. +/// +/// Typically, such contracts would be enforced by a trait, however traits= do not (yet) support +/// const functions. +/// +/// # Example +/// +/// ``` +/// # mod module_firmware_test { +/// # use kernel::firmware; +/// # use kernel::prelude::*; +/// # +/// # struct MyModule; +/// # +/// # impl kernel::Module for MyModule { +/// # fn init(_module: &'static ThisModule) -> Result { +/// # Ok(Self) +/// # } +/// # } +/// # +/// # +/// struct Builder; +/// +/// impl Builder { +/// const DIR: &str =3D "vendor/chip/"; +/// const FILES: [&str; 3] =3D [ "foo", "bar", "baz" ]; +/// +/// const fn create(module_name: &'static kernel::str::CStr) -> firmwa= re::ModInfoBuilder { +/// let mut builder =3D firmware::ModInfoBuilder::new(module_name); +/// +/// let mut i =3D 0; +/// while i < Self::FILES.len() { +/// builder =3D builder.new_entry() +/// .push(Self::DIR) +/// .push(Self::FILES[i]) +/// .push(".bin"); +/// +/// i +=3D 1; +/// } +/// +/// builder +/// } +/// } +/// +/// module! { +/// type: MyModule, +/// name: "module_firmware_test", +/// author: "Rust for Linux", +/// description: "module_firmware! test module", +/// license: "GPL", +/// } +/// +/// kernel::module_firmware!(Builder); +/// # } +/// ``` +#[macro_export] +macro_rules! module_firmware { + // The argument is the builder type without the const generic, since i= t's deferred from within + // this macro. Hence, we can neither use `expr` nor `ty`. + ($($builder:tt)*) =3D> { + const _: () =3D { + const __MODULE_FIRMWARE_PREFIX: &'static $crate::str::CStr =3D= if cfg!(MODULE) { + $crate::c_str!("") + } else { + ::NAME + }; + + #[link_section =3D ".modinfo"] + #[used] + static __MODULE_FIRMWARE: [u8; $($builder)*::create(__MODULE_F= IRMWARE_PREFIX) + .build_length()] =3D $($builder)*::create(__MODULE_FIRMWAR= E_PREFIX).build(); + }; + }; +} + /// Builder for firmware module info. /// /// [`ModInfoBuilder`] is a helper component to flexibly compose firmware = paths strings for the @@ -125,7 +214,7 @@ unsafe impl Sync for Firmware {} /// [`ModInfoBuilder::push`], where the latter is used to push path compon= ents and the former to /// mark the beginning of a new path string. /// -/// [`ModInfoBuilder`] is meant to be used in combination with `kernel::mo= dule_firmware!`. +/// [`ModInfoBuilder`] is meant to be used in combination with [`kernel::m= odule_firmware!`]. /// /// The const generic `N` as well as the `module_name` parameter of [`ModI= nfoBuilder::new`] is an /// internal implementation detail and supplied through the above macro. --=20 2.48.1 From nobody Tue Dec 16 07:07:21 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3B82727CB1E; Thu, 6 Mar 2025 22:24:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741299853; cv=none; b=f6BqNvu+xV+Sc+YmtRg2AqoBamKVz/J8sfRtkoCN9mmeyTo+pKJt2ve8cKEqELzkV4cjZetjh3clCtuVUFXC93vXJU9QYqE3n1QOV7LHlRrPnGzMxQGF1tFHLh19A0NQScoqk0lRTUIYVymN0Szfr6n5LrLWfA6qPGpawzsNMSg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741299853; c=relaxed/simple; bh=5rNrnlADIzzI8XQ8c05QJO5I2btxge9cWlF28b06pj8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LYbJ/Olcy2lXJ3dbk5Sd9d2iY0S3ukySijxo0d5j4YzoHHVJCAgsQv74p64S6ejKMxxQT6DEOl0LyshLPVKJh/NoPoOym6t2w7v1yBbFSp6hkkSuNj8+4ZBQQrZH9PAQBU22/SENGuYAMyb+YhpYib28cYUKGDNTmP98HJNpsEM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=LyhGeF13; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="LyhGeF13" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2D9D3C4CEE0; Thu, 6 Mar 2025 22:24:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1741299852; bh=5rNrnlADIzzI8XQ8c05QJO5I2btxge9cWlF28b06pj8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LyhGeF13ldQKX5KVDNyjfdfaQs5A43vGOV+h5j8vzHsJSKijBqmOLP69KMTjZvU75 gpvG1UojLuKoD83B2NZ7xmWA38Ggl8OZYgW3u0RZetGS3dZjeKsiJfLFUlB9wGe3sm BISGCztGENtXWML6M5tgl95dk6J8872XsbQU1JGsEQ60SA2/riVOnSY9dC7Aen1mJY w/VdtkAYU6l5GBj+pM8WnjM/MfAOk2hYKRzZIL84RBTXwSFn8DqhKBJ4L4lrb5OZVK FiIum0q7DfnFLPivTpy+vI89hjocm3KUScuWItaYdzAk6WS8oAGZdEwkvy/x2s5++L ZONO2V5ZVcZ+Q== From: Danilo Krummrich To: airlied@gmail.com, simona@ffwll.ch, corbet@lwn.net, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, ajanulgu@redhat.com, lyude@redhat.com, pstanner@redhat.com, zhiw@nvidia.com, cjia@nvidia.com, jhubbard@nvidia.com, bskeggs@nvidia.com, acurrid@nvidia.com Cc: ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, gregkh@linuxfoundation.org, mcgrof@kernel.org, russ.weight@linux.dev, dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, nouveau@lists.freedesktop.org, rust-for-linux@vger.kernel.org, Danilo Krummrich , Alexandre Courbot Subject: [PATCH v6 4/5] gpu: nova-core: add initial driver stub Date: Thu, 6 Mar 2025 23:23:30 +0100 Message-ID: <20250306222336.23482-5-dakr@kernel.org> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250306222336.23482-1-dakr@kernel.org> References: <20250306222336.23482-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add the initial nova-core driver stub. nova-core is intended to serve as a common base for nova-drm (the corresponding DRM driver) and the vGPU manager VFIO driver, serving as a hard- and firmware abstraction layer for GSP-based NVIDIA GPUs. The Nova project, including nova-core and nova-drm, in the long term, is intended to serve as the successor of Nouveau for all GSP-based GPUs. The motivation for both, starting a successor project for Nouveau and doing so using the Rust programming language, is documented in detail through a previous post on the mailing list [1], an LWN article [2] and a talk from LPC '24. In order to avoid the chicken and egg problem to require a user to upstream Rust abstractions, but at the same time require the Rust abstractions to implement the driver, nova-core kicks off as a driver stub and is subsequently developed upstream. Link: https://lore.kernel.org/dri-devel/Zfsj0_tb-0-tNrJy@cassiopeiae/T/#u [= 1] Link: https://lwn.net/Articles/990736/ [2] Link: https://youtu.be/3Igmx28B3BQ?si=3DsBdSEer4tAPKGpOs [3] Reviewed-by: Alexandre Courbot Signed-off-by: Danilo Krummrich --- MAINTAINERS | 10 ++ drivers/gpu/Makefile | 1 + drivers/gpu/nova-core/Kconfig | 14 ++ drivers/gpu/nova-core/Makefile | 3 + drivers/gpu/nova-core/driver.rs | 47 +++++++ drivers/gpu/nova-core/firmware.rs | 45 +++++++ drivers/gpu/nova-core/gpu.rs | 199 +++++++++++++++++++++++++++++ drivers/gpu/nova-core/nova_core.rs | 20 +++ drivers/gpu/nova-core/regs.rs | 55 ++++++++ drivers/gpu/nova-core/util.rs | 21 +++ drivers/video/Kconfig | 1 + 11 files changed, 416 insertions(+) create mode 100644 drivers/gpu/nova-core/Kconfig create mode 100644 drivers/gpu/nova-core/Makefile create mode 100644 drivers/gpu/nova-core/driver.rs create mode 100644 drivers/gpu/nova-core/firmware.rs create mode 100644 drivers/gpu/nova-core/gpu.rs create mode 100644 drivers/gpu/nova-core/nova_core.rs create mode 100644 drivers/gpu/nova-core/regs.rs create mode 100644 drivers/gpu/nova-core/util.rs diff --git a/MAINTAINERS b/MAINTAINERS index ca11a553d412..ede8abee210a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7450,6 +7450,16 @@ T: git https://gitlab.freedesktop.org/drm/nouveau.git F: drivers/gpu/drm/nouveau/ F: include/uapi/drm/nouveau_drm.h =20 +CORE DRIVER FOR NVIDIA GPUS [RUST] +M: Danilo Krummrich +L: nouveau@lists.freedesktop.org +S: Supported +Q: https://patchwork.freedesktop.org/project/nouveau/ +B: https://gitlab.freedesktop.org/drm/nova/-/issues +C: irc://irc.oftc.net/nouveau +T: git https://gitlab.freedesktop.org/drm/nova.git nova-next +F: drivers/gpu/nova-core/ + DRM DRIVER FOR OLIMEX LCD-OLINUXINO PANELS M: Stefan Mavrodiev S: Maintained diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile index 8997f0096545..36a54d456630 100644 --- a/drivers/gpu/Makefile +++ b/drivers/gpu/Makefile @@ -5,3 +5,4 @@ obj-y +=3D host1x/ drm/ vga/ obj-$(CONFIG_IMX_IPUV3_CORE) +=3D ipu-v3/ obj-$(CONFIG_TRACE_GPU_MEM) +=3D trace/ +obj-$(CONFIG_NOVA_CORE) +=3D nova-core/ diff --git a/drivers/gpu/nova-core/Kconfig b/drivers/gpu/nova-core/Kconfig new file mode 100644 index 000000000000..ad0c06756516 --- /dev/null +++ b/drivers/gpu/nova-core/Kconfig @@ -0,0 +1,14 @@ +config NOVA_CORE + tristate "Nova Core GPU driver" + depends on PCI + depends on RUST + depends on RUST_FW_LOADER_ABSTRACTIONS + default n + help + Choose this if you want to build the Nova Core driver for Nvidia + GPUs based on the GPU System Processor (GSP). This is true for Turing + and later GPUs. + + This driver is work in progress and may not be functional. + + If M is selected, the module will be called nova_core. diff --git a/drivers/gpu/nova-core/Makefile b/drivers/gpu/nova-core/Makefile new file mode 100644 index 000000000000..2d78c50126e1 --- /dev/null +++ b/drivers/gpu/nova-core/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_NOVA_CORE) +=3D nova_core.o diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver= .rs new file mode 100644 index 000000000000..63c19f140fbd --- /dev/null +++ b/drivers/gpu/nova-core/driver.rs @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 + +use kernel::{bindings, c_str, pci, prelude::*}; + +use crate::gpu::Gpu; + +#[pin_data] +pub(crate) struct NovaCore { + #[pin] + pub(crate) gpu: Gpu, +} + +const BAR0_SIZE: usize =3D 8; +pub(crate) type Bar0 =3D pci::Bar; + +kernel::pci_device_table!( + PCI_TABLE, + MODULE_PCI_TABLE, + ::IdInfo, + [( + pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_NVIDIA, bindings::P= CI_ANY_ID as _), + () + )] +); + +impl pci::Driver for NovaCore { + type IdInfo =3D (); + const ID_TABLE: pci::IdTable =3D &PCI_TABLE; + + fn probe(pdev: &mut pci::Device, _info: &Self::IdInfo) -> Result>> { + dev_dbg!(pdev.as_ref(), "Probe Nova Core GPU driver.\n"); + + pdev.enable_device_mem()?; + pdev.set_master(); + + let bar =3D pdev.iomap_region_sized::(0, c_str!("nova-c= ore/bar0"))?; + + let this =3D KBox::pin_init( + try_pin_init!(Self { + gpu <- Gpu::new(pdev, bar)?, + }), + GFP_KERNEL, + )?; + + Ok(this) + } +} diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firm= ware.rs new file mode 100644 index 000000000000..273713987572 --- /dev/null +++ b/drivers/gpu/nova-core/firmware.rs @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0 + +use crate::gpu; +use kernel::firmware; + +pub(crate) struct ModInfoBuilder(firmware::ModInfoBuilder<= N>); + +impl ModInfoBuilder { + const VERSION: &str =3D "535.113.01"; + + const fn make_entry_file(self, chipset: &str, fw: &str) -> Self { + ModInfoBuilder( + self.0 + .new_entry() + .push("nvidia/") + .push(chipset) + .push("/gsp/") + .push(fw) + .push("-") + .push(Self::VERSION) + .push(".bin"), + ) + } + + const fn make_entry_chipset(self, chipset: &str) -> Self { + self.make_entry_file(chipset, "booter_load") + .make_entry_file(chipset, "booter_unload") + .make_entry_file(chipset, "bootloader") + .make_entry_file(chipset, "gsp") + } + + pub(crate) const fn create( + module_name: &'static kernel::str::CStr, + ) -> firmware::ModInfoBuilder { + let mut this =3D Self(firmware::ModInfoBuilder::new(module_name)); + let mut i =3D 0; + + while i < gpu::Chipset::NAMES.len() { + this =3D this.make_entry_chipset(gpu::Chipset::NAMES[i]); + i +=3D 1; + } + + this.0 + } +} diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs new file mode 100644 index 000000000000..f57b7efa10f3 --- /dev/null +++ b/drivers/gpu/nova-core/gpu.rs @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0 + +use kernel::{ + device, devres::Devres, error::code::*, firmware, fmt, pci, prelude::*= , str::CString, +}; + +use crate::driver::Bar0; +use crate::regs; +use crate::util; +use core::fmt; + +macro_rules! define_chipset { + ({ $($variant:ident =3D $value:expr),* $(,)* }) =3D> + { + /// Enum representation of the GPU chipset. + #[derive(fmt::Debug)] + pub(crate) enum Chipset { + $($variant =3D $value),*, + } + + impl Chipset { + pub(crate) const ALL: &'static [Chipset] =3D &[ + $( Chipset::$variant, )* + ]; + + pub(crate) const NAMES: [&str; Self::ALL.len()] =3D [ + $( util::const_bytes_to_str( + util::to_lowercase_bytes::<{ stringify!($variant).= len() }>( + stringify!($variant) + ).as_slice() + ), )* + ]; + } + + // TODO replace with something like derive(FromPrimitive) + impl TryFrom for Chipset { + type Error =3D kernel::error::Error; + + fn try_from(value: u32) -> Result { + match value { + $( $value =3D> Ok(Chipset::$variant), )* + _ =3D> Err(ENODEV), + } + } + } + } +} + +define_chipset!({ + // Turing + TU102 =3D 0x162, + TU104 =3D 0x164, + TU106 =3D 0x166, + TU117 =3D 0x167, + TU116 =3D 0x168, + // Ampere + GA102 =3D 0x172, + GA103 =3D 0x173, + GA104 =3D 0x174, + GA106 =3D 0x176, + GA107 =3D 0x177, + // Ada + AD102 =3D 0x192, + AD103 =3D 0x193, + AD104 =3D 0x194, + AD106 =3D 0x196, + AD107 =3D 0x197, +}); + +impl Chipset { + pub(crate) fn arch(&self) -> Architecture { + match self { + Self::TU102 | Self::TU104 | Self::TU106 | Self::TU117 | Self::= TU116 =3D> { + Architecture::Turing + } + Self::GA102 | Self::GA103 | Self::GA104 | Self::GA106 | Self::= GA107 =3D> { + Architecture::Ampere + } + Self::AD102 | Self::AD103 | Self::AD104 | Self::AD106 | Self::= AD107 =3D> { + Architecture::Ada + } + } + } +} + +// TODO +// +// The resulting strings are used to generate firmware paths, hence the +// generated strings have to be stable. +// +// Hence, replace with something like strum_macros derive(Display). +// +// For now, redirect to fmt::Debug for convenience. +impl fmt::Display for Chipset { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +/// Enum representation of the GPU generation. +#[derive(fmt::Debug)] +pub(crate) enum Architecture { + Turing, + Ampere, + Ada, +} + +pub(crate) struct Revision { + major: u8, + minor: u8, +} + +impl Revision { + fn from_boot0(boot0: regs::Boot0) -> Self { + Self { + major: boot0.major_rev(), + minor: boot0.minor_rev(), + } + } +} + +impl fmt::Display for Revision { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:x}.{:x}", self.major, self.minor) + } +} + +/// Structure holding the metadata of the GPU. +pub(crate) struct Spec { + chipset: Chipset, + /// The revision of the chipset. + revision: Revision, +} + +impl Spec { + fn new(bar: &Devres) -> Result { + let bar =3D bar.try_access().ok_or(ENXIO)?; + let boot0 =3D regs::Boot0::read(&bar); + + Ok(Self { + chipset: boot0.chipset().try_into()?, + revision: Revision::from_boot0(boot0), + }) + } +} + +/// Structure encapsulating the firmware blobs required for the GPU to ope= rate. +#[expect(dead_code)] +pub(crate) struct Firmware { + booter_load: firmware::Firmware, + booter_unload: firmware::Firmware, + bootloader: firmware::Firmware, + gsp: firmware::Firmware, +} + +impl Firmware { + fn new(dev: &device::Device, spec: &Spec, ver: &str) -> Result { + let mut chip_name =3D CString::try_from_fmt(fmt!("{}", spec.chipse= t))?; + chip_name.make_ascii_lowercase(); + + let request =3D |name_| { + CString::try_from_fmt(fmt!("nvidia/{}/gsp/{}-{}.bin", &*chip_n= ame, name_, ver)) + .and_then(|path| firmware::Firmware::request(&path, dev)) + }; + + Ok(Firmware { + booter_load: request("booter_load")?, + booter_unload: request("booter_unload")?, + bootloader: request("bootloader")?, + gsp: request("gsp")?, + }) + } +} + +/// Structure holding the resources required to operate the GPU. +#[pin_data] +pub(crate) struct Gpu { + spec: Spec, + /// MMIO mapping of PCI BAR 0 + bar: Devres, + fw: Firmware, +} + +impl Gpu { + pub(crate) fn new(pdev: &pci::Device, bar: Devres) -> Result> { + let spec =3D Spec::new(&bar)?; + let fw =3D Firmware::new(pdev.as_ref(), &spec, "535.113.01")?; + + dev_info!( + pdev.as_ref(), + "NVIDIA (Chipset: {}, Architecture: {:?}, Revision: {})\n", + spec.chipset, + spec.chipset.arch(), + spec.revision + ); + + Ok(pin_init!(Self { spec, bar, fw })) + } +} diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nov= a_core.rs new file mode 100644 index 000000000000..a91cd924054b --- /dev/null +++ b/drivers/gpu/nova-core/nova_core.rs @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Nova Core GPU Driver + +mod driver; +mod firmware; +mod gpu; +mod regs; +mod util; + +kernel::module_pci_driver! { + type: driver::NovaCore, + name: "NovaCore", + author: "Danilo Krummrich", + description: "Nova Core GPU driver", + license: "GPL v2", + firmware: [], +} + +kernel::module_firmware!(firmware::ModInfoBuilder); diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs new file mode 100644 index 000000000000..50aefb150b0b --- /dev/null +++ b/drivers/gpu/nova-core/regs.rs @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0 + +use crate::driver::Bar0; + +// TODO +// +// Create register definitions via generic macros. See task "Generic regis= ter +// abstraction" in Documentation/gpu/nova/core/todo.rst. + +const BOOT0_OFFSET: usize =3D 0x00000000; + +// 3:0 - chipset minor revision +const BOOT0_MINOR_REV_SHIFT: u8 =3D 0; +const BOOT0_MINOR_REV_MASK: u32 =3D 0x0000000f; + +// 7:4 - chipset major revision +const BOOT0_MAJOR_REV_SHIFT: u8 =3D 4; +const BOOT0_MAJOR_REV_MASK: u32 =3D 0x000000f0; + +// 23:20 - chipset implementation Identifier (depends on architecture) +const BOOT0_IMPL_SHIFT: u8 =3D 20; +const BOOT0_IMPL_MASK: u32 =3D 0x00f00000; + +// 28:24 - chipset architecture identifier +const BOOT0_ARCH_MASK: u32 =3D 0x1f000000; + +// 28:20 - chipset identifier (virtual register field combining BOOT0_IMPL= and +// BOOT0_ARCH) +const BOOT0_CHIPSET_SHIFT: u8 =3D BOOT0_IMPL_SHIFT; +const BOOT0_CHIPSET_MASK: u32 =3D BOOT0_IMPL_MASK | BOOT0_ARCH_MASK; + +#[derive(Copy, Clone)] +pub(crate) struct Boot0(u32); + +impl Boot0 { + #[inline] + pub(crate) fn read(bar: &Bar0) -> Self { + Self(bar.readl(BOOT0_OFFSET)) + } + + #[inline] + pub(crate) fn chipset(&self) -> u32 { + (self.0 & BOOT0_CHIPSET_MASK) >> BOOT0_CHIPSET_SHIFT + } + + #[inline] + pub(crate) fn minor_rev(&self) -> u8 { + ((self.0 & BOOT0_MINOR_REV_MASK) >> BOOT0_MINOR_REV_SHIFT) as u8 + } + + #[inline] + pub(crate) fn major_rev(&self) -> u8 { + ((self.0 & BOOT0_MAJOR_REV_MASK) >> BOOT0_MAJOR_REV_SHIFT) as u8 + } +} diff --git a/drivers/gpu/nova-core/util.rs b/drivers/gpu/nova-core/util.rs new file mode 100644 index 000000000000..332a64cfc6a9 --- /dev/null +++ b/drivers/gpu/nova-core/util.rs @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 + +pub(crate) const fn to_lowercase_bytes(s: &str) -> [u8; N]= { + let src =3D s.as_bytes(); + let mut dst =3D [0; N]; + let mut i =3D 0; + + while i < src.len() && i < N { + dst[i] =3D (src[i] as char).to_ascii_lowercase() as u8; + i +=3D 1; + } + + dst +} + +pub(crate) const fn const_bytes_to_str(bytes: &[u8]) -> &str { + match core::str::from_utf8(bytes) { + Ok(string) =3D> string, + Err(_) =3D> kernel::build_error!("Bytes are not valid UTF-8."), + } +} diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 44c9ef1435a2..5df981920a94 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -39,6 +39,7 @@ source "drivers/gpu/vga/Kconfig" =20 source "drivers/gpu/host1x/Kconfig" source "drivers/gpu/ipu-v3/Kconfig" +source "drivers/gpu/nova-core/Kconfig" =20 source "drivers/gpu/drm/Kconfig" =20 --=20 2.48.1 From nobody Tue Dec 16 07:07:21 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0F93527C873; Thu, 6 Mar 2025 22:24:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741299860; cv=none; b=K0+c1Oa+irZt/+ZXRTR+rI4IhQy9NaEbArCjrIeYi9DOZ8/oZjJds1LaSzCuCp9zMqvhKLOrXHeVOkReIR27SH0+YZ/RmxVUB+az4GMYSrfq/yNzjUK98P6PfC6QWyS7ZefmMCdBlV3ZW+FtKuUYW+p52uc9XuMRhesGrCeISls= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741299860; c=relaxed/simple; bh=w2Ow+vb2xn4+QHtDYdg1uGN3ICwyDK4L2g+N3PIVV5Q=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ts0gWGngeBPMPgBqCsNX9/K94WhkUEqSlj675It53ZK0fehheI3Q4BHPaGbo6FEgJr3G4M0Px2BEZ69pnVmGsO0BeYjR/1ehDT87n/ngCSApcOLjYncL9+HFUqu/n0x9DJ+08CvMJ9vSMQHMEevbm83mzKU+ZSooLwb8F6zhRtA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=g17qllWB; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="g17qllWB" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0EAF9C4CEE9; Thu, 6 Mar 2025 22:24:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1741299859; bh=w2Ow+vb2xn4+QHtDYdg1uGN3ICwyDK4L2g+N3PIVV5Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=g17qllWBFC0SQ8HEsm7Y0r+66KsLYJEJNYEsK+8WEGjO4GFKlhngMq7XYMFaJodDg QBiA4s3dCOPGCixczPOaC9wGt1ZGYgp/TIU7KdodjlhTcAQ6uu5piW2pINxnsL9qZV 9dO9N9g3LReXt6frJZgAMPD/ciAjB0eqMkm8+DAinZ8Qq58GjSSuDuSLWGJNzfKubW oIERRZ4TgR6wotwO5SsQmVTt5tsaJqv8SZIj7kvOTXlKWDWz2mth6RHHU0g0tsXscF b4/BkdEJa2ikDAAAQEDXcFyAZ2MJ+GpCL460cqGp7q3KGlmD6sV9dLKBAofpcvLxc7 BLKDoQaeNce3A== From: Danilo Krummrich To: airlied@gmail.com, simona@ffwll.ch, corbet@lwn.net, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, ajanulgu@redhat.com, lyude@redhat.com, pstanner@redhat.com, zhiw@nvidia.com, cjia@nvidia.com, jhubbard@nvidia.com, bskeggs@nvidia.com, acurrid@nvidia.com Cc: ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, gregkh@linuxfoundation.org, mcgrof@kernel.org, russ.weight@linux.dev, dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, nouveau@lists.freedesktop.org, rust-for-linux@vger.kernel.org, Danilo Krummrich , Alexandre Courbot Subject: [PATCH v6 5/5] gpu: nova-core: add initial documentation Date: Thu, 6 Mar 2025 23:23:31 +0100 Message-ID: <20250306222336.23482-6-dakr@kernel.org> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250306222336.23482-1-dakr@kernel.org> References: <20250306222336.23482-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add the initial documentation of the Nova project. The initial project documentation consists out of a brief introduction of the project, as well as project guidelines both general and nova-core specific and a task list for nova-core specifically. The task list is divided into tasks for general Rust infrastructure required by the project, tasks regarding GSP enablement and firmware abstraction, general GPU driver tasks as well as tasks related to external API design and test infrastructure. Reviewed-by: Alexandre Courbot Signed-off-by: Danilo Krummrich --- Documentation/gpu/drivers.rst | 1 + Documentation/gpu/nova/core/guidelines.rst | 24 ++ Documentation/gpu/nova/core/todo.rst | 446 +++++++++++++++++++++ Documentation/gpu/nova/guidelines.rst | 69 ++++ Documentation/gpu/nova/index.rst | 30 ++ MAINTAINERS | 1 + 6 files changed, 571 insertions(+) create mode 100644 Documentation/gpu/nova/core/guidelines.rst create mode 100644 Documentation/gpu/nova/core/todo.rst create mode 100644 Documentation/gpu/nova/guidelines.rst create mode 100644 Documentation/gpu/nova/index.rst diff --git a/Documentation/gpu/drivers.rst b/Documentation/gpu/drivers.rst index 1f17ad0790d7..7c2c5dcb5fd4 100644 --- a/Documentation/gpu/drivers.rst +++ b/Documentation/gpu/drivers.rst @@ -24,6 +24,7 @@ GPU Driver Documentation panfrost panthor zynqmp + nova/index =20 .. only:: subproject and html =20 diff --git a/Documentation/gpu/nova/core/guidelines.rst b/Documentation/gpu= /nova/core/guidelines.rst new file mode 100644 index 000000000000..a389d65d7982 --- /dev/null +++ b/Documentation/gpu/nova/core/guidelines.rst @@ -0,0 +1,24 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Guidelines +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +This documents contains the guidelines for nova-core. Additionally, all co= mmon +guidelines of the Nova project do apply. + +Driver API +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +One main purpose of nova-core is to implement the abstraction around the +firmware interface of GSP and provide a firmware (version) independent API= for +2nd level drivers, such as nova-drm or the vGPU manager VFIO driver. + +Therefore, it is not permitted to leak firmware (version) specifics, throu= gh the +driver API, to 2nd level drivers. + +Acceptance Criteria +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +- To the extend possible, patches submitted to nova-core must be tested for + regressions with all 2nd level drivers. diff --git a/Documentation/gpu/nova/core/todo.rst b/Documentation/gpu/nova/= core/todo.rst new file mode 100644 index 000000000000..ca08377d3b73 --- /dev/null +++ b/Documentation/gpu/nova/core/todo.rst @@ -0,0 +1,446 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +=3D=3D=3D=3D=3D=3D=3D=3D=3D +Task List +=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Tasks may have the following fields: + +- ``Complexity``: Describes the required familiarity with Rust and / or the + corresponding kernel APIs or subsystems. There are four different comple= xities, + ``Beginner``, ``Intermediate``, ``Advanced`` and ``Expert``. +- ``Reference``: References to other tasks. +- ``Link``: Links to external resources. +- ``Contact``: The person that can be contacted for further information ab= out + the task. + +Enablement (Rust) +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Tasks that are not directly related to nova-core, but are preconditions in= terms +of required APIs. + +FromPrimitive API +----------------- + +Sometimes the need arises to convert a number to a value of an enum or a +structure. + +A good example from nova-core would be the ``Chipset`` enum type, which de= fines +the value ``AD102``. When probing the GPU the value ``0x192`` can be read = from a +certain register indication the chipset AD102. Hence, the enum value ``AD1= 02`` +should be derived from the number ``0x192``. Currently, nova-core uses a c= ustom +implementation (``Chipset::from_u32`` for this. + +Instead, it would be desirable to have something like the ``FromPrimitive`` +trait [1] from the num crate. + +Having this generalization also helps with implementing a generic macro th= at +automatically generates the corresponding mappings between a value and a n= umber. + +| Complexity: Beginner +| Link: https://docs.rs/num/latest/num/trait.FromPrimitive.html + +Generic register abstraction +---------------------------- + +Work out how register constants and structures can be automatically genera= ted +through generalized macros. + +Example: + +.. code-block:: rust + + register!(BOOT0, 0x0, u32, pci::Bar, Fields [ + MINOR_REVISION(3:0, RO), + MAJOR_REVISION(7:4, RO), + REVISION(7:0, RO), // Virtual register combining major and minor rev. + ]) + +This could expand to something like: + +.. code-block:: rust + + const BOOT0_OFFSET: usize =3D 0x00000000; + const BOOT0_MINOR_REVISION_SHIFT: u8 =3D 0; + const BOOT0_MINOR_REVISION_MASK: u32 =3D 0x0000000f; + const BOOT0_MAJOR_REVISION_SHIFT: u8 =3D 4; + const BOOT0_MAJOR_REVISION_MASK: u32 =3D 0x000000f0; + const BOOT0_REVISION_SHIFT: u8 =3D BOOT0_MINOR_REVISION_SHIFT; + const BOOT0_REVISION_MASK: u32 =3D BOOT0_MINOR_REVISION_MASK | BOOT0_MAJO= R_REVISION_MASK; + + struct Boot0(u32); + + impl Boot0 { + #[inline] + fn read(bar: &RevocableGuard<'_, pci::Bar>) -> Self { + Self(bar.readl(BOOT0_OFFSET)) + } + + #[inline] + fn minor_revision(&self) -> u32 { + (self.0 & BOOT0_MINOR_REVISION_MASK) >> BOOT0_MINOR_REVISION_SHIFT + } + + #[inline] + fn major_revision(&self) -> u32 { + (self.0 & BOOT0_MAJOR_REVISION_MASK) >> BOOT0_MAJOR_REVISION_SHIFT + } + + #[inline] + fn revision(&self) -> u32 { + (self.0 & BOOT0_REVISION_MASK) >> BOOT0_REVISION_SHIFT + } + } + +Usage: + +.. code-block:: rust + + let bar =3D bar.try_access().ok_or(ENXIO)?; + + let boot0 =3D Boot0::read(&bar); + pr_info!("Revision: {}\n", boot0.revision()); + +| Complexity: Advanced + +Delay / Sleep abstractions +-------------------------- + +Rust abstractions for the kernel's delay() and sleep() functions. + +FUJITA Tomonori plans to work on abstractions for read_poll_timeout_atomic= () +(and friends) [1]. + +| Complexity: Beginner +| Link: https://lore.kernel.org/netdev/20250228.080550.354359820929821928.= fujita.tomonori@gmail.com/ [1] + +IRQ abstractions +---------------- + +Rust abstractions for IRQ handling. + +There is active ongoing work from Daniel Almeida [1] for the "core" abstra= ctions +to request IRQs. + +Besides optional review and testing work, the required ``pci::Device`` code +around those core abstractions needs to be worked out. + +| Complexity: Intermediate +| Link: https://lore.kernel.org/lkml/20250122163932.46697-1-daniel.almeida= @collabora.com/ [1] +| Contact: Daniel Almeida + +Page abstraction for foreign pages +---------------------------------- + +Rust abstractions for pages not created by the Rust page abstraction witho= ut +direct ownership. + +There is active onging work from Abdiel Janulgue [1] and Lina [2]. + +| Complexity: Advanced +| Link: https://lore.kernel.org/linux-mm/20241119112408.779243-1-abdiel.ja= nulgue@gmail.com/ [1] +| Link: https://lore.kernel.org/rust-for-linux/20250202-rust-page-v1-0-e31= 70d7fe55e@asahilina.net/ [2] + +Scatterlist / sg_table abstractions +----------------------------------- + +Rust abstractions for scatterlist / sg_table. + +There is preceding work from Abdiel Janulgue, which hasn't made it to the +mailing list yet. + +| Complexity: Intermediate +| Contact: Abdiel Janulgue + +ELF utils +--------- + +Rust implementation of ELF header representation to retrieve section header +tables, names, and data from an ELF-formatted images. + +There is preceding work from Abdiel Janulgue, which hasn't made it to the +mailing list yet. + +| Complexity: Beginner +| Contact: Abdiel Janulgue + +PCI MISC APIs +------------- + +Extend the existing PCI device / driver abstractions by SR-IOV, config spa= ce, +capability, MSI API abstractions. + +| Complexity: Beginner + +Auxiliary bus abstractions +-------------------------- + +Rust abstraction for the auxiliary bus APIs. + +This is needed to connect nova-core to the nova-drm driver. + +| Complexity: Intermediate + +Debugfs abstractions +-------------------- + +Rust abstraction for debugfs APIs. + +| Reference: Export GSP log buffers +| Complexity: Intermediate + +Vec extensions +-------------- + +Implement ``Vec::truncate`` and ``Vec::resize``. + +Currently this is used for some experimental code to parse the vBIOS. + +| Reference vBIOS support +| Complexity: Beginner + +GPU (general) +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Parse firmware headers +---------------------- + +Parse ELF headers from the firmware files loaded from the filesystem. + +| Reference: ELF utils +| Complexity: Beginner +| Contact: Abdiel Janulgue + +Build radix3 page table +----------------------- + +Build the radix3 page table to map the firmware. + +| Complexity: Intermediate +| Contact: Abdiel Janulgue + +vBIOS support +------------- + +Parse the vBIOS and probe the structures required for driver initializatio= n. + +| Contact: Dave Airlie +| Reference: Vec extensions +| Complexity: Intermediate + +Initial Devinit support +----------------------- + +Implement BIOS Device Initialization, i.e. memory sizing, waiting, PLL +configuration. + +| Contact: Dave Airlie +| Complexity: Beginner + +Boot Falcon controller +---------------------- + +Infrastructure to load and execute falcon (sec2) firmware images; handle t= he +GSP falcon processor and fwsec loading. + +| Complexity: Advanced +| Contact: Dave Airlie + +GPU Timer support +----------------- + +Support for the GPU's internal timer peripheral. + +| Complexity: Beginner +| Contact: Dave Airlie + +MMU / PT management +------------------- + +Work out the architecture for MMU / page table management. + +We need to consider that nova-drm will need rather fine-grained control, +especially in terms of locking, in order to be able to implement asynchron= ous +Vulkan queues. + +While generally sharing the corresponding code is desirable, it needs to be +evaluated how (and if at all) sharing the corresponding code is expedient. + +| Complexity: Expert + +VRAM memory allocator +--------------------- + +Investigate options for a VRAM memory allocator. + +Some possible options: + - Rust abstractions for + - RB tree (interval tree) / drm_mm + - maple_tree + - native Rust collections + +| Complexity: Advanced + +Instance Memory +--------------- + +Implement support for instmem (bar2) used to store page tables. + +| Complexity: Intermediate +| Contact: Dave Airlie + +GPU System Processor (GSP) +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D + +Export GSP log buffers +---------------------- + +Recent patches from Timur Tabi [1] added support to expose GSP-RM log buff= ers +(even after failure to probe the driver) through debugfs. + +This is also an interesting feature for nova-core, especially in the early= days. + +| Link: https://lore.kernel.org/nouveau/20241030202952.694055-2-ttabi@nvid= ia.com/ [1] +| Reference: Debugfs abstractions +| Complexity: Intermediate + +GSP firmware abstraction +------------------------ + +The GSP-RM firmware API is unstable and may incompatibly change from versi= on to +version, in terms of data structures and semantics. + +This problem is one of the big motivations for using Rust for nova-core, s= ince +it turns out that Rust's procedural macro feature provides a rather elegan= t way +to address this issue: + +1. generate Rust structures from the C headers in a separate namespace per= version +2. build abstraction structures (within a generic namespace) that implemen= t the + firmware interfaces; annotate the differences in implementation with ve= rsion + identifiers +3. use a procedural macro to generate the actual per version implementatio= n out + of this abstraction +4. instantiate the correct version type one on runtime (can be sure that a= ll + have the same interface because it's defined by a common trait) + +There is a PoC implementation of this pattern, in the context of the nova-= core +PoC driver. + +This task aims at refining the feature and ideally generalize it, to be us= able +by other drivers as well. + +| Complexity: Expert + +GSP message queue +----------------- + +Implement low level GSP message queue (command, status) for communication +between the kernel driver and GSP. + +| Complexity: Advanced +| Contact: Dave Airlie + +Bootstrap GSP +------------- + +Call the boot firmware to boot the GSP processor; execute initial control +messages. + +| Complexity: Intermediate +| Contact: Dave Airlie + +Client / Device APIs +-------------------- + +Implement the GSP message interface for client / device allocation and the +corresponding client and device allocation APIs. + +| Complexity: Intermediate +| Contact: Dave Airlie + +Bar PDE handling +---------------- + +Synchronize page table handling for BARs between the kernel driver and GSP. + +| Complexity: Beginner +| Contact: Dave Airlie + +FIFO engine +----------- + +Implement support for the FIFO engine, i.e. the corresponding GSP message +interface and provide an API for chid allocation and channel handling. + +| Complexity: Advanced +| Contact: Dave Airlie + +GR engine +--------- + +Implement support for the graphics engine, i.e. the corresponding GSP mess= age +interface and provide an API for (golden) context creation and promotion. + +| Complexity: Advanced +| Contact: Dave Airlie + +CE engine +--------- + +Implement support for the copy engine, i.e. the corresponding GSP message +interface. + +| Complexity: Intermediate +| Contact: Dave Airlie + +VFN IRQ controller +------------------ + +Support for the VFN interrupt controller. + +| Complexity: Intermediate +| Contact: Dave Airlie + +External APIs +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +nova-core base API +------------------ + +Work out the common pieces of the API to connect 2nd level drivers, i.e. v= GPU +manager and nova-drm. + +| Complexity: Advanced + +vGPU manager API +---------------- + +Work out the API parts required by the vGPU manager, which are not covered= by +the base API. + +| Complexity: Advanced + +nova-core C API +--------------- + +Implement a C wrapper for the APIs required by the vGPU manager driver. + +| Complexity: Intermediate + +Testing +=3D=3D=3D=3D=3D=3D=3D + +CI pipeline +----------- + +Investigate option for continuous integration testing. + +This can go from as simple as running KUnit tests over running (graphics) = CTS to +booting up (multiple) guest VMs to test VFIO use-cases. + +It might also be worth to consider the introduction of a new test suite di= rectly +sitting on top of the uAPI for more targeted testing and debugging. There = may be +options for collaboration / shared code with the Mesa project. + +| Complexity: Advanced diff --git a/Documentation/gpu/nova/guidelines.rst b/Documentation/gpu/nova= /guidelines.rst new file mode 100644 index 000000000000..13ab13984a18 --- /dev/null +++ b/Documentation/gpu/nova/guidelines.rst @@ -0,0 +1,69 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Guidelines +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +This document describes the general project guidelines that apply to nova-= core +and nova-drm. + +Language +=3D=3D=3D=3D=3D=3D=3D=3D + +The Nova project uses the Rust programming language. In this context, all = rules +of the Rust for Linux project as documented in +:doc:`../../rust/general-information` apply. Additionally, the following r= ules +apply. + +- Unless technically necessary otherwise (e.g. uAPI), any driver code is w= ritten + in Rust. + +- Unless technically necessary, unsafe Rust code must be avoided. In case = of + technical necessity, unsafe code should be isolated in a separate compon= ent + providing a safe API for other driver code to use. + +Style +----- + +All rules of the Rust for Linux project as documented in +:doc:`../../rust/coding-guidelines` apply. + +For a submit checklist, please also see the `Rust for Linux Submit checkli= st +addendum `_. + +Documentation +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The availability of proper documentation is essential in terms of scalabil= ity, +accessibility for new contributors and maintainability of a project in gen= eral, +but especially for a driver running as complex hardware as Nova is targeti= ng. + +Hence, adding documentation of any kind is very much encouraged by the pro= ject. + +Besides that, there are some minimum requirements. + +- Every non-private structure needs at least a brief doc comment explainin= g the + semantical sense of the structure, as well as potential locking and life= time + requirements. It is encouraged to have the same minimum documentation for + non-trivial private structures. + +- uAPIs must be fully documented with kernel-doc comments; additionally, t= he + semantical behavior must be explained including potential special or cor= ner + cases. + +- The APIs connecting the 1st level driver (nova-core) with 2nd level driv= ers + must be fully documented. This includes doc comments, potential locking = and + lifetime requirements, as well as example code if applicable. + +- Abbreviations must be explained when introduced; terminology must be uni= quely + defined. + +- Register addresses, layouts, shift values and masks must be defined prop= erly; + unless obvious, the semantical sense must be documented. This only appli= es if + the author is able to obtain the corresponding information. + +Acceptance Criteria +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +- Patches must only be applied if reviewed by at least one other person on= the + mailing list; this also applies for maintainers. diff --git a/Documentation/gpu/nova/index.rst b/Documentation/gpu/nova/inde= x.rst new file mode 100644 index 000000000000..2701b3f4af35 --- /dev/null +++ b/Documentation/gpu/nova/index.rst @@ -0,0 +1,30 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +nova NVIDIA GPU drivers +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The nova driver project consists out of two separate drivers nova-core and +nova-drm and intends to supersede the nouveau driver for NVIDIA GPUs based= on +the GPU System Processor (GSP). + +The following documents apply to both nova-core and nova-drm. + +.. toctree:: + :titlesonly: + + guidelines + +nova-core +=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The nova-core driver is the core driver for NVIDIA GPUs based on GSP. nova= -core, +as the 1st level driver, provides an abstraction around the GPUs hard- and +firmware interfaces providing a common base for 2nd level drivers, such as= the +vGPU manager VFIO driver and the nova-drm driver. + +.. toctree:: + :titlesonly: + + core/guidelines + core/todo diff --git a/MAINTAINERS b/MAINTAINERS index ede8abee210a..9530899b6b0a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7458,6 +7458,7 @@ Q: https://patchwork.freedesktop.org/project/nouveau/ B: https://gitlab.freedesktop.org/drm/nova/-/issues C: irc://irc.oftc.net/nouveau T: git https://gitlab.freedesktop.org/drm/nova.git nova-next +F: Documentation/gpu/nova/ F: drivers/gpu/nova-core/ =20 DRM DRIVER FOR OLIMEX LCD-OLINUXINO PANELS --=20 2.48.1