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 07/13] drm: nova: Add an info ioctl
Date: Wed, 9 Sep 2026 16:45:00 +1000 [thread overview]
Message-ID: <20260909064506.910162-8-apopple@nvidia.com> (raw)
In-Reply-To: <20260909064506.910162-1-apopple@nvidia.com>
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
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 ` [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:45 ` Alistair Popple [this message]
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-8-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
all inboxes | Powered by JetHome®