git: cd7541977e2c - main - gpioled: defer gpio pin writes to a taskqueue
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 29 Aug 2026 18:56:52 UTC
The branch main has been updated by seuros:
URL: https://cgit.FreeBSD.org/src/commit/?id=cd7541977e2ce5aebeeeae3e8a375256ee1ecb1d
commit cd7541977e2ce5aebeeeae3e8a375256ee1ecb1d
Author: Abdelkader Boudih <seuros@FreeBSD.org>
AuthorDate: 2026-08-29 18:46:23 +0000
Commit: Abdelkader Boudih <seuros@FreeBSD.org>
CommitDate: 2026-08-29 18:46:23 +0000
gpioled: defer gpio pin writes to a taskqueue
led(4) invoked the led_t callback with its mutex held, including from the
blink callout, so the callback must not sleep.
PR: 251032
MFC After: 1 week
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D59263
---
sys/dev/gpio/gpioled_fdt.c | 29 ++++++++++++++++++++++++++---
1 file changed, 26 insertions(+), 3 deletions(-)
diff --git a/sys/dev/gpio/gpioled_fdt.c b/sys/dev/gpio/gpioled_fdt.c
index 4003d532dd9f..b6afeba703c0 100644
--- a/sys/dev/gpio/gpioled_fdt.c
+++ b/sys/dev/gpio/gpioled_fdt.c
@@ -36,6 +36,9 @@
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
+#include <sys/taskqueue.h>
+
+#include <machine/atomic.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/ofw_bus.h>
@@ -50,6 +53,8 @@ struct gpioled
struct gpioleds_softc *parent_sc;
gpio_pin_t pin;
struct cdev *leddev;
+ struct task task;
+ int state;
};
struct gpioleds_softc
@@ -65,14 +70,28 @@ static int gpioled_probe(device_t);
static int gpioled_attach(device_t);
static int gpioled_detach(device_t);
+/* Writes the most recently requested state, not every state update. */
+static void
+gpioled_update(void *arg, int pending __unused)
+{
+ struct gpioled *led;
+
+ led = arg;
+ gpio_pin_set_active(led->pin, atomic_load_int(&led->state) != 0);
+}
+
static void
gpioled_control(void *priv, int onoff)
{
struct gpioled *led;
led = (struct gpioled *)priv;
- if (led->pin)
- gpio_pin_set_active(led->pin, onoff);
+ if (led->pin == NULL)
+ return;
+
+ /* Runs under the led(4) mutex, so the pin write is deferred. */
+ atomic_store_int(&led->state, onoff);
+ taskqueue_enqueue(taskqueue_thread, &led->task);
}
static void
@@ -121,6 +140,8 @@ gpioleds_attach_led(struct gpioleds_softc *sc, phandle_t node,
}
gpio_pin_setflags(led->pin, GPIO_PIN_OUTPUT);
+ TASK_INIT(&led->task, 0, gpioled_update, led);
+
led->leddev = led_create_state(gpioled_control, led, name,
state);
@@ -132,8 +153,10 @@ static void
gpioleds_detach_led(struct gpioled *led)
{
- if (led->leddev != NULL)
+ if (led->leddev != NULL) {
led_destroy(led->leddev);
+ taskqueue_drain(taskqueue_thread, &led->task);
+ }
if (led->pin)
gpio_pin_release(led->pin);