* [PATCH 1/9] device property: fix fwnode_name_eq() for empty node names
2026-11-04 14:03 [PATCH 0/9] gpio: make gpiolib-shared more fwnode-centric Bartosz Golaszewski
@ 2026-11-04 14:03 ` Bartosz Golaszewski
2026-11-04 14:03 ` [PATCH 2/9] lib: string_helpers: implement a CLASS() for string arrays Bartosz Golaszewski
` (7 subsequent siblings)
8 siblings, 0 replies; 18+ messages in thread
From: Bartosz Golaszewski @ 2026-11-04 14:03 UTC (permalink / raw)
To: Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki,
Danilo Krummrich, Johan Hovold, Hans Verkuil, Laurent Pinchart,
Kees Cook, Andy Shevchenko, Len Brown, Rob Herring,
Saravana Kannan, Linus Walleij
Cc: linux-acpi, driver-core, linux-kernel, linux-hardening,
devicetree, linux-gpio, Bartosz Golaszewski
str_has_prefix() returns the prefix length on match and 0 on mismatch,
so the mistmatch case can't be told from "empty prefix matched an empty
string". For instance: the OF root node's name as returned by
fwnode_get_name() is "" and will return 0 for any name matched against
it and since len is 0 too, fwnode_name_eq() will return true.
Do what OF code already does in of_node_name_eq(): check if the length
of the expected name matches the length of the actual node name before
comparing it.
Fixes: a9c8c738066b ("device property: Add fwnode_name_eq()")
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/base/property.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 51109794d7275ddaf4571584d0e77d8573ebb475..a97575ff9199004b4f401f432aed6c95e40d0c25 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -700,7 +700,7 @@ bool fwnode_name_eq(const struct fwnode_handle *fwnode, const char *name)
len = strchrnul(node_name, '@') - node_name;
- return str_has_prefix(node_name, name) == len;
+ return len == strlen(name) && !strncmp(node_name, name, len);
}
EXPORT_SYMBOL_GPL(fwnode_name_eq);
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 2/9] lib: string_helpers: implement a CLASS() for string arrays
2026-11-04 14:03 [PATCH 0/9] gpio: make gpiolib-shared more fwnode-centric Bartosz Golaszewski
2026-11-04 14:03 ` [PATCH 1/9] device property: fix fwnode_name_eq() for empty node names Bartosz Golaszewski
@ 2026-11-04 14:03 ` Bartosz Golaszewski
2026-11-04 21:07 ` Andy Shevchenko
2026-11-04 14:03 ` [PATCH 3/9] fwnode: define the property_get_names() operation Bartosz Golaszewski
` (6 subsequent siblings)
8 siblings, 1 reply; 18+ messages in thread
From: Bartosz Golaszewski @ 2026-11-04 14:03 UTC (permalink / raw)
To: Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki,
Danilo Krummrich, Johan Hovold, Hans Verkuil, Laurent Pinchart,
Kees Cook, Andy Shevchenko, Len Brown, Rob Herring,
Saravana Kannan, Linus Walleij
Cc: linux-acpi, driver-core, linux-kernel, linux-hardening,
devicetree, linux-gpio, Bartosz Golaszewski
Provide a CLASS() for managed arrays of strings. It can be used for
automated release of temporary string arrays when they go out of scope.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
include/linux/string_helpers.h | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/include/linux/string_helpers.h b/include/linux/string_helpers.h
index 3fb88a1e989833ad5ea1a46858efa16e3971bf08..3122be1359a36272190264d1c3e4c84dce785e6e 100644
--- a/include/linux/string_helpers.h
+++ b/include/linux/string_helpers.h
@@ -3,6 +3,7 @@
#define _LINUX_STRING_HELPERS_H_
#include <linux/bits.h>
+#include <linux/cleanup.h>
#include <linux/ctype.h>
#include <linux/string_choices.h>
#include <linux/string.h>
@@ -119,6 +120,17 @@ char *kstrdup_and_replace(const char *src, char old, char new, gfp_t gfp);
char **kasprintf_strarray(gfp_t gfp, const char *prefix, size_t n);
void kfree_strarray(char **array, size_t n);
+struct kstrarray {
+ char **array;
+ size_t size;
+};
+
+DEFINE_CLASS(strarray,
+ struct kstrarray,
+ kfree_strarray(_T.array, _T.size),
+ ((struct kstrarray){ .array = array, .size = size }),
+ char **array, size_t size);
+
char **devm_kasprintf_strarray(struct device *dev, const char *prefix, size_t n);
#endif
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH 2/9] lib: string_helpers: implement a CLASS() for string arrays
2026-11-04 14:03 ` [PATCH 2/9] lib: string_helpers: implement a CLASS() for string arrays Bartosz Golaszewski
@ 2026-11-04 21:07 ` Andy Shevchenko
0 siblings, 0 replies; 18+ messages in thread
From: Andy Shevchenko @ 2026-11-04 21:07 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Daniel Scally, Heikki Krogerus, Sakari Ailus, Bartosz Golaszewski,
Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Johan Hovold, Hans Verkuil, Laurent Pinchart, Kees Cook,
Andy Shevchenko, Len Brown, Rob Herring, Saravana Kannan,
Linus Walleij, linux-acpi, driver-core, linux-kernel,
linux-hardening, devicetree, linux-gpio
On Wed, Nov 04, 2026 at 03:03:44PM +0100, Bartosz Golaszewski wrote:
> Provide a CLASS() for managed arrays of strings. It can be used for
> automated release of temporary string arrays when they go out of scope.
...
> +struct kstrarray {
> + char **array;
> + size_t size;
> +};
Hmm... Why struct strarray can't be used?
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 3/9] fwnode: define the property_get_names() operation
2026-11-04 14:03 [PATCH 0/9] gpio: make gpiolib-shared more fwnode-centric Bartosz Golaszewski
2026-11-04 14:03 ` [PATCH 1/9] device property: fix fwnode_name_eq() for empty node names Bartosz Golaszewski
2026-11-04 14:03 ` [PATCH 2/9] lib: string_helpers: implement a CLASS() for string arrays Bartosz Golaszewski
@ 2026-11-04 14:03 ` Bartosz Golaszewski
2026-11-04 14:03 ` [PATCH 4/9] device property: provide fwnode_property_get_names() Bartosz Golaszewski
` (5 subsequent siblings)
8 siblings, 0 replies; 18+ messages in thread
From: Bartosz Golaszewski @ 2026-11-04 14:03 UTC (permalink / raw)
To: Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki,
Danilo Krummrich, Johan Hovold, Hans Verkuil, Laurent Pinchart,
Kees Cook, Andy Shevchenko, Len Brown, Rob Herring,
Saravana Kannan, Linus Walleij
Cc: linux-acpi, driver-core, linux-kernel, linux-hardening,
devicetree, linux-gpio, Bartosz Golaszewski
Define a new fwnode operation allowing to retrieve the list of all
properties of given firmware node in a dynamically allocated array of
strings.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
include/linux/fwnode.h | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h
index a9dcaf7e70765637a0c33af2ae0ac541e15752ad..2d7e0b9245d445d473c7317bd27058abe5750b40 100644
--- a/include/linux/fwnode.h
+++ b/include/linux/fwnode.h
@@ -125,6 +125,13 @@ struct fwnode_reference_args {
* success, a negative error code otherwise.
* @property_read_string_array: Read an array of string properties. Return zero
* on success, a negative error code otherwise.
+ * @property_get_names: Retrieve the list of all properties of this firmware
+ * node. On success: returns the number of properties and
+ * sets *props to an array of NULL-terminated strings that
+ * must be freed by the user with kfree_strarray(). If
+ * there are no properties, 0 is returned and the props
+ * pointer is not changed. Returns negative error number on
+ * failure.
* @get_name: Return the name of an fwnode.
* @get_name_prefix: Get a prefix for a node (for printing purposes).
* @get_parent: Return the parent of an fwnode.
@@ -162,6 +169,8 @@ struct fwnode_operations {
(*property_read_string_array)(const struct fwnode_handle *fwnode_handle,
const char *propname, const char **val,
size_t nval);
+ int (*property_get_names)(const struct fwnode_handle *fwnode,
+ char ***props);
const char *(*get_name)(const struct fwnode_handle *fwnode);
const char *(*get_name_prefix)(const struct fwnode_handle *fwnode);
struct fwnode_handle *(*get_parent)(const struct fwnode_handle *fwnode);
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 4/9] device property: provide fwnode_property_get_names()
2026-11-04 14:03 [PATCH 0/9] gpio: make gpiolib-shared more fwnode-centric Bartosz Golaszewski
` (2 preceding siblings ...)
2026-11-04 14:03 ` [PATCH 3/9] fwnode: define the property_get_names() operation Bartosz Golaszewski
@ 2026-11-04 14:03 ` Bartosz Golaszewski
2026-11-04 14:12 ` sashiko-bot
2026-11-04 21:17 ` Andy Shevchenko
2026-11-04 14:03 ` [PATCH 5/9] of: property: implement the .property_get_names() fwnode operation Bartosz Golaszewski
` (4 subsequent siblings)
8 siblings, 2 replies; 18+ messages in thread
From: Bartosz Golaszewski @ 2026-11-04 14:03 UTC (permalink / raw)
To: Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki,
Danilo Krummrich, Johan Hovold, Hans Verkuil, Laurent Pinchart,
Kees Cook, Andy Shevchenko, Len Brown, Rob Herring,
Saravana Kannan, Linus Walleij
Cc: linux-acpi, driver-core, linux-kernel, linux-hardening,
devicetree, linux-gpio, Bartosz Golaszewski
Provide fwnode_property_get_names() - a new fwnode function that allows
callers to retrieve the list of all properties of given firmware node.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/base/property.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/property.h | 1 +
2 files changed, 78 insertions(+)
diff --git a/drivers/base/property.c b/drivers/base/property.c
index a97575ff9199004b4f401f432aed6c95e40d0c25..7b0df3dfae53b6377dba91330aac746684e8adec 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -11,11 +11,13 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/export.h>
+#include <linux/minmax.h>
#include <linux/of.h>
#include <linux/property.h>
#include <linux/phy.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/string_helpers.h>
#include <linux/types.h>
struct fwnode_handle *__dev_fwnode(struct device *dev)
@@ -542,6 +544,81 @@ int fwnode_property_match_string(const struct fwnode_handle *fwnode,
}
EXPORT_SYMBOL_GPL(fwnode_property_match_string);
+/**
+ * fwnode_property_get_names - get the list of all properties of this fwnode
+ * @fwnode: Firmware node to get the list of properties for
+ * @props: Pointer to an array of strings. It will contain the address of the
+ * string list containing the property names.
+ *
+ * Return: Number of property names written into *props. If > 0, the caller must
+ * free the array with kfree_strarray(). *props is only valid for
+ * a positive return value.
+ * %-EINVAL if arguments are not valid
+ * %-ENXIO if no suitable firmware interface is present
+ * %-ENOMEM if memory allocation failed
+ *
+ * The list also includes the properties of the secondary firmware node, if
+ * any. Properties present in both nodes are listed once.
+ */
+int fwnode_property_get_names(const struct fwnode_handle *fwnode, char ***props)
+{
+ int ret1, ret2 = -ENXIO, n1, n2, i, j, count;
+ char **prim = NULL, **sec = NULL, **merged;
+
+ if (IS_ERR_OR_NULL(fwnode))
+ return -EINVAL;
+
+ ret1 = fwnode_call_int_op(fwnode, property_get_names, &prim);
+ if (!IS_ERR_OR_NULL(fwnode->secondary))
+ ret2 = fwnode_call_int_op(fwnode->secondary, property_get_names, &sec);
+
+ if (ret1 == -ENXIO && ret2 == -ENXIO)
+ return -ENXIO;
+
+ n1 = max(ret1, 0);
+ n2 = max(ret2, 0);
+
+ CLASS(strarray, prim_props)(prim, n1);
+ CLASS(strarray, sec_props)(sec, n2);
+
+ if (ret1 < 0 && ret1 != -ENXIO)
+ return ret1;
+
+ if (ret2 < 0 && ret2 != -ENXIO)
+ return ret2;
+
+ if (n1 == 0 && n2 == 0)
+ return 0;
+
+ merged = kcalloc(n1 + n2, sizeof(*merged), GFP_KERNEL);
+ if (!merged)
+ return -ENOMEM;
+
+ /* The strings are now owned by merged, only free the container. */
+ for (i = 0; i < n1; i++) {
+ merged[i] = prim_props.array[i];
+ prim_props.array[i] = NULL;
+ }
+ count = n1;
+
+ /* Properties from the primary node take precedence. */
+ for (i = 0; i < n2; i++) {
+ for (j = 0; j < n1; j++) {
+ if (!strcmp(merged[j], sec_props.array[i]))
+ break;
+ }
+
+ if (j >= n1) {
+ merged[count++] = sec_props.array[i];
+ sec_props.array[i] = NULL;
+ }
+ }
+
+ *props = merged;
+ return count;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_get_names);
+
/**
* fwnode_property_match_property_string - find a property string value in an array and return index
* @fwnode: Firmware node to get the property of
diff --git a/include/linux/property.h b/include/linux/property.h
index 9143fe4f5c05179e595ba875aafbcb006a740824..a70f3c4c087dd85390951da950c3632f89c6cfd1 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -77,6 +77,7 @@ int fwnode_property_read_string(const struct fwnode_handle *fwnode,
const char *propname, const char **val);
int fwnode_property_match_string(const struct fwnode_handle *fwnode,
const char *propname, const char *string);
+int fwnode_property_get_names(const struct fwnode_handle *fwnode, char ***props);
bool fwnode_device_is_available(const struct fwnode_handle *fwnode);
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH 4/9] device property: provide fwnode_property_get_names()
2026-11-04 14:03 ` [PATCH 4/9] device property: provide fwnode_property_get_names() Bartosz Golaszewski
@ 2026-11-04 14:12 ` sashiko-bot
2026-11-04 21:17 ` Andy Shevchenko
1 sibling, 0 replies; 18+ messages in thread
From: sashiko-bot @ 2026-11-04 14:12 UTC (permalink / raw)
To: Bartosz Golaszewski; +Cc: devicetree, linux-gpio, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] device property: missing NULL check for props in fwnode_property_get_names()
--
commit c6de0ca7eaa5586d9db8c473e272baa86e7c8e04
Author: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
device property: provide fwnode_property_get_names()
This commit adds fwnode_property_get_names() to retrieve the list of all
property names for a given firmware node, merging properties from both the
primary and secondary firmware nodes.
> diff --git a/drivers/base/property.c b/drivers/base/property.c
> index a97575ff91990..7b0df3dfae53b 100644
> --- a/drivers/base/property.c
> +++ b/drivers/base/property.c
[ ... ]
> @@ -542,6 +544,81 @@ int fwnode_property_match_string(const struct fwnode_handle *fwnode,
> }
> EXPORT_SYMBOL_GPL(fwnode_property_match_string);
>
> +/**
> + * fwnode_property_get_names - get the list of all properties of this fwnode
> + * @fwnode: Firmware node to get the list of properties for
> + * @props: Pointer to an array of strings. It will contain the address of the
> + * string list containing the property names.
> + *
> + * Return: Number of property names written into *props. If > 0, the caller must
> + * free the array with kfree_strarray(). *props is only valid for
> + * a positive return value.
> + * %-EINVAL if arguments are not valid
> + * %-ENXIO if no suitable firmware interface is present
> + * %-ENOMEM if memory allocation failed
> + *
> + * The list also includes the properties of the secondary firmware node, if
> + * any. Properties present in both nodes are listed once.
> + */
> +int fwnode_property_get_names(const struct fwnode_handle *fwnode, char ***props)
> +{
> + int ret1, ret2 = -ENXIO, n1, n2, i, j, count;
> + char **prim = NULL, **sec = NULL, **merged;
> +
> + if (IS_ERR_OR_NULL(fwnode))
> + return -EINVAL;
> +
> + ret1 = fwnode_call_int_op(fwnode, property_get_names, &prim);
> + if (!IS_ERR_OR_NULL(fwnode->secondary))
> + ret2 = fwnode_call_int_op(fwnode->secondary, property_get_names, &sec);
> +
> + if (ret1 == -ENXIO && ret2 == -ENXIO)
> + return -ENXIO;
> +
> + n1 = max(ret1, 0);
> + n2 = max(ret2, 0);
> +
> + CLASS(strarray, prim_props)(prim, n1);
> + CLASS(strarray, sec_props)(sec, n2);
> +
> + if (ret1 < 0 && ret1 != -ENXIO)
> + return ret1;
> +
> + if (ret2 < 0 && ret2 != -ENXIO)
> + return ret2;
> +
> + if (n1 == 0 && n2 == 0)
> + return 0;
> +
> + merged = kcalloc(n1 + n2, sizeof(*merged), GFP_KERNEL);
> + if (!merged)
> + return -ENOMEM;
> +
> + /* The strings are now owned by merged, only free the container. */
> + for (i = 0; i < n1; i++) {
> + merged[i] = prim_props.array[i];
> + prim_props.array[i] = NULL;
> + }
> + count = n1;
> +
> + /* Properties from the primary node take precedence. */
> + for (i = 0; i < n2; i++) {
> + for (j = 0; j < n1; j++) {
> + if (!strcmp(merged[j], sec_props.array[i]))
> + break;
> + }
> +
> + if (j >= n1) {
> + merged[count++] = sec_props.array[i];
> + sec_props.array[i] = NULL;
> + }
> + }
> +
> + *props = merged;
> + return count;
> +}
[Severity: Medium]
Should fwnode_property_get_names() in drivers/base/property.c also check
!props at entry and return -EINVAL?
The kernel-doc states that -EINVAL is returned if arguments are not valid,
and unlike fwnode_property_read_string_array(), props is not optional.
Because fwnode_property_get_names() passes &prim and &sec to the backend
property_get_names callbacks rather than forwarding props, the backend
callbacks never validate props either.
If a caller passes NULL for props (for instance, expecting it to query the
property count like fwnode_property_read_string_array()), it will return 0
instead of -EINVAL when the node has no properties, or dereference a NULL
props pointer at *props = merged and leak merged and all transferred property
name strings when the node has at least one property.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261104-fwnode-for-each-prop-v1-0-6e28fe1c72c4@oss.qualcomm.com?part=4
^ permalink raw reply [flat|nested] 18+ messages in thread* Re: [PATCH 4/9] device property: provide fwnode_property_get_names()
2026-11-04 14:03 ` [PATCH 4/9] device property: provide fwnode_property_get_names() Bartosz Golaszewski
2026-11-04 14:12 ` sashiko-bot
@ 2026-11-04 21:17 ` Andy Shevchenko
1 sibling, 0 replies; 18+ messages in thread
From: Andy Shevchenko @ 2026-11-04 21:17 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Daniel Scally, Heikki Krogerus, Sakari Ailus, Bartosz Golaszewski,
Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Johan Hovold, Hans Verkuil, Laurent Pinchart, Kees Cook,
Andy Shevchenko, Len Brown, Rob Herring, Saravana Kannan,
Linus Walleij, linux-acpi, driver-core, linux-kernel,
linux-hardening, devicetree, linux-gpio
On Wed, Nov 04, 2026 at 03:03:46PM +0100, Bartosz Golaszewski wrote:
> Provide fwnode_property_get_names() - a new fwnode function that allows
> callers to retrieve the list of all properties of given firmware node.
...
> #include <linux/device.h>
> #include <linux/err.h>
> #include <linux/export.h>
> +#include <linux/minmax.h>
> #include <linux/of.h>
> #include <linux/property.h>
> #include <linux/phy.h>
> #include <linux/slab.h>
> #include <linux/string.h>
> +#include <linux/string_helpers.h>
You can replace string.h with string_helpers.h.
We already rely on the fact that the latter includes the former
elsewhere in the kernel.
> #include <linux/types.h>
> +/**
> + * fwnode_property_get_names - get the list of all properties of this fwnode
> + * @fwnode: Firmware node to get the list of properties for
> + * @props: Pointer to an array of strings. It will contain the address of the
> + * string list containing the property names.
> + *
> + * Return: Number of property names written into *props. If > 0, the caller must
> + * free the array with kfree_strarray(). *props is only valid for
> + * a positive return value.
> + * %-EINVAL if arguments are not valid
> + * %-ENXIO if no suitable firmware interface is present
> + * %-ENOMEM if memory allocation failed
> + * The list also includes the properties of the secondary firmware node, if
> + * any. Properties present in both nodes are listed once.
I don't know if this paragraph is for Return section or not. If not, it should
go before as the Return section must be the last one in the kernel-doc (it's
documented). Otherwise I'm not sure it belongs to the Return section. I think
it would be better as a part of the description which should elaborate on the
returning values in the parameter.
> + */
> +int fwnode_property_get_names(const struct fwnode_handle *fwnode, char ***props)
Triple indirection is rare. Do we really need it?
> +{
> + int ret1, ret2 = -ENXIO, n1, n2, i, j, count;
> + char **prim = NULL, **sec = NULL, **merged;
> +
> + if (IS_ERR_OR_NULL(fwnode))
> + return -EINVAL;
> +
> + ret1 = fwnode_call_int_op(fwnode, property_get_names, &prim);
> + if (!IS_ERR_OR_NULL(fwnode->secondary))
> + ret2 = fwnode_call_int_op(fwnode->secondary, property_get_names, &sec);
> +
> + if (ret1 == -ENXIO && ret2 == -ENXIO)
> + return -ENXIO;
> +
> + n1 = max(ret1, 0);
> + n2 = max(ret2, 0);
> +
> + CLASS(strarray, prim_props)(prim, n1);
> + CLASS(strarray, sec_props)(sec, n2);
> +
> + if (ret1 < 0 && ret1 != -ENXIO)
> + return ret1;
> +
> + if (ret2 < 0 && ret2 != -ENXIO)
> + return ret2;
> + if (n1 == 0 && n2 == 0)
> + return 0;
Shouldn't these checks be before any CLASS()? Otherwise seems strange to me.
> + merged = kcalloc(n1 + n2, sizeof(*merged), GFP_KERNEL);
Shouldn't here be something from overflow.h?
> + if (!merged)
> + return -ENOMEM;
> +
> + /* The strings are now owned by merged, only free the container. */
> + for (i = 0; i < n1; i++) {
> + merged[i] = prim_props.array[i];
> + prim_props.array[i] = NULL;
> + }
> + count = n1;
> +
> + /* Properties from the primary node take precedence. */
> + for (i = 0; i < n2; i++) {
> + for (j = 0; j < n1; j++) {
> + if (!strcmp(merged[j], sec_props.array[i]))
> + break;
> + }
match_string() ?
> + if (j >= n1) {
> + merged[count++] = sec_props.array[i];
> + sec_props.array[i] = NULL;
> + }
> + }
> +
> + *props = merged;
> + return count;
> +}
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 5/9] of: property: implement the .property_get_names() fwnode operation
2026-11-04 14:03 [PATCH 0/9] gpio: make gpiolib-shared more fwnode-centric Bartosz Golaszewski
` (3 preceding siblings ...)
2026-11-04 14:03 ` [PATCH 4/9] device property: provide fwnode_property_get_names() Bartosz Golaszewski
@ 2026-11-04 14:03 ` Bartosz Golaszewski
2026-11-04 14:18 ` sashiko-bot
2026-11-04 21:21 ` Andy Shevchenko
2026-11-04 14:03 ` [PATCH 6/9] fwnode: define the count_references() " Bartosz Golaszewski
` (3 subsequent siblings)
8 siblings, 2 replies; 18+ messages in thread
From: Bartosz Golaszewski @ 2026-11-04 14:03 UTC (permalink / raw)
To: Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki,
Danilo Krummrich, Johan Hovold, Hans Verkuil, Laurent Pinchart,
Kees Cook, Andy Shevchenko, Len Brown, Rob Herring,
Saravana Kannan, Linus Walleij
Cc: linux-acpi, driver-core, linux-kernel, linux-hardening,
devicetree, linux-gpio, Bartosz Golaszewski
Implement the property_get_names() callback from the fwnode interface
for OF nodes.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/of/property.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/drivers/of/property.c b/drivers/of/property.c
index 45e55f61848801ed497702c6cfe501009904c49d..16c9c307633bdc7c9343782b1cd3bdb845552c6a 100644
--- a/drivers/of/property.c
+++ b/drivers/of/property.c
@@ -28,6 +28,7 @@
#include <linux/of_graph.h>
#include <linux/of_irq.h>
#include <linux/string.h>
+#include <linux/string_helpers.h>
#include <linux/moduleparam.h>
#include "of_private.h"
@@ -1120,6 +1121,34 @@ of_fwnode_property_read_string_array(const struct fwnode_handle *fwnode,
of_property_count_strings(node, propname);
}
+static int of_fwnode_property_get_names(const struct fwnode_handle *fwnode,
+ char ***props)
+{
+ const struct device_node *node = to_of_node(fwnode);
+ struct property *prop;
+ int count = 0, i = 0;
+ char **names;
+
+ for_each_property_of_node(node, prop)
+ count++;
+
+ names = kcalloc(count, sizeof(*names), GFP_KERNEL);
+ if (!names)
+ return -ENOMEM;
+
+ for_each_property_of_node(node, prop) {
+ names[i] = kstrdup(prop->name, GFP_KERNEL);
+ if (!names[i]) {
+ kfree_strarray(names, i);
+ return -ENOMEM;
+ }
+ i++;
+ }
+
+ *props = names;
+ return count;
+}
+
static const char *of_fwnode_get_name(const struct fwnode_handle *fwnode)
{
return kbasename(to_of_node(fwnode)->full_name);
@@ -1712,6 +1741,7 @@ const struct fwnode_operations of_fwnode_ops = {
.property_read_bool = of_fwnode_property_read_bool,
.property_read_int_array = of_fwnode_property_read_int_array,
.property_read_string_array = of_fwnode_property_read_string_array,
+ .property_get_names = of_fwnode_property_get_names,
.get_name = of_fwnode_get_name,
.get_name_prefix = of_fwnode_get_name_prefix,
.get_parent = of_fwnode_get_parent,
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH 5/9] of: property: implement the .property_get_names() fwnode operation
2026-11-04 14:03 ` [PATCH 5/9] of: property: implement the .property_get_names() fwnode operation Bartosz Golaszewski
@ 2026-11-04 14:18 ` sashiko-bot
2026-11-04 21:21 ` Andy Shevchenko
1 sibling, 0 replies; 18+ messages in thread
From: sashiko-bot @ 2026-11-04 14:18 UTC (permalink / raw)
To: Bartosz Golaszewski; +Cc: devicetree, linux-gpio, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] of: property: of_fwnode_property_get_names() sets *props to ZERO_SIZE_PTR
--
commit 9f35cc327cc9ae6d6d25a8e2fba2753d5485053e
Author: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
of: property: implement the .property_get_names() fwnode operation
This commit implements the .property_get_names() fwnode callback for OF
nodes by iterating over the device node properties and returning a newly
allocated string array of property names.
> diff --git a/drivers/of/property.c b/drivers/of/property.c
> index 45e55f6184880..16c9c307633bd 100644
> --- a/drivers/of/property.c
> +++ b/drivers/of/property.c
[ ... ]
> @@ -1120,6 +1121,34 @@ of_fwnode_property_read_string_array(const struct fwnode_handle *fwnode,
> of_property_count_strings(node, propname);
> }
>
> +static int of_fwnode_property_get_names(const struct fwnode_handle *fwnode,
> + char ***props)
> +{
> + const struct device_node *node = to_of_node(fwnode);
> + struct property *prop;
> + int count = 0, i = 0;
> + char **names;
> +
> + for_each_property_of_node(node, prop)
> + count++;
> +
> + names = kcalloc(count, sizeof(*names), GFP_KERNEL);
> + if (!names)
> + return -ENOMEM;
> +
> + for_each_property_of_node(node, prop) {
> + names[i] = kstrdup(prop->name, GFP_KERNEL);
> + if (!names[i]) {
> + kfree_strarray(names, i);
> + return -ENOMEM;
> + }
> + i++;
> + }
> +
> + *props = names;
> + return count;
> +}
[Severity: Medium]
What happens in of_fwnode_property_get_names() if node->properties is NULL
(for example, on a dynamically created empty node from
of_changeset_create_node() or a node whose properties were removed via
of_remove_property())?
When count is 0, kcalloc(0, sizeof(*names), GFP_KERNEL) returns
ZERO_SIZE_PTR, which passes the !names check and sets *props to
ZERO_SIZE_PTR before returning 0.
However, the documentation for struct fwnode_operations in
include/linux/fwnode.h states:
* @property_get_names: Retrieve the list of all properties of this firmware
* node. On success: returns the number of properties and
* sets *props to an array of NULL-terminated strings that
* must be freed by the user with kfree_strarray(). If
* there are no properties, 0 is returned and the props
* pointer is not changed. Returns negative error number on
* failure.
Should of_fwnode_property_get_names() return 0 early when count is 0 so
that *props is left untouched?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261104-fwnode-for-each-prop-v1-0-6e28fe1c72c4@oss.qualcomm.com?part=5
^ permalink raw reply [flat|nested] 18+ messages in thread* Re: [PATCH 5/9] of: property: implement the .property_get_names() fwnode operation
2026-11-04 14:03 ` [PATCH 5/9] of: property: implement the .property_get_names() fwnode operation Bartosz Golaszewski
2026-11-04 14:18 ` sashiko-bot
@ 2026-11-04 21:21 ` Andy Shevchenko
1 sibling, 0 replies; 18+ messages in thread
From: Andy Shevchenko @ 2026-11-04 21:21 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Daniel Scally, Heikki Krogerus, Sakari Ailus, Bartosz Golaszewski,
Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Johan Hovold, Hans Verkuil, Laurent Pinchart, Kees Cook,
Andy Shevchenko, Len Brown, Rob Herring, Saravana Kannan,
Linus Walleij, linux-acpi, driver-core, linux-kernel,
linux-hardening, devicetree, linux-gpio
On Wed, Nov 04, 2026 at 03:03:47PM +0100, Bartosz Golaszewski wrote:
> Implement the property_get_names() callback from the fwnode interface
> for OF nodes.
...
> #include <linux/string.h>
> +#include <linux/string_helpers.h>
Same comment as per fwnode patch.
...
> +static int of_fwnode_property_get_names(const struct fwnode_handle *fwnode,
> + char ***props)
> +{
> + const struct device_node *node = to_of_node(fwnode);
> + struct property *prop;
> + int count = 0, i = 0;
> + char **names;
> + for_each_property_of_node(node, prop)
> + count++;
Hmm... Don't we have a helper for that already?
> + names = kcalloc(count, sizeof(*names), GFP_KERNEL);
> + if (!names)
> + return -ENOMEM;
> +
> + for_each_property_of_node(node, prop) {
> + names[i] = kstrdup(prop->name, GFP_KERNEL);
Can property be statically defined somewhere? We might want to also optimize
these duplications with const variant (here or elsewhere, for fwnode generic
path, I believe).
> + if (!names[i]) {
> + kfree_strarray(names, i);
> + return -ENOMEM;
> + }
> + i++;
> + }
> +
> + *props = names;
> + return count;
> +}
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 6/9] fwnode: define the count_references() fwnode operation
2026-11-04 14:03 [PATCH 0/9] gpio: make gpiolib-shared more fwnode-centric Bartosz Golaszewski
` (4 preceding siblings ...)
2026-11-04 14:03 ` [PATCH 5/9] of: property: implement the .property_get_names() fwnode operation Bartosz Golaszewski
@ 2026-11-04 14:03 ` Bartosz Golaszewski
2026-11-04 14:03 ` [PATCH 7/9] device property: provide fwnode_property_count_references() Bartosz Golaszewski
` (2 subsequent siblings)
8 siblings, 0 replies; 18+ messages in thread
From: Bartosz Golaszewski @ 2026-11-04 14:03 UTC (permalink / raw)
To: Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki,
Danilo Krummrich, Johan Hovold, Hans Verkuil, Laurent Pinchart,
Kees Cook, Andy Shevchenko, Len Brown, Rob Herring,
Saravana Kannan, Linus Walleij
Cc: linux-acpi, driver-core, linux-kernel, linux-hardening,
devicetree, linux-gpio, Bartosz Golaszewski
Add a new fwnode callback allowing to count all references of given
firmware node.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
include/linux/fwnode.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h
index 2d7e0b9245d445d473c7317bd27058abe5750b40..15acade60564ddb5f5a48f2235b626466d77dbdf 100644
--- a/include/linux/fwnode.h
+++ b/include/linux/fwnode.h
@@ -137,6 +137,10 @@ struct fwnode_reference_args {
* @get_parent: Return the parent of an fwnode.
* @get_next_child_node: Return the next child node in an iteration.
* @get_named_child_node: Return a child node with a given name.
+ * @count_references: Return the number of references in a property, including
+ * empty ones. @nargs_prop names the property in the
+ * referenced node holding the number of arguments, if NULL
+ * the references have no arguments.
* @get_reference_args: Return a reference pointed to by a property, with args
* @graph_get_next_endpoint: Return an endpoint node in an iteration.
* @graph_get_remote_endpoint: Return the remote endpoint node of a local
@@ -180,6 +184,8 @@ struct fwnode_operations {
struct fwnode_handle *
(*get_named_child_node)(const struct fwnode_handle *fwnode,
const char *name);
+ int (*count_references)(const struct fwnode_handle *fwnode,
+ const char *prop, const char *nargs_prop);
int (*get_reference_args)(const struct fwnode_handle *fwnode,
const char *prop, const char *nargs_prop,
unsigned int nargs, unsigned int index,
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 7/9] device property: provide fwnode_property_count_references()
2026-11-04 14:03 [PATCH 0/9] gpio: make gpiolib-shared more fwnode-centric Bartosz Golaszewski
` (5 preceding siblings ...)
2026-11-04 14:03 ` [PATCH 6/9] fwnode: define the count_references() " Bartosz Golaszewski
@ 2026-11-04 14:03 ` Bartosz Golaszewski
2026-11-04 14:03 ` [PATCH 8/9] of: property: implement the count_references() fwnode operation Bartosz Golaszewski
2026-11-04 14:03 ` [PATCH 9/9] gpio: shared: generalize most code to firmware nodes Bartosz Golaszewski
8 siblings, 0 replies; 18+ messages in thread
From: Bartosz Golaszewski @ 2026-11-04 14:03 UTC (permalink / raw)
To: Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki,
Danilo Krummrich, Johan Hovold, Hans Verkuil, Laurent Pinchart,
Kees Cook, Andy Shevchenko, Len Brown, Rob Herring,
Saravana Kannan, Linus Walleij
Cc: linux-acpi, driver-core, linux-kernel, linux-hardening,
devicetree, linux-gpio, Bartosz Golaszewski
Provide fwnode_property_count_references() - a new fwnode function that
allows callers to retrieve the number of references in given property.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/base/property.c | 35 +++++++++++++++++++++++++++++++++++
include/linux/property.h | 3 +++
2 files changed, 38 insertions(+)
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 7b0df3dfae53b6377dba91330aac746684e8adec..259ecc4dc31a7b07e2ae5f53aa2424de54ba8236 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -654,6 +654,41 @@ int fwnode_property_match_property_string(const struct fwnode_handle *fwnode,
}
EXPORT_SYMBOL_GPL(fwnode_property_match_property_string);
+/**
+ * fwnode_property_count_references() - Count the references in a property
+ * @fwnode: Firmware node where to look for the property
+ * @prop: The name of the property
+ * @nargs_prop: The name of the property telling the number of arguments in the
+ * referred node. NULL if the references have no arguments.
+ *
+ * Empty references count too, so every index in the range [0, count) can be
+ * passed to fwnode_property_get_reference_args(), which may still fail for
+ * empty entries.
+ *
+ * Return: Number of references on success,
+ * %-ENOENT if the property was not found,
+ * %-EINVAL on parse error.
+ */
+int fwnode_property_count_references(const struct fwnode_handle *fwnode,
+ const char *prop, const char *nargs_prop)
+{
+ int ret;
+
+ if (IS_ERR_OR_NULL(fwnode))
+ return -ENOENT;
+
+ ret = fwnode_call_int_op(fwnode, count_references, prop, nargs_prop);
+ if (ret >= 0)
+ return ret;
+
+ if (IS_ERR_OR_NULL(fwnode->secondary))
+ return ret;
+
+ return fwnode_call_int_op(fwnode->secondary, count_references, prop,
+ nargs_prop);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_count_references);
+
/**
* fwnode_property_get_reference_args() - Find a reference with arguments
* @fwnode: Firmware node where to look for the reference
diff --git a/include/linux/property.h b/include/linux/property.h
index a70f3c4c087dd85390951da950c3632f89c6cfd1..9f0b9aab5920513cd468572fa96dbe3371609591 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -137,6 +137,9 @@ int device_property_match_property_string(const struct device *dev,
return fwnode_property_match_property_string(dev_fwnode(dev), propname, array, n);
}
+int fwnode_property_count_references(const struct fwnode_handle *fwnode,
+ const char *prop, const char *nargs_prop);
+
int fwnode_property_get_reference_args(const struct fwnode_handle *fwnode,
const char *prop, const char *nargs_prop,
unsigned int nargs, unsigned int index,
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 8/9] of: property: implement the count_references() fwnode operation
2026-11-04 14:03 [PATCH 0/9] gpio: make gpiolib-shared more fwnode-centric Bartosz Golaszewski
` (6 preceding siblings ...)
2026-11-04 14:03 ` [PATCH 7/9] device property: provide fwnode_property_count_references() Bartosz Golaszewski
@ 2026-11-04 14:03 ` Bartosz Golaszewski
2026-11-04 15:33 ` Rob Herring
2026-11-04 14:03 ` [PATCH 9/9] gpio: shared: generalize most code to firmware nodes Bartosz Golaszewski
8 siblings, 1 reply; 18+ messages in thread
From: Bartosz Golaszewski @ 2026-11-04 14:03 UTC (permalink / raw)
To: Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki,
Danilo Krummrich, Johan Hovold, Hans Verkuil, Laurent Pinchart,
Kees Cook, Andy Shevchenko, Len Brown, Rob Herring,
Saravana Kannan, Linus Walleij
Cc: linux-acpi, driver-core, linux-kernel, linux-hardening,
devicetree, linux-gpio, Bartosz Golaszewski
Implement the property_count_references() fwnode operation for OF nodes
by wrapping the existing of_count_phandle_with_args().
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/of/property.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/of/property.c b/drivers/of/property.c
index 16c9c307633bdc7c9343782b1cd3bdb845552c6a..ae2561479e2382b241fd87dcddf52dc7f52a950e 100644
--- a/drivers/of/property.c
+++ b/drivers/of/property.c
@@ -1231,6 +1231,12 @@ of_fwnode_get_reference_args(const struct fwnode_handle *fwnode,
return 0;
}
+static int of_fwnode_count_references(const struct fwnode_handle *fwnode,
+ const char *prop, const char *nargs_prop)
+{
+ return of_count_phandle_with_args(to_of_node(fwnode), prop, nargs_prop);
+}
+
static struct fwnode_handle *
of_fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode,
struct fwnode_handle *prev)
@@ -1747,6 +1753,7 @@ const struct fwnode_operations of_fwnode_ops = {
.get_parent = of_fwnode_get_parent,
.get_next_child_node = of_fwnode_get_next_child_node,
.get_named_child_node = of_fwnode_get_named_child_node,
+ .count_references = of_fwnode_count_references,
.get_reference_args = of_fwnode_get_reference_args,
.graph_get_next_endpoint = of_fwnode_graph_get_next_endpoint,
.graph_get_remote_endpoint = of_fwnode_graph_get_remote_endpoint,
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH 8/9] of: property: implement the count_references() fwnode operation
2026-11-04 14:03 ` [PATCH 8/9] of: property: implement the count_references() fwnode operation Bartosz Golaszewski
@ 2026-11-04 15:33 ` Rob Herring
0 siblings, 0 replies; 18+ messages in thread
From: Rob Herring @ 2026-11-04 15:33 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki,
Danilo Krummrich, Johan Hovold, Hans Verkuil, Laurent Pinchart,
Kees Cook, Andy Shevchenko, Len Brown, Saravana Kannan,
Linus Walleij, linux-acpi, driver-core, linux-kernel,
linux-hardening, devicetree, linux-gpio
On Wed, Nov 04, 2026 at 03:03:50PM +0100, Bartosz Golaszewski wrote:
> Implement the property_count_references() fwnode operation for OF nodes
> by wrapping the existing of_count_phandle_with_args().
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
> ---
> drivers/of/property.c | 7 +++++++
> 1 file changed, 7 insertions(+)
Acked-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 9/9] gpio: shared: generalize most code to firmware nodes
2026-11-04 14:03 [PATCH 0/9] gpio: make gpiolib-shared more fwnode-centric Bartosz Golaszewski
` (7 preceding siblings ...)
2026-11-04 14:03 ` [PATCH 8/9] of: property: implement the count_references() fwnode operation Bartosz Golaszewski
@ 2026-11-04 14:03 ` Bartosz Golaszewski
2026-11-04 14:15 ` sashiko-bot
2026-11-04 21:33 ` Andy Shevchenko
8 siblings, 2 replies; 18+ messages in thread
From: Bartosz Golaszewski @ 2026-11-04 14:03 UTC (permalink / raw)
To: Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki,
Danilo Krummrich, Johan Hovold, Hans Verkuil, Laurent Pinchart,
Kees Cook, Andy Shevchenko, Len Brown, Rob Herring,
Saravana Kannan, Linus Walleij
Cc: linux-acpi, driver-core, linux-kernel, linux-hardening,
devicetree, linux-gpio, Bartosz Golaszewski
Ahead of adding support for sharing of GPIOs for other types of firmware
nodes, convert as much code in gpiolib-shared.c as possible to using
fwnode APIs and guard the remaining OF-specific bits with CONFIG_OF
guards.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/gpio/gpiolib-shared.c | 241 +++++++++++++++++++++++-------------------
1 file changed, 131 insertions(+), 110 deletions(-)
diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c
index 8c9ac9d9330490b17fb3936b8758beb97a308a15..58ac049bb603e2946c81e67a047b4788d39213b4 100644
--- a/drivers/gpio/gpiolib-shared.c
+++ b/drivers/gpio/gpiolib-shared.c
@@ -23,6 +23,7 @@
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/string_helpers.h>
#include "gpiolib.h"
#include "gpiolib-shared.h"
@@ -63,7 +64,7 @@ struct gpio_shared_entry {
static LIST_HEAD(gpio_shared_list);
static DEFINE_IDA(gpio_shared_ida);
-#if IS_ENABLED(CONFIG_OF)
+
static struct gpio_shared_entry *
gpio_shared_find_entry(struct fwnode_handle *controller_node,
unsigned int offset)
@@ -133,158 +134,162 @@ static int gpio_shared_setup_reset_proxy(struct gpio_shared_entry *entry,
}
/* Handle all special nodes that we should ignore. */
-static bool gpio_shared_of_node_ignore(struct device_node *node)
+static bool gpio_shared_fwnode_ignore(struct fwnode_handle *fwnode)
{
/* Ignore disabled devices. */
- if (!of_device_is_available(node))
+ if (!fwnode_device_is_available(fwnode))
return true;
/*
- * __symbols__ is a special, internal node and should not be considered
- * when scanning for shared GPIOs.
+ * On OF-systems __symbols__ is a special, internal node and should not
+ * be considered when scanning for shared GPIOs.
*/
- if (of_node_name_eq(node, "__symbols__"))
+ if (fwnode_name_eq(fwnode, "__symbols__"))
return true;
/*
* GPIO hogs have a "gpios" property which is not a phandle and can't
* possibly refer to a shared GPIO.
*/
- if (of_property_present(node, "gpio-hog"))
+ if (fwnode_property_present(fwnode, "gpio-hog"))
return true;
return false;
}
-static int gpio_shared_of_traverse(struct device_node *curr)
+static int gpio_shared_fwnode_scan_property(struct fwnode_handle *curr,
+ const char *propname)
{
+ struct fwnode_reference_args args;
struct gpio_shared_entry *entry;
size_t con_id_len, suffix_len;
struct fwnode_handle *fwnode;
- struct of_phandle_args args;
struct gpio_shared_ref *ref;
- struct property *prop;
unsigned int offset;
const char *suffix;
- int ret, count, i;
+ int ret, i, count;
- if (gpio_shared_of_node_ignore(curr))
+ /*
+ * The standard name for a GPIO property is "foo-gpios"
+ * or "foo-gpio". Some bindings also use "gpios" or "gpio".
+ * There are some legacy device-trees which have a different
+ * naming convention and for which we have rename quirks in
+ * place in gpiolib-of.c. I don't think any of them require
+ * support for shared GPIOs so for now let's just ignore
+ * them. We can always just export the quirk list and
+ * iterate over it here.
+ */
+ if (!strends(propname, "-gpios") && !strends(propname, "-gpio") &&
+ strcmp(propname, "gpios") != 0 && strcmp(propname, "gpio") != 0)
return 0;
- for_each_property_of_node(curr, prop) {
- /*
- * The standard name for a GPIO property is "foo-gpios"
- * or "foo-gpio". Some bindings also use "gpios" or "gpio".
- * There are some legacy device-trees which have a different
- * naming convention and for which we have rename quirks in
- * place in gpiolib-of.c. I don't think any of them require
- * support for shared GPIOs so for now let's just ignore
- * them. We can always just export the quirk list and
- * iterate over it here.
- */
- if (!strends(prop->name, "-gpios") &&
- !strends(prop->name, "-gpio") &&
- strcmp(prop->name, "gpios") != 0 &&
- strcmp(prop->name, "gpio") != 0)
- continue;
-
- count = of_count_phandle_with_args(curr, prop->name,
- "#gpio-cells");
- if (count <= 0)
- continue;
+ count = fwnode_property_count_references(curr, propname, "#gpio-cells");
+ if (count <= 0)
+ return 0;
- for (i = 0; i < count; i++) {
- struct device_node *np __free(device_node) = NULL;
- char *con_id __free(kfree) = NULL;
+ for (i = 0; i < count; i++) {
+ struct fwnode_handle *ctrl __free(fwnode_handle) = NULL;
+ char *con_id __free(kfree) = NULL;
- ret = of_parse_phandle_with_args(curr, prop->name,
- "#gpio-cells", i,
+ ret = fwnode_property_get_reference_args(curr, propname,
+ "#gpio-cells", 0, i,
&args);
- if (ret)
- continue;
+ if (ret)
+ continue;
- np = args.np;
+ ctrl = args.fwnode;
- if (!of_property_present(np, "gpio-controller"))
- continue;
+ if (!fwnode_property_present(ctrl, "gpio-controller"))
+ continue;
- /*
- * We support 1, 2 and 3 cell GPIO bindings in the
- * kernel currently. There's only one old MIPS dts that
- * has a one-cell binding but there's no associated
- * consumer so it may as well be an error. There don't
- * seem to be any 3-cell users of non-exclusive GPIOs,
- * so we can skip this as well. Let's occupy ourselves
- * with the predominant 2-cell binding with the first
- * cell indicating the hardware offset of the GPIO and
- * the second defining the GPIO flags of the request.
- */
- if (args.args_count != 2)
- continue;
+ /*
+ * We support 1, 2 and 3 cell GPIO bindings in the
+ * kernel currently. There's only one old MIPS dts that
+ * has a one-cell binding but there's no associated
+ * consumer so it may as well be an error. There don't
+ * seem to be any 3-cell users of non-exclusive GPIOs,
+ * so we can skip this as well. Let's occupy ourselves
+ * with the predominant 2-cell binding with the first
+ * cell indicating the hardware offset of the GPIO and
+ * the second defining the GPIO flags of the request.
+ */
+ if (args.nargs != 2)
+ continue;
- fwnode = of_fwnode_handle(args.np);
- offset = args.args[0];
+ fwnode = ctrl;
+ offset = args.args[0];
- entry = gpio_shared_find_entry(fwnode, offset);
- if (!entry) {
- entry = kzalloc_obj(*entry);
- if (!entry)
- return -ENOMEM;
+ entry = gpio_shared_find_entry(fwnode, offset);
+ if (!entry) {
+ entry = kzalloc_obj(*entry);
+ if (!entry)
+ return -ENOMEM;
- entry->fwnode = fwnode_handle_get(fwnode);
- entry->offset = offset;
- entry->index = count;
- INIT_LIST_HEAD(&entry->refs);
- mutex_init(&entry->lock);
+ entry->fwnode = fwnode_handle_get(fwnode);
+ entry->offset = offset;
+ entry->index = count;
+ INIT_LIST_HEAD(&entry->refs);
+ mutex_init(&entry->lock);
- list_add_tail(&entry->list, &gpio_shared_list);
- }
+ list_add_tail(&entry->list, &gpio_shared_list);
+ }
- if (strends(prop->name, "gpios"))
- suffix = "-gpios";
- else if (strends(prop->name, "gpio"))
- suffix = "-gpio";
- else
- suffix = NULL;
- if (!suffix)
- continue;
+ if (strends(propname, "gpios"))
+ suffix = "-gpios";
+ else if (strends(propname, "gpio"))
+ suffix = "-gpio";
+ else
+ suffix = NULL;
+ if (!suffix)
+ continue;
- /* We only set con_id if there's actually one. */
- if (strcmp(prop->name, "gpios") && strcmp(prop->name, "gpio")) {
- con_id = kstrdup(prop->name, GFP_KERNEL);
- if (!con_id)
- return -ENOMEM;
+ /* We only set con_id if there's actually one. */
+ if (strcmp(propname, "gpios") && strcmp(propname, "gpio")) {
+ con_id = kstrdup(propname, GFP_KERNEL);
+ if (!con_id)
+ return -ENOMEM;
- con_id_len = strlen(con_id);
- suffix_len = strlen(suffix);
+ con_id_len = strlen(con_id);
+ suffix_len = strlen(suffix);
- con_id[con_id_len - suffix_len] = '\0';
- }
+ con_id[con_id_len - suffix_len] = '\0';
+ }
- struct fwnode_handle *curr_fwnode =
- fwnode_handle_get(of_fwnode_handle(curr));
- ref = gpio_shared_make_ref(curr_fwnode, con_id, args.args[1]);
- if (!ref) {
- fwnode_handle_put(curr_fwnode);
- return -ENOMEM;
- }
+ ref = gpio_shared_make_ref(fwnode_handle_get(curr), con_id, args.args[1]);
+ if (!ref) {
+ fwnode_handle_put(curr);
+ return -ENOMEM;
+ }
- if (!list_empty(&entry->refs))
- pr_debug("GPIO %u at %s is shared by multiple firmware nodes\n",
- entry->offset, fwnode_get_name(entry->fwnode));
+ if (!list_empty(&entry->refs))
+ pr_debug("GPIO %u at %s is shared by multiple firmware nodes\n",
+ entry->offset, fwnode_get_name(entry->fwnode));
- list_add_tail(&ref->list, &entry->refs);
+ list_add_tail(&ref->list, &entry->refs);
- if (strcmp(prop->name, "reset-gpios") == 0) {
- ret = gpio_shared_setup_reset_proxy(entry, args.args[1]);
- if (ret)
- return ret;
- }
+ if (strcmp(propname, "reset-gpios") == 0) {
+ ret = gpio_shared_setup_reset_proxy(entry, args.args[1]);
+ if (ret)
+ return ret;
}
}
- for_each_child_of_node_scoped(curr, child) {
- ret = gpio_shared_of_traverse(child);
+ return 0;
+}
+
+static int gpio_shared_fwnode_scan_properties(struct fwnode_handle *curr)
+{
+ char **props;
+ int ret, i;
+
+ ret = fwnode_property_get_names(curr, &props);
+ if (ret <= 0)
+ return ret;
+
+ CLASS(strarray, names)(props, ret);
+
+ for (i = 0; i < names.size; i++) {
+ ret = gpio_shared_fwnode_scan_property(curr, names.array[i]);
if (ret)
return ret;
}
@@ -292,19 +297,35 @@ static int gpio_shared_of_traverse(struct device_node *curr)
return 0;
}
-static int gpio_shared_of_scan(void)
+static int gpio_shared_fwnode_traverse(struct fwnode_handle *curr)
{
- if (of_root)
- return gpio_shared_of_traverse(of_root);
+ int ret;
+
+ if (gpio_shared_fwnode_ignore(curr))
+ return 0;
+
+ ret = gpio_shared_fwnode_scan_properties(curr);
+ if (ret)
+ return ret;
+
+ fwnode_for_each_child_node_scoped(curr, child) {
+ ret = gpio_shared_fwnode_traverse(child);
+ if (ret)
+ return ret;
+ }
return 0;
}
-#else
+
static int gpio_shared_of_scan(void)
{
+#if IS_ENABLED(CONFIG_OF)
+ if (of_root)
+ return gpio_shared_fwnode_traverse(of_fwnode_handle(of_root));
+#endif
+
return 0;
}
-#endif /* CONFIG_OF */
static void gpio_shared_adev_release(struct device *dev)
{
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH 9/9] gpio: shared: generalize most code to firmware nodes
2026-11-04 14:03 ` [PATCH 9/9] gpio: shared: generalize most code to firmware nodes Bartosz Golaszewski
@ 2026-11-04 14:15 ` sashiko-bot
2026-11-04 21:33 ` Andy Shevchenko
1 sibling, 0 replies; 18+ messages in thread
From: sashiko-bot @ 2026-11-04 14:15 UTC (permalink / raw)
To: Bartosz Golaszewski; +Cc: devicetree, linux-gpio, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] gpio: shared: unused gpio_shared_fwnode_traverse() when CONFIG_OF=n
--
commit 6eeb937e478380a7cc0f030271074c97cd8b7361
Author: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
gpio: shared: generalize most code to firmware nodes
This commit converts the device-tree scanning code in gpiolib-shared.c to
use generic fwnode APIs and restricts the CONFIG_OF preprocessor guard to
gpio_shared_of_scan().
> diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c
> index 8c9ac9d933049..58ac049bb603e 100644
> --- a/drivers/gpio/gpiolib-shared.c
> +++ b/drivers/gpio/gpiolib-shared.c
[ ... ]
> @@ -292,19 +297,35 @@ static int gpio_shared_of_traverse(struct device_node *curr)
> return 0;
> }
>
> -static int gpio_shared_of_scan(void)
> +static int gpio_shared_fwnode_traverse(struct fwnode_handle *curr)
> {
> - if (of_root)
> - return gpio_shared_of_traverse(of_root);
> + int ret;
> +
> + if (gpio_shared_fwnode_ignore(curr))
> + return 0;
> +
> + ret = gpio_shared_fwnode_scan_properties(curr);
> + if (ret)
> + return ret;
> +
> + fwnode_for_each_child_node_scoped(curr, child) {
> + ret = gpio_shared_fwnode_traverse(child);
> + if (ret)
> + return ret;
> + }
>
> return 0;
> }
> -#else
> +
> static int gpio_shared_of_scan(void)
> {
> +#if IS_ENABLED(CONFIG_OF)
> + if (of_root)
> + return gpio_shared_fwnode_traverse(of_fwnode_handle(of_root));
> +#endif
> +
> return 0;
> }
> -#endif /* CONFIG_OF */
[Severity: Low]
When building with CONFIG_GPIO_SHARED=y and CONFIG_OF=n (for example, under
CONFIG_COMPILE_TEST=y), the only non-recursive caller of
gpio_shared_fwnode_traverse() in gpio_shared_of_scan() is preprocessed out.
Does this trigger a -Wunused-function compiler warning for
gpio_shared_fwnode_traverse() unless it is marked __maybe_unused?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261104-fwnode-for-each-prop-v1-0-6e28fe1c72c4@oss.qualcomm.com?part=9
^ permalink raw reply [flat|nested] 18+ messages in thread* Re: [PATCH 9/9] gpio: shared: generalize most code to firmware nodes
2026-11-04 14:03 ` [PATCH 9/9] gpio: shared: generalize most code to firmware nodes Bartosz Golaszewski
2026-11-04 14:15 ` sashiko-bot
@ 2026-11-04 21:33 ` Andy Shevchenko
1 sibling, 0 replies; 18+ messages in thread
From: Andy Shevchenko @ 2026-11-04 21:33 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Daniel Scally, Heikki Krogerus, Sakari Ailus, Bartosz Golaszewski,
Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Johan Hovold, Hans Verkuil, Laurent Pinchart, Kees Cook,
Andy Shevchenko, Len Brown, Rob Herring, Saravana Kannan,
Linus Walleij, linux-acpi, driver-core, linux-kernel,
linux-hardening, devicetree, linux-gpio
On Wed, Nov 04, 2026 at 03:03:51PM +0100, Bartosz Golaszewski wrote:
> Ahead of adding support for sharing of GPIOs for other types of firmware
> nodes, convert as much code in gpiolib-shared.c as possible to using
> fwnode APIs and guard the remaining OF-specific bits with CONFIG_OF
> guards.
...
> #include <linux/string.h>
> +#include <linux/string_helpers.h>
As commented before...
...
> static LIST_HEAD(gpio_shared_list);
> static DEFINE_IDA(gpio_shared_ida);
>
> -#if IS_ENABLED(CONFIG_OF)
> +
Do we need an extra blank line?
> static struct gpio_shared_entry *
> gpio_shared_find_entry(struct fwnode_handle *controller_node,
> unsigned int offset)
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 18+ messages in thread