diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index ec945c08e01..4728ddb27c6 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -34,6 +34,10 @@ config BLUETOOTH_CONTROLLER_TX_BUFFER_SIZE Maximum is set to 16384 due to implementation limitations (use of uint16_t for size/length variables). +config BLUETOOTH_CONTROLLER_RX_PRIO_STACK_SIZE + int + default 320 + comment "BLE Controller features" config BLUETOOTH_CONTROLLER_LE_PING diff --git a/subsys/bluetooth/controller/hci/hci_driver.c b/subsys/bluetooth/controller/hci/hci_driver.c index 1e27d653027..4e23c2fff98 100644 --- a/subsys/bluetooth/controller/hci/hci_driver.c +++ b/subsys/bluetooth/controller/hci/hci_driver.c @@ -73,9 +73,12 @@ static uint8_t MALIGN(4) _ticker_user_ops[RADIO_TICKER_USER_OPS] [TICKER_USER_OP_T_SIZE]; static uint8_t MALIGN(4) _radio[LL_MEM_TOTAL]; -static K_SEM_DEFINE(sem_recv, 0, UINT_MAX); -static BT_STACK_NOINIT(recv_thread_stack, - CONFIG_BLUETOOTH_RX_STACK_SIZE); +static K_SEM_DEFINE(sem_prio_recv, 0, UINT_MAX); +static K_FIFO_DEFINE(recv_fifo); + +static BT_STACK_NOINIT(prio_recv_thread_stack, + CONFIG_BLUETOOTH_CONTROLLER_RX_PRIO_STACK_SIZE); +static BT_STACK_NOINIT(recv_thread_stack, CONFIG_BLUETOOTH_RX_STACK_SIZE); K_MUTEX_DEFINE(mutex_rand); @@ -164,7 +167,7 @@ void radio_active_callback(uint8_t active) void radio_event_callback(void) { - k_sem_give(&sem_recv); + k_sem_give(&sem_prio_recv); } static void radio_nrf5_isr(void *arg) @@ -207,11 +210,10 @@ static void swi4_nrf5_isr(void *arg) mayfly_run(MAYFLY_CALL_ID_1); } -static void recv_thread(void *p1, void *p2, void *p3) +static void prio_recv_thread(void *p1, void *p2, void *p3) { while (1) { struct radio_pdu_node_rx *node_rx; - struct pdu_data *pdu_data; struct net_buf *buf; uint8_t num_cmplt; uint16_t handle; @@ -229,50 +231,74 @@ static void recv_thread(void *p1, void *p2, void *p3) if (node_rx) { - pdu_data = (void *)node_rx->pdu_data; - /* Check if we need to generate an HCI event or ACL - * data - */ - if (node_rx->hdr.type != NODE_RX_TYPE_DC_PDU || - pdu_data->ll_id == PDU_DATA_LLID_CTRL) { - /* generate a (non-priority) HCI event */ - if (hci_evt_is_discardable(node_rx)) { - buf = bt_buf_get_rx(K_NO_WAIT); - } else { - buf = bt_buf_get_rx(K_FOREVER); - } + radio_rx_dequeue(); - if (buf) { - bt_buf_set_type(buf, BT_BUF_EVT); - hci_evt_encode(node_rx, buf); - } + BT_DBG("RX node enqueue"); + k_fifo_put(&recv_fifo, node_rx); + + continue; + } + + BT_DBG("sem take..."); + k_sem_take(&sem_prio_recv, K_FOREVER); + BT_DBG("sem taken"); + + stack_analyze("prio recv thread stack", prio_recv_thread_stack, + sizeof(prio_recv_thread_stack)); + } +} + +static void recv_thread(void *p1, void *p2, void *p3) +{ + while (1) { + struct radio_pdu_node_rx *node_rx; + struct pdu_data *pdu_data; + struct net_buf *buf; + + BT_DBG("RX node get"); + node_rx = k_fifo_get(&recv_fifo, K_FOREVER); + BT_DBG("RX node dequeued"); + + pdu_data = (void *)node_rx->pdu_data; + /* Check if we need to generate an HCI event or ACL + * data + */ + if (node_rx->hdr.type != NODE_RX_TYPE_DC_PDU || + pdu_data->ll_id == PDU_DATA_LLID_CTRL) { + /* generate a (non-priority) HCI event */ + if (hci_evt_is_discardable(node_rx)) { + buf = bt_buf_get_rx(K_NO_WAIT); } else { - /* generate ACL data */ buf = bt_buf_get_rx(K_FOREVER); - bt_buf_set_type(buf, BT_BUF_ACL_IN); - hci_acl_encode(node_rx, buf); } if (buf) { - if (buf->len) { - BT_DBG("Packet in: type:%u len:%u", - bt_buf_get_type(buf), buf->len); - bt_recv(buf); - } else { - net_buf_unref(buf); - } + bt_buf_set_type(buf, BT_BUF_EVT); + hci_evt_encode(node_rx, buf); } - - radio_rx_dequeue(); - radio_rx_fc_set(node_rx->hdr.handle, 0); - node_rx->hdr.onion.next = 0; - radio_rx_mem_release(&node_rx); - - k_yield(); } else { - k_sem_take(&sem_recv, K_FOREVER); + /* generate ACL data */ + buf = bt_buf_get_rx(K_FOREVER); + bt_buf_set_type(buf, BT_BUF_ACL_IN); + hci_acl_encode(node_rx, buf); } + radio_rx_fc_set(node_rx->hdr.handle, 0); + node_rx->hdr.onion.next = 0; + radio_rx_mem_release(&node_rx); + + if (buf) { + if (buf->len) { + BT_DBG("Packet in: type:%u len:%u", + bt_buf_get_type(buf), buf->len); + bt_recv(buf); + } else { + net_buf_unref(buf); + } + } + + k_yield(); + stack_analyze("recv thread stack", recv_thread_stack, sizeof(recv_thread_stack)); } @@ -394,6 +420,10 @@ static int hci_driver_open(void) irq_enable(NRF5_IRQ_RNG_IRQn); irq_enable(NRF5_IRQ_SWI4_IRQn); + k_thread_spawn(prio_recv_thread_stack, sizeof(prio_recv_thread_stack), + prio_recv_thread, NULL, NULL, NULL, K_PRIO_COOP(6), 0, + K_NO_WAIT); + k_thread_spawn(recv_thread_stack, sizeof(recv_thread_stack), recv_thread, NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT); diff --git a/subsys/bluetooth/controller/ll/ctrl.h b/subsys/bluetooth/controller/ll/ctrl.h index 166cf517ca9..339c06cb28d 100644 --- a/subsys/bluetooth/controller/ll/ctrl.h +++ b/subsys/bluetooth/controller/ll/ctrl.h @@ -222,13 +222,14 @@ enum radio_pdu_node_rx_type { }; struct radio_pdu_node_rx_hdr { - enum radio_pdu_node_rx_type type; - uint16_t handle; union { - void *next; + void *next; /* used also by k_fifo once pulled */ void *link; uint8_t packet_release_last; } onion; + + enum radio_pdu_node_rx_type type; + uint16_t handle; }; struct radio_pdu_node_rx {