Devicetree
 help / color / mirror / Atom feed
* [PATCH 0/9] gpio: make gpiolib-shared more fwnode-centric
@ 2026-11-04 14:03 Bartosz Golaszewski
  2026-11-04 14:03 ` [PATCH 1/9] device property: fix fwnode_name_eq() for empty node names Bartosz Golaszewski
                   ` (8 more replies)
  0 siblings, 9 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

Currently the code in gpiolib-shared.c only supports OF nodes and uses a
lot of OF-specific APIs. This series attempts to make the code more
generic, ahead of extending support for sharing GPIOs to other types of
firmware nodes, by defining two new fwnode operations, implementing them
for OF nodes and using them in GPIOLIB in order to limit the OF-specific
API usage to only a few places guarded by ifdefs.

The new fwnode APIs are:
a) property_get_names() - this closes the gap between OF nodes and
   fwnodes: OF nodes allow users to iterate over all properties while
   fwnodes don't advertise all properties in any way at the moment
b) count_references() - there's currently no way of counting references
   in an fwnode reliably: using fwnode_property_get_reference_args()
   does not work for empty references (e.g.: phandle = <0>, <&foo 1 2>;)

The first patch is a fix to fwnode_name_eq(). The second adds a CLASS()
for string arrays. The following 6 define and implement new fwnode
operations. The final patch generalizes the code in gpiolib-shared.c.

Merging strategy: patches 1-8 should go through the driver core tree and
be provided on an immutable branch to me so that I can pull it and queue
the final patch via the GPIO tree.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
Bartosz Golaszewski (9):
      device property: fix fwnode_name_eq() for empty node names
      lib: string_helpers: implement a CLASS() for string arrays
      fwnode: define the property_get_names() operation
      device property: provide fwnode_property_get_names()
      of: property: implement the .property_get_names() fwnode operation
      fwnode: define the count_references() fwnode operation
      device property: provide fwnode_property_count_references()
      of: property: implement the count_references() fwnode operation
      gpio: shared: generalize most code to firmware nodes

 drivers/base/property.c        | 114 ++++++++++++++++++-
 drivers/gpio/gpiolib-shared.c  | 241 ++++++++++++++++++++++-------------------
 drivers/of/property.c          |  37 +++++++
 include/linux/fwnode.h         |  15 +++
 include/linux/property.h       |   4 +
 include/linux/string_helpers.h |  12 ++
 6 files changed, 312 insertions(+), 111 deletions(-)
---
base-commit: 6628e7d4c6b25c8d18f1345e3a20d21829aae7e4
change-id: 20260916-fwnode-for-each-prop-d7a6f90e7338

Best regards,
-- 
Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [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

* [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

* [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

* [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

* [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 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 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 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 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

* 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

* 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

* 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

* 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

end of thread, other threads:[~2026-11-04 21:34 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 21:07   ` Andy Shevchenko
2026-11-04 14:03 ` [PATCH 3/9] fwnode: define the property_get_names() operation Bartosz Golaszewski
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
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
2026-11-04 14:03 ` [PATCH 6/9] fwnode: define the count_references() " Bartosz Golaszewski
2026-11-04 14:03 ` [PATCH 7/9] device property: provide fwnode_property_count_references() Bartosz Golaszewski
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
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox