From 214e280b67f2c8b75dc612ae5451c288aecd2707 Mon Sep 17 00:00:00 2001 From: liqigan Date: Fri, 26 Jun 2026 14:55:04 +0800 Subject: [PATCH] change(bt/bluedroid): Refactored HCI ACL datapath --- components/bt/host/bluedroid/hci/hci_layer.c | 19 +- .../bt/host/bluedroid/stack/btu/btu_init.c | 20 +- .../bt/host/bluedroid/stack/btu/btu_task.c | 174 ++++++++++++++++++ .../host/bluedroid/stack/include/stack/btu.h | 9 + 4 files changed, 214 insertions(+), 8 deletions(-) diff --git a/components/bt/host/bluedroid/hci/hci_layer.c b/components/bt/host/bluedroid/hci/hci_layer.c index 7ca7ad03256..c43f8dc46e4 100644 --- a/components/bt/host/bluedroid/hci/hci_layer.c +++ b/components/bt/host/bluedroid/hci/hci_layer.c @@ -576,8 +576,23 @@ intercepted: static void dispatch_reassembled(BT_HDR *packet) { // Events should already have been dispatched before this point - //Tell Up-layer received packet. - if (btu_task_post(SIG_BTU_HCI_MSG, packet, OSI_THREAD_MAX_TIMEOUT) == false) { + // Tell Up-layer received packet. + do { + if ((packet->event & BT_EVT_MASK) == BT_EVT_TO_BTU_HCI_ACL) { + if (btu_hci_acl_data_post(packet)) { + packet = NULL; + } + // TODO: Use controller to host flow control + break; + } + + if (btu_task_post(SIG_BTU_HCI_MSG, packet, OSI_THREAD_MAX_TIMEOUT)) { + packet = NULL; + break; + } + } while (0); + + if (packet != NULL) { osi_free(packet); } } diff --git a/components/bt/host/bluedroid/stack/btu/btu_init.c b/components/bt/host/bluedroid/stack/btu/btu_init.c index 67b48effa50..c57bb42dfe9 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_init.c +++ b/components/bt/host/bluedroid/stack/btu/btu_init.c @@ -201,6 +201,10 @@ bool BTU_StartUp(void) goto error_exit; } + if (!btu_acl_queue_init()) { + goto error_exit; + } + if (btu_task_post(SIG_BTU_START_UP, NULL, OSI_THREAD_MAX_TIMEOUT) == false) { goto error_exit; } @@ -224,10 +228,19 @@ error_exit:; ******************************************************************************/ void BTU_ShutDown(void) { + btu_acl_queue_close(); + + btu_task_shut_down(); + + if (btu_thread) { + osi_thread_free(btu_thread); + btu_thread = NULL; + } + + btu_acl_queue_deinit(); #if BTU_DYNAMIC_MEMORY FREE_AND_RESET(btu_cb_ptr); #endif - btu_task_shut_down(); hash_map_free(btu_general_alarm_hash_map); osi_mutex_free(&btu_general_alarm_lock); @@ -238,11 +251,6 @@ void BTU_ShutDown(void) hash_map_free(btu_l2cap_alarm_hash_map); osi_mutex_free(&btu_l2cap_alarm_lock); - if (btu_thread) { - osi_thread_free(btu_thread); - btu_thread = NULL; - } - btu_general_alarm_hash_map = NULL; btu_oneshot_alarm_hash_map = NULL; btu_l2cap_alarm_hash_map = NULL; diff --git a/components/bt/host/bluedroid/stack/btu/btu_task.c b/components/bt/host/bluedroid/stack/btu/btu_task.c index c38ecea33bc..02bbea910b1 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_task.c +++ b/components/bt/host/bluedroid/stack/btu/btu_task.c @@ -29,6 +29,7 @@ #include "btm_int.h" #include "stack/btu.h" #include "osi/hash_map.h" +#include "osi/pkt_queue.h" #include "stack/hcimsgs.h" #include "l2c_int.h" #include "osi/osi.h" @@ -122,6 +123,25 @@ typedef void (tUSER_TIMEOUT_FUNC) (TIMER_LIST_ENT *p_tle); static void btu_l2cap_alarm_process(void *param); static void btu_general_alarm_process(void *param); static void btu_hci_msg_process(void *param); +static void btu_hci_acl_data_handler(void *param); +static bool btu_hci_acl_data_ready(uint32_t timeout); +static void btu_acl_pkt_linked_free(pkt_linked_item_t *linked_pkt); + +static void btu_acl_pkt_linked_free(pkt_linked_item_t *linked_pkt) +{ + do { + if (linked_pkt == NULL) { + break; + } + + BT_HDR *packet = NULL; + memcpy(&packet, linked_pkt->data, sizeof(packet)); + if (packet != NULL) { + osi_free(packet); + } + osi_free(linked_pkt); + } while (0); +} #if (defined(BTA_INCLUDED) && BTA_INCLUDED == TRUE) static void btu_bta_alarm_process(void *param); @@ -197,6 +217,57 @@ static void btu_hci_msg_process(void *param) } +static bool btu_hci_acl_data_ready(uint32_t timeout) +{ + bool status = false; + + do { + if (btu_cb.acl_closing || btu_cb.acl_data_ready == NULL) { + break; + } + + status = osi_thread_post_event(btu_cb.acl_data_ready, timeout); + } while (0); + + return status; +} + +static void btu_hci_acl_data_handler(void *param) +{ + UNUSED(param); + struct pkt_queue *acl_pkt_queue = btu_cb.acl_pkt_queue; + if (acl_pkt_queue == NULL || btu_cb.acl_closing) { + return; + } + + size_t pkts_to_process = pkt_queue_length(acl_pkt_queue); + if (pkts_to_process > BTU_ACL_QUEUE_BATCH_SIZE) { + pkts_to_process = BTU_ACL_QUEUE_BATCH_SIZE; + } + + for (size_t i = 0; i < pkts_to_process; i++) { + pkt_linked_item_t *linked_pkt = pkt_queue_dequeue(acl_pkt_queue); + if (linked_pkt == NULL) { + break; + } + + BT_HDR *packet = NULL; + memcpy(&packet, linked_pkt->data, sizeof(packet)); + if (packet == NULL) { + osi_free(linked_pkt); + continue; + } + l2c_rcv_acl_data(packet); + osi_free(linked_pkt); + } + + size_t pending = pkt_queue_length(acl_pkt_queue); + if (pending != 0) { + // Re-post from BTU thread itself must stay non-blocking to avoid deadlock on a full queue. + btu_hci_acl_data_ready(0); + } +} + #if (defined(BTA_INCLUDED) && BTA_INCLUDED == TRUE) static void btu_bta_alarm_process(void *param) { @@ -263,6 +334,109 @@ bool btu_task_post(uint32_t sig, void *param, uint32_t timeout) return status; } +bool btu_acl_queue_init(void) +{ + bool status = false; + + btu_cb.acl_closing = FALSE; + + do { + btu_cb.acl_pkt_queue = pkt_queue_create(); + if (btu_cb.acl_pkt_queue == NULL) { + break; + } + + btu_cb.acl_data_ready = osi_event_create(btu_hci_acl_data_handler, NULL); + if (btu_cb.acl_data_ready == NULL) { + break; + } + + if (!osi_event_bind(btu_cb.acl_data_ready, btu_thread, 0)) { + break; + } + status = true; + } while (0); + + if (status == false) { + if (btu_cb.acl_data_ready != NULL) { + osi_event_delete(btu_cb.acl_data_ready); + btu_cb.acl_data_ready = NULL; + } + + if (btu_cb.acl_pkt_queue != NULL) { + pkt_queue_destroy(btu_cb.acl_pkt_queue, NULL); + btu_cb.acl_pkt_queue = NULL; + } + + btu_cb.acl_closing = TRUE; + } + + return status; +} + +void btu_acl_queue_close(void) +{ +#if BTU_DYNAMIC_MEMORY == TRUE + if (!btu_cb_ptr) { + return; + } +#endif /* BTU_DYNAMIC_MEMORY == FALSE */ + + btu_cb.acl_closing = TRUE; + + if (btu_cb.acl_data_ready != NULL) { + osi_event_delete(btu_cb.acl_data_ready); + btu_cb.acl_data_ready = NULL; + } +} + +void btu_acl_queue_deinit(void) +{ +#if BTU_DYNAMIC_MEMORY == TRUE + if (!btu_cb_ptr) { + return; + } +#endif /* BTU_DYNAMIC_MEMORY == FALSE */ + + btu_cb.acl_closing = TRUE; + + if (btu_cb.acl_pkt_queue != NULL) { + pkt_queue_destroy(btu_cb.acl_pkt_queue, btu_acl_pkt_linked_free); + btu_cb.acl_pkt_queue = NULL; + } +} + +bool btu_hci_acl_data_post(BT_HDR *packet) +{ + bool status = false; + + do { + if (packet == NULL || btu_cb.acl_closing || btu_cb.acl_pkt_queue == NULL) { + break; + } + + size_t acl_q_len = pkt_queue_length(btu_cb.acl_pkt_queue); + if (acl_q_len >= BTU_ACL_QUEUE_HIGH_WATERMARK) { + HCI_TRACE_WARNING("ACL queue high watermark (len=%u)", (unsigned)acl_q_len); + break; + } + + pkt_linked_item_t *linked_pkt = (pkt_linked_item_t *)osi_malloc(BT_PKT_LINKED_HDR_SIZE + sizeof(packet)); + if (linked_pkt == NULL) { + HCI_TRACE_WARNING("ACL queue malloc pkt failed"); + break; + } + + memcpy(linked_pkt->data, &packet, sizeof(packet)); + pkt_queue_enqueue(btu_cb.acl_pkt_queue, linked_pkt); + + btu_hci_acl_data_ready(OSI_THREAD_MAX_TIMEOUT); + status = true; + } while (0); + + return status; +} + void btu_task_start_up(void *param) { UNUSED(param); diff --git a/components/bt/host/bluedroid/stack/include/stack/btu.h b/components/bt/host/bluedroid/stack/include/stack/btu.h index f973cccb68c..7a49619e050 100644 --- a/components/bt/host/bluedroid/stack/include/stack/btu.h +++ b/components/bt/host/bluedroid/stack/include/stack/btu.h @@ -206,6 +206,8 @@ typedef struct { #define BTU_MAX_REG_TIMER (2) /* max # timer callbacks which may register */ #define BTU_MAX_REG_EVENT (6) /* max # event callbacks which may register */ #define BTU_DEFAULT_DATA_SIZE (0x2a0) +#define BTU_ACL_QUEUE_BATCH_SIZE (12) +#define BTU_ACL_QUEUE_HIGH_WATERMARK (100) #if (BLE_INCLUDED == TRUE) #define BTU_DEFAULT_BLE_DATA_SIZE (27) @@ -234,6 +236,9 @@ typedef struct { typedef struct { tBTU_TIMER_REG timer_reg[BTU_MAX_REG_TIMER]; tBTU_EVENT_REG event_reg[BTU_MAX_REG_EVENT]; + struct pkt_queue *acl_pkt_queue; + struct osi_event *acl_data_ready; + BOOLEAN acl_closing; BOOLEAN reset_complete; /* TRUE after first ack from device received */ UINT8 trace_level; /* Trace level for HCI layer */ @@ -303,6 +308,10 @@ void btu_task_shut_down(void); UINT16 BTU_BleAclPktSize(void); bool btu_task_post(uint32_t sig, void *param, uint32_t timeout); +bool btu_acl_queue_init(void); +void btu_acl_queue_close(void); +void btu_acl_queue_deinit(void); +bool btu_hci_acl_data_post(BT_HDR *packet); int get_btu_work_queue_size(void);