Bluetooth: controller: llcp: fixing tx buffer queue handling

Misc. fixups to get the tx buffer alloc mechanism to work as intended

Signed-off-by: Erik Brockhoff <erbr@oticon.com>
This commit is contained in:
Erik Brockhoff 2022-06-21 13:33:32 +02:00 committed by Carles Cufí
commit 1ff458ec87
7 changed files with 66 additions and 26 deletions

View file

@ -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 */

View file

@ -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 */

View file

@ -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) {
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--;
#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;

View file

@ -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);
/**
*
*/

View file

@ -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

View file

@ -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 */

View file

@ -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);