From nobody Fri Oct 10 02:44:39 2025 Received: from mout-p-101.mailbox.org (mout-p-101.mailbox.org [80.241.56.151]) (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 5D02927F73D; Mon, 16 Jun 2025 15:45:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=80.241.56.151 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750088728; cv=none; b=ndB3VwcMs0q7NW/ODgLxNWC6mou3FrrTriZ2Rf5C2hCgnckD8b4J3iiD+gm1ngJoc7lYifA6ymAY64XCYEHuHSlkF7pbJHlLANgvjP9TbD9AFHe2OaohfLzvaTspIRYTpAKDPhIctFIxmJSuWtlq+cEjM+6AyE8G7uxq5iKuj94= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750088728; c=relaxed/simple; bh=2DcCEW5A+fitd6ayjyNNQC+WlEKDFwvkCcCfv+9L59g=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sSlVzZJ68R2/pw7hHaaoJFzbcj+XwcnIxLMUa3oGdhG1hhf2nFPq0dgTHbIMbwG+sebrQqUbzWVFbfT0mrigPDzJEjBP8YupqmMKA9RKm9fmqHRMC8zHfPLzrqSkfqNstnWP8Br6R6WMQ53bTYPRGwzAcf3e7vxqVGyYMtaJVnA= 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.151 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 smtp102.mailbox.org (smtp102.mailbox.org [IPv6:2001:67c:2050:b231:465::102]) (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-101.mailbox.org (Postfix) with ESMTPS id 4bLZ8L4Qhyz9sxH; Mon, 16 Jun 2025 17:45:22 +0200 (CEST) From: Remo Senekowitsch To: Rob Herring , Saravana Kannan , Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Mark Brown , Dirk Behme , Remo Senekowitsch Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org Subject: [PATCH v1 1/3] rust: device: Add child accessor and iterator Date: Mon, 16 Jun 2025 17:45:09 +0200 Message-ID: <20250616154511.1862909-2-remo@buenzli.dev> In-Reply-To: <20250616154511.1862909-1-remo@buenzli.dev> References: <20250616154511.1862909-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 X-Rspamd-Queue-Id: 4bLZ8L4Qhyz9sxH 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. Tested-by: Dirk Behme Signed-off-by: Remo Senekowitsch --- rust/kernel/device/property.rs | 56 ++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/rust/kernel/device/property.rs b/rust/kernel/device/property.rs index 838509111e57..04a13d05785a 100644 --- a/rust/kernel/device/property.rs +++ b/rust/kernel/device/property.rs @@ -190,6 +190,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 used 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