* [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
` (12 subsequent siblings)
13 siblings, 0 replies; 20+ 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] 20+ 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
` (11 subsequent siblings)
13 siblings, 0 replies; 20+ 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] 20+ 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 14:40 ` Gary Guo
2026-03-26 16:35 ` Miguel Ojeda
2026-03-26 6:52 ` [PATCH 04/13] rust: sync: add hazard pointer abstraction Alvin Sun
` (10 subsequent siblings)
13 siblings, 2 replies; 20+ 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] 20+ messages in thread* Re: [PATCH 03/13] rust: sync: set_once: Rename InitError variants to fix clippy warning
2026-03-26 6:52 ` [PATCH 03/13] rust: sync: set_once: Rename InitError variants to fix clippy warning Alvin Sun
@ 2026-03-26 14:40 ` Gary Guo
2026-03-27 6:07 ` Alvin Sun
2026-03-26 16:35 ` Miguel Ojeda
1 sibling, 1 reply; 20+ messages in thread
From: Gary Guo @ 2026-03-26 14:40 UTC (permalink / raw)
To: Alvin Sun, 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
On Thu Mar 26, 2026 at 6:52 AM GMT, Alvin Sun wrote:
> Fixes clippy warning:
> warning: all variants have the same postfix: `Init`
> --> rust/kernel/sync/set_once.rs:68:1
I am not sure that this makes the code look nicer :/
AlreadyInit is very clear on what's wrong, which `InitError::Already` is weird.
Perhaps just allow this warning.
Best,
Gary
>
> 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),
> }
> }
>
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [PATCH 03/13] rust: sync: set_once: Rename InitError variants to fix clippy warning
2026-03-26 14:40 ` Gary Guo
@ 2026-03-27 6:07 ` Alvin Sun
0 siblings, 0 replies; 20+ messages in thread
From: Alvin Sun @ 2026-03-27 6:07 UTC (permalink / raw)
To: Gary Guo, Miguel Ojeda, Boqun Feng, 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
On 3/26/26 22:40, Gary Guo wrote:
> On Thu Mar 26, 2026 at 6:52 AM GMT, Alvin Sun wrote:
>> Fixes clippy warning:
>> warning: all variants have the same postfix: `Init`
>> --> rust/kernel/sync/set_once.rs:68:1
> I am not sure that this makes the code look nicer :/
>
> AlreadyInit is very clear on what's wrong, which `InitError::Already` is weird.
>
> Perhaps just allow this warning.
Got it, that makes more sense. I was actually a bit confused by this clippy
warning when I first saw it too, wasn't sure whether to just follow it
or not.
Now I know what to do - I'll drop this patch and allow the warning directly.
Best regards,
Alvin
>
> Best,
> Gary
>
>> 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),
>> }
>> }
>>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 03/13] rust: sync: set_once: Rename InitError variants to fix clippy warning
2026-03-26 6:52 ` [PATCH 03/13] rust: sync: set_once: Rename InitError variants to fix clippy warning Alvin Sun
2026-03-26 14:40 ` Gary Guo
@ 2026-03-26 16:35 ` Miguel Ojeda
2026-03-27 6:13 ` Alvin Sun
1 sibling, 1 reply; 20+ messages in thread
From: Miguel Ojeda @ 2026-03-26 16:35 UTC (permalink / raw)
To: Alvin Sun
Cc: 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, rust-for-linux, dri-devel
On Thu, Mar 26, 2026 at 7:55 AM Alvin Sun <alvin.sun@linux.dev> wrote:
>
> Fixes clippy warning:
> warning: all variants have the same postfix: `Init`
> --> rust/kernel/sync/set_once.rs:68:1
Is this fixing an issue earlier in the series?
If so, then I would suggest just fixing the patch that introduced the
issue directly (since you are not the author, you can use square
brackets between the Signed-off-bys to indicate what you changed. I
agree with Gary that is may be simpler to just allow the warning.
If not, then please add a Fixes: tag pointing to the commit being fixed.
(By the way, if you do keep this patch, then please copy-paste more of
the warning, i.e. it doesn't say what lint is being triggered. In
addition, the imperative mood is what is expected in commit messages
for the kernel.)
Thanks!
Cheers,
Miguel
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 03/13] rust: sync: set_once: Rename InitError variants to fix clippy warning
2026-03-26 16:35 ` Miguel Ojeda
@ 2026-03-27 6:13 ` Alvin Sun
0 siblings, 0 replies; 20+ messages in thread
From: Alvin Sun @ 2026-03-27 6:13 UTC (permalink / raw)
To: Miguel Ojeda
Cc: 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, rust-for-linux, dri-devel
On 3/27/26 00:35, Miguel Ojeda wrote:
> On Thu, Mar 26, 2026 at 7:55 AM Alvin Sun <alvin.sun@linux.dev> wrote:
>> Fixes clippy warning:
>> warning: all variants have the same postfix: `Init`
>> --> rust/kernel/sync/set_once.rs:68:1
> Is this fixing an issue earlier in the series?
>
> If so, then I would suggest just fixing the patch that introduced the
> issue directly (since you are not the author, you can use square
> brackets between the Signed-off-bys to indicate what you changed. I
> agree with Gary that is may be simpler to just allow the warning.
Agreed. This clippy warning already exists in Gary's original patch.
I'll fix it
there by allowing the warning directly, and add a square-bracket note
between
the Signed-off-bys describing the change.
Thanks,
Alvin
>
> If not, then please add a Fixes: tag pointing to the commit being fixed.
>
> (By the way, if you do keep this patch, then please copy-paste more of
> the warning, i.e. it doesn't say what lint is being triggered. In
> addition, the imperative mood is what is expected in commit messages
> for the kernel.)
>
> Thanks!
>
> Cheers,
> Miguel
^ permalink raw reply [flat|nested] 20+ 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
` (9 subsequent siblings)
13 siblings, 0 replies; 20+ 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] 20+ 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
` (8 subsequent siblings)
13 siblings, 0 replies; 20+ 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] 20+ 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
` (7 subsequent siblings)
13 siblings, 0 replies; 20+ 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] 20+ 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
` (6 subsequent siblings)
13 siblings, 0 replies; 20+ 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] 20+ 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
` (5 subsequent siblings)
13 siblings, 0 replies; 20+ 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] 20+ 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
` (4 subsequent siblings)
13 siblings, 0 replies; 20+ 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] 20+ 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
` (3 subsequent siblings)
13 siblings, 0 replies; 20+ 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] 20+ 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
` (2 subsequent siblings)
13 siblings, 0 replies; 20+ 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] 20+ 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
2026-03-26 14:32 ` [PATCH 00/13] drm/tyr: add debugfs support Boqun Feng
13 siblings, 0 replies; 20+ 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] 20+ 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
2026-03-26 14:32 ` [PATCH 00/13] drm/tyr: add debugfs support Boqun Feng
13 siblings, 0 replies; 20+ 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] 20+ messages in thread* Re: [PATCH 00/13] drm/tyr: add debugfs support
2026-03-26 6:52 [PATCH 00/13] drm/tyr: add debugfs support Alvin Sun
` (12 preceding siblings ...)
2026-03-26 6:53 ` [PATCH 13/13] drm/tyr: add gems field and gems " Alvin Sun
@ 2026-03-26 14:32 ` Boqun Feng
2026-03-27 6:18 ` Alvin Sun
13 siblings, 1 reply; 20+ messages in thread
From: Boqun Feng @ 2026-03-26 14:32 UTC (permalink / raw)
To: Alvin Sun
Cc: Miguel Ojeda, 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, rust-for-linux, dri-devel, rcu, Mathieu Desnoyers
Hi Alvin,
[cc rcu list and Mathieu]
On Thu, Mar 26, 2026 at 02:52:53PM +0800, Alvin Sun wrote:
> 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].
>
Thank you for the nice work!
I know the context of why you're doing this because we had some
discussion on zulip, but maybe most of people on the list don't. So
could you add a "why" or "motivation" part in the cover letter for the
next time? It's about syncing with everyone on the same page so that
they can review with the context ;-) Thanks!
Also since this is about hazptr and RCU, could you Cc
rcu@vger.kernel.org and Mathieu the next time? Thanks!
Regards,
Boqun
> 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] 20+ messages in thread* Re: [PATCH 00/13] drm/tyr: add debugfs support
2026-03-26 14:32 ` [PATCH 00/13] drm/tyr: add debugfs support Boqun Feng
@ 2026-03-27 6:18 ` Alvin Sun
0 siblings, 0 replies; 20+ messages in thread
From: Alvin Sun @ 2026-03-27 6:18 UTC (permalink / raw)
To: Boqun Feng
Cc: Miguel Ojeda, 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, rust-for-linux, dri-devel, rcu, Mathieu Desnoyers
On 3/26/26 22:32, Boqun Feng wrote:
> Hi Alvin,
>
> [cc rcu list and Mathieu]
>
> On Thu, Mar 26, 2026 at 02:52:53PM +0800, Alvin Sun wrote:
>> 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].
>>
> Thank you for the nice work!
>
> I know the context of why you're doing this because we had some
> discussion on zulip, but maybe most of people on the list don't. So
> could you add a "why" or "motivation" part in the cover letter for the
> next time? It's about syncing with everyone on the same page so that
> they can review with the context ;-) Thanks!
>
> Also since this is about hazptr and RCU, could you Cc
> rcu@vger.kernel.org and Mathieu the next time? Thanks!
Thanks for the reminder! I'll add the motivation section to the cover
letter and
CC the correct lists/people in the next version.
Best regards,
Alvin
>
> Regards,
> Boqun
>
>> 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] 20+ messages in thread