From fab4511164724eaf846763a38693fcc9ad9e0608 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Fri, 13 May 2022 16:44:49 +0530 Subject: [PATCH] Bluetooth: Controller: Fix overlapping advertising events When multiple advertising sets are support then use advanced scheduling implementation to place multiple auxiliary PDUs and periodic advertising PDUs in a non-overlapping schedule. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/CMakeLists.txt | 3 +- .../bluetooth/controller/Kconfig.ll_sw_split | 7 +- .../controller/ll_sw/nordic/lll/lll_adv_pdu.h | 3 +- subsys/bluetooth/controller/ll_sw/ull_adv.c | 3 +- .../bluetooth/controller/ll_sw/ull_adv_aux.c | 85 ++++- .../controller/ll_sw/ull_adv_internal.h | 10 +- .../bluetooth/controller/ll_sw/ull_adv_iso.c | 4 +- .../bluetooth/controller/ll_sw/ull_adv_sync.c | 14 +- subsys/bluetooth/controller/ll_sw/ull_sched.c | 314 ++++++++++++------ .../controller/ll_sw/ull_sched_internal.h | 5 +- 10 files changed, 326 insertions(+), 122 deletions(-) diff --git a/subsys/bluetooth/controller/CMakeLists.txt b/subsys/bluetooth/controller/CMakeLists.txt index 82a15ef9d9a..a5ecdf07d34 100644 --- a/subsys/bluetooth/controller/CMakeLists.txt +++ b/subsys/bluetooth/controller/CMakeLists.txt @@ -114,8 +114,7 @@ if(CONFIG_BT_LL_SW_SPLIT) ) endif() endif() - if(CONFIG_BT_CTLR_SCHED_ADVANCED AND - (CONFIG_BT_CONN OR CONFIG_BT_CTLR_ADV_ISO)) + if(CONFIG_BT_CTLR_SCHED_ADVANCED) zephyr_library_sources( ll_sw/ull_sched.c ) diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index 62a447db70d..b5ec064f8f1 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -341,8 +341,11 @@ config BT_CTLR_XTAL_THRESHOLD config BT_CTLR_SCHED_ADVANCED bool "Advanced scheduling" - depends on (BT_MAX_CONN != 0) && BT_CTLR_SCHED_ADVANCED_SUPPORT - default y if !(BT_PERIPHERAL && !BT_CENTRAL) + depends on BT_CTLR_SCHED_ADVANCED_SUPPORT && \ + (BT_CONN || \ + (BT_CTLR_ADV_EXT && (BT_CTLR_ADV_AUX_SET > 1)) || \ + BT_CTLR_ADV_ISO) + default y if BT_CENTRAL || (BT_BROADCASTER && BT_CTLR_ADV_EXT) || BT_CTLR_ADV_ISO help Enable non-overlapping placement of observer, initiator and central roles in timespace. Uses window offset in connection updates and uses diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_pdu.h b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_pdu.h index ef8224a53d4..8baccb50f8d 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_pdu.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_pdu.h @@ -101,7 +101,8 @@ static inline void lll_adv_aux_data_enqueue(struct lll_adv_aux *lll, lll_adv_pdu_enqueue(&lll->data, idx); } -static inline struct pdu_adv *lll_adv_aux_data_peek(struct lll_adv_aux *lll) +static inline struct pdu_adv * + lll_adv_aux_data_peek(const struct lll_adv_aux *const lll) { return (void *)lll->data.pdu[lll->data.last]; } diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv.c b/subsys/bluetooth/controller/ll_sw/ull_adv.c index a297fb102c9..94491f04a6b 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv.c @@ -1407,7 +1407,8 @@ uint8_t ll_adv_enable(uint8_t enable) EVENT_OVERHEAD_START_US + (EVENT_TICKER_RES_MARGIN_US << 1)); - ticks_slot_overhead_aux = ull_adv_aux_evt_init(aux); + ticks_slot_overhead_aux = + ull_adv_aux_evt_init(aux, &ticks_anchor_aux); #if defined(CONFIG_BT_CTLR_ADV_PERIODIC) /* Start periodic advertising if enabled and not already diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c b/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c index 4b3f0268edf..273a7391b6b 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c @@ -39,6 +39,7 @@ #include "ull_internal.h" #include "ull_chan_internal.h" #include "ull_adv_internal.h" +#include "ull_sched_internal.h" #include "ll.h" @@ -168,7 +169,8 @@ uint8_t ll_adv_aux_ad_data_set(uint8_t handle, uint8_t op, uint8_t frag_pref, */ ticks_anchor = ticker_ticks_now_get(); - ticks_slot_overhead = ull_adv_aux_evt_init(aux); + ticks_slot_overhead = + ull_adv_aux_evt_init(aux, &ticks_anchor); ret = ull_adv_aux_start(aux, ticks_anchor, ticks_slot_overhead); @@ -1039,7 +1041,8 @@ uint8_t ull_adv_aux_lll_handle_get(struct lll_adv_aux *lll) return ull_adv_aux_handle_get((void *)lll->hdr.parent); } -uint32_t ull_adv_aux_evt_init(struct ll_adv_aux_set *aux) +uint32_t ull_adv_aux_evt_init(struct ll_adv_aux_set *aux, + uint32_t *ticks_anchor) { uint32_t ticks_slot_overhead; struct lll_adv_aux *lll_aux; @@ -1071,6 +1074,26 @@ uint32_t ull_adv_aux_evt_init(struct ll_adv_aux_set *aux) ticks_slot_overhead = 0; } +#if defined(CONFIG_BT_CTLR_SCHED_ADVANCED) + uint32_t ticks_anchor_aux; + uint32_t ticks_slot; + int err; + + time_us = ull_adv_aux_time_get(aux, PDU_AC_PAYLOAD_SIZE_MAX, + PDU_AC_PAYLOAD_SIZE_MAX); + ticks_slot = HAL_TICKER_US_TO_TICKS(time_us); + + err = ull_sched_adv_aux_sync_free_slot_get(TICKER_USER_ID_THREAD, + (ticks_slot + + ticks_slot_overhead), + &ticks_anchor_aux); + if (!err) { + *ticks_anchor = ticks_anchor_aux; + *ticks_anchor += HAL_TICKER_US_TO_TICKS( + EVENT_TICKER_RES_MARGIN_US); + } +#endif /* CONFIG_BT_CTLR_SCHED_ADVANCED */ + return ticks_slot_overhead; } @@ -1082,15 +1105,14 @@ uint32_t ull_adv_aux_start(struct ll_adv_aux_set *aux, uint32_t ticks_anchor, uint8_t aux_handle; uint32_t ret; - interval_us = aux->interval * PERIODIC_INT_UNIT_US; - ull_hdr_init(&aux->ull); aux_handle = ull_adv_aux_handle_get(aux); + interval_us = aux->interval * PERIODIC_INT_UNIT_US; ret_cb = TICKER_STATUS_BUSY; ret = ticker_start(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD, (TICKER_ID_ADV_AUX_BASE + aux_handle), - ticks_anchor, 0, + ticks_anchor, 0U, HAL_TICKER_US_TO_TICKS(interval_us), TICKER_NULL_REMAINDER, TICKER_NULL_LAZY, (aux->ull.ticks_slot + ticks_slot_overhead), @@ -1168,6 +1190,59 @@ void ull_adv_aux_release(struct ll_adv_aux_set *aux) aux_release(aux); } +struct ll_adv_aux_set *ull_adv_aux_get(uint8_t handle) +{ + if (handle >= CONFIG_BT_CTLR_ADV_AUX_SET) { + return NULL; + } + + return &ll_adv_aux_pool[handle]; +} + +uint32_t ull_adv_aux_time_get(const struct ll_adv_aux_set *aux, uint8_t pdu_len, + uint8_t pdu_scan_len) +{ + const struct lll_adv_aux *lll_aux; + const struct lll_adv *lll; + const struct pdu_adv *pdu; + uint32_t time_us; + + lll_aux = &aux->lll; + lll = lll_aux->adv; + + /* NOTE: 16-bit values are sufficient for minimum radio event time + * reservation, 32-bit are used here so that reservations for + * whole back-to-back chaining of PDUs can be accomodated where + * the required microseconds could overflow 16-bits, example, + * back-to-back chained Coded PHY PDUs. + */ + time_us = PDU_AC_US(pdu_len, lll->phy_s, lll->phy_flags) + + EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US; + + pdu = lll_adv_aux_data_peek(lll_aux); + if ((pdu->adv_ext_ind.adv_mode & BT_HCI_LE_ADV_PROP_CONN) == + BT_HCI_LE_ADV_PROP_CONN) { + const uint16_t conn_req_us = + PDU_AC_MAX_US((INITA_SIZE + ADVA_SIZE + LLDATA_SIZE), + lll->phy_s); + const uint16_t conn_rsp_us = + PDU_AC_US((PDU_AC_EXT_HEADER_SIZE_MIN + ADVA_SIZE + + TARGETA_SIZE), lll->phy_s, lll->phy_flags); + + time_us += EVENT_IFS_MAX_US * 2 + conn_req_us + conn_rsp_us; + } else if ((pdu->adv_ext_ind.adv_mode & BT_HCI_LE_ADV_PROP_SCAN) == + BT_HCI_LE_ADV_PROP_SCAN) { + const uint16_t scan_req_us = + PDU_AC_MAX_US((SCANA_SIZE + ADVA_SIZE), lll->phy_s); + const uint16_t scan_rsp_us = + PDU_AC_US(pdu_scan_len, lll->phy_s, lll->phy_flags); + + time_us += EVENT_IFS_MAX_US * 2 + scan_req_us + scan_rsp_us; + } + + return time_us; +} + void ull_adv_aux_offset_get(struct ll_adv_set *adv) { static memq_link_t link; diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h b/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h index 1abe3a505b2..151632f31ed 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h @@ -84,7 +84,8 @@ uint8_t ull_adv_aux_handle_get(struct ll_adv_aux_set *aux); uint8_t ull_adv_aux_chm_update(void); /* helper function to initialize event timings */ -uint32_t ull_adv_aux_evt_init(struct ll_adv_aux_set *aux); +uint32_t ull_adv_aux_evt_init(struct ll_adv_aux_set *aux, + uint32_t *ticks_anchor); /* helper function to start auxiliary advertising */ uint32_t ull_adv_aux_start(struct ll_adv_aux_set *aux, uint32_t ticks_anchor, @@ -99,6 +100,13 @@ struct ll_adv_aux_set *ull_adv_aux_acquire(struct lll_adv *lll); /* helper function to release auxiliary advertising instance */ void ull_adv_aux_release(struct ll_adv_aux_set *aux); +/* helper function to give the auxiliary context */ +struct ll_adv_aux_set *ull_adv_aux_get(uint8_t handle); + +/* helper function to return time reservation for auxiliary PDU */ +uint32_t ull_adv_aux_time_get(const struct ll_adv_aux_set *aux, uint8_t pdu_len, + uint8_t pdu_scan_len); + /* helper function to schedule a mayfly to get aux offset */ void ull_adv_aux_offset_get(struct ll_adv_set *adv); diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c index 07a89d9c245..86b6143e7f8 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c @@ -805,8 +805,8 @@ static uint32_t adv_iso_start(struct ll_adv_iso_set *adv_iso, ticks_slot = adv_iso->ull.ticks_slot + ticks_slot_overhead; /* Find the slot after Periodic Advertisings events */ - err = ull_sched_after_adv_sync_slot_get(TICKER_USER_ID_THREAD, - ticks_slot, &ticks_anchor); + err = ull_sched_adv_aux_sync_free_slot_get(TICKER_USER_ID_THREAD, + ticks_slot, &ticks_anchor); if (err) { ticks_anchor = ticker_ticks_now_get(); } diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c index 1e15a31f291..caac4f46669 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c @@ -740,11 +740,15 @@ uint8_t ll_adv_sync_enable(uint8_t handle, uint8_t enable) lll_aux = adv->lll.aux; aux = HDR_LLL2ULL(lll_aux); ticks_anchor_aux = ticker_ticks_now_get(); - ticks_slot_overhead_aux = ull_adv_aux_evt_init(aux); - ticks_anchor_sync = - ticks_anchor_aux + ticks_slot_overhead_aux + - aux->ull.ticks_slot + - HAL_TICKER_US_TO_TICKS(EVENT_MAFS_US); + ticks_slot_overhead_aux = + ull_adv_aux_evt_init(aux, &ticks_anchor_aux); + ticks_anchor_sync = ticks_anchor_aux + + ticks_slot_overhead_aux + aux->ull.ticks_slot + + HAL_TICKER_US_TO_TICKS( + MAX(EVENT_MAFS_US, + EVENT_OVERHEAD_START_US) - + EVENT_OVERHEAD_START_US + + (EVENT_TICKER_RES_MARGIN_US << 1)); } ret = ull_adv_sync_start(adv, sync, ticks_anchor_sync); diff --git a/subsys/bluetooth/controller/ll_sw/ull_sched.c b/subsys/bluetooth/controller/ll_sw/ull_sched.c index d43a080bb88..fe1c7e31d76 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sched.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sched.c @@ -49,8 +49,6 @@ #include "common/log.h" #include "hal/debug.h" -typedef struct ull_hdr *(*ull_hdr_get_func)(uint8_t ticker_id); - #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) #if defined(CONFIG_BT_LL_SW_LLCP_LEGACY) static void win_offset_calc(struct ll_conn *conn_curr, uint8_t is_select, @@ -60,6 +58,14 @@ static void win_offset_calc(struct ll_conn *conn_curr, uint8_t is_select, #endif #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */ +#if defined(CONFIG_BT_CONN) +static void after_cen_offset_get(uint16_t conn_interval, uint32_t ticks_slot, + uint32_t ticks_anchor, + uint32_t *win_offset_us); +#endif /* CONFIG_BT_CONN */ + +typedef struct ull_hdr *(*ull_hdr_get_func)(uint8_t ticker_id, + uint32_t *ticks_slot); static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, ticker_op_match_func ticker_match_op_cb, ull_hdr_get_func ull_hdr_get_cb, @@ -67,49 +73,77 @@ static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, uint32_t *ticks_to_expire_match, uint32_t *ticks_slot_match); static void ticker_op_cb(uint32_t status, void *param); +static bool ticker_match_op_cb(uint8_t ticker_id, uint32_t ticks_slot, + uint32_t ticks_to_expire, void *op_context); +static struct ull_hdr *ull_hdr_get_cb(uint8_t ticker_id, uint32_t *ticks_slot); -#if defined(CONFIG_BT_CONN) -static bool ticker_conn_match_op_cb(uint8_t ticker_id, uint32_t ticks_slot, - uint32_t ticks_to_expire, void *op_context); -static struct ull_hdr *conn_ull_hdr_get_cb(uint8_t ticker_id); -static void after_cen_offset_get(uint16_t conn_interval, uint32_t ticks_slot, - uint32_t ticks_anchor, - uint32_t *win_offset_us); -#endif /* CONFIG_BT_CONN */ - -#if defined(CONFIG_BT_CTLR_ADV_ISO) -static bool ticker_adv_sync_match_op_cb(uint8_t ticker_id, uint32_t ticks_slot, - uint32_t ticks_to_expire, - void *op_context); -static struct ull_hdr *adv_sync_ull_hdr_get_cb(uint8_t ticker_id); - -int ull_sched_after_adv_sync_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, - uint32_t *ticks_anchor) +#if defined(CONFIG_BT_CTLR_ADV_EXT) && defined(CONFIG_BT_BROADCASTER) +int ull_sched_adv_aux_sync_free_slot_get(uint8_t user_id, + uint32_t ticks_slot_abs, + uint32_t *ticks_anchor) { uint32_t ticks_to_expire; uint32_t ticks_slot; uint8_t ticker_id; ticker_id = after_match_slot_get(user_id, ticks_slot_abs, - ticker_adv_sync_match_op_cb, - adv_sync_ull_hdr_get_cb, ticks_anchor, - &ticks_to_expire, &ticks_slot); + ticker_match_op_cb, ull_hdr_get_cb, + ticks_anchor, &ticks_to_expire, + &ticks_slot); if (ticker_id != TICKER_NULL) { - const struct ll_adv_sync_set *sync = - (void *)adv_sync_ull_hdr_get_cb(ticker_id); - uint32_t time_us; + if (false) { - time_us = ull_adv_sync_time_get(sync, PDU_AC_PAYLOAD_SIZE_MAX); + } else if (IN_RANGE(ticker_id, TICKER_ID_ADV_AUX_BASE, + TICKER_ID_ADV_AUX_LAST)) { + const struct ll_adv_aux_set *aux; - *ticks_anchor += ticks_to_expire; - *ticks_anchor += HAL_TICKER_US_TO_TICKS(time_us); + aux = (void *)ull_hdr_get_cb(ticker_id, &ticks_slot); - return 0; + *ticks_anchor += ticks_to_expire; + *ticks_anchor += ticks_slot; + + if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) { + *ticks_anchor += + MAX(aux->ull.ticks_active_to_start, + aux->ull.ticks_prepare_to_start); + } + + return 0; + +#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) + } else if (IN_RANGE(ticker_id, TICKER_ID_ADV_SYNC_BASE, + TICKER_ID_ADV_SYNC_LAST)) { + const struct ll_adv_sync_set *sync; + + sync = (void *)ull_hdr_get_cb(ticker_id, &ticks_slot); + + *ticks_anchor += ticks_to_expire; + *ticks_anchor += ticks_slot; + + if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) { + *ticks_anchor += + MAX(sync->ull.ticks_active_to_start, + sync->ull.ticks_prepare_to_start); + } + + return 0; +#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ + +#if defined(CONFIG_BT_CONN) + } else if (IN_RANGE(ticker_id, TICKER_ID_CONN_BASE, + TICKER_ID_CONN_LAST)) { + *ticks_anchor += ticks_to_expire; + *ticks_anchor += ticks_slot; + + return 0; +#endif /* CONFIG_BT_CONN */ + + } } return -ECHILD; } -#endif /* CONFIG_BT_CTLR_ADV_ISO */ +#endif /* CONFIG_BT_CTLR_ADV_EXT && CONFIG_BT_BROADCASTER */ #if defined(CONFIG_BT_CONN) int ull_sched_after_cen_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, @@ -120,9 +154,9 @@ int ull_sched_after_cen_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, uint8_t ticker_id; ticker_id = after_match_slot_get(user_id, ticks_slot_abs, - ticker_conn_match_op_cb, - conn_ull_hdr_get_cb, ticks_anchor, - &ticks_to_expire, &ticks_slot); + ticker_match_op_cb, ull_hdr_get_cb, + ticks_anchor, &ticks_to_expire, + &ticks_slot); if (ticker_id != TICKER_NULL) { *us_offset = HAL_TICKER_TICKS_TO_US(ticks_to_expire + ticks_slot) + @@ -560,6 +594,45 @@ static void win_offset_calc(struct ll_conn *conn_curr, uint8_t is_select, } #endif /* CONFIG_BT_LL_SW_LLCP_LEGACY */ #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */ + +static void after_cen_offset_get(uint16_t conn_interval, uint32_t ticks_slot, + uint32_t ticks_anchor, + uint32_t *win_offset_us) +{ + uint32_t ticks_anchor_offset = ticks_anchor; + int err; + + err = ull_sched_after_cen_slot_get(TICKER_USER_ID_ULL_LOW, ticks_slot, + &ticks_anchor_offset, + win_offset_us); + if (err) { + return; + } + + if ((ticks_anchor_offset - ticks_anchor) & BIT(HAL_TICKER_CNTR_MSBIT)) { + *win_offset_us -= HAL_TICKER_TICKS_TO_US( + ticker_ticks_diff_get(ticks_anchor, + ticks_anchor_offset)); + } else { + *win_offset_us += HAL_TICKER_TICKS_TO_US( + ticker_ticks_diff_get(ticks_anchor_offset, + ticks_anchor)); + } + + /* Round positive offset value in the future to within one connection + * interval value. + * Offsets in the past, value with MSBit set, are handled by caller by + * adding radio end time and connection interval as necessary to get a + * window offset in future when establishing a connection. + */ + if ((*win_offset_us & BIT(31)) == 0) { + uint32_t conn_interval_us = conn_interval * CONN_INT_UNIT_US; + + while (*win_offset_us > conn_interval_us) { + *win_offset_us -= conn_interval_us; + } + } +} #endif /* CONFIG_BT_CONN */ static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, @@ -571,19 +644,40 @@ static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, { uint32_t ticks_to_expire_prev; uint32_t ticks_slot_abs_prev; + uint32_t ticks_anchor_prev; uint32_t ticks_to_expire; uint8_t ticker_id_prev; uint8_t ticker_id; + uint8_t retry; + /* As we may place the event between two other events, ensure there is + * space for 3 times +/- 16 us jitter. I.e. with 32KHz sleep clock, + * ~30.517 us after previous event, ~30.517 us before and after current + * event, and an ~30.517 us before next event. Hence 8 time of ceil + * value 16 us (30.517 / 2). + */ ticks_slot_abs += HAL_TICKER_US_TO_TICKS(EVENT_JITTER_US << 3); + /* There is a possibility that ticker nodes expire during iterations in + * this function causing the reference ticks_anchor returned for the + * found ticker to change. In this case the iterations have to be + * restarted with the new reference ticks_anchor value. + * Simultaneous continuous scanning on 1M and Coded PHY, alongwith + * directed advertising and one other state/role could expire in quick + * succession, hence have a retry count of 4. + */ + retry = 4U; + + /* Initialize variable required for iterations to find a free slot */ ticker_id = ticker_id_prev = TICKER_NULL; + ticks_anchor_prev = 0U; ticks_to_expire = ticks_to_expire_prev = 0U; ticks_slot_abs_prev = 0U; while (1) { uint32_t ticks_slot_abs_curr = 0U; uint32_t ticks_to_expire_normal; uint32_t volatile ret_cb; + uint32_t ticks_slot; struct ull_hdr *hdr; uint32_t ret; bool success; @@ -619,6 +713,21 @@ static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, success = (ret_cb == TICKER_STATUS_SUCCESS); LL_ASSERT(success); + /* There is a possibility that tickers expire while we + * iterate through the active list of tickers, start over with + * a fresh iteration. + */ + if ((ticker_id_prev != TICKER_NULL) && + (*ticks_anchor != ticks_anchor_prev)) { + LL_ASSERT(retry); + retry--; + + ticker_id = ticker_id_prev = TICKER_NULL; + + continue; + } + + /* No more active tickers with slot */ if (ticker_id == TICKER_NULL) { break; } @@ -629,7 +738,7 @@ static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, } #endif /* CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */ - hdr = ull_hdr_get_cb(ticker_id); + hdr = ull_hdr_get_cb(ticker_id, &ticks_slot); if (!hdr) { continue; } @@ -658,7 +767,7 @@ static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, } #endif - ticks_slot_abs_curr += hdr->ticks_slot; + ticks_slot_abs_curr += ticks_slot; if ((ticker_id_prev != TICKER_NULL) && (ticker_ticks_diff_get(ticks_to_expire_normal, @@ -667,6 +776,7 @@ static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, break; } + ticks_anchor_prev = *ticks_anchor; ticker_id_prev = ticker_id; ticks_to_expire_prev = ticks_to_expire_normal; ticks_slot_abs_prev = ticks_slot_abs_curr; @@ -685,86 +795,88 @@ static void ticker_op_cb(uint32_t status, void *param) *((uint32_t volatile *)param) = status; } -#if defined(CONFIG_BT_CONN) -static bool ticker_conn_match_op_cb(uint8_t ticker_id, uint32_t ticks_slot, - uint32_t ticks_to_expire, void *op_context) +static bool ticker_match_op_cb(uint8_t ticker_id, uint32_t ticks_slot, + uint32_t ticks_to_expire, void *op_context) { ARG_UNUSED(ticks_slot); ARG_UNUSED(ticks_to_expire); ARG_UNUSED(op_context); - return (ticker_id >= TICKER_ID_CONN_BASE) && - (ticker_id <= TICKER_ID_CONN_LAST); -} + return false || -static struct ull_hdr *conn_ull_hdr_get_cb(uint8_t ticker_id) -{ - struct ll_conn *conn; +#if defined(CONFIG_BT_CTLR_ADV_EXT) && defined(CONFIG_BT_BROADCASTER) + IN_RANGE(ticker_id, TICKER_ID_ADV_AUX_BASE, + TICKER_ID_ADV_AUX_LAST) || - conn = ll_conn_get(ticker_id - TICKER_ID_CONN_BASE); - if (!conn || conn->lll.role) { - return NULL; - } +#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) + IN_RANGE(ticker_id, TICKER_ID_ADV_SYNC_BASE, + TICKER_ID_ADV_SYNC_LAST) || +#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ +#endif /* CONFIG_BT_CTLR_ADV_EXT && CONFIG_BT_BROADCASTER */ - return &conn->ull; -} - -static void after_cen_offset_get(uint16_t conn_interval, uint32_t ticks_slot, - uint32_t ticks_anchor, - uint32_t *win_offset_us) -{ - uint32_t ticks_anchor_offset = ticks_anchor; - int err; - - err = ull_sched_after_cen_slot_get(TICKER_USER_ID_ULL_LOW, ticks_slot, - &ticks_anchor_offset, - win_offset_us); - if (err) { - return; - } - - if ((ticks_anchor_offset - ticks_anchor) & BIT(HAL_TICKER_CNTR_MSBIT)) { - *win_offset_us -= HAL_TICKER_TICKS_TO_US( - ticker_ticks_diff_get(ticks_anchor, - ticks_anchor_offset)); - } else { - *win_offset_us += HAL_TICKER_TICKS_TO_US( - ticker_ticks_diff_get(ticks_anchor_offset, - ticks_anchor)); - } - - if ((*win_offset_us & BIT(31)) == 0) { - uint32_t conn_interval_us = conn_interval * CONN_INT_UNIT_US; - - while (*win_offset_us > conn_interval_us) { - *win_offset_us -= conn_interval_us; - } - } -} +#if defined(CONFIG_BT_CONN) + IN_RANGE(ticker_id, TICKER_ID_CONN_BASE, + TICKER_ID_CONN_LAST) || #endif /* CONFIG_BT_CONN */ -#if defined(CONFIG_BT_CTLR_ADV_ISO) -static bool ticker_adv_sync_match_op_cb(uint8_t ticker_id, uint32_t ticks_slot, - uint32_t ticks_to_expire, - void *op_context) -{ - ARG_UNUSED(ticks_slot); - ARG_UNUSED(ticks_to_expire); - ARG_UNUSED(op_context); - - return (ticker_id >= TICKER_ID_ADV_SYNC_BASE) && - (ticker_id <= TICKER_ID_ADV_SYNC_LAST); + false; } -static struct ull_hdr *adv_sync_ull_hdr_get_cb(uint8_t ticker_id) +static struct ull_hdr *ull_hdr_get_cb(uint8_t ticker_id, uint32_t *ticks_slot) { - struct ll_adv_sync_set *sync; + if (false) { + +#if defined(CONFIG_BT_CTLR_ADV_EXT) && defined(CONFIG_BT_BROADCASTER) + } else if (IN_RANGE(ticker_id, TICKER_ID_ADV_AUX_BASE, + TICKER_ID_ADV_AUX_LAST)) { + struct ll_adv_aux_set *aux; + + aux = ull_adv_aux_get(ticker_id - TICKER_ID_ADV_AUX_BASE); + if (aux) { + uint32_t time_us; + + time_us = ull_adv_aux_time_get(aux, + PDU_AC_PAYLOAD_SIZE_MAX, + PDU_AC_PAYLOAD_SIZE_MAX); + + *ticks_slot = HAL_TICKER_US_TO_TICKS(time_us); + + return &aux->ull; + } + +#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) + } else if (IN_RANGE(ticker_id, TICKER_ID_ADV_SYNC_BASE, + TICKER_ID_ADV_SYNC_LAST)) { + struct ll_adv_sync_set *sync; + + sync = ull_adv_sync_get(ticker_id - TICKER_ID_ADV_SYNC_BASE); + if (sync) { + uint32_t time_us; + + time_us = ull_adv_sync_time_get(sync, + PDU_AC_PAYLOAD_SIZE_MAX); + + *ticks_slot = HAL_TICKER_US_TO_TICKS(time_us); + + return &sync->ull; + } +#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ +#endif /* CONFIG_BT_CTLR_ADV_EXT && CONFIG_BT_BROADCASTER */ + +#if defined(CONFIG_BT_CONN) + } else if (IN_RANGE(ticker_id, TICKER_ID_CONN_BASE, + TICKER_ID_CONN_LAST)) { + struct ll_conn *conn; + + conn = ll_conn_get(ticker_id - TICKER_ID_CONN_BASE); + if (conn && !conn->lll.role) { + *ticks_slot = conn->ull.ticks_slot; + + return &conn->ull; + } +#endif /* CONFIG_BT_CONN */ - sync = ull_adv_sync_get(ticker_id - TICKER_ID_ADV_SYNC_BASE); - if (!sync) { - return NULL; } - return &sync->ull; + return NULL; } -#endif /* CONFIG_BT_CTLR_ADV_ISO */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_sched_internal.h b/subsys/bluetooth/controller/ll_sw/ull_sched_internal.h index f00d4384ede..e40ece6670f 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sched_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_sched_internal.h @@ -4,10 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +int ull_sched_adv_aux_sync_free_slot_get(uint8_t user_id, + uint32_t ticks_slot_abs, + uint32_t *ticks_anchor); int ull_sched_after_cen_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, uint32_t *ticks_anchor, uint32_t *us_offset); void ull_sched_mfy_win_offset_use(void *param); void ull_sched_mfy_free_win_offset_calc(void *param); void ull_sched_mfy_win_offset_select(void *param); -int ull_sched_after_adv_sync_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, - uint32_t *ticks_anchor);