From 218da9121110ce6010c6f98ceebc37b112406206 Mon Sep 17 00:00:00 2001 From: Erik Brockhoff Date: Thu, 8 Sep 2022 13:38:08 +0200 Subject: [PATCH] Bluetooth: controller: Implementing CIS STO & establishment timeout Adding a bit-mask to the 'extra' data structure allowing passing info re. active CIS's to the ull_conn_iso_done handling. Per CIS storing an expiration time counter, monitoring in done handling. Adding establishment timeout monitor in CIS Create procedure, completing and ntf'ing accordingly. Signed-off-by: Erik Brockhoff --- subsys/bluetooth/controller/ll_sw/lll.h | 5 +- .../bluetooth/controller/ll_sw/lll_conn_iso.h | 2 + .../bluetooth/controller/ll_sw/ull_conn_iso.c | 59 ++++++++++++++++--- .../controller/ll_sw/ull_conn_iso_types.h | 2 + .../bluetooth/controller/ll_sw/ull_llcp_cc.c | 22 +++++-- 5 files changed, 77 insertions(+), 13 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/lll.h b/subsys/bluetooth/controller/ll_sw/lll.h index 423da586dd6..80fe85fffe1 100644 --- a/subsys/bluetooth/controller/ll_sw/lll.h +++ b/subsys/bluetooth/controller/ll_sw/lll.h @@ -496,7 +496,10 @@ struct event_done_extra { #endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */ union { struct { - uint16_t trx_cnt; + union { + uint32_t trx_performed_mask; + uint16_t trx_cnt; + }; uint8_t crc_valid:1; #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING) && \ defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT) diff --git a/subsys/bluetooth/controller/ll_sw/lll_conn_iso.h b/subsys/bluetooth/controller/ll_sw/lll_conn_iso.h index 48977c2dfca..81db6b70b2a 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_conn_iso.h +++ b/subsys/bluetooth/controller/ll_sw/lll_conn_iso.h @@ -74,4 +74,6 @@ struct lll_conn_iso_group { int lll_conn_iso_init(void); int lll_conn_iso_reset(void); +void lll_conn_iso_done(struct lll_conn_iso_group *cig, uint32_t trx_performed, + uint16_t prog_to_anchor_us, uint8_t mic_state); void lll_conn_iso_flush(uint16_t handle, struct lll_conn_iso_stream *lll); diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c index dda024011c3..5bdbd395922 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c @@ -286,8 +286,11 @@ void ull_conn_iso_done(struct node_rx_event_done *done) { struct lll_conn_iso_group *lll; struct ll_conn_iso_group *cig; + struct ll_conn_iso_stream *cis; uint32_t ticks_drift_minus; uint32_t ticks_drift_plus; + uint16_t handle_iter; + uint8_t cis_idx; /* Get reference to ULL context */ cig = CONTAINER_OF(done->param, struct ll_conn_iso_group, ull); @@ -300,19 +303,58 @@ void ull_conn_iso_done(struct node_rx_event_done *done) ticks_drift_plus = 0; ticks_drift_minus = 0; + handle_iter = UINT16_MAX; + cis = NULL; - if (done->extra.trx_cnt) { - if (IS_ENABLED(CONFIG_BT_CTLR_PERIPHERAL_ISO) && lll->role) { - ull_drift_ticks_get(done, &ticks_drift_plus, - &ticks_drift_minus); + /* Check all CISes for supervison/establishment timeout */ + for (cis_idx = 0; cis_idx < cig->lll.num_cis; cis_idx++) { + cis = ll_conn_iso_stream_get_by_group(cig, &handle_iter); + LL_ASSERT(cis); + + if (cis->lll.handle != LLL_HANDLE_INVALID) { + /* CIS was setup and is now expected to be going */ + if (!(done->extra.trx_performed_mask & + (1U << LL_CIS_IDX_FROM_HANDLE(cis->lll.handle)))) { + /* We did NOT have successful transaction on established CIS, + * or CIS was not yet established, so handle timeout + */ + if (!cis->event_expire) { + struct ll_conn *conn = ll_conn_get(cis->lll.acl_handle); + + cis->event_expire = + RADIO_CONN_EVENTS( + conn->supervision_timeout * 10U * 1000U, + cig->iso_interval * CONN_INT_UNIT_US) + 1; + } + + if (--cis->event_expire == 0) { + /* Stop CIS and defer cleanup to after teardown. */ + ull_conn_iso_cis_stop(cis, NULL, + cis->established ? + BT_HCI_ERR_CONN_TIMEOUT : + BT_HCI_ERR_CONN_FAIL_TO_ESTAB); + + } + } else { + cis->event_expire = 0; + } } } - /* Update CIG ticker to compensate for drift */ - if (ticks_drift_plus || ticks_drift_minus) { + if (done->extra.trx_performed_mask && + IS_ENABLED(CONFIG_BT_CTLR_PERIPHERAL_ISO) && lll->role) { + ull_drift_ticks_get(done, &ticks_drift_plus, + &ticks_drift_minus); + } + + /* Update CIG ticker to compensate for drift. + * Since all CISes in a CIG 'belong to' the same ACL, + * any CIS found in the above for-loop will do to dereference the ACL + */ + if (cis && (ticks_drift_plus || ticks_drift_minus)) { uint8_t ticker_id = TICKER_ID_CONN_ISO_BASE + ll_conn_iso_group_handle_get(cig); - struct ll_conn *conn = lll->hdr.parent; + struct ll_conn *conn = ll_connected_get(cis->lll.acl_handle); uint32_t ticker_status; ticker_status = ticker_update(TICKER_INSTANCE_ID_CTLR, @@ -645,6 +687,9 @@ void ull_conn_iso_start(struct ll_conn *acl, uint32_t ticks_at_expire, uint16_t cis->lll.handle = cis_handle; cis->lll.active = 1U; + /* Connection establishment timeout */ + cis->event_expire = CONN_ESTAB_COUNTDOWN; + /* Check if another CIS was already started and CIG ticker is * running. If so, we just return with updated offset and * validated handle. diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_iso_types.h b/subsys/bluetooth/controller/ll_sw/ull_conn_iso_types.h index 53308eb54d1..7efe57b54d1 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_iso_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_iso_types.h @@ -24,6 +24,7 @@ struct ll_conn_iso_stream { * notified. */ uint16_t teardown:1; /* 1 if CIS teardown has been initiated */ + uint16_t trx_performed:1; /* 1 if CIS had a transaction */ uint16_t p_max_sdu:12; /* Maximum SDU size P_To_C */ uint16_t c_max_sdu:12; /* Maximum SDU size C_To_P */ union { @@ -33,6 +34,7 @@ struct ll_conn_iso_stream { uint16_t instant; } central; }; + uint16_t event_expire; /* Supervision & Connect Timeout event counter */ }; struct ll_conn_iso_group { diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c index abd9f0e9211..c580f7594ac 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c @@ -49,12 +49,21 @@ #include #include "hal/debug.h" -static bool cc_check_cis_established_lll(struct proc_ctx *ctx) +static bool cc_check_cis_established_or_timeout_lll(struct proc_ctx *ctx) { const struct ll_conn_iso_stream *cis = ll_conn_iso_stream_get(ctx->data.cis_create.cis_handle); - return cis->established; + if (cis->established) { + return true; + } + + if (!cis->event_expire) { + ctx->data.cis_create.error = BT_HCI_ERR_CONN_FAIL_TO_ESTAB; + return true; + } + + return false; } static void cc_ntf_established(struct ll_conn *conn, struct proc_ctx *ctx) @@ -508,8 +517,11 @@ static void rp_cc_state_wait_cis_established(struct ll_conn *conn, struct proc_c switch (evt) { case RP_CC_EVT_RUN: /* Check for CIS state */ - if (cc_check_cis_established_lll(ctx)) { - /* CIS was established, so let's got ahead and complete procedure */ + if (cc_check_cis_established_or_timeout_lll(ctx)) { + /* CIS was established or establishement timed out, + * In either case complete procedure and generate + * notification + */ rp_cc_complete(conn, ctx, evt, param); } break; @@ -858,7 +870,7 @@ static void lp_cc_st_wait_established(struct ll_conn *conn, struct proc_ctx *ctx { switch (evt) { case LP_CC_EVT_RUN: - if (cc_check_cis_established_lll(ctx)) { + if (cc_check_cis_established_or_timeout_lll(ctx)) { /* CIS was established, so let's got ahead and complete procedure */ lp_cc_complete(conn, ctx, evt, param); }