* [PATCH v3 01/14] reset: gpio: remove unneeded OF-node put
2026-03-06 17:22 [PATCH v3 00/14] reset: major reset core refactoring Bartosz Golaszewski
@ 2026-03-06 17:22 ` Bartosz Golaszewski
2026-03-06 17:22 ` [PATCH v3 02/14] reset: gpio: add a devlink between reset-gpio and its consumer Bartosz Golaszewski
` (13 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Bartosz Golaszewski @ 2026-03-06 17:22 UTC (permalink / raw)
To: Krzysztof Kozlowski, Philipp Zabel, Jonathan Corbet, Shuah Khan
Cc: linux-kernel, brgl, linux-doc, Bartosz Golaszewski
priv->rc.of_node is never set in reset core. Even if it were: tasking
the reset-gpio driver with controlling the reference count of an OF node
set up in reset core is a weird inversion of responsability. But it's
also wrong in that the underlying device never actually gets removed so
the node should not be put at all and especially not at driver detach.
Remove the devres action.
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/reset/reset-gpio.c | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/drivers/reset/reset-gpio.c b/drivers/reset/reset-gpio.c
index 0a1610d9e78a3f1db8f523654a548fbba6087106..ad5bfe27aaef7de57f9566330253333aa2b1253f 100644
--- a/drivers/reset/reset-gpio.c
+++ b/drivers/reset/reset-gpio.c
@@ -52,18 +52,12 @@ static int reset_gpio_of_xlate(struct reset_controller_dev *rcdev,
return reset_spec->args[0];
}
-static void reset_gpio_of_node_put(void *data)
-{
- of_node_put(data);
-}
-
static int reset_gpio_probe(struct auxiliary_device *adev,
const struct auxiliary_device_id *id)
{
struct device *dev = &adev->dev;
struct of_phandle_args *platdata = dev_get_platdata(dev);
struct reset_gpio_priv *priv;
- int ret;
if (!platdata)
return -EINVAL;
@@ -83,10 +77,6 @@ static int reset_gpio_probe(struct auxiliary_device *adev,
priv->rc.owner = THIS_MODULE;
priv->rc.dev = dev;
priv->rc.of_args = platdata;
- ret = devm_add_action_or_reset(dev, reset_gpio_of_node_put,
- priv->rc.of_node);
- if (ret)
- return ret;
/* Cells to match GPIO specifier, but it's not really used */
priv->rc.of_reset_n_cells = 2;
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH v3 02/14] reset: gpio: add a devlink between reset-gpio and its consumer
2026-03-06 17:22 [PATCH v3 00/14] reset: major reset core refactoring Bartosz Golaszewski
2026-03-06 17:22 ` [PATCH v3 01/14] reset: gpio: remove unneeded OF-node put Bartosz Golaszewski
@ 2026-03-06 17:22 ` Bartosz Golaszewski
2026-03-06 17:22 ` [PATCH v3 03/14] reset: gpio: simplify fallback device matching Bartosz Golaszewski
` (12 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Bartosz Golaszewski @ 2026-03-06 17:22 UTC (permalink / raw)
To: Krzysztof Kozlowski, Philipp Zabel, Jonathan Corbet, Shuah Khan
Cc: linux-kernel, brgl, linux-doc, Bartosz Golaszewski
The device that requests the reset control managed by the reset-gpio
device is effectively its consumer but the devlink is only established
between it and the GPIO controller exposing the reset pin. Add a devlink
between the consumer of the reset control and its supplier. This will
allow us to simplify the GPIOLIB code managing shared GPIOs when
handling the corner case of reset-gpio and gpiolib-shared interacting.
While at it and since we need to store the address of the auxiliary
device: don't allocate memory for the device separately but fold it into
struct reset_gpio_lookup instead.
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/reset/core.c | 79 ++++++++++++++++++++++++++++++++++++----------------
1 file changed, 55 insertions(+), 24 deletions(-)
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index fceec45c8afc1e74fe46311bdc023ff257e8d770..3845e77a8d32bf615c9d430847b497af0ba374ad 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -77,11 +77,13 @@ struct reset_control_array {
* @of_args: phandle 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_handle *swnode;
struct list_head list;
+ struct auxiliary_device adev;
};
static const char *rcdev_name(struct reset_controller_dev *rcdev)
@@ -824,49 +826,72 @@ static void __reset_control_put_internal(struct reset_control *rstc)
static void reset_gpio_aux_device_release(struct device *dev)
{
- struct auxiliary_device *adev = to_auxiliary_dev(dev);
- kfree(adev);
}
-static int reset_add_gpio_aux_device(struct device *parent,
- struct fwnode_handle *swnode,
- int id, void *pdata)
+static int reset_create_gpio_aux_device(struct reset_gpio_lookup *rgpio_dev,
+ struct device *parent, int id)
{
- struct auxiliary_device *adev;
+ struct auxiliary_device *adev = &rgpio_dev->adev;
int ret;
- adev = kzalloc_obj(*adev);
- if (!adev)
- return -ENOMEM;
-
adev->id = id;
adev->name = "gpio";
adev->dev.parent = parent;
- adev->dev.platform_data = pdata;
+ adev->dev.platform_data = &rgpio_dev->of_args;
adev->dev.release = reset_gpio_aux_device_release;
- device_set_node(&adev->dev, swnode);
+ device_set_node(&adev->dev, rgpio_dev->swnode);
ret = auxiliary_device_init(adev);
- if (ret) {
- kfree(adev);
+ if (ret)
return ret;
- }
ret = __auxiliary_device_add(adev, "reset");
if (ret) {
auxiliary_device_uninit(adev);
- kfree(adev);
return ret;
}
- return ret;
+ return 0;
+}
+
+static void reset_gpio_add_devlink(struct device_node *np,
+ struct reset_gpio_lookup *rgpio_dev)
+{
+ struct device *consumer;
+
+ /*
+ * We must use get_dev_from_fwnode() and not of_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));
+ if (consumer) {
+ if (!device_link_add(consumer, &rgpio_dev->adev.dev,
+ DL_FLAG_AUTOREMOVE_CONSUMER))
+ pr_warn("Failed to create a device link between reset-gpio and its consumer");
+
+ put_device(consumer);
+ }
+ /*
+ * else { }
+ *
+ * TODO: If ever there's a case where we need to support shared
+ * reset-gpios retrieved from a device node for which there's no
+ * device present yet, this is where we'd set up a notifier waiting
+ * for the device to appear in the system. This would be a lot of code
+ * that would go unused for now so let's cross that bridge when and if
+ * we get there.
+ */
}
/*
- * @args: phandle to the GPIO provider with all the args like GPIO number
+ * @np: OF-node associated with the consumer
+ * @args: phandle to the GPIO provider with all the args like GPIO number
*/
-static int __reset_add_reset_gpio_device(const struct of_phandle_args *args)
+static int __reset_add_reset_gpio_device(struct device_node *np,
+ const struct of_phandle_args *args)
{
struct property_entry properties[3] = { };
unsigned int offset, of_flags, lflags;
@@ -916,8 +941,14 @@ static int __reset_add_reset_gpio_device(const struct of_phandle_args *args)
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))
- return 0; /* Already on the list, done */
+ 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;
+ }
}
}
@@ -951,11 +982,11 @@ static int __reset_add_reset_gpio_device(const struct of_phandle_args *args)
goto err_put_of_node;
}
- ret = reset_add_gpio_aux_device(parent, rgpio_dev->swnode, id,
- &rgpio_dev->of_args);
+ ret = reset_create_gpio_aux_device(rgpio_dev, parent, id);
if (ret)
goto err_del_swnode;
+ reset_gpio_add_devlink(np, rgpio_dev);
list_add(&rgpio_dev->list, &reset_gpio_lookup_list);
return 0;
@@ -1035,7 +1066,7 @@ __of_reset_control_get(struct device_node *node, const char *id, int index,
gpio_fallback = true;
- ret = __reset_add_reset_gpio_device(&args);
+ ret = __reset_add_reset_gpio_device(node, &args);
if (ret) {
rstc = ERR_PTR(ret);
goto out_put;
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH v3 03/14] reset: gpio: simplify fallback device matching
2026-03-06 17:22 [PATCH v3 00/14] reset: major reset core refactoring Bartosz Golaszewski
2026-03-06 17:22 ` [PATCH v3 01/14] reset: gpio: remove unneeded OF-node put Bartosz Golaszewski
2026-03-06 17:22 ` [PATCH v3 02/14] reset: gpio: add a devlink between reset-gpio and its consumer Bartosz Golaszewski
@ 2026-03-06 17:22 ` Bartosz Golaszewski
2026-03-06 17:22 ` [PATCH v3 04/14] reset: gpio: remove unneeded auxiliary_set_drvdata() Bartosz Golaszewski
` (11 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Bartosz Golaszewski @ 2026-03-06 17:22 UTC (permalink / raw)
To: Krzysztof Kozlowski, Philipp Zabel, Jonathan Corbet, Shuah Khan
Cc: linux-kernel, brgl, linux-doc, Bartosz Golaszewski
The of_args field of struct reset_controller_dev was introduced to allow
the reset-gpio driver to pass the phandle arguments back to reset core.
The thing is: it doesn't even have to do it. The core sets the platform
data of the auxiliary device *AND* has access to it later on during the
lookup. This means the field is unneeded and all can happen entirely in
reset core.
Remove the field from the public header and don't set it in
reset-gpio.c. Retrieve the platform data in reset core when needed
instead.
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/reset/core.c | 15 ++++++---------
drivers/reset/reset-gpio.c | 5 -----
include/linux/reset-controller.h | 4 ----
3 files changed, 6 insertions(+), 18 deletions(-)
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 3845e77a8d32bf615c9d430847b497af0ba374ad..954df36a242e804b639027384700b8d988be0e90 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -94,9 +94,6 @@ static const char *rcdev_name(struct reset_controller_dev *rcdev)
if (rcdev->of_node)
return rcdev->of_node->full_name;
- if (rcdev->of_args)
- return rcdev->of_args->np->full_name;
-
return NULL;
}
@@ -125,9 +122,6 @@ static int of_reset_simple_xlate(struct reset_controller_dev *rcdev,
*/
int reset_controller_register(struct reset_controller_dev *rcdev)
{
- if (rcdev->of_node && rcdev->of_args)
- return -EINVAL;
-
if (!rcdev->of_xlate) {
rcdev->of_reset_n_cells = 1;
rcdev->of_xlate = of_reset_simple_xlate;
@@ -1006,13 +1000,16 @@ static struct reset_controller_dev *__reset_find_rcdev(const struct of_phandle_a
bool gpio_fallback)
{
struct reset_controller_dev *rcdev;
+ struct of_phandle_args *rc_args;
lockdep_assert_held(&reset_list_mutex);
list_for_each_entry(rcdev, &reset_controller_list, list) {
- if (gpio_fallback) {
- if (rcdev->of_args && of_phandle_args_equal(args,
- rcdev->of_args))
+ if (gpio_fallback && rcdev->dev &&
+ device_is_compatible(rcdev->dev, "reset-gpio")) {
+ rc_args = dev_get_platdata(rcdev->dev);
+
+ if (of_phandle_args_equal(args, rc_args))
return rcdev;
} else {
if (args->np == rcdev->of_node)
diff --git a/drivers/reset/reset-gpio.c b/drivers/reset/reset-gpio.c
index ad5bfe27aaef7de57f9566330253333aa2b1253f..6e1c4f990bc0e54f4a47186340cef03b1a2ee29b 100644
--- a/drivers/reset/reset-gpio.c
+++ b/drivers/reset/reset-gpio.c
@@ -56,12 +56,8 @@ static int reset_gpio_probe(struct auxiliary_device *adev,
const struct auxiliary_device_id *id)
{
struct device *dev = &adev->dev;
- struct of_phandle_args *platdata = dev_get_platdata(dev);
struct reset_gpio_priv *priv;
- if (!platdata)
- return -EINVAL;
-
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -76,7 +72,6 @@ static int reset_gpio_probe(struct auxiliary_device *adev,
priv->rc.ops = &reset_gpio_ops;
priv->rc.owner = THIS_MODULE;
priv->rc.dev = dev;
- priv->rc.of_args = platdata;
/* Cells to match GPIO specifier, but it's not really used */
priv->rc.of_reset_n_cells = 2;
diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h
index 46514cb1b9e0626872fe71357b24d54ff0e81a8b..aa95b460fdf86f10002a465e285cd0119da6eeaf 100644
--- a/include/linux/reset-controller.h
+++ b/include/linux/reset-controller.h
@@ -35,9 +35,6 @@ struct of_phandle_args;
* @reset_control_head: head of internal list of requested reset controls
* @dev: corresponding driver model device struct
* @of_node: corresponding device tree node as phandle target
- * @of_args: for reset-gpios controllers: corresponding phandle args with
- * of_node and GPIO number complementing of_node; either this or
- * of_node should be present
* @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
@@ -51,7 +48,6 @@ struct reset_controller_dev {
struct list_head reset_control_head;
struct device *dev;
struct device_node *of_node;
- const struct of_phandle_args *of_args;
int of_reset_n_cells;
int (*of_xlate)(struct reset_controller_dev *rcdev,
const struct of_phandle_args *reset_spec);
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH v3 04/14] reset: gpio: remove unneeded auxiliary_set_drvdata()
2026-03-06 17:22 [PATCH v3 00/14] reset: major reset core refactoring Bartosz Golaszewski
` (2 preceding siblings ...)
2026-03-06 17:22 ` [PATCH v3 03/14] reset: gpio: simplify fallback device matching Bartosz Golaszewski
@ 2026-03-06 17:22 ` Bartosz Golaszewski
2026-03-06 17:22 ` [PATCH v3 05/14] reset: warn on reset-gpio release Bartosz Golaszewski
` (10 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Bartosz Golaszewski @ 2026-03-06 17:22 UTC (permalink / raw)
To: Krzysztof Kozlowski, Philipp Zabel, Jonathan Corbet, Shuah Khan
Cc: linux-kernel, brgl, linux-doc, Bartosz Golaszewski
There's no user of the driver data so don't needlessly assign it.
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/reset/reset-gpio.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/reset/reset-gpio.c b/drivers/reset/reset-gpio.c
index 6e1c4f990bc0e54f4a47186340cef03b1a2ee29b..5044f809d0e59a08861597f4aeb685e95328c2af 100644
--- a/drivers/reset/reset-gpio.c
+++ b/drivers/reset/reset-gpio.c
@@ -62,8 +62,6 @@ static int reset_gpio_probe(struct auxiliary_device *adev,
if (!priv)
return -ENOMEM;
- auxiliary_set_drvdata(adev, &priv->rc);
-
priv->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(priv->reset))
return dev_err_probe(dev, PTR_ERR(priv->reset),
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH v3 05/14] reset: warn on reset-gpio release
2026-03-06 17:22 [PATCH v3 00/14] reset: major reset core refactoring Bartosz Golaszewski
` (3 preceding siblings ...)
2026-03-06 17:22 ` [PATCH v3 04/14] reset: gpio: remove unneeded auxiliary_set_drvdata() Bartosz Golaszewski
@ 2026-03-06 17:22 ` Bartosz Golaszewski
2026-03-09 9:21 ` Philipp Zabel
2026-03-06 17:22 ` [PATCH v3 06/14] reset: fold ida_alloc() into reset_create_gpio_aux_device() Bartosz Golaszewski
` (9 subsequent siblings)
14 siblings, 1 reply; 30+ messages in thread
From: Bartosz Golaszewski @ 2026-03-06 17:22 UTC (permalink / raw)
To: Krzysztof Kozlowski, Philipp Zabel, Jonathan Corbet, Shuah Khan
Cc: linux-kernel, brgl, linux-doc, Bartosz Golaszewski
While we implement an empty .release() callback for reset-gpio (driver
core requires it), this function will never actually be called as nobody
ever removes the device and the last reference is not dropped anywhere.
This is by design - once created, the reset-gpio device stays in memory.
Make the .release() callback emit a warning, should it ever be called
due to a programming bug.
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/reset/core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 954df36a242e804b639027384700b8d988be0e90..3e55f794d539e4edc99104cb5396cac72ba30618 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -820,7 +820,7 @@ static void __reset_control_put_internal(struct reset_control *rstc)
static void reset_gpio_aux_device_release(struct device *dev)
{
-
+ WARN("reset-gpio device %s should never have been removed", dev_name(dev));
}
static int reset_create_gpio_aux_device(struct reset_gpio_lookup *rgpio_dev,
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH v3 05/14] reset: warn on reset-gpio release
2026-03-06 17:22 ` [PATCH v3 05/14] reset: warn on reset-gpio release Bartosz Golaszewski
@ 2026-03-09 9:21 ` Philipp Zabel
0 siblings, 0 replies; 30+ messages in thread
From: Philipp Zabel @ 2026-03-09 9:21 UTC (permalink / raw)
To: Bartosz Golaszewski, Krzysztof Kozlowski, Jonathan Corbet,
Shuah Khan
Cc: linux-kernel, brgl, linux-doc
On Fr, 2026-03-06 at 18:22 +0100, Bartosz Golaszewski wrote:
> While we implement an empty .release() callback for reset-gpio (driver
> core requires it), this function will never actually be called as nobody
> ever removes the device and the last reference is not dropped anywhere.
>
> This is by design - once created, the reset-gpio device stays in memory.
> Make the .release() callback emit a warning, should it ever be called
> due to a programming bug.
>
> Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
> ---
> drivers/reset/core.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/reset/core.c b/drivers/reset/core.c
> index 954df36a242e804b639027384700b8d988be0e90..3e55f794d539e4edc99104cb5396cac72ba30618 100644
> --- a/drivers/reset/core.c
> +++ b/drivers/reset/core.c
> @@ -820,7 +820,7 @@ static void __reset_control_put_internal(struct reset_control *rstc)
>
> static void reset_gpio_aux_device_release(struct device *dev)
> {
> -
> + WARN("reset-gpio device %s should never have been removed", dev_name(dev));
I'll change this to
WARN(1, "reset-gpio device %s should never have been removed", dev_name(dev));
when applying.
regards
Philipp
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v3 06/14] reset: fold ida_alloc() into reset_create_gpio_aux_device()
2026-03-06 17:22 [PATCH v3 00/14] reset: major reset core refactoring Bartosz Golaszewski
` (4 preceding siblings ...)
2026-03-06 17:22 ` [PATCH v3 05/14] reset: warn on reset-gpio release Bartosz Golaszewski
@ 2026-03-06 17:22 ` Bartosz Golaszewski
2026-03-09 7:47 ` Philipp Zabel
2026-03-06 17:22 ` [PATCH v3 07/14] reset: use lock guards in reset core Bartosz Golaszewski
` (8 subsequent siblings)
14 siblings, 1 reply; 30+ messages in thread
From: Bartosz Golaszewski @ 2026-03-06 17:22 UTC (permalink / raw)
To: Krzysztof Kozlowski, Philipp Zabel, Jonathan Corbet, Shuah Khan
Cc: linux-kernel, brgl, linux-doc, Bartosz Golaszewski
We don't need to know the IDA value outside of the function that creates
the auxiliary reset-gpio device. Simplify error handling by folding it
into reset_create_gpio_aux_device().
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/reset/core.c | 29 ++++++++++++++---------------
1 file changed, 14 insertions(+), 15 deletions(-)
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 3e55f794d539e4edc99104cb5396cac72ba30618..025004989595ac60381804a7705a1eb584b63326 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -824,10 +824,14 @@ static void reset_gpio_aux_device_release(struct device *dev)
}
static int reset_create_gpio_aux_device(struct reset_gpio_lookup *rgpio_dev,
- struct device *parent, int id)
+ struct device *parent)
{
struct auxiliary_device *adev = &rgpio_dev->adev;
- int ret;
+ int ret, id;
+
+ id = ida_alloc(&reset_gpio_ida, GFP_KERNEL);
+ if (id < 0)
+ return -ENOMEM;
adev->id = id;
adev->name = "gpio";
@@ -837,12 +841,15 @@ static int reset_create_gpio_aux_device(struct reset_gpio_lookup *rgpio_dev,
device_set_node(&adev->dev, rgpio_dev->swnode);
ret = auxiliary_device_init(adev);
- if (ret)
+ if (ret) {
+ ida_free(&reset_gpio_ida, id);
return ret;
+ }
ret = __auxiliary_device_add(adev, "reset");
if (ret) {
auxiliary_device_uninit(adev);
+ ida_free(&reset_gpio_ida, id);
return ret;
}
@@ -891,7 +898,7 @@ static int __reset_add_reset_gpio_device(struct device_node *np,
unsigned int offset, of_flags, lflags;
struct reset_gpio_lookup *rgpio_dev;
struct device *parent;
- int id, ret, prop = 0;
+ int ret, prop = 0;
/*
* Currently only #gpio-cells=2 is supported with the meaning of:
@@ -951,16 +958,10 @@ static int __reset_add_reset_gpio_device(struct device_node *np,
properties[prop++] = PROPERTY_ENTRY_STRING("compatible", "reset-gpio");
properties[prop++] = PROPERTY_ENTRY_GPIO("reset-gpios", parent->fwnode, offset, lflags);
- id = ida_alloc(&reset_gpio_ida, GFP_KERNEL);
- if (id < 0)
- return id;
-
/* Not freed on success, because it is persisent subsystem data. */
rgpio_dev = kzalloc_obj(*rgpio_dev);
- if (!rgpio_dev) {
- ret = -ENOMEM;
- goto err_ida_free;
- }
+ if (!rgpio_dev)
+ return -ENOMEM;
rgpio_dev->of_args = *args;
/*
@@ -976,7 +977,7 @@ static int __reset_add_reset_gpio_device(struct device_node *np,
goto err_put_of_node;
}
- ret = reset_create_gpio_aux_device(rgpio_dev, parent, id);
+ ret = reset_create_gpio_aux_device(rgpio_dev, parent);
if (ret)
goto err_del_swnode;
@@ -990,8 +991,6 @@ static int __reset_add_reset_gpio_device(struct device_node *np,
err_put_of_node:
of_node_put(rgpio_dev->of_args.np);
kfree(rgpio_dev);
-err_ida_free:
- ida_free(&reset_gpio_ida, id);
return ret;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH v3 07/14] reset: use lock guards in reset core
2026-03-06 17:22 [PATCH v3 00/14] reset: major reset core refactoring Bartosz Golaszewski
` (5 preceding siblings ...)
2026-03-06 17:22 ` [PATCH v3 06/14] reset: fold ida_alloc() into reset_create_gpio_aux_device() Bartosz Golaszewski
@ 2026-03-06 17:22 ` Bartosz Golaszewski
2026-03-06 17:22 ` [PATCH v3 08/14] reset: handle removing supplier before consumers Bartosz Golaszewski
` (7 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Bartosz Golaszewski @ 2026-03-06 17:22 UTC (permalink / raw)
To: Krzysztof Kozlowski, Philipp Zabel, Jonathan Corbet, Shuah Khan
Cc: linux-kernel, brgl, linux-doc, Bartosz Golaszewski
Simplify the locking code in reset core by using lock guard from
linux/cleanup.h.
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/reset/core.c | 55 ++++++++++++++++++++++++----------------------------
1 file changed, 25 insertions(+), 30 deletions(-)
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 025004989595ac60381804a7705a1eb584b63326..9fef9f972e93fb7388f27ac3bbdf68c884b72ff5 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -129,9 +129,9 @@ int reset_controller_register(struct reset_controller_dev *rcdev)
INIT_LIST_HEAD(&rcdev->reset_control_head);
- mutex_lock(&reset_list_mutex);
+ guard(mutex)(&reset_list_mutex);
+
list_add(&rcdev->list, &reset_controller_list);
- mutex_unlock(&reset_list_mutex);
return 0;
}
@@ -143,9 +143,9 @@ EXPORT_SYMBOL_GPL(reset_controller_register);
*/
void reset_controller_unregister(struct reset_controller_dev *rcdev)
{
- mutex_lock(&reset_list_mutex);
+ guard(mutex)(&reset_list_mutex);
+
list_del(&rcdev->list);
- mutex_unlock(&reset_list_mutex);
}
EXPORT_SYMBOL_GPL(reset_controller_unregister);
@@ -646,25 +646,20 @@ int reset_control_acquire(struct reset_control *rstc)
if (reset_control_is_array(rstc))
return reset_control_array_acquire(rstc_to_array(rstc));
- mutex_lock(&reset_list_mutex);
+ guard(mutex)(&reset_list_mutex);
- if (rstc->acquired) {
- mutex_unlock(&reset_list_mutex);
+ if (rstc->acquired)
return 0;
- }
list_for_each_entry(rc, &rstc->rcdev->reset_control_head, list) {
if (rstc != rc && rstc->id == rc->id) {
- if (rc->acquired) {
- mutex_unlock(&reset_list_mutex);
+ if (rc->acquired)
return -EBUSY;
- }
}
}
rstc->acquired = true;
- mutex_unlock(&reset_list_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(reset_control_acquire);
@@ -1064,27 +1059,28 @@ __of_reset_control_get(struct device_node *node, const char *id, int index,
ret = __reset_add_reset_gpio_device(node, &args);
if (ret) {
- rstc = ERR_PTR(ret);
- goto out_put;
+ of_node_put(args.np);
+ return ERR_PTR(ret);
}
}
- mutex_lock(&reset_list_mutex);
+ guard(mutex)(&reset_list_mutex);
+
rcdev = __reset_find_rcdev(&args, gpio_fallback);
if (!rcdev) {
rstc = ERR_PTR(-EPROBE_DEFER);
- goto out_unlock;
+ goto out_put;
}
if (WARN_ON(args.args_count != rcdev->of_reset_n_cells)) {
rstc = ERR_PTR(-EINVAL);
- goto out_unlock;
+ goto out_put;
}
rstc_id = rcdev->of_xlate(rcdev, &args);
if (rstc_id < 0) {
rstc = ERR_PTR(rstc_id);
- goto out_unlock;
+ goto out_put;
}
flags &= ~RESET_CONTROL_FLAGS_BIT_OPTIONAL;
@@ -1092,8 +1088,6 @@ __of_reset_control_get(struct device_node *node, const char *id, int index,
/* reset_list_mutex also protects the rcdev's reset_control list */
rstc = __reset_control_get_internal(rcdev, rstc_id, flags);
-out_unlock:
- mutex_unlock(&reset_list_mutex);
out_put:
of_node_put(args.np);
@@ -1135,10 +1129,11 @@ int __reset_control_bulk_get(struct device *dev, int num_rstcs,
return 0;
err:
- mutex_lock(&reset_list_mutex);
+ guard(mutex)(&reset_list_mutex);
+
while (i--)
__reset_control_put_internal(rstcs[i].rstc);
- mutex_unlock(&reset_list_mutex);
+
return ret;
}
EXPORT_SYMBOL_GPL(__reset_control_bulk_get);
@@ -1147,10 +1142,10 @@ static void reset_control_array_put(struct reset_control_array *resets)
{
int i;
- mutex_lock(&reset_list_mutex);
+ guard(mutex)(&reset_list_mutex);
+
for (i = 0; i < resets->num_rstcs; i++)
__reset_control_put_internal(resets->rstc[i]);
- mutex_unlock(&reset_list_mutex);
kfree(resets);
}
@@ -1168,9 +1163,9 @@ void reset_control_put(struct reset_control *rstc)
return;
}
- mutex_lock(&reset_list_mutex);
+ guard(mutex)(&reset_list_mutex);
+
__reset_control_put_internal(rstc);
- mutex_unlock(&reset_list_mutex);
}
EXPORT_SYMBOL_GPL(reset_control_put);
@@ -1181,10 +1176,10 @@ EXPORT_SYMBOL_GPL(reset_control_put);
*/
void reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs)
{
- mutex_lock(&reset_list_mutex);
+ guard(mutex)(&reset_list_mutex);
+
while (num_rstcs--)
__reset_control_put_internal(rstcs[num_rstcs].rstc);
- mutex_unlock(&reset_list_mutex);
}
EXPORT_SYMBOL_GPL(reset_control_bulk_put);
@@ -1403,10 +1398,10 @@ of_reset_control_array_get(struct device_node *np, enum reset_control_flags flag
return &resets->base;
err_rst:
- mutex_lock(&reset_list_mutex);
+ guard(mutex)(&reset_list_mutex);
+
while (--i >= 0)
__reset_control_put_internal(resets->rstc[i]);
- mutex_unlock(&reset_list_mutex);
kfree(resets);
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH v3 08/14] reset: handle removing supplier before consumers
2026-03-06 17:22 [PATCH v3 00/14] reset: major reset core refactoring Bartosz Golaszewski
` (6 preceding siblings ...)
2026-03-06 17:22 ` [PATCH v3 07/14] reset: use lock guards in reset core Bartosz Golaszewski
@ 2026-03-06 17:22 ` Bartosz Golaszewski
2026-03-09 7:47 ` Philipp Zabel
2026-03-06 17:22 ` [PATCH v3 09/14] reset: protect struct reset_controller_dev with its own mutex Bartosz Golaszewski
` (6 subsequent siblings)
14 siblings, 1 reply; 30+ messages in thread
From: Bartosz Golaszewski @ 2026-03-06 17:22 UTC (permalink / raw)
To: Krzysztof Kozlowski, Philipp Zabel, Jonathan Corbet, Shuah Khan
Cc: linux-kernel, brgl, linux-doc, Bartosz Golaszewski
Except for the reset-gpio, all reset drivers use device tree - and as
such - benefit from the device links set up by driver core. This means,
that no reset supplier will be unbound before all its consumers have
been. For this reason, nobody bothered making the reset core resiliant
to the object life-time issues that are plagueing the kernel. In this
case: reset control handles referencing the reset provider device with
no serialization or NULL-pointer checking.
We now want to make the reset core fwnode-agnostic but before we do, we
must make sure it can survive unbinding of suppliers with consumers
still holding reset control handles.
To that end: use SRCU to protect the rcdev pointer inside struct
reset_control. We protect all sections using the pointer with SRCU
read-only critical sections and synchronize SRCU after every
modification of the pointer.
This is in line with what the GPIO subsystem does and what the proposed
revocable API tries to generalize. When and if the latter makes its way
into the kernel, reset core could potentially also be generalized to use
it.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/reset/core.c | 108 +++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 91 insertions(+), 17 deletions(-)
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 9fef9f972e93fb7388f27ac3bbdf68c884b72ff5..96199e7b0dd7c89c5a11e2e2c3e5eb7fd5d49355 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -23,6 +23,7 @@
#include <linux/reset.h>
#include <linux/reset-controller.h>
#include <linux/slab.h>
+#include <linux/srcu.h>
static DEFINE_MUTEX(reset_list_mutex);
static LIST_HEAD(reset_controller_list);
@@ -36,6 +37,7 @@ static DEFINE_IDA(reset_gpio_ida);
* struct reset_control - a reset control
* @rcdev: a pointer to the reset controller device
* this reset control belongs to
+ * @srcu: protects the rcdev pointer from removal during consumer access
* @list: list entry for the rcdev's reset controller list
* @id: ID of the reset controller in the reset
* controller device
@@ -49,7 +51,8 @@ static DEFINE_IDA(reset_gpio_ida);
* will be either 0 or 1.
*/
struct reset_control {
- struct reset_controller_dev *rcdev;
+ struct reset_controller_dev __rcu *rcdev;
+ struct srcu_struct srcu;
struct list_head list;
unsigned int id;
struct kref refcnt;
@@ -137,15 +140,35 @@ int reset_controller_register(struct reset_controller_dev *rcdev)
}
EXPORT_SYMBOL_GPL(reset_controller_register);
+static void reset_controller_remove(struct reset_controller_dev *rcdev,
+ struct reset_control *rstc)
+{
+ list_del(&rstc->list);
+ module_put(rcdev->owner);
+ put_device(rcdev->dev);
+}
+
/**
* reset_controller_unregister - unregister a reset controller device
* @rcdev: a pointer to the reset controller device
*/
void reset_controller_unregister(struct reset_controller_dev *rcdev)
{
+ struct reset_control *rstc, *pos;
+
guard(mutex)(&reset_list_mutex);
list_del(&rcdev->list);
+
+ /*
+ * Numb but don't free the remaining reset control handles that are
+ * still held by consumers.
+ */
+ list_for_each_entry_safe(rstc, pos, &rcdev->reset_control_head, list) {
+ rcu_assign_pointer(rstc->rcdev, NULL);
+ synchronize_srcu(&rstc->srcu);
+ reset_controller_remove(rcdev, rstc);
+ }
}
EXPORT_SYMBOL_GPL(reset_controller_unregister);
@@ -322,6 +345,7 @@ static inline bool reset_control_is_array(struct reset_control *rstc)
*/
int reset_control_reset(struct reset_control *rstc)
{
+ struct reset_controller_dev *rcdev;
int ret;
if (!rstc)
@@ -333,7 +357,13 @@ int reset_control_reset(struct reset_control *rstc)
if (reset_control_is_array(rstc))
return reset_control_array_reset(rstc_to_array(rstc));
- if (!rstc->rcdev->ops->reset)
+ guard(srcu)(&rstc->srcu);
+
+ rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu);
+ if (!rcdev)
+ return -ENODEV;
+
+ if (!rcdev->ops->reset)
return -ENOTSUPP;
if (rstc->shared) {
@@ -347,7 +377,7 @@ int reset_control_reset(struct reset_control *rstc)
return -EPERM;
}
- ret = rstc->rcdev->ops->reset(rstc->rcdev, rstc->id);
+ ret = rcdev->ops->reset(rcdev, rstc->id);
if (rstc->shared && ret)
atomic_dec(&rstc->triggered_count);
@@ -437,6 +467,8 @@ EXPORT_SYMBOL_GPL(reset_control_rearm);
*/
int reset_control_assert(struct reset_control *rstc)
{
+ struct reset_controller_dev *rcdev;
+
if (!rstc)
return 0;
@@ -446,6 +478,12 @@ int reset_control_assert(struct reset_control *rstc)
if (reset_control_is_array(rstc))
return reset_control_array_assert(rstc_to_array(rstc));
+ guard(srcu)(&rstc->srcu);
+
+ rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu);
+ if (!rcdev)
+ return -ENODEV;
+
if (rstc->shared) {
if (WARN_ON(atomic_read(&rstc->triggered_count) != 0))
return -EINVAL;
@@ -460,7 +498,7 @@ int reset_control_assert(struct reset_control *rstc)
* Shared reset controls allow the reset line to be in any state
* after this call, so doing nothing is a valid option.
*/
- if (!rstc->rcdev->ops->assert)
+ if (!rcdev->ops->assert)
return 0;
} else {
/*
@@ -468,17 +506,17 @@ int reset_control_assert(struct reset_control *rstc)
* is no way to guarantee that the reset line is asserted after
* this call.
*/
- if (!rstc->rcdev->ops->assert)
+ if (!rcdev->ops->assert)
return -ENOTSUPP;
if (!rstc->acquired) {
WARN(1, "reset %s (ID: %u) is not acquired\n",
- rcdev_name(rstc->rcdev), rstc->id);
+ rcdev_name(rcdev), rstc->id);
return -EPERM;
}
}
- return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id);
+ return rcdev->ops->assert(rcdev, rstc->id);
}
EXPORT_SYMBOL_GPL(reset_control_assert);
@@ -525,6 +563,8 @@ EXPORT_SYMBOL_GPL(reset_control_bulk_assert);
*/
int reset_control_deassert(struct reset_control *rstc)
{
+ struct reset_controller_dev *rcdev;
+
if (!rstc)
return 0;
@@ -534,6 +574,12 @@ int reset_control_deassert(struct reset_control *rstc)
if (reset_control_is_array(rstc))
return reset_control_array_deassert(rstc_to_array(rstc));
+ guard(srcu)(&rstc->srcu);
+
+ rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu);
+ if (!rcdev)
+ return -ENODEV;
+
if (rstc->shared) {
if (WARN_ON(atomic_read(&rstc->triggered_count) != 0))
return -EINVAL;
@@ -543,7 +589,7 @@ int reset_control_deassert(struct reset_control *rstc)
} else {
if (!rstc->acquired) {
WARN(1, "reset %s (ID: %u) is not acquired\n",
- rcdev_name(rstc->rcdev), rstc->id);
+ rcdev_name(rcdev), rstc->id);
return -EPERM;
}
}
@@ -555,10 +601,10 @@ int reset_control_deassert(struct reset_control *rstc)
* case, the reset controller driver should implement .deassert() and
* return -ENOTSUPP.
*/
- if (!rstc->rcdev->ops->deassert)
+ if (!rcdev->ops->deassert)
return 0;
- return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
+ return rcdev->ops->deassert(rcdev, rstc->id);
}
EXPORT_SYMBOL_GPL(reset_control_deassert);
@@ -600,14 +646,22 @@ EXPORT_SYMBOL_GPL(reset_control_bulk_deassert);
*/
int reset_control_status(struct reset_control *rstc)
{
+ struct reset_controller_dev *rcdev;
+
if (!rstc)
return 0;
if (WARN_ON(IS_ERR(rstc)) || reset_control_is_array(rstc))
return -EINVAL;
- if (rstc->rcdev->ops->status)
- return rstc->rcdev->ops->status(rstc->rcdev, rstc->id);
+ guard(srcu)(&rstc->srcu);
+
+ rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu);
+ if (!rcdev)
+ return -ENODEV;
+
+ if (rcdev->ops->status)
+ return rcdev->ops->status(rcdev, rstc->id);
return -ENOTSUPP;
}
@@ -635,6 +689,7 @@ EXPORT_SYMBOL_GPL(reset_control_status);
*/
int reset_control_acquire(struct reset_control *rstc)
{
+ struct reset_controller_dev *rcdev;
struct reset_control *rc;
if (!rstc)
@@ -651,7 +706,13 @@ int reset_control_acquire(struct reset_control *rstc)
if (rstc->acquired)
return 0;
- list_for_each_entry(rc, &rstc->rcdev->reset_control_head, list) {
+ guard(srcu)(&rstc->srcu);
+
+ rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu);
+ if (!rcdev)
+ return -ENODEV;
+
+ list_for_each_entry(rc, &rcdev->reset_control_head, list) {
if (rstc != rc && rstc->id == rc->id) {
if (rc->acquired)
return -EBUSY;
@@ -743,6 +804,7 @@ __reset_control_get_internal(struct reset_controller_dev *rcdev,
bool shared = flags & RESET_CONTROL_FLAGS_BIT_SHARED;
bool acquired = flags & RESET_CONTROL_FLAGS_BIT_ACQUIRED;
struct reset_control *rstc;
+ int ret;
lockdep_assert_held(&reset_list_mutex);
@@ -773,12 +835,19 @@ __reset_control_get_internal(struct reset_controller_dev *rcdev,
if (!rstc)
return ERR_PTR(-ENOMEM);
+ ret = init_srcu_struct(&rstc->srcu);
+ if (ret) {
+ kfree(rstc);
+ return ERR_PTR(ret);
+ }
+
if (!try_module_get(rcdev->owner)) {
+ cleanup_srcu_struct(&rstc->srcu);
kfree(rstc);
return ERR_PTR(-ENODEV);
}
- rstc->rcdev = rcdev;
+ rcu_assign_pointer(rstc->rcdev, rcdev);
list_add(&rstc->list, &rcdev->reset_control_head);
rstc->id = index;
kref_init(&rstc->refcnt);
@@ -793,13 +862,18 @@ static void __reset_control_release(struct kref *kref)
{
struct reset_control *rstc = container_of(kref, struct reset_control,
refcnt);
+ struct reset_controller_dev *rcdev;
lockdep_assert_held(&reset_list_mutex);
- module_put(rstc->rcdev->owner);
+ scoped_guard(srcu, &rstc->srcu) {
+ rcdev = rcu_replace_pointer(rstc->rcdev, NULL, true);
+ if (rcdev)
+ reset_controller_remove(rcdev, rstc);
+ }
- list_del(&rstc->list);
- put_device(rstc->rcdev->dev);
+ synchronize_srcu(&rstc->srcu);
+ cleanup_srcu_struct(&rstc->srcu);
kfree(rstc);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH v3 08/14] reset: handle removing supplier before consumers
2026-03-06 17:22 ` [PATCH v3 08/14] reset: handle removing supplier before consumers Bartosz Golaszewski
@ 2026-03-09 7:47 ` Philipp Zabel
0 siblings, 0 replies; 30+ messages in thread
From: Philipp Zabel @ 2026-03-09 7:47 UTC (permalink / raw)
To: Bartosz Golaszewski, Krzysztof Kozlowski, Jonathan Corbet,
Shuah Khan
Cc: linux-kernel, brgl, linux-doc
On Fr, 2026-03-06 at 18:22 +0100, Bartosz Golaszewski wrote:
> Except for the reset-gpio, all reset drivers use device tree - and as
> such - benefit from the device links set up by driver core. This means,
> that no reset supplier will be unbound before all its consumers have
> been. For this reason, nobody bothered making the reset core resiliant
> to the object life-time issues that are plagueing the kernel. In this
> case: reset control handles referencing the reset provider device with
> no serialization or NULL-pointer checking.
>
> We now want to make the reset core fwnode-agnostic but before we do, we
> must make sure it can survive unbinding of suppliers with consumers
> still holding reset control handles.
>
> To that end: use SRCU to protect the rcdev pointer inside struct
> reset_control. We protect all sections using the pointer with SRCU
> read-only critical sections and synchronize SRCU after every
> modification of the pointer.
>
> This is in line with what the GPIO subsystem does and what the proposed
> revocable API tries to generalize. When and if the latter makes its way
> into the kernel, reset core could potentially also be generalized to use
> it.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
regards
Philipp
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v3 09/14] reset: protect struct reset_controller_dev with its own mutex
2026-03-06 17:22 [PATCH v3 00/14] reset: major reset core refactoring Bartosz Golaszewski
` (7 preceding siblings ...)
2026-03-06 17:22 ` [PATCH v3 08/14] reset: handle removing supplier before consumers Bartosz Golaszewski
@ 2026-03-06 17:22 ` Bartosz Golaszewski
2026-03-09 8:01 ` Philipp Zabel
2026-03-06 17:22 ` [PATCH v3 10/14] reset: protect struct reset_control " Bartosz Golaszewski
` (5 subsequent siblings)
14 siblings, 1 reply; 30+ messages in thread
From: Bartosz Golaszewski @ 2026-03-06 17:22 UTC (permalink / raw)
To: Krzysztof Kozlowski, Philipp Zabel, Jonathan Corbet, Shuah Khan
Cc: linux-kernel, brgl, linux-doc, Bartosz Golaszewski
Currently we use a single, global mutex - misleadingly names
reset_list_mutex - to protect the global list of reset devices,
per-controller list of reset control handles and also internal fields of
struct reset_control. Locking can be made a lot more fine-grained if we
use a separate mutex for serializing operations on the list AND
accessing the reset controller device.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/reset/core.c | 44 ++++++++++++++++++++++++----------------
include/linux/reset-controller.h | 3 +++
2 files changed, 30 insertions(+), 17 deletions(-)
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 96199e7b0dd7c89c5a11e2e2c3e5eb7fd5d49355..d4813c712abf3df7993b0c2be1fe292b89241d11 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -131,6 +131,7 @@ int reset_controller_register(struct reset_controller_dev *rcdev)
}
INIT_LIST_HEAD(&rcdev->reset_control_head);
+ mutex_init(&rcdev->lock);
guard(mutex)(&reset_list_mutex);
@@ -143,6 +144,8 @@ EXPORT_SYMBOL_GPL(reset_controller_register);
static void reset_controller_remove(struct reset_controller_dev *rcdev,
struct reset_control *rstc)
{
+ lockdep_assert_held(&rcdev->lock);
+
list_del(&rstc->list);
module_put(rcdev->owner);
put_device(rcdev->dev);
@@ -156,19 +159,22 @@ void reset_controller_unregister(struct reset_controller_dev *rcdev)
{
struct reset_control *rstc, *pos;
- guard(mutex)(&reset_list_mutex);
-
- list_del(&rcdev->list);
+ scoped_guard(mutex, &reset_list_mutex)
+ list_del(&rcdev->list);
- /*
- * Numb but don't free the remaining reset control handles that are
- * still held by consumers.
- */
- list_for_each_entry_safe(rstc, pos, &rcdev->reset_control_head, list) {
- rcu_assign_pointer(rstc->rcdev, NULL);
- synchronize_srcu(&rstc->srcu);
- reset_controller_remove(rcdev, rstc);
+ scoped_guard(mutex, &rcdev->lock) {
+ /*
+ * Numb but don't free the remaining reset control handles that are
+ * still held by consumers.
+ */
+ list_for_each_entry_safe(rstc, pos, &rcdev->reset_control_head, list) {
+ rcu_assign_pointer(rstc->rcdev, NULL);
+ synchronize_srcu(&rstc->srcu);
+ reset_controller_remove(rcdev, rstc);
+ }
}
+
+ mutex_destroy(&rcdev->lock);
}
EXPORT_SYMBOL_GPL(reset_controller_unregister);
@@ -712,10 +718,12 @@ int reset_control_acquire(struct reset_control *rstc)
if (!rcdev)
return -ENODEV;
- list_for_each_entry(rc, &rcdev->reset_control_head, list) {
- if (rstc != rc && rstc->id == rc->id) {
- if (rc->acquired)
- return -EBUSY;
+ scoped_guard(mutex, &rcdev->lock) {
+ list_for_each_entry(rc, &rcdev->reset_control_head, list) {
+ if (rstc != rc && rstc->id == rc->id) {
+ if (rc->acquired)
+ return -EBUSY;
+ }
}
}
@@ -806,7 +814,7 @@ __reset_control_get_internal(struct reset_controller_dev *rcdev,
struct reset_control *rstc;
int ret;
- lockdep_assert_held(&reset_list_mutex);
+ lockdep_assert_held(&rcdev->lock);
/* Expect callers to filter out OPTIONAL and DEASSERTED bits */
if (WARN_ON(flags & ~(RESET_CONTROL_FLAGS_BIT_SHARED |
@@ -868,8 +876,10 @@ static void __reset_control_release(struct kref *kref)
scoped_guard(srcu, &rstc->srcu) {
rcdev = rcu_replace_pointer(rstc->rcdev, NULL, true);
- if (rcdev)
+ if (rcdev) {
+ guard(mutex)(&rcdev->lock);
reset_controller_remove(rcdev, rstc);
+ }
}
synchronize_srcu(&rstc->srcu);
diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h
index aa95b460fdf86f10002a465e285cd0119da6eeaf..185d2a9bd7cd381ddc51c0f1643c4e3cb196015e 100644
--- a/include/linux/reset-controller.h
+++ b/include/linux/reset-controller.h
@@ -3,6 +3,7 @@
#define _LINUX_RESET_CONTROLLER_H_
#include <linux/list.h>
+#include <linux/mutex.h>
struct reset_controller_dev;
@@ -40,6 +41,7 @@ struct of_phandle_args;
* device tree to id as given to the reset control ops, defaults
* to :c:func:`of_reset_simple_xlate`.
* @nr_resets: number of reset controls in this reset controller device
+ * @lock: protects the reset control list from concurrent access
*/
struct reset_controller_dev {
const struct reset_control_ops *ops;
@@ -52,6 +54,7 @@ struct reset_controller_dev {
int (*of_xlate)(struct reset_controller_dev *rcdev,
const struct of_phandle_args *reset_spec);
unsigned int nr_resets;
+ struct mutex lock;
};
#if IS_ENABLED(CONFIG_RESET_CONTROLLER)
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH v3 09/14] reset: protect struct reset_controller_dev with its own mutex
2026-03-06 17:22 ` [PATCH v3 09/14] reset: protect struct reset_controller_dev with its own mutex Bartosz Golaszewski
@ 2026-03-09 8:01 ` Philipp Zabel
0 siblings, 0 replies; 30+ messages in thread
From: Philipp Zabel @ 2026-03-09 8:01 UTC (permalink / raw)
To: Bartosz Golaszewski, Krzysztof Kozlowski, Jonathan Corbet,
Shuah Khan
Cc: linux-kernel, brgl, linux-doc
On Fr, 2026-03-06 at 18:22 +0100, Bartosz Golaszewski wrote:
> Currently we use a single, global mutex - misleadingly names
> reset_list_mutex - to protect the global list of reset devices,
> per-controller list of reset control handles and also internal fields of
> struct reset_control. Locking can be made a lot more fine-grained if we
> use a separate mutex for serializing operations on the list AND
> accessing the reset controller device.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
regards
Philipp
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v3 10/14] reset: protect struct reset_control with its own mutex
2026-03-06 17:22 [PATCH v3 00/14] reset: major reset core refactoring Bartosz Golaszewski
` (8 preceding siblings ...)
2026-03-06 17:22 ` [PATCH v3 09/14] reset: protect struct reset_controller_dev with its own mutex Bartosz Golaszewski
@ 2026-03-06 17:22 ` Bartosz Golaszewski
2026-03-09 8:01 ` Philipp Zabel
2026-03-06 17:22 ` [PATCH v3 11/14] reset: convert of_reset_control_get_count() to using firmware nodes Bartosz Golaszewski
` (4 subsequent siblings)
14 siblings, 1 reply; 30+ messages in thread
From: Bartosz Golaszewski @ 2026-03-06 17:22 UTC (permalink / raw)
To: Krzysztof Kozlowski, Philipp Zabel, Jonathan Corbet, Shuah Khan
Cc: linux-kernel, brgl, linux-doc, Bartosz Golaszewski
Currently we use a single, global mutex - misleadingly names
reset_list_mutex - to protect the global list of reset devices,
per-controller list of reset control handles and also internal fields of
struct reset_control. Locking can be made a lot more fine-grained if we
use a separate mutex for serializing operations on the list AND
accessing the reset control handle.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/reset/core.c | 68 +++++++++++++++++++++++++++-------------------------
1 file changed, 36 insertions(+), 32 deletions(-)
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index d4813c712abf3df7993b0c2be1fe292b89241d11..34b11a68f28cd32e7b0ac852503193b0d9514915 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -49,6 +49,7 @@ static DEFINE_IDA(reset_gpio_ida);
* @triggered_count: Number of times this reset line has been reset. Currently
* only used for shared resets, which means that the value
* will be either 0 or 1.
+ * @lock: serializes the internals of reset_control_acquire()
*/
struct reset_control {
struct reset_controller_dev __rcu *rcdev;
@@ -61,6 +62,7 @@ struct reset_control {
bool array;
atomic_t deassert_count;
atomic_t triggered_count;
+ struct mutex lock;
};
/**
@@ -707,7 +709,7 @@ int reset_control_acquire(struct reset_control *rstc)
if (reset_control_is_array(rstc))
return reset_control_array_acquire(rstc_to_array(rstc));
- guard(mutex)(&reset_list_mutex);
+ guard(mutex)(&rstc->lock);
if (rstc->acquired)
return 0;
@@ -859,6 +861,7 @@ __reset_control_get_internal(struct reset_controller_dev *rcdev,
list_add(&rstc->list, &rcdev->reset_control_head);
rstc->id = index;
kref_init(&rstc->refcnt);
+ mutex_init(&rstc->lock);
rstc->acquired = acquired;
rstc->shared = shared;
get_device(rcdev->dev);
@@ -872,29 +875,40 @@ static void __reset_control_release(struct kref *kref)
refcnt);
struct reset_controller_dev *rcdev;
- lockdep_assert_held(&reset_list_mutex);
+ lockdep_assert_held(&rstc->srcu);
- scoped_guard(srcu, &rstc->srcu) {
- rcdev = rcu_replace_pointer(rstc->rcdev, NULL, true);
- if (rcdev) {
- guard(mutex)(&rcdev->lock);
- reset_controller_remove(rcdev, rstc);
- }
+ rcdev = rcu_replace_pointer(rstc->rcdev, NULL, true);
+ if (rcdev) {
+ lockdep_assert_held(&rcdev->lock);
+ reset_controller_remove(rcdev, rstc);
}
- synchronize_srcu(&rstc->srcu);
- cleanup_srcu_struct(&rstc->srcu);
- kfree(rstc);
+ mutex_destroy(&rstc->lock);
}
-static void __reset_control_put_internal(struct reset_control *rstc)
+static void reset_control_put_internal(struct reset_control *rstc)
{
- lockdep_assert_held(&reset_list_mutex);
+ struct reset_controller_dev *rcdev;
+ int ret = 0;
if (IS_ERR_OR_NULL(rstc))
return;
- kref_put(&rstc->refcnt, __reset_control_release);
+ scoped_guard(srcu, &rstc->srcu) {
+ rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu);
+ if (!rcdev)
+ /* Already released. */
+ return;
+
+ guard(mutex)(&rcdev->lock);
+ ret = kref_put(&rstc->refcnt, __reset_control_release);
+ }
+
+ if (ret) {
+ synchronize_srcu(&rstc->srcu);
+ cleanup_srcu_struct(&rstc->srcu);
+ kfree(rstc);
+ }
}
static void reset_gpio_aux_device_release(struct device *dev)
@@ -1104,7 +1118,7 @@ __of_reset_control_get(struct device_node *node, const char *id, int index,
{
bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
bool gpio_fallback = false;
- struct reset_control *rstc;
+ struct reset_control *rstc = ERR_PTR(-EINVAL);
struct reset_controller_dev *rcdev;
struct of_phandle_args args;
int rstc_id;
@@ -1169,8 +1183,8 @@ __of_reset_control_get(struct device_node *node, const char *id, int index,
flags &= ~RESET_CONTROL_FLAGS_BIT_OPTIONAL;
- /* reset_list_mutex also protects the rcdev's reset_control list */
- rstc = __reset_control_get_internal(rcdev, rstc_id, flags);
+ scoped_guard(mutex, &rcdev->lock)
+ rstc = __reset_control_get_internal(rcdev, rstc_id, flags);
out_put:
of_node_put(args.np);
@@ -1213,10 +1227,8 @@ int __reset_control_bulk_get(struct device *dev, int num_rstcs,
return 0;
err:
- guard(mutex)(&reset_list_mutex);
-
while (i--)
- __reset_control_put_internal(rstcs[i].rstc);
+ reset_control_put_internal(rstcs[i].rstc);
return ret;
}
@@ -1226,10 +1238,8 @@ static void reset_control_array_put(struct reset_control_array *resets)
{
int i;
- guard(mutex)(&reset_list_mutex);
-
for (i = 0; i < resets->num_rstcs; i++)
- __reset_control_put_internal(resets->rstc[i]);
+ reset_control_put_internal(resets->rstc[i]);
kfree(resets);
}
@@ -1247,9 +1257,7 @@ void reset_control_put(struct reset_control *rstc)
return;
}
- guard(mutex)(&reset_list_mutex);
-
- __reset_control_put_internal(rstc);
+ reset_control_put_internal(rstc);
}
EXPORT_SYMBOL_GPL(reset_control_put);
@@ -1260,10 +1268,8 @@ EXPORT_SYMBOL_GPL(reset_control_put);
*/
void reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs)
{
- guard(mutex)(&reset_list_mutex);
-
while (num_rstcs--)
- __reset_control_put_internal(rstcs[num_rstcs].rstc);
+ reset_control_put_internal(rstcs[num_rstcs].rstc);
}
EXPORT_SYMBOL_GPL(reset_control_bulk_put);
@@ -1482,10 +1488,8 @@ of_reset_control_array_get(struct device_node *np, enum reset_control_flags flag
return &resets->base;
err_rst:
- guard(mutex)(&reset_list_mutex);
-
while (--i >= 0)
- __reset_control_put_internal(resets->rstc[i]);
+ reset_control_put_internal(resets->rstc[i]);
kfree(resets);
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH v3 10/14] reset: protect struct reset_control with its own mutex
2026-03-06 17:22 ` [PATCH v3 10/14] reset: protect struct reset_control " Bartosz Golaszewski
@ 2026-03-09 8:01 ` Philipp Zabel
0 siblings, 0 replies; 30+ messages in thread
From: Philipp Zabel @ 2026-03-09 8:01 UTC (permalink / raw)
To: Bartosz Golaszewski, Krzysztof Kozlowski, Jonathan Corbet,
Shuah Khan
Cc: linux-kernel, brgl, linux-doc
On Fr, 2026-03-06 at 18:22 +0100, Bartosz Golaszewski wrote:
> Currently we use a single, global mutex - misleadingly names
> reset_list_mutex - to protect the global list of reset devices,
> per-controller list of reset control handles and also internal fields of
> struct reset_control. Locking can be made a lot more fine-grained if we
> use a separate mutex for serializing operations on the list AND
> accessing the reset control handle.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
regards
Philipp
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v3 11/14] reset: convert of_reset_control_get_count() to using firmware nodes
2026-03-06 17:22 [PATCH v3 00/14] reset: major reset core refactoring Bartosz Golaszewski
` (9 preceding siblings ...)
2026-03-06 17:22 ` [PATCH v3 10/14] reset: protect struct reset_control " Bartosz Golaszewski
@ 2026-03-06 17:22 ` Bartosz Golaszewski
2026-03-06 17:22 ` [PATCH v3 12/14] reset: convert the core API " Bartosz Golaszewski
` (3 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Bartosz Golaszewski @ 2026-03-06 17:22 UTC (permalink / raw)
To: Krzysztof Kozlowski, Philipp Zabel, Jonathan Corbet, Shuah Khan
Cc: linux-kernel, brgl, linux-doc, Bartosz Golaszewski
Start the conversion of reset core to using firmware nodes by reworking
of_reset_control_get_count(). Unfortunately there is no fwnode-based
alternative to of_count_phandle_with_args() so we have to hand-code it.
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/reset/core.c | 36 +++++++++++++++++++++++++++---------
1 file changed, 27 insertions(+), 9 deletions(-)
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 34b11a68f28cd32e7b0ac852503193b0d9514915..a00a08b3ca9e90853659a4a94607947fddcfcff4 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -12,6 +12,7 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/export.h>
+#include <linux/fwnode.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/machine.h>
#include <linux/gpio/property.h>
@@ -20,6 +21,7 @@
#include <linux/kref.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/property.h>
#include <linux/reset.h>
#include <linux/reset-controller.h>
#include <linux/slab.h>
@@ -1430,21 +1432,35 @@ EXPORT_SYMBOL_GPL(__device_reset);
*/
/**
- * of_reset_control_get_count - Count number of resets available with a device
+ * fwnode_reset_control_get_count - Count number of resets available with a device
*
- * @node: device node that contains 'resets'.
+ * @fwnode: firmware node that contains 'resets'.
*
* Returns positive reset count on success, or error number on failure and
* on count being zero.
*/
-static int of_reset_control_get_count(struct device_node *node)
+static int fwnode_reset_control_get_count(struct fwnode_handle *fwnode)
{
- int count;
+ struct fwnode_reference_args args;
+ int count = 0, ret;
- if (!node)
+ if (!fwnode)
return -EINVAL;
- count = of_count_phandle_with_args(node, "resets", "#reset-cells");
+ for (;;) {
+ ret = fwnode_property_get_reference_args(fwnode, "resets", "#reset-cells",
+ 0, count, &args);
+ if (ret) {
+ if (ret == -ENOENT)
+ break;
+
+ return ret;
+ }
+
+ fwnode_handle_put(args.fwnode);
+ count++;
+ }
+
if (count == 0)
count = -ENOENT;
@@ -1468,7 +1484,7 @@ of_reset_control_array_get(struct device_node *np, enum reset_control_flags flag
struct reset_control *rstc;
int num, i;
- num = of_reset_control_get_count(np);
+ num = fwnode_reset_control_get_count(of_fwnode_handle(np));
if (num < 0)
return optional ? NULL : ERR_PTR(num);
@@ -1542,8 +1558,10 @@ EXPORT_SYMBOL_GPL(devm_reset_control_array_get);
*/
int reset_control_get_count(struct device *dev)
{
- if (dev->of_node)
- return of_reset_control_get_count(dev->of_node);
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
+
+ if (fwnode)
+ return fwnode_reset_control_get_count(fwnode);
return -ENOENT;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH v3 12/14] reset: convert the core API to using firmware nodes
2026-03-06 17:22 [PATCH v3 00/14] reset: major reset core refactoring Bartosz Golaszewski
` (10 preceding siblings ...)
2026-03-06 17:22 ` [PATCH v3 11/14] reset: convert of_reset_control_get_count() to using firmware nodes Bartosz Golaszewski
@ 2026-03-06 17:22 ` Bartosz Golaszewski
2026-03-06 17:22 ` [PATCH v3 13/14] reset: convert reset core " Bartosz Golaszewski
` (2 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Bartosz Golaszewski @ 2026-03-06 17:22 UTC (permalink / raw)
To: Krzysztof Kozlowski, Philipp Zabel, Jonathan Corbet, Shuah Khan
Cc: linux-kernel, brgl, linux-doc, Bartosz Golaszewski
In order to simplify the commit converting the internals of reset core
to using firmware nodes, first convert the user-facing API. Modify the
signature of the core consumer functions but leave the specialized
wrappers as is to avoid modifying users for now.
No functional change intended.
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
Documentation/driver-api/reset.rst | 1 -
drivers/reset/core.c | 33 ++++++++++++++++-------------
include/linux/reset.h | 43 +++++++++++++++++++++++++-------------
3 files changed, 46 insertions(+), 31 deletions(-)
diff --git a/Documentation/driver-api/reset.rst b/Documentation/driver-api/reset.rst
index f773100daaa415ac2c74b7b0db7a4f6f05d736d8..7a6571849664f08758a975fca3e078cd45967c8d 100644
--- a/Documentation/driver-api/reset.rst
+++ b/Documentation/driver-api/reset.rst
@@ -198,7 +198,6 @@ query the reset line status using reset_control_status().
reset_control_rearm
reset_control_put
of_reset_control_get_count
- of_reset_control_array_get
devm_reset_control_array_get
reset_control_get_count
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index a00a08b3ca9e90853659a4a94607947fddcfcff4..0817afe72de75f795d62e02451520726da7c9844 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -1061,7 +1061,7 @@ static int __reset_add_reset_gpio_device(struct device_node *np,
rgpio_dev->of_args = *args;
/*
* We keep the device_node reference, but of_args.np is put at the end
- * of __of_reset_control_get(), so get it one more time.
+ * 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);
@@ -1115,18 +1115,19 @@ static struct reset_controller_dev *__reset_find_rcdev(const struct of_phandle_a
}
struct reset_control *
-__of_reset_control_get(struct device_node *node, const char *id, int index,
- enum reset_control_flags flags)
+__fwnode_reset_control_get(struct fwnode_handle *fwnode, const char *id, int index,
+ enum reset_control_flags flags)
{
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;
int ret;
- if (!node)
+ if (!fwnode)
return ERR_PTR(-EINVAL);
if (id) {
@@ -1193,7 +1194,7 @@ __of_reset_control_get(struct device_node *node, const char *id, int index,
return rstc;
}
-EXPORT_SYMBOL_GPL(__of_reset_control_get);
+EXPORT_SYMBOL_GPL(__fwnode_reset_control_get);
struct reset_control *__reset_control_get(struct device *dev, const char *id,
int index, enum reset_control_flags flags)
@@ -1201,12 +1202,13 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id,
bool shared = flags & RESET_CONTROL_FLAGS_BIT_SHARED;
bool acquired = flags & RESET_CONTROL_FLAGS_BIT_ACQUIRED;
bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
if (WARN_ON(shared && acquired))
return ERR_PTR(-EINVAL);
- if (dev->of_node)
- return __of_reset_control_get(dev->of_node, id, index, flags);
+ if (fwnode)
+ return __fwnode_reset_control_get(fwnode, id, index, flags);
return optional ? NULL : ERR_PTR(-ENOENT);
}
@@ -1468,23 +1470,24 @@ static int fwnode_reset_control_get_count(struct fwnode_handle *fwnode)
}
/**
- * of_reset_control_array_get - Get a list of reset controls using
- * device node.
+ * fwnode_reset_control_array_get - Get a list of reset controls using
+ * a firmware node.
*
- * @np: device node for the device that requests the reset controls array
+ * @fwnode: firmware node for the device that requests the reset controls array
* @flags: whether reset controls are shared, optional, acquired
*
* Returns pointer to allocated reset_control on success or error on failure
*/
struct reset_control *
-of_reset_control_array_get(struct device_node *np, enum reset_control_flags flags)
+fwnode_reset_control_array_get(struct fwnode_handle *fwnode,
+ enum reset_control_flags flags)
{
bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
struct reset_control_array *resets;
struct reset_control *rstc;
int num, i;
- num = fwnode_reset_control_get_count(of_fwnode_handle(np));
+ num = fwnode_reset_control_get_count(fwnode);
if (num < 0)
return optional ? NULL : ERR_PTR(num);
@@ -1494,7 +1497,7 @@ of_reset_control_array_get(struct device_node *np, enum reset_control_flags flag
resets->num_rstcs = num;
for (i = 0; i < num; i++) {
- rstc = __of_reset_control_get(np, NULL, i, flags);
+ rstc = __fwnode_reset_control_get(fwnode, NULL, i, flags);
if (IS_ERR(rstc))
goto err_rst;
resets->rstc[i] = rstc;
@@ -1511,7 +1514,7 @@ of_reset_control_array_get(struct device_node *np, enum reset_control_flags flag
return rstc;
}
-EXPORT_SYMBOL_GPL(of_reset_control_array_get);
+EXPORT_SYMBOL_GPL(fwnode_reset_control_array_get);
/**
* devm_reset_control_array_get - Resource managed reset control array get
@@ -1535,7 +1538,7 @@ devm_reset_control_array_get(struct device *dev, enum reset_control_flags flags)
if (!ptr)
return ERR_PTR(-ENOMEM);
- rstc = of_reset_control_array_get(dev->of_node, flags);
+ rstc = fwnode_reset_control_array_get(dev_fwnode(dev), flags);
if (IS_ERR_OR_NULL(rstc)) {
devres_free(ptr);
return rstc;
diff --git a/include/linux/reset.h b/include/linux/reset.h
index 44f9e3415f92c9d7591b898cdb4bf7f05f2b0568..9c391cf0c82298a06a4d84eebd293864ef8c48da 100644
--- a/include/linux/reset.h
+++ b/include/linux/reset.h
@@ -5,10 +5,12 @@
#include <linux/bits.h>
#include <linux/err.h>
#include <linux/errno.h>
+#include <linux/of.h>
#include <linux/types.h>
struct device;
struct device_node;
+struct fwnode_handle;
struct reset_control;
/**
@@ -84,7 +86,7 @@ int reset_control_bulk_deassert(int num_rstcs, struct reset_control_bulk_data *r
int reset_control_bulk_acquire(int num_rstcs, struct reset_control_bulk_data *rstcs);
void reset_control_bulk_release(int num_rstcs, struct reset_control_bulk_data *rstcs);
-struct reset_control *__of_reset_control_get(struct device_node *node,
+struct reset_control *__fwnode_reset_control_get(struct fwnode_handle *fwnode,
const char *id, int index, enum reset_control_flags flags);
struct reset_control *__reset_control_get(struct device *dev, const char *id,
int index, enum reset_control_flags flags);
@@ -103,7 +105,8 @@ int __devm_reset_control_bulk_get(struct device *dev, int num_rstcs,
struct reset_control *devm_reset_control_array_get(struct device *dev,
enum reset_control_flags flags);
-struct reset_control *of_reset_control_array_get(struct device_node *np, enum reset_control_flags);
+struct reset_control *fwnode_reset_control_array_get(struct fwnode_handle *fwnode,
+ enum reset_control_flags);
int reset_control_get_count(struct device *dev);
@@ -152,8 +155,8 @@ static inline int __device_reset(struct device *dev, bool optional)
return optional ? 0 : -ENOTSUPP;
}
-static inline struct reset_control *__of_reset_control_get(
- struct device_node *node,
+static inline struct reset_control *__fwnode_reset_control_get(
+ struct fwnode_handle *fwnode,
const char *id, int index, enum reset_control_flags flags)
{
bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
@@ -242,7 +245,7 @@ devm_reset_control_array_get(struct device *dev, enum reset_control_flags flags)
}
static inline struct reset_control *
-of_reset_control_array_get(struct device_node *np, enum reset_control_flags flags)
+fwnode_reset_control_array_get(struct fwnode_handle *fwnode, enum reset_control_flags flags)
{
bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
@@ -500,7 +503,8 @@ reset_control_bulk_get_optional_shared(struct device *dev, int num_rstcs,
static inline struct reset_control *of_reset_control_get_exclusive(
struct device_node *node, const char *id)
{
- return __of_reset_control_get(node, id, 0, RESET_CONTROL_EXCLUSIVE);
+ return __fwnode_reset_control_get(of_fwnode_handle(node), id, 0,
+ RESET_CONTROL_EXCLUSIVE);
}
/**
@@ -520,7 +524,8 @@ static inline struct reset_control *of_reset_control_get_exclusive(
static inline struct reset_control *of_reset_control_get_optional_exclusive(
struct device_node *node, const char *id)
{
- return __of_reset_control_get(node, id, 0, RESET_CONTROL_OPTIONAL_EXCLUSIVE);
+ return __fwnode_reset_control_get(of_fwnode_handle(node), id, 0,
+ RESET_CONTROL_OPTIONAL_EXCLUSIVE);
}
/**
@@ -545,7 +550,8 @@ static inline struct reset_control *of_reset_control_get_optional_exclusive(
static inline struct reset_control *of_reset_control_get_shared(
struct device_node *node, const char *id)
{
- return __of_reset_control_get(node, id, 0, RESET_CONTROL_SHARED);
+ return __fwnode_reset_control_get(of_fwnode_handle(node), id, 0,
+ RESET_CONTROL_SHARED);
}
/**
@@ -562,7 +568,8 @@ static inline struct reset_control *of_reset_control_get_shared(
static inline struct reset_control *of_reset_control_get_exclusive_by_index(
struct device_node *node, int index)
{
- return __of_reset_control_get(node, NULL, index, RESET_CONTROL_EXCLUSIVE);
+ return __fwnode_reset_control_get(of_fwnode_handle(node), NULL, index,
+ RESET_CONTROL_EXCLUSIVE);
}
/**
@@ -590,7 +597,8 @@ static inline struct reset_control *of_reset_control_get_exclusive_by_index(
static inline struct reset_control *of_reset_control_get_shared_by_index(
struct device_node *node, int index)
{
- return __of_reset_control_get(node, NULL, index, RESET_CONTROL_SHARED);
+ return __fwnode_reset_control_get(of_fwnode_handle(node), NULL, index,
+ RESET_CONTROL_SHARED);
}
/**
@@ -1032,30 +1040,35 @@ devm_reset_control_array_get_optional_shared(struct device *dev)
static inline struct reset_control *
of_reset_control_array_get_exclusive(struct device_node *node)
{
- return of_reset_control_array_get(node, RESET_CONTROL_EXCLUSIVE);
+ return fwnode_reset_control_array_get(of_fwnode_handle(node),
+ RESET_CONTROL_EXCLUSIVE);
}
static inline struct reset_control *
of_reset_control_array_get_exclusive_released(struct device_node *node)
{
- return of_reset_control_array_get(node, RESET_CONTROL_EXCLUSIVE_RELEASED);
+ return fwnode_reset_control_array_get(of_fwnode_handle(node),
+ RESET_CONTROL_EXCLUSIVE_RELEASED);
}
static inline struct reset_control *
of_reset_control_array_get_shared(struct device_node *node)
{
- return of_reset_control_array_get(node, RESET_CONTROL_SHARED);
+ return fwnode_reset_control_array_get(of_fwnode_handle(node),
+ RESET_CONTROL_SHARED);
}
static inline struct reset_control *
of_reset_control_array_get_optional_exclusive(struct device_node *node)
{
- return of_reset_control_array_get(node, RESET_CONTROL_OPTIONAL_EXCLUSIVE);
+ return fwnode_reset_control_array_get(of_fwnode_handle(node),
+ RESET_CONTROL_OPTIONAL_EXCLUSIVE);
}
static inline struct reset_control *
of_reset_control_array_get_optional_shared(struct device_node *node)
{
- return of_reset_control_array_get(node, RESET_CONTROL_OPTIONAL_SHARED);
+ return fwnode_reset_control_array_get(of_fwnode_handle(node),
+ RESET_CONTROL_OPTIONAL_SHARED);
}
#endif
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH v3 13/14] reset: convert reset core to using firmware nodes
2026-03-06 17:22 [PATCH v3 00/14] reset: major reset core refactoring Bartosz Golaszewski
` (11 preceding siblings ...)
2026-03-06 17:22 ` [PATCH v3 12/14] reset: convert the core API " Bartosz Golaszewski
@ 2026-03-06 17:22 ` Bartosz Golaszewski
2026-03-09 8:01 ` Philipp Zabel
` (3 more replies)
2026-03-06 17:22 ` [PATCH v3 14/14] reset: gpio: make the driver fwnode-agnostic Bartosz Golaszewski
2026-03-09 9:25 ` [PATCH v3 00/14] reset: major reset core refactoring Philipp Zabel
14 siblings, 4 replies; 30+ messages in thread
From: Bartosz Golaszewski @ 2026-03-06 17:22 UTC (permalink / raw)
To: Krzysztof Kozlowski, Philipp Zabel, Jonathan Corbet, Shuah Khan
Cc: linux-kernel, brgl, linux-doc, Bartosz Golaszewski
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@oss.qualcomm.com>
---
drivers/reset/core.c | 166 +++++++++++++++++++++++----------------
include/linux/reset-controller.h | 14 +++-
2 files changed, 112 insertions(+), 68 deletions(-)
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 0817afe72de75f795d62e02451520726da7c9844..e33a9bc9f94fc6867be6efd32178658d99fc088f 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
- * :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.
+ * This static translation function is used by default if neither fwnode_xlate
+ * not of_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,23 @@ 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) {
+ rcdev->fwnode = dev_fwnode(rcdev->dev);
+ if (!rcdev->fwnode)
+ 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);
@@ -931,7 +945,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);
@@ -951,18 +965,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))
@@ -982,15 +996,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;
@@ -1001,7 +1023,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;
/*
@@ -1012,7 +1034,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
@@ -1022,33 +1044,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);
@@ -1058,43 +1078,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 fwnode_reference_args *rc_args;
struct reset_controller_dev *rcdev;
- struct of_phandle_args *rc_args;
lockdep_assert_held(&reset_list_mutex);
@@ -1103,10 +1123,10 @@ static struct reset_controller_dev *__reset_find_rcdev(const struct of_phandle_a
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;
}
}
@@ -1120,27 +1140,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) {
@@ -1151,16 +1170,16 @@ __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) {
- of_node_put(args.np);
+ fwnode_handle_put(args.fwnode);
return ERR_PTR(ret);
}
}
@@ -1173,15 +1192,30 @@ __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;
+ goto out_put;
}
flags &= ~RESET_CONTROL_FLAGS_BIT_OPTIONAL;
@@ -1190,7 +1224,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 185d2a9bd7cd381ddc51c0f1643c4e3cb196015e..52a5a4e81f1844075210339bf7ffa46ec5ca6edf 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: protects the reset control list from concurrent access
*/
@@ -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
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH v3 13/14] reset: convert reset core to using firmware nodes
2026-03-06 17:22 ` [PATCH v3 13/14] reset: convert reset core " Bartosz Golaszewski
@ 2026-03-09 8:01 ` Philipp Zabel
2026-03-10 14:16 ` Mark Brown
` (2 subsequent siblings)
3 siblings, 0 replies; 30+ messages in thread
From: Philipp Zabel @ 2026-03-09 8:01 UTC (permalink / raw)
To: Bartosz Golaszewski, Krzysztof Kozlowski, Jonathan Corbet,
Shuah Khan
Cc: linux-kernel, brgl, linux-doc
On Fr, 2026-03-06 at 18:22 +0100, Bartosz Golaszewski wrote:
> 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@oss.qualcomm.com>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
regards
Philipp
^ permalink raw reply [flat|nested] 30+ messages in thread* Re: [PATCH v3 13/14] reset: convert reset core to using firmware nodes
2026-03-06 17:22 ` [PATCH v3 13/14] reset: convert reset core " Bartosz Golaszewski
2026-03-09 8:01 ` Philipp Zabel
@ 2026-03-10 14:16 ` Mark Brown
2026-03-10 14:48 ` Philipp Zabel
2026-03-10 15:00 ` Geert Uytterhoeven
2026-03-11 15:47 ` Tommaso Merciai
3 siblings, 1 reply; 30+ messages in thread
From: Mark Brown @ 2026-03-10 14:16 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Krzysztof Kozlowski, Philipp Zabel, Jonathan Corbet, Shuah Khan,
linux-kernel, brgl, linux-doc
[-- Attachment #1: Type: text/plain, Size: 15823 bytes --]
On Fri, Mar 06, 2026 at 06:22:57PM +0100, Bartosz Golaszewski wrote:
> 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.
This patch is causing issues for me in yesterday's -next on a Toradax
Mallow platform with a TI K3 AM625. Things start to go wrong with a
WARN_ON():
[ 11.544610] WARNING: drivers/reset/core.c:1195 at __fwnode_reset_control_get+0x488/0x580, CPU#0: (udev-worker)/129
...
[ 11.693583] __fwnode_reset_control_get+0x488/0x580 (P)
[ 11.698802] __reset_control_get+0x64/0xa0
[ 11.702892] __devm_reset_control_get+0x74/0x110
[ 11.707502] k3_m4_rproc_probe+0xf8/0x3d0 [ti_k3_m4_remoteproc]
[ 11.713421] platform_probe+0x5c/0xa4
and ends up not probing the relevant device due to:
[ 12.155596] platform 78000000.r5f: error -EINVAL: failed to get reset handle
Full log:
https://lava.sirena.org.uk/scheduler/job/2545371#L1126
bisect log:
# bad: [343f51842f4ed7143872f3aa116a214a5619a4b9] Add linux-next specific files for 20260309
# good: [7c426ecc244791791ec70ffb264e99bb5e158ef0] Merge branch 'for-linux-next-fixes' of https://gitlab.freedesktop.org/drm/misc/kernel.git
# good: [aa3d0c93a333182e887426366a4f3e5f06ee0d83] regulator: max20411: show failure on register
# good: [b1ef855c62601ed4de2c4b0ff75a075877e3dac8] regmap: Simplify devres handling
# good: [ef0b4783afc211a4b120e72b5a57f3d0340a9981] ASoC: cs35l56: KUnit tests for reading speaker ID from host GPIOs
# good: [e7662bced2e98ffa2c572126677deb9cf55d43b3] regcache: Move HW readback after cache initialisation
# good: [2adac914c72b6cb5aba2612f49050c82aecd498e] ASoC: cs35l56-test: Add test cases without onchip pulls defined
# good: [96f06d055ca03d1dfb5830fd07ff6eadbd66264c] spi: dt-bindings: mpfs-spi: remove clock-names
# good: [f48e7a246a567e3764112e2463274c479d95cd96] ASoC: soc-core: Use guard()/scoped_guard() for mutex lock
# good: [9891b52ba12e9d5fed5901b6b5f6e0cdcd424390] regcache: Factor out regcache_hw_exit() helper
# good: [e84141846decb77d2826e553318a608b256804e5] regulator: pf9453: Allow shared IRQ
# good: [9ab637ac5d3826606947f4e861107da958eda324] regcache: Amend printf() specifiers when printing registers
# good: [d3b693a13b39bce16e284e1c737874966b3a96de] spi: spi-mem: clean up kernel-doc in spi-mem.h
# good: [da37bfe76b5b4ccc01ed8132215098e20d78e5f3] ASoC: cs42xx8: add error checks for constraints in TDM mode
# good: [06dba254de95b16e7793224d29daa5195de2e581] ASoC: dt-bindings: nvidia,tegra-audio-max9808x: document additional board pins
# good: [1696fad8b259a2d46e51cd6e17e4bcdbe02279fa] ASoC: sti: use managed regmap_field allocations
# good: [17c6bf433742e0c1ff5ce175145877c0194e4a7a] ASoC: cs35l45: Hibernate wm_adsp on runtime suspend
# good: [34b4fc44e4f904fbb81335d53163ffdcb0180000] ASoC: soc_sdw_utils: remove index from sdca codec name
# good: [2974aa42e6696a1d95b727d677dc01a71af5b998] ASoC: remove snd_soc_pcm_subclass
# good: [501efdcb3b3ab099fc0ce2f6e668b1c4095dd476] ASoC: SDCA: Pull the Q7.8 volume helpers out of soc-ops
# good: [d90c0f78379454d51a428e312ac6db573060185c] regulator: cpcap-regulator: add support for Mot regulators
# good: [5c74a008ffc62fc57a041602b4517519c8bf9436] firmware: cs_dsp: Mark KUnit test suites KUNIT_SPEED_SLOW
# good: [260c3fff1fefc570d8f23e87953e181d7d248861] ASoC: cs-amp-lib-test: Stop including platform_device.h
# good: [e02902dd493bf9c9b05353c761737ac514ad7a5c] spi: add devm_spi_new_ancillary_device()
# good: [37983fad7f3ef296fa0504c8e945987459dc5487] regmap: define cleanup helper for regmap_field
# good: [196b2b95fec447c2c4460f753b277d840633fbef] drm/nouveau: Add DRM_IOCTL_NOUVEAU_GET_ZCULL_INFO
# good: [7c12f6ead4672cb08b74e6f6115eb04dca8ccfa4] spi: tegra210-quad: Add runtime autosuspend support
# good: [ada32396f90951e12465224c04742607ca56a982] ASoC: SDCA: Add CS47L47 to class driver
# good: [507a071d9868cb60e4e76f8a06fc8eb014f59ae4] spi: pxa2xx: use min() instead of min_t()
# good: [5ebc20921b7fff9feb44de465448e17a382c9965] ASoC: tas2552: Allow audio enable GPIO to sleep
# good: [5943243914b9fed8e26edcb9d45421721a5e3576] dma-buf: use inline lock for the dma-fence-array
# good: [541c8f2468b933acc5d129e84bd264923675a66e] dma-buf: detach fence ops on signal v3
# good: [fed6e5084894373d76270cad4a32eb6479ad8247] spi: atcspi200: Remove redundant assignment to .owner
# good: [171b3663f33e1efdc97f5112f49be10b47b20fa8] ASoC: codecs: aw88261: Add firmware-name support
# good: [c2bcf62ca75c541ec4297e6ff02a68ddc2e02029] regcache: Split regcache_count_cacheable_registers() helper
# good: [0556bb42a84ee391a2145ddba86756f9747bc27f] regulator: pf0900: Make regu_irqs variable static const
# good: [a480f5c6f5fa14c954aa8c462302d34223947510] drm/mcde: dsi: convert to of_drm_find_and_get_bridge()
# good: [8b85987d3cf50178f67618122d9f3bb202f62f42] Merge drm/drm-next into drm-misc-next
# good: [d075cef4af6327a5de4bee7bf77591e3201e54f4] ASoC: simple-card-utils: add sysclk ordering support
# good: [bf122191473e26a8f195308b1ba924c98424c8e1] ASoC: rt5677-spi: Add SPI device ID matching table
# good: [78dfbd4ad0be9f51de7b9a19388809254aeccd26] ASoC: Add quirk for Lecoo Bellator N176
# good: [fbb4c52ccdcb4a612d2b7f800aa57090eeee16d7] regulator: spacemit-p1: Update supply names
# good: [fe0b1b8269eba268a7dee293b32d6c008a6c3fec] drm/mcde: dsi: mcde_dsi_bind: break when a panel or bridge is found
git bisect start '343f51842f4ed7143872f3aa116a214a5619a4b9' '7c426ecc244791791ec70ffb264e99bb5e158ef0' 'aa3d0c93a333182e887426366a4f3e5f06ee0d83' 'b1ef855c62601ed4de2c4b0ff75a075877e3dac8' 'ef0b4783afc211a4b120e72b5a57f3d0340a9981' 'e7662bced2e98ffa2c572126677deb9cf55d43b3' '2adac914c72b6cb5aba2612f49050c82aecd498e' '96f06d055ca03d1dfb5830fd07ff6eadbd66264c' 'f48e7a246a567e3764112e2463274c479d95cd96' '9891b52ba12e9d5fed5901b6b5f6e0cdcd424390' 'e84141846decb77d2826e553318a608b256804e5' '9ab637ac5d3826606947f4e861107da958eda324' 'd3b693a13b39bce16e284e1c737874966b3a96de' 'da37bfe76b5b4ccc01ed8132215098e20d78e5f3' '06dba254de95b16e7793224d29daa5195de2e581' '1696fad8b259a2d46e51cd6e17e4bcdbe02279fa' '17c6bf433742e0c1ff5ce175145877c0194e4a7a' '34b4fc44e4f904fbb81335d53163ffdcb0180000' '2974aa42e6696a1d95b727d677dc01a71af5b998' '501efdcb3b3ab099fc0ce2f6e668b1c4095dd476' 'd90c0f78379454d51a428e312ac6db573060185c' '5c74a008ffc62fc57a041602b4517519c8bf9436' '260c3fff1fefc570d8f23e87953e181d7d248861' 'e02902dd493bf9c9b05353c761737ac514ad7a5c' '37983fad7f3ef296fa0504c8e945987459dc5487' '196b2b95fec447c2c4460f753b277d840633fbef' '7c12f6ead4672cb08b74e6f6115eb04dca8ccfa4' 'ada32396f90951e12465224c04742607ca56a982' '507a071d9868cb60e4e76f8a06fc8eb014f59ae4' '5ebc20921b7fff9feb44de465448e17a382c9965' '5943243914b9fed8e26edcb9d45421721a5e3576' '541c8f2468b933acc5d129e84bd264923675a66e' 'fed6e5084894373d76270cad4a32eb6479ad8247' '171b3663f33e1efdc97f5112f49be10b47b20fa8' 'c2bcf62ca75c541ec4297e6ff02a68ddc2e02029' '0556bb42a84ee391a2145ddba86756f9747bc27f' 'a480f5c6f5fa14c954aa8c462302d34223947510' '8b85987d3cf50178f67618122d9f3bb202f62f42' 'd075cef4af6327a5de4bee7bf77591e3201e54f4' 'bf122191473e26a8f195308b1ba924c98424c8e1' '78dfbd4ad0be9f51de7b9a19388809254aeccd26' 'fbb4c52ccdcb4a612d2b7f800aa57090eeee16d7' 'fe0b1b8269eba268a7dee293b32d6c008a6c3fec'
# test job: [aa3d0c93a333182e887426366a4f3e5f06ee0d83] https://lava.sirena.org.uk/scheduler/job/2531476
# test job: [b1ef855c62601ed4de2c4b0ff75a075877e3dac8] https://lava.sirena.org.uk/scheduler/job/2531902
# test job: [ef0b4783afc211a4b120e72b5a57f3d0340a9981] https://lava.sirena.org.uk/scheduler/job/2530824
# test job: [e7662bced2e98ffa2c572126677deb9cf55d43b3] https://lava.sirena.org.uk/scheduler/job/2530811
# test job: [2adac914c72b6cb5aba2612f49050c82aecd498e] https://lava.sirena.org.uk/scheduler/job/2523914
# test job: [96f06d055ca03d1dfb5830fd07ff6eadbd66264c] https://lava.sirena.org.uk/scheduler/job/2523382
# test job: [f48e7a246a567e3764112e2463274c479d95cd96] https://lava.sirena.org.uk/scheduler/job/2522152
# test job: [9891b52ba12e9d5fed5901b6b5f6e0cdcd424390] https://lava.sirena.org.uk/scheduler/job/2522265
# test job: [e84141846decb77d2826e553318a608b256804e5] https://lava.sirena.org.uk/scheduler/job/2516897
# test job: [9ab637ac5d3826606947f4e861107da958eda324] https://lava.sirena.org.uk/scheduler/job/2516463
# test job: [d3b693a13b39bce16e284e1c737874966b3a96de] https://lava.sirena.org.uk/scheduler/job/2511822
# test job: [da37bfe76b5b4ccc01ed8132215098e20d78e5f3] https://lava.sirena.org.uk/scheduler/job/2511897
# test job: [06dba254de95b16e7793224d29daa5195de2e581] https://lava.sirena.org.uk/scheduler/job/2513785
# test job: [1696fad8b259a2d46e51cd6e17e4bcdbe02279fa] https://lava.sirena.org.uk/scheduler/job/2514115
# test job: [17c6bf433742e0c1ff5ce175145877c0194e4a7a] https://lava.sirena.org.uk/scheduler/job/2513841
# test job: [34b4fc44e4f904fbb81335d53163ffdcb0180000] https://lava.sirena.org.uk/scheduler/job/2513660
# test job: [2974aa42e6696a1d95b727d677dc01a71af5b998] https://lava.sirena.org.uk/scheduler/job/2502250
# test job: [501efdcb3b3ab099fc0ce2f6e668b1c4095dd476] https://lava.sirena.org.uk/scheduler/job/2500570
# test job: [d90c0f78379454d51a428e312ac6db573060185c] https://lava.sirena.org.uk/scheduler/job/2500334
# test job: [5c74a008ffc62fc57a041602b4517519c8bf9436] https://lava.sirena.org.uk/scheduler/job/2496444
# test job: [260c3fff1fefc570d8f23e87953e181d7d248861] https://lava.sirena.org.uk/scheduler/job/2494135
# test job: [e02902dd493bf9c9b05353c761737ac514ad7a5c] https://lava.sirena.org.uk/scheduler/job/2489689
# test job: [37983fad7f3ef296fa0504c8e945987459dc5487] https://lava.sirena.org.uk/scheduler/job/2489177
# test job: [196b2b95fec447c2c4460f753b277d840633fbef] https://lava.sirena.org.uk/scheduler/job/2497877
# test job: [7c12f6ead4672cb08b74e6f6115eb04dca8ccfa4] https://lava.sirena.org.uk/scheduler/job/2488549
# test job: [ada32396f90951e12465224c04742607ca56a982] https://lava.sirena.org.uk/scheduler/job/2489110
# test job: [507a071d9868cb60e4e76f8a06fc8eb014f59ae4] https://lava.sirena.org.uk/scheduler/job/2486368
# test job: [5ebc20921b7fff9feb44de465448e17a382c9965] https://lava.sirena.org.uk/scheduler/job/2485121
# test job: [5943243914b9fed8e26edcb9d45421721a5e3576] https://lava.sirena.org.uk/scheduler/job/2498010
# test job: [541c8f2468b933acc5d129e84bd264923675a66e] https://lava.sirena.org.uk/scheduler/job/2498115
# test job: [fed6e5084894373d76270cad4a32eb6479ad8247] https://lava.sirena.org.uk/scheduler/job/2484678
# test job: [171b3663f33e1efdc97f5112f49be10b47b20fa8] https://lava.sirena.org.uk/scheduler/job/2482573
# test job: [c2bcf62ca75c541ec4297e6ff02a68ddc2e02029] https://lava.sirena.org.uk/scheduler/job/2483266
# test job: [0556bb42a84ee391a2145ddba86756f9747bc27f] https://lava.sirena.org.uk/scheduler/job/2483182
# test job: [a480f5c6f5fa14c954aa8c462302d34223947510] https://lava.sirena.org.uk/scheduler/job/2498343
# test job: [8b85987d3cf50178f67618122d9f3bb202f62f42] https://lava.sirena.org.uk/scheduler/job/2498190
# test job: [d075cef4af6327a5de4bee7bf77591e3201e54f4] https://lava.sirena.org.uk/scheduler/job/2483446
# test job: [bf122191473e26a8f195308b1ba924c98424c8e1] https://lava.sirena.org.uk/scheduler/job/2482807
# test job: [78dfbd4ad0be9f51de7b9a19388809254aeccd26] https://lava.sirena.org.uk/scheduler/job/2483097
# test job: [fbb4c52ccdcb4a612d2b7f800aa57090eeee16d7] https://lava.sirena.org.uk/scheduler/job/2482446
# test job: [fe0b1b8269eba268a7dee293b32d6c008a6c3fec] https://lava.sirena.org.uk/scheduler/job/2497744
# test job: [d9cc39c565935b634aed60237a0d9262efd703ef] https://lava.sirena.org.uk/scheduler/job/2545125
# bad: [d9cc39c565935b634aed60237a0d9262efd703ef] Merge branch 'xtensa-for-next' of https://github.com/jcmvbkbc/linux-xtensa.git
git bisect bad d9cc39c565935b634aed60237a0d9262efd703ef
# test job: [343f51842f4ed7143872f3aa116a214a5619a4b9] https://lava.sirena.org.uk/scheduler/job/2545371
# bad: [343f51842f4ed7143872f3aa116a214a5619a4b9] Add linux-next specific files for 20260309
git bisect bad 343f51842f4ed7143872f3aa116a214a5619a4b9
# test job: [601a8229b851e12ef5bb4fe12c034c342180df21] https://lava.sirena.org.uk/scheduler/job/2545813
# bad: [601a8229b851e12ef5bb4fe12c034c342180df21] Merge branch 'main' of https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git
git bisect bad 601a8229b851e12ef5bb4fe12c034c342180df21
# test job: [d9cc39c565935b634aed60237a0d9262efd703ef] https://lava.sirena.org.uk/scheduler/job/2545125
# bad: [d9cc39c565935b634aed60237a0d9262efd703ef] Merge branch 'xtensa-for-next' of https://github.com/jcmvbkbc/linux-xtensa.git
git bisect bad d9cc39c565935b634aed60237a0d9262efd703ef
# test job: [68ade9d1ef86387fb7e6c50f0099d9685eebccfc] https://lava.sirena.org.uk/scheduler/job/2545938
# good: [68ade9d1ef86387fb7e6c50f0099d9685eebccfc] Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/bmc/linux.git
git bisect good 68ade9d1ef86387fb7e6c50f0099d9685eebccfc
# test job: [5fc055700d1c1c44b455cbba097eb0456a8e7e80] https://lava.sirena.org.uk/scheduler/job/2546007
# good: [5fc055700d1c1c44b455cbba097eb0456a8e7e80] Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git
git bisect good 5fc055700d1c1c44b455cbba097eb0456a8e7e80
# test job: [759498ea498be7915fb7680db1b82ab24d2ea4a1] https://lava.sirena.org.uk/scheduler/job/2546151
# bad: [759498ea498be7915fb7680db1b82ab24d2ea4a1] Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git
git bisect bad 759498ea498be7915fb7680db1b82ab24d2ea4a1
# test job: [febe1d6bb4aedf5909524c9d2b7a0f951ff5b2cd] https://lava.sirena.org.uk/scheduler/job/2546362
# good: [febe1d6bb4aedf5909524c9d2b7a0f951ff5b2cd] Merge branch 'v7.1-armsoc/dts64' into for-next
git bisect good febe1d6bb4aedf5909524c9d2b7a0f951ff5b2cd
# test job: [ed463b91c8f535b0480177e7ca164852c6a8a222] https://lava.sirena.org.uk/scheduler/job/2546598
# bad: [ed463b91c8f535b0480177e7ca164852c6a8a222] Merge branch 'reset/next' of https://git.pengutronix.de/git/pza/linux
git bisect bad ed463b91c8f535b0480177e7ca164852c6a8a222
# test job: [3a76b5326d67bbfe2bc81f834d2f21a5b4498b57] https://lava.sirena.org.uk/scheduler/job/2546759
# good: [3a76b5326d67bbfe2bc81f834d2f21a5b4498b57] Merge branches 'renesas-arm-defconfig-for-v7.1', 'renesas-drivers-for-v7.1', 'renesas-dt-bindings-for-v7.1' and 'renesas-dts-for-v7.1' into renesas-next
git bisect good 3a76b5326d67bbfe2bc81f834d2f21a5b4498b57
# test job: [20adbf3b8f5c5787da29f8cdd7cfc4fa87854bd5] https://lava.sirena.org.uk/scheduler/job/2546854
# good: [20adbf3b8f5c5787da29f8cdd7cfc4fa87854bd5] reset: warn on reset-gpio release
git bisect good 20adbf3b8f5c5787da29f8cdd7cfc4fa87854bd5
# test job: [8c91302a29bc1b710c7a164d4b81b5bb432f4eb5] https://lava.sirena.org.uk/scheduler/job/2546912
# good: [8c91302a29bc1b710c7a164d4b81b5bb432f4eb5] reset: protect struct reset_control with its own mutex
git bisect good 8c91302a29bc1b710c7a164d4b81b5bb432f4eb5
# test job: [9035073d0ef1de813c6335239250248bfe0a64aa] https://lava.sirena.org.uk/scheduler/job/2546951
# bad: [9035073d0ef1de813c6335239250248bfe0a64aa] reset: convert reset core to using firmware nodes
git bisect bad 9035073d0ef1de813c6335239250248bfe0a64aa
# test job: [ba8dbbb14b7e6734afbb5ba37d0679831aa3d590] https://lava.sirena.org.uk/scheduler/job/2547005
# good: [ba8dbbb14b7e6734afbb5ba37d0679831aa3d590] reset: convert the core API to using firmware nodes
git bisect good ba8dbbb14b7e6734afbb5ba37d0679831aa3d590
# first bad commit: [9035073d0ef1de813c6335239250248bfe0a64aa] reset: convert reset core to using firmware nodes
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 13/14] reset: convert reset core to using firmware nodes
2026-03-10 14:16 ` Mark Brown
@ 2026-03-10 14:48 ` Philipp Zabel
2026-03-10 14:53 ` Bartosz Golaszewski
0 siblings, 1 reply; 30+ messages in thread
From: Philipp Zabel @ 2026-03-10 14:48 UTC (permalink / raw)
To: Mark Brown, Bartosz Golaszewski
Cc: Krzysztof Kozlowski, Jonathan Corbet, Shuah Khan, linux-kernel,
brgl, linux-doc
On Di, 2026-03-10 at 14:16 +0000, Mark Brown wrote:
> On Fri, Mar 06, 2026 at 06:22:57PM +0100, Bartosz Golaszewski wrote:
> > 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.
>
> This patch is causing issues for me in yesterday's -next on a Toradax
> Mallow platform with a TI K3 AM625. Things start to go wrong with a
> WARN_ON():
>
> [ 11.544610] WARNING: drivers/reset/core.c:1195 at __fwnode_reset_control_get+0x488/0x580, CPU#0: (udev-worker)/129
Thank you, that's reset_controller_register() setting
fwnode_reset_n_cells to 2 since rcdev->of_node is set and rcdev-
>of_reset_n_cells == 2:
if (rcdev->of_node) {
rcdev->fwnode = of_fwnode_handle(rcdev->of_node);
rcdev->fwnode_reset_n_cells = rcdev->of_reset_n_cells;
}
and then overwriting it with 1, because rcdev->fwnode is now set as
well, rcdev->fwnode_xlate is NULL, and rcdev->of_xlate is ignored:
if (rcdev->fwnode && !rcdev->fwnode_xlate) {
rcdev->fwnode_reset_n_cells = 1;
rcdev->fwnode_xlate = fwnode_reset_simple_xlate;
}
That then fails because #reset-cells is <2> for k3_reset.
We also have to check !rcdev->of_xlate here. Could you check if this
fixes the issue?
----------8<----------
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index e625cf59cfb0..d52595db5f87 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -143,7 +143,7 @@ int reset_controller_register(struct reset_controller_dev *rcdev)
rcdev->fwnode_reset_n_cells = rcdev->of_reset_n_cells;
}
- if (rcdev->fwnode && !rcdev->fwnode_xlate) {
+ if (rcdev->fwnode && !rcdev->fwnode_xlate && !rcdev->of_xlate) {
rcdev->fwnode_reset_n_cells = 1;
rcdev->fwnode_xlate = fwnode_reset_simple_xlate;
}
---------->8----------
regards
Philipp
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH v3 13/14] reset: convert reset core to using firmware nodes
2026-03-10 14:48 ` Philipp Zabel
@ 2026-03-10 14:53 ` Bartosz Golaszewski
0 siblings, 0 replies; 30+ messages in thread
From: Bartosz Golaszewski @ 2026-03-10 14:53 UTC (permalink / raw)
To: Philipp Zabel
Cc: Mark Brown, Bartosz Golaszewski, Krzysztof Kozlowski,
Jonathan Corbet, Shuah Khan, linux-kernel, linux-doc
On Tue, Mar 10, 2026 at 3:49 PM Philipp Zabel <p.zabel@pengutronix.de> wrote:
>
> On Di, 2026-03-10 at 14:16 +0000, Mark Brown wrote:
> > On Fri, Mar 06, 2026 at 06:22:57PM +0100, Bartosz Golaszewski wrote:
> > > 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.
> >
> > This patch is causing issues for me in yesterday's -next on a Toradax
> > Mallow platform with a TI K3 AM625. Things start to go wrong with a
> > WARN_ON():
> >
> > [ 11.544610] WARNING: drivers/reset/core.c:1195 at __fwnode_reset_control_get+0x488/0x580, CPU#0: (udev-worker)/129
>
> Thank you, that's reset_controller_register() setting
> fwnode_reset_n_cells to 2 since rcdev->of_node is set and rcdev-
> >of_reset_n_cells == 2:
>
> if (rcdev->of_node) {
> rcdev->fwnode = of_fwnode_handle(rcdev->of_node);
> rcdev->fwnode_reset_n_cells = rcdev->of_reset_n_cells;
> }
>
> and then overwriting it with 1, because rcdev->fwnode is now set as
> well, rcdev->fwnode_xlate is NULL, and rcdev->of_xlate is ignored:
>
> if (rcdev->fwnode && !rcdev->fwnode_xlate) {
> rcdev->fwnode_reset_n_cells = 1;
> rcdev->fwnode_xlate = fwnode_reset_simple_xlate;
> }
>
> That then fails because #reset-cells is <2> for k3_reset.
> We also have to check !rcdev->of_xlate here. Could you check if this
> fixes the issue?
>
> ----------8<----------
> diff --git a/drivers/reset/core.c b/drivers/reset/core.c
> index e625cf59cfb0..d52595db5f87 100644
> --- a/drivers/reset/core.c
> +++ b/drivers/reset/core.c
> @@ -143,7 +143,7 @@ int reset_controller_register(struct reset_controller_dev *rcdev)
> rcdev->fwnode_reset_n_cells = rcdev->of_reset_n_cells;
> }
>
> - if (rcdev->fwnode && !rcdev->fwnode_xlate) {
> + if (rcdev->fwnode && !rcdev->fwnode_xlate && !rcdev->of_xlate) {
> rcdev->fwnode_reset_n_cells = 1;
> rcdev->fwnode_xlate = fwnode_reset_simple_xlate;
> }
> ---------->8----------
>
Yeah, I just noticed the same. I'm fixing it and will send a patch shortly.
Bart
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 13/14] reset: convert reset core to using firmware nodes
2026-03-06 17:22 ` [PATCH v3 13/14] reset: convert reset core " Bartosz Golaszewski
2026-03-09 8:01 ` Philipp Zabel
2026-03-10 14:16 ` Mark Brown
@ 2026-03-10 15:00 ` Geert Uytterhoeven
2026-03-11 15:47 ` Tommaso Merciai
3 siblings, 0 replies; 30+ messages in thread
From: Geert Uytterhoeven @ 2026-03-10 15:00 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Krzysztof Kozlowski, Philipp Zabel, Jonathan Corbet, Shuah Khan,
linux-kernel, brgl, linux-doc
Hi Bartosz,
On Fri, 6 Mar 2026 at 18:30, Bartosz Golaszewski
<bartosz.golaszewski@oss.qualcomm.com> wrote:
> 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@oss.qualcomm.com>
Thanks for your patch, which is now commit 9035073d0ef1de81 ("reset:
convert reset core to using firmware nodes") in reset/next.
> --- a/drivers/reset/core.c
> +++ b/drivers/reset/core.c
> @@ -951,18 +965,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()
ref_find_device_by_node() does not exist. What should it be?
> * 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))
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply [flat|nested] 30+ messages in thread* Re: [PATCH v3 13/14] reset: convert reset core to using firmware nodes
2026-03-06 17:22 ` [PATCH v3 13/14] reset: convert reset core " Bartosz Golaszewski
` (2 preceding siblings ...)
2026-03-10 15:00 ` Geert Uytterhoeven
@ 2026-03-11 15:47 ` Tommaso Merciai
2026-03-11 15:54 ` Bartosz Golaszewski
3 siblings, 1 reply; 30+ messages in thread
From: Tommaso Merciai @ 2026-03-11 15:47 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Krzysztof Kozlowski, Philipp Zabel, Jonathan Corbet, Shuah Khan,
linux-kernel, brgl, linux-doc
Hi Bartosz,
Thanks for your patch.
On Fri, Mar 06, 2026 at 06:22:57PM +0100, Bartosz Golaszewski wrote:
> 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@oss.qualcomm.com>
Just to share I'm seeing the following on RZ/G3E (next-20260310):
[ 16.806538] ------------[ cut here ]------------
[ 16.806546] WARNING: drivers/reset/core.c:1195 at __fwnode_reset_control_get+0x474/0x568, CPU#3: kworker/u16:0/11
[ 16.806566] Modules linked in: reset_rzv2h_usb2phy(+) rcar_canfd(+) rtc_isl1208 can_dev ecdh_generic ecc rfkill renesas_rpc_if fuse drm backlight ipv6
[ 16.806603] CPU: 3 UID: 0 PID: 11 Comm: kworker/u16:0 Not tainted 7.0.0-rc3-next-20260310-00016-g866b1999e3fc #17 PREEMPT
[ 16.806610] Hardware name: Renesas SMARC EVK version 2 based on r9a09g047e57 (DT)
[ 16.806615] Workqueue: events_unbound deferred_probe_work_func
[ 16.806627] pstate: 80400005 (Nzcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[ 16.806632] pc : __fwnode_reset_control_get+0x474/0x568
[ 16.806638] lr : __fwnode_reset_control_get+0x164/0x568
[ 16.806644] sp : ffff800083263930
[ 16.806646] x29: ffff800083263a30 x28: ffff0000ff8370a8 x27: ffff800081d8d590
[ 16.806655] x26: ffff800081e3a6c8 x25: ffff800082fec430 x24: ffff800082fec450
[ 16.806663] x23: 0000000000000000 x22: 0000000000000003 x21: ffff0000ff835940
[ 16.806671] x20: 0000000000000000 x19: ffff0000c0294e98 x18: 00000000ffffffff
[ 16.806679] x17: 6e6f637478652f79 x16: 68702d6273752e30 x15: 303230303835312f
[ 16.806687] x14: ffff8000831a6200 x13: 00363038343d4d55 x12: 0000000000000000
[ 16.806695] x11: 7478653d4d455453 x10: ffff8000827b0ab7 x9 : 0000000000000028
[ 16.806703] x8 : 0101010101010101 x7 : 00000000736c6c65 x6 : 000000000080a3f0
[ 16.806711] x5 : ffff800083263864 x4 : ffffffffff604034 x3 : 0000000000000000
[ 16.806719] x2 : ffff0000c0128fc0 x1 : 0000000000000000 x0 : 0000000000000001
[ 16.806727] Call trace:
[ 16.806731] __fwnode_reset_control_get+0x474/0x568 (P)
[ 16.806738] fwnode_reset_control_array_get+0x84/0x134
[ 16.806745] devm_reset_control_array_get+0x54/0xb4
[ 16.806751] rcar_gen3_phy_usb2_probe+0x108/0x5b8
[ 16.806762] platform_probe+0x5c/0x98
[ 16.806770] really_probe+0xbc/0x29c
[ 16.806776] __driver_probe_device+0x78/0x12c
[ 16.806782] driver_probe_device+0x3c/0x15c
[ 16.806789] __device_attach_driver+0xb8/0x134
[ 16.806795] bus_for_each_drv+0x88/0xe8
[ 16.806802] __device_attach+0xa0/0x190
[ 16.806808] device_initial_probe+0x50/0x54
[ 16.806814] bus_probe_device+0x38/0xa4
[ 16.806820] deferred_probe_work_func+0x88/0xc0
[ 16.806826] process_one_work+0x154/0x294
[ 16.806835] worker_thread+0x180/0x300
[ 16.806840] kthread+0x118/0x124
[ 16.806847] ret_from_fork+0x10/0x20
[ 16.806856] ---[ end trace 0000000000000000 ]---
[ 16.806867] phy_rcar_gen3_usb2 15800200.usb-phy: probe with driver phy_rcar_gen3_usb2 failed with error -22
Hope this help.
Thanks & Regards,
Tommaso
> ---
> drivers/reset/core.c | 166 +++++++++++++++++++++++----------------
> include/linux/reset-controller.h | 14 +++-
> 2 files changed, 112 insertions(+), 68 deletions(-)
>
> diff --git a/drivers/reset/core.c b/drivers/reset/core.c
> index 0817afe72de75f795d62e02451520726da7c9844..e33a9bc9f94fc6867be6efd32178658d99fc088f 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
> - * :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.
> + * This static translation function is used by default if neither fwnode_xlate
> + * not of_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,23 @@ 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) {
> + rcdev->fwnode = dev_fwnode(rcdev->dev);
> + if (!rcdev->fwnode)
> + 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);
> @@ -931,7 +945,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);
>
> @@ -951,18 +965,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))
> @@ -982,15 +996,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;
> @@ -1001,7 +1023,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;
>
> /*
> @@ -1012,7 +1034,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
> @@ -1022,33 +1044,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);
> @@ -1058,43 +1078,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 fwnode_reference_args *rc_args;
> struct reset_controller_dev *rcdev;
> - struct of_phandle_args *rc_args;
>
> lockdep_assert_held(&reset_list_mutex);
>
> @@ -1103,10 +1123,10 @@ static struct reset_controller_dev *__reset_find_rcdev(const struct of_phandle_a
> 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;
> }
> }
> @@ -1120,27 +1140,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) {
> @@ -1151,16 +1170,16 @@ __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) {
> - of_node_put(args.np);
> + fwnode_handle_put(args.fwnode);
> return ERR_PTR(ret);
> }
> }
> @@ -1173,15 +1192,30 @@ __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;
> + goto out_put;
> }
>
> flags &= ~RESET_CONTROL_FLAGS_BIT_OPTIONAL;
> @@ -1190,7 +1224,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 185d2a9bd7cd381ddc51c0f1643c4e3cb196015e..52a5a4e81f1844075210339bf7ffa46ec5ca6edf 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: protects the reset control list from concurrent access
> */
> @@ -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
>
^ permalink raw reply [flat|nested] 30+ messages in thread* Re: [PATCH v3 13/14] reset: convert reset core to using firmware nodes
2026-03-11 15:47 ` Tommaso Merciai
@ 2026-03-11 15:54 ` Bartosz Golaszewski
2026-03-11 16:06 ` Tommaso Merciai
0 siblings, 1 reply; 30+ messages in thread
From: Bartosz Golaszewski @ 2026-03-11 15:54 UTC (permalink / raw)
To: Tommaso Merciai
Cc: Krzysztof Kozlowski, Philipp Zabel, Jonathan Corbet, Shuah Khan,
linux-kernel, brgl, linux-doc, Bartosz Golaszewski
On Wed, 11 Mar 2026 16:47:57 +0100, Tommaso Merciai
<tommaso.merciai.xr@bp.renesas.com> said:
> Hi Bartosz,
> Thanks for your patch.
>
> On Fri, Mar 06, 2026 at 06:22:57PM +0100, Bartosz Golaszewski wrote:
>> 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@oss.qualcomm.com>
>
> Just to share I'm seeing the following on RZ/G3E (next-20260310):
>
> [ 16.806538] ------------[ cut here ]------------
> [ 16.806546] WARNING: drivers/reset/core.c:1195 at __fwnode_reset_control_get+0x474/0x568, CPU#3: kworker/u16:0/11
> [ 16.806566] Modules linked in: reset_rzv2h_usb2phy(+) rcar_canfd(+) rtc_isl1208 can_dev ecdh_generic ecc rfkill renesas_rpc_if fuse drm backlight ipv6
> [ 16.806603] CPU: 3 UID: 0 PID: 11 Comm: kworker/u16:0 Not tainted 7.0.0-rc3-next-20260310-00016-g866b1999e3fc #17 PREEMPT
> [ 16.806610] Hardware name: Renesas SMARC EVK version 2 based on r9a09g047e57 (DT)
> [ 16.806615] Workqueue: events_unbound deferred_probe_work_func
> [ 16.806627] pstate: 80400005 (Nzcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
> [ 16.806632] pc : __fwnode_reset_control_get+0x474/0x568
> [ 16.806638] lr : __fwnode_reset_control_get+0x164/0x568
> [ 16.806644] sp : ffff800083263930
> [ 16.806646] x29: ffff800083263a30 x28: ffff0000ff8370a8 x27: ffff800081d8d590
> [ 16.806655] x26: ffff800081e3a6c8 x25: ffff800082fec430 x24: ffff800082fec450
> [ 16.806663] x23: 0000000000000000 x22: 0000000000000003 x21: ffff0000ff835940
> [ 16.806671] x20: 0000000000000000 x19: ffff0000c0294e98 x18: 00000000ffffffff
> [ 16.806679] x17: 6e6f637478652f79 x16: 68702d6273752e30 x15: 303230303835312f
> [ 16.806687] x14: ffff8000831a6200 x13: 00363038343d4d55 x12: 0000000000000000
> [ 16.806695] x11: 7478653d4d455453 x10: ffff8000827b0ab7 x9 : 0000000000000028
> [ 16.806703] x8 : 0101010101010101 x7 : 00000000736c6c65 x6 : 000000000080a3f0
> [ 16.806711] x5 : ffff800083263864 x4 : ffffffffff604034 x3 : 0000000000000000
> [ 16.806719] x2 : ffff0000c0128fc0 x1 : 0000000000000000 x0 : 0000000000000001
> [ 16.806727] Call trace:
> [ 16.806731] __fwnode_reset_control_get+0x474/0x568 (P)
> [ 16.806738] fwnode_reset_control_array_get+0x84/0x134
> [ 16.806745] devm_reset_control_array_get+0x54/0xb4
> [ 16.806751] rcar_gen3_phy_usb2_probe+0x108/0x5b8
> [ 16.806762] platform_probe+0x5c/0x98
> [ 16.806770] really_probe+0xbc/0x29c
> [ 16.806776] __driver_probe_device+0x78/0x12c
> [ 16.806782] driver_probe_device+0x3c/0x15c
> [ 16.806789] __device_attach_driver+0xb8/0x134
> [ 16.806795] bus_for_each_drv+0x88/0xe8
> [ 16.806802] __device_attach+0xa0/0x190
> [ 16.806808] device_initial_probe+0x50/0x54
> [ 16.806814] bus_probe_device+0x38/0xa4
> [ 16.806820] deferred_probe_work_func+0x88/0xc0
> [ 16.806826] process_one_work+0x154/0x294
> [ 16.806835] worker_thread+0x180/0x300
> [ 16.806840] kthread+0x118/0x124
> [ 16.806847] ret_from_fork+0x10/0x20
> [ 16.806856] ---[ end trace 0000000000000000 ]---
> [ 16.806867] phy_rcar_gen3_usb2 15800200.usb-phy: probe with driver phy_rcar_gen3_usb2 failed with error -22
>
> Hope this help.
>
> Thanks & Regards,
> Tommaso
>
Does [1] fix it?
Bart
[1] https://lore.kernel.org/all/20260310151515.34681-1-bartosz.golaszewski@oss.qualcomm.com/
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 13/14] reset: convert reset core to using firmware nodes
2026-03-11 15:54 ` Bartosz Golaszewski
@ 2026-03-11 16:06 ` Tommaso Merciai
0 siblings, 0 replies; 30+ messages in thread
From: Tommaso Merciai @ 2026-03-11 16:06 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Krzysztof Kozlowski, Philipp Zabel, Jonathan Corbet, Shuah Khan,
linux-kernel, linux-doc, Bartosz Golaszewski
Hi Bartosz,
On Wed, Mar 11, 2026 at 08:54:52AM -0700, Bartosz Golaszewski wrote:
> On Wed, 11 Mar 2026 16:47:57 +0100, Tommaso Merciai
> <tommaso.merciai.xr@bp.renesas.com> said:
> > Hi Bartosz,
> > Thanks for your patch.
> >
> > On Fri, Mar 06, 2026 at 06:22:57PM +0100, Bartosz Golaszewski wrote:
> >> 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@oss.qualcomm.com>
> >
> > Just to share I'm seeing the following on RZ/G3E (next-20260310):
> >
> > [ 16.806538] ------------[ cut here ]------------
> > [ 16.806546] WARNING: drivers/reset/core.c:1195 at __fwnode_reset_control_get+0x474/0x568, CPU#3: kworker/u16:0/11
> > [ 16.806566] Modules linked in: reset_rzv2h_usb2phy(+) rcar_canfd(+) rtc_isl1208 can_dev ecdh_generic ecc rfkill renesas_rpc_if fuse drm backlight ipv6
> > [ 16.806603] CPU: 3 UID: 0 PID: 11 Comm: kworker/u16:0 Not tainted 7.0.0-rc3-next-20260310-00016-g866b1999e3fc #17 PREEMPT
> > [ 16.806610] Hardware name: Renesas SMARC EVK version 2 based on r9a09g047e57 (DT)
> > [ 16.806615] Workqueue: events_unbound deferred_probe_work_func
> > [ 16.806627] pstate: 80400005 (Nzcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
> > [ 16.806632] pc : __fwnode_reset_control_get+0x474/0x568
> > [ 16.806638] lr : __fwnode_reset_control_get+0x164/0x568
> > [ 16.806644] sp : ffff800083263930
> > [ 16.806646] x29: ffff800083263a30 x28: ffff0000ff8370a8 x27: ffff800081d8d590
> > [ 16.806655] x26: ffff800081e3a6c8 x25: ffff800082fec430 x24: ffff800082fec450
> > [ 16.806663] x23: 0000000000000000 x22: 0000000000000003 x21: ffff0000ff835940
> > [ 16.806671] x20: 0000000000000000 x19: ffff0000c0294e98 x18: 00000000ffffffff
> > [ 16.806679] x17: 6e6f637478652f79 x16: 68702d6273752e30 x15: 303230303835312f
> > [ 16.806687] x14: ffff8000831a6200 x13: 00363038343d4d55 x12: 0000000000000000
> > [ 16.806695] x11: 7478653d4d455453 x10: ffff8000827b0ab7 x9 : 0000000000000028
> > [ 16.806703] x8 : 0101010101010101 x7 : 00000000736c6c65 x6 : 000000000080a3f0
> > [ 16.806711] x5 : ffff800083263864 x4 : ffffffffff604034 x3 : 0000000000000000
> > [ 16.806719] x2 : ffff0000c0128fc0 x1 : 0000000000000000 x0 : 0000000000000001
> > [ 16.806727] Call trace:
> > [ 16.806731] __fwnode_reset_control_get+0x474/0x568 (P)
> > [ 16.806738] fwnode_reset_control_array_get+0x84/0x134
> > [ 16.806745] devm_reset_control_array_get+0x54/0xb4
> > [ 16.806751] rcar_gen3_phy_usb2_probe+0x108/0x5b8
> > [ 16.806762] platform_probe+0x5c/0x98
> > [ 16.806770] really_probe+0xbc/0x29c
> > [ 16.806776] __driver_probe_device+0x78/0x12c
> > [ 16.806782] driver_probe_device+0x3c/0x15c
> > [ 16.806789] __device_attach_driver+0xb8/0x134
> > [ 16.806795] bus_for_each_drv+0x88/0xe8
> > [ 16.806802] __device_attach+0xa0/0x190
> > [ 16.806808] device_initial_probe+0x50/0x54
> > [ 16.806814] bus_probe_device+0x38/0xa4
> > [ 16.806820] deferred_probe_work_func+0x88/0xc0
> > [ 16.806826] process_one_work+0x154/0x294
> > [ 16.806835] worker_thread+0x180/0x300
> > [ 16.806840] kthread+0x118/0x124
> > [ 16.806847] ret_from_fork+0x10/0x20
> > [ 16.806856] ---[ end trace 0000000000000000 ]---
> > [ 16.806867] phy_rcar_gen3_usb2 15800200.usb-phy: probe with driver phy_rcar_gen3_usb2 failed with error -22
> >
> > Hope this help.
> >
> > Thanks & Regards,
> > Tommaso
> >
>
> Does [1] fix it?
Yes, thanks for sharing.
I will provide my Tested-by tag.
Kind Regards,
Tommaso
>
> Bart
>
> [1] https://lore.kernel.org/all/20260310151515.34681-1-bartosz.golaszewski@oss.qualcomm.com/
>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v3 14/14] reset: gpio: make the driver fwnode-agnostic
2026-03-06 17:22 [PATCH v3 00/14] reset: major reset core refactoring Bartosz Golaszewski
` (12 preceding siblings ...)
2026-03-06 17:22 ` [PATCH v3 13/14] reset: convert reset core " Bartosz Golaszewski
@ 2026-03-06 17:22 ` Bartosz Golaszewski
2026-03-09 9:25 ` [PATCH v3 00/14] reset: major reset core refactoring Philipp Zabel
14 siblings, 0 replies; 30+ messages in thread
From: Bartosz Golaszewski @ 2026-03-06 17:22 UTC (permalink / raw)
To: Krzysztof Kozlowski, Philipp Zabel, Jonathan Corbet, Shuah Khan
Cc: linux-kernel, brgl, linux-doc, Bartosz Golaszewski
With reset core now being able to work with firmware nodes, we can make
reset-gpio node-agnostic and drop any OF dependencies.
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/reset/reset-gpio.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/reset/reset-gpio.c b/drivers/reset/reset-gpio.c
index 5044f809d0e59a08861597f4aeb685e95328c2af..26aa2c3a2e689385ffa6ac056ce8787518ea4376 100644
--- a/drivers/reset/reset-gpio.c
+++ b/drivers/reset/reset-gpio.c
@@ -4,7 +4,7 @@
#include <linux/gpio/consumer.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of.h>
+#include <linux/property.h>
#include <linux/reset-controller.h>
struct reset_gpio_priv {
@@ -46,8 +46,8 @@ static const struct reset_control_ops reset_gpio_ops = {
.status = reset_gpio_status,
};
-static int reset_gpio_of_xlate(struct reset_controller_dev *rcdev,
- const struct of_phandle_args *reset_spec)
+static int reset_gpio_fwnode_xlate(struct reset_controller_dev *rcdev,
+ const struct fwnode_reference_args *reset_spec)
{
return reset_spec->args[0];
}
@@ -72,8 +72,8 @@ static int reset_gpio_probe(struct auxiliary_device *adev,
priv->rc.dev = dev;
/* Cells to match GPIO specifier, but it's not really used */
- priv->rc.of_reset_n_cells = 2;
- priv->rc.of_xlate = reset_gpio_of_xlate;
+ priv->rc.fwnode_reset_n_cells = 2;
+ priv->rc.fwnode_xlate = reset_gpio_fwnode_xlate;
priv->rc.nr_resets = 1;
return devm_reset_controller_register(dev, &priv->rc);
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH v3 00/14] reset: major reset core refactoring
2026-03-06 17:22 [PATCH v3 00/14] reset: major reset core refactoring Bartosz Golaszewski
` (13 preceding siblings ...)
2026-03-06 17:22 ` [PATCH v3 14/14] reset: gpio: make the driver fwnode-agnostic Bartosz Golaszewski
@ 2026-03-09 9:25 ` Philipp Zabel
2026-03-09 9:34 ` Bartosz Golaszewski
14 siblings, 1 reply; 30+ messages in thread
From: Philipp Zabel @ 2026-03-09 9:25 UTC (permalink / raw)
To: Bartosz Golaszewski, Krzysztof Kozlowski, Jonathan Corbet,
Shuah Khan
Cc: linux-kernel, brgl, linux-doc
On Fr, 2026-03-06 at 18:22 +0100, Bartosz Golaszewski wrote:
> Here is the promised refactoring of the reset core. The main goal of the
> series is to make the reset subsystem fwnode-agnostic - meaning it can
> work with all kinds of firmware nodes instead of being OF-centric - but
> there are some other related changes in here as well. I'm sending it all
> out for review to give Phillipp a better picture of the end result but
> individual pieces can be picked up earlier if accepted.
[...]
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Applied to reset/next, thanks!
[01/14] reset: gpio: remove unneeded OF-node put
https://git.pengutronix.de/cgit/pza/linux/commit/?id=fe3da77f2f94
[02/14] reset: gpio: add a devlink between reset-gpio and its consumer
https://git.pengutronix.de/cgit/pza/linux/commit/?id=a9b95ce36de4
[03/14] reset: gpio: simplify fallback device matching
https://git.pengutronix.de/cgit/pza/linux/commit/?id=ad9d28e68f4f
[04/14] reset: gpio: remove unneeded auxiliary_set_drvdata()
https://git.pengutronix.de/cgit/pza/linux/commit/?id=1acd46638408
[05/14] reset: warn on reset-gpio release
https://git.pengutronix.de/cgit/pza/linux/commit/?id=20adbf3b8f5c
[06/14] reset: fold ida_alloc() into reset_create_gpio_aux_device()
https://git.pengutronix.de/cgit/pza/linux/commit/?id=6703784ab9a8
[07/14] reset: use lock guards in reset core
https://git.pengutronix.de/cgit/pza/linux/commit/?id=1f10008aff71
[08/14] reset: handle removing supplier before consumers
https://git.pengutronix.de/cgit/pza/linux/commit/?id=78ebbff6d1a0
[09/14] reset: protect struct reset_controller_dev with its own mutex
https://git.pengutronix.de/cgit/pza/linux/commit/?id=44a0acb2caca
[10/14] reset: protect struct reset_control with its own mutex
https://git.pengutronix.de/cgit/pza/linux/commit/?id=8c91302a29bc
[11/14] reset: convert of_reset_control_get_count() to using firmware nodes
https://git.pengutronix.de/cgit/pza/linux/commit/?id=9d52054a4fc3
[12/14] reset: convert the core API to using firmware nodes
https://git.pengutronix.de/cgit/pza/linux/commit/?id=ba8dbbb14b7e
[13/14] reset: convert reset core to using firmware nodes
https://git.pengutronix.de/cgit/pza/linux/commit/?id=9035073d0ef1
[14/14] reset: gpio: make the driver fwnode-agnostic
https://git.pengutronix.de/cgit/pza/linux/commit/?id=faaad5006e58
regards
Philipp
^ permalink raw reply [flat|nested] 30+ messages in thread* Re: [PATCH v3 00/14] reset: major reset core refactoring
2026-03-09 9:25 ` [PATCH v3 00/14] reset: major reset core refactoring Philipp Zabel
@ 2026-03-09 9:34 ` Bartosz Golaszewski
0 siblings, 0 replies; 30+ messages in thread
From: Bartosz Golaszewski @ 2026-03-09 9:34 UTC (permalink / raw)
To: Philipp Zabel
Cc: Bartosz Golaszewski, Krzysztof Kozlowski, Jonathan Corbet,
Shuah Khan, linux-kernel, linux-doc
On Mon, Mar 9, 2026 at 10:25 AM Philipp Zabel <p.zabel@pengutronix.de> wrote:
>
> On Fr, 2026-03-06 at 18:22 +0100, Bartosz Golaszewski wrote:
> > Here is the promised refactoring of the reset core. The main goal of the
> > series is to make the reset subsystem fwnode-agnostic - meaning it can
> > work with all kinds of firmware nodes instead of being OF-centric - but
> > there are some other related changes in here as well. I'm sending it all
> > out for review to give Phillipp a better picture of the end result but
> > individual pieces can be picked up earlier if accepted.
> [...]
> > Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
>
> Applied to reset/next, thanks!
>
Thanks for the careful reviews and spotting all the corner-cases!
Bartosz
^ permalink raw reply [flat|nested] 30+ messages in thread