esp32s3/ble: fix saving/restoring the interrupt status flags

Whenever we enter/leave a critical section, the interrupt status is
saved and, then, restored. However, for the ESP32-S3's BLE adapter,
entering/leaving a critical section is done on separate functions
that need to be registered as a callback.

The status flag was being saved as a global variable. However,
calling nested enter_critical_section would overwrite this global
variable that was storing the previous flag and, when leaving the
last critical section, the restored status would be different from
the one expected. The proposed solution for this issue is to create
a global array to store the interrupt status flags for nested calls.
This commit is contained in:
Tiago Medicci Serrano 2023-09-25 17:36:17 -03:00 committed by Xiang Xiao
parent a71a3258b7
commit 6521bdfa1f
2 changed files with 51 additions and 4 deletions

View File

@ -1415,6 +1415,12 @@ config ESP32S3_BLE_TASK_PRIORITY
int "Controller task priority"
default 253
config ESP32S3_BLE_INTERRUPT_SAVE_STATUS
int "Number of interrupt save status"
default 3
---help---
Number of interrupt save status variables to keep track. Increase it if any related bug is found.
endmenu # BLE Configuration
menu "Timer/Counter Configuration"

View File

@ -94,6 +94,12 @@
# define BLE_TASK_EVENT_QUEUE_LEN 1
#endif
#ifdef CONFIG_ESP32S3_BLE_INTERRUPT_SAVE_STATUS
# define NR_IRQSTATE_FLAGS CONFIG_ESP32S3_BLE_INTERRUPT_SAVE_STATUS
#else
# define NR_IRQSTATE_FLAGS 3
#endif
/****************************************************************************
* Private Types
****************************************************************************/
@ -173,6 +179,12 @@ struct bt_sem_s
#endif
};
struct irqstate_list_s
{
struct irqstate_list_s *flink;
irqstate_t flags;
};
/* prototype of function to handle vendor dependent signals */
typedef void (*btdm_vnd_ol_task_func_t)(void *param);
@ -436,7 +448,11 @@ static DRAM_ATTR void * g_light_sleep_pm_lock;
/* BT interrupt private data */
static irqstate_t g_inter_flags;
static sq_queue_t g_int_flags_free;
static sq_queue_t g_int_flags_used;
static struct irqstate_list_s g_int_flags[NR_IRQSTATE_FLAGS];
/* Cached queue control variables */
@ -799,7 +815,15 @@ static void interrupt_off_wrapper(int intr_num)
static void IRAM_ATTR interrupt_disable(void)
{
g_inter_flags = enter_critical_section();
struct irqstate_list_s *irqstate;
irqstate = (struct irqstate_list_s *)sq_remlast(&g_int_flags_free);
DEBUGASSERT(irqstate != NULL);
irqstate->flags = enter_critical_section();
sq_addlast((sq_entry_t *)irqstate, &g_int_flags_used);
}
/****************************************************************************
@ -819,7 +843,15 @@ static void IRAM_ATTR interrupt_disable(void)
static void IRAM_ATTR interrupt_restore(void)
{
leave_critical_section(g_inter_flags);
struct irqstate_list_s *irqstate;
irqstate = (struct irqstate_list_s *)sq_remlast(&g_int_flags_used);
DEBUGASSERT(irqstate != NULL);
leave_critical_section(irqstate->flags);
sq_addlast((sq_entry_t *)irqstate, &g_int_flags_free);
}
/****************************************************************************
@ -1558,7 +1590,7 @@ static int task_create_wrapper(void *task_func, const char *name,
{
return esp_task_create_pinned_to_core(task_func, name,
stack_depth, param,
prio, task_handle, UINT32_MAX);
prio, task_handle, core_id);
}
/****************************************************************************
@ -2200,6 +2232,15 @@ int esp32s3_bt_controller_init(void)
esp_bt_controller_config_t *cfg = &bt_cfg;
bool select_src_ret;
bool set_div_ret;
int i;
sq_init(&g_int_flags_free);
sq_init(&g_int_flags_used);
for (i = 0; i < NR_IRQSTATE_FLAGS; i++)
{
sq_addlast((sq_entry_t *)&g_int_flags[i], &g_int_flags_free);
}
if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE)
{