Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion subsys/bluetooth/controller/ll_sw/lll.h
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ struct lll_event *ull_prepare_enqueue(lll_is_abort_cb_t is_abort_cb,
lll_prepare_cb_t prepare_cb,
uint8_t is_resume);
void *ull_prepare_dequeue_get(void);
void *ull_prepare_dequeue_iter(uint8_t *idx);
void *ull_prepare_dequeue_iter(void **idx);
void ull_prepare_dequeue(uint8_t caller_id);
void *ull_pdu_rx_alloc_peek(uint8_t count);
void *ull_pdu_rx_alloc_peek_iter(uint8_t *idx);
Expand Down
162 changes: 39 additions & 123 deletions subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ static int init_reset(void);
static inline void done_inc(void);
#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL_DONE */
static inline bool is_done_sync(void);
static inline struct lll_event *prepare_dequeue_iter_ready_get(uint8_t *idx);
static inline struct lll_event *prepare_dequeue_iter_ready_get(void **idx);
static inline struct lll_event *resume_enqueue(lll_is_abort_cb_t is_abort_cb,
lll_abort_cb_t abort_cb, lll_prepare_cb_t resume_cb,
void *param);
Expand Down Expand Up @@ -466,9 +466,9 @@ void lll_disable(void *param)
}
{
struct lll_event *next;
uint8_t idx;
void *idx;

idx = UINT8_MAX;
idx = NULL;
next = ull_prepare_dequeue_iter(&idx);
while (next) {
if (!next->is_aborted &&
Expand All @@ -482,8 +482,10 @@ void lll_disable(void *param)
* the prepare pipeline hence re-iterate
* through the prepare pipeline.
*/
idx = UINT8_MAX;
idx = NULL;
#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL_DONE */
} else if (!idx) {
break;
}

next = ull_prepare_dequeue_iter(&idx);
Expand Down Expand Up @@ -835,53 +837,30 @@ int lll_prepare_resolve(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb,
struct lll_event *ready_short = NULL;
struct lll_event *ready;
struct lll_event *next;
uint8_t idx;
void *idx;
int err;

/* Find the ready prepare in the pipeline */
idx = UINT8_MAX;
idx = NULL;
ready = prepare_dequeue_iter_ready_get(&idx);

/* Find any short prepare */
if (ready) {
if (ready && (&ready->prepare_param != prepare_param)) {
uint32_t ticks_at_preempt_min = prepare_param->ticks_at_expire;
uint32_t ticks_at_preempt_next;
uint8_t idx_backup = idx;
uint32_t diff;

ticks_at_preempt_next = ready->prepare_param.ticks_at_expire;
diff = ticker_ticks_diff_get(ticks_at_preempt_min,
ticks_at_preempt_next);
if (is_resume || ((diff & BIT(HAL_TICKER_CNTR_MSBIT)) == 0U)) {
ticks_at_preempt_min = ticks_at_preempt_next;
if (&ready->prepare_param != prepare_param) {
ready_short = ready;
}
ready_short = ready;
} else {
ready = NULL;
idx_backup = UINT8_MAX;
}

do {
struct lll_event *ready_next;

ready_next = prepare_dequeue_iter_ready_get(&idx);
if (!ready_next) {
break;
}

ticks_at_preempt_next = ready_next->prepare_param.ticks_at_expire;
diff = ticker_ticks_diff_get(ticks_at_preempt_next,
ticks_at_preempt_min);
if ((diff & BIT(HAL_TICKER_CNTR_MSBIT)) == 0U) {
continue;
}

ready_short = ready_next;
ticks_at_preempt_min = ticks_at_preempt_next;
} while (true);

idx = idx_backup;
} else {
ready = NULL;
}

/* Current event active or another prepare is ready in the pipeline */
Expand Down Expand Up @@ -932,6 +911,8 @@ int lll_prepare_resolve(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb,
} else {
next = ready;
}
} else if (!idx) {
break;
}

ready = ull_prepare_dequeue_iter(&idx);
Expand Down Expand Up @@ -989,6 +970,7 @@ int lll_prepare_resolve(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb,
*/

/* Find next prepare needing preempt timeout to be setup */
idx = NULL;
next = prepare_dequeue_iter_ready_get(&idx);
if (!next) {
return err;
Expand Down Expand Up @@ -1025,14 +1007,20 @@ static inline bool is_done_sync(void)
#endif /* !CONFIG_BT_CTLR_LOW_LAT_ULL_DONE */
}

static inline struct lll_event *prepare_dequeue_iter_ready_get(uint8_t *idx)
static inline struct lll_event *prepare_dequeue_iter_ready_get(void **idx)
{
struct lll_event *ready;

do {
ready = ull_prepare_dequeue_iter(idx);
while ((ready != NULL) && ((ready->is_aborted != 0U) || (ready->is_resume != 0U) ||
(ready->prepare_param.defer != 0U))) {
if (!*idx) {
ready = NULL;
break;
}

ready = ull_prepare_dequeue_iter(idx);
} while ((ready != NULL) && ((ready->is_aborted != 0U) || (ready->is_resume != 0U) ||
(ready->prepare_param.defer != 0U)));
}

return ready;
}
Expand Down Expand Up @@ -1223,17 +1211,16 @@ static void preempt(void *param)
{
lll_prepare_cb_t resume_cb;
struct lll_event *ready;
uint8_t idx;
void *idx;
int err;

/* No event to abort */
if (!event.curr.abort_cb || !event.curr.param) {
return;
}

preempt_find_preemptor:
/* Find a prepare that is ready and not a resume */
idx = UINT8_MAX;
idx = NULL;
ready = prepare_dequeue_iter_ready_get(&idx);
if (!ready) {
/* No ready prepare */
Expand All @@ -1242,87 +1229,14 @@ static void preempt(void *param)

/* Preemptor not in pipeline */
if (ready->prepare_param.param != param) {
uint32_t ticks_at_preempt_min = ready->prepare_param.ticks_at_expire;
struct lll_event *ready_short = NULL;
struct lll_event *ready_next = NULL;
struct lll_event *preemptor;

/* Find if the short prepare request in the pipeline */
do {
uint32_t ticks_at_preempt_next;
uint32_t diff;

preemptor = prepare_dequeue_iter_ready_get(&idx);
if (!preemptor) {
break;
}

if (!ready_next) {
ready_next = preemptor;
}

if (preemptor->prepare_param.param == param) {
break;
}

ticks_at_preempt_next = preemptor->prepare_param.ticks_at_expire;
diff = ticker_ticks_diff_get(ticks_at_preempt_next,
ticks_at_preempt_min);
if ((diff & BIT(HAL_TICKER_CNTR_MSBIT)) == 0U) {
continue;
}

ready_short = preemptor;
ticks_at_preempt_min = ticks_at_preempt_next;
} while (true);

/* "The" short prepare we were looking for is not in pipeline */
if (!preemptor) {
uint32_t ret;

/* Find any short prepare */
if (ready_short) {
ready = ready_short;
}

/* Start the preempt timeout for (short) ready event */
ret = preempt_ticker_start(ready, NULL, ready);
LL_ASSERT((ret == TICKER_STATUS_SUCCESS) ||
(ret == TICKER_STATUS_BUSY));

return;
}

/* FIXME: Prepare pipeline is not a ordered list implementation,
* and for short prepare being enqueued, ideally the
* pipeline has to be implemented as ordered list.
* Until then a workaround to abort a prepare present
* before the short prepare being enqueued is implemented
* below.
* A proper solution will be to re-design the pipeline
* as a ordered list, instead of the current FIFO.
*/

/* Abort the prepare that is present before the short prepare */
ready->is_aborted = 1;
ready->abort_cb(&ready->prepare_param, ready->prepare_param.param);

/* Abort all events in pipeline before the short prepare */
if (preemptor != ready_next) {
goto preempt_find_preemptor;
}
uint32_t ret;

/* As the prepare queue has been refreshed due to the call of
* abort_cb which invokes the lll_done, find the latest prepare
*/
idx = UINT8_MAX;
ready = prepare_dequeue_iter_ready_get(&idx);
if (!ready) {
/* No ready prepare */
return;
}
/* Start the preempt timeout for ready event */
ret = preempt_ticker_start(ready, NULL, ready);
LL_ASSERT((ret == TICKER_STATUS_SUCCESS) ||
(ret == TICKER_STATUS_BUSY));

LL_ASSERT(ready->prepare_param.param == param);
return;
}

/* Check if current event want to continue */
Expand Down Expand Up @@ -1366,8 +1280,8 @@ static void preempt(void *param)
lll_abort_cb_t abort_cb;
uint8_t is_resume_abort;
struct lll_event *iter;
uint8_t iter_idx;
void *curr_param;
void *iter_idx;

/* Remove parameter assignment from currently active radio event so that done event
* is not generated.
Expand All @@ -1385,8 +1299,8 @@ static void preempt(void *param)
is_resume_abort = 0U;

preempt_abort_resume:
/* Abort any duplicate non-resume, that they get dequeued */
iter_idx = UINT8_MAX;
/* Abort any duplicates so that they get dequeued */
iter_idx = NULL;
iter = ull_prepare_dequeue_iter(&iter_idx);
while (iter) {
if (!iter->is_aborted &&
Expand All @@ -1401,8 +1315,10 @@ static void preempt(void *param)
* the prepare pipeline hence re-iterate
* through the prepare pipeline.
*/
iter_idx = UINT8_MAX;
iter_idx = NULL;
#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL_DONE */
} else if (!iter_idx) {
break;
}

iter = ull_prepare_dequeue_iter(&iter_idx);
Expand Down
Loading
Loading