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>
This commit is contained in:
Remo Senekowitsch 2025-06-11 12:29:00 +02:00 committed by Danilo Krummrich
parent 19272b37aa
commit a2801affa7
5 changed files with 86 additions and 0 deletions

View File

@ -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

View File

@ -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"

8
rust/helpers/property.c Normal file
View File

@ -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);
}

View File

@ -14,6 +14,8 @@
#[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

View File

@ -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()) }
}
}