Skip to content

Commit

Permalink
Bluetooth: Controller: Fix CIS failed to be established
Browse files Browse the repository at this point in the history
Fix CIS create implementation to consider CIG events with
laziness before the new CIS in an already active CIG is
made active.

Previous laziness value of the CIG events is determined and
at the CIG event where the new CIS event_count is calculated
the lazy_active value determined is decremented from the
total lazy value.

Without this fix, event_count of the new active CIS events
where incorrect, causing CIS create resulting in fail to be
established.

Signed-off-by: Vinayak Kariappa Chettimada <[email protected]>
  • Loading branch information
cvinayak authored and carlescufi committed Jun 29, 2023
1 parent 6da521c commit 019f88e
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 9 deletions.
9 changes: 9 additions & 0 deletions subsys/bluetooth/controller/ll_sw/lll_conn_iso.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ struct lll_conn_iso_stream {
uint8_t active:1; /* 1 if CIS LLL is active */
uint8_t datapath_ready_rx:1;/* 1 if datapath for RX is ready */

#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
/* Lazy at CIS active. Number of previously skipped CIG events that is
* determined when CIS is made active and subtracted from total CIG
* events that where skipped when this CIS gets to use radio for the
* first time.
*/
uint16_t lazy_active;
#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */

/* Resumption information */
uint8_t next_subevent; /* Next subevent to schedule */

Expand Down
135 changes: 126 additions & 9 deletions subsys/bluetooth/controller/ll_sw/ull_conn_iso.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@


static int init_reset(void);
#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
static void cis_lazy_fill(struct ll_conn_iso_stream *cis);
static void mfy_cis_lazy_fill(void *param);
static void ticker_next_slot_get_op_cb(uint32_t status, void *param);
#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */
static void ticker_start_op_cb(uint32_t status, void *param);
static void ticker_update_cig_op_cb(uint32_t status, void *param);
static void ticker_resume_op_cb(uint32_t status, void *param);
static void ticker_resume_cb(uint32_t ticks_at_expire, uint32_t ticks_drift,
Expand Down Expand Up @@ -686,6 +692,11 @@ void ull_conn_iso_ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift,
if (cis->lll.handle != 0xFFFF && cis->lll.active) {
cis->lll.event_count += (lazy + 1U);

#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
cis->lll.event_count -= cis->lll.lazy_active;
cis->lll.lazy_active = 0U;
#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */

leading_event_count = MAX(leading_event_count,
cis->lll.event_count);

Expand Down Expand Up @@ -760,13 +771,6 @@ void ull_conn_iso_ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift,
ull_conn_iso_transmit_test_cig_interval(cig->lll.handle, ticks_at_expire);
}

static void ticker_op_cb(uint32_t status, void *param)
{
ARG_UNUSED(param);

LL_ASSERT(status == TICKER_STATUS_SUCCESS);
}

void ull_conn_iso_start(struct ll_conn *conn, uint16_t cis_handle,
uint32_t ticks_at_expire, uint32_t remainder,
uint16_t instant_latency)
Expand All @@ -790,7 +794,6 @@ void ull_conn_iso_start(struct ll_conn *conn, uint16_t cis_handle,

cis->lll.offset = cis_offs_to_cig_ref;
cis->lll.handle = cis_handle;
cis->lll.active = 1U;

#if defined(CONFIG_BT_CTLR_LE_ENC)
if (conn->lll.enc_tx) {
Expand Down Expand Up @@ -844,6 +847,13 @@ void ull_conn_iso_start(struct ll_conn *conn, uint16_t cis_handle,
* validated handle.
*/
if (cig->state == CIG_STATE_ACTIVE) {
#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
cis_lazy_fill(cis);
#else /* CONFIG_BT_CTLR_JIT_SCHEDULING */
/* Set CIS active in already active CIG */
cis->lll.active = 1U;
#endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */

/* We're done */
return;
}
Expand Down Expand Up @@ -994,11 +1004,118 @@ void ull_conn_iso_start(struct ll_conn *conn, uint16_t cis_handle,
ticks_periodic, ticks_remainder,
TICKER_NULL_LAZY, ticks_slot,
ull_conn_iso_ticker_cb, cig,
ticker_op_cb, NULL);
ticker_start_op_cb, NULL);
LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
(ticker_status == TICKER_STATUS_BUSY));

/* Set CIG and the first CIS state as active */
cig->state = CIG_STATE_ACTIVE;
cis->lll.active = 1U;

#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
/* CIS event lazy at CIS create */
cis->lll.lazy_active = 0U;
#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */
}

#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
static void cis_lazy_fill(struct ll_conn_iso_stream *cis)
{
static memq_link_t link;
static struct mayfly mfy = {0U, 0U, &link, NULL, mfy_cis_lazy_fill};
uint32_t ret;

mfy.param = cis;
ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_ULL_LOW, 1U, &mfy);
LL_ASSERT(!ret);
}

static void mfy_cis_lazy_fill(void *param)
{
struct ll_conn_iso_stream *cis;
struct ll_conn_iso_group *cig;
uint32_t ticks_to_expire;
uint32_t ticks_current;
uint32_t remainder;
uint8_t ticker_id;
uint16_t lazy;
uint8_t retry;
uint8_t id;

cis = param;
cig = cis->group;
ticker_id = TICKER_ID_CONN_ISO_BASE + ll_conn_iso_group_handle_get(cig);

id = TICKER_NULL;
ticks_to_expire = 0U;
ticks_current = 0U;

/* In the first iteration the actual ticks_current value is returned
* which will be different from the initial value of 0 that is set.
* Subsequent iterations should return the same ticks_current as the
* reference tick.
* In order to avoid infinite updates to ticker's reference due to any
* race condition due to expiring tickers, we try upto 3 more times.
* Hence, first iteration to get an actual ticks_current and 3 more as
* retries when there could be race conditions that changes the value
* of ticks_current.
*
* ticker_next_slot_get_ext() restarts iterating when updated value of
* ticks_current is returned.
*/
retry = 4U;
do {
uint32_t volatile ret_cb;
uint32_t ticks_previous;
uint32_t ret;
bool success;

ticks_previous = ticks_current;

ret_cb = TICKER_STATUS_BUSY;
ret = ticker_next_slot_get_ext(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_LOW, &id,
&ticks_current, &ticks_to_expire, &remainder, &lazy,
NULL, NULL, ticker_next_slot_get_op_cb,
(void *)&ret_cb);
if (ret == TICKER_STATUS_BUSY) {
/* Busy wait until Ticker Job is enabled after any Radio
* event is done using the Radio hardware. Ticker Job
* ISR is disabled during Radio events in LOW_LAT
* feature to avoid Radio ISR latencies.
*/
while (ret_cb == TICKER_STATUS_BUSY) {
ticker_job_sched(TICKER_INSTANCE_ID_CTLR,
TICKER_USER_ID_ULL_LOW);
}
}

success = (ret_cb == TICKER_STATUS_SUCCESS);
LL_ASSERT(success);

LL_ASSERT((ticks_current == ticks_previous) || retry--);

LL_ASSERT(id != TICKER_NULL);
} while (id != ticker_id);

/* Set CIS active in already active CIG and any previous laziness in
* CIG before the CIS gets active that be decremented when event_count
* is incremented in ull_conn_iso_ticker_cb().
*/
cis->lll.active = 1U;
cis->lll.lazy_active = lazy;
}

static void ticker_next_slot_get_op_cb(uint32_t status, void *param)
{
*((uint32_t volatile *)param) = status;
}
#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */

static void ticker_start_op_cb(uint32_t status, void *param)
{
ARG_UNUSED(param);

LL_ASSERT(status == TICKER_STATUS_SUCCESS);
}

static void ticker_update_cig_op_cb(uint32_t status, void *param)
Expand Down

0 comments on commit 019f88e

Please sign in to comment.