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 <vich@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2022-09-08 07:21:14 +05:30 committed by Carles Cufí
commit f11fe69450
6 changed files with 73 additions and 5 deletions

View file

@ -149,6 +149,7 @@ void lll_conn_prepare_reset(void)
void lll_conn_abort_cb(struct lll_prepare_param *prepare_param, void *param) void lll_conn_abort_cb(struct lll_prepare_param *prepare_param, void *param)
{ {
struct event_done_extra *e;
struct lll_conn *lll; struct lll_conn *lll;
int err; int err;
@ -173,6 +174,17 @@ void lll_conn_abort_cb(struct lll_prepare_param *prepare_param, void *param)
lll = prepare_param->param; lll = prepare_param->param;
lll->latency_prepare += (prepare_param->lazy + 1); 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); lll_done(param);
} }

View file

@ -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) static void abort_cb(struct lll_prepare_param *prepare_param, void *param)
{ {
struct event_done_extra *e;
struct lll_sync *lll; struct lll_sync *lll;
int err; int err;
@ -557,6 +558,20 @@ static void abort_cb(struct lll_prepare_param *prepare_param, void *param)
lll = prepare_param->param; lll = prepare_param->param;
lll->skip_prepare += (prepare_param->lazy + 1U); 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); lll_done(param);
} }

View file

@ -42,6 +42,7 @@ static void prepare_bh(void *param);
static int create_prepare_cb(struct lll_prepare_param *p); static int create_prepare_cb(struct lll_prepare_param *p);
static int 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 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_estab(void *param);
static void isr_rx(void *param); static void isr_rx(void *param);
static void isr_rx_iso_data_valid(const struct lll_sync_iso *const lll, 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; int err;
/* Invoke common pipeline handling of prepare */ /* 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); param);
LL_ASSERT(!err || err == -EINPROGRESS); LL_ASSERT(!err || err == -EINPROGRESS);
} }
@ -141,7 +142,7 @@ static void prepare_bh(void *param)
int err; int err;
/* Invoke common pipeline handling of prepare */ /* 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); LL_ASSERT(!err || err == -EINPROGRESS);
} }
@ -335,6 +336,34 @@ static int prepare_cb_common(struct lll_prepare_param *p)
return 0; 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) static void isr_rx_estab(void *param)
{ {

View file

@ -1552,7 +1552,11 @@ void ull_conn_done(struct node_rx_event_done *done)
#else #else
latency_event = lll->latency_event; latency_event = lll->latency_event;
#endif #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 /* Peripheral drift compensation calc and new latency or
* central terminate acked * central terminate acked

View file

@ -983,7 +983,11 @@ void ull_sync_done(struct node_rx_event_done *done)
/* Events elapsed used in timeout checks below */ /* Events elapsed used in timeout checks below */
skip_event = lll->skip_event; 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 */ /* Sync drift compensation and new skip calculation */
ticks_drift_plus = 0U; ticks_drift_plus = 0U;

View file

@ -516,7 +516,11 @@ void ull_sync_iso_done(struct node_rx_event_done *done)
/* Events elapsed used in timeout checks below */ /* Events elapsed used in timeout checks below */
latency_event = lll->latency_event; 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 /* Sync drift compensation and new skip calculation
*/ */