Bluetooth: Controller: Fix instant based procedure complete event

Fix instant based procedure complete event generation to be
held until after the on-air instant has elapsed.

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2022-04-12 10:57:08 +05:30 committed by Marti Bolivar
commit 4c674aa1f2
7 changed files with 150 additions and 9 deletions

View file

@ -563,6 +563,7 @@ config BT_CTLR_LLID_DATA_START_EMPTY
config BT_CTLR_RX_ENQUEUE_HOLD config BT_CTLR_RX_ENQUEUE_HOLD
bool "Procedure Complete after on-air instant" bool "Procedure Complete after on-air instant"
depends on BT_LL_SW_LLCP_LEGACY
default y if BT_HCI_RAW default y if BT_HCI_RAW
help help
Hold enqueue of Procedure Complete events with instant until after the Hold enqueue of Procedure Complete events with instant until after the

View file

@ -140,6 +140,14 @@ struct lll_conn {
#endif /* CONFIG_BT_CTLR_CONN_RSSI_EVENT */ #endif /* CONFIG_BT_CTLR_CONN_RSSI_EVENT */
#endif /* CONFIG_BT_CTLR_CONN_RSSI */ #endif /* CONFIG_BT_CTLR_CONN_RSSI */
#if defined(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)
#define RX_HOLD_MASK 3U
#define RX_HOLD_REQ 1U
#define RX_HOLD_ACK 2U
uint8_t rx_hold_req;
uint8_t rx_hold_ack;
#endif /* CONFIG_BT_CTLR_RX_ENQUEUE_HOLD */
#if defined(CONFIG_BT_CTLR_CONN_META) #if defined(CONFIG_BT_CTLR_CONN_META)
struct lll_conn_meta conn_meta; struct lll_conn_meta conn_meta;
#endif /* CONFIG_BT_CTLR_CONN_META */ #endif /* CONFIG_BT_CTLR_CONN_META */

View file

@ -395,6 +395,13 @@ lll_conn_isr_rx_exit:
is_ull_rx = 0U; is_ull_rx = 0U;
#if defined(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)
if (((lll->rx_hold_req - lll->rx_hold_ack) & RX_HOLD_MASK) ==
RX_HOLD_REQ) {
lll->rx_hold_ack--;
}
#endif /* CONFIG_BT_CTLR_RX_ENQUEUE_HOLD */
if (tx_release) { if (tx_release) {
LL_ASSERT(lll->handle != 0xFFFF); LL_ASSERT(lll->handle != 0xFFFF);

View file

@ -1092,6 +1092,12 @@ uint8_t ll_adv_enable(uint8_t enable)
*/ */
conn->llcp_terminate.node_rx.hdr.link = link; conn->llcp_terminate.node_rx.hdr.link = link;
#if defined(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)
conn->llcp_rx_hold = NULL;
conn_lll->rx_hold_req = 0U;
conn_lll->rx_hold_ack = 0U;
#endif /* CONFIG_BT_CTLR_RX_ENQUEUE_HOLD */
#if defined(CONFIG_BT_CTLR_LE_ENC) #if defined(CONFIG_BT_CTLR_LE_ENC)
conn_lll->enc_rx = conn_lll->enc_tx = 0U; conn_lll->enc_rx = conn_lll->enc_tx = 0U;
conn->llcp_enc.req = conn->llcp_enc.ack = 0U; conn->llcp_enc.req = conn->llcp_enc.ack = 0U;

View file

@ -325,6 +325,12 @@ uint8_t ll_create_connection(uint16_t scan_interval, uint16_t scan_window,
*/ */
conn->llcp_terminate.node_rx.hdr.link = link; conn->llcp_terminate.node_rx.hdr.link = link;
#if defined(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)
conn->llcp_rx_hold = NULL;
conn_lll->rx_hold_req = 0U;
conn_lll->rx_hold_ack = 0U;
#endif /* CONFIG_BT_CTLR_RX_ENQUEUE_HOLD */
#if defined(CONFIG_BT_CTLR_LE_ENC) #if defined(CONFIG_BT_CTLR_LE_ENC)
conn_lll->enc_rx = conn_lll->enc_tx = 0U; conn_lll->enc_rx = conn_lll->enc_tx = 0U;
conn->llcp_enc.req = conn->llcp_enc.ack = 0U; conn->llcp_enc.req = conn->llcp_enc.ack = 0U;

View file

@ -73,6 +73,10 @@
#include "hal/debug.h" #include "hal/debug.h"
static int init_reset(void); static int init_reset(void);
#if defined(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)
static bool rx_hold_is_done(struct ll_conn *conn);
static void rx_hold_flush(struct ll_conn *conn);
#endif /* CONFIG_BT_CTLR_RX_ENQUEUE_HOLD */
#if !defined(CONFIG_BT_CTLR_LOW_LAT_ULL) #if !defined(CONFIG_BT_CTLR_LOW_LAT_ULL)
static void tx_demux_sched(struct ll_conn *conn); static void tx_demux_sched(struct ll_conn *conn);
#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL */ #endif /* CONFIG_BT_CTLR_LOW_LAT_ULL */
@ -1010,6 +1014,12 @@ int ull_conn_rx(memq_link_t *link, struct node_rx_pdu **rx)
return 0; return 0;
} }
#if defined(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)
if (conn->llcp_rx_hold && rx_hold_is_done(conn)) {
rx_hold_flush(conn);
}
#endif /* CONFIG_BT_CTLR_RX_ENQUEUE_HOLD */
pdu_rx = (void *)(*rx)->pdu; pdu_rx = (void *)(*rx)->pdu;
switch (pdu_rx->ll_id) { switch (pdu_rx->ll_id) {
@ -1379,6 +1389,16 @@ void ull_conn_done(struct node_rx_event_done *done)
return; return;
} }
#if defined(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)
if (conn->llcp_rx_hold && rx_hold_is_done(conn)) {
rx_hold_flush(conn);
#if !defined(CONFIG_BT_CTLR_LOW_LAT_ULL)
ll_rx_sched();
#endif /* !CONFIG_BT_CTLR_LOW_LAT_ULL */
}
#endif /* CONFIG_BT_CTLR_RX_ENQUEUE_HOLD */
#if defined(CONFIG_BT_CTLR_LE_ENC) #if defined(CONFIG_BT_CTLR_LE_ENC)
/* Check authenticated payload expiry or MIC failure */ /* Check authenticated payload expiry or MIC failure */
switch (done->extra.mic_state) { switch (done->extra.mic_state) {
@ -1936,6 +1956,12 @@ void ull_conn_tx_ack(uint16_t handle, memq_link_t *link, struct node_tx *tx)
if (handle != LLL_HANDLE_INVALID) { if (handle != LLL_HANDLE_INVALID) {
struct ll_conn *conn = ll_conn_get(handle); struct ll_conn *conn = ll_conn_get(handle);
#if defined(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)
if (conn->llcp_rx_hold && rx_hold_is_done(conn)) {
rx_hold_flush(conn);
}
#endif /* CONFIG_BT_CTLR_RX_ENQUEUE_HOLD */
#if defined(CONFIG_BT_LL_SW_LLCP_LEGACY) #if defined(CONFIG_BT_LL_SW_LLCP_LEGACY)
ctrl_tx_ack(conn, &tx, pdu_tx); ctrl_tx_ack(conn, &tx, pdu_tx);
#else /* CONFIG_BT_LL_SW_LLCP_LEGACY */ #else /* CONFIG_BT_LL_SW_LLCP_LEGACY */
@ -1964,6 +1990,14 @@ void ull_conn_tx_ack(uint16_t handle, memq_link_t *link, struct node_tx *tx)
pdu_tx->ll_id = PDU_DATA_LLID_RESV; pdu_tx->ll_id = PDU_DATA_LLID_RESV;
} else { } else {
LL_ASSERT(handle != LLL_HANDLE_INVALID); LL_ASSERT(handle != LLL_HANDLE_INVALID);
#if defined(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)
struct ll_conn *conn = ll_conn_get(handle);
if (conn->llcp_rx_hold && rx_hold_is_done(conn)) {
rx_hold_flush(conn);
}
#endif /* CONFIG_BT_CTLR_RX_ENQUEUE_HOLD */
} }
ll_tx_ack_put(handle, tx); ll_tx_ack_put(handle, tx);
@ -2154,6 +2188,72 @@ static int init_reset(void)
return 0; return 0;
} }
#if defined(CONFIG_BT_LL_SW_LLCP_LEGACY)
static void rx_hold_put(struct ll_conn *conn, memq_link_t *link,
struct node_rx_pdu *rx)
{
#if defined(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)
struct node_rx_pdu *rx_last;
struct lll_conn *lll;
link->mem = NULL;
rx->hdr.link = link;
rx_last = conn->llcp_rx_hold;
while (rx_last && rx_last->hdr.link && rx_last->hdr.link->mem) {
rx_last = rx_last->hdr.link->mem;
}
if (rx_last) {
rx_last->hdr.link->mem = rx;
} else {
conn->llcp_rx_hold = rx;
}
lll = &conn->lll;
if (lll->rx_hold_req == lll->rx_hold_ack) {
lll->rx_hold_req++;
}
#else /* !CONFIG_BT_CTLR_RX_ENQUEUE_HOLD */
ARG_UNUSED(conn);
ll_rx_put(link, rx);
#endif /* !CONFIG_BT_CTLR_RX_ENQUEUE_HOLD */
}
#if defined(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)
static bool rx_hold_is_done(struct ll_conn *conn)
{
return ((conn->lll.rx_hold_req -
conn->lll.rx_hold_ack) & RX_HOLD_MASK) == RX_HOLD_ACK;
}
static void rx_hold_flush(struct ll_conn *conn)
{
struct node_rx_pdu *rx;
struct lll_conn *lll;
rx = conn->llcp_rx_hold;
do {
struct node_rx_hdr *hdr;
/* traverse to next rx node */
hdr = &rx->hdr;
rx = hdr->link->mem;
/* enqueue rx node towards Thread */
ll_rx_put(hdr->link, hdr);
} while (rx);
conn->llcp_rx_hold = NULL;
lll = &conn->lll;
lll->rx_hold_req = 0U;
lll->rx_hold_ack = 0U;
}
#endif /* CONFIG_BT_CTLR_RX_ENQUEUE_HOLD */
#endif /* CONFIG_BT_LL_SW_LLCP_LEGACY */
#if !defined(CONFIG_BT_CTLR_LOW_LAT_ULL) #if !defined(CONFIG_BT_CTLR_LOW_LAT_ULL)
static void tx_demux_sched(struct ll_conn *conn) static void tx_demux_sched(struct ll_conn *conn)
{ {
@ -3121,14 +3221,21 @@ static inline int event_conn_upd_prep(struct ll_conn *conn, uint16_t lazy,
cu->interval = conn->llcp_cu.interval; cu->interval = conn->llcp_cu.interval;
cu->latency = conn->llcp_cu.latency; cu->latency = conn->llcp_cu.latency;
cu->timeout = conn->llcp_cu.timeout; cu->timeout = conn->llcp_cu.timeout;
/* hold node rx until the instant's anchor point sync */
rx_hold_put(conn, rx->hdr.link, rx);
if (!IS_ENABLED(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)) {
ll_rx_sched();
}
} else { } else {
/* Mark for buffer for release */ /* Mark for buffer for release */
rx->hdr.type = NODE_RX_TYPE_RELEASE; rx->hdr.type = NODE_RX_TYPE_RELEASE;
}
/* enqueue rx node towards Thread */ /* enqueue rx node towards Thread */
ll_rx_put(rx->hdr.link, rx); ll_rx_put(rx->hdr.link, rx);
ll_rx_sched(); ll_rx_sched();
}
#if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
/* restore to normal prepare */ /* restore to normal prepare */
@ -4672,8 +4779,8 @@ static inline void event_phy_upd_ind_prep(struct ll_conn *conn,
upd->tx = lll->phy_tx; upd->tx = lll->phy_tx;
upd->rx = lll->phy_rx; upd->rx = lll->phy_rx;
/* enqueue rx node towards Thread */ /* hold node rx until the instant's anchor point sync */
ll_rx_put(rx->hdr.link, rx); rx_hold_put(conn, rx->hdr.link, rx);
#if defined(CONFIG_BT_CTLR_DATA_LENGTH) #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
/* get a rx node for ULL->LL */ /* get a rx node for ULL->LL */
@ -4716,11 +4823,13 @@ static inline void event_phy_upd_ind_prep(struct ll_conn *conn,
lr->max_rx_time = sys_cpu_to_le16(lll->max_rx_time); lr->max_rx_time = sys_cpu_to_le16(lll->max_rx_time);
lr->max_tx_time = sys_cpu_to_le16(lll->max_tx_time); lr->max_tx_time = sys_cpu_to_le16(lll->max_tx_time);
/* enqueue rx node towards Thread */ /* hold node rx until the instant's anchor point sync */
ll_rx_put(rx->hdr.link, rx); rx_hold_put(conn, rx->hdr.link, rx);
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
ll_rx_sched(); if (!IS_ENABLED(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)) {
ll_rx_sched();
}
} }
} }
#endif /* CONFIG_BT_CTLR_PHY */ #endif /* CONFIG_BT_CTLR_PHY */

View file

@ -153,6 +153,10 @@ struct ll_conn {
struct node_rx_pdu *llcp_rx; struct node_rx_pdu *llcp_rx;
#if defined(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)
struct node_rx_pdu *llcp_rx_hold;
#endif /* CONFIG_BT_CTLR_RX_ENQUEUE_HOLD */
struct { struct {
uint8_t req; uint8_t req;
uint8_t ack; uint8_t ack;