summaryrefslogtreecommitdiff
path: root/drivers/gpio/gpiolib-sysfs.c
diff options
context:
space:
mode:
authorBartosz Golaszewski <bartosz.golaszewski@linaro.org>2023-12-15 16:53:00 +0100
committerBartosz Golaszewski <bartosz.golaszewski@linaro.org>2023-12-18 10:00:43 +0100
commit65a828bab15887b33336d251fd659b2ae86de6d6 (patch)
tree3b33dddd67f9d8914c1034ea0d09cf47723a77df /drivers/gpio/gpiolib-sysfs.c
parentf95fd4ac155733b5735c84a2e56eee8321232095 (diff)
gpiolib: use a mutex to protect the list of GPIO devices
The global list of GPIO devices is never modified or accessed from atomic context so it's fine to protect it using a mutex. Add a new global lock dedicated to the gpio_devices list and use it whenever accessing or modifying it. Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Diffstat (limited to 'drivers/gpio/gpiolib-sysfs.c')
-rw-r--r--drivers/gpio/gpiolib-sysfs.c45
1 files changed, 21 insertions, 24 deletions
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index 6f309a3b2d9a..ae4fc013b675 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -766,6 +766,25 @@ int gpiochip_sysfs_register(struct gpio_device *gdev)
return 0;
}
+int gpiochip_sysfs_register_all(void)
+{
+ struct gpio_device *gdev;
+ int ret;
+
+ guard(mutex)(&gpio_devices_lock);
+
+ list_for_each_entry(gdev, &gpio_devices, list) {
+ if (gdev->mockdev)
+ continue;
+
+ ret = gpiochip_sysfs_register(gdev);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
void gpiochip_sysfs_unregister(struct gpio_device *gdev)
{
struct gpio_desc *desc;
@@ -790,9 +809,7 @@ void gpiochip_sysfs_unregister(struct gpio_device *gdev)
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)
@@ -804,26 +821,6 @@ 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);
-
- return status;
+ return gpiochip_sysfs_register_all();
}
postcore_initcall(gpiolib_sysfs_init);