]> www.infradead.org Git - users/hch/block.git/commitdiff
gpio: add SRCU infrastructure to struct gpio_desc
authorBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Fri, 5 Jan 2024 14:46:27 +0000 (15:46 +0100)
committerBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Mon, 12 Feb 2024 09:50:37 +0000 (10:50 +0100)
Extend the GPIO descriptor with an SRCU structure in order to serialize
the access to the label. Initialize and clean it up where applicable.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.h

index 79717776be84fe30c350a0f7e2d2567b904e7834..78b9e9dc268a61138435a6abe99258fea3fdc40e 100644 (file)
@@ -672,6 +672,10 @@ EXPORT_SYMBOL_GPL(gpiochip_line_is_valid);
 static void gpiodev_release(struct device *dev)
 {
        struct gpio_device *gdev = to_gpio_device(dev);
+       unsigned int i;
+
+       for (i = 0; i < gdev->ngpio; i++)
+               cleanup_srcu_struct(&gdev->descs[i].srcu);
 
        ida_free(&gpio_ida, gdev->id);
        kfree_const(gdev->label);
@@ -836,7 +840,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
                               struct lock_class_key *request_key)
 {
        struct gpio_device *gdev;
-       unsigned int i;
+       unsigned int i, j;
        int base = 0;
        int ret = 0;
 
@@ -970,6 +974,13 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
        for (i = 0; i < gc->ngpio; i++) {
                struct gpio_desc *desc = &gdev->descs[i];
 
+               ret = init_srcu_struct(&desc->srcu);
+               if (ret) {
+                       for (j = 0; j < i; j++)
+                               cleanup_srcu_struct(&gdev->descs[j].srcu);
+                       goto err_remove_of_chip;
+               }
+
                if (gc->get_direction && gpiochip_line_is_valid(gc, i)) {
                        assign_bit(FLAG_IS_OUT,
                                   &desc->flags, !gc->get_direction(gc, i));
@@ -981,7 +992,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
 
        ret = gpiochip_add_pin_ranges(gc);
        if (ret)
-               goto err_remove_of_chip;
+               goto err_cleanup_desc_srcu;
 
        acpi_gpiochip_add(gc);
 
@@ -1020,6 +1031,9 @@ err_remove_irqchip_mask:
        gpiochip_irqchip_free_valid_mask(gc);
 err_remove_acpi_chip:
        acpi_gpiochip_remove(gc);
+err_cleanup_desc_srcu:
+       for (i = 0; i < gdev->ngpio; i++)
+               cleanup_srcu_struct(&gdev->descs[i].srcu);
 err_remove_of_chip:
        gpiochip_free_hogs(gc);
        of_gpiochip_remove(gc);
index 1058f326fe2b76df30831a0eadaf1e85204bac91..6e14b629c48ba9865924617ceddc35a069e21806 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/notifier.h>
 #include <linux/rwsem.h>
+#include <linux/srcu.h>
 
 #define GPIOCHIP_NAME  "gpiochip"
 
@@ -147,6 +148,7 @@ void gpiod_line_state_notify(struct gpio_desc *desc, unsigned long action);
  * @label:             Name of the consumer
  * @name:              Line name
  * @hog:               Pointer to the device node that hogs this line (if any)
+ * @srcu:              SRCU struct protecting the label pointer.
  *
  * These are obtained using gpiod_get() and are preferable to the old
  * integer-based handles.
@@ -184,6 +186,7 @@ struct gpio_desc {
 #ifdef CONFIG_OF_DYNAMIC
        struct device_node      *hog;
 #endif
+       struct srcu_struct      srcu;
 };
 
 #define gpiod_not_found(desc)          (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT)