From nobody Fri Dec 19 17:36:21 2025 Received: from mout-p-201.mailbox.org (mout-p-201.mailbox.org [80.241.56.171]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4252225D1F7; Fri, 25 Apr 2025 15:02:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=80.241.56.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745593338; cv=none; b=H42LJS2VmJTXTXi52j/Rja0uaanEzcOvFIWqkK2buLvAK7g5J3pNx1muz0drbkxGMnNiN2EEMib+9e0Ar+IKwMRcFTo0+zrloEqPMRiNgbMMVwRJkCHpIc4aXX/8ZBjX8Jkh6p4EysOb2xhy5mbWwVOovS9qbzuUFyGakrrQXS4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745593338; c=relaxed/simple; bh=KeMi7aWTKimdysNNp/dvl+FY+DnpfOJGIWKRaRPVmxc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=EU6hgv+SA7jOGicy4ifbsjt1ro71KW9ruhQQSoxwTMzzyme0jviAfN0xQyF5n2FJyzV8+zdEE7N0UXt/nVDApAhufjr51UG3QuFf17LjULNzduiXyjqPPTphf/6nL1Joacr6DP6K3GcZqHVxuucsZsrmblvJxBwMbKcMiJ1ZXI0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=buenzli.dev; spf=pass smtp.mailfrom=buenzli.dev; arc=none smtp.client-ip=80.241.56.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=buenzli.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=buenzli.dev Received: from smtp202.mailbox.org (smtp202.mailbox.org [10.196.197.202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-201.mailbox.org (Postfix) with ESMTPS id 4ZkbfX3fjYz9sv9; Fri, 25 Apr 2025 17:02:12 +0200 (CEST) From: Remo Senekowitsch To: Rob Herring , Saravana Kannan , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Greg Kroah-Hartman , "Rafael J. Wysocki" , Dirk Behme , Remo Senekowitsch Cc: linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, rust-for-linux@vger.kernel.org Subject: [PATCH v3 5/7] rust: property: Add child accessor and iterator Date: Fri, 25 Apr 2025 17:01:28 +0200 Message-ID: <20250425150130.13917-6-remo@buenzli.dev> In-Reply-To: <20250425150130.13917-1-remo@buenzli.dev> References: <20250425150130.13917-1-remo@buenzli.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Allow Rust drivers to access children of a fwnode either by name or by iterating over all of them. In C, there is the function `fwnode_get_next_child_node` for iteration and the macro `fwnode_for_each_child_node` that helps with handling the pointers. Instead of a macro, a native iterator is used in Rust such that regular for-loops can be used. Signed-off-by: Remo Senekowitsch --- rust/kernel/device/property.rs | 79 +++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/rust/kernel/device/property.rs b/rust/kernel/device/property.rs index 9505cc35d..0a0cb0c02 100644 --- a/rust/kernel/device/property.rs +++ b/rust/kernel/device/property.rs @@ -13,7 +13,7 @@ error::{to_result, Result}, prelude::*, str::{CStr, CString}, - types::Opaque, + types::{ARef, Opaque}, }; =20 impl Device { @@ -52,6 +52,27 @@ pub fn fwnode(&self) -> Option<&FwNode> { pub struct FwNode(Opaque); =20 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`. + unsafe fn from_raw(raw: *mut bindings::fwnode_handle) -> ARef { + // 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() @@ -238,6 +259,62 @@ pub fn property_read<'fwnode, 'name, T: Property>( name, } } + + /// Returns first matching named child node handle. + pub fn get_child_by_name(&self, name: &CStr) -> Option> { + // SAFETY: `self` and `name` are valid by their type invariants. + let child =3D + unsafe { bindings::fwnode_get_named_child_node(self.as_raw(), = name.as_char_ptr()) }; + if child.is_null() { + return None; + } + // SAFETY: + // - `fwnode_get_named_child_node` returns a pointer with its refc= ount + // incremented. + // - That increment is relinquished, i.e. the underlying object is= not + // used anymore except via the newly created `ARef`. + Some(unsafe { Self::from_raw(child) }) + } + + /// Returns an iterator over a node's children. + pub fn children<'a>(&'a self) -> impl Iterator> = + 'a { + let mut prev: Option> =3D None; + + core::iter::from_fn(move || { + let prev_ptr =3D match prev.take() { + None =3D> ptr::null_mut(), + Some(prev) =3D> { + // We will pass `prev` to `fwnode_get_next_child_node`, + // which decrements its refcount, so we use + // `ARef::into_raw` to avoid decrementing the refcount + // twice. + let prev =3D ARef::into_raw(prev); + prev.as_ptr().cast() + } + }; + // SAFETY: + // - `self.as_raw()` is valid by its type invariant. + // - `prev_ptr` may be null, which is allowed and corresponds = to + // getting the first child. Otherwise, `prev_ptr` is valid, = as it + // is the stored return value from the previous invocation. + // - `prev_ptr` has its refount incremented. + // - The increment of `prev_ptr` is relinquished, i.e. the + // underlying object won't be unsed anymore. + let next =3D unsafe { bindings::fwnode_get_next_child_node(sel= f.as_raw(), prev_ptr) }; + if next.is_null() { + return None; + } + // SAFETY: + // - `next` is valid because `fwnode_get_next_child_node` retu= rns a + // pointer with its refcount incremented. + // - That increment is relinquished, i.e. the underlying object + // won't be used anymore, except via the newly created + // `ARef`. + let next =3D unsafe { FwNode::from_raw(next) }; + prev =3D Some(next.clone()); + Some(next) + }) + } } =20 // SAFETY: Instances of `FwNode` are always reference-counted. --=20 2.49.0