lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20260105-reset-core-refactor-v1-14-ac443103498d@oss.qualcomm.com>
Date: Mon, 05 Jan 2026 15:15:33 +0100
From: Bartosz Golaszewski <bartosz.golaszewski@....qualcomm.com>
To: Krzysztof Kozlowski <krzk@...nel.org>,
        Philipp Zabel <p.zabel@...gutronix.de>
Cc: linux-kernel@...r.kernel.org,
        Bartosz Golaszewski <bartosz.golaszewski@....qualcomm.com>
Subject: [PATCH 14/15] reset: convert reset core to using firmware nodes

With everything else now in place, we can convert the remaining parts of
the reset subsystem to becoming fwnode-agnostic - meaning it will work
with all kinds of firmware nodes, not only devicetree.

To that end: extend struct reset_controller_dev with fields taking
information relevant for using firmware nodes (which mirrors what we
already do for OF-nodes) and limit using of_ APIs only to where it's
absolutely necessary (mostly around the of_xlate callback).

For backward compatibility of existing drivers we still support OF-nodes
but firmware nodes become the preferred method.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@....qualcomm.com>
---
 drivers/reset/core.c             | 150 +++++++++++++++++++++++----------------
 include/linux/reset-controller.h |  14 +++-
 2 files changed, 101 insertions(+), 63 deletions(-)

diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 11c5bd0fe2b23e76db0b4739c5e34e478d83608b..310434ba5caae716a21e4f8ea7062dd201fb1f2c 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -81,13 +81,13 @@ struct reset_control_array {
 
 /**
  * struct reset_gpio_lookup - lookup key for ad-hoc created reset-gpio devices
- * @of_args: phandle to the reset controller with all the args like GPIO number
+ * @ref_args: Reference to the reset controller with all the args like GPIO number
  * @swnode: Software node containing the reference to the GPIO provider
  * @list: list entry for the reset_gpio_lookup_list
  * @adev: Auxiliary device representing the reset controller
  */
 struct reset_gpio_lookup {
-	struct of_phandle_args of_args;
+	struct fwnode_reference_args ref_args;
 	struct fwnode_handle *swnode;
 	struct list_head list;
 	struct auxiliary_device adev;
@@ -98,24 +98,24 @@ static const char *rcdev_name(struct reset_controller_dev *rcdev)
 	if (rcdev->dev)
 		return dev_name(rcdev->dev);
 
-	if (rcdev->of_node)
-		return rcdev->of_node->full_name;
+	if (rcdev->fwnode)
+		return fwnode_get_name(rcdev->fwnode);
 
 	return NULL;
 }
 
 /**
- * of_reset_simple_xlate - translate reset_spec to the reset line number
+ * fwnode_reset_simple_xlate - translate reset_spec to the reset line number
  * @rcdev: a pointer to the reset controller device
- * @reset_spec: reset line specifier as found in the device tree
+ * @reset_spec: reset line specifier as found in firmware
  *
- * This static translation function is used by default if of_xlate in
+ * This static translation function is used by default if fwnode_xlate in
  * :c:type:`reset_controller_dev` is not set. It is useful for all reset
  * controllers with 1:1 mapping, where reset lines can be indexed by number
  * without gaps.
  */
-static int of_reset_simple_xlate(struct reset_controller_dev *rcdev,
-				 const struct of_phandle_args *reset_spec)
+static int fwnode_reset_simple_xlate(struct reset_controller_dev *rcdev,
+				     const struct fwnode_reference_args *reset_spec)
 {
 	if (reset_spec->args[0] >= rcdev->nr_resets)
 		return -EINVAL;
@@ -129,9 +129,17 @@ static int of_reset_simple_xlate(struct reset_controller_dev *rcdev,
  */
 int reset_controller_register(struct reset_controller_dev *rcdev)
 {
-	if (!rcdev->of_xlate) {
-		rcdev->of_reset_n_cells = 1;
-		rcdev->of_xlate = of_reset_simple_xlate;
+	if ((rcdev->of_node && rcdev->fwnode) || (rcdev->of_xlate && rcdev->fwnode_xlate))
+		return -EINVAL;
+
+	if (rcdev->of_node) {
+		rcdev->fwnode = of_fwnode_handle(rcdev->of_node);
+		rcdev->fwnode_reset_n_cells = rcdev->of_reset_n_cells;
+	}
+
+	if (rcdev->fwnode && !rcdev->fwnode_xlate) {
+		rcdev->fwnode_reset_n_cells = 1;
+		rcdev->fwnode_xlate = fwnode_reset_simple_xlate;
 	}
 
 	INIT_LIST_HEAD(&rcdev->reset_control_head);
@@ -917,7 +925,7 @@ static int reset_create_gpio_aux_device(struct reset_gpio_lookup *rgpio_dev,
 	adev->id = id;
 	adev->name = "gpio";
 	adev->dev.parent = parent;
-	adev->dev.platform_data = &rgpio_dev->of_args;
+	adev->dev.platform_data = &rgpio_dev->ref_args;
 	adev->dev.release = reset_gpio_aux_device_release;
 	device_set_node(&adev->dev, rgpio_dev->swnode);
 
@@ -937,18 +945,18 @@ static int reset_create_gpio_aux_device(struct reset_gpio_lookup *rgpio_dev,
 	return 0;
 }
 
-static void reset_gpio_add_devlink(struct device_node *np,
+static void reset_gpio_add_devlink(struct fwnode_handle *fwnode,
 				   struct reset_gpio_lookup *rgpio_dev)
 {
 	struct device *consumer;
 
 	/*
-	 * We must use get_dev_from_fwnode() and not of_find_device_by_node()
+	 * We must use get_dev_from_fwnode() and not ref_find_device_by_node()
 	 * because the latter only considers the platform bus while we want to
 	 * get consumers of any kind that can be associated with firmware
 	 * nodes: auxiliary, soundwire, etc.
 	 */
-	consumer = get_dev_from_fwnode(of_fwnode_handle(np));
+	consumer = get_dev_from_fwnode(fwnode);
 	if (consumer) {
 		if (!device_link_add(consumer, &rgpio_dev->adev.dev,
 				     DL_FLAG_AUTOREMOVE_CONSUMER))
@@ -968,15 +976,23 @@ static void reset_gpio_add_devlink(struct device_node *np,
 	 */
 }
 
+/* TODO: move it out into drivers/base/ */
+static bool fwnode_reference_args_equal(const struct fwnode_reference_args *left,
+					const struct fwnode_reference_args *right)
+{
+	return left->fwnode == right->fwnode && left->nargs == right->nargs &&
+	       !memcmp(left->args, right->args, sizeof(left->args[0]) * left->nargs);
+}
+
 /*
  * @np: OF-node associated with the consumer
- * @args: phandle to the GPIO provider with all the args like GPIO number
+ * @args: Reference to the GPIO provider with all the args like GPIO number
  */
-static int __reset_add_reset_gpio_device(struct device_node *np,
-					 const struct of_phandle_args *args)
+static int __reset_add_reset_gpio_device(struct fwnode_handle *fwnode,
+					 const struct fwnode_reference_args *args)
 {
 	struct property_entry properties[3] = { };
-	unsigned int offset, of_flags, lflags;
+	unsigned int offset, flags, lflags;
 	struct reset_gpio_lookup *rgpio_dev;
 	struct device *parent;
 	int ret, prop = 0;
@@ -987,7 +1003,7 @@ static int __reset_add_reset_gpio_device(struct device_node *np,
 	 * args[1]: GPIO flags
 	 * TODO: Handle other cases.
 	 */
-	if (args->args_count != 2)
+	if (args->nargs != 2)
 		return -ENOENT;
 
 	/*
@@ -998,7 +1014,7 @@ static int __reset_add_reset_gpio_device(struct device_node *np,
 	lockdep_assert_not_held(&reset_list_mutex);
 
 	offset = args->args[0];
-	of_flags = args->args[1];
+	flags = args->args[1];
 
 	/*
 	 * Later we map GPIO flags between OF and Linux, however not all
@@ -1008,33 +1024,31 @@ static int __reset_add_reset_gpio_device(struct device_node *np,
 	 * FIXME: Find a better way of translating OF flags to GPIO lookup
 	 * flags.
 	 */
-	if (of_flags > GPIO_ACTIVE_LOW) {
+	if (flags > GPIO_ACTIVE_LOW) {
 		pr_err("reset-gpio code does not support GPIO flags %u for GPIO %u\n",
-		       of_flags, offset);
+		       flags, offset);
 		return -EINVAL;
 	}
 
 	struct gpio_device *gdev __free(gpio_device_put) =
-		gpio_device_find_by_fwnode(of_fwnode_handle(args->np));
+			gpio_device_find_by_fwnode(args->fwnode);
 	if (!gdev)
 		return -EPROBE_DEFER;
 
 	guard(mutex)(&reset_gpio_lookup_mutex);
 
 	list_for_each_entry(rgpio_dev, &reset_gpio_lookup_list, list) {
-		if (args->np == rgpio_dev->of_args.np) {
-			if (of_phandle_args_equal(args, &rgpio_dev->of_args)) {
-				/*
-				 * Already on the list, create the device link
-				 * and stop here.
-				 */
-				reset_gpio_add_devlink(np, rgpio_dev);
-				return 0;
-			}
+		if (fwnode_reference_args_equal(args, &rgpio_dev->ref_args)) {
+			/*
+			 * Already on the list, create the device link
+			 * and stop here.
+			 */
+			reset_gpio_add_devlink(fwnode, rgpio_dev);
+			return 0;
 		}
 	}
 
-	lflags = GPIO_PERSISTENT | (of_flags & GPIO_ACTIVE_LOW);
+	lflags = GPIO_PERSISTENT | (flags & GPIO_ACTIVE_LOW);
 	parent = gpio_device_to_device(gdev);
 	properties[prop++] = PROPERTY_ENTRY_STRING("compatible", "reset-gpio");
 	properties[prop++] = PROPERTY_ENTRY_GPIO("reset-gpios", parent->fwnode, offset, lflags);
@@ -1044,43 +1058,43 @@ static int __reset_add_reset_gpio_device(struct device_node *np,
 	if (!rgpio_dev)
 		return -ENOMEM;
 
-	rgpio_dev->of_args = *args;
+	rgpio_dev->ref_args = *args;
 	/*
-	 * We keep the device_node reference, but of_args.np is put at the end
-	 * of __fwnode_reset_control_get(), so get it one more time.
+	 * We keep the fwnode_handle reference, but ref_args.fwnode is put at
+	 * the end of __fwnode_reset_control_get(), so get it one more time.
 	 * Hold reference as long as rgpio_dev memory is valid.
 	 */
-	of_node_get(rgpio_dev->of_args.np);
+	fwnode_handle_get(rgpio_dev->ref_args.fwnode);
 
 	rgpio_dev->swnode = fwnode_create_software_node(properties, NULL);
 	if (IS_ERR(rgpio_dev->swnode)) {
 		ret = PTR_ERR(rgpio_dev->swnode);
-		goto err_put_of_node;
+		goto err_put_fwnode;
 	}
 
 	ret = reset_create_gpio_aux_device(rgpio_dev, parent);
 	if (ret)
 		goto err_del_swnode;
 
-	reset_gpio_add_devlink(np, rgpio_dev);
+	reset_gpio_add_devlink(fwnode, rgpio_dev);
 	list_add(&rgpio_dev->list, &reset_gpio_lookup_list);
 
 	return 0;
 
 err_del_swnode:
 	fwnode_remove_software_node(rgpio_dev->swnode);
-err_put_of_node:
-	of_node_put(rgpio_dev->of_args.np);
+err_put_fwnode:
+	fwnode_handle_put(rgpio_dev->ref_args.fwnode);
 	kfree(rgpio_dev);
 
 	return ret;
 }
 
-static struct reset_controller_dev *__reset_find_rcdev(const struct of_phandle_args *args,
-						       bool gpio_fallback)
+static struct reset_controller_dev *
+__reset_find_rcdev(const struct fwnode_reference_args *args, bool gpio_fallback)
 {
 	struct reset_controller_dev *rcdev;
-	struct of_phandle_args *rc_args;
+	struct fwnode_reference_args *rc_args;
 
 	lockdep_assert_held(&reset_list_mutex);
 
@@ -1088,10 +1102,10 @@ static struct reset_controller_dev *__reset_find_rcdev(const struct of_phandle_a
 		if (gpio_fallback && device_is_compatible(rcdev->dev, "reset-gpio")) {
 			rc_args = dev_get_platdata(rcdev->dev);
 
-			if (of_phandle_args_equal(args, rc_args))
+			if (fwnode_reference_args_equal(args, rc_args))
 				return rcdev;
 		} else {
-			if (args->np == rcdev->of_node)
+			if (args->fwnode == rcdev->fwnode)
 				return rcdev;
 		}
 	}
@@ -1105,27 +1119,26 @@ __fwnode_reset_control_get(struct fwnode_handle *fwnode, const char *id, int ind
 {
 	bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
 	bool gpio_fallback = false;
-	struct device_node *node = to_of_node(fwnode);
 	struct reset_control *rstc = ERR_PTR(-EINVAL);
 	struct reset_controller_dev *rcdev;
-	struct of_phandle_args args;
-	int rstc_id;
+	struct fwnode_reference_args args;
+	struct of_phandle_args of_args;
+	int rstc_id = -EINVAL;
 	int ret;
 
 	if (!fwnode)
 		return ERR_PTR(-EINVAL);
 
 	if (id) {
-		index = of_property_match_string(node,
-						 "reset-names", id);
+		index = fwnode_property_match_string(fwnode, "reset-names", id);
 		if (index == -EILSEQ)
 			return ERR_PTR(index);
 		if (index < 0)
 			return optional ? NULL : ERR_PTR(-ENOENT);
 	}
 
-	ret = of_parse_phandle_with_args(node, "resets", "#reset-cells",
-					 index, &args);
+	ret = fwnode_property_get_reference_args(fwnode, "resets", "#reset-cells",
+						 0, index, &args);
 	if (ret == -EINVAL)
 		return ERR_PTR(ret);
 	if (ret) {
@@ -1136,14 +1149,14 @@ __fwnode_reset_control_get(struct fwnode_handle *fwnode, const char *id, int ind
 		 * There can be only one reset-gpio for regular devices, so
 		 * don't bother with the "reset-gpios" phandle index.
 		 */
-		ret = of_parse_phandle_with_args(node, "reset-gpios", "#gpio-cells",
-						 0, &args);
+		ret = fwnode_property_get_reference_args(fwnode, "reset-gpios",
+							 "#gpio-cells", 0, 0, &args);
 		if (ret)
 			return optional ? NULL : ERR_PTR(ret);
 
 		gpio_fallback = true;
 
-		ret = __reset_add_reset_gpio_device(node, &args);
+		ret = __reset_add_reset_gpio_device(fwnode, &args);
 		if (ret) {
 			rstc = ERR_PTR(ret);
 			goto out_put;
@@ -1158,12 +1171,27 @@ __fwnode_reset_control_get(struct fwnode_handle *fwnode, const char *id, int ind
 		goto out_put;
 	}
 
-	if (WARN_ON(args.args_count != rcdev->of_reset_n_cells)) {
+	if (WARN_ON(args.nargs != rcdev->fwnode_reset_n_cells)) {
 		rstc = ERR_PTR(-EINVAL);
 		goto out_put;
 	}
 
-	rstc_id = rcdev->of_xlate(rcdev, &args);
+	if (rcdev->of_xlate && is_of_node(fwnode)) {
+		ret = of_parse_phandle_with_args(to_of_node(fwnode),
+						 gpio_fallback ? "reset-gpios" : "resets",
+						 gpio_fallback ? "#gpio-cells" : "#reset-cells",
+						 gpio_fallback ? 0 : index,
+						 &of_args);
+		if (ret) {
+			rstc = ERR_PTR(ret);
+			goto out_put;
+		}
+
+		rstc_id = rcdev->of_xlate(rcdev, &of_args);
+		of_node_put(of_args.np);
+	} else if (rcdev->fwnode_xlate) {
+		rstc_id = rcdev->fwnode_xlate(rcdev, &args);
+	}
 	if (rstc_id < 0) {
 		rstc = ERR_PTR(rstc_id);
 		goto out_put;
@@ -1175,7 +1203,7 @@ __fwnode_reset_control_get(struct fwnode_handle *fwnode, const char *id, int ind
 		rstc = __reset_control_get_internal(rcdev, rstc_id, flags);
 
 out_put:
-	of_node_put(args.np);
+	fwnode_handle_put(args.fwnode);
 
 	return rstc;
 }
diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h
index 2fecb4edeba1a2b1f5f5db2b34c867362c5f9c18..2f7a1217d0ec6dba4f8831fb8c66308188f7a339 100644
--- a/include/linux/reset-controller.h
+++ b/include/linux/reset-controller.h
@@ -5,6 +5,8 @@
 #include <linux/list.h>
 #include <linux/mutex.h>
 
+struct fwnode_handle;
+struct fwnode_reference_args;
 struct reset_controller_dev;
 
 /**
@@ -38,8 +40,12 @@ struct of_phandle_args;
  * @of_node: corresponding device tree node as phandle target
  * @of_reset_n_cells: number of cells in reset line specifiers
  * @of_xlate: translation function to translate from specifier as found in the
- *            device tree to id as given to the reset control ops, defaults
- *            to :c:func:`of_reset_simple_xlate`.
+ *            device tree to id as given to the reset control ops
+ * @fwnode: firmware node associated with this device
+ * @fwnode_reset_n_cells: number of cells in reset line specifiers
+ * @fwnode_xlate: translation function to translate from firmware specifier to
+ *                id as given to the reset control ops, defaults to
+ *                :c:func:`fwnode_reset_simple_xlate`
  * @nr_resets: number of reset controls in this reset controller device
  * @lock: synchronizes concurrent access to the structure's fields
  */
@@ -53,6 +59,10 @@ struct reset_controller_dev {
 	int of_reset_n_cells;
 	int (*of_xlate)(struct reset_controller_dev *rcdev,
 			const struct of_phandle_args *reset_spec);
+	struct fwnode_handle *fwnode;
+	int fwnode_reset_n_cells;
+	int (*fwnode_xlate)(struct reset_controller_dev *rcdev,
+			    const struct fwnode_reference_args *reset_spec);
 	unsigned int nr_resets;
 	struct mutex lock;
 };

-- 
2.47.3


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ