/* * Copyright (c) 2020 Demant * * SPDX-License-Identifier: Apache-2.0 */ #include #include #define ULL_LLCP_UNITTEST #include #include #include #include #include "hal/ccm.h" #include "util/util.h" #include "util/mem.h" #include "util/memq.h" #include "util/dbuf.h" #include "pdu_df.h" #include "lll/pdu_vendor.h" #include "pdu.h" #include "ll.h" #include "ll_settings.h" #include "lll.h" #include "lll/lll_df_types.h" #include "lll_conn.h" #include "lll_conn_iso.h" #include "ull_tx_queue.h" #include "isoal.h" #include "ull_iso_types.h" #include "ull_conn_iso_types.h" #include "ull_conn_types.h" #include "ull_llcp.h" #include "ull_conn_internal.h" #include "ull_llcp_internal.h" #include "helper_pdu.h" #include "helper_util.h" static struct ll_conn conn[CONFIG_BT_CTLR_LLCP_CONN]; static void alloc_setup(void *data) { ull_conn_init(); for (int i = 0; i < CONFIG_BT_MAX_CONN; i++) { test_setup(&conn[i]); } } ZTEST(tx_buffer_alloc, test_tx_buffer_alloc) { struct proc_ctx *ctxs[CONFIG_BT_CTLR_LLCP_CONN]; struct node_tx *tx[CONFIG_BT_CTLR_LLCP_COMMON_TX_CTRL_BUF_NUM + CONFIG_BT_CTLR_LLCP_CONN * CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM + 3]; uint16_t tx_alloc_idx = 0; int i; for (int ctx_idx = 0; ctx_idx < CONFIG_BT_CTLR_LLCP_CONN; ctx_idx++) { 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])); tx[tx_alloc_idx] = llcp_tx_alloc(&conn[0], ctxs[0]); zassert_equal(conn[0].llcp.tx_buffer_alloc, i + 1); zassert_equal(llcp_common_tx_buffer_alloc_count(), 0); 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])); 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(llcp_common_tx_buffer_alloc_count(), i+1); zassert_not_null(tx[tx_alloc_idx], NULL); tx_alloc_idx++; } zassert_false(llcp_tx_alloc_peek(&conn[0], ctxs[0])); zassert_equal(ctxs[0]->wait_reason, WAITING_FOR_TX_BUFFER); for (int j = 1; j < CONFIG_BT_CTLR_LLCP_CONN; j++) { /* Now global pool is exausted, but conn pool is not */ for (i = 0; i < CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM; i++) { zassert_true(llcp_tx_alloc_peek(&conn[j], ctxs[j])); tx[tx_alloc_idx] = llcp_tx_alloc(&conn[j], ctxs[j]); zassert_not_null(tx[tx_alloc_idx], NULL); zassert_equal(llcp_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); tx_alloc_idx++; } zassert_false(llcp_tx_alloc_peek(&conn[j], ctxs[j])); zassert_equal(ctxs[j]->wait_reason, WAITING_FOR_TX_BUFFER); } ull_cp_release_tx(&conn[0], tx[1]); zassert_equal(llcp_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])); /* ... ctxs[0] is */ zassert_true(llcp_tx_alloc_peek(&conn[0], ctxs[0])); tx[tx_alloc_idx] = llcp_tx_alloc(&conn[0], ctxs[0]); zassert_equal(llcp_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(llcp_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])); #if (CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM > 0) /* Release conn[2] held tx, to confirm alloc is allowed after releasing pre-alloted buf */ zassert_true(!(conn[2].llcp.tx_buffer_alloc < CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM), NULL); ull_cp_release_tx(&conn[2], tx[CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM + CONFIG_BT_CTLR_LLCP_COMMON_TX_CTRL_BUF_NUM + CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM]); zassert_true((conn[2].llcp.tx_buffer_alloc < CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM), NULL); /* global pool does not allow as ctxs[2] is not next up, but pre alloted is now avail */ zassert_equal(ctxs[2]->wait_reason, WAITING_FOR_TX_BUFFER); zassert_not_null(ctxs[2]->wait_node.next, NULL); zassert_true(llcp_tx_alloc_peek(&conn[2], ctxs[2])); tx[tx_alloc_idx] = llcp_tx_alloc(&conn[2], ctxs[2]); zassert_not_null(tx[tx_alloc_idx], NULL); tx_alloc_idx++; /* No longer waiting in line */ zassert_equal(ctxs[2]->wait_reason, WAITING_FOR_NOTHING); zassert_is_null(ctxs[2]->wait_node.next, NULL); #endif /* (CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM > 0) */ /* now ctxs[1] is next up */ zassert_true(llcp_tx_alloc_peek(&conn[1], ctxs[1])); tx[tx_alloc_idx] = llcp_tx_alloc(&conn[0], ctxs[0]); zassert_not_null(tx[tx_alloc_idx], NULL); tx_alloc_idx++; #else /* LLCP_TX_CTRL_BUF_QUEUE_ENABLE */ /* Test that there are exactly LLCP_CONN * LLCP_TX_CTRL_BUF_NUM_MAX * buffers available */ for (i = 0; i < CONFIG_BT_CTLR_LLCP_TX_PER_CONN_TX_CTRL_BUF_NUM_MAX * CONFIG_BT_CTLR_LLCP_CONN; i++) { zassert_true(llcp_tx_alloc_peek(&conn[0], ctxs[0])); tx[tx_alloc_idx] = llcp_tx_alloc(&conn[0], ctxs[0]); zassert_not_null(tx[tx_alloc_idx], NULL); tx_alloc_idx++; } zassert_false(llcp_tx_alloc_peek(&conn[0], ctxs[0])); #endif /* LLCP_TX_CTRL_BUF_QUEUE_ENABLE */ } ZTEST_SUITE(tx_buffer_alloc, NULL, NULL, alloc_setup, NULL, NULL);