* [PATCH v4 1/5] gpio: sysfs: use cleanup guards for gpiod_data::mutex
2024-10-31 20:01 [PATCH v4 0/5] gpio: sysfs: send character device notifications for sysfs class events Bartosz Golaszewski
@ 2024-10-31 20:01 ` Bartosz Golaszewski
2024-10-31 20:01 ` [PATCH v4 2/5] gpio: sysfs: use cleanup guards for the sysfs_lock mutex Bartosz Golaszewski
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Bartosz Golaszewski @ 2024-10-31 20:01 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Kent Gibson
Cc: linux-gpio, linux-kernel, Bartosz Golaszewski
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Shrink the code and drop some goto labels by using lock guards around
gpiod_data::mutex.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
drivers/gpio/gpiolib-sysfs.c | 82 ++++++++++++++++----------------------------
1 file changed, 30 insertions(+), 52 deletions(-)
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index 0c713baa7784..a0926a1061ae 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -77,12 +77,10 @@ static ssize_t direction_show(struct device *dev,
struct gpio_desc *desc = data->desc;
int value;
- mutex_lock(&data->mutex);
-
- gpiod_get_direction(desc);
- value = !!test_bit(FLAG_IS_OUT, &desc->flags);
-
- mutex_unlock(&data->mutex);
+ scoped_guard(mutex, &data->mutex) {
+ gpiod_get_direction(desc);
+ value = !!test_bit(FLAG_IS_OUT, &desc->flags);
+ }
return sysfs_emit(buf, "%s\n", value ? "out" : "in");
}
@@ -94,7 +92,7 @@ static ssize_t direction_store(struct device *dev,
struct gpio_desc *desc = data->desc;
ssize_t status;
- mutex_lock(&data->mutex);
+ guard(mutex)(&data->mutex);
if (sysfs_streq(buf, "high"))
status = gpiod_direction_output_raw(desc, 1);
@@ -105,8 +103,6 @@ static ssize_t direction_store(struct device *dev,
else
status = -EINVAL;
- mutex_unlock(&data->mutex);
-
return status ? : size;
}
static DEVICE_ATTR_RW(direction);
@@ -118,11 +114,8 @@ static ssize_t value_show(struct device *dev,
struct gpio_desc *desc = data->desc;
ssize_t status;
- mutex_lock(&data->mutex);
-
- status = gpiod_get_value_cansleep(desc);
-
- mutex_unlock(&data->mutex);
+ scoped_guard(mutex, &data->mutex)
+ status = gpiod_get_value_cansleep(desc);
if (status < 0)
return status;
@@ -140,18 +133,17 @@ static ssize_t value_store(struct device *dev,
status = kstrtol(buf, 0, &value);
- mutex_lock(&data->mutex);
+ guard(mutex)(&data->mutex);
- if (!test_bit(FLAG_IS_OUT, &desc->flags)) {
- status = -EPERM;
- } else if (status == 0) {
- gpiod_set_value_cansleep(desc, value);
- status = size;
- }
+ if (!test_bit(FLAG_IS_OUT, &desc->flags))
+ return -EPERM;
- mutex_unlock(&data->mutex);
+ if (status)
+ return status;
- return status;
+ gpiod_set_value_cansleep(desc, value);
+
+ return size;
}
static DEVICE_ATTR_PREALLOC(value, S_IWUSR | S_IRUGO, value_show, value_store);
@@ -253,11 +245,8 @@ static ssize_t edge_show(struct device *dev,
struct gpiod_data *data = dev_get_drvdata(dev);
int flags;
- mutex_lock(&data->mutex);
-
- flags = data->irq_flags;
-
- mutex_unlock(&data->mutex);
+ scoped_guard(mutex, &data->mutex)
+ flags = data->irq_flags;
if (flags >= ARRAY_SIZE(trigger_names))
return 0;
@@ -276,26 +265,22 @@ static ssize_t edge_store(struct device *dev,
if (flags < 0)
return flags;
- mutex_lock(&data->mutex);
+ guard(mutex)(&data->mutex);
- if (flags == data->irq_flags) {
- status = size;
- goto out_unlock;
- }
+ if (flags == data->irq_flags)
+ return size;
if (data->irq_flags)
gpio_sysfs_free_irq(dev);
- if (flags) {
- status = gpio_sysfs_request_irq(dev, flags);
- if (!status)
- status = size;
- }
+ if (!flags)
+ return size;
-out_unlock:
- mutex_unlock(&data->mutex);
+ status = gpio_sysfs_request_irq(dev, flags);
+ if (status)
+ return status;
- return status;
+ return size;
}
static DEVICE_ATTR_RW(edge);
@@ -330,11 +315,8 @@ static ssize_t active_low_show(struct device *dev,
struct gpio_desc *desc = data->desc;
int value;
- mutex_lock(&data->mutex);
-
- value = !!test_bit(FLAG_ACTIVE_LOW, &desc->flags);
-
- mutex_unlock(&data->mutex);
+ scoped_guard(mutex, &data->mutex)
+ value = !!test_bit(FLAG_ACTIVE_LOW, &desc->flags);
return sysfs_emit(buf, "%d\n", value);
}
@@ -350,13 +332,9 @@ static ssize_t active_low_store(struct device *dev,
if (status)
return status;
- mutex_lock(&data->mutex);
+ guard(mutex)(&data->mutex);
- status = gpio_sysfs_set_active_low(dev, value);
-
- mutex_unlock(&data->mutex);
-
- return status ? : size;
+ return gpio_sysfs_set_active_low(dev, value) ?: size;
}
static DEVICE_ATTR_RW(active_low);
--
2.45.2
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH v4 2/5] gpio: sysfs: use cleanup guards for the sysfs_lock mutex
2024-10-31 20:01 [PATCH v4 0/5] gpio: sysfs: send character device notifications for sysfs class events Bartosz Golaszewski
2024-10-31 20:01 ` [PATCH v4 1/5] gpio: sysfs: use cleanup guards for gpiod_data::mutex Bartosz Golaszewski
@ 2024-10-31 20:01 ` Bartosz Golaszewski
2024-10-31 20:01 ` [PATCH v4 3/5] gpio: sysfs: emit chardev line-state events on GPIO export Bartosz Golaszewski
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Bartosz Golaszewski @ 2024-10-31 20:01 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Kent Gibson
Cc: linux-gpio, linux-kernel, Bartosz Golaszewski
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Shrink the code and remove some goto labels by using guards around the
sysfs_lock mutex.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
drivers/gpio/gpiolib-sysfs.c | 55 ++++++++++++++++++--------------------------
1 file changed, 22 insertions(+), 33 deletions(-)
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index a0926a1061ae..e6c1e26f302d 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -575,24 +575,24 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
gdev = desc->gdev;
- mutex_lock(&sysfs_lock);
+ guard(mutex)(&sysfs_lock);
/* check if chip is being removed */
if (!gdev->mockdev) {
status = -ENODEV;
- goto err_unlock;
+ goto err_clear_bit;
}
if (!test_bit(FLAG_REQUESTED, &desc->flags)) {
gpiod_dbg(desc, "%s: unavailable (not requested)\n", __func__);
status = -EPERM;
- goto err_unlock;
+ goto err_clear_bit;
}
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) {
status = -ENOMEM;
- goto err_unlock;
+ goto err_clear_bit;
}
data->desc = desc;
@@ -610,13 +610,11 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
goto err_free_data;
}
- mutex_unlock(&sysfs_lock);
return 0;
err_free_data:
kfree(data);
-err_unlock:
- mutex_unlock(&sysfs_lock);
+err_clear_bit:
clear_bit(FLAG_EXPORT, &desc->flags);
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
return status;
@@ -680,36 +678,28 @@ void gpiod_unexport(struct gpio_desc *desc)
return;
}
- mutex_lock(&sysfs_lock);
+ scoped_guard(mutex, &sysfs_lock) {
+ if (!test_bit(FLAG_EXPORT, &desc->flags))
+ return;
- if (!test_bit(FLAG_EXPORT, &desc->flags))
- goto err_unlock;
+ dev = class_find_device(&gpio_class, NULL, desc, match_export);
+ if (!dev)
+ return;
- dev = class_find_device(&gpio_class, NULL, desc, match_export);
- if (!dev)
- goto err_unlock;
+ data = dev_get_drvdata(dev);
+ clear_bit(FLAG_EXPORT, &desc->flags);
+ device_unregister(dev);
- data = dev_get_drvdata(dev);
-
- clear_bit(FLAG_EXPORT, &desc->flags);
-
- device_unregister(dev);
-
- /*
- * Release irq after deregistration to prevent race with edge_store.
- */
- if (data->irq_flags)
- gpio_sysfs_free_irq(dev);
-
- mutex_unlock(&sysfs_lock);
+ /*
+ * Release irq after deregistration to prevent race with
+ * edge_store.
+ */
+ if (data->irq_flags)
+ gpio_sysfs_free_irq(dev);
+ }
put_device(dev);
kfree(data);
-
- return;
-
-err_unlock:
- mutex_unlock(&sysfs_lock);
}
EXPORT_SYMBOL_GPL(gpiod_unexport);
@@ -750,9 +740,8 @@ int gpiochip_sysfs_register(struct gpio_device *gdev)
if (IS_ERR(dev))
return PTR_ERR(dev);
- mutex_lock(&sysfs_lock);
+ guard(mutex)(&sysfs_lock);
gdev->mockdev = dev;
- mutex_unlock(&sysfs_lock);
return 0;
}
--
2.45.2
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH v4 3/5] gpio: sysfs: emit chardev line-state events on GPIO export
2024-10-31 20:01 [PATCH v4 0/5] gpio: sysfs: send character device notifications for sysfs class events Bartosz Golaszewski
2024-10-31 20:01 ` [PATCH v4 1/5] gpio: sysfs: use cleanup guards for gpiod_data::mutex Bartosz Golaszewski
2024-10-31 20:01 ` [PATCH v4 2/5] gpio: sysfs: use cleanup guards for the sysfs_lock mutex Bartosz Golaszewski
@ 2024-10-31 20:01 ` Bartosz Golaszewski
2024-10-31 20:01 ` [PATCH v4 4/5] gpio: sysfs: emit chardev line-state events on active-low changes Bartosz Golaszewski
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Bartosz Golaszewski @ 2024-10-31 20:01 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Kent Gibson
Cc: linux-gpio, linux-kernel, Bartosz Golaszewski
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
We already emit a CONFIG_RELEASED event when a line is unexported over
sysfs (this is handled by gpiod_free()) but we don't do the opposite
when it's exported. This adds the missing call to
gpiod_line_state_notify().
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
drivers/gpio/gpiolib-sysfs.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index e6c1e26f302d..dd5e850c9517 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -21,6 +21,8 @@
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
+#include <uapi/linux/gpio.h>
+
#include "gpiolib.h"
#include "gpiolib-sysfs.h"
@@ -471,10 +473,12 @@ static ssize_t export_store(const struct class *class,
}
status = gpiod_export(desc, true);
- if (status < 0)
+ if (status < 0) {
gpiod_free(desc);
- else
+ } else {
set_bit(FLAG_SYSFS, &desc->flags);
+ gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_REQUESTED);
+ }
done:
if (status)
--
2.45.2
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH v4 4/5] gpio: sysfs: emit chardev line-state events on active-low changes
2024-10-31 20:01 [PATCH v4 0/5] gpio: sysfs: send character device notifications for sysfs class events Bartosz Golaszewski
` (2 preceding siblings ...)
2024-10-31 20:01 ` [PATCH v4 3/5] gpio: sysfs: emit chardev line-state events on GPIO export Bartosz Golaszewski
@ 2024-10-31 20:01 ` Bartosz Golaszewski
2024-10-31 20:01 ` [PATCH v4 5/5] gpio: sysfs: emit chardev line-state events on edge store Bartosz Golaszewski
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Bartosz Golaszewski @ 2024-10-31 20:01 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Kent Gibson
Cc: linux-gpio, linux-kernel, Bartosz Golaszewski
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
The sysfs active_low attribute doesn't go through the usual paths so it
doesn't emit the line-state event. Add the missing call to
gpiod_line_state_notify() to gpio_sysfs_set_active_low().
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
drivers/gpio/gpiolib-sysfs.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index dd5e850c9517..49a5aa89cafc 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -307,6 +307,8 @@ static int gpio_sysfs_set_active_low(struct device *dev, int value)
status = gpio_sysfs_request_irq(dev, flags);
}
+ gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_CONFIG);
+
return status;
}
--
2.45.2
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH v4 5/5] gpio: sysfs: emit chardev line-state events on edge store
2024-10-31 20:01 [PATCH v4 0/5] gpio: sysfs: send character device notifications for sysfs class events Bartosz Golaszewski
` (3 preceding siblings ...)
2024-10-31 20:01 ` [PATCH v4 4/5] gpio: sysfs: emit chardev line-state events on active-low changes Bartosz Golaszewski
@ 2024-10-31 20:01 ` Bartosz Golaszewski
2024-11-01 5:31 ` [PATCH v4 0/5] gpio: sysfs: send character device notifications for sysfs class events Kent Gibson
2024-11-04 7:56 ` Bartosz Golaszewski
6 siblings, 0 replies; 8+ messages in thread
From: Bartosz Golaszewski @ 2024-10-31 20:01 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Kent Gibson
Cc: linux-gpio, linux-kernel, Bartosz Golaszewski
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
In order to emit line-state events on edge changes in sysfs, update the
EDGE flags in the descriptor in gpio_sysfs_request_irq() and emit the
event on a successful store.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
drivers/gpio/gpiolib-sysfs.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index 49a5aa89cafc..5d7e8e64783c 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -179,12 +179,16 @@ static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags)
return -ENODEV;
irq_flags = IRQF_SHARED;
- if (flags & GPIO_IRQF_TRIGGER_FALLING)
+ if (flags & GPIO_IRQF_TRIGGER_FALLING) {
irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
- if (flags & GPIO_IRQF_TRIGGER_RISING)
+ set_bit(FLAG_EDGE_FALLING, &desc->flags);
+ }
+ if (flags & GPIO_IRQF_TRIGGER_RISING) {
irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
+ set_bit(FLAG_EDGE_RISING, &desc->flags);
+ }
/*
* FIXME: This should be done in the irq_request_resources callback
@@ -210,6 +214,8 @@ static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags)
err_unlock:
gpiochip_unlock_as_irq(guard.gc, gpio_chip_hwgpio(desc));
err_put_kn:
+ clear_bit(FLAG_EDGE_RISING, &desc->flags);
+ clear_bit(FLAG_EDGE_FALLING, &desc->flags);
sysfs_put(data->value_kn);
return ret;
@@ -231,6 +237,8 @@ static void gpio_sysfs_free_irq(struct device *dev)
data->irq_flags = 0;
free_irq(data->irq, data);
gpiochip_unlock_as_irq(guard.gc, gpio_chip_hwgpio(desc));
+ clear_bit(FLAG_EDGE_RISING, &desc->flags);
+ clear_bit(FLAG_EDGE_FALLING, &desc->flags);
sysfs_put(data->value_kn);
}
@@ -282,6 +290,8 @@ static ssize_t edge_store(struct device *dev,
if (status)
return status;
+ gpiod_line_state_notify(data->desc, GPIO_V2_LINE_CHANGED_CONFIG);
+
return size;
}
static DEVICE_ATTR_RW(edge);
--
2.45.2
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH v4 0/5] gpio: sysfs: send character device notifications for sysfs class events
2024-10-31 20:01 [PATCH v4 0/5] gpio: sysfs: send character device notifications for sysfs class events Bartosz Golaszewski
` (4 preceding siblings ...)
2024-10-31 20:01 ` [PATCH v4 5/5] gpio: sysfs: emit chardev line-state events on edge store Bartosz Golaszewski
@ 2024-11-01 5:31 ` Kent Gibson
2024-11-04 7:56 ` Bartosz Golaszewski
6 siblings, 0 replies; 8+ messages in thread
From: Kent Gibson @ 2024-11-01 5:31 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Linus Walleij, linux-gpio, linux-kernel, Bartosz Golaszewski
On Thu, Oct 31, 2024 at 09:01:50PM +0100, Bartosz Golaszewski wrote:
> This may be a total corner-case but for consistency and completeness I
> think it makes sense to also send out line state change events on actions
> triggered from the GPIO sysfs class.
>
> The first two patches use cleanup helpers in sysfs code. The next three
> change the code to emit notifications on line export (unexport is
> already handled) and active_low & edge changes.
>
> One last thing I considered was also notifying user-space whenever
> gpiochip_un/lock_as_irq() is called but that doesn't make much sense as
> it's largely independent from the GPIO core and can be called for both
> requested and available lines whenever someone requests an interrupt
> from a GPIO controller.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Looks good to me, though I'm sure there are a few places Andy would like
to tidy up the ret/error handling :).
Reviewed-by: Kent Gibson <warthog618@gmail.com>
Cheers,
Kent.
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH v4 0/5] gpio: sysfs: send character device notifications for sysfs class events
2024-10-31 20:01 [PATCH v4 0/5] gpio: sysfs: send character device notifications for sysfs class events Bartosz Golaszewski
` (5 preceding siblings ...)
2024-11-01 5:31 ` [PATCH v4 0/5] gpio: sysfs: send character device notifications for sysfs class events Kent Gibson
@ 2024-11-04 7:56 ` Bartosz Golaszewski
6 siblings, 0 replies; 8+ messages in thread
From: Bartosz Golaszewski @ 2024-11-04 7:56 UTC (permalink / raw)
To: Linus Walleij, Kent Gibson, Bartosz Golaszewski
Cc: Bartosz Golaszewski, linux-gpio, linux-kernel
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
On Thu, 31 Oct 2024 21:01:50 +0100, Bartosz Golaszewski wrote:
> This may be a total corner-case but for consistency and completeness I
> think it makes sense to also send out line state change events on actions
> triggered from the GPIO sysfs class.
>
> The first two patches use cleanup helpers in sysfs code. The next three
> change the code to emit notifications on line export (unexport is
> already handled) and active_low & edge changes.
>
> [...]
Applied, thanks!
[1/5] gpio: sysfs: use cleanup guards for gpiod_data::mutex
commit: d99c980cfe9423cd1ac719a73ae52437da29a45e
[2/5] gpio: sysfs: use cleanup guards for the sysfs_lock mutex
commit: f4af1671c28854bb0a400740a9c6ebacb8b9aa6b
[3/5] gpio: sysfs: emit chardev line-state events on GPIO export
commit: 285678c947197b0a071328f9344b0312e5545e92
[4/5] gpio: sysfs: emit chardev line-state events on active-low changes
commit: 5a7119e0d951fdf7ebcc25a77565ac184798639a
[5/5] gpio: sysfs: emit chardev line-state events on edge store
commit: 7b925098c937599c8ad1bc757db80743a990f57e
Best regards,
--
Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
^ permalink raw reply [flat|nested] 8+ messages in thread