Merge branch 'bugfix/workaround_free_peripherals_isr_when_using_dual_core' into 'master'

driver(interrupt): fix the issue that interrupt might be allocated and freed on different cores.

See merge request idf/esp-idf!3152
This commit is contained in:
Ivan Grokhotkov 2018-09-30 21:42:52 +08:00
commit 94e5ffdedc
3 changed files with 50 additions and 8 deletions

View file

@ -194,18 +194,19 @@ esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusre
/**
* @brief Disable and free an interrupt.
*
* Use an interrupt handle to disable the interrupt and release the resources
* associated with it.
* Use an interrupt handle to disable the interrupt and release the resources associated with it.
* If the current core is not the core that registered this interrupt, this routine will be assigned to
* the core that allocated this interrupt, blocking and waiting until the resource is successfully released.
*
* @note
* When the handler shares its source with other handlers, the interrupt status
* bits it's responsible for should be managed properly before freeing it. see
* ``esp_intr_disable`` for more details.
* ``esp_intr_disable`` for more details. Please do not call this function in ``esp_ipc_call_blocking``.
*
* @param handle The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus
*
* @return ESP_ERR_INVALID_ARG if handle is invalid, or esp_intr_free runs on another core than
* where the interrupt is allocated on.
* @return ESP_ERR_INVALID_ARG the handle is NULL
* ESP_FAIL failed to release this handle
* ESP_OK otherwise
*/
esp_err_t esp_intr_free(intr_handle_t handle);

View file

@ -29,6 +29,7 @@
#include "esp_intr.h"
#include "esp_attr.h"
#include "esp_intr_alloc.h"
#include "esp_ipc.h"
#include <limits.h>
#include <assert.h>
@ -709,9 +710,11 @@ esp_err_t esp_intr_free(intr_handle_t handle)
{
bool free_shared_vector=false;
if (!handle) return ESP_ERR_INVALID_ARG;
//This routine should be called from the interrupt the task is scheduled on.
if (handle->vector_desc->cpu!=xPortGetCoreID()) return ESP_ERR_INVALID_ARG;
//Assign this routine to the core where this interrupt is allocated on.
if (handle->vector_desc->cpu!=xPortGetCoreID()) {
esp_err_t ret = esp_ipc_call_blocking(handle->vector_desc->cpu, (esp_ipc_func_t)&esp_intr_free, (void *)handle);
return ret == ESP_OK ? ESP_OK : ESP_FAIL;
}
portENTER_CRITICAL(&spinlock);
esp_intr_disable(handle);
if (handle->vector_desc->flags&VECDESC_FL_SHARED) {

View file

@ -297,3 +297,41 @@ TEST_CASE("allocate 2 handlers for a same source and remove the later one","[esp
TEST_ASSERT( ctx.flag3 && !ctx.flag4 );
printf("test passed.\n");
}
#ifndef CONFIG_FREERTOS_UNICORE
void isr_free_task(void *param)
{
esp_err_t ret = ESP_FAIL;
intr_handle_t *test_handle = (intr_handle_t *)param;
if(*test_handle != NULL) {
ret = esp_intr_free(*test_handle);
if(ret == ESP_OK) {
*test_handle = NULL;
}
}
vTaskDelete(NULL);
}
void isr_alloc_free_test(void)
{
intr_handle_t test_handle = NULL;
esp_err_t ret = esp_intr_alloc(ETS_SPI2_INTR_SOURCE, 0, int_handler1, NULL, &test_handle);
if(ret != ESP_OK) {
printf("alloc isr handle fail\n");
} else {
printf("alloc isr handle on core %d\n",esp_intr_get_cpu(test_handle));
}
TEST_ASSERT(ret == ESP_OK);
xTaskCreatePinnedToCore(isr_free_task, "isr_free_task", 1024*2, (void *)&test_handle, 10, NULL, !xPortGetCoreID());
vTaskDelay(1000/portTICK_RATE_MS);
TEST_ASSERT(test_handle == NULL);
printf("test passed\n");
}
TEST_CASE("alloc and free isr handle on different core", "[esp32]")
{
isr_alloc_free_test();
}
#endif