diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn.c b/subsys/bluetooth/controller/ll_sw/ull_conn.c index 83dfce376e1..14a228e81a2 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn.c @@ -2014,7 +2014,7 @@ void ull_conn_tx_ack(uint16_t handle, memq_link_t *link, struct node_tx *tx) #if defined(CONFIG_BT_LL_SW_LLCP_LEGACY) mem_release(tx, &mem_conn_tx_ctrl.free); #else /* CONFIG_BT_LL_SW_LLCP_LEGACY */ - struct ll_conn *conn = ll_conn_get(handle); + struct ll_conn *conn = ll_connected_get(handle); ull_cp_release_tx(conn, tx); #endif /* CONFIG_BT_LL_SW_LLCP_LEGACY */ @@ -2492,6 +2492,11 @@ static void conn_cleanup_finalize(struct ll_conn *conn) #else /* CONFIG_BT_LL_SW_LLCP_LEGACY */ ARG_UNUSED(rx); ull_cp_state_set(conn, ULL_CP_DISCONNECTED); + + /* Update tx buffer queue handling */ +#if defined(LLCP_TX_CTRL_BUF_QUEUE_ENABLE) + ull_cp_update_tx_buffer_queue(conn); +#endif /* LLCP_TX_CTRL_BUF_QUEUE_ENABLE */ #endif /* CONFIG_BT_LL_SW_LLCP_LEGACY */ /* flush demux-ed Tx buffer still in ULL context */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_types.h b/subsys/bluetooth/controller/ll_sw/ull_conn_types.h index 9bd5f7b18b2..0976167b80d 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_types.h @@ -462,12 +462,7 @@ struct llcp_struct { } cte_rsp; #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ -#if (CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM > 0) &&\ - (CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM <\ - CONFIG_BT_CTLR_LLCP_TX_PER_CONN_TX_CTRL_BUF_NUM_MAX) - uint8_t tx_buffer_alloc; -#endif /* (CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM > 0) */ uint8_t tx_q_pause_data_mask; }; /* struct llcp_struct */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp.c b/subsys/bluetooth/controller/ll_sw/ull_llcp.c index cf6806a0bbc..58b9d221911 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp.c @@ -92,6 +92,18 @@ void llcp_proc_ctx_release(struct proc_ctx *ctx) } #if defined(LLCP_TX_CTRL_BUF_QUEUE_ENABLE) +/* + * @brief Update 'global' tx buffer allowance + */ +void ull_cp_update_tx_buffer_queue(struct ll_conn *conn) +{ + if (conn->llcp.tx_buffer_alloc > CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM) { + common_tx_buffer_alloc -= (conn->llcp.tx_buffer_alloc - + CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM); + } +} + + /* * @brief Check for per conn pre-allocated tx buffer allowance * @return true if buffer is available @@ -159,8 +171,8 @@ void llcp_tx_alloc_unpeek(struct proc_ctx *ctx) */ struct node_tx *llcp_tx_alloc(struct ll_conn *conn, struct proc_ctx *ctx) { -#if (CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM > 0) conn->llcp.tx_buffer_alloc++; +#if (CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM > 0) if (conn->llcp.tx_buffer_alloc > CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM) { common_tx_buffer_alloc++; /* global buffer allocated, so we're at the head and should just pop head */ @@ -494,9 +506,7 @@ void ull_llcp_init(struct ll_conn *conn) #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ #if defined(LLCP_TX_CTRL_BUF_QUEUE_ENABLE) -#if (CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM > 0) conn->llcp.tx_buffer_alloc = 0; -#endif /* (CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM > 0) */ #endif /* LLCP_TX_CTRL_BUF_QUEUE_ENABLE */ conn->llcp.tx_q_pause_data_mask = 0; @@ -506,15 +516,13 @@ void ull_llcp_init(struct ll_conn *conn) void ull_cp_release_tx(struct ll_conn *conn, struct node_tx *tx) { #if defined(LLCP_TX_CTRL_BUF_QUEUE_ENABLE) -#if (CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM > 0) - if (conn->llcp.tx_buffer_alloc > CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM) { - common_tx_buffer_alloc--; + if (conn) { + LL_ASSERT(conn->llcp.tx_buffer_alloc > 0); + if (conn->llcp.tx_buffer_alloc > CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM) { + common_tx_buffer_alloc--; + } + conn->llcp.tx_buffer_alloc--; } - conn->llcp.tx_buffer_alloc--; -#else /* CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM > 0 */ - ARG_UNUSED(conn); - common_tx_buffer_alloc--; -#endif /* CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM > 0 */ #else /* LLCP_TX_CTRL_BUF_QUEUE_ENABLE */ ARG_UNUSED(conn); #endif /* LLCP_TX_CTRL_BUF_QUEUE_ENABLE */ @@ -1616,6 +1624,13 @@ uint16_t ctx_buffers_free(void) return local_ctx_buffers_free() + remote_ctx_buffers_free(); } +#if defined(LLCP_TX_CTRL_BUF_QUEUE_ENABLE) +uint8_t common_tx_buffer_alloc_count(void) +{ + return common_tx_buffer_alloc; +} +#endif /* LLCP_TX_CTRL_BUF_QUEUE_ENABLE */ + void test_int_mem_proc_ctx(void) { struct proc_ctx *ctx1; diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp.h b/subsys/bluetooth/controller/ll_sw/ull_llcp.h index 011bd3e0c6c..8216c2fcd32 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp.h +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp.h @@ -25,6 +25,11 @@ void ull_llcp_init(struct ll_conn *conn); */ void ull_cp_state_set(struct ll_conn *conn, uint8_t state); +/* + * @brief Update 'global' tx buffer allowance + */ +void ull_cp_update_tx_buffer_queue(struct ll_conn *conn); + /** * */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h b/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h index 00b35b913df..347b000adc4 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h @@ -643,4 +643,5 @@ bool lr_is_idle(struct ll_conn *conn); bool rr_is_disconnected(struct ll_conn *conn); bool rr_is_idle(struct ll_conn *conn); uint16_t ctx_buffers_free(void); +uint8_t common_tx_buffer_alloc_count(void); #endif diff --git a/tests/bluetooth/controller/ctrl_conn_update/src/main.c b/tests/bluetooth/controller/ctrl_conn_update/src/main.c index 9f2a4210f19..1242ee90d04 100644 --- a/tests/bluetooth/controller/ctrl_conn_update/src/main.c +++ b/tests/bluetooth/controller/ctrl_conn_update/src/main.c @@ -1090,9 +1090,6 @@ void test_conn_update_central_loc_unsupp_w_feat_exch(void) pdu = (struct pdu_data *)tx->pdu; instant = sys_le16_to_cpu(pdu->llctrl.conn_update_ind.instant); - /* Release Tx */ - ull_cp_release_tx(&conn, tx); - /* */ while (!is_instant_reached(&conn, instant)) { /* Prepare */ @@ -2491,7 +2488,7 @@ void test_conn_update_periph_loc_collision_reject_2nd_cpr(void) struct ll_conn conn_2nd; struct ll_conn conn_3rd; uint8_t err; - struct node_tx *tx; + struct node_tx *tx, *tx1; struct node_rx_pdu *ntf; uint16_t instant; @@ -2532,7 +2529,7 @@ void test_conn_update_periph_loc_collision_reject_2nd_cpr(void) event_prepare(&conn); /* (A) Tx Queue should have one LL Control PDU */ - lt_rx(LL_CONNECTION_PARAM_REQ, &conn, &tx, &conn_param_req); + lt_rx(LL_CONNECTION_PARAM_REQ, &conn, &tx1, &conn_param_req); lt_rx_q_is_empty(&conn); /* (B) Rx */ @@ -2611,7 +2608,7 @@ void test_conn_update_periph_loc_collision_reject_2nd_cpr(void) /* Release Tx */ - ull_cp_release_tx(&conn, tx); + ull_cp_release_tx(&conn, tx1); /*******************/ @@ -3668,9 +3665,6 @@ void test_conn_update_central_loc_accept_no_param_req(void) pdu = (struct pdu_data *)tx->pdu; instant = sys_le16_to_cpu(pdu->llctrl.conn_update_ind.instant); - /* Release Tx */ - ull_cp_release_tx(&conn, tx); - /* */ while (!is_instant_reached(&conn, instant)) { /* Prepare */ diff --git a/tests/bluetooth/controller/ctrl_tx_buffer_alloc/src/main.c b/tests/bluetooth/controller/ctrl_tx_buffer_alloc/src/main.c index 2228bc33960..1dacd336276 100644 --- a/tests/bluetooth/controller/ctrl_tx_buffer_alloc/src/main.c +++ b/tests/bluetooth/controller/ctrl_tx_buffer_alloc/src/main.c @@ -59,17 +59,26 @@ void test_tx_buffer_alloc(void) ctxs[ctx_idx] = llcp_create_local_procedure(PROC_VERSION_EXCHANGE); } + /* Init per conn tx_buffer_alloc count */ + for (int j = 1; j < CONFIG_BT_CTLR_LLCP_CONN; j++) { + conn[j].llcp.tx_buffer_alloc = 0; + } #if defined(LLCP_TX_CTRL_BUF_QUEUE_ENABLE) /* Check alloc flow */ for (i = 0; i < CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM; i++) { zassert_true(llcp_tx_alloc_peek(&conn[0], ctxs[0]), NULL); tx[tx_alloc_idx] = llcp_tx_alloc(&conn[0], ctxs[0]); + zassert_equal(conn[0].llcp.tx_buffer_alloc, i + 1, NULL); + zassert_equal(common_tx_buffer_alloc_count(), 0, NULL); zassert_not_null(tx[tx_alloc_idx], NULL); tx_alloc_idx++; } for (i = 0; i < CONFIG_BT_CTLR_LLCP_COMMON_TX_CTRL_BUF_NUM; i++) { zassert_true(llcp_tx_alloc_peek(&conn[0], ctxs[0]), NULL); tx[tx_alloc_idx] = llcp_tx_alloc(&conn[0], ctxs[0]); + zassert_equal(conn[0].llcp.tx_buffer_alloc, + CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM + i + 1, NULL); + zassert_equal(common_tx_buffer_alloc_count(), i+1, NULL); zassert_not_null(tx[tx_alloc_idx], NULL); tx_alloc_idx++; } @@ -82,6 +91,9 @@ void test_tx_buffer_alloc(void) zassert_true(llcp_tx_alloc_peek(&conn[j], ctxs[j]), NULL); tx[tx_alloc_idx] = llcp_tx_alloc(&conn[j], ctxs[j]); zassert_not_null(tx[tx_alloc_idx], NULL); + zassert_equal(common_tx_buffer_alloc_count(), + CONFIG_BT_CTLR_LLCP_COMMON_TX_CTRL_BUF_NUM, NULL); + zassert_equal(conn[j].llcp.tx_buffer_alloc, i + 1, NULL); tx_alloc_idx++; } @@ -90,6 +102,10 @@ void test_tx_buffer_alloc(void) } ull_cp_release_tx(&conn[0], tx[1]); + zassert_equal(common_tx_buffer_alloc_count(), + CONFIG_BT_CTLR_LLCP_COMMON_TX_CTRL_BUF_NUM - 1, NULL); + zassert_equal(conn[0].llcp.tx_buffer_alloc, CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM + + CONFIG_BT_CTLR_LLCP_COMMON_TX_CTRL_BUF_NUM - 1, NULL); /* global pool is now 'open' again, but ctxs[1] is NOT next in line */ zassert_false(llcp_tx_alloc_peek(&conn[1], ctxs[1]), NULL); @@ -97,9 +113,18 @@ void test_tx_buffer_alloc(void) /* ... ctxs[0] is */ zassert_true(llcp_tx_alloc_peek(&conn[0], ctxs[0]), NULL); tx[tx_alloc_idx] = llcp_tx_alloc(&conn[0], ctxs[0]); + zassert_equal(common_tx_buffer_alloc_count(), CONFIG_BT_CTLR_LLCP_COMMON_TX_CTRL_BUF_NUM, + NULL); + zassert_equal(conn[0].llcp.tx_buffer_alloc, CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM + + CONFIG_BT_CTLR_LLCP_COMMON_TX_CTRL_BUF_NUM, NULL); + zassert_not_null(tx[tx_alloc_idx], NULL); tx_alloc_idx++; ull_cp_release_tx(&conn[0], tx[tx_alloc_idx - 1]); + zassert_equal(common_tx_buffer_alloc_count(), + CONFIG_BT_CTLR_LLCP_COMMON_TX_CTRL_BUF_NUM - 1, NULL); + zassert_equal(conn[0].llcp.tx_buffer_alloc, CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM + + CONFIG_BT_CTLR_LLCP_COMMON_TX_CTRL_BUF_NUM - 1, NULL); /* global pool does not allow as ctxs[2] is NOT next up */ zassert_false(llcp_tx_alloc_peek(&conn[2], ctxs[2]), NULL);