From: Alistair Popple <apopple@nvidia.com>
To: rust-for-linux@vger.kernel.org, nova-gpu <nova-gpu@lists.linux.dev>
Cc: Alistair Popple <apopple@nvidia.com>,
M Henning <mhenning@darkrefraction.com>,
Danilo Krummrich <dakr@kernel.org>,
Alice Ryhl <aliceryhl@google.com>,
David Airlie <airlied@gmail.com>,
Alexandre Courbot <acourbot@nvidia.com>,
Benno Lossin <lossin@kernel.org>, Gary Guo <gary@garyguo.net>,
Eliot Courtney <ecourtney@nvidia.com>,
John Hubbard <jhubbard@nvidia.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
"Rafael J. Wysocki" <rafael@kernel.org>,
linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org
Subject: [PATCH v6 02/13] gpu: nova-core: Add public driver API to nova-core
Date: Wed, 9 Sep 2026 16:44:55 +1000 [thread overview]
Message-ID: <20260909064506.910162-3-apopple@nvidia.com> (raw)
In-Reply-To: <20260909064506.910162-1-apopple@nvidia.com>
Nova core will be used to export core functionality to other drivers
which will bind to it via auxiliary bus devices. Add a NovaCoreApi type
which drivers can use to call nova-core methods.
Auxiliary bus drivers obtain a NovaCoreApiHandle for a particular GPU
using NovaCoreApi::of(). This takes a reference to a bound auxiliary bus
device and checks that its registration data is a NovaCoreApi. The
NovaCoreApi itself is then accessed by passing a closure to
NovaCoreApiHandle::with().
Closure based access is used because NovaCoreApi cannot be assumed to be
covariant over its lifetime. It references the Gpu, which will carry
locks around types holding device resources, making it invariant.
Covariant sub-fields can still be returned directly from the closure
thanks to the lifetime bound on registration_data_with().
Co-developed-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Alistair Popple <apopple@nvidia.com>
---
Changes since v5:
- Access NovaCoreApi through a closure based NovaCoreApiHandle using
ForLt instead of a direct reference via CovariantForLt, as NovaCoreApi
will not remain covariant. Based on a diff from Danilo.
Changes since v4:
- Move the `_reg` field declaration, since it must be dropped before
`gpu` to satisfy the safety requirements of holding a reference to it.
Changes since v2:
- Add accidentally dropped TODO comment
Changes since v1:
- Rework unsafe pin-init to make safety comments clearer, suggested
by Danilo.
- s/allow(dead_code)/expect(unused)/
---
drivers/gpu/nova-core/api.rs | 48 ++++++++++++++++++++++++++++++
drivers/gpu/nova-core/driver.rs | 48 +++++++++++++++++++++---------
drivers/gpu/nova-core/gsp/hal.rs | 2 +-
drivers/gpu/nova-core/nova_core.rs | 1 +
4 files changed, 84 insertions(+), 15 deletions(-)
create mode 100644 drivers/gpu/nova-core/api.rs
diff --git a/drivers/gpu/nova-core/api.rs b/drivers/gpu/nova-core/api.rs
new file mode 100644
index 000000000000..ae023242594e
--- /dev/null
+++ b/drivers/gpu/nova-core/api.rs
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Nova-core auxbus data. Contains all the methods used by the auxbus drivers
+//! to interact with nova-core.
+
+use core::pin::Pin;
+
+use kernel::{
+ auxiliary,
+ device::Bound,
+ prelude::*,
+ types::ForLt, //
+};
+
+use crate::gpu::Gpu;
+
+/// API handle for the auxiliary bus child drivers to interact with nova-core.
+pub struct NovaCoreApi<'bound> {
+ #[expect(unused)]
+ pub(crate) gpu: Pin<&'bound Gpu<'bound>>,
+}
+
+impl NovaCoreApi<'_> {
+ /// Obtain a [`NovaCoreApi`] handle from an auxiliary device registered
+ /// by nova-core.
+ pub fn of(adev: &auxiliary::Device<Bound>) -> Result<NovaCoreApiHandle<'_>> {
+ NovaCoreApiHandle::of(adev)
+ }
+}
+
+/// Expose a handle to nova-core API
+pub struct NovaCoreApiHandle<'a> {
+ adev: &'a auxiliary::Device<Bound>,
+}
+
+impl<'a> NovaCoreApiHandle<'a> {
+ fn of(adev: &'a auxiliary::Device<Bound>) -> Result<Self> {
+ adev.registration_data_with::<ForLt!(NovaCoreApi<'_>), ()>(|_| ())?;
+ Ok(Self { adev })
+ }
+
+ /// Access the [`NovaCoreApi`] through a closure.
+ pub fn with<R>(&self, f: impl for<'b> FnOnce(Pin<&'a NovaCoreApi<'b>>) -> R) -> R {
+ self.adev
+ .registration_data_with::<ForLt!(NovaCoreApi<'_>), R>(f)
+ .expect("TypeId was validated in NovaCoreApiHandle::of()")
+ }
+}
diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs
index bbd93959e0b2..922068df7707 100644
--- a/drivers/gpu/nova-core/driver.rs
+++ b/drivers/gpu/nova-core/driver.rs
@@ -15,21 +15,24 @@
Atomic,
Relaxed, //
},
- types::CovariantForLt,
+ types::ForLt,
};
-use crate::gpu::Gpu;
+use crate::{
+ api::NovaCoreApi,
+ gpu::Gpu, //
+};
/// Counter for generating unique auxiliary device IDs.
static AUXILIARY_ID_COUNTER: Atomic<u32> = Atomic::new(0);
#[pin_data]
pub(crate) struct NovaCore<'bound> {
+ #[allow(clippy::type_complexity)]
+ _reg: auxiliary::Registration<'bound, ForLt!(NovaCoreApi<'_>)>,
#[pin]
pub(crate) gpu: Gpu<'bound>,
bar: pci::Bar<'bound, BAR0_SIZE>,
- #[allow(clippy::type_complexity)]
- _reg: auxiliary::Registration<'bound, CovariantForLt!(())>,
}
pub(crate) struct NovaCoreDriver;
@@ -82,18 +85,35 @@ fn probe<'bound>(
// TODO: Use `&bar` self-referential pin-init syntax once available.
//
// SAFETY: `bar` is initialized before this expression is evaluated
- // (`try_pin_init!()` initializes fields in declaration order), lives at a pinned
+ // (`try_pin_init!()` initializes fields in initializer order), lives at a pinned
// stable address, and is dropped after `gpu` (struct field drop order).
gpu <- Gpu::new(pdev, unsafe { &*core::ptr::from_ref(bar) }),
- _reg: auxiliary::Registration::new(
- pdev.as_ref(),
- c"nova-drm",
- // TODO[XARR]: Use XArray or perhaps IDA for proper ID allocation/recycling. For
- // now, use a simple atomic counter that never recycles IDs.
- AUXILIARY_ID_COUNTER.fetch_add(1, Relaxed),
- crate::MODULE_NAME,
- (),
- )?,
+ _reg: {
+ // TODO: Use `&gpu` self-referential pin-init syntax once available.
+ //
+ // SAFETY: `gpu` is initialized before this expression is evaluated
+ // (`try_pin_init!()` initializes fields in initializer order), lives at
+ // a pinned stable address, and is dropped after `_reg` (struct field
+ // drop order).
+ let gpu = unsafe {
+ Pin::new_unchecked(&*core::ptr::from_ref(gpu.as_ref().get_ref()))
+ };
+
+ // SAFETY: `NovaCore` is dropped when the device is unbound;
+ // i.e. `mem::forget()` is never called on it.
+ unsafe {
+ auxiliary::Registration::new_with_lt(
+ pdev.as_ref(),
+ c"nova-drm",
+ // TODO[XARR]: Use XArray or perhaps IDA for proper ID
+ // allocation/recycling. For now, use a simple atomic counter that
+ // never recycles IDs.
+ AUXILIARY_ID_COUNTER.fetch_add(1, Relaxed),
+ crate::MODULE_NAME,
+ NovaCoreApi { gpu },
+ )?
+ }
+ },
}))
})
}
diff --git a/drivers/gpu/nova-core/gsp/hal.rs b/drivers/gpu/nova-core/gsp/hal.rs
index 5850fa0fe0e9..0c8670c57bbb 100644
--- a/drivers/gpu/nova-core/gsp/hal.rs
+++ b/drivers/gpu/nova-core/gsp/hal.rs
@@ -24,7 +24,7 @@
/// The GSP unload code might run in a situation where we cannot load firmware dynamically (e.g.
/// because we are in shutdown and the file system is not accessible anymore). Thus, the firmware
/// required for unloading is prepared at load time, and stored here until it needs to be run.
-pub(super) trait UnloadBundle: Send {
+pub(super) trait UnloadBundle: Send + Sync {
/// Performs the steps required to properly reset the GSP after it has been stopped.
fn run(&self, ctx: &mut GspBootContext<'_, '_>) -> Result;
}
diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs
index 35a8b1214b0e..503898cee042 100644
--- a/drivers/gpu/nova-core/nova_core.rs
+++ b/drivers/gpu/nova-core/nova_core.rs
@@ -10,6 +10,7 @@
InPlaceModule, //
};
+pub mod api;
mod driver;
mod falcon;
mod fb;
--
2.54.0
next prev parent reply other threads:[~2026-09-09 6:45 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-09 6:44 [PATCH v6 00/13] gpu: nova: Export parameters from nova-core to nova-drm Alistair Popple
2026-09-09 6:44 ` [PATCH v6 01/13] rust: auxiliary: let registration_data_with() closures return covariant sub-fields Alistair Popple
2026-09-09 6:44 ` Alistair Popple [this message]
2026-09-09 6:44 ` [PATCH v6 03/13] drm: nova: Add DRM registration data Alistair Popple
2026-09-09 6:44 ` [PATCH v6 04/13] drm: nova: Add GPU architecture enum to nova-drm UAPI Alistair Popple
2026-09-09 6:44 ` [PATCH v6 05/13] drm: nova: Add chipid " Alistair Popple
2026-09-09 6:44 ` [PATCH v6 06/13] rust: uaccess: add UserSliceWriter::write_truncated() Alistair Popple
2026-09-09 6:45 ` [PATCH v6 07/13] drm: nova: Add an info ioctl Alistair Popple
2026-09-09 6:45 ` [PATCH v6 08/13] drm: nova: Add usable VRAM size to GPU info Alistair Popple
2026-09-09 6:45 ` [PATCH v6 09/13] drm: nova: Use nova-core to read VRAM_BAR_SIZE parameter Alistair Popple
2026-09-09 6:45 ` [PATCH v6 10/13] drm: nova: Expose a render node Alistair Popple
2026-09-09 6:45 ` [PATCH v6 11/13] drm: nova: Report GPU name in GPU info Alistair Popple
2026-09-09 6:45 ` [PATCH v6 12/13] drm: nova: Report GPU short " Alistair Popple
2026-09-09 6:45 ` [PATCH v6 13/13] drm: nova: Report GPU GID " Alistair Popple
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260909064506.910162-3-apopple@nvidia.com \
--to=apopple@nvidia.com \
--cc=acourbot@nvidia.com \
--cc=airlied@gmail.com \
--cc=aliceryhl@google.com \
--cc=dakr@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=ecourtney@nvidia.com \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=jhubbard@nvidia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=mhenning@darkrefraction.com \
--cc=nova-gpu@lists.linux.dev \
--cc=rafael@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox