public inbox for devnull+b4-sent@kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/13] drm/tyr: add debugfs support
@ 2026-03-26  6:52 Alvin Sun
  2026-03-26  6:52 ` [PATCH 01/13] rust: sync: support [pin_]init for `SetOnce` Alvin Sun
                   ` (12 more replies)
  0 siblings, 13 replies; 14+ messages in thread
From: Alvin Sun @ 2026-03-26  6:52 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, David Airlie, Simona Vetter, Sumit Semwal,
	Christian König, Daniel Almeida
  Cc: rust-for-linux, dri-devel, Alvin Sun

This patchset contains:
- hazptr: Add hazard pointer abstraction to kernel::sync
- revocable: Introduce HazPtrRevocable, and adapt Gary Guo's downstream
  LazyRevocable implementation to use hazard pointers internally,
  enabling safe sharing of debugfs-root data across the tyr module and
  DRM driver
- drm: Add device and GEM helper functions to support debugfs
- tyr: Add debugfs infrastructure and interfaces to expose GEM/VM
  information

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>
---
Alvin Sun (11):
      rust: sync: set_once: Rename InitError variants to fix clippy warning
      rust: sync: add hazard pointer abstraction
      rust: revocable: add HazPtrRevocable
      rust: revocable: make LazyRevocable use HazPtrRevocable
      rust: drm: add Device::primary_index()
      rust: drm/gem: add GEM object query helpers for debugfs
      rust: drm/gem/shmem: add resident_size() and madv() for debugfs
      drm/tyr: expose Vm gpuvm_core, gpuvm and va_range as pub(crate)
      drm/tyr: add debugfs infrastructure
      drm/tyr: add vms and gpuvas debugfs interface
      drm/tyr: add gems field and gems debugfs interface

Gary Guo (2):
      rust: sync: support [pin_]init for `SetOnce`
      rust: revocable: add lazily instantiated revocable variant

 drivers/gpu/drm/tyr/debugfs.rs  | 190 ++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/tyr/driver.rs   |  18 +++-
 drivers/gpu/drm/tyr/fw.rs       |   7 +-
 drivers/gpu/drm/tyr/mmu.rs      |   6 +-
 drivers/gpu/drm/tyr/tyr.rs      |  39 +++++++-
 drivers/gpu/drm/tyr/vm.rs       |   6 +-
 rust/bindings/bindings_helper.h |   1 +
 rust/helpers/hazptr.c           |  13 +++
 rust/helpers/helpers.c          |   1 +
 rust/kernel/drm/device.rs       |  10 ++
 rust/kernel/drm/gem/mod.rs      |  49 +++++++++-
 rust/kernel/drm/gem/shmem.rs    |  21 ++++
 rust/kernel/revocable.rs        | 209 +++++++++++++++++++++++++++++++++++++++-
 rust/kernel/sync.rs             |   1 +
 rust/kernel/sync/hazptr.rs      |  91 +++++++++++++++++
 rust/kernel/sync/set_once.rs    | 120 +++++++++++++++++++----
 16 files changed, 746 insertions(+), 36 deletions(-)
---
base-commit: 34cb4f916af10153c87fabaf6c34e4cafa170427
change-id: 20260320-b4-tyr-debugfs-3fcaff064297
prerequisite-change-id: 20260202-io-81fd368f7565:v2
prerequisite-patch-id: 74873afed2b65f5a11c33f0c0c54375c55079109
prerequisite-patch-id: ae853e8eb8d58c77881371960be4ae92755e83c6
prerequisite-patch-id: 0ab78b50648c7d8f66b83c32ed2af0ec3ede42a3
prerequisite-patch-id: 8d20a8db8cf4660c682ee91f3db04e640c144e33
prerequisite-patch-id: 299de9cd2789c19c22e2816f7c817d80d5a4f1db
prerequisite-patch-id: 661ee334905f359daa8fb8d808ed5f4a8085f5c9
prerequisite-change-id: 20260117-register-ccaba1d21713:v9
prerequisite-patch-id: e4cb34ef09bccb92e1c35435e346b3a0459d3cdf
prerequisite-patch-id: 2c3c42ae9f3f4544c088dffbe4a0527f28b1c135
prerequisite-patch-id: 9f40e176e1b67bada943e376950debabb3f196d5
prerequisite-patch-id: ccc86d3ab9f62883c90d1275c99720942bd2bcb3
prerequisite-patch-id: 216427f1fdf94755cca0ed0676c4290f85d45e5c
prerequisite-patch-id: 7e1ea4d184297dfaba1351a7cb23e3b6827fed46
prerequisite-patch-id: 29ff9ffe37669d23b5509bfefb0cc1f8950eaa7c
prerequisite-patch-id: e5723722ff970c585cbf559456fa4cda05f28952
prerequisite-patch-id: afdae76e12011bb158d2008b8cd1ffba084db0bb
prerequisite-patch-id: b0473d5c7af0bbeec6f6ec8dd36d8a09cc180fed
prerequisite-message-id: <20260206223431.693765-1-lyude@redhat.com>
prerequisite-patch-id: 454c4fe7a7bcc65b2c9cc69dd5dd8e4c1d952297
prerequisite-patch-id: aff529cc205f5ab35518b8e4568e6e1319eecaa9
prerequisite-patch-id: 9f7d5c4a8ed052f5c5f2a28c862a9392d7a812cc
prerequisite-patch-id: ec9d104ba7c67488f19e6dd1a50d1ec4f682f333
prerequisite-patch-id: e7a844bd6254643d1f23827886b487c196ee9968
prerequisite-patch-id: 3c57ebf13497cf57c586b955d5ce90f2f9fd8cdc
prerequisite-patch-id: 1a327345ac71599ece0b2272fba81472f70c568c
prerequisite-change-id: 20251128-gpuvm-rust-b719cac27ad6:v5
prerequisite-patch-id: 6a8ddd47a2e1c769c65a942b3d9315e6ae5cae7e
prerequisite-patch-id: d4ee9fb80025c4fd8129c3477cc3dc36e13076cb
prerequisite-patch-id: 0ad35cd3dfcf8a8804e9fed8df3e5612cf07da69
prerequisite-patch-id: 275a900645e14169911ee00bab54553c84b48ad0
prerequisite-patch-id: 2a2de2f6c4fac065de5c459026daa2c32f340d22
prerequisite-patch-id: 9a721bc700da778f2554cf32917dda4807744520
prerequisite-message-id: <20260131001602.2095470-1-lyude@redhat.com>
prerequisite-patch-id: 6c622d1df9166ad081acba46237f8cecbf728356
prerequisite-patch-id: 769892e477c161e6c7a57519ec635b1455310f1d
prerequisite-patch-id: 3c5f5070ded87e95a8045083a55501fbbe9f6313
prerequisite-patch-id: 10fbd8695264e67421946dda4d39e29d5fe77c64

Best regards,
-- 
Alvin Sun <alvin.sun@linux.dev>


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 01/13] rust: sync: support [pin_]init for `SetOnce`
  2026-03-26  6:52 [PATCH 00/13] drm/tyr: add debugfs support Alvin Sun
@ 2026-03-26  6:52 ` Alvin Sun
  2026-03-26  6:52 ` [PATCH 02/13] rust: revocable: add lazily instantiated revocable variant Alvin Sun
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Alvin Sun @ 2026-03-26  6:52 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, David Airlie, Simona Vetter, Sumit Semwal,
	Christian König, Daniel Almeida
  Cc: rust-for-linux, dri-devel, Alvin Sun

From: Gary Guo <gary@garyguo.net>

Make `SetOnce` support initialization via `impl Init` or `impl PinInit`.

This adds a possible failing path if an initializer fails. In such case,
the state is dropped back to 0 instead of keep increasing; so the monotonicity
invariant is dropped. The order for initialization is upgraded from Relaxed
to Acquire so it can observe the effect of a previously failed initialization.

Signed-off-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 rust/kernel/sync/set_once.rs | 120 +++++++++++++++++++++++++++++++++++--------
 1 file changed, 99 insertions(+), 21 deletions(-)

diff --git a/rust/kernel/sync/set_once.rs b/rust/kernel/sync/set_once.rs
index 139cef05e935f..db9c5423fade3 100644
--- a/rust/kernel/sync/set_once.rs
+++ b/rust/kernel/sync/set_once.rs
@@ -2,11 +2,23 @@
 
 //! A container that can be initialized at most once.
 
+use core::{
+    cell::UnsafeCell,
+    mem::MaybeUninit, //
+};
+use pin_init::{
+    Init,
+    PinInit, //
+};
+
 use super::atomic::{
-    ordering::{Acquire, Relaxed, Release},
-    Atomic,
+    ordering::{
+        Acquire,
+        Release, //
+    },
+    Atomic, //
 };
-use core::{cell::UnsafeCell, mem::MaybeUninit};
+use crate::prelude::*;
 
 /// A container that can be populated at most once. Thread safe.
 ///
@@ -15,13 +27,13 @@
 ///
 /// # Invariants
 ///
-/// - `init` may only increase in value.
 /// - `init` may only assume values in the range `0..=2`.
 /// - `init == 0` if and only if `value` is uninitialized.
 /// - `init == 1` if and only if there is exactly one thread with exclusive
 ///   access to `self.value`.
 /// - `init == 2` if and only if `value` is initialized and valid for shared
 ///   access.
+/// - once `init == 2`, it must remain so.
 ///
 /// # Example
 ///
@@ -51,6 +63,35 @@ fn default() -> Self {
     }
 }
 
+/// Error that can occur during initialization of `SetOnce`.
+#[derive(Debug)]
+pub enum InitError<E> {
+    /// The `Once` has already been initialized.
+    AlreadyInit,
+    /// The `Once` is being raced to initialize by another thread.
+    RacedInit,
+    /// Error occurs during initialization.
+    DuringInit(E),
+}
+
+impl<E> From<E> for InitError<E> {
+    #[inline]
+    fn from(err: E) -> Self {
+        InitError::DuringInit(err)
+    }
+}
+
+impl<E: Into<Error>> From<InitError<E>> for Error {
+    #[inline]
+    fn from(this: InitError<E>) -> Self {
+        match this {
+            InitError::AlreadyInit => EEXIST,
+            InitError::RacedInit => EBUSY,
+            InitError::DuringInit(e) => e.into(),
+        }
+    }
+}
+
 impl<T> SetOnce<T> {
     /// Create a new [`SetOnce`].
     ///
@@ -76,31 +117,68 @@ pub fn as_ref(&self) -> Option<&T> {
         }
     }
 
-    /// Populate the [`SetOnce`].
+    /// Populate the [`SetOnce`] with an initializer.
     ///
-    /// Returns `true` if the [`SetOnce`] was successfully populated.
-    pub fn populate(&self, value: T) -> bool {
+    /// Returns the initialized reference if the [`SetOnce`] was successfully populated.
+    pub fn init<E>(&self, init: impl Init<T, E>) -> Result<&T, InitError<E>> {
         // INVARIANT: If the swap succeeds:
-        //  - We increase `init`.
         //  - We write the valid value `1` to `init`.
+        //  - The previous value is not `2`, so it is valid to move to `1`.
         //  - Only one thread can succeed in this write, so we have exclusive access after the
         //    write.
-        if let Ok(0) = self.init.cmpxchg(0, 1, Relaxed) {
-            // SAFETY: By the type invariants of `Self`, the fact that we succeeded in writing `1`
-            // to `self.init` means we obtained exclusive access to `self.value`.
-            unsafe { core::ptr::write(self.value.get().cast(), value) };
-            // INVARIANT:
-            //  - We increase `init`.
-            //  - We write the valid value `2` to `init`.
-            //  - We release our exclusive access to `self.value` and it is now valid for shared
-            //    access.
-            self.init.store(2, Release);
-            true
-        } else {
-            false
+        match self.init.cmpxchg(0, 1, Acquire) {
+            Ok(_) => {
+                // SAFETY:
+                // - By the type invariants of `Self`, the fact that we succeeded in writing `1`
+                //   to `self.init` means we obtained exclusive access to `self.value`.
+                // - When `Err` is returned, we did not set `self.init` to `2` so the `Drop` is not
+                //   armed.
+                match unsafe { init.__init(self.value.get().cast()) } {
+                    Ok(()) => {
+                        // INVARIANT:
+                        //  - The previous value is `1`, so it is valid to move to `2`.
+                        //  - We write the valid value `2` to `init`.
+                        //  - We release our exclusive access to `self.value` and it is now valid
+                        //    for shared access.
+                        self.init.store(2, Release);
+                        // SAFETY: we have just initialized the value.
+                        Ok(unsafe { &*self.value.get().cast() })
+                    }
+                    Err(err) => {
+                        // INVARIANT:
+                        //  - The previous value is `1`, so it is valid to move to `0`.
+                        //  - We write the valid value `0` to `init`.
+                        //  - We release our exclusive access to `self.value` and it is now valid
+                        //    for shared access.
+                        self.init.store(0, Release);
+                        Err(err.into())
+                    }
+                }
+            }
+            Err(1) => Err(InitError::RacedInit),
+            Err(_) => Err(InitError::AlreadyInit),
         }
     }
 
+    /// Populate the [`SetOnce`] with a pinned initializer.
+    ///
+    /// Returns the initialized reference if the [`SetOnce`] was successfully populated.
+    pub fn pin_init<E>(self: Pin<&Self>, init: impl PinInit<T, E>) -> Result<&T, InitError<E>> {
+        // SAFETY:
+        // - `__pinned_init` satisfy all requirements of `init_from_closure`
+        // - calling `__pinned_init` require additional that the slot is pinned, which is satisfied
+        //   given `self: Pin<&Self>`.
+        self.get_ref()
+            .init(unsafe { pin_init::init_from_closure(|slot| init.__pinned_init(slot)) })
+    }
+
+    /// Populate the [`SetOnce`].
+    ///
+    /// Returns `true` if the [`SetOnce`] was successfully populated.
+    pub fn populate(&self, value: T) -> bool {
+        self.init(value).is_ok()
+    }
+
     /// Get a copy of the contained object.
     ///
     /// Returns [`None`] if the [`SetOnce`] is empty.

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 02/13] rust: revocable: add lazily instantiated revocable variant
  2026-03-26  6:52 [PATCH 00/13] drm/tyr: add debugfs support Alvin Sun
  2026-03-26  6:52 ` [PATCH 01/13] rust: sync: support [pin_]init for `SetOnce` Alvin Sun
@ 2026-03-26  6:52 ` Alvin Sun
  2026-03-26  6:52 ` [PATCH 03/13] rust: sync: set_once: Rename InitError variants to fix clippy warning Alvin Sun
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Alvin Sun @ 2026-03-26  6:52 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, David Airlie, Simona Vetter, Sumit Semwal,
	Christian König, Daniel Almeida
  Cc: rust-for-linux, dri-devel, Alvin Sun

From: Gary Guo <gary@garyguo.net>

Add a `LazyRevocable` type, an variant to `Revocable` where
the data is initialized lazily. This type can be constructed as const and
put into statics.

Signed-off-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 rust/kernel/revocable.rs | 80 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 79 insertions(+), 1 deletion(-)

diff --git a/rust/kernel/revocable.rs b/rust/kernel/revocable.rs
index 0f4ae673256d5..70733ff5961cd 100644
--- a/rust/kernel/revocable.rs
+++ b/rust/kernel/revocable.rs
@@ -7,7 +7,12 @@
 
 use pin_init::Wrapper;
 
-use crate::{bindings, prelude::*, sync::rcu, types::Opaque};
+use crate::{
+    bindings,
+    prelude::*,
+    sync::{rcu, SetOnce},
+    types::Opaque,
+};
 use core::{
     marker::PhantomData,
     ops::Deref,
@@ -261,3 +266,76 @@ fn deref(&self) -> &Self::Target {
         unsafe { &*self.data_ref }
     }
 }
+
+/// A handle to perform revocation on a [`Revocable`].
+///
+/// The associated `Revocable` is revoked when the handle is dropped.
+pub struct RevokeHandle<'a, T>(&'a Revocable<T>);
+
+impl<'a, T> RevokeHandle<'a, T> {
+    /// Create a revoke-on-drop handle on an existing revocable.
+    pub fn new(revocable: &'a Revocable<T>) -> Self {
+        Self(revocable)
+    }
+
+    /// Dismiss the handle.
+    ///
+    /// This method consumes ownership without revoking the `Revocable`.
+    pub fn dismiss(self) {
+        core::mem::forget(self);
+    }
+}
+
+impl<'a, T> Drop for RevokeHandle<'a, T> {
+    fn drop(&mut self) {
+        self.0.revoke();
+    }
+}
+
+/// An object that is initialized and can become inaccessible at runtime.
+///
+/// [`Revocable`] is initialized at the beginning, and can be made inaccessible at runtime.
+/// `LazyRevocable` is uninitialized at the beginning, and can be initialized later; it can be
+/// revoked in a similar manner to [`Revocable`]. Once revoked, it cannot be initialized again.
+#[pin_data]
+pub struct LazyRevocable<T> {
+    #[pin]
+    once: SetOnce<Revocable<T>>,
+}
+
+impl<T> LazyRevocable<T> {
+    /// Creates a new lazy revocable instance.
+    ///
+    /// The instance starts uninitialized, where all accesses would fail.
+    pub const fn new() -> Self {
+        LazyRevocable {
+            once: SetOnce::new(),
+        }
+    }
+
+    /// Initialize a `LazyRevocable` and obtain a handle to revoke the content if successful.
+    ///
+    /// An error would be returned if the revocable has already been initialized.
+    pub fn init<E: Into<Error>>(
+        self: Pin<&Self>,
+        init: impl PinInit<T, E>,
+    ) -> Result<RevokeHandle<'_, T>> {
+        // SAFETY: `once` is structurally pinned.
+        let once = unsafe { self.map_unchecked(|x| &x.once) };
+        let revocable = once.pin_init(Revocable::new(init))?;
+        Ok(RevokeHandle::new(revocable))
+    }
+
+    /// Tries to access the revocable wrapped object.
+    ///
+    /// Returns `None` if the object has not been initialized, or it has been revoked and is therefore no longer accessible.
+    pub fn try_access(&self) -> Option<RevocableGuard<'_, T>> {
+        self.once.as_ref()?.try_access()
+    }
+}
+
+impl<T> Default for LazyRevocable<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 03/13] rust: sync: set_once: Rename InitError variants to fix clippy warning
  2026-03-26  6:52 [PATCH 00/13] drm/tyr: add debugfs support Alvin Sun
  2026-03-26  6:52 ` [PATCH 01/13] rust: sync: support [pin_]init for `SetOnce` Alvin Sun
  2026-03-26  6:52 ` [PATCH 02/13] rust: revocable: add lazily instantiated revocable variant Alvin Sun
@ 2026-03-26  6:52 ` Alvin Sun
  2026-03-26  6:52 ` [PATCH 04/13] rust: sync: add hazard pointer abstraction Alvin Sun
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Alvin Sun @ 2026-03-26  6:52 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, David Airlie, Simona Vetter, Sumit Semwal,
	Christian König, Daniel Almeida
  Cc: rust-for-linux, dri-devel, Alvin Sun

Fixes clippy warning:
warning: all variants have the same postfix: `Init`
  --> rust/kernel/sync/set_once.rs:68:1

Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 rust/kernel/sync/set_once.rs | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/rust/kernel/sync/set_once.rs b/rust/kernel/sync/set_once.rs
index db9c5423fade3..3af5538aae1d4 100644
--- a/rust/kernel/sync/set_once.rs
+++ b/rust/kernel/sync/set_once.rs
@@ -67,17 +67,17 @@ fn default() -> Self {
 #[derive(Debug)]
 pub enum InitError<E> {
     /// The `Once` has already been initialized.
-    AlreadyInit,
+    Already,
     /// The `Once` is being raced to initialize by another thread.
-    RacedInit,
+    Raced,
     /// Error occurs during initialization.
-    DuringInit(E),
+    Inner(E),
 }
 
 impl<E> From<E> for InitError<E> {
     #[inline]
     fn from(err: E) -> Self {
-        InitError::DuringInit(err)
+        InitError::Inner(err)
     }
 }
 
@@ -85,9 +85,9 @@ impl<E: Into<Error>> From<InitError<E>> for Error {
     #[inline]
     fn from(this: InitError<E>) -> Self {
         match this {
-            InitError::AlreadyInit => EEXIST,
-            InitError::RacedInit => EBUSY,
-            InitError::DuringInit(e) => e.into(),
+            InitError::Already => EEXIST,
+            InitError::Raced => EBUSY,
+            InitError::Inner(e) => e.into(),
         }
     }
 }
@@ -155,8 +155,8 @@ pub fn init<E>(&self, init: impl Init<T, E>) -> Result<&T, InitError<E>> {
                     }
                 }
             }
-            Err(1) => Err(InitError::RacedInit),
-            Err(_) => Err(InitError::AlreadyInit),
+            Err(1) => Err(InitError::Raced),
+            Err(_) => Err(InitError::Already),
         }
     }
 

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 04/13] rust: sync: add hazard pointer abstraction
  2026-03-26  6:52 [PATCH 00/13] drm/tyr: add debugfs support Alvin Sun
                   ` (2 preceding siblings ...)
  2026-03-26  6:52 ` [PATCH 03/13] rust: sync: set_once: Rename InitError variants to fix clippy warning Alvin Sun
@ 2026-03-26  6:52 ` Alvin Sun
  2026-03-26  6:52 ` [PATCH 05/13] rust: revocable: add HazPtrRevocable Alvin Sun
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Alvin Sun @ 2026-03-26  6:52 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, David Airlie, Simona Vetter, Sumit Semwal,
	Christian König, Daniel Almeida
  Cc: rust-for-linux, dri-devel, Alvin Sun

Add C helpers and Rust wrappers for the kernel hazard pointer API,
to be used by revocable and other code.

Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 rust/bindings/bindings_helper.h |  1 +
 rust/helpers/hazptr.c           | 13 ++++++
 rust/helpers/helpers.c          |  1 +
 rust/kernel/sync.rs             |  1 +
 rust/kernel/sync/hazptr.rs      | 91 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 107 insertions(+)

diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 9058b09a016ec..8ace50a3dc104 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -60,6 +60,7 @@
 #include <linux/file.h>
 #include <linux/firmware.h>
 #include <linux/fs.h>
+#include <linux/hazptr.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/io-pgtable.h>
diff --git a/rust/helpers/hazptr.c b/rust/helpers/hazptr.c
new file mode 100644
index 0000000000000..aa53fbcd0da1d
--- /dev/null
+++ b/rust/helpers/hazptr.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/hazptr.h>
+
+__rust_helper void *rust_helper_hazptr_acquire(struct hazptr_ctx *ctx, void *const *addr_p)
+{
+	return hazptr_acquire(ctx, addr_p);
+}
+
+__rust_helper void rust_helper_hazptr_release(struct hazptr_ctx *ctx, void *addr)
+{
+	hazptr_release(ctx, addr);
+}
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index f1ac40b0bd1a4..ed8cb74d394a3 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -34,6 +34,7 @@
 #include "err.c"
 #include "irq.c"
 #include "fs.c"
+#include "hazptr.c"
 #include "io.c"
 #include "jump_label.c"
 #include "kunit.c"
diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs
index 993dbf2caa0e3..45da761eaee05 100644
--- a/rust/kernel/sync.rs
+++ b/rust/kernel/sync.rs
@@ -15,6 +15,7 @@
 pub mod barrier;
 pub mod completion;
 mod condvar;
+pub mod hazptr;
 pub mod lock;
 mod locked_by;
 pub mod poll;
diff --git a/rust/kernel/sync/hazptr.rs b/rust/kernel/sync/hazptr.rs
new file mode 100644
index 0000000000000..f94ae45dd3d66
--- /dev/null
+++ b/rust/kernel/sync/hazptr.rs
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Hazard pointer support.
+//!
+//! C header: [`include/linux/hazptr.h`](srctree/include/linux/hazptr.h)
+
+use crate::{
+    bindings,
+    ffi::c_void,
+    prelude::*,
+    types::Opaque, //
+};
+use core::{
+    ops::Deref,
+    ptr::NonNull, //
+};
+
+/// Per-thread context for one hazard-pointer acquire/release pair.
+#[repr(transparent)]
+pub struct HazptrCtx(Opaque<bindings::hazptr_ctx>);
+
+impl HazptrCtx {
+    /// Creates a new zero-initialized context for one acquire/release pair.
+    #[inline]
+    pub const fn new() -> Self {
+        Self(Opaque::zeroed())
+    }
+
+    /// Get the raw pointer.
+    #[inline]
+    pub fn as_raw(self: &Pin<&mut Self>) -> *mut bindings::hazptr_ctx {
+        self.0.get()
+    }
+}
+
+impl Default for HazptrCtx {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+/// Guard holding a hazard-pointer-protected reference.
+pub struct Guard<'a, T> {
+    ctx: Pin<&'a mut HazptrCtx>,
+    ptr: NonNull<T>,
+}
+
+impl<'a, T> Guard<'a, T> {
+    #[inline]
+    fn new(ctx: Pin<&'a mut HazptrCtx>, ptr: NonNull<T>) -> Self {
+        Self { ctx, ptr }
+    }
+}
+
+impl<T> Deref for Guard<'_, T> {
+    type Target = T;
+
+    #[inline]
+    fn deref(&self) -> &T {
+        // SAFETY: hazptr protocol keeps the pointer valid until release.
+        unsafe { self.ptr.as_ref() }
+    }
+}
+
+impl<T> Drop for Guard<'_, T> {
+    #[inline]
+    fn drop(&mut self) {
+        // SAFETY: `self.ctx` and `self.ptr` are the same as the ones used in `acquire`.
+        unsafe { bindings::hazptr_release(self.ctx.as_raw().cast(), self.ptr.as_ptr().cast()) };
+    }
+}
+
+/// Acquires a hazard pointer for the pointer at `addr_p` and returns a guard.
+///
+/// Returns `None` if the loaded value is null.
+#[inline]
+pub fn acquire<'a, T>(
+    ctx: Pin<&'a mut HazptrCtx>,
+    addr_p: *const *const T,
+) -> Option<Guard<'a, T>> {
+    // SAFETY: ctx is valid and pinned, addr_p is a valid pointer to a pointer.
+    let ptr = unsafe { bindings::hazptr_acquire(ctx.as_raw().cast(), addr_p.cast()) };
+    NonNull::new(ptr.cast()).map(|p| Guard::new(ctx, p))
+}
+
+/// Waits until no slot holds `addr`.
+#[inline]
+pub fn synchronize(addr: usize) {
+    // SAFETY: addr is only compared with slot values, not dereferenced.
+    unsafe { bindings::hazptr_synchronize(addr as *mut c_void) };
+}

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 05/13] rust: revocable: add HazPtrRevocable
  2026-03-26  6:52 [PATCH 00/13] drm/tyr: add debugfs support Alvin Sun
                   ` (3 preceding siblings ...)
  2026-03-26  6:52 ` [PATCH 04/13] rust: sync: add hazard pointer abstraction Alvin Sun
@ 2026-03-26  6:52 ` Alvin Sun
  2026-03-26  6:52 ` [PATCH 06/13] rust: revocable: make LazyRevocable use HazPtrRevocable Alvin Sun
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Alvin Sun @ 2026-03-26  6:52 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, David Airlie, Simona Vetter, Sumit Semwal,
	Christian König, Daniel Almeida
  Cc: rust-for-linux, dri-devel, Alvin Sun

Add hazard-pointer-based revocable type and related handle/guard.

Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 rust/kernel/revocable.rs | 127 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 124 insertions(+), 3 deletions(-)

diff --git a/rust/kernel/revocable.rs b/rust/kernel/revocable.rs
index 70733ff5961cd..eabb76ce92c43 100644
--- a/rust/kernel/revocable.rs
+++ b/rust/kernel/revocable.rs
@@ -10,14 +10,25 @@
 use crate::{
     bindings,
     prelude::*,
-    sync::{rcu, SetOnce},
+    sync::{
+        hazptr,
+        hazptr::HazptrCtx,
+        rcu,
+        SetOnce, //
+    },
     types::Opaque,
 };
 use core::{
     marker::PhantomData,
     ops::Deref,
-    ptr::drop_in_place,
-    sync::atomic::{AtomicBool, Ordering},
+    ptr::{
+        addr_of,
+        drop_in_place, //
+    },
+    sync::atomic::{
+        AtomicBool,
+        Ordering, //
+    },
 };
 
 /// An object that can become inaccessible at runtime.
@@ -292,6 +303,116 @@ fn drop(&mut self) {
     }
 }
 
+/// Revocable protected by hazard pointer instead of RCU.
+#[pin_data(PinnedDrop)]
+pub struct HazPtrRevocable<T> {
+    #[pin]
+    data: Opaque<T>,
+    is_available: AtomicBool,
+}
+
+// SAFETY: HazPtrRevocable<T> only moves ownership of T across threads;
+// revocation/drop follow the hazptr protocol, so T: Send suffices.
+unsafe impl<T: Send> Send for HazPtrRevocable<T> {}
+
+// SAFETY: &HazPtrRevocable<T> may be shared across threads and yields
+// &T via hazptr guards; with T: Send + Sync such shared access is sound.
+unsafe impl<T: Sync + Send> Sync for HazPtrRevocable<T> {}
+
+impl<T> HazPtrRevocable<T> {
+    /// Creates a new hazard-pointer revocable instance.
+    pub fn new<E>(data_pin_init: impl PinInit<T, E>) -> impl PinInit<Self, E> {
+        try_pin_init!(Self {
+            data <- Opaque::pin_init(data_pin_init),
+            is_available: AtomicBool::new(true),
+        }? E)
+    }
+
+    /// Tries to access the wrapped object. Returns `None` if revoked.
+    ///
+    /// `ctx` is moved into the returned guard and released when the guard is dropped.
+    pub fn try_access<'a>(
+        &self,
+        ctx: Pin<&'a mut HazptrCtx>,
+    ) -> Option<HazPtrRevocableGuard<'a, T>> {
+        let data_ptr = self.data.get();
+        let guard = hazptr::acquire(ctx, addr_of!(data_ptr).cast())?;
+        if !self.is_available.load(Ordering::Relaxed) {
+            return None;
+        }
+        Some(HazPtrRevocableGuard::new(guard))
+    }
+
+    /// Revokes access and drops the wrapped object. Waits for readers via hazptr.
+    pub fn revoke(&self) -> bool {
+        let revoke = self.is_available.swap(false, Ordering::Relaxed);
+        if revoke {
+            hazptr::synchronize(self.data.get() as usize);
+            // SAFETY: `synchronize()` ensures no reader still holds the pointer,
+            // and `self.is_available` is false so no new reader can start, so
+            // `drop_in_place` is safe.
+            unsafe { drop_in_place(self.data.get()) };
+        }
+        revoke
+    }
+}
+
+#[pinned_drop]
+impl<T> PinnedDrop for HazPtrRevocable<T> {
+    fn drop(self: Pin<&mut Self>) {
+        // Drop only if the data hasn't been revoked yet (in which case it has already been
+        // dropped).
+        // SAFETY: We are not moving out of `p`, only dropping in place
+        let p = unsafe { self.get_unchecked_mut() };
+        if *p.is_available.get_mut() {
+            // SAFETY: We know `self.data` is valid because no other CPU has changed
+            // `is_available` to `false` yet, and no other CPU can do it anymore because this CPU
+            // holds the only reference (mutable) to `self` now.
+            unsafe { drop_in_place(p.data.get()) };
+        }
+    }
+}
+
+/// A handle to perform revocation on a [`HazPtrRevocable`]. Revokes when dropped.
+pub struct HazPtrRevokeHandle<'a, T>(&'a HazPtrRevocable<T>);
+
+impl<'a, T> HazPtrRevokeHandle<'a, T> {
+    /// Create a revoke-on-drop handle.
+    pub fn new(revocable: &'a HazPtrRevocable<T>) -> Self {
+        Self(revocable)
+    }
+
+    /// Dismiss the handle without revoking.
+    pub fn dismiss(self) {
+        core::mem::forget(self);
+    }
+}
+
+impl<T> Drop for HazPtrRevokeHandle<'_, T> {
+    fn drop(&mut self) {
+        self.0.revoke();
+    }
+}
+
+/// Guard for a [`HazPtrRevocable`].
+pub struct HazPtrRevocableGuard<'a, T> {
+    guard: hazptr::Guard<'a, T>,
+}
+
+impl<'a, T> HazPtrRevocableGuard<'a, T> {
+    fn new(guard: hazptr::Guard<'a, T>) -> Self {
+        Self { guard }
+    }
+}
+
+impl<T> Deref for HazPtrRevocableGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.guard
+    }
+}
+
 /// An object that is initialized and can become inaccessible at runtime.
 ///
 /// [`Revocable`] is initialized at the beginning, and can be made inaccessible at runtime.

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 06/13] rust: revocable: make LazyRevocable use HazPtrRevocable
  2026-03-26  6:52 [PATCH 00/13] drm/tyr: add debugfs support Alvin Sun
                   ` (4 preceding siblings ...)
  2026-03-26  6:52 ` [PATCH 05/13] rust: revocable: add HazPtrRevocable Alvin Sun
@ 2026-03-26  6:52 ` Alvin Sun
  2026-03-26  6:53 ` [PATCH 07/13] rust: drm: add Device::primary_index() Alvin Sun
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Alvin Sun @ 2026-03-26  6:52 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, David Airlie, Simona Vetter, Sumit Semwal,
	Christian König, Daniel Almeida
  Cc: rust-for-linux, dri-devel, Alvin Sun

Change LazyRevocable to use the existing HazPtrRevocable backend instead
of the RCU-based Revocable. init() now returns HazPtrRevokeHandle and
try_access(ctx) forwards to the hazptr-based implementation.

Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 rust/kernel/revocable.rs | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/rust/kernel/revocable.rs b/rust/kernel/revocable.rs
index eabb76ce92c43..e974c75a90ec0 100644
--- a/rust/kernel/revocable.rs
+++ b/rust/kernel/revocable.rs
@@ -421,7 +421,7 @@ fn deref(&self) -> &Self::Target {
 #[pin_data]
 pub struct LazyRevocable<T> {
     #[pin]
-    once: SetOnce<Revocable<T>>,
+    once: SetOnce<HazPtrRevocable<T>>,
 }
 
 impl<T> LazyRevocable<T> {
@@ -440,18 +440,22 @@ pub const fn new() -> Self {
     pub fn init<E: Into<Error>>(
         self: Pin<&Self>,
         init: impl PinInit<T, E>,
-    ) -> Result<RevokeHandle<'_, T>> {
+    ) -> Result<HazPtrRevokeHandle<'_, T>> {
         // SAFETY: `once` is structurally pinned.
         let once = unsafe { self.map_unchecked(|x| &x.once) };
-        let revocable = once.pin_init(Revocable::new(init))?;
-        Ok(RevokeHandle::new(revocable))
+        let revocable = once.pin_init(HazPtrRevocable::new(init))?;
+        Ok(HazPtrRevokeHandle::new(revocable))
     }
 
     /// Tries to access the revocable wrapped object.
     ///
-    /// Returns `None` if the object has not been initialized, or it has been revoked and is therefore no longer accessible.
-    pub fn try_access(&self) -> Option<RevocableGuard<'_, T>> {
-        self.once.as_ref()?.try_access()
+    /// Returns `None` if the object has not been initialized, or it has been revoked and is
+    /// therefore no longer accessible.
+    pub fn try_access<'a>(
+        &self,
+        ctx: Pin<&'a mut HazptrCtx>,
+    ) -> Option<HazPtrRevocableGuard<'a, T>> {
+        self.once.as_ref()?.try_access(ctx)
     }
 }
 

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 07/13] rust: drm: add Device::primary_index()
  2026-03-26  6:52 [PATCH 00/13] drm/tyr: add debugfs support Alvin Sun
                   ` (5 preceding siblings ...)
  2026-03-26  6:52 ` [PATCH 06/13] rust: revocable: make LazyRevocable use HazPtrRevocable Alvin Sun
@ 2026-03-26  6:53 ` Alvin Sun
  2026-03-26  6:53 ` [PATCH 08/13] rust: drm/gem: add GEM object query helpers for debugfs Alvin Sun
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Alvin Sun @ 2026-03-26  6:53 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, David Airlie, Simona Vetter, Sumit Semwal,
	Christian König, Daniel Almeida
  Cc: rust-for-linux, dri-devel, Alvin Sun

Add primary_index() to return the primary minor index (e.g. the N in
/dev/dri/cardN). Needed by drivers to register per-device debugfs under
a unique directory name.

Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 rust/kernel/drm/device.rs | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs
index d7bb338efb9d8..268ac02e800fd 100644
--- a/rust/kernel/drm/device.rs
+++ b/rust/kernel/drm/device.rs
@@ -336,6 +336,16 @@ pub(crate) unsafe fn assume_ctx<NewCtx: DeviceContext>(&self) -> &Device<T, NewC
     }
 }
 
+impl<T: drm::Driver> Device<T, Registered> {
+    /// Returns the primary minor index (the number in `/dev/dri/cardN`).
+    #[inline]
+    pub fn primary_index(&self) -> u32 {
+        // SAFETY: `self.as_raw()` is guaranteed to be a valid pointer to a `struct drm_device`.
+        let index = unsafe { (*(*self.as_raw()).primary).index };
+        index as u32
+    }
+}
+
 impl<T: drm::Driver> Deref for Device<T, Registered> {
     type Target = T::Data;
 

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 08/13] rust: drm/gem: add GEM object query helpers for debugfs
  2026-03-26  6:52 [PATCH 00/13] drm/tyr: add debugfs support Alvin Sun
                   ` (6 preceding siblings ...)
  2026-03-26  6:53 ` [PATCH 07/13] rust: drm: add Device::primary_index() Alvin Sun
@ 2026-03-26  6:53 ` Alvin Sun
  2026-03-26  6:53 ` [PATCH 09/13] rust: drm/gem/shmem: add resident_size() and madv() " Alvin Sun
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Alvin Sun @ 2026-03-26  6:53 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, David Airlie, Simona Vetter, Sumit Semwal,
	Christian König, Daniel Almeida
  Cc: rust-for-linux, dri-devel, Alvin Sun

Add name(), refcount(), is_imported(), is_exported(), and mmap_offset()
to BaseObject so drivers can expose GEM state in debugfs.

Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 rust/kernel/drm/gem/mod.rs | 49 +++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 46 insertions(+), 3 deletions(-)

diff --git a/rust/kernel/drm/gem/mod.rs b/rust/kernel/drm/gem/mod.rs
index 276ba3c53475d..b6188c8873ece 100644
--- a/rust/kernel/drm/gem/mod.rs
+++ b/rust/kernel/drm/gem/mod.rs
@@ -21,9 +21,13 @@
     },
     error::to_result,
     prelude::*,
-    sync::aref::{
-        ARef,
-        AlwaysRefCounted, //
+    sync::{
+        aref::{
+            ARef,
+            AlwaysRefCounted, //
+        },
+        atomic::Relaxed,
+        Refcount, //
     },
     types::Opaque,
 };
@@ -177,6 +181,45 @@ fn size(&self) -> usize {
         unsafe { (*self.as_raw()).size }
     }
 
+    /// Returns the name of the object.
+    #[inline]
+    fn name(&self) -> i32 {
+        // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a valid `struct drm_gem_object`.
+        unsafe { (*self.as_raw()).name }
+    }
+
+    /// Returns the reference count of the object.
+    #[inline]
+    fn refcount(&self) -> u32 {
+        // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a valid `struct drm_gem_object`.
+        let raw_refcount = unsafe { &raw mut (*self.as_raw()).refcount }.cast::<Refcount>();
+        // SAFETY: `raw_refcount` has the same layout as `Refcount`.
+        let refcount = unsafe { &*raw_refcount };
+
+        refcount.as_atomic().load(Relaxed) as u32
+    }
+
+    /// Returns true if the object is imported.
+    #[inline]
+    fn is_imported(&self) -> bool {
+        // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a valid `struct drm_gem_object`.
+        !unsafe { (*self.as_raw()).import_attach }.is_null()
+    }
+
+    /// Returns true if the object is exported.
+    #[inline]
+    fn is_exported(&self) -> bool {
+        // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a valid `struct drm_gem_object`.
+        !unsafe { (*self.as_raw()).dma_buf }.is_null()
+    }
+
+    /// Returns the offset for mmap, or 0 if no offset has been allocated.
+    #[inline]
+    fn mmap_offset(&self) -> u64 {
+        // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a valid `struct drm_gem_object`.
+        unsafe { (*self.as_raw()).vma_node.vm_node.start }
+    }
+
     /// Creates a new handle for the object associated with a given `File`
     /// (or returns an existing one).
     fn create_handle<D, F>(&self, file: &drm::File<F>) -> Result<u32>

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 09/13] rust: drm/gem/shmem: add resident_size() and madv() for debugfs
  2026-03-26  6:52 [PATCH 00/13] drm/tyr: add debugfs support Alvin Sun
                   ` (7 preceding siblings ...)
  2026-03-26  6:53 ` [PATCH 08/13] rust: drm/gem: add GEM object query helpers for debugfs Alvin Sun
@ 2026-03-26  6:53 ` Alvin Sun
  2026-03-26  6:53 ` [PATCH 10/13] drm/tyr: expose Vm gpuvm_core, gpuvm and va_range as pub(crate) Alvin Sun
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Alvin Sun @ 2026-03-26  6:53 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, David Airlie, Simona Vetter, Sumit Semwal,
	Christian König, Daniel Almeida
  Cc: rust-for-linux, dri-devel, Alvin Sun

Expose resident size and madvise state of shmem GEM objects so drivers
can show per-BO memory usage and reclaimable size in debugfs.

Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 rust/kernel/drm/gem/shmem.rs | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs
index 065bdd78d1ba6..ba25a4a832db6 100644
--- a/rust/kernel/drm/gem/shmem.rs
+++ b/rust/kernel/drm/gem/shmem.rs
@@ -196,6 +196,27 @@ extern "C" fn free_callback(obj: *mut bindings::drm_gem_object) {
         let _ = unsafe { KBox::from_raw(this) };
     }
 
+    /// Returns the resident size of this object.
+    #[inline]
+    pub fn resident_size(&self) -> usize {
+        // SAFETY: `self.as_raw_shmem()` is guaranteed to be a valid pointer to a
+        // drm_gem_shmem_object.
+        if unsafe { (*self.as_raw_shmem()).pages }.is_null() {
+            0
+        } else {
+            // SAFETY: `self.as_raw()` is guaranteed to be a valid pointer to a drm_gem_object.
+            unsafe { (*self.as_raw()).size }
+        }
+    }
+
+    /// Returns the state for madvise of this object.
+    #[inline]
+    pub fn madv(&self) -> i32 {
+        // SAFETY: `self.as_raw_shmem()` is guaranteed to be a valid pointer to a
+        // drm_gem_shmem_object.
+        unsafe { (*self.as_raw_shmem()).madv }
+    }
+
     /// Creates (if necessary) and returns an immutable reference to a scatter-gather table of DMA
     /// pages for this object.
     ///

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 10/13] drm/tyr: expose Vm gpuvm_core, gpuvm and va_range as pub(crate)
  2026-03-26  6:52 [PATCH 00/13] drm/tyr: add debugfs support Alvin Sun
                   ` (8 preceding siblings ...)
  2026-03-26  6:53 ` [PATCH 09/13] rust: drm/gem/shmem: add resident_size() and madv() " Alvin Sun
@ 2026-03-26  6:53 ` Alvin Sun
  2026-03-26  6:53 ` [PATCH 11/13] drm/tyr: add debugfs infrastructure Alvin Sun
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Alvin Sun @ 2026-03-26  6:53 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, David Airlie, Simona Vetter, Sumit Semwal,
	Christian König, Daniel Almeida
  Cc: rust-for-linux, dri-devel, Alvin Sun

Allow the debugfs module to read VM and GPU VA state for the gpuvas file.

Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 drivers/gpu/drm/tyr/vm.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/tyr/vm.rs b/drivers/gpu/drm/tyr/vm.rs
index 936c3049812b3..ccf4493065a49 100644
--- a/drivers/gpu/drm/tyr/vm.rs
+++ b/drivers/gpu/drm/tyr/vm.rs
@@ -306,12 +306,12 @@ pub(crate) struct Vm {
     pdev: ARef<platform::Device>,
     /// DRM GPUVM core for managing virtual address space.
     #[pin]
-    gpuvm_core: Mutex<GpuVmCore<GpuVmData>>,
+    pub(crate) gpuvm_core: Mutex<GpuVmCore<GpuVmData>>,
     /// Non-core part of the GPUVM. Can be used for stuff that doesn't modify the
     /// internal mapping tree, like GpuVm::obtain()
-    gpuvm: ARef<GpuVm<GpuVmData>>,
+    pub(crate) gpuvm: ARef<GpuVm<GpuVmData>>,
     /// VA range for this VM.
-    va_range: Range<u64>,
+    pub(crate) va_range: Range<u64>,
 }
 
 impl Vm {

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 11/13] drm/tyr: add debugfs infrastructure
  2026-03-26  6:52 [PATCH 00/13] drm/tyr: add debugfs support Alvin Sun
                   ` (9 preceding siblings ...)
  2026-03-26  6:53 ` [PATCH 10/13] drm/tyr: expose Vm gpuvm_core, gpuvm and va_range as pub(crate) Alvin Sun
@ 2026-03-26  6:53 ` Alvin Sun
  2026-03-26  6:53 ` [PATCH 12/13] drm/tyr: add vms and gpuvas debugfs interface Alvin Sun
  2026-03-26  6:53 ` [PATCH 13/13] drm/tyr: add gems field and gems " Alvin Sun
  12 siblings, 0 replies; 14+ messages in thread
From: Alvin Sun @ 2026-03-26  6:53 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, David Airlie, Simona Vetter, Sumit Semwal,
	Christian König, Daniel Almeida
  Cc: rust-for-linux, dri-devel, Alvin Sun

Add module debugfs root, per-device directory and TyrDebugFSData; wire
into driver and call debugfs_init.

Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 drivers/gpu/drm/tyr/debugfs.rs | 46 ++++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/tyr/driver.rs  | 11 +++++++++-
 drivers/gpu/drm/tyr/tyr.rs     | 39 ++++++++++++++++++++++++++++++++---
 3 files changed, 92 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/tyr/debugfs.rs b/drivers/gpu/drm/tyr/debugfs.rs
new file mode 100644
index 0000000000000..254ecef43ea9a
--- /dev/null
+++ b/drivers/gpu/drm/tyr/debugfs.rs
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0 or MIT
+
+//! Debugfs support for the Tyr DRM driver.
+
+use core::pin;
+
+use kernel::{
+    debugfs,
+    device::Core,
+    drm,
+    platform,
+    prelude::*,
+    revocable::LazyRevocable,
+    str::CString,
+    sync::{
+        hazptr::HazptrCtx,
+        Arc,
+        ArcBorrow, //
+    }, //
+};
+
+use crate::driver::TyrDrmDriver;
+
+pub(crate) static DEBUGFS_ROOT: LazyRevocable<debugfs::Dir> = LazyRevocable::new();
+
+/// Per-device debugfs data.
+pub(crate) struct TyrDebugFSData {}
+
+/// Registers per-device debugfs directory under the module's debugfs root.
+pub(crate) fn debugfs_init(
+    ddev: &drm::Device<TyrDrmDriver>,
+    pdev: &platform::Device<Core>,
+    debugfs_data: ArcBorrow<'_, TyrDebugFSData>,
+) -> Result {
+    let idx = ddev.primary_index();
+    let dir_name = CString::try_from_fmt(fmt!("{}", idx))?;
+    let ctx = pin::pin!(HazptrCtx::new());
+    let root_dir = DEBUGFS_ROOT.try_access(ctx).ok_or_else(|| {
+        pr_err!("DEBUGFS_ROOT is not set");
+        ENOENT
+    })?;
+    let debugfs_data: Arc<TyrDebugFSData> = debugfs_data.into();
+    let scope_init = root_dir.scope(debugfs_data, &dir_name, |_data, _dir| {});
+
+    kernel::devres::register(pdev.as_ref(), scope_init, GFP_KERNEL)
+}
diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
index 593f71c550e08..c8c929fda06ac 100644
--- a/drivers/gpu/drm/tyr/driver.rs
+++ b/drivers/gpu/drm/tyr/driver.rs
@@ -38,6 +38,7 @@
 };
 
 use crate::{
+    debugfs::TyrDebugFSData,
     file::TyrDrmFileData,
     fw::Firmware,
     gem::BoData,
@@ -75,6 +76,9 @@ pub(crate) struct TyrDrmDeviceData {
     ///
     /// This is mainly queried by userspace, i.e.: Mesa.
     pub(crate) gpu_info: GpuInfo,
+
+    /// Per-device debugfs data.
+    pub(crate) debugfs_data: Arc<TyrDebugFSData>,
 }
 
 // Both `Clk` and `Regulator` do not implement `Send` or `Sync`, but they
@@ -150,6 +154,8 @@ fn probe(
         let platform: ARef<platform::Device> = pdev.into();
 
         let mmu = Mmu::new(pdev, iomem.as_arc_borrow(), &gpu_info)?;
+        let debugfs_data = Arc::new(TyrDebugFSData {}, GFP_KERNEL)?;
+        let debugfs_data_clone = debugfs_data.clone();
 
         let firmware = Firmware::new(
             pdev,
@@ -174,9 +180,12 @@ fn probe(
                     _sram: sram_regulator,
                 }),
                 gpu_info,
+                debugfs_data: debugfs_data_clone,
         });
-
         let ddev = Registration::new_foreign_owned(uninit_ddev, pdev.as_ref(), data, 0)?;
+
+        crate::debugfs::debugfs_init(ddev, pdev, debugfs_data.as_arc_borrow())?;
+
         let driver = TyrPlatformDriverData {
             _device: ddev.into(),
         };
diff --git a/drivers/gpu/drm/tyr/tyr.rs b/drivers/gpu/drm/tyr/tyr.rs
index 18b0668bb2178..cda4955db4dc9 100644
--- a/drivers/gpu/drm/tyr/tyr.rs
+++ b/drivers/gpu/drm/tyr/tyr.rs
@@ -5,8 +5,20 @@
 //! The name "Tyr" is inspired by Norse mythology, reflecting Arm's tradition of
 //! naming their GPUs after Nordic mythological figures and places.
 
-use crate::driver::TyrPlatformDriverData;
+use crate::{
+    debugfs::DEBUGFS_ROOT,
+    driver::TyrPlatformDriverData, //
+};
+use kernel::{
+    driver::Registration,
+    error,
+    platform,
+    prelude::*,
+    revocable::HazPtrRevokeHandle,
+    InPlaceModule, //
+};
 
+mod debugfs;
 mod driver;
 mod file;
 mod fw;
@@ -17,8 +29,29 @@
 mod slot;
 mod vm;
 
-kernel::module_platform_driver! {
-    type: TyrPlatformDriverData,
+pub(crate) const MODULE_NAME: &kernel::str::CStr = <LocalModule as kernel::ModuleMetadata>::NAME;
+
+#[pin_data]
+struct TyrModule {
+    _debugfs_root: HazPtrRevokeHandle<'static, kernel::debugfs::Dir>,
+    #[pin]
+    _driver: Registration<platform::Adapter<TyrPlatformDriverData>>,
+}
+
+impl InPlaceModule for TyrModule {
+    fn init(module: &'static kernel::ThisModule) -> impl PinInit<Self, error::Error> {
+        let dir = kernel::debugfs::Dir::new(kernel::c_str!("tyr"));
+        let debugfs_root_handle = Pin::static_ref(&DEBUGFS_ROOT).init(dir);
+
+        try_pin_init!(Self {
+            _driver <- Registration::new(MODULE_NAME, module),
+            _debugfs_root <- debugfs_root_handle,
+        })
+    }
+}
+
+module! {
+    type: TyrModule,
     name: "tyr",
     authors: ["The Tyr driver authors"],
     description: "Arm Mali Tyr DRM driver",

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 12/13] drm/tyr: add vms and gpuvas debugfs interface
  2026-03-26  6:52 [PATCH 00/13] drm/tyr: add debugfs support Alvin Sun
                   ` (10 preceding siblings ...)
  2026-03-26  6:53 ` [PATCH 11/13] drm/tyr: add debugfs infrastructure Alvin Sun
@ 2026-03-26  6:53 ` Alvin Sun
  2026-03-26  6:53 ` [PATCH 13/13] drm/tyr: add gems field and gems " Alvin Sun
  12 siblings, 0 replies; 14+ messages in thread
From: Alvin Sun @ 2026-03-26  6:53 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, David Airlie, Simona Vetter, Sumit Semwal,
	Christian König, Daniel Almeida
  Cc: rust-for-linux, dri-devel, Alvin Sun

Add vms list to Mmu and vms field to TyrDebugFSData; populate vms in
Firmware::new and register gpuvas read-only file under debugfs
per-device directory.

Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 drivers/gpu/drm/tyr/debugfs.rs | 59 +++++++++++++++++++++++++++++++++++++++---
 drivers/gpu/drm/tyr/driver.rs  |  5 +++-
 drivers/gpu/drm/tyr/fw.rs      |  5 +++-
 drivers/gpu/drm/tyr/mmu.rs     |  6 ++++-
 4 files changed, 69 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/tyr/debugfs.rs b/drivers/gpu/drm/tyr/debugfs.rs
index 254ecef43ea9a..edbdb83a5b132 100644
--- a/drivers/gpu/drm/tyr/debugfs.rs
+++ b/drivers/gpu/drm/tyr/debugfs.rs
@@ -8,6 +8,9 @@
     debugfs,
     device::Core,
     drm,
+    drm::gem::IntoGEMObject,
+    fmt,
+    fmt::Write,
     platform,
     prelude::*,
     revocable::LazyRevocable,
@@ -15,16 +18,64 @@
     sync::{
         hazptr::HazptrCtx,
         Arc,
-        ArcBorrow, //
+        ArcBorrow,
+        Mutex, //
     }, //
 };
 
 use crate::driver::TyrDrmDriver;
+use crate::vm::Vm;
 
 pub(crate) static DEBUGFS_ROOT: LazyRevocable<debugfs::Dir> = LazyRevocable::new();
 
 /// Per-device debugfs data.
-pub(crate) struct TyrDebugFSData {}
+#[pin_data]
+pub(crate) struct TyrDebugFSData {
+    #[pin]
+    pub(crate) vms: Mutex<KVec<Arc<Vm>>>,
+}
+
+/// Writes VM debug information for the "gpuvas" debugfs file.
+fn show_vm(vm: &Vm, f: &mut impl Write) -> core::fmt::Result {
+    writeln!(
+        f,
+        "DRM GPU VA space ({:?}) [0x{:016x};0x{:016x}]",
+        vm.gpuvm.name(),
+        vm.va_range.start,
+        vm.va_range.end,
+    )?;
+
+    let kva = vm.gpuvm.kernel_alloc_va();
+    writeln!(
+        f,
+        "Kernel reserved node [0x{:016x};0x{:016x}]",
+        kva.addr(),
+        kva.addr() + kva.length(),
+    )?;
+
+    writeln!(f, " VAs | start              | range              | end                | object             | object offset")?;
+    writeln!(f, "-------------------------------------------------------------------------------------------------------------")?;
+    for va in vm.gpuvm_core.lock().va_mappings() {
+        f.write_fmt(fmt!(
+            "     | 0x{:016x} | 0x{:016x} | 0x{:016x} | {:18p} | 0x{:016x}\n",
+            va.addr(),
+            va.length(),
+            va.addr() + va.length(),
+            va.obj().as_raw(),
+            va.gem_offset(),
+        ))?;
+    }
+    Ok(())
+}
+
+fn show_gpuvas(data: &Arc<TyrDebugFSData>, f: &mut fmt::Formatter<'_>) -> core::fmt::Result {
+    let vms = data.vms.lock();
+    for vm in vms.iter() {
+        show_vm(vm, f)?;
+        writeln!(f)?;
+    }
+    Ok(())
+}
 
 /// Registers per-device debugfs directory under the module's debugfs root.
 pub(crate) fn debugfs_init(
@@ -40,7 +91,9 @@ pub(crate) fn debugfs_init(
         ENOENT
     })?;
     let debugfs_data: Arc<TyrDebugFSData> = debugfs_data.into();
-    let scope_init = root_dir.scope(debugfs_data, &dir_name, |_data, _dir| {});
+    let scope_init = root_dir.scope(debugfs_data, &dir_name, |data, dir| {
+        dir.read_callback_file(c"gpuvas", data, &show_gpuvas);
+    });
 
     kernel::devres::register(pdev.as_ref(), scope_init, GFP_KERNEL)
 }
diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
index c8c929fda06ac..e1d5e908de876 100644
--- a/drivers/gpu/drm/tyr/driver.rs
+++ b/drivers/gpu/drm/tyr/driver.rs
@@ -154,7 +154,9 @@ fn probe(
         let platform: ARef<platform::Device> = pdev.into();
 
         let mmu = Mmu::new(pdev, iomem.as_arc_borrow(), &gpu_info)?;
-        let debugfs_data = Arc::new(TyrDebugFSData {}, GFP_KERNEL)?;
+        let debugfs_data = Arc::pin_init(try_pin_init!(TyrDebugFSData {
+            vms <- new_mutex!(KVec::new()),
+        }), GFP_KERNEL)?;
         let debugfs_data_clone = debugfs_data.clone();
 
         let firmware = Firmware::new(
@@ -163,6 +165,7 @@ fn probe(
             &uninit_ddev,
             mmu.as_arc_borrow(),
             &gpu_info,
+            debugfs_data.as_arc_borrow(),
         )?;
 
         firmware.boot()?;
diff --git a/drivers/gpu/drm/tyr/fw.rs b/drivers/gpu/drm/tyr/fw.rs
index b62e5ed69c4d4..c46320bb54516 100644
--- a/drivers/gpu/drm/tyr/fw.rs
+++ b/drivers/gpu/drm/tyr/fw.rs
@@ -37,6 +37,7 @@
 };
 
 use crate::{
+    debugfs::TyrDebugFSData,
     driver::{
         IoMem,
         TyrDrmDevice, //
@@ -200,6 +201,7 @@ pub(crate) fn new(
         ddev: &TyrDrmDevice<Uninit>,
         mmu: ArcBorrow<'_, Mmu>,
         gpu_info: &GpuInfo,
+        debugfs_data: ArcBorrow<'_, TyrDebugFSData>,
     ) -> Result<Arc<Firmware>> {
         let vm = Vm::new(pdev, ddev, mmu, gpu_info)?;
 
@@ -238,11 +240,12 @@ pub(crate) fn new(
             Firmware {
                 pdev: pdev.into(),
                 iomem: iomem.into(),
-                vm,
+                vm: vm.clone(),
                 sections,
             },
             GFP_KERNEL,
         )?;
+        debugfs_data.vms.lock().push(vm, GFP_KERNEL)?;
 
         Ok(firmware)
     }
diff --git a/drivers/gpu/drm/tyr/mmu.rs b/drivers/gpu/drm/tyr/mmu.rs
index 52a6bbbb179a2..d5e6af4b804e4 100644
--- a/drivers/gpu/drm/tyr/mmu.rs
+++ b/drivers/gpu/drm/tyr/mmu.rs
@@ -35,7 +35,8 @@
         VmAsData, //
     },
     regs::MAX_AS_REGISTERS,
-    slot::SlotManager, //
+    slot::SlotManager,
+    vm, //
 };
 
 pub(crate) mod address_space;
@@ -51,6 +52,8 @@
 /// threads. Methods may block if another thread holds the lock.
 #[pin_data]
 pub(crate) struct Mmu {
+    #[pin]
+    pub(crate) vms: Mutex<KVec<Arc<vm::Vm>>>,
     /// Manages the allocation of hardware MMU slots to GPU address spaces.
     ///
     /// Tracks which address spaces are currently active in hardware slots and
@@ -75,6 +78,7 @@ pub(crate) fn new(
         let as_manager = AddressSpaceManager::new(pdev, iomem, gpu_info.as_present)?;
         let mmu_init = try_pin_init!(Self{
             as_manager <- new_mutex!(SlotManager::new(as_manager, slot_count)?),
+            vms <- new_mutex!(KVec::new()),
         });
         Arc::pin_init(mmu_init, GFP_KERNEL)
     }

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 13/13] drm/tyr: add gems field and gems debugfs interface
  2026-03-26  6:52 [PATCH 00/13] drm/tyr: add debugfs support Alvin Sun
                   ` (11 preceding siblings ...)
  2026-03-26  6:53 ` [PATCH 12/13] drm/tyr: add vms and gpuvas debugfs interface Alvin Sun
@ 2026-03-26  6:53 ` Alvin Sun
  12 siblings, 0 replies; 14+ messages in thread
From: Alvin Sun @ 2026-03-26  6:53 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, David Airlie, Simona Vetter, Sumit Semwal,
	Christian König, Daniel Almeida
  Cc: rust-for-linux, dri-devel, Alvin Sun

Add gems field to TyrDebugFSData; populate gems in Firmware::new and
register gems read-only file under debugfs per-device directory.

Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 drivers/gpu/drm/tyr/debugfs.rs | 93 +++++++++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/tyr/driver.rs  | 10 +++--
 drivers/gpu/drm/tyr/fw.rs      |  2 +
 3 files changed, 101 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/tyr/debugfs.rs b/drivers/gpu/drm/tyr/debugfs.rs
index edbdb83a5b132..d0e9e268aeac2 100644
--- a/drivers/gpu/drm/tyr/debugfs.rs
+++ b/drivers/gpu/drm/tyr/debugfs.rs
@@ -8,14 +8,19 @@
     debugfs,
     device::Core,
     drm,
-    drm::gem::IntoGEMObject,
+    drm::gem::{
+        BaseObject,
+        IntoGEMObject, //
+    },
     fmt,
     fmt::Write,
+    impl_flags,
     platform,
     prelude::*,
     revocable::LazyRevocable,
     str::CString,
     sync::{
+        aref::ARef,
         hazptr::HazptrCtx,
         Arc,
         ArcBorrow,
@@ -24,15 +29,100 @@
 };
 
 use crate::driver::TyrDrmDriver;
+use crate::gem::Bo;
 use crate::vm::Vm;
 
 pub(crate) static DEBUGFS_ROOT: LazyRevocable<debugfs::Dir> = LazyRevocable::new();
 
+impl_flags!(
+    #[derive(Debug, Clone, Default, Copy, PartialEq, Eq)]
+    struct BoStateFlags(u32);
+
+    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+    enum BoStateFlag {
+        Imported = 1 << 0,
+        Exported = 1 << 1,
+    }
+);
+
+/// Writes per-BO debug information for the "gems" debugfs file.
+fn show_bo(bo: &Bo, f: &mut impl Write) -> core::fmt::Result {
+    let name: i32 = bo.name();
+    let refcount: u32 = bo.refcount();
+    let size: usize = bo.size();
+    let resident_size: usize = bo.resident_size();
+    let mmap_offset = bo.mmap_offset();
+    let mut gem_state_flags = BoStateFlags::default();
+
+    if bo.is_imported() {
+        gem_state_flags |= BoStateFlag::Imported;
+    }
+    if bo.is_exported() {
+        gem_state_flags |= BoStateFlag::Exported;
+    }
+
+    writeln!(
+        f,
+        "{:<16}{:<16}{:<16}{:<16}0x{:<16x}0x{:<8x}",
+        name,
+        refcount,
+        size,
+        resident_size,
+        mmap_offset,
+        u32::from(gem_state_flags),
+    )
+}
+
+fn show_gems(data: &Arc<TyrDebugFSData>, f: &mut fmt::Formatter<'_>) -> core::fmt::Result {
+    writeln!(
+        f,
+        "GEM state flags: {:?} (0x{:x}), {:?} (0x{:x})",
+        BoStateFlag::Imported,
+        BoStateFlag::Imported as u32,
+        BoStateFlag::Exported,
+        BoStateFlag::Exported as u32,
+    )?;
+    writeln!(
+        f,
+        "global-name     refcount        size            resident-size   file-offset       state",
+    )?;
+    writeln!(
+        f,
+        "--------------------------------------------------------------------------------------------",
+    )?;
+
+    let mut total_size: usize = 0;
+    let mut total_resident: usize = 0;
+    let mut total_reclaimable: usize = 0;
+    let gems = data.gems.lock();
+    for bo in gems.iter() {
+        total_size += bo.size();
+        total_resident += bo.resident_size();
+        if bo.madv() > 0 {
+            total_reclaimable += bo.resident_size();
+        }
+        show_bo(bo, f)?;
+    }
+
+    writeln!(
+        f,
+        "============================================================================================",
+    )?;
+    writeln!(
+        f,
+        "Total size: {}, Total resident: {}, Total reclaimable: {}",
+        total_size, total_resident, total_reclaimable,
+    )?;
+    Ok(())
+}
+
 /// Per-device debugfs data.
 #[pin_data]
 pub(crate) struct TyrDebugFSData {
     #[pin]
     pub(crate) vms: Mutex<KVec<Arc<Vm>>>,
+    #[pin]
+    pub(crate) gems: Mutex<KVec<ARef<Bo>>>,
 }
 
 /// Writes VM debug information for the "gpuvas" debugfs file.
@@ -93,6 +183,7 @@ pub(crate) fn debugfs_init(
     let debugfs_data: Arc<TyrDebugFSData> = debugfs_data.into();
     let scope_init = root_dir.scope(debugfs_data, &dir_name, |data, dir| {
         dir.read_callback_file(c"gpuvas", data, &show_gpuvas);
+        dir.read_callback_file(c"gems", data, &show_gems);
     });
 
     kernel::devres::register(pdev.as_ref(), scope_init, GFP_KERNEL)
diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
index e1d5e908de876..a6d8760070d44 100644
--- a/drivers/gpu/drm/tyr/driver.rs
+++ b/drivers/gpu/drm/tyr/driver.rs
@@ -154,9 +154,13 @@ fn probe(
         let platform: ARef<platform::Device> = pdev.into();
 
         let mmu = Mmu::new(pdev, iomem.as_arc_borrow(), &gpu_info)?;
-        let debugfs_data = Arc::pin_init(try_pin_init!(TyrDebugFSData {
-            vms <- new_mutex!(KVec::new()),
-        }), GFP_KERNEL)?;
+        let debugfs_data = Arc::pin_init(
+            try_pin_init!(TyrDebugFSData {
+                vms <- new_mutex!(KVec::new()),
+                gems <- new_mutex!(KVec::new()),
+            }),
+            GFP_KERNEL,
+        )?;
         let debugfs_data_clone = debugfs_data.clone();
 
         let firmware = Firmware::new(
diff --git a/drivers/gpu/drm/tyr/fw.rs b/drivers/gpu/drm/tyr/fw.rs
index c46320bb54516..4d5efa79a7348 100644
--- a/drivers/gpu/drm/tyr/fw.rs
+++ b/drivers/gpu/drm/tyr/fw.rs
@@ -222,6 +222,8 @@ pub(crate) fn new(
                 parsed.vm_map_flags,
             )?;
 
+            debugfs_data.gems.lock().push(mem.bo.clone(), GFP_KERNEL)?;
+
             let section_start = parsed.data_range.start as usize;
             let section_end = parsed.data_range.end as usize;
             let mut data = KVec::new();

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2026-03-26  6:53 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-26  6:52 [PATCH 00/13] drm/tyr: add debugfs support Alvin Sun
2026-03-26  6:52 ` [PATCH 01/13] rust: sync: support [pin_]init for `SetOnce` Alvin Sun
2026-03-26  6:52 ` [PATCH 02/13] rust: revocable: add lazily instantiated revocable variant Alvin Sun
2026-03-26  6:52 ` [PATCH 03/13] rust: sync: set_once: Rename InitError variants to fix clippy warning Alvin Sun
2026-03-26  6:52 ` [PATCH 04/13] rust: sync: add hazard pointer abstraction Alvin Sun
2026-03-26  6:52 ` [PATCH 05/13] rust: revocable: add HazPtrRevocable Alvin Sun
2026-03-26  6:52 ` [PATCH 06/13] rust: revocable: make LazyRevocable use HazPtrRevocable Alvin Sun
2026-03-26  6:53 ` [PATCH 07/13] rust: drm: add Device::primary_index() Alvin Sun
2026-03-26  6:53 ` [PATCH 08/13] rust: drm/gem: add GEM object query helpers for debugfs Alvin Sun
2026-03-26  6:53 ` [PATCH 09/13] rust: drm/gem/shmem: add resident_size() and madv() " Alvin Sun
2026-03-26  6:53 ` [PATCH 10/13] drm/tyr: expose Vm gpuvm_core, gpuvm and va_range as pub(crate) Alvin Sun
2026-03-26  6:53 ` [PATCH 11/13] drm/tyr: add debugfs infrastructure Alvin Sun
2026-03-26  6:53 ` [PATCH 12/13] drm/tyr: add vms and gpuvas debugfs interface Alvin Sun
2026-03-26  6:53 ` [PATCH 13/13] drm/tyr: add gems field and gems " Alvin Sun

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox