Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rust: device: Implement accessors for firmware properties

Add methods to FwNode for reading several firmware property types like
strings, integers and arrays.

Most types are read with the generic `property_read` method. There are
two exceptions:

* `property_read_bool` cannot fail, so the fallible function signature
of `property_read` would not make sense for reading booleans.

* `property_read_array_vec` can fail because of a dynamic memory
allocation. This error must be handled separately, leading to a
different function signature than `property_read`.

The traits `Property` and `PropertyInt` drive the generic behavior
of `property_read`. `PropertyInt` is necessary to associate
specific integer types with the C functions to read them. While
there is a C function to read integers of generic sizes called
`fwnode_property_read_int_array`, it was preferred not to make this
public.

Tested-by: Dirk Behme <dirk.behme@de.bosch.com>
Co-developed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Remo Senekowitsch <remo@buenzli.dev>
Link: https://lore.kernel.org/r/20250611102908.212514-7-remo@buenzli.dev
[ Properly include kernel::device::private::Sealed; add explicit type
annotations for core::mem::transmute(). - Danilo ]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>

authored by

Remo Senekowitsch and committed by
Danilo Krummrich
2db61137 9bd791d9

+252 -2
+252 -2
rust/kernel/device/property.rs
··· 4 4 //! 5 5 //! C header: [`include/linux/property.h`](srctree/include/linux/property.h) 6 6 7 - use core::ptr; 7 + use core::{mem::MaybeUninit, ptr}; 8 8 9 + use super::private::Sealed; 9 10 use crate::{ 11 + alloc::KVec, 10 12 bindings, 13 + error::{to_result, Result}, 11 14 prelude::*, 12 - str::CStr, 15 + str::{CStr, CString}, 13 16 types::{ARef, Opaque}, 14 17 }; 15 18 ··· 92 89 // SAFETY: By the invariant of `CStr`, `name` is null-terminated. 93 90 unsafe { bindings::fwnode_property_present(self.as_raw().cast_const(), name.as_char_ptr()) } 94 91 } 92 + 93 + /// Returns firmware property `name` boolean value. 94 + pub fn property_read_bool(&self, name: &CStr) -> bool { 95 + // SAFETY: 96 + // - `name` is non-null and null-terminated. 97 + // - `self.as_raw()` is valid because `self` is valid. 98 + unsafe { bindings::fwnode_property_read_bool(self.as_raw(), name.as_char_ptr()) } 99 + } 100 + 101 + /// Returns the index of matching string `match_str` for firmware string 102 + /// property `name`. 103 + pub fn property_match_string(&self, name: &CStr, match_str: &CStr) -> Result<usize> { 104 + // SAFETY: 105 + // - `name` and `match_str` are non-null and null-terminated. 106 + // - `self.as_raw` is valid because `self` is valid. 107 + let ret = unsafe { 108 + bindings::fwnode_property_match_string( 109 + self.as_raw(), 110 + name.as_char_ptr(), 111 + match_str.as_char_ptr(), 112 + ) 113 + }; 114 + to_result(ret)?; 115 + Ok(ret as usize) 116 + } 117 + 118 + /// Returns firmware property `name` integer array values in a [`KVec`]. 119 + pub fn property_read_array_vec<'fwnode, 'name, T: PropertyInt>( 120 + &'fwnode self, 121 + name: &'name CStr, 122 + len: usize, 123 + ) -> Result<PropertyGuard<'fwnode, 'name, KVec<T>>> { 124 + let mut val: KVec<T> = KVec::with_capacity(len, GFP_KERNEL)?; 125 + 126 + let res = T::read_array_from_fwnode_property(self, name, val.spare_capacity_mut()); 127 + let res = match res { 128 + Ok(_) => { 129 + // SAFETY: 130 + // - `len` is equal to `val.capacity - val.len`, because 131 + // `val.capacity` is `len` and `val.len` is zero. 132 + // - All elements within the interval [`0`, `len`) were initialized 133 + // by `read_array_from_fwnode_property`. 134 + unsafe { val.inc_len(len) } 135 + Ok(val) 136 + } 137 + Err(e) => Err(e), 138 + }; 139 + Ok(PropertyGuard { 140 + inner: res, 141 + fwnode: self, 142 + name, 143 + }) 144 + } 145 + 146 + /// Returns integer array length for firmware property `name`. 147 + pub fn property_count_elem<T: PropertyInt>(&self, name: &CStr) -> Result<usize> { 148 + T::read_array_len_from_fwnode_property(self, name) 149 + } 150 + 151 + /// Returns the value of firmware property `name`. 152 + /// 153 + /// This method is generic over the type of value to read. The types that 154 + /// can be read are strings, integers and arrays of integers. 155 + /// 156 + /// Reading a [`KVec`] of integers is done with the separate 157 + /// method [`Self::property_read_array_vec`], because it takes an 158 + /// additional `len` argument. 159 + /// 160 + /// Reading a boolean is done with the separate method 161 + /// [`Self::property_read_bool`], because this operation is infallible. 162 + /// 163 + /// For more precise documentation about what types can be read, see 164 + /// the [implementors of Property][Property#implementors] and [its 165 + /// implementations on foreign types][Property#foreign-impls]. 166 + /// 167 + /// # Examples 168 + /// 169 + /// ``` 170 + /// # use kernel::{c_str, device::{Device, property::FwNode}, str::CString}; 171 + /// fn examples(dev: &Device) -> Result { 172 + /// let fwnode = dev.fwnode().ok_or(ENOENT)?; 173 + /// let b: u32 = fwnode.property_read(c_str!("some-number")).required_by(dev)?; 174 + /// if let Some(s) = fwnode.property_read::<CString>(c_str!("some-str")).optional() { 175 + /// // ... 176 + /// } 177 + /// Ok(()) 178 + /// } 179 + /// ``` 180 + pub fn property_read<'fwnode, 'name, T: Property>( 181 + &'fwnode self, 182 + name: &'name CStr, 183 + ) -> PropertyGuard<'fwnode, 'name, T> { 184 + PropertyGuard { 185 + inner: T::read_from_fwnode_property(self, name), 186 + fwnode: self, 187 + name, 188 + } 189 + } 95 190 } 96 191 97 192 // SAFETY: Instances of `FwNode` are always reference-counted. ··· 255 154 256 155 Ok(()) 257 156 } 157 + } 158 + 159 + /// Implemented for types that can be read as properties. 160 + /// 161 + /// This is implemented for strings, integers and arrays of integers. It's used 162 + /// to make [`FwNode::property_read`] generic over the type of property being 163 + /// read. There are also two dedicated methods to read other types, because they 164 + /// require more specialized function signatures: 165 + /// - [`property_read_bool`](FwNode::property_read_bool) 166 + /// - [`property_read_array_vec`](FwNode::property_read_array_vec) 167 + /// 168 + /// It must be public, because it appears in the signatures of other public 169 + /// functions, but its methods shouldn't be used outside the kernel crate. 170 + pub trait Property: Sized + Sealed { 171 + /// Used to make [`FwNode::property_read`] generic. 172 + fn read_from_fwnode_property(fwnode: &FwNode, name: &CStr) -> Result<Self>; 173 + } 174 + 175 + impl Sealed for CString {} 176 + 177 + impl Property for CString { 178 + fn read_from_fwnode_property(fwnode: &FwNode, name: &CStr) -> Result<Self> { 179 + let mut str: *mut u8 = ptr::null_mut(); 180 + let pstr: *mut _ = &mut str; 181 + 182 + // SAFETY: 183 + // - `name` is non-null and null-terminated. 184 + // - `fwnode.as_raw` is valid because `fwnode` is valid. 185 + let ret = unsafe { 186 + bindings::fwnode_property_read_string(fwnode.as_raw(), name.as_char_ptr(), pstr.cast()) 187 + }; 188 + to_result(ret)?; 189 + 190 + // SAFETY: 191 + // - `pstr` is a valid pointer to a NUL-terminated C string. 192 + // - It is valid for at least as long as `fwnode`, but it's only used 193 + // within the current function. 194 + // - The memory it points to is not mutated during that time. 195 + let str = unsafe { CStr::from_char_ptr(*pstr) }; 196 + Ok(str.try_into()?) 197 + } 198 + } 199 + 200 + /// Implemented for all integers that can be read as properties. 201 + /// 202 + /// This helper trait is needed on top of the existing [`Property`] 203 + /// trait to associate the integer types of various sizes with their 204 + /// corresponding `fwnode_property_read_*_array` functions. 205 + /// 206 + /// It must be public, because it appears in the signatures of other public 207 + /// functions, but its methods shouldn't be used outside the kernel crate. 208 + pub trait PropertyInt: Copy + Sealed { 209 + /// Reads a property array. 210 + fn read_array_from_fwnode_property<'a>( 211 + fwnode: &FwNode, 212 + name: &CStr, 213 + out: &'a mut [MaybeUninit<Self>], 214 + ) -> Result<&'a mut [Self]>; 215 + 216 + /// Reads the length of a property array. 217 + fn read_array_len_from_fwnode_property(fwnode: &FwNode, name: &CStr) -> Result<usize>; 218 + } 219 + // This macro generates implementations of the traits `Property` and 220 + // `PropertyInt` for integers of various sizes. Its input is a list 221 + // of pairs separated by commas. The first element of the pair is the 222 + // type of the integer, the second one is the name of its corresponding 223 + // `fwnode_property_read_*_array` function. 224 + macro_rules! impl_property_for_int { 225 + ($($int:ty: $f:ident),* $(,)?) => { $( 226 + impl Sealed for $int {} 227 + impl<const N: usize> Sealed for [$int; N] {} 228 + 229 + impl PropertyInt for $int { 230 + fn read_array_from_fwnode_property<'a>( 231 + fwnode: &FwNode, 232 + name: &CStr, 233 + out: &'a mut [MaybeUninit<Self>], 234 + ) -> Result<&'a mut [Self]> { 235 + // SAFETY: 236 + // - `fwnode`, `name` and `out` are all valid by their type 237 + // invariants. 238 + // - `out.len()` is a valid bound for the memory pointed to by 239 + // `out.as_mut_ptr()`. 240 + // CAST: It's ok to cast from `*mut MaybeUninit<$int>` to a 241 + // `*mut $int` because they have the same memory layout. 242 + let ret = unsafe { 243 + bindings::$f( 244 + fwnode.as_raw(), 245 + name.as_char_ptr(), 246 + out.as_mut_ptr().cast(), 247 + out.len(), 248 + ) 249 + }; 250 + to_result(ret)?; 251 + // SAFETY: Transmuting from `&'a mut [MaybeUninit<Self>]` to 252 + // `&'a mut [Self]` is sound, because the previous call to a 253 + // `fwnode_property_read_*_array` function (which didn't fail) 254 + // fully initialized the slice. 255 + Ok(unsafe { core::mem::transmute::<&mut [MaybeUninit<Self>], &mut [Self]>(out) }) 256 + } 257 + 258 + fn read_array_len_from_fwnode_property(fwnode: &FwNode, name: &CStr) -> Result<usize> { 259 + // SAFETY: 260 + // - `fwnode` and `name` are valid by their type invariants. 261 + // - It's ok to pass a null pointer to the 262 + // `fwnode_property_read_*_array` functions if `nval` is zero. 263 + // This will return the length of the array. 264 + let ret = unsafe { 265 + bindings::$f( 266 + fwnode.as_raw(), 267 + name.as_char_ptr(), 268 + ptr::null_mut(), 269 + 0, 270 + ) 271 + }; 272 + to_result(ret)?; 273 + Ok(ret as usize) 274 + } 275 + } 276 + 277 + impl Property for $int { 278 + fn read_from_fwnode_property(fwnode: &FwNode, name: &CStr) -> Result<Self> { 279 + let val: [_; 1] = <[$int; 1]>::read_from_fwnode_property(fwnode, name)?; 280 + Ok(val[0]) 281 + } 282 + } 283 + 284 + impl<const N: usize> Property for [$int; N] { 285 + fn read_from_fwnode_property(fwnode: &FwNode, name: &CStr) -> Result<Self> { 286 + let mut val: [MaybeUninit<$int>; N] = [const { MaybeUninit::uninit() }; N]; 287 + 288 + <$int>::read_array_from_fwnode_property(fwnode, name, &mut val)?; 289 + 290 + // SAFETY: `val` is always initialized when 291 + // `fwnode_property_read_*_array` is successful. 292 + Ok(val.map(|v| unsafe { v.assume_init() })) 293 + } 294 + } 295 + )* }; 296 + } 297 + impl_property_for_int! { 298 + u8: fwnode_property_read_u8_array, 299 + u16: fwnode_property_read_u16_array, 300 + u32: fwnode_property_read_u32_array, 301 + u64: fwnode_property_read_u64_array, 302 + i8: fwnode_property_read_u8_array, 303 + i16: fwnode_property_read_u16_array, 304 + i32: fwnode_property_read_u32_array, 305 + i64: fwnode_property_read_u64_array, 258 306 } 259 307 260 308 /// A helper for reading device properties.