This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 3d267aab2a86b3fdb91594f9bce4c48b1fb451c0
Author: Felipe Moura <[email protected]>
AuthorDate: Thu Sep 17 18:59:12 2026 -0300

    espressif/esp_irq.c: fix up_disable_irq()/up_enable_irq() for GPIO IRQs
    
    esp_gpio_irq() registers per-pin GPIO interrupts through
    gpio_isr_handler_add(), never through esp_setup_irq(), so
    esp_get_handle() never finds them and up_disable_irq()/up_enable_irq()
    silently no-op for any GPIO-derived irq number. Fall back to
    esp_gpioirqdisable()/esp_gpioirqenable() (translating irq back to a
    pin via ESP_IRQ2PIN()) when the normal interrupt-matrix lookup misses.
    
    This surfaced through drivers/sensors/lsm6ds3trc_uorb.c: its ISR
    schedules a worker to drain the sensor's FIFO over I2C and disables
    its own IRQ until the worker re-enables it, so a level-triggered
    source (e.g. a PM GPIO wake source left in level mode) doesn't
    refire continuously and starve every task, HPWORK included, before
    the worker ever gets to run. That disable/enable only works now that
    up_disable_irq()/up_enable_irq() actually do something for GPIO irqs.
    
    Signed-off-by: Felipe Moura <[email protected]>
    Assisted-by: Claude:claude-sonnet-5
---
 arch/xtensa/src/common/espressif/esp_irq.c | 27 +++++++++++++++
 drivers/sensors/lsm6ds3trc_uorb.c          | 55 +++++++++++++++++++++++++++---
 2 files changed, 78 insertions(+), 4 deletions(-)

diff --git a/arch/xtensa/src/common/espressif/esp_irq.c 
b/arch/xtensa/src/common/espressif/esp_irq.c
index 403bfe99a83..b5c525ebef4 100644
--- a/arch/xtensa/src/common/espressif/esp_irq.c
+++ b/arch/xtensa/src/common/espressif/esp_irq.c
@@ -42,6 +42,7 @@
 
 #include "xtensa.h"
 
+#include "esp_gpio.h"
 #include "esp_irq.h"
 
 #include "esp_intr_alloc.h"
@@ -596,6 +597,21 @@ void up_enable_irq(int irq)
 
   if (intr_handle == IRQ_UNMAPPED)
     {
+      /* Not a real interrupt-matrix source -- esp_gpio_irq() registers
+       * per-pin GPIO IRQs through gpio_isr_handler_add() instead, so
+       * esp_get_handle() never finds them here. Try it as a GPIO pin.
+       */
+
+#ifdef CONFIG_ESPRESSIF_GPIO_IRQ
+      int pin = ESP_IRQ2PIN(irq);
+
+      if (pin >= 0 && pin < SOC_GPIO_PIN_COUNT && ESP_PIN2IRQ(pin) == irq)
+        {
+          esp_gpioirqenable(pin);
+          return;
+        }
+#endif
+
       irqwarn("IRQ %d not mapped to handle\n", irq);
       return;
     }
@@ -636,6 +652,17 @@ void up_disable_irq(int irq)
   intr_handle = esp_get_handle(this_cpu(), irq);
   if (intr_handle == IRQ_UNMAPPED)
     {
+      /* See the matching comment in up_enable_irq(). */
+
+#ifdef CONFIG_ESPRESSIF_GPIO_IRQ
+      int pin = ESP_IRQ2PIN(irq);
+
+      if (pin >= 0 && pin < SOC_GPIO_PIN_COUNT && ESP_PIN2IRQ(pin) == irq)
+        {
+          esp_gpioirqdisable(pin);
+        }
+#endif
+
       return;
     }
 
diff --git a/drivers/sensors/lsm6ds3trc_uorb.c 
b/drivers/sensors/lsm6ds3trc_uorb.c
index 86f2b78f0eb..93703e8231e 100644
--- a/drivers/sensors/lsm6ds3trc_uorb.c
+++ b/drivers/sensors/lsm6ds3trc_uorb.c
@@ -25,6 +25,7 @@
 #include <nuttx/config.h>
 #include <nuttx/nuttx.h>
 
+#include <nuttx/arch.h>
 #include <nuttx/debug.h>
 
 #include <nuttx/fs/fs.h>
@@ -202,6 +203,8 @@ struct lsm6ds3trc_dev_s
   bool interrupt_mode;            /* True if using the INT pin instead of
                                    * kthread polling */
   enum lsm6ds3trc_int_e int_pin;  /* Shared INT pin (interrupt mode only) */
+  int irq;                        /* IRQ number for int_pin, saved by the
+                                   * ISR so the worker can re-enable it */
   struct work_s work;             /* Shared interrupt work queue
                                    * structure -- one burst read serves
                                    * both sub-sensors */
@@ -834,9 +837,8 @@ static int accel_thread(int argc, char **argv)
  *
  ****************************************************************************/
 
-static void lsm6ds3trc_fifo_worker(FAR void *arg)
+static void lsm6ds3trc_fifo_worker_body(FAR struct lsm6ds3trc_dev_s *dev)
 {
-  FAR struct lsm6ds3trc_dev_s *dev = arg;
   uint8_t status[2];
   int16_t raw[FIFO_MAX_WORDS];
   int16_t raw_temp;
@@ -980,6 +982,24 @@ static void lsm6ds3trc_fifo_worker(FAR void *arg)
     }
 }
 
+/****************************************************************************
+ * Name: lsm6ds3trc_fifo_worker
+ *
+ * Description:
+ *   work_queue() entry point. Re-enables the IRQ lsm6ds3trc_interrupt()
+ *   disabled, after the FIFO has actually been drained -- see the comment
+ *   on lsm6ds3trc_interrupt() for why the order matters.
+ *
+ ****************************************************************************/
+
+static void lsm6ds3trc_fifo_worker(FAR void *arg)
+{
+  FAR struct lsm6ds3trc_dev_s *dev = arg;
+
+  lsm6ds3trc_fifo_worker_body(dev);
+  up_enable_irq(dev->irq);
+}
+
 #else
 /****************************************************************************
  * Name: lsm6ds3trc_worker
@@ -993,9 +1013,8 @@ static void lsm6ds3trc_fifo_worker(FAR void *arg)
  *
  ****************************************************************************/
 
-static void lsm6ds3trc_worker(FAR void *arg)
+static void lsm6ds3trc_worker_body(FAR struct lsm6ds3trc_dev_s *dev)
 {
-  FAR struct lsm6ds3trc_dev_s *dev = arg;
   int16_t raw[7]; /* temp, gx, gy, gz, ax, ay, az */
   struct sensor_gyro gyro_data;
   struct sensor_accel accel_data;
@@ -1043,6 +1062,24 @@ static void lsm6ds3trc_worker(FAR void *arg)
                                   sizeof(accel_data));
     }
 }
+
+/****************************************************************************
+ * Name: lsm6ds3trc_worker
+ *
+ * Description:
+ *   work_queue() entry point. Re-enables the IRQ lsm6ds3trc_interrupt()
+ *   disabled, after the measurement has actually been drained -- see the
+ *   comment on lsm6ds3trc_interrupt() for why the order matters.
+ *
+ ****************************************************************************/
+
+static void lsm6ds3trc_worker(FAR void *arg)
+{
+  FAR struct lsm6ds3trc_dev_s *dev = arg;
+
+  lsm6ds3trc_worker_body(dev);
+  up_enable_irq(dev->irq);
+}
 #endif
 
 /****************************************************************************
@@ -1053,6 +1090,13 @@ static void lsm6ds3trc_worker(FAR void *arg)
  *   became ready -- the I2C read cannot run in interrupt context, so it's
  *   deferred to lsm6ds3trc_worker()/lsm6ds3trc_fifo_worker() on HPWORK.
  *
+ *   The IRQ is disabled here and only re-enabled once the worker has
+ *   drained the condition that raised it: if a PM wake source ever leaves
+ *   this pin level-triggered instead of edge-triggered (or the line is
+ *   simply slow to fall), leaving the IRQ enabled would re-fire it
+ *   continuously and starve every task, including the worker that would
+ *   otherwise clear it.
+ *
  ****************************************************************************/
 
 static int lsm6ds3trc_interrupt(int irq, FAR void *context, FAR void *arg)
@@ -1064,6 +1108,9 @@ static int lsm6ds3trc_interrupt(int irq, FAR void 
*context, FAR void *arg)
 
   DEBUGASSERT(arg != NULL);
 
+  dev->irq = irq;
+  up_disable_irq(irq);
+
   dev->timestamp = sensor_get_timestamp();
 
 #ifdef CONFIG_SENSORS_LSM6DS3TRC_FIFO

Reply via email to