[PATCH 1/3] of: add of_property_read_variable_uxx_array()

Sascha Hauer s.hauer at pengutronix.de
Wed Apr 3 01:07:01 PDT 2024


This adds of_property_read_variable_uxx_array() which allow to read
arrays from properties with min/max size boundaries. Code is directly
taken from Linux.
We already had of_property_read_variable_u64_array(), but without
min/max arguments. This one is updated to match the Kernel code.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 drivers/of/base.c | 197 ++++++++++++++++++++++++++++++++++++++++++----
 include/of.h      |  40 +++++++++-
 2 files changed, 218 insertions(+), 19 deletions(-)

diff --git a/drivers/of/base.c b/drivers/of/base.c
index b22959dabe..20cfa0274c 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -773,22 +773,24 @@ int of_match(struct device *dev, struct driver *drv)
 	return 0;
 }
 EXPORT_SYMBOL(of_match);
-
 /**
  * of_find_property_value_of_size
  *
  * @np:		device node from which the property value is to be read.
  * @propname:	name of the property to be searched.
- * @len:	requested length of property value
+ * @min:	minimum allowed length of property value
+ * @max:	maximum allowed length of property value (0 means unlimited)
+ * @len:	if !=NULL, actual length is written to here
  *
  * Search for a property in a device node and valid the requested size.
- * Returns the property value on success, -EINVAL if the property does not
- *  exist, -ENODATA if property does not have a value, and -EOVERFLOW if the
- * property data isn't large enough.
+ *
+ * Return: The property value on success, -EINVAL if the property does not
+ * exist, -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data is too small or too large.
  *
  */
 static const void *of_find_property_value_of_size(const struct device_node *np,
-			const char *propname, u32 len)
+			const char *propname, u32 min, u32 max, size_t *len)
 {
 	struct property *prop = of_find_property(np, propname, NULL);
 	const void *value;
@@ -798,8 +800,13 @@ static const void *of_find_property_value_of_size(const struct device_node *np,
 	value = of_property_get_value(prop);
 	if (!value)
 		return ERR_PTR(-ENODATA);
-	if (len > prop->length)
+	if (prop->length < min)
 		return ERR_PTR(-EOVERFLOW);
+	if (max && prop->length > max)
+		return ERR_PTR(-EOVERFLOW);
+
+	if (len)
+		*len = prop->length;
 
 	return value;
 }
@@ -824,7 +831,8 @@ int of_property_read_u32_index(const struct device_node *np,
 				       u32 index, u32 *out_value)
 {
 	const u32 *val = of_find_property_value_of_size(np, propname,
-					((index + 1) * sizeof(*out_value)));
+					((index + 1) * sizeof(*out_value)),
+							0, NULL);
 
 	if (IS_ERR(val))
 		return PTR_ERR(val);
@@ -888,7 +896,8 @@ int of_property_read_u8_array(const struct device_node *np,
 			const char *propname, u8 *out_values, size_t sz)
 {
 	const u8 *val = of_find_property_value_of_size(np, propname,
-						(sz * sizeof(*out_values)));
+						(sz * sizeof(*out_values)),
+						       0, NULL);
 
 	if (IS_ERR(val))
 		return PTR_ERR(val);
@@ -921,7 +930,8 @@ int of_property_read_u16_array(const struct device_node *np,
 			const char *propname, u16 *out_values, size_t sz)
 {
 	const __be16 *val = of_find_property_value_of_size(np, propname,
-						(sz * sizeof(*out_values)));
+						(sz * sizeof(*out_values)),
+							   0, NULL);
 
 	if (IS_ERR(val))
 		return PTR_ERR(val);
@@ -953,7 +963,8 @@ int of_property_read_u32_array(const struct device_node *np,
 			       size_t sz)
 {
 	const __be32 *val = of_find_property_value_of_size(np, propname,
-						(sz * sizeof(*out_values)));
+						(sz * sizeof(*out_values)),
+							   0, NULL);
 
 	if (IS_ERR(val))
 		return PTR_ERR(val);
@@ -981,7 +992,7 @@ int of_property_read_u64(const struct device_node *np, const char *propname,
 			 u64 *out_value)
 {
 	const __be32 *val = of_find_property_value_of_size(np, propname,
-						sizeof(*out_value));
+						sizeof(*out_value), 0, NULL);
 
 	if (IS_ERR(val))
 		return PTR_ERR(val);
@@ -992,7 +1003,154 @@ int of_property_read_u64(const struct device_node *np, const char *propname,
 EXPORT_SYMBOL_GPL(of_property_read_u64);
 
 /**
- * of_property_read_u64_array - Find and read an array of 64 bit integers
+ * of_property_read_variable_u8_array - Find and read an array of u8 from a
+ * property, with bounds on the minimum and maximum array size.
+ *
+ * @np:		device node from which the property value is to be read.
+ * @propname:	name of the property to be searched.
+ * @out_values:	pointer to found values.
+ * @sz_min:	minimum number of array elements to read
+ * @sz_max:	maximum number of array elements to read, if zero there is no
+ *		upper limit on the number of elements in the dts entry but only
+ *		sz_min will be read.
+ *
+ * Search for a property in a device node and read 8-bit value(s) from
+ * it.
+ *
+ * dts entry of array should be like:
+ *  ``property = /bits/ 8 <0x50 0x60 0x70>;``
+ *
+ * Return: The number of elements read on success, -EINVAL if the property
+ * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
+ * if the property data is smaller than sz_min or longer than sz_max.
+ *
+ * The out_values is modified only if a valid u8 value can be decoded.
+ */
+int of_property_read_variable_u8_array(const struct device_node *np,
+					const char *propname, u8 *out_values,
+					size_t sz_min, size_t sz_max)
+{
+	size_t sz, count;
+	const u8 *val = of_find_property_value_of_size(np, propname,
+						(sz_min * sizeof(*out_values)),
+						(sz_max * sizeof(*out_values)),
+						&sz);
+
+	if (IS_ERR(val))
+		return PTR_ERR(val);
+
+	if (!sz_max)
+		sz = sz_min;
+	else
+		sz /= sizeof(*out_values);
+
+	count = sz;
+	while (count--)
+		*out_values++ = *val++;
+
+	return sz;
+}
+EXPORT_SYMBOL_GPL(of_property_read_variable_u8_array);
+
+/**
+ * of_property_read_variable_u16_array - Find and read an array of u16 from a
+ * property, with bounds on the minimum and maximum array size.
+ *
+ * @np:		device node from which the property value is to be read.
+ * @propname:	name of the property to be searched.
+ * @out_values:	pointer to found values.
+ * @sz_min:	minimum number of array elements to read
+ * @sz_max:	maximum number of array elements to read, if zero there is no
+ *		upper limit on the number of elements in the dts entry but only
+ *		sz_min will be read.
+ *
+ * Search for a property in a device node and read 16-bit value(s) from
+ * it.
+ *
+ * dts entry of array should be like:
+ *  ``property = /bits/ 16 <0x5000 0x6000 0x7000>;``
+ *
+ * Return: The number of elements read on success, -EINVAL if the property
+ * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
+ * if the property data is smaller than sz_min or longer than sz_max.
+ *
+ * The out_values is modified only if a valid u16 value can be decoded.
+ */
+int of_property_read_variable_u16_array(const struct device_node *np,
+					const char *propname, u16 *out_values,
+					size_t sz_min, size_t sz_max)
+{
+	size_t sz, count;
+	const __be16 *val = of_find_property_value_of_size(np, propname,
+						(sz_min * sizeof(*out_values)),
+						(sz_max * sizeof(*out_values)),
+						&sz);
+
+	if (IS_ERR(val))
+		return PTR_ERR(val);
+
+	if (!sz_max)
+		sz = sz_min;
+	else
+		sz /= sizeof(*out_values);
+
+	count = sz;
+	while (count--)
+		*out_values++ = be16_to_cpup(val++);
+
+	return sz;
+}
+EXPORT_SYMBOL_GPL(of_property_read_variable_u16_array);
+
+/**
+ * of_property_read_variable_u32_array - Find and read an array of 32 bit
+ * integers from a property, with bounds on the minimum and maximum array size.
+ *
+ * @np:		device node from which the property value is to be read.
+ * @propname:	name of the property to be searched.
+ * @out_values:	pointer to return found values.
+ * @sz_min:	minimum number of array elements to read
+ * @sz_max:	maximum number of array elements to read, if zero there is no
+ *		upper limit on the number of elements in the dts entry but only
+ *		sz_min will be read.
+ *
+ * Search for a property in a device node and read 32-bit value(s) from
+ * it.
+ *
+ * Return: The number of elements read on success, -EINVAL if the property
+ * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
+ * if the property data is smaller than sz_min or longer than sz_max.
+ *
+ * The out_values is modified only if a valid u32 value can be decoded.
+ */
+int of_property_read_variable_u32_array(const struct device_node *np,
+			       const char *propname, u32 *out_values,
+			       size_t sz_min, size_t sz_max)
+{
+	size_t sz, count;
+	const __be32 *val = of_find_property_value_of_size(np, propname,
+						(sz_min * sizeof(*out_values)),
+						(sz_max * sizeof(*out_values)),
+						&sz);
+
+	if (IS_ERR(val))
+		return PTR_ERR(val);
+
+	if (!sz_max)
+		sz = sz_min;
+	else
+		sz /= sizeof(*out_values);
+
+	count = sz;
+	while (count--)
+		*out_values++ = be32_to_cpup(val++);
+
+	return sz;
+}
+EXPORT_SYMBOL_GPL(of_property_read_variable_u32_array);
+
+/**
+ * of_property_read_variable_u64_array - Find and read an array of 64 bit integers
  * from a property.
  *
  * @np:		device node from which the property value is to be read.
@@ -1009,15 +1167,22 @@ EXPORT_SYMBOL_GPL(of_property_read_u64);
  */
 int of_property_read_variable_u64_array(const struct device_node *np,
 			       const char *propname, u64 *out_values,
-			       size_t sz)
+			       size_t sz_min, size_t sz_max)
 {
-	size_t count;
+	size_t sz, count;
 	const __be32 *val = of_find_property_value_of_size(np, propname,
-						(sz * sizeof(*out_values)));
+						(sz_min * sizeof(*out_values)),
+						(sz_max * sizeof(*out_values)),
+						&sz);
 
 	if (IS_ERR(val))
 		return PTR_ERR(val);
 
+	if (!sz_max)
+		sz = sz_min;
+	else
+		sz /= sizeof(*out_values);
+
 	count = sz;
 	while (count--) {
 		*out_values++ = of_read_number(val, 2);
diff --git a/include/of.h b/include/of.h
index 9eef6d7f13..dbdc4a524a 100644
--- a/include/of.h
+++ b/include/of.h
@@ -240,11 +240,22 @@ extern int of_property_read_u32_array(const struct device_node *np,
 				      size_t sz);
 extern int of_property_read_u64(const struct device_node *np,
 				const char *propname, u64 *out_value);
-
+extern int of_property_read_variable_u8_array(const struct device_node *np,
+					      const char *propname, u8 *out_values,
+					      size_t sz_min, size_t sz_max);
+extern int of_property_read_variable_u16_array(const struct device_node *np,
+					       const char *propname, u16 *out_values,
+					       size_t sz_min, size_t sz_max);
+extern int of_property_read_variable_u32_array(const struct device_node *np,
+					       const char *propname,
+					       u32 *out_values,
+					       size_t sz_min,
+					       size_t sz_max);
 extern int of_property_read_variable_u64_array(const struct device_node *np,
 					const char *propname,
 					u64 *out_values,
-					size_t sz);
+					size_t sz_min,
+					size_t sz_max);
 
 extern int of_property_read_string(struct device_node *np,
 				   const char *propname,
@@ -669,6 +680,29 @@ static inline int of_property_read_u64(const struct device_node *np,
 	return -ENOSYS;
 }
 
+static inline  int of_property_read_variable_u8_array(const struct device_node *np,
+					      const char *propname, u8 *out_values,
+					      size_t sz_min, size_t sz_max)
+{
+	return -ENOSYS;
+}
+
+static inline  int of_property_read_variable_u16_array(const struct device_node *np,
+					       const char *propname, u16 *out_values,
+					       size_t sz_min, size_t sz_max)
+{
+	return -ENOSYS;
+}
+
+static inline  int of_property_read_variable_u32_array(const struct device_node *np,
+					       const char *propname,
+					       u32 *out_values,
+					       size_t sz_min,
+					       size_t sz_max)
+{
+	return -ENOSYS;
+}
+
 static inline int of_property_read_variable_u64_array(const struct device_node *np,
 					const char *propname,
 					u64 *out_values,
@@ -1166,7 +1200,7 @@ static inline int of_property_read_u64_array(const struct device_node *np,
 					     u64 *out_values, size_t sz)
 {
 	int ret = of_property_read_variable_u64_array(np, propname, out_values,
-						      sz);
+						      sz, 0);
 	if (ret >= 0)
 		return 0;
 	else
-- 
2.39.2




More information about the barebox mailing list