If we allocate a node in LLL and it turns out that we don't need it (e.g. allocated connection on AUX_CONNECT_REQ, but connection handshake did not complete and we don't need it) we still need to send it to ULL to be released. We can use existing NODE_RX_TYPE_DC_PDU_RELEASE node type for this purpose, but we just need to make sure it's passed from LLL to ULL properly. Also, since this now does not only release DC PDUs, let's change its name to a more generic one. Signed-off-by: Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
375 lines
10 KiB
C
375 lines
10 KiB
C
/*
|
|
* Copyright (c) 2018-2019 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#if defined(CONFIG_BT_CTLR_RX_PDU_META)
|
|
#include "lll_meta.h"
|
|
#endif /* CONFIG_BT_CTLR_RX_PDU_META */
|
|
|
|
#define TICKER_INSTANCE_ID_CTLR 0
|
|
#define TICKER_USER_ID_LLL MAYFLY_CALL_ID_0
|
|
#define TICKER_USER_ID_ULL_HIGH MAYFLY_CALL_ID_1
|
|
#define TICKER_USER_ID_ULL_LOW MAYFLY_CALL_ID_2
|
|
#define TICKER_USER_ID_THREAD MAYFLY_CALL_ID_PROGRAM
|
|
|
|
#define EVENT_PIPELINE_MAX 7
|
|
#define EVENT_DONE_MAX 3
|
|
|
|
#define HDR_ULL(p) ((void *)((uint8_t *)(p) + sizeof(struct evt_hdr)))
|
|
#define HDR_ULL2LLL(p) ((struct lll_hdr *)((uint8_t *)(p) + \
|
|
sizeof(struct ull_hdr)))
|
|
#define HDR_LLL2EVT(p) ((struct evt_hdr *)((struct lll_hdr *)(p))->parent)
|
|
|
|
#if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
|
|
#define XON_BITMASK BIT(31) /* XTAL has been retained from previous prepare */
|
|
#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
|
|
|
|
#if defined(CONFIG_BT_OBSERVER)
|
|
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
|
#if defined(CONFIG_BT_CTLR_PHY_CODED)
|
|
#define BT_CTLR_SCAN_SET 2
|
|
#else /* !CONFIG_BT_CTLR_PHY_CODED */
|
|
#define BT_CTLR_SCAN_SET 1
|
|
#endif /* !CONFIG_BT_CTLR_PHY_CODED */
|
|
#else /* !CONFIG_BT_CTLR_ADV_EXT */
|
|
#define BT_CTLR_SCAN_SET 1
|
|
#endif /* !CONFIG_BT_CTLR_ADV_EXT */
|
|
#endif /* CONFIG_BT_OBSERVER */
|
|
|
|
enum {
|
|
TICKER_ID_LLL_PREEMPT = 0,
|
|
|
|
#if defined(CONFIG_BT_BROADCASTER)
|
|
TICKER_ID_ADV_STOP,
|
|
TICKER_ID_ADV_BASE,
|
|
#if defined(CONFIG_BT_CTLR_ADV_EXT) || defined(CONFIG_BT_HCI_MESH_EXT)
|
|
TICKER_ID_ADV_LAST = ((TICKER_ID_ADV_BASE) +
|
|
(CONFIG_BT_CTLR_ADV_SET) - 1),
|
|
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
|
#if (CONFIG_BT_CTLR_ADV_AUX_SET > 0)
|
|
TICKER_ID_ADV_AUX_BASE,
|
|
TICKER_ID_ADV_AUX_LAST = ((TICKER_ID_ADV_AUX_BASE) +
|
|
(CONFIG_BT_CTLR_ADV_AUX_SET) - 1),
|
|
#if defined(CONFIG_BT_CTLR_ADV_PERIODIC)
|
|
TICKER_ID_ADV_SYNC_BASE,
|
|
TICKER_ID_ADV_SYNC_LAST = ((TICKER_ID_ADV_SYNC_BASE) +
|
|
(CONFIG_BT_CTLR_ADV_SYNC_SET) - 1),
|
|
#if defined(CONFIG_BT_CTLR_ADV_ISO)
|
|
TICKER_ID_ADV_ISO_BASE,
|
|
TICKER_ID_ADV_ISO_LAST = ((TICKER_ID_ADV_ISO_BASE) +
|
|
(CONFIG_BT_CTLR_ADV_ISO_SET) - 1),
|
|
#endif /* CONFIG_BT_CTLR_ADV_ISO */
|
|
#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */
|
|
#endif /* CONFIG_BT_CTLR_ADV_AUX_SET > 0 */
|
|
#endif /* CONFIG_BT_CTLR_ADV_EXT */
|
|
#endif /* !CONFIG_BT_CTLR_ADV_EXT || !CONFIG_BT_HCI_MESH_EXT */
|
|
#endif /* CONFIG_BT_BROADCASTER */
|
|
|
|
#if defined(CONFIG_BT_OBSERVER)
|
|
TICKER_ID_SCAN_STOP,
|
|
TICKER_ID_SCAN_BASE,
|
|
TICKER_ID_SCAN_LAST = ((TICKER_ID_SCAN_BASE) + (BT_CTLR_SCAN_SET) - 1),
|
|
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
|
TICKER_ID_SCAN_AUX_BASE,
|
|
TICKER_ID_SCAN_AUX_LAST = ((TICKER_ID_SCAN_AUX_BASE) +
|
|
(CONFIG_BT_CTLR_SCAN_AUX_SET) - 1),
|
|
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC)
|
|
TICKER_ID_SCAN_SYNC_BASE,
|
|
TICKER_ID_SCAN_SYNC_LAST = ((TICKER_ID_SCAN_SYNC_BASE) +
|
|
(CONFIG_BT_CTLR_SCAN_SYNC_SET) - 1),
|
|
#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */
|
|
#endif /* CONFIG_BT_CTLR_ADV_EXT */
|
|
#endif /* CONFIG_BT_OBSERVER */
|
|
|
|
#if defined(CONFIG_BT_CONN)
|
|
TICKER_ID_CONN_BASE,
|
|
TICKER_ID_CONN_LAST = ((TICKER_ID_CONN_BASE) + (CONFIG_BT_MAX_CONN) -
|
|
1),
|
|
#endif /* CONFIG_BT_CONN */
|
|
|
|
#if defined(CONFIG_BT_CTLR_USER_EXT) && \
|
|
(CONFIG_BT_CTLR_USER_TICKER_ID_RANGE > 0)
|
|
TICKER_ID_USER_BASE,
|
|
TICKER_ID_USER_LAST = (TICKER_ID_USER_BASE +
|
|
CONFIG_BT_CTLR_USER_TICKER_ID_RANGE - 1),
|
|
#endif /* CONFIG_BT_CTLR_USER_EXT */
|
|
|
|
TICKER_ID_MAX,
|
|
};
|
|
|
|
#if defined(CONFIG_BT_BROADCASTER) && !defined(CONFIG_BT_CTLR_ADV_EXT) && \
|
|
!defined(CONFIG_BT_HCI_MESH_EXT)
|
|
#define TICKER_ID_ADV_LAST TICKER_ID_ADV_BASE
|
|
#endif
|
|
|
|
#define TICKER_ID_ULL_BASE ((TICKER_ID_LLL_PREEMPT) + 1)
|
|
|
|
enum ull_status {
|
|
ULL_STATUS_SUCCESS,
|
|
ULL_STATUS_FAILURE,
|
|
ULL_STATUS_BUSY,
|
|
};
|
|
|
|
struct evt_hdr {
|
|
uint32_t ticks_xtal_to_start;
|
|
uint32_t ticks_active_to_start;
|
|
uint32_t ticks_preempt_to_start;
|
|
uint32_t ticks_slot;
|
|
};
|
|
|
|
struct ull_hdr {
|
|
uint8_t volatile ref; /* Number of ongoing (between Prepare and Done)
|
|
* events
|
|
*/
|
|
void (*disabled_cb)(void *param);
|
|
void *disabled_param;
|
|
};
|
|
|
|
struct lll_hdr {
|
|
void *parent;
|
|
uint8_t is_stop:1;
|
|
};
|
|
|
|
struct lll_prepare_param {
|
|
uint32_t ticks_at_expire;
|
|
uint32_t remainder;
|
|
uint16_t lazy;
|
|
void *param;
|
|
};
|
|
|
|
typedef int (*lll_prepare_cb_t)(struct lll_prepare_param *prepare_param);
|
|
typedef int (*lll_is_abort_cb_t)(void *next, int prio, void *curr,
|
|
lll_prepare_cb_t *resume_cb, int *resume_prio);
|
|
typedef void (*lll_abort_cb_t)(struct lll_prepare_param *prepare_param,
|
|
void *param);
|
|
|
|
struct lll_event {
|
|
struct lll_prepare_param prepare_param;
|
|
lll_prepare_cb_t prepare_cb;
|
|
lll_is_abort_cb_t is_abort_cb;
|
|
lll_abort_cb_t abort_cb;
|
|
int prio;
|
|
uint8_t is_resume:1;
|
|
uint8_t is_aborted:1;
|
|
};
|
|
|
|
#define DEFINE_NODE_RX_USER_TYPE(i, _) NODE_RX_TYPE_##i,
|
|
|
|
enum node_rx_type {
|
|
/* Unused */
|
|
NODE_RX_TYPE_NONE = 0x00,
|
|
/* Signals release of node */
|
|
NODE_RX_TYPE_RELEASE,
|
|
/* Signals completion of RX event */
|
|
NODE_RX_TYPE_EVENT_DONE,
|
|
/* Signals arrival of RX Data Channel payload */
|
|
NODE_RX_TYPE_DC_PDU,
|
|
/* Advertisement report from scanning */
|
|
NODE_RX_TYPE_REPORT,
|
|
NODE_RX_TYPE_EXT_1M_REPORT,
|
|
NODE_RX_TYPE_EXT_2M_REPORT,
|
|
NODE_RX_TYPE_EXT_CODED_REPORT,
|
|
NODE_RX_TYPE_EXT_AUX_REPORT,
|
|
NODE_RX_TYPE_EXT_SCAN_TERMINATE,
|
|
NODE_RX_TYPE_SYNC,
|
|
NODE_RX_TYPE_SYNC_REPORT,
|
|
NODE_RX_TYPE_SYNC_LOST,
|
|
NODE_RX_TYPE_EXT_ADV_TERMINATE,
|
|
NODE_RX_TYPE_BIG_COMPLETE,
|
|
NODE_RX_TYPE_BIG_TERMINATE,
|
|
NODE_RX_TYPE_SCAN_REQ,
|
|
NODE_RX_TYPE_CONNECTION,
|
|
NODE_RX_TYPE_TERMINATE,
|
|
NODE_RX_TYPE_CONN_UPDATE,
|
|
NODE_RX_TYPE_ENC_REFRESH,
|
|
NODE_RX_TYPE_APTO,
|
|
NODE_RX_TYPE_CHAN_SEL_ALGO,
|
|
NODE_RX_TYPE_PHY_UPDATE,
|
|
NODE_RX_TYPE_RSSI,
|
|
NODE_RX_TYPE_PROFILE,
|
|
NODE_RX_TYPE_ADV_INDICATION,
|
|
NODE_RX_TYPE_SCAN_INDICATION,
|
|
NODE_RX_TYPE_CIS_REQUEST,
|
|
NODE_RX_TYPE_CIS_ESTABLISHED,
|
|
NODE_RX_TYPE_MESH_ADV_CPLT,
|
|
NODE_RX_TYPE_MESH_REPORT,
|
|
|
|
#if defined(CONFIG_BT_CTLR_USER_EXT)
|
|
/* No entries shall be added after the NODE_RX_TYPE_USER_START/END */
|
|
NODE_RX_TYPE_USER_START,
|
|
UTIL_LISTIFY(CONFIG_BT_CTLR_USER_EVT_RANGE, DEFINE_NODE_RX_USER_TYPE, _)
|
|
NODE_RX_TYPE_USER_END,
|
|
#endif /* CONFIG_BT_CTLR_USER_EXT */
|
|
};
|
|
|
|
/* Footer of node_rx_hdr */
|
|
struct node_rx_ftr {
|
|
union {
|
|
void *param;
|
|
struct {
|
|
uint8_t status;
|
|
uint8_t num_events;
|
|
uint16_t conn_handle;
|
|
} param_adv_term;
|
|
};
|
|
void *extra;
|
|
uint32_t ticks_anchor;
|
|
uint32_t radio_end_us;
|
|
uint8_t rssi;
|
|
#if defined(CONFIG_BT_CTLR_PRIVACY)
|
|
uint8_t lrpa_used:1;
|
|
uint8_t rl_idx;
|
|
#endif /* CONFIG_BT_CTLR_PRIVACY */
|
|
#if defined(CONFIG_BT_CTLR_EXT_SCAN_FP)
|
|
uint8_t direct;
|
|
#endif /* CONFIG_BT_CTLR_EXT_SCAN_FP */
|
|
#if defined(CONFIG_BT_HCI_MESH_EXT)
|
|
uint8_t chan_idx;
|
|
#endif /* CONFIG_BT_HCI_MESH_EXT */
|
|
};
|
|
|
|
|
|
/* Header of node_rx_pdu */
|
|
struct node_rx_hdr {
|
|
union {
|
|
void *next; /* For slist, by hci module */
|
|
memq_link_t *link; /* Supply memq_link from ULL to LLL */
|
|
uint8_t ack_last; /* Tx ack queue index at this node rx */
|
|
};
|
|
|
|
enum node_rx_type type;
|
|
uint8_t user_meta; /* User metadata */
|
|
uint16_t handle; /* State/Role instance handle */
|
|
|
|
union {
|
|
#if defined(CONFIG_BT_CTLR_RX_PDU_META)
|
|
lll_rx_pdu_meta_t rx_pdu_meta;
|
|
#endif /* CONFIG_BT_CTLR_RX_PDU_META */
|
|
struct node_rx_ftr rx_ftr;
|
|
};
|
|
};
|
|
|
|
/* Template node rx type with memory aligned offset to PDU buffer.
|
|
* NOTE: offset to memory aligned pdu buffer location is used to reference
|
|
* node rx type specific information, like, terminate or sync lost reason
|
|
* from a dedicated node rx structure storage location.
|
|
*/
|
|
struct node_rx_pdu {
|
|
struct node_rx_hdr hdr;
|
|
union {
|
|
uint8_t pdu[0] __aligned(4);
|
|
};
|
|
};
|
|
|
|
enum {
|
|
EVENT_DONE_EXTRA_TYPE_NONE,
|
|
|
|
#if defined(CONFIG_BT_CONN)
|
|
EVENT_DONE_EXTRA_TYPE_CONN,
|
|
#endif /* CONFIG_BT_CONN */
|
|
|
|
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
|
#if defined(CONFIG_BT_BROADCASTER)
|
|
EVENT_DONE_EXTRA_TYPE_ADV,
|
|
#endif /* CONFIG_BT_BROADCASTER */
|
|
#endif /* CONFIG_BT_CTLR_ADV_EXT */
|
|
|
|
#if defined(CONFIG_BT_OBSERVER)
|
|
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
|
EVENT_DONE_EXTRA_TYPE_SCAN,
|
|
EVENT_DONE_EXTRA_TYPE_SCAN_AUX,
|
|
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC)
|
|
EVENT_DONE_EXTRA_TYPE_SYNC,
|
|
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */
|
|
#endif /* CONFIG_BT_CTLR_ADV_EXT */
|
|
#endif /* CONFIG_BT_OBSERVER */
|
|
|
|
/* Following proprietary defines must be at end of enum range */
|
|
#if defined(CONFIG_BT_CTLR_USER_EXT)
|
|
EVENT_DONE_EXTRA_TYPE_USER_START,
|
|
EVENT_DONE_EXTRA_TYPE_USER_END = EVENT_DONE_EXTRA_TYPE_USER_START +
|
|
CONFIG_BT_CTLR_USER_EVT_RANGE,
|
|
#endif /* CONFIG_BT_CTLR_USER_EXT */
|
|
|
|
};
|
|
|
|
struct event_done_extra_drift {
|
|
uint32_t start_to_address_actual_us;
|
|
uint32_t window_widening_event_us;
|
|
uint32_t preamble_to_addr_us;
|
|
};
|
|
|
|
struct event_done_extra {
|
|
uint8_t type;
|
|
union {
|
|
struct {
|
|
uint16_t trx_cnt;
|
|
uint8_t crc_valid;
|
|
#if defined(CONFIG_BT_CTLR_LE_ENC)
|
|
uint8_t mic_state;
|
|
#endif /* CONFIG_BT_CTLR_LE_ENC */
|
|
#if defined(CONFIG_BT_PERIPHERAL) || defined(CONFIG_BT_CTLR_SYNC_PERIODIC)
|
|
union {
|
|
struct event_done_extra_drift drift;
|
|
};
|
|
#endif /* CONFIG_BT_PERIPHERAL || CONFIG_BT_CTLR_SYNC_PERIODIC */
|
|
};
|
|
};
|
|
};
|
|
|
|
struct node_rx_event_done {
|
|
struct node_rx_hdr hdr;
|
|
void *param;
|
|
struct event_done_extra extra;
|
|
};
|
|
|
|
static inline void lll_hdr_init(void *lll, void *parent)
|
|
{
|
|
struct lll_hdr *hdr = lll;
|
|
|
|
hdr->parent = parent;
|
|
hdr->is_stop = 0U;
|
|
}
|
|
|
|
static inline int lll_stop(void *lll)
|
|
{
|
|
struct lll_hdr *hdr = lll;
|
|
int ret = !!hdr->is_stop;
|
|
|
|
hdr->is_stop = 1U;
|
|
|
|
return ret;
|
|
}
|
|
|
|
int lll_init(void);
|
|
int lll_reset(void);
|
|
void lll_resume(void *param);
|
|
void lll_disable(void *param);
|
|
uint32_t lll_radio_is_idle(void);
|
|
uint32_t lll_radio_tx_ready_delay_get(uint8_t phy, uint8_t flags);
|
|
uint32_t lll_radio_rx_ready_delay_get(uint8_t phy, uint8_t flags);
|
|
int8_t lll_radio_tx_pwr_min_get(void);
|
|
int8_t lll_radio_tx_pwr_max_get(void);
|
|
int8_t lll_radio_tx_pwr_floor(int8_t tx_pwr_lvl);
|
|
|
|
int lll_csrand_get(void *buf, size_t len);
|
|
int lll_csrand_isr_get(void *buf, size_t len);
|
|
int lll_rand_get(void *buf, size_t len);
|
|
int lll_rand_isr_get(void *buf, size_t len);
|
|
|
|
int ull_prepare_enqueue(lll_is_abort_cb_t is_abort_cb,
|
|
lll_abort_cb_t abort_cb,
|
|
struct lll_prepare_param *prepare_param,
|
|
lll_prepare_cb_t prepare_cb, int prio,
|
|
uint8_t is_resume);
|
|
void *ull_prepare_dequeue_get(void);
|
|
void *ull_prepare_dequeue_iter(uint8_t *idx);
|
|
void *ull_pdu_rx_alloc_peek(uint8_t count);
|
|
void *ull_pdu_rx_alloc_peek_iter(uint8_t *idx);
|
|
void *ull_pdu_rx_alloc(void);
|
|
void ull_rx_put(memq_link_t *link, void *rx);
|
|
void ull_rx_sched(void);
|
|
void *ull_event_done_extra_get(void);
|
|
void *ull_event_done(void *param);
|