blob: 53781a499e78e3040cc6e83e2b6b6d95c443681a [file] [log] [blame]
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/types.h>
#include <zephyr/bluetooth/hci.h>
#include "hal/cpu_vendor_hal.h"
#include "hal/ccm.h"
#include "util/mem.h"
#include "util/mfifo.h"
#include "util/memq.h"
#include "util/dbuf.h"
#include "util.h"
#include "pdu.h"
#include "ll.h"
#include "ll_feat.h"
#include "ll_settings.h"
#include "lll.h"
#include "lll_vendor.h"
#include "lll/lll_adv_types.h"
#include "lll_adv.h"
#include "lll/lll_adv_pdu.h"
#include "lll_scan.h"
#include "lll_sync.h"
#include "lll/lll_df_types.h"
#include "lll_conn.h"
#include "ull_conn_internal.h"
#define EVENT_DONE_MAX 3
/* Backing storage for elements in mfifo_done */
static struct {
void *free;
uint8_t pool[sizeof(struct node_rx_event_done) * EVENT_DONE_MAX];
} mem_done;
static struct {
void *free;
uint8_t pool[sizeof(memq_link_t) * EVENT_DONE_MAX];
} mem_link_done;
#if defined(CONFIG_BT_CTLR_PHY) && defined(CONFIG_BT_CTLR_DATA_LENGTH)
#define LL_PDU_RX_CNT (3 + 128)
#else
#define LL_PDU_RX_CNT (2 + 128)
#endif
#define PDU_RX_CNT (CONFIG_BT_CTLR_RX_BUFFERS + 3)
#define RX_CNT (PDU_RX_CNT + LL_PDU_RX_CNT)
static MFIFO_DEFINE(pdu_rx_free, sizeof(void *), PDU_RX_CNT);
#if defined(CONFIG_BT_RX_USER_PDU_LEN)
#define PDU_RX_USER_PDU_OCTETS_MAX (CONFIG_BT_RX_USER_PDU_LEN)
#else
#define PDU_RX_USER_PDU_OCTETS_MAX 0
#endif
#define NODE_RX_HEADER_SIZE (offsetof(struct node_rx_pdu, pdu))
#define NODE_RX_STRUCT_OVERHEAD (NODE_RX_HEADER_SIZE)
#define PDU_ADV_SIZE MAX(PDU_AC_LL_SIZE_MAX, \
(PDU_AC_LL_HEADER_SIZE + LL_EXT_OCTETS_RX_MAX))
#define PDU_DATA_SIZE (PDU_DC_LL_HEADER_SIZE + LL_LENGTH_OCTETS_RX_MAX)
#define PDU_RX_NODE_POOL_ELEMENT_SIZE \
MROUND(NODE_RX_STRUCT_OVERHEAD + \
MAX(MAX(PDU_ADV_SIZE, PDU_DATA_SIZE), PDU_RX_USER_PDU_OCTETS_MAX))
/*
* just a big number
*/
#define PDU_RX_POOL_SIZE 16384
static struct {
void *free;
uint8_t pool[PDU_RX_POOL_SIZE];
} mem_pdu_rx;
/*
* just a big number
*/
#define LINK_RX_POOL_SIZE 16384
static struct {
uint8_t quota_pdu; /* Number of un-utilized buffers */
void *free;
uint8_t pool[LINK_RX_POOL_SIZE];
} mem_link_rx;
static MEMQ_DECLARE(ull_rx);
static MEMQ_DECLARE(ll_rx);
#if defined(CONFIG_BT_CONN)
static MFIFO_DEFINE(ll_pdu_rx_free, sizeof(void *), LL_PDU_RX_CNT);
#endif /* CONFIG_BT_CONN */
#ifdef ZTEST_UNITTEST
extern sys_slist_t ut_rx_q;
#else
sys_slist_t ut_rx_q;
#endif
static inline int init_reset(void);
static inline void rx_alloc(uint8_t max);
static inline void ll_rx_link_inc_quota(int8_t delta);
void ll_reset(void)
{
MFIFO_INIT(ll_pdu_rx_free);
init_reset();
}
void ll_rx_mem_release(void **node_rx)
{
struct node_rx_hdr *rx;
rx = *node_rx;
while (rx) {
struct node_rx_hdr *rx_free;
rx_free = rx;
rx = rx->next;
switch (rx_free->type) {
case NODE_RX_TYPE_DC_PDU:
ll_rx_link_inc_quota(1);
mem_release(rx_free, &mem_pdu_rx.free);
break;
default:
__ASSERT(0, "Tried to release unknown rx node type");
break;
}
}
*node_rx = rx;
rx_alloc(UINT8_MAX);
}
static inline void ll_rx_link_inc_quota(int8_t delta)
{
mem_link_rx.quota_pdu += delta;
}
void *ll_rx_link_alloc(void)
{
return mem_acquire(&mem_link_rx.free);
}
void ll_rx_link_release(void *link)
{
mem_release(link, &mem_link_rx.free);
}
void *ll_rx_alloc(void)
{
return mem_acquire(&mem_pdu_rx.free);
}
void ll_rx_release(void *node_rx)
{
mem_release(node_rx, &mem_pdu_rx.free);
}
void ll_rx_put(memq_link_t *link, void *rx)
{
sys_slist_append(&ut_rx_q, (sys_snode_t *)rx);
}
void ll_rx_sched(void)
{
}
void *ll_pdu_rx_alloc_peek(uint8_t count)
{
if (count > MFIFO_AVAIL_COUNT_GET(ll_pdu_rx_free)) {
return NULL;
}
return MFIFO_DEQUEUE_PEEK(ll_pdu_rx_free);
}
void *ll_pdu_rx_alloc(void)
{
return MFIFO_DEQUEUE(ll_pdu_rx_free);
}
void ll_tx_ack_put(uint16_t handle, struct node_tx *node)
{
}
void ull_ticker_status_give(uint32_t status, void *param)
{
}
uint32_t ull_ticker_status_take(uint32_t ret, uint32_t volatile *ret_cb)
{
return *ret_cb;
}
void *ull_disable_mark(void *param)
{
return NULL;
}
void *ull_disable_unmark(void *param)
{
return NULL;
}
void *ull_disable_mark_get(void)
{
return NULL;
}
int ull_ticker_stop_with_mark(uint8_t ticker_handle, void *param, void *lll_disable)
{
return 0;
}
void *ull_update_mark(void *param)
{
return NULL;
}
void *ull_update_unmark(void *param)
{
return NULL;
}
void *ull_update_mark_get(void)
{
return NULL;
}
int ull_disable(void *lll)
{
return 0;
}
void ull_rx_put(memq_link_t *link, void *rx)
{
}
void ull_rx_sched(void)
{
}
/* Forward declaration */
struct node_rx_event_done;
void ull_drift_ticks_get(struct node_rx_event_done *done, uint32_t *ticks_drift_plus,
uint32_t *ticks_drift_minus)
{
}
static inline int init_reset(void)
{
memq_link_t *link;
/* Initialize done pool. */
mem_init(mem_done.pool, sizeof(struct node_rx_event_done), EVENT_DONE_MAX, &mem_done.free);
/* Initialize done link pool. */
mem_init(mem_link_done.pool, sizeof(memq_link_t), EVENT_DONE_MAX, &mem_link_done.free);
/* Initialize rx pool. */
mem_init(mem_pdu_rx.pool, (PDU_RX_NODE_POOL_ELEMENT_SIZE),
sizeof(mem_pdu_rx.pool) / (PDU_RX_NODE_POOL_ELEMENT_SIZE), &mem_pdu_rx.free);
/* Initialize rx link pool. */
mem_init(mem_link_rx.pool, sizeof(memq_link_t),
sizeof(mem_link_rx.pool) / sizeof(memq_link_t), &mem_link_rx.free);
/* Acquire a link to initialize ull rx memq */
link = mem_acquire(&mem_link_rx.free);
/* Initialize ull rx memq */
MEMQ_INIT(ull_rx, link);
/* Acquire a link to initialize ll rx memq */
link = mem_acquire(&mem_link_rx.free);
/* Initialize ll rx memq */
MEMQ_INIT(ll_rx, link);
/* Allocate rx free buffers */
mem_link_rx.quota_pdu = RX_CNT;
rx_alloc(UINT8_MAX);
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
/* Reset CPR mutex */
cpr_active_reset();
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
return 0;
}
static inline void rx_alloc(uint8_t max)
{
uint8_t idx;
#if defined(CONFIG_BT_CONN)
while (mem_link_rx.quota_pdu && MFIFO_ENQUEUE_IDX_GET(ll_pdu_rx_free, &idx)) {
memq_link_t *link;
struct node_rx_hdr *rx;
link = mem_acquire(&mem_link_rx.free);
if (!link) {
break;
}
rx = mem_acquire(&mem_pdu_rx.free);
if (!rx) {
mem_release(link, &mem_link_rx.free);
break;
}
link->mem = NULL;
rx->link = link;
MFIFO_BY_IDX_ENQUEUE(ll_pdu_rx_free, idx, rx);
ll_rx_link_inc_quota(-1);
}
#endif /* CONFIG_BT_CONN */
if (max > mem_link_rx.quota_pdu) {
max = mem_link_rx.quota_pdu;
}
while ((max--) && MFIFO_ENQUEUE_IDX_GET(pdu_rx_free, &idx)) {
memq_link_t *link;
struct node_rx_hdr *rx;
link = mem_acquire(&mem_link_rx.free);
if (!link) {
break;
}
rx = mem_acquire(&mem_pdu_rx.free);
if (!rx) {
mem_release(link, &mem_link_rx.free);
break;
}
rx->link = link;
MFIFO_BY_IDX_ENQUEUE(pdu_rx_free, idx, rx);
ll_rx_link_inc_quota(-1);
}
}