From f11fe69450a8a258b07be097cfcbaf03a3f60ec8 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Thu, 8 Sep 2022 07:21:14 +0530 Subject: [PATCH] Bluetooth: Controller: Fix missing supervision/sync lost When radio event prepare is cancelled due to preemption by overlapping radio events, the extra done event processing was missing and hence the use of accumulated prepares' skip/latency count. This caused the check for supervision timeout and sync lost not be aware of the elapsed events. Signed-off-by: Vinayak Kariappa Chettimada --- .../controller/ll_sw/nordic/lll/lll_conn.c | 12 +++++++ .../controller/ll_sw/nordic/lll/lll_sync.c | 15 +++++++++ .../ll_sw/nordic/lll/lll_sync_iso.c | 33 +++++++++++++++++-- subsys/bluetooth/controller/ll_sw/ull_conn.c | 6 +++- subsys/bluetooth/controller/ll_sw/ull_sync.c | 6 +++- .../bluetooth/controller/ll_sw/ull_sync_iso.c | 6 +++- 6 files changed, 73 insertions(+), 5 deletions(-) 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 02eaa450067..48b9b793f70 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c @@ -149,6 +149,7 @@ void lll_conn_prepare_reset(void) void lll_conn_abort_cb(struct lll_prepare_param *prepare_param, void *param) { + struct event_done_extra *e; struct lll_conn *lll; int err; @@ -173,6 +174,17 @@ void lll_conn_abort_cb(struct lll_prepare_param *prepare_param, void *param) lll = prepare_param->param; lll->latency_prepare += (prepare_param->lazy + 1); + /* Extra done event, to check supervision timeout */ + e = ull_event_done_extra_get(); + LL_ASSERT(e); + + e->type = EVENT_DONE_EXTRA_TYPE_CONN; + e->trx_cnt = 0U; + e->crc_valid = 0U; +#if defined(CONFIG_BT_CTLR_LE_ENC) + e->mic_state = LLL_CONN_MIC_NONE; +#endif /* CONFIG_BT_CTLR_LE_ENC */ + 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 27d6665d223..0b44068196f 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c @@ -532,6 +532,7 @@ 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) { + struct event_done_extra *e; struct lll_sync *lll; int err; @@ -557,6 +558,20 @@ static void abort_cb(struct lll_prepare_param *prepare_param, void *param) lll = prepare_param->param; lll->skip_prepare += (prepare_param->lazy + 1U); + /* Extra done event, to check sync lost */ + e = ull_event_done_extra_get(); + LL_ASSERT(e); + + e->type = EVENT_DONE_EXTRA_TYPE_SYNC; + e->trx_cnt = 0U; + e->crc_valid = 0U; +#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING) && \ + defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT) + e->sync_term = 0U; +#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING && + * CONFIG_BT_CTLR_CTEINLINE_SUPPORT + */ + lll_done(param); } 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 de8cdf6f15b..520a8ad5021 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 @@ -42,6 +42,7 @@ 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_common(struct lll_prepare_param *p); +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); static void isr_rx_iso_data_valid(const struct lll_sync_iso *const lll, @@ -131,7 +132,7 @@ static void create_prepare_bh(void *param) int err; /* Invoke common pipeline handling of prepare */ - err = lll_prepare(lll_is_abort_cb, lll_abort_cb, create_prepare_cb, 0U, + err = lll_prepare(lll_is_abort_cb, abort_cb, create_prepare_cb, 0U, param); LL_ASSERT(!err || err == -EINPROGRESS); } @@ -141,7 +142,7 @@ static void prepare_bh(void *param) int err; /* Invoke common pipeline handling of prepare */ - err = lll_prepare(lll_is_abort_cb, lll_abort_cb, prepare_cb, 0U, param); + err = lll_prepare(lll_is_abort_cb, abort_cb, prepare_cb, 0U, param); LL_ASSERT(!err || err == -EINPROGRESS); } @@ -335,6 +336,34 @@ static int prepare_cb_common(struct lll_prepare_param *p) return 0; } +static void abort_cb(struct lll_prepare_param *prepare_param, void *param) +{ + struct event_done_extra *e; + int err; + + /* NOTE: This is not a prepare being cancelled */ + if (!prepare_param) { + radio_isr_set(lll_isr_done, param); + radio_disable(); + return; + } + + /* NOTE: Else clean the top half preparations of the aborted event + * currently in preparation pipeline. + */ + err = lll_hfclock_off(); + LL_ASSERT(err >= 0); + + /* Extra done event, to check sync lost */ + e = ull_event_done_extra_get(); + LL_ASSERT(e); + + e->type = EVENT_DONE_EXTRA_TYPE_SYNC_ISO; + e->trx_cnt = 0U; + e->crc_valid = 0U; + + lll_done(param); +} static void isr_rx_estab(void *param) { diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn.c b/subsys/bluetooth/controller/ll_sw/ull_conn.c index 45d0e5c83e5..2b11e52408a 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn.c @@ -1552,7 +1552,11 @@ void ull_conn_done(struct node_rx_event_done *done) #else latency_event = lll->latency_event; #endif - elapsed_event = latency_event + 1; + 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 diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync.c b/subsys/bluetooth/controller/ll_sw/ull_sync.c index 981de61ae1b..f87b260d0a9 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync.c @@ -983,7 +983,11 @@ void ull_sync_done(struct node_rx_event_done *done) /* Events elapsed used in timeout checks below */ skip_event = lll->skip_event; - elapsed_event = skip_event + 1; + 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; diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c index 929b55c316a..07da87be9af 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c @@ -516,7 +516,11 @@ void ull_sync_iso_done(struct node_rx_event_done *done) /* Events elapsed used in timeout checks below */ latency_event = lll->latency_event; - elapsed_event = latency_event + 1U; + if (lll->latency_prepare) { + elapsed_event = latency_event + lll->latency_prepare; + } else { + elapsed_event = latency_event + 1U; + } /* Sync drift compensation and new skip calculation */