* [PATCH v19 4/8] rust: page: convert to `Ownable`
From: Andreas Hindborg @ 2026-06-26 11:54 UTC (permalink / raw)
To: Danilo Krummrich, Lorenzo Stoakes, Vlastimil Babka,
Liam R. Howlett, Uladzislau Rezki, Miguel Ojeda, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Alice Ryhl,
Trevor Gross, Daniel Almeida, Tamir Duberstein, Alexandre Courbot,
Onur Özkan, Lyude Paul, Greg Kroah-Hartman,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas, Rafael J. Wysocki, Dave Ertman, Ira Weiny,
Leon Romanovsky, Paul Moore, Serge Hallyn, David Airlie,
Simona Vetter, Alexander Viro, Jan Kara, Igor Korotin,
Viresh Kumar, Nishanth Menon, Stephen Boyd, Bjorn Helgaas,
Krzysztof Wilczyński, Pavel Tikhomirov, Michal Wilczynski
Cc: Andreas Hindborg, Philipp Stanner, rust-for-linux, linux-kernel,
linux-mm, driver-core, linux-block, linux-security-module,
dri-devel, linux-fsdevel, linux-pm, linux-pci, linux-pwm,
Asahi Lina
In-Reply-To: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org>
From: Asahi Lina <lina@asahilina.net>
This allows Page references to be returned as borrowed references,
without necessarily owning the struct page.
Remove `BorrowedPage` and update users to use `Owned<Page>`.
Signed-off-by: Asahi Lina <lina@asahilina.net>
[ Andreas: Fix formatting and add a safety comment, update users. ]
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
---
drivers/android/binder/page_range.rs | 10 +--
rust/kernel/alloc/allocator.rs | 19 +++---
rust/kernel/alloc/allocator/iter.rs | 6 +-
rust/kernel/page.rs | 122 +++++++++--------------------------
4 files changed, 46 insertions(+), 111 deletions(-)
diff --git a/drivers/android/binder/page_range.rs b/drivers/android/binder/page_range.rs
index e54a90e62402a..7941eb85b4ef4 100644
--- a/drivers/android/binder/page_range.rs
+++ b/drivers/android/binder/page_range.rs
@@ -33,7 +33,7 @@
sync::{aref::ARef, Mutex, SpinLock},
task::Pid,
transmute::FromBytes,
- types::Opaque,
+ types::{Opaque, Owned},
uaccess::UserSliceReader,
};
@@ -198,7 +198,7 @@ unsafe impl Send for Inner {}
#[repr(C)]
struct PageInfo {
lru: bindings::list_head,
- page: Option<Page>,
+ page: Option<Owned<Page>>,
range: *const ShrinkablePageRange,
}
@@ -206,7 +206,7 @@ impl PageInfo {
/// # Safety
///
/// The caller ensures that writing to `me.page` is ok, and that the page is not currently set.
- unsafe fn set_page(me: *mut PageInfo, page: Page) {
+ unsafe fn set_page(me: *mut PageInfo, page: Owned<Page>) {
// SAFETY: This pointer offset is in bounds.
let ptr = unsafe { &raw mut (*me).page };
@@ -229,13 +229,13 @@ unsafe fn get_page<'a>(me: *const PageInfo) -> Option<&'a Page> {
let ptr = unsafe { &raw const (*me).page };
// SAFETY: The pointer is valid for reading.
- unsafe { (*ptr).as_ref() }
+ unsafe { (*ptr).as_deref() }
}
/// # Safety
///
/// The caller ensures that writing to `me.page` is ok for the duration of 'a.
- unsafe fn take_page(me: *mut PageInfo) -> Option<Page> {
+ unsafe fn take_page(me: *mut PageInfo) -> Option<Owned<Page>> {
// SAFETY: This pointer offset is in bounds.
let ptr = unsafe { &raw mut (*me).page };
diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs
index cd4203f27aed0..c7b9b069cf75d 100644
--- a/rust/kernel/alloc/allocator.rs
+++ b/rust/kernel/alloc/allocator.rs
@@ -169,7 +169,7 @@ unsafe fn realloc(
}
impl Vmalloc {
- /// Convert a pointer to a [`Vmalloc`] allocation to a [`page::BorrowedPage`].
+ /// Convert a pointer to a [`Vmalloc`] allocation to a [`Page`](page::Page) reference.
///
/// # Examples
///
@@ -202,20 +202,17 @@ impl Vmalloc {
///
/// - `ptr` must be a valid pointer to a [`Vmalloc`] allocation.
/// - `ptr` must remain valid for the entire duration of `'a`.
- pub unsafe fn to_page<'a>(ptr: NonNull<u8>) -> page::BorrowedPage<'a> {
+ pub unsafe fn to_page<'a>(ptr: NonNull<u8>) -> &'a page::Page {
// SAFETY: `ptr` is a valid pointer to `Vmalloc` memory.
let page = unsafe { bindings::vmalloc_to_page(ptr.as_ptr().cast()) };
- // SAFETY: `vmalloc_to_page` returns a valid pointer to a `struct page` for a valid pointer
- // to `Vmalloc` memory.
- let page = unsafe { NonNull::new_unchecked(page) };
-
// SAFETY:
- // - `page` is a valid pointer to a `struct page`, given that by the safety requirements of
- // this function `ptr` is a valid pointer to a `Vmalloc` allocation.
- // - By the safety requirements of this function `ptr` is valid for the entire lifetime of
- // `'a`.
- unsafe { page::BorrowedPage::from_raw(page) }
+ // - `vmalloc_to_page` returns a valid, non-null pointer to a `struct page` for a valid
+ // pointer to `Vmalloc` memory, given that by the safety requirements of this function
+ // `ptr` is a valid pointer to a `Vmalloc` allocation.
+ // - By the safety requirements of this function `ptr`, and hence the `struct page`, is
+ // valid for the entire lifetime of `'a`.
+ unsafe { &*page.cast() }
}
}
diff --git a/rust/kernel/alloc/allocator/iter.rs b/rust/kernel/alloc/allocator/iter.rs
index 02fda3ea5cae6..8dcc16ed89893 100644
--- a/rust/kernel/alloc/allocator/iter.rs
+++ b/rust/kernel/alloc/allocator/iter.rs
@@ -9,7 +9,7 @@
ptr::NonNull, //
};
-/// An [`Iterator`] of [`page::BorrowedPage`] items owned by a [`Vmalloc`] allocation.
+/// An [`Iterator`] of [`Page`](page::Page) references owned by a [`Vmalloc`] allocation.
///
/// # Guarantees
///
@@ -28,11 +28,11 @@ pub struct VmallocPageIter<'a> {
size: usize,
/// The current page index of the [`Iterator`].
index: usize,
- _p: PhantomData<page::BorrowedPage<'a>>,
+ _p: PhantomData<&'a page::Page>,
}
impl<'a> Iterator for VmallocPageIter<'a> {
- type Item = page::BorrowedPage<'a>;
+ type Item = &'a page::Page;
fn next(&mut self) -> Option<Self::Item> {
let offset = self.index.checked_mul(page::PAGE_SIZE)?;
diff --git a/rust/kernel/page.rs b/rust/kernel/page.rs
index 8affd8262891b..6dc1c2395acaf 100644
--- a/rust/kernel/page.rs
+++ b/rust/kernel/page.rs
@@ -12,16 +12,16 @@
code::*,
Result, //
},
+ types::{
+ Opaque,
+ Ownable,
+ Owned, //
+ },
uaccess::UserSliceReader, //
};
-use core::{
- marker::PhantomData,
- mem::ManuallyDrop,
- ops::Deref,
- ptr::{
- self,
- NonNull, //
- }, //
+use core::ptr::{
+ self,
+ NonNull, //
};
/// A bitwise shift for the page size.
@@ -65,93 +65,29 @@ pub const fn page_align(addr: usize) -> Option<usize> {
Some(sum & PAGE_MASK)
}
-/// Representation of a non-owning reference to a [`Page`].
-///
-/// This type provides a borrowed version of a [`Page`] that is owned by some other entity, e.g. a
-/// [`Vmalloc`] allocation such as [`VBox`].
-///
-/// # Example
-///
-/// ```
-/// # use kernel::{bindings, prelude::*};
-/// use kernel::page::{BorrowedPage, Page, PAGE_SIZE};
-/// # use core::{mem::MaybeUninit, ptr, ptr::NonNull };
-///
-/// fn borrow_page<'a>(vbox: &'a mut VBox<MaybeUninit<[u8; PAGE_SIZE]>>) -> BorrowedPage<'a> {
-/// let ptr = ptr::from_ref(&**vbox);
-///
-/// // SAFETY: `ptr` is a valid pointer to `Vmalloc` memory.
-/// let page = unsafe { bindings::vmalloc_to_page(ptr.cast()) };
-///
-/// // SAFETY: `vmalloc_to_page` returns a valid pointer to a `struct page` for a valid
-/// // pointer to `Vmalloc` memory.
-/// let page = unsafe { NonNull::new_unchecked(page) };
-///
-/// // SAFETY:
-/// // - `self.0` is a valid pointer to a `struct page`.
-/// // - `self.0` is valid for the entire lifetime of `self`.
-/// unsafe { BorrowedPage::from_raw(page) }
-/// }
-///
-/// let mut vbox = VBox::<[u8; PAGE_SIZE]>::new_uninit(GFP_KERNEL)?;
-/// let page = borrow_page(&mut vbox);
-///
-/// // SAFETY: There is no concurrent read or write to this page.
-/// unsafe { page.fill_zero_raw(0, PAGE_SIZE)? };
-/// # Ok::<(), Error>(())
-/// ```
-///
-/// # Invariants
-///
-/// The borrowed underlying pointer to a `struct page` is valid for the entire lifetime `'a`.
-///
-/// [`VBox`]: kernel::alloc::VBox
-/// [`Vmalloc`]: kernel::alloc::allocator::Vmalloc
-pub struct BorrowedPage<'a>(ManuallyDrop<Page>, PhantomData<&'a Page>);
-
-impl<'a> BorrowedPage<'a> {
- /// Constructs a [`BorrowedPage`] from a raw pointer to a `struct page`.
- ///
- /// # Safety
- ///
- /// - `ptr` must point to a valid `bindings::page`.
- /// - `ptr` must remain valid for the entire lifetime `'a`.
- pub unsafe fn from_raw(ptr: NonNull<bindings::page>) -> Self {
- let page = Page { page: ptr };
-
- // INVARIANT: The safety requirements guarantee that `ptr` is valid for the entire lifetime
- // `'a`.
- Self(ManuallyDrop::new(page), PhantomData)
- }
-}
-
-impl<'a> Deref for BorrowedPage<'a> {
- type Target = Page;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
-
-/// Trait to be implemented by types which provide an [`Iterator`] implementation of
-/// [`BorrowedPage`] items, such as [`VmallocPageIter`](kernel::alloc::allocator::VmallocPageIter).
+/// Trait to be implemented by types which provide an [`Iterator`] of [`Page`] references, such as
+/// [`VmallocPageIter`](kernel::alloc::allocator::VmallocPageIter).
pub trait AsPageIter {
/// The [`Iterator`] type, e.g. [`VmallocPageIter`](kernel::alloc::allocator::VmallocPageIter).
- type Iter<'a>: Iterator<Item = BorrowedPage<'a>>
+ type Iter<'a>: Iterator<Item = &'a Page>
where
Self: 'a;
- /// Returns an [`Iterator`] of [`BorrowedPage`] items over all pages owned by `self`.
+ /// Returns an [`Iterator`] of [`Page`] references over all pages owned by `self`.
fn page_iter(&mut self) -> Self::Iter<'_>;
}
-/// A pointer to a page that owns the page allocation.
+/// A `struct page`.
+///
+/// A `Page` is accessed through a shared reference or through an owning [`Owned<Page>`]; the latter
+/// frees the page allocation when it is dropped.
///
/// # Invariants
///
-/// The pointer is valid, and has ownership over the page.
+/// The `Page` is backed by a valid `struct page`.
+#[repr(transparent)]
pub struct Page {
- page: NonNull<bindings::page>,
+ page: Opaque<bindings::page>,
}
// SAFETY: Pages have no logic that relies on them staying on a given thread, so moving them across
@@ -185,19 +121,20 @@ impl Page {
/// # Ok::<(), kernel::alloc::AllocError>(())
/// ```
#[inline]
- pub fn alloc_page(flags: Flags) -> Result<Self, AllocError> {
+ pub fn alloc_page(flags: Flags) -> Result<Owned<Self>, AllocError> {
// SAFETY: Depending on the value of `gfp_flags`, this call may sleep. Other than that, it
// is always safe to call this method.
let page = unsafe { bindings::alloc_pages(flags.as_raw(), 0) };
let page = NonNull::new(page).ok_or(AllocError)?;
- // INVARIANT: We just successfully allocated a page, so we now have ownership of the newly
- // allocated page. We transfer that ownership to the new `Page` object.
- Ok(Self { page })
+ // SAFETY: We just successfully allocated a page, so we now have ownership of the newly
+ // allocated page. We transfer that ownership to the new `Owned<Page>` object.
+ // Since `Page` is transparent, we can cast the pointer directly.
+ Ok(unsafe { Owned::from_raw(page.cast()) })
}
/// Returns a raw pointer to the page.
pub fn as_ptr(&self) -> *mut bindings::page {
- self.page.as_ptr()
+ Opaque::cast_into(&self.page)
}
/// Get the node id containing this page.
@@ -372,10 +309,11 @@ pub unsafe fn copy_from_user_slice_raw(
}
}
-impl Drop for Page {
+impl Ownable for Page {
#[inline]
- fn drop(&mut self) {
- // SAFETY: By the type invariants, we have ownership of the page and can free it.
- unsafe { bindings::__free_pages(self.page.as_ptr(), 0) };
+ unsafe fn release(this: NonNull<Self>) {
+ // SAFETY: By the function safety requirements, we have ownership of the page and can free
+ // it. Since Page is transparent, we can cast the raw pointer directly.
+ unsafe { bindings::__free_pages(this.as_ptr().cast(), 0) };
}
}
--
2.51.2
^ permalink raw reply related
* [PATCH v19 7/8] rust: Add `OwnableRefCounted`
From: Andreas Hindborg @ 2026-06-26 11:54 UTC (permalink / raw)
To: Danilo Krummrich, Lorenzo Stoakes, Vlastimil Babka,
Liam R. Howlett, Uladzislau Rezki, Miguel Ojeda, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Alice Ryhl,
Trevor Gross, Daniel Almeida, Tamir Duberstein, Alexandre Courbot,
Onur Özkan, Lyude Paul, Greg Kroah-Hartman,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas, Rafael J. Wysocki, Dave Ertman, Ira Weiny,
Leon Romanovsky, Paul Moore, Serge Hallyn, David Airlie,
Simona Vetter, Alexander Viro, Jan Kara, Igor Korotin,
Viresh Kumar, Nishanth Menon, Stephen Boyd, Bjorn Helgaas,
Krzysztof Wilczyński, Pavel Tikhomirov, Michal Wilczynski
Cc: Andreas Hindborg, Philipp Stanner, rust-for-linux, linux-kernel,
linux-mm, driver-core, linux-block, linux-security-module,
dri-devel, linux-fsdevel, linux-pm, linux-pci, linux-pwm,
Oliver Mangold
In-Reply-To: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org>
From: Oliver Mangold <oliver.mangold@pm.me>
Types implementing one of these traits can safely convert between an
`ARef<T>` and an `Owned<T>`.
This is useful for types which generally are accessed through an `ARef`
but have methods which can only safely be called when the reference is
unique, like e.g. `block::mq::Request::end_ok()`.
Signed-off-by: Oliver Mangold <oliver.mangold@pm.me>
[ Andreas: Fix formatting, update documentation, fix error handling in
examples. ]
Co-developed-by: Andreas Hindborg <a.hindborg@kernel.org>
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/owned.rs | 145 +++++++++++++++++++++++++++++++++++++++++++++--
rust/kernel/sync/aref.rs | 16 +++++-
rust/kernel/types.rs | 1 +
3 files changed, 156 insertions(+), 6 deletions(-)
diff --git a/rust/kernel/owned.rs b/rust/kernel/owned.rs
index a156267bf8bb1..acb611f084ff3 100644
--- a/rust/kernel/owned.rs
+++ b/rust/kernel/owned.rs
@@ -14,20 +14,26 @@
pin::Pin,
ptr::NonNull, //
};
+use kernel::{
+ sync::aref::ARef,
+ types::RefCounted, //
+};
use kernel::types::ForeignOwnable;
/// Types that specify their own way of performing allocation and destruction. Typically, this trait
/// is implemented on types from the C side.
///
-/// Implementing this trait allows types to be referenced via the [`Owned<Self>`] pointer type. This
-/// is useful when it is desirable to tie the lifetime of the reference to an owned object, rather
-/// than pass around a bare reference. [`Ownable`] types can define custom drop logic that is
-/// executed when the owned reference [`Owned<Self>`] pointing to the object is dropped.
+/// Implementing this trait allows types to be referenced via the [`Owned<Self>`] pointer type.
+/// - This is useful when it is desirable to tie the lifetime of an object reference to an owned
+/// object, rather than pass around a bare reference.
+/// - [`Ownable`] types can define custom drop logic that is executed when the owned reference
+/// of type [`Owned<_>`] pointing to the object is dropped.
///
/// Note: The underlying object is not required to provide internal reference counting, because it
/// represents a unique, owned reference. If reference counting (on the Rust side) is required,
-/// [`RefCounted`](crate::types::RefCounted) should be implemented.
+/// [`RefCounted`] should be implemented. [`OwnableRefCounted`] should be implemented if conversion
+/// between unique and shared (reference counted) ownership is needed.
///
/// # Examples
///
@@ -99,6 +105,8 @@ pub trait Ownable {
/// Callers must ensure that they have exclusive ownership of the `Self` pointed to by `this`,
/// and that this ownership is transferred to the `release` method. `this` must not be used
/// after calling this method, as the underlying object may have been freed.
+ ///
+ /// `this` is pinned and implementers of this method must observe this constraint.
unsafe fn release(this: NonNull<Self>);
}
@@ -136,6 +144,8 @@ pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
///
/// This function does not drop the underlying `T`. When this function returns, ownership of the
/// underlying `T` is with the caller.
+ ///
+ /// Note that the returned pointer is pinned.
#[inline]
pub fn into_raw(me: Self) -> NonNull<T> {
ManuallyDrop::new(me).ptr
@@ -236,3 +246,128 @@ unsafe fn borrow_mut<'a>(ptr: *mut kernel::ffi::c_void) -> Self::BorrowedMut<'a>
unsafe { Pin::new_unchecked(inner) }
}
}
+
+/// A trait for objects that can be wrapped in either one of the reference types [`Owned`] and
+/// [`ARef`].
+///
+/// # Examples
+///
+/// A minimal example implementation of [`OwnableRefCounted`], [`Ownable`] and its usage with
+/// [`ARef`] and [`Owned`] looks like this:
+///
+/// ```
+/// # #![expect(clippy::disallowed_names)]
+/// # use core::cell::Cell;
+/// # use core::ptr::NonNull;
+/// # use kernel::alloc::{flags, kbox::KBox, AllocError};
+/// # use kernel::sync::aref::{ARef, RefCounted};
+/// # use kernel::types::{Owned, Ownable, OwnableRefCounted};
+///
+/// // An internally refcounted struct for demonstration purposes.
+/// //
+/// // # Invariants
+/// //
+/// // - `refcount` is always non-zero for a valid object.
+/// // - `refcount` is >1 if there is more than one Rust reference to it.
+/// //
+/// struct Foo {
+/// refcount: Cell<usize>,
+/// }
+///
+/// impl Foo {
+/// fn new() -> Result<Owned<Self>> {
+/// // We are just using a `KBox` here to handle the actual allocation, as our `Foo` is
+/// // not actually a C-allocated object.
+/// // INVARIANT: We initialize `refcount` to 1, satisfying the invariants.
+/// let result = KBox::new(
+/// Foo {
+/// refcount: Cell::new(1),
+/// },
+/// flags::GFP_KERNEL,
+/// )?;
+/// let result = KBox::into_non_null(result);
+/// // SAFETY:
+/// // - We just allocated the `Self`, thus it is valid and we own it.
+/// // - We can transfer this ownership to the `from_raw` method.
+/// Ok(unsafe { Owned::from_raw(result) })
+/// }
+/// }
+///
+/// // SAFETY: We increment and decrement each time the respective function is called and only free
+/// // the `Foo` when the refcount reaches zero.
+/// unsafe impl RefCounted for Foo {
+/// fn inc_ref(&self) {
+/// self.refcount.replace(self.refcount.get() + 1);
+/// }
+///
+/// unsafe fn dec_ref(this: NonNull<Self>) {
+/// // SAFETY: By requirement on calling this function, the refcount is non-zero,
+/// // implying the underlying object is valid.
+/// let refcount = unsafe { &this.as_ref().refcount };
+/// let new_refcount = refcount.get() - 1;
+/// if new_refcount == 0 {
+/// // The `Foo` will be dropped when `KBox` goes out of scope.
+/// // SAFETY: The [`KBox<Foo>`] is still alive as the old refcount is 1. We can pass
+/// // ownership to the [`KBox`] as by requirement on calling this function,
+/// // the `Self` will no longer be used by the caller.
+/// unsafe { KBox::from_raw(this.as_ptr()) };
+/// } else {
+/// refcount.replace(new_refcount);
+/// }
+/// }
+/// }
+///
+/// impl OwnableRefCounted for Foo {
+/// fn try_from_shared(this: ARef<Self>) -> Result<Owned<Self>, ARef<Self>> {
+/// if this.refcount.get() == 1 {
+/// // SAFETY: The `Foo` is still alive and has no other Rust references as the refcount
+/// // is 1.
+/// Ok(unsafe { Owned::from_raw(ARef::into_raw(this)) })
+/// } else {
+/// Err(this)
+/// }
+/// }
+///
+/// fn into_shared(this: Owned<Self>) -> ARef<Self> {
+/// // SAFETY: An `Owned<Foo>` holds the unique reference (refcount 1), which we transfer to
+/// // the new `ARef`.
+/// unsafe { ARef::from_raw(Owned::into_raw(this)) }
+/// }
+/// }
+///
+/// impl Ownable for Foo {
+/// unsafe fn release(this: NonNull<Self>) {
+/// // SAFETY: Using `dec_ref()` from [`RefCounted`] to release is okay, as the refcount is
+/// // always 1 for an [`Owned<Foo>`].
+/// unsafe { Foo::dec_ref(this) };
+/// }
+/// }
+///
+/// let foo = Foo::new()?;
+/// let foo = ARef::from(foo);
+/// {
+/// let bar = foo.clone();
+/// assert!(Owned::try_from(bar).is_err());
+/// }
+/// assert!(Owned::try_from(foo).is_ok());
+/// # Ok::<(), Error>(())
+/// ```
+pub trait OwnableRefCounted: RefCounted + Ownable + Sized {
+ /// Checks if the [`ARef`] is unique and converts it to an [`Owned`] if that is the case.
+ /// Otherwise it returns again an [`ARef`] to the same underlying object.
+ fn try_from_shared(this: ARef<Self>) -> Result<Owned<Self>, ARef<Self>>;
+
+ /// Converts the [`Owned`] into an [`ARef`].
+ fn into_shared(this: Owned<Self>) -> ARef<Self>;
+}
+
+impl<T: OwnableRefCounted> TryFrom<ARef<T>> for Owned<T> {
+ type Error = ARef<T>;
+ /// Tries to convert the [`ARef`] to an [`Owned`] by calling
+ /// [`try_from_shared()`](OwnableRefCounted::try_from_shared). In case the [`ARef`] is not
+ /// unique, it returns again an [`ARef`] to the same underlying object.
+ #[inline]
+ fn try_from(b: ARef<T>) -> Result<Owned<T>, Self::Error> {
+ T::try_from_shared(b)
+ }
+}
diff --git a/rust/kernel/sync/aref.rs b/rust/kernel/sync/aref.rs
index f26ca39b84d0d..e6ffe7c650c39 100644
--- a/rust/kernel/sync/aref.rs
+++ b/rust/kernel/sync/aref.rs
@@ -23,6 +23,10 @@
ops::Deref,
ptr::NonNull, //
};
+use kernel::types::{
+ OwnableRefCounted,
+ Owned, //
+};
/// Types that are internally reference counted.
///
@@ -35,7 +39,10 @@
/// Note: Implementing this trait allows types to be wrapped in an [`ARef<Self>`]. It requires an
/// internal reference count and provides only shared references. If unique references are required
/// [`Ownable`](crate::types::Ownable) should be implemented which allows types to be wrapped in an
-/// [`Owned<Self>`](crate::types::Owned).
+/// [`Owned<Self>`](crate::types::Owned). Implementing the trait
+/// [`OwnableRefCounted`] allows to convert between unique and
+/// shared references (i.e. [`Owned<Self>`](crate::types::Owned) and
+/// [`ARef<Self>`]).
///
/// # Safety
///
@@ -188,6 +195,13 @@ fn from(b: &T) -> Self {
}
}
+impl<T: OwnableRefCounted> From<Owned<T>> for ARef<T> {
+ #[inline]
+ fn from(b: Owned<T>) -> Self {
+ T::into_shared(b)
+ }
+}
+
impl<T: RefCounted> Drop for ARef<T> {
fn drop(&mut self) {
// SAFETY: The type invariants guarantee that the `ARef` owns the reference we're about to
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index 5ef763717e59a..6aa760952cb63 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -18,6 +18,7 @@
pub use crate::{
owned::{
Ownable,
+ OwnableRefCounted,
Owned, //
},
sync::aref::{
--
2.51.2
^ permalink raw reply related
* [PATCH v19 6/8] rust: Add missing SAFETY documentation for `ARef` example
From: Andreas Hindborg @ 2026-06-26 11:54 UTC (permalink / raw)
To: Danilo Krummrich, Lorenzo Stoakes, Vlastimil Babka,
Liam R. Howlett, Uladzislau Rezki, Miguel Ojeda, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Alice Ryhl,
Trevor Gross, Daniel Almeida, Tamir Duberstein, Alexandre Courbot,
Onur Özkan, Lyude Paul, Greg Kroah-Hartman,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas, Rafael J. Wysocki, Dave Ertman, Ira Weiny,
Leon Romanovsky, Paul Moore, Serge Hallyn, David Airlie,
Simona Vetter, Alexander Viro, Jan Kara, Igor Korotin,
Viresh Kumar, Nishanth Menon, Stephen Boyd, Bjorn Helgaas,
Krzysztof Wilczyński, Pavel Tikhomirov, Michal Wilczynski
Cc: Andreas Hindborg, Philipp Stanner, rust-for-linux, linux-kernel,
linux-mm, driver-core, linux-block, linux-security-module,
dri-devel, linux-fsdevel, linux-pm, linux-pci, linux-pwm,
Oliver Mangold
In-Reply-To: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org>
From: Oliver Mangold <oliver.mangold@pm.me>
SAFETY comment in rustdoc example was just 'TODO'. Fixed.
Signed-off-by: Oliver Mangold <oliver.mangold@pm.me>
Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
Co-developed-by: Andreas Hindborg <a.hindborg@kernel.org>
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/sync/aref.rs | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/rust/kernel/sync/aref.rs b/rust/kernel/sync/aref.rs
index ea5a16b8163a6..f26ca39b84d0d 100644
--- a/rust/kernel/sync/aref.rs
+++ b/rust/kernel/sync/aref.rs
@@ -142,7 +142,9 @@ pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
///
/// struct Empty {}
///
- /// # // SAFETY: TODO.
+ /// // SAFETY: The `RefCounted` implementation for `Empty` does not count references and never
+ /// // frees the underlying object. Thus we can act as owning an increment on the refcount for
+ /// // the object that we pass to the newly created `ARef`.
/// unsafe impl RefCounted for Empty {
/// fn inc_ref(&self) {}
/// unsafe fn dec_ref(_obj: NonNull<Self>) {}
@@ -150,7 +152,7 @@ pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
///
/// let mut data = Empty {};
/// let ptr = NonNull::<Empty>::new(&mut data).unwrap();
- /// # // SAFETY: TODO.
+ /// // SAFETY: We keep `data` around longer than the `ARef`.
/// let data_ref: ARef<Empty> = unsafe { ARef::from_raw(ptr) };
/// let raw_ptr: NonNull<Empty> = ARef::into_raw(data_ref);
///
--
2.51.2
^ permalink raw reply related
* [PATCH v19 5/8] rust: rename `AlwaysRefCounted` to `RefCounted`.
From: Andreas Hindborg @ 2026-06-26 11:54 UTC (permalink / raw)
To: Danilo Krummrich, Lorenzo Stoakes, Vlastimil Babka,
Liam R. Howlett, Uladzislau Rezki, Miguel Ojeda, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Alice Ryhl,
Trevor Gross, Daniel Almeida, Tamir Duberstein, Alexandre Courbot,
Onur Özkan, Lyude Paul, Greg Kroah-Hartman,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas, Rafael J. Wysocki, Dave Ertman, Ira Weiny,
Leon Romanovsky, Paul Moore, Serge Hallyn, David Airlie,
Simona Vetter, Alexander Viro, Jan Kara, Igor Korotin,
Viresh Kumar, Nishanth Menon, Stephen Boyd, Bjorn Helgaas,
Krzysztof Wilczyński, Pavel Tikhomirov, Michal Wilczynski
Cc: Andreas Hindborg, Philipp Stanner, rust-for-linux, linux-kernel,
linux-mm, driver-core, linux-block, linux-security-module,
dri-devel, linux-fsdevel, linux-pm, linux-pci, linux-pwm,
Oliver Mangold, Viresh Kumar, Igor Korotin
In-Reply-To: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org>
From: Oliver Mangold <oliver.mangold@pm.me>
There are types where it may both be reference counted in some cases and
owned in others. In such cases, obtaining `ARef<T>` from `&T` would be
unsound as it allows creation of `ARef<T>` copy from `&Owned<T>`.
Therefore, we split `AlwaysRefCounted` into `RefCounted` (which `ARef<T>`
would require) and a marker trait to indicate that the type is always
reference counted (and not `Ownable`) so the `&T` -> `ARef<T>` conversion
is possible.
- Rename `AlwaysRefCounted` to `RefCounted`.
- Add a new unsafe trait `AlwaysRefCounted`.
- Implement the new trait `AlwaysRefCounted` for the newly renamed
`RefCounted` implementations. This leaves functionality of existing
implementers of `AlwaysRefCounted` intact.
Suggested-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
Signed-off-by: Oliver Mangold <oliver.mangold@pm.me>
[ Andreas: Updated commit message and rebase on rust-next (7.2) ]
Acked-by: Igor Korotin <igor.korotin.linux@gmail.com>
Acked-by: Danilo Krummrich <dakr@kernel.org>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
Co-developed-by: Andreas Hindborg <a.hindborg@kernel.org>
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/auxiliary.rs | 10 ++++++-
rust/kernel/block/mq/request.rs | 19 ++++++++-----
rust/kernel/cred.rs | 16 +++++++++--
rust/kernel/device.rs | 12 +++++++--
rust/kernel/device/property.rs | 11 ++++++--
rust/kernel/drm/device.rs | 9 +++++--
rust/kernel/drm/gem/mod.rs | 16 ++++++++---
rust/kernel/fs/file.rs | 23 +++++++++++++---
rust/kernel/i2c.rs | 13 ++++++---
rust/kernel/mm.rs | 22 ++++++++++++---
rust/kernel/mm/mmput_async.rs | 12 +++++++--
rust/kernel/opp.rs | 16 ++++++++---
rust/kernel/owned.rs | 2 +-
rust/kernel/pci.rs | 10 ++++++-
rust/kernel/pid_namespace.rs | 15 +++++++++--
rust/kernel/platform.rs | 10 ++++++-
rust/kernel/pwm.rs | 12 +++++++--
rust/kernel/sync/aref.rs | 59 +++++++++++++++++++++++++----------------
rust/kernel/task.rs | 13 +++++++--
rust/kernel/types.rs | 12 ++++++---
rust/kernel/usb.rs | 17 +++++++++---
rust/kernel/workqueue.rs | 8 +++---
22 files changed, 260 insertions(+), 77 deletions(-)
diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs
index c42928d5a2393..854525289c8b4 100644
--- a/rust/kernel/auxiliary.rs
+++ b/rust/kernel/auxiliary.rs
@@ -19,6 +19,10 @@
to_result, //
},
prelude::*,
+ sync::aref::{
+ AlwaysRefCounted,
+ RefCounted, //
+ },
types::{
ForLt,
ForeignOwnable,
@@ -344,7 +348,7 @@ unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for Device<Ctx>
kernel::impl_device_context_into_aref!(Device);
// SAFETY: Instances of `Device` are always reference-counted.
-unsafe impl crate::sync::aref::AlwaysRefCounted for Device {
+unsafe impl RefCounted for Device {
fn inc_ref(&self) {
// SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
unsafe { bindings::get_device(self.as_ref().as_raw()) };
@@ -363,6 +367,10 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
}
}
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Device>` from a
+// `&Device`.
+unsafe impl AlwaysRefCounted for Device {}
+
impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> {
fn as_ref(&self) -> &device::Device<Ctx> {
// SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid
diff --git a/rust/kernel/block/mq/request.rs b/rust/kernel/block/mq/request.rs
index ce3e30c81cb5e..8dad15ae4cfb0 100644
--- a/rust/kernel/block/mq/request.rs
+++ b/rust/kernel/block/mq/request.rs
@@ -9,7 +9,11 @@
block::mq::Operations,
error::Result,
sync::{
- aref::{ARef, AlwaysRefCounted},
+ aref::{
+ ARef,
+ AlwaysRefCounted,
+ RefCounted, //
+ },
atomic::Relaxed,
Refcount,
},
@@ -229,11 +233,10 @@ unsafe impl<T: Operations> Send for Request<T> {}
// mutate `self` are internally synchronized`
unsafe impl<T: Operations> Sync for Request<T> {}
-// SAFETY: All instances of `Request<T>` are reference counted. This
-// implementation of `AlwaysRefCounted` ensure that increments to the ref count
-// keeps the object alive in memory at least until a matching reference count
-// decrement is executed.
-unsafe impl<T: Operations> AlwaysRefCounted for Request<T> {
+// SAFETY: All instances of `Request<T>` are reference counted. This implementation of `RefCounted`
+// ensure that increments to the ref count keeps the object alive in memory at least until a
+// matching reference count decrement is executed.
+unsafe impl<T: Operations> RefCounted for Request<T> {
fn inc_ref(&self) {
self.wrapper_ref().refcount().inc();
}
@@ -255,3 +258,7 @@ unsafe fn dec_ref(obj: core::ptr::NonNull<Self>) {
}
}
}
+
+// SAFETY: We currently do not implement `Ownable`, thus it is okay to obtain an `ARef<Request>`
+// from a `&Request` (but this will change in the future).
+unsafe impl<T: Operations> AlwaysRefCounted for Request<T> {}
diff --git a/rust/kernel/cred.rs b/rust/kernel/cred.rs
index ffa156b9df377..b17736a9adcd5 100644
--- a/rust/kernel/cred.rs
+++ b/rust/kernel/cred.rs
@@ -8,7 +8,15 @@
//!
//! Reference: <https://www.kernel.org/doc/html/latest/security/credentials.html>
-use crate::{bindings, sync::aref::AlwaysRefCounted, task::Kuid, types::Opaque};
+use crate::{
+ bindings,
+ sync::aref::RefCounted,
+ task::Kuid,
+ types::{
+ AlwaysRefCounted,
+ Opaque, //
+ }, //
+};
/// Wraps the kernel's `struct cred`.
///
@@ -76,7 +84,7 @@ pub fn euid(&self) -> Kuid {
}
// SAFETY: The type invariants guarantee that `Credential` is always ref-counted.
-unsafe impl AlwaysRefCounted for Credential {
+unsafe impl RefCounted for Credential {
#[inline]
fn inc_ref(&self) {
// SAFETY: The existence of a shared reference means that the refcount is nonzero.
@@ -90,3 +98,7 @@ unsafe fn dec_ref(obj: core::ptr::NonNull<Credential>) {
unsafe { bindings::put_cred(obj.cast().as_ptr()) };
}
}
+
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Credential>` from a
+// `&Credential`.
+unsafe impl AlwaysRefCounted for Credential {}
diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs
index 645afc49a27d6..2e90f6a06fd05 100644
--- a/rust/kernel/device.rs
+++ b/rust/kernel/device.rs
@@ -8,8 +8,12 @@
bindings,
fmt,
prelude::*,
- sync::aref::ARef,
+ sync::aref::{
+ ARef,
+ RefCounted, //
+ },
types::{
+ AlwaysRefCounted,
ForeignOwnable,
Opaque, //
}, //
@@ -448,7 +452,7 @@ pub fn name(&self) -> &CStr {
kernel::impl_device_context_into_aref!(Device);
// SAFETY: Instances of `Device` are always reference-counted.
-unsafe impl crate::sync::aref::AlwaysRefCounted for Device {
+unsafe impl RefCounted for Device {
fn inc_ref(&self) {
// SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
unsafe { bindings::get_device(self.as_raw()) };
@@ -460,6 +464,10 @@ unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
}
}
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Device>` from a
+// `&Device`.
+unsafe impl AlwaysRefCounted for Device {}
+
// SAFETY: As by the type invariant `Device` can be sent to any thread.
unsafe impl Send for Device {}
diff --git a/rust/kernel/device/property.rs b/rust/kernel/device/property.rs
index 5aead835fbbc0..cee7e25013689 100644
--- a/rust/kernel/device/property.rs
+++ b/rust/kernel/device/property.rs
@@ -14,7 +14,10 @@
fmt,
prelude::*,
str::{CStr, CString},
- sync::aref::ARef,
+ sync::aref::{
+ ARef,
+ AlwaysRefCounted, //
+ },
types::Opaque,
};
@@ -360,7 +363,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
// SAFETY: Instances of `FwNode` are always reference-counted.
-unsafe impl crate::sync::aref::AlwaysRefCounted for FwNode {
+unsafe impl crate::sync::aref::RefCounted for FwNode {
fn inc_ref(&self) {
// SAFETY: The existence of a shared reference guarantees that the
// refcount is non-zero.
@@ -374,6 +377,10 @@ unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
}
}
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<FwNode>` from a
+// `&FwNode`.
+unsafe impl AlwaysRefCounted for FwNode {}
+
enum Node<'a> {
Borrowed(&'a FwNode),
Owned(ARef<FwNode>),
diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs
index 403fc35353c74..368742a258376 100644
--- a/rust/kernel/drm/device.rs
+++ b/rust/kernel/drm/device.rs
@@ -15,7 +15,8 @@
prelude::*,
sync::aref::{
ARef,
- AlwaysRefCounted, //
+ AlwaysRefCounted,
+ RefCounted, //
},
types::Opaque,
workqueue::{
@@ -227,7 +228,7 @@ fn deref(&self) -> &Self::Target {
// SAFETY: DRM device objects are always reference counted and the get/put functions
// satisfy the requirements.
-unsafe impl<T: drm::Driver> AlwaysRefCounted for Device<T> {
+unsafe impl<T: drm::Driver> RefCounted for Device<T> {
fn inc_ref(&self) {
// SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
unsafe { bindings::drm_dev_get(self.as_raw()) };
@@ -242,6 +243,10 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
}
}
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Device>` from a
+// `&Device`.
+unsafe impl<T: drm::Driver> AlwaysRefCounted for Device<T> {}
+
impl<T: drm::Driver> AsRef<device::Device> for Device<T> {
fn as_ref(&self) -> &device::Device {
// SAFETY: `bindings::drm_device::dev` is valid as long as the DRM device itself is valid,
diff --git a/rust/kernel/drm/gem/mod.rs b/rust/kernel/drm/gem/mod.rs
index 01b5bd47a3332..30d3718578fe8 100644
--- a/rust/kernel/drm/gem/mod.rs
+++ b/rust/kernel/drm/gem/mod.rs
@@ -17,7 +17,7 @@
prelude::*,
sync::aref::{
ARef,
- AlwaysRefCounted, //
+ RefCounted, //
},
types::Opaque,
};
@@ -29,7 +29,7 @@
#[cfg(CONFIG_RUST_DRM_GEM_SHMEM_HELPER)]
pub mod shmem;
-/// A macro for implementing [`AlwaysRefCounted`] for any GEM object type.
+/// A macro for implementing [`RefCounted`] for any GEM object type.
///
/// Since all GEM objects use the same refcounting scheme.
#[macro_export]
@@ -42,7 +42,7 @@ impl $( <$( $tparam_id:ident ),+> )? for $type:ty
)?
) => {
// SAFETY: All GEM objects are refcounted.
- unsafe impl $( <$( $tparam_id ),+> )? $crate::sync::aref::AlwaysRefCounted for $type
+ unsafe impl $( <$( $tparam_id ),+> )? $crate::sync::aref::RefCounted for $type
where
Self: IntoGEMObject,
$( $( $bind_param : $bind_trait ),+ )?
@@ -61,6 +61,14 @@ unsafe fn dec_ref(obj: core::ptr::NonNull<Self>) {
unsafe { bindings::drm_gem_object_put(obj) };
}
}
+
+ // SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<$type>` from a
+ // `&$type`.
+ unsafe impl $( <$( $tparam_id ),+> )? $crate::sync::aref::AlwaysRefCounted for $type
+ where
+ Self: IntoGEMObject,
+ $( $( $bind_param : $bind_trait ),+ )?
+ {}
};
}
#[cfg_attr(not(CONFIG_RUST_DRM_GEM_SHMEM_HELPER), allow(unused))]
@@ -98,7 +106,7 @@ fn close(_obj: &<Self::Driver as drm::Driver>::Object, _file: &DriverFile<Self>)
}
/// Trait that represents a GEM object subtype
-pub trait IntoGEMObject: Sized + super::private::Sealed + AlwaysRefCounted {
+pub trait IntoGEMObject: Sized + super::private::Sealed + RefCounted {
/// Returns a reference to the raw `drm_gem_object` structure, which must be valid as long as
/// this owning object is valid.
fn as_raw(&self) -> *mut bindings::drm_gem_object;
diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs
index 23ee689bd2400..720e57418358d 100644
--- a/rust/kernel/fs/file.rs
+++ b/rust/kernel/fs/file.rs
@@ -12,8 +12,15 @@
cred::Credential,
error::{code::*, to_result, Error, Result},
fmt,
- sync::aref::{ARef, AlwaysRefCounted},
- types::{NotThreadSafe, Opaque},
+ sync::aref::{
+ ARef,
+ RefCounted, //
+ },
+ types::{
+ AlwaysRefCounted,
+ NotThreadSafe,
+ Opaque, //
+ }, //
};
use core::ptr;
@@ -197,7 +204,7 @@ unsafe impl Sync for File {}
// SAFETY: The type invariants guarantee that `File` is always ref-counted. This implementation
// makes `ARef<File>` own a normal refcount.
-unsafe impl AlwaysRefCounted for File {
+unsafe impl RefCounted for File {
#[inline]
fn inc_ref(&self) {
// SAFETY: The existence of a shared reference means that the refcount is nonzero.
@@ -212,6 +219,10 @@ unsafe fn dec_ref(obj: ptr::NonNull<File>) {
}
}
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<File>` from a
+// `&File`.
+unsafe impl AlwaysRefCounted for File {}
+
/// Wraps the kernel's `struct file`. Not thread safe.
///
/// This type represents a file that is not known to be safe to transfer across thread boundaries.
@@ -233,7 +244,7 @@ pub struct LocalFile {
// SAFETY: The type invariants guarantee that `LocalFile` is always ref-counted. This implementation
// makes `ARef<LocalFile>` own a normal refcount.
-unsafe impl AlwaysRefCounted for LocalFile {
+unsafe impl RefCounted for LocalFile {
#[inline]
fn inc_ref(&self) {
// SAFETY: The existence of a shared reference means that the refcount is nonzero.
@@ -249,6 +260,10 @@ unsafe fn dec_ref(obj: ptr::NonNull<LocalFile>) {
}
}
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<LocalFile>` from a
+// `&LocalFile`.
+unsafe impl AlwaysRefCounted for LocalFile {}
+
impl LocalFile {
/// Constructs a new `struct file` wrapper from a file descriptor.
///
diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs
index 624b971ca8b0b..02b2c9220eb11 100644
--- a/rust/kernel/i2c.rs
+++ b/rust/kernel/i2c.rs
@@ -18,7 +18,8 @@
prelude::*,
sync::aref::{
ARef,
- AlwaysRefCounted, //
+ AlwaysRefCounted,
+ RefCounted, //
},
types::Opaque, //
};
@@ -424,7 +425,7 @@ pub fn get(index: i32) -> Result<ARef<Self>> {
kernel::impl_device_context_into_aref!(I2cAdapter);
// SAFETY: Instances of `I2cAdapter` are always reference-counted.
-unsafe impl AlwaysRefCounted for I2cAdapter {
+unsafe impl RefCounted for I2cAdapter {
fn inc_ref(&self) {
// SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
unsafe { bindings::i2c_get_adapter(self.index()) };
@@ -435,6 +436,9 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
unsafe { bindings::i2c_put_adapter(obj.as_ref().as_raw()) }
}
}
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Device>` from an
+// `&I2cAdapter`.
+unsafe impl AlwaysRefCounted for I2cAdapter {}
/// The i2c board info representation
///
@@ -500,7 +504,7 @@ unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for I2cClient<C
kernel::impl_device_context_into_aref!(I2cClient);
// SAFETY: Instances of `I2cClient` are always reference-counted.
-unsafe impl AlwaysRefCounted for I2cClient {
+unsafe impl RefCounted for I2cClient {
fn inc_ref(&self) {
// SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
unsafe { bindings::get_device(self.as_ref().as_raw()) };
@@ -511,6 +515,9 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
unsafe { bindings::put_device(&raw mut (*obj.as_ref().as_raw()).dev) }
}
}
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Device>` from an
+// `&I2cClient`.
+unsafe impl AlwaysRefCounted for I2cClient {}
impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for I2cClient<Ctx> {
fn as_ref(&self) -> &device::Device<Ctx> {
diff --git a/rust/kernel/mm.rs b/rust/kernel/mm.rs
index 4764d7b68f2a7..83ed94fca14ca 100644
--- a/rust/kernel/mm.rs
+++ b/rust/kernel/mm.rs
@@ -13,8 +13,15 @@
use crate::{
bindings,
- sync::aref::{ARef, AlwaysRefCounted},
- types::{NotThreadSafe, Opaque},
+ sync::aref::{
+ ARef,
+ RefCounted, //
+ },
+ types::{
+ AlwaysRefCounted,
+ NotThreadSafe,
+ Opaque, //
+ }, //
};
use core::{ops::Deref, ptr::NonNull};
@@ -55,7 +62,7 @@ unsafe impl Send for Mm {}
unsafe impl Sync for Mm {}
// SAFETY: By the type invariants, this type is always refcounted.
-unsafe impl AlwaysRefCounted for Mm {
+unsafe impl RefCounted for Mm {
#[inline]
fn inc_ref(&self) {
// SAFETY: The pointer is valid since self is a reference.
@@ -69,6 +76,9 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
}
}
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Mm>` from a `&Mm`.
+unsafe impl AlwaysRefCounted for Mm {}
+
/// A wrapper for the kernel's `struct mm_struct`.
///
/// This type is like [`Mm`], but with non-zero `mm_users`. It can only be used when `mm_users` can
@@ -91,7 +101,7 @@ unsafe impl Send for MmWithUser {}
unsafe impl Sync for MmWithUser {}
// SAFETY: By the type invariants, this type is always refcounted.
-unsafe impl AlwaysRefCounted for MmWithUser {
+unsafe impl RefCounted for MmWithUser {
#[inline]
fn inc_ref(&self) {
// SAFETY: The pointer is valid since self is a reference.
@@ -105,6 +115,10 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
}
}
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<MmWithUser>` from a
+// `&MmWithUser`.
+unsafe impl AlwaysRefCounted for MmWithUser {}
+
// Make all `Mm` methods available on `MmWithUser`.
impl Deref for MmWithUser {
type Target = Mm;
diff --git a/rust/kernel/mm/mmput_async.rs b/rust/kernel/mm/mmput_async.rs
index b8d2f051225c7..8fbc396e46028 100644
--- a/rust/kernel/mm/mmput_async.rs
+++ b/rust/kernel/mm/mmput_async.rs
@@ -10,7 +10,11 @@
use crate::{
bindings,
mm::MmWithUser,
- sync::aref::{ARef, AlwaysRefCounted},
+ sync::aref::{
+ ARef,
+ RefCounted, //
+ },
+ types::AlwaysRefCounted,
};
use core::{ops::Deref, ptr::NonNull};
@@ -34,7 +38,7 @@ unsafe impl Send for MmWithUserAsync {}
unsafe impl Sync for MmWithUserAsync {}
// SAFETY: By the type invariants, this type is always refcounted.
-unsafe impl AlwaysRefCounted for MmWithUserAsync {
+unsafe impl RefCounted for MmWithUserAsync {
#[inline]
fn inc_ref(&self) {
// SAFETY: The pointer is valid since self is a reference.
@@ -48,6 +52,10 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
}
}
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<MmWithUserAsync>`
+// from a `&MmWithUserAsync`.
+unsafe impl AlwaysRefCounted for MmWithUserAsync {}
+
// Make all `MmWithUser` methods available on `MmWithUserAsync`.
impl Deref for MmWithUserAsync {
type Target = MmWithUser;
diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs
index 62e44676125d1..b8db6bdefd077 100644
--- a/rust/kernel/opp.rs
+++ b/rust/kernel/opp.rs
@@ -16,8 +16,14 @@
ffi::{c_char, c_ulong},
prelude::*,
str::CString,
- sync::aref::{ARef, AlwaysRefCounted},
- types::Opaque,
+ sync::aref::{
+ ARef,
+ RefCounted, //
+ },
+ types::{
+ AlwaysRefCounted,
+ Opaque, //
+ }, //
};
#[cfg(CONFIG_CPU_FREQ)]
@@ -1041,7 +1047,7 @@ unsafe impl Send for OPP {}
unsafe impl Sync for OPP {}
/// SAFETY: The type invariants guarantee that [`OPP`] is always refcounted.
-unsafe impl AlwaysRefCounted for OPP {
+unsafe impl RefCounted for OPP {
#[inline]
fn inc_ref(&self) {
// SAFETY: The existence of a shared reference means that the refcount is nonzero.
@@ -1055,6 +1061,10 @@ unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
}
}
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<OPP>` from an
+// `&OPP`.
+unsafe impl AlwaysRefCounted for OPP {}
+
impl OPP {
/// Creates an owned reference to a [`OPP`] from a valid pointer.
///
diff --git a/rust/kernel/owned.rs b/rust/kernel/owned.rs
index 93a5dfcc1e6f5..a156267bf8bb1 100644
--- a/rust/kernel/owned.rs
+++ b/rust/kernel/owned.rs
@@ -27,7 +27,7 @@
///
/// Note: The underlying object is not required to provide internal reference counting, because it
/// represents a unique, owned reference. If reference counting (on the Rust side) is required,
-/// [`AlwaysRefCounted`](crate::sync::aref::AlwaysRefCounted) should be implemented.
+/// [`RefCounted`](crate::types::RefCounted) should be implemented.
///
/// # Examples
///
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index 5071cae6543fd..ea9ef99cecb07 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -19,6 +19,10 @@
},
prelude::*,
str::CStr,
+ sync::aref::{
+ AlwaysRefCounted,
+ RefCounted, //
+ },
types::Opaque,
ThisModule, //
};
@@ -481,7 +485,7 @@ unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for Device<Ctx>
impl<'a> crate::dma::Device<'a> for Device<device::Core<'a>> {}
// SAFETY: Instances of `Device` are always reference-counted.
-unsafe impl crate::sync::aref::AlwaysRefCounted for Device {
+unsafe impl RefCounted for Device {
fn inc_ref(&self) {
// SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
unsafe { bindings::pci_dev_get(self.as_raw()) };
@@ -493,6 +497,10 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
}
}
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Device>` from a
+// `&Device`.
+unsafe impl AlwaysRefCounted for Device {}
+
impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> {
fn as_ref(&self) -> &device::Device<Ctx> {
// SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid
diff --git a/rust/kernel/pid_namespace.rs b/rust/kernel/pid_namespace.rs
index 979a9718f153d..067f68b99e8c5 100644
--- a/rust/kernel/pid_namespace.rs
+++ b/rust/kernel/pid_namespace.rs
@@ -7,7 +7,14 @@
//! C header: [`include/linux/pid_namespace.h`](srctree/include/linux/pid_namespace.h) and
//! [`include/linux/pid.h`](srctree/include/linux/pid.h)
-use crate::{bindings, sync::aref::AlwaysRefCounted, types::Opaque};
+use crate::{
+ bindings,
+ sync::aref::RefCounted,
+ types::{
+ AlwaysRefCounted,
+ Opaque, //
+ }, //
+};
use core::ptr;
/// Wraps the kernel's `struct pid_namespace`. Thread safe.
@@ -41,7 +48,7 @@ pub unsafe fn from_ptr<'a>(ptr: *const bindings::pid_namespace) -> &'a Self {
}
// SAFETY: Instances of `PidNamespace` are always reference-counted.
-unsafe impl AlwaysRefCounted for PidNamespace {
+unsafe impl RefCounted for PidNamespace {
#[inline]
fn inc_ref(&self) {
// SAFETY: The existence of a shared reference means that the refcount is nonzero.
@@ -55,6 +62,10 @@ unsafe fn dec_ref(obj: ptr::NonNull<PidNamespace>) {
}
}
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<PidNamespace>` from
+// a `&PidNamespace`.
+unsafe impl AlwaysRefCounted for PidNamespace {}
+
// SAFETY:
// - `PidNamespace::dec_ref` can be called from any thread.
// - It is okay to send ownership of `PidNamespace` across thread boundaries.
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
index 9b362e0495d32..0ba676445b06d 100644
--- a/rust/kernel/platform.rs
+++ b/rust/kernel/platform.rs
@@ -27,6 +27,10 @@
},
of,
prelude::*,
+ sync::aref::{
+ AlwaysRefCounted,
+ RefCounted, //
+ },
types::Opaque,
ThisModule, //
};
@@ -518,7 +522,7 @@ pub fn optional_irq_by_name(&self, name: &CStr) -> Result<IrqRequest<'_>> {
impl<'a> crate::dma::Device<'a> for Device<device::Core<'a>> {}
// SAFETY: Instances of `Device` are always reference-counted.
-unsafe impl crate::sync::aref::AlwaysRefCounted for Device {
+unsafe impl RefCounted for Device {
fn inc_ref(&self) {
// SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
unsafe { bindings::get_device(self.as_ref().as_raw()) };
@@ -530,6 +534,10 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
}
}
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Device>` from a
+// `&Device`.
+unsafe impl AlwaysRefCounted for Device {}
+
impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> {
fn as_ref(&self) -> &device::Device<Ctx> {
// SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid
diff --git a/rust/kernel/pwm.rs b/rust/kernel/pwm.rs
index 6c9d667009ef7..2d1cd74dd98e1 100644
--- a/rust/kernel/pwm.rs
+++ b/rust/kernel/pwm.rs
@@ -13,7 +13,11 @@
devres,
error::{self, to_result},
prelude::*,
- sync::aref::{ARef, AlwaysRefCounted},
+ sync::aref::{
+ ARef,
+ AlwaysRefCounted,
+ RefCounted, //
+ },
types::Opaque, //
};
use core::{
@@ -629,7 +633,7 @@ pub fn new<'a>(
}
// SAFETY: Implements refcounting for `Chip` using the embedded `struct device`.
-unsafe impl<T: PwmOps> AlwaysRefCounted for Chip<T> {
+unsafe impl<T: PwmOps> RefCounted for Chip<T> {
#[inline]
fn inc_ref(&self) {
// SAFETY: `self.0.get()` points to a valid `pwm_chip` because `self` exists.
@@ -647,6 +651,10 @@ unsafe fn dec_ref(obj: NonNull<Chip<T>>) {
}
}
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Chip<T>>` from a
+// `&Chip<T>`.
+unsafe impl<T: PwmOps> AlwaysRefCounted for Chip<T> {}
+
// SAFETY: `Chip` is a wrapper around `*mut bindings::pwm_chip`. The underlying C
// structure's state is managed and synchronized by the kernel's device model
// and PWM core locking mechanisms. Therefore, it is safe to move the `Chip`
diff --git a/rust/kernel/sync/aref.rs b/rust/kernel/sync/aref.rs
index 3bd5eb8a1a526..ea5a16b8163a6 100644
--- a/rust/kernel/sync/aref.rs
+++ b/rust/kernel/sync/aref.rs
@@ -11,7 +11,7 @@
//! underlying object, but this refcount is internal to the object. It essentially is a Rust
//! implementation of the `get_` and `put_` pattern used in C for reference counting.
//!
-//! To make use of [`ARef<MyType>`], `MyType` needs to implement [`AlwaysRefCounted`]. It is a trait
+//! To make use of [`ARef<MyType>`], `MyType` needs to implement [`RefCounted`]. It is a trait
//! for accessing the internal reference count of an object of the `MyType` type.
//!
//! [`Arc`]: crate::sync::Arc
@@ -24,11 +24,9 @@
ptr::NonNull, //
};
-/// Types that are _always_ reference counted.
+/// Types that are internally reference counted.
///
/// It allows such types to define their own custom ref increment and decrement functions.
-/// Additionally, it allows users to convert from a shared reference `&T` to an owned reference
-/// [`ARef<T>`].
///
/// This is usually implemented by wrappers to existing structures on the C side of the code. For
/// Rust code, the recommendation is to use [`Arc`](crate::sync::Arc) to create reference-counted
@@ -45,9 +43,8 @@
/// at least until matching decrements are performed.
///
/// Implementers must also ensure that all instances are reference-counted. (Otherwise they
-/// won't be able to honour the requirement that [`AlwaysRefCounted::inc_ref`] keep the object
-/// alive.)
-pub unsafe trait AlwaysRefCounted {
+/// won't be able to honour the requirement that [`RefCounted::inc_ref`] keep the object alive.)
+pub unsafe trait RefCounted {
/// Increments the reference count on the object.
fn inc_ref(&self);
@@ -60,11 +57,27 @@ pub unsafe trait AlwaysRefCounted {
/// Callers must ensure that there was a previous matching increment to the reference count,
/// and that the object is no longer used after its reference count is decremented (as it may
/// result in the object being freed), unless the caller owns another increment on the refcount
- /// (e.g., it calls [`AlwaysRefCounted::inc_ref`] twice, then calls
- /// [`AlwaysRefCounted::dec_ref`] once).
+ /// (e.g., it calls [`RefCounted::inc_ref`] twice, then calls [`RefCounted::dec_ref`] once).
unsafe fn dec_ref(obj: NonNull<Self>);
}
+/// Always reference-counted type.
+///
+/// It allows deriving a counted reference [`ARef<T>`] from a `&T`.
+///
+/// This provides some convenience, but it allows "escaping" borrow checks on `&T`. As it
+/// complicates attempts to ensure that a reference to T is unique, it is optional to provide for
+/// [`RefCounted`] types. See *Safety* below.
+///
+/// # Safety
+///
+/// Implementers must ensure that no safety invariants are violated by upgrading an `&T` to an
+/// [`ARef<T>`]. In particular that implies [`AlwaysRefCounted`] and [`crate::types::Ownable`]
+/// cannot be implemented for the same type, as this would allow violating the uniqueness guarantee
+/// of [`crate::types::Owned<T>`] by dereferencing it into an `&T` and obtaining an [`ARef`] from
+/// that.
+pub unsafe trait AlwaysRefCounted: RefCounted {}
+
/// An owned reference to an always-reference-counted object.
///
/// The object's reference count is automatically decremented when an instance of [`ARef`] is
@@ -75,7 +88,7 @@ pub unsafe trait AlwaysRefCounted {
///
/// The pointer stored in `ptr` is non-null and valid for the lifetime of the [`ARef`] instance. In
/// particular, the [`ARef`] instance owns an increment on the underlying object's reference count.
-pub struct ARef<T: AlwaysRefCounted> {
+pub struct ARef<T: RefCounted> {
ptr: NonNull<T>,
_p: PhantomData<T>,
}
@@ -84,19 +97,19 @@ pub struct ARef<T: AlwaysRefCounted> {
// it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally, it needs
// `T` to be `Send` because any thread that has an `ARef<T>` may ultimately access `T` using a
// mutable reference, for example, when the reference count reaches zero and `T` is dropped.
-unsafe impl<T: AlwaysRefCounted + Sync + Send> Send for ARef<T> {}
+unsafe impl<T: RefCounted + Sync + Send> Send for ARef<T> {}
// SAFETY: It is safe to send `&ARef<T>` to another thread when the underlying `T` is `Sync`
// because it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally,
// it needs `T` to be `Send` because any thread that has a `&ARef<T>` may clone it and get an
// `ARef<T>` on that thread, so the thread may ultimately access `T` using a mutable reference, for
// example, when the reference count reaches zero and `T` is dropped.
-unsafe impl<T: AlwaysRefCounted + Sync + Send> Sync for ARef<T> {}
+unsafe impl<T: RefCounted + Sync + Send> Sync for ARef<T> {}
// Even if `T` is pinned, pointers to `T` can still move.
-impl<T: AlwaysRefCounted> Unpin for ARef<T> {}
+impl<T: RefCounted> Unpin for ARef<T> {}
-impl<T: AlwaysRefCounted> ARef<T> {
+impl<T: RefCounted> ARef<T> {
/// Creates a new instance of [`ARef`].
///
/// It takes over an increment of the reference count on the underlying object.
@@ -125,12 +138,12 @@ pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
///
/// ```
/// use core::ptr::NonNull;
- /// use kernel::sync::aref::{ARef, AlwaysRefCounted};
+ /// use kernel::sync::aref::{ARef, RefCounted};
///
/// struct Empty {}
///
/// # // SAFETY: TODO.
- /// unsafe impl AlwaysRefCounted for Empty {
+ /// unsafe impl RefCounted for Empty {
/// fn inc_ref(&self) {}
/// unsafe fn dec_ref(_obj: NonNull<Self>) {}
/// }
@@ -148,7 +161,7 @@ pub fn into_raw(me: Self) -> NonNull<T> {
}
}
-impl<T: AlwaysRefCounted> Clone for ARef<T> {
+impl<T: RefCounted> Clone for ARef<T> {
fn clone(&self) -> Self {
self.inc_ref();
// SAFETY: We just incremented the refcount above.
@@ -156,7 +169,7 @@ fn clone(&self) -> Self {
}
}
-impl<T: AlwaysRefCounted> Deref for ARef<T> {
+impl<T: RefCounted> Deref for ARef<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
@@ -173,7 +186,7 @@ fn from(b: &T) -> Self {
}
}
-impl<T: AlwaysRefCounted> Drop for ARef<T> {
+impl<T: RefCounted> Drop for ARef<T> {
fn drop(&mut self) {
// SAFETY: The type invariants guarantee that the `ARef` owns the reference we're about to
// decrement.
@@ -183,19 +196,19 @@ fn drop(&mut self) {
impl<T, U> PartialEq<ARef<U>> for ARef<T>
where
- T: AlwaysRefCounted + PartialEq<U>,
- U: AlwaysRefCounted,
+ T: RefCounted + PartialEq<U>,
+ U: RefCounted,
{
#[inline]
fn eq(&self, other: &ARef<U>) -> bool {
T::eq(&**self, &**other)
}
}
-impl<T: AlwaysRefCounted + Eq> Eq for ARef<T> {}
+impl<T: RefCounted + Eq> Eq for ARef<T> {}
impl<T, U> PartialEq<&'_ U> for ARef<T>
where
- T: AlwaysRefCounted + PartialEq<U>,
+ T: RefCounted + PartialEq<U>,
{
#[inline]
fn eq(&self, other: &&U) -> bool {
diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs
index 38273f4eedb51..6259430b0ca31 100644
--- a/rust/kernel/task.rs
+++ b/rust/kernel/task.rs
@@ -10,7 +10,12 @@
pid_namespace::PidNamespace,
prelude::*,
sync::aref::ARef,
- types::{NotThreadSafe, Opaque},
+ types::{
+ AlwaysRefCounted,
+ NotThreadSafe,
+ Opaque,
+ RefCounted, //
+ },
};
use core::{
ops::Deref,
@@ -347,7 +352,7 @@ pub fn group_leader(&self) -> &Task {
}
// SAFETY: The type invariants guarantee that `Task` is always refcounted.
-unsafe impl crate::sync::aref::AlwaysRefCounted for Task {
+unsafe impl RefCounted for Task {
#[inline]
fn inc_ref(&self) {
// SAFETY: The existence of a shared reference means that the refcount is nonzero.
@@ -361,6 +366,10 @@ unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
}
}
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Task>` from a
+// `&Task`.
+unsafe impl AlwaysRefCounted for Task {}
+
impl PartialEq for Task {
#[inline]
fn eq(&self, other: &Self) -> bool {
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index c41eab0ec983c..5ef763717e59a 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -15,9 +15,15 @@
pub mod for_lt;
pub use for_lt::ForLt;
-pub use crate::owned::{
- Ownable,
- Owned, //
+pub use crate::{
+ owned::{
+ Ownable,
+ Owned, //
+ },
+ sync::aref::{
+ AlwaysRefCounted,
+ RefCounted, //
+ }, //
};
/// Used to transfer ownership to and from foreign (non-Rust) languages.
diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs
index 7aff0c82d0afc..59350c6b0df2a 100644
--- a/rust/kernel/usb.rs
+++ b/rust/kernel/usb.rs
@@ -18,7 +18,10 @@
to_result, //
},
prelude::*,
- sync::aref::AlwaysRefCounted,
+ sync::aref::{
+ AlwaysRefCounted,
+ RefCounted, //
+ },
types::Opaque,
ThisModule, //
};
@@ -392,7 +395,7 @@ fn as_ref(&self) -> &Device {
}
// SAFETY: Instances of `Interface` are always reference-counted.
-unsafe impl AlwaysRefCounted for Interface {
+unsafe impl RefCounted for Interface {
fn inc_ref(&self) {
// SAFETY: The invariants of `Interface` guarantee that `self.as_raw()`
// returns a valid `struct usb_interface` pointer, for which we will
@@ -406,6 +409,10 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
}
}
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Interface>` from a
+// `&Interface`.
+unsafe impl AlwaysRefCounted for Interface {}
+
// SAFETY: A `Interface` is always reference-counted and can be released from any thread.
unsafe impl Send for Interface {}
@@ -443,7 +450,7 @@ fn as_raw(&self) -> *mut bindings::usb_device {
kernel::impl_device_context_into_aref!(Device);
// SAFETY: Instances of `Device` are always reference-counted.
-unsafe impl AlwaysRefCounted for Device {
+unsafe impl RefCounted for Device {
fn inc_ref(&self) {
// SAFETY: The invariants of `Device` guarantee that `self.as_raw()`
// returns a valid `struct usb_device` pointer, for which we will
@@ -457,6 +464,10 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
}
}
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Device>` from a
+// `&Device`.
+unsafe impl AlwaysRefCounted for Device {}
+
impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> {
fn as_ref(&self) -> &device::Device<Ctx> {
// SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid
diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs
index 7e253b6f299ce..77673b8ea45fb 100644
--- a/rust/kernel/workqueue.rs
+++ b/rust/kernel/workqueue.rs
@@ -192,7 +192,7 @@
sync::{
aref::{
ARef,
- AlwaysRefCounted, //
+ RefCounted, //
},
Arc,
LockClassKey, //
@@ -954,7 +954,7 @@ unsafe impl<T, const ID: u64> RawDelayedWorkItem<ID> for Pin<KBox<T>>
// implementation of `WorkItemPointer` for `ARef<T>`.
unsafe impl<T, const ID: u64> WorkItemPointer<ID> for ARef<T>
where
- T: AlwaysRefCounted,
+ T: RefCounted,
T: WorkItem<ID, Pointer = Self>,
T: HasWork<T, ID>,
{
@@ -987,7 +987,7 @@ unsafe impl<T, const ID: u64> WorkItemPointer<ID> for ARef<T>
// requirements of `WorkItemPointer`.
unsafe impl<T, const ID: u64> RawWorkItem<ID> for ARef<T>
where
- T: AlwaysRefCounted,
+ T: RefCounted,
T: WorkItem<ID, Pointer = Self>,
T: HasWork<T, ID>,
{
@@ -1020,7 +1020,7 @@ unsafe impl<T, const ID: u64> RawDelayedWorkItem<ID> for ARef<T>
where
T: WorkItem<ID, Pointer = Self>,
T: HasDelayedWork<T, ID>,
- T: AlwaysRefCounted,
+ T: RefCounted,
{
}
--
2.51.2
^ permalink raw reply related
* [PATCH v19 3/8] rust: implement `ForeignOwnable` for `Owned`
From: Andreas Hindborg @ 2026-06-26 11:54 UTC (permalink / raw)
To: Danilo Krummrich, Lorenzo Stoakes, Vlastimil Babka,
Liam R. Howlett, Uladzislau Rezki, Miguel Ojeda, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Alice Ryhl,
Trevor Gross, Daniel Almeida, Tamir Duberstein, Alexandre Courbot,
Onur Özkan, Lyude Paul, Greg Kroah-Hartman,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas, Rafael J. Wysocki, Dave Ertman, Ira Weiny,
Leon Romanovsky, Paul Moore, Serge Hallyn, David Airlie,
Simona Vetter, Alexander Viro, Jan Kara, Igor Korotin,
Viresh Kumar, Nishanth Menon, Stephen Boyd, Bjorn Helgaas,
Krzysztof Wilczyński, Pavel Tikhomirov, Michal Wilczynski
Cc: Andreas Hindborg, Philipp Stanner, rust-for-linux, linux-kernel,
linux-mm, driver-core, linux-block, linux-security-module,
dri-devel, linux-fsdevel, linux-pm, linux-pci, linux-pwm
In-Reply-To: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org>
Implement `ForeignOwnable` for `Owned<T>`. This allows use of `Owned<T>` in
places such as the `XArray`.
Note that `T` does not need to implement `ForeignOwnable` for `Owned<T>` to
implement `ForeignOwnable`.
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
---
rust/kernel/owned.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 50 insertions(+)
diff --git a/rust/kernel/owned.rs b/rust/kernel/owned.rs
index 7fe9ec3e55126..93a5dfcc1e6f5 100644
--- a/rust/kernel/owned.rs
+++ b/rust/kernel/owned.rs
@@ -15,6 +15,8 @@
ptr::NonNull, //
};
+use kernel::types::ForeignOwnable;
+
/// Types that specify their own way of performing allocation and destruction. Typically, this trait
/// is implemented on types from the C side.
///
@@ -186,3 +188,51 @@ fn drop(&mut self) {
unsafe { T::release(self.ptr) };
}
}
+
+// SAFETY: We derive the pointer to `T` from a valid `T`, so the returned
+// pointer satisfy alignment requirements of `T`.
+unsafe impl<T: Ownable> ForeignOwnable for Owned<T> {
+ const FOREIGN_ALIGN: usize = core::mem::align_of::<T>();
+
+ type Borrowed<'a>
+ = &'a T
+ where
+ Self: 'a;
+ type BorrowedMut<'a>
+ = Pin<&'a mut T>
+ where
+ Self: 'a;
+
+ #[inline]
+ fn into_foreign(self) -> *mut kernel::ffi::c_void {
+ Owned::into_raw(self).as_ptr().cast()
+ }
+
+ #[inline]
+ unsafe fn from_foreign(ptr: *mut kernel::ffi::c_void) -> Self {
+ // SAFETY: By function safety contract, `ptr` came from `into_foreign` and cannot be null.
+ let ptr = unsafe { NonNull::new_unchecked(ptr.cast()) };
+
+ // SAFETY: By the function safety contract, `ptr` was returned by `into_foreign`, which gave
+ // up exclusive ownership of a valid, pinned `T`; we retake that ownership here.
+ unsafe { Owned::from_raw(ptr) }
+ }
+
+ #[inline]
+ unsafe fn borrow<'a>(ptr: *mut kernel::ffi::c_void) -> Self::Borrowed<'a> {
+ // SAFETY: By function safety requirements, `ptr` is valid for use as a
+ // reference for `'a`.
+ unsafe { &*ptr.cast() }
+ }
+
+ #[inline]
+ unsafe fn borrow_mut<'a>(ptr: *mut kernel::ffi::c_void) -> Self::BorrowedMut<'a> {
+ // SAFETY: By function safety requirements, `ptr` is valid for use as a
+ // unique reference for `'a`.
+ let inner = unsafe { &mut *ptr.cast() };
+
+ // SAFETY: We never move out of inner, and we do not hand out mutable
+ // references when `T: !Unpin`.
+ unsafe { Pin::new_unchecked(inner) }
+ }
+}
--
2.51.2
^ permalink raw reply related
* [PATCH v19 0/8] rust: add `Ownable` trait and `Owned` type
From: Andreas Hindborg @ 2026-06-26 11:53 UTC (permalink / raw)
To: Danilo Krummrich, Lorenzo Stoakes, Vlastimil Babka,
Liam R. Howlett, Uladzislau Rezki, Miguel Ojeda, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Alice Ryhl,
Trevor Gross, Daniel Almeida, Tamir Duberstein, Alexandre Courbot,
Onur Özkan, Lyude Paul, Greg Kroah-Hartman,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas, Rafael J. Wysocki, Dave Ertman, Ira Weiny,
Leon Romanovsky, Paul Moore, Serge Hallyn, David Airlie,
Simona Vetter, Alexander Viro, Jan Kara, Igor Korotin,
Viresh Kumar, Nishanth Menon, Stephen Boyd, Bjorn Helgaas,
Krzysztof Wilczyński, Pavel Tikhomirov, Michal Wilczynski
Cc: Andreas Hindborg, Philipp Stanner, rust-for-linux, linux-kernel,
linux-mm, driver-core, linux-block, linux-security-module,
dri-devel, linux-fsdevel, linux-pm, linux-pci, linux-pwm,
Asahi Lina, Oliver Mangold, Viresh Kumar, Boqun Feng, Asahi Lina,
Igor Korotin, Andreas Hindborg
Add a new trait `Ownable` and type `Owned` for types that specify their
own way of performing allocation and destruction. This is useful for
types from the C side.
Implement `ForeignOwnable` for `Owned`.
Convert `Page` to be `Ownable` and add a `from_raw` method.
Add the trait `OwnableRefCounted` that allows conversion between
`ARef` and `Owned`. This is analogous to conversion between `Arc` and
`UniqueArc`.
Patches 1-4 implement `Ownable` and applies it to `Page`. These patches
can be merged on their own.
Patches 5-7 add `Ownable` -> `ARef` interop and can be merged later if
consensus on their shape cannot be reached.
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
Changes in v19:
- Update `workqueue.rs` and the `aref` module docs to use `RefCounted` instead of `AlwaysRefCounted` (Sashiko).
- Remove the default `OwnableRefCounted::into_shared` implementation to keep the trait safe (Sashiko).
- Fix the `ARef<Self>` rustdoc link (Sashiko).
- Reuse `Owned::into_raw`/`from_raw` in the `ForeignOwnable` implementation (Gary).
- Link to v18: https://msgid.link/20260625-unique-ref-v18-0-4e06b5896d47@kernel.org
Changes in v18:
- Rebase on `rust-next` (2026-06-24).
- Drop the `'static` bound on `ForeignOwnable for Owned` (Gary).
- Make `Ownable::release` take a raw pointer instead of `&mut self` (Alice, Sashiko).
- Drop `types::ARef` re-export (Alice).
- Drop unneeded `#[repr(transparent)]` on `Owned` (Gary).
- Fix `FOREIGN_ALIGN` for `Owned` to report the pointee alignment (Sashiko).
- Remove `BorrowedPage`; use `&Page` directly (Alice).
- Update Rust Binder for the `Owned<Page>` conversion (Alice).
- Update `pwm.rs` for the `RefCounted`/`AlwaysRefCounted` split (Sashiko).
- Fix documentation nits: missing `// INVARIANT:` comments, stale `Page` docs, and a stray `mut` (Sashiko).
- Expand the `use` statements touched by the rename patch to the multi-line style (Onur).
- Link to v17: https://msgid.link/20260604-unique-ref-v17-0-7b4c3d2930b9@kernel.org
Changes in v17:
- Rebase on v7.1-rc2.
- Reorder patches so that `Ownable` can merge without `OwnableRefCounted` (Alice).
- Add `#[inline]` directives to short functions added by the series (Gary).
- Link to v16: https://msgid.link/20260224-unique-ref-v16-0-c21afcb118d3@kernel.org
Changes in v16:
- Simplify pointer to reference cast in `Page::from_raw`.
- Use `NonNull<Page>` rather than `Owned<Page>` for `BorrowedPage` internals.
- Use "convertible to reference" wording when converting pointers to references.
- Fix formatting for `Page::from_raw` docs.
- Leave imports alone when adding safety comment to aref example.
- Use `KBox::into_nonnull` for examples.
- Add patch for `KBox::into_nonnull`.
- Change invariants and safety comments of `Ownable` and make the trait safe.
- Make `Ownable::release` take a mutable reference.
- Fix error handling in example for `Ownable`
- Link to v15: https://msgid.link/20260220-unique-ref-v15-0-893ed86b06cc@kernel.org
Changes in v15:
- Update series with original SoB's.
- Rename `AlwaysRefCounted` in `kernel::usb`.
- Rename `Owned::get_pin_mut` to `Owned::as_pin_mut`.
- Link to v14: https://msgid.link/20260204-unique-ref-v14-0-17cb29ebacbb@kernel.org
Changes in v14:
- Rebase on v6.19-rc7.
- Rewrite cover letter.
- Update documentation and safety comments based on v13 feedback.
- Update commit messages.
- Reorder implementation blocks in owned.rs.
- Update example in owned.rs to use try operator rather than `expect`.
- Reformat use statements.
- Add patch: rust: page: convert to `Ownable`.
- Add patch: rust: implement `ForeignOwnable` for `Owned`.
- Add patch: rust: page: add `from_raw()`.
- Link to v13: https://lore.kernel.org/r/20251117-unique-ref-v13-0-b5b243df1250@pm.me
Changes in v13:
- Rebase onto v6.18-rc1 (Andreas's work).
- Documentation and style fixes contributed by Andreas
- Link to v12: https://lore.kernel.org/r/20251001-unique-ref-v12-0-fa5c31f0c0c4@pm.me
Changes in v12:
-
- Rebase onto v6.17-rc1 (Andreas's work).
- moved kernel/types/ownable.rs to kernel/owned.rs
- Drop OwnableMut, make DerefMut depend on Unpin instead. I understood
ML discussion as that being okay, but probably needs further scrunity.
- Lots of more documentation changes suggested by reviewers.
- Usage example for Ownable/Owned.
- Link to v11: https://lore.kernel.org/r/20250618-unique-ref-v11-0-49eadcdc0aa6@pm.me
Changes in v11:
- Rework of documentation. I tried to honor all requests for changes "in
spirit" plus some clearifications and corrections of my own.
- Dropping `SimpleOwnedRefCounted` by request from Alice, as it creates a
potentially problematic blanket implementation (which a derive macro that
could be created later would not have).
- Dropping Miguel's "kbuild: provide `RUSTC_HAS_DO_NOT_RECOMMEND` symbol"
patch, as it is not needed anymore after dropping `SimpleOwnedRefCounted`.
(I can add it again, if it is considered useful anyway).
- Link to v10: https://lore.kernel.org/r/20250502-unique-ref-v10-0-25de64c0307f@pm.me
Changes in v10:
- Moved kernel/ownable.rs to kernel/types/ownable.rs
- Fixes in documentation / comments as suggested by Andreas Hindborg
- Added Reviewed-by comment for Andreas Hindborg
- Fix rustfmt of pid_namespace.rs
- Link to v9: https://lore.kernel.org/r/20250325-unique-ref-v9-0-e91618c1de26@pm.me
Changes in v9:
- Rebase onto v6.14-rc7
- Move Ownable/OwnedRefCounted/Ownable, etc., into separate module
- Documentation fixes to Ownable/OwnableMut/OwnableRefCounted
- Add missing SAFETY documentation to ARef example
- Link to v8: https://lore.kernel.org/r/20250313-unique-ref-v8-0-3082ffc67a31@pm.me
Changes in v8:
- Fix Co-developed-by and Suggested-by tags as suggested by Miguel and Boqun
- Some small documentation fixes in Owned/Ownable patch
- removing redundant trait constraint on DerefMut for Owned as suggested by Boqun Feng
- make SimpleOwnedRefCounted no longer implement RefCounted as suggested by Boqun Feng
- documentation for RefCounted as suggested by Boqun Feng
- Link to v7: https://lore.kernel.org/r/20250310-unique-ref-v7-0-4caddb78aa05@pm.me
Changes in v7:
- Squash patch to make Owned::from_raw/into_raw public into parent
- Added Signed-off-by to other people's commits
- Link to v6: https://lore.kernel.org/r/20250310-unique-ref-v6-0-1ff53558617e@pm.me
Changes in v6:
- Changed comments/formatting as suggested by Miguel Ojeda
- Included and used new config flag RUSTC_HAS_DO_NOT_RECOMMEND,
thus no changes to types.rs will be needed when the attribute
becomes available.
- Fixed commit message for Owned patch.
- Link to v5: https://lore.kernel.org/r/20250307-unique-ref-v5-0-bffeb633277e@pm.me
Changes in v5:
- Rebase the whole thing on top of the Ownable/Owned traits by Asahi Lina.
- Rename AlwaysRefCounted to RefCounted and make AlwaysRefCounted a
marker trait instead to allow to obtain an ARef<T> from an &T,
which (as Alice pointed out) is unsound when combined with UniqueRef/Owned.
- Change the Trait design and naming to implement this feature,
UniqueRef/UniqueRefCounted is dropped in favor of Ownable/Owned and
OwnableRefCounted is used to provide the functions to convert
between Owned and ARef.
- Link to v4: https://lore.kernel.org/r/20250305-unique-ref-v4-1-a8fdef7b1c2c@pm.me
Changes in v4:
- Just a minor change in naming by request from Andreas Hindborg,
try_shared_to_unique() -> try_from_shared(),
unique_to_shared() -> into_shared(),
which is more in line with standard Rust naming conventions.
- Link to v3: https://lore.kernel.org/r/Z8Wuud2UQX6Yukyr@mango
To: Danilo Krummrich <dakr@kernel.org>
To: Lorenzo Stoakes <ljs@kernel.org>
To: Vlastimil Babka <vbabka@kernel.org>
To: "Liam R. Howlett" <liam@infradead.org>
To: Uladzislau Rezki <urezki@gmail.com>
To: Miguel Ojeda <ojeda@kernel.org>
To: Boqun Feng <boqun@kernel.org>
To: Gary Guo <gary@garyguo.net>
To: Björn Roy Baron <bjorn3_gh@protonmail.com>
To: Benno Lossin <lossin@kernel.org>
To: Andreas Hindborg <a.hindborg@kernel.org>
To: Alice Ryhl <aliceryhl@google.com>
To: Trevor Gross <tmgross@umich.edu>
To: Daniel Almeida <daniel.almeida@collabora.com>
To: Tamir Duberstein <tamird@kernel.org>
To: Alexandre Courbot <acourbot@nvidia.com>
To: Onur Özkan <work@onurozkan.dev>
To: Lyude Paul <lyude@redhat.com>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: Arve Hjønnevåg <arve@android.com>
To: Todd Kjos <tkjos@android.com>
To: Christian Brauner <brauner@kernel.org>
To: Carlos Llamas <cmllamas@google.com>
To: "Rafael J. Wysocki" <rafael@kernel.org>
To: Dave Ertman <david.m.ertman@intel.com>
To: Ira Weiny <ira.weiny@intel.com>
To: Leon Romanovsky <leon@kernel.org>
To: Paul Moore <paul@paul-moore.com>
To: Serge Hallyn <sergeh@kernel.org>
To: David Airlie <airlied@gmail.com>
To: Simona Vetter <simona@ffwll.ch>
To: Alexander Viro <viro@zeniv.linux.org.uk>
To: Jan Kara <jack@suse.cz>
To: Igor Korotin <igor.korotin@linux.dev>
To: Viresh Kumar <vireshk@kernel.org>
To: Nishanth Menon <nm@ti.com>
To: Stephen Boyd <sboyd@kernel.org>
To: Bjorn Helgaas <bhelgaas@google.com>
To: Krzysztof Wilczyński <kwilczynski@kernel.org>
To: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
To: Michal Wilczynski <m.wilczynski@samsung.com>
Cc: Philipp Stanner <phasta@kernel.org>
Cc: rust-for-linux@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-mm@kvack.org
Cc: driver-core@lists.linux.dev
Cc: linux-block@vger.kernel.org
Cc: linux-security-module@vger.kernel.org
Cc: dri-devel@lists.freedesktop.org
Cc: linux-fsdevel@vger.kernel.org
Cc: linux-pm@vger.kernel.org
Cc: linux-pci@vger.kernel.org
Cc: linux-pwm@vger.kernel.org
---
Andreas Hindborg (3):
rust: alloc: add `KBox::into_non_null`
rust: implement `ForeignOwnable` for `Owned`
rust: page: add `from_raw()`
Asahi Lina (2):
rust: types: Add Ownable/Owned types
rust: page: convert to `Ownable`
Oliver Mangold (3):
rust: rename `AlwaysRefCounted` to `RefCounted`.
rust: Add missing SAFETY documentation for `ARef` example
rust: Add `OwnableRefCounted`
drivers/android/binder/page_range.rs | 10 +-
rust/kernel/alloc/allocator.rs | 19 +-
rust/kernel/alloc/allocator/iter.rs | 6 +-
rust/kernel/alloc/kbox.rs | 9 +
rust/kernel/auxiliary.rs | 10 +-
rust/kernel/block/mq/request.rs | 19 +-
rust/kernel/cred.rs | 16 +-
rust/kernel/device.rs | 12 +-
rust/kernel/device/property.rs | 11 +-
rust/kernel/drm/device.rs | 9 +-
rust/kernel/drm/gem/mod.rs | 16 +-
rust/kernel/fs/file.rs | 23 ++-
rust/kernel/i2c.rs | 13 +-
rust/kernel/lib.rs | 1 +
rust/kernel/mm.rs | 22 ++-
rust/kernel/mm/mmput_async.rs | 12 +-
rust/kernel/opp.rs | 16 +-
rust/kernel/owned.rs | 373 +++++++++++++++++++++++++++++++++++
rust/kernel/page.rs | 136 +++++--------
rust/kernel/pci.rs | 10 +-
rust/kernel/pid_namespace.rs | 15 +-
rust/kernel/platform.rs | 10 +-
rust/kernel/pwm.rs | 12 +-
rust/kernel/sync/aref.rs | 84 +++++---
rust/kernel/task.rs | 13 +-
rust/kernel/types.rs | 12 ++
rust/kernel/usb.rs | 17 +-
rust/kernel/workqueue.rs | 8 +-
28 files changed, 728 insertions(+), 186 deletions(-)
---
base-commit: 43a393185e33e573a374c1d4f7ddf6481484ef8d
change-id: 20250305-unique-ref-29fcd675f9e9
Best regards,
--
Andreas Hindborg <a.hindborg@kernel.org>
^ permalink raw reply
* [PATCH v19 2/8] rust: types: Add Ownable/Owned types
From: Andreas Hindborg @ 2026-06-26 11:53 UTC (permalink / raw)
To: Danilo Krummrich, Lorenzo Stoakes, Vlastimil Babka,
Liam R. Howlett, Uladzislau Rezki, Miguel Ojeda, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Alice Ryhl,
Trevor Gross, Daniel Almeida, Tamir Duberstein, Alexandre Courbot,
Onur Özkan, Lyude Paul, Greg Kroah-Hartman,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas, Rafael J. Wysocki, Dave Ertman, Ira Weiny,
Leon Romanovsky, Paul Moore, Serge Hallyn, David Airlie,
Simona Vetter, Alexander Viro, Jan Kara, Igor Korotin,
Viresh Kumar, Nishanth Menon, Stephen Boyd, Bjorn Helgaas,
Krzysztof Wilczyński, Pavel Tikhomirov, Michal Wilczynski
Cc: Andreas Hindborg, Philipp Stanner, rust-for-linux, linux-kernel,
linux-mm, driver-core, linux-block, linux-security-module,
dri-devel, linux-fsdevel, linux-pm, linux-pci, linux-pwm,
Asahi Lina, Oliver Mangold, Boqun Feng
In-Reply-To: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org>
From: Asahi Lina <lina+kernel@asahilina.net>
By analogy to `AlwaysRefCounted` and `ARef`, an `Ownable` type is a
(typically C FFI) type that *may* be owned by Rust, but need not be. Unlike
`AlwaysRefCounted`, this mechanism expects the reference to be unique
within Rust, and does not allow cloning.
Conceptually, this is similar to a `KBox<T>`, except that it delegates
resource management to the `T` instead of using a generic allocator.
[ om:
- Split code into separate file and `pub use` it from types.rs.
- Make from_raw() and into_raw() public.
- Remove OwnableMut, and make DerefMut dependent on Unpin instead.
- Usage example/doctest for Ownable/Owned.
- Fixes to documentation and commit message.
]
Link: https://lore.kernel.org/all/20250202-rust-page-v1-1-e3170d7fe55e@asahilina.net/
Signed-off-by: Asahi Lina <lina+kernel@asahilina.net>
Co-developed-by: Oliver Mangold <oliver.mangold@pm.me>
Signed-off-by: Oliver Mangold <oliver.mangold@pm.me>
Reviewed-by: Boqun Feng <boqun.feng@gmail.com>
Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
Reviewed-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
[ Andreas: Updated documentation, examples, and formatting. Change safety
requirements, safety comments. ]
Co-developed-by: Andreas Hindborg <a.hindborg@kernel.org>
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/lib.rs | 1 +
rust/kernel/owned.rs | 188 +++++++++++++++++++++++++++++++++++++++++++++++
rust/kernel/sync/aref.rs | 5 ++
rust/kernel/types.rs | 5 ++
4 files changed, 199 insertions(+)
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 9512af7156df2..eb5256204a174 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -101,6 +101,7 @@
pub mod of;
#[cfg(CONFIG_PM_OPP)]
pub mod opp;
+pub mod owned;
pub mod page;
#[cfg(CONFIG_PCI)]
pub mod pci;
diff --git a/rust/kernel/owned.rs b/rust/kernel/owned.rs
new file mode 100644
index 0000000000000..7fe9ec3e55126
--- /dev/null
+++ b/rust/kernel/owned.rs
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Unique owned pointer types for objects with custom drop logic.
+//!
+//! These pointer types are useful for C-allocated objects which by API-contract
+//! are owned by Rust, but need to be freed through the C API.
+
+use core::{
+ mem::ManuallyDrop,
+ ops::{
+ Deref,
+ DerefMut, //
+ },
+ pin::Pin,
+ ptr::NonNull, //
+};
+
+/// Types that specify their own way of performing allocation and destruction. Typically, this trait
+/// is implemented on types from the C side.
+///
+/// Implementing this trait allows types to be referenced via the [`Owned<Self>`] pointer type. This
+/// is useful when it is desirable to tie the lifetime of the reference to an owned object, rather
+/// than pass around a bare reference. [`Ownable`] types can define custom drop logic that is
+/// executed when the owned reference [`Owned<Self>`] pointing to the object is dropped.
+///
+/// Note: The underlying object is not required to provide internal reference counting, because it
+/// represents a unique, owned reference. If reference counting (on the Rust side) is required,
+/// [`AlwaysRefCounted`](crate::sync::aref::AlwaysRefCounted) should be implemented.
+///
+/// # Examples
+///
+/// A minimal example implementation of [`Ownable`] and its usage with [`Owned`] looks like
+/// this:
+///
+/// ```
+/// # #![expect(clippy::disallowed_names)]
+/// # use core::cell::Cell;
+/// # use core::ptr::NonNull;
+/// # use kernel::sync::global_lock;
+/// # use kernel::alloc::{flags, kbox::KBox, AllocError};
+/// # use kernel::types::{Owned, Ownable};
+///
+/// // Let's count the allocations to see if freeing works.
+/// kernel::sync::global_lock! {
+/// // SAFETY: we call `init()` right below, before doing anything else.
+/// unsafe(uninit) static FOO_ALLOC_COUNT: Mutex<usize> = 0;
+/// }
+/// // SAFETY: We call `init()` only once, here.
+/// unsafe { FOO_ALLOC_COUNT.init() };
+///
+/// struct Foo;
+///
+/// impl Foo {
+/// fn new() -> Result<Owned<Self>> {
+/// // We are just using a `KBox` here to handle the actual allocation, as our `Foo` is
+/// // not actually a C-allocated object.
+/// let result = KBox::new(
+/// Foo {},
+/// flags::GFP_KERNEL,
+/// )?;
+/// let result = KBox::into_non_null(result);
+/// // Count new allocation
+/// *FOO_ALLOC_COUNT.lock() += 1;
+/// // SAFETY:
+/// // - We just allocated the `Self`, thus it is valid and we own it.
+/// // - We can transfer this ownership to the `from_raw` method.
+/// Ok(unsafe { Owned::from_raw(result) })
+/// }
+/// }
+///
+/// impl Ownable for Foo {
+/// unsafe fn release(this: NonNull<Self>) {
+/// // SAFETY: The [`KBox<Self>`] is still alive. We can pass ownership to the [`KBox`], as
+/// // by requirement on calling this function.
+/// drop(unsafe { KBox::from_raw(this.as_ptr()) });
+/// // Count released allocation
+/// *FOO_ALLOC_COUNT.lock() -= 1;
+/// }
+/// }
+///
+/// {
+/// let foo = Foo::new()?;
+/// assert!(*FOO_ALLOC_COUNT.lock() == 1);
+/// }
+/// // `foo` is out of scope now, so we expect no live allocations.
+/// assert!(*FOO_ALLOC_COUNT.lock() == 0);
+/// # Ok::<(), Error>(())
+/// ```
+pub trait Ownable {
+ /// Tear down this `Ownable`.
+ ///
+ /// Implementers of `Ownable` can use this function to clean up the use of `Self`. This can
+ /// include freeing the underlying object.
+ ///
+ /// # Safety
+ ///
+ /// Callers must ensure that they have exclusive ownership of the `Self` pointed to by `this`,
+ /// and that this ownership is transferred to the `release` method. `this` must not be used
+ /// after calling this method, as the underlying object may have been freed.
+ unsafe fn release(this: NonNull<Self>);
+}
+
+/// A mutable reference to an owned `T`.
+///
+/// The [`Ownable`] is automatically freed or released when an instance of [`Owned`] is
+/// dropped.
+///
+/// # Invariants
+///
+/// - Until `T::release` is called, this `Owned<T>` exclusively owns the underlying `T`.
+/// - The `T` value is pinned.
+pub struct Owned<T: Ownable> {
+ ptr: NonNull<T>,
+}
+
+impl<T: Ownable> Owned<T> {
+ /// Creates a new instance of [`Owned`].
+ ///
+ /// This function takes over ownership of the underlying object.
+ ///
+ /// # Safety
+ ///
+ /// Callers must ensure that:
+ /// - `ptr` points to a valid instance of `T`.
+ /// - Until `T::release` is called, the returned `Owned<T>` exclusively owns the underlying `T`.
+ #[inline]
+ pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
+ // INVARIANT: By function safety requirement we satisfy the first invariant of `Self`.
+ // We treat `T` as pinned from now on.
+ Self { ptr }
+ }
+
+ /// Consumes the [`Owned`], returning a raw pointer.
+ ///
+ /// This function does not drop the underlying `T`. When this function returns, ownership of the
+ /// underlying `T` is with the caller.
+ #[inline]
+ pub fn into_raw(me: Self) -> NonNull<T> {
+ ManuallyDrop::new(me).ptr
+ }
+
+ /// Get a pinned mutable reference to the data owned by this `Owned<T>`.
+ #[inline]
+ pub fn as_pin_mut(&mut self) -> Pin<&mut T> {
+ // SAFETY: The type invariants guarantee that the object is valid, and that we can safely
+ // return a mutable reference to it.
+ let unpinned = unsafe { self.ptr.as_mut() };
+
+ // SAFETY: By type invariant `T` is pinned.
+ unsafe { Pin::new_unchecked(unpinned) }
+ }
+}
+
+// SAFETY: It is safe to send an [`Owned<T>`] to another thread when the underlying `T` is [`Send`],
+// because of the ownership invariant. Sending an [`Owned<T>`] is equivalent to sending the `T`.
+unsafe impl<T: Ownable + Send> Send for Owned<T> {}
+
+// SAFETY: It is safe to send [`&Owned<T>`] to another thread when the underlying `T` is [`Sync`],
+// because of the ownership invariant. Sending an [`&Owned<T>`] is equivalent to sending the `&T`.
+unsafe impl<T: Ownable + Sync> Sync for Owned<T> {}
+
+impl<T: Ownable> Deref for Owned<T> {
+ type Target = T;
+
+ #[inline]
+ fn deref(&self) -> &Self::Target {
+ // SAFETY: The type invariants guarantee that the object is valid.
+ unsafe { self.ptr.as_ref() }
+ }
+}
+
+impl<T: Ownable + Unpin> DerefMut for Owned<T> {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ // SAFETY: The type invariants guarantee that the object is valid, and that we can safely
+ // return a mutable reference to it.
+ unsafe { self.ptr.as_mut() }
+ }
+}
+
+impl<T: Ownable> Drop for Owned<T> {
+ #[inline]
+ fn drop(&mut self) {
+ // SAFETY: By existence of `&mut self` we exclusively own `self` and the underlying `T`. As
+ // we are dropping `self`, we can transfer ownership of the `T` to the `release` method.
+ unsafe { T::release(self.ptr) };
+ }
+}
diff --git a/rust/kernel/sync/aref.rs b/rust/kernel/sync/aref.rs
index b721b2e00b986..3bd5eb8a1a526 100644
--- a/rust/kernel/sync/aref.rs
+++ b/rust/kernel/sync/aref.rs
@@ -34,6 +34,11 @@
/// Rust code, the recommendation is to use [`Arc`](crate::sync::Arc) to create reference-counted
/// instances of a type.
///
+/// Note: Implementing this trait allows types to be wrapped in an [`ARef<Self>`]. It requires an
+/// internal reference count and provides only shared references. If unique references are required
+/// [`Ownable`](crate::types::Ownable) should be implemented which allows types to be wrapped in an
+/// [`Owned<Self>`](crate::types::Owned).
+///
/// # Safety
///
/// Implementers must ensure that increments to the reference count keep the object alive in memory
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index ac316fd7b538f..c41eab0ec983c 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -15,6 +15,11 @@
pub mod for_lt;
pub use for_lt::ForLt;
+pub use crate::owned::{
+ Ownable,
+ Owned, //
+};
+
/// Used to transfer ownership to and from foreign (non-Rust) languages.
///
/// Ownership is transferred from Rust to a foreign language by calling [`Self::into_foreign`] and
--
2.51.2
^ permalink raw reply related
* [PATCH v19 8/8] rust: page: add `from_raw()`
From: Andreas Hindborg @ 2026-06-26 11:54 UTC (permalink / raw)
To: Danilo Krummrich, Lorenzo Stoakes, Vlastimil Babka,
Liam R. Howlett, Uladzislau Rezki, Miguel Ojeda, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Alice Ryhl,
Trevor Gross, Daniel Almeida, Tamir Duberstein, Alexandre Courbot,
Onur Özkan, Lyude Paul, Greg Kroah-Hartman,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas, Rafael J. Wysocki, Dave Ertman, Ira Weiny,
Leon Romanovsky, Paul Moore, Serge Hallyn, David Airlie,
Simona Vetter, Alexander Viro, Jan Kara, Igor Korotin,
Viresh Kumar, Nishanth Menon, Stephen Boyd, Bjorn Helgaas,
Krzysztof Wilczyński, Pavel Tikhomirov, Michal Wilczynski
Cc: Andreas Hindborg, Philipp Stanner, rust-for-linux, linux-kernel,
linux-mm, driver-core, linux-block, linux-security-module,
dri-devel, linux-fsdevel, linux-pm, linux-pci, linux-pwm,
Andreas Hindborg
In-Reply-To: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org>
From: Andreas Hindborg <a.hindborg@samsung.com>
Add a method to `Page` that allows construction of an instance from `struct
page` pointer.
Signed-off-by: Andreas Hindborg <a.hindborg@samsung.com>
Reviewed-by: Onur Özkan <work@onurozkan.dev>
---
rust/kernel/page.rs | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/rust/kernel/page.rs b/rust/kernel/page.rs
index 6dc1c2395acaf..c88fda09ead5a 100644
--- a/rust/kernel/page.rs
+++ b/rust/kernel/page.rs
@@ -143,6 +143,20 @@ pub fn nid(&self) -> i32 {
unsafe { bindings::page_to_nid(self.as_ptr()) }
}
+ /// Create a `&Page` from a raw `struct page` pointer.
+ ///
+ /// # Safety
+ ///
+ /// `ptr` must be convertible to a shared reference with a lifetime of `'a`.
+ #[inline]
+ pub unsafe fn from_raw<'a>(ptr: *const bindings::page) -> &'a Self {
+ // INVARIANT: By the function safety requirements, `ptr` refers to a valid `struct page`, so
+ // the returned reference upholds the type invariant of `Page`.
+ // SAFETY: By function safety requirements, `ptr` is not null and is convertible to a shared
+ // reference.
+ unsafe { &*ptr.cast() }
+ }
+
/// Runs a piece of code with this page mapped to an address.
///
/// The page is unmapped when this call returns.
--
2.51.2
^ permalink raw reply related
* Re: [PATCH v3] thermal/drivers/rcar: fix error checking in probe()
From: Niklas Söderlund @ 2026-06-26 11:13 UTC (permalink / raw)
To: Dan Carpenter
Cc: Rafael J. Wysocki, Daniel Lezcano, Zhang Rui, Lukasz Luba,
Geert Uytterhoeven, Magnus Damm, linux-renesas-soc, linux-pm,
linux-kernel, kernel-janitors
In-Reply-To: <aj5WnseULiwgmlWv@stanley.mountain>
Hi Dan,
Thanks for your work.
On 2026-06-26 13:38:22 +0300, Dan Carpenter wrote:
> This code accidentally calls thermal_zone_device_enable() before checking
> whether thermal_zone_device_register_with_trips() failed. Move the call
> until later to avoid an error pointer dereference of "priv->zone".
>
> The driver works differently depending on if we are using OF thermal or
> not. We use thermal_add_hwmon_sysfs() if we are using OF thermal and
> call thermal_zone_device_enable() if not. We can share same error check
> for if either of these fail.
>
> Moving the thermal_zone_device_enable() call is a bit cleaner as well.
> The original code used a three step process to cleanup:
> 1. Call thermal_zone_device_unregister() to cleanup.
> 2. Set priv->zone to an error pointer to preserve the error code.
> 3. Set priv->zone to NULL to avoid a second call to
> thermal_zone_device_unregister() in the rcar_thermal_remove()
> function.
>
> Now we can just do a direct goto error_unregister and rcar_thermal_remove()
> handles the cleanup properly.
>
> Fixes: bbcf90c0646a ("thermal: Explicitly enable non-changing thermal zone devices")
> Signed-off-by: Dan Carpenter <error27@gmail.com>
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> ---
> v2: Use the correct fixes tag and re-write the check in a cleaner way.
> v3: Share the same error checking as a further cleanup. The
> thermal_add_hwmon_sysfs() and thermal_zone_device_enable() functions
> really do serve the same purpose even though their names are
> different.
>
> drivers/thermal/renesas/rcar_thermal.c | 15 +++++----------
> 1 file changed, 5 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/thermal/renesas/rcar_thermal.c b/drivers/thermal/renesas/rcar_thermal.c
> index 6e5dcac5d47a..fd686da9252e 100644
> --- a/drivers/thermal/renesas/rcar_thermal.c
> +++ b/drivers/thermal/renesas/rcar_thermal.c
> @@ -492,12 +492,6 @@ static int rcar_thermal_probe(struct platform_device *pdev)
> "rcar_thermal", trips, ARRAY_SIZE(trips), priv,
> &rcar_thermal_zone_ops, NULL, 0,
> idle);
> -
> - ret = thermal_zone_device_enable(priv->zone);
> - if (ret) {
> - thermal_zone_device_unregister(priv->zone);
> - priv->zone = ERR_PTR(ret);
> - }
> }
> if (IS_ERR(priv->zone)) {
> dev_err(dev, "can't register thermal zone\n");
> @@ -506,11 +500,12 @@ static int rcar_thermal_probe(struct platform_device *pdev)
> goto error_unregister;
> }
>
> - if (chip->use_of_thermal) {
> + if (chip->use_of_thermal)
> ret = thermal_add_hwmon_sysfs(priv->zone);
> - if (ret)
> - goto error_unregister;
> - }
> + else
> + ret = thermal_zone_device_enable(priv->zone);
> + if (ret)
> + goto error_unregister;
>
> rcar_thermal_irq_enable(priv);
>
> --
> 2.53.0
>
--
Kind Regards,
Niklas Söderlund
^ permalink raw reply
* [PATCH v3] thermal/drivers/rcar: fix error checking in probe()
From: Dan Carpenter @ 2026-06-26 10:38 UTC (permalink / raw)
To: Niklas Söderlund
Cc: Rafael J. Wysocki, Daniel Lezcano, Zhang Rui, Lukasz Luba,
Geert Uytterhoeven, Magnus Damm, linux-renesas-soc, linux-pm,
linux-kernel, kernel-janitors
This code accidentally calls thermal_zone_device_enable() before checking
whether thermal_zone_device_register_with_trips() failed. Move the call
until later to avoid an error pointer dereference of "priv->zone".
The driver works differently depending on if we are using OF thermal or
not. We use thermal_add_hwmon_sysfs() if we are using OF thermal and
call thermal_zone_device_enable() if not. We can share same error check
for if either of these fail.
Moving the thermal_zone_device_enable() call is a bit cleaner as well.
The original code used a three step process to cleanup:
1. Call thermal_zone_device_unregister() to cleanup.
2. Set priv->zone to an error pointer to preserve the error code.
3. Set priv->zone to NULL to avoid a second call to
thermal_zone_device_unregister() in the rcar_thermal_remove()
function.
Now we can just do a direct goto error_unregister and rcar_thermal_remove()
handles the cleanup properly.
Fixes: bbcf90c0646a ("thermal: Explicitly enable non-changing thermal zone devices")
Signed-off-by: Dan Carpenter <error27@gmail.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
v2: Use the correct fixes tag and re-write the check in a cleaner way.
v3: Share the same error checking as a further cleanup. The
thermal_add_hwmon_sysfs() and thermal_zone_device_enable() functions
really do serve the same purpose even though their names are
different.
drivers/thermal/renesas/rcar_thermal.c | 15 +++++----------
1 file changed, 5 insertions(+), 10 deletions(-)
diff --git a/drivers/thermal/renesas/rcar_thermal.c b/drivers/thermal/renesas/rcar_thermal.c
index 6e5dcac5d47a..fd686da9252e 100644
--- a/drivers/thermal/renesas/rcar_thermal.c
+++ b/drivers/thermal/renesas/rcar_thermal.c
@@ -492,12 +492,6 @@ static int rcar_thermal_probe(struct platform_device *pdev)
"rcar_thermal", trips, ARRAY_SIZE(trips), priv,
&rcar_thermal_zone_ops, NULL, 0,
idle);
-
- ret = thermal_zone_device_enable(priv->zone);
- if (ret) {
- thermal_zone_device_unregister(priv->zone);
- priv->zone = ERR_PTR(ret);
- }
}
if (IS_ERR(priv->zone)) {
dev_err(dev, "can't register thermal zone\n");
@@ -506,11 +500,12 @@ static int rcar_thermal_probe(struct platform_device *pdev)
goto error_unregister;
}
- if (chip->use_of_thermal) {
+ if (chip->use_of_thermal)
ret = thermal_add_hwmon_sysfs(priv->zone);
- if (ret)
- goto error_unregister;
- }
+ else
+ ret = thermal_zone_device_enable(priv->zone);
+ if (ret)
+ goto error_unregister;
rcar_thermal_irq_enable(priv);
--
2.53.0
^ permalink raw reply related
* Re: [PATCH v4 2/2] riscv: dts: spacemit: Add cpu scaling for K1 SoC
From: Andre Heider @ 2026-06-26 10:36 UTC (permalink / raw)
To: Shuwei Wu, Rafael J. Wysocki, Viresh Kumar, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Yixun Lan
Cc: linux-pm, linux-kernel, linux-riscv, spacemit, devicetree
In-Reply-To: <20260626-shadow-deps-v4-2-bba9831f2f1d@mailbox.org>
On 26.06.26 10:10 AM, Shuwei Wu wrote:
> Add CPU clock properties and OPP tables for the two CPU clusters in the
> SpacemiT K1 SoC. The OPP entries use voltage ranges because the CPU
> supply is shared by both clusters.
>
> Enable CPU DVFS on Banana Pi BPI-F3 by including the OPP tables and
> wiring the CPU nodes to the CPU regulator supply.
>
> Signed-off-by: Shuwei Wu <shuwei.wu@mailbox.org>
With the musepi-pro dts enablement patch [0] on top, this is
Tested-by: Andre Heider <a.heider@gmail.com> # k1-musepi-pro
Works as advertised, I get two policies, matching the clusters:
$ cat /sys/devices/system/cpu/cpufreq/policy0/related_cpus
0 1 2 3
$ cat /sys/devices/system/cpu/cpufreq/policy4/related_cpus
4 5 6 7
Some time after boot:
$ cat /sys/devices/system/cpu/cpufreq/policy0/stats/time_in_state
614400 31124
819000 185
1000000 158
1228800 341
1600000 1148
$ cat /sys/devices/system/cpu/cpufreq/policy4/stats/time_in_state
614400 29232
819000 198
1000000 212
1228800 443
1600000 3428
Creating one single-threaded load increases max freq time_in_state in one policy (4 here):
$ yes > /dev/null &
(...after some time)
$ cat /sys/devices/system/cpu/cpufreq/policy0/stats/time_in_state
614400 45244
819000 187
1000000 169
1228800 345
1600000 1148
$ cat /sys/devices/system/cpu/cpufreq/policy4/stats/time_in_state
614400 38794
819000 201
1000000 226
1228800 450
1600000 7580
Creating load for all 8 cores in both:
$ yes > /dev/null &
$ yes > /dev/null &
$ yes > /dev/null &
$ yes > /dev/null &
$ yes > /dev/null &
$ yes > /dev/null &
$ yes > /dev/null &
$ yes > /dev/null &
$ cat /sys/devices/system/cpu/cpufreq/policy0/stats/time_in_state
614400 51371
819000 190
1000000 171
1228800 352
1600000 4391
$ cat /sys/devices/system/cpu/cpufreq/policy4/stats/time_in_state
614400 44121
819000 203
1000000 244
1228800 452
1600000 11812
Thanks!
Andre
[0] https://lore.kernel.org/all/20260614122812.2287506-1-a.heider@gmail.com/
> ---
> Changes in v4:
> - Use separate OPP tables for the two CPU clock clusters
> - Use voltage ranges for the shared CPU supply
>
> Changes in v3:
> - Use one shared CPU OPP table for all CPUs
>
> Changes in v2:
> - Add k1-opp.dtsi with OPP tables for both CPU clusters
> - Assign CPU supplies and include OPP table for Banana Pi BPI-F3
> ---
> ---
> arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts | 35 +++++++-
> arch/riscv/boot/dts/spacemit/k1-opp.dtsi | 105 ++++++++++++++++++++++++
> arch/riscv/boot/dts/spacemit/k1.dtsi | 8 ++
> 3 files changed, 147 insertions(+), 1 deletion(-)
>
> diff --git a/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts b/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts
> index 444c3b1e6f44..487179f7b9b9 100644
> --- a/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts
> +++ b/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts
> @@ -4,6 +4,7 @@
> */
>
> #include "k1.dtsi"
> +#include "k1-opp.dtsi"
> #include "k1-pinctrl.dtsi"
>
> / {
> @@ -86,6 +87,38 @@ &combo_phy {
> status = "okay";
> };
>
> +&cpu_0 {
> + cpu-supply = <&buck1_0v9>;
> +};
> +
> +&cpu_1 {
> + cpu-supply = <&buck1_0v9>;
> +};
> +
> +&cpu_2 {
> + cpu-supply = <&buck1_0v9>;
> +};
> +
> +&cpu_3 {
> + cpu-supply = <&buck1_0v9>;
> +};
> +
> +&cpu_4 {
> + cpu-supply = <&buck1_0v9>;
> +};
> +
> +&cpu_5 {
> + cpu-supply = <&buck1_0v9>;
> +};
> +
> +&cpu_6 {
> + cpu-supply = <&buck1_0v9>;
> +};
> +
> +&cpu_7 {
> + cpu-supply = <&buck1_0v9>;
> +};
> +
> &emmc {
> bus-width = <8>;
> mmc-hs400-1_8v;
> @@ -201,7 +234,7 @@ pmic@41 {
> dldoin2-supply = <&buck5>;
>
> regulators {
> - buck1 {
> + buck1_0v9: buck1 {
> regulator-min-microvolt = <500000>;
> regulator-max-microvolt = <3450000>;
> regulator-ramp-delay = <5000>;
> diff --git a/arch/riscv/boot/dts/spacemit/k1-opp.dtsi b/arch/riscv/boot/dts/spacemit/k1-opp.dtsi
> new file mode 100644
> index 000000000000..4cebfcd87485
> --- /dev/null
> +++ b/arch/riscv/boot/dts/spacemit/k1-opp.dtsi
> @@ -0,0 +1,105 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +
> +/ {
> + cluster0_opp_table: opp-table-cluster0 {
> + compatible = "operating-points-v2";
> + opp-shared;
> +
> + opp-614400000 {
> + opp-hz = /bits/ 64 <614400000>;
> + opp-microvolt = <950000 950000 1050000>;
> + clock-latency-ns = <200000>;
> + };
> +
> + opp-819000000 {
> + opp-hz = /bits/ 64 <819000000>;
> + opp-microvolt = <950000 950000 1050000>;
> + clock-latency-ns = <200000>;
> + };
> +
> + opp-1000000000 {
> + opp-hz = /bits/ 64 <1000000000>;
> + opp-microvolt = <950000 950000 1050000>;
> + clock-latency-ns = <200000>;
> + };
> +
> + opp-1228800000 {
> + opp-hz = /bits/ 64 <1228800000>;
> + opp-microvolt = <950000 950000 1050000>;
> + clock-latency-ns = <200000>;
> + };
> +
> + opp-1600000000 {
> + opp-hz = /bits/ 64 <1600000000>;
> + opp-microvolt = <1050000 1050000 1050000>;
> + clock-latency-ns = <200000>;
> + };
> + };
> +
> + cluster1_opp_table: opp-table-cluster1 {
> + compatible = "operating-points-v2";
> + opp-shared;
> +
> + opp-614400000 {
> + opp-hz = /bits/ 64 <614400000>;
> + opp-microvolt = <950000 950000 1050000>;
> + clock-latency-ns = <200000>;
> + };
> +
> + opp-819000000 {
> + opp-hz = /bits/ 64 <819000000>;
> + opp-microvolt = <950000 950000 1050000>;
> + clock-latency-ns = <200000>;
> + };
> +
> + opp-1000000000 {
> + opp-hz = /bits/ 64 <1000000000>;
> + opp-microvolt = <950000 950000 1050000>;
> + clock-latency-ns = <200000>;
> + };
> +
> + opp-1228800000 {
> + opp-hz = /bits/ 64 <1228800000>;
> + opp-microvolt = <950000 950000 1050000>;
> + clock-latency-ns = <200000>;
> + };
> +
> + opp-1600000000 {
> + opp-hz = /bits/ 64 <1600000000>;
> + opp-microvolt = <1050000 1050000 1050000>;
> + clock-latency-ns = <200000>;
> + };
> + };
> +};
> +
> +&cpu_0 {
> + operating-points-v2 = <&cluster0_opp_table>;
> +};
> +
> +&cpu_1 {
> + operating-points-v2 = <&cluster0_opp_table>;
> +};
> +
> +&cpu_2 {
> + operating-points-v2 = <&cluster0_opp_table>;
> +};
> +
> +&cpu_3 {
> + operating-points-v2 = <&cluster0_opp_table>;
> +};
> +
> +&cpu_4 {
> + operating-points-v2 = <&cluster1_opp_table>;
> +};
> +
> +&cpu_5 {
> + operating-points-v2 = <&cluster1_opp_table>;
> +};
> +
> +&cpu_6 {
> + operating-points-v2 = <&cluster1_opp_table>;
> +};
> +
> +&cpu_7 {
> + operating-points-v2 = <&cluster1_opp_table>;
> +};
> diff --git a/arch/riscv/boot/dts/spacemit/k1.dtsi b/arch/riscv/boot/dts/spacemit/k1.dtsi
> index 529ec68e9c23..bdd109b81730 100644
> --- a/arch/riscv/boot/dts/spacemit/k1.dtsi
> +++ b/arch/riscv/boot/dts/spacemit/k1.dtsi
> @@ -54,6 +54,7 @@ cpu_0: cpu@0 {
> compatible = "spacemit,x60", "riscv";
> device_type = "cpu";
> reg = <0>;
> + clocks = <&syscon_apmu CLK_CPU_C0_CORE>;
> riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
> riscv,isa-base = "rv64i";
> riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
> @@ -84,6 +85,7 @@ cpu_1: cpu@1 {
> compatible = "spacemit,x60", "riscv";
> device_type = "cpu";
> reg = <1>;
> + clocks = <&syscon_apmu CLK_CPU_C0_CORE>;
> riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
> riscv,isa-base = "rv64i";
> riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
> @@ -114,6 +116,7 @@ cpu_2: cpu@2 {
> compatible = "spacemit,x60", "riscv";
> device_type = "cpu";
> reg = <2>;
> + clocks = <&syscon_apmu CLK_CPU_C0_CORE>;
> riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
> riscv,isa-base = "rv64i";
> riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
> @@ -144,6 +147,7 @@ cpu_3: cpu@3 {
> compatible = "spacemit,x60", "riscv";
> device_type = "cpu";
> reg = <3>;
> + clocks = <&syscon_apmu CLK_CPU_C0_CORE>;
> riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
> riscv,isa-base = "rv64i";
> riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
> @@ -174,6 +178,7 @@ cpu_4: cpu@4 {
> compatible = "spacemit,x60", "riscv";
> device_type = "cpu";
> reg = <4>;
> + clocks = <&syscon_apmu CLK_CPU_C1_CORE>;
> riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
> riscv,isa-base = "rv64i";
> riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
> @@ -204,6 +209,7 @@ cpu_5: cpu@5 {
> compatible = "spacemit,x60", "riscv";
> device_type = "cpu";
> reg = <5>;
> + clocks = <&syscon_apmu CLK_CPU_C1_CORE>;
> riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
> riscv,isa-base = "rv64i";
> riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
> @@ -234,6 +240,7 @@ cpu_6: cpu@6 {
> compatible = "spacemit,x60", "riscv";
> device_type = "cpu";
> reg = <6>;
> + clocks = <&syscon_apmu CLK_CPU_C1_CORE>;
> riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
> riscv,isa-base = "rv64i";
> riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
> @@ -264,6 +271,7 @@ cpu_7: cpu@7 {
> compatible = "spacemit,x60", "riscv";
> device_type = "cpu";
> reg = <7>;
> + clocks = <&syscon_apmu CLK_CPU_C1_CORE>;
> riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
> riscv,isa-base = "rv64i";
> riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
>
^ permalink raw reply
* [rafael-pm:fixes] BUILD SUCCESS 852b859dc948dc38efe965a1849d1a09fa46ec97
From: kernel test robot @ 2026-06-26 9:52 UTC (permalink / raw)
To: Rafael J. Wysocki; +Cc: linux-acpi, linux-pm
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git fixes
branch HEAD: 852b859dc948dc38efe965a1849d1a09fa46ec97 Merge branch 'acpi-processor' into fixes
elapsed time: 894m
configs tested: 280
configs skipped: 9
The following configs have been built successfully.
More configs may be tested in the coming days.
tested configs:
alpha allnoconfig gcc-16.1.0
alpha allyesconfig gcc-16.1.0
alpha defconfig gcc-16.1.0
arc allmodconfig clang-23
arc allmodconfig gcc-16.1.0
arc allnoconfig gcc-16.1.0
arc allyesconfig clang-23
arc allyesconfig gcc-16.1.0
arc defconfig gcc-16.1.0
arc randconfig-001 gcc-16.1.0
arc randconfig-001-20260626 gcc-13.4.0
arc randconfig-001-20260626 gcc-16.1.0
arc randconfig-002 gcc-16.1.0
arc randconfig-002-20260626 gcc-13.4.0
arc randconfig-002-20260626 gcc-16.1.0
arm allnoconfig clang-17
arm allnoconfig gcc-16.1.0
arm allyesconfig clang-23
arm allyesconfig gcc-16.1.0
arm defconfig gcc-16.1.0
arm mxs_defconfig clang-17
arm randconfig-001 gcc-16.1.0
arm randconfig-001-20260626 gcc-13.4.0
arm randconfig-001-20260626 gcc-16.1.0
arm randconfig-002 gcc-16.1.0
arm randconfig-002-20260626 gcc-13.4.0
arm randconfig-002-20260626 gcc-16.1.0
arm randconfig-003 gcc-16.1.0
arm randconfig-003-20260626 gcc-13.4.0
arm randconfig-003-20260626 gcc-16.1.0
arm randconfig-004 gcc-16.1.0
arm randconfig-004-20260626 gcc-13.4.0
arm randconfig-004-20260626 gcc-16.1.0
arm64 allmodconfig clang-23
arm64 allnoconfig gcc-16.1.0
arm64 defconfig gcc-16.1.0
arm64 randconfig-001 clang-23
arm64 randconfig-001-20260626 clang-23
arm64 randconfig-001-20260626 gcc-8.5.0
arm64 randconfig-002 clang-23
arm64 randconfig-002-20260626 clang-23
arm64 randconfig-002-20260626 gcc-8.5.0
arm64 randconfig-003 clang-23
arm64 randconfig-003-20260626 clang-23
arm64 randconfig-003-20260626 gcc-8.5.0
arm64 randconfig-004 clang-23
arm64 randconfig-004-20260626 clang-23
arm64 randconfig-004-20260626 gcc-8.5.0
csky allmodconfig gcc-16.1.0
csky allnoconfig gcc-16.1.0
csky defconfig gcc-16.1.0
csky randconfig-001 clang-23
csky randconfig-001-20260626 clang-23
csky randconfig-001-20260626 gcc-8.5.0
csky randconfig-002 clang-23
csky randconfig-002-20260626 clang-23
csky randconfig-002-20260626 gcc-8.5.0
hexagon allmodconfig clang-23
hexagon allmodconfig gcc-16.1.0
hexagon allnoconfig clang-23
hexagon allnoconfig gcc-16.1.0
hexagon defconfig gcc-16.1.0
hexagon randconfig-001 gcc-11.5.0
hexagon randconfig-001-20260626 gcc-11.5.0
hexagon randconfig-002 gcc-11.5.0
hexagon randconfig-002-20260626 gcc-11.5.0
i386 allmodconfig clang-22
i386 allnoconfig gcc-14
i386 allnoconfig gcc-16.1.0
i386 allyesconfig clang-22
i386 buildonly-randconfig-001 gcc-14
i386 buildonly-randconfig-001-20260626 gcc-14
i386 buildonly-randconfig-002 gcc-14
i386 buildonly-randconfig-002-20260626 gcc-14
i386 buildonly-randconfig-003 gcc-14
i386 buildonly-randconfig-003-20260626 gcc-14
i386 buildonly-randconfig-004 gcc-14
i386 buildonly-randconfig-004-20260626 gcc-14
i386 buildonly-randconfig-005 gcc-14
i386 buildonly-randconfig-005-20260626 gcc-14
i386 buildonly-randconfig-006 gcc-14
i386 buildonly-randconfig-006-20260626 gcc-14
i386 defconfig gcc-16.1.0
i386 randconfig-001 gcc-14
i386 randconfig-001-20260626 gcc-14
i386 randconfig-002 gcc-14
i386 randconfig-002-20260626 gcc-14
i386 randconfig-003 gcc-14
i386 randconfig-003-20260626 gcc-14
i386 randconfig-004 gcc-14
i386 randconfig-004-20260626 gcc-14
i386 randconfig-005 gcc-14
i386 randconfig-005-20260626 gcc-14
i386 randconfig-006 gcc-14
i386 randconfig-006-20260626 gcc-14
i386 randconfig-007 gcc-14
i386 randconfig-007-20260626 gcc-14
i386 randconfig-011 gcc-14
i386 randconfig-011-20260626 gcc-14
i386 randconfig-012 gcc-14
i386 randconfig-012-20260626 gcc-14
i386 randconfig-013 gcc-14
i386 randconfig-013-20260626 gcc-14
i386 randconfig-014 gcc-14
i386 randconfig-014-20260626 gcc-14
i386 randconfig-015 gcc-14
i386 randconfig-015-20260626 gcc-14
i386 randconfig-016 gcc-14
i386 randconfig-016-20260626 gcc-14
i386 randconfig-017 gcc-14
i386 randconfig-017-20260626 gcc-14
loongarch allmodconfig clang-19
loongarch allmodconfig clang-23
loongarch allnoconfig clang-20
loongarch allnoconfig gcc-16.1.0
loongarch defconfig clang-23
loongarch randconfig-001 gcc-11.5.0
loongarch randconfig-001-20260626 gcc-11.5.0
loongarch randconfig-002 gcc-11.5.0
loongarch randconfig-002-20260626 gcc-11.5.0
m68k allmodconfig gcc-16.1.0
m68k allnoconfig gcc-16.1.0
m68k allyesconfig clang-23
m68k allyesconfig gcc-16.1.0
m68k defconfig clang-23
microblaze allnoconfig gcc-16.1.0
microblaze allyesconfig gcc-16.1.0
microblaze defconfig clang-23
microblaze mmu_defconfig gcc-16.1.0
mips allmodconfig gcc-16.1.0
mips allnoconfig gcc-16.1.0
mips allyesconfig gcc-16.1.0
mips loongson2k_defconfig gcc-16.1.0
nios2 allmodconfig clang-20
nios2 allmodconfig gcc-11.5.0
nios2 allnoconfig clang-23
nios2 defconfig clang-23
nios2 randconfig-001 gcc-11.5.0
nios2 randconfig-001-20260626 gcc-11.5.0
nios2 randconfig-002 gcc-11.5.0
nios2 randconfig-002-20260626 gcc-11.5.0
openrisc allmodconfig clang-20
openrisc allmodconfig gcc-16.1.0
openrisc allnoconfig clang-23
openrisc defconfig gcc-16.1.0
parisc allmodconfig gcc-16.1.0
parisc allnoconfig clang-23
parisc allyesconfig clang-17
parisc allyesconfig gcc-16.1.0
parisc defconfig gcc-16.1.0
parisc randconfig-001 gcc-8.5.0
parisc randconfig-001-20260626 gcc-8.5.0
parisc randconfig-002 gcc-8.5.0
parisc randconfig-002-20260626 gcc-8.5.0
parisc64 defconfig clang-23
powerpc allmodconfig gcc-16.1.0
powerpc allnoconfig clang-23
powerpc ep88xc_defconfig gcc-16.1.0
powerpc motionpro_defconfig clang-23
powerpc randconfig-001 gcc-8.5.0
powerpc randconfig-001-20260626 gcc-8.5.0
powerpc randconfig-002 gcc-8.5.0
powerpc randconfig-002-20260626 gcc-8.5.0
powerpc64 randconfig-001 gcc-8.5.0
powerpc64 randconfig-001-20260626 gcc-8.5.0
powerpc64 randconfig-002 gcc-8.5.0
powerpc64 randconfig-002-20260626 gcc-8.5.0
riscv allmodconfig clang-23
riscv allnoconfig clang-23
riscv allyesconfig clang-23
riscv defconfig gcc-16.1.0
riscv nommu_k210_sdcard_defconfig gcc-16.1.0
riscv randconfig-001 clang-23
riscv randconfig-001-20260626 clang-23
riscv randconfig-002 clang-23
riscv randconfig-002-20260626 clang-23
s390 allmodconfig clang-17
s390 allmodconfig clang-23
s390 allnoconfig clang-23
s390 allyesconfig gcc-16.1.0
s390 defconfig gcc-16.1.0
s390 randconfig-001 clang-23
s390 randconfig-001-20260626 clang-23
s390 randconfig-002 clang-23
s390 randconfig-002-20260626 clang-23
sh allmodconfig gcc-16.1.0
sh allnoconfig clang-23
sh allyesconfig clang-17
sh allyesconfig gcc-16.1.0
sh defconfig gcc-14
sh randconfig-001 clang-23
sh randconfig-001-20260626 clang-23
sh randconfig-002 clang-23
sh randconfig-002-20260626 clang-23
sh rsk7264_defconfig gcc-16.1.0
sparc allnoconfig clang-23
sparc defconfig gcc-16.1.0
sparc randconfig-001 gcc-12.5.0
sparc randconfig-001-20260626 gcc-12.5.0
sparc randconfig-002 gcc-12.5.0
sparc randconfig-002-20260626 gcc-12.5.0
sparc64 allmodconfig clang-20
sparc64 defconfig gcc-14
sparc64 randconfig-001 gcc-12.5.0
sparc64 randconfig-001-20260626 gcc-12.5.0
sparc64 randconfig-002 gcc-12.5.0
sparc64 randconfig-002-20260626 gcc-12.5.0
um allmodconfig clang-17
um allnoconfig clang-23
um allyesconfig gcc-14
um allyesconfig gcc-16.1.0
um defconfig gcc-14
um i386_defconfig gcc-14
um randconfig-001 gcc-12.5.0
um randconfig-001-20260626 gcc-12.5.0
um randconfig-002 gcc-12.5.0
um randconfig-002-20260626 gcc-12.5.0
um x86_64_defconfig gcc-14
x86_64 allmodconfig clang-22
x86_64 allnoconfig clang-23
x86_64 allyesconfig clang-22
x86_64 buildonly-randconfig-001 gcc-14
x86_64 buildonly-randconfig-001-20260626 gcc-14
x86_64 buildonly-randconfig-002 gcc-14
x86_64 buildonly-randconfig-002-20260626 gcc-14
x86_64 buildonly-randconfig-003 gcc-14
x86_64 buildonly-randconfig-003-20260626 gcc-14
x86_64 buildonly-randconfig-004 gcc-14
x86_64 buildonly-randconfig-004-20260626 gcc-14
x86_64 buildonly-randconfig-005 gcc-14
x86_64 buildonly-randconfig-005-20260626 gcc-14
x86_64 buildonly-randconfig-006 gcc-14
x86_64 buildonly-randconfig-006-20260626 gcc-14
x86_64 defconfig gcc-14
x86_64 kexec clang-22
x86_64 randconfig-001-20260626 clang-22
x86_64 randconfig-002-20260626 clang-22
x86_64 randconfig-003-20260626 clang-22
x86_64 randconfig-004-20260626 clang-22
x86_64 randconfig-005-20260626 clang-22
x86_64 randconfig-006-20260626 clang-22
x86_64 randconfig-011 gcc-14
x86_64 randconfig-011-20260626 gcc-14
x86_64 randconfig-012 gcc-14
x86_64 randconfig-012-20260626 gcc-14
x86_64 randconfig-013 gcc-14
x86_64 randconfig-013-20260626 gcc-14
x86_64 randconfig-014 gcc-14
x86_64 randconfig-014-20260626 gcc-14
x86_64 randconfig-015 gcc-14
x86_64 randconfig-015-20260626 gcc-14
x86_64 randconfig-016 gcc-14
x86_64 randconfig-016-20260626 gcc-14
x86_64 randconfig-071 gcc-14
x86_64 randconfig-071-20260626 gcc-14
x86_64 randconfig-072 gcc-14
x86_64 randconfig-072-20260626 clang-22
x86_64 randconfig-072-20260626 gcc-14
x86_64 randconfig-073 gcc-14
x86_64 randconfig-073-20260626 gcc-14
x86_64 randconfig-074 gcc-14
x86_64 randconfig-074-20260626 gcc-14
x86_64 randconfig-075 gcc-14
x86_64 randconfig-075-20260626 gcc-14
x86_64 randconfig-076 gcc-14
x86_64 randconfig-076-20260626 gcc-14
x86_64 rhel-9.4 clang-22
x86_64 rhel-9.4-bpf gcc-14
x86_64 rhel-9.4-func clang-22
x86_64 rhel-9.4-kselftests clang-22
x86_64 rhel-9.4-kunit gcc-14
x86_64 rhel-9.4-ltp gcc-14
x86_64 rhel-9.4-rust clang-22
xtensa allnoconfig clang-23
xtensa allyesconfig clang-20
xtensa allyesconfig gcc-16.1.0
xtensa randconfig-001 gcc-12.5.0
xtensa randconfig-001-20260626 gcc-12.5.0
xtensa randconfig-002 gcc-12.5.0
xtensa randconfig-002-20260626 gcc-12.5.0
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH v11] PCI: Add support for PCIe WAKE# interrupt
From: Bartosz Golaszewski @ 2026-06-26 9:31 UTC (permalink / raw)
To: Krishna Chaitanya Chundru
Cc: linux-pm, linux-kernel, linux-pci, linux-gpio, quic_vbadigan,
sherry.sun, driver-core, devicetree, Manivannan Sadhasivam,
Rafael J. Wysocki, Len Brown, Pavel Machek, Greg Kroah-Hartman,
Danilo Krummrich, Bjorn Helgaas, Bartosz Golaszewski,
Linus Walleij, Bartosz Golaszewski, Rob Herring, Saravana Kannan
In-Reply-To: <20260624-wakeirq_support-v11-1-120fbfaebe59@oss.qualcomm.com>
On Wed, 24 Jun 2026 13:25:49 +0200, Krishna Chaitanya Chundru
<krishna.chundru@oss.qualcomm.com> said:
> According to the PCI Express specification (PCIe r7.0, Section 5.3.3.2),
> two link wakeup mechanisms are defined: Beacon and WAKE#. Beacon is a
> hardware-only mechanism and is invisible to software (PCIe r7.0,
> Section 4.2.7.8.1). This change adds support for the WAKE# mechanism
> in the PCI core.
>
> According to the PCIe specification, multiple WAKE# signals can exist in
> a system or each component in the hierarchy could share a single WAKE#
> signal. In configurations involving a PCIe switch, each downstream port
> (DSP) of the switch may be connected to a separate WAKE# line, allowing
> each endpoint to signal WAKE# independently. From figure 5.4 in sec
> 5.3.3.2, WAKE# can also be terminated at the switch itself. Such topologies
> are typically not described in Device Tree, therefore it is out of scope
> for this series.
>
> To support this, the WAKE# should be described in the device tree node of
> the endpoint/bridge. If all endpoints share a single WAKE# line, then each
> endpoint node shall describe the same WAKE# signal or a single WAKE# in
> the Root Port node.
>
> In pci_device_add(), PCI framework will search for the WAKE# in device
> node. Once found, register for the wake IRQ through
> dev_pm_set_dedicated_wake_irq() associates a wakeup IRQ with a device
> and requests it, but the PM core keeps the IRQ disabled by default. The
> IRQ is enabled by the PM core, only when the device is permitted to wake
> the system, i.e. during system suspend and after runtime suspend, and
> only when device wakeup is enabled.
>
> If the same WAKE# GPIO is described in multiple device tree nodes, only the
> first device that successfully registers the wake IRQ will succeed, while
> subsequent registrations may fail. This limitation does not affect
> functional correctness, since WAKE# is only used to bring the link to D0,
> and endpoint-specific wakeup handling is resolved later through
> PME detection (PME_EN is set in suspend path by PCI core by default).
>
> When the wake IRQ fires, the wakeirq handler invokes pm_runtime_resume() to
> bring the device back to an active power state, such as transitioning from
> D3cold to D0. Once the device is active and the link is usable, the
> endpoint may generate a PME, which is then handled by the PCI core through
> PME polling or the PCIe PME service driver to complete the wakeup of the
> endpoint.
>
> WAKE# is added in dts schema and merged based on below links.
>
> Link: https://lore.kernel.org/all/20250515090517.3506772-1-krishna.chundru@oss.qualcomm.com/
> Link: https://github.com/devicetree-org/dt-schema/pull/170
> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
> Acked-by: Manivannan Sadhasivam <mani@kernel.org>
> Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
> ---
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
^ permalink raw reply
* [PATCH] cpufreq: tegra124: Disable DFLL clock on removal
From: Myeonghun Pak @ 2026-06-26 9:30 UTC (permalink / raw)
To: Rafael J . Wysocki, Viresh Kumar, linux-pm
Cc: Thierry Reding, Jonathan Hunter, linux-tegra, linux-kernel,
Myeonghun Pak, Ijae Kim
tegra124_cpu_switch_to_dfll() enables the DFLL clock before switching
the CPU clock parent to it. If cpufreq_dt_pdev_register() fails after
that point, or when the driver is removed, the driver only drops clock
references and never disables the enabled DFLL clock.
Add a helper for switching the CPU back to PLLP and disabling DFLL, then
use it in the post-DFLL probe unwind path and in remove.
Fixes: 9f5ed5fe6060 ("cpufreq: tegra124: do not handle the CPU rail")
Co-developed-by: Ijae Kim <ae878000@gmail.com>
Signed-off-by: Ijae Kim <ae878000@gmail.com>
Signed-off-by: Myeonghun Pak <mhun512@gmail.com>
---
drivers/cpufreq/tegra124-cpufreq.c | 25 +++++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/drivers/cpufreq/tegra124-cpufreq.c b/drivers/cpufreq/tegra124-cpufreq.c
index f8a76bbec..1fb3bf50b 100644
--- a/drivers/cpufreq/tegra124-cpufreq.c
+++ b/drivers/cpufreq/tegra124-cpufreq.c
@@ -54,12 +54,25 @@
return ret;
}
+static int tegra124_cpu_disable_dfll(struct tegra124_cpufreq_priv *priv)
+{
+ int ret;
+
+ ret = clk_set_parent(priv->cpu_clk, priv->pllp_clk);
+ if (ret)
+ return ret;
+
+ clk_disable_unprepare(priv->dfll_clk);
+
+ return 0;
+}
+
static int tegra124_cpufreq_probe(struct platform_device *pdev)
{
struct device_node *np __free(device_node) = of_cpu_device_node_get(0);
struct tegra124_cpufreq_priv *priv;
struct device *cpu_dev;
- int ret;
+ int err, ret;
if (!np)
return -ENODEV;
@@ -101,13 +114,17 @@
priv->cpufreq_dt_pdev = cpufreq_dt_pdev_register(&pdev->dev);
if (IS_ERR(priv->cpufreq_dt_pdev)) {
ret = PTR_ERR(priv->cpufreq_dt_pdev);
- goto out_put_pllp_clk;
+ goto out_disable_dfll;
}
platform_set_drvdata(pdev, priv);
return 0;
+out_disable_dfll:
+ err = tegra124_cpu_disable_dfll(priv);
+ if (err)
+ dev_err(&pdev->dev, "failed to disable DFLL clock: %d\n", err);
out_put_pllp_clk:
clk_put(priv->pllp_clk);
out_put_pllx_clk:
@@ -175,12 +192,17 @@
static void tegra124_cpufreq_remove(struct platform_device *pdev)
{
struct tegra124_cpufreq_priv *priv = dev_get_drvdata(&pdev->dev);
+ int err;
if (!IS_ERR(priv->cpufreq_dt_pdev)) {
platform_device_unregister(priv->cpufreq_dt_pdev);
priv->cpufreq_dt_pdev = ERR_PTR(-ENODEV);
}
+ err = tegra124_cpu_disable_dfll(priv);
+ if (err)
+ dev_err(&pdev->dev, "failed to disable DFLL clock: %d\n", err);
+
clk_put(priv->pllp_clk);
clk_put(priv->pllx_clk);
clk_put(priv->dfll_clk);
--
2.39.5
^ permalink raw reply related
* Re: [PATCH v1 0/6] power: Use named initializers for platform_device_id arrays
From: patchwork-bot+linux-riscv @ 2026-06-26 8:20 UTC (permalink / raw)
To: =?utf-8?q?Uwe_Kleine-K=C3=B6nig_=28The_Capable_Hub=29_=3Cu=2Ekleine-koenig?=,
=?utf-8?q?=40baylibre=2Ecom=3E?=
Cc: linux-riscv, sre, visitorckw, bleung, groeck, linux, krzk,
matthias.bgg, angelogioacchino.delregno, linux-pm, linux-kernel,
chrome-platform, linux-arm-kernel, linux-mediatek, hansg,
m.szyprowski, sebastian.krzyszkowiak, kernel, dlan, andreas,
mazziesaccount, sven, j, neal, amitsd, samkay014, spacemit, asahi,
imx, wens
In-Reply-To: <cover.1780048925.git.u.kleine-koenig@baylibre.com>
Hello:
This patch was applied to riscv/linux.git (fixes)
by Sebastian Reichel <sebastian.reichel@collabora.com>:
On Fri, 29 May 2026 12:18:15 +0200 you wrote:
> Hello,
>
> this series targets to use named initializers for platform_device_id
> arrays. In general these are better readable for humans and more robust
> to changes in the respective struct definition.
>
> This robustness is needed as I want to do
>
> [...]
Here is the summary with links:
- [v1,4/6] power: Use named initializers for platform_device_id arrays
https://git.kernel.org/riscv/c/e28f7498dd81
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* [PATCH v4 2/2] riscv: dts: spacemit: Add cpu scaling for K1 SoC
From: Shuwei Wu @ 2026-06-26 8:10 UTC (permalink / raw)
To: Rafael J. Wysocki, Viresh Kumar, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Yixun Lan, Yixun Lan
Cc: linux-pm, linux-kernel, linux-riscv, spacemit, devicetree,
Shuwei Wu
In-Reply-To: <20260626-shadow-deps-v4-0-bba9831f2f1d@mailbox.org>
Add CPU clock properties and OPP tables for the two CPU clusters in the
SpacemiT K1 SoC. The OPP entries use voltage ranges because the CPU
supply is shared by both clusters.
Enable CPU DVFS on Banana Pi BPI-F3 by including the OPP tables and
wiring the CPU nodes to the CPU regulator supply.
Signed-off-by: Shuwei Wu <shuwei.wu@mailbox.org>
---
Changes in v4:
- Use separate OPP tables for the two CPU clock clusters
- Use voltage ranges for the shared CPU supply
Changes in v3:
- Use one shared CPU OPP table for all CPUs
Changes in v2:
- Add k1-opp.dtsi with OPP tables for both CPU clusters
- Assign CPU supplies and include OPP table for Banana Pi BPI-F3
---
---
arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts | 35 +++++++-
arch/riscv/boot/dts/spacemit/k1-opp.dtsi | 105 ++++++++++++++++++++++++
arch/riscv/boot/dts/spacemit/k1.dtsi | 8 ++
3 files changed, 147 insertions(+), 1 deletion(-)
diff --git a/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts b/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts
index 444c3b1e6f44..487179f7b9b9 100644
--- a/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts
+++ b/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts
@@ -4,6 +4,7 @@
*/
#include "k1.dtsi"
+#include "k1-opp.dtsi"
#include "k1-pinctrl.dtsi"
/ {
@@ -86,6 +87,38 @@ &combo_phy {
status = "okay";
};
+&cpu_0 {
+ cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_1 {
+ cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_2 {
+ cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_3 {
+ cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_4 {
+ cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_5 {
+ cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_6 {
+ cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_7 {
+ cpu-supply = <&buck1_0v9>;
+};
+
&emmc {
bus-width = <8>;
mmc-hs400-1_8v;
@@ -201,7 +234,7 @@ pmic@41 {
dldoin2-supply = <&buck5>;
regulators {
- buck1 {
+ buck1_0v9: buck1 {
regulator-min-microvolt = <500000>;
regulator-max-microvolt = <3450000>;
regulator-ramp-delay = <5000>;
diff --git a/arch/riscv/boot/dts/spacemit/k1-opp.dtsi b/arch/riscv/boot/dts/spacemit/k1-opp.dtsi
new file mode 100644
index 000000000000..4cebfcd87485
--- /dev/null
+++ b/arch/riscv/boot/dts/spacemit/k1-opp.dtsi
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/ {
+ cluster0_opp_table: opp-table-cluster0 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp-614400000 {
+ opp-hz = /bits/ 64 <614400000>;
+ opp-microvolt = <950000 950000 1050000>;
+ clock-latency-ns = <200000>;
+ };
+
+ opp-819000000 {
+ opp-hz = /bits/ 64 <819000000>;
+ opp-microvolt = <950000 950000 1050000>;
+ clock-latency-ns = <200000>;
+ };
+
+ opp-1000000000 {
+ opp-hz = /bits/ 64 <1000000000>;
+ opp-microvolt = <950000 950000 1050000>;
+ clock-latency-ns = <200000>;
+ };
+
+ opp-1228800000 {
+ opp-hz = /bits/ 64 <1228800000>;
+ opp-microvolt = <950000 950000 1050000>;
+ clock-latency-ns = <200000>;
+ };
+
+ opp-1600000000 {
+ opp-hz = /bits/ 64 <1600000000>;
+ opp-microvolt = <1050000 1050000 1050000>;
+ clock-latency-ns = <200000>;
+ };
+ };
+
+ cluster1_opp_table: opp-table-cluster1 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp-614400000 {
+ opp-hz = /bits/ 64 <614400000>;
+ opp-microvolt = <950000 950000 1050000>;
+ clock-latency-ns = <200000>;
+ };
+
+ opp-819000000 {
+ opp-hz = /bits/ 64 <819000000>;
+ opp-microvolt = <950000 950000 1050000>;
+ clock-latency-ns = <200000>;
+ };
+
+ opp-1000000000 {
+ opp-hz = /bits/ 64 <1000000000>;
+ opp-microvolt = <950000 950000 1050000>;
+ clock-latency-ns = <200000>;
+ };
+
+ opp-1228800000 {
+ opp-hz = /bits/ 64 <1228800000>;
+ opp-microvolt = <950000 950000 1050000>;
+ clock-latency-ns = <200000>;
+ };
+
+ opp-1600000000 {
+ opp-hz = /bits/ 64 <1600000000>;
+ opp-microvolt = <1050000 1050000 1050000>;
+ clock-latency-ns = <200000>;
+ };
+ };
+};
+
+&cpu_0 {
+ operating-points-v2 = <&cluster0_opp_table>;
+};
+
+&cpu_1 {
+ operating-points-v2 = <&cluster0_opp_table>;
+};
+
+&cpu_2 {
+ operating-points-v2 = <&cluster0_opp_table>;
+};
+
+&cpu_3 {
+ operating-points-v2 = <&cluster0_opp_table>;
+};
+
+&cpu_4 {
+ operating-points-v2 = <&cluster1_opp_table>;
+};
+
+&cpu_5 {
+ operating-points-v2 = <&cluster1_opp_table>;
+};
+
+&cpu_6 {
+ operating-points-v2 = <&cluster1_opp_table>;
+};
+
+&cpu_7 {
+ operating-points-v2 = <&cluster1_opp_table>;
+};
diff --git a/arch/riscv/boot/dts/spacemit/k1.dtsi b/arch/riscv/boot/dts/spacemit/k1.dtsi
index 529ec68e9c23..bdd109b81730 100644
--- a/arch/riscv/boot/dts/spacemit/k1.dtsi
+++ b/arch/riscv/boot/dts/spacemit/k1.dtsi
@@ -54,6 +54,7 @@ cpu_0: cpu@0 {
compatible = "spacemit,x60", "riscv";
device_type = "cpu";
reg = <0>;
+ clocks = <&syscon_apmu CLK_CPU_C0_CORE>;
riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
riscv,isa-base = "rv64i";
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
@@ -84,6 +85,7 @@ cpu_1: cpu@1 {
compatible = "spacemit,x60", "riscv";
device_type = "cpu";
reg = <1>;
+ clocks = <&syscon_apmu CLK_CPU_C0_CORE>;
riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
riscv,isa-base = "rv64i";
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
@@ -114,6 +116,7 @@ cpu_2: cpu@2 {
compatible = "spacemit,x60", "riscv";
device_type = "cpu";
reg = <2>;
+ clocks = <&syscon_apmu CLK_CPU_C0_CORE>;
riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
riscv,isa-base = "rv64i";
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
@@ -144,6 +147,7 @@ cpu_3: cpu@3 {
compatible = "spacemit,x60", "riscv";
device_type = "cpu";
reg = <3>;
+ clocks = <&syscon_apmu CLK_CPU_C0_CORE>;
riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
riscv,isa-base = "rv64i";
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
@@ -174,6 +178,7 @@ cpu_4: cpu@4 {
compatible = "spacemit,x60", "riscv";
device_type = "cpu";
reg = <4>;
+ clocks = <&syscon_apmu CLK_CPU_C1_CORE>;
riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
riscv,isa-base = "rv64i";
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
@@ -204,6 +209,7 @@ cpu_5: cpu@5 {
compatible = "spacemit,x60", "riscv";
device_type = "cpu";
reg = <5>;
+ clocks = <&syscon_apmu CLK_CPU_C1_CORE>;
riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
riscv,isa-base = "rv64i";
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
@@ -234,6 +240,7 @@ cpu_6: cpu@6 {
compatible = "spacemit,x60", "riscv";
device_type = "cpu";
reg = <6>;
+ clocks = <&syscon_apmu CLK_CPU_C1_CORE>;
riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
riscv,isa-base = "rv64i";
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
@@ -264,6 +271,7 @@ cpu_7: cpu@7 {
compatible = "spacemit,x60", "riscv";
device_type = "cpu";
reg = <7>;
+ clocks = <&syscon_apmu CLK_CPU_C1_CORE>;
riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
riscv,isa-base = "rv64i";
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
--
2.53.0
^ permalink raw reply related
* [PATCH v4 1/2] cpufreq: dt-platdev: Add SpacemiT K1 SoC to the allowlist
From: Shuwei Wu @ 2026-06-26 8:10 UTC (permalink / raw)
To: Rafael J. Wysocki, Viresh Kumar, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Yixun Lan, Yixun Lan
Cc: linux-pm, linux-kernel, linux-riscv, spacemit, devicetree,
Shuwei Wu
In-Reply-To: <20260626-shadow-deps-v4-0-bba9831f2f1d@mailbox.org>
Add the compatible string for supporting the generic
cpufreq driver on the SpacemiT K1 SoC.
Signed-off-by: Shuwei Wu <shuwei.wu@mailbox.org>
---
Changes in v4:
- Drop the K1-specific cpufreq driver and use cpufreq-dt again
- Add spacemit,k1 back to the cpufreq-dt allowlist
Changes in v3:
- Add a K1-specific cpufreq driver for the shared-rail, dual-clock topology
- Add spacemit,k1 to the cpufreq-dt blocklist
---
---
drivers/cpufreq/cpufreq-dt-platdev.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
index 25fd3b191b7e..e262394b56f9 100644
--- a/drivers/cpufreq/cpufreq-dt-platdev.c
+++ b/drivers/cpufreq/cpufreq-dt-platdev.c
@@ -81,6 +81,8 @@ static const struct of_device_id allowlist[] __initconst = {
{ .have_governor_per_policy = true, },
},
+ { .compatible = "spacemit,k1", },
+
{ .compatible = "st-ericsson,u8500", },
{ .compatible = "st-ericsson,u8540", },
{ .compatible = "st-ericsson,u9500", },
--
2.53.0
^ permalink raw reply related
* [PATCH v4 0/2] cpufreq: spacemit: Add cpufreq support for K1 SoC
From: Shuwei Wu @ 2026-06-26 8:10 UTC (permalink / raw)
To: Rafael J. Wysocki, Viresh Kumar, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Yixun Lan, Yixun Lan
Cc: linux-pm, linux-kernel, linux-riscv, spacemit, devicetree,
Shuwei Wu
This series enables CPU DVFS for the SpacemiT K1 SoC using the generic
cpufreq-dt driver.
K1 has two CPU clock clusters. The two clusters have separate CPU clocks,
so they are represented as two cpufreq policies: policy0 for CPUs 0-3 and
policy4 for CPUs 4-7.
The CPU voltage rail is shared between the clusters. To model this with two
policies, the OPP entries describe voltage ranges instead of a single fixed
voltage, so the shared regulator can keep the rail within a range acceptable
for the active OPP constraints.
Tested on Banana Pi BPI-F3:
~ # cat /sys/devices/system/cpu/online
0-7
~ # ls /sys/devices/system/cpu/cpufreq/
policy0 policy4
~ # cat /sys/devices/system/cpu/cpufreq/policy0/scaling_driver
cpufreq-dt
~ # cat /sys/devices/system/cpu/cpufreq/policy0/affected_cpus
0 1 2 3
~ # cat /sys/devices/system/cpu/cpufreq/policy4/scaling_driver
cpufreq-dt
~ # cat /sys/devices/system/cpu/cpufreq/policy4/affected_cpus
4 5 6 7
Both policies expose the same OPP frequencies:
~ # cat /sys/devices/system/cpu/cpufreq/policy0/scaling_available_frequencies
614400 819000 1000000 1228800 1600000
~ # cat /sys/devices/system/cpu/cpufreq/policy4/scaling_available_frequencies
614400 819000 1000000 1228800 1600000
For each policy, scaling_setspeed was set to each supported OPP and the
workload was pinned to one CPU covered by that policy with taskset.
CPU0 was used for policy0, and CPU4 was used for policy4. The clock rates below
are from /sys/kernel/debug/clk/clk_summary.
policy0 / CPU0:
----------------------------------------------------------
Frequency | cpu_c0_core_clk | Real (s) | User (s)
(kHz) | (Hz) | |
-------------+-------------------+------------+-----------
1,600,000 | 1,600,000,000 | 1.81 | 1.80
1,228,800 | 1,228,800,000 | 2.37 | 2.37
1,000,000 | 1,000,000,000 | 2.89 | 2.89
819,000 | 819,200,000 | 3.56 | 3.55
614,400 | 614,400,000 | 4.71 | 4.71
----------------------------------------------------------
policy4 / CPU4:
----------------------------------------------------------
Frequency | cpu_c1_core_clk | Real (s) | User (s)
(kHz) | (Hz) | |
-------------+-------------------+------------+-----------
1,600,000 | 1,600,000,000 | 1.81 | 1.80
1,228,800 | 1,228,800,000 | 2.36 | 2.36
1,000,000 | 1,000,000,000 | 2.89 | 2.89
819,000 | 819,200,000 | 3.55 | 3.55
614,400 | 614,400,000 | 4.71 | 4.70
----------------------------------------------------------
Signed-off-by: Shuwei Wu <shuwei.wu@mailbox.org>
---
Changes in v4:
- Represent K1 as two cpufreq-dt policies, one per CPU clock cluster
- Use OPP voltage ranges for the shared CPU supply
- Link to v3: https://lore.kernel.org/r/20260612-shadow-deps-v3-0-2f3ba88611ff@mailbox.org
Changes in v3:
- Add a K1-specific cpufreq driver for the shared-rail, dual-clock topology
- Use one shared CPU OPP table and one cpufreq policy for all CPUs
- Link to v2: https://lore.kernel.org/r/20260410-shadow-deps-v2-0-4e16b8c0f60e@mailbox.org
Changes in v2:
- Move OPP tables to dedicated k1-opp.dtsi
- Enable OPP only on BPI-F3 with cpu-supply present
- Link to v1: https://lore.kernel.org/r/20260308-shadow-deps-v1-0-0ceb5c7c07eb@mailbox.org
---
Shuwei Wu (2):
cpufreq: dt-platdev: Add SpacemiT K1 SoC to the allowlist
riscv: dts: spacemit: Add cpu scaling for K1 SoC
arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts | 35 +++++++-
arch/riscv/boot/dts/spacemit/k1-opp.dtsi | 105 ++++++++++++++++++++++++
arch/riscv/boot/dts/spacemit/k1.dtsi | 8 ++
drivers/cpufreq/cpufreq-dt-platdev.c | 2 +
4 files changed, 149 insertions(+), 1 deletion(-)
---
base-commit: 5164e95565d3fd508ca8a95351323f5716dfb695
change-id: 20260307-shadow-deps-3582a78aa756
prerequisite-patch-id: 154bd4f720ce5065d58b988de8f273207b44572e
prerequisite-message-id: <20260206-spacemit-p1-v4-0-8f695d93811e@riscstar.com>
prerequisite-patch-id: 5da3e75b18291a5540d4f66d7a0600fb8975ef62
prerequisite-patch-id: bcf41917414ecef8cf743095d130f6004c32f6a5
prerequisite-patch-id: cfe3800f8c791ec4c63e070af9628e88e0fc31b9
prerequisite-message-id: <20260305-k1-clk-fix-v1-1-abca85d6e266@mailbox.org>
prerequisite-patch-id: 7c7fb9f87dba019ece4c97c45750349a7cd28f3a
Best regards,
--
Shuwei Wu <shuwei.wu@mailbox.org>
^ permalink raw reply
* [rafael-pm:bleeding-edge] BUILD SUCCESS 05139b845e19bd4296b4226971a75c64a21e3d97
From: kernel test robot @ 2026-06-26 7:04 UTC (permalink / raw)
To: Rafael J. Wysocki; +Cc: linux-acpi, linux-pm
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git bleeding-edge
branch HEAD: 05139b845e19bd4296b4226971a75c64a21e3d97 Merge branch 'acpi-tad' into bleeding-edge
elapsed time: 726m
configs tested: 232
configs skipped: 2
The following configs have been built successfully.
More configs may be tested in the coming days.
tested configs:
alpha allnoconfig gcc-16.1.0
alpha allyesconfig gcc-16.1.0
alpha defconfig gcc-16.1.0
arc allmodconfig clang-23
arc allmodconfig gcc-16.1.0
arc allnoconfig gcc-16.1.0
arc allyesconfig clang-23
arc defconfig gcc-16.1.0
arc randconfig-001 gcc-16.1.0
arc randconfig-001-20260626 gcc-13.4.0
arc randconfig-001-20260626 gcc-16.1.0
arc randconfig-002 gcc-16.1.0
arc randconfig-002-20260626 gcc-13.4.0
arc randconfig-002-20260626 gcc-16.1.0
arm allnoconfig clang-17
arm allnoconfig gcc-16.1.0
arm allyesconfig clang-23
arm allyesconfig gcc-16.1.0
arm defconfig gcc-16.1.0
arm mxs_defconfig clang-17
arm randconfig-001 gcc-16.1.0
arm randconfig-001-20260626 gcc-13.4.0
arm randconfig-001-20260626 gcc-16.1.0
arm randconfig-002 gcc-16.1.0
arm randconfig-002-20260626 gcc-13.4.0
arm randconfig-002-20260626 gcc-16.1.0
arm randconfig-003 gcc-16.1.0
arm randconfig-003-20260626 gcc-13.4.0
arm randconfig-003-20260626 gcc-16.1.0
arm randconfig-004 gcc-16.1.0
arm randconfig-004-20260626 gcc-13.4.0
arm randconfig-004-20260626 gcc-16.1.0
arm64 allmodconfig clang-23
arm64 allnoconfig gcc-16.1.0
arm64 defconfig gcc-16.1.0
arm64 randconfig-001-20260626 gcc-8.5.0
arm64 randconfig-002-20260626 gcc-8.5.0
arm64 randconfig-003-20260626 gcc-8.5.0
arm64 randconfig-004-20260626 gcc-8.5.0
csky allmodconfig gcc-16.1.0
csky allnoconfig gcc-16.1.0
csky defconfig gcc-16.1.0
csky randconfig-001-20260626 gcc-8.5.0
csky randconfig-002-20260626 gcc-8.5.0
hexagon allmodconfig gcc-16.1.0
hexagon allnoconfig clang-23
hexagon allnoconfig gcc-16.1.0
hexagon defconfig gcc-16.1.0
hexagon randconfig-001-20260626 gcc-11.5.0
hexagon randconfig-002-20260626 gcc-11.5.0
i386 allmodconfig clang-22
i386 allnoconfig gcc-14
i386 allnoconfig gcc-16.1.0
i386 allyesconfig clang-22
i386 buildonly-randconfig-001 gcc-14
i386 buildonly-randconfig-001-20260626 gcc-14
i386 buildonly-randconfig-002 gcc-14
i386 buildonly-randconfig-002-20260626 gcc-14
i386 buildonly-randconfig-003 gcc-14
i386 buildonly-randconfig-003-20260626 gcc-14
i386 buildonly-randconfig-004 gcc-14
i386 buildonly-randconfig-004-20260626 gcc-14
i386 buildonly-randconfig-005 gcc-14
i386 buildonly-randconfig-005-20260626 gcc-14
i386 buildonly-randconfig-006 gcc-14
i386 buildonly-randconfig-006-20260626 gcc-14
i386 defconfig gcc-16.1.0
i386 randconfig-001-20260626 gcc-14
i386 randconfig-002-20260626 gcc-14
i386 randconfig-003-20260626 gcc-14
i386 randconfig-004-20260626 gcc-14
i386 randconfig-005-20260626 gcc-14
i386 randconfig-006-20260626 gcc-14
i386 randconfig-007-20260626 gcc-14
i386 randconfig-011 gcc-14
i386 randconfig-011-20260626 gcc-14
i386 randconfig-012 gcc-14
i386 randconfig-012-20260626 gcc-14
i386 randconfig-013 gcc-14
i386 randconfig-013-20260626 gcc-14
i386 randconfig-014 gcc-14
i386 randconfig-014-20260626 gcc-14
i386 randconfig-015 gcc-14
i386 randconfig-015-20260626 gcc-14
i386 randconfig-016 gcc-14
i386 randconfig-016-20260626 gcc-14
i386 randconfig-017 gcc-14
i386 randconfig-017-20260626 gcc-14
loongarch allmodconfig clang-23
loongarch allnoconfig clang-20
loongarch allnoconfig gcc-16.1.0
loongarch defconfig clang-23
loongarch randconfig-001-20260626 gcc-11.5.0
loongarch randconfig-002-20260626 gcc-11.5.0
m68k allmodconfig gcc-16.1.0
m68k allnoconfig gcc-16.1.0
m68k allyesconfig clang-23
m68k allyesconfig gcc-16.1.0
m68k defconfig clang-23
microblaze allnoconfig gcc-16.1.0
microblaze allyesconfig gcc-16.1.0
microblaze defconfig clang-23
mips allmodconfig gcc-16.1.0
mips allnoconfig gcc-16.1.0
mips allyesconfig gcc-16.1.0
mips loongson2k_defconfig gcc-16.1.0
nios2 allmodconfig clang-20
nios2 allmodconfig gcc-11.5.0
nios2 allnoconfig clang-23
nios2 allnoconfig gcc-11.5.0
nios2 defconfig clang-23
nios2 randconfig-001-20260626 gcc-11.5.0
nios2 randconfig-002-20260626 gcc-11.5.0
openrisc allmodconfig clang-20
openrisc allmodconfig gcc-16.1.0
openrisc allnoconfig clang-23
openrisc allnoconfig gcc-16.1.0
openrisc defconfig gcc-16.1.0
parisc allmodconfig gcc-16.1.0
parisc allnoconfig clang-23
parisc allnoconfig gcc-16.1.0
parisc allyesconfig clang-17
parisc allyesconfig gcc-16.1.0
parisc defconfig gcc-16.1.0
parisc randconfig-001-20260626 gcc-8.5.0
parisc randconfig-002-20260626 gcc-8.5.0
parisc64 defconfig clang-23
powerpc allmodconfig gcc-16.1.0
powerpc allnoconfig clang-23
powerpc allnoconfig gcc-16.1.0
powerpc motionpro_defconfig clang-23
powerpc randconfig-001-20260626 gcc-8.5.0
powerpc randconfig-002-20260626 gcc-8.5.0
powerpc64 randconfig-001-20260626 gcc-8.5.0
powerpc64 randconfig-002-20260626 gcc-8.5.0
riscv allmodconfig clang-23
riscv allnoconfig clang-23
riscv allnoconfig gcc-16.1.0
riscv allyesconfig clang-23
riscv defconfig gcc-16.1.0
riscv nommu_k210_sdcard_defconfig gcc-16.1.0
riscv randconfig-001 clang-23
riscv randconfig-001-20260626 clang-23
riscv randconfig-002 clang-23
riscv randconfig-002-20260626 clang-23
s390 allmodconfig clang-17
s390 allmodconfig clang-23
s390 allnoconfig clang-23
s390 allyesconfig gcc-16.1.0
s390 defconfig gcc-16.1.0
s390 randconfig-001 clang-23
s390 randconfig-001-20260626 clang-23
s390 randconfig-002 clang-23
s390 randconfig-002-20260626 clang-23
sh allmodconfig gcc-16.1.0
sh allnoconfig clang-23
sh allnoconfig gcc-16.1.0
sh allyesconfig clang-17
sh allyesconfig gcc-16.1.0
sh defconfig gcc-14
sh randconfig-001 clang-23
sh randconfig-001-20260626 clang-23
sh randconfig-002 clang-23
sh randconfig-002-20260626 clang-23
sh rsk7264_defconfig gcc-16.1.0
sparc allnoconfig clang-23
sparc allnoconfig gcc-16.1.0
sparc defconfig gcc-16.1.0
sparc randconfig-001-20260626 gcc-12.5.0
sparc randconfig-002-20260626 gcc-12.5.0
sparc64 allmodconfig clang-20
sparc64 defconfig gcc-14
sparc64 randconfig-001-20260626 gcc-12.5.0
sparc64 randconfig-002-20260626 gcc-12.5.0
um allmodconfig clang-17
um allnoconfig clang-17
um allnoconfig clang-23
um allyesconfig gcc-16.1.0
um defconfig gcc-14
um i386_defconfig gcc-14
um randconfig-001-20260626 gcc-12.5.0
um randconfig-002-20260626 gcc-12.5.0
um x86_64_defconfig gcc-14
x86_64 allmodconfig clang-22
x86_64 allnoconfig clang-22
x86_64 allnoconfig clang-23
x86_64 allyesconfig clang-22
x86_64 buildonly-randconfig-001-20260626 gcc-14
x86_64 buildonly-randconfig-002-20260626 gcc-14
x86_64 buildonly-randconfig-003-20260626 gcc-14
x86_64 buildonly-randconfig-004-20260626 gcc-14
x86_64 buildonly-randconfig-005-20260626 gcc-14
x86_64 buildonly-randconfig-006-20260626 gcc-14
x86_64 defconfig gcc-14
x86_64 kexec clang-22
x86_64 randconfig-001-20260626 clang-22
x86_64 randconfig-002-20260626 clang-22
x86_64 randconfig-003-20260626 clang-22
x86_64 randconfig-004-20260626 clang-22
x86_64 randconfig-005-20260626 clang-22
x86_64 randconfig-006-20260626 clang-22
x86_64 randconfig-011-20260626 gcc-14
x86_64 randconfig-012-20260626 gcc-14
x86_64 randconfig-013-20260626 gcc-14
x86_64 randconfig-014-20260626 gcc-14
x86_64 randconfig-015-20260626 gcc-14
x86_64 randconfig-016-20260626 gcc-14
x86_64 randconfig-071 gcc-14
x86_64 randconfig-071-20260626 gcc-14
x86_64 randconfig-072 gcc-14
x86_64 randconfig-072-20260626 gcc-14
x86_64 randconfig-073 gcc-14
x86_64 randconfig-073-20260626 gcc-14
x86_64 randconfig-074 gcc-14
x86_64 randconfig-074-20260626 gcc-14
x86_64 randconfig-075 gcc-14
x86_64 randconfig-075-20260626 gcc-14
x86_64 randconfig-076 gcc-14
x86_64 randconfig-076-20260626 gcc-14
x86_64 rhel-9.4 clang-22
x86_64 rhel-9.4-bpf gcc-14
x86_64 rhel-9.4-func clang-22
x86_64 rhel-9.4-kselftests clang-22
x86_64 rhel-9.4-kunit gcc-14
x86_64 rhel-9.4-ltp gcc-14
x86_64 rhel-9.4-rust clang-22
xtensa allnoconfig clang-23
xtensa allnoconfig gcc-16.1.0
xtensa allyesconfig clang-20
xtensa allyesconfig gcc-16.1.0
xtensa randconfig-001-20260626 gcc-12.5.0
xtensa randconfig-002-20260626 gcc-12.5.0
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH] selftests: helpers: handle multi line in test_sysfs_prop_optional_list
From: borissh1983 @ 2026-06-26 6:40 UTC (permalink / raw)
To: Sebastian Reichel, Shuah Khan; +Cc: linux-pm, linux-kselftest, linux-kernel
In-Reply-To: <20260625125237.36605-1-borissh1983@gmail.com>
On Thursday, 25 June 2026 15:52:37 Israel Daylight Time Boris Shtrasman wrote:
> Modify test_sysfs_prop_optional_list to allow multi line parameters, in
> order to comply with checkpatch output that limit line by 100 chars.
>
> Allow use cases like:
>
> test_sysfs_prop_optional_list \
> property_name "value1","value2","val3","very_long_option"\
> ,"extra_long_option" \
> ,"even_more_data"
>
> Signed-off-by: Boris Shtrasman <borissh1983@gmail.com>
> ---
> tools/testing/selftests/power_supply/helpers.sh | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/tools/testing/selftests/power_supply/helpers.sh b/tools/testing/selftests/power_supply/helpers.sh
> index 1ec90d7c9108..8535cb7ed094 100644
> --- a/tools/testing/selftests/power_supply/helpers.sh
> +++ b/tools/testing/selftests/power_supply/helpers.sh
> @@ -108,7 +108,7 @@ test_sysfs_prop_optional_range() {
>
> test_sysfs_prop_optional_list() {
> PROP=$1
> - LIST=$2
> + shift
>
> TEST_NAME="$DEVNAME".sysfs."$PROP"
>
> @@ -118,9 +118,9 @@ test_sysfs_prop_optional_list() {
> valid=0
>
> OLDIFS=$IFS
> - IFS=","
> - for item in $LIST; do
> - if [ "$DATA" = "$item" ]; then
> + IFS=",IFS"
> + for item in $*; do
> + if [ "$item" ] && [ "$DATA" = "$item" ]; then
> valid=1
> break
> fi
>
A new version of this patch now at
https://lore.kernel.org/linux-pm/20260625160556.54830-1-borissh1983@gmail.com/
^ permalink raw reply
* [PATCH V3 8/8] arm64: dts: imx8qxp-mek: Describe the PCIe M.2 Key E connector
From: Sherry Sun (OSS) @ 2026-06-26 2:31 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, Frank.Li, s.hauer, kernel, festevam,
amitkumar.karwar, neeraj.sanjaykale, marcel, luiz.dentz,
hongxing.zhu, l.stach, lpieralisi, kwilczynski, mani, bhelgaas,
brgl
Cc: imx, linux-pci, linux-arm-kernel, devicetree, linux-kernel,
linux-bluetooth, linux-pm, sherry.sun
In-Reply-To: <20260626023126.2189931-1-sherry.sun@oss.nxp.com>
From: Sherry Sun <sherry.sun@nxp.com>
The i.MX8QXP-MEK has the PCIe M.2 Mechanical Key E connector to connect
wireless connectivity cards over PCIe and UART interfaces. Hence,
describe the connector node and link it with the PCIe b Root Port and
LPUART1 nodes through graph port/endpoint.
The M.2 Key E connector is powered by a 3.3V fixed regulator
(reg_3v3) on board.
Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
---
arch/arm64/boot/dts/freescale/imx8qxp-mek.dts | 54 ++++++++++++++-----
1 file changed, 41 insertions(+), 13 deletions(-)
diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts
index a9b967d0a9be..c9fe4034cc2d 100644
--- a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts
+++ b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts
@@ -40,6 +40,37 @@ memory@80000000 {
reg = <0x00000000 0x80000000 0 0x40000000>;
};
+ m2-connector {
+ compatible = "pcie-m2-e-connector";
+ vpcie3v3-supply = <®_3v3>;
+ w-disable1-gpios = <&pca9557_a 2 GPIO_ACTIVE_LOW>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ m2_e_pcie_ep: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&pcieb_port0_ep>;
+ };
+ };
+
+ port@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ m2_e_uart_ep: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&lpuart1_ep>;
+ };
+ };
+ };
+ };
+
reg_usdhc2_vmmc: usdhc2-vmmc {
compatible = "regulator-fixed";
regulator-name = "SD1_SPWR";
@@ -157,15 +188,6 @@ reg_3v3: regulator-3v3 {
regulator-max-microvolt = <3300000>;
};
- reg_pcieb: regulator-pcie {
- compatible = "regulator-fixed";
- regulator-max-microvolt = <3300000>;
- regulator-min-microvolt = <3300000>;
- regulator-name = "mpcie_3v3";
- gpio = <&pca9557_a 2 GPIO_ACTIVE_HIGH>;
- enable-active-high;
- };
-
reg_audio: regulator-audio {
compatible = "regulator-fixed";
regulator-max-microvolt = <3300000>;
@@ -696,8 +718,10 @@ &lpuart1 {
pinctrl-0 = <&pinctrl_lpuart1>;
status = "okay";
- bluetooth {
- compatible = "nxp,88w8987-bt";
+ port {
+ lpuart1_ep: endpoint {
+ remote-endpoint = <&m2_e_uart_ep>;
+ };
};
};
@@ -746,8 +770,12 @@ &pcie0_ep {
&pcieb_port0 {
reset-gpios = <&lsio_gpio4 0 GPIO_ACTIVE_LOW>;
- vpcie-supply = <®_pcieb>;
- vpcie3v3aux-supply = <®_pcieb>;
+
+ port {
+ pcieb_port0_ep: endpoint {
+ remote-endpoint = <&m2_e_pcie_ep>;
+ };
+ };
};
&scu_key {
--
2.50.1
^ permalink raw reply related
* [PATCH V3 7/8] arm64: dts: imx8qm-mek: Describe the PCIe M.2 Key E connector
From: Sherry Sun (OSS) @ 2026-06-26 2:31 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, Frank.Li, s.hauer, kernel, festevam,
amitkumar.karwar, neeraj.sanjaykale, marcel, luiz.dentz,
hongxing.zhu, l.stach, lpieralisi, kwilczynski, mani, bhelgaas,
brgl
Cc: imx, linux-pci, linux-arm-kernel, devicetree, linux-kernel,
linux-bluetooth, linux-pm, sherry.sun
In-Reply-To: <20260626023126.2189931-1-sherry.sun@oss.nxp.com>
From: Sherry Sun <sherry.sun@nxp.com>
The i.MX8QM-MEK has the PCIe M.2 Mechanical Key E connector to connect
wireless connectivity cards over PCIe and UART interfaces. Hence,
describe the connector node and link it with the PCIe a Root Port and
LPUART1 nodes through graph port/endpoint.
The M.2 Key E connector is powered by a 3.3V fixed regulator
(reg_3v3) on board.
Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
---
arch/arm64/boot/dts/freescale/imx8qm-mek.dts | 58 +++++++++++++++-----
1 file changed, 43 insertions(+), 15 deletions(-)
diff --git a/arch/arm64/boot/dts/freescale/imx8qm-mek.dts b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts
index 5e725ad8aef9..4c02592cfe14 100644
--- a/arch/arm64/boot/dts/freescale/imx8qm-mek.dts
+++ b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts
@@ -32,6 +32,39 @@ memory@80000000 {
reg = <0x00000000 0x80000000 0 0x40000000>;
};
+ m2-connector {
+ compatible = "pcie-m2-e-connector";
+ pinctrl-0 = <&pinctrl_pciea_reg>;
+ pinctrl-names = "default";
+ vpcie3v3-supply = <®_3v3>;
+ w-disable1-gpios = <&lsio_gpio1 13 GPIO_ACTIVE_LOW>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ m2_e_pcie_ep: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&pciea_port0_ep>;
+ };
+ };
+
+ port@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ m2_e_uart_ep: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&lpuart1_ep>;
+ };
+ };
+ };
+ };
+
xtal24m: clock-xtal24m {
compatible = "fixed-clock";
#clock-cells = <0>;
@@ -320,17 +353,6 @@ reg_can2_stby: regulator-can2-stby {
vin-supply = <®_can2_en>;
};
- reg_pciea: regulator-pcie {
- compatible = "regulator-fixed";
- pinctrl-0 = <&pinctrl_pciea_reg>;
- pinctrl-names = "default";
- regulator-max-microvolt = <3300000>;
- regulator-min-microvolt = <3300000>;
- regulator-name = "mpcie_3v3";
- gpio = <&lsio_gpio1 13 GPIO_ACTIVE_HIGH>;
- enable-active-high;
- };
-
reg_usb_otg1_vbus: regulator-usbotg1-vbus {
compatible = "regulator-fixed";
regulator-name = "usb_otg1_vbus";
@@ -718,8 +740,10 @@ &lpuart1 {
pinctrl-0 = <&pinctrl_lpuart1>;
status = "okay";
- bluetooth {
- compatible = "nxp,88w8987-bt";
+ port {
+ lpuart1_ep: endpoint {
+ remote-endpoint = <&m2_e_uart_ep>;
+ };
};
};
@@ -818,8 +842,12 @@ &pciea {
&pciea_port0 {
reset-gpios = <&lsio_gpio4 29 GPIO_ACTIVE_LOW>;
- vpcie-supply = <®_pciea>;
- vpcie3v3aux-supply = <®_pciea>;
+
+ port {
+ pciea_port0_ep: endpoint {
+ remote-endpoint = <&m2_e_pcie_ep>;
+ };
+ };
};
&pcieb {
--
2.50.1
^ permalink raw reply related
* [PATCH V3 6/8] arm64: dts: imx8dxl-evk: Describe the PCIe M.2 Key E connector
From: Sherry Sun (OSS) @ 2026-06-26 2:31 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, Frank.Li, s.hauer, kernel, festevam,
amitkumar.karwar, neeraj.sanjaykale, marcel, luiz.dentz,
hongxing.zhu, l.stach, lpieralisi, kwilczynski, mani, bhelgaas,
brgl
Cc: imx, linux-pci, linux-arm-kernel, devicetree, linux-kernel,
linux-bluetooth, linux-pm, sherry.sun
In-Reply-To: <20260626023126.2189931-1-sherry.sun@oss.nxp.com>
From: Sherry Sun <sherry.sun@nxp.com>
The i.MX8DXL-EVK has the PCIe M.2 Mechanical Key E connector to connect
wireless connectivity cards over PCIe and UART interfaces. Hence,
describe the connector node and link it with the PCIe b Root Port and
LPUART1 nodes through graph port/endpoint.
The M.2 Key E connector is powered by a 3.3V fixed regulator
(reg_audio_3v3), add a reg_3v3 label to avoid confusion.
Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
---
arch/arm64/boot/dts/freescale/imx8dxl-evk.dts | 56 ++++++++++++++-----
1 file changed, 42 insertions(+), 14 deletions(-)
diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts b/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts
index 1084164d1381..6afee1f1a9fc 100644
--- a/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts
@@ -42,6 +42,37 @@ memory@80000000 {
reg = <0x00000000 0x80000000 0 0x40000000>;
};
+ m2-connector {
+ compatible = "pcie-m2-e-connector";
+ vpcie3v3-supply = <®_3v3>;
+ w-disable1-gpios = <&pca6416_1 13 GPIO_ACTIVE_LOW>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ m2_e_pcie_ep: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&pcieb_port0_ep>;
+ };
+ };
+
+ port@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ m2_e_uart_ep: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&lpuart1_ep>;
+ };
+ };
+ };
+ };
+
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
@@ -182,15 +213,6 @@ mii_select: regulator-4 {
regulator-always-on;
};
- reg_pcieb: regulator-pcieb {
- compatible = "regulator-fixed";
- regulator-max-microvolt = <3300000>;
- regulator-min-microvolt = <3300000>;
- regulator-name = "reg_pcieb";
- gpio = <&pca6416_1 13 GPIO_ACTIVE_HIGH>;
- enable-active-high;
- };
-
reg_audio_5v: regulator-audio-pwr {
compatible = "regulator-fixed";
regulator-name = "audio-5v";
@@ -200,7 +222,7 @@ reg_audio_5v: regulator-audio-pwr {
regulator-boot-on;
};
- reg_audio_3v3: regulator-audio-3v3 {
+ reg_3v3: reg_audio_3v3: regulator-audio-3v3 {
compatible = "regulator-fixed";
regulator-name = "audio-3v3";
regulator-min-microvolt = <3300000>;
@@ -623,8 +645,10 @@ &lpuart1 {
pinctrl-0 = <&pinctrl_lpuart1>;
status = "okay";
- bluetooth {
- compatible = "nxp,88w8987-bt";
+ port {
+ lpuart1_ep: endpoint {
+ remote-endpoint = <&m2_e_uart_ep>;
+ };
};
};
@@ -690,8 +714,12 @@ &pcie0_ep {
&pcieb_port0 {
reset-gpios = <&lsio_gpio4 0 GPIO_ACTIVE_LOW>;
- vpcie-supply = <®_pcieb>;
- vpcie3v3aux-supply = <®_pcieb>;
+
+ port {
+ pcieb_port0_ep: endpoint {
+ remote-endpoint = <&m2_e_pcie_ep>;
+ };
+ };
};
&sai0 {
--
2.50.1
^ permalink raw reply related
* [PATCH V3 5/8] arm64: dts: imx95-19x19-evk: Describe the PCIe M.2 Key E connector
From: Sherry Sun (OSS) @ 2026-06-26 2:31 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, Frank.Li, s.hauer, kernel, festevam,
amitkumar.karwar, neeraj.sanjaykale, marcel, luiz.dentz,
hongxing.zhu, l.stach, lpieralisi, kwilczynski, mani, bhelgaas,
brgl
Cc: imx, linux-pci, linux-arm-kernel, devicetree, linux-kernel,
linux-bluetooth, linux-pm, sherry.sun
In-Reply-To: <20260626023126.2189931-1-sherry.sun@oss.nxp.com>
From: Sherry Sun <sherry.sun@nxp.com>
The i.MX95-19x19-EVK has the PCIe M.2 Mechanical Key E connector to
connect wireless connectivity cards over PCIe and UART interfaces. Hence,
describe the connector node and link it with the PCIe 0 Root Port and
LPUART5 nodes through graph port/endpoint.
Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
---
.../boot/dts/freescale/imx95-19x19-evk.dts | 55 ++++++++++++++-----
1 file changed, 41 insertions(+), 14 deletions(-)
diff --git a/arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts b/arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts
index c08731dfb1ee..d2c0345f0d61 100644
--- a/arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts
@@ -57,6 +57,37 @@ memory@80000000 {
reg = <0x0 0x80000000 0 0x80000000>;
};
+ m2-connector {
+ compatible = "pcie-m2-e-connector";
+ vpcie3v3-supply = <®_m2_pwr>;
+ w-disable1-gpios = <&i2c7_pcal6524 6 GPIO_ACTIVE_LOW>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ m2_e_pcie_ep: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&pcie0_port0_ep>;
+ };
+ };
+
+ port@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ m2_e_uart_ep: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&lpuart5_ep>;
+ };
+ };
+ };
+ };
+
fan0: pwm-fan {
compatible = "pwm-fan";
#cooling-cells = <2>;
@@ -145,16 +176,6 @@ reg_m2_pwr: regulator-m2-pwr {
startup-delay-us = <5000>;
};
- reg_pcie0: regulator-pcie {
- compatible = "regulator-fixed";
- regulator-name = "PCIE_WLAN_EN";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- vin-supply = <®_m2_pwr>;
- gpio = <&i2c7_pcal6524 6 GPIO_ACTIVE_HIGH>;
- enable-active-high;
- };
-
reg_slot_pwr: regulator-slot-pwr {
compatible = "regulator-fixed";
regulator-name = "PCIe slot-power";
@@ -477,8 +498,10 @@ &lpuart5 {
pinctrl-0 = <&pinctrl_uart5>;
status = "okay";
- bluetooth {
- compatible = "nxp,88w8987-bt";
+ port {
+ lpuart5_ep: endpoint {
+ remote-endpoint = <&m2_e_uart_ep>;
+ };
};
};
@@ -555,8 +578,12 @@ &pcie0_ep {
&pcie0_port0 {
reset-gpios = <&i2c7_pcal6524 5 GPIO_ACTIVE_LOW>;
- vpcie-supply = <®_pcie0>;
- vpcie3v3aux-supply = <®_pcie0>;
+
+ port {
+ pcie0_port0_ep: endpoint {
+ remote-endpoint = <&m2_e_pcie_ep>;
+ };
+ };
};
&pcie1 {
--
2.50.1
^ permalink raw reply related
* [PATCH V3 4/8] arm64: dts: imx8mq-evk: Describe the PCIe M.2 Key E connector
From: Sherry Sun (OSS) @ 2026-06-26 2:31 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, Frank.Li, s.hauer, kernel, festevam,
amitkumar.karwar, neeraj.sanjaykale, marcel, luiz.dentz,
hongxing.zhu, l.stach, lpieralisi, kwilczynski, mani, bhelgaas,
brgl
Cc: imx, linux-pci, linux-arm-kernel, devicetree, linux-kernel,
linux-bluetooth, linux-pm, sherry.sun
In-Reply-To: <20260626023126.2189931-1-sherry.sun@oss.nxp.com>
From: Sherry Sun <sherry.sun@nxp.com>
The i.MX8MQ-EVK has the PCIe M.2 Mechanical Key E connector to connect
wireless connectivity cards over PCIe and UART interfaces. Hence,
describe the connector node and link it with the PCIe 1 Root Port and
UART3 nodes through graph port/endpoint.
Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
---
arch/arm64/boot/dts/freescale/imx8mq-evk.dts | 44 ++++++++++++++++++--
1 file changed, 40 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/boot/dts/freescale/imx8mq-evk.dts b/arch/arm64/boot/dts/freescale/imx8mq-evk.dts
index 71504a0af87f..482e5203e879 100644
--- a/arch/arm64/boot/dts/freescale/imx8mq-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mq-evk.dts
@@ -21,6 +21,36 @@ memory@40000000 {
reg = <0x00000000 0x40000000 0 0xc0000000>;
};
+ m2-connector {
+ compatible = "pcie-m2-e-connector";
+ vpcie3v3-supply = <®_pcie1>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ m2_e_pcie_ep: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&pcie1_port0_ep>;
+ };
+ };
+
+ port@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ m2_e_uart_ep: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&uart3_ep>;
+ };
+ };
+ };
+ };
+
pcie0_refclk: pcie0-refclk {
compatible = "fixed-clock";
#clock-cells = <0>;
@@ -420,8 +450,12 @@ &pcie1_ep {
&pcie1_port0 {
reset-gpios = <&gpio5 12 GPIO_ACTIVE_LOW>;
- vpcie-supply = <®_pcie1>;
- vpcie3v3aux-supply = <®_pcie1>;
+
+ port {
+ pcie1_port0_ep: endpoint {
+ remote-endpoint = <&m2_e_pcie_ep>;
+ };
+ };
};
&pgc_gpu {
@@ -506,8 +540,10 @@ &uart3 { /* BT */
uart-has-rtscts;
status = "okay";
- bluetooth {
- compatible = "nxp,88w8987-bt";
+ port {
+ uart3_ep: endpoint {
+ remote-endpoint = <&m2_e_uart_ep>;
+ };
};
};
--
2.50.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox