mirror of
https://github.com/apache/nuttx.git
synced 2026-10-03 20:27:53 +00:00
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 <moura.fmo@gmail.com> Assisted-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
b38b03072a
commit
1c6ed642bf
5 changed files with 135 additions and 66 deletions
|
|
@ -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)
|
||||
{
|
||||
wlerr("Failed to kmm_calloc\n");
|
||||
return;
|
||||
}
|
||||
|
||||
handle->vector_desc = get_desc_for_int(intr_num, cpu_no);
|
||||
if (handle->vector_desc == NULL)
|
||||
desc = get_desc_for_int(intr_num, cpu_no);
|
||||
if (desc == NULL)
|
||||
{
|
||||
wlerr("get_desc_for_int failed\n");
|
||||
kmm_free(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
wlerr("Failed to kmm_calloc\n");
|
||||
return;
|
||||
}
|
||||
|
||||
handle->vector_desc = get_desc_for_int(intr_num, cpu_no);
|
||||
if (handle->vector_desc == NULL)
|
||||
desc = get_desc_for_int(intr_num, cpu_no);
|
||||
if (desc == NULL)
|
||||
{
|
||||
wlerr("get_desc_for_int failed\n");
|
||||
kmm_free(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
wlerr("Failed to kmm_calloc\n");
|
||||
return;
|
||||
}
|
||||
|
||||
handle->vector_desc = get_desc_for_int(intr_num, cpu_no);
|
||||
if (handle->vector_desc == NULL)
|
||||
desc = get_desc_for_int(intr_num, cpu_no);
|
||||
if (desc == NULL)
|
||||
{
|
||||
wlerr("get_desc_for_int failed\n");
|
||||
kmm_free(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
wlerr("Failed to kmm_calloc\n");
|
||||
return;
|
||||
}
|
||||
|
||||
handle->vector_desc = get_desc_for_int(intr_num, cpu_no);
|
||||
if (handle->vector_desc == NULL)
|
||||
desc = get_desc_for_int(intr_num, cpu_no);
|
||||
if (desc == NULL)
|
||||
{
|
||||
wlerr("get_desc_for_int failed\n");
|
||||
kmm_free(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
wlerr("Failed to kmm_calloc\n");
|
||||
return;
|
||||
}
|
||||
|
||||
handle->vector_desc = get_desc_for_int(intr_num, cpu_no);
|
||||
if (handle->vector_desc == NULL)
|
||||
desc = get_desc_for_int(intr_num, cpu_no);
|
||||
if (desc == NULL)
|
||||
{
|
||||
wlerr("get_desc_for_int failed\n");
|
||||
kmm_free(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue