From db72c462aeab49719a8864dec5adb11c9e513080 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Thu, 5 Oct 2023 21:26:11 +0200 Subject: [PATCH 01/10] Bluetooth: Controller: Simplify ticker reschedule_in_window Simplify ticker reschedule_in_window implementation. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ticker/ticker.c | 31 +++++++++++---------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/subsys/bluetooth/controller/ticker/ticker.c b/subsys/bluetooth/controller/ticker/ticker.c index 5922ad0739697c..9d648ff98a1279 100644 --- a/subsys/bluetooth/controller/ticker/ticker.c +++ b/subsys/bluetooth/controller/ticker/ticker.c @@ -2466,11 +2466,15 @@ static uint8_t ticker_job_reschedule_in_window(struct ticker_instance *instance, ticker_id_resched_prev = ticker_id_resched; ticker_id_resched = ticker_resched->next; } + + /* Exit if no tickers to be rescheduled */ if (ticker_id_resched == TICKER_NULL) { - /* Done */ break; } + /* Ensure that resched ticker is expired */ + LL_ASSERT(ticker_resched->ticks_to_expire == 0U); + /* Check for intersection with already active node */ window_start_ticks = 0U; if (instance->ticks_slot_previous > ticks_elapsed) { @@ -2481,8 +2485,6 @@ static uint8_t ticker_job_reschedule_in_window(struct ticker_instance *instance, ticks_elapsed; } - ticker_id_next = ticker_resched->next; - /* If drift was applied to this node, this must be * taken into consideration. Reduce the window with * the amount of drift already applied. @@ -2496,6 +2498,10 @@ static uint8_t ticker_job_reschedule_in_window(struct ticker_instance *instance, if (ext_data->ticks_drift < ext_data->ticks_slot_window) { ticks_slot_window = ext_data->ticks_slot_window - ext_data->ticks_drift; + /* Window available, proceed to calculate further + * drift + */ + ticker_id_next = ticker_resched->next; } else { /* Window has been exhausted - we can't reschedule */ ticker_id_next = TICKER_NULL; @@ -2553,7 +2559,7 @@ static uint8_t ticker_job_reschedule_in_window(struct ticker_instance *instance, /* Next expiry is too close - try the next * node */ - window_end_ticks = 0; + window_end_ticks = 0U; } /* Calculate new ticks_to_expire as end of window minus @@ -2575,7 +2581,7 @@ static uint8_t ticker_job_reschedule_in_window(struct ticker_instance *instance, } } else { /* No space in window - try the next node */ - ticks_to_expire = 0; + ticks_to_expire = 0U; } /* Decide if the re-scheduling ticker node fits in the @@ -2613,9 +2619,7 @@ static uint8_t ticker_job_reschedule_in_window(struct ticker_instance *instance, ticker_id_next = ticker_next->next; } - ext_data->ticks_drift += ticks_to_expire - - ticker_resched->ticks_to_expire; - ticker_resched->ticks_to_expire = ticks_to_expire; + ext_data->ticks_drift += ticks_to_expire; /* Place the ticker node sorted by expiration time and adjust * delta times @@ -2626,21 +2630,20 @@ static uint8_t ticker_job_reschedule_in_window(struct ticker_instance *instance, struct ticker_node *ticker_next; ticker_next = &nodes[ticker_id_next]; - if (ticker_resched->ticks_to_expire > - ticker_next->ticks_to_expire) { + if (ticks_to_expire > ticker_next->ticks_to_expire) { /* Node is after this - adjust delta */ - ticker_resched->ticks_to_expire -= - ticker_next->ticks_to_expire; + ticks_to_expire -= ticker_next->ticks_to_expire; } else { /* Node is before this one */ - ticker_next->ticks_to_expire -= - ticker_resched->ticks_to_expire; + ticker_next->ticks_to_expire -= ticks_to_expire; break; } ticker_id_prev = ticker_id_next; ticker_id_next = ticker_next->next; } + ticker_resched->ticks_to_expire = ticks_to_expire; + /* If the node moved in the list, insert it */ if (ticker_id_prev != TICKER_NULL) { /* Remove node from its current position in list */ From 0e02ef41e3e19096a26e5e0c36dbe6a4aa2776e4 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Sun, 14 Jul 2024 06:32:32 +0200 Subject: [PATCH 02/10] Bluetooth: Controller: Fix ticks_elapsed use in reschedule_in_window Remove ticks_elapsed use in reschedule_in_window as it has already been used in the bottom half processing. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ticker/ticker.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/subsys/bluetooth/controller/ticker/ticker.c b/subsys/bluetooth/controller/ticker/ticker.c index 9d648ff98a1279..b85598535cdd2c 100644 --- a/subsys/bluetooth/controller/ticker/ticker.c +++ b/subsys/bluetooth/controller/ticker/ticker.c @@ -2425,8 +2425,7 @@ static inline uint8_t ticker_job_insert(struct ticker_instance *instance, * * @internal */ -static uint8_t ticker_job_reschedule_in_window(struct ticker_instance *instance, - uint32_t ticks_elapsed) +static uint8_t ticker_job_reschedule_in_window(struct ticker_instance *instance) { struct ticker_node *nodes; uint8_t rescheduling; @@ -2475,15 +2474,8 @@ static uint8_t ticker_job_reschedule_in_window(struct ticker_instance *instance, /* Ensure that resched ticker is expired */ LL_ASSERT(ticker_resched->ticks_to_expire == 0U); - /* Check for intersection with already active node */ - window_start_ticks = 0U; - if (instance->ticks_slot_previous > ticks_elapsed) { - /* Active node intersects - window starts after end of - * active slot - */ - window_start_ticks = instance->ticks_slot_previous - - ticks_elapsed; - } + /* Window start after intersection with already active node */ + window_start_ticks = instance->ticks_slot_previous; /* If drift was applied to this node, this must be * taken into consideration. Reduce the window with @@ -2540,6 +2532,11 @@ static uint8_t ticker_job_reschedule_in_window(struct ticker_instance *instance, if (TICKER_RESCHEDULE_PENDING(ticker_next) || !ticker_next->ticks_slot || !ticker_next->ticks_periodic) { + /* Reschedule at window start if no more tickers + * in the list. + */ + ticks_to_expire = window_start_ticks; + ticker_id_next = ticker_next->next; continue; @@ -3271,7 +3268,7 @@ void ticker_job(void *param) #if defined(CONFIG_BT_TICKER_EXT) && !defined(CONFIG_BT_TICKER_SLOT_AGNOSTIC) &&\ !defined(CONFIG_BT_TICKER_LOW_LAT) /* Re-schedule any pending nodes with slot_window */ - if (ticker_job_reschedule_in_window(instance, ticks_elapsed)) { + if (ticker_job_reschedule_in_window(instance)) { flag_compare_update = 1U; } #endif /* CONFIG_BT_TICKER_EXT */ From cbd9524ee93bdc8888ec233a1d49a6dcc766fc47 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Thu, 11 Jul 2024 15:19:46 +0200 Subject: [PATCH 03/10] Bluetooth: Controller: Introduce ticker reschedule with jitter Introduce ticker reschedule with jitter so that role like BIG can start after overlapping ACL and receive subsequent subevents. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ticker/ticker.c | 40 +++++++++++++++++---- subsys/bluetooth/controller/ticker/ticker.h | 27 +++++++++----- 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/subsys/bluetooth/controller/ticker/ticker.c b/subsys/bluetooth/controller/ticker/ticker.c index b85598535cdd2c..5d18b683b64fd9 100644 --- a/subsys/bluetooth/controller/ticker/ticker.c +++ b/subsys/bluetooth/controller/ticker/ticker.c @@ -1299,6 +1299,7 @@ void ticker_worker(void *param) node = &instance->nodes[0]; while (ticker_id_head != TICKER_NULL) { + uint32_t ticks_to_expire_minus; struct ticker_node *ticker; uint32_t ticks_to_expire; uint8_t must_expire_skip; @@ -1381,10 +1382,23 @@ void ticker_worker(void *param) must_expire_skip = 1U; } + /* Pick the ticker expiry latency, to calculate ticks_at_expire + */ + ticks_to_expire_minus = ticker->ticks_to_expire_minus; + #if defined(CONFIG_BT_TICKER_EXT) if (ticker->ext_data) { + /* Pick the drift, to give it in the ticker_cb */ ticks_drift = ticker->ext_data->ticks_drift; ticker->ext_data->ticks_drift = 0U; + + /* Revert back drift so that next expiry maintains the + * average periodic interval. + */ + if (ticker->ext_data->is_jitter_in_window) { + ticker->ticks_to_expire_minus += ticks_drift; + } + /* Mark node as not re-scheduling */ ticker->ext_data->reschedule_state = TICKER_RESCHEDULE_STATE_NONE; @@ -1399,6 +1413,10 @@ void ticker_worker(void *param) #else /* CONFIG_BT_TICKER_LOW_LAT || * CONFIG_BT_TICKER_SLOT_AGNOSTIC */ + /* Pick the ticker expiry latency, to calculate ticks_at_expire + */ + ticks_to_expire_minus = ticker->ticks_to_expire_minus; + ticks_drift = 0U; #endif /* CONFIG_BT_TICKER_LOW_LAT || * CONFIG_BT_TICKER_SLOT_AGNOSTIC @@ -1413,7 +1431,7 @@ void ticker_worker(void *param) ticks_at_expire = (instance->ticks_current + ticks_expired - - ticker->ticks_to_expire_minus) & + ticks_to_expire_minus) & HAL_TICKER_CNTR_MASK; #if defined(CONFIG_BT_TICKER_REMAINDER_SUPPORT) @@ -1734,7 +1752,8 @@ static inline uint32_t ticker_job_node_update(struct ticker_instance *instance, */ struct ticker_ext *ext_data = ticker->ext_data; - if (ext_data && ext_data->ticks_slot_window != 0U) { + if (ext_data && ext_data->ticks_slot_window && + !ext_data->is_jitter_in_window) { ext_data->ticks_drift = user_op->params.update.ticks_drift_plus - user_op->params.update.ticks_drift_minus; @@ -2564,7 +2583,8 @@ static uint8_t ticker_job_reschedule_in_window(struct ticker_instance *instance) */ if (window_end_ticks > (ticks_start_offset + ticks_slot)) { - if (!ticker_resched->ticks_slot) { + if (!ticker_resched->ticks_slot || + ext_data->is_jitter_in_window) { /* Place at start of window */ ticks_to_expire = window_start_ticks; } else { @@ -2590,6 +2610,9 @@ static uint8_t ticker_job_reschedule_in_window(struct ticker_instance *instance) ticks_slot))) { /* Re-scheduled node fits before this node */ break; + } else { + /* Not inside the window */ + ticks_to_expire = 0U; } /* We din't find a valid slot for re-scheduling - try @@ -2600,9 +2623,14 @@ static uint8_t ticker_job_reschedule_in_window(struct ticker_instance *instance) ticker_next->ticks_slot; ticks_to_expire_offset = 0U; - if (!ticker_resched->ticks_slot) { - /* Try at the end of the next node */ - ticks_to_expire = window_start_ticks; + if (!ticker_resched->ticks_slot || + ext_data->is_jitter_in_window) { + if (!ext_data->is_jitter_in_window || + (window_start_ticks <= (ticks_slot_window - + ticks_slot))) { + /* Try at the end of the next node */ + ticks_to_expire = window_start_ticks; + } } else { /* Try at the end of the slot window. This * ensures that ticker with slot window and that diff --git a/subsys/bluetooth/controller/ticker/ticker.h b/subsys/bluetooth/controller/ticker/ticker.h index f75cd21b80ae65..4fe014e925cd67 100644 --- a/subsys/bluetooth/controller/ticker/ticker.h +++ b/subsys/bluetooth/controller/ticker/ticker.h @@ -229,15 +229,24 @@ uint8_t ticker_priority_set(uint8_t instance_index, uint8_t user_id, #if defined(CONFIG_BT_TICKER_EXT) struct ticker_ext { #if !defined(CONFIG_BT_TICKER_SLOT_AGNOSTIC) - uint32_t ticks_slot_window;/* Window in which the slot - * reservation may be re-scheduled - * to avoid collision - */ - uint32_t ticks_drift; /* Actual drift since last expiry */ - uint8_t reschedule_state; /* State of re-scheduling of the - * node. See defines - * TICKER_RESCHEDULE_STATE_XXX - */ + uint32_t ticks_slot_window; /* Window in which the slot + * reservation may be re-scheduled + * to avoid collision + */ + uint32_t ticks_drift; /* Actual drift since last expiry, + * includes any ticker update interface + * made changes plus drift due to + * reschedule when not + * is_jitter_in_window, otherwise is only + * the value of drift due to reschedule + */ + uint8_t reschedule_state:3; /* State of re-scheduling of the + * node. See defines + * TICKER_RESCHEDULE_STATE_XXX + */ + uint8_t is_jitter_in_window:1; /* Jitter in slot window, maintaining + * the average periodic interval + */ #endif /* CONFIG_BT_TICKER_SLOT_AGNOSTIC */ #if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) From e728cfb24b199ca12c23fe2bb5779936a7616ed4 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Thu, 11 Jul 2024 07:32:52 +0200 Subject: [PATCH 04/10] Bluetooth: Controller: ISO Sync Receiver with ticks_slot_window Add implementation for ISO Sync Receiver to use ticks slot window feature. Signed-off-by: Vinayak Kariappa Chettimada --- .../bluetooth/controller/Kconfig.ll_sw_split | 10 +++ subsys/bluetooth/controller/ll_sw/lll.h | 3 + .../ll_sw/nordic/lll/lll_sync_iso.c | 29 ++++++++ .../bluetooth/controller/ll_sw/ull_sync_iso.c | 68 +++++++++++++++---- 4 files changed, 97 insertions(+), 13 deletions(-) diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index 111f62272afff5..9273778b82f3a3 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -540,6 +540,16 @@ config BT_CTLR_SYNC_ISO_RESERVE_MAX disabled, then time reservation does not include the pre-transmissions and any Control subevents. +config BT_CTLR_SYNC_ISO_SLOT_WINDOW_JITTER + bool "Wrap ISO Synchronized Receiver event around overlapping roles" + depends on BT_CTLR_SYNC_ISO && !BT_CTLR_SYNC_ISO_RESERVE_MAX + select BT_TICKER_EXT + help + Wrap ISO Synchronized Receiver event around overlapping roles using + ticker ticks_slot_window feature with jitter in window. + LLL implementation can use the ticks_drifts value to determine the + correct subevents to setup for reception. + config BT_CTLR_ADV_ENABLE_STRICT bool "Enforce Strict Advertising Enable/Disable" depends on BT_BROADCASTER diff --git a/subsys/bluetooth/controller/ll_sw/lll.h b/subsys/bluetooth/controller/ll_sw/lll.h index 529c5e2d9b6ebb..f4df224b39f7c0 100644 --- a/subsys/bluetooth/controller/ll_sw/lll.h +++ b/subsys/bluetooth/controller/ll_sw/lll.h @@ -239,6 +239,9 @@ struct lll_hdr { struct lll_prepare_param { uint32_t ticks_at_expire; +#if defined(CONFIG_BT_CTLR_SYNC_ISO_SLOT_WINDOW_JITTER) + uint32_t ticks_drift; +#endif /* CONFIG_BT_CTLR_SYNC_ISO_SLOT_WINDOW_JITTER */ uint32_t remainder; uint16_t lazy; #if defined(CONFIG_BT_CTLR_JIT_SCHEDULING) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c index 42c57790516ee2..dc9570d2b39c32 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c @@ -296,6 +296,35 @@ static int prepare_cb_common(struct lll_prepare_param *p) crc_init[0] = lll->bis_curr; (void)memcpy(&crc_init[1], lll->base_crc_init, sizeof(uint16_t)); +#if defined(CONFIG_BT_CTLR_SYNC_ISO_SLOT_WINDOW_JITTER) + if (p->ticks_drift) { + uint32_t drift_us; + uint8_t skipped; + + drift_us = HAL_TICKER_TICKS_TO_US(p->ticks_drift); + + skipped = DIV_ROUND_UP(drift_us, lll->sub_interval); + if (skipped >= lll->irc) { + skipped = lll->irc; + } + + lll->irc_curr += skipped; + + while (skipped--) { + /* Calculate the radio channel to use for subevent */ + data_chan_use = lll_chan_iso_subevent(data_chan_id, + lll->data_chan_map, + lll->data_chan_count, + &lll->data_chan_prn_s, + &lll->data_chan_remap_idx); + } + + drift_us %= lll->sub_interval; + drift_us = lll->sub_interval - drift_us; + p->ticks_at_expire += HAL_TICKER_US_TO_TICKS(drift_us); + } +#endif /* CONFIG_BT_CTLR_SYNC_ISO_SLOT_WINDOW_JITTER */ + /* Start setting up of Radio h/w */ radio_reset(); diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c index 542c46e287037c..d000025b52967d 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c @@ -78,6 +78,10 @@ static struct ll_iso_rx_test_mode test_mode[CONFIG_BT_CTLR_SYNC_ISO_STREAM_COUNT]; static void *stream_free; +#if defined(CONFIG_BT_CTLR_SYNC_ISO_SLOT_WINDOW_JITTER) +static struct ticker_ext ll_sync_iso_ticker_ext[CONFIG_BT_CTLR_SCAN_SYNC_ISO_SET]; +#endif /* CONFIG_BT_CTLR_SYNC_ISO_SLOT_WINDOW_JITTER */ + uint8_t ll_big_sync_create(uint8_t big_handle, uint16_t sync_handle, uint8_t encryption, uint8_t *bcode, uint8_t mse, uint16_t sync_timeout, uint8_t num_bis, @@ -409,14 +413,15 @@ void ull_sync_iso_setup(struct ll_sync_iso_set *sync_iso, uint32_t ready_delay_us; uint32_t ticks_expire; uint32_t ctrl_spacing; - uint32_t pdu_spacing; uint32_t interval_us; uint32_t ticks_diff; struct pdu_adv *pdu; + uint32_t jitter_us; uint32_t slot_us; uint8_t num_bis; uint8_t bi_size; uint8_t handle; + uint8_t index; uint32_t ret; uint8_t sca; @@ -571,10 +576,7 @@ void ull_sync_iso_setup(struct ll_sync_iso_set *sync_iso, interval_us -= lll->window_widening_periodic_us; - /* Calculate ISO Receiver BIG event timings */ - pdu_spacing = PDU_BIS_US(lll->max_pdu, lll->enc, lll->phy, - PHY_FLAGS_S8) + - EVENT_MSS_US; + /* Calculate ISO Receiver BIG control subevent timings */ ctrl_spacing = PDU_BIS_US(sizeof(struct pdu_big_ctrl), lll->enc, lll->phy, PHY_FLAGS_S8); @@ -596,22 +598,42 @@ void ull_sync_iso_setup(struct ll_sync_iso_set *sync_iso, */ if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_ISO_RESERVE_MAX)) { - /* Maximum time reservation for both sequential and interleaved + /* Maximum time reservation for sequential and interleaved * packing. */ - slot_us = (pdu_spacing * lll->nse * num_bis) + ctrl_spacing; + if (lll->bis_spacing >= (lll->sub_interval * lll->nse)) { + slot_us = lll->sub_interval * lll->nse * num_bis + ctrl_spacing; + } else { + slot_us = lll->bis_spacing * num_bis * lll->nse + ctrl_spacing; + } + + jitter_us = 0U; } else if (lll->bis_spacing >= (lll->sub_interval * lll->nse)) { /* Time reservation omitting PTC subevents in sequential * packing. */ - slot_us = pdu_spacing * ((lll->nse * num_bis) - lll->ptc); + + if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_ISO_SLOT_WINDOW_JITTER)) { + slot_us = lll->sub_interval * lll->bn; + jitter_us = lll->sub_interval * lll->bn * (lll->irc - 1U); + } else { + slot_us = lll->sub_interval * ((lll->nse * num_bis) - lll->ptc); + jitter_us = 0U; + } } else { /* Time reservation omitting PTC subevents in interleaved * packing. */ - slot_us = pdu_spacing * ((lll->nse - lll->ptc) * num_bis); + + if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_ISO_SLOT_WINDOW_JITTER)) { + jitter_us = lll->bis_spacing * num_bis * lll->bn * (lll->irc - 1U); + slot_us = lll->bis_spacing * num_bis * lll->bn; + } else { + slot_us = lll->bis_spacing * (lll->nse - lll->ptc) * num_bis; + jitter_us = 0U; + } } /* Add radio ready delay */ @@ -659,9 +681,21 @@ void ull_sync_iso_setup(struct ll_sync_iso_set *sync_iso, mfy_lll_prepare.fp = lll_sync_iso_create_prepare; handle = sync_iso_handle_get(sync_iso); - ret = ticker_start(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_HIGH, - (TICKER_ID_SCAN_SYNC_ISO_BASE + - sync_iso_handle_to_index(handle)), + index = sync_iso_handle_to_index(handle); + +#if defined(CONFIG_BT_CTLR_SYNC_ISO_SLOT_WINDOW_JITTER) +#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING) + ll_sync_iso_ticker_ext[index].ticks_slot_window = + HAL_TICKER_US_TO_TICKS(jitter_us + slot_us); + ll_sync_iso_ticker_ext[index].is_jitter_in_window = 1U; +#endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */ + + ret = ticker_start_ext( +#else /* !CONFIG_BT_CTLR_SYNC_ISO_SLOT_WINDOW_JITTER */ + ret = ticker_start( +#endif /* !CONFIG_BT_CTLR_SYNC_ISO_SLOT_WINDOW_JITTER */ + TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_HIGH, + (TICKER_ID_SCAN_SYNC_ISO_BASE + index), ftr->ticks_anchor - ticks_slot_offset, HAL_TICKER_US_TO_TICKS(sync_iso_offset_us), HAL_TICKER_US_TO_TICKS(interval_us), @@ -674,7 +708,12 @@ void ull_sync_iso_setup(struct ll_sync_iso_set *sync_iso, #endif /* !CONFIG_BT_TICKER_LOW_LAT && !CONFIG_BT_CTLR_LOW_LAT */ (sync_iso->ull.ticks_slot + ticks_slot_overhead), ticker_cb, sync_iso, - ticker_start_op_cb, (void *)__LINE__); + ticker_start_op_cb, (void *)__LINE__ +#if defined(CONFIG_BT_CTLR_SYNC_ISO_SLOT_WINDOW_JITTER) + , + &ll_sync_iso_ticker_ext[index] +#endif /* CONFIG_BT_CTLR_SYNC_ISO_SLOT_WINDOW_JITTER */ + ); LL_ASSERT((ret == TICKER_STATUS_SUCCESS) || (ret == TICKER_STATUS_BUSY)); } @@ -991,6 +1030,9 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, /* Append timing parameters */ p.ticks_at_expire = ticks_at_expire; +#if defined(CONFIG_BT_CTLR_SYNC_ISO_SLOT_WINDOW_JITTER) + p.ticks_drift = ticks_drift; +#endif /* CONFIG_BT_CTLR_SYNC_ISO_SLOT_WINDOW_JITTER */ p.remainder = remainder; p.lazy = lazy; p.force = force; From ab2b255095fe78a113d1734ec77adbfddd135baa Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Sun, 14 Jul 2024 12:15:40 +0200 Subject: [PATCH 05/10] Bluetooth: Controller: Resume feature for cancelled prepare Add implementation to support resumption of cancelled prepare. Signed-off-by: Vinayak Kariappa Chettimada --- .../controller/ll_sw/nordic/lll/lll.c | 38 ++++++++++++++++++- .../controller/ll_sw/nordic/lll/lll_adv.c | 9 ++++- .../controller/ll_sw/nordic/lll/lll_scan.c | 9 ++++- .../ll_sw/nordic/lll/lll_scan_aux.c | 5 +++ .../controller/ll_sw/nordic/lll/lll_sync.c | 5 +++ 5 files changed, 62 insertions(+), 4 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c index ec2ad2896f554e..dbcd5ae2761f50 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c @@ -45,6 +45,7 @@ static struct { struct { void *param; + uint32_t ticks_at_expire; lll_is_abort_cb_t is_abort_cb; lll_abort_cb_t abort_cb; } curr; @@ -882,6 +883,7 @@ int lll_prepare_resolve(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb, LL_ASSERT(!ready || &ready->prepare_param == prepare_param); event.curr.param = prepare_param->param; + event.curr.ticks_at_expire = prepare_param->ticks_at_expire; event.curr.is_abort_cb = is_abort_cb; event.curr.abort_cb = abort_cb; @@ -962,6 +964,8 @@ static inline struct lll_event *resume_enqueue(lll_prepare_cb_t resume_cb) prepare_param.param = event.curr.param; event.curr.param = NULL; + prepare_param.ticks_at_expire = event.curr.ticks_at_expire; + return ull_prepare_enqueue(event.curr.is_abort_cb, event.curr.abort_cb, &prepare_param, resume_cb, 1); } @@ -1235,15 +1239,45 @@ static void preempt(void *param) } /* Check if current event want to continue */ - err = event.curr.is_abort_cb(ready->prepare_param.param, event.curr.param, &resume_cb); + err = event.curr.is_abort_cb(ready->prepare_param.param, + event.curr.param, &resume_cb); if (!err) { - /* Let preemptor LLL know about the cancelled prepare */ + /* Do not need to ask same event wants to continue */ + if (event.curr.param != ready->prepare_param.param) { + /* Check if ready event want to continue */ + err = ready->is_abort_cb(NULL, + ready->prepare_param.param, + &resume_cb); + if (!err) { + err = -ECANCELED; + + goto preempt_cancel_curr; + } + } + + /* Let the prepare be dequeued from the pipeline */ ready->is_aborted = 1; + + /* Check if resume requested */ + if (err == -EAGAIN) { + struct lll_event *next; + + next = ull_prepare_enqueue(ready->is_abort_cb, + ready->abort_cb, + &ready->prepare_param, + resume_cb, 1U); + LL_ASSERT(next); + + return; + } + + /* Let preemptor LLL know about the cancelled prepare */ ready->abort_cb(&ready->prepare_param, ready->prepare_param.param); return; } +preempt_cancel_curr: /* Abort the current event */ event.curr.abort_cb(NULL, event.curr.param); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c index c28776f37c594c..e26dbc5df7f281 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c @@ -1086,8 +1086,15 @@ static int resume_prepare_cb(struct lll_prepare_param *p) static int is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb) { #if defined(CONFIG_BT_PERIPHERAL) - struct lll_adv *lll = curr; + struct lll_adv *lll; struct pdu_adv *pdu; + + /* Prepare being cancelled (no resume for directed adv) */ + if (!next) { + return -ECANCELED; + } + + lll = curr; #endif /* CONFIG_BT_PERIPHERAL */ /* TODO: prio check */ diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c index fc85e67441e2b2..90ebceeb7bea1f 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c @@ -529,7 +529,14 @@ static int common_prepare_cb(struct lll_prepare_param *p, bool is_resume) static int is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb) { - struct lll_scan *lll = curr; + struct lll_scan *lll; + + /* Prepare being cancelled (no resume for scan) */ + if (!next) { + return -ECANCELED; + } + + lll = curr; #if defined(CONFIG_BT_CENTRAL) /* Irrespective of same state/role (initiator radio event) or different diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c index eb97ab789fd57c..7dc7eed87dc456 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c @@ -621,6 +621,11 @@ static int is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb) */ ARG_UNUSED(resume_cb); + /* Prepare being cancelled (no resume for scan aux) */ + if (!next) { + return -ECANCELED; + } + /* Auxiliary event shall not overlap as they are not periodically * scheduled. */ diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c index 63b6e9a53b5d3f..11b3504d4d0983 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c @@ -534,6 +534,11 @@ static int is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb) */ ARG_UNUSED(resume_cb); + /* Prepare being cancelled (no resume for periodic sync) */ + if (!next) { + return -ECANCELED; + } + /* Different radio event overlap */ if (next != curr) { struct lll_scan_aux *lll_aux; From 0da05fc21e971008ca11fc7860d84e20a02c24f7 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Sun, 14 Jul 2024 13:38:57 +0200 Subject: [PATCH 06/10] Bluetooth: Controller: ISO Sync Receiver with resume feature Added implementation to have ISO Sync Receiver resume its subevents after being aborted by other overlapping events. Signed-off-by: Vinayak Kariappa Chettimada --- .../bluetooth/controller/ll_sw/lll_sync_iso.h | 2 + .../ll_sw/nordic/lll/lll_sync_iso.c | 155 +++++++++++++++--- 2 files changed, 133 insertions(+), 24 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/lll_sync_iso.h b/subsys/bluetooth/controller/ll_sw/lll_sync_iso.h index 6dd6a0907a5711..9f3e4816f9ee68 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_sync_iso.h +++ b/subsys/bluetooth/controller/ll_sw/lll_sync_iso.h @@ -67,6 +67,8 @@ struct lll_sync_iso { uint8_t chm_chan_map[PDU_CHANNEL_MAP_SIZE]; uint8_t chm_chan_count:6; + uint8_t is_lll_resume:1; + uint8_t term_reason; uint16_t ctrl_instant; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c index dc9570d2b39c32..f5c3fa35b5a7bb 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c @@ -21,6 +21,8 @@ #include "util/mem.h" #include "util/memq.h" +#include "ticker/ticker.h" + #include "pdu_df.h" #include "lll/pdu_vendor.h" #include "pdu.h" @@ -45,7 +47,9 @@ static void create_prepare_bh(void *param); static void prepare_bh(void *param); static int create_prepare_cb(struct lll_prepare_param *p); static int prepare_cb(struct lll_prepare_param *p); +static int prepare_cb_event(struct lll_prepare_param *p); static int prepare_cb_common(struct lll_prepare_param *p); +static int is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb); static void abort_cb(struct lll_prepare_param *prepare_param, void *param); static void isr_rx_estab(void *param); static void isr_rx(void *param); @@ -146,7 +150,7 @@ static void create_prepare_bh(void *param) int err; /* Invoke common pipeline handling of prepare */ - err = lll_prepare(lll_is_abort_cb, abort_cb, create_prepare_cb, 0U, + err = lll_prepare(is_abort_cb, abort_cb, create_prepare_cb, 0U, param); LL_ASSERT(!err || err == -EINPROGRESS); } @@ -156,7 +160,7 @@ static void prepare_bh(void *param) int err; /* Invoke common pipeline handling of prepare */ - err = lll_prepare(lll_is_abort_cb, abort_cb, prepare_cb, 0U, param); + err = lll_prepare(is_abort_cb, abort_cb, prepare_cb, 0U, param); LL_ASSERT(!err || err == -EINPROGRESS); } @@ -164,7 +168,7 @@ static int create_prepare_cb(struct lll_prepare_param *p) { int err; - err = prepare_cb_common(p); + err = prepare_cb_event(p); if (err) { DEBUG_RADIO_START_O(1); return 0; @@ -173,6 +177,7 @@ static int create_prepare_cb(struct lll_prepare_param *p) radio_isr_set(isr_rx_estab, p->param); DEBUG_RADIO_START_O(1); + return 0; } @@ -180,7 +185,7 @@ static int prepare_cb(struct lll_prepare_param *p) { int err; - err = prepare_cb_common(p); + err = prepare_cb_event(p); if (err) { DEBUG_RADIO_START_O(1); return 0; @@ -189,9 +194,37 @@ static int prepare_cb(struct lll_prepare_param *p) radio_isr_set(isr_rx, p->param); DEBUG_RADIO_START_O(1); + return 0; } +static int prepare_cb_event(struct lll_prepare_param *p) +{ + struct lll_sync_iso *lll; + + DEBUG_RADIO_START_O(1); + + lll = p->param; + + /* Deduce the latency */ + lll->latency_event = lll->latency_prepare - 1U; + + /* Update BIS packet counter to next value */ + lll->payload_count += (lll->latency_prepare * lll->bn); + + /* Reset accumulated latencies */ + lll->latency_prepare = 0U; + + /* Current window widening */ + lll->window_widening_event_us += lll->window_widening_prepare_us; + lll->window_widening_prepare_us = 0U; + if (lll->window_widening_event_us > lll->window_widening_max_us) { + lll->window_widening_event_us = lll->window_widening_max_us; + } + + return prepare_cb_common(p); +} + static int prepare_cb_common(struct lll_prepare_param *p) { struct lll_sync_iso_stream *stream; @@ -216,25 +249,6 @@ static int prepare_cb_common(struct lll_prepare_param *p) lll = p->param; - /* Deduce the latency */ - lll->latency_event = lll->latency_prepare - 1U; - - /* Calculate the current event counter value */ - event_counter = (lll->payload_count / lll->bn) + lll->latency_event; - - /* Update BIS packet counter to next value */ - lll->payload_count += (lll->latency_prepare * lll->bn); - - /* Reset accumulated latencies */ - lll->latency_prepare = 0U; - - /* Current window widening */ - lll->window_widening_event_us += lll->window_widening_prepare_us; - lll->window_widening_prepare_us = 0U; - if (lll->window_widening_event_us > lll->window_widening_max_us) { - lll->window_widening_event_us = lll->window_widening_max_us; - } - /* Initialize trx chain count */ trx_cnt = 0U; @@ -250,10 +264,16 @@ static int prepare_cb_common(struct lll_prepare_param *p) /* Initialize control subevent flag */ lll->ctrl = 0U; + /* Initialise resume subevent flag */ + lll->is_lll_resume = 0U; + /* Calculate the Access Address for the BIS event */ util_bis_aa_le32(lll->bis_curr, lll->seed_access_addr, access_addr); data_chan_id = lll_chan_id(access_addr); + /* Calculate the current event counter value */ + event_counter = (lll->payload_count / lll->bn) - 1U; + /* Calculate the radio channel to use for ISO event and hence store the * channel to be used for control subevent. */ @@ -433,6 +453,77 @@ static int prepare_cb_common(struct lll_prepare_param *p) return 0; } +#if defined(CONFIG_BT_CTLR_SYNC_ISO_SLOT_WINDOW_JITTER) +static int drift_prepare_cb(struct lll_prepare_param *p) +{ + uint32_t ticks_at_expire; + struct ull_hdr *ull; + + ticks_at_expire = p->ticks_at_expire; + + ull = HDR_LLL2ULL(p->param); + p->ticks_at_expire = ticker_ticks_diff_get(ticker_ticks_now_get(), + lll_event_offset_get(ull)); + p->ticks_drift += ticker_ticks_diff_get(p->ticks_at_expire, + ticks_at_expire); + p->remainder = 0U; + p->lazy = 0U; + + return prepare_cb(p); +} + +static int resume_prepare_cb(struct lll_prepare_param *p) +{ + uint32_t ticks_at_expire; + struct ull_hdr *ull; + int err; + + ticks_at_expire = p->ticks_at_expire; + + ull = HDR_LLL2ULL(p->param); + p->ticks_at_expire = ticker_ticks_diff_get(ticker_ticks_now_get(), + lll_event_offset_get(ull)); + p->ticks_drift += ticker_ticks_diff_get(p->ticks_at_expire, + ticks_at_expire); + p->remainder = 0U; + p->lazy = 0U; + + err = prepare_cb_common(p); + + radio_isr_set(isr_rx, p->param); + + return err; +} +#endif /* CONFIG_BT_CTLR_SYNC_ISO_SLOT_WINDOW_JITTER */ + +static int is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb) +{ +#if defined(CONFIG_BT_CTLR_SYNC_ISO_SLOT_WINDOW_JITTER) + if (!next) { + *resume_cb = drift_prepare_cb; + + return -EAGAIN; + } + + if (next != curr) { + struct lll_sync_iso *lll; + + if (!trx_cnt) { + return 0; + } + + *resume_cb = resume_prepare_cb; + + lll = curr; + lll->is_lll_resume = 1U; + + return -EAGAIN; + } +#endif /* CONFIG_BT_CTLR_SYNC_ISO_SLOT_WINDOW_JITTER */ + + return -ECANCELED; +} + static void abort_cb(struct lll_prepare_param *prepare_param, void *param) { struct event_done_extra *e; @@ -440,8 +531,24 @@ static void abort_cb(struct lll_prepare_param *prepare_param, void *param) /* NOTE: This is not a prepare being cancelled */ if (!prepare_param) { - radio_isr_set(isr_done, param); + struct lll_sync_iso *lll = param; + + if (false) { + + } else if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_ISO_SLOT_WINDOW_JITTER) && + lll->is_lll_resume) { + /* Retain HF clock */ + err = lll_hfclock_on(); + LL_ASSERT(err >= 0); + + radio_isr_set(lll_isr_abort, param); + + } else { + radio_isr_set(isr_done, param); + } + radio_disable(); + return; } From 33f21eea3a85bbcd31409f02edea72b27afaeb29 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Fri, 12 Jul 2024 04:18:38 +0200 Subject: [PATCH 07/10] Bluetooth: Controller: Introduce BT_CTLR_PERIPHERAL_RESERVE_MAX Introduce BT_CTLR_PERIPHERAL_RESERVE_MAX Kconfig option so that disabling this option will use minimum time reservation and exercise the peripheral connection event continuation using is_abort_cb mechanism. Signed-off-by: Vinayak Kariappa Chettimada --- .../bluetooth/controller/Kconfig.ll_sw_split | 13 ++++++++ subsys/bluetooth/controller/ll_sw/lll.h | 1 + subsys/bluetooth/controller/ll_sw/lll_conn.h | 10 +++++++ .../controller/ll_sw/nordic/lll/lll_conn.c | 30 ++++++++++++++++++- .../ll_sw/nordic/lll/lll_peripheral.c | 3 +- subsys/bluetooth/controller/ll_sw/ull_adv.c | 1 + .../bluetooth/controller/ll_sw/ull_central.c | 1 + subsys/bluetooth/controller/ll_sw/ull_conn.c | 25 ++++++++++++++-- .../controller/ll_sw/ull_peripheral.c | 17 ++++++++++- 9 files changed, 96 insertions(+), 5 deletions(-) diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index 9273778b82f3a3..9e6f07456fa0bb 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -759,6 +759,19 @@ config BT_CTLR_CENTRAL_RESERVE_MAX Note, currently this value is only used to space multiple central connections and not for actual ticker time reservations. +config BT_CTLR_PERIPHERAL_RESERVE_MAX + bool "Use maximum data PDU size time reservation for Peripheral" + depends on BT_PERIPHERAL + default y + help + Use the maximum data PDU size time reservation considering the Data + length could be updated from default 27 bytes to maximum support size. + + If maximum time reservation is disabled then time reservation required + for empty PDU transmission is used. Overlapping radio events will use + the is_abort_cb mechanism to decide on continuation of the connection + event. + config BT_CTLR_EVENT_OVERHEAD_RESERVE_MAX bool "Reserve maximum event overhead in time reservations" default y diff --git a/subsys/bluetooth/controller/ll_sw/lll.h b/subsys/bluetooth/controller/ll_sw/lll.h index f4df224b39f7c0..68911ad7036fca 100644 --- a/subsys/bluetooth/controller/ll_sw/lll.h +++ b/subsys/bluetooth/controller/ll_sw/lll.h @@ -508,6 +508,7 @@ struct event_done_extra { struct { uint16_t trx_cnt; uint8_t crc_valid:1; + uint8_t is_aborted:1; #if defined(CONFIG_BT_CTLR_SYNC_ISO) uint8_t estab_failed:1; #endif /* CONFIG_BT_CTLR_SYNC_ISO */ diff --git a/subsys/bluetooth/controller/ll_sw/lll_conn.h b/subsys/bluetooth/controller/ll_sw/lll_conn.h index f18e46567868cc..a32b06bf122490 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_conn.h +++ b/subsys/bluetooth/controller/ll_sw/lll_conn.h @@ -69,11 +69,20 @@ struct lll_conn { struct { uint8_t initiated:1; uint8_t cancelled:1; + uint8_t forced:1; + }; + + struct { + uint8_t initiated:1; + uint8_t cancelled:1; + uint8_t forced:1; } central; + #if defined(CONFIG_BT_PERIPHERAL) struct { uint8_t initiated:1; uint8_t cancelled:1; + uint8_t forced:1; uint8_t latency_enabled:1; uint32_t window_widening_periodic_us; @@ -160,6 +169,7 @@ int lll_conn_reset(void); void lll_conn_flush(uint16_t handle, struct lll_conn *lll); void lll_conn_prepare_reset(void); +int lll_conn_is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb); void lll_conn_abort_cb(struct lll_prepare_param *prepare_param, void *param); void lll_conn_isr_rx(void *param); void lll_conn_isr_tx(void *param); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c index 131fcde4d48efa..c6b9f3b2f28eb5 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c @@ -59,6 +59,7 @@ static struct pdu_data *get_last_tx_pdu(struct lll_conn *lll); static uint8_t crc_expire; static uint8_t crc_valid; +static uint8_t is_aborted; static uint16_t trx_cnt; #if defined(CONFIG_BT_CTLR_LE_ENC) @@ -142,12 +143,25 @@ void lll_conn_prepare_reset(void) trx_cnt = 0U; crc_valid = 0U; crc_expire = 0U; + is_aborted = 0U; #if defined(CONFIG_BT_CTLR_LE_ENC) mic_state = LLL_CONN_MIC_NONE; #endif /* CONFIG_BT_CTLR_LE_ENC */ } +int lll_conn_is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb) +{ + struct lll_conn *lll = curr; + + /* Do not abort if near supervision timeout */ + if (lll->forced) { + return 0; + } + + return -ECANCELED; +} + void lll_conn_abort_cb(struct lll_prepare_param *prepare_param, void *param) { struct event_done_extra *e; @@ -156,6 +170,17 @@ void lll_conn_abort_cb(struct lll_prepare_param *prepare_param, void *param) /* NOTE: This is not a prepare being cancelled */ if (!prepare_param) { + /* Get reference to LLL connection context */ + lll = param; + + /* For a peripheral role, ensure at least one PDU is tx-ed + * back to central, otherwise let the supervision timeout + * countdown be started. + */ + if (lll->role && (trx_cnt <= 1U)) { + is_aborted = 1U; + } + /* Perform event abort here. * After event has been cleanly aborted, clean up resources * and dispatch event done. @@ -171,8 +196,10 @@ void lll_conn_abort_cb(struct lll_prepare_param *prepare_param, void *param) err = lll_hfclock_off(); LL_ASSERT(err >= 0); - /* Accumulate the latency as event is aborted while being in pipeline */ + /* Get reference to LLL connection context */ lll = prepare_param->param; + + /* Accumulate the latency as event is aborted while being in pipeline */ lll->latency_prepare += (prepare_param->lazy + 1); /* Extra done event, to check supervision timeout */ @@ -867,6 +894,7 @@ static void isr_done(void *param) e->type = EVENT_DONE_EXTRA_TYPE_CONN; e->trx_cnt = trx_cnt; e->crc_valid = crc_valid; + e->is_aborted = is_aborted; #if defined(CONFIG_BT_CTLR_LE_ENC) e->mic_state = mic_state; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c index 30ad77fb5328cf..0f8b89e4b3a74e 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c @@ -89,7 +89,8 @@ void lll_periph_prepare(void *param) } /* Invoke common pipeline handling of prepare */ - err = lll_prepare(lll_is_abort_cb, lll_conn_abort_cb, prepare_cb, 0, p); + err = lll_prepare(lll_conn_is_abort_cb, lll_conn_abort_cb, prepare_cb, + 0U, p); LL_ASSERT(!err || err == -EINPROGRESS); } diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv.c b/subsys/bluetooth/controller/ll_sw/ull_adv.c index 269d4dddb5b8dc..a6c9a91a4b7a9d 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv.c @@ -1071,6 +1071,7 @@ uint8_t ll_adv_enable(uint8_t enable) conn_lll->role = 1; conn_lll->periph.initiated = 0; conn_lll->periph.cancelled = 0; + conn_lll->periph.forced = 0; conn_lll->data_chan_sel = 0; conn_lll->data_chan_use = 0; conn_lll->event_counter = 0; diff --git a/subsys/bluetooth/controller/ll_sw/ull_central.c b/subsys/bluetooth/controller/ll_sw/ull_central.c index a39ef8b5989986..397c0d0b5f9da5 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central.c @@ -253,6 +253,7 @@ uint8_t ll_create_connection(uint16_t scan_interval, uint16_t scan_window, conn_lll->role = 0; conn_lll->central.initiated = 0; conn_lll->central.cancelled = 0; + conn_lll->central.forced = 0; /* FIXME: END: Move to ULL? */ #if defined(CONFIG_BT_CTLR_CONN_META) memset(&conn_lll->conn_meta, 0, sizeof(conn_lll->conn_meta)); diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn.c b/subsys/bluetooth/controller/ll_sw/ull_conn.c index 94bbc2ea9d8669..96652cc7ae4933 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn.c @@ -943,6 +943,7 @@ void ull_conn_done(struct node_rx_event_done *done) struct lll_conn *lll; struct ll_conn *conn; uint8_t reason_final; + uint8_t force_lll; uint16_t lazy; uint8_t force; @@ -1054,7 +1055,7 @@ void ull_conn_done(struct node_rx_event_done *done) } /* Reset supervision countdown */ - if (done->extra.crc_valid) { + if (done->extra.crc_valid && !done->extra.is_aborted) { conn->supervision_expire = 0U; } @@ -1085,6 +1086,7 @@ void ull_conn_done(struct node_rx_event_done *done) /* check supervision timeout */ force = 0U; + force_lll = 0U; if (conn->supervision_expire) { if (conn->supervision_expire > elapsed_event) { conn->supervision_expire -= elapsed_event; @@ -1096,6 +1098,8 @@ void ull_conn_done(struct node_rx_event_done *done) * supervision timeout. */ if (conn->supervision_expire <= 6U) { + force_lll = 1U; + force = 1U; } #if defined(CONFIG_BT_CTLR_CONN_RANDOM_FORCE) @@ -1123,6 +1127,8 @@ void ull_conn_done(struct node_rx_event_done *done) } } + lll->forced = force_lll; + /* check procedure timeout */ uint8_t error_code; @@ -1233,26 +1239,41 @@ void ull_conn_done(struct node_rx_event_done *done) uint32_t ready_delay, rx_time, tx_time, ticks_slot, slot_us; lll->evt_len_upd = 0; + #if defined(CONFIG_BT_CTLR_PHY) ready_delay = (lll->role) ? lll_radio_rx_ready_delay_get(lll->phy_rx, PHY_FLAGS_S8) : lll_radio_tx_ready_delay_get(lll->phy_tx, lll->phy_flags); + +#if defined(CONFIG_BT_CTLR_PERIPHERAL_RESERVE_MAX) #if defined(CONFIG_BT_CTLR_DATA_LENGTH) tx_time = lll->dle.eff.max_tx_time; rx_time = lll->dle.eff.max_rx_time; -#else /* CONFIG_BT_CTLR_DATA_LENGTH */ +#else /* CONFIG_BT_CTLR_DATA_LENGTH */ tx_time = MAX(PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, 0), PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, lll->phy_tx)); rx_time = MAX(PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, 0), PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, lll->phy_rx)); #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ + +#else /* !CONFIG_BT_CTLR_PERIPHERAL_RESERVE_MAX */ + tx_time = PDU_MAX_US(0U, 0U, lll->phy_tx); + rx_time = PDU_MAX_US(0U, 0U, lll->phy_rx); +#endif /* !CONFIG_BT_CTLR_PERIPHERAL_RESERVE_MAX */ + #else /* CONFIG_BT_CTLR_PHY */ ready_delay = (lll->role) ? lll_radio_rx_ready_delay_get(0, 0) : lll_radio_tx_ready_delay_get(0, 0); +#if defined(CONFIG_BT_CTLR_PERIPHERAL_RESERVE_MAX) tx_time = PDU_DC_MAX_US(lll->dle.eff.max_tx_octets, 0); rx_time = PDU_DC_MAX_US(lll->dle.eff.max_rx_octets, 0); + +#else /* !CONFIG_BT_CTLR_PERIPHERAL_RESERVE_MAX */ + tx_time = PDU_MAX_US(0U, 0U, PHY_1M); + rx_time = PDU_MAX_US(0U, 0U, PHY_1M); +#endif /* !CONFIG_BT_CTLR_PERIPHERAL_RESERVE_MAX */ #endif /* CONFIG_BT_CTLR_PHY */ /* Calculate event time reservation */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_peripheral.c b/subsys/bluetooth/controller/ll_sw/ull_peripheral.c index 5abde0647e80fc..cb2eda865927b7 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_peripheral.c +++ b/subsys/bluetooth/controller/ll_sw/ull_peripheral.c @@ -341,25 +341,40 @@ void ull_periph_setup(struct node_rx_pdu *rx, struct node_rx_ftr *ftr, ll_rx_put_sched(link, rx); +#if defined(CONFIG_BT_CTLR_PERIPHERAL_RESERVE_MAX) #if defined(CONFIG_BT_CTLR_DATA_LENGTH) #if defined(CONFIG_BT_CTLR_PHY) max_tx_time = lll->dle.eff.max_tx_time; max_rx_time = lll->dle.eff.max_rx_time; + #else /* !CONFIG_BT_CTLR_PHY */ max_tx_time = PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, PHY_1M); max_rx_time = PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, PHY_1M); #endif /* !CONFIG_BT_CTLR_PHY */ + #else /* !CONFIG_BT_CTLR_DATA_LENGTH */ max_tx_time = PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, PHY_1M); max_rx_time = PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, PHY_1M); + #if defined(CONFIG_BT_CTLR_PHY) max_tx_time = MAX(max_tx_time, PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, lll->phy_tx)); max_rx_time = MAX(max_rx_time, PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, lll->phy_rx)); -#endif /* !CONFIG_BT_CTLR_PHY */ +#endif /* CONFIG_BT_CTLR_PHY */ #endif /* !CONFIG_BT_CTLR_DATA_LENGTH */ +#else /* !CONFIG_BT_CTLR_PERIPHERAL_RESERVE_MAX */ +#if defined(CONFIG_BT_CTLR_PHY) + max_tx_time = PDU_MAX_US(0U, 0U, lll->phy_tx); + max_rx_time = PDU_MAX_US(0U, 0U, lll->phy_rx); + +#else /* !CONFIG_BT_CTLR_PHY */ + max_tx_time = PDU_MAX_US(0U, 0U, PHY_1M); + max_rx_time = PDU_MAX_US(0U, 0U, PHY_1M); +#endif /* !CONFIG_BT_CTLR_PHY */ +#endif /* !CONFIG_BT_CTLR_PERIPHERAL_RESERVE_MAX */ + #if defined(CONFIG_BT_CTLR_PHY) ready_delay_us = lll_radio_rx_ready_delay_get(lll->phy_rx, PHY_FLAGS_S8); #else /* CONFIG_BT_CTLR_PHY */ From 309b3ece36146c9fa479b0c54c6ca53b48e2ff73 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Mon, 15 Jul 2024 18:03:27 +0200 Subject: [PATCH 08/10] Bluetooth: Controller: Fix BT_CTLR_SCAN_AUX_SYNC_RESERVE_MIN Fix BT_CTLR_SCAN_AUX_SYNC_RESERVE_MIN such that event is not aborted when near supervision timeout conditions. Relates to commit ddf04997a5ba ("Bluetooth: Controller: Add abort fairness in overlapping Periodic Sync"). Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/lll_sync.h | 1 + .../bluetooth/controller/ll_sw/nordic/lll/lll_sync.c | 7 +++++++ subsys/bluetooth/controller/ll_sw/ull_sync.c | 11 ++++++++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/controller/ll_sw/lll_sync.h b/subsys/bluetooth/controller/ll_sw/lll_sync.h index 03c1d4e2eda9a8..568c71fe8a8c79 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_sync.h +++ b/subsys/bluetooth/controller/ll_sw/lll_sync.h @@ -27,6 +27,7 @@ struct lll_sync { uint8_t filter_policy:1; uint8_t is_rx_enabled:1; uint8_t is_aux_sched:1; + uint8_t forced:1; #if defined(CONFIG_BT_CTLR_SYNC_ISO) uint8_t sca:3; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c index 11b3504d4d0983..1e216ae56af6ea 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c @@ -567,6 +567,13 @@ static int is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb) lll_sync_next = ull_sync_lll_is_valid_get(next); if (!lll_sync_next) { + lll_sync_curr = curr; + + /* Do not abort if near supervision timeout */ + if (lll_sync_curr->forced) { + return 0; + } + /* Abort current event as next event is not a * scan and not a scan aux event. */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync.c b/subsys/bluetooth/controller/ll_sw/ull_sync.c index c557260c22ad23..bc7b673b97ecd3 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync.c @@ -722,6 +722,7 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux, memcpy(lll->crc_init, si->crc_init, sizeof(lll->crc_init)); lll->event_counter = sys_le16_to_cpu(si->evt_cntr); lll->phy = aux->lll.phy; + lll->forced = 0U; interval = sys_le16_to_cpu(si->interval); interval_us = interval * PERIODIC_INT_UNIT_US; @@ -1020,6 +1021,7 @@ void ull_sync_done(struct node_rx_event_done *done) struct ll_sync_set *sync; uint16_t elapsed_event; uint16_t skip_event; + uint8_t force_lll; uint16_t lazy; uint8_t force; @@ -1100,6 +1102,7 @@ void ull_sync_done(struct node_rx_event_done *done) /* check timeout */ force = 0U; + force_lll = 0U; if (sync->timeout_expire) { if (sync->timeout_expire > elapsed_event) { sync->timeout_expire -= elapsed_event; @@ -1107,7 +1110,11 @@ void ull_sync_done(struct node_rx_event_done *done) /* break skip */ lll->skip_event = 0U; - if (skip_event) { + if (sync->timeout_expire <= 6U) { + force_lll = 1U; + + force = 1U; + } else if (skip_event) { force = 1U; } } else { @@ -1117,6 +1124,8 @@ void ull_sync_done(struct node_rx_event_done *done) } } + lll->forced = force_lll; + /* Check if skip needs update */ lazy = 0U; if ((force) || (skip_event != lll->skip_event)) { From 11964928f0f387ca32113e6cb7de4f2ba420a4f2 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Thu, 18 Jul 2024 07:56:09 +0200 Subject: [PATCH 09/10] Bluetooth: Controller: Fix incorrect elapsed events value Fix incorrect elapsed events value when event prepare are aborted in the pipeline. This caused premature supervision timeouts. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/lll_conn.h | 1 + .../bluetooth/controller/ll_sw/lll_conn_iso.h | 1 + subsys/bluetooth/controller/ll_sw/lll_sync.h | 1 + .../controller/ll_sw/nordic/lll/lll_central.c | 3 +- .../controller/ll_sw/nordic/lll/lll_conn.c | 17 +++++- .../ll_sw/nordic/lll/lll_peripheral.c | 21 ++++---- .../ll_sw/nordic/lll/lll_peripheral_iso.c | 54 +++++++++++-------- .../controller/ll_sw/nordic/lll/lll_sync.c | 10 ++-- subsys/bluetooth/controller/ll_sw/ull_conn.c | 7 +-- .../bluetooth/controller/ll_sw/ull_conn_iso.c | 6 ++- subsys/bluetooth/controller/ll_sw/ull_sync.c | 21 ++++---- 11 files changed, 85 insertions(+), 57 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/lll_conn.h b/subsys/bluetooth/controller/ll_sw/lll_conn.h index a32b06bf122490..b57e4db5ea24c3 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_conn.h +++ b/subsys/bluetooth/controller/ll_sw/lll_conn.h @@ -48,6 +48,7 @@ struct lll_conn { uint16_t latency; uint16_t latency_prepare; + uint16_t lazy_prepare; uint16_t latency_event; uint16_t event_counter; diff --git a/subsys/bluetooth/controller/ll_sw/lll_conn_iso.h b/subsys/bluetooth/controller/ll_sw/lll_conn_iso.h index 4e52da506c17c3..a8c1d5325905e0 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_conn_iso.h +++ b/subsys/bluetooth/controller/ll_sw/lll_conn_iso.h @@ -93,6 +93,7 @@ struct lll_conn_iso_group { /* Accumulates LLL prepare callback latencies */ uint16_t latency_prepare; + uint16_t lazy_prepare; uint16_t latency_event; #if defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) diff --git a/subsys/bluetooth/controller/ll_sw/lll_sync.h b/subsys/bluetooth/controller/ll_sw/lll_sync.h index 568c71fe8a8c79..595c85396f0978 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_sync.h +++ b/subsys/bluetooth/controller/ll_sw/lll_sync.h @@ -42,6 +42,7 @@ struct lll_sync { #endif /* CONFIG_BT_CTLR_SCAN_AUX_SYNC_RESERVE_MIN */ uint16_t skip_prepare; + uint16_t lazy_prepare; uint16_t skip_event; uint16_t event_counter; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c index a73364ef4109bd..7a8405de84c9ef 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c @@ -120,7 +120,8 @@ static int prepare_cb(struct lll_prepare_param *p) lll_conn_prepare_reset(); /* Calculate the current event latency */ - lll->latency_event = lll->latency_prepare + p->lazy; + lll->lazy_prepare = p->lazy; + lll->latency_event = lll->latency_prepare + lll->lazy_prepare; /* Calculate the current event counter value */ event_counter = lll->event_counter + lll->latency_event; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c index c6b9f3b2f28eb5..420b623fa05752 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c @@ -200,7 +200,22 @@ void lll_conn_abort_cb(struct lll_prepare_param *prepare_param, void *param) lll = prepare_param->param; /* Accumulate the latency as event is aborted while being in pipeline */ - lll->latency_prepare += (prepare_param->lazy + 1); + lll->lazy_prepare = prepare_param->lazy; + lll->latency_prepare += (lll->lazy_prepare + 1U); + +#if defined(CONFIG_BT_PERIPHERAL) + if (lll->role) { + /* Accumulate window widening */ + lll->periph.window_widening_prepare_us += + lll->periph.window_widening_periodic_us * + (prepare_param->lazy + 1); + if (lll->periph.window_widening_prepare_us > + lll->periph.window_widening_max_us) { + lll->periph.window_widening_prepare_us = + lll->periph.window_widening_max_us; + } + } +#endif /* CONFIG_BT_PERIPHERAL */ /* Extra done event, to check supervision timeout */ e = ull_event_done_extra_get(); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c index 0f8b89e4b3a74e..b8e82692e3c0db 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c @@ -79,15 +79,6 @@ void lll_periph_prepare(void *param) lll = p->param; - /* Accumulate window widening */ - lll->periph.window_widening_prepare_us += - lll->periph.window_widening_periodic_us * (p->lazy + 1); - if (lll->periph.window_widening_prepare_us > - lll->periph.window_widening_max_us) { - lll->periph.window_widening_prepare_us = - lll->periph.window_widening_max_us; - } - /* Invoke common pipeline handling of prepare */ err = lll_prepare(lll_conn_is_abort_cb, lll_conn_abort_cb, prepare_cb, 0U, p); @@ -133,7 +124,8 @@ static int prepare_cb(struct lll_prepare_param *p) lll_conn_prepare_reset(); /* Calculate the current event latency */ - lll->latency_event = lll->latency_prepare + p->lazy; + lll->lazy_prepare = p->lazy; + lll->latency_event = lll->latency_prepare + lll->lazy_prepare; /* Calculate the current event counter value */ event_counter = lll->event_counter + lll->latency_event; @@ -161,6 +153,15 @@ static int prepare_cb(struct lll_prepare_param *p) lll->data_chan_count); } + /* Accumulate window widening */ + lll->periph.window_widening_prepare_us += + lll->periph.window_widening_periodic_us * (lll->lazy_prepare + 1U); + if (lll->periph.window_widening_prepare_us > + lll->periph.window_widening_max_us) { + lll->periph.window_widening_prepare_us = + lll->periph.window_widening_max_us; + } + /* current window widening */ lll->periph.window_widening_event_us += lll->periph.window_widening_prepare_us; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c index 4c57de3e065854..b79869111baa8e 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c @@ -95,29 +95,15 @@ void lll_peripheral_iso_prepare(void *param) { struct lll_conn_iso_group *cig_lll; struct lll_prepare_param *p; - uint16_t elapsed; int err; /* Initiate HF clock start up */ err = lll_hfclock_on(); LL_ASSERT(err >= 0); - /* Instants elapsed */ p = param; - elapsed = p->lazy + 1U; - /* Save the (latency + 1) for use in event and/or supervision timeout */ cig_lll = p->param; - cig_lll->latency_prepare += elapsed; - - /* Accumulate window widening */ - cig_lll->window_widening_prepare_us_frac += - cig_lll->window_widening_periodic_us_frac * elapsed; - if (cig_lll->window_widening_prepare_us_frac > - EVENT_US_TO_US_FRAC(cig_lll->window_widening_max_us)) { - cig_lll->window_widening_prepare_us_frac = - EVENT_US_TO_US_FRAC(cig_lll->window_widening_max_us); - } /* Invoke common pipeline handling of prepare */ err = lll_prepare(lll_is_abort_cb, abort_cb, prepare_cb, 0U, param); @@ -152,7 +138,6 @@ static int prepare_cb(struct lll_prepare_param *p) memq_link_t *link; uint32_t start_us; uint32_t hcto; - uint16_t lazy; uint32_t ret; uint8_t phy; int err = 0; @@ -190,14 +175,23 @@ static int prepare_cb(struct lll_prepare_param *p) &data_chan_prn_s, &data_chan_remap_idx); - /* Store the current event latency */ - cig_lll->latency_event = cig_lll->latency_prepare; - lazy = cig_lll->latency_prepare - 1U; + /* Calculate the current event latency */ + cig_lll->lazy_prepare = p->lazy; + cig_lll->latency_event = cig_lll->latency_prepare + cig_lll->lazy_prepare; /* Reset accumulated latencies */ cig_lll->latency_prepare = 0U; - /* current window widening */ + /* Accumulate window widening */ + cig_lll->window_widening_prepare_us_frac += + cig_lll->window_widening_periodic_us_frac * (cig_lll->lazy_prepare + 1U); + if (cig_lll->window_widening_prepare_us_frac > + EVENT_US_TO_US_FRAC(cig_lll->window_widening_max_us)) { + cig_lll->window_widening_prepare_us_frac = + EVENT_US_TO_US_FRAC(cig_lll->window_widening_max_us); + } + + /* Current window widening */ cig_lll->window_widening_event_us_frac += cig_lll->window_widening_prepare_us_frac; cig_lll->window_widening_prepare_us_frac = 0; @@ -210,7 +204,7 @@ static int prepare_cb(struct lll_prepare_param *p) se_curr = 1U; /* Adjust sn and nesn for skipped CIG events */ - payload_count_lazy(cis_lll, lazy); + payload_count_lazy(cis_lll, cig_lll->lazy_prepare); /* Start setting up of Radio h/w */ radio_reset(); @@ -381,7 +375,7 @@ static int prepare_cb(struct lll_prepare_param *p) } /* Adjust sn and nesn for skipped CIG events */ - payload_count_lazy(cis_lll, lazy); + payload_count_lazy(cis_lll, cig_lll->lazy_prepare); /* Adjust sn and nesn for canceled events */ if (err) { @@ -405,13 +399,13 @@ static int prepare_cb(struct lll_prepare_param *p) static void abort_cb(struct lll_prepare_param *prepare_param, void *param) { + struct lll_conn_iso_group *cig_lll; int err; /* NOTE: This is not a prepare being cancelled */ if (!prepare_param) { struct lll_conn_iso_stream *next_cis_lll; struct lll_conn_iso_stream *cis_lll; - struct lll_conn_iso_group *cig_lll; cis_lll = ull_conn_iso_lll_stream_get(cis_handle_curr); cig_lll = param; @@ -442,6 +436,22 @@ static void abort_cb(struct lll_prepare_param *prepare_param, void *param) err = lll_hfclock_off(); LL_ASSERT(err >= 0); + /* Get reference to CIG LLL context */ + cig_lll = prepare_param->param; + + /* Accumulate the latency as event is aborted while being in pipeline */ + cig_lll->lazy_prepare = prepare_param->lazy; + cig_lll->latency_prepare += (cig_lll->lazy_prepare + 1U); + + /* Accumulate window widening */ + cig_lll->window_widening_prepare_us_frac += + cig_lll->window_widening_periodic_us_frac * (cig_lll->lazy_prepare + 1U); + if (cig_lll->window_widening_prepare_us_frac > + EVENT_US_TO_US_FRAC(cig_lll->window_widening_max_us)) { + cig_lll->window_widening_prepare_us_frac = + EVENT_US_TO_US_FRAC(cig_lll->window_widening_max_us); + } + lll_done(param); } diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c index 1e216ae56af6ea..3a74913dd46fc7 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c @@ -132,9 +132,11 @@ static void prepare(void *param) lll = p->param; + lll->lazy_prepare = p->lazy; + /* Accumulate window widening */ lll->window_widening_prepare_us += lll->window_widening_periodic_us * - (p->lazy + 1U); + (lll->lazy_prepare + 1U); if (lll->window_widening_prepare_us > lll->window_widening_max_us) { lll->window_widening_prepare_us = lll->window_widening_max_us; } @@ -272,7 +274,7 @@ static int create_prepare_cb(struct lll_prepare_param *p) lll = p->param; /* Calculate the current event latency */ - lll->skip_event = lll->skip_prepare + p->lazy; + lll->skip_event = lll->skip_prepare + lll->lazy_prepare; /* Calculate the current event counter value */ event_counter = lll->event_counter + lll->skip_event; @@ -360,7 +362,7 @@ static int prepare_cb(struct lll_prepare_param *p) lll = p->param; /* Calculate the current event latency */ - lll->skip_event = lll->skip_prepare + p->lazy; + lll->skip_event = lll->skip_prepare + lll->lazy_prepare; /* Calculate the current event counter value */ event_counter = lll->event_counter + lll->skip_event; @@ -636,7 +638,7 @@ static void abort_cb(struct lll_prepare_param *prepare_param, void *param) /* Accumulate the latency as event is aborted while being in pipeline */ lll = prepare_param->param; - lll->skip_prepare += (prepare_param->lazy + 1U); + lll->skip_prepare += (lll->lazy_prepare + 1U); /* Extra done event, to check sync lost */ e = ull_event_done_extra_get(); diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn.c b/subsys/bluetooth/controller/ll_sw/ull_conn.c index 96652cc7ae4933..5fe33ad1acfd30 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn.c @@ -1015,11 +1015,6 @@ void ull_conn_done(struct node_rx_event_done *done) #else latency_event = lll->latency_event; #endif - if (lll->latency_prepare) { - elapsed_event = latency_event + lll->latency_prepare; - } else { - elapsed_event = latency_event + 1U; - } /* Peripheral drift compensation calc and new latency or * central terminate acked @@ -1054,6 +1049,8 @@ void ull_conn_done(struct node_rx_event_done *done) conn->connect_expire = 0U; } + elapsed_event = latency_event + lll->lazy_prepare + 1U; + /* Reset supervision countdown */ if (done->extra.crc_valid && !done->extra.is_aborted) { conn->supervision_expire = 0U; diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c index 06f8f9f3bc520f..b4a09c84c4649f 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c @@ -493,8 +493,10 @@ void ull_conn_iso_done(struct node_rx_event_done *done) conn->supervision_timeout * 10U * 1000U, cig->iso_interval * CONN_INT_UNIT_US); - } else if (cis->event_expire > cig->lll.latency_event) { - cis->event_expire -= cig->lll.latency_event; + } else if (cis->event_expire > (cig->lll.latency_event + + cig->lll.lazy_prepare + 1U)) { + cis->event_expire -= cig->lll.latency_event + + cig->lll.lazy_prepare + 1U; } else { cis->event_expire = 0U; diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync.c b/subsys/bluetooth/controller/ll_sw/ull_sync.c index bc7b673b97ecd3..900e35cecd657e 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync.c @@ -1016,14 +1016,7 @@ void ull_sync_established_report(memq_link_t *link, struct node_rx_pdu *rx) void ull_sync_done(struct node_rx_event_done *done) { - uint32_t ticks_drift_minus; - uint32_t ticks_drift_plus; struct ll_sync_set *sync; - uint16_t elapsed_event; - uint16_t skip_event; - uint8_t force_lll; - uint16_t lazy; - uint8_t force; /* Get reference to ULL context */ sync = CONTAINER_OF(done->param, struct ll_sync_set, ull); @@ -1053,17 +1046,19 @@ void ull_sync_done(struct node_rx_event_done *done) } else #endif /* CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING */ { + uint32_t ticks_drift_minus; + uint32_t ticks_drift_plus; + uint16_t elapsed_event; struct lll_sync *lll; + uint16_t skip_event; + uint8_t force_lll; + uint16_t lazy; + uint8_t force; lll = &sync->lll; /* Events elapsed used in timeout checks below */ skip_event = lll->skip_event; - if (lll->skip_prepare) { - elapsed_event = skip_event + lll->skip_prepare; - } else { - elapsed_event = skip_event + 1U; - } /* Sync drift compensation and new skip calculation */ ticks_drift_plus = 0U; @@ -1079,6 +1074,8 @@ void ull_sync_done(struct node_rx_event_done *done) sync->sync_expire = 0U; } + elapsed_event = skip_event + lll->lazy_prepare + 1U; + /* Reset supervision countdown */ if (done->extra.crc_valid) { sync->timeout_expire = 0U; From 0c4ab4b9684ca11a0e0a2fe0d384077ff0e1d157 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Thu, 11 Jul 2024 07:32:52 +0200 Subject: [PATCH 10/10] Bluetooth: Controller: Ext Adv Auxiliary PDUs with ticks_slot_window Add implementation for Extended Advertising Auxiliary PDUs to use ticks slot window feature. Signed-off-by: Vinayak Kariappa Chettimada --- .../bluetooth/controller/Kconfig.ll_sw_split | 7 ++++ .../bluetooth/controller/ll_sw/ull_adv_aux.c | 36 +++++++++++++++---- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index 9e6f07456fa0bb..f4fadeb3ae62fe 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -430,6 +430,13 @@ config BT_CTLR_ADV_RESERVE_MAX corresponding to the Advertising Data present at the time of the start/enable of Advertising is used. +config BT_CTLR_ADV_AUX_SLOT_WINDOW + bool "Reschedule Extended Advertising Auxiliary PDUs" + depends on BT_BROADCASTER && BT_CTLR_ADV_EXT + select BT_TICKER_EXT + help + Reschedule Extended Advertising Auxiliary PDUs. + config BT_CTLR_ADV_ISO_RESERVE_MAX bool "Use maximum Broadcast ISO event time reservation" depends on BT_CTLR_ADV_ISO diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c b/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c index 482239a617a4a0..39c16be7d23e9f 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c @@ -71,11 +71,18 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, static struct ll_adv_aux_set ll_adv_aux_pool[CONFIG_BT_CTLR_ADV_AUX_SET]; static void *adv_aux_free; -#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) && defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) +#if defined(CONFIG_BT_CTLR_ADV_AUX_SLOT_WINDOW) || \ + (defined(CONFIG_BT_CTLR_ADV_PERIODIC) && \ + defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)) +#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) && \ + defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) static void ticker_update_op_cb(uint32_t status, void *param); +#endif /* CONFIG_BT_CTLR_ADV_PERIODIC && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ static struct ticker_ext ll_adv_aux_ticker_ext[CONFIG_BT_CTLR_ADV_AUX_SET]; -#endif /* !CONFIG_BT_CTLR_ADV_PERIODIC && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ +#endif /* CONFIG_BT_CTLR_ADV_AUX_SLOT_WINDOW || + * (CONFIG_BT_CTLR_ADV_PERIODIC && CONFIG_BT_TICKER_EXT_EXPIRE_INFO) + */ #endif /* (CONFIG_BT_CTLR_ADV_AUX_SET > 0) */ static uint16_t did_unique[PDU_ADV_SID_COUNT]; @@ -2600,6 +2607,11 @@ uint32_t ull_adv_aux_start(struct ll_adv_aux_set *aux, uint32_t ticks_anchor, aux_handle = ull_adv_aux_handle_get(aux); interval_us = aux->interval * PERIODIC_INT_UNIT_US; +#if defined(CONFIG_BT_CTLR_ADV_AUX_SLOT_WINDOW) + ll_adv_aux_ticker_ext[aux_handle].ticks_slot_window = + ULL_ADV_RANDOM_DELAY + aux->ull.ticks_slot; +#endif /* CONFIG_BT_CTLR_ADV_AUX_SLOT_WINDOW */ + #if defined(CONFIG_BT_CTLR_ADV_PERIODIC) && defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) if (aux->lll.adv->sync) { const struct ll_adv_sync_set *sync = HDR_LLL2ULL(aux->lll.adv->sync); @@ -2612,14 +2624,22 @@ uint32_t ull_adv_aux_start(struct ll_adv_aux_set *aux, uint32_t ticks_anchor, } ll_adv_aux_ticker_ext[aux_handle].ext_timeout_func = ticker_cb; +#endif /* !CONFIG_BT_CTLR_ADV_PERIODIC || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ +#if defined(CONFIG_BT_CTLR_ADV_AUX_SLOT_WINDOW) || \ + (defined(CONFIG_BT_CTLR_ADV_PERIODIC) && \ + defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)) ret_cb = TICKER_STATUS_BUSY; ret = ticker_start_ext( -#else /* !CONFIG_BT_CTLR_ADV_PERIODIC || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ +#else /* !CONFIG_BT_CTLR_ADV_AUX_SLOT_WINDOW && + * !(CONFIG_BT_CTLR_ADV_PERIODIC && CONFIG_BT_TICKER_EXT_EXPIRE_INFO) + */ ret_cb = TICKER_STATUS_BUSY; ret = ticker_start( -#endif /* !CONFIG_BT_CTLR_ADV_PERIODIC || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ +#endif /* !CONFIG_BT_CTLR_ADV_AUX_SLOT_WINDOW && + * !(CONFIG_BT_CTLR_ADV_PERIODIC && CONFIG_BT_TICKER_EXT_EXPIRE_INFO) + */ TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD, (TICKER_ID_ADV_AUX_BASE + aux_handle), ticks_anchor, 0U, @@ -2628,10 +2648,14 @@ uint32_t ull_adv_aux_start(struct ll_adv_aux_set *aux, uint32_t ticks_anchor, (aux->ull.ticks_slot + ticks_slot_overhead), ticker_cb, aux, ull_ticker_status_give, (void *)&ret_cb -#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) && defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) +#if defined(CONFIG_BT_CTLR_ADV_AUX_SLOT_WINDOW) || \ + (defined(CONFIG_BT_CTLR_ADV_PERIODIC) && \ + defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)) , &ll_adv_aux_ticker_ext[aux_handle] -#endif /* !CONFIG_BT_CTLR_ADV_PERIODIC || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ +#endif /* CONFIG_BT_CTLR_ADV_AUX_SLOT_WINDOW || + * (CONFIG_BT_CTLR_ADV_PERIODIC && CONFIG_BT_TICKER_EXT_EXPIRE_INFO) + */ ); ret = ull_ticker_status_take(ret, &ret_cb);