From nobody Thu Oct 9 20:24:37 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 From nobody Thu Oct 9 20:24:37 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 C776D2206AA; Mon, 16 Jun 2025 15:45:30 +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=1750088732; cv=none; b=nx2Aph+O5VOI+QcTYfrAvAzdCf8ZbaUBH1USn33htElhJPMP3Fqh0++EsKL/mnOpfziox5z7PTwVZul6WI49WN0EtoMQfu+1QHEKb4ivp8deIcZofwXL+XVSMj7pPdFkbGHyS7Z6/0tGJahKYrHY+PvlgJ1Et3mI/Tpr39VqQLk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750088732; c=relaxed/simple; bh=wCc2MJxokZdRhbLuh4AmtlILrl48Ts3XtGp1UmsQOBg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tpFrYytcpU6iFL5ZrQdxbZ3r65Cad3vG1LpfiIe8rVnPZVEj9AmuYfjIlK8i6UCG358Wqm16UUscrL0n6BEkuZErGF6QSgZa7LRD6Aw96n9zzlZAkf50FWb2R1jG8ORpw0WyH+kMXwaY15ChXz3sjI2iuK5Pg+E8cAOnD2KHIww= 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 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-201.mailbox.org (Postfix) with ESMTPS id 4bLZ8R0rZHz9sTh; Mon, 16 Jun 2025 17:45:27 +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 2/3] rust: device: Add property_get_reference_args Date: Mon, 16 Jun 2025 17:45:10 +0200 Message-ID: <20250616154511.1862909-3-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: 4bLZ8R0rZHz9sTh Content-Type: text/plain; charset="utf-8" Allow Rust code to read reference args from device properties. The wrapper type `FwNodeReferenceArgs` allows callers to access the buffer of read args safely. Signed-off-by: Remo Senekowitsch --- --- rust/kernel/device/property.rs | 102 +++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/rust/kernel/device/property.rs b/rust/kernel/device/property.rs index 04a13d05785a..f56ffbd43a94 100644 --- a/rust/kernel/device/property.rs +++ b/rust/kernel/device/property.rs @@ -246,6 +246,99 @@ pub fn children<'a>(&'a self) -> impl Iterator> + 'a { Some(next) }) } + + /// Finds a reference with arguments. + pub fn property_get_reference_args( + &self, + prop: &CStr, + nargs: NArgs<'_>, + index: u32, + ) -> Result { + let mut out_args =3D FwNodeReferenceArgs::default(); + + let (nargs_prop, nargs) =3D match nargs { + NArgs::Prop(nargs_prop) =3D> (nargs_prop.as_char_ptr(), 0), + NArgs::N(nargs) =3D> (ptr::null(), nargs), + }; + + // SAFETY: + // - `self.0.get()` is valid. + // - `prop.as_char_ptr()` is valid and zero-terminated. + // - `nargs_prop` is valid and zero-terminated if `nargs` + // is zero, otherwise it is allowed to be a null-pointer. + // - The function upholds the type invariants of `out_args`, + // namely: + // - It may fill the field `fwnode` with a valid pointer, + // in which case its refcount is incremented. + // - It may modify the field `nargs`, in which case it + // initializes at least as many elements in `args`. + let ret =3D unsafe { + bindings::fwnode_property_get_reference_args( + self.0.get(), + prop.as_char_ptr(), + nargs_prop, + nargs, + index, + &mut out_args.0, + ) + }; + to_result(ret)?; + + Ok(out_args) + } +} + +/// The return value of [`FwNode::property_get_reference_args`]. +/// +/// This structure represents the Rust abstraction for a C +/// `struct fwnode_reference_args` which was initialized by the C side. +/// +/// # Invariants +/// +/// If the field `fwnode` is valid, it owns an increment of its refcount. +/// +/// The field `args` contains at least as many initialized elements as ind= icated +/// by the field `nargs`. +#[repr(transparent)] +#[derive(Default)] +pub struct FwNodeReferenceArgs(bindings::fwnode_reference_args); + +impl Drop for FwNodeReferenceArgs { + fn drop(&mut self) { + if !self.0.fwnode.is_null() { + // SAFETY: + // - By the type invariants of `FwNodeReferenceArgs`, its field + // `fwnode` owns an increment of its refcount. + // - That increment is relinquished. The underlying object won= 't be + // used anymore because we are dropping it. + let _ =3D unsafe { FwNode::from_raw(self.0.fwnode) }; + } + } +} + +impl FwNodeReferenceArgs { + /// Returns the slice of reference arguments. + pub fn as_slice(&self) -> &[u64] { + // SAFETY: As per the safety invariant of `FwNodeReferenceArgs`, `= nargs` + // is the minimum number of elements in `args` that is valid. + unsafe { core::slice::from_raw_parts(self.0.args.as_ptr(), self.0.= nargs as usize) } + } + + /// Returns the number of reference arguments. + pub fn len(&self) -> usize { + self.0.nargs as usize + } + + /// Returns `true` if there are no reference arguments. + pub fn is_empty(&self) -> bool { + self.0.nargs =3D=3D 0 + } +} + +impl core::fmt::Debug for FwNodeReferenceArgs { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:?}", self.as_slice()) + } } =20 // SAFETY: Instances of `FwNode` are always reference-counted. @@ -462,6 +555,15 @@ fn read_from_fwnode_property(fwnode: &FwNode, name: &C= Str) -> Result { i64: fwnode_property_read_u64_array, } =20 +/// The number of arguments of a reference. +pub enum NArgs<'a> { + /// The name of the property of the reference indicating the number of + /// arguments. + Prop(&'a CStr), + /// The known number of arguments. + N(u32), +} + /// A helper for reading device properties. /// /// Use [`Self::required_by`] if a missing property is considered a bug and --=20 2.49.0 From nobody Thu Oct 9 20:24:37 2025 Received: from mout-p-202.mailbox.org (mout-p-202.mailbox.org [80.241.56.172]) (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 F092E272E48; Mon, 16 Jun 2025 15:45:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=80.241.56.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750088736; cv=none; b=sCfoO47G1qmZrH419heseR08FjPYl8x+G5BK6dOEOxn+hA3NkVfqLh+Ku557iR3kA1JdTR/YzyFH/1WhatTcI1LRatLANjVGDE58ANIEHpmcLoZNOhTP/bz09rXs8mXo2FvoEBDEHr7SdSUua6sSv0QCQfffJcJVYkwT7xMKN/E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750088736; c=relaxed/simple; bh=ra8p9X0kjOiFPIwyw3A4kgvR0ernRDG0F99sfFix9qg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dYXnFhqFFXWPCJL2/i9RsuqPNu3Qxut2rTovEUSJ4Az3Mmhsbk7/S01aPmmF1fmm+gHBNgPcJEwi0ZSDka/AlxOytdwdayxeM6mM1lMfFdQoxh/n6yKDCr6hUWcQHf21lNsTTLvwxvtAWS6i8A6fCXOBIBrm1U080pawIuS3oHw= 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.172 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 [10.196.197.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-202.mailbox.org (Postfix) with ESMTPS id 4bLZ8W4LT5z9sWF; Mon, 16 Jun 2025 17:45:31 +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 3/3] samples: rust: platform: Add property child and reference args examples Date: Mon, 16 Jun 2025 17:45:11 +0200 Message-ID: <20250616154511.1862909-4-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 Content-Type: text/plain; charset="utf-8" Add some example usage of the device property methods for reading DT/ACPI/swnode child nodes and reference args. Signed-off-by: Remo Senekowitsch --- drivers/of/unittest-data/tests-platform.dtsi | 7 +++++++ samples/rust/rust_driver_platform.rs | 13 ++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/of/unittest-data/tests-platform.dtsi b/drivers/of/unit= test-data/tests-platform.dtsi index 50a51f38afb6..509eb614ab2b 100644 --- a/drivers/of/unittest-data/tests-platform.dtsi +++ b/drivers/of/unittest-data/tests-platform.dtsi @@ -40,6 +40,13 @@ test-device@2 { =20 test,u32-prop =3D <0xdeadbeef>; test,i16-array =3D /bits/ 16 <1 2 (-3) (-4)>; + + ref_child_0: child@0 { + test,ref-arg =3D <&ref_child_1 0x20 0x32>; + }; + ref_child_1: child@1 { + test,ref-arg =3D <&ref_child_0 0x10 0x64>; + }; }; }; =20 diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_drive= r_platform.rs index c0abf78d0683..4dcedb22a4bb 100644 --- a/samples/rust/rust_driver_platform.rs +++ b/samples/rust/rust_driver_platform.rs @@ -4,7 +4,11 @@ =20 use kernel::{ c_str, - device::{self, Core}, + device::{ + self, + property::{FwNodeReferenceArgs, NArgs}, + Core, + }, of, platform, prelude::*, str::CString, @@ -91,6 +95,13 @@ fn properties_parse(dev: &device::Device) -> Result { let prop: KVec =3D fwnode.property_read_array_vec(name, 4)?.r= equired_by(dev)?; dev_info!(dev, "'{name}'=3D'{prop:?}' (KVec)\n"); =20 + for child in fwnode.children() { + let name =3D c_str!("test,ref-arg"); + let nargs =3D NArgs::N(2); + let prop: FwNodeReferenceArgs =3D child.property_get_reference= _args(name, nargs, 0)?; + dev_info!(dev, "'{name}'=3D'{prop:?}'\n"); + } + Ok(()) } } --=20 2.49.0