Skip to content

Commit 1e5dfb5

Browse files
senekorjannau
authored andcommitted
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>
1 parent c13016a commit 1e5dfb5

1 file changed

Lines changed: 253 additions & 2 deletions

File tree

rust/kernel/device/property.rs

Lines changed: 253 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@
44
//!
55
//! C header: [`include/linux/property.h`](srctree/include/linux/property.h)
66
7-
use core::ptr;
7+
use core::{mem::MaybeUninit, ptr};
88

99
use crate::{
10+
alloc::KVec,
1011
bindings,
11-
str::CStr,
12+
error::{to_result, Result},
13+
prelude::*,
14+
private::Sealed,
15+
str::{CStr, CString},
1216
types::{ARef, Opaque},
1317
};
1418

@@ -88,6 +92,104 @@ impl FwNode {
8892
// SAFETY: By the invariant of `CStr`, `name` is null-terminated.
8993
unsafe { bindings::fwnode_property_present(self.as_raw().cast_const(), name.as_char_ptr()) }
9094
}
95+
96+
/// Returns firmware property `name` boolean value.
97+
pub fn property_read_bool(&self, name: &CStr) -> bool {
98+
// SAFETY:
99+
// - `name` is non-null and null-terminated.
100+
// - `self.as_raw()` is valid because `self` is valid.
101+
unsafe { bindings::fwnode_property_read_bool(self.as_raw(), name.as_char_ptr()) }
102+
}
103+
104+
/// Returns the index of matching string `match_str` for firmware string
105+
/// property `name`.
106+
pub fn property_match_string(&self, name: &CStr, match_str: &CStr) -> Result<usize> {
107+
// SAFETY:
108+
// - `name` and `match_str` are non-null and null-terminated.
109+
// - `self.as_raw` is valid because `self` is valid.
110+
let ret = unsafe {
111+
bindings::fwnode_property_match_string(
112+
self.as_raw(),
113+
name.as_char_ptr(),
114+
match_str.as_char_ptr(),
115+
)
116+
};
117+
to_result(ret)?;
118+
Ok(ret as usize)
119+
}
120+
121+
/// Returns firmware property `name` integer array values in a [`KVec`].
122+
pub fn property_read_array_vec<'fwnode, 'name, T: PropertyInt>(
123+
&'fwnode self,
124+
name: &'name CStr,
125+
len: usize,
126+
) -> Result<PropertyGuard<'fwnode, 'name, KVec<T>>> {
127+
let mut val: KVec<T> = KVec::with_capacity(len, GFP_KERNEL)?;
128+
129+
let res = T::read_array_from_fwnode_property(self, name, val.spare_capacity_mut());
130+
let res = match res {
131+
Ok(_) => {
132+
// SAFETY:
133+
// - `len` is equal to `val.capacity - val.len`, because
134+
// `val.capacity` is `len` and `val.len` is zero.
135+
// - All elements within the interval [`0`, `len`) were initialized
136+
// by `read_array_from_fwnode_property`.
137+
unsafe { val.inc_len(len) }
138+
Ok(val)
139+
}
140+
Err(e) => Err(e),
141+
};
142+
Ok(PropertyGuard {
143+
inner: res,
144+
fwnode: self,
145+
name,
146+
})
147+
}
148+
149+
/// Returns integer array length for firmware property `name`.
150+
pub fn property_count_elem<T: PropertyInt>(&self, name: &CStr) -> Result<usize> {
151+
T::read_array_len_from_fwnode_property(self, name)
152+
}
153+
154+
/// Returns the value of firmware property `name`.
155+
///
156+
/// This method is generic over the type of value to read. The types that
157+
/// can be read are strings, integers and arrays of integers.
158+
///
159+
/// Reading a [`KVec`] of integers is done with the separate
160+
/// method [`Self::property_read_array_vec`], because it takes an
161+
/// additional `len` argument.
162+
///
163+
/// Reading a boolean is done with the separate method
164+
/// [`Self::property_read_bool`], because this operation is infallible.
165+
///
166+
/// For more precise documentation about what types can be read, see
167+
/// the [implementors of Property][Property#implementors] and [its
168+
/// implementations on foreign types][Property#foreign-impls].
169+
///
170+
/// # Examples
171+
///
172+
/// ```
173+
/// # use kernel::{c_str, device::{Device, property::FwNode}, str::CString};
174+
/// fn examples(dev: &Device) -> Result {
175+
/// let fwnode = dev.fwnode().ok_or(ENOENT)?;
176+
/// let b: u32 = fwnode.property_read(c_str!("some-number")).required_by(dev)?;
177+
/// if let Some(s) = fwnode.property_read::<CString>(c_str!("some-str")).optional() {
178+
/// // ...
179+
/// }
180+
/// Ok(())
181+
/// }
182+
/// ```
183+
pub fn property_read<'fwnode, 'name, T: Property>(
184+
&'fwnode self,
185+
name: &'name CStr,
186+
) -> PropertyGuard<'fwnode, 'name, T> {
187+
PropertyGuard {
188+
inner: T::read_from_fwnode_property(self, name),
189+
fwnode: self,
190+
name,
191+
}
192+
}
91193
}
92194

93195
// SAFETY: Instances of `FwNode` are always reference-counted.
@@ -105,6 +207,155 @@ unsafe impl crate::types::AlwaysRefCounted for FwNode {
105207
}
106208
}
107209

210+
/// Implemented for types that can be read as properties.
211+
///
212+
/// This is implemented for strings, integers and arrays of integers. It's used
213+
/// to make [`FwNode::property_read`] generic over the type of property being
214+
/// read. There are also two dedicated methods to read other types, because they
215+
/// require more specialized function signatures:
216+
/// - [`property_read_bool`](FwNode::property_read_bool)
217+
/// - [`property_read_array_vec`](FwNode::property_read_array_vec)
218+
///
219+
/// It must be public, because it appears in the signatures of other public
220+
/// functions, but its methods shouldn't be used outside the kernel crate.
221+
pub trait Property: Sized + Sealed {
222+
/// Used to make [`FwNode::property_read`] generic.
223+
fn read_from_fwnode_property(fwnode: &FwNode, name: &CStr) -> Result<Self>;
224+
}
225+
226+
impl Sealed for CString {}
227+
228+
impl Property for CString {
229+
fn read_from_fwnode_property(fwnode: &FwNode, name: &CStr) -> Result<Self> {
230+
let mut str: *mut u8 = ptr::null_mut();
231+
let pstr: *mut _ = &mut str;
232+
233+
// SAFETY:
234+
// - `name` is non-null and null-terminated.
235+
// - `fwnode.as_raw` is valid because `fwnode` is valid.
236+
let ret = unsafe {
237+
bindings::fwnode_property_read_string(fwnode.as_raw(), name.as_char_ptr(), pstr.cast())
238+
};
239+
to_result(ret)?;
240+
241+
// SAFETY:
242+
// - `pstr` is a valid pointer to a NUL-terminated C string.
243+
// - It is valid for at least as long as `fwnode`, but it's only used
244+
// within the current function.
245+
// - The memory it points to is not mutated during that time.
246+
let str = unsafe { CStr::from_char_ptr(*pstr) };
247+
Ok(str.try_into()?)
248+
}
249+
}
250+
251+
/// Implemented for all integers that can be read as properties.
252+
///
253+
/// This helper trait is needed on top of the existing [`Property`]
254+
/// trait to associate the integer types of various sizes with their
255+
/// corresponding `fwnode_property_read_*_array` functions.
256+
///
257+
/// It must be public, because it appears in the signatures of other public
258+
/// functions, but its methods shouldn't be used outside the kernel crate.
259+
pub trait PropertyInt: Copy + Sealed {
260+
/// Reads a property array.
261+
fn read_array_from_fwnode_property<'a>(
262+
fwnode: &FwNode,
263+
name: &CStr,
264+
out: &'a mut [MaybeUninit<Self>],
265+
) -> Result<&'a mut [Self]>;
266+
267+
/// Reads the length of a property array.
268+
fn read_array_len_from_fwnode_property(fwnode: &FwNode, name: &CStr) -> Result<usize>;
269+
}
270+
// This macro generates implementations of the traits `Property` and
271+
// `PropertyInt` for integers of various sizes. Its input is a list
272+
// of pairs separated by commas. The first element of the pair is the
273+
// type of the integer, the second one is the name of its corresponding
274+
// `fwnode_property_read_*_array` function.
275+
macro_rules! impl_property_for_int {
276+
($($int:ty: $f:ident),* $(,)?) => { $(
277+
impl Sealed for $int {}
278+
impl<const N: usize> Sealed for [$int; N] {}
279+
280+
impl PropertyInt for $int {
281+
fn read_array_from_fwnode_property<'a>(
282+
fwnode: &FwNode,
283+
name: &CStr,
284+
out: &'a mut [MaybeUninit<Self>],
285+
) -> Result<&'a mut [Self]> {
286+
// SAFETY:
287+
// - `fwnode`, `name` and `out` are all valid by their type
288+
// invariants.
289+
// - `out.len()` is a valid bound for the memory pointed to by
290+
// `out.as_mut_ptr()`.
291+
// CAST: It's ok to cast from `*mut MaybeUninit<$int>` to a
292+
// `*mut $int` because they have the same memory layout.
293+
let ret = unsafe {
294+
bindings::$f(
295+
fwnode.as_raw(),
296+
name.as_char_ptr(),
297+
out.as_mut_ptr().cast(),
298+
out.len(),
299+
)
300+
};
301+
to_result(ret)?;
302+
// SAFETY: Transmuting from `&'a mut [MaybeUninit<Self>]` to
303+
// `&'a mut [Self]` is sound, because the previous call to a
304+
// `fwnode_property_read_*_array` function (which didn't fail)
305+
// fully initialized the slice.
306+
Ok(unsafe { core::mem::transmute(out) })
307+
}
308+
309+
fn read_array_len_from_fwnode_property(fwnode: &FwNode, name: &CStr) -> Result<usize> {
310+
// SAFETY:
311+
// - `fwnode` and `name` are valid by their type invariants.
312+
// - It's ok to pass a null pointer to the
313+
// `fwnode_property_read_*_array` functions if `nval` is zero.
314+
// This will return the length of the array.
315+
let ret = unsafe {
316+
bindings::$f(
317+
fwnode.as_raw(),
318+
name.as_char_ptr(),
319+
ptr::null_mut(),
320+
0,
321+
)
322+
};
323+
to_result(ret)?;
324+
Ok(ret as usize)
325+
}
326+
}
327+
328+
impl Property for $int {
329+
fn read_from_fwnode_property(fwnode: &FwNode, name: &CStr) -> Result<Self> {
330+
let val: [_; 1] = <[$int; 1]>::read_from_fwnode_property(fwnode, name)?;
331+
Ok(val[0])
332+
}
333+
}
334+
335+
impl<const N: usize> Property for [$int; N] {
336+
fn read_from_fwnode_property(fwnode: &FwNode, name: &CStr) -> Result<Self> {
337+
let mut val: [MaybeUninit<$int>; N] = [const { MaybeUninit::uninit() }; N];
338+
339+
<$int>::read_array_from_fwnode_property(fwnode, name, &mut val)?;
340+
341+
// SAFETY: `val` is always initialized when
342+
// `fwnode_property_read_*_array` is successful.
343+
Ok(val.map(|v| unsafe { v.assume_init() }))
344+
}
345+
}
346+
)* };
347+
}
348+
impl_property_for_int! {
349+
u8: fwnode_property_read_u8_array,
350+
u16: fwnode_property_read_u16_array,
351+
u32: fwnode_property_read_u32_array,
352+
u64: fwnode_property_read_u64_array,
353+
i8: fwnode_property_read_u8_array,
354+
i16: fwnode_property_read_u16_array,
355+
i32: fwnode_property_read_u32_array,
356+
i64: fwnode_property_read_u64_array,
357+
}
358+
108359
/// A helper for reading device properties.
109360
///
110361
/// Use [`Self::required_by`] if a missing property is considered a bug and

0 commit comments

Comments
 (0)