* [PATCH v3 0/8] drm/tyr: add debugfs support
@ 2026-08-06 17:07 Alvin Sun
2026-08-06 17:07 ` [PATCH v3 1/8] rust: seq_file: add as_raw() method Alvin Sun
` (7 more replies)
0 siblings, 8 replies; 9+ messages in thread
From: Alvin Sun @ 2026-08-06 17:07 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, Greg Kroah-Hartman,
Rafael J. Wysocki, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter
Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Brost,
Thomas Hellström, rust-for-linux, driver-core, dri-devel,
Alvin Sun
Add debugfs support for the Tyr DRM driver.
The series adds a SeqShow trait for seq_file-backed debugfs files, a
debugfs_init callback on the DRM Driver trait, and a gpuvas debugfs
file in Tyr exposing GPU VA space information.
This is based on drm-rust-next and depends on:
[PATCH v10 0/7] drm/tyr: firmware loading and MCU boot support
https://lore.kernel.org/r/20260728-fw-boot-b4-v10-0-9187aefa3f2f@collabora.com
See the full dependency and commit history at [1].
Link: https://gitlab.freedesktop.org/panfrost/linux/-/issues/11
Link: https://gitlab.freedesktop.org/panfrost/linux/-/merge_requests/59 [1]
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
Changes in v3:
- Drop the DrmSeqShow adapter and use SeqShow directly, per Danilo's
feedback. Simplify the debugfs_init callback signature accordingly.
- Redesign VmRegistry per Daniel's and Alice's feedback: move it to
vm.rs at the top level of the registration data, use Arc<VmRegistry>
for shared ownership, and separate register/unregister from Vm::new
and Vm::kill. Registration failure is non-fatal (dev_warn) since the
registry is a debugfs convenience.
- Add VmRegistry::unregister to remove VMs on teardown, addressing
Alice's concern about the list going out of sync.
- Drop the "hold device reference for open files" patch; the debugfs
proxy fops already ensure file operations cannot outlive
debugfs_remove().
- Improve SAFETY comments and fix style issues identified during review.
- Link to v2: https://lore.kernel.org/r/20260731-tyr-debugfs-v2-v2-0-aea19eccb996@linux.dev
Changes in v2:
- Reworked the debugfs implementation per feedback from Danilo on v1:
dropped the hazptr/revocable-based approach in favor of the DRM
debugfs_init callback and generic seq_file abstractions.
- Fixed a UAF in drm_debugfs where a device could be unregistered while
a debugfs file remains open (drm_dev_get/put across file lifetime).
- Link to v1: https://lore.kernel.org/r/20260326-b4-tyr-debugfs-v1-0-074badd18716@linux.dev
---
Alvin Sun (8):
rust: seq_file: add as_raw() method
rust: debugfs: add seq_file support
rust: debugfs: add ScopeRef for existing dentries
drm: move debugfs_init after dev->registered is set
rust: drm: add debugfs_init callback to Driver trait
rust: drm: gpuvm: add dump_gpuva_info to UniqueRefGpuVm
drm/tyr: track VMs in a registry
drm/tyr: add gpuvas debugfs file
drivers/gpu/drm/drm_debugfs.c | 3 --
drivers/gpu/drm/drm_drv.c | 5 +++
drivers/gpu/drm/tyr/debugfs.rs | 20 ++++++++++
drivers/gpu/drm/tyr/driver.rs | 16 +++++++-
drivers/gpu/drm/tyr/fw.rs | 18 +++++++--
drivers/gpu/drm/tyr/tyr.rs | 1 +
drivers/gpu/drm/tyr/vm.rs | 33 ++++++++++++++++
rust/bindings/bindings_helper.h | 1 +
rust/kernel/debugfs.rs | 84 ++++++++++++++++++++++++++++++++++++++++-
rust/kernel/debugfs/entry.rs | 15 +++++++-
rust/kernel/debugfs/file_ops.rs | 60 +++++++++++++++++++++++++++++
rust/kernel/debugfs/traits.rs | 11 ++++++
rust/kernel/drm/device.rs | 41 +++++++++++++++++++-
rust/kernel/drm/driver.rs | 11 ++++++
rust/kernel/drm/gpuvm/mod.rs | 9 +++++
rust/kernel/seq_file.rs | 6 +++
16 files changed, 323 insertions(+), 11 deletions(-)
---
base-commit: 0ffc014cb2abfc79d161662b125e085b3e7107e7
change-id: 20260730-tyr-debugfs-v2-608cef77d6e9
Best regards,
--
Alvin Sun <alvin.sun@linux.dev>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 1/8] rust: seq_file: add as_raw() method
2026-08-06 17:07 [PATCH v3 0/8] drm/tyr: add debugfs support Alvin Sun
@ 2026-08-06 17:07 ` Alvin Sun
2026-08-06 17:07 ` [PATCH v3 2/8] rust: debugfs: add seq_file support Alvin Sun
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Alvin Sun @ 2026-08-06 17:07 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, Greg Kroah-Hartman,
Rafael J. Wysocki, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter
Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Brost,
Thomas Hellström, rust-for-linux, driver-core, dri-devel,
Alvin Sun
Add a method to obtain a raw pointer to the underlying struct
seq_file, needed for FFI calls into C (e.g. drm_debugfs_gpuva_info).
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
rust/kernel/seq_file.rs | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/rust/kernel/seq_file.rs b/rust/kernel/seq_file.rs
index 518265558d66f..fbc75e0e77634 100644
--- a/rust/kernel/seq_file.rs
+++ b/rust/kernel/seq_file.rs
@@ -29,6 +29,12 @@ pub unsafe fn from_raw<'a>(ptr: *mut bindings::seq_file) -> &'a SeqFile {
unsafe { &*ptr.cast() }
}
+ /// Returns a raw pointer to the underlying `struct seq_file`.
+ #[inline]
+ pub fn as_raw(&self) -> *mut bindings::seq_file {
+ self.inner.get()
+ }
+
/// Used by the [`seq_print`] macro.
#[inline]
pub fn call_printf(&self, args: fmt::Arguments<'_>) {
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 2/8] rust: debugfs: add seq_file support
2026-08-06 17:07 [PATCH v3 0/8] drm/tyr: add debugfs support Alvin Sun
2026-08-06 17:07 ` [PATCH v3 1/8] rust: seq_file: add as_raw() method Alvin Sun
@ 2026-08-06 17:07 ` Alvin Sun
2026-08-06 17:07 ` [PATCH v3 3/8] rust: debugfs: add ScopeRef for existing dentries Alvin Sun
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Alvin Sun @ 2026-08-06 17:07 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, Greg Kroah-Hartman,
Rafael J. Wysocki, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter
Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Brost,
Thomas Hellström, rust-for-linux, driver-core, dri-devel,
Alvin Sun
Add SeqShow trait for seq_file-backed debugfs files. Needed by DRM
and other subsystems to expose readable debugfs state via seq_file.
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
rust/kernel/debugfs/file_ops.rs | 60 +++++++++++++++++++++++++++++++++++++++++
rust/kernel/debugfs/traits.rs | 11 ++++++++
2 files changed, 71 insertions(+)
diff --git a/rust/kernel/debugfs/file_ops.rs b/rust/kernel/debugfs/file_ops.rs
index f15908f71c4a2..ee8c85360e924 100644
--- a/rust/kernel/debugfs/file_ops.rs
+++ b/rust/kernel/debugfs/file_ops.rs
@@ -5,11 +5,13 @@
BinaryReader,
BinaryWriter,
Reader,
+ SeqShow,
Writer, //
};
use crate::{
debugfs::callback_adapters::Adapter,
+ error::from_result,
fmt,
fs::file,
prelude::*,
@@ -123,6 +125,64 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
0
}
+/// Show callback for `SeqShow` types.
+///
+/// # Safety
+///
+/// The seq_file core guarantees that `seq` points to a live `seq_file`
+/// whose private data is a valid pointer to a `T` with no outstanding
+/// mutable references.
+unsafe extern "C" fn seq_file_show<S: SeqShow<T>, T: Sync>(
+ seq: *mut bindings::seq_file,
+ _: *mut c_void,
+) -> c_int {
+ // SAFETY: `seq->private` is a valid `T` pointer with no outstanding
+ // mutable references.
+ let data = unsafe { &*((*seq).private.cast::<T>()) };
+ // SAFETY: `seq` points to a live `seq_file`.
+ let m = unsafe { SeqFile::from_raw(seq) };
+ from_result(|| S::show(data, m).map(|()| 0))
+}
+
+/// Open callback for `SeqShow` types.
+///
+/// # Safety
+///
+/// The VFS guarantees that `inode` is valid with `i_private` pointing to a
+/// valid `T` that remains valid for the duration of the call, and that `file`
+/// points to a live, uninitialized file object.
+unsafe extern "C" fn seq_file_open<S: SeqShow<T>, T: Sync>(
+ inode: *mut bindings::inode,
+ file: *mut bindings::file,
+) -> c_int {
+ // SAFETY: `inode` is valid per VFS. `i_private` points to a valid `T`
+ // (guaranteed by the `FileOps<T>` invariants).
+ let data = unsafe { (*inode).i_private.cast::<T>() };
+
+ // SAFETY: `file` is valid per VFS; `data` matches `seq_file_show`'s contract.
+ unsafe { bindings::single_open(file, Some(seq_file_show::<S, T>), data.cast()) }
+}
+
+pub(crate) trait SeqReadFile<T> {
+ const FILE_OPS: FileOps<T>;
+}
+
+impl<S: SeqShow<T>, T: Sync> SeqReadFile<T> for S {
+ const FILE_OPS: FileOps<T> = {
+ let operations = bindings::file_operations {
+ read: Some(bindings::seq_read),
+ llseek: Some(bindings::seq_lseek),
+ release: Some(bindings::single_release),
+ open: Some(seq_file_open::<Self, T>),
+ ..pin_init::zeroed()
+ };
+ // SAFETY: `read` and `llseek` are stock `seq_file` implementations.
+ // `seq_file_open` treats `inode->i_private` as a valid `&T` reference,
+ // satisfying the `FileOps::new` contract.
+ unsafe { FileOps::new(operations, 0o400) }
+ };
+}
+
// Work around lack of generic const items.
pub(crate) trait ReadFile<T> {
const FILE_OPS: FileOps<T>;
diff --git a/rust/kernel/debugfs/traits.rs b/rust/kernel/debugfs/traits.rs
index 8c39524b6a990..02782cd817c4b 100644
--- a/rust/kernel/debugfs/traits.rs
+++ b/rust/kernel/debugfs/traits.rs
@@ -8,6 +8,7 @@
fmt,
fs::file,
prelude::*,
+ seq_file::SeqFile,
sync::{
atomic::{
Atomic,
@@ -338,3 +339,13 @@ fn read_from_slice(
self.deref().read_from_slice(reader, offset)
}
}
+
+/// Renders `data` into a seq_file.
+///
+/// `data` is the value stashed as the debugfs file's `i_private` at creation
+/// time. `show` is invoked on each read to produce the file's contents.
+/// `data` must remain valid while the debugfs file is registered.
+pub trait SeqShow<T> {
+ /// Writes debugfs output for the file.
+ fn show(data: &T, m: &SeqFile) -> Result;
+}
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 3/8] rust: debugfs: add ScopeRef for existing dentries
2026-08-06 17:07 [PATCH v3 0/8] drm/tyr: add debugfs support Alvin Sun
2026-08-06 17:07 ` [PATCH v3 1/8] rust: seq_file: add as_raw() method Alvin Sun
2026-08-06 17:07 ` [PATCH v3 2/8] rust: debugfs: add seq_file support Alvin Sun
@ 2026-08-06 17:07 ` Alvin Sun
2026-08-06 17:07 ` [PATCH v3 4/8] drm: move debugfs_init after dev->registered is set Alvin Sun
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Alvin Sun @ 2026-08-06 17:07 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, Greg Kroah-Hartman,
Rafael J. Wysocki, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter
Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Brost,
Thomas Hellström, rust-for-linux, driver-core, dri-devel,
Alvin Sun
Add methods to construct debugfs abstractions from raw C dentry
pointers. Needed by DRM debugfs_init callback to create ScopedDir
from an existing dentry.
Add ScopeRef<'a, T>, a debugfs directory handle that carries a
reference to associated data of type T.
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
rust/kernel/debugfs.rs | 84 ++++++++++++++++++++++++++++++++++++++++++--
rust/kernel/debugfs/entry.rs | 15 +++++++-
2 files changed, 96 insertions(+), 3 deletions(-)
diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs
index d7b8014a64746..831d6750a34ba 100644
--- a/rust/kernel/debugfs.rs
+++ b/rust/kernel/debugfs.rs
@@ -24,7 +24,7 @@
PhantomData,
PhantomPinned, //
},
- ops::Deref,
+ ops::Deref, //
};
mod traits;
@@ -33,6 +33,7 @@
BinaryReaderMut,
BinaryWriter,
Reader,
+ SeqShow,
Writer, //
};
@@ -51,6 +52,7 @@
FileOps,
ReadFile,
ReadWriteFile,
+ SeqReadFile,
WriteFile, //
};
@@ -538,7 +540,7 @@ pub fn dir<'dir2>(&'dir2 self, name: &CStr) -> ScopedDir<'data, 'dir2> {
}
}
- fn create_file<T: Sync>(&self, name: &CStr, data: &'data T, vtable: &'static FileOps<T>) {
+ fn create_file<T: Sync>(&self, name: &CStr, data: &'data T, vtable: &FileOps<T>) {
#[cfg(CONFIG_DEBUG_FS)]
core::mem::forget(Entry::file(name, &self.entry, data, vtable));
}
@@ -588,6 +590,14 @@ pub fn read_callback_file<T, F>(&self, name: &CStr, data: &'data T, _f: &'static
self.create_file(name, data, vtable)
}
+ /// Creates a seq_file debugfs file in this directory.
+ ///
+ /// The file's contents are produced by invoking [`SeqShow::show`] with
+ /// `data` on each read.
+ pub fn seq_file<S: SeqShow<U>, U: Sync>(&self, name: &CStr, data: &'data U) {
+ self.create_file(name, data, &<S as SeqReadFile<U>>::FILE_OPS)
+ }
+
/// Creates a read-write file in this directory.
///
/// Reading the file uses the [`Writer`] implementation on `data`. Writing to the file uses
@@ -721,4 +731,74 @@ fn new(name: &CStr) -> ScopedDir<'data, 'static> {
_phantom: PhantomData,
}
}
+
+ /// Creates a [`ScopedDir`] wrapping an existing debugfs dentry.
+ ///
+ /// Files created under this directory are not automatically removed on drop;
+ /// their lifetime is tied to the dentry owner.
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure the dentry remains valid for the lifetime of the
+ /// returned `ScopedDir`.
+ pub unsafe fn from_dentry(dentry: *mut bindings::dentry) -> Self {
+ let _ = dentry;
+ ScopedDir {
+ #[cfg(CONFIG_DEBUG_FS)]
+ // SAFETY: The caller guarantees the dentry is valid and outlives this `ScopedDir`.
+ entry: ManuallyDrop::new(unsafe { Entry::from_raw(dentry) }),
+ _phantom: PhantomData,
+ }
+ }
+}
+
+/// A reference to a debugfs directory that also holds a reference to
+/// associated data of type `T`.
+///
+/// Created from an existing debugfs dentry (e.g. the DRM debugfs root).
+/// `data` must remain valid while the debugfs files created under this
+/// scope may be accessed.
+pub struct ScopeRef<'a, T> {
+ #[cfg(CONFIG_DEBUG_FS)]
+ inner: ScopedDir<'a, 'a>,
+ data: &'a T,
+}
+
+impl<'a, T> ScopeRef<'a, T> {
+ /// Creates a [`ScopeRef`] from an existing debugfs dentry and a data reference.
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that `dentry` remains valid for the lifetime of
+ /// the returned [`ScopeRef`] and that `data` remains valid while the
+ /// debugfs files created under this scope may be accessed.
+ pub unsafe fn new(dentry: *mut bindings::dentry, data: &'a T) -> Self {
+ let _ = dentry;
+ ScopeRef {
+ #[cfg(CONFIG_DEBUG_FS)]
+ // SAFETY: By the safety preconditions of `new`, `dentry` is valid
+ // and remains valid for the lifetime of the returned `ScopeRef`.
+ inner: unsafe { ScopedDir::from_dentry(dentry) },
+ data,
+ }
+ }
+
+ /// Creates a seq_file debugfs file in this directory.
+ ///
+ /// The file's contents are produced by invoking [`SeqShow::show`] with
+ /// `data` on each read.
+ #[cfg(CONFIG_DEBUG_FS)]
+ pub fn seq_file<S: SeqShow<T>>(&self, name: &CStr)
+ where
+ T: Sync,
+ {
+ self.inner.seq_file::<S, T>(name, self.data);
+ }
+
+ #[cfg(not(CONFIG_DEBUG_FS))]
+ pub fn seq_file<S: SeqShow<T>>(&self, _name: &CStr)
+ where
+ T: Sync,
+ {
+ }
}
diff --git a/rust/kernel/debugfs/entry.rs b/rust/kernel/debugfs/entry.rs
index 46aad64896ecb..7643ff0fa6093 100644
--- a/rust/kernel/debugfs/entry.rs
+++ b/rust/kernel/debugfs/entry.rs
@@ -8,7 +8,7 @@
CStr,
CStrExt as _, //
},
- sync::Arc,
+ sync::Arc, //
};
use core::marker::PhantomData;
@@ -87,6 +87,19 @@ pub(crate) unsafe fn dynamic_file<T>(
}
impl<'a> Entry<'a> {
+ /// Wraps a raw dentry pointer.
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure the dentry is valid and outlives this `Entry`.
+ pub(crate) unsafe fn from_raw(entry: *mut bindings::dentry) -> Self {
+ Self {
+ entry,
+ _parent: None,
+ _phantom: PhantomData,
+ }
+ }
+
pub(crate) fn dir(name: &CStr, parent: Option<&'a Entry<'_>>) -> Self {
let parent_ptr = match &parent {
Some(entry) => entry.as_ptr(),
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 4/8] drm: move debugfs_init after dev->registered is set
2026-08-06 17:07 [PATCH v3 0/8] drm/tyr: add debugfs support Alvin Sun
` (2 preceding siblings ...)
2026-08-06 17:07 ` [PATCH v3 3/8] rust: debugfs: add ScopeRef for existing dentries Alvin Sun
@ 2026-08-06 17:07 ` Alvin Sun
2026-08-06 17:07 ` [PATCH v3 5/8] rust: drm: add debugfs_init callback to Driver trait Alvin Sun
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Alvin Sun @ 2026-08-06 17:07 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, Greg Kroah-Hartman,
Rafael J. Wysocki, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter
Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Brost,
Thomas Hellström, rust-for-linux, driver-core, dri-devel,
Alvin Sun
The debugfs_init callback is called from drm_debugfs_register during
drm_minor_register, before dev->registered is set to true. Move it to
drm_dev_register after dev->registered = true so that callbacks see a
fully registered device.
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
drivers/gpu/drm/drm_debugfs.c | 3 ---
drivers/gpu/drm/drm_drv.c | 5 +++++
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c
index ae1c6126c2c59..38cf6ce387cc8 100644
--- a/drivers/gpu/drm/drm_debugfs.c
+++ b/drivers/gpu/drm/drm_debugfs.c
@@ -442,9 +442,6 @@ int drm_debugfs_register(struct drm_minor *minor, int minor_id)
/* TODO: Only for compatibility with drivers */
minor->debugfs_root = dev->debugfs_root;
- if (dev->driver->debugfs_init && dev->render != minor)
- dev->driver->debugfs_init(minor);
-
return 0;
}
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index e890052061f30..15669764fe625 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -1101,6 +1101,11 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
dev->registered = true;
dev->unplugged = false;
+ /* Call debugfs_init after the device is fully registered. */
+ if (dev->driver->debugfs_init && dev->primary &&
+ dev->render != dev->primary)
+ dev->driver->debugfs_init(dev->primary);
+
if (driver->load) {
ret = driver->load(dev, flags);
if (ret)
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 5/8] rust: drm: add debugfs_init callback to Driver trait
2026-08-06 17:07 [PATCH v3 0/8] drm/tyr: add debugfs support Alvin Sun
` (3 preceding siblings ...)
2026-08-06 17:07 ` [PATCH v3 4/8] drm: move debugfs_init after dev->registered is set Alvin Sun
@ 2026-08-06 17:07 ` Alvin Sun
2026-08-06 17:07 ` [PATCH v3 6/8] rust: drm: gpuvm: add dump_gpuva_info to UniqueRefGpuVm Alvin Sun
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Alvin Sun @ 2026-08-06 17:07 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, Greg Kroah-Hartman,
Rafael J. Wysocki, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter
Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Brost,
Thomas Hellström, rust-for-linux, driver-core, dri-devel,
Alvin Sun
Add debugfs_init method to the Driver trait, enabling Rust DRM drivers
to populate debugfs entries during device registration.
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
rust/kernel/drm/device.rs | 41 ++++++++++++++++++++++++++++++++++++++++-
rust/kernel/drm/driver.rs | 11 +++++++++++
2 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs
index 7a3a0e21e9557..35fd514fec274 100644
--- a/rust/kernel/drm/device.rs
+++ b/rust/kernel/drm/device.rs
@@ -7,6 +7,7 @@
use crate::{
alloc::allocator::Kmalloc,
bindings,
+ debugfs,
device,
drm::{
self,
@@ -170,7 +171,7 @@ const fn compute_features() -> u32 {
release: Some(Device::<T>::release),
master_set: None,
master_drop: None,
- debugfs_init: None,
+ debugfs_init: Some(Device::<T>::debugfs_init_callback),
gem_create_object: T::Object::ALLOC_OPS.gem_create_object,
prime_handle_to_fd: T::Object::ALLOC_OPS.prime_handle_to_fd,
@@ -353,6 +354,44 @@ extern "C" fn release(ptr: *mut bindings::drm_device) {
unsafe { core::ptr::drop_in_place(this) };
}
+ /// C callback for `drm_driver.debugfs_init`.
+ ///
+ /// # Safety
+ ///
+ /// The DRM core guarantees that `minor` is valid and non-null, that
+ /// `minor->dev` is a valid `drm_device` embedded in a `Device<T>`.
+ unsafe extern "C" fn debugfs_init_callback(minor: *mut bindings::drm_minor) {
+ // SAFETY: `minor` is valid and non-null per the function's safety
+ // precondition.
+ let dev_ptr = unsafe { (*minor).dev };
+ // SAFETY: `minor` is valid per the function's safety precondition.
+ let debugfs_root = unsafe { (*minor).debugfs_root };
+
+ // Debugfs may be disabled.
+ if debugfs_root.is_null() {
+ return;
+ }
+
+ // SAFETY: `dev_ptr` points to a valid `drm_device` embedded in
+ // `Device<T>`.
+ let dev = unsafe { Self::from_raw(dev_ptr) };
+
+ // SAFETY: The device is in the registered state per the function's
+ // safety precondition.
+ let dev = unsafe { dev.assume_ctx::<Registered>() };
+
+ dev.registration_data_with(|reg_data| {
+ // SAFETY: `debugfs_root` is valid as long as the DRM device is
+ // registered. The debugfs proxy fops wait for in-progress file
+ // operations and block new ones during `debugfs_remove()`, so no
+ // access to `reg_data` can outlive it. `debugfs_remove()` runs
+ // before `Registration::drop` frees `reg_data`.
+ let dir = unsafe { debugfs::ScopeRef::new(debugfs_root, reg_data) };
+
+ T::debugfs_init(&dir);
+ });
+ }
+
/// Change the [`DeviceContext`] for a [`Device`].
///
/// # Safety
diff --git a/rust/kernel/drm/driver.rs b/rust/kernel/drm/driver.rs
index 08b2a318cf02a..f850b11fd5c53 100644
--- a/rust/kernel/drm/driver.rs
+++ b/rust/kernel/drm/driver.rs
@@ -6,6 +6,7 @@
use crate::{
bindings,
+ debugfs,
device,
drm,
error::to_result,
@@ -138,6 +139,16 @@ pub trait Driver {
/// usable from the render node (i.e. marked DRM_RENDER_ALLOW), whereas
/// userspace processes using the master node can invoke any ioctl.
const FEAT_RENDER: bool = false;
+
+ /// Populates debugfs for this DRM device.
+ ///
+ /// Called by the DRM core during registration. The `ScopeRef` provides
+ /// access to the device's `RegistrationData` for creating debugfs files.
+ fn debugfs_init(_dir: &debugfs::ScopeRef<'_, Self::RegistrationData<'_>>)
+ where
+ Self: Sized,
+ {
+ }
}
/// The registration type of a `drm::Device`.
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 6/8] rust: drm: gpuvm: add dump_gpuva_info to UniqueRefGpuVm
2026-08-06 17:07 [PATCH v3 0/8] drm/tyr: add debugfs support Alvin Sun
` (4 preceding siblings ...)
2026-08-06 17:07 ` [PATCH v3 5/8] rust: drm: add debugfs_init callback to Driver trait Alvin Sun
@ 2026-08-06 17:07 ` Alvin Sun
2026-08-06 17:07 ` [PATCH v3 7/8] drm/tyr: track VMs in a registry Alvin Sun
2026-08-06 17:07 ` [PATCH v3 8/8] drm/tyr: add gpuvas debugfs file Alvin Sun
7 siblings, 0 replies; 9+ messages in thread
From: Alvin Sun @ 2026-08-06 17:07 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, Greg Kroah-Hartman,
Rafael J. Wysocki, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter
Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Brost,
Thomas Hellström, rust-for-linux, driver-core, dri-devel,
Alvin Sun
Add method wrapping drm_debugfs_gpuva_info to dump GPU VA space
mappings into a seq_file. Needed by the Tyr gpuvas debugfs file.
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
rust/bindings/bindings_helper.h | 1 +
rust/kernel/drm/gpuvm/mod.rs | 9 +++++++++
2 files changed, 10 insertions(+)
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 1124785e210b3..c3b2a86528934 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -30,6 +30,7 @@
#include <linux/acpi.h>
#include <linux/gpu_buddy.h>
+#include <drm/drm_debugfs.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
diff --git a/rust/kernel/drm/gpuvm/mod.rs b/rust/kernel/drm/gpuvm/mod.rs
index 20a08b3defeb8..9348b1c3064ec 100644
--- a/rust/kernel/drm/gpuvm/mod.rs
+++ b/rust/kernel/drm/gpuvm/mod.rs
@@ -312,6 +312,15 @@ pub fn data_ref(&self) -> &T {
unsafe { &*self.0.data.get() }
}
+ /// Dumps GPU VA space info into a seq_file.
+ ///
+ /// Wraps the C `drm_debugfs_gpuva_info` function.
+ #[inline]
+ pub fn dump_gpuva_info(&self, m: &crate::seq_file::SeqFile) -> Result {
+ // SAFETY: `m.as_raw()` and `self.as_raw()` are valid by the type invariants.
+ to_result(unsafe { bindings::drm_debugfs_gpuva_info(m.as_raw(), self.as_raw()) })
+ }
+
/// Access the data owned by this `UniqueRefGpuVm` mutably.
#[inline]
pub fn data(&mut self) -> &mut T {
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 7/8] drm/tyr: track VMs in a registry
2026-08-06 17:07 [PATCH v3 0/8] drm/tyr: add debugfs support Alvin Sun
` (5 preceding siblings ...)
2026-08-06 17:07 ` [PATCH v3 6/8] rust: drm: gpuvm: add dump_gpuva_info to UniqueRefGpuVm Alvin Sun
@ 2026-08-06 17:07 ` Alvin Sun
2026-08-06 17:07 ` [PATCH v3 8/8] drm/tyr: add gpuvas debugfs file Alvin Sun
7 siblings, 0 replies; 9+ messages in thread
From: Alvin Sun @ 2026-08-06 17:07 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, Greg Kroah-Hartman,
Rafael J. Wysocki, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter
Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Brost,
Thomas Hellström, rust-for-linux, driver-core, dri-devel,
Alvin Sun
Add VmRegistry to track all VMs for debugfs enumeration. VMs are
explicitly registered and unregistered to keep the list in sync.
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
drivers/gpu/drm/tyr/driver.rs | 6 +++++-
drivers/gpu/drm/tyr/fw.rs | 18 +++++++++++++++---
drivers/gpu/drm/tyr/vm.rs | 33 +++++++++++++++++++++++++++++++++
3 files changed, 53 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
index a6694400be659..f26c3bb332e70 100644
--- a/drivers/gpu/drm/tyr/driver.rs
+++ b/drivers/gpu/drm/tyr/driver.rs
@@ -57,7 +57,8 @@
gpu,
gpu::GpuInfo,
mmu::Mmu,
- regs::gpu_control::*, //
+ regs::gpu_control::*,
+ vm::VmRegistry, //
};
pub(crate) type IoMem<'a> = kernel::io::mem::IoMem<'a, SZ_2M>;
@@ -167,11 +168,14 @@ fn probe<'bound>(
let mmu = Mmu::new(pdev.as_ref(), iomem.as_arc_borrow(), &gpu_info)?;
+ let registry = Arc::pin_init(VmRegistry::new(), GFP_KERNEL)?;
+
let firmware = Firmware::new(
pdev.as_ref(),
iomem.clone(),
&unreg_dev,
mmu.as_arc_borrow(),
+ registry.clone(),
&gpu_info,
)?;
diff --git a/drivers/gpu/drm/tyr/fw.rs b/drivers/gpu/drm/tyr/fw.rs
index 65ac18b92b4f2..8b09ea6c7c6d2 100644
--- a/drivers/gpu/drm/tyr/fw.rs
+++ b/drivers/gpu/drm/tyr/fw.rs
@@ -64,7 +64,6 @@
KernelBoVaAlloc, //
},
gpu::GpuInfo,
-
mmu::Mmu,
regs::{
gpu_control::{
@@ -76,7 +75,8 @@
}, //
job_control::JOB_IRQ_CLEAR,
},
- vm::Vm, //
+ vm::Vm,
+ vm::VmRegistry, //
};
mod interfaces;
@@ -174,6 +174,9 @@ pub(crate) struct Firmware<'drm> {
/// MCU VM.
vm: Arc<Vm<'drm>>,
+ /// VM registry, used to unregister `vm` on drop.
+ vm_registry: Arc<VmRegistry<'drm>>,
+
/// List of firmware sections.
sections: KVec<Section<'drm>>,
@@ -195,6 +198,7 @@ fn drop(self: Pin<&mut Self>) {
let _ = self.stop();
// AS slots retain a VM ref, we need to kill the circular ref manually.
+ self.vm_registry.unregister(&self.vm);
self.vm.kill();
}
}
@@ -251,12 +255,18 @@ pub(crate) fn new(
iomem: Arc<IoMem<'drm>>,
ddev: &TyrDrmDevice,
mmu: ArcBorrow<'_, Mmu<'drm>>,
+ vm_registry: Arc<VmRegistry<'drm>>,
gpu_info: &GpuInfo,
) -> Result<Arc<Firmware<'drm>>> {
let vm = Vm::new(dev, ddev, mmu, gpu_info)?;
- vm.activate()?;
+ if let Err(e) = vm_registry.register(vm.clone()) {
+ dev_warn!(dev, "failed to register VM: {e:?}\n");
+ }
+ let registry = vm_registry.clone();
let result = (|| {
+ vm.activate()?;
+
let vm = &vm;
let (fw, parsed_sections) = Self::load(dev, ddev, gpu_info)?;
let mut sections = KVec::new();
@@ -291,6 +301,7 @@ pub(crate) fn new(
try_pin_init!(Firmware {
iomem,
vm: vm.clone(),
+ vm_registry: registry,
sections,
global_iface <- new_mutex!(GlobalInterface::new()?),
job_irq_wait: Arc::pin_init(new_waitqueue!(), GFP_KERNEL)?,
@@ -301,6 +312,7 @@ pub(crate) fn new(
})();
if result.is_err() {
+ vm_registry.unregister(&vm);
vm.kill();
}
diff --git a/drivers/gpu/drm/tyr/vm.rs b/drivers/gpu/drm/tyr/vm.rs
index 74c3d6c8efc49..690d08b8aa901 100644
--- a/drivers/gpu/drm/tyr/vm.rs
+++ b/drivers/gpu/drm/tyr/vm.rs
@@ -311,6 +311,34 @@ pub(crate) struct GpuVmData<'drm> {
_phantom: PhantomData<&'drm ()>,
}
+/// Tracks all VMs for this device.
+#[pin_data]
+pub(crate) struct VmRegistry<'drm> {
+ #[pin]
+ vms: Mutex<KVec<Arc<Vm<'drm>>>>,
+}
+
+impl<'drm> VmRegistry<'drm> {
+ pub(crate) fn new() -> impl PinInit<Self> {
+ pin_init!(Self { vms <- new_mutex!(KVec::new()) })
+ }
+
+ pub(crate) fn register(&self, vm: Arc<Vm<'drm>>) -> Result {
+ Ok(self.vms.lock().push(vm, GFP_KERNEL)?)
+ }
+
+ pub(crate) fn unregister(&self, vm: &Vm<'drm>) {
+ self.vms.lock().retain(|v| !core::ptr::eq(&**v, vm));
+ }
+
+ pub(crate) fn for_each(&self, mut f: impl FnMut(&Vm<'drm>) -> Result) -> Result {
+ for vm in self.vms.lock().iter() {
+ f(vm)?;
+ }
+ Ok(())
+ }
+}
+
/// GPU virtual address space.
///
/// Each VM can be mapped into a hardware address space slot.
@@ -401,6 +429,11 @@ pub(crate) fn activate(&self) -> Result {
})
}
+ /// Dumps GPU VA space info into a seq_file.
+ pub(crate) fn dump_gpuva_info(&self, m: &kernel::seq_file::SeqFile) -> Result {
+ self.gpuvm_unique.lock().dump_gpuva_info(m)
+ }
+
/// Deactivate the VM by evicting it from its address space slot.
fn deactivate(&self) -> Result {
self.mmu.deactivate_vm(&self.as_data).inspect_err(|e| {
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 8/8] drm/tyr: add gpuvas debugfs file
2026-08-06 17:07 [PATCH v3 0/8] drm/tyr: add debugfs support Alvin Sun
` (6 preceding siblings ...)
2026-08-06 17:07 ` [PATCH v3 7/8] drm/tyr: track VMs in a registry Alvin Sun
@ 2026-08-06 17:07 ` Alvin Sun
7 siblings, 0 replies; 9+ messages in thread
From: Alvin Sun @ 2026-08-06 17:07 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, Greg Kroah-Hartman,
Rafael J. Wysocki, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter
Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Brost,
Thomas Hellström, rust-for-linux, driver-core, dri-devel,
Alvin Sun
Add a gpuvas debugfs file listing all GPU VAs for the Tyr DRM driver.
Collects VMs into a shared list during firmware init and renders them
via dump_gpuva_info on read.
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
drivers/gpu/drm/tyr/debugfs.rs | 20 ++++++++++++++++++++
drivers/gpu/drm/tyr/driver.rs | 10 ++++++++++
drivers/gpu/drm/tyr/tyr.rs | 1 +
3 files changed, 31 insertions(+)
diff --git a/drivers/gpu/drm/tyr/debugfs.rs b/drivers/gpu/drm/tyr/debugfs.rs
new file mode 100644
index 0000000000000..0e93c629829cd
--- /dev/null
+++ b/drivers/gpu/drm/tyr/debugfs.rs
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0 or MIT
+
+//! Debugfs support for the Tyr DRM driver.
+
+use kernel::{
+ debugfs::SeqShow,
+ prelude::*,
+ seq_file, //
+};
+
+use crate::driver::TyrDrmRegistrationData;
+
+/// `SeqShow` implementation for the `gpuvas` debugfs file.
+pub(crate) struct GpuvasShow;
+
+impl SeqShow<TyrDrmRegistrationData<'_>> for GpuvasShow {
+ fn show(reg_data: &TyrDrmRegistrationData<'_>, m: &seq_file::SeqFile) -> Result {
+ reg_data.vm_registry.for_each(|vm| vm.dump_gpuva_info(m))
+ }
+}
diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
index f26c3bb332e70..20be2dafa8421 100644
--- a/drivers/gpu/drm/tyr/driver.rs
+++ b/drivers/gpu/drm/tyr/driver.rs
@@ -7,6 +7,7 @@
Clk,
OptionalClk, //
},
+ debugfs,
device::{
Bound,
Core,
@@ -45,6 +46,7 @@
};
use crate::{
+ debugfs::GpuvasShow,
file::TyrDrmFileData,
fw::{
irq::{
@@ -87,6 +89,9 @@ pub(crate) struct TyrDrmRegistrationData<'drm> {
/// Firmware sections.
pub(crate) fw: Arc<Firmware<'drm>>,
+ /// VM registry, used by debugfs to enumerate GPU VA spaces.
+ pub(crate) vm_registry: Arc<VmRegistry<'drm>>,
+
#[pin]
clks: Mutex<Clocks>,
@@ -198,6 +203,7 @@ fn probe<'bound>(
let reg_data = pin_init!(TyrDrmRegistrationData {
pdev,
fw: firmware,
+ vm_registry: registry,
clks <- new_mutex!(Clocks {
core: core_clk,
stacks: stacks_clk,
@@ -252,6 +258,10 @@ impl drm::Driver for TyrDrmDriver {
kernel::declare_drm_ioctls! {
(PANTHOR_DEV_QUERY, drm_panthor_dev_query, ioctl::RENDER_ALLOW, TyrDrmFileData::dev_query),
}
+
+ fn debugfs_init(dir: &debugfs::ScopeRef<'_, TyrDrmRegistrationData<'_>>) {
+ dir.seq_file::<GpuvasShow>(c"gpuvas");
+ }
}
struct Clocks {
diff --git a/drivers/gpu/drm/tyr/tyr.rs b/drivers/gpu/drm/tyr/tyr.rs
index e7ec450bdc9c0..6eb13c15d1657 100644
--- a/drivers/gpu/drm/tyr/tyr.rs
+++ b/drivers/gpu/drm/tyr/tyr.rs
@@ -7,6 +7,7 @@
use crate::driver::TyrPlatformDriver;
+mod debugfs;
mod driver;
mod file;
mod fw;
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-08-06 17:09 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-06 17:07 [PATCH v3 0/8] drm/tyr: add debugfs support Alvin Sun
2026-08-06 17:07 ` [PATCH v3 1/8] rust: seq_file: add as_raw() method Alvin Sun
2026-08-06 17:07 ` [PATCH v3 2/8] rust: debugfs: add seq_file support Alvin Sun
2026-08-06 17:07 ` [PATCH v3 3/8] rust: debugfs: add ScopeRef for existing dentries Alvin Sun
2026-08-06 17:07 ` [PATCH v3 4/8] drm: move debugfs_init after dev->registered is set Alvin Sun
2026-08-06 17:07 ` [PATCH v3 5/8] rust: drm: add debugfs_init callback to Driver trait Alvin Sun
2026-08-06 17:07 ` [PATCH v3 6/8] rust: drm: gpuvm: add dump_gpuva_info to UniqueRefGpuVm Alvin Sun
2026-08-06 17:07 ` [PATCH v3 7/8] drm/tyr: track VMs in a registry Alvin Sun
2026-08-06 17:07 ` [PATCH v3 8/8] drm/tyr: add gpuvas debugfs file Alvin Sun
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.