The branch main has been updated by seuros:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=cd7541977e2ce5aebeeeae3e8a375256ee1ecb1d

commit cd7541977e2ce5aebeeeae3e8a375256ee1ecb1d
Author:     Abdelkader Boudih <[email protected]>
AuthorDate: 2026-08-29 18:46:23 +0000
Commit:     Abdelkader Boudih <[email protected]>
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);

Reply via email to