فهرست منبع

component/bt: allocate and use one static buffer for HCI adv flow control command

Karl Wang 3 سال پیش
والد
کامیت
8c756dad23

+ 65 - 6
components/bt/host/bluedroid/hci/hci_hal_h4.c

@@ -76,6 +76,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;
@@ -96,6 +98,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)
@@ -107,10 +110,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);
@@ -142,10 +148,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;
@@ -300,7 +309,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);
     }
@@ -323,15 +332,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;
@@ -342,8 +400,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;

+ 7 - 2
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;

+ 2 - 0
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;

+ 14 - 6
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);

+ 1 - 1
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);