Bluetooth: Controller: Fix repeated per sync drift compensations

Fix repeated periodic sync drift compensation invoked when
receiving chain PDUs which caused memory corruptions and
bus faults.

Use `is_aux_sched` flag in Periodic Sync's LLL context to
differentiate between the first AUX_SYNC_IND PDU followed by
use of LLL scheduling to receive following AUX_CHAIN_IND PDU
versus ULL scheduling being used to receive AUX_CHAIN_IND
PDUs.

Drift compensation to be done only using the AUX_SYNC_IND
PDU and not on reception of AUX_CHAIN_IND PDU using ULL
scheduling.

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2021-09-13 22:27:31 +05:30 committed by Carles Cufí
parent a18bc0f4f7
commit 665a8d2c6e
3 changed files with 43 additions and 24 deletions

View File

@ -10,6 +10,10 @@ struct lll_sync {
uint8_t access_addr[4];
uint8_t crc_init[3];
uint8_t phy:3;
uint8_t is_rx_enabled:1;
uint8_t is_aux_sched:1;
uint16_t skip_prepare;
uint16_t skip_event;
uint16_t event_counter;
@ -32,9 +36,6 @@ struct lll_sync {
/* used to store lll_aux when chain is being scanned */
struct lll_scan_aux *lll_aux;
uint8_t phy:3;
uint8_t is_rx_enabled:1;
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX)
struct lll_df_sync df_cfg;
#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */

View File

@ -112,6 +112,9 @@ void lll_sync_aux_prepare_cb(struct lll_sync *lll,
{
struct node_rx_pdu *node_rx;
/* Initialize Trx count */
trx_cnt = 0U;
/* Start setting up Radio h/w */
radio_reset();
@ -201,6 +204,9 @@ static int prepare_cb(struct lll_prepare_param *p)
lll->window_widening_event_us = lll->window_widening_max_us;
}
/* Reset chain PDU being scheduled by lll_sync context */
lll->is_aux_sched = 0U;
/* Initialize Trx count */
trx_cnt = 0U;
@ -453,7 +459,7 @@ static int isr_rx(struct lll_sync *lll, uint8_t node_type, uint8_t *crc_ok)
{
uint8_t rssi_ready;
uint8_t trx_done;
int err = 0;
int err;
/* Read radio status and events */
trx_done = radio_is_done();
@ -469,14 +475,11 @@ static int isr_rx(struct lll_sync *lll, uint8_t node_type, uint8_t *crc_ok)
/* No Rx */
if (!trx_done) {
/* TODO: Combine the early exit with above if-then-else block
*/
err = -EINVAL;
goto isr_rx_done;
}
/* Rx-ed */
trx_cnt++;
/* Check CRC and generate Periodic Advertising Report */
if (*crc_ok) {
struct node_rx_pdu *node_rx;
@ -507,29 +510,34 @@ static int isr_rx(struct lll_sync *lll, uint8_t node_type, uint8_t *crc_ok)
isr_aux_setup,
lll);
if (ftr->aux_lll_sched) {
lll->is_aux_sched = 1U;
err = -EBUSY;
} else {
err = 0;
}
ull_rx_put(node_rx->hdr.link, node_rx);
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX)
create_iq_report(lll, rssi_ready, BT_HCI_LE_CTE_CRC_OK);
(void)create_iq_report(lll, rssi_ready,
BT_HCI_LE_CTE_CRC_OK);
#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */
ull_rx_sched();
} else {
err = 0;
}
}
} else {
#if defined(CONFIG_BT_CTLR_DF_SAMPLE_CTE_FOR_PDU_WITH_BAD_CRC)
else {
err = create_iq_report(lll, rssi_ready,
BT_HCI_LE_CTE_CRC_ERR_CTE_BASED_TIME);
if (!err) {
ull_rx_sched();
}
#endif /* CONFIG_BT_CTLR_DF_SAMPLE_CTE_FOR_PDU_WITH_BAD_CRC */
err = 0;
}
#endif /* CONFIG_BT_CTLR_DF_SAMPLE_CTE_FOR_PDU_WITH_BAD_CRC */
isr_rx_done:
return err;
@ -548,8 +556,12 @@ static void isr_rx_adv_sync(void *param)
/* Save radio ready and address capture timestamp for later use for
* drift compensation.
*/
radio_tmr_aa_save(radio_tmr_aa_get());
radio_tmr_ready_save(radio_tmr_ready_get());
if (err != -EINVAL) {
trx_cnt = 1U;
radio_tmr_aa_save(radio_tmr_aa_get());
radio_tmr_ready_save(radio_tmr_ready_get());
}
if (err == -EBUSY) {
return;
@ -560,14 +572,14 @@ static void isr_rx_adv_sync(void *param)
static void isr_rx_aux_chain(void *param)
{
struct lll_scan_aux *aux_lll;
struct lll_scan_aux *lll_aux;
struct lll_sync *lll;
uint8_t crc_ok;
int err;
lll = param;
aux_lll = lll->lll_aux;
if (!aux_lll) {
lll_aux = lll->lll_aux;
if (!lll_aux) {
/* auxiliary context not assigned (yet) in ULL execution
* context, drop current reception and abort further chain PDU
* receptions, if any.
@ -583,7 +595,7 @@ static void isr_rx_aux_chain(void *param)
return;
}
if (!trx_cnt || !crc_ok) {
if (!crc_ok) {
struct node_rx_pdu *node_rx;
node_rx = ull_pdu_rx_alloc();
@ -599,7 +611,13 @@ static void isr_rx_aux_chain(void *param)
}
isr_rx_aux_chain_done:
isr_rx_done_cleanup(lll, 1U);
if (lll->is_aux_sched) {
lll->is_aux_sched = 0U;
isr_rx_done_cleanup(lll, 1U);
} else {
lll_isr_cleanup(lll);
}
}
static void isr_rx_done_cleanup(struct lll_sync *lll, uint8_t crc_ok)

View File

@ -522,8 +522,6 @@ ull_scan_aux_rx_flush:
if (aux) {
struct ull_hdr *hdr;
hdr = &aux->ull;
/* Enqueue last rx in aux context if possible, otherwise send
* immediately since we are in sync context.
*/
@ -544,6 +542,7 @@ ull_scan_aux_rx_flush:
* callback. Flushing here would release aux context and thus
* ull_hdr before done event was processed.
*/
hdr = &aux->ull;
LL_ASSERT(ull_ref_get(hdr) < 2);
if (ull_ref_get(hdr) == 0) {
flush(aux);
@ -658,7 +657,7 @@ void ull_scan_aux_release(memq_link_t *link, struct node_rx_hdr *rx)
* data properly.
*/
rx->type = NODE_RX_TYPE_SYNC_REPORT;
rx->handle = ull_sync_handle_get(HDR_LLL2ULL(lll));
rx->handle = ull_sync_handle_get(param_ull);
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */
} else {
LL_ASSERT(0);
@ -673,6 +672,7 @@ void ull_scan_aux_release(memq_link_t *link, struct node_rx_hdr *rx)
hdr = &aux->ull;
LL_ASSERT(ull_ref_get(hdr) < 2);
/* Flush from here of from done event, if one is pending */
if (ull_ref_get(hdr) == 0) {
flush(aux);