diff --git a/components/bt/host/bluedroid/hci/hci_hal_h4.c b/components/bt/host/bluedroid/hci/hci_hal_h4.c index 77cde40d5a..e55b2d99ef 100644 --- a/components/bt/host/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/host/bluedroid/hci/hci_hal_h4.c @@ -72,6 +72,8 @@ typedef struct { osi_alarm_t *adv_flow_monitor; int adv_credits; int adv_credits_to_release; + pkt_linked_item_t *adv_fc_cmd_buf; + bool cmd_buf_in_use; #endif hci_hal_callbacks_t *callbacks; osi_thread_t *hci_h4_thread; @@ -92,6 +94,7 @@ static bool hci_upstream_data_post(uint32_t timeout); #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) static void hci_adv_flow_monitor(void *context); +static void hci_adv_flow_cmd_free_cb(pkt_linked_item_t *linked_pkt); #endif static bool hci_hal_env_init(const hci_hal_callbacks_t *upper_callbacks, osi_thread_t *task_thread) @@ -103,10 +106,13 @@ static bool hci_hal_env_init(const hci_hal_callbacks_t *upper_callbacks, osi_thr hci_hal_env.callbacks = (hci_hal_callbacks_t *)upper_callbacks; #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) + hci_hal_env.adv_fc_cmd_buf = osi_calloc(HCI_CMD_LINKED_BUF_SIZE(HCIC_PARAM_SIZE_BLE_UPDATE_ADV_FLOW_CONTROL)); + assert(hci_hal_env.adv_fc_cmd_buf != NULL); osi_mutex_new(&hci_hal_env.adv_flow_lock); osi_mutex_lock(&hci_hal_env.adv_flow_lock, OSI_MUTEX_MAX_TIMEOUT); hci_hal_env.adv_credits = BLE_ADV_REPORT_FLOW_CONTROL_NUM; hci_hal_env.adv_credits_to_release = 0; + hci_hal_env.cmd_buf_in_use = false; osi_mutex_unlock(&hci_hal_env.adv_flow_lock); hci_hal_env.adv_flow_monitor = osi_alarm_new("adv_fc_mon", hci_adv_flow_monitor, NULL, HCI_ADV_FLOW_MONITOR_PERIOD_MS); assert (hci_hal_env.adv_flow_monitor != NULL); @@ -138,10 +144,13 @@ static void hci_hal_env_deinit(void) hci_hal_env.upstream_data_ready = NULL; #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) + hci_hal_env.cmd_buf_in_use = true; osi_alarm_cancel(hci_hal_env.adv_flow_monitor); osi_alarm_free(hci_hal_env.adv_flow_monitor); hci_hal_env.adv_flow_monitor = NULL; osi_mutex_free(&hci_hal_env.adv_flow_lock); + osi_free(hci_hal_env.adv_fc_cmd_buf); + hci_hal_env.adv_fc_cmd_buf = NULL; #endif hci_hal_env.hci_h4_thread = NULL; @@ -296,7 +305,7 @@ int hci_adv_credits_prep_to_release(uint16_t num) hci_hal_env.adv_credits_to_release = credits_to_release; osi_mutex_unlock(&hci_hal_env.adv_flow_lock); - if (credits_to_release == num) { + if (credits_to_release == num && num != 0) { osi_alarm_cancel(hci_hal_env.adv_flow_monitor); osi_alarm_set(hci_hal_env.adv_flow_monitor, HCI_ADV_FLOW_MONITOR_PERIOD_MS); } @@ -319,15 +328,64 @@ static int hci_adv_credits_release(void) return credits_released; } +static int hci_adv_credits_release_rollback(uint16_t num) +{ + osi_mutex_lock(&hci_hal_env.adv_flow_lock, OSI_MUTEX_MAX_TIMEOUT); + hci_hal_env.adv_credits -= num; + hci_hal_env.adv_credits_to_release += num; + assert(hci_hal_env.adv_credits >=0); + assert(hci_hal_env.adv_credits_to_release <= BLE_ADV_REPORT_FLOW_CONTROL_NUM); + osi_mutex_unlock(&hci_hal_env.adv_flow_lock); + + return num; +} + +static void hci_adv_flow_cmd_free_cb(pkt_linked_item_t *linked_pkt) +{ + osi_mutex_lock(&hci_hal_env.adv_flow_lock, OSI_MUTEX_MAX_TIMEOUT); + hci_hal_env.cmd_buf_in_use = false; + osi_mutex_unlock(&hci_hal_env.adv_flow_lock); + hci_adv_credits_try_release(0); +} + +bool hci_adv_flow_try_send_command(uint16_t credits_released) +{ + bool sent = false; + bool use_static_buffer = false; + + /* first try using static buffer, then dynamic buffer */ + if (!hci_hal_env.cmd_buf_in_use) { + osi_mutex_lock(&hci_hal_env.adv_flow_lock, OSI_MUTEX_MAX_TIMEOUT); + if (!hci_hal_env.cmd_buf_in_use) { + hci_hal_env.cmd_buf_in_use = true; + use_static_buffer = true; + } + osi_mutex_unlock(&hci_hal_env.adv_flow_lock); + } + + if (use_static_buffer) { + hci_cmd_metadata_t *metadata = (hci_cmd_metadata_t *)(hci_hal_env.adv_fc_cmd_buf->data); + BT_HDR *static_buffer = &metadata->command; + metadata->command_free_cb = hci_adv_flow_cmd_free_cb; + sent = btsnd_hcic_ble_update_adv_report_flow_control(credits_released, static_buffer); + } else { + sent = btsnd_hcic_ble_update_adv_report_flow_control(credits_released, NULL); + } + + return sent; +} + int hci_adv_credits_try_release(uint16_t num) { int credits_released = 0; if (hci_adv_credits_prep_to_release(num) >= HCI_BLE_ADV_MIN_CREDITS_TO_RELEASE) { credits_released = hci_adv_credits_release(); - assert(credits_released >= 0); if (credits_released > 0) { - // TODO: handle the exception that the command is discarded due to heap exhaustion - btsnd_hcic_ble_update_adv_report_flow_control(credits_released); + if (!hci_adv_flow_try_send_command(credits_released)) { + hci_adv_credits_release_rollback(credits_released); + } + } else { + assert (credits_released == 0); } } return credits_released; @@ -338,8 +396,9 @@ int hci_adv_credits_force_release(uint16_t num) hci_adv_credits_prep_to_release(num); int credits_released = hci_adv_credits_release(); if (credits_released > 0) { - // TODO: handle the exception that the command is discarded due to heap exhaustion - btsnd_hcic_ble_update_adv_report_flow_control(credits_released); + if (!hci_adv_flow_try_send_command(credits_released)) { + hci_adv_credits_release_rollback(credits_released); + } } return credits_released; diff --git a/components/bt/host/bluedroid/hci/hci_layer.c b/components/bt/host/bluedroid/hci/hci_layer.c index 8d79043dd4..dab99ad2b9 100644 --- a/components/bt/host/bluedroid/hci/hci_layer.c +++ b/components/bt/host/bluedroid/hci/hci_layer.c @@ -242,9 +242,12 @@ static void transmit_command( pkt_linked_item_t *linked_pkt = HCI_GET_CMD_LINKED_STRUCT(metadata); assert(command->layer_specific == HCI_CMD_BUF_TYPE_METADATA); + metadata->flags_vnd |= HCI_CMD_MSG_F_VND_QUEUED; + // Store the command message type in the event field // in case the upper layer didn't already command->event = MSG_STACK_TO_HC_HCI_CMD; + HCI_TRACE_DEBUG("HCI Enqueue Comamnd opcode=0x%x\n", metadata->opcode); BTTRC_DUMP_BUFFER(NULL, command->data + command->offset, command->len); @@ -259,7 +262,7 @@ static future_t *transmit_command_futured(BT_HDR *command) pkt_linked_item_t *linked_pkt = HCI_GET_CMD_LINKED_STRUCT(metadata); assert(command->layer_specific == HCI_CMD_BUF_TYPE_METADATA); - metadata->flags_vnd |= HCI_CMD_MSG_F_VND_FUTURE; + metadata->flags_vnd |= (HCI_CMD_MSG_F_VND_QUEUED | HCI_CMD_MSG_F_VND_FUTURE); future_t *future = future_new(); @@ -294,8 +297,10 @@ static void event_command_ready(fixed_pkt_queue_t *queue) command_waiting_response_t *cmd_wait_q = &hci_host_env.cmd_waiting_q; wait_entry = fixed_pkt_queue_dequeue(queue, FIXED_QUEUE_MAX_TIMEOUT); - hci_cmd_metadata_t *metadata = (hci_cmd_metadata_t *)(wait_entry->data); + metadata->flags_vnd |= HCI_CMD_MSG_F_VND_SENT; + metadata->flags_vnd &= ~HCI_CMD_MSG_F_VND_QUEUED; + if (metadata->flags_src & HCI_CMD_MSG_F_SRC_NOACK) { packet_fragmenter->fragment_and_dispatch(&metadata->command); hci_cmd_free_cb free_func = metadata->command_free_cb ? metadata->command_free_cb : (hci_cmd_free_cb) osi_free_func; diff --git a/components/bt/host/bluedroid/hci/include/hci/hci_layer.h b/components/bt/host/bluedroid/hci/include/hci/hci_layer.h index 728c4997a8..e090149a39 100644 --- a/components/bt/host/bluedroid/hci/include/hci/hci_layer.h +++ b/components/bt/host/bluedroid/hci/include/hci/hci_layer.h @@ -49,6 +49,8 @@ #define LOCAL_BR_EDR_CONTROLLER_ID 0 #define HCI_CMD_MSG_F_VND_FUTURE (0x01) +#define HCI_CMD_MSG_F_VND_QUEUED (0x02) +#define HCI_CMD_MSG_F_VND_SENT (0x04) ///// END LEGACY DEFINITIONS ///// typedef struct hci_hal_t hci_hal_t; diff --git a/components/bt/host/bluedroid/stack/hcic/hciblecmds.c b/components/bt/host/bluedroid/stack/hcic/hciblecmds.c index b816d0227b..4369ecc2c8 100644 --- a/components/bt/host/bluedroid/stack/hcic/hciblecmds.c +++ b/components/bt/host/bluedroid/stack/hcic/hciblecmds.c @@ -1028,23 +1028,31 @@ BOOLEAN btsnd_hcic_ble_set_data_length(UINT16 conn_handle, UINT16 tx_octets, UIN return TRUE; } -BOOLEAN btsnd_hcic_ble_update_adv_report_flow_control (UINT16 num) +BOOLEAN btsnd_hcic_ble_update_adv_report_flow_control (UINT16 num, BT_HDR *static_buf) { BT_HDR *p; UINT8 *pp; - if ((p = HCI_GET_CMD_BUF (HCIC_PARAM_SIZE_BLE_UPDATE_ADV_FLOW_CONTROL)) == NULL) { - return (FALSE); + if (static_buf != NULL) { + p = static_buf; + } else { + if ((p = HCI_GET_CMD_BUF (HCIC_PARAM_SIZE_BLE_UPDATE_ADV_FLOW_CONTROL)) == NULL) { + return (FALSE); + } } + hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(p); + metadata->flags_src = HCI_CMD_MSG_F_SRC_NOACK; + if (static_buf == p) { + assert(metadata->command_free_cb != NULL); + } + p->layer_specific = HCI_CMD_BUF_TYPE_METADATA; + pp = (UINT8 *)(p + 1); p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_UPDATE_ADV_FLOW_CONTROL; p->offset = 0; - hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(p); - metadata->flags_src |= HCI_CMD_MSG_F_SRC_NOACK; - UINT16_TO_STREAM (pp, HCI_VENDOR_BLE_ADV_REPORT_FLOW_CONTROL); UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_UPDATE_ADV_FLOW_CONTROL); UINT16_TO_STREAM (pp, num); diff --git a/components/bt/host/bluedroid/stack/include/stack/hcimsgs.h b/components/bt/host/bluedroid/stack/include/stack/hcimsgs.h index 9e4eda774f..44aa840945 100644 --- a/components/bt/host/bluedroid/stack/include/stack/hcimsgs.h +++ b/components/bt/host/bluedroid/stack/include/stack/hcimsgs.h @@ -939,7 +939,7 @@ BOOLEAN btsnd_hcic_read_authenticated_payload_tout(UINT16 handle); BOOLEAN btsnd_hcic_write_authenticated_payload_tout(UINT16 handle, UINT16 timeout); -BOOLEAN btsnd_hcic_ble_update_adv_report_flow_control (UINT16 num); +BOOLEAN btsnd_hcic_ble_update_adv_report_flow_control (UINT16 num, BT_HDR *static_buf); #if (BLE_50_FEATURE_SUPPORT == TRUE) BOOLEAN btsnd_hcic_ble_read_phy(UINT16 conn_handle);