components/bt: High level interrupt in bluetooth

components/os: Move ETS_T1_WDT_INUM, ETS_CACHEERR_INUM and ETS_DPORT_INUM to l5 interrupt

components/os: high level interrupt(5)

components/os: hli_api: meta queue: fix out of bounds access, check for overflow

components/os: hli: don't spill registers, instead save them to a separate region

Level 4 interrupt has a chance of preempting a window overflow or underflow exception.
Therefore it is not possible to use standard context save functions,
as the SP on entry to Level 4 interrupt may be invalid (e.g. in WindowUnderflow4).

Instead, mask window overflows and save the entire general purpose register file,
plus some of the special registers.
Then clear WindowStart, allowing the C handler to execute without spilling the old windows.
On exit from the interrupt handler, do everything in reverse.

components/bt: using high level interrupt in lc

components/os: Add DRAM_ATTR to avoid feature `Allow .bss segment placed in external memory`

components/bt: optimize code structure

components/os: Modify the BT assert process to adapt to coredump and HLI

components/os: Disable exception mode after saving special registers

To store some registers first, avoid stuck due to live lock after disabling exception mode

components/os: using dport instead of AHB in BT to fix live lock

components/bt: Fix hli queue send error

components/bt: Fix CI fail

# Conflicts:
#	components/bt/CMakeLists.txt
#	components/bt/component.mk
#	components/bt/controller/bt.c
#	components/bt/controller/lib
#	components/esp_common/src/int_wdt.c
#	components/esp_system/port/soc/esp32/dport_panic_highint_hdl.S
#	components/soc/esp32/include/soc/soc.h
This commit is contained in:
baohongde
2021-09-01 21:55:50 +08:00
committed by bot
parent df1b524d07
commit d1db2df316
13 changed files with 1109 additions and 499 deletions

View File

@@ -1,6 +1,8 @@
if(CONFIG_BT_ENABLED)
if(CONFIG_IDF_TARGET_ESP32)
set(srcs "controller/esp32/bt.c")
set(srcs "controller/esp32/bt.c"
"controller/esp32/hli_api.c"
"controller/esp32/hli_vectors.S")
elseif(CONFIG_IDF_TARGET_ESP32C3)
set(srcs "controller/esp32c3/bt.c")
elseif(CONFIG_IDF_TARGET_ESP32S3)
@@ -608,6 +610,8 @@ if(CONFIG_BT_ENABLED)
if(CONFIG_IDF_TARGET_ESP32)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-L${CMAKE_CURRENT_LIST_DIR}/controller/lib_esp32/esp32")
target_link_libraries(${COMPONENT_LIB} PUBLIC btdm_app)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u ld_include_hli_vectors_bt")
elseif(CONFIG_IDF_TARGET_ESP32C3)
target_link_libraries(${COMPONENT_LIB} INTERFACE
"-L${CMAKE_CURRENT_LIST_DIR}/controller/lib_esp32c3_family/esp32c3")

View File

@@ -10,6 +10,7 @@ COMPONENT_ADD_INCLUDEDIRS := include
LIBS := btdm_app
COMPONENT_ADD_LDFLAGS := -lbt -L $(COMPONENT_PATH)/controller/lib_esp32/esp32 \
-u ld_include_hli_vectors_bt \
$(addprefix -l,$(LIBS))
# re-link program if BT binary libs change

View File

@@ -40,6 +40,7 @@
#include "driver/periph_ctrl.h"
#include "soc/rtc.h"
#include "soc/soc_memory_layout.h"
#include "soc/dport_reg.h"
#include "esp32/clk.h"
#include "esp_coexist_internal.h"
#if !CONFIG_FREERTOS_UNICORE
@@ -47,6 +48,7 @@
#endif
#include "esp_rom_sys.h"
#include "hli_api.h"
#if CONFIG_BT_ENABLED
@@ -54,6 +56,7 @@
************************************************************************
*/
#define UNUSED(x) (void)(x)
#define BTDM_LOG_TAG "BTDM_INIT"
#define BTDM_INIT_PERIOD (5000) /* ms */
@@ -92,14 +95,9 @@ do{\
} while(0)
#define OSI_FUNCS_TIME_BLOCKING 0xffffffff
#define OSI_VERSION 0x00010002
#define OSI_VERSION 0x00010003
#define OSI_MAGIC_VALUE 0xFADEBEAD
/* SPIRAM Configuration */
#if CONFIG_SPIRAM_USE_MALLOC
#define BTDM_MAX_QUEUE_NUM (5)
#endif
/* Types definition
************************************************************************
*/
@@ -117,15 +115,6 @@ typedef struct {
intptr_t end;
} btdm_dram_available_region_t;
/* PSRAM configuration */
#if CONFIG_SPIRAM_USE_MALLOC
typedef struct {
QueueHandle_t handle;
void *storage;
void *buffer;
} btdm_queue_item_t;
#endif
/* OSI function */
struct osi_funcs_t {
uint32_t _version;
@@ -184,6 +173,10 @@ struct osi_funcs_t {
void *(* _coex_schm_curr_phase_get)(void);
int (* _coex_wifi_channel_get)(uint8_t *primary, uint8_t *secondary);
int (* _coex_register_wifi_channel_change_callback)(void *cb);
xt_handler (*_set_isr_l3)(int n, xt_handler f, void *arg);
void (*_interrupt_l3_disable)(void);
void (*_interrupt_l3_restore)(void);
void *(* _customer_queue_create)(uint32_t queue_len, uint32_t item_size);
uint32_t _magic;
};
@@ -264,12 +257,10 @@ extern uint32_t _btdm_data_end;
/* Local Function Declare
*********************************************************************
*/
#if CONFIG_SPIRAM_USE_MALLOC
static bool btdm_queue_generic_register(const btdm_queue_item_t *queue);
static bool btdm_queue_generic_deregister(btdm_queue_item_t *queue);
#endif /* CONFIG_SPIRAM_USE_MALLOC */
static void IRAM_ATTR interrupt_disable(void);
static void IRAM_ATTR interrupt_restore(void);
static xt_handler set_isr_hlevel_wrapper(int n, xt_handler f, void *arg);
static void IRAM_ATTR interrupt_hlevel_disable(void);
static void IRAM_ATTR interrupt_hlevel_restore(void);
static void IRAM_ATTR task_yield(void);
static void IRAM_ATTR task_yield_from_isr(void);
static void *semphr_create_wrapper(uint32_t max, uint32_t init);
static void semphr_delete_wrapper(void *semphr);
@@ -281,12 +272,12 @@ static void *mutex_create_wrapper(void);
static void mutex_delete_wrapper(void *mutex);
static int32_t mutex_lock_wrapper(void *mutex);
static int32_t mutex_unlock_wrapper(void *mutex);
static void *queue_create_wrapper(uint32_t queue_len, uint32_t item_size);
static void queue_delete_wrapper(void *queue);
static int32_t queue_send_wrapper(void *queue, void *item, uint32_t block_time_ms);
static int32_t IRAM_ATTR queue_send_from_isr_wrapper(void *queue, void *item, void *hptw);
static int32_t queue_recv_wrapper(void *queue, void *item, uint32_t block_time_ms);
static int32_t IRAM_ATTR queue_recv_from_isr_wrapper(void *queue, void *item, void *hptw);
static void *queue_create_hlevel_wrapper(uint32_t queue_len, uint32_t item_size);
static void queue_delete_hlevel_wrapper(void *queue);
static int32_t IRAM_ATTR queue_send_hlevel_wrapper(void *queue, void *item, uint32_t block_time_ms);
static int32_t IRAM_ATTR queue_send_from_isr_hlevel_wrapper(void *queue, void *item, void *hptw);
static int32_t IRAM_ATTR queue_recv_hlevel_wrapper(void *queue, void *item, uint32_t block_time_ms);
static int32_t IRAM_ATTR queue_recv_from_isr_hlevel_wrapper(void *queue, void *item, void *hptw);
static int32_t task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id);
static void task_delete_wrapper(void *task_handle);
static bool IRAM_ATTR is_in_isr_wrapper(void);
@@ -317,17 +308,21 @@ static uint8_t coex_schm_curr_period_get_wrapper(void);
static void * coex_schm_curr_phase_get_wrapper(void);
static int coex_wifi_channel_get_wrapper(uint8_t *primary, uint8_t *secondary);
static int coex_register_wifi_channel_change_callback_wrapper(void *cb);
static void *customer_queue_create_hlevel_wrapper(uint32_t queue_len, uint32_t item_size);
static void IRAM_ATTR interrupt_l3_disable(void);
static void IRAM_ATTR interrupt_l3_restore(void);
/* Local variable definition
***************************************************************************
*/
/* OSI funcs */
static const struct osi_funcs_t osi_funcs_ro = {
._version = OSI_VERSION,
._set_isr = xt_set_interrupt_handler,
._set_isr = set_isr_hlevel_wrapper,
._ints_on = xt_ints_on,
._interrupt_disable = interrupt_disable,
._interrupt_restore = interrupt_restore,
._task_yield = vPortYield,
._interrupt_disable = interrupt_hlevel_disable,
._interrupt_restore = interrupt_hlevel_restore,
._task_yield = task_yield,
._task_yield_from_isr = task_yield_from_isr,
._semphr_create = semphr_create_wrapper,
._semphr_delete = semphr_delete_wrapper,
@@ -339,12 +334,12 @@ static const struct osi_funcs_t osi_funcs_ro = {
._mutex_delete = mutex_delete_wrapper,
._mutex_lock = mutex_lock_wrapper,
._mutex_unlock = mutex_unlock_wrapper,
._queue_create = queue_create_wrapper,
._queue_delete = queue_delete_wrapper,
._queue_send = queue_send_wrapper,
._queue_send_from_isr = queue_send_from_isr_wrapper,
._queue_recv = queue_recv_wrapper,
._queue_recv_from_isr = queue_recv_from_isr_wrapper,
._queue_create = queue_create_hlevel_wrapper,
._queue_delete = queue_delete_hlevel_wrapper,
._queue_send = queue_send_hlevel_wrapper,
._queue_send_from_isr = queue_send_from_isr_hlevel_wrapper,
._queue_recv = queue_recv_hlevel_wrapper,
._queue_recv_from_isr = queue_recv_from_isr_hlevel_wrapper,
._task_create = task_create_wrapper,
._task_delete = task_delete_wrapper,
._is_in_isr = is_in_isr_wrapper,
@@ -378,6 +373,10 @@ static const struct osi_funcs_t osi_funcs_ro = {
._coex_schm_curr_phase_get = coex_schm_curr_phase_get_wrapper,
._coex_wifi_channel_get = coex_wifi_channel_get_wrapper,
._coex_register_wifi_channel_change_callback = coex_register_wifi_channel_change_callback_wrapper,
._set_isr_l3 = xt_set_interrupt_handler,
._interrupt_l3_disable = interrupt_l3_disable,
._interrupt_l3_restore = interrupt_l3_restore,
._customer_queue_create = customer_queue_create_hlevel_wrapper,
._magic = OSI_MAGIC_VALUE,
};
@@ -404,11 +403,6 @@ SOC_RESERVE_MEMORY_REGION(SOC_MEM_BT_DATA_START, SOC_MEM_BT_DATA_END,
static DRAM_ATTR struct osi_funcs_t *osi_funcs_p;
#if CONFIG_SPIRAM_USE_MALLOC
static DRAM_ATTR btdm_queue_item_t btdm_queue_table[BTDM_MAX_QUEUE_NUM];
static DRAM_ATTR SemaphoreHandle_t btdm_queue_table_mux = NULL;
#endif /* #if CONFIG_SPIRAM_USE_MALLOC */
/* Static variable declare */
// timestamp when PHY/RF was switched on
static DRAM_ATTR int64_t s_time_phy_rf_just_enabled = 0;
@@ -448,53 +442,45 @@ static inline void btdm_check_and_init_bb(void)
}
}
#if CONFIG_SPIRAM_USE_MALLOC
static bool btdm_queue_generic_register(const btdm_queue_item_t *queue)
struct interrupt_hlevel_cb{
uint32_t status;
uint8_t nested;
};
static DRAM_ATTR struct interrupt_hlevel_cb hli_cb = {
.status = 0,
.nested = 0,
};
static xt_handler set_isr_hlevel_wrapper(int mask, xt_handler f, void *arg)
{
if (!btdm_queue_table_mux || !queue) {
return NULL;
esp_err_t err = hli_intr_register((intr_handler_t) f, arg, DPORT_PRO_INTR_STATUS_0_REG, mask);
if (err == ESP_OK) {
return f;
} else {
return 0;
}
}
bool ret = false;
btdm_queue_item_t *item;
xSemaphoreTake(btdm_queue_table_mux, portMAX_DELAY);
for (int i = 0; i < BTDM_MAX_QUEUE_NUM; ++i) {
item = &btdm_queue_table[i];
if (item->handle == NULL) {
memcpy(item, queue, sizeof(btdm_queue_item_t));
ret = true;
break;
}
}
xSemaphoreGive(btdm_queue_table_mux);
return ret;
}
static bool btdm_queue_generic_deregister(btdm_queue_item_t *queue)
static void IRAM_ATTR interrupt_hlevel_disable(void)
{
if (!btdm_queue_table_mux || !queue) {
return false;
assert(xPortGetCoreID() == CONFIG_BTDM_CTRL_PINNED_TO_CORE);
uint32_t status = hli_intr_disable();
if (hli_cb.nested++ == 0) {
hli_cb.status = status;
}
}
bool ret = false;
btdm_queue_item_t *item;
xSemaphoreTake(btdm_queue_table_mux, portMAX_DELAY);
for (int i = 0; i < BTDM_MAX_QUEUE_NUM; ++i) {
item = &btdm_queue_table[i];
if (item->handle == queue->handle) {
memcpy(queue, item, sizeof(btdm_queue_item_t));
memset(item, 0, sizeof(btdm_queue_item_t));
ret = true;
break;
static void IRAM_ATTR interrupt_hlevel_restore(void)
{
assert(xPortGetCoreID() == CONFIG_BTDM_CTRL_PINNED_TO_CORE);
assert(hli_cb.nested > 0);
if (--hli_cb.nested == 0) {
hli_intr_restore(hli_cb.status);
}
}
xSemaphoreGive(btdm_queue_table_mux);
return ret;
}
#endif /* CONFIG_SPIRAM_USE_MALLOC */
static void IRAM_ATTR interrupt_disable(void)
static void IRAM_ATTR interrupt_l3_disable(void)
{
if (xPortInIsrContext()) {
portENTER_CRITICAL_ISR(&global_int_mux);
@@ -503,7 +489,7 @@ static void IRAM_ATTR interrupt_disable(void)
}
}
static void IRAM_ATTR interrupt_restore(void)
static void IRAM_ATTR interrupt_l3_restore(void)
{
if (xPortInIsrContext()) {
portEXIT_CRITICAL_ISR(&global_int_mux);
@@ -512,6 +498,12 @@ static void IRAM_ATTR interrupt_restore(void)
}
}
static void IRAM_ATTR task_yield(void)
{
vPortYield();
}
static void IRAM_ATTR task_yield_from_isr(void)
{
portYIELD_FROM_ISR();
@@ -519,148 +511,58 @@ static void IRAM_ATTR task_yield_from_isr(void)
static void *semphr_create_wrapper(uint32_t max, uint32_t init)
{
#if !CONFIG_SPIRAM_USE_MALLOC
return (void *)xSemaphoreCreateCounting(max, init);
#else
StaticQueue_t *queue_buffer = NULL;
QueueHandle_t handle = NULL;
queue_buffer = heap_caps_malloc(sizeof(StaticQueue_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
if (!queue_buffer) {
goto error;
}
handle = xSemaphoreCreateCountingStatic(max, init, queue_buffer);
if (!handle) {
goto error;
}
btdm_queue_item_t item = {
.handle = handle,
.storage = NULL,
.buffer = queue_buffer,
};
if (!btdm_queue_generic_register(&item)) {
goto error;
}
return handle;
error:
if (handle) {
vSemaphoreDelete(handle);
}
if (queue_buffer) {
free(queue_buffer);
}
return NULL;
#endif
SemaphoreHandle_t downstream_semaphore = xSemaphoreCreateCounting(max, init);
assert(downstream_semaphore);
hli_queue_handle_t s_semaphore = hli_semaphore_create(max, downstream_semaphore);
assert(downstream_semaphore);
return s_semaphore;
}
static void semphr_delete_wrapper(void *semphr)
{
#if !CONFIG_SPIRAM_USE_MALLOC
vSemaphoreDelete(semphr);
#else
btdm_queue_item_t item = {
.handle = semphr,
.storage = NULL,
.buffer = NULL,
};
if (btdm_queue_generic_deregister(&item)) {
vSemaphoreDelete(item.handle);
free(item.buffer);
if (((hli_queue_handle_t)semphr)->downstream != NULL) {
vSemaphoreDelete(((hli_queue_handle_t)semphr)->downstream);
}
return;
#endif
hli_queue_delete(semphr);
}
static int32_t IRAM_ATTR semphr_take_from_isr_wrapper(void *semphr, void *hptw)
{
return (int32_t)xSemaphoreTakeFromISR(semphr, hptw);
return (int32_t)xSemaphoreTakeFromISR(((hli_queue_handle_t)semphr)->downstream, hptw);
}
static int32_t IRAM_ATTR semphr_give_from_isr_wrapper(void *semphr, void *hptw)
{
return (int32_t)xSemaphoreGiveFromISR(semphr, hptw);
UNUSED(hptw);
assert(xPortGetCoreID() == CONFIG_BTDM_CTRL_PINNED_TO_CORE);
return hli_semaphore_give(semphr);
}
static int32_t semphr_take_wrapper(void *semphr, uint32_t block_time_ms)
{
bool ret;
if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
return (int32_t)xSemaphoreTake(semphr, portMAX_DELAY);
ret = xSemaphoreTake(((hli_queue_handle_t)semphr)->downstream, portMAX_DELAY);
} else {
return (int32_t)xSemaphoreTake(semphr, block_time_ms / portTICK_PERIOD_MS);
ret = xSemaphoreTake(((hli_queue_handle_t)semphr)->downstream, block_time_ms / portTICK_PERIOD_MS);
}
return (int32_t)ret;
}
static int32_t semphr_give_wrapper(void *semphr)
{
return (int32_t)xSemaphoreGive(semphr);
return (int32_t)xSemaphoreGive(((hli_queue_handle_t)semphr)->downstream);
}
static void *mutex_create_wrapper(void)
{
#if CONFIG_SPIRAM_USE_MALLOC
StaticQueue_t *queue_buffer = NULL;
QueueHandle_t handle = NULL;
queue_buffer = heap_caps_malloc(sizeof(StaticQueue_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
if (!queue_buffer) {
goto error;
}
handle = xSemaphoreCreateMutexStatic(queue_buffer);
if (!handle) {
goto error;
}
btdm_queue_item_t item = {
.handle = handle,
.storage = NULL,
.buffer = queue_buffer,
};
if (!btdm_queue_generic_register(&item)) {
goto error;
}
return handle;
error:
if (handle) {
vSemaphoreDelete(handle);
}
if (queue_buffer) {
free(queue_buffer);
}
return NULL;
#else
return (void *)xSemaphoreCreateMutex();
#endif
}
static void mutex_delete_wrapper(void *mutex)
{
#if !CONFIG_SPIRAM_USE_MALLOC
vSemaphoreDelete(mutex);
#else
btdm_queue_item_t item = {
.handle = mutex,
.storage = NULL,
.buffer = NULL,
};
if (btdm_queue_generic_deregister(&item)) {
vSemaphoreDelete(item.handle);
free(item.buffer);
}
return;
#endif
}
static int32_t mutex_lock_wrapper(void *mutex)
@@ -673,104 +575,74 @@ static int32_t mutex_unlock_wrapper(void *mutex)
return (int32_t)xSemaphoreGive(mutex);
}
static void *queue_create_wrapper(uint32_t queue_len, uint32_t item_size)
static void *queue_create_hlevel_wrapper(uint32_t queue_len, uint32_t item_size)
{
#if CONFIG_SPIRAM_USE_MALLOC
StaticQueue_t *queue_buffer = NULL;
uint8_t *queue_storage = NULL;
QueueHandle_t handle = NULL;
queue_buffer = heap_caps_malloc(sizeof(StaticQueue_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
if (!queue_buffer) {
goto error;
QueueHandle_t downstream_queue = xQueueCreate(queue_len, item_size);
assert(downstream_queue);
hli_queue_handle_t queue = hli_queue_create(queue_len, item_size, downstream_queue);
assert(queue);
return queue;
}
queue_storage = heap_caps_malloc((queue_len*item_size), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
if (!queue_storage ) {
goto error;
}
handle = xQueueCreateStatic(queue_len, item_size, queue_storage, queue_buffer);
if (!handle) {
goto error;
}
btdm_queue_item_t item = {
.handle = handle,
.storage = queue_storage,
.buffer = queue_buffer,
};
if (!btdm_queue_generic_register(&item)) {
goto error;
}
return handle;
error:
if (handle) {
vQueueDelete(handle);
}
if (queue_storage) {
free(queue_storage);
}
if (queue_buffer) {
free(queue_buffer);
}
return NULL;
#else
return (void *)xQueueCreate(queue_len, item_size);
#endif
}
static void queue_delete_wrapper(void *queue)
static void *customer_queue_create_hlevel_wrapper(uint32_t queue_len, uint32_t item_size)
{
#if !CONFIG_SPIRAM_USE_MALLOC
vQueueDelete(queue);
#else
btdm_queue_item_t item = {
.handle = queue,
.storage = NULL,
.buffer = NULL,
};
if (btdm_queue_generic_deregister(&item)) {
vQueueDelete(item.handle);
free(item.storage);
free(item.buffer);
QueueHandle_t downstream_queue = xQueueCreate(queue_len, item_size);
assert(downstream_queue);
hli_queue_handle_t queue = hli_customer_queue_create(queue_len, item_size, downstream_queue);
assert(queue);
return queue;
}
return;
#endif
static void queue_delete_hlevel_wrapper(void *queue)
{
if (((hli_queue_handle_t)queue)->downstream != NULL) {
vQueueDelete(((hli_queue_handle_t)queue)->downstream);
}
hli_queue_delete(queue);
}
static int32_t queue_send_wrapper(void *queue, void *item, uint32_t block_time_ms)
static int32_t queue_send_hlevel_wrapper(void *queue, void *item, uint32_t block_time_ms)
{
if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
return (int32_t)xQueueSend(queue, item, portMAX_DELAY);
return (int32_t)xQueueSend(((hli_queue_handle_t)queue)->downstream, item, portMAX_DELAY);
} else {
return (int32_t)xQueueSend(queue, item, block_time_ms / portTICK_PERIOD_MS);
return (int32_t)xQueueSend(((hli_queue_handle_t)queue)->downstream, item, block_time_ms / portTICK_PERIOD_MS);
}
}
static int32_t IRAM_ATTR queue_send_from_isr_wrapper(void *queue, void *item, void *hptw)
/**
* Queue send from isr
* @param queue The queue which will send to
* @param item The message which will be send
* @param hptw need do task yield or not
* @return send success or not
* There is an issue here: When the queue is full, it may reture true but it send fail to the queue, sometimes.
* But in Bluetooth controller's isr, We don't care about the return value.
* It only required tp send success when the queue is empty all the time.
* So, this function meets the requirement.
*/
static int32_t IRAM_ATTR queue_send_from_isr_hlevel_wrapper(void *queue, void *item, void *hptw)
{
return (int32_t)xQueueSendFromISR(queue, item, hptw);
UNUSED(hptw);
assert(xPortGetCoreID() == CONFIG_BTDM_CTRL_PINNED_TO_CORE);
return hli_queue_put(queue, item);
}
static int32_t queue_recv_wrapper(void *queue, void *item, uint32_t block_time_ms)
static int32_t queue_recv_hlevel_wrapper(void *queue, void *item, uint32_t block_time_ms)
{
bool ret;
if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
return (int32_t)xQueueReceive(queue, item, portMAX_DELAY);
ret = (int32_t)xQueueReceive(((hli_queue_handle_t)queue)->downstream, item, portMAX_DELAY);
} else {
return (int32_t)xQueueReceive(queue, item, block_time_ms / portTICK_PERIOD_MS);
}
ret =(int32_t)xQueueReceive(((hli_queue_handle_t)queue)->downstream, item, block_time_ms / portTICK_PERIOD_MS);
}
static int32_t IRAM_ATTR queue_recv_from_isr_wrapper(void *queue, void *item, void *hptw)
return ret;
}
static int32_t IRAM_ATTR queue_recv_from_isr_hlevel_wrapper(void *queue, void *item, void *hptw)
{
return (int32_t)xQueueReceiveFromISR(queue, item, hptw);
return (int32_t)xQueueReceiveFromISR(((hli_queue_handle_t)queue)->downstream, item, hptw);
}
static int32_t task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id)
@@ -1317,11 +1189,31 @@ esp_err_t esp_bt_mem_release(esp_bt_mode_t mode)
return ESP_OK;
}
static void hli_queue_setup_cb(void* arg)
{
hli_queue_setup();
}
static void hli_queue_setup_pinned_to_core(int core_id)
{
#if CONFIG_FREERTOS_UNICORE
hli_queue_setup_cb(NULL);
#else /* CONFIG_FREERTOS_UNICORE */
if (xPortGetCoreID() == core_id) {
hli_queue_setup_cb(NULL);
} else {
esp_ipc_call(core_id, hli_queue_setup_cb, NULL);
}
#endif /* !CONFIG_FREERTOS_UNICORE */
}
esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
{
esp_err_t err;
uint32_t btdm_cfg_mask = 0;
hli_queue_setup_pinned_to_core(CONFIG_BTDM_CTRL_PINNED_TO_CORE);
//if all the bt available memory was already released, cannot initialize bluetooth controller
if (btdm_dram_available_region[0].mode == ESP_BT_MODE_IDLE) {
return ESP_ERR_INVALID_STATE;
@@ -1362,14 +1254,6 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
ESP_LOGI(BTDM_LOG_TAG, "BT controller compile version [%s]", btdm_controller_get_compile_version());
#if CONFIG_SPIRAM_USE_MALLOC
btdm_queue_table_mux = xSemaphoreCreateMutex();
if (btdm_queue_table_mux == NULL) {
return ESP_ERR_NO_MEM;
}
memset(btdm_queue_table, 0, sizeof(btdm_queue_item_t) * BTDM_MAX_QUEUE_NUM);
#endif
s_wakeup_req_sem = semphr_create_wrapper(1, 0);
if (s_wakeup_req_sem == NULL) {
err = ESP_ERR_NO_MEM;
@@ -1515,12 +1399,6 @@ esp_err_t esp_bt_controller_deinit(void)
semphr_delete_wrapper(s_wakeup_req_sem);
s_wakeup_req_sem = NULL;
#if CONFIG_SPIRAM_USE_MALLOC
vSemaphoreDelete(btdm_queue_table_mux);
btdm_queue_table_mux = NULL;
memset(btdm_queue_table, 0, sizeof(btdm_queue_item_t) * BTDM_MAX_QUEUE_NUM);
#endif
free(osi_funcs_p);
osi_funcs_p = NULL;
@@ -1736,4 +1614,15 @@ esp_err_t esp_ble_scan_dupilcate_list_flush(void)
return ESP_OK;
}
/**
* This function re-write controller's function,
* As coredump can not show paramerters in function which is in a .a file.
*
* After coredump fixing this issue, just delete this function.
*/
void IRAM_ATTR r_assert(const char *condition, int param0, int param1, const char *file, int line)
{
__asm__ __volatile__("ill\n");
}
#endif /* CONFIG_BT_ENABLED */

View File

@@ -0,0 +1,294 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
// All rights reserved.
#include <string.h>
#include "esp_log.h"
#include "esp_heap_caps.h"
#include "xtensa/core-macros.h"
#include "soc/dport_reg.h"
#include "hli_api.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#define HLI_MAX_HANDLERS 4
typedef struct {
intr_handler_t handler;
void* arg;
uint32_t intr_reg;
uint32_t intr_mask;
} hli_handler_info_t;
typedef struct {
#define CUSTOMER_TYPE_REQUEST (0)
#define CUSTOMER_TYPE_RELEASE (1)
struct {
uint32_t cb_type;
union {
int (* request)(uint32_t, uint32_t, uint32_t);
int (* release)(uint32_t);
} cb;
} customer_cb;
uint32_t arg0, arg1, arg2;
} customer_swisr_t;
static void IRAM_ATTR customer_swisr_handle(customer_swisr_t *cus_swisr)
{
if (cus_swisr->customer_cb.cb_type == CUSTOMER_TYPE_REQUEST) {
if (cus_swisr->customer_cb.cb.request != NULL) {
cus_swisr->customer_cb.cb.request(cus_swisr->arg0, cus_swisr->arg1, cus_swisr->arg2);
}
} else if(cus_swisr->customer_cb.cb_type == CUSTOMER_TYPE_RELEASE) {
if (cus_swisr->customer_cb.cb.release != NULL) {
cus_swisr->customer_cb.cb.release(cus_swisr->arg0);
}
}
}
static DRAM_ATTR hli_handler_info_t s_hli_handlers[HLI_MAX_HANDLERS];
// static const char* TAG = "hli_queue";
esp_err_t hli_intr_register(intr_handler_t handler, void* arg, uint32_t intr_reg, uint32_t intr_mask)
{
for (hli_handler_info_t* hip = s_hli_handlers;
hip < s_hli_handlers + HLI_MAX_HANDLERS;
++hip) {
if (hip->handler == NULL) {
hip->arg = arg;
hip->intr_reg = intr_reg;
hip->intr_mask = intr_mask;
hip->handler = handler; /* set last, indicates the entry as valid */
return ESP_OK;
}
}
return ESP_ERR_NO_MEM;
}
void IRAM_ATTR hli_c_handler(void)
{
bool handled = false;
/* Iterate over registered interrupt handlers,
* and check if the expected mask is present in the interrupt status register.
*/
for (hli_handler_info_t* hip = s_hli_handlers;
hip < s_hli_handlers + HLI_MAX_HANDLERS;
++hip) {
if (hip->handler == NULL) {
continue;
}
uint32_t reg = hip->intr_reg;
uint32_t val;
if (reg == 0) { /* special case for CPU internal interrupts */
val = XTHAL_GET_INTERRUPT();
} else {
/* "reg" might not be in DPORT, but this will work in any case */
val = DPORT_REG_READ(reg);
}
if ((val & hip->intr_mask) != 0) {
handled = true;
(*hip->handler)(hip->arg);
}
}
if (!handled) {
// esp_rom_printf(DRAM_STR("hli_c_handler: no handler found!\n"));
// abort();
}
}
uint32_t IRAM_ATTR hli_intr_disable(void)
{
// disable level 4 and below
return XTOS_SET_INTLEVEL(XCHAL_DEBUGLEVEL - 2);
}
void IRAM_ATTR hli_intr_restore(uint32_t state)
{
XTOS_RESTORE_JUST_INTLEVEL(state);
}
#define HLI_META_QUEUE_SIZE 16
#define HLI_QUEUE_MAX_ELEM_SIZE 32
#define HLI_QUEUE_SW_INT_NUM 29
#define HLI_QUEUE_FLAG_SEMAPHORE BIT(0)
#define HLI_QUEUE_FLAG_CUSTOMER BIT(1)
static DRAM_ATTR struct hli_queue_t *s_meta_queue_ptr = NULL;
intr_handle_t ret_handle;
static inline char* IRAM_ATTR wrap_ptr(hli_queue_handle_t queue, char *ptr)
{
return (ptr == queue->bufend) ? queue->buf : ptr;
}
static inline bool IRAM_ATTR queue_empty(hli_queue_handle_t queue)
{
return queue->begin == queue->end;
}
static inline bool IRAM_ATTR queue_full(hli_queue_handle_t queue)
{
return wrap_ptr(queue, queue->end + queue->elem_size) == queue->begin;
}
static void IRAM_ATTR queue_isr_handler(void* arg)
{
int do_yield = pdFALSE;
XTHAL_SET_INTCLEAR(BIT(HLI_QUEUE_SW_INT_NUM));
hli_queue_handle_t queue;
while (hli_queue_get(s_meta_queue_ptr, &queue)) {
static DRAM_ATTR char scratch[HLI_QUEUE_MAX_ELEM_SIZE];
while (hli_queue_get(queue, scratch)) {
int res = pdPASS;
if ((queue->flags & HLI_QUEUE_FLAG_CUSTOMER) != 0) {
customer_swisr_handle((customer_swisr_t *)scratch);
} else if ((queue->flags & HLI_QUEUE_FLAG_SEMAPHORE) != 0) {
res = xSemaphoreGiveFromISR((SemaphoreHandle_t) queue->downstream, &do_yield);
} else {
res = xQueueSendFromISR(queue->downstream, scratch, &do_yield);
}
if (res == pdFAIL) {
// ESP_EARLY_LOGE(TAG, "Failed to send to %s %p", (queue->flags & HLI_QUEUE_FLAG_SEMAPHORE) == 0 ? "queue" : "semaphore", queue->downstream);
}
}
}
if (do_yield) {
portYIELD_FROM_ISR();
}
}
/* Notify the level 3 handler that an element is added to the given hli queue.
* Do this by placing the queue handle onto s_meta_queue, and raising a SW interrupt.
*
* This function must be called with HL interrupts disabled!
*/
static void IRAM_ATTR queue_signal(hli_queue_handle_t queue)
{
/* See if the queue is already in s_meta_queue, before adding */
bool found = false;
const hli_queue_handle_t *end = (hli_queue_handle_t*) s_meta_queue_ptr->end;
hli_queue_handle_t *item = (hli_queue_handle_t*) s_meta_queue_ptr->begin;
for (;item != end; item = (hli_queue_handle_t*) wrap_ptr(s_meta_queue_ptr, (char*) (item + 1))) {
if (*item == queue) {
found = true;
break;
}
}
if (!found) {
bool res = hli_queue_put(s_meta_queue_ptr, &queue);
if (!res) {
esp_rom_printf(DRAM_STR("Fatal error in queue_signal: s_meta_queue full\n"));
abort();
}
XTHAL_SET_INTSET(BIT(HLI_QUEUE_SW_INT_NUM));
}
}
static void queue_init(hli_queue_handle_t queue, size_t buf_size, size_t elem_size, QueueHandle_t downstream)
{
queue->elem_size = elem_size;
queue->begin = queue->buf;
queue->end = queue->buf;
queue->bufend = queue->buf + buf_size;
queue->downstream = downstream;
queue->flags = 0;
}
void hli_queue_setup(void)
{
if (s_meta_queue_ptr == NULL) {
s_meta_queue_ptr = hli_queue_create(HLI_META_QUEUE_SIZE, sizeof(void*), NULL);
ESP_ERROR_CHECK(esp_intr_alloc(ETS_INTERNAL_SW1_INTR_SOURCE, ESP_INTR_FLAG_IRAM, queue_isr_handler, NULL, &ret_handle));
xt_ints_on(BIT(HLI_QUEUE_SW_INT_NUM));
}
}
void hli_queue_shutdown(void)
{
if (s_meta_queue_ptr != NULL) {
hli_queue_delete(s_meta_queue_ptr);
s_meta_queue_ptr = NULL;
esp_intr_free(ret_handle);
xt_ints_off(BIT(HLI_QUEUE_SW_INT_NUM));
}
}
hli_queue_handle_t hli_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream)
{
const size_t buf_elem = nelem + 1;
if (elem_size > HLI_QUEUE_MAX_ELEM_SIZE) {
return NULL;
}
size_t buf_size = buf_elem * elem_size;
hli_queue_handle_t res = (hli_queue_handle_t) heap_caps_malloc(sizeof(*res) + buf_size,
MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
if (res == NULL) {
return NULL;
}
queue_init(res, buf_size, elem_size, downstream);
return res;
}
hli_queue_handle_t hli_customer_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream)
{
hli_queue_handle_t res = hli_queue_create(nelem, elem_size, (QueueHandle_t) downstream);
if (res == NULL) {
return NULL;
}
res->flags |= HLI_QUEUE_FLAG_CUSTOMER;
return res;
}
hli_queue_handle_t hli_semaphore_create(size_t max_count, SemaphoreHandle_t downstream)
{
const size_t elem_size = 1;
hli_queue_handle_t res = hli_queue_create(max_count, elem_size, (QueueHandle_t) downstream);
if (res == NULL) {
return NULL;
}
res->flags |= HLI_QUEUE_FLAG_SEMAPHORE;
return res;
}
void hli_queue_delete(hli_queue_handle_t queue)
{
free(queue);
}
bool IRAM_ATTR hli_queue_get(hli_queue_handle_t queue, void* out)
{
uint32_t int_state = hli_intr_disable();
bool res = false;
if (!queue_empty(queue)) {
memcpy(out, queue->begin, queue->elem_size);
queue->begin = wrap_ptr(queue, queue->begin + queue->elem_size);
res = true;
}
hli_intr_restore(int_state);
return res;
}
bool IRAM_ATTR hli_queue_put(hli_queue_handle_t queue, const void* data)
{
uint32_t int_state = hli_intr_disable();
bool res = false;
bool was_empty = queue_empty(queue);
if (!queue_full(queue)) {
memcpy(queue->end, data, queue->elem_size);
queue->end = wrap_ptr(queue, queue->end + queue->elem_size);
if (was_empty && queue != s_meta_queue_ptr) {
queue_signal(queue);
}
res = true;
}
hli_intr_restore(int_state);
return res;
}
bool IRAM_ATTR hli_semaphore_give(hli_queue_handle_t queue)
{
uint8_t data = 0;
return hli_queue_put(queue, &data);
}

View File

@@ -0,0 +1,160 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
// All rights reserved.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "esp_err.h"
#include "esp_intr_alloc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
/*** Queues ***/
struct hli_queue_t
{
size_t elem_size;
char* begin;
char* end;
const char* bufend;
QueueHandle_t downstream;
int flags;
char buf[0];
};
/**
* @brief Register a high level interrupt function
*
* @param handler interrupt handler function
* @param arg argument to pass to the interrupt handler
* @param intr_reg address of the peripheral register containing the interrupt status,
* or value 0 to get the status from CPU INTERRUPT register
* @param intr_mask mask of the interrupt, in the interrupt status register
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM if too many handlers are registered
*/
esp_err_t hli_intr_register(intr_handler_t handler, void* arg, uint32_t intr_reg, uint32_t intr_mask);
/**
* @brief Mask all interrupts (including high level ones) on the current CPU
*
* @return uint32_t interrupt status, pass it to hli_intr_restore
*/
uint32_t hli_intr_disable(void);
/**
* @brief Re-enable interrupts
*
* @param state value returned by hli_intr_disable
*/
void hli_intr_restore(uint32_t state);
/**
* @brief Type of a hli queue
*/
typedef struct hli_queue_t* hli_queue_handle_t;
/**
* @brief Initialize hli_queue module. Must be called once before using hli queue APIs.
*/
void hli_queue_setup(void);
/**
* @brief Shutdown hli_queue module.
*/
void hli_queue_shutdown(void);
/**
* @brief Create a hli queue, wrapping a FreeRTOS queue
*
* This queue can be used from high level interrupts,
* but **ONLY ON THE CPU WHERE hli_queue_setup WAS CALLED**. Values sent to this
* queue are automatically forwarded to "downstream" FreeRTOS queue using a level 3
* software interrupt.
*
* @param nelem number of elements in the queue
* @param elem_size size of one element; must match element size of a downstream queue
* @param downstream FreeRTOS queue to send the values to
* @return hli_queue_handle_t handle of the created queue, or NULL on failure
*/
hli_queue_handle_t hli_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream);
/**
* @brief Create a customer hli queue, wrapping a FreeRTOS queue
*
* This queue can be used from high level interrupts,
* but **ONLY ON THE CPU WHERE hli_queue_setup WAS CALLED**. Values sent to this
* queue are automatically forwarded to "downstream" FreeRTOS queue using a level 3
* software interrupt.
*
* @param nelem number of elements in the queue
* @param elem_size size of one element; must match element size of a downstream queue
* @param downstream FreeRTOS queue to send the values to
* @return hli_queue_handle_t handle of the created queue, or NULL on failure
*/
hli_queue_handle_t hli_customer_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream);
/**
* @brief Create a hli queue, wrapping a FreeRTOS semaphore
*
* See notes on hli_queue_create.
*
* @param max_count maximum semaphore count
* @param downstream FreeRTOS semaphore to forward the calls to
* @return hli_queue_handle_t handle of the created queue, or NULL on failure
*/
hli_queue_handle_t hli_semaphore_create(size_t max_count, SemaphoreHandle_t downstream);
/**
* @brief Delete a hli queue
*
* Make sure noone is using the queue before deleting it.
*
* @param queue handle returned by hli_queue_create or hli_semaphore_create
*/
void hli_queue_delete(hli_queue_handle_t queue);
/**
* @brief Get one element from a hli queue
*
* Usually not used, values get sent to a downstream FreeRTOS queue automatically.
* However if downstream queue is NULL, this API can be used to get values from a hli queue.
*
* @param queue handle of a queue
* @param out pointer where to store the element
* @return true if the element was successfully read from the queue
*/
bool hli_queue_get(hli_queue_handle_t queue, void* out);
/**
* @brief Put one element into a hli queue
*
* This puts copies an element into the queue and raises a software interrupt (level 3).
* In the interrupt, the value is copied to a FreeRTOS "downstream" queue.
*
* Note that if the value does not fit into a downstream queue, no error is returned,
* and the value is lost.
*
* @param queue handle of a queue
* @param data pointer to the element to be sent
* @return true if data was placed into the hli queue successfully
*/
bool hli_queue_put(hli_queue_handle_t queue, const void* data);
/**
* @brief "Give" a semaphore wrapped by a hli queue
*
* @param queue handle returned by hli_semaphore_create
* @return true if the event was sent to a hli queue successfully
*/
bool hli_semaphore_give(hli_queue_handle_t queue);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,225 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
// All rights reserved.
#include <xtensa/coreasm.h>
#include <xtensa/corebits.h>
#include <xtensa/config/system.h>
#include "freertos/xtensa_context.h"
#include "sdkconfig.h"
#include "soc/soc.h"
/* Interrupt stack size, for C code.
* TODO: reduce and make configurable.
*/
#define L4_INTR_STACK_SIZE 4096
/* Save area for the CPU state:
* - 64 words for the general purpose registers
* - 7 words for some of the special registers:
* - WINDOWBASE, WINDOWSTART only WINDOWSTART is truly needed
* - SAR, LBEG, LEND, LCOUNT since the C code might use these
* - EPC1 since the C code might cause window overflow exceptions
* This is not laid out a standard exception frame structure
* for simplicity of the save/restore code.
*/
#define REG_FILE_SIZE (64 * 4)
#define SPECREG_OFFSET REG_FILE_SIZE
#define SPECREG_SIZE (7 * 4)
#define REG_SAVE_AREA_SIZE (SPECREG_OFFSET * SPECREG_SIZE)
.data
_l4_intr_stack:
.space L4_INTR_STACK_SIZE
_l4_save_ctx:
.space REG_SAVE_AREA_SIZE
.section .iram1,"ax"
.global xt_highint4
.type xt_highint4,@function
.align 4
xt_highint4:
movi a0, _l4_save_ctx
/* save 4 lower registers */
s32i a1, a0, 4
s32i a2, a0, 8
s32i a3, a0, 12
rsr a2, EXCSAVE_4 /* holds the value of a0 */
s32i a2, a0, 0
/* Save special registers */
addi a0, a0, SPECREG_OFFSET
rsr a2, WINDOWBASE
s32i a2, a0, 0
rsr a2, WINDOWSTART
s32i a2, a0, 4
rsr a2, SAR
s32i a2, a0, 8
rsr a2, LBEG
s32i a2, a0, 12
rsr a2, LEND
s32i a2, a0, 16
rsr a2, LCOUNT
s32i a2, a0, 20
rsr a2, EPC1
s32i a2, a0, 24
/* disable exception mode, window overflow */
movi a0, PS_INTLEVEL(5) | PS_EXCM /*TOCHECK*/
wsr a0, PS
rsync
/* Save the remaining physical registers.
* 4 registers are already saved, which leaves 60 registers to save.
* (FIXME: consider the case when the CPU is configured with physical 32 registers)
* These 60 registers are saved in 5 iterations, 12 registers at a time.
*/
movi a1, 5
movi a3, _l4_save_ctx + 4 * 4
/* This is repeated 5 times, each time the window is shifted by 12 registers.
* We come here with a1 = downcounter, a3 = save pointer, a2 and a0 unused.
*/
1:
s32i a4, a3, 0
s32i a5, a3, 4
s32i a6, a3, 8
s32i a7, a3, 12
s32i a8, a3, 16
s32i a9, a3, 20
s32i a10, a3, 24
s32i a11, a3, 28
s32i a12, a3, 32
s32i a13, a3, 36
s32i a14, a3, 40
s32i a15, a3, 44
/* We are about to rotate the window, so that a12-a15 will become the new a0-a3.
* Copy a0-a3 to a12-15 to still have access to these values.
* At the same time we can decrement the counter and adjust the save area pointer
*/
/* a0 is constant (_l4_save_ctx), no need to copy */
addi a13, a1, -1 /* copy and decrement the downcounter */
/* a2 is scratch so no need to copy */
addi a15, a3, 48 /* copy and adjust the save area pointer */
beqz a13, 2f /* have saved all registers ? */
rotw 3 /* rotate the window and go back */
j 1b
/* the loop is complete */
2:
rotw 4 /* this brings us back to the original window */
/* a0 still points to _l4_save_ctx */
/* Can clear WINDOWSTART now, all registers are saved */
rsr a2, WINDOWBASE
/* WINDOWSTART = (1 << WINDOWBASE) */
movi a3, 1
ssl a2
sll a3, a3
wsr a3, WINDOWSTART
_highint4_stack_switch:
movi a0, 0
movi sp, _l4_intr_stack + L4_INTR_STACK_SIZE - 16
s32e a0, sp, -12 /* For GDB: set null SP */
s32e a0, sp, -16 /* For GDB: set null PC */
movi a0, _highint4_stack_switch /* For GDB: cosmetics, for the frame where stack switch happened */
/* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
movi a6, PS_INTLEVEL(4) | PS_UM | PS_WOE
wsr a6, PS
rsync
/* Call C handler */
mov a6, sp
call4 hli_c_handler
l32e sp, sp, -12 /* switch back to the original stack */
/* Done with C handler; re-enable exception mode, disabling window overflow */
movi a2, PS_INTLEVEL(5) | PS_EXCM /* TOCHECK */
wsr a2, PS
rsync
/* Restore the special registers.
* WINDOWSTART will be restored near the end.
*/
movi a0, _l4_save_ctx + SPECREG_OFFSET
l32i a2, a0, 8
wsr a2, SAR
l32i a2, a0, 12
wsr a2, LBEG
l32i a2, a0, 16
wsr a2, LEND
l32i a2, a0, 20
wsr a2, LCOUNT
l32i a2, a0, 24
wsr a2, EPC1
/* Restoring the physical registers.
* This is the reverse to the saving process above.
*/
/* Rotate back to the final window, then start loading 12 registers at a time,
* in 5 iterations.
* Again, a1 is the downcounter and a3 is the save area pointer.
* After each rotation, a1 and a3 are copied from a13 and a15.
* To simplify the loop, we put the initial values into a13 and a15.
*/
rotw -4
movi a15, _l4_save_ctx + 64 * 4 /* point to the end of the save area */
movi a13, 5
1:
/* Copy a1 and a3 from their previous location,
* at the same time decrementing and adjusting the save area pointer.
*/
addi a1, a13, -1
addi a3, a15, -48
/* Load 12 registers */
l32i a4, a3, 0
l32i a5, a3, 4
l32i a6, a3, 8
l32i a7, a3, 12
l32i a8, a3, 16
l32i a9, a3, 20
l32i a10, a3, 24
l32i a11, a3, 28 /* ensure PS and EPC written */
l32i a12, a3, 32
l32i a13, a3, 36
l32i a14, a3, 40
l32i a15, a3, 44
/* Done with the loop? */
beqz a1, 2f
/* If no, rotate the window and repeat */
rotw -3
j 1b
2:
/* Done with the loop. Only 4 registers (a0-a3 in the original window) remain
* to be restored. Also need to restore WINDOWSTART, since all the general
* registers are now in place.
*/
movi a0, _l4_save_ctx
l32i a2, a0, SPECREG_OFFSET + 4
wsr a2, WINDOWSTART
l32i a1, a0, 4
l32i a2, a0, 8
l32i a3, a0, 12
rsr a0, EXCSAVE_4 /* holds the value of a0 before the interrupt handler */
/* Return from the interrupt, restoring PS from EPS_4 */
rfi 4
/* The linker has no reason to link in this file; all symbols it exports are already defined
(weakly!) in the default int handler. Define a symbol here so we can use it to have the
linker inspect this anyway. */
.global ld_include_hli_vectors_bt
ld_include_hli_vectors_bt:

View File

@@ -15,14 +15,14 @@
/* High-priority interrupt - IPC_ISR handler */
#define L4_INTR_STACK_SIZE 16
#define L4_INTR_A0_OFFSET 0
#define L4_INTR_A2_OFFSET 4
#define L4_INTR_A3_OFFSET 8
#define L4_INTR_A4_OFFSET 12
#define L5_INTR_STACK_SIZE 16
#define L5_INTR_A0_OFFSET 0
#define L5_INTR_A2_OFFSET 4
#define L5_INTR_A3_OFFSET 8
#define L5_INTR_A4_OFFSET 12
.data
_l4_intr_stack:
.space L4_INTR_STACK_SIZE
_l5_intr_stack:
.space L5_INTR_STACK_SIZE
.section .iram1,"ax"
.global esp_ipc_isr_handler
.type esp_ipc_isr_handler,@function
@@ -32,15 +32,15 @@ esp_ipc_isr_handler:
/* Because the interrupt cause code has protection that only
allows one cpu to enter in the IPC_ISR section of the L4
interrupt at one time, there's no need to have two
_l4_intr_stack for each cpu */
_l5_intr_stack for each cpu */
/* Save A0, A2, A3, A4 so we can use those registers further*/
movi a0, _l4_intr_stack
s32i a2, a0, L4_INTR_A2_OFFSET
s32i a3, a0, L4_INTR_A3_OFFSET
s32i a4, a0, L4_INTR_A4_OFFSET
rsr a2, EXCSAVE_4
s32i a2, a0, L4_INTR_A0_OFFSET
movi a0, _l5_intr_stack
s32i a2, a0, L5_INTR_A2_OFFSET
s32i a3, a0, L5_INTR_A3_OFFSET
s32i a4, a0, L5_INTR_A4_OFFSET
rsr a2, EXCSAVE_5
s32i a2, a0, L5_INTR_A0_OFFSET
/* disable nested iterrupts */
/* PS.EXCM is changed from 1 to 0 . It allows using usually exception handler instead of the Double exception handler. */
@@ -85,16 +85,16 @@ esp_ipc_isr_handler:
callx0 a0
/* Done. Restore registers and return. */
movi a0, _l4_intr_stack
l32i a2, a0, L4_INTR_A2_OFFSET
l32i a3, a0, L4_INTR_A3_OFFSET
l32i a4, a0, L4_INTR_A4_OFFSET
movi a0, _l5_intr_stack
l32i a2, a0, L5_INTR_A2_OFFSET
l32i a3, a0, L5_INTR_A3_OFFSET
l32i a4, a0, L5_INTR_A4_OFFSET
/* set the end flag */
movi a0, esp_ipc_isr_end_fl
s32i a0, a0, 0
/* restore a0 */
rsr a0, EXCSAVE_4
/* restores PS from EPS[4] and jumps to the address in EPC[4] */
rfi 4
rsr a0, EXCSAVE_5
/* restores PS from EPS[5] and jumps to the address in EPC[5] */
rfi 5

View File

@@ -51,7 +51,7 @@ static wdt_hal_context_t iwdt_context;
*/
#define IWDT_LIVELOCK_TIMEOUT_MS (20)
extern uint32_t _l4_intr_livelock_counter, _l4_intr_livelock_max;
extern uint32_t _l5_intr_livelock_counter, _l5_intr_livelock_max;
#endif
//Take care: the tick hook can also be called before esp_int_wdt_init() is called.
@@ -70,9 +70,9 @@ static void IRAM_ATTR tick_hook(void)
wdt_hal_write_protect_disable(&iwdt_context);
//Reconfigure stage timeouts
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
_l4_intr_livelock_counter = 0;
_l5_intr_livelock_counter = 0;
wdt_hal_config_stage(&iwdt_context, WDT_STAGE0,
CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US / (_l4_intr_livelock_max + 1), WDT_STAGE_ACTION_INT); //Set timeout before interrupt
CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US / (_l5_intr_livelock_max + 1), WDT_STAGE_ACTION_INT); //Set timeout before interrupt
#else
wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT); //Set timeout before interrupt
#endif
@@ -136,11 +136,11 @@ void esp_int_wdt_cpu_init(void)
* This is a workaround for issue 3.15 in "ESP32 ECO and workarounds for
* Bugs" document.
*/
_l4_intr_livelock_counter = 0;
_l5_intr_livelock_counter = 0;
if (soc_has_cache_lock_bug()) {
assert((portTICK_PERIOD_MS << 1) <= IWDT_LIVELOCK_TIMEOUT_MS);
assert(CONFIG_ESP_INT_WDT_TIMEOUT_MS >= (IWDT_LIVELOCK_TIMEOUT_MS * 3));
_l4_intr_livelock_max = CONFIG_ESP_INT_WDT_TIMEOUT_MS / IWDT_LIVELOCK_TIMEOUT_MS - 1;
_l5_intr_livelock_max = CONFIG_ESP_INT_WDT_TIMEOUT_MS / IWDT_LIVELOCK_TIMEOUT_MS - 1;
}
#endif

View File

@@ -54,7 +54,7 @@ _xt_panic:
s32i a0, sp, XT_STK_A0
/* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE
movi a0, PS_INTLEVEL(XCHAL_DEBUGLEVEL - 2) | PS_UM | PS_WOE
wsr a0, PS
//Call panic handler

View File

@@ -33,156 +33,10 @@ Interrupt , a high-priority interrupt, is used for several things:
*/
#define L4_INTR_STACK_SIZE 12
#define L4_INTR_A2_OFFSET 0
#define L4_INTR_A3_OFFSET 4
#define L4_INTR_A4_OFFSET 8
.data
_l4_intr_stack:
.space L4_INTR_STACK_SIZE*portNUM_PROCESSORS /* This allocates stacks for each individual CPU. */
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_ESP_INT_WDT
.global _l4_intr_livelock_counter
.global _l4_intr_livelock_max
.align 16
_l4_intr_livelock_counter:
.word 0
_l4_intr_livelock_max:
.word 0
_l4_intr_livelock_sync:
.word 0, 0
_l4_intr_livelock_app:
.word 0
_l4_intr_livelock_pro:
.word 0
#endif
.section .iram1,"ax"
.global xt_highint4
.type xt_highint4,@function
.align 4
xt_highint4:
#ifndef CONFIG_FREERTOS_UNICORE
/* See if we're here for the IPC_ISR interrupt */
rsr a0, INTERRUPT
extui a0, a0, ETS_IPC_ISR_INUM, 1
bnez a0, esp_ipc_isr_handler
#endif // not CONFIG_FREERTOS_UNICORE
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_ESP_INT_WDT
/* See if we're here for the tg1 watchdog interrupt */
rsr a0, INTERRUPT
extui a0, a0, ETS_T1_WDT_INUM, 1
beqz a0, 1f
wsr a5, depc /* use DEPC as temp storage */
movi a0, _l4_intr_livelock_counter
l32i a0, a0, 0
movi a5, _l4_intr_livelock_max
l32i a5, a5, 0
bltu a0, a5, .handle_livelock_int /* _l4_intr_livelock_counter < _l4_intr_livelock_max */
rsr a5, depc /* restore a5 */
#endif
/* Allocate exception frame and save minimal context. */
1: mov a0, sp
addi sp, sp, -XT_STK_FRMSZ
s32i a0, sp, XT_STK_A1
#if XCHAL_HAVE_WINDOWED
s32e a0, sp, -12 /* for debug backtrace */
#endif
rsr a0, PS /* save interruptee's PS */
s32i a0, sp, XT_STK_PS
rsr a0, EPC_4 /* save interruptee's PC */
s32i a0, sp, XT_STK_PC
#if XCHAL_HAVE_WINDOWED
s32e a0, sp, -16 /* for debug backtrace */
#endif
s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */
s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */
call0 _xt_context_save
/* Save vaddr into exception frame */
rsr a0, EXCVADDR
s32i a0, sp, XT_STK_EXCVADDR
/* Figure out reason, save into EXCCAUSE reg */
rsr a0, INTERRUPT
extui a0, a0, ETS_MEMACCESS_ERR_INUM, 1 /* get cacheerr int bit */
beqz a0, 1f
/* Kill this interrupt; we cannot reset it. */
rsr a0, INTENABLE
movi a4, ~(1<<ETS_MEMACCESS_ERR_INUM)
and a0, a4, a0
wsr a0, INTENABLE
movi a0, PANIC_RSN_CACHEERR
j 9f
1:
#if CONFIG_ESP_INT_WDT_CHECK_CPU1
/* Check if the cause is the app cpu failing to tick.*/
movi a0, int_wdt_app_cpu_ticked
l32i a0, a0, 0
bnez a0, 2f
/* It is. Modify cause. */
movi a0,PANIC_RSN_INTWDT_CPU1
j 9f
2:
#endif
/* Set EXCCAUSE to reflect cause of the wdt int trigger */
movi a0,PANIC_RSN_INTWDT_CPU0
9:
/* Found the reason, now save it. */
s32i a0, sp, XT_STK_EXCCAUSE
/* _xt_context_save seems to save the current a0, but we need the interuptees a0. Fix this. */
rsr a0, EXCSAVE_4 /* save interruptee's a0 */
s32i a0, sp, XT_STK_A0
/* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE
wsr a0, PS
//Call panic handler
mov a6,sp
call4 panicHandler
call0 _xt_context_restore
l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */
wsr a0, PS
l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
wsr a0, EPC_4
l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */
l32i sp, sp, XT_STK_A1 /* remove exception frame */
rsync /* ensure PS and EPC written */
rsr a0, EXCSAVE_4 /* restore a0 */
rfi 4
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_ESP_INT_WDT
/*
--------------------------------------------------------------------------------
Macro intr_matrix_map - Attach an CPU interrupt to a hardware source.
Input : "addr" - Interrupt map configuration base address
Input : "src" - Interrupt source.
Input : "inum" - Interrupt number.
--------------------------------------------------------------------------------
*/
.macro intr_matrix_map addr src inum
movi a2, \src
slli a2, a2, 2
movi a3, \addr
add a3, a3, a2
movi a2, \inum
s32i a2, a3, 0
memw
.endm
#define L5_INTR_STACK_SIZE 12
#define L5_INTR_A2_OFFSET 0
#define L5_INTR_A3_OFFSET 4
#define L5_INTR_A4_OFFSET 8
/*
--------------------------------------------------------------------------------
@@ -190,6 +44,10 @@ xt_highint4:
Macro wdt_feed - Feed the WDT.
Input : "dev" - Beginning address of the peripheral registers
Macro get_int_status_tg1wdt - Get the ETS_TG1_WDT_LEVEL_INTR_SOURCE bit in interrupt status
output : "reg" - Store the result into the reg
--------------------------------------------------------------------------------
*/
@@ -221,7 +79,7 @@ xt_highint4:
movi a3, TIMG_WDT_WKEY_VALUE
s32i a3, a2, TIMG1_WDTWPROTECT_OFFSET /* disable write protect */
memw
movi a4, _l4_intr_livelock_max
movi a4, _l5_intr_livelock_max
l32i a4, a4, 0
memw
addi a4, a4, 1
@@ -240,19 +98,197 @@ xt_highint4:
memw
.endm
.macro get_int_status_tg1wdt reg
rsr \reg, INTERRUPT
extui \reg, \reg, ETS_T1_WDT_CACHEERR_INUM, 1
beqz \reg, 99f // not ETS_T1_WDT_INUM or ETS_CACHEERR_INUM
getcoreid \reg
bnez \reg, 98f
// core 0
movi \reg, 0x3FF40078
l32i \reg, \reg, 0 // Workaround for DPORT read error, for silicon revision 0~2 (ECO V0 ~ ECO V2).
movi \reg, DPORT_PRO_INTR_STATUS_0_REG
l32i \reg, \reg, 0
extui \reg, \reg, 20, 1 // ETS_TG1_WDT_LEVEL_INTR_SOURCE
j 99f
98: // core 1
movi \reg, 0x3FF40078
l32i \reg, \reg, 0 // Workaround for DPORT read error, for silicon revision 0~2 (ECO V0 ~ ECO V2).
movi \reg, DPORT_APP_INTR_STATUS_0_REG
l32i \reg, \reg, 0
extui \reg, \reg, 20, 1 // ETS_TG1_WDT_LEVEL_INTR_SOURCE
99:
.endm
.data
_l5_intr_stack:
.space L5_INTR_STACK_SIZE*portNUM_PROCESSORS /* This allocates stacks for each individual CPU. */
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_ESP_INT_WDT
.global _l5_intr_livelock_counter
.global _l5_intr_livelock_max
.align 16
_l5_intr_livelock_counter:
.word 0
_l5_intr_livelock_max:
.word 0
_l5_intr_livelock_sync:
.word 0, 0
_l5_intr_livelock_app:
.word 0
_l5_intr_livelock_pro:
.word 0
#endif
.section .iram1,"ax"
.global xt_highint5
.type xt_highint5,@function
.align 4
xt_highint5:
#ifndef CONFIG_FREERTOS_UNICORE
/* See if we're here for the IPC_ISR interrupt */
rsr a0, INTERRUPT
extui a0, a0, ETS_IPC_ISR_INUM, 1
bnez a0, esp_ipc_isr_handler
#endif // not CONFIG_FREERTOS_UNICORE
// ETS_T1_WDT_INUM
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_ESP_INT_WDT
get_int_status_tg1wdt a0
beqz a0, 1f
wsr a5, depc /* use DEPC as temp storage */
movi a0, _l5_intr_livelock_counter
l32i a0, a0, 0
movi a5, _l5_intr_livelock_max
l32i a5, a5, 0
bltu a0, a5, .handle_livelock_int /* _l5_intr_livelock_counter < _l5_intr_livelock_max */
rsr a5, depc /* restore a5 */
#endif
1: //ETS_CACHEERR_INUM or ETS_T1_WDT_INUM
/* Allocate exception frame and save minimal context. */
mov a0, sp
addi sp, sp, -XT_STK_FRMSZ
s32i a0, sp, XT_STK_A1
#if XCHAL_HAVE_WINDOWED
s32e a0, sp, -12 /* for debug backtrace */
#endif
rsr a0, PS /* save interruptee's PS */
s32i a0, sp, XT_STK_PS
rsr a0, EPC_5 /* save interruptee's PC */
s32i a0, sp, XT_STK_PC
#if XCHAL_HAVE_WINDOWED
s32e a0, sp, -16 /* for debug backtrace */
#endif
s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */
s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */
call0 _xt_context_save
/* Save vaddr into exception frame */
rsr a0, EXCVADDR
s32i a0, sp, XT_STK_EXCVADDR
/* Figure out reason, save into EXCCAUSE reg */
get_int_status_tg1wdt a0
bnez a0, 1f
/* TODO: Clear the MEMACCESS_ERR interrupt status. */
/* Kill this interrupt; we cannot reset it. */
rsr a0, INTENABLE
movi a4, ~(1<<ETS_MEMACCESS_ERR_INUM)
and a0, a4, a0
wsr a0, INTENABLE
movi a0, PANIC_RSN_CACHEERR
j 9f
1:
/* Clear the WDT interrupt status. */
wdt_clr_intr_status TIMERG1
#if CONFIG_ESP_INT_WDT_CHECK_CPU1
/* Check if the cause is the app cpu failing to tick.*/
movi a0, int_wdt_app_cpu_ticked
l32i a0, a0, 0
bnez a0, 2f
/* It is. Modify cause. */
movi a0,PANIC_RSN_INTWDT_CPU1
j 9f
2:
#endif
/* Set EXCCAUSE to reflect cause of the wdt int trigger */
movi a0,PANIC_RSN_INTWDT_CPU0
9:
/* Found the reason, now save it. */
s32i a0, sp, XT_STK_EXCCAUSE
/* _xt_context_save seems to save the current a0, but we need the interuptees a0. Fix this. */
rsr a0, EXCSAVE_5 /* save interruptee's a0 */
s32i a0, sp, XT_STK_A0
/* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE
wsr a0, PS
//Call panic handler
mov a6,sp
call4 panicHandler
call0 _xt_context_restore
l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */
wsr a0, PS
l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
wsr a0, EPC_5
l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */
l32i sp, sp, XT_STK_A1 /* remove exception frame */
rsync /* ensure PS and EPC written */
rsr a0, EXCSAVE_5 /* restore a0 */
rfi 5
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_ESP_INT_WDT
/*
--------------------------------------------------------------------------------
Macro intr_matrix_map - Attach an CPU interrupt to a hardware source.
Input : "addr" - Interrupt map configuration base address
Input : "src" - Interrupt source.
Input : "inum" - Interrupt number.
--------------------------------------------------------------------------------
*/
.macro intr_matrix_map addr src inum
movi a2, \src
slli a2, a2, 2
movi a3, \addr
add a3, a3, a2
movi a2, \inum
s32i a2, a3, 0
memw
.endm
.align 4
.handle_livelock_int:
getcoreid a5
/* Save A2, A3, A4 so we can use those registers */
movi a0, L4_INTR_STACK_SIZE
movi a0, L5_INTR_STACK_SIZE
mull a5, a5, a0
movi a0, _l4_intr_stack
movi a0, _l5_intr_stack
add a0, a0, a5
s32i a2, a0, L4_INTR_A2_OFFSET
s32i a3, a0, L4_INTR_A3_OFFSET
s32i a4, a0, L4_INTR_A4_OFFSET
s32i a2, a0, L5_INTR_A2_OFFSET
s32i a3, a0, L5_INTR_A3_OFFSET
s32i a4, a0, L5_INTR_A4_OFFSET
/* Here, we can use a0, a2, a3, a4, a5 registers */
getcoreid a5
@@ -260,18 +296,18 @@ xt_highint4:
rsil a0, CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL /* disable nested interrupt */
beqz a5, 1f
movi a2, _l4_intr_livelock_app
movi a2, _l5_intr_livelock_app
l32i a3, a2, 0
addi a3, a3, 1
s32i a3, a2, 0
/* Dual core synchronization, ensuring that both cores enter interrupts */
1: movi a4, 0x1
movi a2, _l4_intr_livelock_sync
movi a2, _l5_intr_livelock_sync
addx4 a3, a5, a2
s32i a4, a3, 0
1: movi a2, _l4_intr_livelock_sync
1: movi a2, _l5_intr_livelock_sync
movi a3, 1
addx4 a3, a3, a2
l32i a2, a2, 0
@@ -281,10 +317,10 @@ xt_highint4:
beqz a5, 1f /* Pro cpu (Core 0) jump bypass */
movi a2, _l4_intr_livelock_app
movi a2, _l5_intr_livelock_app
l32i a2, a2, 0
bnei a2, 2, 1f
movi a2, _l4_intr_livelock_counter /* _l4_intr_livelock_counter++ */
movi a2, _l5_intr_livelock_counter /* _l5_intr_livelock_counter++ */
l32i a3, a2, 0
addi a3, a3, 1
s32i a3, a2, 0
@@ -333,17 +369,17 @@ xt_highint4:
bltu a4, a3, 2b
beqz a5, 2f
movi a2, _l4_intr_livelock_app
movi a2, _l5_intr_livelock_app
l32i a2, a2, 0
beqi a2, 2, 8f
j 3f
2: movi a2, _l4_intr_livelock_pro
2: movi a2, _l5_intr_livelock_pro
l32i a4, a2, 0
addi a4, a4, 1
s32i a4, a2, 0
movi a2, _l4_intr_livelock_sync
movi a2, _l5_intr_livelock_sync
movi a3, 1
addx4 a3, a3, a2
l32i a2, a2, 0
@@ -357,7 +393,7 @@ xt_highint4:
/*
Pro cpu (Core 0) jump bypass, continue waiting, App cpu (Core 1)
can execute to here, unmap itself tg1 1st stage timeout interrupt
then restore registers and exit highint4.
then restore registers and exit highint5.
*/
3: intr_matrix_map DPORT_APP_MAC_INTR_MAP_REG, ETS_TG1_WDT_LEVEL_INTR_SOURCE, 16
j 9f
@@ -368,13 +404,13 @@ xt_highint4:
*/
4: intr_matrix_map DPORT_APP_MAC_INTR_MAP_REG, ETS_TG1_WDT_LEVEL_INTR_SOURCE, ETS_T1_WDT_INUM
1: movi a2, _l4_intr_livelock_sync
1: movi a2, _l5_intr_livelock_sync
movi a4, 1
addx4 a3, a4, a2
l32i a2, a2, 0
l32i a3, a3, 0
and a2, a2, a3
beqz a2, 1b /* Wait for App cpu to enter highint4 again */
beqz a2, 1b /* Wait for App cpu to enter highint5 again */
wdt_clr_intr_status TIMERG1
j 9f
@@ -386,32 +422,32 @@ xt_highint4:
movi a0, 0
beqz a5, 1f
movi a2, _l4_intr_livelock_app
movi a2, _l5_intr_livelock_app
l32i a3, a2, 0
bnei a3, 2, 1f
s32i a0, a2, 0
1: bnez a5, 2f
movi a2, _l4_intr_livelock_pro
movi a2, _l5_intr_livelock_pro
s32i a0, a2, 0
2: movi a2, _l4_intr_livelock_sync
2: movi a2, _l5_intr_livelock_sync
addx4 a2, a5, a2
s32i a0, a2, 0
/* Done. Restore registers and return. */
movi a0, L4_INTR_STACK_SIZE
movi a0, L5_INTR_STACK_SIZE
mull a5, a5, a0
movi a0, _l4_intr_stack
movi a0, _l5_intr_stack
add a0, a0, a5
l32i a2, a0, L4_INTR_A2_OFFSET
l32i a3, a0, L4_INTR_A3_OFFSET
l32i a4, a0, L4_INTR_A4_OFFSET
l32i a2, a0, L5_INTR_A2_OFFSET
l32i a3, a0, L5_INTR_A3_OFFSET
l32i a4, a0, L5_INTR_A4_OFFSET
rsync /* ensure register restored */
rsr a5, depc
rsr a0, EXCSAVE_4 /* restore a0 */
rfi 4
rsr a0, EXCSAVE_5 /* restore a0 */
rfi 5
#endif

View File

@@ -639,11 +639,11 @@ _xt_user_exc:
rsr a0, EXCSAVE_1 /* save interruptee's a0 */
s32i a0, sp, XT_STK_A0
/* Set up PS for C, reenable hi-pri interrupts, and clear EXCM. */
/* Set up PS for C, reenable debug and NMI interrupts, and clear EXCM. */
#ifdef __XTENSA_CALL0_ABI__
movi a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM
movi a0, PS_INTLEVEL(XCHAL_DEBUGLEVEL - 2) | PS_UM
#else
movi a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE
movi a0, PS_INTLEVEL(XCHAL_DEBUGLEVEL - 2) | PS_UM | PS_WOE
#endif
wsr a0, PS

View File

@@ -359,7 +359,7 @@
* 2 1 extern level
* 3 1 extern level
* 4 1 extern level WBB
* 5 1 extern level BT/BLE Controller BT/BLE Controller
* 5 1 extern level
* 6 1 timer FreeRTOS Tick(L1) FreeRTOS Tick(L1)
* 7 1 software BT/BLE VHCI BT/BLE VHCI
* 8 1 extern level BT/BLE BB(RX/TX) BT/BLE BB(RX/TX)
@@ -378,14 +378,14 @@
* 21 2 extern level
* 22 3 extern edge
* 23 3 extern level
* 24 4 extern level TG1_WDT
* 25 4 extern level CACHEERR
* 26 5 extern level
* 24 4 extern level
* 25 4 extern level BT/BLE Controller BT/BLE Controller
* 26 5 extern level TG1_WDT & CACHEERR
* 27 3 extern level Reserved Reserved
* 28 4 extern edge IPC_ISR IPC_ISR
* 29 3 software Reserved Reserved
* 28 4 extern edge
* 29 3 software BT/BLE hli BT/BLE hli
* 30 4 extern edge Reserved Reserved
* 31 5 extern level
* 31 5 extern level IPC_ISR IPC_ISR
*************************************************************************************************************
*/
@@ -395,11 +395,12 @@
#define ETS_WBB_INUM 4
#define ETS_TG0_T1_INUM 10 /**< use edge interrupt*/
#define ETS_FRC1_INUM 22
#define ETS_T1_WDT_INUM 24
#define ETS_MEMACCESS_ERR_INUM 25
#define ETS_T1_WDT_CACHEERR_INUM 26
#define ETS_T1_WDT_INUM ETS_T1_WDT_CACHEERR_INUM
#define ETS_MEMACCESS_ERR_INUM ETS_T1_WDT_CACHEERR_INUM
/* backwards compatibility only, use ETS_MEMACCESS_ERR_INUM instead*/
#define ETS_CACHEERR_INUM ETS_MEMACCESS_ERR_INUM
#define ETS_IPC_ISR_INUM 28
#define ETS_IPC_ISR_INUM 31
//CPU0 Interrupt number used in ROM, should be cancelled in SDK
#define ETS_SLC_INUM 1