From 7c81ed71d0a96dce53df7ec55d825c45a444c103 Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Tue, 2 Feb 2021 15:37:05 +0100 Subject: [PATCH] Bluetooth: controller: Enable back-to-back chaining for periodic adv This enables chaining ota for periodic advertising. AUX_CHAIN_IND PDUs will be sent automatically if AuxPtr is detected in preceding PDU. AuxPtr offset is always set to achieve minimal required frame spacing, i.e. 300us (T_mafs). AuxPtr in all PDUs in advertising train are updated on enqueue since PDU spacing is already known at that time so we do not need to waste time in LLL. Signed-off-by: Andrzej Kaczmarek --- .../bluetooth/controller/Kconfig.ll_sw_split | 20 ++ subsys/bluetooth/controller/ll_sw/lll_adv.h | 3 + .../controller/ll_sw/nordic/lll/lll_adv_pdu.h | 4 + .../ll_sw/nordic/lll/lll_adv_sync.c | 174 +++++++++++++++++- .../controller/ll_sw/nordic/lll/lll_scan.c | 2 +- .../ll_sw/nordic/lll/lll_scan_aux.c | 6 +- 6 files changed, 197 insertions(+), 12 deletions(-) diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index 7f67727df21..a2f53f1a694 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -172,6 +172,26 @@ config BT_CTLR_ADV_PDU_LINK is required to enable advertising data trains (i.e. transmission of AUX_CHAIN_IND). +config BT_CTLR_ADV_SYNC_PDU_BACK2BACK + bool "Enable back-to-back transmission of periodic advertising trains" + depends on BT_CTLR_ADV_PERIODIC + select BT_CTLR_ADV_PDU_LINK + help + Enables transmission of AUX_CHAIN_IND in periodic advertising train by + sending each AUX_CHAIN_IND one after another back-to-back. + Note, consecutive AUX_CHAIN_IND packets are not scheduled but sent at + a constant offset on a best effort basis. This means advertising train can + be preempted by other event at any time. + +config BT_CTLR_ADV_SYNC_PDU_BACK2BACK_AFS + int "AUX Frame Space for back-to-back transmission of periodic advertising trains" + depends on BT_CTLR_ADV_SYNC_PDU_BACK2BACK + default 300 + range 300 1000 + help + Specific AUX Frame Space to be used for back-to-back transmission of + periodic advertising trains. Time specified in microseconds. + config BT_CTLR_ADV_DATA_BUF_MAX int "Advertising Data Maximum Buffers" depends on BT_BROADCASTER diff --git a/subsys/bluetooth/controller/ll_sw/lll_adv.h b/subsys/bluetooth/controller/ll_sw/lll_adv.h index 5baaec68561..fc01cffaf25 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_adv.h +++ b/subsys/bluetooth/controller/ll_sw/lll_adv.h @@ -27,6 +27,9 @@ struct lll_adv_sync { uint32_t ticks_offset; struct lll_adv_pdu data; +#if defined(CONFIG_BT_CTLR_ADV_PDU_LINK) + struct pdu_adv *last_pdu; +#endif /* CONFIG_BT_CTLR_ADV_PDU_LINK */ #if defined(CONFIG_BT_CTLR_ADV_ISO) struct lll_adv_iso *iso; 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 8b1e20f7e61..3d314a12668 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 @@ -91,6 +91,10 @@ static inline struct pdu_adv *lll_adv_aux_data_curr_get(struct lll_adv_aux *lll) #if defined(CONFIG_BT_CTLR_ADV_PERIODIC) int lll_adv_and_extra_data_release(struct lll_adv_pdu *pdu); +#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK) +void lll_adv_sync_pdu_b2b_update(struct lll_adv_sync *lll, uint8_t idx); +#endif + struct pdu_adv *lll_adv_pdu_and_extra_data_alloc(struct lll_adv_pdu *pdu, void **extra_data, uint8_t *idx); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c index 777bff0a29d..59f85e389ae 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c @@ -33,6 +33,7 @@ #include "lll_internal.h" #include "lll_adv_internal.h" #include "lll_tim_internal.h" +#include "lll_prof_internal.h" #include "lll_df_internal.h" #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER) @@ -40,10 +41,21 @@ #include "common/log.h" #include "hal/debug.h" +#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK) +#define ADV_SYNC_PDU_B2B_AFS (CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK_AFS) +#endif + static int init_reset(void); static int prepare_cb(struct lll_prepare_param *p); static void abort_cb(struct lll_prepare_param *prepare_param, void *param); static void isr_done(void *param); +#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK) +static void isr_tx(void *param); +static void pdu_b2b_update(struct lll_adv_sync *lll, struct pdu_adv *pdu); +static void pdu_b2b_aux_ptr_update(struct pdu_adv *pdu, uint8_t phy, + uint8_t flags, uint8_t chan_idx, + uint32_t tifs); +#endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */ int lll_adv_sync_init(void) { @@ -148,6 +160,15 @@ static int prepare_cb(struct lll_prepare_param *p) pdu = lll_adv_sync_data_latest_get(lll, &extra_data, &upd); LL_ASSERT(pdu); +#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK) + if (upd) { + /* AuxPtr offsets for b2b TX are fixed for given chain so we can + * calculate them here in advance. + */ + pdu_b2b_update(lll, pdu); + } +#endif + #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX) if (extra_data) { df_cfg = (struct lll_df_adv_cfg *)extra_data; @@ -162,16 +183,26 @@ static int prepare_cb(struct lll_prepare_param *p) radio_pkt_tx_set(pdu); - /* TODO: chaining */ - radio_isr_set(isr_done, lll); +#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK) + if (pdu->adv_ext_ind.ext_hdr_len && pdu->adv_ext_ind.ext_hdr.aux_ptr) { + lll->last_pdu = pdu; + radio_isr_set(isr_tx, lll); + radio_tmr_tifs_set(ADV_SYNC_PDU_B2B_AFS); + radio_switch_complete_and_b2b_tx(phy_s, 0, phy_s, 0); +#else + if (0) { +#endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */ + } else { + radio_isr_set(isr_done, lll); #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX) - if (df_cfg) { - radio_switch_complete_and_phy_end_disable(); - } else + if (df_cfg) { + radio_switch_complete_and_phy_end_disable(); + } else #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */ - { - radio_switch_complete_and_disable(); + { + radio_switch_complete_and_disable(); + } } ticks_at_event = p->ticks_at_expire; @@ -256,3 +287,132 @@ static void isr_done(void *param) #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */ lll_isr_done(lll); } + +#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK) +static void isr_tx(void *param) +{ + struct lll_adv_sync *lll_sync; + struct pdu_adv *pdu; + struct lll_adv *lll; + + if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) { + lll_prof_latency_capture(); + } + + /* Clear radio tx status and events */ + lll_isr_tx_status_reset(); + + lll_sync = param; + lll = lll_sync->adv; + + /* TODO: do not hardcode to single value */ + lll_chan_set(0); + + pdu = lll_adv_pdu_linked_next_get(lll_sync->last_pdu); + LL_ASSERT(pdu); + lll_sync->last_pdu = pdu; + + /* setup tIFS switching */ + if (pdu->adv_ext_ind.ext_hdr_len && pdu->adv_ext_ind.ext_hdr.aux_ptr) { + radio_tmr_tifs_set(ADV_SYNC_PDU_B2B_AFS); + radio_isr_set(isr_tx, lll_sync); + radio_switch_complete_and_b2b_tx(lll->phy_s, 0, lll->phy_s, 0); + } else { + radio_isr_set(lll_isr_done, lll); +#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX) + if (lll_sync->cte_started) { + radio_switch_complete_and_phy_end_disable(); + } else +#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */ + { + radio_switch_complete_and_disable(); + } + } + + radio_pkt_tx_set(pdu); + + /* assert if radio packet ptr is not set and radio started rx */ + LL_ASSERT(!radio_is_ready()); + + if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) { + lll_prof_cputime_capture(); + } + + /* capture end of AUX_SYNC_IND/AUX_CHAIN_IND PDU, used for calculating + * next PDU timestamp. + */ + radio_tmr_end_capture(); + +#if defined(CONFIG_BT_CTLR_GPIO_LNA_PIN) + if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) { + /* PA/LNA enable is overwriting packet end used in ISR + * profiling, hence back it up for later use. + */ + lll_prof_radio_end_backup(); + } + + radio_gpio_lna_setup(); + radio_gpio_pa_lna_enable(radio_tmr_tifs_base_get() + + ADV_SYNC_PDU_B2B_AFS - 4 - + radio_tx_chain_delay_get(lll->phy_s, 0) - + CONFIG_BT_CTLR_GPIO_LNA_OFFSET); +#endif /* CONFIG_BT_CTLR_GPIO_LNA_PIN */ + + if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) { + lll_prof_send(); + } +} + +static void pdu_b2b_update(struct lll_adv_sync *lll, struct pdu_adv *pdu) +{ + while (pdu) { + pdu_b2b_aux_ptr_update(pdu, lll->adv->phy_s, 0, 0, + ADV_SYNC_PDU_B2B_AFS); + pdu = lll_adv_pdu_linked_next_get(pdu); + } +} + +static void pdu_b2b_aux_ptr_update(struct pdu_adv *pdu, uint8_t phy, + uint8_t flags, uint8_t chan_idx, + uint32_t tifs) +{ + struct pdu_adv_com_ext_adv *com_hdr; + struct pdu_adv_ext_hdr *hdr; + struct pdu_adv_aux_ptr *aux; + uint32_t offs; + uint8_t *dptr; + + com_hdr = &pdu->adv_ext_ind; + hdr = &com_hdr->ext_hdr; + /* Skip flags */ + dptr = hdr->data; + + if (!com_hdr->ext_hdr_len || !hdr->aux_ptr) { + return; + } + + LL_ASSERT(!hdr->adv_addr); + LL_ASSERT(!hdr->tgt_addr); + + if (hdr->cte_info) { + dptr++; + } + + LL_ASSERT(!hdr->adi); + + /* Update AuxPtr */ + aux = (void *)dptr; + offs = PKT_AC_US(pdu->len, phy) + tifs; + offs = offs / OFFS_UNIT_30_US; + if ((offs >> 13) != 0) { + aux->offs = offs / (OFFS_UNIT_300_US / OFFS_UNIT_30_US); + aux->offs_units = 1U; + } else { + aux->offs = offs; + aux->offs_units = 0U; + } + aux->chan_idx = chan_idx; + aux->ca = 0; + aux->phy = find_lsb_set(phy) - 1; +} +#endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */ 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 0747008022e..0a94f09aa79 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c @@ -146,7 +146,7 @@ void lll_scan_prepare_connect_req(struct lll_scan *lll, struct pdu_adv *pdu_tx, conn_interval_us = (uint32_t)lll_conn->interval * CONN_INT_UNIT_US; conn_offset_us = radio_tmr_end_get() + EVENT_IFS_US + - PKT_AC_US(sizeof(struct pdu_adv_connect_ind), 0, + PKT_AC_US(sizeof(struct pdu_adv_connect_ind), phy == PHY_LEGACY ? PHY_1M : phy); /* Add transmitWindowDelay to default calculated connection offset: 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 fa843c3fbde..f55eed1cc9b 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 @@ -434,11 +434,9 @@ static int isr_rx_pdu(struct lll_scan_aux *lll, uint8_t devmatch_ok, ull = HDR_LLL2ULL(lll_scan); if (pdu_end_us > (HAL_TICKER_TICKS_TO_US(ull->ticks_slot) - EVENT_IFS_US - - PKT_AC_US(aux_connect_req_len, 0, - lll->phy) - + PKT_AC_US(aux_connect_req_len, lll->phy) - EVENT_IFS_US - - PKT_AC_US(aux_connect_rsp_len, 0, - lll->phy) - + PKT_AC_US(aux_connect_rsp_len, lll->phy) - EVENT_OVERHEAD_START_US - EVENT_TICKER_RES_MARGIN_US)) { return -ETIME;