* [PATCH v6 00/13] gpu: nova: Export parameters from nova-core to nova-drm
@ 2026-09-09 6:44 Alistair Popple
2026-09-09 6:44 ` [PATCH v6 01/13] rust: auxiliary: let registration_data_with() closures return covariant sub-fields Alistair Popple
` (12 more replies)
0 siblings, 13 replies; 16+ messages in thread
From: Alistair Popple @ 2026-09-09 6:44 UTC (permalink / raw)
To: rust-for-linux, nova-gpu
Cc: Alistair Popple, M Henning, Danilo Krummrich, Alice Ryhl,
David Airlie, Alexandre Courbot, Benno Lossin, Gary Guo,
Eliot Courtney, John Hubbard, Greg Kroah-Hartman,
Rafael J. Wysocki, linux-kernel, dri-devel
This patch series adds some basic GPU properties via a new GPU info
ioctl. The goal is to provide enough information for a basic CUDA
deviceQuery sample, and the equivalent Mesa device properties, to be
populated from nova-drm.
It builds on the "drm: Higher-Ranked Lifetime private data" series[1] to
correctly manage lifetimes of registration data shared between DRM,
auxbus and nova-core, and on "ForLt/CovariantForLt split, auxiliary
closure API and DevresLt"[2]. Both are now in drm-rust-next.
This series exposes a latent build breakage with
CONFIG_RUST_DEBUG_ASSERTIONS=y, as nothing from the uapi crate is exported
to modules. The fix for this has been posted as a standalone patch at [3].
Properties are exported via a new NovaCoreApi type which implements
methods to read data from the GPU. This has been implemented in a separate
module to make the public API implementations obvious and to keep them in
one place. Auxiliary bus drivers obtain a NovaCoreApiHandle using
NovaCoreApi::of() and access the NovaCoreApi through a closure. This avoids
assuming registration data is covariant. This required a small change to
the auxiliary bus registration_data_with() closure signature, which is the
first patch.
The handle is stored as part of the DRM registration data and used to
interact with the GPU via the nova-core driver.
A new info ioctl is introduced which provides an info type field and a
method for reading extendable structs containing GPU information. The GPU
info reports the architecture and an opaque chip identifier along with
the usable VRAM size, the GPU names and the GID.
This series can be tested using drm-test[4]. The merge request adding the
tests[5] will be updated once this has been posted. A pull request for Mesa
has also been raised but is out of date. That will be updated once this
series has been merged.
Changes since v5:
- Export an opaque chipid alongside the architecture instead of the
implementation.
- Access NovaCoreApi through a closure based NovaCoreApiHandle using
ForLt as it will not remain covariant, based on a diff from Danilo.
Add the auxiliary bus change suggested by Gary that lets the closure
return covariant sub-fields directly
- Expose Spec and the GSP static info via accessors rather than
forwarding methods, and use the validated GPU name accessors
- Rename struct drm_nova_gpu_info to drm_nova_info_gpu for consistency
and document the NULL data pointer size query
- Handle the size query in write_info()
- Address further review comments
Changes since v4:
- No longer export chip-id, instead export architecture and implementation
- Add a separate info ioctl with types to read GPU info as suggested by
Danilo
Changes since v3:
- Use an ioctl to return all parameters rather than multiple key/value
queries
Changes since v2:
- Addressed review Danilo and Alex
- Minor renames to better align with HW based on internal feedback
Changes since v1:
- Address review comments from Danilo
- Add an API call to read VRAM PCI BAR size using nova-core
[1] - https://lore.kernel.org/rust-for-linux/20260628145406.2107056-1-dakr@kernel.org/
[2] - https://lore.kernel.org/driver-core/20260626183630.2585057-1-dakr@kernel.org/
[3] - https://lore.kernel.org/rust-for-linux/20260909060623.888777-1-apopple@nvidia.com/
[4] - https://gitlab.freedesktop.org/dakr/drm-test
[5] - https://gitlab.freedesktop.org/dakr/drm-test/-/merge_requests/1
Cc: M Henning <mhenning@darkrefraction.com>
Cc: Danilo Krummrich <dakr@kernel.org>
Cc: Alice Ryhl <aliceryhl@google.com>
Cc: David Airlie <airlied@gmail.com>
Cc: Alexandre Courbot <acourbot@nvidia.com>
Cc: Benno Lossin <lossin@kernel.org>
Cc: Gary Guo <gary@garyguo.net>
Cc: Eliot Courtney <ecourtney@nvidia.com>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: "Rafael J. Wysocki" <rafael@kernel.org>
Cc: linux-kernel@vger.kernel.org
Cc: nova-gpu@lists.linux.dev
Cc: dri-devel@lists.freedesktop.org
Cc: rust-for-linux@vger.kernel.org
Alistair Popple (13):
rust: auxiliary: let registration_data_with() closures return
covariant sub-fields
gpu: nova-core: Add public driver API to nova-core
drm: nova: Add DRM registration data
drm: nova: Add GPU architecture enum to nova-drm UAPI
drm: nova: Add chipid enum to nova-drm UAPI
rust: uaccess: add UserSliceWriter::write_truncated()
drm: nova: Add an info ioctl
drm: nova: Add usable VRAM size to GPU info
drm: nova: Use nova-core to read VRAM_BAR_SIZE parameter
drm: nova: Expose a render node
drm: nova: Report GPU name in GPU info
drm: nova: Report GPU short name in GPU info
drm: nova: Report GPU GID in GPU info
drivers/gpu/drm/nova/driver.rs | 19 +++-
drivers/gpu/drm/nova/file.rs | 109 +++++++++++++++++---
drivers/gpu/nova-core/api.rs | 68 ++++++++++++
drivers/gpu/nova-core/driver.rs | 48 ++++++---
drivers/gpu/nova-core/gpu.rs | 111 +++++++++++---------
drivers/gpu/nova-core/gsp/commands.rs | 31 +++++-
drivers/gpu/nova-core/gsp/fw/commands.rs | 15 +++
drivers/gpu/nova-core/gsp/hal.rs | 2 +-
drivers/gpu/nova-core/nova_core.rs | 1 +
drivers/gpu/nova-core/num.rs | 2 +-
include/uapi/drm/nova_drm.h | 126 +++++++++++++++++++++++
rust/kernel/auxiliary.rs | 17 +--
rust/kernel/uaccess.rs | 14 +++
13 files changed, 476 insertions(+), 87 deletions(-)
create mode 100644 drivers/gpu/nova-core/api.rs
base-commit: b705c185105762676aa6ec16cf976101df87cc35
prerequisite-patch-id: 76f69e9677d66758b273f8415cc7785347544655
--
2.54.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v6 01/13] rust: auxiliary: let registration_data_with() closures return covariant sub-fields
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 ` Alistair Popple
2026-09-09 6:57 ` sashiko-bot
2026-09-09 6:44 ` [PATCH v6 02/13] gpu: nova-core: Add public driver API to nova-core Alistair Popple
` (11 subsequent siblings)
12 siblings, 1 reply; 16+ messages in thread
From: Alistair Popple @ 2026-09-09 6:44 UTC (permalink / raw)
To: rust-for-linux, nova-gpu
Cc: Alistair Popple, M Henning, Danilo Krummrich, Alice Ryhl,
David Airlie, Alexandre Courbot, Benno Lossin, Gary Guo,
Eliot Courtney, John Hubbard, Greg Kroah-Hartman,
Rafael J. Wysocki, linux-kernel, dri-devel
The closure passed to registration_data_with() currently receives
`Pin<&'a F::Of<'a>>` with `'a` universally quantified. This prevents the
closure from returning references derived from the registration data,
even for sub-fields that are covariant in their lifetime, because the
compiler cannot relate `'a` to any lifetime the caller knows about.
Tie the outer reference to the `&self` lifetime instead, i.e. pass
`Pin<&'this F::Of<'a>>`. This gives the closure the implied bound
`'a: 'this`, so covariant sub-fields such as `&'a T` can be coerced to
`'this` and returned directly, while invariant fields still cannot be
coerced and therefore cannot escape with an incorrect lifetime.
This allows auxiliary child drivers to project covariant data out of
invariant registration data without having to wrap every use in a
closure.
Link: https://lore.kernel.org/nova-gpu/DL3WPTVM033J.33RWYCZOC67Z1@kernel.org/
Suggested-by: Gary Guo <gary@garyguo.net>
Co-developed-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Alistair Popple <apopple@nvidia.com>
---
Changes since v5:
- New for v6
---
rust/kernel/auxiliary.rs | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs
index 60dfbec8f330..06f816420790 100644
--- a/rust/kernel/auxiliary.rs
+++ b/rust/kernel/auxiliary.rs
@@ -305,6 +305,10 @@ unsafe fn registration_data_pinned<F: ForLt + 'static>(&self) -> Result<Pin<&F::
/// `F` is the [`ForLt`](trait@ForLt) encoding of the data type. The closure receives a pinned
/// reference to the registration data.
///
+ /// The outer reference carries the `&self` lifetime while the inner type carries the HRTB
+ /// lifetime `'a`, implying `'a` outlives `&self`. This allows the closure to coerce covariant
+ /// sub-fields (e.g. `&'a T` to the caller's lifetime) and return them directly in `R`.
+ ///
/// For covariant types that implement [`trait@CovariantForLt`], prefer
/// [`registration_data`](Self::registration_data) which returns a direct reference.
///
@@ -314,13 +318,14 @@ unsafe fn registration_data_pinned<F: ForLt + 'static>(&self) -> Result<Pin<&F::
/// Returns [`ENOENT`] if no registration data has been set, e.g. when the device was
/// registered by a C driver.
#[inline]
- pub fn registration_data_with<F: ForLt + 'static, R>(
- &self,
- f: impl for<'a> FnOnce(Pin<&'a F::Of<'a>>) -> R,
+ pub fn registration_data_with<'this, F: ForLt + 'static, R>(
+ &'this self,
+ f: impl for<'a> FnOnce(Pin<&'this F::Of<'a>>) -> R,
) -> Result<R> {
- // SAFETY: The HRTB closure prevents the caller from smuggling in references with a
- // concrete short lifetime, making the round-trip from `'static` sound regardless of
- // variance.
+ // SAFETY: The HRTB on the inner type prevents the caller from exploiting a specific
+ // choice of `'a`. Covariant sub-fields can be safely coerced to `'this`, while
+ // invariant fields cannot be coerced and thus cannot escape with an incorrect
+ // lifetime.
let pinned = unsafe { self.registration_data_pinned::<F>()? };
Ok(f(pinned))
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v6 02/13] gpu: nova-core: Add public driver API to nova-core
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
2026-09-09 6:44 ` [PATCH v6 03/13] drm: nova: Add DRM registration data Alistair Popple
` (10 subsequent siblings)
12 siblings, 0 replies; 16+ messages in thread
From: Alistair Popple @ 2026-09-09 6:44 UTC (permalink / raw)
To: rust-for-linux, nova-gpu
Cc: Alistair Popple, M Henning, Danilo Krummrich, Alice Ryhl,
David Airlie, Alexandre Courbot, Benno Lossin, Gary Guo,
Eliot Courtney, John Hubbard, Greg Kroah-Hartman,
Rafael J. Wysocki, linux-kernel, dri-devel
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
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v6 03/13] drm: nova: Add DRM registration data
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 ` [PATCH v6 02/13] gpu: nova-core: Add public driver API to nova-core Alistair Popple
@ 2026-09-09 6:44 ` Alistair Popple
2026-09-09 6:44 ` [PATCH v6 04/13] drm: nova: Add GPU architecture enum to nova-drm UAPI Alistair Popple
` (9 subsequent siblings)
12 siblings, 0 replies; 16+ messages in thread
From: Alistair Popple @ 2026-09-09 6:44 UTC (permalink / raw)
To: rust-for-linux, nova-gpu
Cc: Alistair Popple, M Henning, Danilo Krummrich, Alice Ryhl,
David Airlie, Alexandre Courbot, Benno Lossin, Gary Guo,
Eliot Courtney, John Hubbard, Greg Kroah-Hartman,
Rafael J. Wysocki, linux-kernel, dri-devel
Currently the nova-drm stub driver doesn't really interact with a real
device, so it doesn't have any registration data and has no way to call
into nova-core.
To allow for this add a DrmRegData type which will hold a
NovaCoreApiHandle for the NovaCoreApi associated with the auxbus device.
Signed-off-by: Alistair Popple <apopple@nvidia.com>
Suggested-by: Danilo Krummrich <dakr@kernel.org>
---
Changes since v5:
- Store a NovaCoreApiHandle rather than a reference to NovaCoreApi
Changes from v2:
- Add newline in crate import
Changes from v1:
- Drop unrelated device::Bound removal.
- Switch exisiting import to vertical style.
- s/allow(dead_code)/expect(unused)/
---
drivers/gpu/drm/nova/driver.rs | 18 ++++++++++++++++--
drivers/gpu/drm/nova/file.rs | 12 ++++++++----
2 files changed, 24 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/nova/driver.rs b/drivers/gpu/drm/nova/driver.rs
index 60752bccddc0..52550e694729 100644
--- a/drivers/gpu/drm/nova/driver.rs
+++ b/drivers/gpu/drm/nova/driver.rs
@@ -18,6 +18,11 @@
use crate::file::File;
use crate::gem::NovaObject;
+use nova_core::api::{
+ NovaCoreApi,
+ NovaCoreApiHandle, //
+};
+
pub(crate) struct NovaDriver;
pub(crate) struct Nova<'bound> {
@@ -26,6 +31,12 @@ pub(crate) struct Nova<'bound> {
_reg: drm::Registration<'bound, NovaDriver>,
}
+/// DRM registration data, accessible from ioctl handlers via the registration guard.
+pub(crate) struct DrmRegData<'bound> {
+ #[expect(unused)]
+ pub(crate) api: NovaCoreApiHandle<'bound>,
+}
+
/// Convienence type alias for the DRM device type for this driver
pub(crate) type NovaDevice<Ctx = drm::Normal> = drm::Device<NovaDriver, Ctx>;
@@ -59,9 +70,12 @@ fn probe<'bound>(
_info: &'bound Self::IdInfo,
) -> impl PinInit<Self::Data<'bound>, Error> + 'bound {
let drm = drm::UnregisteredDevice::<Self>::new(adev, Ok(()))?;
+ let reg_data = DrmRegData {
+ api: NovaCoreApi::of(adev)?,
+ };
// SAFETY: `reg` is stored in `Nova` and dropped when the driver is unbound; it is
// never forgotten.
- let reg = unsafe { drm::Registration::new(adev.as_ref(), drm, (), 0)? };
+ let reg = unsafe { drm::Registration::new(adev.as_ref(), drm, reg_data, 0)? };
Ok(Nova {
drm: reg.device().into(),
@@ -73,7 +87,7 @@ fn probe<'bound>(
#[vtable]
impl drm::Driver for NovaDriver {
type Data = ();
- type RegistrationData<'a> = ();
+ type RegistrationData<'a> = DrmRegData<'a>;
type File = File;
type Object = gem::Object<NovaObject>;
type ParentDevice<Ctx: DeviceContext> = auxiliary::Device<Ctx>;
diff --git a/drivers/gpu/drm/nova/file.rs b/drivers/gpu/drm/nova/file.rs
index 298c02bacb4b..1156df51c533 100644
--- a/drivers/gpu/drm/nova/file.rs
+++ b/drivers/gpu/drm/nova/file.rs
@@ -1,6 +1,10 @@
// SPDX-License-Identifier: GPL-2.0
-use crate::driver::{NovaDevice, NovaDriver};
+use crate::driver::{
+ DrmRegData,
+ NovaDevice,
+ NovaDriver, //
+};
use crate::gem::NovaObject;
use kernel::{
alloc::flags::*,
@@ -30,7 +34,7 @@ impl File {
/// IOCTL: get_param: Query GPU / driver metadata.
pub(crate) fn get_param(
dev: &NovaDevice<Registered>,
- _reg_data: &(),
+ _reg_data: &DrmRegData<'_>,
getparam: &mut uapi::drm_nova_getparam,
_file: &drm::File<File>,
) -> Result<u32> {
@@ -50,7 +54,7 @@ pub(crate) fn get_param(
/// IOCTL: gem_create: Create a new DRM GEM object.
pub(crate) fn gem_create(
dev: &NovaDevice<Registered>,
- _reg_data: &(),
+ _reg_data: &DrmRegData<'_>,
req: &mut uapi::drm_nova_gem_create,
file: &drm::File<File>,
) -> Result<u32> {
@@ -64,7 +68,7 @@ pub(crate) fn gem_create(
/// IOCTL: gem_info: Query GEM metadata.
pub(crate) fn gem_info(
_dev: &NovaDevice<Registered>,
- _reg_data: &(),
+ _reg_data: &DrmRegData<'_>,
req: &mut uapi::drm_nova_gem_info,
file: &drm::File<File>,
) -> Result<u32> {
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v6 04/13] drm: nova: Add GPU architecture enum to nova-drm UAPI
2026-09-09 6:44 [PATCH v6 00/13] gpu: nova: Export parameters from nova-core to nova-drm Alistair Popple
` (2 preceding siblings ...)
2026-09-09 6:44 ` [PATCH v6 03/13] drm: nova: Add DRM registration data Alistair Popple
@ 2026-09-09 6:44 ` Alistair Popple
2026-09-09 6:44 ` [PATCH v6 05/13] drm: nova: Add chipid " Alistair Popple
` (8 subsequent siblings)
12 siblings, 0 replies; 16+ messages in thread
From: Alistair Popple @ 2026-09-09 6:44 UTC (permalink / raw)
To: rust-for-linux, nova-gpu
Cc: Alistair Popple, M Henning, Danilo Krummrich, Alice Ryhl,
David Airlie, Alexandre Courbot, Benno Lossin, Gary Guo,
Eliot Courtney, John Hubbard, Greg Kroah-Hartman,
Rafael J. Wysocki, linux-kernel, dri-devel
The GPU architecture to be exposed to user-space. This adds a public
enum to the userspace headers for each chip architecture. Nova-core can
then use this enum to define its architectures.
This does create a coupling between nova-drm and nova-core whereby
nova-core depends on the values defined by the user-space API for
nova-drm. However this is entirely appropriate as nova-core must be
bound by the UAPI headers as the enum values are read by nova-core and
passed through to user-space.
It also requires a minor change to the bounded_enum! macro to match the
architecture values in an expression context.
Signed-off-by: Alistair Popple <apopple@nvidia.com>
---
Changes since v4:
- Rewritten for v5 as exposing chip-id was dropped.
Changes since v3:
- New for v4, split out from "drm: nova: Add GETPARAM parameter to read
the GPU chipset"
---
drivers/gpu/nova-core/gpu.rs | 28 +++++++++++++++++-----------
drivers/gpu/nova-core/num.rs | 2 +-
include/uapi/drm/nova_drm.h | 12 ++++++++++++
3 files changed, 30 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index e1ac8ee9ba4d..8726beb4f693 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -10,7 +10,8 @@
num::Bounded,
pci,
prelude::*,
- sizes::SizeConstants, //
+ sizes::SizeConstants,
+ uapi, //
};
use crate::{
@@ -36,8 +37,9 @@
mod regs;
macro_rules! define_chipset {
- ({ $($variant:ident = $value:expr),* $(,)* }) =>
+ ({ $($variant:ident = $value:literal),* $(,)* }) =>
{
+ ::kernel::macros::paste!(
/// Enum representation of the GPU chipset.
#[derive(fmt::Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
pub(crate) enum Chipset {
@@ -49,7 +51,6 @@ impl Chipset {
$( Chipset::$variant, )*
];
- ::kernel::macros::paste!(
/// Returns the name of this chipset, in lowercase.
///
/// # Examples
@@ -65,7 +66,6 @@ pub(crate) const fn name(&self) -> &'static str {
)*
}
}
- );
}
// TODO[FPRI]: replace with something like derive(FromPrimitive)
@@ -74,11 +74,14 @@ impl TryFrom<u32> for Chipset {
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
- $( $value => Ok(Chipset::$variant), )*
+ $(
+ $value => Ok(Chipset::$variant),
+ )*
_ => Err(ENODEV),
}
}
}
+ );
}
}
@@ -158,13 +161,16 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
bounded_enum! {
/// Enum representation of the GPU generation.
#[derive(fmt::Debug, Copy, Clone)]
+ #[repr(u32)]
pub(crate) enum Architecture with TryFrom<Bounded<u32, 6>> {
- Turing = 0x16,
- Ampere = 0x17,
- Hopper = 0x18,
- Ada = 0x19,
- BlackwellGB10x = 0x1a,
- BlackwellGB20x = 0x1b,
+ Turing = uapi::drm_nova_architecture_NOVA_DRM_ARCHITECTURE_TURING,
+ Ampere = uapi::drm_nova_architecture_NOVA_DRM_ARCHITECTURE_AMPERE,
+ Hopper = uapi::drm_nova_architecture_NOVA_DRM_ARCHITECTURE_HOPPER,
+ Ada = uapi::drm_nova_architecture_NOVA_DRM_ARCHITECTURE_ADA,
+ BlackwellGB10x =
+ uapi::drm_nova_architecture_NOVA_DRM_ARCHITECTURE_BLACKWELL_GB10X,
+ BlackwellGB20x =
+ uapi::drm_nova_architecture_NOVA_DRM_ARCHITECTURE_BLACKWELL_GB20X,
}
}
diff --git a/drivers/gpu/nova-core/num.rs b/drivers/gpu/nova-core/num.rs
index 6eb174d136ab..f4169235bc24 100644
--- a/drivers/gpu/nova-core/num.rs
+++ b/drivers/gpu/nova-core/num.rs
@@ -263,7 +263,7 @@ fn try_from(
) -> kernel::error::Result<Self> {
match value.get() {
$(
- $value => Ok($enum_type::$variant),
+ value if value == $value => Ok($enum_type::$variant),
)*
_ => Err(kernel::error::code::EINVAL),
}
diff --git a/include/uapi/drm/nova_drm.h b/include/uapi/drm/nova_drm.h
index 3ca90ed9d2bb..f0dcbca1908d 100644
--- a/include/uapi/drm/nova_drm.h
+++ b/include/uapi/drm/nova_drm.h
@@ -25,6 +25,18 @@ extern "C" {
*/
#define NOVA_GETPARAM_VRAM_BAR_SIZE 0x1
+/**
+ * enum drm_nova_architecture - GPU architecture identifier
+ */
+enum drm_nova_architecture {
+ NOVA_DRM_ARCHITECTURE_TURING = 0x16,
+ NOVA_DRM_ARCHITECTURE_AMPERE = 0x17,
+ NOVA_DRM_ARCHITECTURE_HOPPER = 0x18,
+ NOVA_DRM_ARCHITECTURE_ADA = 0x19,
+ NOVA_DRM_ARCHITECTURE_BLACKWELL_GB10X = 0x1a,
+ NOVA_DRM_ARCHITECTURE_BLACKWELL_GB20X = 0x1b,
+};
+
/**
* struct drm_nova_getparam - query GPU and driver metadata
*/
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v6 05/13] drm: nova: Add chipid enum to nova-drm UAPI
2026-09-09 6:44 [PATCH v6 00/13] gpu: nova: Export parameters from nova-core to nova-drm Alistair Popple
` (3 preceding siblings ...)
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 ` Alistair Popple
2026-09-09 6:44 ` [PATCH v6 06/13] rust: uaccess: add UserSliceWriter::write_truncated() Alistair Popple
` (7 subsequent siblings)
12 siblings, 0 replies; 16+ messages in thread
From: Alistair Popple @ 2026-09-09 6:44 UTC (permalink / raw)
To: rust-for-linux, nova-gpu
Cc: Alistair Popple, M Henning, Danilo Krummrich, Alice Ryhl,
David Airlie, Alexandre Courbot, Benno Lossin, Gary Guo,
Eliot Courtney, John Hubbard, Greg Kroah-Hartman,
Rafael J. Wysocki, linux-kernel, dri-devel
The chip identifier uniquely identifies a GPU chip and needs to be
exposed to user-space so it can look up chip specific properties that
cannot be derived from the architecture alone. This adds a public enum
to the userspace headers for each chip ID. Nova-core can then use this
enum to define its chipsets.
The values are opaque to user-space. They may be compared against the
enum to identify a chip but user-space must not assume the values carry
any particular meaning or encoding.
This does create a coupling between nova-drm and nova-core whereby
nova-core depends on the values defined by the user-space API for
nova-drm. However this is entirely appropriate as nova-core must be
bound by the UAPI headers as the enum values are read by nova-core and
passed through to user-space.
Note that nova-core currently refers to the chipid as a chipset. This
isn't ideal given that chipid is the preferred and more accurate term
and is what should be exposed via the uAPI. Therefore a future patch
series will be posted that aligns nova-core internals to using chipid
rather than chipset.
Signed-off-by: Alistair Popple <apopple@nvidia.com>
Assisted-by: LLM
---
Changes since v5:
- Re-added. Following discussion an opaque chipid is exposed alongside
the architecture in place of the implementation.
Changes since v4:
- Dropped in favour of exposing architecture and implementation.
Changes since v3:
- New for v4, split out from "drm: nova: Add GETPARAM parameter to read
the GPU chipset"
---
drivers/gpu/nova-core/gpu.rs | 57 +++++++++++++++++++-----------------
include/uapi/drm/nova_drm.h | 40 +++++++++++++++++++++++++
2 files changed, 70 insertions(+), 27 deletions(-)
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index 8726beb4f693..933bd3657db1 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -37,13 +37,14 @@
mod regs;
macro_rules! define_chipset {
- ({ $($variant:ident = $value:literal),* $(,)* }) =>
+ ({ $($variant:ident),* $(,)* }) =>
{
::kernel::macros::paste!(
/// Enum representation of the GPU chipset.
#[derive(fmt::Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
+ #[repr(u32)]
pub(crate) enum Chipset {
- $($variant = $value),*,
+ $($variant = uapi::[<drm_nova_chipid_NOVA_DRM_CHIPID_ $variant:upper>]),*,
}
impl Chipset {
@@ -75,7 +76,9 @@ impl TryFrom<u32> for Chipset {
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
$(
- $value => Ok(Chipset::$variant),
+ uapi::[<drm_nova_chipid_NOVA_DRM_CHIPID_ $variant:upper>] => {
+ Ok(Chipset::$variant)
+ }
)*
_ => Err(ENODEV),
}
@@ -87,35 +90,35 @@ fn try_from(value: u32) -> Result<Self, Self::Error> {
define_chipset!({
// Turing
- TU102 = 0x162,
- TU104 = 0x164,
- TU106 = 0x166,
- TU117 = 0x167,
- TU116 = 0x168,
+ TU102,
+ TU104,
+ TU106,
+ TU117,
+ TU116,
// Ampere
- GA100 = 0x170,
- GA102 = 0x172,
- GA103 = 0x173,
- GA104 = 0x174,
- GA106 = 0x176,
- GA107 = 0x177,
+ GA100,
+ GA102,
+ GA103,
+ GA104,
+ GA106,
+ GA107,
// Hopper
- GH100 = 0x180,
+ GH100,
// Ada
- AD102 = 0x192,
- AD103 = 0x193,
- AD104 = 0x194,
- AD106 = 0x196,
- AD107 = 0x197,
+ AD102,
+ AD103,
+ AD104,
+ AD106,
+ AD107,
// Blackwell GB10x
- GB100 = 0x1a0,
- GB102 = 0x1a2,
+ GB100,
+ GB102,
// Blackwell GB20x
- GB202 = 0x1b2,
- GB203 = 0x1b3,
- GB205 = 0x1b5,
- GB206 = 0x1b6,
- GB207 = 0x1b7,
+ GB202,
+ GB203,
+ GB205,
+ GB206,
+ GB207,
});
impl Chipset {
diff --git a/include/uapi/drm/nova_drm.h b/include/uapi/drm/nova_drm.h
index f0dcbca1908d..e35f09a1ebe8 100644
--- a/include/uapi/drm/nova_drm.h
+++ b/include/uapi/drm/nova_drm.h
@@ -37,6 +37,46 @@ enum drm_nova_architecture {
NOVA_DRM_ARCHITECTURE_BLACKWELL_GB20X = 0x1b,
};
+/**
+ * enum drm_nova_chipid - opaque GPU chip identifier
+ *
+ * These values identify the chip a GPU is based on. They are otherwise
+ * opaque: userspace must not assume the values carry any particular meaning
+ * or encoding, only that they may be compared against this enum.
+ */
+enum drm_nova_chipid {
+ /* Turing */
+ NOVA_DRM_CHIPID_TU102 = 0x162,
+ NOVA_DRM_CHIPID_TU104 = 0x164,
+ NOVA_DRM_CHIPID_TU106 = 0x166,
+ NOVA_DRM_CHIPID_TU117 = 0x167,
+ NOVA_DRM_CHIPID_TU116 = 0x168,
+ /* Ampere */
+ NOVA_DRM_CHIPID_GA100 = 0x170,
+ NOVA_DRM_CHIPID_GA102 = 0x172,
+ NOVA_DRM_CHIPID_GA103 = 0x173,
+ NOVA_DRM_CHIPID_GA104 = 0x174,
+ NOVA_DRM_CHIPID_GA106 = 0x176,
+ NOVA_DRM_CHIPID_GA107 = 0x177,
+ /* Hopper */
+ NOVA_DRM_CHIPID_GH100 = 0x180,
+ /* Ada */
+ NOVA_DRM_CHIPID_AD102 = 0x192,
+ NOVA_DRM_CHIPID_AD103 = 0x193,
+ NOVA_DRM_CHIPID_AD104 = 0x194,
+ NOVA_DRM_CHIPID_AD106 = 0x196,
+ NOVA_DRM_CHIPID_AD107 = 0x197,
+ /* Blackwell GB10x */
+ NOVA_DRM_CHIPID_GB100 = 0x1a0,
+ NOVA_DRM_CHIPID_GB102 = 0x1a2,
+ /* Blackwell GB20x */
+ NOVA_DRM_CHIPID_GB202 = 0x1b2,
+ NOVA_DRM_CHIPID_GB203 = 0x1b3,
+ NOVA_DRM_CHIPID_GB205 = 0x1b5,
+ NOVA_DRM_CHIPID_GB206 = 0x1b6,
+ NOVA_DRM_CHIPID_GB207 = 0x1b7,
+};
+
/**
* struct drm_nova_getparam - query GPU and driver metadata
*/
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v6 06/13] rust: uaccess: add UserSliceWriter::write_truncated()
2026-09-09 6:44 [PATCH v6 00/13] gpu: nova: Export parameters from nova-core to nova-drm Alistair Popple
` (4 preceding siblings ...)
2026-09-09 6:44 ` [PATCH v6 05/13] drm: nova: Add chipid " Alistair Popple
@ 2026-09-09 6:44 ` Alistair Popple
2026-09-09 6:56 ` sashiko-bot
2026-09-09 6:45 ` [PATCH v6 07/13] drm: nova: Add an info ioctl Alistair Popple
` (6 subsequent siblings)
12 siblings, 1 reply; 16+ messages in thread
From: Alistair Popple @ 2026-09-09 6:44 UTC (permalink / raw)
To: rust-for-linux, nova-gpu
Cc: Alistair Popple, M Henning, Danilo Krummrich, Alice Ryhl,
David Airlie, Alexandre Courbot, Benno Lossin, Gary Guo,
Eliot Courtney, John Hubbard, Greg Kroah-Hartman,
Rafael J. Wysocki, linux-kernel, dri-devel
Add a helper that writes as much of an AsBytes value as fits in the
remaining userspace buffer and returns the number of bytes copied. This
avoids requiring callers of versioned UAPIs to convert values to byte
slices and truncate them manually.
Signed-off-by: Alistair Popple <apopple@nvidia.com>
Suggested-by: Danilo Krummrich <dakr@kernel.org>
---
rust/kernel/uaccess.rs | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
index 5f6c4d7a1a51..c63b91942631 100644
--- a/rust/kernel/uaccess.rs
+++ b/rust/kernel/uaccess.rs
@@ -624,6 +624,20 @@ pub fn write<T: AsBytes>(&mut self, value: &T) -> Result {
self.length -= len;
Ok(())
}
+
+ /// Writes as much of the provided value as fits in the remaining buffer.
+ ///
+ /// Copies `min(size_of::<T>(), self.len())` bytes to userspace. Returns the number of bytes
+ /// actually written. This is useful for versioned structs where an older userspace may provide
+ /// a smaller buffer than the current kernel struct.
+ ///
+ /// Fails with [`EFAULT`] if the write happens on a bad address. This call may modify the
+ /// associated userspace slice even if it returns an error.
+ pub fn write_truncated<T: AsBytes>(&mut self, value: &T) -> Result<usize> {
+ let len = self.length.min(size_of::<T>());
+ self.write_slice(&value.as_bytes()[..len])?;
+ Ok(len)
+ }
}
/// Reads a nul-terminated string into `dst` and returns the length.
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v6 07/13] drm: nova: Add an info ioctl
2026-09-09 6:44 [PATCH v6 00/13] gpu: nova: Export parameters from nova-core to nova-drm Alistair Popple
` (5 preceding siblings ...)
2026-09-09 6:44 ` [PATCH v6 06/13] rust: uaccess: add UserSliceWriter::write_truncated() Alistair Popple
@ 2026-09-09 6:45 ` Alistair Popple
2026-09-09 6:45 ` [PATCH v6 08/13] drm: nova: Add usable VRAM size to GPU info Alistair Popple
` (5 subsequent siblings)
12 siblings, 0 replies; 16+ messages in thread
From: Alistair Popple @ 2026-09-09 6:45 UTC (permalink / raw)
To: rust-for-linux, nova-gpu
Cc: Alistair Popple, M Henning, Danilo Krummrich, Alice Ryhl,
David Airlie, Alexandre Courbot, Benno Lossin, Gary Guo,
Eliot Courtney, John Hubbard, Greg Kroah-Hartman,
Rafael J. Wysocki, linux-kernel, dri-devel
Add an extensible info ioctl and use it to report basic GPU information.
One of the first things userspace needs to know about a GPU is its
architecture and which chip it is, so add those as the first fields in
the GPU info result. The chip identifier is opaque to userspace and is
only meaningful when compared against the values of enum
drm_nova_chipid.
The ioctl selects an information type by ID and writes the result through
a sized userspace buffer. The kernel truncates results to the supplied
size, allowing information structures to grow and new logical information
groups to be added without introducing new ioctls. Passing a NULL data
pointer returns the size of the requested information structure instead.
Signed-off-by: Alistair Popple <apopple@nvidia.com>
---
Changes since v5:
- Report an opaque chipid alongside the architecture instead of the
implementation
- Rename struct drm_nova_gpu_info to drm_nova_info_gpu for consistency
with the DRM_NOVA_INFO_<type> identifiers
- Expose a Spec accessor from NovaCoreApi rather than forwarding
methods, as suggested by Danilo
- Handle the size query in write_info() and pass the value by value
- Document the NULL data pointer size query in the uAPI header
- Drop the redundant GpuInfo invariants, as suggested by Danilo
Changes since v4:
- Add a new info ioctl interface as suggested by Danilo
Changes since v3:
- New for v4 - chipid was previously returned as a GETPARAM parameter
---
drivers/gpu/drm/nova/driver.rs | 2 +-
drivers/gpu/drm/nova/file.rs | 60 ++++++++++++++++++++++++++++++++++
drivers/gpu/nova-core/api.rs | 8 ++++-
drivers/gpu/nova-core/gpu.rs | 24 ++++++++++----
include/uapi/drm/nova_drm.h | 53 ++++++++++++++++++++++++++++++
5 files changed, 138 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/nova/driver.rs b/drivers/gpu/drm/nova/driver.rs
index 52550e694729..0acdd2eb45ca 100644
--- a/drivers/gpu/drm/nova/driver.rs
+++ b/drivers/gpu/drm/nova/driver.rs
@@ -33,7 +33,6 @@ pub(crate) struct Nova<'bound> {
/// DRM registration data, accessible from ioctl handlers via the registration guard.
pub(crate) struct DrmRegData<'bound> {
- #[expect(unused)]
pub(crate) api: NovaCoreApiHandle<'bound>,
}
@@ -98,5 +97,6 @@ impl drm::Driver for NovaDriver {
(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),
+ (NOVA_INFO, drm_nova_info, ioctl::RENDER_ALLOW, File::info),
}
}
diff --git a/drivers/gpu/drm/nova/file.rs b/drivers/gpu/drm/nova/file.rs
index 1156df51c533..4a65bec0fbce 100644
--- a/drivers/gpu/drm/nova/file.rs
+++ b/drivers/gpu/drm/nova/file.rs
@@ -17,11 +17,56 @@
},
pci,
prelude::*,
+ transmute::AsBytes,
+ uaccess::UserSlice,
uapi,
};
pub(crate) struct File;
+/// GPU information returned to userspace.
+#[repr(transparent)]
+struct GpuInfo(uapi::drm_nova_info_gpu);
+
+impl GpuInfo {
+ /// Collects the GPU information reported to userspace.
+ ///
+ /// This is fallible so that unexpected GSP behaviour, such as a malformed name string, is
+ /// reported to userspace instead of being silently replaced with a made up value. When adding
+ /// a field, take care that a value the GSP simply does not provide, for example because the
+ /// firmware predates it, does not cause a failure. Such fields must fall back to zero or
+ /// another documented default instead.
+ fn new(reg_data: &DrmRegData<'_>) -> Result<Self> {
+ let spec = reg_data.api.with(|api| api.get_ref().spec());
+
+ let info = uapi::drm_nova_info_gpu {
+ architecture: spec.chipset.arch() as u32,
+ chipid: spec.chipset as u32,
+ };
+ Ok(Self(info))
+ }
+}
+
+// SAFETY: `GpuInfo` has no implicit padding, kernel pointers, or interior
+// mutability, and all of its fields are initialized before it is written to
+// userspace.
+unsafe impl AsBytes for GpuInfo {}
+
+fn write_info<T: AsBytes>(info: &mut uapi::drm_nova_info, value: T) -> Result {
+ // A NULL data pointer requests the size of the information structure.
+ if info.data == 0 {
+ info.size = size_of::<T>() as u32;
+ return Ok(());
+ }
+
+ let mut writer =
+ UserSlice::new(UserPtr::from_addr(info.data as usize), info.size as usize).writer();
+
+ info.size = writer.write_truncated(&value)? as u32;
+
+ Ok(())
+}
+
impl drm::file::DriverFile for File {
type Driver = NovaDriver;
@@ -78,4 +123,19 @@ pub(crate) fn gem_info(
Ok(0)
}
+
+ /// IOCTL: info: Query device information.
+ pub(crate) fn info(
+ _dev: &NovaDevice<Registered>,
+ reg_data: &DrmRegData<'_>,
+ info: &mut uapi::drm_nova_info,
+ _file: &drm::File<File>,
+ ) -> Result<u32> {
+ match info.id {
+ uapi::DRM_NOVA_INFO_GPU => write_info(info, GpuInfo::new(reg_data)?)?,
+ _ => return Err(EINVAL),
+ }
+
+ Ok(0)
+ }
}
diff --git a/drivers/gpu/nova-core/api.rs b/drivers/gpu/nova-core/api.rs
index ae023242594e..876451dcc051 100644
--- a/drivers/gpu/nova-core/api.rs
+++ b/drivers/gpu/nova-core/api.rs
@@ -12,11 +12,12 @@
types::ForLt, //
};
+pub use crate::gpu::Spec;
+
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>>,
}
@@ -26,6 +27,11 @@ impl NovaCoreApi<'_> {
pub fn of(adev: &auxiliary::Device<Bound>) -> Result<NovaCoreApiHandle<'_>> {
NovaCoreApiHandle::of(adev)
}
+
+ /// Returns the GPU [`Spec`].
+ pub fn spec(&self) -> &Spec {
+ &self.gpu.spec
+ }
}
/// Expose a handle to nova-core API
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index 933bd3657db1..91db64dcaea7 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -43,12 +43,14 @@ macro_rules! define_chipset {
/// Enum representation of the GPU chipset.
#[derive(fmt::Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
#[repr(u32)]
- pub(crate) enum Chipset {
+ #[allow(missing_docs)]
+ pub enum Chipset {
$($variant = uapi::[<drm_nova_chipid_NOVA_DRM_CHIPID_ $variant:upper>]),*,
}
impl Chipset {
- pub(crate) const ALL: &'static [Chipset] = &[
+ /// All chipsets known to the driver.
+ pub const ALL: &'static [Chipset] = &[
$( Chipset::$variant, )*
];
@@ -122,7 +124,8 @@ fn try_from(value: u32) -> Result<Self, Self::Error> {
});
impl Chipset {
- pub(crate) const fn arch(self) -> Architecture {
+ /// Returns the [`Architecture`] generation of this chipset.
+ pub const fn arch(self) -> Architecture {
match self {
Self::TU102 | Self::TU104 | Self::TU106 | Self::TU117 | Self::TU116 => {
Architecture::Turing
@@ -165,13 +168,19 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// Enum representation of the GPU generation.
#[derive(fmt::Debug, Copy, Clone)]
#[repr(u32)]
- pub(crate) enum Architecture with TryFrom<Bounded<u32, 6>> {
+ pub enum Architecture with TryFrom<Bounded<u32, 6>> {
+ /// Turing (TU1xx).
Turing = uapi::drm_nova_architecture_NOVA_DRM_ARCHITECTURE_TURING,
+ /// Ampere (GA10x).
Ampere = uapi::drm_nova_architecture_NOVA_DRM_ARCHITECTURE_AMPERE,
+ /// Hopper (GH100).
Hopper = uapi::drm_nova_architecture_NOVA_DRM_ARCHITECTURE_HOPPER,
+ /// Ada Lovelace (AD10x).
Ada = uapi::drm_nova_architecture_NOVA_DRM_ARCHITECTURE_ADA,
+ /// Blackwell (GB10x).
BlackwellGB10x =
uapi::drm_nova_architecture_NOVA_DRM_ARCHITECTURE_BLACKWELL_GB10X,
+ /// Blackwell (GB20x).
BlackwellGB20x =
uapi::drm_nova_architecture_NOVA_DRM_ARCHITECTURE_BLACKWELL_GB20X,
}
@@ -200,8 +209,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// Structure holding a basic description of the GPU: `Chipset` and `Revision`.
#[derive(Clone, Copy)]
-pub(crate) struct Spec {
- chipset: Chipset,
+pub struct Spec {
+ /// The GPU chipset.
+ pub chipset: Chipset,
revision: Revision,
}
@@ -289,7 +299,7 @@ struct GspResources<'gpu> {
/// Structure holding the resources required to operate the GPU.
#[pin_data]
pub(crate) struct Gpu<'gpu> {
- spec: Spec,
+ pub(crate) spec: Spec,
/// Static GPU information as provided by the GSP.
gsp_static_info: GetGspStaticInfoReply,
/// GSP and its resources.
diff --git a/include/uapi/drm/nova_drm.h b/include/uapi/drm/nova_drm.h
index e35f09a1ebe8..26a5e7ca5425 100644
--- a/include/uapi/drm/nova_drm.h
+++ b/include/uapi/drm/nova_drm.h
@@ -132,9 +132,60 @@ struct drm_nova_gem_info {
__u64 size;
};
+/**
+ * struct drm_nova_info - query device information
+ */
+struct drm_nova_info {
+ /**
+ * @id: The identifier of the information to query.
+ */
+ __u32 id;
+
+ /**
+ * @size: The amount of space allocated by userspace at @data. The kernel
+ * will return the number of bytes it wrote, or the size of the queried
+ * information structure if @data is NULL.
+ */
+ __u32 size;
+
+ /**
+ * @data: Pointer to the userspace buffer into which the queried
+ * information will be written. May be NULL, in which case nothing is
+ * written and @size is set to the size of the information structure so
+ * userspace can allocate a suitably sized buffer.
+ */
+ __u64 data;
+};
+
+/**
+ * DRM_NOVA_INFO_GPU
+ *
+ * Query GPU information. The result is returned in a
+ * &struct drm_nova_info_gpu.
+ */
+#define DRM_NOVA_INFO_GPU 0x00
+
+/**
+ * struct drm_nova_info_gpu - GPU information
+ */
+struct drm_nova_info_gpu {
+ /**
+ * @architecture: GPU architecture identifier. See
+ * &enum drm_nova_architecture for currently known architectures.
+ */
+ __u32 architecture;
+
+ /**
+ * @chipid: Opaque GPU chip identifier. See &enum drm_nova_chipid for
+ * currently known chips.
+ */
+ __u32 chipid;
+};
+
#define DRM_NOVA_GETPARAM 0x00
#define DRM_NOVA_GEM_CREATE 0x01
#define DRM_NOVA_GEM_INFO 0x02
+#define DRM_NOVA_INFO 0x03
/* Note: this is an enum so that it can be resolved by Rust bindgen. */
enum {
@@ -144,6 +195,8 @@ enum {
struct drm_nova_gem_create),
DRM_IOCTL_NOVA_GEM_INFO = DRM_IOWR(DRM_COMMAND_BASE + DRM_NOVA_GEM_INFO,
struct drm_nova_gem_info),
+ DRM_IOCTL_NOVA_INFO = DRM_IOWR(DRM_COMMAND_BASE + DRM_NOVA_INFO,
+ struct drm_nova_info),
};
#if defined(__cplusplus)
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v6 08/13] drm: nova: Add usable VRAM size to GPU info
2026-09-09 6:44 [PATCH v6 00/13] gpu: nova: Export parameters from nova-core to nova-drm Alistair Popple
` (6 preceding siblings ...)
2026-09-09 6:45 ` [PATCH v6 07/13] drm: nova: Add an info ioctl Alistair Popple
@ 2026-09-09 6:45 ` Alistair Popple
2026-09-09 6:45 ` [PATCH v6 09/13] drm: nova: Use nova-core to read VRAM_BAR_SIZE parameter Alistair Popple
` (4 subsequent siblings)
12 siblings, 0 replies; 16+ messages in thread
From: Alistair Popple @ 2026-09-09 6:45 UTC (permalink / raw)
To: rust-for-linux, nova-gpu
Cc: Alistair Popple, M Henning, Danilo Krummrich, Alice Ryhl,
David Airlie, Alexandre Courbot, Benno Lossin, Gary Guo,
Eliot Courtney, John Hubbard, Greg Kroah-Hartman,
Rafael J. Wysocki, linux-kernel, dri-devel
Add a field to the GPU info structure containing the total usable
framebuffer size. The usable framebuffer excludes GSP carveouts and
other protected regions, so it may differ from the BAR size and total
physical VRAM.
Signed-off-by: Alistair Popple <apopple@nvidia.com>
---
Changes since v5:
- Expose the GSP static info through a NovaCoreApi::gsp_static_info()
accessor and read the VRAM size from it rather than adding a
forwarding method, as suggested by Danilo
Changes since v3:
- Partially new for v4 - previously a separate scalar GETPARAM
parameter
---
drivers/gpu/drm/nova/file.rs | 2 ++
drivers/gpu/nova-core/api.rs | 6 ++++++
drivers/gpu/nova-core/gpu.rs | 6 ++----
drivers/gpu/nova-core/gsp/commands.rs | 10 +++++++++-
include/uapi/drm/nova_drm.h | 6 ++++++
5 files changed, 25 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/nova/file.rs b/drivers/gpu/drm/nova/file.rs
index 4a65bec0fbce..d0ab3df6bcd2 100644
--- a/drivers/gpu/drm/nova/file.rs
+++ b/drivers/gpu/drm/nova/file.rs
@@ -38,10 +38,12 @@ impl GpuInfo {
/// another documented default instead.
fn new(reg_data: &DrmRegData<'_>) -> Result<Self> {
let spec = reg_data.api.with(|api| api.get_ref().spec());
+ let gsp_static_info = reg_data.api.with(|api| api.get_ref().gsp_static_info());
let info = uapi::drm_nova_info_gpu {
architecture: spec.chipset.arch() as u32,
chipid: spec.chipset as u32,
+ vram_size: gsp_static_info.vram_size(),
};
Ok(Self(info))
}
diff --git a/drivers/gpu/nova-core/api.rs b/drivers/gpu/nova-core/api.rs
index 876451dcc051..64f9ea442278 100644
--- a/drivers/gpu/nova-core/api.rs
+++ b/drivers/gpu/nova-core/api.rs
@@ -15,6 +15,7 @@
pub use crate::gpu::Spec;
use crate::gpu::Gpu;
+use crate::gsp::commands::GetGspStaticInfoReply;
/// API handle for the auxiliary bus child drivers to interact with nova-core.
pub struct NovaCoreApi<'bound> {
@@ -28,6 +29,11 @@ pub fn of(adev: &auxiliary::Device<Bound>) -> Result<NovaCoreApiHandle<'_>> {
NovaCoreApiHandle::of(adev)
}
+ /// Returns the GPU [`GetGspStaticInfoReply`].
+ pub fn gsp_static_info(&self) -> &GetGspStaticInfoReply {
+ &self.gpu.gsp_static_info
+ }
+
/// Returns the GPU [`Spec`].
pub fn spec(&self) -> &Spec {
&self.gpu.spec
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index 91db64dcaea7..b9fba3a79b1e 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -301,7 +301,7 @@ struct GspResources<'gpu> {
pub(crate) struct Gpu<'gpu> {
pub(crate) spec: Spec,
/// Static GPU information as provided by the GSP.
- gsp_static_info: GetGspStaticInfoReply,
+ pub(crate) gsp_static_info: GetGspStaticInfoReply,
/// GSP and its resources.
#[pin]
gsp_resources: GspResources<'gpu>,
@@ -422,9 +422,7 @@ pub(crate) fn new<'a>(
dev_dbg!(
dev,
"Total usable VRAM: {} MiB\n",
- info.usable_fb_regions.iter().fold(0u64, |res, region| res
- .saturating_add(region.end - region.start))
- / u64::SZ_1M
+ info.vram_size() / u64::SZ_1M
);
}
diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
index ffc25fd8c47b..5c1f9d296198 100644
--- a/drivers/gpu/nova-core/gsp/commands.rs
+++ b/drivers/gpu/nova-core/gsp/commands.rs
@@ -212,7 +212,7 @@ fn init(&self) -> impl Init<Self::Command, Self::InitError> {
}
/// The reply from the GSP to the [`GetGspStaticInfo`] command.
-pub(crate) struct GetGspStaticInfoReply {
+pub struct GetGspStaticInfoReply {
gpu_name: [u8; 64],
/// Usable FB (VRAM) regions for driver memory allocation.
pub(crate) usable_fb_regions: KVec<Range<u64>>,
@@ -261,6 +261,14 @@ pub(crate) fn gpu_name(&self) -> core::result::Result<&str, GpuNameError> {
.to_str()
.map_err(GpuNameError::InvalidUtf8)
}
+
+ /// Returns the total usable VRAM size in bytes, i.e. the summed lengths of all usable FB
+ /// regions.
+ pub fn vram_size(&self) -> u64 {
+ self.usable_fb_regions.iter().fold(0, |size, region| {
+ size.saturating_add(region.end - region.start)
+ })
+ }
}
pub(crate) use fw::commands::PowerStateLevel;
diff --git a/include/uapi/drm/nova_drm.h b/include/uapi/drm/nova_drm.h
index 26a5e7ca5425..946bd4bf8fbd 100644
--- a/include/uapi/drm/nova_drm.h
+++ b/include/uapi/drm/nova_drm.h
@@ -180,6 +180,12 @@ struct drm_nova_info_gpu {
* currently known chips.
*/
__u32 chipid;
+
+ /**
+ * @vram_size: Amount of usable FB, excluding GSP carveouts and protected
+ * regions.
+ */
+ __u64 vram_size;
};
#define DRM_NOVA_GETPARAM 0x00
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v6 09/13] drm: nova: Use nova-core to read VRAM_BAR_SIZE parameter
2026-09-09 6:44 [PATCH v6 00/13] gpu: nova: Export parameters from nova-core to nova-drm Alistair Popple
` (7 preceding siblings ...)
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 ` Alistair Popple
2026-09-09 6:45 ` [PATCH v6 10/13] drm: nova: Expose a render node Alistair Popple
` (3 subsequent siblings)
12 siblings, 0 replies; 16+ messages in thread
From: Alistair Popple @ 2026-09-09 6:45 UTC (permalink / raw)
To: rust-for-linux, nova-gpu
Cc: Alistair Popple, M Henning, Danilo Krummrich, Alice Ryhl,
David Airlie, Alexandre Courbot, Benno Lossin, Gary Guo,
Eliot Courtney, John Hubbard, Greg Kroah-Hartman,
Rafael J. Wysocki, linux-kernel, dri-devel
Currently nova-drm reads the VRAM BAR size directly from the PCIe device
which requires trying to cast the parent device into a PCIe device. This
obviously requires the parent device to actually be a PCIe bus device.
Whilst that is true today it may not always be the case, and there
is no reason to make this assumption now that NovaCoreApi can hold a
reference to the bound PCIe device.
So convert nova-drm to using nova-core to obtain the VRAM_BAR_SIZE
parameter.
Signed-off-by: Alistair Popple <apopple@nvidia.com>
---
Changes since v5:
- Call bar1_size() through the NovaCoreApiHandle closure
Changes from v2:
- Update nova-core API to use bar1_size() instead of vram_bar_size() as
this is used internally throughout our chip HW.
---
drivers/gpu/drm/nova/file.rs | 12 +++---------
drivers/gpu/nova-core/api.rs | 8 ++++++++
drivers/gpu/nova-core/driver.rs | 2 +-
3 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/nova/file.rs b/drivers/gpu/drm/nova/file.rs
index d0ab3df6bcd2..dad3c83c920b 100644
--- a/drivers/gpu/drm/nova/file.rs
+++ b/drivers/gpu/drm/nova/file.rs
@@ -8,14 +8,11 @@
use crate::gem::NovaObject;
use kernel::{
alloc::flags::*,
- auxiliary,
- device::Bound,
drm::{
self,
gem::BaseObject,
Registered, //
},
- pci,
prelude::*,
transmute::AsBytes,
uaccess::UserSlice,
@@ -80,16 +77,13 @@ fn open(_dev: &NovaDevice) -> Result<Pin<KBox<Self>>> {
impl File {
/// IOCTL: get_param: Query GPU / driver metadata.
pub(crate) fn get_param(
- dev: &NovaDevice<Registered>,
- _reg_data: &DrmRegData<'_>,
+ _dev: &NovaDevice<Registered>,
+ reg_data: &DrmRegData<'_>,
getparam: &mut uapi::drm_nova_getparam,
_file: &drm::File<File>,
) -> Result<u32> {
- let adev: &auxiliary::Device<Bound> = dev.as_ref();
- let pdev: &pci::Device<Bound> = adev.parent().try_into()?;
-
let value = match getparam.param as u32 {
- uapi::NOVA_GETPARAM_VRAM_BAR_SIZE => pdev.resource_len(1)?,
+ uapi::NOVA_GETPARAM_VRAM_BAR_SIZE => reg_data.api.with(|api| api.bar1_size())?,
_ => return Err(EINVAL),
};
diff --git a/drivers/gpu/nova-core/api.rs b/drivers/gpu/nova-core/api.rs
index 64f9ea442278..f02c6c7c7e51 100644
--- a/drivers/gpu/nova-core/api.rs
+++ b/drivers/gpu/nova-core/api.rs
@@ -8,6 +8,7 @@
use kernel::{
auxiliary,
device::Bound,
+ pci,
prelude::*,
types::ForLt, //
};
@@ -20,6 +21,7 @@
/// API handle for the auxiliary bus child drivers to interact with nova-core.
pub struct NovaCoreApi<'bound> {
pub(crate) gpu: Pin<&'bound Gpu<'bound>>,
+ pub(crate) pdev: &'bound pci::Device<Bound>,
}
impl NovaCoreApi<'_> {
@@ -38,6 +40,12 @@ pub fn gsp_static_info(&self) -> &GetGspStaticInfoReply {
pub fn spec(&self) -> &Spec {
&self.gpu.spec
}
+
+ /// Returns the size of the PCIe BAR used for accessing VRAM, typically
+ /// BAR1.
+ pub fn bar1_size(&self) -> Result<u64> {
+ self.pdev.resource_len(1)
+ }
}
/// Expose a handle to nova-core API
diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs
index 922068df7707..025ba2869d6c 100644
--- a/drivers/gpu/nova-core/driver.rs
+++ b/drivers/gpu/nova-core/driver.rs
@@ -110,7 +110,7 @@ fn probe<'bound>(
// never recycles IDs.
AUXILIARY_ID_COUNTER.fetch_add(1, Relaxed),
crate::MODULE_NAME,
- NovaCoreApi { gpu },
+ NovaCoreApi { gpu, pdev },
)?
}
},
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v6 10/13] drm: nova: Expose a render node
2026-09-09 6:44 [PATCH v6 00/13] gpu: nova: Export parameters from nova-core to nova-drm Alistair Popple
` (8 preceding siblings ...)
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 ` Alistair Popple
2026-09-09 6:45 ` [PATCH v6 11/13] drm: nova: Report GPU name in GPU info Alistair Popple
` (2 subsequent siblings)
12 siblings, 0 replies; 16+ messages in thread
From: Alistair Popple @ 2026-09-09 6:45 UTC (permalink / raw)
To: rust-for-linux, nova-gpu
Cc: Alistair Popple, M Henning, Danilo Krummrich, Alice Ryhl,
David Airlie, Alexandre Courbot, Benno Lossin, Gary Guo,
Eliot Courtney, John Hubbard, Greg Kroah-Hartman,
Rafael J. Wysocki, linux-kernel, dri-devel
nova-drm currently only exposes a primary node even though all of its
ioctls are already marked DRM_RENDER_ALLOW. Set the DRIVER_RENDER
feature so that a render node (/dev/dri/renderDXX) is created as well.
This is required to allow render and compute clients to interact with
nova-drm.
Signed-off-by: Alistair Popple <apopple@nvidia.com>
---
Changes since v2:
- New for v3.
---
drivers/gpu/drm/nova/driver.rs | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/nova/driver.rs b/drivers/gpu/drm/nova/driver.rs
index 0acdd2eb45ca..46e13fe795eb 100644
--- a/drivers/gpu/drm/nova/driver.rs
+++ b/drivers/gpu/drm/nova/driver.rs
@@ -92,6 +92,7 @@ impl drm::Driver for NovaDriver {
type ParentDevice<Ctx: DeviceContext> = auxiliary::Device<Ctx>;
const INFO: drm::DriverInfo = INFO;
+ const FEAT_RENDER: bool = true;
kernel::declare_drm_ioctls! {
(NOVA_GETPARAM, drm_nova_getparam, ioctl::RENDER_ALLOW, File::get_param),
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v6 11/13] drm: nova: Report GPU name in GPU info
2026-09-09 6:44 [PATCH v6 00/13] gpu: nova: Export parameters from nova-core to nova-drm Alistair Popple
` (9 preceding siblings ...)
2026-09-09 6:45 ` [PATCH v6 10/13] drm: nova: Expose a render node Alistair Popple
@ 2026-09-09 6:45 ` 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
12 siblings, 0 replies; 16+ messages in thread
From: Alistair Popple @ 2026-09-09 6:45 UTC (permalink / raw)
To: rust-for-linux, nova-gpu
Cc: Alistair Popple, M Henning, Danilo Krummrich, Alice Ryhl,
David Airlie, Alexandre Courbot, Benno Lossin, Gary Guo,
Eliot Courtney, John Hubbard, Greg Kroah-Hartman,
Rafael J. Wysocki, linux-kernel, dri-devel
Add the full GPU name to the GPU info structure. The name is copied from
the validated, NUL-terminated string nova-core already extracts from the
GSP static info rather than from the raw firmware bytes.
GpuInfo::new() is deliberately fallible here. A malformed name string
from the GSP is unexpected and is reported to userspace as an error
rather than being silently replaced with an empty name.
Signed-off-by: Alistair Popple <apopple@nvidia.com>
---
Changes since v5:
- Use the existing validated gpu_name() accessor instead of exposing the
raw bytes, as suggested by Danilo
- Keep GpuInfo::new() fallible so that unexpected GSP errors such as a
bad name string fail the ioctl instead of falling back to an empty name
Changes since v4:
- New for v5
---
drivers/gpu/drm/nova/file.rs | 21 ++++++++++++++++++++-
drivers/gpu/nova-core/gsp/commands.rs | 5 ++---
include/uapi/drm/nova_drm.h | 5 +++++
3 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/nova/file.rs b/drivers/gpu/drm/nova/file.rs
index dad3c83c920b..4753d9bca13b 100644
--- a/drivers/gpu/drm/nova/file.rs
+++ b/drivers/gpu/drm/nova/file.rs
@@ -25,6 +25,21 @@
#[repr(transparent)]
struct GpuInfo(uapi::drm_nova_info_gpu);
+/// Copies `name` into the zero initialised, fixed size uAPI buffer `dst`, keeping it
+/// NUL-terminated.
+///
+/// Fails with [`ENAMETOOLONG`] if `name` does not fit in `dst` with room for the terminator.
+fn copy_name(dst: &mut [u8], name: &str) -> Result {
+ let bytes = name.as_bytes();
+
+ if bytes.len() >= dst.len() {
+ return Err(ENAMETOOLONG);
+ }
+ dst[..bytes.len()].copy_from_slice(bytes);
+
+ Ok(())
+}
+
impl GpuInfo {
/// Collects the GPU information reported to userspace.
///
@@ -37,11 +52,15 @@ fn new(reg_data: &DrmRegData<'_>) -> Result<Self> {
let spec = reg_data.api.with(|api| api.get_ref().spec());
let gsp_static_info = reg_data.api.with(|api| api.get_ref().gsp_static_info());
- let info = uapi::drm_nova_info_gpu {
+ let mut info = uapi::drm_nova_info_gpu {
architecture: spec.chipset.arch() as u32,
chipid: spec.chipset as u32,
vram_size: gsp_static_info.vram_size(),
+ ..Default::default()
};
+
+ copy_name(&mut info.gpu_name, gsp_static_info.gpu_name().map_err(|_| EINVAL)?)?;
+
Ok(Self(info))
}
}
diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
index 5c1f9d296198..00cfcef260c5 100644
--- a/drivers/gpu/nova-core/gsp/commands.rs
+++ b/drivers/gpu/nova-core/gsp/commands.rs
@@ -241,12 +241,11 @@ fn read(
/// Error type for [`GetGspStaticInfoReply::gpu_name`].
#[derive(Debug)]
-pub(crate) enum GpuNameError {
+pub enum GpuNameError {
/// The GPU name string does not contain a null terminator.
NoNullTerminator(FromBytesUntilNulError),
/// The GPU name string contains invalid UTF-8.
- #[expect(dead_code)]
InvalidUtf8(Utf8Error),
}
@@ -255,7 +254,7 @@ impl GetGspStaticInfoReply {
///
/// Returns an error if the string given by the GSP does not contain a null terminator or
/// contains invalid UTF-8.
- pub(crate) fn gpu_name(&self) -> core::result::Result<&str, GpuNameError> {
+ pub fn gpu_name(&self) -> core::result::Result<&str, GpuNameError> {
CStr::from_bytes_until_nul(&self.gpu_name)
.map_err(GpuNameError::NoNullTerminator)?
.to_str()
diff --git a/include/uapi/drm/nova_drm.h b/include/uapi/drm/nova_drm.h
index 946bd4bf8fbd..c692cacaa552 100644
--- a/include/uapi/drm/nova_drm.h
+++ b/include/uapi/drm/nova_drm.h
@@ -186,6 +186,11 @@ struct drm_nova_info_gpu {
* regions.
*/
__u64 vram_size;
+
+ /**
+ * @gpu_name: NUL-terminated full GPU name.
+ */
+ __u8 gpu_name[64];
};
#define DRM_NOVA_GETPARAM 0x00
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v6 12/13] drm: nova: Report GPU short name in GPU info
2026-09-09 6:44 [PATCH v6 00/13] gpu: nova: Export parameters from nova-core to nova-drm Alistair Popple
` (10 preceding siblings ...)
2026-09-09 6:45 ` [PATCH v6 11/13] drm: nova: Report GPU name in GPU info Alistair Popple
@ 2026-09-09 6:45 ` Alistair Popple
2026-09-09 6:45 ` [PATCH v6 13/13] drm: nova: Report GPU GID " Alistair Popple
12 siblings, 0 replies; 16+ messages in thread
From: Alistair Popple @ 2026-09-09 6:45 UTC (permalink / raw)
To: rust-for-linux, nova-gpu
Cc: Alistair Popple, M Henning, Danilo Krummrich, Alice Ryhl,
David Airlie, Alexandre Courbot, Benno Lossin, Gary Guo,
Eliot Courtney, John Hubbard, Greg Kroah-Hartman,
Rafael J. Wysocki, linux-kernel, dri-devel
Add the short GPU name to the GPU info structure. As with the full name
it is copied from a validated, NUL-terminated string extracted by
nova-core rather than from the raw firmware bytes.
Signed-off-by: Alistair Popple <apopple@nvidia.com>
---
Changes since v5:
- Add a validating gpu_short_name() accessor to nova-core and use it
instead of exposing the raw bytes, as suggested by Danilo
Changes since v4:
- New for v5
---
drivers/gpu/drm/nova/file.rs | 5 +++++
drivers/gpu/nova-core/gsp/commands.rs | 13 +++++++++++++
drivers/gpu/nova-core/gsp/fw/commands.rs | 5 +++++
include/uapi/drm/nova_drm.h | 5 +++++
4 files changed, 28 insertions(+)
diff --git a/drivers/gpu/drm/nova/file.rs b/drivers/gpu/drm/nova/file.rs
index 4753d9bca13b..d2e1f9f798a4 100644
--- a/drivers/gpu/drm/nova/file.rs
+++ b/drivers/gpu/drm/nova/file.rs
@@ -61,6 +61,11 @@ fn new(reg_data: &DrmRegData<'_>) -> Result<Self> {
copy_name(&mut info.gpu_name, gsp_static_info.gpu_name().map_err(|_| EINVAL)?)?;
+ copy_name(
+ &mut info.gpu_short_name,
+ gsp_static_info.gpu_short_name().map_err(|_| EINVAL)?,
+ )?;
+
Ok(Self(info))
}
}
diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
index 00cfcef260c5..5ea0f625f7df 100644
--- a/drivers/gpu/nova-core/gsp/commands.rs
+++ b/drivers/gpu/nova-core/gsp/commands.rs
@@ -214,6 +214,7 @@ fn init(&self) -> impl Init<Self::Command, Self::InitError> {
/// The reply from the GSP to the [`GetGspStaticInfo`] command.
pub struct GetGspStaticInfoReply {
gpu_name: [u8; 64],
+ gpu_short_name: [u8; 64],
/// Usable FB (VRAM) regions for driver memory allocation.
pub(crate) usable_fb_regions: KVec<Range<u64>>,
}
@@ -234,6 +235,7 @@ fn read(
Ok(GetGspStaticInfoReply {
gpu_name: msg.gpu_name_str(),
+ gpu_short_name: msg.gpu_short_name_str(),
usable_fb_regions,
})
}
@@ -261,6 +263,17 @@ pub fn gpu_name(&self) -> core::result::Result<&str, GpuNameError> {
.map_err(GpuNameError::InvalidUtf8)
}
+ /// Returns the short name of the GPU as a string.
+ ///
+ /// Returns an error if the string given by the GSP does not contain a null terminator or
+ /// contains invalid UTF-8.
+ pub fn gpu_short_name(&self) -> core::result::Result<&str, GpuNameError> {
+ CStr::from_bytes_until_nul(&self.gpu_short_name)
+ .map_err(GpuNameError::NoNullTerminator)?
+ .to_str()
+ .map_err(GpuNameError::InvalidUtf8)
+ }
+
/// Returns the total usable VRAM size in bytes, i.e. the summed lengths of all usable FB
/// regions.
pub fn vram_size(&self) -> u64 {
diff --git a/drivers/gpu/nova-core/gsp/fw/commands.rs b/drivers/gpu/nova-core/gsp/fw/commands.rs
index 6dc31d1bf5ae..f62fb85f4473 100644
--- a/drivers/gpu/nova-core/gsp/fw/commands.rs
+++ b/drivers/gpu/nova-core/gsp/fw/commands.rs
@@ -131,6 +131,11 @@ impl GspStaticConfigInfo {
self.0.gpuNameString
}
+ /// Returns a bytes array containing the (hopefully) zero-terminated short name of this GPU.
+ pub(crate) fn gpu_short_name_str(&self) -> [u8; 64] {
+ self.0.gpuShortNameString
+ }
+
/// Returns an iterator over valid FB regions from GSP firmware data.
fn fb_regions(
&self,
diff --git a/include/uapi/drm/nova_drm.h b/include/uapi/drm/nova_drm.h
index c692cacaa552..b0af9945b6c5 100644
--- a/include/uapi/drm/nova_drm.h
+++ b/include/uapi/drm/nova_drm.h
@@ -191,6 +191,11 @@ struct drm_nova_info_gpu {
* @gpu_name: NUL-terminated full GPU name.
*/
__u8 gpu_name[64];
+
+ /**
+ * @gpu_short_name: NUL-terminated short GPU name.
+ */
+ __u8 gpu_short_name[64];
};
#define DRM_NOVA_GETPARAM 0x00
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v6 13/13] drm: nova: Report GPU GID in GPU info
2026-09-09 6:44 [PATCH v6 00/13] gpu: nova: Export parameters from nova-core to nova-drm Alistair Popple
` (11 preceding siblings ...)
2026-09-09 6:45 ` [PATCH v6 12/13] drm: nova: Report GPU short " Alistair Popple
@ 2026-09-09 6:45 ` Alistair Popple
12 siblings, 0 replies; 16+ messages in thread
From: Alistair Popple @ 2026-09-09 6:45 UTC (permalink / raw)
To: rust-for-linux, nova-gpu
Cc: Alistair Popple, M Henning, Danilo Krummrich, Alice Ryhl,
David Airlie, Alexandre Courbot, Benno Lossin, Gary Guo,
Eliot Courtney, John Hubbard, Greg Kroah-Hartman,
Rafael J. Wysocki, linux-kernel, dri-devel
Add the GPU GID to the reported GPU info. This is the 16-byte SHA-1
based identifier GSP-RM reports for the GPU.
Signed-off-by: Alistair Popple <apopple@nvidia.com>
---
Changes since v5:
- Read the GID from the GSP static info exposed by nova-core rather
than adding a forwarding method
Changes since v4:
- New for v5
---
drivers/gpu/drm/nova/file.rs | 1 +
drivers/gpu/nova-core/gsp/commands.rs | 3 +++
drivers/gpu/nova-core/gsp/fw/commands.rs | 10 ++++++++++
include/uapi/drm/nova_drm.h | 5 +++++
4 files changed, 19 insertions(+)
diff --git a/drivers/gpu/drm/nova/file.rs b/drivers/gpu/drm/nova/file.rs
index d2e1f9f798a4..7f7f0a0ba622 100644
--- a/drivers/gpu/drm/nova/file.rs
+++ b/drivers/gpu/drm/nova/file.rs
@@ -56,6 +56,7 @@ fn new(reg_data: &DrmRegData<'_>) -> Result<Self> {
architecture: spec.chipset.arch() as u32,
chipid: spec.chipset as u32,
vram_size: gsp_static_info.vram_size(),
+ gpu_gid: gsp_static_info.gpu_gid,
..Default::default()
};
diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
index 5ea0f625f7df..40cef8332eae 100644
--- a/drivers/gpu/nova-core/gsp/commands.rs
+++ b/drivers/gpu/nova-core/gsp/commands.rs
@@ -215,6 +215,8 @@ fn init(&self) -> impl Init<Self::Command, Self::InitError> {
pub struct GetGspStaticInfoReply {
gpu_name: [u8; 64],
gpu_short_name: [u8; 64],
+ /// The 16-byte SHA-1 based GPU identifier (GID) reported by GSP-RM.
+ pub gpu_gid: [u8; 16],
/// Usable FB (VRAM) regions for driver memory allocation.
pub(crate) usable_fb_regions: KVec<Range<u64>>,
}
@@ -236,6 +238,7 @@ fn read(
Ok(GetGspStaticInfoReply {
gpu_name: msg.gpu_name_str(),
gpu_short_name: msg.gpu_short_name_str(),
+ gpu_gid: msg.gpu_gid(),
usable_fb_regions,
})
}
diff --git a/drivers/gpu/nova-core/gsp/fw/commands.rs b/drivers/gpu/nova-core/gsp/fw/commands.rs
index f62fb85f4473..d1ce2f1aeda9 100644
--- a/drivers/gpu/nova-core/gsp/fw/commands.rs
+++ b/drivers/gpu/nova-core/gsp/fw/commands.rs
@@ -136,6 +136,16 @@ impl GspStaticConfigInfo {
self.0.gpuShortNameString
}
+ /// Returns the 16-byte SHA-1 GPU identifier supplied by GSP-RM.
+ ///
+ /// GSP-RM reports the GID in binary SHA-1 form, which occupies the first 16 bytes of the
+ /// GID info payload.
+ pub(crate) fn gpu_gid(&self) -> [u8; 16] {
+ let mut gid = [0u8; 16];
+ gid.copy_from_slice(&self.0.gidInfo.data[..16]);
+ gid
+ }
+
/// Returns an iterator over valid FB regions from GSP firmware data.
fn fb_regions(
&self,
diff --git a/include/uapi/drm/nova_drm.h b/include/uapi/drm/nova_drm.h
index b0af9945b6c5..9283660a04cb 100644
--- a/include/uapi/drm/nova_drm.h
+++ b/include/uapi/drm/nova_drm.h
@@ -196,6 +196,11 @@ struct drm_nova_info_gpu {
* @gpu_short_name: NUL-terminated short GPU name.
*/
__u8 gpu_short_name[64];
+
+ /**
+ * @gpu_gid: 16-byte SHA-1 GPU identifier supplied by GSP-RM.
+ */
+ __u8 gpu_gid[16];
};
#define DRM_NOVA_GETPARAM 0x00
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH v6 06/13] rust: uaccess: add UserSliceWriter::write_truncated()
2026-09-09 6:44 ` [PATCH v6 06/13] rust: uaccess: add UserSliceWriter::write_truncated() Alistair Popple
@ 2026-09-09 6:56 ` sashiko-bot
0 siblings, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-09-09 6:56 UTC (permalink / raw)
To: Alistair Popple
Cc: dri-devel, ojeda, Danilo Krummrich, gary, Alexandre Courbot
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The small abstraction function `write_truncated` is missing the `#[inline]` attribute.
--
commit e02911d12d3fe66c588f96439e4940e145b90f1e
Author: Alistair Popple <apopple@nvidia.com>
rust: uaccess: add UserSliceWriter::write_truncated()
This commit adds a new write_truncated() helper to UserSliceWriter that
writes as much of an AsBytes value as fits in the remaining userspace
buffer. It avoids requiring callers to manually truncate values for
versioned UAPIs.
> diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
> index 5f6c4d7a1a516..c63b919426315 100644
> --- a/rust/kernel/uaccess.rs
> +++ b/rust/kernel/uaccess.rs
> @@ -624,6 +624,20 @@ pub fn write<T: AsBytes>(&mut self, value: &T) -> Result {
> self.length -= len;
> Ok(())
> }
> +
> + /// Writes as much of the provided value as fits in the remaining buffer.
> + ///
> + /// Copies `min(size_of::<T>(), self.len())` bytes to userspace. Returns the number of bytes
> + /// actually written. This is useful for versioned structs where an older userspace may provide
> + /// a smaller buffer than the current kernel struct.
> + ///
> + /// Fails with [`EFAULT`] if the write happens on a bad address. This call may modify the
> + /// associated userspace slice even if it returns an error.
> + pub fn write_truncated<T: AsBytes>(&mut self, value: &T) -> Result<usize> {
[Severity: Low]
This isn't a bug, but should this abstraction function include the #[inline]
attribute?
According to the Rust subsystem guidelines, small functions in abstractions
like the kernel crate should be annotated with #[inline] to allow the
compiler to optimally inline them across crate boundaries.
> + let len = self.length.min(size_of::<T>());
> + self.write_slice(&value.as_bytes()[..len])?;
> + Ok(len)
> + }
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260909064506.910162-1-apopple@nvidia.com?part=6
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v6 01/13] rust: auxiliary: let registration_data_with() closures return covariant sub-fields
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:57 ` sashiko-bot
0 siblings, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-09-09 6:57 UTC (permalink / raw)
To: Alistair Popple
Cc: ojeda, dri-devel, Danilo Krummrich, Alexandre Courbot, gary
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Safe methods `registration_data_with` and `registration_data` can cause a Use-After-Free because `Registration::drop` frees the registration data but leaves a dangling pointer in the underlying C struct.
--
commit f7dbc67a0cd0bf4fcd048c32f110a8ba459452b3
Author: Alistair Popple <apopple@nvidia.com>
rust: auxiliary: let registration_data_with() closures return covariant sub-fields
The closure passed to registration_data_with() currently receives
Pin<&'a F::Of<'a>> with 'a universally quantified. This prevents the
closure from returning references derived from the registration data,
even for sub-fields that are covariant in their lifetime. By tying the
outer reference to the &self lifetime, the closure can coerce covariant
sub-fields and return them directly.
Link: https://lore.kernel.org/nova-gpu/DL3WPTVM033J.33RWYCZOC67Z1@kernel.org/
> diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs
> index 60dfbec8f3302..06f816420790a 100644
> --- a/rust/kernel/auxiliary.rs
> +++ b/rust/kernel/auxiliary.rs
[ ... ]
> @@ -314,13 +318,14 @@ unsafe fn registration_data_pinned<F: ForLt + 'static>(&self) -> Result<Pin<&F::
> /// Returns [`ENOENT`] if no registration data has been set, e.g. when the device was
> /// registered by a C driver.
> #[inline]
> - pub fn registration_data_with<F: ForLt + 'static, R>(
> - &self,
> - f: impl for<'a> FnOnce(Pin<&'a F::Of<'a>>) -> R,
> + pub fn registration_data_with<'this, F: ForLt + 'static, R>(
> + &'this self,
> + f: impl for<'a> FnOnce(Pin<&'this F::Of<'a>>) -> R,
> ) -> Result<R> {
[Severity: High]
This is a pre-existing issue, but can this safe method cause a use-after-free
if a child driver or a detached kernel thread retains an ARef<Device> after
the parent's unbind event?
Looking at Registration::drop in rust/kernel/auxiliary.rs, it frees the
registration data but does not clear the registration_data_rust pointer in
the underlying C struct:
Registration::drop() {
...
// SAFETY: registration_data was set in new() via into_foreign().
drop(unsafe {
Pin::<KBox<RegistrationData<F::Of<'static>>>>::from_foreign(
(*self.adev.as_ptr()).registration_data_rust,
)
});
...
}
If a safely retained Device is then used to call registration_data_with(), the
internal registration_data_pinned() method will bypass the null check and
read from the dangling pointer:
Device::registration_data_pinned() {
let ptr = unsafe { (*self.as_raw()).registration_data_rust };
if ptr.is_null() {
...
return Err(ENOENT);
}
...
let type_id = unsafe { ptr.cast::<TypeId>().read() };
...
}
Could Registration::drop be updated to clear registration_data_rust to NULL
before freeing the data to prevent this issue? Or does this also need
additional synchronization to handle concurrent access safely?
> - // SAFETY: The HRTB closure prevents the caller from smuggling in references with a
> - // concrete short lifetime, making the round-trip from `'static` sound regardless of
> - // variance.
> + // SAFETY: The HRTB on the inner type prevents the caller from exploiting a specific
> + // choice of `'a`. Covariant sub-fields can be safely coerced to `'this`, while
> + // invariant fields cannot be coerced and thus cannot escape with an incorrect
> + // lifetime.
> let pinned = unsafe { self.registration_data_pinned::<F>()? };
>
> Ok(f(pinned))
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260909064506.910162-1-apopple@nvidia.com?part=1
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2026-09-09 6:57 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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:57 ` sashiko-bot
2026-09-09 6:44 ` [PATCH v6 02/13] gpu: nova-core: Add public driver API to nova-core Alistair Popple
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:56 ` sashiko-bot
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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox