From b5b35c0d252be28752571d555b1a73c416f5c135 Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Mon, 29 Jun 2026 11:27:50 +0530 Subject: [PATCH] fix(nimble): Defer Events / ATT related information from stack Defer Events/ ATT related GAP events from stack until connection event is sent to GAP layer --- components/bt/host/nimble/Kconfig.in | 10 +++ components/bt/host/nimble/nimble | 2 +- .../host/nimble/port/include/esp_nimble_cfg.h | 9 ++ .../npl/freertos/src/npl_os_freertos.c | 90 ++++++++++++------- 4 files changed, 79 insertions(+), 32 deletions(-) diff --git a/components/bt/host/nimble/Kconfig.in b/components/bt/host/nimble/Kconfig.in index 393761cc470..57282c7d708 100644 --- a/components/bt/host/nimble/Kconfig.in +++ b/components/bt/host/nimble/Kconfig.in @@ -349,6 +349,16 @@ menu "GAP" Enable this option to send number-of-completed-packets event to controller after disconnection + config BT_NIMBLE_DEFER_CONN_EVENTS_UNTIL_CONNECT + bool "Defer connection GAP/ATT events until CONNECT callback" + depends on BT_NIMBLE_ENABLED + default y + help + Queue connection-related GAP callbacks and ATT server requests until + BLE_GAP_EVENT_CONNECT event is delivered for that connection handle. + Required when the host delays CONNECT so applications never receive other + events before CONNECT event. + endmenu #GAP menu "GATT / ATT" diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index bdc5010548e..37599327e21 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit bdc5010548e988a770adb8af107d01feb850c0ca +Subproject commit 37599327e214accc849d0d007295028b0ec262ab diff --git a/components/bt/host/nimble/port/include/esp_nimble_cfg.h b/components/bt/host/nimble/port/include/esp_nimble_cfg.h index a0f62f36aa2..e4c095ff2d5 100644 --- a/components/bt/host/nimble/port/include/esp_nimble_cfg.h +++ b/components/bt/host/nimble/port/include/esp_nimble_cfg.h @@ -2390,4 +2390,13 @@ #endif #endif +#ifndef MYNEWT_VAL_BLE_DEFER_CONN_EVENTS +#ifdef CONFIG_BT_NIMBLE_DEFER_CONN_EVENTS_UNTIL_CONNECT +#define MYNEWT_VAL_BLE_DEFER_CONN_EVENTS CONFIG_BT_NIMBLE_DEFER_CONN_EVENTS_UNTIL_CONNECT +#else +#define MYNEWT_VAL_BLE_DEFER_CONN_EVENTS (0) +#endif +#endif + + #endif diff --git a/components/bt/porting/npl/freertos/src/npl_os_freertos.c b/components/bt/porting/npl/freertos/src/npl_os_freertos.c index c06258323fa..8d0f92a6e3e 100644 --- a/components/bt/porting/npl/freertos/src/npl_os_freertos.c +++ b/components/bt/porting/npl/freertos/src/npl_os_freertos.c @@ -26,6 +26,7 @@ portMUX_TYPE ble_port_mutex = portMUX_INITIALIZER_UNLOCKED; static SemaphoreHandle_t npl_eventq_sync; +static uint8_t hw_critical_state_status[portNUM_PROCESSORS]; #if BLE_NPL_USE_ESP_TIMER static const char *TAG = "Timer"; @@ -203,25 +204,35 @@ static void npl_eventq_sync_init(void) { if (npl_eventq_sync == NULL) { - npl_eventq_sync = xSemaphoreCreateMutex(); + npl_eventq_sync = xSemaphoreCreateRecursiveMutex(); BLE_LL_ASSERT(npl_eventq_sync); } } -static void +static bool npl_eventq_lock(void) { - if (!in_isr()) { - BLE_LL_ASSERT(npl_eventq_sync); - xSemaphoreTake(npl_eventq_sync, portMAX_DELAY); + BaseType_t core; + + if (in_isr()) { + return false; } + + core = xPortGetCoreID(); + if (core >= portNUM_PROCESSORS || hw_critical_state_status[core] != 0) { + return false; + } + + BLE_LL_ASSERT(npl_eventq_sync); + xSemaphoreTakeRecursive(npl_eventq_sync, portMAX_DELAY); + return true; } static void -npl_eventq_unlock(void) +npl_eventq_unlock(bool locked) { - if (!in_isr()) { - xSemaphoreGive(npl_eventq_sync); + if (locked) { + xSemaphoreGiveRecursive(npl_eventq_sync); } } @@ -331,7 +342,8 @@ IRAM_ATTR npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo } } } else if (tmo == 0) { - npl_eventq_lock(); + bool locked = npl_eventq_lock(); + portENTER_CRITICAL(&ble_port_mutex); ret = xQueueReceive(eventq->q, &ev, 0); if (ret == pdPASS && ev != NULL) { @@ -341,7 +353,7 @@ IRAM_ATTR npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo } } portEXIT_CRITICAL(&ble_port_mutex); - npl_eventq_unlock(); + npl_eventq_unlock(locked); } else { TickType_t deadline = 0; TickType_t remaining; @@ -364,7 +376,8 @@ IRAM_ATTR npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo return NULL; } - npl_eventq_lock(); + bool locked = npl_eventq_lock(); + portENTER_CRITICAL(&ble_port_mutex); ret = xQueueReceive(eventq->q, &ev, 0); if (ret == pdPASS && ev != NULL) { @@ -372,12 +385,13 @@ IRAM_ATTR npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo if (event) { event->queued = false; } - portEXIT_CRITICAL(&ble_port_mutex); - npl_eventq_unlock(); - break; } portEXIT_CRITICAL(&ble_port_mutex); - npl_eventq_unlock(); + if (ret == pdPASS && ev != NULL) { + npl_eventq_unlock(locked); + break; + } + npl_eventq_unlock(locked); } } @@ -407,10 +421,10 @@ IRAM_ATTR npl_freertos_eventq_put(struct ble_npl_eventq *evq, struct ble_npl_eve } return; } else { - npl_eventq_lock(); + bool locked = npl_eventq_lock(); if (npl_eventq_queued_claim(event)) { - npl_eventq_unlock(); + npl_eventq_unlock(locked); return; } @@ -419,7 +433,7 @@ IRAM_ATTR npl_freertos_eventq_put(struct ble_npl_eventq *evq, struct ble_npl_eve ESP_LOGW("NimBLE", "eventq put: queue full, event dropped"); npl_eventq_queued_set_task(event, false); } - npl_eventq_unlock(); + npl_eventq_unlock(locked); } } @@ -446,10 +460,10 @@ IRAM_ATTR npl_freertos_eventq_put_to_front(struct ble_npl_eventq *evq, struct bl } return; } else { - npl_eventq_lock(); + bool locked = npl_eventq_lock(); if (npl_eventq_queued_claim(event)) { - npl_eventq_unlock(); + npl_eventq_unlock(locked); return; } @@ -458,7 +472,7 @@ IRAM_ATTR npl_freertos_eventq_put_to_front(struct ble_npl_eventq *evq, struct bl ESP_LOGW("NimBLE", "eventq put_to_front: queue full, event dropped"); npl_eventq_queued_set_task(event, false); } - npl_eventq_unlock(); + npl_eventq_unlock(locked); } } @@ -522,9 +536,10 @@ IRAM_ATTR npl_freertos_eventq_remove(struct ble_npl_eventq *evq, } else { removed = false; - npl_eventq_lock(); + bool locked = npl_eventq_lock(); + if (!npl_eventq_queued_get_task(event)) { - npl_eventq_unlock(); + npl_eventq_unlock(locked); return; } @@ -548,11 +563,10 @@ IRAM_ATTR npl_freertos_eventq_remove(struct ble_npl_eventq *evq, } } if (removed) { - event->queued = 0; + event->queued = false; } portEXIT_CRITICAL(&ble_port_mutex); - - npl_eventq_unlock(); + npl_eventq_unlock(locked); } } @@ -1231,26 +1245,40 @@ IRAM_ATTR npl_freertos_time_delay(ble_npl_time_t ticks) } -uint8_t hw_critical_state_status = 0; - uint32_t IRAM_ATTR npl_freertos_hw_enter_critical(void) { - ++hw_critical_state_status; + BaseType_t core; + portENTER_CRITICAL(&ble_port_mutex); + core = xPortGetCoreID(); + if (core < portNUM_PROCESSORS) { + ++hw_critical_state_status[core]; + } return 0; } uint8_t IRAM_ATTR npl_freertos_hw_is_in_critical(void) { - return hw_critical_state_status; + BaseType_t core; + + core = xPortGetCoreID(); + if (core >= portNUM_PROCESSORS) { + return 0; + } + return hw_critical_state_status[core]; } void IRAM_ATTR npl_freertos_hw_exit_critical(uint32_t ctx) { - --hw_critical_state_status; + BaseType_t core; + + core = xPortGetCoreID(); + if (core < portNUM_PROCESSORS && hw_critical_state_status[core] > 0) { + --hw_critical_state_status[core]; + } portEXIT_CRITICAL(&ble_port_mutex); }