gpio: sysfs: use gpio_device_find() to iterate over existing devices
authorBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Wed, 24 Jan 2024 15:29:39 +0000 (16:29 +0100)
committerBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Mon, 12 Feb 2024 09:50:42 +0000 (10:50 +0100)
With the list of GPIO devices now protected with SRCU we can use
gpio_device_find() to traverse it from sysfs.

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-sysfs.c
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.h

index 6bf5332136e5a9d4bd0b4c52618fa05241ccaa00..54b77ae1d176436409b26e9619e528f1b018ceb5 100644 (file)
@@ -790,11 +790,29 @@ void gpiochip_sysfs_unregister(struct gpio_device *gdev)
        }
 }
 
+/*
+ * We're not really looking for a device - we just want to iterate over the
+ * list and call this callback for each GPIO device. This is why this function
+ * always returns 0.
+ */
+static int gpiofind_sysfs_register(struct gpio_chip *gc, const void *data)
+{
+       struct gpio_device *gdev = gc->gpiodev;
+       int ret;
+
+       if (gdev->mockdev)
+               return 0;
+
+       ret = gpiochip_sysfs_register(gdev);
+       if (ret)
+               chip_err(gc, "failed to register the sysfs entry: %d\n", ret);
+
+       return 0;
+}
+
 static int __init gpiolib_sysfs_init(void)
 {
-       int             status;
-       unsigned long   flags;
-       struct gpio_device *gdev;
+       int status;
 
        status = class_register(&gpio_class);
        if (status < 0)
@@ -806,26 +824,8 @@ static int __init gpiolib_sysfs_init(void)
         * We run before arch_initcall() so chip->dev nodes can have
         * registered, and so arch_initcall() can always gpiod_export().
         */
-       spin_lock_irqsave(&gpio_lock, flags);
-       list_for_each_entry(gdev, &gpio_devices, list) {
-               if (gdev->mockdev)
-                       continue;
-
-               /*
-                * TODO we yield gpio_lock here because
-                * gpiochip_sysfs_register() acquires a mutex. This is unsafe
-                * and needs to be fixed.
-                *
-                * Also it would be nice to use gpio_device_find() here so we
-                * can keep gpio_chips local to gpiolib.c, but the yield of
-                * gpio_lock prevents us from doing this.
-                */
-               spin_unlock_irqrestore(&gpio_lock, flags);
-               status = gpiochip_sysfs_register(gdev);
-               spin_lock_irqsave(&gpio_lock, flags);
-       }
-       spin_unlock_irqrestore(&gpio_lock, flags);
+       (void)gpio_device_find(NULL, gpiofind_sysfs_register);
 
-       return status;
+       return 0;
 }
 postcore_initcall(gpiolib_sysfs_init);
index c72f3ffbe6b454c1b1cfbaedccae734c25c36de0..f0cbbab17dc339b855af33cc2ced3a93a56068a9 100644 (file)
@@ -85,7 +85,7 @@ DEFINE_SPINLOCK(gpio_lock);
 static DEFINE_MUTEX(gpio_lookup_lock);
 static LIST_HEAD(gpio_lookup_list);
 
-LIST_HEAD(gpio_devices);
+static LIST_HEAD(gpio_devices);
 /* Protects the GPIO device list against concurrent modifications. */
 static DEFINE_MUTEX(gpio_devices_lock);
 /* Ensures coherence during read-only accesses to the list of GPIO devices. */
index d2e73eea9e922687664fcf806f588babcd2a5b11..2bf3f9e13ae4139754a127412bfaefb58410844e 100644 (file)
@@ -136,7 +136,6 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
 int gpiod_set_transitory(struct gpio_desc *desc, bool transitory);
 
 extern spinlock_t gpio_lock;
-extern struct list_head gpio_devices;
 
 void gpiod_line_state_notify(struct gpio_desc *desc, unsigned long action);