From cda7dc8c825b9923e7659536186ab6fc0a6db103 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 17 Jun 2019 15:54:45 +0300 Subject: [PATCH 1/2] Bluetooth: Add dedicated pool for HCI_Num_Completed_Packets HCI event This event is a priority one, so it's not safe to have it use the RX buffer pool which may be depleted due to non-priority events (e.g. advertising events). Since the event is consumed synchronously it's safe to have a single-buffer pool for it. Also introduce a new bt_buf_get_evt() API for HCI drivers to simplify the driver-side code, this effectively also deprecates bt_buf_get_cmd_complete() which now has no in-tree HCI driver users anymore. Fixes #16864 Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci/h4.c | 11 +- drivers/bluetooth/hci/h5.c | 11 +- drivers/bluetooth/hci/ipm_stm32wb.c | 394 +++++++++++++++++++ drivers/bluetooth/hci/spi.c | 7 +- drivers/bluetooth/hci/userchan.c | 11 +- include/bluetooth/buf.h | 12 + subsys/bluetooth/controller/hci/hci.c | 4 +- subsys/bluetooth/controller/hci/hci_driver.c | 3 +- subsys/bluetooth/host/hci_core.c | 35 ++ subsys/bluetooth/host/hci_ecc.c | 2 +- subsys/bluetooth/host/hci_raw.c | 12 + tests/bluetooth/hci_prop_evt/src/main.c | 386 ++++++++++++++++++ 12 files changed, 853 insertions(+), 35 deletions(-) create mode 100644 drivers/bluetooth/hci/ipm_stm32wb.c create mode 100644 tests/bluetooth/hci_prop_evt/src/main.c diff --git a/drivers/bluetooth/hci/h4.c b/drivers/bluetooth/hci/h4.c index 70a8fbbf96a319..c3fe9038d99cfd 100644 --- a/drivers/bluetooth/hci/h4.c +++ b/drivers/bluetooth/hci/h4.c @@ -165,16 +165,11 @@ static struct net_buf *get_rx(int timeout) { BT_DBG("type 0x%02x, evt 0x%02x", rx.type, rx.evt.evt); - if (rx.type == H4_EVT && (rx.evt.evt == BT_HCI_EVT_CMD_COMPLETE || - rx.evt.evt == BT_HCI_EVT_CMD_STATUS)) { - return bt_buf_get_cmd_complete(timeout); + if (rx.type == H4_EVT) { + return bt_buf_get_evt(rx.evt.evt, timeout); } - if (rx.type == H4_ACL) { - return bt_buf_get_rx(BT_BUF_ACL_IN, timeout); - } else { - return bt_buf_get_rx(BT_BUF_EVT, timeout); - } + return bt_buf_get_rx(BT_BUF_ACL_IN, timeout); } static void rx_thread(void *p1, void *p2, void *p3) diff --git a/drivers/bluetooth/hci/h5.c b/drivers/bluetooth/hci/h5.c index 34ee0b19b20812..3d5ae9a34114a1 100644 --- a/drivers/bluetooth/hci/h5.c +++ b/drivers/bluetooth/hci/h5.c @@ -408,16 +408,7 @@ static inline struct net_buf *get_evt_buf(u8_t evt) { struct net_buf *buf; - switch (evt) { - case BT_HCI_EVT_CMD_COMPLETE: - case BT_HCI_EVT_CMD_STATUS: - buf = bt_buf_get_cmd_complete(K_NO_WAIT); - break; - default: - buf = bt_buf_get_rx(BT_BUF_EVT, K_NO_WAIT); - break; - } - + buf = bt_buf_get_evt(evt, K_NO_WAIT); if (buf) { net_buf_add_u8(h5.rx_buf, evt); } diff --git a/drivers/bluetooth/hci/ipm_stm32wb.c b/drivers/bluetooth/hci/ipm_stm32wb.c new file mode 100644 index 00000000000000..9f2b95129f674e --- /dev/null +++ b/drivers/bluetooth/hci/ipm_stm32wb.c @@ -0,0 +1,394 @@ +/* ipm_stm32wb.c - HCI driver for stm32wb shared ram */ + +/* + * Copyright (c) 2019 Linaro Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#include +#include + +#include +#include + +#include "app_conf.h" +#include "stm32_wpan_common.h" +#include "shci.h" +#include "shci_tl.h" + +#define POOL_SIZE (CFG_TLBLE_EVT_QUEUE_LENGTH * 4 * \ + DIVC((sizeof(TL_PacketHeader_t) + TL_BLE_EVENT_FRAME_SIZE), 4)) + +/* Private variables ---------------------------------------------------------*/ +PLACE_IN_SECTION("MB_MEM1") ALIGN(4) static TL_CmdPacket_t BleCmdBuffer; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static u8_t EvtPool[POOL_SIZE]; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static TL_CmdPacket_t SystemCmdBuffer; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static u8_t + SystemSpareEvtBuffer[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255]; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static u8_t + BleSpareEvtBuffer[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255]; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static u8_t + HciAclDataBuffer[sizeof(TL_PacketHeader_t) + 5 + 251]; + +static void syscmd_status_not(SHCI_TL_CmdStatus_t status); +static void sysevt_received(void *pdata); + +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER) +#define LOG_MODULE_NAME hci_ipm +#include "common/log.h" + +#define HCI_CMD 0x01 +#define HCI_ACL 0x02 +#define HCI_SCO 0x03 +#define HCI_EVT 0x04 + +static K_SEM_DEFINE(c2_started, 0, 1); +static K_SEM_DEFINE(ble_sys_wait_cmd_rsp, 0, 1); +static K_SEM_DEFINE(acl_data_ack, 1, 1); +static K_SEM_DEFINE(ipm_busy, 1, 1); + +struct aci_set_tx_power { + u8_t cmd; + u8_t value[2]; +}; + +#define ACI_WRITE_SET_TX_POWER_LEVEL BT_OP(BT_OGF_VS, 0xFC0F) + +static void stm32wb_start_ble(void) +{ + SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet = { + { { 0, 0, 0 } }, /**< Header unused */ + { 0, /** pBleBufferAddress not used */ + 0, /** BleBufferSize not used */ + CFG_BLE_NUM_GATT_ATTRIBUTES, + CFG_BLE_NUM_GATT_SERVICES, + CFG_BLE_ATT_VALUE_ARRAY_SIZE, + CFG_BLE_NUM_LINK, + CFG_BLE_DATA_LENGTH_EXTENSION, + CFG_BLE_PREPARE_WRITE_LIST_SIZE, + CFG_BLE_MBLOCK_COUNT, + CFG_BLE_MAX_ATT_MTU, + CFG_BLE_SLAVE_SCA, + CFG_BLE_MASTER_SCA, + CFG_BLE_LSE_SOURCE, + CFG_BLE_MAX_CONN_EVENT_LENGTH, + CFG_BLE_HSE_STARTUP_TIME, + CFG_BLE_VITERBI_MODE, + CFG_BLE_LL_ONLY, + 0 } + }; + + /** + * Starts the BLE Stack on CPU2 + */ + SHCI_C2_BLE_Init(&ble_init_cmd_packet); +} + +static void sysevt_received(void *pdata) +{ + k_sem_give(&c2_started); +} + +static void syscmd_status_not(SHCI_TL_CmdStatus_t status) +{ + BT_DBG("status:%d", status); +} + +void TM_EvtReceivedCb(TL_EvtPacket_t *hcievt) +{ + struct net_buf *buf; + struct bt_hci_acl_hdr acl_hdr; + TL_AclDataSerial_t *acl; + + k_sem_take(&ipm_busy, K_NO_WAIT); + + switch (hcievt->evtserial.type) { + case HCI_EVT: + BT_DBG("EVT: hcievt->evtserial.evt.evtcode: 0x%02x", + hcievt->evtserial.evt.evtcode); + switch (hcievt->evtserial.evt.evtcode) { + case BT_HCI_EVT_VENDOR: + /* Vendor events are currently unsupported */ + BT_ERR("Unknown evtcode type 0x%02x", + hcievt->evtserial.evt.evtcode); + goto out; + default: + buf = bt_buf_get_evt(evtserial.evt.evtcode, K_FOREVER); + break; + } + net_buf_add_mem(buf, &hcievt->evtserial.evt, + hcievt->evtserial.evt.plen + 2); + break; + case HCI_ACL: + acl = &(((TL_AclDataPacket_t *)hcievt)->AclDataSerial); + buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_FOREVER); + acl_hdr.handle = acl->handle; + acl_hdr.len = acl->length; + BT_DBG("ACL: handle %x, len %x", acl_hdr.handle, acl_hdr.len); + net_buf_add_mem(buf, &acl_hdr, sizeof(acl_hdr)); + net_buf_add_mem(buf, (u8_t *)&acl->acl_data, acl_hdr.len); + break; + default: + BT_ERR("Unknown BT buf type %d", hcievt->evtserial.type); + TL_MM_EvtDone(hcievt); + goto out; + } + + TL_MM_EvtDone(hcievt); + + if (hcievt->evtserial.type == HCI_EVT && + bt_hci_evt_is_prio(hcievt->evtserial.evt.evtcode)) { + bt_recv_prio(buf); + } else { + bt_recv(buf); + } + +out: + k_sem_give(&ipm_busy); +} + +static void TM_AclDataAck(void) +{ + k_sem_give(&acl_data_ack); +} + +void shci_notify_asynch_evt(void *pdata) +{ + shci_user_evt_proc(); +} + +void shci_cmd_resp_release(uint32_t flag) +{ + k_sem_give(&ble_sys_wait_cmd_rsp); +} + +void shci_cmd_resp_wait(uint32_t timeout) +{ + k_sem_take(&ble_sys_wait_cmd_rsp, timeout); +} + +void ipcc_reset(void) +{ + /* Reset IPCC */ + LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_IPCC); + + LL_C1_IPCC_ClearFlag_CHx( + IPCC, + LL_IPCC_CHANNEL_1 | LL_IPCC_CHANNEL_2 | LL_IPCC_CHANNEL_3 | + LL_IPCC_CHANNEL_4 | LL_IPCC_CHANNEL_5 | LL_IPCC_CHANNEL_6); + + LL_C2_IPCC_ClearFlag_CHx( + IPCC, + LL_IPCC_CHANNEL_1 | LL_IPCC_CHANNEL_2 | LL_IPCC_CHANNEL_3 | + LL_IPCC_CHANNEL_4 | LL_IPCC_CHANNEL_5 | LL_IPCC_CHANNEL_6); + + LL_C1_IPCC_DisableTransmitChannel( + IPCC, + LL_IPCC_CHANNEL_1 | LL_IPCC_CHANNEL_2 | LL_IPCC_CHANNEL_3 | + LL_IPCC_CHANNEL_4 | LL_IPCC_CHANNEL_5 | LL_IPCC_CHANNEL_6); + + LL_C2_IPCC_DisableTransmitChannel( + IPCC, + LL_IPCC_CHANNEL_1 | LL_IPCC_CHANNEL_2 | LL_IPCC_CHANNEL_3 | + LL_IPCC_CHANNEL_4 | LL_IPCC_CHANNEL_5 | LL_IPCC_CHANNEL_6); + + LL_C1_IPCC_DisableReceiveChannel( + IPCC, + LL_IPCC_CHANNEL_1 | LL_IPCC_CHANNEL_2 | LL_IPCC_CHANNEL_3 | + LL_IPCC_CHANNEL_4 | LL_IPCC_CHANNEL_5 | LL_IPCC_CHANNEL_6); + + LL_C2_IPCC_DisableReceiveChannel( + IPCC, + LL_IPCC_CHANNEL_1 | LL_IPCC_CHANNEL_2 | LL_IPCC_CHANNEL_3 | + LL_IPCC_CHANNEL_4 | LL_IPCC_CHANNEL_5 | LL_IPCC_CHANNEL_6); + + /* Set IPCC default IRQ handlers */ + IRQ_CONNECT(IPCC_C1_RX_IRQn, 0, HW_IPCC_Rx_Handler, NULL, 0); + IRQ_CONNECT(IPCC_C1_TX_IRQn, 0, HW_IPCC_Tx_Handler, NULL, 0); +} + +void transport_init(void) +{ + TL_MM_Config_t tl_mm_config; + TL_BLE_InitConf_t tl_ble_config; + SHCI_TL_HciInitConf_t shci_init_config; + + BT_DBG("BleCmdBuffer: %p", (void *)&BleCmdBuffer); + BT_DBG("HciAclDataBuffer: %p", (void *)&HciAclDataBuffer); + BT_DBG("SystemCmdBuffer: %p", (void *)&SystemCmdBuffer); + BT_DBG("EvtPool: %p", (void *)&EvtPool); + BT_DBG("SystemSpareEvtBuffer: %p", (void *)&SystemSpareEvtBuffer); + BT_DBG("BleSpareEvtBuffer: %p", (void *)&BleSpareEvtBuffer); + + /**< Reference table initialization */ + TL_Init(); + + /**< System channel initialization */ + shci_init_config.p_cmdbuffer = (u8_t *)&SystemCmdBuffer; + shci_init_config.StatusNotCallBack = syscmd_status_not; + shci_init(sysevt_received, (void *) &shci_init_config); + + /**< Memory Manager channel initialization */ + tl_mm_config.p_BleSpareEvtBuffer = BleSpareEvtBuffer; + tl_mm_config.p_SystemSpareEvtBuffer = SystemSpareEvtBuffer; + tl_mm_config.p_AsynchEvtPool = EvtPool; + tl_mm_config.AsynchEvtPoolSize = POOL_SIZE; + TL_MM_Init(&tl_mm_config); + + /**< BLE channel initialization */ + tl_ble_config.p_cmdbuffer = (u8_t *)&BleCmdBuffer; + tl_ble_config.p_AclDataBuffer = HciAclDataBuffer; + tl_ble_config.IoBusEvtCallBack = TM_EvtReceivedCb; + tl_ble_config.IoBusAclDataTxAck = TM_AclDataAck; + TL_BLE_Init((void *)&tl_ble_config); + + TL_Enable(); +} + +static int bt_ipm_send(struct net_buf *buf) +{ + TL_CmdPacket_t *ble_cmd_buff = &BleCmdBuffer; + + k_sem_take(&ipm_busy, K_FOREVER); + + switch (bt_buf_get_type(buf)) { + case BT_BUF_ACL_OUT: + BT_DBG("ACL: buf %p type %u len %u", buf, bt_buf_get_type(buf), + buf->len); + k_sem_take(&acl_data_ack, K_FOREVER); + net_buf_push_u8(buf, HCI_ACL); + memcpy((void *) + &((TL_AclDataPacket_t *)HciAclDataBuffer)->AclDataSerial, + buf->data, buf->len); + TL_BLE_SendAclData(NULL, 0); + break; + case BT_BUF_CMD: + BT_DBG("CMD: buf %p type %u len %u", buf, bt_buf_get_type(buf), + buf->len); + ble_cmd_buff->cmdserial.type = HCI_CMD; + ble_cmd_buff->cmdserial.cmd.plen = buf->len; + memcpy((void *)&ble_cmd_buff->cmdserial.cmd, buf->data, + buf->len); + TL_BLE_SendCmd(NULL, 0); + break; + default: + k_sem_give(&ipm_busy); + BT_ERR("Unsupported type"); + return -EINVAL; + } + + k_sem_give(&ipm_busy); + + net_buf_unref(buf); + + return 0; +} + +static void start_ble_rf(void) +{ + if ((LL_RCC_IsActiveFlag_PINRST()) && (!LL_RCC_IsActiveFlag_SFTRST())) { + /* Simulate power off reset */ + LL_PWR_EnableBkUpAccess(); + LL_PWR_EnableBkUpAccess(); + LL_RCC_ForceBackupDomainReset(); + LL_RCC_ReleaseBackupDomainReset(); + } + + /* Select LSE clock */ + LL_RCC_LSE_Enable(); + while (!LL_RCC_LSE_IsReady()) { + } + + /* Select wakeup source of BLE RF */ + LL_RCC_SetRFWKPClockSource(LL_RCC_RFWKP_CLKSOURCE_LSE); + LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSE); + + /* Switch OFF LSI */ + LL_RCC_LSI1_Disable(); + /* Set RNG on HSI48 */ + LL_RCC_HSI48_Enable(); + while (!LL_RCC_HSI48_IsReady()) { + } + + LL_RCC_SetCLK48ClockSource(LL_RCC_CLK48_CLKSOURCE_HSI48); +} + +static int bt_ipm_ble_init(void) +{ + struct aci_set_tx_power *param; + struct net_buf *buf, *rsp; + int err; + + /* Send HCI_RESET */ + err = bt_hci_cmd_send_sync(BT_HCI_OP_RESET, NULL, &rsp); + if (err) { + return err; + } + /* TDB: Something to do on reset complete? */ + net_buf_unref(rsp); + + /* Send ACI_WRITE_SET_TX_POWER_LEVEL */ + buf = bt_hci_cmd_create(ACI_WRITE_SET_TX_POWER_LEVEL, 3); + if (!buf) { + return -ENOBUFS; + } + param = net_buf_add(buf, sizeof(*param)); + param->cmd = 0x0F; + param->value[0] = 0x18; + param->value[1] = 0x01; + + err = bt_hci_cmd_send_sync(ACI_WRITE_SET_TX_POWER_LEVEL, buf, &rsp); + if (err) { + return err; + } + net_buf_unref(rsp); + + return 0; +} + +static int bt_ipm_open(void) +{ + int err; + + /* Take BLE out of reset */ + ipcc_reset(); + + transport_init(); + + /* Device will let us know when it's ready */ + k_sem_take(&c2_started, K_FOREVER); + BT_DBG("C2 unlocked"); + + stm32wb_start_ble(); + + BT_DBG("IPM Channel Open Completed"); + + err = bt_ipm_ble_init(); + if (err) { + return err; + } + + return 0; +} + +static const struct bt_hci_driver drv = { + .name = "BT IPM", + .bus = BT_HCI_DRIVER_BUS_IPM, + .quirks = BT_QUIRK_NO_RESET, + .open = bt_ipm_open, + .send = bt_ipm_send, +}; + +static int _bt_ipm_init(struct device *unused) +{ + ARG_UNUSED(unused); + + bt_hci_driver_register(&drv); + + start_ble_rf(); + return 0; +} + +SYS_INIT(_bt_ipm_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); diff --git a/drivers/bluetooth/hci/spi.c b/drivers/bluetooth/hci/spi.c index b83e288872b519..1115820d96c600 100644 --- a/drivers/bluetooth/hci/spi.c +++ b/drivers/bluetooth/hci/spi.c @@ -353,12 +353,9 @@ static void bt_spi_rx_thread(void) /* Vendor events are currently unsupported */ bt_spi_handle_vendor_evt(rxmsg); continue; - case BT_HCI_EVT_CMD_COMPLETE: - case BT_HCI_EVT_CMD_STATUS: - buf = bt_buf_get_cmd_complete(K_FOREVER); - break; default: - buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER); + buf = bt_buf_get_evt(rxmsg[EVT_HEADER_EVENT], + K_FOREVER); break; } diff --git a/drivers/bluetooth/hci/userchan.c b/drivers/bluetooth/hci/userchan.c index d6be3863a66bd9..749cfab3061862 100644 --- a/drivers/bluetooth/hci/userchan.c +++ b/drivers/bluetooth/hci/userchan.c @@ -57,16 +57,11 @@ static int bt_dev_index = -1; static struct net_buf *get_rx(const u8_t *buf) { - if (buf[0] == H4_EVT && (buf[1] == BT_HCI_EVT_CMD_COMPLETE || - buf[1] == BT_HCI_EVT_CMD_STATUS)) { - return bt_buf_get_cmd_complete(K_FOREVER); + if (buf[0] == H4_EVT) { + return bt_buf_get_evt(buf[1], K_FOREVER); } - if (buf[0] == H4_ACL) { - return bt_buf_get_rx(BT_BUF_ACL_IN, K_FOREVER); - } else { - return bt_buf_get_rx(BT_BUF_EVT, K_FOREVER); - } + return bt_buf_get_rx(BT_BUF_ACL_IN, K_FOREVER); } static bool uc_ready(void) diff --git a/include/bluetooth/buf.h b/include/bluetooth/buf.h index a71f14ed0e67bc..f71a3672dc5003 100644 --- a/include/bluetooth/buf.h +++ b/include/bluetooth/buf.h @@ -64,6 +64,18 @@ struct net_buf *bt_buf_get_rx(enum bt_buf_type type, s32_t timeout); */ struct net_buf *bt_buf_get_cmd_complete(s32_t timeout); +/** Allocate a buffer for an HCI Event + * + * This will set the buffer type so bt_buf_set_type() does not need to + * be explicitly called before bt_recv_prio() or bt_recv(). + * + * @param evt HCI event code + * @param timeout Timeout in milliseconds, or one of the special values + * K_NO_WAIT and K_FOREVER. + * @return A new buffer. + */ +struct net_buf *bt_buf_get_evt(u8_t evt, s32_t timeout); + /** Set the buffer type * * @param buf Bluetooth buffer diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index 5acf21032f997f..800b8037312acd 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -115,7 +115,7 @@ static void *cmd_complete(struct net_buf **buf, u8_t plen) { struct bt_hci_evt_cmd_complete *cc; - *buf = bt_buf_get_cmd_complete(K_FOREVER); + *buf = bt_buf_get_evt(BT_HCI_EVT_CMD_COMPLETE, K_FOREVER); evt_create(*buf, BT_HCI_EVT_CMD_COMPLETE, sizeof(*cc) + plen); @@ -132,7 +132,7 @@ static struct net_buf *cmd_status(u8_t status) struct bt_hci_evt_cmd_status *cs; struct net_buf *buf; - buf = bt_buf_get_cmd_complete(K_FOREVER); + buf = bt_buf_get_evt(BT_HCI_EVT_CMD_STATUS, K_FOREVER); evt_create(buf, BT_HCI_EVT_CMD_STATUS, sizeof(*cs)); cs = net_buf_add(buf, sizeof(*cs)); diff --git a/subsys/bluetooth/controller/hci/hci_driver.c b/subsys/bluetooth/controller/hci/hci_driver.c index 8deb308fabb036..84482699449eb5 100644 --- a/subsys/bluetooth/controller/hci/hci_driver.c +++ b/subsys/bluetooth/controller/hci/hci_driver.c @@ -87,7 +87,8 @@ static void prio_recv_thread(void *p1, void *p2, void *p3) #if defined(CONFIG_BT_CONN) struct net_buf *buf; - buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER); + buf = bt_buf_get_evt(BT_HCI_EVT_NUM_COMPLETED_PACKETS, + K_FOREVER); hci_num_cmplt_encode(buf, handle, num_cmplt); BT_DBG("Num Complete: 0x%04x:%u", handle, num_cmplt); bt_recv_prio(buf); diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index b7cc7ac542aeb6..153c0423445528 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -133,6 +133,16 @@ NET_BUF_POOL_DEFINE(hci_cmd_pool, CONFIG_BT_HCI_CMD_COUNT, NET_BUF_POOL_DEFINE(hci_rx_pool, CONFIG_BT_RX_BUF_COUNT, BT_BUF_RX_SIZE, BT_BUF_USER_DATA_MIN, NULL); +#if defined(CONFIG_BT_CONN) +/* Dedicated pool for HCI_Number_of_Completed_Packets. This event is always + * consumed synchronously by bt_recv_prio() so a single buffer is enough. + * Having a dedicated pool for it ensures that exhaustion of the RX pool + * cannot block the delivery of this priority event. + */ +NET_BUF_POOL_DEFINE(num_complete_pool, 1, BT_BUF_RX_SIZE, + BT_BUF_USER_DATA_MIN, NULL); +#endif /* CONFIG_BT_CONN */ + struct event_handler { u8_t event; u8_t min_len; @@ -5625,6 +5635,31 @@ struct net_buf *bt_buf_get_cmd_complete(s32_t timeout) return bt_buf_get_rx(BT_BUF_EVT, timeout); } +struct net_buf *bt_buf_get_evt(u8_t evt, s32_t timeout) +{ + switch (evt) { +#if defined(CONFIG_BT_CONN) + case BT_HCI_EVT_NUM_COMPLETED_PACKETS: + { + struct net_buf *buf; + + buf = net_buf_alloc(&num_complete_pool, timeout); + if (buf) { + net_buf_reserve(buf, CONFIG_BT_HCI_RESERVE); + bt_buf_set_type(buf, BT_BUF_EVT); + } + + return buf; + } +#endif /* CONFIG_BT_CONN */ + case BT_HCI_EVT_CMD_COMPLETE: + case BT_HCI_EVT_CMD_STATUS: + return bt_buf_get_cmd_complete(timeout); + default: + return bt_buf_get_rx(BT_BUF_EVT, timeout); + } +} + #if defined(CONFIG_BT_BREDR) static int br_start_inquiry(const struct bt_br_discovery_param *param) { diff --git a/subsys/bluetooth/host/hci_ecc.c b/subsys/bluetooth/host/hci_ecc.c index 683c06412dae62..75ae8d2892ebdf 100644 --- a/subsys/bluetooth/host/hci_ecc.c +++ b/subsys/bluetooth/host/hci_ecc.c @@ -84,7 +84,7 @@ static void send_cmd_status(u16_t opcode, u8_t status) BT_DBG("opcode %x status %x", opcode, status); - buf = bt_buf_get_cmd_complete(K_FOREVER); + buf = bt_buf_get_evt(BT_HCI_EVT_CMD_STATUS, K_FOREVER); bt_buf_set_type(buf, BT_BUF_EVT); hdr = net_buf_add(buf, sizeof(*hdr)); diff --git a/subsys/bluetooth/host/hci_raw.c b/subsys/bluetooth/host/hci_raw.c index 6a7394627ed653..9d79f7a9fa0dfd 100644 --- a/subsys/bluetooth/host/hci_raw.c +++ b/subsys/bluetooth/host/hci_raw.c @@ -72,6 +72,18 @@ struct net_buf *bt_buf_get_cmd_complete(s32_t timeout) return buf; } +struct net_buf *bt_buf_get_evt(u8_t evt, s32_t timeout) +{ + struct net_buf *buf; + + buf = net_buf_alloc(&hci_rx_pool, timeout); + if (buf) { + bt_buf_set_type(buf, BT_BUF_EVT); + } + + return buf; +} + int bt_recv(struct net_buf *buf) { BT_DBG("buf %p len %u", buf, buf->len); diff --git a/tests/bluetooth/hci_prop_evt/src/main.c b/tests/bluetooth/hci_prop_evt/src/main.c new file mode 100644 index 00000000000000..75a50bc4daaad2 --- /dev/null +++ b/tests/bluetooth/hci_prop_evt/src/main.c @@ -0,0 +1,386 @@ +/* main.c - HCI prop event test */ + +/* + * Copyright (c) 2019 Oticon A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +/* HCI Proprietary vendor event */ +const u8_t hci_prop_evt_prefix[2] = { 0xAB, 0xBA }; + +struct hci_evt_prop { + u8_t prefix[2]; +} __packed; + +struct hci_evt_prop_report { + u8_t data_len; + u8_t data[0]; +} __packed; + +/* Command handler structure for cmd_handle(). */ +struct cmd_handler { + u16_t opcode; /* HCI command opcode */ + u8_t len; /* HCI command response length */ + void (*handler)(struct net_buf *buf, struct net_buf **evt, + u8_t len, u16_t opcode); +}; + +/* Add event to net_buf. */ +static void evt_create(struct net_buf *buf, u8_t evt, u8_t len) +{ + struct bt_hci_evt_hdr *hdr; + + hdr = net_buf_add(buf, sizeof(*hdr)); + hdr->evt = evt; + hdr->len = len; +} + +/* Create a command complete event. */ +static void *cmd_complete(struct net_buf **buf, u8_t plen, u16_t opcode) +{ + struct bt_hci_evt_cmd_complete *cc; + + *buf = bt_buf_get_evt(BT_HCI_EVT_CMD_COMPLETE, K_FOREVER); + evt_create(*buf, BT_HCI_EVT_CMD_COMPLETE, sizeof(*cc) + plen); + cc = net_buf_add(*buf, sizeof(*cc)); + cc->ncmd = 1U; + cc->opcode = sys_cpu_to_le16(opcode); + return net_buf_add(*buf, plen); +} + +/* Loop over handlers to try to handle the command given by opcode. */ +static int cmd_handle_helper(u16_t opcode, struct net_buf *cmd, + struct net_buf **evt, + const struct cmd_handler *handlers, + size_t num_handlers) +{ + for (size_t i = 0; i < num_handlers; i++) { + const struct cmd_handler *handler = &handlers[i]; + + if (handler->opcode != opcode) { + continue; + } + + if (handler->handler) { + handler->handler(cmd, evt, handler->len, opcode); + return 0; + } + } + + return -EINVAL; +} + +/* Lookup the command opcode and invoke handler. */ +static int cmd_handle(struct net_buf *cmd, + const struct cmd_handler *handlers, + size_t num_handlers) +{ + struct net_buf *evt = NULL; + struct bt_hci_evt_cc_status *ccst; + struct bt_hci_cmd_hdr *chdr; + u16_t opcode; + int err; + + chdr = net_buf_pull_mem(cmd, sizeof(*chdr)); + opcode = sys_le16_to_cpu(chdr->opcode); + + err = cmd_handle_helper(opcode, cmd, &evt, handlers, num_handlers); + + if (err == -EINVAL) { + ccst = cmd_complete(&evt, sizeof(*ccst), opcode); + ccst->status = BT_HCI_ERR_UNKNOWN_CMD; + } + + if (evt) { + bt_recv_prio(evt); + } + + return err; +} + +/* Generic command complete with success status. */ +static void generic_success(struct net_buf *buf, struct net_buf **evt, + u8_t len, u16_t opcode) +{ + struct bt_hci_evt_cc_status *ccst; + + ccst = cmd_complete(evt, len, opcode); + + /* Fill any event parameters with zero */ + (void)memset(ccst, 0, len); + + ccst->status = BT_HCI_ERR_SUCCESS; +} + +/* Bogus handler for BT_HCI_OP_READ_LOCAL_FEATURES. */ +static void read_local_features(struct net_buf *buf, struct net_buf **evt, + u8_t len, u16_t opcode) +{ + struct bt_hci_rp_read_local_features *rp; + + rp = cmd_complete(evt, sizeof(*rp), opcode); + rp->status = 0x00; + (void)memset(&rp->features[0], 0xFF, sizeof(rp->features)); +} + +/* Bogus handler for BT_HCI_OP_READ_SUPPORTED_COMMANDS. */ +static void read_supported_commands(struct net_buf *buf, struct net_buf **evt, + u8_t len, u16_t opcode) +{ + struct bt_hci_rp_read_supported_commands *rp; + + rp = cmd_complete(evt, sizeof(*rp), opcode); + (void)memset(&rp->commands[0], 0xFF, sizeof(rp->commands)); + rp->status = 0x00; +} + +/* Bogus handler for BT_HCI_OP_LE_READ_LOCAL_FEATURES. */ +static void le_read_local_features(struct net_buf *buf, struct net_buf **evt, + u8_t len, u16_t opcode) +{ + struct bt_hci_rp_le_read_local_features *rp; + + rp = cmd_complete(evt, sizeof(*rp), opcode); + rp->status = 0x00; + (void)memset(&rp->features[0], 0xFF, sizeof(rp->features)); +} + +/* Bogus handler for BT_HCI_OP_LE_READ_SUPP_STATES. */ +static void le_read_supp_states(struct net_buf *buf, struct net_buf **evt, + u8_t len, u16_t opcode) +{ + struct bt_hci_rp_le_read_supp_states *rp; + + rp = cmd_complete(evt, sizeof(*rp), opcode); + rp->status = 0x00; + (void)memset(&rp->le_states, 0xFF, sizeof(rp->le_states)); +} + +/* Setup handlers needed for bt_enable to function. */ +static const struct cmd_handler cmds[] = { + { BT_HCI_OP_READ_LOCAL_VERSION_INFO, + sizeof(struct bt_hci_rp_read_local_version_info), + generic_success }, + { BT_HCI_OP_READ_SUPPORTED_COMMANDS, + sizeof(struct bt_hci_rp_read_supported_commands), + read_supported_commands }, + { BT_HCI_OP_READ_LOCAL_FEATURES, + sizeof(struct bt_hci_rp_read_local_features), + read_local_features }, + { BT_HCI_OP_READ_BD_ADDR, + sizeof(struct bt_hci_rp_read_bd_addr), + generic_success }, + { BT_HCI_OP_SET_EVENT_MASK, + sizeof(struct bt_hci_evt_cc_status), + generic_success }, + { BT_HCI_OP_LE_SET_EVENT_MASK, + sizeof(struct bt_hci_evt_cc_status), + generic_success }, + { BT_HCI_OP_LE_READ_LOCAL_FEATURES, + sizeof(struct bt_hci_rp_le_read_local_features), + le_read_local_features }, + { BT_HCI_OP_LE_READ_SUPP_STATES, + sizeof(struct bt_hci_rp_le_read_supp_states), + le_read_supp_states }, + { BT_HCI_OP_LE_RAND, + sizeof(struct bt_hci_rp_le_rand), + generic_success }, +}; + +/* HCI driver open. */ +static int driver_open(void) +{ + return 0; +} + +/* HCI driver send. */ +static int driver_send(struct net_buf *buf) +{ + zassert_true(cmd_handle(buf, cmds, ARRAY_SIZE(cmds)) == 0, + "Unknown HCI command"); + + net_buf_unref(buf); + + return 0; +} + +/* HCI driver structure. */ +static const struct bt_hci_driver drv = { + .name = "test", + .bus = BT_HCI_DRIVER_BUS_VIRTUAL, + .open = driver_open, + .send = driver_send, + .quirks = BT_QUIRK_NO_RESET, +}; + +struct bt_recv_job_data { + struct k_work work; /* Work item */ + struct k_sem *sync; /* Semaphore to synchronize with */ + struct net_buf *buf; /* Net buffer to be passed to bt_recv() */ +} job_data[CONFIG_BT_RX_BUF_COUNT]; + +#define job(buf) (&job_data[net_buf_id(buf)]) + +/* Work item handler for bt_recv() jobs. */ +static void bt_recv_job_cb(struct k_work *item) +{ + struct bt_recv_job_data *data = + CONTAINER_OF(item, struct bt_recv_job_data, work); + + /* Send net buffer to host */ + bt_recv(data->buf); + + /* Wake up bt_recv_job_submit */ + k_sem_give(job(data->buf)->sync); +} + +/* Prepare a job to call bt_recv() to be submitted to the system workqueue. */ +static void bt_recv_job_submit(struct net_buf *buf) +{ + struct k_sem sync_sem; + + /* Store the net buffer to be passed to bt_recv */ + job(buf)->buf = buf; + + /* Initialize job work item/semaphore */ + k_work_init(&job(buf)->work, bt_recv_job_cb); + k_sem_init(&sync_sem, 0, 1); + job(buf)->sync = &sync_sem; + + /* Make sure the buffer stays around until the command completes */ + net_buf_ref(buf); + + /* Submit the work item */ + k_work_submit(&job(buf)->work); + + /* Wait for bt_recv_job_cb to be done */ + k_sem_take(&sync_sem, K_FOREVER); + + net_buf_unref(buf); +} + +/* Semaphore to test if the prop callback was called. */ +static K_SEM_DEFINE(prop_cb_sem, 0, 1); + +/* Used to verify prop event data. */ +static u8_t *prop_cb_data; +static u8_t prop_cb_data_len; + +/* Prop callback. */ +static bool prop_cb(struct net_buf_simple *buf) +{ + struct hci_evt_prop *pe; + + pe = net_buf_simple_pull_mem(buf, sizeof(*pe)); + + if (memcmp(&pe->prefix[0], &hci_prop_evt_prefix[0], + ARRAY_SIZE(hci_prop_evt_prefix)) == 0) { + struct hci_evt_prop_report *per; + + per = net_buf_simple_pull_mem(buf, sizeof(*per)); + + u8_t data_len = per->data_len; + u8_t *data = &per->data[0]; + + /* Allocate memory for storing the data */ + prop_cb_data = k_malloc(data_len); + zassert_not_null(prop_cb_data, "Cannot allocate memory"); + + /* Copy data so it can be verified later */ + memcpy(prop_cb_data, data, data_len); + prop_cb_data_len = data_len; + + /* Give control back to test */ + k_sem_give(&prop_cb_sem); + + return true; + } + + return false; +} + +/* Create a HCI Vendor Specific event to carry the prop event report. */ +static void *prop_evt(struct net_buf *buf, u8_t pelen) +{ + struct hci_evt_prop *pe; + + evt_create(buf, BT_HCI_EVT_VENDOR, sizeof(*pe) + pelen); + pe = net_buf_add(buf, sizeof(*pe)); + memcpy(&pe->prefix[0], &hci_prop_evt_prefix[0], + ARRAY_SIZE(hci_prop_evt_prefix)); + + return net_buf_add(buf, pelen); +} + +/* Send a prop event report wit the given data. */ +static void send_prop_report(u8_t *data, u8_t data_len) +{ + struct net_buf *buf; + struct hci_evt_prop_report *per; + + buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER); + per = prop_evt(buf, sizeof(*per) + data_len); + per->data_len = data_len; + memcpy(&per->data[0], data, data_len); + + /* Submit job */ + bt_recv_job_submit(buf); +} + +/* Test. */ +static void test_hci_prop_evt_entry(void) +{ + /* Register the test HCI driver */ + bt_hci_driver_register(&drv); + + /* Go! Wait until Bluetooth initialization is done */ + zassert_true((bt_enable(NULL) == 0), + "bt_enable failed"); + + /* Register the prop callback */ + bt_hci_register_vnd_evt_cb(prop_cb); + + /* Generate some data */ + u8_t data_len = 10; + u8_t data[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + /* Send the prop event report */ + send_prop_report(&data[0], data_len); + + /* Wait for the prop callback to be called */ + zassert_true(k_sem_take(&prop_cb_sem, K_MSEC(100)) == 0, + "prop_cb was not called within timeout"); + + /* Verify the data length */ + zassert_true(prop_cb_data_len == data_len, + "prop_cb_data_len invalid"); + + /* Verify the data itself */ + zassert_true(memcmp(prop_cb_data, data, data_len) == 0, + "prop_cb_data invalid"); + + /* Free the data memory */ + k_free(prop_cb_data); +} + +/*test case main entry*/ +void test_main(void) +{ + ztest_test_suite(test_hci_prop_evt, + ztest_unit_test(test_hci_prop_evt_entry)); + + ztest_run_test_suite(test_hci_prop_evt); +} From c19eaa96936768d4bb34f5ade30c82cd44b429b9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 28 Jun 2019 12:09:36 +0300 Subject: [PATCH 2/2] Bluetooth: Introduce separate pool for discardable events Introduce a separate buffer pool for events which the HCI driver considers discardable. Examples of such events could be e.g. Advertising Reports. The benefit of having such a pool means that the if there is a heavy inflow of such events it will not cause the allocation for other critical events to block and may even eliminate deadlocks in some cases. Also update all mesh samples not to specify explicit RX buffer counts anymore. Instead, create appropriate defaults in Kconfig so that we only need to override this in the app for cases like the bbc:microbit with limited memory. Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci/h4.c | 2 +- drivers/bluetooth/hci/h5.c | 2 +- drivers/bluetooth/hci/ipm_stm32wb.c | 3 ++- drivers/bluetooth/hci/spi.c | 2 +- drivers/bluetooth/hci/userchan.c | 2 +- include/bluetooth/buf.h | 9 ++++---- include/bluetooth/hci.h | 1 + samples/bluetooth/mesh/prj.conf | 1 - samples/bluetooth/mesh/prj_bbc_microbit.conf | 2 ++ samples/bluetooth/mesh_demo/prj.conf | 1 - samples/boards/nrf52/mesh/onoff-app/prj.conf | 1 - .../onoff_level_lighting_vnd_app/prj.conf | 1 - samples/boards/reel_board/mesh_badge/prj.conf | 1 - subsys/bluetooth/controller/hci/hci.c | 4 ++-- subsys/bluetooth/controller/hci/hci_driver.c | 5 +++-- subsys/bluetooth/host/Kconfig | 15 +++++++++++++ subsys/bluetooth/host/hci_core.c | 21 ++++++++++++++++++- subsys/bluetooth/host/hci_ecc.c | 2 +- subsys/bluetooth/host/hci_raw.c | 2 +- tests/bluetooth/hci_prop_evt/src/main.c | 2 +- tests/bluetooth/mesh/dbg.conf | 1 - tests/bluetooth/mesh/friend.conf | 1 - tests/bluetooth/mesh/gatt.conf | 1 - tests/bluetooth/mesh/lpn.conf | 1 - tests/bluetooth/mesh/pb_gatt.conf | 1 - tests/bluetooth/mesh/prj.conf | 1 - tests/bluetooth/mesh/proxy.conf | 1 - tests/bluetooth/mesh_shell/prj.conf | 1 - tests/bluetooth/shell/mesh.conf | 1 - 29 files changed, 57 insertions(+), 31 deletions(-) diff --git a/drivers/bluetooth/hci/h4.c b/drivers/bluetooth/hci/h4.c index c3fe9038d99cfd..835584e12806b0 100644 --- a/drivers/bluetooth/hci/h4.c +++ b/drivers/bluetooth/hci/h4.c @@ -166,7 +166,7 @@ static struct net_buf *get_rx(int timeout) BT_DBG("type 0x%02x, evt 0x%02x", rx.type, rx.evt.evt); if (rx.type == H4_EVT) { - return bt_buf_get_evt(rx.evt.evt, timeout); + return bt_buf_get_evt(rx.evt.evt, rx.discardable, timeout); } return bt_buf_get_rx(BT_BUF_ACL_IN, timeout); diff --git a/drivers/bluetooth/hci/h5.c b/drivers/bluetooth/hci/h5.c index 3d5ae9a34114a1..bb0fbca115da0e 100644 --- a/drivers/bluetooth/hci/h5.c +++ b/drivers/bluetooth/hci/h5.c @@ -408,7 +408,7 @@ static inline struct net_buf *get_evt_buf(u8_t evt) { struct net_buf *buf; - buf = bt_buf_get_evt(evt, K_NO_WAIT); + buf = bt_buf_get_evt(evt, false, K_NO_WAIT); if (buf) { net_buf_add_u8(h5.rx_buf, evt); } diff --git a/drivers/bluetooth/hci/ipm_stm32wb.c b/drivers/bluetooth/hci/ipm_stm32wb.c index 9f2b95129f674e..029ac5a5b449e8 100644 --- a/drivers/bluetooth/hci/ipm_stm32wb.c +++ b/drivers/bluetooth/hci/ipm_stm32wb.c @@ -115,7 +115,8 @@ void TM_EvtReceivedCb(TL_EvtPacket_t *hcievt) hcievt->evtserial.evt.evtcode); goto out; default: - buf = bt_buf_get_evt(evtserial.evt.evtcode, K_FOREVER); + buf = bt_buf_get_evt(evtserial.evt.evtcode, false, + K_FOREVER); break; } net_buf_add_mem(buf, &hcievt->evtserial.evt, diff --git a/drivers/bluetooth/hci/spi.c b/drivers/bluetooth/hci/spi.c index 1115820d96c600..dfd177ca37a1a1 100644 --- a/drivers/bluetooth/hci/spi.c +++ b/drivers/bluetooth/hci/spi.c @@ -355,7 +355,7 @@ static void bt_spi_rx_thread(void) continue; default: buf = bt_buf_get_evt(rxmsg[EVT_HEADER_EVENT], - K_FOREVER); + false, K_FOREVER); break; } diff --git a/drivers/bluetooth/hci/userchan.c b/drivers/bluetooth/hci/userchan.c index 749cfab3061862..bdc4bbe14e2a83 100644 --- a/drivers/bluetooth/hci/userchan.c +++ b/drivers/bluetooth/hci/userchan.c @@ -58,7 +58,7 @@ static int bt_dev_index = -1; static struct net_buf *get_rx(const u8_t *buf) { if (buf[0] == H4_EVT) { - return bt_buf_get_evt(buf[1], K_FOREVER); + return bt_buf_get_evt(buf[1], false, K_FOREVER); } return bt_buf_get_rx(BT_BUF_ACL_IN, K_FOREVER); diff --git a/include/bluetooth/buf.h b/include/bluetooth/buf.h index f71a3672dc5003..ee941e2661bb28 100644 --- a/include/bluetooth/buf.h +++ b/include/bluetooth/buf.h @@ -69,12 +69,13 @@ struct net_buf *bt_buf_get_cmd_complete(s32_t timeout); * This will set the buffer type so bt_buf_set_type() does not need to * be explicitly called before bt_recv_prio() or bt_recv(). * - * @param evt HCI event code - * @param timeout Timeout in milliseconds, or one of the special values - * K_NO_WAIT and K_FOREVER. + * @param evt HCI event code + * @param discardable Whether the driver considers the event discardable. + * @param timeout Timeout in milliseconds, or one of the special values + * K_NO_WAIT and K_FOREVER. * @return A new buffer. */ -struct net_buf *bt_buf_get_evt(u8_t evt, s32_t timeout); +struct net_buf *bt_buf_get_evt(u8_t evt, bool discardable, s32_t timeout); /** Set the buffer type * diff --git a/include/bluetooth/hci.h b/include/bluetooth/hci.h index 1fc488cccf31e7..6b8a6559e104cd 100644 --- a/include/bluetooth/hci.h +++ b/include/bluetooth/hci.h @@ -1355,6 +1355,7 @@ struct bt_hci_cp_le_set_privacy_mode { /* Event definitions */ +#define BT_HCI_EVT_UNKNOWN 0x00 #define BT_HCI_EVT_VENDOR 0xff #define BT_HCI_EVT_INQUIRY_COMPLETE 0x01 diff --git a/samples/bluetooth/mesh/prj.conf b/samples/bluetooth/mesh/prj.conf index 8db2bae562e31e..4db81eca0c47db 100644 --- a/samples/bluetooth/mesh/prj.conf +++ b/samples/bluetooth/mesh/prj.conf @@ -26,7 +26,6 @@ CONFIG_BT_PERIPHERAL=y CONFIG_BT=y CONFIG_BT_TINYCRYPT_ECC=y -CONFIG_BT_RX_BUF_COUNT=30 CONFIG_BT_L2CAP_RX_MTU=69 CONFIG_BT_L2CAP_TX_MTU=69 CONFIG_BT_L2CAP_TX_BUF_COUNT=5 diff --git a/samples/bluetooth/mesh/prj_bbc_microbit.conf b/samples/bluetooth/mesh/prj_bbc_microbit.conf index f70891f7f0635c..79755b5ab4c04f 100644 --- a/samples/bluetooth/mesh/prj_bbc_microbit.conf +++ b/samples/bluetooth/mesh/prj_bbc_microbit.conf @@ -17,6 +17,8 @@ CONFIG_SETTINGS_FCB=y CONFIG_BT=y CONFIG_BT_TINYCRYPT_ECC=y CONFIG_BT_RX_STACK_SIZE=1100 +CONFIG_BT_RX_BUF_COUNT=3 +CONFIG_BT_DISCARDABLE_BUF_COUNT=3 CONFIG_BT_CTLR_DUP_FILTER_LEN=0 CONFIG_BT_OBSERVER=y diff --git a/samples/bluetooth/mesh_demo/prj.conf b/samples/bluetooth/mesh_demo/prj.conf index 38336d3ba7458b..9b8ac6712f71b7 100644 --- a/samples/bluetooth/mesh_demo/prj.conf +++ b/samples/bluetooth/mesh_demo/prj.conf @@ -3,7 +3,6 @@ CONFIG_MAIN_STACK_SIZE=512 CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 CONFIG_BT=y -CONFIG_BT_RX_BUF_COUNT=30 CONFIG_BT_TINYCRYPT_ECC=y #CONFIG_BT_DEBUG_LOG=y CONFIG_BT_OBSERVER=y diff --git a/samples/boards/nrf52/mesh/onoff-app/prj.conf b/samples/boards/nrf52/mesh/onoff-app/prj.conf index 92c2b3af64644e..63c32c8cedc247 100644 --- a/samples/boards/nrf52/mesh/onoff-app/prj.conf +++ b/samples/boards/nrf52/mesh/onoff-app/prj.conf @@ -31,7 +31,6 @@ CONFIG_BT_PERIPHERAL=y CONFIG_BT=y CONFIG_BT_TINYCRYPT_ECC=y -CONFIG_BT_RX_BUF_COUNT=30 CONFIG_BT_L2CAP_RX_MTU=69 CONFIG_BT_L2CAP_TX_MTU=69 CONFIG_BT_L2CAP_TX_BUF_COUNT=8 diff --git a/samples/boards/nrf52/mesh/onoff_level_lighting_vnd_app/prj.conf b/samples/boards/nrf52/mesh/onoff_level_lighting_vnd_app/prj.conf index 86199fc2c952d3..bcf24f764378f7 100644 --- a/samples/boards/nrf52/mesh/onoff_level_lighting_vnd_app/prj.conf +++ b/samples/boards/nrf52/mesh/onoff_level_lighting_vnd_app/prj.conf @@ -26,7 +26,6 @@ CONFIG_BT_CTLR_TX_PWR_PLUS_8=y CONFIG_BT_PERIPHERAL=y CONFIG_BT=y CONFIG_BT_TINYCRYPT_ECC=y -CONFIG_BT_RX_BUF_COUNT=30 CONFIG_BT_RX_STACK_SIZE=4096 CONFIG_BT_L2CAP_RX_MTU=69 CONFIG_BT_L2CAP_TX_MTU=69 diff --git a/samples/boards/reel_board/mesh_badge/prj.conf b/samples/boards/reel_board/mesh_badge/prj.conf index 877a5c150ad2b0..898b7ae4b5c236 100644 --- a/samples/boards/reel_board/mesh_badge/prj.conf +++ b/samples/boards/reel_board/mesh_badge/prj.conf @@ -19,7 +19,6 @@ CONFIG_BT_MESH_DEBUG=y CONFIG_BT_OBSERVER=y CONFIG_BT_BROADCASTER=y -CONFIG_BT_RX_BUF_COUNT=30 CONFIG_BT_L2CAP_RX_MTU=69 CONFIG_BT_L2CAP_TX_MTU=69 CONFIG_BT_L2CAP_TX_BUF_COUNT=8 diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index 800b8037312acd..adcd0102967a13 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -115,7 +115,7 @@ static void *cmd_complete(struct net_buf **buf, u8_t plen) { struct bt_hci_evt_cmd_complete *cc; - *buf = bt_buf_get_evt(BT_HCI_EVT_CMD_COMPLETE, K_FOREVER); + *buf = bt_buf_get_evt(BT_HCI_EVT_CMD_COMPLETE, false, K_FOREVER); evt_create(*buf, BT_HCI_EVT_CMD_COMPLETE, sizeof(*cc) + plen); @@ -132,7 +132,7 @@ static struct net_buf *cmd_status(u8_t status) struct bt_hci_evt_cmd_status *cs; struct net_buf *buf; - buf = bt_buf_get_evt(BT_HCI_EVT_CMD_STATUS, K_FOREVER); + buf = bt_buf_get_evt(BT_HCI_EVT_CMD_STATUS, false, K_FOREVER); evt_create(buf, BT_HCI_EVT_CMD_STATUS, sizeof(*cs)); cs = net_buf_add(buf, sizeof(*cs)); diff --git a/subsys/bluetooth/controller/hci/hci_driver.c b/subsys/bluetooth/controller/hci/hci_driver.c index 84482699449eb5..e6fa9d30885678 100644 --- a/subsys/bluetooth/controller/hci/hci_driver.c +++ b/subsys/bluetooth/controller/hci/hci_driver.c @@ -88,7 +88,7 @@ static void prio_recv_thread(void *p1, void *p2, void *p3) struct net_buf *buf; buf = bt_buf_get_evt(BT_HCI_EVT_NUM_COMPLETED_PACKETS, - K_FOREVER); + false, K_FOREVER); hci_num_cmplt_encode(buf, handle, num_cmplt); BT_DBG("Num Complete: 0x%04x:%u", handle, num_cmplt); bt_recv_prio(buf); @@ -143,7 +143,8 @@ static inline struct net_buf *encode_node(struct node_rx_pdu *node_rx, case HCI_CLASS_EVT_REQUIRED: case HCI_CLASS_EVT_CONNECTION: if (class == HCI_CLASS_EVT_DISCARDABLE) { - buf = bt_buf_get_rx(BT_BUF_EVT, K_NO_WAIT); + buf = bt_buf_get_evt(BT_HCI_EVT_UNKNOWN, true, + K_NO_WAIT); } else { buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER); } diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index 5a0190a2daec06..525c2e7d35ae1a 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -26,6 +26,7 @@ config BT_HCI_CMD_COUNT config BT_RX_BUF_COUNT int "Number of HCI RX buffers" default 3 if BT_RECV_IS_RX_THREAD + default 20 if (BT_MESH && !BT_DISCARDABLE_BUF_COUNT) default 10 range 2 255 help @@ -47,6 +48,20 @@ config BT_RX_BUF_LEN an L2CAP MTU of 65 bytes. On top of this there's the L2CAP header (4 bytes) and the ACL header (also 4 bytes) which yields 73 bytes. +config BT_DISCARDABLE_BUF_COUNT + int "Number of discardable event buffers" + range 1 255 + default 20 if BT_MESH + default 3 + depends on BT_H4 || BT_CTLR + help + Number of buffers in a separate buffer pool for events which + the HCI driver considers discardable. Examples of such events + could be e.g. Advertising Reports. The benefit of having such + a pool means that the if there is a heavy inflow of such events + it will not cause the allocation for other critical events to + block and may even eliminate deadlocks in some cases. + config BT_HCI_TX_STACK_SIZE # NOTE: This value is derived from other symbols and should not be # user-configurable. Do not give it a prompt. diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 153c0423445528..c2e1a2f8b22546 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -143,6 +143,11 @@ NET_BUF_POOL_DEFINE(num_complete_pool, 1, BT_BUF_RX_SIZE, BT_BUF_USER_DATA_MIN, NULL); #endif /* CONFIG_BT_CONN */ +#if defined(CONFIG_BT_DISCARDABLE_BUF_COUNT) +NET_BUF_POOL_DEFINE(discardable_pool, CONFIG_BT_DISCARDABLE_BUF_COUNT, + BT_BUF_RX_SIZE, BT_BUF_USER_DATA_MIN, NULL); +#endif /* CONFIG_BT_DISCARDABLE_BUF_COUNT */ + struct event_handler { u8_t event; u8_t min_len; @@ -5635,7 +5640,7 @@ struct net_buf *bt_buf_get_cmd_complete(s32_t timeout) return bt_buf_get_rx(BT_BUF_EVT, timeout); } -struct net_buf *bt_buf_get_evt(u8_t evt, s32_t timeout) +struct net_buf *bt_buf_get_evt(u8_t evt, bool discardable, s32_t timeout) { switch (evt) { #if defined(CONFIG_BT_CONN) @@ -5656,6 +5661,20 @@ struct net_buf *bt_buf_get_evt(u8_t evt, s32_t timeout) case BT_HCI_EVT_CMD_STATUS: return bt_buf_get_cmd_complete(timeout); default: +#if defined(CONFIG_BT_DISCARDABLE_BUF_COUNT) + if (discardable) { + struct net_buf *buf; + + buf = net_buf_alloc(&discardable_pool, timeout); + if (buf) { + net_buf_reserve(buf, CONFIG_BT_HCI_RESERVE); + bt_buf_set_type(buf, BT_BUF_EVT); + } + + return buf; + } +#endif /* CONFIG_BT_DISCARDABLE_BUF_COUNT */ + return bt_buf_get_rx(BT_BUF_EVT, timeout); } } diff --git a/subsys/bluetooth/host/hci_ecc.c b/subsys/bluetooth/host/hci_ecc.c index 75ae8d2892ebdf..73bcc3b9716c7e 100644 --- a/subsys/bluetooth/host/hci_ecc.c +++ b/subsys/bluetooth/host/hci_ecc.c @@ -84,7 +84,7 @@ static void send_cmd_status(u16_t opcode, u8_t status) BT_DBG("opcode %x status %x", opcode, status); - buf = bt_buf_get_evt(BT_HCI_EVT_CMD_STATUS, K_FOREVER); + buf = bt_buf_get_evt(BT_HCI_EVT_CMD_STATUS, false, K_FOREVER); bt_buf_set_type(buf, BT_BUF_EVT); hdr = net_buf_add(buf, sizeof(*hdr)); diff --git a/subsys/bluetooth/host/hci_raw.c b/subsys/bluetooth/host/hci_raw.c index 9d79f7a9fa0dfd..28eeee2261d31b 100644 --- a/subsys/bluetooth/host/hci_raw.c +++ b/subsys/bluetooth/host/hci_raw.c @@ -72,7 +72,7 @@ struct net_buf *bt_buf_get_cmd_complete(s32_t timeout) return buf; } -struct net_buf *bt_buf_get_evt(u8_t evt, s32_t timeout) +struct net_buf *bt_buf_get_evt(u8_t evt, bool discardable, s32_t timeout) { struct net_buf *buf; diff --git a/tests/bluetooth/hci_prop_evt/src/main.c b/tests/bluetooth/hci_prop_evt/src/main.c index 75a50bc4daaad2..e458d8b728d93f 100644 --- a/tests/bluetooth/hci_prop_evt/src/main.c +++ b/tests/bluetooth/hci_prop_evt/src/main.c @@ -53,7 +53,7 @@ static void *cmd_complete(struct net_buf **buf, u8_t plen, u16_t opcode) { struct bt_hci_evt_cmd_complete *cc; - *buf = bt_buf_get_evt(BT_HCI_EVT_CMD_COMPLETE, K_FOREVER); + *buf = bt_buf_get_evt(BT_HCI_EVT_CMD_COMPLETE, false, K_FOREVER); evt_create(*buf, BT_HCI_EVT_CMD_COMPLETE, sizeof(*cc) + plen); cc = net_buf_add(*buf, sizeof(*cc)); cc->ncmd = 1U; diff --git a/tests/bluetooth/mesh/dbg.conf b/tests/bluetooth/mesh/dbg.conf index ecb4800203816d..19f44173020c44 100644 --- a/tests/bluetooth/mesh/dbg.conf +++ b/tests/bluetooth/mesh/dbg.conf @@ -19,7 +19,6 @@ CONFIG_BT_PERIPHERAL=y CONFIG_BT=y CONFIG_BT_TINYCRYPT_ECC=y -CONFIG_BT_RX_BUF_COUNT=30 CONFIG_BT_L2CAP_RX_MTU=69 CONFIG_BT_L2CAP_TX_MTU=69 diff --git a/tests/bluetooth/mesh/friend.conf b/tests/bluetooth/mesh/friend.conf index 055a67d3ec5c31..da39b203b749c6 100644 --- a/tests/bluetooth/mesh/friend.conf +++ b/tests/bluetooth/mesh/friend.conf @@ -17,7 +17,6 @@ CONFIG_BT_CTLR_PRIVACY=n CONFIG_BT=y CONFIG_BT_TINYCRYPT_ECC=y -CONFIG_BT_RX_BUF_COUNT=30 CONFIG_BT_MESH=y CONFIG_BT_MESH_RELAY=y diff --git a/tests/bluetooth/mesh/gatt.conf b/tests/bluetooth/mesh/gatt.conf index aa4ad455c09ed3..5120ff7a86a5f0 100644 --- a/tests/bluetooth/mesh/gatt.conf +++ b/tests/bluetooth/mesh/gatt.conf @@ -19,7 +19,6 @@ CONFIG_BT_PERIPHERAL=y CONFIG_BT=y CONFIG_BT_TINYCRYPT_ECC=y -CONFIG_BT_RX_BUF_COUNT=30 CONFIG_BT_L2CAP_RX_MTU=69 CONFIG_BT_L2CAP_TX_MTU=69 diff --git a/tests/bluetooth/mesh/lpn.conf b/tests/bluetooth/mesh/lpn.conf index d2c45c18e7ff50..5fe4922be7ede1 100644 --- a/tests/bluetooth/mesh/lpn.conf +++ b/tests/bluetooth/mesh/lpn.conf @@ -19,7 +19,6 @@ CONFIG_BT_PERIPHERAL=y CONFIG_BT=y CONFIG_BT_TINYCRYPT_ECC=y -CONFIG_BT_RX_BUF_COUNT=30 CONFIG_BT_L2CAP_RX_MTU=69 CONFIG_BT_L2CAP_TX_MTU=69 diff --git a/tests/bluetooth/mesh/pb_gatt.conf b/tests/bluetooth/mesh/pb_gatt.conf index 752cedf9458c98..bf15568d04b42c 100644 --- a/tests/bluetooth/mesh/pb_gatt.conf +++ b/tests/bluetooth/mesh/pb_gatt.conf @@ -19,7 +19,6 @@ CONFIG_BT_PERIPHERAL=y CONFIG_BT=y CONFIG_BT_TINYCRYPT_ECC=y -CONFIG_BT_RX_BUF_COUNT=30 CONFIG_BT_L2CAP_RX_MTU=69 CONFIG_BT_L2CAP_TX_MTU=69 diff --git a/tests/bluetooth/mesh/prj.conf b/tests/bluetooth/mesh/prj.conf index 1a17dbc042c8cb..9f2e77c7fd199e 100644 --- a/tests/bluetooth/mesh/prj.conf +++ b/tests/bluetooth/mesh/prj.conf @@ -19,7 +19,6 @@ CONFIG_BT_PERIPHERAL=y CONFIG_BT=y CONFIG_BT_TINYCRYPT_ECC=y -CONFIG_BT_RX_BUF_COUNT=30 CONFIG_BT_L2CAP_RX_MTU=69 CONFIG_BT_L2CAP_TX_MTU=69 diff --git a/tests/bluetooth/mesh/proxy.conf b/tests/bluetooth/mesh/proxy.conf index 90765913e8a597..06992610af8e31 100644 --- a/tests/bluetooth/mesh/proxy.conf +++ b/tests/bluetooth/mesh/proxy.conf @@ -19,7 +19,6 @@ CONFIG_BT_PERIPHERAL=y CONFIG_BT=y CONFIG_BT_TINYCRYPT_ECC=y -CONFIG_BT_RX_BUF_COUNT=30 CONFIG_BT_L2CAP_RX_MTU=69 CONFIG_BT_L2CAP_TX_MTU=69 diff --git a/tests/bluetooth/mesh_shell/prj.conf b/tests/bluetooth/mesh_shell/prj.conf index 58e45cd0d14884..ea6aae1ec5bbed 100644 --- a/tests/bluetooth/mesh_shell/prj.conf +++ b/tests/bluetooth/mesh_shell/prj.conf @@ -34,7 +34,6 @@ CONFIG_BT_CTLR_MIN_USED_CHAN=n CONFIG_BT_CTLR_ADV_EXT=n CONFIG_BT_CTLR_PRIVACY=n -CONFIG_BT_RX_BUF_COUNT=30 CONFIG_BT_L2CAP_RX_MTU=69 CONFIG_BT_L2CAP_TX_MTU=69 CONFIG_BT_L2CAP_TX_BUF_COUNT=4 diff --git a/tests/bluetooth/shell/mesh.conf b/tests/bluetooth/shell/mesh.conf index 937d47f60dd991..723848040c24f2 100644 --- a/tests/bluetooth/shell/mesh.conf +++ b/tests/bluetooth/shell/mesh.conf @@ -18,7 +18,6 @@ CONFIG_BT_SHELL=y CONFIG_BT_DEVICE_NAME="test shell" CONFIG_BT_L2CAP_TX_BUF_COUNT=6 -CONFIG_BT_RX_BUF_COUNT=30 CONFIG_BT_L2CAP_RX_MTU=69 CONFIG_BT_L2CAP_TX_MTU=69