diff options
author | 2025-06-11 12:29:00 +0200 | |
---|---|---|
committer | 2025-06-12 23:56:42 +0200 | |
commit | a2801affa7103862d549050401a9f53b3365fca4 (patch) | |
tree | edbb87db9147201aadb1e63d4f215faa726d6f30 | |
parent | Linux 6.16-rc1 (diff) | |
download | wireguard-linux-a2801affa7103862d549050401a9f53b3365fca4.tar.xz wireguard-linux-a2801affa7103862d549050401a9f53b3365fca4.zip |
rust: device: Create FwNode abstraction for accessing device properties
Accessing device properties is currently done via methods on `Device`
itself, using bindings to device_property_* functions. This is
sufficient for the existing method property_present. However, it's not
sufficient for other device properties we want to access. For example,
iterating over child nodes of a device will yield a fwnode_handle.
That's not a device, so it wouldn't be possible to read the properties
of that child node. Thus, we need an abstraction over fwnode_handle and
methods for reading its properties.
Add a struct FwNode which abstracts over the C struct fwnode_handle.
Implement its reference counting analogous to other Rust abstractions
over reference-counted C structs.
Subsequent patches will add functionality to access FwNode and read
properties with it.
Tested-by: Dirk Behme <dirk.behme@de.bosch.com>
Signed-off-by: Remo Senekowitsch <remo@buenzli.dev>
Link: https://lore.kernel.org/r/20250611102908.212514-2-remo@buenzli.dev
[ Add temporary #[expect(dead_code)] to avoid a warning. - Danilo ]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
-rw-r--r-- | MAINTAINERS | 1 | ||||
-rw-r--r-- | rust/helpers/helpers.c | 1 | ||||
-rw-r--r-- | rust/helpers/property.c | 8 | ||||
-rw-r--r-- | rust/kernel/device.rs | 2 | ||||
-rw-r--r-- | rust/kernel/device/property.rs | 74 |
5 files changed, 86 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index a92290fffa16..9f724cd556f4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7366,6 +7366,7 @@ F: include/linux/property.h F: include/linux/sysfs.h F: lib/kobj* F: rust/kernel/device.rs +F: rust/kernel/device/ F: rust/kernel/device_id.rs F: rust/kernel/devres.rs F: rust/kernel/driver.rs diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 0f1b5d115985..ed00695af971 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -30,6 +30,7 @@ #include "platform.c" #include "pci.c" #include "pid_namespace.c" +#include "property.c" #include "rbtree.c" #include "rcu.c" #include "refcount.c" diff --git a/rust/helpers/property.c b/rust/helpers/property.c new file mode 100644 index 000000000000..08f68e2dac4a --- /dev/null +++ b/rust/helpers/property.c @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/property.h> + +void rust_helper_fwnode_handle_put(struct fwnode_handle *fwnode) +{ + fwnode_handle_put(fwnode); +} diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index dea06b79ecb5..d6237827a936 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -14,6 +14,8 @@ use core::{fmt, marker::PhantomData, ptr}; #[cfg(CONFIG_PRINTK)] use crate::c_str; +pub mod property; + /// A reference-counted device. /// /// This structure represents the Rust abstraction for a C `struct device`. This implementation diff --git a/rust/kernel/device/property.rs b/rust/kernel/device/property.rs new file mode 100644 index 000000000000..82ef54b54f18 --- /dev/null +++ b/rust/kernel/device/property.rs @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Unified device property interface. +//! +//! C header: [`include/linux/property.h`](srctree/include/linux/property.h) + +use core::ptr; + +use crate::{ + bindings, + types::{ARef, Opaque}, +}; + +/// A reference-counted fwnode_handle. +/// +/// This structure represents the Rust abstraction for a +/// C `struct fwnode_handle`. This implementation abstracts the usage of an +/// already existing C `struct fwnode_handle` within Rust code that we get +/// passed from the C side. +/// +/// # Invariants +/// +/// A `FwNode` instance represents a valid `struct fwnode_handle` created by the +/// C portion of the kernel. +/// +/// Instances of this type are always reference-counted, that is, a call to +/// `fwnode_handle_get` ensures that the allocation remains valid at least until +/// the matching call to `fwnode_handle_put`. +#[repr(transparent)] +pub struct FwNode(Opaque<bindings::fwnode_handle>); + +impl FwNode { + /// # Safety + /// + /// Callers must ensure that: + /// - The reference count was incremented at least once. + /// - They relinquish that increment. That is, if there is only one + /// increment, callers must not use the underlying object anymore -- it is + /// only safe to do so via the newly created `ARef<FwNode>`. + #[expect(dead_code)] + unsafe fn from_raw(raw: *mut bindings::fwnode_handle) -> ARef<Self> { + // SAFETY: As per the safety requirements of this function: + // - `NonNull::new_unchecked`: + // - `raw` is not null. + // - `ARef::from_raw`: + // - `raw` has an incremented refcount. + // - that increment is relinquished, i.e. it won't be decremented + // elsewhere. + // CAST: It is safe to cast from a `*mut fwnode_handle` to + // `*mut FwNode`, because `FwNode` is defined as a + // `#[repr(transparent)]` wrapper around `fwnode_handle`. + unsafe { ARef::from_raw(ptr::NonNull::new_unchecked(raw.cast())) } + } + + /// Obtain the raw `struct fwnode_handle *`. + pub(crate) fn as_raw(&self) -> *mut bindings::fwnode_handle { + self.0.get() + } +} + +// SAFETY: Instances of `FwNode` are always reference-counted. +unsafe impl crate::types::AlwaysRefCounted for FwNode { + fn inc_ref(&self) { + // SAFETY: The existence of a shared reference guarantees that the + // refcount is non-zero. + unsafe { bindings::fwnode_handle_get(self.as_raw()) }; + } + + unsafe fn dec_ref(obj: ptr::NonNull<Self>) { + // SAFETY: The safety requirements guarantee that the refcount is + // non-zero. + unsafe { bindings::fwnode_handle_put(obj.cast().as_ptr()) } + } +} |