This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 1c6ed642bf2 espressif: stop leaking a Wi-Fi interrupt handle on every
esp_wifi_start()
1c6ed642bf2 is described below
commit 1c6ed642bf2d999816d90c979101decad4c25cab
Author: Felipe Moura <[email protected]>
AuthorDate: Tue Sep 29 18:20:08 2026 -0300
espressif: stop leaking a Wi-Fi interrupt handle on every esp_wifi_start()
set_intr_wrapper() allocates a new intr_handle_data_t from the kernel
heap each time the Wi-Fi driver calls it, and the driver calls it on
every esp_wifi_start() -- twice per start on esp32s3 -- not only the
first time. clear_intr_wrapper() is a no-op, so the IRQ still holds the
handle from the previous start: esp_set_handle() refuses to replace it
with -EINVAL, the return value is ignored, and the new block is lost.
Any application that stops and restarts Wi-Fi to save power therefore
loses a few bytes of kernel heap per cycle, without bound.
Look up the vector descriptor first, then reuse the handle already
registered for the IRQ and only allocate and register one when there is
none. A failed descriptor lookup no longer touches the registered
handle.
The same code is present in the esp32, esp32s2, esp32s3, esp32c3 and
esp32c6 Wi-Fi adapters; all five are fixed the same way.
Signed-off-by: Felipe Moura <[email protected]>
Assisted-by: Claude Opus 5.5 <[email protected]>
---
arch/risc-v/src/esp32c3/esp_wifi_adapter.c | 35 +++++++++++++++++-------
arch/risc-v/src/esp32c6/esp_wifi_adapter.c | 35 +++++++++++++++++-------
arch/xtensa/src/esp32/esp32_wifi_adapter.c | 37 +++++++++++++++++---------
arch/xtensa/src/esp32s2/esp32s2_wifi_adapter.c | 37 +++++++++++++++++---------
arch/xtensa/src/esp32s3/esp32s3_wifi_adapter.c | 37 +++++++++++++++++---------
5 files changed, 125 insertions(+), 56 deletions(-)
diff --git a/arch/risc-v/src/esp32c3/esp_wifi_adapter.c
b/arch/risc-v/src/esp32c3/esp_wifi_adapter.c
index 30be4f099dc..b95031714a6 100644
--- a/arch/risc-v/src/esp32c3/esp_wifi_adapter.c
+++ b/arch/risc-v/src/esp32c3/esp_wifi_adapter.c
@@ -558,6 +558,7 @@ static void set_intr_wrapper(int32_t cpu_no, uint32_t
intr_source,
uint32_t intr_num, int32_t intr_prio)
{
intr_handle_t handle;
+ vector_desc_t *desc;
int irq = ESP_SOURCE2IRQ(intr_source);
esp_err_t err;
@@ -569,26 +570,40 @@ static void set_intr_wrapper(int32_t cpu_no, uint32_t
intr_source,
esprv_int_set_priority(intr_num, intr_prio);
esprv_int_set_type(intr_num, INTR_TYPE_LEVEL);
- handle = kmm_calloc(1, sizeof(intr_handle_data_t));
- if (handle == NULL)
+ desc = get_desc_for_int(intr_num, cpu_no);
+ if (desc == NULL)
{
- wlerr("Failed to kmm_calloc\n");
+ wlerr("get_desc_for_int failed\n");
return;
}
- handle->vector_desc = get_desc_for_int(intr_num, cpu_no);
- if (handle->vector_desc == NULL)
+ /* The Wi-Fi driver calls this on every esp_wifi_start(), not only on
+ * the first one, and nothing clears the handle in between (see
+ * clear_intr_wrapper()). Reuse the registered handle: a new one would
+ * be refused by esp_set_handle() and leaked.
+ */
+
+ handle = esp_get_handle(cpu_no, irq);
+ if (handle == IRQ_UNMAPPED)
{
- wlerr("get_desc_for_int failed\n");
- kmm_free(handle);
- return;
+ handle = kmm_calloc(1, sizeof(intr_handle_data_t));
+ if (handle == NULL)
+ {
+ wlerr("Failed to kmm_calloc\n");
+ return;
+ }
+
+ /* Register the handle - it contains all needed information
+ * (cpuint, cpu)
+ */
+
+ esp_set_handle(cpu_no, irq, handle);
}
+ handle->vector_desc = desc;
handle->vector_desc->source = intr_source;
handle->shared_vector_desc = NULL;
- esp_set_handle(cpu_no, irq, handle);
-
err = esp_intr_set_in_iram(handle, false);
if (err != ESP_OK)
{
diff --git a/arch/risc-v/src/esp32c6/esp_wifi_adapter.c
b/arch/risc-v/src/esp32c6/esp_wifi_adapter.c
index f770a0f2e2b..c18f7122f37 100644
--- a/arch/risc-v/src/esp32c6/esp_wifi_adapter.c
+++ b/arch/risc-v/src/esp32c6/esp_wifi_adapter.c
@@ -591,6 +591,7 @@ static void set_intr_wrapper(int32_t cpu_no, uint32_t
intr_source,
uint32_t intr_num, int32_t intr_prio)
{
intr_handle_t handle;
+ vector_desc_t *desc;
int irq = ESP_SOURCE2IRQ(intr_source);
esp_err_t err;
@@ -602,26 +603,40 @@ static void set_intr_wrapper(int32_t cpu_no, uint32_t
intr_source,
esprv_int_set_priority(intr_num, intr_prio);
esprv_int_set_type(intr_num, INTR_TYPE_LEVEL);
- handle = kmm_calloc(1, sizeof(intr_handle_data_t));
- if (handle == NULL)
+ desc = get_desc_for_int(intr_num, cpu_no);
+ if (desc == NULL)
{
- wlerr("Failed to kmm_calloc\n");
+ wlerr("get_desc_for_int failed\n");
return;
}
- handle->vector_desc = get_desc_for_int(intr_num, cpu_no);
- if (handle->vector_desc == NULL)
+ /* The Wi-Fi driver calls this on every esp_wifi_start(), not only on
+ * the first one, and nothing clears the handle in between (see
+ * clear_intr_wrapper()). Reuse the registered handle: a new one would
+ * be refused by esp_set_handle() and leaked.
+ */
+
+ handle = esp_get_handle(cpu_no, irq);
+ if (handle == IRQ_UNMAPPED)
{
- wlerr("get_desc_for_int failed\n");
- kmm_free(handle);
- return;
+ handle = kmm_calloc(1, sizeof(intr_handle_data_t));
+ if (handle == NULL)
+ {
+ wlerr("Failed to kmm_calloc\n");
+ return;
+ }
+
+ /* Register the handle - it contains all needed information
+ * (cpuint, cpu)
+ */
+
+ esp_set_handle(cpu_no, irq, handle);
}
+ handle->vector_desc = desc;
handle->vector_desc->source = intr_source;
handle->shared_vector_desc = NULL;
- esp_set_handle(cpu_no, irq, handle);
-
err = esp_intr_set_in_iram(handle, false);
if (err != ESP_OK)
{
diff --git a/arch/xtensa/src/esp32/esp32_wifi_adapter.c
b/arch/xtensa/src/esp32/esp32_wifi_adapter.c
index 2b60394f1d7..0bbf485a303 100644
--- a/arch/xtensa/src/esp32/esp32_wifi_adapter.c
+++ b/arch/xtensa/src/esp32/esp32_wifi_adapter.c
@@ -1765,6 +1765,7 @@ static void set_intr_wrapper(int32_t cpu_no, uint32_t
intr_source,
uint32_t intr_num, int32_t intr_prio)
{
intr_handle_t handle;
+ vector_desc_t *desc;
int irq = ESP_SOURCE2IRQ(intr_source);
esp_err_t err;
@@ -1774,28 +1775,40 @@ static void set_intr_wrapper(int32_t cpu_no, uint32_t
intr_source,
esp_rom_route_intr_matrix(cpu_no, intr_source, intr_num);
- handle = kmm_calloc(1, sizeof(intr_handle_data_t));
- if (handle == NULL)
+ desc = get_desc_for_int(intr_num, cpu_no);
+ if (desc == NULL)
{
- wlerr("Failed to kmm_calloc\n");
+ wlerr("get_desc_for_int failed\n");
return;
}
- handle->vector_desc = get_desc_for_int(intr_num, cpu_no);
- if (handle->vector_desc == NULL)
+ /* The Wi-Fi driver calls this on every esp_wifi_start(), not only on
+ * the first one, and nothing clears the handle in between (see
+ * clear_intr_wrapper()). Reuse the registered handle: a new one would
+ * be refused by esp_set_handle() and leaked.
+ */
+
+ handle = esp_get_handle(cpu_no, irq);
+ if (handle == IRQ_UNMAPPED)
{
- wlerr("get_desc_for_int failed\n");
- kmm_free(handle);
- return;
+ handle = kmm_calloc(1, sizeof(intr_handle_data_t));
+ if (handle == NULL)
+ {
+ wlerr("Failed to kmm_calloc\n");
+ return;
+ }
+
+ /* Register the handle - it contains all needed information
+ * (cpuint, cpu)
+ */
+
+ esp_set_handle(cpu_no, irq, handle);
}
+ handle->vector_desc = desc;
handle->vector_desc->source = intr_source;
handle->shared_vector_desc = NULL;
- /* Register the handle - it contains all needed information (cpuint, cpu) */
-
- esp_set_handle(cpu_no, irq, handle);
-
err = esp_intr_set_in_iram(handle, false);
if (err != OK)
{
diff --git a/arch/xtensa/src/esp32s2/esp32s2_wifi_adapter.c
b/arch/xtensa/src/esp32s2/esp32s2_wifi_adapter.c
index 58fea3062b2..bc1a44a7a66 100644
--- a/arch/xtensa/src/esp32s2/esp32s2_wifi_adapter.c
+++ b/arch/xtensa/src/esp32s2/esp32s2_wifi_adapter.c
@@ -1623,6 +1623,7 @@ static void set_intr_wrapper(int32_t cpu_no, uint32_t
intr_source,
uint32_t intr_num, int32_t intr_prio)
{
intr_handle_t handle;
+ vector_desc_t *desc;
int irq = ESP_SOURCE2IRQ(intr_source);
esp_err_t err;
@@ -1632,28 +1633,40 @@ static void set_intr_wrapper(int32_t cpu_no, uint32_t
intr_source,
esp_rom_route_intr_matrix(cpu_no, intr_source, intr_num);
- handle = kmm_calloc(1, sizeof(intr_handle_data_t));
- if (handle == NULL)
+ desc = get_desc_for_int(intr_num, cpu_no);
+ if (desc == NULL)
{
- wlerr("Failed to kmm_calloc\n");
+ wlerr("get_desc_for_int failed\n");
return;
}
- handle->vector_desc = get_desc_for_int(intr_num, cpu_no);
- if (handle->vector_desc == NULL)
+ /* The Wi-Fi driver calls this on every esp_wifi_start(), not only on
+ * the first one, and nothing clears the handle in between (see
+ * clear_intr_wrapper()). Reuse the registered handle: a new one would
+ * be refused by esp_set_handle() and leaked.
+ */
+
+ handle = esp_get_handle(cpu_no, irq);
+ if (handle == IRQ_UNMAPPED)
{
- wlerr("get_desc_for_int failed\n");
- kmm_free(handle);
- return;
+ handle = kmm_calloc(1, sizeof(intr_handle_data_t));
+ if (handle == NULL)
+ {
+ wlerr("Failed to kmm_calloc\n");
+ return;
+ }
+
+ /* Register the handle - it contains all needed information
+ * (cpuint, cpu)
+ */
+
+ esp_set_handle(cpu_no, irq, handle);
}
+ handle->vector_desc = desc;
handle->vector_desc->source = intr_source;
handle->shared_vector_desc = NULL;
- /* Register the handle - it contains all needed information (cpuint, cpu) */
-
- esp_set_handle(cpu_no, irq, handle);
-
err = esp_intr_set_in_iram(handle, false);
if (err != OK)
{
diff --git a/arch/xtensa/src/esp32s3/esp32s3_wifi_adapter.c
b/arch/xtensa/src/esp32s3/esp32s3_wifi_adapter.c
index ca7f5dfced1..278fa70bc3a 100644
--- a/arch/xtensa/src/esp32s3/esp32s3_wifi_adapter.c
+++ b/arch/xtensa/src/esp32s3/esp32s3_wifi_adapter.c
@@ -1755,6 +1755,7 @@ static void set_intr_wrapper(int32_t cpu_no, uint32_t
intr_source,
uint32_t intr_num, int32_t intr_prio)
{
intr_handle_t handle;
+ vector_desc_t *desc;
int irq = ESP_SOURCE2IRQ(intr_source);
esp_err_t err;
@@ -1764,28 +1765,40 @@ static void set_intr_wrapper(int32_t cpu_no, uint32_t
intr_source,
esp_rom_route_intr_matrix(cpu_no, intr_source, intr_num);
- handle = kmm_calloc(1, sizeof(intr_handle_data_t));
- if (handle == NULL)
+ desc = get_desc_for_int(intr_num, cpu_no);
+ if (desc == NULL)
{
- wlerr("Failed to kmm_calloc\n");
+ wlerr("get_desc_for_int failed\n");
return;
}
- handle->vector_desc = get_desc_for_int(intr_num, cpu_no);
- if (handle->vector_desc == NULL)
+ /* The Wi-Fi driver calls this on every esp_wifi_start(), not only on
+ * the first one, and nothing clears the handle in between (see
+ * clear_intr_wrapper()). Reuse the registered handle: a new one would
+ * be refused by esp_set_handle() and leaked.
+ */
+
+ handle = esp_get_handle(cpu_no, irq);
+ if (handle == IRQ_UNMAPPED)
{
- wlerr("get_desc_for_int failed\n");
- kmm_free(handle);
- return;
+ handle = kmm_calloc(1, sizeof(intr_handle_data_t));
+ if (handle == NULL)
+ {
+ wlerr("Failed to kmm_calloc\n");
+ return;
+ }
+
+ /* Register the handle - it contains all needed information
+ * (cpuint, cpu)
+ */
+
+ esp_set_handle(cpu_no, irq, handle);
}
+ handle->vector_desc = desc;
handle->vector_desc->source = intr_source;
handle->shared_vector_desc = NULL;
- /* Register the handle - it contains all needed information (cpuint, cpu) */
-
- esp_set_handle(cpu_no, irq, handle);
-
err = esp_intr_set_in_iram(handle, false);
if (err != OK)
{