On 15/01/2024 17:55, Philipp Zabel wrote:
On Fr, 2024-01-12 at 17:36 +0100, Krzysztof Kozlowski wrote:
+static bool __reset_gpios_args_match(const struct of_phandle_args *a1,
const struct of_phandle_args *a2)
+{
- unsigned int i;
- if (!a2)
return false;
- if (a1->args_count != a2->args_count)
return false;
- for (i = 0; i < a1->args_count; i++)
if (a1->args[i] != a2->args[i])
return false;
- return true;
+}
How about making this
return a2 && a1->np == a2->np && a1->args_count == a2->args_count && !memcmp(a1->args, a2->args, sizeof(a1->args[0]) * a1->args_count);
?
There's similar code in include/linux/cpufreq.h, maybe this could later be lifted into a common of_phandle_args_equal().
I'll make a helper because such long return is also not the fastest to parse by brain.
+static int __reset_add_reset_gpio_lookup(int id, struct device_node *np,
unsigned int gpio,
unsigned int of_flags)
+{
- struct gpiod_lookup_table *lookup __free(kfree) = NULL;
- struct gpio_device *gdev __free(gpio_device_put) = NULL;
- char *label __free(kfree) = NULL;
- unsigned int lookup_flags;
- /*
* Later we map GPIO flags between OF and Linux, however not all
* constants from include/dt-bindings/gpio/gpio.h and
* include/linux/gpio/machine.h match each other.
*/
- if (of_flags > GPIO_ACTIVE_LOW) {
pr_err("reset-gpio code does not support GPIO flags %u for GPIO %u\n",
of_flags, gpio);
return -EINVAL;
- }
- gdev = gpio_device_find_by_fwnode(of_fwnode_handle(np));
- if (!gdev)
return -EPROBE_DEFER;
- label = kstrdup(gpio_device_get_label(gdev), GFP_KERNEL);
- if (!label)
return -EINVAL;
The kstrdup() failure looks like it should be -ENOMEM to me. I'd check the gpio_device_get_label(gdev) return value separately.
OK, makes sense. One more local variable will be needed for that.
Is this going to be in v6.8-rc1, or does using gpio_device_get_label() introduce a dependency?
We were already in the merge window, so no problem here. gpio_device_get_label() is in v6.8-rc1.
- /* Size: one lookup entry plus sentinel */
- lookup = kzalloc(struct_size(lookup, table, 2), GFP_KERNEL);
- if (!lookup)
return -ENOMEM;
- lookup->dev_id = kasprintf(GFP_KERNEL, "reset-gpio.%d", id);
- if (!lookup->dev_id)
return -ENOMEM;
- lookup_flags = GPIO_PERSISTENT;
- lookup_flags |= of_flags & GPIO_ACTIVE_LOW;
- lookup->table[0] = GPIO_LOOKUP(no_free_ptr(label), gpio, "reset",
lookup_flags);
- gpiod_add_lookup_table(no_free_ptr(lookup));
- return 0;
+}
+/*
- @reset_args: phandle to the GPIO provider with all the args like GPIO number
s/reset_//
ack
- */
+static int __reset_add_reset_gpio_device(const struct of_phandle_args *args) +{
- struct reset_gpio_lookup *rgpio_dev;
- struct platform_device *pdev;
- int id, ret;
- /*
* Registering reset-gpio device might cause immediate
* bind, resulting in its probe() registering new reset controller thus
* taking reset_list_mutex lock via reset_controller_register().
*/
- lockdep_assert_not_held(&reset_list_mutex);
- mutex_lock(&reset_gpio_lookup_mutex);
- list_for_each_entry(rgpio_dev, &reset_gpio_lookup_list, list) {
if (args->np == rgpio_dev->of_args.np) {
if (__reset_gpios_args_match(args, &rgpio_dev->of_args))
goto out; /* Already on the list, done */
}
- }
- id = ida_alloc(&reset_gpio_ida, GFP_KERNEL);
- if (id < 0) {
ret = id;
goto err_unlock;
- }
- /*
* Not freed in normal path, persisent subsystem data (which is assumed
* also in the reset-gpio driver).
*/
- rgpio_dev = kzalloc(sizeof(*rgpio_dev), GFP_KERNEL);
- if (!rgpio_dev) {
ret = -ENOMEM;
goto err_ida_free;
- }
- ret = __reset_add_reset_gpio_lookup(id, args->np, args->args[0],
args->args[1]);
- if (ret < 0)
goto err_kfree;
- 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.
* Hold reference as long as rgpio_dev memory is valid.
*/
- of_node_get(rgpio_dev->of_args.np);
- pdev = platform_device_register_data(NULL, "reset-gpio", id,
&rgpio_dev->of_args,
sizeof(rgpio_dev->of_args));
- ret = PTR_ERR_OR_ZERO(pdev);
- if (ret)
goto err_put;
- list_add(&rgpio_dev->list, &reset_gpio_lookup_list);
+out:
- mutex_unlock(&reset_gpio_lookup_mutex);
- return 0;
+err_put:
- of_node_put(rgpio_dev->of_args.np);
+err_kfree:
- kfree(rgpio_dev);
+err_ida_free:
- ida_free(&reset_gpio_ida, id);
+err_unlock:
- mutex_unlock(&reset_gpio_lookup_mutex);
- return ret;
+}
+static struct reset_controller_dev *__reset_find_rcdev(const struct of_phandle_args *args,
bool gpio_fallback)
+{
- struct reset_controller_dev *r, *rcdev;
Now that this is moved into a function, there's no need for the r, rcdev split anymore. Just return a match when found, and NULL at the end:
struct reset_controller_dev *rcdev;
Indeed, thanks.
- lockdep_assert_held(&reset_list_mutex);
- rcdev = NULL;
- list_for_each_entry(r, &reset_controller_list, list) {
list_for_each_entry(rcdev, &reset_controller_list, list) {
if (args->np == r->of_node) {
if (gpio_fallback) {
if (__reset_gpios_args_match(args, r->of_args)) {
rcdev = r;
break;
return rcdev;
}
} else {
rcdev = r;
break;
}
}
With the np check moved into __reset_gpios_args_match() above, the whole loop could be turned into:
if (gpio_fallback) { if (__reset_gpios_args_match(args, rcdev->of_args)) return rcdev; } else { if (args->np == rcdev->of_node) return rcdev; }
Explicitly checking against rcdev->of_args->np instead of rcdev-
of_node in gpio_fallback mode could avoid false positives in case
anybody ever creates a combined GPIO and reset controller device and then uses its GPIOs to drive a shared reset line..
ack
- }
- return rcdev;
return NULL;
ack
+}
struct reset_control * __of_reset_control_get(struct device_node *node, const char *id, int index, bool shared, bool optional, bool acquired) {
- struct of_phandle_args args = {0};
Is this still needed?
I will double check.
- bool gpio_fallback = false; struct reset_control *rstc;
- struct reset_controller_dev *r, *rcdev;
- struct of_phandle_args args;
- struct reset_controller_dev *rcdev; int rstc_id; int ret;
@@ -839,39 +1028,49 @@ __of_reset_control_get(struct device_node *node, const char *id, int index, index, &args); if (ret == -EINVAL) return ERR_PTR(ret);
- if (ret)
return optional ? NULL : ERR_PTR(ret);
- if (ret) {
/*
* There can be only one reset-gpio for regular devices, so
* don't bother with GPIO index.
*/
ret = of_parse_phandle_with_args(node, "reset-gpios", "#gpio-cells",
0, &args);
if (ret)
return optional ? NULL : ERR_PTR(ret);
- mutex_lock(&reset_list_mutex);
- rcdev = NULL;
- list_for_each_entry(r, &reset_controller_list, list) {
if (args.np == r->of_node) {
rcdev = r;
break;
gpio_fallback = true;
ret = __reset_add_reset_gpio_device(&args);
if (ret) {
rstc = ERR_PTR(ret);
goto out_put;
} }
mutex_lock(&reset_list_mutex);
rcdev = __reset_find_rcdev(&args, gpio_fallback); if (!rcdev) { rstc = ERR_PTR(-EPROBE_DEFER);
goto out;
goto out_unlock;
}
if (WARN_ON(args.args_count != rcdev->of_reset_n_cells)) {
Nice. I like that the __of_reset_control_get() changes are much less invasive now.
rstc = ERR_PTR(-EINVAL);
goto out;
goto out_unlock;
}
rstc_id = rcdev->of_xlate(rcdev, &args); if (rstc_id < 0) { rstc = ERR_PTR(rstc_id);
goto out;
goto out_unlock;
}
/* reset_list_mutex also protects the rcdev's reset_control list */ rstc = __reset_control_get_internal(rcdev, rstc_id, shared, acquired);
-out: +out_unlock: mutex_unlock(&reset_list_mutex); +out_put: of_node_put(args.np);
return rstc; diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h index 0fa4f60e1186..e064473215de 100644 --- a/include/linux/reset-controller.h +++ b/include/linux/reset-controller.h @@ -61,6 +61,9 @@ struct reset_control_lookup {
- @dev: corresponding driver model device struct
- @of_node: corresponding device tree node as phandle target
- @of_reset_n_cells: number of cells in reset line specifiers
- TODO: of_args have of_node, so we have here duplication
Any plans what to do about this? With the above changes we could mandate that either of_node or of_args should be set, never both.
Yes, makes sense. We could also drop of_node, but the code won't be more readable.
Best regards, Krzysztof