From 74c528d836dbdfb26f976b5341420fa517708f9b Mon Sep 17 00:00:00 2001 From: Hrishikesh Dhayagude Date: Wed, 4 Mar 2020 12:01:53 +0530 Subject: [PATCH] NimBLE: Use dynamic buffers instead of static memory. The NimBLE host buffers that consume a significant amount of memory are now allocated dynamically. The advantage is that, the memory can be reclaimed in cases where BLE is turned off and not required for the current boot cycle --- components/bt/CMakeLists.txt | 3 +- components/bt/component.mk | 3 +- components/bt/host/nimble/Kconfig.in | 29 ++++++ .../host/nimble/esp-hci/src/esp_nimble_hci.c | 88 +++++++++++++++---- .../host/nimble/port/include/esp_nimble_mem.h | 39 ++++++++ .../bt/host/nimble/port/src/esp_nimble_mem.c | 52 +++++++++++ 6 files changed, 194 insertions(+), 20 deletions(-) create mode 100644 components/bt/host/nimble/port/include/esp_nimble_mem.h create mode 100644 components/bt/host/nimble/port/src/esp_nimble_mem.c diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index 7032057e5..a3d6fa944 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -495,7 +495,8 @@ if(CONFIG_BT_ENABLED) "host/nimble/nimble/porting/nimble/src/mem.c" "host/nimble/nimble/porting/nimble/src/os_mbuf.c" "host/nimble/nimble/porting/nimble/src/os_cputime.c" - "host/nimble/esp-hci/src/esp_nimble_hci.c") + "host/nimble/esp-hci/src/esp_nimble_hci.c" + "host/nimble/port/src/esp_nimble_mem.c") if (CONFIG_BLE_MESH) list(APPEND srcs "esp_ble_mesh/mesh_core/nimble_host/mesh_bearer_adapt.c") diff --git a/components/bt/component.mk b/components/bt/component.mk index 7e8e4464b..5c1a29e6c 100644 --- a/components/bt/component.mk +++ b/components/bt/component.mk @@ -197,7 +197,8 @@ COMPONENT_SRCDIRS += host/nimble/nimble/nimble/host/src host/nimble/nimble/nimble/host/util/src \ host/nimble/nimble/nimble/host/store/ram/src \ host/nimble/nimble/nimble/host/store/config/src \ - host/nimble/esp-hci/src + host/nimble/esp-hci/src \ + host/nimble/port/src ifndef CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS COMPONENT_SRCDIRS += host/nimble/nimble/ext/tinycrypt/src diff --git a/components/bt/host/nimble/Kconfig.in b/components/bt/host/nimble/Kconfig.in index b56b900f3..918ba48e7 100644 --- a/components/bt/host/nimble/Kconfig.in +++ b/components/bt/host/nimble/Kconfig.in @@ -1,4 +1,33 @@ +choice BT_NIMBLE_MEM_ALLOC_MODE + prompt "Memory allocation strategy" + default BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL + help + Allocation strategy for NimBLE host stack, essentially provides ability to + allocate all required dynamic allocations from, + + - Internal DRAM memory only + - External SPIRAM memory only + - Either internal or external memory based on default malloc() + behavior in ESP-IDF + + Recommended mode here is always internal, since that is most preferred + from security perspective. But if application requirement does not + allow sufficient free internal memory then alternate mode can be + selected. + + config BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL + bool "Internal memory" + + config BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL + bool "External SPIRAM" + depends on ESP32_SPIRAM_SUPPORT + + config BT_NIMBLE_MEM_ALLOC_MODE_DEFAULT + bool "Default alloc mode" + +endchoice + config BT_NIMBLE_MAX_CONNECTIONS int "Maximum number of concurrent connections" range 1 9 diff --git a/components/bt/host/nimble/esp-hci/src/esp_nimble_hci.c b/components/bt/host/nimble/esp-hci/src/esp_nimble_hci.c index 0c0e9ce98..e4ab99932 100644 --- a/components/bt/host/nimble/esp-hci/src/esp_nimble_hci.c +++ b/components/bt/host/nimble/esp-hci/src/esp_nimble_hci.c @@ -26,6 +26,7 @@ #include "nimble/nimble_port.h" #include "nimble/nimble_port_freertos.h" #include "esp_nimble_hci.h" +#include "esp_nimble_mem.h" #include "esp_bt.h" #include "freertos/semphr.h" #include "esp_compiler.h" @@ -49,30 +50,23 @@ static struct os_mempool_ext ble_hci_acl_pool; + BLE_MBUF_MEMBLOCK_OVERHEAD \ + BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT) -static os_membuf_t ble_hci_acl_buf[ - OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ACL_BUF_COUNT), - ACL_BLOCK_SIZE)]; +static os_membuf_t *ble_hci_acl_buf; static struct os_mempool ble_hci_cmd_pool; -static os_membuf_t ble_hci_cmd_buf[ - OS_MEMPOOL_SIZE(1, BLE_HCI_TRANS_CMD_SZ) -]; +static os_membuf_t *ble_hci_cmd_buf; static struct os_mempool ble_hci_evt_hi_pool; -static os_membuf_t ble_hci_evt_hi_buf[ - OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) -]; +static os_membuf_t *ble_hci_evt_hi_buf; static struct os_mempool ble_hci_evt_lo_pool; -static os_membuf_t ble_hci_evt_lo_buf[ - OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) -]; +static os_membuf_t *ble_hci_evt_lo_buf; static SemaphoreHandle_t vhci_send_sem; const static char *TAG = "NimBLE"; +int os_msys_buf_alloc(void); +void os_msys_buf_free(void); + void ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb, void *cmd_arg, ble_hci_trans_rx_acl_fn *acl_cb, @@ -379,24 +373,75 @@ static const esp_vhci_host_callback_t vhci_host_cb = { .notify_host_recv = host_rcv_pkt, }; +static void ble_buf_free(void) +{ + os_msys_buf_free(); + + nimble_platform_mem_free(ble_hci_evt_hi_buf); + ble_hci_evt_hi_buf = NULL; + nimble_platform_mem_free(ble_hci_evt_lo_buf); + ble_hci_evt_lo_buf = NULL; + nimble_platform_mem_free(ble_hci_cmd_buf); + ble_hci_cmd_buf = NULL; + nimble_platform_mem_free(ble_hci_acl_buf); + ble_hci_acl_buf = NULL; +} + +static esp_err_t ble_buf_alloc(void) +{ + if (os_msys_buf_alloc()) { + return ESP_ERR_NO_MEM; + } + + ble_hci_evt_hi_buf = (os_membuf_t *) nimble_platform_mem_calloc(1, + (sizeof(os_membuf_t) * OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)))); + + ble_hci_evt_lo_buf = (os_membuf_t *) nimble_platform_mem_calloc(1, + (sizeof(os_membuf_t) * OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)))); + + ble_hci_cmd_buf = (os_membuf_t *) nimble_platform_mem_calloc(1, + (sizeof(os_membuf_t) * OS_MEMPOOL_SIZE(1, BLE_HCI_TRANS_CMD_SZ))); + + ble_hci_acl_buf = (os_membuf_t *) nimble_platform_mem_calloc(1, + (sizeof(os_membuf_t) * OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ACL_BUF_COUNT), + ACL_BLOCK_SIZE))); + + if (!ble_hci_evt_hi_buf || !ble_hci_evt_lo_buf || !ble_hci_cmd_buf || !ble_hci_acl_buf) { + ble_buf_free(); + return ESP_ERR_NO_MEM; + } + return ESP_OK; +} esp_err_t esp_nimble_hci_init(void) { esp_err_t ret; + + ret = ble_buf_alloc(); + if (ret != ESP_OK) { + goto err; + } if ((ret = esp_vhci_host_register_callback(&vhci_host_cb)) != ESP_OK) { - return ret; + goto err; } ble_hci_transport_init(); vhci_send_sem = xSemaphoreCreateBinary(); if (vhci_send_sem == NULL) { - return ESP_ERR_NO_MEM; + ret = ESP_ERR_NO_MEM; + goto err; } xSemaphoreGive(vhci_send_sem); - return ESP_OK; + return ret; +err: + ble_buf_free(); + return ret; + } esp_err_t esp_nimble_hci_and_controller_init(void) @@ -445,7 +490,14 @@ esp_err_t esp_nimble_hci_deinit(void) vSemaphoreDelete(vhci_send_sem); vhci_send_sem = NULL; } - return ble_hci_transport_deinit(); + esp_err_t ret = ble_hci_transport_deinit(); + if (ret != ESP_OK) { + return ret; + } + + ble_buf_free(); + + return ESP_OK; } esp_err_t esp_nimble_hci_and_controller_deinit(void) diff --git a/components/bt/host/nimble/port/include/esp_nimble_mem.h b/components/bt/host/nimble/port/include/esp_nimble_mem.h new file mode 100644 index 000000000..90e52a20d --- /dev/null +++ b/components/bt/host/nimble/port/include/esp_nimble_mem.h @@ -0,0 +1,39 @@ +/* + * Copyright 2020 Espressif Systems (Shanghai) PTE LTD + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef __ESP_NIMBLE_MEM_H__ +#define __ESP_NIMBLE_MEM_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void *nimble_platform_mem_malloc(size_t size); +void *nimble_platform_mem_calloc(size_t n, size_t size); +void nimble_platform_mem_free(void *ptr); + +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_NIMBLE_MEM_H__ */ diff --git a/components/bt/host/nimble/port/src/esp_nimble_mem.c b/components/bt/host/nimble/port/src/esp_nimble_mem.c new file mode 100644 index 000000000..95d0d930e --- /dev/null +++ b/components/bt/host/nimble/port/src/esp_nimble_mem.c @@ -0,0 +1,52 @@ +/* + * Copyright 2020 Espressif Systems (Shanghai) PTE LTD + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "esp_attr.h" +#include "esp_heap_caps.h" +#include "sdkconfig.h" +#include "esp_nimble_mem.h" + +IRAM_ATTR void *nimble_platform_mem_malloc(size_t size) +{ +#ifdef CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL + return heap_caps_malloc(size, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); +#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL + return heap_caps_malloc(size, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT); +#else + return malloc(size); +#endif +} + +IRAM_ATTR void *nimble_platform_mem_calloc(size_t n, size_t size) +{ +#ifdef CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL + return heap_caps_calloc(n, size, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); +#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL + return heap_caps_calloc(n, size, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT); +#else + return calloc(n, size); +#endif +} + +IRAM_ATTR void nimble_platform_mem_free(void *ptr) +{ + heap_caps_free(ptr); +}