diff --git a/arch/xtensa/src/esp32s3/esp32s3_ble_adapter.c b/arch/xtensa/src/esp32s3/esp32s3_ble_adapter.c index 30ef57b833e..e3b9d6358a7 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_ble_adapter.c +++ b/arch/xtensa/src/esp32s3/esp32s3_ble_adapter.c @@ -60,7 +60,6 @@ #include "esp32s3_rtc.h" #include "esp32s3_spiflash.h" #include "esp32s3_wireless.h" -#include "esp32s3_wireless.h" #include "esp32s3_ble_adapter.h" @@ -90,6 +89,11 @@ #define BTDM_LPCLK_SEL_RTC_SLOW (2) #define BTDM_LPCLK_SEL_8M (3) +#ifdef CONFIG_ESP32S3_SPIFLASH +# define BLE_TASK_EVENT_QUEUE_ITEM_SIZE 8 +# define BLE_TASK_EVENT_QUEUE_LEN 1 +#endif + /**************************************************************************** * Private Types ****************************************************************************/ @@ -159,6 +163,16 @@ enum btdm_wakeup_src_e BTDM_ASYNC_WAKEUP_SRC_MAX, }; +/* Superseded semaphore definition */ + +struct bt_sem_s +{ + sem_t sem; +#ifdef CONFIG_ESP32S3_SPIFLASH + struct esp_semcache_s sc; +#endif +}; + /* prototype of function to handle vendor dependent signals */ typedef void (*btdm_vnd_ol_task_func_t)(void *param); @@ -424,6 +438,13 @@ static DRAM_ATTR void * g_light_sleep_pm_lock; static irqstate_t g_inter_flags; +/* Cached queue control variables */ + +#ifdef CONFIG_ESP32S3_SPIFLASH +static struct esp_queuecache_s g_esp_queuecache; +static uint8_t g_esp_queuecache_buffer[BLE_TASK_EVENT_QUEUE_ITEM_SIZE]; +#endif + /**************************************************************************** * Public Data ****************************************************************************/ @@ -704,7 +725,6 @@ static int IRAM_ATTR esp_int_adpt_cb(int irq, void *context, void *arg) static void interrupt_handler_set_wrapper(int intr_num, void *fn, void *arg) { - int ret; struct irq_adpt_s *adapter; int irq = esp32s3_getirq(0, intr_num); @@ -716,8 +736,7 @@ static void interrupt_handler_set_wrapper(int intr_num, void *fn, void *arg) adapter->func = fn; adapter->arg = arg; - ret = irq_attach(irq, esp_int_adpt_cb, adapter); - DEBUGASSERT(ret == OK); + DEBUGVERIFY(irq_attach(irq, esp_int_adpt_cb, adapter)); } /**************************************************************************** @@ -727,7 +746,7 @@ static void interrupt_handler_set_wrapper(int intr_num, void *fn, void *arg) * Enable Wi-Fi interrupt * * Input Parameters: - * intr_num - No mean + * intr_num - The interrupt CPU number. * * Returned Value: * None @@ -736,7 +755,12 @@ static void interrupt_handler_set_wrapper(int intr_num, void *fn, void *arg) static void interrupt_on_wrapper(int intr_num) { - up_enable_irq(intr_num + XTENSA_IRQ_FIRSTPERIPH); + int cpuint = intr_num; + int irq = esp32s3_getirq(0, cpuint); + + DEBUGVERIFY(esp32s3_irq_set_iram_isr(irq)); + + up_enable_irq(irq); } /**************************************************************************** @@ -834,26 +858,32 @@ static void IRAM_ATTR task_yield_from_isr(void) static void *semphr_create_wrapper(uint32_t max, uint32_t init) { int ret; - sem_t *sem; + struct bt_sem_s *bt_sem; int tmp; - tmp = sizeof(sem_t); - sem = kmm_malloc(tmp); - if (!sem) + tmp = sizeof(struct bt_sem_s); + bt_sem = kmm_malloc(tmp); + DEBUGASSERT(bt_sem); + if (!bt_sem) { wlerr("ERROR: Failed to alloc %d memory\n", tmp); return NULL; } - ret = nxsem_init(sem, 0, init); + ret = nxsem_init(&bt_sem->sem, 0, init); + DEBUGASSERT(ret == OK); if (ret) { wlerr("ERROR: Failed to initialize sem error=%d\n", ret); - kmm_free(sem); + kmm_free(bt_sem); return NULL; } - return sem; +#ifdef CONFIG_ESP32S3_SPIFLASH + esp_init_semcache(&bt_sem->sc, &bt_sem->sem); +#endif + + return bt_sem; } /**************************************************************************** @@ -872,9 +902,9 @@ static void *semphr_create_wrapper(uint32_t max, uint32_t init) static void semphr_delete_wrapper(void *semphr) { - sem_t *sem = (sem_t *)semphr; - nxsem_destroy(sem); - kmm_free(sem); + struct bt_sem_s *bt_sem = (struct bt_sem_s *)semphr; + sem_destroy(&bt_sem->sem); + kmm_free(bt_sem); } /**************************************************************************** @@ -896,7 +926,8 @@ static int IRAM_ATTR semphr_take_from_isr_wrapper(void *semphr, void *hptw) { *(int *)hptw = 0; - return esp_errno_trans(nxsem_trywait(semphr)); + DEBUGPANIC(); + return 0; } /**************************************************************************** @@ -916,9 +947,24 @@ static int IRAM_ATTR semphr_take_from_isr_wrapper(void *semphr, void *hptw) static int IRAM_ATTR semphr_give_from_isr_wrapper(void *semphr, void *hptw) { - sem_t *sem = (sem_t *)semphr; + int ret; + struct bt_sem_s *bt_sem = (struct bt_sem_s *)semphr; - return esp_errno_trans(semphr_give_wrapper(sem)); +#ifdef CONFIG_ESP32S3_SPIFLASH + if (spi_flash_cache_enabled()) + { + ret = semphr_give_wrapper(bt_sem); + } + else + { + esp_post_semcache(&bt_sem->sc); + ret = 0; + } +#else + ret = semphr_give_wrapper(bt_sem); +#endif + + return esp_errno_trans(ret); } /**************************************************************************** @@ -969,21 +1015,21 @@ static void esp_update_time(struct timespec *timespec, uint32_t ticks) static int semphr_take_wrapper(void *semphr, uint32_t block_time_ms) { int ret; - sem_t *sem = (sem_t *)semphr; + struct bt_sem_s *bt_sem = (struct bt_sem_s *)semphr; if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) { - ret = nxsem_wait(sem); + ret = nxsem_wait(&bt_sem->sem); } else { if (block_time_ms > 0) { - ret = nxsem_tickwait(sem, MSEC2TICK(block_time_ms)); + ret = nxsem_tickwait(&bt_sem->sem, MSEC2TICK(block_time_ms)); } else { - ret = nxsem_trywait(sem); + ret = nxsem_trywait(&bt_sem->sem); } } @@ -1013,9 +1059,9 @@ static int semphr_take_wrapper(void *semphr, uint32_t block_time_ms) static int semphr_give_wrapper(void *semphr) { int ret; - sem_t *sem = (sem_t *)semphr; + struct bt_sem_s *bt_sem = (struct bt_sem_s *)semphr; - ret = nxsem_post(sem); + ret = nxsem_post(&bt_sem->sem); if (ret) { wlerr("Failed to post sem error=%d\n", ret); @@ -1150,13 +1196,21 @@ static int mutex_unlock_wrapper(void *mutex) * ****************************************************************************/ -static int32_t esp_queue_send_generic(void *queue, void *item, - uint32_t ticks, int prio) +static IRAM_ATTR int32_t esp_queue_send_generic(void *queue, void *item, + uint32_t ticks, int prio) { int ret; struct timespec timeout; struct mq_adpt_s *mq_adpt = (struct mq_adpt_s *)queue; +#ifdef CONFIG_ESP32S3_SPIFLASH + if (!spi_flash_cache_enabled()) + { + esp_send_queuecache(&g_esp_queuecache, item, mq_adpt->msgsize); + return esp_errno_trans(OK); + } +#endif + if (ticks == OSI_FUNCS_TIME_BLOCKING || ticks == 0) { /** @@ -1239,6 +1293,18 @@ static void *queue_create_wrapper(uint32_t queue_len, uint32_t item_size) } mq_adpt->msgsize = item_size; + +#ifdef CONFIG_ESP32S3_SPIFLASH + if (queue_len == BLE_TASK_EVENT_QUEUE_LEN && + item_size == BLE_TASK_EVENT_QUEUE_ITEM_SIZE) + { + esp_init_queuecache(&g_esp_queuecache, + &mq_adpt->mq, + g_esp_queuecache_buffer, + BLE_TASK_EVENT_QUEUE_ITEM_SIZE); + } +#endif + return (void *)mq_adpt; } @@ -1392,28 +1458,8 @@ static int IRAM_ATTR queue_recv_from_isr_wrapper(void *queue, void *item, void *hptw) { - ssize_t ret; - struct timespec timeout; - unsigned int prio; - struct mq_adpt_s *mq_adpt = (struct mq_adpt_s *)queue; - - ret = clock_gettime(CLOCK_REALTIME, &timeout); - - if (ret < 0) - { - wlerr("Failed to get time %d\n", ret); - return false; - } - - ret = file_mq_timedreceive(&mq_adpt->mq, (char *)item, - mq_adpt->msgsize, &prio, &timeout); - - if (ret < 0 && ret != -ETIMEDOUT) - { - wlerr("Failed to timedreceive from mqueue error=%d\n", ret); - } - - return ret > 0 ? true : false; + DEBUGPANIC(); + return 0; } /**************************************************************************** @@ -2391,6 +2437,13 @@ int esp32s3_bt_controller_init(void) btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; +#ifdef CONFIG_ESP32S3_SPIFLASH + if (esp_wireless_init() != OK) + { + return -EIO; + } +#endif + return OK; error: diff --git a/arch/xtensa/src/esp32s3/esp32s3_wireless.c b/arch/xtensa/src/esp32s3/esp32s3_wireless.c index 58d4eada21a..052b6fac8ea 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_wireless.c +++ b/arch/xtensa/src/esp32s3/esp32s3_wireless.c @@ -24,15 +24,18 @@ #include #include +#include #include #include #include "xtensa.h" +#include "hardware/esp32s3_efuse.h" #include "hardware/esp32s3_rtccntl.h" #include "hardware/esp32s3_soc.h" #include "hardware/esp32s3_syscon.h" -#include "hardware/esp32s3_efuse.h" +#include "hardware/esp32s3_system.h" +#include "esp32s3_irq.h" #include "esp32s3_periph.h" #include "esp_phy_init.h" @@ -47,6 +50,27 @@ #define MAC_ADDR0_REG EFUSE_RD_MAC_SPI_SYS_0_REG #define MAC_ADDR1_REG EFUSE_RD_MAC_SPI_SYS_1_REG +/* Software Interrupt */ + +#define SWI_IRQ ESP32S3_IRQ_INT_FROM_CPU2 +#define SWI_PERIPH ESP32S3_PERIPH_INT_FROM_CPU2 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Wireless Private Data */ + +struct esp_wireless_priv_s +{ + volatile int ref; /* Reference count */ + + int cpuint; /* CPU interrupt assigned to SWI */ + + struct list_node sc_list; /* Semaphore cache list */ + struct list_node qc_list; /* Queue cache list */ +}; + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -91,6 +115,10 @@ static bool g_is_phy_calibrated = false; static uint8_t g_wifi_bt_pd_controller; +/* Private data of the wireless common interface */ + +static struct esp_wireless_priv_s g_esp_wireless_priv; + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -132,6 +160,66 @@ static inline void phy_digital_regs_load(void) } } +/**************************************************************************** + * Name: esp_swi_irq + * + * Description: + * Wireless software interrupt callback function. + * + * Parameters: + * cpuint - CPU interrupt index + * context - Context data from the ISR + * arg - NULL + * + * Returned Value: + * Zero (OK) is returned on success. A negated errno value is returned on + * failure. + * + ****************************************************************************/ + +static int esp_swi_irq(int irq, void *context, void *arg) +{ + int i; + int ret; + struct esp_semcache_s *sc; + struct esp_semcache_s *sc_tmp; + struct esp_queuecache_s *qc; + struct esp_queuecache_s *qc_tmp; + struct esp_wireless_priv_s *priv = &g_esp_wireless_priv; + + modifyreg32(SYSTEM_CPU_INTR_FROM_CPU_2_REG, SYSTEM_CPU_INTR_FROM_CPU_2, 0); + + list_for_every_entry_safe(&priv->sc_list, sc, sc_tmp, + struct esp_semcache_s, node) + { + for (i = 0; i < sc->count; i++) + { + ret = nxsem_post(sc->sem); + if (ret < 0) + { + wlerr("ERROR: Failed to post sem ret=%d\n", ret); + } + } + + sc->count = 0; + list_delete(&sc->node); + } + + list_for_every_entry_safe(&priv->qc_list, qc, qc_tmp, + struct esp_queuecache_s, node) + { + ret = file_mq_send(qc->mq_ptr, (const char *)qc->buffer, qc->size, 0); + if (ret < 0) + { + wlerr("ERROR: Failed to send queue ret=%d\n", ret); + } + + list_delete(&qc->node); + } + + return OK; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -605,3 +693,220 @@ int32_t esp_timer_delete(esp_timer_handle_t timer) return 0; } + +/**************************************************************************** + * Name: esp_init_semcache + * + * Description: + * Initialize semaphore cache. + * + * Parameters: + * sc - Semaphore cache data pointer + * sem - Semaphore data pointer + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp_init_semcache(struct esp_semcache_s *sc, sem_t *sem) +{ + sc->sem = sem; + sc->count = 0; + list_initialize(&sc->node); +} + +/**************************************************************************** + * Name: esp_post_semcache + * + * Description: + * Store posting semaphore action into semaphore cache. + * + * Parameters: + * sc - Semaphore cache data pointer + * + * Returned Value: + * None. + * + ****************************************************************************/ + +IRAM_ATTR void esp_post_semcache(struct esp_semcache_s *sc) +{ + struct esp_wireless_priv_s *priv = &g_esp_wireless_priv; + + if (!sc->count) + { + list_add_tail(&priv->sc_list, &sc->node); + } + + sc->count++; + + /* Enable CPU 0 interrupt. This will generate an IRQ as soon as non-IRAM + * are (re)enabled. + */ + + modifyreg32(SYSTEM_CPU_INTR_FROM_CPU_2_REG, 0, SYSTEM_CPU_INTR_FROM_CPU_2); +} + +/**************************************************************************** + * Name: esp_init_queuecache + * + * Description: + * Initialize queue cache. + * + * Parameters: + * qc - Queue cache data pointer + * mq_ptr - Queue data pointer + * buffer - Queue cache buffer pointer + * size - Queue cache buffer size + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp_init_queuecache(struct esp_queuecache_s *qc, + struct file *mq_ptr, + uint8_t *buffer, + size_t size) +{ + qc->mq_ptr = mq_ptr; + qc->size = size; + qc->buffer = buffer; + list_initialize(&qc->node); +} + +/**************************************************************************** + * Name: esp_send_queuecache + * + * Description: + * Store posting queue action and data into queue cache. + * + * Parameters: + * qc - Queue cache data pointer + * buffer - Data buffer + * size - Buffer size + * + * Returned Value: + * None. + * + ****************************************************************************/ + +IRAM_ATTR void esp_send_queuecache(struct esp_queuecache_s *qc, + uint8_t *buffer, + int size) +{ + struct esp_wireless_priv_s *priv = &g_esp_wireless_priv; + + DEBUGASSERT(qc->size == size); + + list_add_tail(&priv->qc_list, &qc->node); + memcpy(qc->buffer, buffer, size); + + /* Enable CPU 0 interrupt. This will generate an IRQ as soon as non-IRAM + * are (re)enabled. + */ + + modifyreg32(SYSTEM_CPU_INTR_FROM_CPU_2_REG, 0, SYSTEM_CPU_INTR_FROM_CPU_2); +} + +/**************************************************************************** + * Name: esp_wireless_init + * + * Description: + * Initialize ESP32 wireless common components for both BT and Wi-Fi. + * + * Parameters: + * None + * + * Returned Value: + * Zero (OK) is returned on success. A negated errno value is returned on + * failure. + * + ****************************************************************************/ + +int esp_wireless_init(void) +{ + int ret; + irqstate_t flags; + struct esp_wireless_priv_s *priv = &g_esp_wireless_priv; + + flags = enter_critical_section(); + if (priv->ref != 0) + { + priv->ref++; + leave_critical_section(flags); + return OK; + } + + priv->cpuint = esp32s3_setup_irq(0, SWI_PERIPH, ESP32S3_INT_PRIO_DEF, 0); + if (priv->cpuint < 0) + { + /* Failed to allocate a CPU interrupt of this type. */ + + wlerr("ERROR: Failed to attach IRQ ret=%d\n", ret); + ret = priv->cpuint; + leave_critical_section(flags); + + return ret; + } + + ret = irq_attach(SWI_IRQ, esp_swi_irq, NULL); + if (ret < 0) + { + esp32s3_teardown_irq(0, SWI_PERIPH, priv->cpuint); + leave_critical_section(flags); + wlerr("ERROR: Failed to attach IRQ ret=%d\n", ret); + + return ret; + } + + list_initialize(&priv->sc_list); + list_initialize(&priv->qc_list); + + up_enable_irq(SWI_IRQ); + + priv->ref++; + + leave_critical_section(flags); + + return OK; +} + +/**************************************************************************** + * Name: esp_wireless_deinit + * + * Description: + * De-initialize ESP32 wireless common components. + * + * Parameters: + * None + * + * Returned Value: + * Zero (OK) is returned on success. A negated errno value is returned on + * failure. + * + ****************************************************************************/ + +int esp_wireless_deinit(void) +{ + irqstate_t flags; + struct esp_wireless_priv_s *priv = &g_esp_wireless_priv; + + flags = enter_critical_section(); + + if (priv->ref > 0) + { + priv->ref--; + if (priv->ref == 0) + { + up_disable_irq(SWI_IRQ); + irq_detach(SWI_IRQ); + esp32s3_teardown_irq(0, SWI_PERIPH, priv->cpuint); + } + } + + leave_critical_section(flags); + + return OK; +} diff --git a/arch/xtensa/src/esp32s3/esp32s3_wireless.h b/arch/xtensa/src/esp32s3/esp32s3_wireless.h index 4125b88f494..9586d0fa2ac 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_wireless.h +++ b/arch/xtensa/src/esp32s3/esp32s3_wireless.h @@ -24,8 +24,12 @@ /**************************************************************************** * Included Files ****************************************************************************/ +#include +#include +#include #include +#include #include "xtensa_attr.h" #include "esp32s3_rt_timer.h" @@ -45,6 +49,31 @@ #define MAC_LEN (6) +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Semaphore Cache Data */ + +struct esp_semcache_s +{ + struct list_node node; + + sem_t *sem; + uint32_t count; +}; + +/* Queue Cache Data */ + +struct esp_queuecache_s +{ + struct list_node node; + + struct file *mq_ptr; + size_t size; + uint8_t *buffer; +}; + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ @@ -266,4 +295,113 @@ int32_t esp_timer_stop(esp_timer_handle_t timer); int32_t esp_timer_delete(esp_timer_handle_t timer); +/**************************************************************************** + * Name: esp_init_semcache + * + * Description: + * Initialize semaphore cache. + * + * Parameters: + * sc - Semaphore cache data pointer + * sem - Semaphore data pointer + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp_init_semcache(struct esp_semcache_s *sc, sem_t *sem); + +/**************************************************************************** + * Name: esp_post_semcache + * + * Description: + * Store posting semaphore action into semaphore cache. + * + * Parameters: + * sc - Semaphore cache data pointer + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp_post_semcache(struct esp_semcache_s *sc); + +/**************************************************************************** + * Name: esp_init_queuecache + * + * Description: + * Initialize queue cache. + * + * Parameters: + * qc - Queue cache data pointer + * mq_ptr - Queue data pointer + * buffer - Queue cache buffer pointer + * size - Queue cache buffer size + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp_init_queuecache(struct esp_queuecache_s *qc, + struct file *mq_ptr, + uint8_t *buffer, + size_t size); + +/**************************************************************************** + * Name: esp32_wl_send_queuecache + * + * Description: + * Store posting queue action and data into queue cache. + * + * Parameters: + * qc - Queue cache data pointer + * buffer - Data buffer + * size - Buffer size + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp_send_queuecache(struct esp_queuecache_s *qc, + uint8_t *buffer, + int size); + +/**************************************************************************** + * Name: esp_wireless_init + * + * Description: + * Initialize ESP32 wireless common components for both BT and Wi-Fi. + * + * Parameters: + * None + * + * Returned Value: + * Zero (OK) is returned on success. A negated errno value is returned on + * failure. + * + ****************************************************************************/ + +int esp_wireless_init(void); + +/**************************************************************************** + * Name: esp_wireless_deinit + * + * Description: + * De-initialize ESP32 wireless common components. + * + * Parameters: + * None + * + * Returned Value: + * Zero (OK) is returned on success. A negated errno value is returned on + * failure. + * + ****************************************************************************/ + +int esp_wireless_deinit(void); + #endif /* __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_WIRELESS_H */ diff --git a/boards/xtensa/esp32s3/common/scripts/legacy_sections.ld b/boards/xtensa/esp32s3/common/scripts/legacy_sections.ld index 41d56c8129b..3410ea515c3 100644 --- a/boards/xtensa/esp32s3/common/scripts/legacy_sections.ld +++ b/boards/xtensa/esp32s3/common/scripts/legacy_sections.ld @@ -78,6 +78,7 @@ SECTIONS *libarch.a:esp32s3_cpuindex.*(.literal .text .literal.* .text.*) *libarch.a:esp32s3_irq.*(.literal .text .literal.* .text.*) + *libarch.a:esp32s3_user.*(.literal .text .literal.* .text.*) *libarch.a:esp32s3_spiflash.*(.literal .text .literal.* .text.*) *libarch.a:xtensa_assert.*(.literal .text .literal.* .text.*) *libarch.a:xtensa_cpuint.*(.literal .text .literal.* .text.*) @@ -86,6 +87,10 @@ SECTIONS *libarch.a:xtensa_modifyreg32.*(.literal .text .literal.* .text.*) *libarch.a:xtensa_testset.*(.literal .text .literal.* .text.*) +#ifdef CONFIG_ESP32S3_BLE + *libc.a:bin/sq_remlast.*(.literal .text .literal.* .text.*) +#endif + *libdrivers.a:syslog_flush.*(.literal .text .literal.* .text.*) *libsched.a:assert.*(.literal .text .literal.* .text.*)