Skip to content

Commit

Permalink
gpio: add SRCU infrastructure to struct gpio_desc
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Bartosz Golaszewski committed Feb 12, 2024
1 parent ccfb6ff commit be711ca
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 2 deletions.
18 changes: 16 additions & 2 deletions drivers/gpio/gpiolib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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));
Expand All @@ -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);

Expand Down Expand Up @@ -1020,6 +1031,9 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
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);
Expand Down
3 changes: 3 additions & 0 deletions drivers/gpio/gpiolib.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/rwsem.h>
#include <linux/srcu.h>

#define GPIOCHIP_NAME "gpiochip"

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit be711ca

Please sign in to comment.