From: Remo Senekowitsch Date: Wed, 11 Jun 2025 10:29:03 +0000 (+0200) Subject: rust: device: Enable printing fwnode name and path X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=ecea2459818383c2886ec1cff81cce7e70d99893;p=users%2Fjedix%2Flinux-maple.git rust: device: Enable printing fwnode name and path Add two new public methods `display_name` and `display_path` to `FwNode`. They can be used by driver authors for logging purposes. In addition, they will be used by core property abstractions for automatic logging, for example when a driver attempts to read a required but missing property. Tested-by: Dirk Behme Signed-off-by: Remo Senekowitsch Link: https://lore.kernel.org/r/20250611102908.212514-5-remo@buenzli.dev [ Remove #[expect(dead_code)] from FwNode::from_raw(). - Danilo ] Signed-off-by: Danilo Krummrich --- diff --git a/rust/kernel/device/property.rs b/rust/kernel/device/property.rs index ed17b20f7ae11..4cac335bad78c 100644 --- a/rust/kernel/device/property.rs +++ b/rust/kernel/device/property.rs @@ -38,7 +38,6 @@ impl FwNode { /// - 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`. - #[expect(dead_code)] unsafe fn from_raw(raw: *mut bindings::fwnode_handle) -> ARef { // SAFETY: As per the safety requirements of this function: // - `NonNull::new_unchecked`: @@ -58,6 +57,32 @@ impl FwNode { self.0.get() } + /// Returns an object that implements [`Display`](core::fmt::Display) for + /// printing the name of a node. + /// + /// This is an alternative to the default `Display` implementation, which + /// prints the full path. + pub fn display_name(&self) -> impl core::fmt::Display + '_ { + struct FwNodeDisplayName<'a>(&'a FwNode); + + impl core::fmt::Display for FwNodeDisplayName<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + // SAFETY: `self` is valid by its type invariant. + let name = unsafe { bindings::fwnode_get_name(self.0.as_raw()) }; + if name.is_null() { + return Ok(()); + } + // SAFETY: + // - `fwnode_get_name` returns null or a valid C string. + // - `name` was checked to be non-null. + let name = unsafe { CStr::from_char_ptr(name) }; + write!(f, "{name}") + } + } + + FwNodeDisplayName(self) + } + /// Checks if property is present or not. pub fn property_present(&self, name: &CStr) -> bool { // SAFETY: By the invariant of `CStr`, `name` is null-terminated. @@ -79,3 +104,53 @@ unsafe impl crate::types::AlwaysRefCounted for FwNode { unsafe { bindings::fwnode_handle_put(obj.cast().as_ptr()) } } } + +enum Node<'a> { + Borrowed(&'a FwNode), + Owned(ARef), +} + +impl core::fmt::Display for FwNode { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + // The logic here is the same as the one in lib/vsprintf.c + // (fwnode_full_name_string). + + // SAFETY: `self.as_raw()` is valid by its type invariant. + let num_parents = unsafe { bindings::fwnode_count_parents(self.as_raw()) }; + + for depth in (0..=num_parents).rev() { + let fwnode = if depth == 0 { + Node::Borrowed(self) + } else { + // SAFETY: `self.as_raw()` is valid. + let ptr = unsafe { bindings::fwnode_get_nth_parent(self.as_raw(), depth) }; + // SAFETY: + // - The depth passed to `fwnode_get_nth_parent` is + // within the valid range, so the returned pointer is + // not null. + // - The reference count was incremented by + // `fwnode_get_nth_parent`. + // - That increment is relinquished to + // `FwNode::from_raw`. + Node::Owned(unsafe { FwNode::from_raw(ptr) }) + }; + // Take a reference to the owned or borrowed `FwNode`. + let fwnode: &FwNode = match &fwnode { + Node::Borrowed(f) => f, + Node::Owned(f) => f, + }; + + // SAFETY: `fwnode` is valid by its type invariant. + let prefix = unsafe { bindings::fwnode_get_name_prefix(fwnode.as_raw()) }; + if !prefix.is_null() { + // SAFETY: `fwnode_get_name_prefix` returns null or a + // valid C string. + let prefix = unsafe { CStr::from_char_ptr(prefix) }; + write!(f, "{prefix}")?; + } + write!(f, "{}", fwnode.display_name())?; + } + + Ok(()) + } +}